Merging trunk up to r38932.
authorJoerg Mueller <nexyon@gmail.com>
Tue, 2 Aug 2011 12:16:06 +0000 (12:16 +0000)
committerJoerg Mueller <nexyon@gmail.com>
Tue, 2 Aug 2011 12:16:06 +0000 (12:16 +0000)
114 files changed:
CMakeLists.txt
SConstruct
build_files/cmake/Modules/FindSpacenav.cmake [new file with mode: 0644]
build_files/cmake/cmake_consistency_check.py
build_files/cmake/cmake_netbeans_project.py
build_files/cmake/cmake_qtcreator_project.py
build_files/cmake/macros.cmake
build_files/scons/config/darwin-config.py
build_files/scons/config/linux2-config.py
build_files/scons/config/win32-vc-config.py
build_files/scons/config/win64-vc-config.py
build_files/scons/tools/btools.py
doc/python_api/rst/bge.constraints.rst
doc/python_api/rst/bge.events.rst
doc/python_api/rst/bge.logic.rst
doc/python_api/rst/bge.render.rst
doc/python_api/rst/bge.texture.rst
doc/python_api/rst/bge.types.rst
doc/python_api/rst/bgl.rst
doc/python_api/sphinx_doc_gen.py
intern/ghost/CMakeLists.txt
intern/ghost/GHOST_C-api.h
intern/ghost/GHOST_ISystem.h
intern/ghost/GHOST_Types.h
intern/ghost/SConscript
intern/ghost/intern/GHOST_C-api.cpp
intern/ghost/intern/GHOST_DisplayManagerWin32.cpp
intern/ghost/intern/GHOST_DropTargetWin32.cpp
intern/ghost/intern/GHOST_DropTargetWin32.h
intern/ghost/intern/GHOST_EventManager.cpp
intern/ghost/intern/GHOST_EventNDOF.h
intern/ghost/intern/GHOST_NDOFManager.cpp
intern/ghost/intern/GHOST_NDOFManager.h
intern/ghost/intern/GHOST_NDOFManagerCocoa.h [new file with mode: 0644]
intern/ghost/intern/GHOST_NDOFManagerCocoa.mm [new file with mode: 0644]
intern/ghost/intern/GHOST_NDOFManagerWin32.cpp [new file with mode: 0644]
intern/ghost/intern/GHOST_NDOFManagerWin32.h [new file with mode: 0644]
intern/ghost/intern/GHOST_NDOFManagerX11.cpp [new file with mode: 0644]
intern/ghost/intern/GHOST_NDOFManagerX11.h [new file with mode: 0644]
intern/ghost/intern/GHOST_System.cpp
intern/ghost/intern/GHOST_System.h
intern/ghost/intern/GHOST_SystemCocoa.h
intern/ghost/intern/GHOST_SystemCocoa.mm
intern/ghost/intern/GHOST_SystemPathsWin32.cpp
intern/ghost/intern/GHOST_SystemPathsWin32.h
intern/ghost/intern/GHOST_SystemWin32.cpp
intern/ghost/intern/GHOST_SystemWin32.h
intern/ghost/intern/GHOST_SystemX11.cpp
intern/ghost/intern/GHOST_SystemX11.h
intern/ghost/intern/GHOST_TaskbarWin32.h
intern/ghost/intern/GHOST_WindowWin32.h
release/scripts/modules/addon_utils.py
release/scripts/modules/bpy/__init__.py
release/scripts/modules/bpy/path.py
release/scripts/modules/bpy/utils.py
release/scripts/modules/bpy_extras/__init__.py
release/scripts/modules/bpy_extras/image_utils.py
release/scripts/modules/bpy_extras/io_utils.py
release/scripts/modules/bpy_extras/mesh_utils.py
release/scripts/modules/bpy_extras/object_utils.py
release/scripts/modules/bpy_extras/view3d_utils.py
release/scripts/modules/keyingsets_utils.py
release/scripts/startup/bl_ui/space_userpref.py
release/scripts/startup/bl_ui/space_userpref_keymap.py
release/scripts/startup/bl_ui/space_view3d.py
release/scripts/templates/addon_add_object.py
source/blender/blenkernel/BKE_curve.h
source/blender/blenkernel/BKE_global.h
source/blender/blenkernel/BKE_material.h
source/blender/blenkernel/intern/DerivedMesh.c
source/blender/blenkernel/intern/curve.c
source/blender/blenkernel/intern/key.c
source/blender/blenkernel/intern/material.c
source/blender/blenkernel/intern/mesh.c
source/blender/blenlib/intern/BLI_args.c
source/blender/blenlib/intern/pbvh.c
source/blender/blenloader/intern/readfile.c
source/blender/editors/curve/editcurve.c
source/blender/editors/gpencil/gpencil_paint.c
source/blender/editors/interface/interface_anim.c
source/blender/editors/interface/resources.c
source/blender/editors/object/object_relations.c
source/blender/editors/screen/screen_ops.c
source/blender/editors/sculpt_paint/paint_image.c
source/blender/editors/sculpt_paint/paint_stroke.c
source/blender/editors/space_image/image_intern.h
source/blender/editors/space_image/image_ops.c
source/blender/editors/space_image/space_image.c
source/blender/editors/space_view3d/view3d_draw.c
source/blender/editors/space_view3d/view3d_edit.c
source/blender/editors/space_view3d/view3d_fly.c
source/blender/editors/space_view3d/view3d_header.c
source/blender/editors/space_view3d/view3d_intern.h
source/blender/editors/space_view3d/view3d_ops.c
source/blender/editors/space_view3d/view3d_select.c
source/blender/editors/transform/transform.c
source/blender/editors/transform/transform_ops.c
source/blender/makesdna/DNA_userdef_types.h
source/blender/makesdna/DNA_view3d_types.h
source/blender/makesrna/intern/rna_ID.c
source/blender/makesrna/intern/rna_action.c
source/blender/makesrna/intern/rna_userdef.c
source/blender/makesrna/intern/rna_wm.c
source/blender/makesrna/intern/rna_wm_api.c
source/blender/modifiers/intern/MOD_uvproject.c
source/blender/python/intern/bpy_props.c
source/blender/python/intern/bpy_rna.c
source/blender/windowmanager/WM_types.h
source/blender/windowmanager/intern/wm_event_system.c
source/blender/windowmanager/intern/wm_init_exit.c
source/blender/windowmanager/intern/wm_operators.c
source/blender/windowmanager/intern/wm_window.c
source/blender/windowmanager/wm_event_types.h
source/gameengine/Ketsji/KX_PyConstraintBinding.cpp

index d4489a8..d95cbb6 100644 (file)
@@ -179,6 +179,7 @@ option(WITH_LZO           "Enable fast LZO compression (used for pointcache)" ON
 option(WITH_LZMA          "Enable best LZMA compression, (used for pointcache)" ON)
 
 # Misc
+option(WITH_INPUT_NDOF "Enable NDOF input devices (SpaceNavigator and friends)" ON)
 option(WITH_RAYOPTIMIZATION    "Enable use of SIMD (SSE) optimizations for the raytracer" ON) 
 if(UNIX AND NOT APPLE)
        option(WITH_INSTALL_PORTABLE "Install redistributeable runtime, otherwise install into CMAKE_INSTALL_PREFIX" ON)
@@ -452,6 +453,19 @@ if(UNIX AND NOT APPLE)
                endif()
        endif()
 
+       if (WITH_INPUT_NDOF)
+               find_package(Spacenav)
+               if(NOT SPACENAV_FOUND)
+                       set(WITH_INPUT_NDOF OFF)
+               endif()
+
+               # use generic names within blenders buildsystem.
+               if(SPACENAV_FOUND)
+                       set(NDOF_INCLUDE_DIRS ${SPACENAV_INCLUDE_DIRS})
+                       set(NDOF_LIBRARIES ${SPACENAV_LIBRARIES})
+               endif()
+       endif()
+
        # OpenSuse needs lutil, ArchLinux not, for now keep, can avoid by using --as-needed
        set(PLATFORM_LINKLIBS "-lutil -lc -lm -lpthread -lstdc++")
 
@@ -1029,6 +1043,10 @@ elseif(APPLE)
                set(TIFF_LIBPATH ${TIFF}/lib)
        endif()
 
+       if (WITH_INPUT_NDOF)
+               # linker needs "-weak_framework 3DconnexionClient"
+       endif()
+
        set(EXETYPE MACOSX_BUNDLE)
 
        set(CMAKE_C_FLAGS_DEBUG "-fno-strict-aliasing -g")
@@ -1054,20 +1072,34 @@ if(APPLE OR WIN32)
        endif()
 endif()
 
+# See TEST_SSE_SUPPORT() for how this is defined.
+
 if(WITH_RAYOPTIMIZATION)
        if(CMAKE_COMPILER_IS_GNUCC)
-               if(SUPPORT_SSE_BUILD)
-                       set(PLATFORM_CFLAGS " -msse ${PLATFORM_CFLAGS}")
-                       add_definitions(-D__SSE__ -D__MMX__)
-               endif()
-               if(SUPPORT_SSE2_BUILD)
-                       set(PLATFORM_CFLAGS " -msse2 ${PLATFORM_CFLAGS}")
-                       add_definitions(-D__SSE2__)
-                       if(NOT SUPPORT_SSE_BUILD) # dont double up
-                               add_definitions(-D__MMX__)
-                       endif()
+               set(_sse "-msse")
+               set(_sse2 "-msse2")
+       elseif(MSVC)
+               set(_sse "/arch:SSE")
+               set(_sse2 "/arch:SSE2")
+       else()
+               message(WARNING "SSE flags for this compiler not known")
+               set(_sse)
+               set(_sse2)
+       endif()
+
+       if(SUPPORT_SSE_BUILD)
+               set(PLATFORM_CFLAGS " ${_sse} ${PLATFORM_CFLAGS}")
+               add_definitions(-D__SSE__ -D__MMX__)
+       endif()
+       if(SUPPORT_SSE2_BUILD)
+               set(PLATFORM_CFLAGS " ${_sse2} ${PLATFORM_CFLAGS}")
+               add_definitions(-D__SSE2__)
+               if(NOT SUPPORT_SSE_BUILD) # dont double up
+                       add_definitions(-D__MMX__)
                endif()
        endif()
+       unset(_sse)
+       unset(_sse2)
 endif()
 
 if(WITH_IMAGE_OPENJPEG)
@@ -1306,6 +1338,7 @@ if(FIRST_RUN)
        info_cfg_option(WITH_OPENCOLLADA)
        info_cfg_option(WITH_FFTW3)
        info_cfg_option(WITH_INTERNATIONAL)
+       info_cfg_option(WITH_INPUT_NDOF)
 
        info_cfg_text("Compiler Options:")
        info_cfg_option(WITH_BUILDINFO)
index 053f414..e27f8ea 100644 (file)
@@ -241,6 +241,7 @@ if 'blenderlite' in B.targets:
     target_env_defs['BF_BUILDINFO'] = False
     target_env_defs['BF_NO_ELBEEM'] = True
     target_env_defs['WITH_BF_PYTHON'] = False
+    target_env_defs['WITH_BF_3DMOUSE'] = False
     
     # Merge blenderlite, let command line to override
     for k,v in target_env_defs.iteritems():
diff --git a/build_files/cmake/Modules/FindSpacenav.cmake b/build_files/cmake/Modules/FindSpacenav.cmake
new file mode 100644 (file)
index 0000000..206f361
--- /dev/null
@@ -0,0 +1,70 @@
+# - Find Spacenav library
+# Find the native Spacenav includes and library
+# This module defines
+#  SPACENAV_INCLUDE_DIRS, where to find spnav.h, Set when
+#                        SPACENAV_INCLUDE_DIR is found.
+#  SPACENAV_LIBRARIES, libraries to link against to use Spacenav.
+#  SPACENAV_ROOT_DIR, The base directory to search for Spacenav.
+#                    This can also be an environment variable.
+#  SPACENAV_FOUND, If false, do not try to use Spacenav.
+#
+# also defined, but not for general use are
+#  SPACENAV_LIBRARY, where to find the Spacenav library.
+
+#=============================================================================
+# Copyright 2011 Blender Foundation.
+#
+# Distributed under the OSI-approved BSD License (the "License");
+# see accompanying file Copyright.txt for details.
+#
+# This software is distributed WITHOUT ANY WARRANTY; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the License for more information.
+#=============================================================================
+
+# If SPACENAV_ROOT_DIR was defined in the environment, use it.
+IF(NOT SPACENAV_ROOT_DIR AND NOT $ENV{SPACENAV_ROOT_DIR} STREQUAL "")
+  SET(SPACENAV_ROOT_DIR $ENV{SPACENAV_ROOT_DIR})
+ENDIF()
+
+SET(_spacenav_SEARCH_DIRS
+  ${SPACENAV_ROOT_DIR}
+  /usr/local
+  /sw # Fink
+  /opt/local # DarwinPorts
+  /opt/csw # Blastwave
+)
+
+FIND_PATH(SPACENAV_INCLUDE_DIR
+  NAMES
+    spnav.h
+  HINTS
+    ${_spacenav_SEARCH_DIRS}
+  PATH_SUFFIXES
+    include
+)
+
+FIND_LIBRARY(SPACENAV_LIBRARY
+  NAMES
+    spnav
+  HINTS
+    ${_spacenav_SEARCH_DIRS}
+  PATH_SUFFIXES
+    lib64 lib
+  )
+
+# handle the QUIETLY and REQUIRED arguments and set SPACENAV_FOUND to TRUE if 
+# all listed variables are TRUE
+INCLUDE(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(Spacenav DEFAULT_MSG
+    SPACENAV_LIBRARY SPACENAV_INCLUDE_DIR)
+
+IF(SPACENAV_FOUND)
+  SET(SPACENAV_LIBRARIES ${SPACENAV_LIBRARY})
+  SET(SPACENAV_INCLUDE_DIRS ${SPACENAV_INCLUDE_DIR})
+ENDIF(SPACENAV_FOUND)
+
+MARK_AS_ADVANCED(
+  SPACENAV_INCLUDE_DIR
+  SPACENAV_LIBRARY
+)
index ba71603..880cb58 100755 (executable)
@@ -39,7 +39,7 @@ def replace_line(f, i, text, keep_indent=True):
     file_handle = open(f, 'r')
     data = file_handle.readlines()
     file_handle.close()
-    
+
     l = data[i]
     ws = l[:len(l) - len(l.lstrip())]
 
index 8060574..02dfec0 100755 (executable)
@@ -37,7 +37,7 @@ from project_info import (SIMPLE_PROJECTFILE,
                           source_list,
                           is_project_file,
                           is_c_header,
-                          is_py,
+                          is_py,
                           cmake_advanced_info,
                           cmake_compiler_defines,
                           )
index d8993c3..2a2774c 100755 (executable)
@@ -33,7 +33,7 @@ example linux usage
 
 from project_info import (SIMPLE_PROJECTFILE,
                           SOURCE_DIR,
-                          CMAKE_DIR,
+                          CMAKE_DIR,
                           PROJECT_DIR,
                           source_list,
                           is_project_file,
index 3430145..ed200ab 100644 (file)
@@ -314,6 +314,10 @@ macro(setup_liblinks
        if(WITH_MEM_JEMALLOC)
                target_link_libraries(${target} ${JEMALLOC_LIBRARIES})
        endif()
+       if(WITH_INPUT_NDOF)
+               target_link_libraries(${target} ${NDOF_LIBRARIES})
+       endif()
+
        if(WIN32 AND NOT UNIX)
                target_link_libraries(${target} ${PTHREADS_LIBRARIES})
        endif()
index 0c51476..4a4bc4a 100644 (file)
@@ -264,7 +264,9 @@ if MACOSX_ARCHITECTURE == 'i386':
     BF_RAYOPTIMIZATION_SSE_FLAGS = ['-msse']
 elif MACOSX_ARCHITECTURE == 'x86_64':
     BF_RAYOPTIMIZATION_SSE_FLAGS = ['-msse','-msse2']
-    
+
+# SpaceNavigator and related 3D mice
+WITH_BF_3DMOUSE = True
 
 #############################################################################
 ###################  various compile settings and flags    ##################
@@ -294,6 +296,9 @@ if WITH_BF_QUICKTIME == True:
        else:
                PLATFORM_LINKFLAGS = PLATFORM_LINKFLAGS+['-framework','QuickTime']
 
+if WITH_BF_3DMOUSE:
+       PLATFORM_LINKFLAGS = PLATFORM_LINKFLAGS + ['-weak_framework','3DconnexionClient']
+
 #note to build succesfully on 10.3.9 SDK you need to patch  10.3.9 by adding the SystemStubs.a lib from 10.4
 LLIBS = ['stdc++', 'SystemStubs']
 
index 328cd4c..6fb9090 100644 (file)
@@ -192,6 +192,10 @@ WITH_BF_OPENMP = True
 WITH_BF_RAYOPTIMIZATION = True
 BF_RAYOPTIMIZATION_SSE_FLAGS = ['-msse','-pthread']
 
+#SpaceNavigator and friends
+WITH_BF_3DMOUSE = True
+BF_3DMOUSE_LIB = 'spnav'
+
 ##
 CC = 'gcc'
 CXX = 'g++'
@@ -223,6 +227,8 @@ CXX_WARN = ['-Wno-invalid-offsetof', '-Wno-sign-compare']
 ##FIX_STUBS_WARNINGS = -Wno-unused
 
 LLIBS = ['util', 'c', 'm', 'dl', 'pthread', 'stdc++']
+if WITH_BF_3DMOUSE:
+       LLIBS = LLIBS + [BF_3DMOUSE_LIB];
 ##LOPTS = --dynamic
 ##DYNLDFLAGS = -shared $(LDFLAGS)
 
index 89b246c..5a91852 100644 (file)
@@ -149,6 +149,8 @@ BF_OPENCOLLADA_INC = '${BF_OPENCOLLADA}/include'
 BF_OPENCOLLADA_LIB = 'OpenCOLLADAStreamWriter OpenCOLLADASaxFrameworkLoader OpenCOLLADAFramework OpenCOLLADABaseUtils GeneratedSaxParser MathMLSolver xml2 pcre buffer ftoa UTF'
 BF_OPENCOLLADA_LIBPATH = '${BF_OPENCOLLADA}/lib'
 
+WITH_BF_3DMOUSE = True
+
 #Ray trace optimization
 WITH_BF_RAYOPTIMIZATION = True
 BF_RAYOPTIMIZATION_SSE_FLAGS = ['/arch:SSE']
index 67db1c4..6717f12 100644 (file)
@@ -153,6 +153,8 @@ BF_OPENCOLLADA_INC = '${BF_OPENCOLLADA}/include'
 BF_OPENCOLLADA_LIB = 'OpenCOLLADAStreamWriter OpenCOLLADASaxFrameworkLoader OpenCOLLADAFramework OpenCOLLADABaseUtils GeneratedSaxParser MathMLSolver xml2 pcre buffer ftoa UTF'
 BF_OPENCOLLADA_LIBPATH = '${BF_OPENCOLLADA}/lib'
 
+WITH_BF_3DMOUSE = True
+
 #Ray trace optimization
 WITH_BF_RAYOPTIMIZATION = True
 BF_RAYOPTIMIZATION_SSE_FLAGS = ['/arch:SSE','/arch:SSE2']
index 677ddab..a96bf8c 100644 (file)
@@ -136,7 +136,7 @@ def validate_arguments(args, bc):
             'BF_NO_ELBEEM',
             'WITH_BF_CXX_GUARDEDALLOC',
             'WITH_BF_JEMALLOC', 'WITH_BF_STATICJEMALLOC', 'BF_JEMALLOC', 'BF_JEMALLOC_INC', 'BF_JEMALLOC_LIBPATH', 'BF_JEMALLOC_LIB', 'BF_JEMALLOC_LIB_STATIC',
-            'BUILDBOT_BRANCH'
+            'BUILDBOT_BRANCH', 'WITH_BF_3DMOUSE'
             ]
     
     # Have options here that scons expects to be lists
@@ -437,6 +437,8 @@ def read_opts(env, cfg, args):
         (BoolVariable('WITH_BF_PLAYER', 'Build blenderplayer if true', False)),
         (BoolVariable('WITH_BF_NOBLENDER', 'Do not build blender if true', False)),
 
+        (BoolVariable('WITH_BF_3DMOUSE', 'Build blender with support of 3D mouses', False)),
+
         ('CFLAGS', 'C only flags', []),
         ('CCFLAGS', 'Generic C and C++ flags', []),
         ('CXXFLAGS', 'C++ only flags', []),
index 882bbc3..12ce861 100644 (file)
@@ -1,28 +1,47 @@
 
-Game Engine bge.constraints Module
-==================================
+Physics Constraints (bge.constraints)
+=====================================
 
-.. note::
-   This documentation is still very weak, and needs some help!
-
-.. function:: createConstraint([obj1, [obj2, [restLength, [restitution, [damping]]]]])
+.. function:: createConstraint(physicsid, physicsid2, constrainttype, [pivotX, pivotY, pivotZ, [axisX, axisY, axisZ, [flag]]]])
 
    Creates a constraint.
 
-   :arg obj1: first object on Constraint
-   :type obj1: :class:'bge.types.KX_GameObject' #I think, there is no error when I use one
+   :arg physicsid: the physics id of the first object in constraint
+   :type physicsid: int
 
-   :arg obj2: second object on Constraint
-   :type obj2: :class:'bge.types.KX_GameObject' #too
+   :arg physicsid2: the physics id of the second object in constraint
+   :type physicsid2: int
 
-   :arg restLength: #to be filled
-   :type restLength: float
+   :arg constrainttype: the type of the constraint. The constraint types are:
 
-   :arg restitution: #to be filled
-   :type restitution: float
+   - :class:`POINTTOPOINT_CONSTRAINT`
+   - :class:`LINEHINGE_CONSTRAINT`
+   - :class:`ANGULAR_CONSTRAINT`
+   - :class:`CONETWIST_CONSTRAINT`
+   - :class:`VEHICLE_CONSTRAINT`
 
-   :arg damping: #to be filled
-   :type damping: float
+   :type constrainttype: int
+
+   :arg pivotX: pivot X position
+   :type pivotX: float
+
+   :arg pivotY: pivot Y position
+   :type pivotY: float
+
+   :arg pivotZ: pivot Z position
+   :type pivotZ: float
+
+   :arg axisX: X axis
+   :type axisX: float
+
+   :arg axisY: Y axis
+   :type axisY: float
+
+   :arg axisZ: Z axis
+   :type axisZ: float
+
+   :arg flag: .. to do
+   :type flag: int
 
 .. attribute:: error
 
@@ -49,7 +68,7 @@ Game Engine bge.constraints Module
    :type constraintId: int
 
    :return: a vehicle constraint object.
-   :rtype: :class:'KX_VehicleWrapper'
+   :rtype: :class:`bge.types.KX_VehicleWrapper`
 
 .. function:: removeConstraint(constraintId)
 
@@ -60,10 +79,10 @@ Game Engine bge.constraints Module
 
 .. function:: setCcdMode(ccdMode)
 
-   ..note::
+   .. note::
       Very experimental, not recommended
 
-   Sets the CCD mode in the Physics Environment.
+   Sets the CCD (Continous Colision Detection) mode in the Physics Environment.
 
    :arg ccdMode: The new CCD mode.
    :type ccdMode: int
@@ -73,21 +92,21 @@ Game Engine bge.constraints Module
    .. note::
       Reasonable default is 0.02 (if units are meters)
 
-   Sets the contact breaking treshold in the Physics Environment.
+   Sets tresholds to do with contact point management.
 
    :arg breakingTreshold: The new contact breaking treshold.
    :type breakingTreshold: float
 
 .. function:: setDeactivationAngularTreshold(angularTreshold)
 
-   Sets the deactivation angular treshold.
+   Sets the angular velocity treshold.
 
    :arg angularTreshold: New deactivation angular treshold.
    :type angularTreshold: float
 
 .. function:: setDeactivationLinearTreshold(linearTreshold)
 
-   Sets the deactivation linear treshold.
+   Sets the linear velocity treshold.
 
    :arg linearTreshold: New deactivation linear treshold.
    :type linearTreshold: float
@@ -104,21 +123,20 @@ Game Engine bge.constraints Module
    Sets the debug mode.
 
    Debug modes:
-      - No debug: 0
-      - Draw wireframe: 1
-      - Draw Aabb: 2 #What's Aabb?
-      - Draw freatures text: 4
-      - Draw contact points: 8
-      - No deactivation: 16
-      - No help text: 32
-      - Draw text: 64
-      - Profile timings: 128
-      - Enable sat comparision: 256
-      - Disable Bullet LCP: 512
-      - Enable CCD: 1024
-      - Draw Constraints: #(1 << 11) = ?
-      - Draw Constraint Limits: #(1 << 12) = ?
-      - Fast Wireframe: #(1 << 13) = ?
+      - :class:`DBG_NODEBUG`
+      - :class:`DBG_DRAWWIREFRAME`
+      - :class:`DBG_DRAWAABB`
+      - :class:`DBG_DRAWFREATURESTEXT`
+      - :class:`DBG_DRAWCONTACTPOINTS`
+      - :class:`DBG_NOHELPTEXT`
+      - :class:`DBG_DRAWTEXT`
+      - :class:`DBG_PROFILETIMINGS`
+      - :class:`DBG_ENABLESATCOMPARISION`
+      - :class:`DBG_DISABLEBULLETLCP`
+      - :class:`DBG_ENABLECCD`
+      - :class:`DBG_DRAWCONSTRAINTS`
+      - :class:`DBG_DRAWCONSTRAINTLIMITS`
+      - :class:`DBG_FASTWIREFRAME`
 
    :arg mode: The new debug mode.
    :type mode: int
@@ -138,7 +156,10 @@ Game Engine bge.constraints Module
 
 .. function:: setLinearAirDamping(damping)
 
-   Not implemented.
+   .. note::
+      Not implemented.
+
+   Sets the linear air damping for rigidbodies.
 
 .. function:: setNumIterations(numiter)
 
@@ -156,10 +177,10 @@ Game Engine bge.constraints Module
 
 .. function:: setSolverDamping(damping)
 
-   ..note::
+   .. note::
       Very experimental, not recommended
 
-   Sets the solver damping.
+   Sets the damper constant of a penalty based solver.
 
    :arg damping: New damping for the solver.
    :type damping: float
@@ -169,7 +190,7 @@ Game Engine bge.constraints Module
    .. note::
       Very experimental, not recommended
 
-   Sets the solver tau.
+   Sets the spring constant of a penalty based solver.
 
    :arg tau: New tau for the solver.
    :type tau: float
@@ -189,7 +210,7 @@ Game Engine bge.constraints Module
    .. note::
       Very experimental, not recommended
 
-   Sets the sor constant.
+   Sets the successive overrelaxation constant.
 
    :arg sor: New sor value.
    :type sor: float
@@ -197,3 +218,136 @@ Game Engine bge.constraints Module
 .. function:: setUseEpa(epa)
 
    Not implemented.
+
+.. data:: DBG_NODEBUG
+   
+   .. note::
+      Debug mode to be used with function :class:`setDebugMode`
+   
+   No debug.
+
+.. data:: DBG_DRAWWIREFRAME
+   
+   .. note::
+      Debug mode to be used with function :class:`setDebugMode`
+   
+   Draw wireframe in debug.
+
+.. data:: DBG_DRAWAABB
+   
+   .. note::
+      Debug mode to be used with function :class:`setDebugMode`
+   
+   Draw Axis Aligned Bounding Box in debug.
+
+.. data:: DBG_DRAWFREATURESTEXT
+   
+   .. note::
+      Debug mode to be used with function :class:`setDebugMode`
+   
+   Draw freatures text in debug.
+
+.. data:: DBG_DRAWCONTACTPOINTS
+   
+   .. note::
+      Debug mode to be used with function :class:`setDebugMode`
+   
+   Draw contact points in debug.
+
+.. data:: DBG_NOHELPTEXT
+   
+   .. note::
+      Debug mode to be used with function :class:`setDebugMode`
+   
+   Debug without help text.
+
+.. data:: DBG_DRAWTEXT
+   
+   .. note::
+      Debug mode to be used with function :class:`setDebugMode`
+   
+   Draw text in debug.
+
+.. data:: DBG_PROFILETIMINGS
+   
+   .. note::
+      Debug mode to be used with function :class:`setDebugMode`
+   
+   Draw profile timings in debug.
+
+.. data:: DBG_ENABLESATCOMPARISION
+   
+   .. note::
+      Debug mode to be used with function :class:`setDebugMode`
+   
+   Enable sat comparision in debug.
+
+.. data:: DBG_DISABLEBULLETLCP
+   
+   .. note::
+      Debug mode to be used with function :class:`setDebugMode`
+   
+   Disable Bullet LCP.
+
+.. data:: DBG_ENABLECCD
+
+   .. note::
+      Debug mode to be used with function :class:`setDebugMode`
+   
+   Enable Continous Colision Detection in debug.
+
+.. data:: DBG_DRAWCONSTRAINTS
+   
+   .. note::
+      Debug mode to be used with function :class:`setDebugMode`
+   
+   Draw constraints in debug.
+
+.. data:: DBG_DRAWCONSTRAINTLIMITS
+   
+   .. note::
+      Debug mode to be used with function :class:`setDebugMode`
+   
+   Draw constraint limits in debug.
+
+.. data:: DBG_FASTWIREFRAME
+   
+   .. note::
+      Debug mode to be used with function :class:`setDebugMode`
+   
+   Draw a fast wireframe in debug.
+
+.. data:: POINTTOPOINT_CONSTRAINT
+
+   .. note::
+      Constraint type to be used with function :class:`createConstraint`
+
+   .. to do
+
+.. data:: LINEHINGE_CONSTRAINT
+
+   .. note::
+      Constraint type to be used with function :class:`createConstraint`
+
+   .. to do
+
+.. data:: ANGULAR_CONSTRAINT
+
+   .. note::
+      Constraint type to be used with function :class:`createConstraint`
+
+   .. to do
+
+.. data:: CONETWIST_CONSTRAINT
+
+   .. note::
+       Constraint type to be used with function :class:`createConstraint`
+
+   .. to do
+
+.. data:: VEHICLE_CONSTRAINT
+
+   .. note::
+      Constraint type to be used with function :class:`createConstraint`
+
+   .. to do
index cc76ecd..074e928 100644 (file)
@@ -1,6 +1,6 @@
 
-Game Engine bge.events Module
-=============================
+Game Keys (bge.events)
+======================
 
 *****
 Intro
index f7163ea..128f87f 100644 (file)
@@ -1,6 +1,7 @@
 
-Game Engine bge.logic Module
-============================
+Game Logic (bge.logic)
+======================
+
 *****
 Intro
 *****
index 9f17455..1051404 100644 (file)
@@ -1,6 +1,6 @@
 
-Game Engine bge.render Module
-=============================
+Rasterizer (bge.render)
+=======================
 
 *****
 Intro
@@ -16,8 +16,8 @@ Intro
    import bge.render
    import bge.logic
 
-   # SCALE sets the speed of motion
-   SCALE=[1, 0.5]
+   # scale sets the speed of motion
+   scale = 1.0, 0.5
    
    co = bge.logic.getCurrentController()
    obj = co.getOwner()
@@ -27,8 +27,8 @@ Intro
    
    # Transform the mouse coordinates to see how far the mouse has moved.
    def mousePos():
-      x = (bge.render.getWindowWidth()/2 - mouse.getXPosition())*SCALE[0]
-      y = (bge.render.getWindowHeight()/2 - mouse.getYPosition())*SCALE[1]
+      x = (bge.render.getWindowWidth() / 2 - mouse.getXPosition()) * scale[0]
+      y = (bge.render.getWindowHeight() / 2 - mouse.getYPosition()) * scale[1]
       return (x, y)
    
    pos = mousePos()
@@ -43,7 +43,7 @@ Intro
    bge.logic.addActiveActuator(wmotion, True)
    
    # Centre the mouse
-   bge.render.setMousePosition(bge.render.getWindowWidth()/2, bge.render.getWindowHeight()/2)
+   bge.render.setMousePosition(bge.render.getWindowWidth() / 2, bge.render.getWindowHeight() / 2)
 
 *********
 Constants
index 996f79a..f3e9f98 100644 (file)
@@ -1,10 +1,6 @@
 
-Game Engine bge.texture Module
-==============================
-
-.. note::
-   This documentation is still very weak, and needs some help! Right now they are mostly a collection
-   of the docstrings found in the bge.texture source code + some random places filled with text.
+Video Texture (bge.texture)
+===========================
 
 *****
 Intro
index 367f647..d1fc859 100644 (file)
@@ -1,6 +1,6 @@
 
-Game Engine  bge.types Module
-=============================
+Game Types (bge.types)
+======================
 
 .. module:: bge.types
 
index 76b7442..236bfaf 100644 (file)
@@ -1,6 +1,6 @@
 
-bgl module (OpenGL wrapper)
-===========================
+OpenGL Wrapper (bgl)
+====================
 
 .. module:: bgl
 
@@ -71,8 +71,8 @@ OpenGL}" and the online NeHe tutorials are two of the best resources.
    .. seealso:: `OpenGL Docs <http://www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/begin.html>`_
 
    :type mode: Enumerated constant
-   :arg mode: Specifies the primitive that will be create from vertices between glBegin and
-      glEnd.
+   :arg mode: Specifies the primitive that will be create from vertices between
+      glBegin and glEnd.
 
 
 .. function:: glBindTexture(target, texture):
@@ -1886,4 +1886,3 @@ class Buffer:
          the Buffer. If a template is not passed in all fields will be initialized to 0.
       :rtype: Buffer object
       :return: The newly created buffer as a PyObject.
-
index 6b514cf..f8561c7 100644 (file)
@@ -416,6 +416,7 @@ def pymodule2sphinx(BASEPATH, module_name, module, title):
     del key, descr
 
     classes = []
+    submodules = []
 
     for attribute in module_dir:
         if not attribute.startswith("_"):
@@ -437,6 +438,8 @@ def pymodule2sphinx(BASEPATH, module_name, module, title):
                 py_c_func2sphinx("", fw, module_name, None, attribute, value, is_class=False)
             elif value_type == type:
                 classes.append((attribute, value))
+            elif issubclass(value_type, types.ModuleType):
+                submodules.append((attribute, value))
             elif value_type in (bool, int, float, str, tuple):
                 # constant, not much fun we can do here except to list it.
                 # TODO, figure out some way to document these!
@@ -444,12 +447,26 @@ def pymodule2sphinx(BASEPATH, module_name, module, title):
                 write_indented_lines("   ", fw, "constant value %s" % repr(value), False)
                 fw("\n")
             else:
-                print("\tnot documenting %s.%s" % (module_name, attribute))
+                print("\tnot documenting %s.%s of %r type" % (module_name, attribute, value_type.__name__))
                 continue
 
             attribute_set.add(attribute)
             # TODO, more types...
 
+    # TODO, bpy_extras does this already, mathutils not.
+    """
+    if submodules:
+        fw("\n"
+           "**********\n"
+           "Submodules\n"
+           "**********\n"
+           "\n"
+           )
+        for attribute, submod in submodules:
+            fw("* :mod:`%s.%s`\n" % (module_name, attribute))
+        fw("\n")
+    """
+
     # write collected classes now
     for (type_name, value) in classes:
         # May need to be its own function
index ccd763e..2180ddb 100644 (file)
@@ -97,6 +97,12 @@ if(WITH_GHOST_DEBUG)
        add_definitions(-DWITH_GHOST_DEBUG)
 endif()
 
+if(WITH_INPUT_NDOF)
+       add_definitions(-DWITH_INPUT_NDOF)
+       list(APPEND INC_SYS
+               ${NDOF_INCLUDE_DIRS}
+       )
+endif()
 
 if(WITH_HEADLESS OR WITH_GHOST_SDL)
        if(WITH_HEADLESS)
@@ -158,12 +164,21 @@ elseif(APPLE)
                        intern/GHOST_SystemCocoa.mm
                        intern/GHOST_SystemPathsCocoa.mm
                        intern/GHOST_WindowCocoa.mm
-                       
+
                        intern/GHOST_DisplayManagerCocoa.h
                        intern/GHOST_SystemCocoa.h
                        intern/GHOST_SystemPathsCocoa.h
                        intern/GHOST_WindowCocoa.h
                )
+
+               if(WITH_INPUT_NDOF)
+                       list(APPEND SRC
+                               intern/GHOST_NDOFManagerCocoa.mm
+
+                               intern/GHOST_NDOFManagerCocoa.h
+                       )
+               endif()
+
        else()
                list(APPEND SRC
                        intern/GHOST_DisplayManagerCarbon.cpp
@@ -215,6 +230,14 @@ elseif(UNIX)
                )
        endif()
 
+       if(WITH_INPUT_NDOF)
+               list(APPEND SRC
+                       intern/GHOST_NDOFManagerX11.cpp
+
+                       intern/GHOST_NDOFManagerX11.h
+               )
+       endif()
+
 elseif(WIN32)
        if(MSVC)
                set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /WX")
@@ -238,6 +261,15 @@ elseif(WIN32)
                intern/GHOST_WindowWin32.h
                intern/GHOST_TaskbarWin32.h
        )
+
+       if(WITH_INPUT_NDOF)
+               list(APPEND SRC
+                       intern/GHOST_NDOFManagerWin32.cpp
+
+                       intern/GHOST_NDOFManagerWin32.h
+               )
+       endif()
+
 endif()
 
 blender_add_lib(bf_intern_ghost "${SRC}" "${INC}" "${INC_SYS}")
index 7583723..a315dfa 100644 (file)
@@ -288,21 +288,6 @@ extern GHOST_TSuccess GHOST_SetProgressBar(GHOST_WindowHandle windowhandle, floa
  * @param windowhandle The handle to the window
  */
 extern GHOST_TSuccess GHOST_EndProgressBar(GHOST_WindowHandle windowhandle);
-       
-       
-/***************************************************************************************
- ** N-degree of freedom device management functionality
- ***************************************************************************************/
-/**
-* Open N-degree of freedom devices
- */
-extern int GHOST_OpenNDOF(GHOST_SystemHandle systemhandle, 
-                           GHOST_WindowHandle windowhandle,
-                          GHOST_NDOFLibraryInit_fp setNdofLibraryInit, 
-                          GHOST_NDOFLibraryShutdown_fp setNdofLibraryShutdown,
-                          GHOST_NDOFDeviceOpen_fp setNdofDeviceOpen
-                          );
 
 /***************************************************************************************
  ** Cursor management functionality
index 69e1007..015ae78 100644 (file)
@@ -298,22 +298,6 @@ public:
         */
        virtual GHOST_TSuccess removeEventConsumer(GHOST_IEventConsumer* consumer) = 0;
 
-        /***************************************************************************************
-        ** N-degree of freedom device management functionality
-        ***************************************************************************************/
-
-   /**
-    * Starts the N-degree of freedom device manager
-    */
-   virtual int openNDOF(GHOST_IWindow*,
-       GHOST_NDOFLibraryInit_fp setNdofLibraryInit, 
-       GHOST_NDOFLibraryShutdown_fp setNdofLibraryShutdown,
-       GHOST_NDOFDeviceOpen_fp setNdofDeviceOpen
-       // original patch only
-      // GHOST_NDOFEventHandler_fp setNdofEventHandler
-       ) = 0;
-
-
        /***************************************************************************************
         ** Cursor management functionality
         ***************************************************************************************/
index 6a4da5c..f24ab00 100644 (file)
@@ -47,11 +47,6 @@ typedef unsigned short               GHOST_TUns16;
 typedef        int                                     GHOST_TInt32;
 typedef        unsigned int            GHOST_TUns32;
 
-#ifdef WIN32
-#define WM_BLND_NDOF_AXIS      WM_USER + 1
-#define WM_BLND_NDOF_BTN       WM_USER + 2
-#endif
-
 #if defined(WIN32) && !defined(FREE_WINDOWS)
 typedef __int64                                GHOST_TInt64;
 typedef unsigned __int64       GHOST_TUns64;
@@ -440,37 +435,33 @@ typedef struct {
        GHOST_TUns8 **strings;
 } GHOST_TStringArray;
 
+typedef enum {
+       GHOST_kNotStarted,
+       GHOST_kStarting,
+       GHOST_kInProgress,
+       GHOST_kFinishing,
+       GHOST_kFinished
+       } GHOST_TProgress;
 
-/* original patch used floats, but the driver return ints and uns. We will calibrate in view, no sense on doing conversions twice */
-/* as all USB device controls are likely to use ints, this is also more future proof */
-//typedef struct {
-//   /** N-degree of freedom device data */
-//   float tx, ty, tz;   /** -x left, +y up, +z forward */
-//   float rx, ry, rz;
-//   float dt;
-//} GHOST_TEventNDOFData;
+typedef struct {
+       /** N-degree of freedom device data v3 [GSoC 2010] */
+       // Each component normally ranges from -1 to +1, but can exceed that.
+       // These use blender standard view coordinates, with positive rotations being CCW about the axis.
+       float tx, ty, tz; // translation
+       float rx, ry, rz; // rotation:
+               // axis = (rx,ry,rz).normalized
+               // amount = (rx,ry,rz).magnitude [in revolutions, 1.0 = 360 deg]
+       float dt; // time since previous NDOF Motion event
+       GHOST_TProgress progress; // Starting, InProgress or Finishing (for modal handlers)
+} GHOST_TEventNDOFMotionData;
+
+typedef enum { GHOST_kPress, GHOST_kRelease } GHOST_TButtonAction;
+       // good for mouse or other buttons too, hmmm?
 
 typedef struct {
-   /** N-degree of freedom device data v2*/
-   int changed;
-   GHOST_TUns64 client;
-   GHOST_TUns64 address;
-   GHOST_TInt16 tx, ty, tz;   /** -x left, +y up, +z forward */
-   GHOST_TInt16 rx, ry, rz;
-   GHOST_TInt16 buttons;
-   GHOST_TUns64 time;
-   GHOST_TUns64 delta;
-} GHOST_TEventNDOFData;
-
-typedef int     (*GHOST_NDOFLibraryInit_fp)(void);
-typedef void    (*GHOST_NDOFLibraryShutdown_fp)(void* deviceHandle);
-typedef void*   (*GHOST_NDOFDeviceOpen_fp)(void* platformData);
-
-// original patch windows callback. In mac os X version the callback is internal to the plug-in and post an event to main thead.
-// not necessary faster, but better integration with other events. 
-
-//typedef int     (*GHOST_NDOFEventHandler_fp)(float* result7, void* deviceHandle, unsigned int message, unsigned int* wParam, unsigned long* lParam);
-//typedef void     (*GHOST_NDOFCallBack_fp)(GHOST_TEventNDOFDataV2 *VolDatas);
+       GHOST_TButtonAction action;
+       short button;
+} GHOST_TEventNDOFButtonData;
 
 typedef struct {
        /** The key code. */
index c65ec58..45a1f44 100644 (file)
@@ -11,7 +11,7 @@ if window_system == 'darwin':
     sources += env.Glob('intern/*.mm')
 
 
-pf = ['GHOST_DisplayManager', 'GHOST_System', 'GHOST_SystemPaths', 'GHOST_Window', 'GHOST_DropTarget']
+pf = ['GHOST_DisplayManager', 'GHOST_System', 'GHOST_SystemPaths', 'GHOST_Window', 'GHOST_DropTarget', 'GHOST_NDOFManager']
 defs=['_USE_MATH_DEFINES']
 
 incs = '. ../string #extern/glew/include #source/blender/imbuf #source/blender/makesdna ' + env['BF_OPENGL_INC']
@@ -76,7 +76,22 @@ else:
 if env['BF_GHOST_DEBUG']:
     defs.append('WITH_GHOST_DEBUG')
 else:
-       sources.remove('intern' + os.sep + 'GHOST_EventPrinter.cpp')
+    sources.remove('intern' + os.sep + 'GHOST_EventPrinter.cpp')
+
+if env['WITH_BF_3DMOUSE']:
+    defs.append('WITH_INPUT_NDOF')
+else:
+    sources.remove('intern' + os.sep + 'GHOST_NDOFManager.cpp')
+    try:
+        if window_system in ('win32-vc', 'win32-mingw', 'cygwin', 'linuxcross', 'win64-vc'):
+            sources.remove('intern' + os.sep + 'GHOST_NDOFManagerWin32.cpp')
+        elif window_system=='darwin':
+            sources.remove('intern' + os.sep + 'GHOST_NDOFManagerCocoa.mm')
+        else:
+            sources.remove('intern' + os.sep + 'GHOST_NDOFManagerX11.mm')
+    except ValueError:
+        pass
+
 
 if window_system in ('win32-vc', 'win32-mingw', 'cygwin', 'linuxcross', 'win64-vc'):
     incs = env['BF_WINTAB_INC'] + ' ' + incs
index 7ba8d7d..6332d72 100644 (file)
@@ -275,23 +275,6 @@ GHOST_TSuccess GHOST_EndProgressBar(GHOST_WindowHandle windowhandle)
 }
 
 
-int GHOST_OpenNDOF(GHOST_SystemHandle systemhandle, GHOST_WindowHandle windowhandle,
-   GHOST_NDOFLibraryInit_fp setNdofLibraryInit, 
-    GHOST_NDOFLibraryShutdown_fp setNdofLibraryShutdown,
-    GHOST_NDOFDeviceOpen_fp setNdofDeviceOpen)
-  //original patch only
-  /*  GHOST_NDOFEventHandler_fp setNdofEventHandler)*/
-{
-       GHOST_ISystem* system = (GHOST_ISystem*) systemhandle;
-
-    return system->openNDOF((GHOST_IWindow*) windowhandle,
-        setNdofLibraryInit, setNdofLibraryShutdown, setNdofDeviceOpen);
-//     original patch
-//        setNdofLibraryInit, setNdofLibraryShutdown, setNdofDeviceOpen, setNdofEventHandler);
-}
-
-
-
 GHOST_TStandardCursor GHOST_GetCursorShape(GHOST_WindowHandle windowhandle)
 {
        GHOST_IWindow* window = (GHOST_IWindow*) windowhandle;
index 30d9aa3..47f7489 100644 (file)
 #include "GHOST_DisplayManagerWin32.h"
 #include "GHOST_Debug.h"
 
-// We do not support multiple monitors at the moment
+#define _WIN32_WINNT 0x501 // require Windows XP or newer
+#define WIN32_LEAN_AND_MEAN
 #include <windows.h>
+
+// We do not support multiple monitors at the moment
 #define COMPILE_MULTIMON_STUBS
 #ifndef FREE_WINDOWS
 #include <multimon.h>
index 2e77da4..99990a4 100644 (file)
@@ -33,6 +33,7 @@
  
 #include "GHOST_Debug.h"
 #include "GHOST_DropTargetWin32.h"
+#include <ShellApi.h>
 
 #ifdef GHOST_DEBUG
 // utility
index 0a553b6..980e9f9 100644 (file)
@@ -33,7 +33,6 @@
 #ifndef _GHOST_DROP_TARGET_WIN32_H_
 #define _GHOST_DROP_TARGET_WIN32_H_
 
-#include <windows.h>
 #include <string.h>
 #include <GHOST_Types.h>
 #include "GHOST_WindowWin32.h"
index 1483555..86b8797 100644 (file)
@@ -42,7 +42,7 @@
 #include "GHOST_EventManager.h"
 #include <algorithm>
 #include "GHOST_Debug.h"
-
+#include <stdio.h> // [mce] temp debug
 
 GHOST_EventManager::GHOST_EventManager()
 {
index 70861b0..394aff0 100644 (file)
  *
  * ***** END GPL LICENSE BLOCK *****
  */
-
-/** \file ghost/intern/GHOST_EventNDOF.h
- *  \ingroup GHOST
- */
-
  
 
 #ifndef _GHOST_EVENT_NDOF_H_
 
 #include "GHOST_Event.h"
 
-/**
- * N-degree of freedom device event.
- */
-class GHOST_EventNDOF : 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_EventNDOF(GHOST_TUns64 msec, GHOST_TEventType type, GHOST_IWindow* window, 
-        GHOST_TEventNDOFData data)
-               : GHOST_Event(msec, type, window)
-       {
-               m_ndofEventData = data;
-               m_data = &m_ndofEventData;
-       }
 
-protected:
-       /** translation & rotation from the device. */
-       GHOST_TEventNDOFData m_ndofEventData;
-};
+class GHOST_EventNDOFMotion : public GHOST_Event
+       {
+       protected:
+               GHOST_TEventNDOFMotionData m_axisData;
+       
+       public:
+               GHOST_EventNDOFMotion(GHOST_TUns64 time, GHOST_IWindow* window)
+                       : GHOST_Event(time, GHOST_kEventNDOFMotion, window)
+                       {
+                       m_data = &m_axisData;
+                       }
+       };
+
+
+class GHOST_EventNDOFButton : public GHOST_Event
+       {
+       protected:
+               GHOST_TEventNDOFButtonData m_buttonData;
+       
+       public:
+               GHOST_EventNDOFButton(GHOST_TUns64 time, GHOST_IWindow* window)
+                       : GHOST_Event(time, GHOST_kEventNDOFButton, window)
+                       {
+                       m_data = &m_buttonData;
+                       }
+       };
 
 
 #endif // _GHOST_EVENT_NDOF_H_
-
index dae6cb5..5a0f14c 100644 (file)
@@ -1,4 +1,6 @@
 /*
+ * $Id$
+ *
  * ***** BEGIN GPL LICENSE BLOCK *****
  *
  * This program is free software; you can redistribute it and/or
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  *
- * Contributor(s): none yet.
+ * Contributor(s):
+ *   Mike Erwin
  *
  * ***** END GPL LICENSE BLOCK *****
  */
 
-/** \file ghost/intern/GHOST_NDOFManager.cpp
- *  \ingroup GHOST
- */
+#include "GHOST_Debug.h"
+#include "GHOST_NDOFManager.h"
+#include "GHOST_EventNDOF.h"
+#include "GHOST_EventKey.h"
+#include "GHOST_WindowManager.h"
+#include <string.h> // for memory functions
+#include <stdio.h> // for error/info reporting
+#include <math.h>
 
+#ifdef DEBUG_NDOF_MOTION
+// printable version of each GHOST_TProgress value
+static const char* progress_string[] =
+       {"not started","starting","in progress","finishing","finished"};
+#endif
 
-#include <stdio.h> /* just for printf */
+#ifdef DEBUG_NDOF_BUTTONS
+static const char* ndof_button_names[] = {
+       // used internally, never sent
+       "NDOF_BUTTON_NONE",
+       // these two are available from any 3Dconnexion device
+       "NDOF_BUTTON_MENU",
+       "NDOF_BUTTON_FIT",
+       // standard views
+       "NDOF_BUTTON_TOP",
+       "NDOF_BUTTON_BOTTOM",
+       "NDOF_BUTTON_LEFT",
+       "NDOF_BUTTON_RIGHT",
+       "NDOF_BUTTON_FRONT",
+       "NDOF_BUTTON_BACK",
+       // more views
+       "NDOF_BUTTON_ISO1",
+       "NDOF_BUTTON_ISO2",
+       // 90 degree rotations
+       "NDOF_BUTTON_ROLL_CW",
+       "NDOF_BUTTON_ROLL_CCW",
+       "NDOF_BUTTON_SPIN_CW",
+       "NDOF_BUTTON_SPIN_CCW",
+       "NDOF_BUTTON_TILT_CW",
+       "NDOF_BUTTON_TILT_CCW",
+       // device control
+       "NDOF_BUTTON_ROTATE",
+       "NDOF_BUTTON_PANZOOM",
+       "NDOF_BUTTON_DOMINANT",
+       "NDOF_BUTTON_PLUS",
+       "NDOF_BUTTON_MINUS",
+       // general-purpose buttons
+       "NDOF_BUTTON_1",
+       "NDOF_BUTTON_2",
+       "NDOF_BUTTON_3",
+       "NDOF_BUTTON_4",
+       "NDOF_BUTTON_5",
+       "NDOF_BUTTON_6",
+       "NDOF_BUTTON_7",
+       "NDOF_BUTTON_8",
+       "NDOF_BUTTON_9",
+       "NDOF_BUTTON_10",
+       };
+#endif
 
-#include "GHOST_NDOFManager.h"
+static const NDOF_ButtonT SpaceNavigator_HID_map[] =
+       {
+       NDOF_BUTTON_MENU,
+       NDOF_BUTTON_FIT
+       };
 
+static const NDOF_ButtonT SpaceExplorer_HID_map[] =
+       {
+       NDOF_BUTTON_1,
+       NDOF_BUTTON_2,
+       NDOF_BUTTON_TOP,
+       NDOF_BUTTON_LEFT,
+       NDOF_BUTTON_RIGHT,
+       NDOF_BUTTON_FRONT,
+       NDOF_BUTTON_NONE, // esc key
+       NDOF_BUTTON_NONE, // alt key
+       NDOF_BUTTON_NONE, // shift key
+       NDOF_BUTTON_NONE, // ctrl key
+       NDOF_BUTTON_FIT,
+       NDOF_BUTTON_MENU,
+       NDOF_BUTTON_PLUS,
+       NDOF_BUTTON_MINUS,
+       NDOF_BUTTON_ROTATE
+       };
 
-// the variable is outside the class because it must be accessed from plugin
-static volatile GHOST_TEventNDOFData currentNdofValues = {0,0,0,0,0,0,0,0,0,0,0};
+static const NDOF_ButtonT SpacePilotPro_HID_map[] =
+       {
+       NDOF_BUTTON_MENU,
+       NDOF_BUTTON_FIT,
+       NDOF_BUTTON_TOP,
+       NDOF_BUTTON_LEFT,
+       NDOF_BUTTON_RIGHT,
+       NDOF_BUTTON_FRONT,
+       NDOF_BUTTON_BOTTOM,
+       NDOF_BUTTON_BACK,
+       NDOF_BUTTON_ROLL_CW,
+       NDOF_BUTTON_ROLL_CCW,
+       NDOF_BUTTON_ISO1,
+       NDOF_BUTTON_ISO2,
+       NDOF_BUTTON_1,
+       NDOF_BUTTON_2,
+       NDOF_BUTTON_3,
+       NDOF_BUTTON_4,
+       NDOF_BUTTON_5,
+       NDOF_BUTTON_6,
+       NDOF_BUTTON_7,
+       NDOF_BUTTON_8,
+       NDOF_BUTTON_9,
+       NDOF_BUTTON_10,
+       NDOF_BUTTON_NONE, // esc key
+       NDOF_BUTTON_NONE, // alt key
+       NDOF_BUTTON_NONE, // shift key
+       NDOF_BUTTON_NONE, // ctrl key
+       NDOF_BUTTON_ROTATE,
+       NDOF_BUTTON_PANZOOM,
+       NDOF_BUTTON_DOMINANT,
+       NDOF_BUTTON_PLUS,
+       NDOF_BUTTON_MINUS
+       };
 
-#if !defined(_WIN32) && !defined(__APPLE__)
-#include "GHOST_SystemX11.h"
-#endif
+static const NDOF_ButtonT SpacePilot_HID_map[] =
+// this is the older SpacePilot (sans Pro)
+// thanks to polosson for the info in this table
+       {
+       NDOF_BUTTON_1,
+       NDOF_BUTTON_2,
+       NDOF_BUTTON_3,
+       NDOF_BUTTON_4,
+       NDOF_BUTTON_5,
+       NDOF_BUTTON_6,
+       NDOF_BUTTON_TOP,
+       NDOF_BUTTON_LEFT,
+       NDOF_BUTTON_RIGHT,
+       NDOF_BUTTON_FRONT,
+       NDOF_BUTTON_NONE, // esc key
+       NDOF_BUTTON_NONE, // alt key
+       NDOF_BUTTON_NONE, // shift key
+       NDOF_BUTTON_NONE, // ctrl key
+       NDOF_BUTTON_FIT,
+       NDOF_BUTTON_MENU,
+       NDOF_BUTTON_PLUS,
+       NDOF_BUTTON_MINUS,
+       NDOF_BUTTON_DOMINANT,
+       NDOF_BUTTON_ROTATE,
+       NDOF_BUTTON_NONE // the CONFIG button -- what does it do?
+       };
 
-namespace
-{
-    GHOST_NDOFLibraryInit_fp ndofLibraryInit = 0;
-    GHOST_NDOFLibraryShutdown_fp ndofLibraryShutdown = 0;
-    GHOST_NDOFDeviceOpen_fp ndofDeviceOpen = 0;
-}
-
-GHOST_NDOFManager::GHOST_NDOFManager()
-{
-    m_DeviceHandle = 0;
-
-    // discover the API from the plugin
-    ndofLibraryInit = 0;
-    ndofLibraryShutdown = 0;
-    ndofDeviceOpen = 0;
-}
-
-GHOST_NDOFManager::~GHOST_NDOFManager()
-{
-    if (ndofLibraryShutdown)
-        ndofLibraryShutdown(m_DeviceHandle);
-
-    m_DeviceHandle = 0;
-}
-
-
-int
-GHOST_NDOFManager::deviceOpen(GHOST_IWindow* window,
-        GHOST_NDOFLibraryInit_fp setNdofLibraryInit, 
-        GHOST_NDOFLibraryShutdown_fp setNdofLibraryShutdown,
-        GHOST_NDOFDeviceOpen_fp setNdofDeviceOpen)
-{
-       int Pid;
-       
-    ndofLibraryInit = setNdofLibraryInit;
-    ndofLibraryShutdown = setNdofLibraryShutdown;
-    ndofDeviceOpen = setNdofDeviceOpen;
-
-    if (ndofLibraryInit  && ndofDeviceOpen)
-    {
-       Pid= ndofLibraryInit();
-#if 0
-               printf("%i client \n", Pid);
-#endif
-               #if defined(WITH_HEADLESS)
-                       /* do nothing */
-               #elif defined(_WIN32) || defined(__APPLE__)
-                       m_DeviceHandle = ndofDeviceOpen((void *)&currentNdofValues);    
-               #elif defined(WITH_GHOST_SDL)
-                       /* do nothing */
-               #else
-                       GHOST_SystemX11 *sys;
-                       sys = static_cast<GHOST_SystemX11*>(GHOST_ISystem::getSystem());
-                       void *ndofInfo = sys->prepareNdofInfo(&currentNdofValues);
-                       m_DeviceHandle = ndofDeviceOpen(ndofInfo);
+GHOST_NDOFManager::GHOST_NDOFManager(GHOST_System& sys)
+       : m_system(sys)
+       , m_deviceType(NDOF_UnknownDevice) // each platform has its own device detection code
+       , m_buttonCount(0)
+       , m_buttonMask(0)
+       , m_buttons(0)
+       , m_motionTime(0)
+       , m_prevMotionTime(0)
+       , m_motionState(GHOST_kNotStarted)
+       , m_motionEventPending(false)
+       , m_deadZone(0.f)
+       {
+       // to avoid the rare situation where one triple is updated and
+       // the other is not, initialize them both here:
+       memset(m_translation, 0, sizeof(m_translation));
+       memset(m_rotation, 0, sizeof(m_rotation));
+
+       #ifdef WITH_INPUT_NDOF
+       GHOST_PRINT("WITH_INPUT_NDOF is defined!");
+       #else
+       GHOST_PRINT("WITH_INPUT_NDOF is not defined.");
+       #endif
+       }
+
+bool GHOST_NDOFManager::setDevice(unsigned short vendor_id, unsigned short product_id)
+       {
+       // default to NDOF_UnknownDevice so rogue button events will get discarded
+       // "mystery device" owners can help build a HID_map for their hardware
+
+       switch (vendor_id)
+               {
+               case 0x046D: // Logitech (3Dconnexion)
+                       switch (product_id)
+                               {
+                               // -- current devices --
+                               case 0xC626:
+                                       puts("ndof: using SpaceNavigator");
+                                       m_deviceType = NDOF_SpaceNavigator;
+                                       m_buttonCount = 2;
+                                       break;
+                               case 0xC628:
+                                       puts("ndof: using SpaceNavigator for Notebooks");
+                                       m_deviceType = NDOF_SpaceNavigator; // for Notebooks
+                                       m_buttonCount = 2;
+                                       break;
+                               case 0xC627:
+                                       puts("ndof: using SpaceExplorer");
+                                       m_deviceType = NDOF_SpaceExplorer;
+                                       m_buttonCount = 15;
+                                       break;
+                               case 0xC629:
+                                       puts("ndof: using SpacePilotPro");
+                                       m_deviceType = NDOF_SpacePilotPro;
+                                       m_buttonCount = 31;
+                                       break;
+
+                               // -- older devices --
+                               case 0xC625:
+                                       puts("ndof: using SpacePilot");
+                                       m_deviceType = NDOF_SpacePilot;
+                                       m_buttonCount = 21;
+                                       break;
+
+                               case 0xC623:
+                                       puts("ndof: SpaceTraveler not supported, please file a bug report");
+                                       m_buttonCount = 8;
+                                       break;
+
+                               default:
+                                       printf("ndof: unknown Logitech product %04hx\n", product_id);
+                               }
+                       break;
+               default:
+                       printf("ndof: unknown device %04hx:%04hx\n", vendor_id, product_id);
+               }
+
+       if (m_deviceType == NDOF_UnknownDevice)
+               return false;
+       else
+               {
+               m_buttonMask = ~(-1 << m_buttonCount);
+
+               #ifdef DEBUG_NDOF_BUTTONS
+               printf("ndof: %d buttons -> hex:%X\n", m_buttonCount, m_buttonMask);
                #endif
-                return (Pid > 0) ? 0 : 1;
-                       
-       } else
-               return 1;
-}
-
-
-bool 
-GHOST_NDOFManager::available() const
-{ 
-    return m_DeviceHandle != 0; 
-}
-
-bool 
-GHOST_NDOFManager::event_present() const
-{ 
-    if( currentNdofValues.changed >0) {
-               printf("time %llu but%u x%i y%i z%i rx%i ry%i rz%i \n"  ,                       
-                               currentNdofValues.time,         currentNdofValues.buttons,
-                               currentNdofValues.tx,currentNdofValues.ty,currentNdofValues.tz,
-                               currentNdofValues.rx,currentNdofValues.ry,currentNdofValues.rz);
-       return true;
-       }else
-       return false;
-
-}
-
-void        GHOST_NDOFManager::GHOST_NDOFGetDatas(GHOST_TEventNDOFData &datas) const
-{
-       datas.tx = currentNdofValues.tx;
-       datas.ty = currentNdofValues.ty;
-       datas.tz = currentNdofValues.tz;
-       datas.rx = currentNdofValues.rx;
-       datas.ry = currentNdofValues.ry;
-       datas.rz = currentNdofValues.rz;
-       datas.buttons = currentNdofValues.buttons;
-       datas.client = currentNdofValues.client;
-       datas.address = currentNdofValues.address;
-       datas.time = currentNdofValues.time;
-       datas.delta = currentNdofValues.delta;
-}
+
+               return true;
+               }
+       }
+
+void GHOST_NDOFManager::updateTranslation(short t[3], GHOST_TUns64 time)
+       {
+       memcpy(m_translation, t, sizeof(m_translation));
+       m_motionTime = time;
+       m_motionEventPending = true;
+       }
+
+void GHOST_NDOFManager::updateRotation(short r[3], GHOST_TUns64 time)
+       {
+       memcpy(m_rotation, r, sizeof(m_rotation));
+       m_motionTime = time;
+       m_motionEventPending = true;
+       }
+
+void GHOST_NDOFManager::sendButtonEvent(NDOF_ButtonT button, bool press, GHOST_TUns64 time, GHOST_IWindow* window)
+       {
+       GHOST_EventNDOFButton* event = new GHOST_EventNDOFButton(time, window);
+       GHOST_TEventNDOFButtonData* data = (GHOST_TEventNDOFButtonData*) event->getData();
+
+       data->action = press ? GHOST_kPress : GHOST_kRelease;
+       data->button = button;
+
+       #ifdef DEBUG_NDOF_BUTTONS
+       printf("%s %s\n", ndof_button_names[button], press ? "pressed" : "released");
+       #endif
+
+       m_system.pushEvent(event);
+       }
+
+void GHOST_NDOFManager::sendKeyEvent(GHOST_TKey key, bool press, GHOST_TUns64 time, GHOST_IWindow* window)
+       {
+       GHOST_TEventType type = press ? GHOST_kEventKeyDown : GHOST_kEventKeyUp;
+       GHOST_EventKey* event = new GHOST_EventKey(time, type, window, key);
+
+       #ifdef DEBUG_NDOF_BUTTONS
+       printf("keyboard %s\n", press ? "down" : "up");
+       #endif
+
+       m_system.pushEvent(event);
+       }
+
+void GHOST_NDOFManager::updateButton(int button_number, bool press, GHOST_TUns64 time)
+       {
+       GHOST_IWindow* window = m_system.getWindowManager()->getActiveWindow();
+
+       #ifdef DEBUG_NDOF_BUTTONS
+       if (m_deviceType != NDOF_UnknownDevice)
+               printf("ndof: button %d -> ", button_number);
+       #endif
+
+       switch (m_deviceType)
+               {
+               case NDOF_SpaceNavigator:
+                       sendButtonEvent(SpaceNavigator_HID_map[button_number], press, time, window);
+                       break;
+               case NDOF_SpaceExplorer:
+                       switch (button_number)
+                               {
+                               case 6: sendKeyEvent(GHOST_kKeyEsc, press, time, window); break;
+                               case 7: sendKeyEvent(GHOST_kKeyLeftAlt, press, time, window); break;
+                               case 8: sendKeyEvent(GHOST_kKeyLeftShift, press, time, window); break;
+                               case 9: sendKeyEvent(GHOST_kKeyLeftControl, press, time, window); break;
+                               default: sendButtonEvent(SpaceExplorer_HID_map[button_number], press, time, window);
+                               }
+                       break;
+               case NDOF_SpacePilotPro:
+                       switch (button_number)
+                               {
+                               case 22: sendKeyEvent(GHOST_kKeyEsc, press, time, window); break;
+                               case 23: sendKeyEvent(GHOST_kKeyLeftAlt, press, time, window); break;
+                               case 24: sendKeyEvent(GHOST_kKeyLeftShift, press, time, window); break;
+                               case 25: sendKeyEvent(GHOST_kKeyLeftControl, press, time, window); break;
+                               default: sendButtonEvent(SpacePilotPro_HID_map[button_number], press, time, window);
+                               }
+                       break;
+               case NDOF_SpacePilot:
+                       switch (button_number)
+                               {
+                               case 10: sendKeyEvent(GHOST_kKeyEsc, press, time, window); break;
+                               case 11: sendKeyEvent(GHOST_kKeyLeftAlt, press, time, window); break;
+                               case 12: sendKeyEvent(GHOST_kKeyLeftShift, press, time, window); break;
+                               case 13: sendKeyEvent(GHOST_kKeyLeftControl, press, time, window); break;
+                               case 20: puts("ndof: ignoring CONFIG button"); break;
+                               default: sendButtonEvent(SpacePilot_HID_map[button_number], press, time, window);
+                               }
+                       break;
+               case NDOF_UnknownDevice:
+                       printf("ndof: button %d on unknown device (ignoring)\n", button_number);
+               }
+
+       int mask = 1 << button_number;
+       if (press)
+               m_buttons |= mask; // set this button's bit
+       else
+               m_buttons &= ~mask; // clear this button's bit
+       }
+
+void GHOST_NDOFManager::updateButtons(int button_bits, GHOST_TUns64 time)
+       {
+       button_bits &= m_buttonMask; // discard any "garbage" bits
+
+       int diff = m_buttons ^ button_bits;
+
+       for (int button_number = 0; button_number < m_buttonCount; ++button_number)
+               {
+               int mask = 1 << button_number;
+
+               if (diff & mask)
+                       {
+                       bool press = button_bits & mask;
+                       updateButton(button_number, press, time);
+                       }
+               }
+       }
+
+void GHOST_NDOFManager::setDeadZone(float dz)
+       {
+       if (dz < 0.f)
+               // negative values don't make sense, so clamp at zero
+               dz = 0.f;
+       else if (dz > 0.5f)
+               // warn the rogue user/programmer, but allow it
+               printf("ndof: dead zone of %.2f is rather high...\n", dz);
+
+       m_deadZone = dz;
+
+       printf("ndof: dead zone set to %.2f\n", dz);
+       }
+
+static bool atHomePosition(GHOST_TEventNDOFMotionData* ndof)
+       {
+       #define HOME(foo) (ndof->foo == 0)
+       return HOME(tx) && HOME(ty) && HOME(tz) && HOME(rx) && HOME(ry) && HOME(rz);
+       }
+
+static bool nearHomePosition(GHOST_TEventNDOFMotionData* ndof, float threshold)
+       {
+       if (threshold == 0.f)
+               return atHomePosition(ndof);
+       else
+               {
+               #define HOME1(foo) (fabsf(ndof->foo) < threshold)
+               return HOME1(tx) && HOME1(ty) && HOME1(tz) && HOME1(rx) && HOME1(ry) && HOME1(rz);
+               }
+       }
+
+bool GHOST_NDOFManager::sendMotionEvent()
+       {
+       if (!m_motionEventPending)
+               return false;
+
+       m_motionEventPending = false; // any pending motion is handled right now
+
+       GHOST_IWindow* window = m_system.getWindowManager()->getActiveWindow();
+       if (window == NULL)
+               return false; // delivery will fail, so don't bother sending
+
+       GHOST_EventNDOFMotion* event = new GHOST_EventNDOFMotion(m_motionTime, window);
+       GHOST_TEventNDOFMotionData* data = (GHOST_TEventNDOFMotionData*) event->getData();
+
+       // scale axis values here to normalize them to around +/- 1
+       // they are scaled again for overall sensitivity in the WM based on user prefs
+
+       const float scale = 1.f / 350.f; // 3Dconnexion devices send +/- 350 usually
+
+       data->tx = scale * m_translation[0];
+       data->ty = scale * m_translation[1];
+       data->tz = scale * m_translation[2];
+
+       data->rx = scale * m_rotation[0];
+       data->ry = scale * m_rotation[1];
+       data->rz = scale * m_rotation[2];
+
+       data->dt = 0.001f * (m_motionTime - m_prevMotionTime); // in seconds
+
+       bool handMotion = !nearHomePosition(data, m_deadZone);
+
+       // determine what kind of motion event to send (Starting, InProgress, Finishing)
+       // and where that leaves this NDOF manager (NotStarted, InProgress, Finished)
+       switch (m_motionState)
+               {
+               case GHOST_kNotStarted:
+               case GHOST_kFinished:
+                       if (handMotion)
+                               {
+                               data->progress = GHOST_kStarting;
+                               m_motionState = GHOST_kInProgress;
+                               // prev motion time will be ancient, so just make up something reasonable
+                               data->dt = 0.0125f;
+                               }
+                       else
+                               {
+                               // send no event and keep current state
+                               delete event;
+                               return false;
+                               }
+                       break;
+               case GHOST_kInProgress:
+                       if (handMotion)
+                               {
+                               data->progress = GHOST_kInProgress;
+                               // keep InProgress state
+                               }
+                       else
+                               {
+                               data->progress = GHOST_kFinishing;
+                               m_motionState = GHOST_kFinished;
+                               }
+                       break;
+               }
+
+       #ifdef DEBUG_NDOF_MOTION
+       printf("ndof motion sent -- %s\n", progress_string[data->progress]);
+
+       // show details about this motion event
+       printf("    T=(%.2f,%.2f,%.2f) R=(%.2f,%.2f,%.2f) dt=%.3f\n",
+               data->tx, data->ty, data->tz,
+               data->rx, data->ry, data->rz,
+               data->dt);
+       #endif
+
+       m_system.pushEvent(event);
+
+       m_prevMotionTime = m_motionTime;
+
+       return true;
+       }
index c9e0937..5bdbe7a 100644 (file)
@@ -1,4 +1,6 @@
 /*
+ * $Id$
+ *
  * ***** BEGIN GPL LICENSE BLOCK *****
  *
  * This program is free software; you can redistribute it and/or
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  *
- * Contributor(s): none yet.
+ * Contributor(s):
+ *   Mike Erwin
  *
  * ***** END GPL LICENSE BLOCK *****
  */
-
-/** \file ghost/intern/GHOST_NDOFManager.h
- *  \ingroup GHOST
- */
-
  
 #ifndef _GHOST_NDOFMANAGER_H_
 #define _GHOST_NDOFMANAGER_H_
 
 #include "GHOST_System.h"
-#include "GHOST_IWindow.h"
 
 
+// #define DEBUG_NDOF_MOTION
+// #define DEBUG_NDOF_BUTTONS
+
+typedef enum {
+       NDOF_UnknownDevice, // <-- motion will work fine, buttons are ignored
+
+       // current devices
+       NDOF_SpaceNavigator,
+       NDOF_SpaceExplorer,
+       NDOF_SpacePilotPro,
+
+       // older devices
+       NDOF_SpacePilot
+
+       } NDOF_DeviceT;
+
+// NDOF device button event types
+typedef enum {
+       // used internally, never sent
+       NDOF_BUTTON_NONE,
+       // these two are available from any 3Dconnexion device
+       NDOF_BUTTON_MENU,
+       NDOF_BUTTON_FIT,
+       // standard views
+       NDOF_BUTTON_TOP,
+       NDOF_BUTTON_BOTTOM,
+       NDOF_BUTTON_LEFT,
+       NDOF_BUTTON_RIGHT,
+       NDOF_BUTTON_FRONT,
+       NDOF_BUTTON_BACK,
+       // more views
+       NDOF_BUTTON_ISO1,
+       NDOF_BUTTON_ISO2,
+       // 90 degree rotations
+       // these don't all correspond to physical buttons
+       NDOF_BUTTON_ROLL_CW,
+       NDOF_BUTTON_ROLL_CCW,
+       NDOF_BUTTON_SPIN_CW,
+       NDOF_BUTTON_SPIN_CCW,
+       NDOF_BUTTON_TILT_CW,
+       NDOF_BUTTON_TILT_CCW,
+       // device control
+       NDOF_BUTTON_ROTATE,
+       NDOF_BUTTON_PANZOOM,
+       NDOF_BUTTON_DOMINANT,
+       NDOF_BUTTON_PLUS,
+       NDOF_BUTTON_MINUS,
+       // general-purpose buttons
+       // users can assign functions via keymap editor
+       NDOF_BUTTON_1,
+       NDOF_BUTTON_2,
+       NDOF_BUTTON_3,
+       NDOF_BUTTON_4,
+       NDOF_BUTTON_5,
+       NDOF_BUTTON_6,
+       NDOF_BUTTON_7,
+       NDOF_BUTTON_8,
+       NDOF_BUTTON_9,
+       NDOF_BUTTON_10,
+
+       } NDOF_ButtonT;
 
 class GHOST_NDOFManager
 {
 public:
-       GHOST_NDOFManager();
-       virtual ~GHOST_NDOFManager();
-
-    int deviceOpen(GHOST_IWindow* window,
-        GHOST_NDOFLibraryInit_fp setNdofLibraryInit, 
-        GHOST_NDOFLibraryShutdown_fp setNdofLibraryShutdown,
-        GHOST_NDOFDeviceOpen_fp setNdofDeviceOpen);
-        
-    void GHOST_NDOFGetDatas(GHOST_TEventNDOFData &datas) const;
-        
-    bool available() const;
-    bool event_present() const;
+       GHOST_NDOFManager(GHOST_System&);
+
+       virtual ~GHOST_NDOFManager() {};
+
+       // whether multi-axis functionality is available (via the OS or driver)
+       // does not imply that a device is plugged in or being used
+       virtual bool available() = 0;
+
+       // each platform's device detection should call this
+       // use standard USB/HID identifiers
+       bool setDevice(unsigned short vendor_id, unsigned short product_id);
+
+       // filter out small/accidental/uncalibrated motions by
+       // setting up a "dead zone" around home position
+       // set to 0 to disable
+       // 0.1 is a safe and reasonable value
+       void setDeadZone(float);
+
+       // the latest raw axis data from the device
+       // NOTE: axis data should be in blender view coordinates
+       //       +X is to the right
+       //       +Y is up
+       //       +Z is out of the screen
+       //       for rotations, look from origin to each +axis
+       //       rotations are + when CCW, - when CW
+       // each platform is responsible for getting axis data into this form
+       // these values should not be scaled (just shuffled or flipped)
+       void updateTranslation(short t[3], GHOST_TUns64 time);
+       void updateRotation(short r[3], GHOST_TUns64 time);
+
+       // the latest raw button data from the device
+       // use HID button encoding (not NDOF_ButtonT)
+       void updateButton(int button_number, bool press, GHOST_TUns64 time);
+       void updateButtons(int button_bits, GHOST_TUns64 time);
+       // NDOFButton events are sent immediately
+
+       // processes and sends most recent raw data as an NDOFMotion event
+       // returns whether an event was sent
+       bool sendMotionEvent();
 
 protected:
-    void* m_DeviceHandle;
-};
+       GHOST_System& m_system;
 
+private:
+       void sendButtonEvent(NDOF_ButtonT, bool press, GHOST_TUns64 time, GHOST_IWindow*);
+       void sendKeyEvent(GHOST_TKey, bool press, GHOST_TUns64 time, GHOST_IWindow*);
+
+       NDOF_DeviceT m_deviceType;
+       int m_buttonCount;
+       int m_buttonMask;
+
+       short m_translation[3];
+       short m_rotation[3];
+       int m_buttons; // bit field
+
+       GHOST_TUns64 m_motionTime; // in milliseconds
+       GHOST_TUns64 m_prevMotionTime; // time of most recent Motion event sent
+
+       GHOST_TProgress m_motionState;
+       bool m_motionEventPending;
+       float m_deadZone; // discard motion with each component < this
+};
 
 #endif
diff --git a/intern/ghost/intern/GHOST_NDOFManagerCocoa.h b/intern/ghost/intern/GHOST_NDOFManagerCocoa.h
new file mode 100644 (file)
index 0000000..27397b7
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * $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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s):
+ *   Mike Erwin
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+#ifndef _GHOST_NDOFMANAGERCOCOA_H_
+#define _GHOST_NDOFMANAGERCOCOA_H_
+
+#include "GHOST_NDOFManager.h"
+
+// Event capture is handled within the NDOF manager on Macintosh,
+// so there's no need for SystemCocoa to look for them.
+
+class GHOST_NDOFManagerCocoa : public GHOST_NDOFManager
+{
+public:
+       GHOST_NDOFManagerCocoa(GHOST_System&);
+
+       ~GHOST_NDOFManagerCocoa();
+
+       // whether multi-axis functionality is available (via the OS or driver)
+       // does not imply that a device is plugged in or being used
+       bool available();
+
+private:
+       unsigned short m_clientID;
+};
+
+
+#endif
diff --git a/intern/ghost/intern/GHOST_NDOFManagerCocoa.mm b/intern/ghost/intern/GHOST_NDOFManagerCocoa.mm
new file mode 100644 (file)
index 0000000..07811c5
--- /dev/null
@@ -0,0 +1,174 @@
+/*
+ * $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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s):
+ *   Mike Erwin
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+#include "GHOST_NDOFManagerCocoa.h"
+#include "GHOST_SystemCocoa.h"
+
+extern "C" {
+       #include <3DconnexionClient/ConnexionClientAPI.h>
+       #include <stdio.h>
+       }
+
+// static functions need to talk to these objects:
+static GHOST_SystemCocoa* ghost_system = NULL;
+static GHOST_NDOFManager* ndof_manager = NULL;
+
+// 3Dconnexion drivers before 10.x are "old"
+// not all buttons will work
+static bool has_old_driver = true;
+
+static void NDOF_DeviceAdded(io_connect_t connection)
+       {
+       printf("ndof: device added\n"); // change these: printf --> informational reports
+
+#if 0 // device preferences will be useful some day
+       ConnexionDevicePrefs p;
+       ConnexionGetCurrentDevicePrefs(kDevID_AnyDevice, &p);
+#endif
+
+       // determine exactly which device is plugged in
+       SInt32 result = 0;
+       ConnexionControl(kConnexionCtlGetDeviceID, 0, &result);
+       unsigned short vendorID = result >> 16;
+       unsigned short productID = result & 0xffff;
+
+       ndof_manager->setDevice(vendorID, productID);
+       }
+
+static void NDOF_DeviceRemoved(io_connect_t connection)
+       {
+       printf("ndof: device removed\n");
+       }
+
+static void NDOF_DeviceEvent(io_connect_t connection, natural_t messageType, void* messageArgument)
+       {
+       switch (messageType)
+               {
+               case kConnexionMsgDeviceState:
+                       {
+                       ConnexionDeviceState* s = (ConnexionDeviceState*)messageArgument;
+
+                       GHOST_TUns64 now = ghost_system->getMilliSeconds();
+
+                       switch (s->command)
+                               {
+                               case kConnexionCmdHandleAxis:
+                                       {
+                                       // convert to blender view coordinates
+                                       short t[3] = {s->axis[0], -(s->axis[2]), s->axis[1]};
+                                       short r[3] = {-(s->axis[3]), s->axis[5], -(s->axis[4])};
+
+                                       ndof_manager->updateTranslation(t, now);
+                                       ndof_manager->updateRotation(r, now);
+
+                                       ghost_system->notifyExternalEventProcessed();
+                                       break;
+                                       }
+                               case kConnexionCmdHandleButtons:
+                                       {
+                                       int button_bits = has_old_driver ? s->buttons8 : s->buttons;
+                                       ndof_manager->updateButtons(button_bits, now);
+                                       ghost_system->notifyExternalEventProcessed();
+                                       break;
+                                       }
+                               case kConnexionCmdAppSpecific:
+                                       printf("ndof: app-specific command, param = %hd, value = %d\n", s->param, s->value);
+                                       break;
+
+                               default:
+                                       printf("ndof: mystery device command %d\n", s->command);
+                               }
+                       break;
+                       }
+               case kConnexionMsgPrefsChanged:
+                       // printf("ndof: prefs changed\n"); // this includes app switches
+                       // TODO: look through updated prefs for things blender cares about
+                       break;
+               case kConnexionMsgCalibrateDevice:
+                       printf("ndof: calibrate\n"); // but what should blender do?
+                       break;
+               case kConnexionMsgDoMapping:
+                       // printf("ndof: driver did something\n");
+                       // sent when the driver itself consumes an NDOF event
+                       // and performs whatever action is set in user prefs
+                       // 3Dx header file says to ignore these
+                       break;
+               default:
+                       printf("ndof: mystery event %d\n", messageType);
+               }
+       }
+
+GHOST_NDOFManagerCocoa::GHOST_NDOFManagerCocoa(GHOST_System& sys)
+       : GHOST_NDOFManager(sys)
+       {
+       if (available())
+               {
+               // give static functions something to talk to:
+               ghost_system = dynamic_cast<GHOST_SystemCocoa*>(&sys);
+               ndof_manager = this;
+
+               OSErr error = InstallConnexionHandlers(NDOF_DeviceEvent, NDOF_DeviceAdded, NDOF_DeviceRemoved);
+               if (error)
+                       {
+                       printf("ndof: error %d while installing handlers\n", error);
+                       return;
+                       }
+
+               // Pascal string *and* a four-letter constant. How old-skool.
+               m_clientID = RegisterConnexionClient('blnd', (UInt8*) "\007blender",
+                       kConnexionClientModeTakeOver, kConnexionMaskAll);
+
+               // printf("ndof: client id = %d\n", m_clientID);
+
+               if (SetConnexionClientButtonMask != NULL)
+                       {
+                       has_old_driver = false;
+                       SetConnexionClientButtonMask(m_clientID, kConnexionMaskAllButtons);
+                       }
+               else
+                       printf("ndof: old 3Dx driver installed, some buttons may not work\n");
+               }
+       else
+               {
+               printf("ndof: 3Dx driver not found\n");
+               // This isn't a hard error, just means the user doesn't have a 3D mouse.
+               }
+       }
+
+GHOST_NDOFManagerCocoa::~GHOST_NDOFManagerCocoa()
+       {
+       UnregisterConnexionClient(m_clientID);
+       CleanupConnexionHandlers();
+       ghost_system = NULL;
+       ndof_manager = NULL;
+       }
+
+bool GHOST_NDOFManagerCocoa::available()
+       {
+       // extern OSErr InstallConnexionHandlers() __attribute__((weak_import));
+       // ^^ not needed since the entire framework is weak-linked
+       return InstallConnexionHandlers != NULL;
+       // this means that the driver is installed and dynamically linked to blender
+       }
diff --git a/intern/ghost/intern/GHOST_NDOFManagerWin32.cpp b/intern/ghost/intern/GHOST_NDOFManagerWin32.cpp
new file mode 100644 (file)
index 0000000..099b163
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * $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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s):
+ *   Mike Erwin
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+#include "GHOST_NDOFManagerWin32.h"
+
+
+GHOST_NDOFManagerWin32::GHOST_NDOFManagerWin32(GHOST_System& sys)
+       : GHOST_NDOFManager(sys)
+       {}
+
+// whether multi-axis functionality is available (via the OS or driver)
+// does not imply that a device is plugged in or being used
+bool GHOST_NDOFManagerWin32::available()
+       {
+       // always available since RawInput is built into Windows
+       return true;
+       }
diff --git a/intern/ghost/intern/GHOST_NDOFManagerWin32.h b/intern/ghost/intern/GHOST_NDOFManagerWin32.h
new file mode 100644 (file)
index 0000000..31f7e07
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * $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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s):
+ *   Mike Erwin
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+#ifndef _GHOST_NDOFMANAGERWIN32_H_
+#define _GHOST_NDOFMANAGERWIN32_H_
+
+#include "GHOST_NDOFManager.h"
+
+
+class GHOST_NDOFManagerWin32 : public GHOST_NDOFManager
+{
+public:
+       GHOST_NDOFManagerWin32(GHOST_System&);
+       bool available();
+};
+
+
+#endif
diff --git a/intern/ghost/intern/GHOST_NDOFManagerX11.cpp b/intern/ghost/intern/GHOST_NDOFManagerX11.cpp
new file mode 100644 (file)
index 0000000..8043af2
--- /dev/null
@@ -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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s):
+ *   Mike Erwin
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+#include "GHOST_NDOFManagerX11.h"
+#include "GHOST_SystemX11.h"
+#include <spnav.h>
+#include <stdio.h>
+
+
+GHOST_NDOFManagerX11::GHOST_NDOFManagerX11(GHOST_System& sys)
+       : GHOST_NDOFManager(sys)
+       , m_available(false)
+       {
+       setDeadZone(0.1f); // how to calibrate on Linux? throw away slight motion!
+
+       if (spnav_open() != -1)
+               {
+               // determine exactly which device (if any) is plugged in
+
+               #define MAX_LINE_LENGTH 100
+
+               // look for USB devices with Logitech's vendor ID
+               FILE* command_output = popen("lsusb -d 046d:","r");
+               if (command_output)
+                       {
+                       char line[MAX_LINE_LENGTH] = {0};
+                       while (fgets(line, MAX_LINE_LENGTH, command_output))
+                               {
+                               unsigned short vendor_id = 0, product_id = 0;
+                               if (sscanf(line, "Bus %*d Device %*d: ID %hx:%hx", &vendor_id, &product_id) == 2)
+                                       if (setDevice(vendor_id, product_id))
+                                               {
+                                               m_available = true;
+                                               break; // stop looking once the first 3D mouse is found
+                                               }
+                               }
+                       pclose(command_output);
+                       }
+               }
+       else
+               {
+               printf("ndof: spacenavd not found\n");
+               // This isn't a hard error, just means the user doesn't have a 3D mouse.
+               }
+       }
+
+GHOST_NDOFManagerX11::~GHOST_NDOFManagerX11()
+       {
+       if (m_available)
+               spnav_close();
+       }
+
+bool GHOST_NDOFManagerX11::available()
+       {
+       return m_available;
+       }
+
+//bool GHOST_NDOFManagerX11::identifyDevice()
+//     {
+//     
+//     }
+
+bool GHOST_NDOFManagerX11::processEvents()
+       {
+       GHOST_TUns64 now = m_system.getMilliSeconds();
+
+       bool anyProcessed = false;
+       spnav_event e;
+       while (spnav_poll_event(&e))
+               {
+               switch (e.type)
+                       {
+                       case SPNAV_EVENT_MOTION:
+                               {
+                               // convert to blender view coords
+                               short t[3] = {e.motion.x, e.motion.y, -e.motion.z};
+                               short r[3] = {-e.motion.rx, -e.motion.ry, e.motion.rz};
+
+                               updateTranslation(t, now);
+                               updateRotation(r, now);
+                               break;
+                               }
+                       case SPNAV_EVENT_BUTTON:
+                               updateButton(e.button.bnum, e.button.press, now);
+                               break;
+                       }
+               anyProcessed = true;
+               }
+       return anyProcessed;
+       }
diff --git a/intern/ghost/intern/GHOST_NDOFManagerX11.h b/intern/ghost/intern/GHOST_NDOFManagerX11.h
new file mode 100644 (file)
index 0000000..175041b
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * $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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s):
+ *   Mike Erwin
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+#ifndef _GHOST_NDOFMANAGERX11_H_
+#define _GHOST_NDOFMANAGERX11_H_
+
+#include "GHOST_NDOFManager.h"
+
+// Event capture is handled within the NDOF manager on Linux,
+// so there's no need for SystemX11 to look for them.
+
+class GHOST_NDOFManagerX11 : public GHOST_NDOFManager
+       {
+public:
+       GHOST_NDOFManagerX11(GHOST_System&);
+       ~GHOST_NDOFManagerX11();
+       bool available();
+       bool processEvents();
+
+private:
+//     bool identifyDevice();
+
+       bool m_available;
+       };
+
+#endif
+
index cb3e97f..64c2c21 100644 (file)
 
 
 GHOST_System::GHOST_System()
-: m_displayManager(0), m_timerManager(0), m_windowManager(0), m_eventManager(0), m_ndofManager(0)
+    : m_displayManager(0),
+      m_timerManager(0),
+      m_windowManager(0),
+      m_eventManager(0)
+#ifdef WITH_INPUT_NDOF
+      , m_ndofManager(0)
+#endif
 {
 }
 
@@ -194,12 +200,17 @@ bool GHOST_System::getFullScreen(void)
 
 bool GHOST_System::dispatchEvents()
 {
-       bool handled;
-       if (m_eventManager) {
-               handled = m_eventManager->dispatchEvents();
+       bool handled = false;
+
+#ifdef WITH_INPUT_NDOF
+       // NDOF Motion event is sent only once per dispatch, so do it now:
+       if (m_ndofManager) {
+               handled |= m_ndofManager->sendMotionEvent();
        }
-       else {
-               handled = false;
+#endif
+
+       if (m_eventManager) {
+               handled |= m_eventManager->dispatchEvents();
        }
 
        m_timerManager->fireTimers(getMilliSeconds());
@@ -243,18 +254,6 @@ GHOST_TSuccess GHOST_System::pushEvent(GHOST_IEvent* event)
        return success;
 }
 
-int GHOST_System::openNDOF(GHOST_IWindow* w,
-               GHOST_NDOFLibraryInit_fp setNdofLibraryInit, 
-               GHOST_NDOFLibraryShutdown_fp setNdofLibraryShutdown,
-               GHOST_NDOFDeviceOpen_fp setNdofDeviceOpen)
-{
- return m_ndofManager->deviceOpen(w,
-               setNdofLibraryInit, 
-               setNdofLibraryShutdown,
-               setNdofDeviceOpen);
-}
-
-
 GHOST_TSuccess GHOST_System::getModifierKeyState(GHOST_TModifierKeyMask mask, bool& isDown) const
 {
        GHOST_ModifierKeys keys;
@@ -285,12 +284,6 @@ GHOST_TSuccess GHOST_System::init()
        m_timerManager = new GHOST_TimerManager ();
        m_windowManager = new GHOST_WindowManager ();
        m_eventManager = new GHOST_EventManager ();
-       m_ndofManager = new GHOST_NDOFManager();
-
-#if 0
-       if(m_ndofManager)
-               printf("ndof manager \n");
-#endif
        
 #ifdef GHOST_DEBUG
        if (m_eventManager) {
@@ -328,10 +321,12 @@ GHOST_TSuccess GHOST_System::exit()
                delete m_eventManager;
                m_eventManager = 0;
        }
+#ifdef WITH_INPUT_NDOF
        if (m_ndofManager) {
                delete m_ndofManager;
                m_ndofManager = 0;
        }
+#endif
        return GHOST_kSuccess;
 }
 
index b5c64bf..c1e7091 100644 (file)
@@ -190,25 +190,6 @@ public:
         */
        virtual GHOST_TSuccess removeEventConsumer(GHOST_IEventConsumer* consumer);
 
-       /***************************************************************************************
-        ** N-degree of freedom devcice management functionality
-        ***************************************************************************************/
-
-       /** Inherited from GHOST_ISystem
-     *  Opens the N-degree of freedom device manager
-        * return 0 if device found, 1 otherwise
-     */
-    virtual int openNDOF(GHOST_IWindow* w,        
-        GHOST_NDOFLibraryInit_fp setNdofLibraryInit, 
-        GHOST_NDOFLibraryShutdown_fp setNdofLibraryShutdown,
-        GHOST_NDOFDeviceOpen_fp setNdofDeviceOpen);
-        
-// original patch only        
-//        GHOST_NDOFEventHandler_fp setNdofEventHandler);
-
-
-
-
        /***************************************************************************************
         ** Cursor management functionality
         ***************************************************************************************/
@@ -268,11 +249,13 @@ public:
         */
        virtual inline GHOST_WindowManager* getWindowManager() const;
 
+#ifdef WITH_INPUT_NDOF
        /**
         * Returns a pointer to our n-degree of freedeom manager.
         * @return A pointer to our n-degree of freedeom manager.
         */
        virtual inline GHOST_NDOFManager* getNDOFManager() const;
+#endif
 
        /**
         * Returns the state of all modifier keys.
@@ -337,8 +320,10 @@ protected:
        /** The event manager. */
        GHOST_EventManager* m_eventManager;
 
-    /** The N-degree of freedom device manager */
-    GHOST_NDOFManager* m_ndofManager;
+#ifdef WITH_INPUT_NDOF
+       /** The N-degree of freedom device manager */
+       GHOST_NDOFManager* m_ndofManager;
+#endif
        
        /** Prints all the events. */
 #ifdef GHOST_DEBUG
@@ -364,10 +349,12 @@ inline GHOST_WindowManager* GHOST_System::getWindowManager() const
        return m_windowManager;
 }
 
+#ifdef WITH_INPUT_NDOF
 inline GHOST_NDOFManager* GHOST_System::getNDOFManager() const
 {
        return m_ndofManager;
 }
+#endif
 
 #endif // _GHOST_SYSTEM_H_
 
index ce77735..d20aed6 100644 (file)
@@ -220,6 +220,11 @@ public:
      */
     GHOST_TSuccess handleApplicationBecomeActiveEvent();
 
+       /**
+        * External objects should call this when they send an event outside processEvents.
+        */
+       void notifyExternalEventProcessed();
+
        /**
         * @see GHOST_ISystem
         */
@@ -267,7 +272,7 @@ protected:
        /** Start time at initialization. */
        GHOST_TUns64 m_start_time;
        
-       /** Event has been processed directly by Cocoa and has sent a ghost event to be dispatched */
+       /** Event has been processed directly by Cocoa (or NDOF manager) and has sent a ghost event to be dispatched */
        bool m_outsideLoopEventProcessed;
        
        /** Raised window is not yet known by the window manager, so delay application become active event handling */
index bb3d6e3..17f0f2d 100644 (file)
@@ -52,7 +52,7 @@
 #include "GHOST_TimerTask.h"
 #include "GHOST_WindowManager.h"
 #include "GHOST_WindowCocoa.h"
-#include "GHOST_NDOFManager.h"
+#include "GHOST_NDOFManagerCocoa.h"
 #include "AssertMacros.h"
 
 #pragma mark KeyMap, mouse converters
@@ -596,6 +596,11 @@ GHOST_TSuccess GHOST_SystemCocoa::init()
        
     GHOST_TSuccess success = GHOST_System::init();
     if (success) {
+
+#ifdef WITH_INPUT_NDOF
+               m_ndofManager = new GHOST_NDOFManagerCocoa(*this);
+#endif
+
                //ProcessSerialNumber psn;
                
                //Carbon stuff to move window & menu to foreground
@@ -1007,6 +1012,11 @@ GHOST_TSuccess GHOST_SystemCocoa::handleApplicationBecomeActiveEvent()
        return GHOST_kSuccess;
 }
 
+void GHOST_SystemCocoa::notifyExternalEventProcessed()
+{
+       m_outsideLoopEventProcessed = true;
+}
+
 //Note: called from NSWindow delegate
 GHOST_TSuccess GHOST_SystemCocoa::handleWindowEvent(GHOST_TEventType eventType, GHOST_WindowCocoa* window)
 {
@@ -1560,6 +1570,8 @@ GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr)
                                        GHOST_TInt32 delta;
                                        
                                        double deltaF = [event deltaY];
+
+                                       if (deltaF == 0.0) deltaF = [event deltaX]; // make blender decide if it's horizontal scroll
                                        if (deltaF == 0.0) break; //discard trackpad delta=0 events
                                        
                                        delta = deltaF > 0.0 ? 1 : -1;
index becccc2..523d119 100644 (file)
 
 #include "GHOST_SystemPathsWin32.h"
 
-#define WIN32_LEAN_AND_MEAN
-#ifdef _WIN32_IE
-#undef _WIN32_IE
-#endif
+#ifndef _WIN32_IE
 #define _WIN32_IE 0x0501
-#include <windows.h>
+#endif
 #include <shlobj.h>
 
 #if defined(__MINGW32__) || defined(__CYGWIN__)
index 67cc214..3de7bbf 100644 (file)
@@ -38,6 +38,8 @@
 #error WIN32 only!
 #endif // WIN32
 
+#define _WIN32_WINNT 0x501 // require Windows XP or newer
+#define WIN32_LEAN_AND_MEAN
 #include <windows.h>
 
 #include "GHOST_SystemPaths.h"
index 4f0e7d8..c985c6d 100644 (file)
  * @date       May 7, 2001
  */
 
+#ifdef BF_GHOST_DEBUG
 #include <iostream>
-
-#ifdef FREE_WINDOWS
-#  define WINVER 0x0501 /* GetConsoleWindow() for MinGW */
 #endif
 
+#include <stdio.h> // [mce] temporary debug, remove soon!
+
 #include "GHOST_SystemWin32.h"
 #include "GHOST_EventDragnDrop.h"
 
-#define WIN32_LEAN_AND_MEAN
-#ifdef _WIN32_IE
-#undef _WIN32_IE
+#ifndef _WIN32_IE
+#define _WIN32_IE 0x0501 /* shipped before XP, so doesn't impose additional requirements */
 #endif
-#define _WIN32_IE 0x0501
-#include <windows.h>
 #include <shlobj.h>
+#include <tlhelp32.h>
 
 // win64 doesn't define GWL_USERDATA
 #ifdef WIN32
 #endif
 #endif
 
-/*
- * 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, (old convention! MS changed it) */
-#endif // WHEEL_DELTA
-
-/* 
- * Defines for mouse buttons 4 and 5 aka xbutton1 and xbutton2.
- * MSDN: Declared in Winuser.h, include Windows.h 
- * This does not seem to work with MinGW so we define our own here.
- */
-#ifndef XBUTTON1
-#define XBUTTON1 0x0001
-#endif // XBUTTON1
-#ifndef XBUTTON2
-#define XBUTTON2 0x0002
-#endif // XBUTTON2
-#ifndef WM_XBUTTONUP
-#define WM_XBUTTONUP 524
-#endif // WM_XBUTTONUP
-#ifndef WM_XBUTTONDOWN
-#define WM_XBUTTONDOWN 523
-#endif // WM_XBUTTONDOWN
-
 #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_EventNDOF.h"
 #include "GHOST_TimerTask.h"
 #include "GHOST_TimerManager.h"
 #include "GHOST_WindowManager.h"
 #include "GHOST_WindowWin32.h"
-#include "GHOST_NDOFManager.h"
+#include "GHOST_NDOFManagerWin32.h"
 
 // Key code values not found in winuser.h
 #ifndef VK_MINUS
 #define VK_MEDIA_PLAY_PAUSE    0xB3
 #endif // VK_MEDIA_PLAY_PAUSE
 
-/*
-       Initiates WM_INPUT messages from keyboard
-       That way GHOST can retrieve true keys
-*/
-GHOST_TInt32 GHOST_SystemWin32::initKeyboardRawInput(void)
+static void initRawInput()
 {
-       RAWINPUTDEVICE device = {0};
-       device.usUsagePage      = 0x01; /* usUsagePage & usUsage for keyboard*/
-       device.usUsage          = 0x06; /* http://msdn.microsoft.com/en-us/windows/hardware/gg487473.aspx */
+       RAWINPUTDEVICE devices[2];
+       memset(devices, 0, 2 * sizeof(RAWINPUTDEVICE));
+
+       // multi-axis mouse (SpaceNavigator, etc.)
+       devices[0].usUsagePage = 0x01;
+       devices[0].usUsage = 0x08;
 
-       return RegisterRawInputDevices(&device, 1, sizeof(device));
-};
+       // Initiates WM_INPUT messages from keyboard
+       // That way GHOST can retrieve true keys
+       devices[1].usUsagePage = 0x01;
+       devices[1].usUsage = 0x06; /* http://msdn.microsoft.com/en-us/windows/hardware/gg487473.aspx */
+
+       if (RegisterRawInputDevices(devices, 2, sizeof(RAWINPUTDEVICE)))
+               puts("registered for RawInput (spacenav & keyboard)");
+       else
+               printf("could not register for RawInput: %d\n", (int)GetLastError());
+}
 
 GHOST_SystemWin32::GHOST_SystemWin32()
 : m_hasPerformanceCounter(false), m_freq(0), m_start(0)
@@ -186,6 +160,10 @@ GHOST_SystemWin32::GHOST_SystemWin32()
        this->handleKeyboardChange();
        // Require COM for GHOST_DropTargetWin32 created in GHOST_WindowWin32.
        OleInitialize(0);
+
+#ifdef WITH_INPUT_NDOF
+       m_ndofManager = new GHOST_NDOFManagerWin32(*this);
+#endif
 }
 
 GHOST_SystemWin32::~GHOST_SystemWin32()
@@ -244,6 +222,7 @@ GHOST_IWindow* GHOST_SystemWin32::createWindow(
                        // Store the pointer to the window
 //                     if (state != GHOST_kWindowStateFullScreen) {
                                m_windowManager->addWindow(window);
+                               m_windowManager->setActiveWindow(window);
 //                     }
                }
                else {
@@ -384,22 +363,15 @@ GHOST_TSuccess GHOST_SystemWin32::init()
        GHOST_TSuccess success = GHOST_System::init();
        
        /* Disable scaling on high DPI displays on Vista */
+       HMODULE
        user32 = ::LoadLibraryA("user32.dll");
        typedef BOOL (WINAPI * LPFNSETPROCESSDPIAWARE)();
        LPFNSETPROCESSDPIAWARE SetProcessDPIAware =
                (LPFNSETPROCESSDPIAWARE)GetProcAddress(user32, "SetProcessDPIAware");
        if (SetProcessDPIAware)
                SetProcessDPIAware();
-       #ifdef NEED_RAW_PROC
-               pRegisterRawInputDevices = (LPFNDLLRRID)GetProcAddress(user32, "RegisterRawInputDevices");
-               pGetRawInputData = (LPFNDLLGRID)GetProcAddress(user32, "GetRawInputData");
-       #else
-               FreeLibrary(user32);
-       #endif
-
-       /*      Initiates WM_INPUT messages from keyboard */
-       initKeyboardRawInput();
-
+       FreeLibrary(user32);
+       initRawInput();
 
        // Determine whether this system has a high frequency performance counter. */
        m_hasPerformanceCounter = ::QueryPerformanceFrequency((LARGE_INTEGER*)&m_freq) == TRUE;
@@ -440,104 +412,84 @@ GHOST_TSuccess GHOST_SystemWin32::init()
 
 GHOST_TSuccess GHOST_SystemWin32::exit()
 {
-       #ifdef NEED_RAW_PROC
-       FreeLibrary(user32);
-       #endif
-
        return GHOST_System::exit();
 }
 
-GHOST_TKey GHOST_SystemWin32::hardKey(GHOST_IWindow *window, WPARAM wParam, LPARAM lParam, int * keyDown, char * vk)
+GHOST_TKey GHOST_SystemWin32::hardKey(GHOST_IWindow *window, RAWINPUT const& raw, int * keyDown, char * vk)
 {
-       unsigned int size = 0;
-       char * data;
        GHOST_TKey key = GHOST_kKeyUnknown;
 
 
        if(!keyDown)
                return GHOST_kKeyUnknown;
 
-       GetRawInputData((HRAWINPUT)lParam, RID_INPUT, 0, &size, sizeof(RAWINPUTHEADER));
 
+       GHOST_SystemWin32 *system = (GHOST_SystemWin32 *)getSystem();
 
-       if((data = (char*)malloc(size)) &&
-               GetRawInputData((HRAWINPUT)lParam, RID_INPUT, data, &size, sizeof(RAWINPUTHEADER)))
+       GHOST_ModifierKeys modifiers;
+       system->retrieveModifierKeys(modifiers);
+       
+       *keyDown = !(raw.data.keyboard.Flags & RI_KEY_BREAK);
+       key = this->convertKey(window, raw.data.keyboard.VKey, raw.data.keyboard.MakeCode, (raw.data.keyboard.Flags&(RI_KEY_E1|RI_KEY_E0)));
+       
+       // extra handling of modifier keys: don't send repeats out from GHOST
+       if(key >= GHOST_kKeyLeftShift && key <= GHOST_kKeyRightAlt)
        {
-               RAWINPUT ri;
-               memcpy(&ri,data,(size < sizeof(ri)) ? size : sizeof(ri));
-
-               if (ri.header.dwType == RIM_TYPEKEYBOARD)
-               {
-                       GHOST_SystemWin32 *system = (GHOST_SystemWin32 *)getSystem();
-                       
-                       GHOST_ModifierKeys modifiers;
-                       system->retrieveModifierKeys(modifiers);
-                       
-                       *keyDown = !(ri.data.keyboard.Flags & RI_KEY_BREAK);
-                       key = this->convertKey(window, ri.data.keyboard.VKey, ri.data.keyboard.MakeCode, (ri.data.keyboard.Flags&(RI_KEY_E1|RI_KEY_E0)));
-                       
-                       // extra handling of modifier keys: don't send repeats out from GHOST
-                       if(key >= GHOST_kKeyLeftShift && key <= GHOST_kKeyRightAlt)
-                       {
-                               bool changed = false;
-                               GHOST_TModifierKeyMask modifier;
-                               switch(key) {
-                                       case GHOST_kKeyLeftShift:
-                                               {
-                                                       changed = (modifiers.get(GHOST_kModifierKeyLeftShift) != (bool)*keyDown);
-                                                       modifier = GHOST_kModifierKeyLeftShift;
-                                               }
-                                               break;
-                                       case GHOST_kKeyRightShift:
-                                               {
-                                                       changed = (modifiers.get(GHOST_kModifierKeyRightShift) != (bool)*keyDown);
-                                                       modifier = GHOST_kModifierKeyRightShift;
-                                               }
-                                               break;
-                                       case GHOST_kKeyLeftControl:
-                                               {
-                                                       changed = (modifiers.get(GHOST_kModifierKeyLeftControl) != (bool)*keyDown);
-                                                       modifier = GHOST_kModifierKeyLeftControl;
-                                               }
-                                               break;
-                                       case GHOST_kKeyRightControl:
-                                               {
-                                                       changed = (modifiers.get(GHOST_kModifierKeyRightControl) != (bool)*keyDown);
-                                                       modifier = GHOST_kModifierKeyRightControl;
-                                               }
-                                               break;
-                                       case GHOST_kKeyLeftAlt:
-                                               {
-                                                       changed = (modifiers.get(GHOST_kModifierKeyLeftAlt) != (bool)*keyDown);
-                                                       modifier = GHOST_kModifierKeyLeftAlt;
-                                               }
-                                               break;
-                                       case GHOST_kKeyRightAlt:
-                                               {
-                                                       changed = (modifiers.get(GHOST_kModifierKeyRightAlt) != (bool)*keyDown);
-                                                       modifier = GHOST_kModifierKeyRightAlt;
-                                               }
-                                               break;
-                                       default: break;
+               bool changed = false;
+               GHOST_TModifierKeyMask modifier;
+               switch(key) {
+                       case GHOST_kKeyLeftShift:
+                               {
+                                       changed = (modifiers.get(GHOST_kModifierKeyLeftShift) != (bool)*keyDown);
+                                       modifier = GHOST_kModifierKeyLeftShift;
                                }
-                               
-                               if(changed)
+                               break;
+                       case GHOST_kKeyRightShift:
                                {
-                                       modifiers.set(modifier, (bool)*keyDown);
-                                       system->storeModifierKeys(modifiers);
+                                       changed = (modifiers.get(GHOST_kModifierKeyRightShift) != (bool)*keyDown);
+                                       modifier = GHOST_kModifierKeyRightShift;
                                }
-                               else
+                               break;
+                       case GHOST_kKeyLeftControl:
                                {
-                                       key = GHOST_kKeyUnknown;
+                                       changed = (modifiers.get(GHOST_kModifierKeyLeftControl) != (bool)*keyDown);
+                                       modifier = GHOST_kModifierKeyLeftControl;
                                }
-                       }
-                       
+                               break;
+                       case GHOST_kKeyRightControl:
+                               {
+                                       changed = (modifiers.get(GHOST_kModifierKeyRightControl) != (bool)*keyDown);
+                                       modifier = GHOST_kModifierKeyRightControl;
+                               }
+                               break;
+                       case GHOST_kKeyLeftAlt:
+                               {
+                                       changed = (modifiers.get(GHOST_kModifierKeyLeftAlt) != (bool)*keyDown);
+                                       modifier = GHOST_kModifierKeyLeftAlt;
+                               }
+                               break;
+                       case GHOST_kKeyRightAlt:
+                               {
+                                       changed = (modifiers.get(GHOST_kModifierKeyRightAlt) != (bool)*keyDown);
+                                       modifier = GHOST_kModifierKeyRightAlt;
+                               }
+                               break;
+                       default: break;
+               }
+               
+               if(changed)
+               {
+                       modifiers.set(modifier, (bool)*keyDown);
+                       system->storeModifierKeys(modifiers);
+               }
+               else
+               {
+                       key = GHOST_kKeyUnknown;
+               }
+       }
        
-                       if(vk) *vk = ri.data.keyboard.VKey;
-               };
 
-       };
-       free(data);
+       if(vk) *vk = raw.data.keyboard.VKey;
 
        return key;
 }
@@ -741,12 +693,12 @@ GHOST_EventWheel* GHOST_SystemWin32::processWheelEvent(GHOST_IWindow *window, WP
 }
 
 
-GHOST_EventKey* GHOST_SystemWin32::processKeyEvent(GHOST_IWindow *window, WPARAM wParam, LPARAM lParam)
+GHOST_EventKey* GHOST_SystemWin32::processKeyEvent(GHOST_IWindow *window, RAWINPUT const& raw)
 {
        int keyDown=0;
        char vk;
        GHOST_SystemWin32 * system = (GHOST_SystemWin32 *)getSystem();
-       GHOST_TKey key = system->hardKey(window, wParam, lParam, &keyDown, &vk);
+       GHOST_TKey key = system->hardKey(window, raw, &keyDown, &vk);
        GHOST_EventKey* event;
        if (key != GHOST_kKeyUnknown) {
                char ascii = '\0';
@@ -776,7 +728,15 @@ GHOST_EventKey* GHOST_SystemWin32::processKeyEvent(GHOST_IWindow *window, WPARAM
 
 GHOST_Event* GHOST_SystemWin32::processWindowEvent(GHOST_TEventType type, GHOST_IWindow* window)
 {
-       return new GHOST_Event(getSystem()->getMilliSeconds(), type, window);
+       GHOST_System* system = (GHOST_System*)getSystem();
+
+       if (type == GHOST_kEventWindowActivate)
+               {
+               puts("activating window");
+               system->getWindowManager()->setActiveWindow(window);
+               }
+
+       return new GHOST_Event(system->getMilliSeconds(), type, window);
 }
 
 GHOST_TSuccess GHOST_SystemWin32::pushDragDropEvent(GHOST_TEventType eventType, 
@@ -799,9 +759,102 @@ void GHOST_SystemWin32::processMinMaxInfo(MINMAXINFO * minmax)
        minmax->ptMinTrackSize.y=240;
 }
 
+#ifdef WITH_INPUT_NDOF
+bool GHOST_SystemWin32::processNDOF(RAWINPUT const& raw)
+{
+       bool eventSent = false;
+       GHOST_TUns64 now = getMilliSeconds();
+
+       static bool firstEvent = true;
+       if (firstEvent) { // determine exactly which device is plugged in
+               RID_DEVICE_INFO info;
+               unsigned infoSize = sizeof(RID_DEVICE_INFO);
+               info.cbSize = infoSize;
+
+               GetRawInputDeviceInfo(raw.header.hDevice, RIDI_DEVICEINFO, &info, &infoSize);
+               if (info.dwType == RIM_TYPEHID)
+                       m_ndofManager->setDevice(info.hid.dwVendorId, info.hid.dwProductId);
+               else
+                       puts("<!> not a HID device... mouse/kb perhaps?");
+
+               firstEvent = false;
+       }
+
+       // The NDOF manager sends button changes immediately, and *pretends* to
+       // send motion. Mark as 'sent' so motion will always get dispatched.
+       eventSent = true;
+
+#ifdef _MSC_VER
+       // using Microsoft compiler & header files
+       // they invented the RawInput API, so this version is (probably) correct
+       BYTE const* data = raw.data.hid.bRawData;
+       // struct RAWHID {
+       // DWORD dwSizeHid;
+       // DWORD dwCount;
+       // BYTE  bRawData[1];
+       // };
+#else
+       // MinGW's definition (below) doesn't agree, so we need a slight
+       // workaround until it's fixed
+       BYTE const* data = &raw.data.hid.bRawData;
+       // struct RAWHID {
+       // DWORD dwSizeHid;
+       // DWORD dwCount;
+       // BYTE bRawData; // <== isn't this s'posed to be a BYTE*?
+       // };
+#endif
+
+       BYTE packetType = data[0];
+       switch (packetType)
+       {
+               case 1: // translation
+               {
+                       short* axis = (short*)(data + 1);
+                       short t[3] = {axis[0], -axis[2], axis[1]};
+                       m_ndofManager->updateTranslation(t, now);
+
+                       if (raw.data.hid.dwSizeHid == 13)
+                       { // this report also includes rotation
+                               short r[3] = {-axis[3], axis[5], -axis[4]};
+                               m_ndofManager->updateRotation(r, now);
+
+                               // I've never gotten one of these, has anyone else?
+                               puts("ndof: combined T + R");
+                       }
+                       break;
+               }
+               case 2: // rotation
+               {
+                       short* axis = (short*)(data + 1);
+                       short r[3] = {-axis[0], axis[2], -axis[1]};
+                       m_ndofManager->updateRotation(r, now);
+                       break;
+               }
+               case 3: // buttons
+               {
+#if 0
+                       // I'm getting garbage bits -- examine whole report:
+                       printf("ndof: HID report for buttons [");
+                       for (int i = 0; i < raw.data.hid.dwSizeHid; ++i)
+                               printf(" %02X", data[i]);
+                       printf(" ]\n");
+#endif
+
+                       int button_bits;
+                       memcpy(&button_bits, data + 1, sizeof(button_bits));
+                       m_ndofManager->updateButtons(button_bits, now);
+                       break;
+               }
+       }
+       return eventSent;
+}
+#endif // WITH_INPUT_NDOF
+
 LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
 {
        GHOST_Event* event = 0;
+       bool eventHandled = false;
+
        LRESULT lResult = 0;
        GHOST_SystemWin32* system = ((GHOST_SystemWin32*)getSystem());
        GHOST_ASSERT(system, "GHOST_SystemWin32::s_wndProc(): system not initialized")
@@ -818,18 +871,38 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam,
                                // Keyboard events, processed
                                ////////////////////////////////////////////////////////////////////////
                                case WM_INPUT:
+                               {
                                        // check WM_INPUT from input sink when ghost window is not in the foreground
                                        if (wParam == RIM_INPUTSINK) {
                                                if (GetFocus() != hwnd) // WM_INPUT message not for this window
                                                        return 0;
-                                       } //else wPAram == RIM_INPUT
-                                       event = processKeyEvent(window, wParam, lParam);
-                                       if (!event) {
-                                               GHOST_PRINT("GHOST_SystemWin32::wndProc: key event ")
-                                               GHOST_PRINT(msg)
-                                               GHOST_PRINT(" key ignored\n")
+                                       } //else wParam == RIM_INPUT
+
+                                       RAWINPUT raw;
+                                       RAWINPUT* raw_ptr = &raw;
+                                       UINT rawSize = sizeof(RAWINPUT);
+
+                                       GetRawInputData((HRAWINPUT)lParam, RID_INPUT, raw_ptr, &rawSize, sizeof(RAWINPUTHEADER));
+
+                                       switch (raw.header.dwType)
+                                       {
+                                       case RIM_TYPEKEYBOARD:
+                                               event = processKeyEvent(window, raw);
+                                               if (!event) {
+                                                       GHOST_PRINT("GHOST_SystemWin32::wndProc: key event ")
+                                                       GHOST_PRINT(msg)
+                                                       GHOST_PRINT(" key ignored\n")
+                                               }
+                                               break;
+                                       case RIM_TYPEHID:
+#ifdef WITH_INPUT_NDOF
+                                               if (system->processNDOF(raw))
+                                                       eventHandled = true;
+#endif
+                                               break;
                                        }
-                                       break;
+                               break;
+                               }
                                ////////////////////////////////////////////////////////////////////////
                                // Keyboard events, ignored
                                ////////////////////////////////////////////////////////////////////////
@@ -839,9 +912,9 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam,
                                case WM_SYSKEYUP:
                                        /* These functions were replaced by WM_INPUT*/
                                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. 
+                                       /* 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
@@ -1127,28 +1200,6 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam,
                                         * In GHOST, we let DefWindowProc call the timer callback.
                                         */
                                        break;
-                               case WM_BLND_NDOF_AXIS:
-                                       {
-                                               GHOST_TEventNDOFData ndofdata;
-                                               system->m_ndofManager->GHOST_NDOFGetDatas(ndofdata);
-                                               system->m_eventManager->
-                                                       pushEvent(new GHOST_EventNDOF(
-                                                               system->getMilliSeconds(), 
-                                                               GHOST_kEventNDOFMotion, 
-                                                               window, ndofdata));
-                                       }
-                                       break;
-                               case WM_BLND_NDOF_BTN:
-                                       {
-                                               GHOST_TEventNDOFData ndofdata;
-                                               system->m_ndofManager->GHOST_NDOFGetDatas(ndofdata);
-                                               system->m_eventManager->
-                                                       pushEvent(new GHOST_EventNDOF(
-                                                               system->getMilliSeconds(), 
-                                                               GHOST_kEventNDOFButton, 
-                                                               window, ndofdata));
-                                       }
-                                       break;
                        }
                }
                else {
@@ -1170,10 +1221,12 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam,
 
        if (event) {
                system->pushEvent(event);
+               eventHandled = true;
        }
-       else {
+
+       if (!eventHandled)
                lResult = ::DefWindowProc(hwnd, msg, wParam, lParam);
-       }
+
        return lResult;
 }
 
@@ -1242,8 +1295,32 @@ int GHOST_SystemWin32::toggleConsole(int action)
        {
                case 3: //hide if no console
                        {
-                       CONSOLE_SCREEN_BUFFER_INFO csbi = {{0}};
-                       if(!GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi) || csbi.dwCursorPosition.X || csbi.dwCursorPosition.Y>1)
+                               DWORD sp = GetCurrentProcessId();
+                               HANDLE ptree = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
+                               PROCESSENTRY32 e = {0}; e.dwSize = sizeof(PROCESSENTRY32);
+                               
+                               if( Process32First(ptree, &e)) {
+                                       do { //Searches for Blender's PROCESSENTRY32
+                                                       if (e.th32ProcessID == sp) {
+                                                               sp = e.th32ParentProcessID;
+                                                               Process32First(ptree, &e);
+                                                                       do { //Got parent id, searches for its PROCESSENTRY32
+                                                                               if (e.th32ProcessID == sp) {
+                                                                                       if(strcmp("explorer.exe",e.szExeFile)==0)
+                                                                                       { //If explorer, hide cmd
+                                                                                               ShowWindow(GetConsoleWindow(),SW_HIDE);
+                                                                                               m_consoleStatus = 0;
+                                                                                       }
+                                                                                       break;
+                                                                               }
+
+                                                                       } while( Process32Next(ptree, &e));
+                                                               break;
+                                                       }
+                                       } while( Process32Next(ptree, &e));
+                               }
+
+                               CloseHandle(ptree);
                                break;
                        }
                case 0: //hide
index 729ad56..c5dff27 100644 (file)
 #error WIN32 only!
 #endif // WIN32
 
+#define _WIN32_WINNT 0x501 // require Windows XP or newer
+#define WIN32_LEAN_AND_MEAN
 #include <windows.h>
+#include <ole2.h> // for drag-n-drop
 
 #include "GHOST_System.h"
 
 #      define __int64 long long
 #endif
 
-#ifndef WM_INPUT
-#define WM_INPUT 0x00FF
-#endif 
-#ifndef RID_INPUT
-#define RID_INPUT 0x10000003
-#endif
-#ifndef RIM_INPUTSINK
-#define RIM_INPUTSINK 0x1
-#endif
-#ifndef RI_KEY_BREAK
-#define RI_KEY_BREAK 0x1
-#endif
-#ifndef RI_KEY_E0
-#define RI_KEY_E0 0x2
-#endif
-#ifndef RI_KEY_E1
-#define RI_KEY_E1 0x4
-#endif
-#ifndef RIM_TYPEMOUSE
-#define RIM_TYPEMOUSE          0x0
-#define RIM_TYPEKEYBOARD       0x1
-#define RIM_TYPEHID                    0x2
-
-typedef struct tagRAWINPUTDEVICE {
-       USHORT usUsagePage;
-       USHORT usUsage;
-       DWORD dwFlags;
-       HWND hwndTarget;
-} RAWINPUTDEVICE;
-
-
-
-typedef struct tagRAWINPUTHEADER {
-       DWORD dwType;
-       DWORD dwSize;
-       HANDLE hDevice;
-       WPARAM wParam;
-} RAWINPUTHEADER;
-
-typedef struct tagRAWMOUSE {
-       USHORT usFlags;
-       union {
-               ULONG ulButtons;
-               struct  {
-                       USHORT  usButtonFlags;
-                       USHORT  usButtonData;
-               };
-       };
-       ULONG   ulRawButtons;
-       LONG    lLastX;
-       LONG    lLastY;
-       ULONG   ulExtraInformation;
-} RAWMOUSE;
-
-typedef struct tagRAWKEYBOARD {
-       USHORT  MakeCode;
-       USHORT  Flags;
-       USHORT  Reserved;
-       USHORT  VKey;
-       UINT    Message;
-       ULONG   ExtraInformation;
-} RAWKEYBOARD;
-
-typedef struct tagRAWHID {
-       DWORD   dwSizeHid;
-       DWORD   dwCount;
-       BYTE    bRawData[1];
-} RAWHID;
-
-typedef struct tagRAWINPUT {
-       RAWINPUTHEADER header;
-       union {
-               RAWMOUSE        mouse;
-               RAWKEYBOARD keyboard;
-               RAWHID      hid;
-       } data;
-} RAWINPUT;
-
-DECLARE_HANDLE(HRAWINPUT);
-#endif
-
-#ifdef FREE_WINDOWS
-#define NEED_RAW_PROC
-typedef BOOL (WINAPI * LPFNDLLRRID)(RAWINPUTDEVICE*,UINT, UINT);
-
-typedef UINT (WINAPI * LPFNDLLGRID)(HRAWINPUT, UINT, LPVOID, PUINT, UINT);
-#define GetRawInputData(hRawInput, uiCommand, pData, pcbSize, cbSizeHeader) ((pGetRawInputData)?pGetRawInputData(hRawInput, uiCommand, pData, pcbSize, cbSizeHeader):(UINT)-1)
-#endif
-
 class GHOST_EventButton;
 class GHOST_EventCursor;
 class GHOST_EventKey;
@@ -314,14 +228,13 @@ protected:
 
        /**
         * Catches raw WIN32 key codes from WM_INPUT in the wndproc.
-        * @param window->      The window for this handling
-        * @param wParam        The wParam from the wndproc
-        * @param lParam        The lParam from the wndproc
+        * @param window        The window for this handling
+        * @param raw           RawInput structure with detailed info about the key event
         * @param keyDown       Pointer flag that specify if a key is down
         * @param vk            Pointer to virtual key
         * @return The GHOST key (GHOST_kKeyUnknown if no match).
         */
-       virtual GHOST_TKey hardKey(GHOST_IWindow *window, WPARAM wParam, LPARAM lParam, int * keyDown, char * vk);
+       virtual GHOST_TKey hardKey(GHOST_IWindow *window, RAWINPUT const& raw, int * keyDown, char * vk);
 
        /**
         * Creates modifier key event(s) and updates the key data stored locally (m_modifierKeys).
@@ -362,10 +275,9 @@ protected:
         * 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
+        * @param raw           RawInput structure with detailed info about the key event
         */
-       static GHOST_EventKey* processKeyEvent(GHOST_IWindow *window, WPARAM wParam, LPARAM lParam);
+       static GHOST_EventKey* processKeyEvent(GHOST_IWindow *window, RAWINPUT const& raw);
 
        /**
         * Process special keys (VK_OEM_*), to see if current key layout
@@ -383,12 +295,22 @@ protected:
         * @return The event created.
         */
        static GHOST_Event* processWindowEvent(GHOST_TEventType type, GHOST_IWindow* window);
-       /** 
+
+       /**
         * Handles minimum window size.
         * @param minmax        The MINMAXINFO structure.
         */
        static void processMinMaxInfo(MINMAXINFO * minmax);
-       
+
+       /**
+        * Handles Motion and Button events from a SpaceNavigator or related device.
+        * Instead of returning an event object, this function communicates directly
+        * with the GHOST_NDOFManager.
+        * @param raw           RawInput structure with detailed info about the NDOF event
+        * @return Whether an event was generated and sent.
+        */
+       bool processNDOF(RAWINPUT const& raw);
+
        /**
         * Returns the local state of the modifier keys (from the message queue).
         * @param keys The state of the keys.
@@ -412,11 +334,6 @@ protected:
         */
        static LRESULT WINAPI s_wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
 
-       /**
-        * Initiates WM_INPUT messages from keyboard 
-        */
-       GHOST_TInt32 initKeyboardRawInput(void);
-
        /**
  * Toggles console
  * @action     0 - Hides
@@ -445,15 +362,6 @@ protected:
 
        /** Console status */
        int m_consoleStatus;
-
-       /** handle for user32.dll*/
-       HMODULE user32;
-       #ifdef NEED_RAW_PROC
-       /* pointer to RegisterRawInputDevices function */
-       LPFNDLLRRID pRegisterRawInputDevices;
-       /* pointer to GetRawInputData function */
-       LPFNDLLGRID pGetRawInputData;
-       #endif
 };
 
 inline void GHOST_SystemWin32::retrieveModifierKeys(GHOST_ModifierKeys& keys) const
@@ -487,4 +395,3 @@ inline void GHOST_SystemWin32::handleKeyboardChange(void)
        }
 }
 #endif // _GHOST_SYSTEM_WIN32_H_
-
index dd296fa..105f71b 100644 (file)
@@ -42,8 +42,7 @@
 #include "GHOST_EventKey.h"
 #include "GHOST_EventButton.h"
 #include "GHOST_EventWheel.h"
-#include "GHOST_EventNDOF.h"
-#include "GHOST_NDOFManager.h"
+#include "GHOST_NDOFManagerX11.h"
 #include "GHOST_DisplayManagerX11.h"
 
 #include "GHOST_Debug.h"
 static GHOST_TKey
 convertXKey(KeySym key);
 
-typedef struct NDOFPlatformInfo {
-       Display *display;
-       Window window;
-       volatile GHOST_TEventNDOFData *currValues;
-       Atom cmdAtom;
-       Atom motionAtom;
-       Atom btnPressAtom;
-       Atom btnRelAtom;
-} NDOFPlatformInfo;
-
-static NDOFPlatformInfo sNdofInfo = {NULL, 0, NULL, 0, 0, 0, 0};
-
-
 //these are for copy and select copy
 static char *txt_cut_buffer= NULL;
 static char *txt_select_buffer= NULL;
@@ -181,6 +167,9 @@ init(
        GHOST_TSuccess success = GHOST_System::init();
 
        if (success) {
+#ifdef WITH_INPUT_NDOF
+               m_ndofManager = new GHOST_NDOFManagerX11(*this);
+#endif
                m_displayManager = new GHOST_DisplayManagerX11(this);
 
                if (m_displayManager) {
@@ -275,7 +264,7 @@ createWindow(
                if (window->getValid()) {
                        // Store the pointer to the window 
                        m_windowManager->addWindow(window);
-                       
+                       m_windowManager->setActiveWindow(window);
                        pushEvent( new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowSize, window) );
                }
                else {
@@ -386,8 +375,6 @@ lastEventTime(Time default_time) {
     return data.timestamp;
 }
 
-
-
        bool 
 GHOST_SystemX11::
 processEvents(
@@ -428,6 +415,13 @@ processEvents(
                if (generateWindowExposeEvents()) {
                        anyProcessed = true;
                }
+
+#ifdef WITH_INPUT_NDOF
+               if (dynamic_cast<GHOST_NDOFManagerX11*>(m_ndofManager)->processEvents()) {
+                       anyProcessed = true;
+               }
+#endif
+               
        } while (waitForEvent && !anyProcessed);
        
        return anyProcessed;
@@ -611,6 +605,9 @@ GHOST_SystemX11::processEvent(XEvent *xe)
                case FocusOut:
                {
                        XFocusChangeEvent &xfe = xe->xfocus;
+
+                       // TODO: make sure this is the correct place for activate/deactivate
+                       // printf("X: focus %s for window %d\n", xfe.type == FocusIn ? "in" : "out", (int) xfe.window);
                
                        // May have to look at the type of event and filter some
                        // out.
@@ -641,32 +638,8 @@ GHOST_SystemX11::processEvent(XEvent *xe)
                                );
                        } else 
 #endif
-                       if (sNdofInfo.currValues) {
-                               static GHOST_TEventNDOFData data = {0,0,0,0,0,0,0,0,0,0,0};
-                               if (xcme.message_type == sNdofInfo.motionAtom)
-                               {
-                                       data.changed = 1;
-                                       data.delta = xcme.data.s[8] - data.time;
-                                       data.time = xcme.data.s[8];
-                                       data.tx = xcme.data.s[2] >> 2;
-                                       data.ty = xcme.data.s[3] >> 2;
-                                       data.tz = xcme.data.s[4] >> 2;
-                                       data.rx = xcme.data.s[5];
-                                       data.ry = xcme.data.s[6];
-                                       data.rz =-xcme.data.s[7];
-                                       g_event = new GHOST_EventNDOF(getMilliSeconds(),
-                                                                     GHOST_kEventNDOFMotion,
-                                                                     window, data);
-                               } else if (xcme.message_type == sNdofInfo.btnPressAtom) {
-                                       data.changed = 2;
-                                       data.delta = xcme.data.s[8] - data.time;
-                                       data.time = xcme.data.s[8];
-                                       data.buttons = xcme.data.s[2];
-                                       g_event = new GHOST_EventNDOF(getMilliSeconds(),
-                                                                     GHOST_kEventNDOFButton,
-                                                                     window, data);
-                               }
-                       } else if (((Atom)xcme.data.l[0]) == m_wm_take_focus) {
+
+                       if (((Atom)xcme.data.l[0]) == m_wm_take_focus) {
                                XWindowAttributes attr;
                                Window fwin;
                                int revert_to;
@@ -723,6 +696,14 @@ GHOST_SystemX11::processEvent(XEvent *xe)
                                        xce.y_root
                                );
                        }
+
+                       // printf("X: %s window %d\n", xce.type == EnterNotify ? "entering" : "leaving", (int) xce.window);
+
+                       if (xce.type == EnterNotify)
+                               m_windowManager->setActiveWindow(window);
+                       else
+                               m_windowManager->setWindowInactive(window);
+
                        break;
                }
                case MapNotify:
@@ -834,6 +815,8 @@ GHOST_SystemX11::processEvent(XEvent *xe)
        }
 }
 
+#if 0 // obsolete SpaceNav code
+
        void *
 GHOST_SystemX11::
 prepareNdofInfo(volatile GHOST_TEventNDOFData *currentNdofValues)
@@ -846,6 +829,8 @@ prepareNdofInfo(volatile GHOST_TEventNDOFData *currentNdofValues)
        return (void*)&sNdofInfo;
 }
 
+#endif
+
        GHOST_TSuccess 
 GHOST_SystemX11::
 getModifierKeys(
index 746cd4e..845243f 100644 (file)
@@ -203,11 +203,6 @@ public:
                return m_display;
        }       
 
-               void *
-       prepareNdofInfo(
-               volatile GHOST_TEventNDOFData *current_values
-       );
-
        /* Helped function for get data from the clipboard. */
        void getClipboard_xcout(XEvent evt, Atom sel, Atom target,
                         unsigned char **txt, unsigned long *len,
index ef9ebdf..eddff8b 100644 (file)
@@ -3,20 +3,16 @@
  */
 #ifndef GHOST_TASKBARWIN32_H_
 #define GHOST_TASKBARWIN32_H_
+
 #ifndef WIN32
 #error WIN32 only!
 #endif // WIN32
 
+#define _WIN32_WINNT 0x501 // require Windows XP or newer
+#define WIN32_LEAN_AND_MEAN
 #include <windows.h>
 #include <shlobj.h>
 
-/* MinGW needs it */
-#ifdef FREE_WINDOWS
-#ifdef WINVER
-#undef WINVER
-#endif
-#define WINVER 0x0501
-#endif /* FREE_WINDOWS */
 
 // ITaskbarList, ITaskbarList2 and ITaskbarList3 might be missing, present here in that case.
 // Note, ITaskbarList3 is supported only since Windows 7, though. Check for that is done in
index 4055c3a..70914d9 100644 (file)
 #endif // WIN32
 
 #include "GHOST_Window.h"
+#include "GHOST_TaskbarWin32.h"
 
-/* MinGW needs it */
-#ifdef FREE_WINDOWS
-#ifdef WINVER
-#undef WINVER
-#endif
-#define WINVER 0x0501
-#endif
-
-
-
+#define _WIN32_WINNT 0x501 // require Windows XP or newer
+#define WIN32_LEAN_AND_MEAN
 #include <windows.h>
-#include "GHOST_TaskbarWin32.h"
 
 
 #include <wintab.h>
index 5aed058..22936f4 100644 (file)
@@ -16,7 +16,7 @@
 #
 # ##### END GPL LICENSE BLOCK #####
 
-# <pep8 compliant>
+# <pep8-80 compliant>
 
 __all__ = (
     "paths",
@@ -26,7 +26,7 @@ __all__ = (
     "disable",
     "reset_all",
     "module_bl_info",
-)
+    )
 
 import bpy as _bpy
 
@@ -129,7 +129,12 @@ def modules(module_cache):
                     error_duplicates = True
 
                 elif mod.__time__ != os.path.getmtime(mod_path):
-                    print("reloading addon:", mod_name, mod.__time__, os.path.getmtime(mod_path), mod_path)
+                    print("reloading addon:",
+                          mod_name,
+                          mod.__time__,
+                          os.path.getmtime(mod_path),
+                          mod_path,
+                          )
                     del module_cache[mod_name]
                     mod = None
 
@@ -144,7 +149,9 @@ def modules(module_cache):
     del modules_stale
 
     mod_list = list(module_cache.values())
-    mod_list.sort(key=lambda mod: (mod.bl_info['category'], mod.bl_info['name']))
+    mod_list.sort(key=lambda mod: (mod.bl_info['category'],
+                                   mod.bl_info['name'],
+                                   ))
     return mod_list
 
 
@@ -164,8 +171,9 @@ def check(module_name):
     loaded_state = mod and getattr(mod, "__addon_enabled__", Ellipsis)
 
     if loaded_state is Ellipsis:
-        print("Warning: addon-module %r found module but without"
-               " __addon_enabled__ field, possible name collision from file: %r" %
+        print("Warning: addon-module %r found module "
+               "but without __addon_enabled__ field, "
+               "possible name collision from file: %r" %
                (module_name, getattr(mod, "__file__", "<unknown>")))
 
         loaded_state = False
@@ -208,7 +216,8 @@ def enable(module_name, default_set=True):
                 return None
             mod.__addon_enabled__ = False
 
-    # Split registering up into 3 steps so we can undo if it fails par way through
+    # Split registering up into 3 steps so we can undo
+    # if it fails par way through.
     # 1) try import
     try:
         mod = __import__(module_name)
@@ -255,8 +264,9 @@ def disable(module_name, default_set=True):
     import sys
     mod = sys.modules.get(module_name)
 
-    # possible this addon is from a previous session and didnt load a module this time.
-    # so even if the module is not found, still disable the addon in the user prefs.
+    # possible this addon is from a previous session and didnt load a
+    # module this time. So even if the module is not found, still disable
+    # the addon in the user prefs.
     if mod:
         mod.__addon_enabled__ = False
 
@@ -311,7 +321,22 @@ def reset_all(reload_scripts=False):
                 disable(mod_name)
 
 
-def module_bl_info(mod, info_basis={"name": "", "author": "", "version": (), "blender": (), "api": 0, "location": "", "description": "", "wiki_url": "", "tracker_url": "", "support": 'COMMUNITY', "category": "", "warning": "", "show_expanded": False}):
+def module_bl_info(mod, info_basis={"name": "",
+                                    "author": "",
+                                    "version": (),
+                                    "blender": (),
+                                    "api": 0,
+                                    "location": "",
+                                    "description": "",
+                                    "wiki_url": "",
+                                    "tracker_url": "",
+                                    "support": 'COMMUNITY',
+                                    "category": "",
+                                    "warning": "",
+                                    "show_expanded": False,
+                                    }
+                   ):
+
     addon_info = getattr(mod, "bl_info", {})
 
     # avoid re-initializing
index 0add2b3..a43b42e 100644 (file)
@@ -16,7 +16,7 @@
 #
 # ##### END GPL LICENSE BLOCK #####
 
-# <pep8 compliant>
+# <pep8-80 compliant>
 
 """
 Give access to blender data and utility functions.
@@ -31,7 +31,7 @@ __all__ = (
     "props",
     "types",
     "utils",
-)
+    )
 
 
 # internal blender C module
@@ -49,7 +49,8 @@ def _main():
 
     # Possibly temp. addons path
     from os.path import join, dirname, normpath
-    _sys.path.append(normpath(join(dirname(__file__), "..", "..", "addons", "modules")))
+    _sys.path.append(normpath(join(dirname(__file__),
+                                   "..", "..", "addons", "modules")))
 
     # if "-d" in sys.argv: # Enable this to measure startup speed
     if 0:
index eb1a5ff..a01745f 100644 (file)
 #
 # ##### END GPL LICENSE BLOCK #####
 
-# <pep8 compliant>
+# <pep8-80 compliant>
 
 """
 This module has a similar scope to os.path, containing utility
 functions for dealing with paths in Blender.
 """
 
+__all__ = (
+    "abspath",
+    "basename",
+    "clean_name",
+    "display_name",
+    "display_name_from_filepath",
+    "ensure_ext",
+    "is_subdir",
+    "module_names",
+    "relpath",
+    "resolve_ncase",
+    )
+
 import bpy as _bpy
 import os as _os
 
 
 def abspath(path, start=None):
     """
-    Returns the absolute path relative to the current blend file using the "//" prefix.
+    Returns the absolute path relative to the current blend file
+    using the "//" prefix.
 
-    :arg start: Relative to this path, when not set the current filename is used.
+    :arg start: Relative to this path,
+       when not set the current filename is used.
     :type start: string
     """
     if path.startswith("//"):
-        return _os.path.join(_os.path.dirname(_bpy.data.filepath) if start is None else start, path[2:])
+        return _os.path.join(_os.path.dirname(_bpy.data.filepath)
+                             if start is None else start,
+                             path[2:],
+                             )
 
     return path
 
@@ -44,7 +62,8 @@ def relpath(path, start=None):
     """
     Returns the path relative to the current blend file using the "//" prefix.
 
-    :arg start: Relative to this path, when not set the current filename is used.
+    :arg start: Relative to this path,
+       when not set the current filename is used.
     :type start: string
     """
     if not path.startswith("//"):
@@ -68,27 +87,28 @@ def is_subdir(path, directory):
 
 def clean_name(name, replace="_"):
     """
-    Returns a name with characters replaced that may cause problems under various circumstances, such as writing to a file.
+    Returns a name with characters replaced that
+       may cause problems under various circumstances,
+    such as writing to a file.
     All characters besides A-Z/a-z, 0-9 are replaced with "_"
     or the replace argument if defined.
     """
 
-    unclean_chars = \
-                 "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\
-                  \x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\
-                  \x1e\x1f\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\
-                  \x2e\x2f\x3a\x3b\x3c\x3d\x3e\x3f\x40\x5b\x5c\x5d\x5e\x60\x7b\
-                  \x7c\x7d\x7e\x7f\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\
-                  \x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\
-                  \x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\
-                  \xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\
-                  \xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\
-                  \xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\
-                  \xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\
-                  \xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\
-                  \xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe"
-
-    for ch in unclean_chars:
+    bad_chars = ("\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e"
+                 "\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d"
+                 "\x1e\x1f\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c"
+                 "\x2e\x2f\x3a\x3b\x3c\x3d\x3e\x3f\x40\x5b\x5c\x5d\x5e\x60\x7b"
+                 "\x7c\x7d\x7e\x7f\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a"
+                 "\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99"
+                 "\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8"
+                 "\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7"
+                 "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6"
+                 "\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5"
+                 "\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4"
+                 "\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3"
+                 "\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe")
+
+    for ch in bad_chars:
         name = name.replace(ch, replace)
     return name
 
@@ -96,8 +116,9 @@ def clean_name(name, replace="_"):
 def display_name(name):
     """
     Creates a display string from name to be used menus and the user interface.
-    Capitalize the first letter in all lowercase names, mixed case names are kept as is.
-    Intended for use with filenames and module names.
+    Capitalize the first letter in all lowercase names,
+    mixed case names are kept as is. Intended for use with
+    filenames and module names.
     """
 
     name_base = _os.path.splitext(name)[0]
@@ -115,9 +136,11 @@ def display_name(name):
 
 def display_name_from_filepath(name):
     """
-    Returns the path stripped of directort and extension, ensured to be utf8 compatible.
+    Returns the path stripped of directort and extension,
+    ensured to be utf8 compatible.
     """
-    return _os.path.splitext(basename(name))[0].encode("utf8", "replace").decode("utf8")
+    name = _os.path.splitext(basename(name))[0]
+    return name.encode("utf8", "replace").decode("utf8")
 
 
 def resolve_ncase(path):
@@ -132,7 +155,8 @@ def resolve_ncase(path):
         if not path or os.path.exists(path):
             return path, True
 
-        filename = os.path.basename(path)  # filename may be a directory or a file
+        # filename may be a directory or a file
+        filename = os.path.basename(path)
         dirpath = os.path.dirname(path)
 
         suffix = path[:0]  # "" but ensure byte/str match
@@ -190,7 +214,9 @@ def ensure_ext(filepath, ext, case_sensitive=False):
     import os
     fn_base, fn_ext = os.path.splitext(filepath)
     if fn_base and fn_ext:
-        if (case_sensitive and ext == fn_ext) or (ext.lower() == fn_ext.lower()):
+        if ((case_sensitive and ext == fn_ext) or
+            (ext.lower() == fn_ext.lower())):
+
             return filepath
         else:
             return fn_base + ext
@@ -228,7 +254,9 @@ def module_names(path, recursive=False):
                 modules.append((filename, fullpath))
                 if recursive:
                     for mod_name, mod_path in module_names(directory, True):
-                        modules.append(("%s.%s" % (filename, mod_name), mod_path))
+                        modules.append(("%s.%s" % (filename, mod_name),
+                                       mod_path,
+                                       ))
 
     return modules
 
index 57d3e6d..a630437 100644 (file)
 #
 # ##### END GPL LICENSE BLOCK #####
 
-# <pep8 compliant>
+# <pep8-80 compliant>
 
 """
 This module contains utility functions specific to blender but
 not assosiated with blenders internal data.
 """
 
+__all__ = (
+    "blend_paths",
+    "keyconfig_set",
+    "load_scripts",
+    "modules_from_path",
+    "preset_find",
+    "preset_paths",
+    "refresh_script_paths",
+    "register_class",
+    "register_module",
+    "resource_path",
+    "script_paths",
+    "smpte_from_frame",
+    "smpte_from_seconds",
+    "unregister_class",
+    "unregister_module",
+    "user_resource",
+    "user_script_path",
+    )
+
 from _bpy import register_class, unregister_class, blend_paths, resource_path
 from _bpy import script_paths as _bpy_script_paths
 from _bpy import user_resource as _user_resource
@@ -42,7 +62,8 @@ def _test_import(module_name, loaded_modules):
     if module_name in loaded_modules:
         return None
     if "." in module_name:
-        print("Ignoring '%s', can't import files containing multiple periods." % module_name)
+        print("Ignoring '%s', can't import files containing "
+              "multiple periods." % module_name)
         return None
 
     if use_time:
@@ -74,7 +95,8 @@ def modules_from_path(path, loaded_modules):
 
     :arg path: this path is scanned for scripts and packages.
     :type path: string
-    :arg loaded_modules: already loaded module names, files matching these names will be ignored.
+    :arg loaded_modules: already loaded module names, files matching these
+       names will be ignored.
     :type loaded_modules: set
     :return: all loaded modules.
     :rtype: list
@@ -97,13 +119,17 @@ def load_scripts(reload_scripts=False, refresh_scripts=False):
     """
     Load scripts and run each modules register function.
 
-    :arg reload_scripts: Causes all scripts to have their unregister method called before loading.
+    :arg reload_scripts: Causes all scripts to have their unregister method
+       called before loading.
     :type reload_scripts: bool
-    :arg refresh_scripts: only load scripts which are not already loaded as modules.
+    :arg refresh_scripts: only load scripts which are not already loaded
+       as modules.
     :type refresh_scripts: bool
     """
     use_time = _bpy.app.debug
 
+    prefs = _bpy.context.user_preferences
+
     if use_time:
         import time
         t_main = time.time()
@@ -116,10 +142,11 @@ def load_scripts(reload_scripts=False, refresh_scripts=False):
     if reload_scripts:
         _bpy_types.TypeMap.clear()
 
-        # just unload, dont change user defaults, this means we can sync to reload.
-        # note that they will only actually reload of the modification time changes.
-        # this `wont` work for packages so... its not perfect.
-        for module_name in [ext.module for ext in _bpy.context.user_preferences.addons]:
+        # just unload, dont change user defaults, this means we can sync
+        # to reload. note that they will only actually reload of the
+        # modification time changes. This `wont` work for packages so...
+        # its not perfect.
+        for module_name in [ext.module for ext in prefs.addons]:
             _addon_utils.disable(module_name, default_set=False)
 
     def register_module_call(mod):
@@ -131,7 +158,9 @@ def load_scripts(reload_scripts=False, refresh_scripts=False):
                 import traceback
                 traceback.print_exc()
         else:
-            print("\nWarning! '%s' has no register function, this is now a requirement for registerable scripts." % mod.__file__)
+            print("\nWarning! '%s' has no register function, "
+                  "this is now a requirement for registerable scripts." %
+                  mod.__file__)
 
     def unregister_module_call(mod):
         unregister = getattr(mod, "unregister", None)
@@ -172,7 +201,8 @@ def load_scripts(reload_scripts=False, refresh_scripts=False):
     if reload_scripts:
 
         # module names -> modules
-        _global_loaded_modules[:] = [_sys.modules[mod_name] for mod_name in _global_loaded_modules]
+        _global_loaded_modules[:] = [_sys.modules[mod_name]
+                                     for mod_name in _global_loaded_modules]
 
         # loop over and unload all scripts
         _global_loaded_modules.reverse()
@@ -201,7 +231,8 @@ def load_scripts(reload_scripts=False, refresh_scripts=False):
     _addon_utils.reset_all(reload_scripts)
 
     # run the active integration preset
-    filepath = preset_find(_bpy.context.user_preferences.inputs.active_keyconfig, "keyconfig")
+    filepath = preset_find(prefs.inputs.active_keyconfig, "keyconfig")
+
     if filepath:
         keyconfig_set(filepath)
 
@@ -214,12 +245,16 @@ def load_scripts(reload_scripts=False, refresh_scripts=False):
 
 
 # base scripts
-_scripts = _os.path.join(_os.path.dirname(__file__), _os.path.pardir, _os.path.pardir)
+_scripts = _os.path.join(_os.path.dirname(__file__),
+                         _os.path.pardir,
+                         _os.path.pardir,
+                         )
 _scripts = (_os.path.normpath(_scripts), )
 
 
 def user_script_path():
-    path = _bpy.context.user_preferences.filepaths.script_directory
+    prefs = _bpy.context.user_preferences
+    path = prefs.filepaths.script_directory
 
     if path:
         path = _os.path.normpath(path)
@@ -236,22 +271,25 @@ def script_paths(subdir=None, user_pref=True, all=False):
     :type subdir: string
     :arg user_pref: Include the user preference script path.
     :type user_pref: bool
-    :arg all: Include local, user and system paths rather just the paths blender uses.
+    :arg all: Include local, user and system paths rather just the paths
+       blender uses.
     :type all: bool
     :return: script paths.
     :rtype: list
     """
     scripts = list(_scripts)
+    prefs = _bpy.context.user_preferences
 
     # add user scripts dir
     if user_pref:
-        user_script_path = _bpy.context.user_preferences.filepaths.script_directory
+        user_script_path = prefs.filepaths.script_directory
     else:
         user_script_path = None
 
     if all:
         # all possible paths
-        base_paths = tuple(_os.path.join(resource_path(res), "scripts") for res in ('LOCAL', 'USER', 'SYSTEM'))
+        base_paths = tuple(_os.path.join(resource_path(res), "scripts")
+                           for res in ('LOCAL', 'USER', 'SYSTEM'))
     else:
         # only paths blender uses
         base_paths = _bpy_script_paths()
@@ -426,7 +464,8 @@ def user_resource(type, path="", create=False):
     :type type: string
     :arg subdir: Optional subdirectory.
     :type subdir: string
-    :arg create: Treat the path as a directory and create it if its not existing.
+    :arg create: Treat the path as a directory and create
+       it if its not existing.
     :type create: boolean
     :return: a path.
     :rtype: string
@@ -477,7 +516,8 @@ def register_module(module, verbose=False):
         try:
             register_class(cls)
         except:
-            print("bpy.utils.register_module(): failed to registering class %r" % cls)
+            print("bpy.utils.register_module(): "
+                  "failed to registering class %r" % cls)
             import traceback
             traceback.print_exc()
     if verbose:
@@ -495,7 +535,8 @@ def unregister_module(module, verbose=False):
         try:
             unregister_class(cls)
         except:
-            print("bpy.utils.unregister_module(): failed to unregistering class %r" % cls)
+            print("bpy.utils.unregister_module(): "
+                  "failed to unregistering class %r" % cls)
             import traceback
             traceback.print_exc()
     if verbose:
index 06d41fa..d853d5f 100644 (file)
@@ -16,7 +16,7 @@
 #
 # ##### END GPL LICENSE BLOCK #####
 
-# <pep8 compliant>
+# <pep8-80 compliant>
 
 """
 Utility modules assosiated with the bpy module.
@@ -28,4 +28,4 @@ __all__ = (
     "image_utils",
     "mesh_utils",
     "view3d_utils",
-)
+    )
index e56c1c6..eab75c3 100644 (file)
 #
 # ##### END GPL LICENSE BLOCK #####
 
-# <pep8 compliant>
+# <pep8-80 compliant>
 
 __all__ = (
     "load_image",
-)
+    )
 
 
 # limited replacement for BPyImage.comprehensiveImageLoad
@@ -33,8 +33,8 @@ def load_image(imagepath,
                verbose=False,
                ):
     """
-    Return an image from the file path with options to search multiple paths and
-    return a placeholder if its not found.
+    Return an image from the file path with options to search multiple paths
+    and return a placeholder if its not found.
 
     :arg filepath: The image filename
        If a path precedes it, this will be searched as well.
@@ -51,9 +51,10 @@ def load_image(imagepath,
     :type recursive: bool
     :arg ncase_cmp: on non windows systems, find the correct case for the file.
     :type ncase_cmp: bool
-    :arg convert_callback: a function that takes an existing path and returns a new one.
-       Use this when loading image formats blender may not support, the CONVERT_CALLBACK
-       can take the path for a GIF (for example), convert it to a PNG and return the PNG's path.
+    :arg convert_callback: a function that takes an existing path and returns
+       a new one. Use this when loading image formats blender may not support,
+       the CONVERT_CALLBACK can take the path for a GIF (for example),
+       convert it to a PNG and return the PNG's path.
        For formats blender can read, simply return the path that is given.
     :type convert_callback: function
     :return: an image or None
@@ -92,7 +93,9 @@ def load_image(imagepath,
 
     for filepath_test in variants:
         if ncase_cmp:
-            ncase_variants = filepath_test, bpy.path.resolve_ncase(filepath_test)
+            ncase_variants = (filepath_test,
+                              bpy.path.resolve_ncase(filepath_test),
+                              )
         else:
             ncase_variants = (filepath_test, )
 
index 0a3f139..f476b37 100644 (file)
@@ -16,7 +16,7 @@
 #
 # ##### END GPL LICENSE BLOCK #####
 
-# <pep8 compliant>
+# <pep8-80 compliant>
 
 __all__ = (
     "ExportHelper",
@@ -31,15 +31,25 @@ __all__ = (
     "path_reference_copy",
     "path_reference_mode",
     "unique_name"
-)
+    )
 
 import bpy
 from bpy.props import StringProperty, BoolProperty, EnumProperty
 
 
 class ExportHelper:
-    filepath = StringProperty(name="File Path", description="Filepath used for exporting the file", maxlen=1024, default="", subtype='FILE_PATH')
-    check_existing = BoolProperty(name="Check Existing", description="Check and warn on overwriting existing files", default=True, options={'HIDDEN'})
+    filepath = StringProperty(
+            name="File Path",
+            description="Filepath used for exporting the file",
+            maxlen=1024,
+            subtype='FILE_PATH',
+            )
+    check_existing = BoolProperty(
+            name="Check Existing",
+            description="Check and warn on overwriting existing files",
+            default=True,
+            options={'HIDDEN'},
+            )
 
     # subclasses can override with decorator
     # True == use ext, False == no ext, None == do nothing.
@@ -65,7 +75,10 @@ class ExportHelper:
         if check_extension is None:
             return False
 
-        filepath = bpy.path.ensure_ext(self.filepath, self.filename_ext if check_extension else "")
+        filepath = bpy.path.ensure_ext(self.filepath,
+                                       self.filename_ext
+                                       if check_extension
+                                       else "")
 
         if filepath != self.filepath:
             self.filepath = filepath
@@ -75,7 +88,12 @@ class ExportHelper:
 
 
 class ImportHelper:
-    filepath = StringProperty(name="File Path", description="Filepath used for importing the file", maxlen=1024, default="", subtype='FILE_PATH')
+    filepath = StringProperty(
+            name="File Path",
+            description="Filepath used for importing the file",
+            maxlen=1024,
+            subtype='FILE_PATH',
+            )
 
     def invoke(self, context, event):
         context.window_manager.fileselect_add(self)
@@ -116,29 +134,75 @@ _axis_convert_matrix = (
 # where all 4 values are or'd into a single value...
 #    (i1<<0 | i1<<3 | i1<<6 | i1<<9)
 _axis_convert_lut = (
-    {0x8C8, 0x4D0, 0x2E0, 0xAE8, 0x701, 0x511, 0x119, 0xB29, 0x682, 0x88A, 0x09A, 0x2A2, 0x80B, 0x413, 0x223, 0xA2B, 0x644, 0x454, 0x05C, 0xA6C, 0x745, 0x94D, 0x15D, 0x365},
-    {0xAC8, 0x8D0, 0x4E0, 0x2E8, 0x741, 0x951, 0x159, 0x369, 0x702, 0xB0A, 0x11A, 0x522, 0xA0B, 0x813, 0x423, 0x22B, 0x684, 0x894, 0x09C, 0x2AC, 0x645, 0xA4D, 0x05D, 0x465},
-    {0x4C8, 0x2D0, 0xAE0, 0x8E8, 0x681, 0x291, 0x099, 0x8A9, 0x642, 0x44A, 0x05A, 0xA62, 0x40B, 0x213, 0xA23, 0x82B, 0x744, 0x354, 0x15C, 0x96C, 0x705, 0x50D, 0x11D, 0xB25},
-    {0x2C8, 0xAD0, 0x8E0, 0x4E8, 0x641, 0xA51, 0x059, 0x469, 0x742, 0x34A, 0x15A, 0x962, 0x20B, 0xA13, 0x823, 0x42B, 0x704, 0xB14, 0x11C, 0x52C, 0x685, 0x28D, 0x09D, 0x8A5},
-    {0x708, 0xB10, 0x120, 0x528, 0x8C1, 0xAD1, 0x2D9, 0x4E9, 0x942, 0x74A, 0x35A, 0x162, 0x64B, 0xA53, 0x063, 0x46B, 0x804, 0xA14, 0x21C, 0x42C, 0x885, 0x68D, 0x29D, 0x0A5},
-    {0xB08, 0x110, 0x520, 0x728, 0x941, 0x151, 0x359, 0x769, 0x802, 0xA0A, 0x21A, 0x422, 0xA4B, 0x053, 0x463, 0x66B, 0x884, 0x094, 0x29C, 0x6AC, 0x8C5, 0xACD, 0x2DD, 0x4E5},
-    {0x508, 0x710, 0xB20, 0x128, 0x881, 0x691, 0x299, 0x0A9, 0x8C2, 0x4CA, 0x2DA, 0xAE2, 0x44B, 0x653, 0xA63, 0x06B, 0x944, 0x754, 0x35C, 0x16C, 0x805, 0x40D, 0x21D, 0xA25},
-    {0x108, 0x510, 0x720, 0xB28, 0x801, 0x411, 0x219, 0xA29, 0x882, 0x08A, 0x29A, 0x6A2, 0x04B, 0x453, 0x663, 0xA6B, 0x8C4, 0x4D4, 0x2DC, 0xAEC, 0x945, 0x14D, 0x35D, 0x765},
-    {0x748, 0x350, 0x160, 0x968, 0xAC1, 0x2D1, 0x4D9, 0x8E9, 0xA42, 0x64A, 0x45A, 0x062, 0x68B, 0x293, 0x0A3, 0x8AB, 0xA04, 0x214, 0x41C, 0x82C, 0xB05, 0x70D, 0x51D, 0x125},
-    {0x948, 0x750, 0x360, 0x168, 0xB01, 0x711, 0x519, 0x129, 0xAC2, 0x8CA, 0x4DA, 0x2E2, 0x88B, 0x693, 0x2A3, 0x0AB, 0xA44, 0x654, 0x45C, 0x06C, 0xA05, 0x80D, 0x41D, 0x225},
-    {0x348, 0x150, 0x960, 0x768, 0xA41, 0x051, 0x459, 0x669, 0xA02, 0x20A, 0x41A, 0x822, 0x28B, 0x093, 0x8A3, 0x6AB, 0xB04, 0x114, 0x51C, 0x72C, 0xAC5, 0x2CD, 0x4DD, 0x8E5},
-    {0x148, 0x950, 0x760, 0x368, 0xA01, 0x811, 0x419, 0x229, 0xB02, 0x10A, 0x51A, 0x722, 0x08B, 0x893, 0x6A3, 0x2AB, 0xAC4, 0x8D4, 0x4DC, 0x2EC, 0xA45, 0x04D, 0x45D, 0x665},
-    {0x688, 0x890, 0x0A0, 0x2A8, 0x4C1, 0x8D1, 0xAD9, 0x2E9, 0x502, 0x70A, 0xB1A, 0x122, 0x74B, 0x953, 0x163, 0x36B, 0x404, 0x814, 0xA1C, 0x22C, 0x445, 0x64D, 0xA5D, 0x065},
-    {0x888, 0x090, 0x2A0, 0x6A8, 0x501, 0x111, 0xB19, 0x729, 0x402, 0x80A, 0xA1A, 0x222, 0x94B, 0x153, 0x363, 0x76B, 0x444, 0x054, 0xA5C, 0x66C, 0x4C5, 0x8CD, 0xADD, 0x2E5},
-    {0x288, 0x690, 0x8A0, 0x0A8, 0x441, 0x651, 0xA59, 0x069, 0x4C2, 0x2CA, 0xADA, 0x8E2, 0x34B, 0x753, 0x963, 0x16B, 0x504, 0x714, 0xB1C, 0x12C, 0x405, 0x20D, 0xA1D, 0x825},
-    {0x088, 0x290, 0x6A0, 0x8A8, 0x401, 0x211, 0xA19, 0x829, 0x442, 0x04A, 0xA5A, 0x662, 0x14B, 0x353, 0x763, 0x96B, 0x4C4, 0x2D4, 0xADC, 0x8EC, 0x505, 0x10D, 0xB1D, 0x725},
-    {0x648, 0x450, 0x060, 0xA68, 0x2C1, 0x4D1, 0x8D9, 0xAE9, 0x282, 0x68A, 0x89A, 0x0A2, 0x70B, 0x513, 0x123, 0xB2B, 0x204, 0x414, 0x81C, 0xA2C, 0x345, 0x74D, 0x95D, 0x165},
-    {0xA48, 0x650, 0x460, 0x068, 0x341, 0x751, 0x959, 0x169, 0x2C2, 0xACA, 0x8DA, 0x4E2, 0xB0B, 0x713, 0x523, 0x12B, 0x284, 0x694, 0x89C, 0x0AC, 0x205, 0xA0D, 0x81D, 0x425},
-    {0x448, 0x050, 0xA60, 0x668, 0x281, 0x091, 0x899, 0x6A9, 0x202, 0x40A, 0x81A, 0xA22, 0x50B, 0x113, 0xB23, 0x72B, 0x344, 0x154, 0x95C, 0x76C, 0x2C5, 0x4CD, 0x8DD, 0xAE5},
-    {0x048, 0xA50, 0x660, 0x468, 0x201, 0xA11, 0x819, 0x429, 0x342, 0x14A, 0x95A, 0x762, 0x10B, 0xB13, 0x723, 0x52B, 0x2C4, 0xAD4, 0x8DC, 0x4EC, 0x285, 0x08D, 0x89D, 0x6A5},
-    {0x808, 0xA10, 0x220, 0x428, 0x101, 0xB11, 0x719, 0x529, 0x142, 0x94A, 0x75A, 0x362, 0x8CB, 0xAD3, 0x2E3, 0x4EB, 0x044, 0xA54, 0x65C, 0x46C, 0x085, 0x88D, 0x69D, 0x2A5},
-    {0xA08, 0x210, 0x420, 0x828, 0x141, 0x351, 0x759, 0x969, 0x042, 0xA4A, 0x65A, 0x462, 0xACB, 0x2D3, 0x4E3, 0x8EB, 0x084, 0x294, 0x69C, 0x8AC, 0x105, 0xB0D, 0x71D, 0x525},
-    {0x408, 0x810, 0xA20, 0x228, 0x081, 0x891, 0x699, 0x2A9, 0x102, 0x50A, 0x71A, 0xB22, 0x4CB, 0x8D3, 0xAE3, 0x2EB, 0x144, 0x954, 0x75C, 0x36C, 0x045, 0x44D, 0x65D, 0xA65},
+    {0x8C8, 0x4D0, 0x2E0, 0xAE8, 0x701, 0x511, 0x119, 0xB29, 0x682, 0x88A,
+     0x09A, 0x2A2, 0x80B, 0x413, 0x223, 0xA2B, 0x644, 0x454, 0x05C, 0xA6C,
+     0x745, 0x94D, 0x15D, 0x365},
+    {0xAC8, 0x8D0, 0x4E0, 0x2E8, 0x741, 0x951, 0x159, 0x369, 0x702, 0xB0A,
+     0x11A, 0x522, 0xA0B, 0x813, 0x423, 0x22B, 0x684, 0x894, 0x09C, 0x2AC,
+     0x645, 0xA4D, 0x05D, 0x465},
+    {0x4C8, 0x2D0, 0xAE0, 0x8E8, 0x681, 0x291, 0x099, 0x8A9, 0x642, 0x44A,
+     0x05A, 0xA62, 0x40B, 0x213, 0xA23, 0x82B, 0x744, 0x354, 0x15C, 0x96C,
+     0x705, 0x50D, 0x11D, 0xB25},
+    {0x2C8, 0xAD0, 0x8E0, 0x4E8, 0x641, 0xA51, 0x059, 0x469, 0x742, 0x34A,
+     0x15A, 0x962, 0x20B, 0xA13, 0x823, 0x42B, 0x704, 0xB14, 0x11C, 0x52C,
+     0x685, 0x28D, 0x09D, 0x8A5},
+    {0x708, 0xB10, 0x120, 0x528, 0x8C1, 0xAD1, 0x2D9, 0x4E9, 0x942, 0x74A,
+     0x35A, 0x162, 0x64B, 0xA53, 0x063, 0x46B, 0x804, 0xA14, 0x21C, 0x42C,
+     0x885, 0x68D, 0x29D, 0x0A5},
+    {0xB08, 0x110, 0x520, 0x728, 0x941, 0x151, 0x359, 0x769, 0x802, 0xA0A,
+     0x21A, 0x422, 0xA4B, 0x053, 0x463, 0x66B, 0x884, 0x094, 0x29C, 0x6AC,
+     0x8C5, 0xACD, 0x2DD, 0x4E5},
+    {0x508, 0x710, 0xB20, 0x128, 0x881, 0x691, 0x299, 0x0A9, 0x8C2, 0x4CA,
+     0x2DA, 0xAE2, 0x44B, 0x653, 0xA63, 0x06B, 0x944, 0x754, 0x35C, 0x16C,
+     0x805, 0x40D, 0x21D, 0xA25},
+    {0x108, 0x510, 0x720, 0xB28, 0x801, 0x411, 0x219, 0xA29, 0x882, 0x08A,
+     0x29A, 0x6A2, 0x04B, 0x453, 0x663, 0xA6B, 0x8C4, 0x4D4, 0x2DC, 0xAEC,
+     0x945, 0x14D, 0x35D, 0x765},
+    {0x748, 0x350, 0x160, 0x968, 0xAC1, 0x2D1, 0x4D9, 0x8E9, 0xA42, 0x64A,
+     0x45A, 0x062, 0x68B, 0x293, 0x0A3, 0x8AB, 0xA04, 0x214, 0x41C, 0x82C,
+     0xB05, 0x70D, 0x51D, 0x125},
+    {0x948, 0x750, 0x360, 0x168, 0xB01, 0x711, 0x519, 0x129, 0xAC2, 0x8CA,
+     0x4DA, 0x2E2, 0x88B, 0x693, 0x2A3, 0x0AB, 0xA44, 0x654, 0x45C, 0x06C,
+     0xA05, 0x80D, 0x41D, 0x225},
+    {0x348, 0x150, 0x960, 0x768, 0xA41, 0x051, 0x459, 0x669, 0xA02, 0x20A,
+     0x41A, 0x822, 0x28B, 0x093, 0x8A3, 0x6AB, 0xB04, 0x114, 0x51C, 0x72C,
+     0xAC5, 0x2CD, 0x4DD, 0x8E5},
+    {0x148, 0x950, 0x760, 0x368, 0xA01, 0x811, 0x419, 0x229, 0xB02, 0x10A,
+     0x51A, 0x722, 0x08B, 0x893, 0x6A3, 0x2AB, 0xAC4, 0x8D4, 0x4DC, 0x2EC,
+     0xA45, 0x04D, 0x45D, 0x665},
+    {0x688, 0x890, 0x0A0, 0x2A8, 0x4C1, 0x8D1, 0xAD9, 0x2E9, 0x502, 0x70A,
+     0xB1A, 0x122, 0x74B, 0x953, 0x163, 0x36B, 0x404, 0x814, 0xA1C, 0x22C,
+     0x445, 0x64D, 0xA5D, 0x065},
+    {0x888, 0x090, 0x2A0, 0x6A8, 0x501, 0x111, 0xB19, 0x729, 0x402, 0x80A,
+     0xA1A, 0x222, 0x94B, 0x153, 0x363, 0x76B, 0x444, 0x054, 0xA5C, 0x66C,
+     0x4C5, 0x8CD, 0xADD, 0x2E5},
+    {0x288, 0x690, 0x8A0, 0x0A8, 0x441, 0x651, 0xA59, 0x069, 0x4C2, 0x2CA,
+     0xADA, 0x8E2, 0x34B, 0x753, 0x963, 0x16B, 0x504, 0x714, 0xB1C, 0x12C,
+     0x405, 0x20D, 0xA1D, 0x825},
+    {0x088, 0x290, 0x6A0, 0x8A8, 0x401, 0x211, 0xA19, 0x829, 0x442, 0x04A,
+     0xA5A, 0x662, 0x14B, 0x353, 0x763, 0x96B, 0x4C4, 0x2D4, 0xADC, 0x8EC,
+     0x505, 0x10D, 0xB1D, 0x725},
+    {0x648, 0x450, 0x060, 0xA68, 0x2C1, 0x4D1, 0x8D9, 0xAE9, 0x282, 0x68A,
+     0x89A, 0x0A2, 0x70B, 0x513, 0x123, 0xB2B, 0x204, 0x414, 0x81C, 0xA2C,
+     0x345, 0x74D, 0x95D, 0x165},
+    {0xA48, 0x650, 0x460, 0x068, 0x341, 0x751, 0x959, 0x169, 0x2C2, 0xACA,
+     0x8DA, 0x4E2, 0xB0B, 0x713, 0x523, 0x12B, 0x284, 0x694, 0x89C, 0x0AC,
+     0x205, 0xA0D, 0x81D, 0x425},
+    {0x448, 0x050, 0xA60, 0x668, 0x281, 0x091, 0x899, 0x6A9, 0x202, 0x40A,
+     0x81A, 0xA22, 0x50B, 0x113, 0xB23, 0x72B, 0x344, 0x154, 0x95C, 0x76C,
+     0x2C5, 0x4CD, 0x8DD, 0xAE5},
+    {0x048, 0xA50, 0x660, 0x468, 0x201, 0xA11, 0x819, 0x429, 0x342, 0x14A,
+     0x95A, 0x762, 0x10B, 0xB13, 0x723, 0x52B, 0x2C4, 0xAD4, 0x8DC, 0x4EC,
+     0x285, 0x08D, 0x89D, 0x6A5},
+    {0x808, 0xA10, 0x220, 0x428, 0x101, 0xB11, 0x719, 0x529, 0x142, 0x94A,
+     0x75A, 0x362, 0x8CB, 0xAD3, 0x2E3, 0x4EB, 0x044, 0xA54, 0x65C, 0x46C,
+     0x085, 0x88D, 0x69D, 0x2A5},
+    {0xA08, 0x210, 0x420, 0x828, 0x141, 0x351, 0x759, 0x969, 0x042, 0xA4A,
+     0x65A, 0x462, 0xACB, 0x2D3, 0x4E3, 0x8EB, 0x084, 0x294, 0x69C, 0x8AC,
+     0x105, 0xB0D, 0x71D, 0x525},
+    {0x408, 0x810, 0xA20, 0x228, 0x081, 0x891, 0x699, 0x2A9, 0x102, 0x50A,
+     0x71A, 0xB22, 0x4CB, 0x8D3, 0xAE3, 0x2EB, 0x144, 0x954, 0x75C, 0x36C,
+     0x045, 0x44D, 0x65D, 0xA65},
     )
 
 _axis_convert_num = {'X': 0, 'Y': 1, 'Z': 2, '-X': 3, '-Y': 4, '-Z': 5}
@@ -206,7 +270,8 @@ def axis_conversion_ensure(operator, forward_attr, up_attr):
         return False
 
 
-# return a tuple (free, object list), free is True if memory should be freed later with free_derived_objects()
+# return a tuple (free, object list), free is True if memory should be freed
+# later with free_derived_objects()
 def create_derived_objects(scene, ob):
     if ob.parent and ob.parent.dupli_type in {'VERTS', 'FACES'}:
         return False, None
@@ -254,31 +319,45 @@ path_reference_mode = EnumProperty(
         description="Method used to reference paths",
         items=(('AUTO', "Auto", "Use Relative paths with subdirectories only"),
                ('ABSOLUTE', "Absolute", "Always write absolute paths"),
-               ('RELATIVE', "Relative", "Always write relative patsh (where possible)"),
-               ('MATCH', "Match", "Match Absolute/Relative setting with input path"),
+               ('RELATIVE', "Relative", "Always write relative patsh "
+                                        "(where possible)"),
+               ('MATCH', "Match", "Match Absolute/Relative "
+                                  "setting with input path"),
                ('STRIP', "Strip Path", "Filename only"),
-               ('COPY', "Copy", "copy the file to the destination path (or subdirectory)"),
+               ('COPY', "Copy", "copy the file to the destination path "
+                                "(or subdirectory)"),
                ),
         default='AUTO'
         )
 
 
-def path_reference(filepath, base_src, base_dst, mode='AUTO', copy_subdir="", copy_set=None):
+def path_reference(filepath,
+                   base_src,
+                   base_dst,
+                   mode='AUTO',
+                   copy_subdir="",
+                   copy_set=None,
+                   ):
     """
     Return a filepath relative to a destination directory, for use with
     exporters.
 
-    :arg filepath: the file path to return, supporting blenders relative '//' prefix.
+    :arg filepath: the file path to return,
+       supporting blenders relative '//' prefix.
     :type filepath: string
-    :arg base_src: the directory the *filepath* is relative too (normally the blend file).
+    :arg base_src: the directory the *filepath* is relative too
+       (normally the blend file).
     :type base_src: string
-    :arg base_dst: the directory the *filepath* will be referenced from (normally the export path).
+    :arg base_dst: the directory the *filepath* will be referenced from
+       (normally the export path).
     :type base_dst: string
-    :arg mode: the method used get the path in ['AUTO', 'ABSOLUTE', 'RELATIVE', 'MATCH', 'STRIP', 'COPY']
+    :arg mode: the method used get the path in
+       ['AUTO', 'ABSOLUTE', 'RELATIVE', 'MATCH', 'STRIP', 'COPY']
     :type mode: string
     :arg copy_subdir: the subdirectory of *base_dst* to use when mode='COPY'.
     :type copy_subdir: string
-    :arg copy_set: collect from/to pairs when mode='COPY', pass to *path_reference_copy* when exportign is done.
+    :arg copy_set: collect from/to pairs when mode='COPY',
+       pass to *path_reference_copy* when exportign is done.
     :type copy_set: set
     :return: the new filepath.
     :rtype: string
@@ -292,7 +371,9 @@ def path_reference(filepath, base_src, base_dst, mode='AUTO', copy_subdir="", co
     elif mode == 'MATCH':
         mode = 'RELATIVE' if is_relative else 'ABSOLUTE'
     elif mode == 'AUTO':
-        mode = 'RELATIVE' if bpy.path.is_subdir(filepath, base_dst) else 'ABSOLUTE'
+        mode = ('RELATIVE'
+                if bpy.path.is_subdir(filepath, base_dst)
+                else 'ABSOLUTE')
     elif mode == 'COPY':
         if copy_subdir:
             subdir_abs = os.path.join(os.path.normpath(base_dst), copy_subdir)
@@ -367,7 +448,8 @@ def unique_name(key, name, name_dict, name_max=-1, clean_func=None):
     if name_new is None:
         count = 1
         name_dict_values = name_dict.values()
-        name_new = name_new_orig = name if clean_func is None else clean_func(name)
+        name_new = name_new_orig = (name if clean_func is None
+                                    else clean_func(name))
 
         if name_max == -1:
             while name_new in name_dict_values:
@@ -377,7 +459,10 @@ def unique_name(key, name, name_dict, name_max=-1, clean_func=None):
             name_new = name_new[:name_max]
             while name_new in name_dict_values:
                 count_str = "%03d" % count
-                name_new = "%.*s.%s" % (name_max - (len(count_str) + 1), name_new_orig, count_str)
+                name_new = "%.*s.%s" % (name_max - (len(count_str) + 1),
+                                        name_new_orig,
+                                        count_str,
+                                        )
                 count += 1
 
         name_dict[key] = name_new
index ecd620f..f940067 100644 (file)
@@ -26,7 +26,7 @@ __all__ = (
     "edge_loops_from_edges",
     "ngon_tesselate",
     "face_random_points",
-)
+    )
 
 
 def mesh_linked_faces(mesh):
index 51a8d4b..790f5ba 100644 (file)
 #
 # ##### END GPL LICENSE BLOCK #####
 
-# <pep8 compliant>
+# <pep8-80 compliant>
 
 __all__ = (
     "add_object_align_init",
     "object_data_add",
-)
+    )
 
 
 import bpy
@@ -39,42 +39,49 @@ def add_object_align_init(context, operator):
     :return: the matrix from the context and settings.
     :rtype: :class:`Matrix`
     """
+
+    from mathutils import Matrix, Vector, Euler
+    properties = operator.properties if operator is not None else None
+
     space_data = context.space_data
     if space_data.type != 'VIEW_3D':
         space_data = None
 
     # location
-    if operator and operator.properties.is_property_set("location"):
-        location = mathutils.Matrix.Translation(mathutils.Vector(operator.properties.location))
+    if operator and properties.is_property_set("location"):
+        location = Matrix.Translation(Vector(properties.location))
     else:
         if space_data:  # local view cursor is detected below
-            location = mathutils.Matrix.Translation(space_data.cursor_location)
+            location = Matrix.Translation(space_data.cursor_location)
         else:
-            location = mathutils.Matrix.Translation(context.scene.cursor_location)
+            location = Matrix.Translation(context.scene.cursor_location)
 
         if operator:
-            operator.properties.location = location.to_translation()
+            properties.location = location.to_translation()
 
     # rotation
     view_align = (context.user_preferences.edit.object_align == 'VIEW')
     view_align_force = False
     if operator:
-        if operator.properties.is_property_set("view_align"):
+        if properties.is_property_set("view_align"):
             view_align = view_align_force = operator.view_align
         else:
-            operator.properties.view_align = view_align
+            properties.view_align = view_align
 
-    if operator and operator.properties.is_property_set("rotation") and not view_align_force:
-        rotation = mathutils.Euler(operator.properties.rotation).to_matrix().to_4x4()
+    if operator and (properties.is_property_set("rotation") and
+                     not view_align_force):
+
+        rotation = Euler(properties.rotation).to_matrix().to_4x4()
     else:
         if view_align and space_data:
-            rotation = space_data.region_3d.view_matrix.to_3x3().inverted().to_4x4()
+            rotation = space_data.region_3d.view_matrix.to_3x3().inverted()
+            rotation.resize_4x4()
         else:
             rotation = mathutils.Matrix()
 
         # set the operator properties
         if operator:
-            operator.properties.rotation = rotation.to_euler()
+            properties.rotation = rotation.to_euler()
 
     return location * rotation
 
@@ -114,14 +121,18 @@ def object_data_add(context, obdata, operator=None):
     # XXX
     # caused because entering editmodedoes not add a empty undo slot!
     if context.user_preferences.edit.use_enter_edit_mode:
-        if not (obj_act and obj_act.mode == 'EDIT' and obj_act.type == obj_new.type):
+        if not (obj_act and
+                obj_act.mode == 'EDIT' and
+                obj_act.type == obj_new.type):
+
             _obdata = bpy.data.meshes.new(obdata.name)
             obj_act = bpy.data.objects.new(_obdata.name, _obdata)
             obj_act.matrix_world = obj_new.matrix_world
             scene.objects.link(obj_act)
             scene.objects.active = obj_act
             bpy.ops.object.mode_set(mode='EDIT')
-            bpy.ops.ed.undo_push(message="Enter Editmode")  # need empty undo step
+            # need empty undo step
+            bpy.ops.ed.undo_push(message="Enter Editmode")
     # XXX
 
     if obj_act and obj_act.mode == 'EDIT' and obj_act.type == obj_new.type:
index 5796abc..2632563 100644 (file)
 #
 # ##### END GPL LICENSE BLOCK #####
 
-# <pep8 compliant>
+# <pep8-80 compliant>
 
 __all__ = (
     "region_2d_to_vector_3d",
     "region_2d_to_location_3d",
     "location_3d_to_region_2d",
-)
+    )
 
 
 def region_2d_to_vector_3d(region, rv3d, coord):
@@ -90,15 +90,23 @@ def region_2d_to_location_3d(region, rv3d, coord, depth_location):
         origin_start = rv3d.view_matrix.inverted()[3].to_3d()
         origin_end = origin_start + coord_vec
         view_vec = rv3d.view_matrix.inverted()[2]
-        return intersect_line_plane(origin_start, origin_end, depth_location, view_vec, 1)
+        return intersect_line_plane(origin_start,
+                                    origin_end,
+                                    depth_location,
+                                    view_vec, 1,
+                                    )
     else:
         dx = (2.0 * coord[0] / region.width) - 1.0
         dy = (2.0 * coord[1] / region.height) - 1.0
         persinv = persmat.inverted()
         viewinv = rv3d.view_matrix.inverted()
-        origin_start = (persinv[0].xyz * dx) + (persinv[1].xyz * dy) + viewinv[3].xyz
+        origin_start = ((persinv[0].xyz * dx) +
+                        (persinv[1].xyz * dy) + viewinv[3].xyz)
         origin_end = origin_start + coord_vec
-        return intersect_point_line(depth_location, origin_start, origin_end)[0]
+        return intersect_point_line(depth_location,
+                                    origin_start,
+                                    origin_end,
+                                    )[0]
 
 
 def location_3d_to_region_2d(region, rv3d, coord):
index dc61ce2..03400ed 100644 (file)
 #
 # ##### END GPL LICENSE BLOCK #####
 
-# <pep8 compliant>
+# <pep8-80 compliant>
 
 # This file defines a set of methods that are useful for various
 # Relative Keying Set (RKS) related operations, such as: callbacks
 # for polling, iterator callbacks, and also generate callbacks.
 # All of these can be used in conjunction with the others.
 
-__all__ = [
+__all__ = (
     "path_add_property",
     "RKS_POLL_selected_objects",
     "RKS_POLL_selected_bones",
@@ -33,7 +33,7 @@ __all__ = [
     "RKS_GEN_location",
     "RKS_GEN_rotation",
     "RKS_GEN_scaling",
-]
+    )
 
 import bpy
 
@@ -75,7 +75,8 @@ def RKS_POLL_selected_bones(ksi, context):
 
 # selected bones or objects
 def RKS_POLL_selected_items(ksi, context):
-    return RKS_POLL_selected_bones(ksi, context) or RKS_POLL_selected_objects(ksi, context)
+    return (RKS_POLL_selected_bones(ksi, context) or
+            RKS_POLL_selected_objects(ksi, context))
 
 ###########################
 # Iterator Callbacks
index fed776a..411060a 100644 (file)
@@ -818,12 +818,9 @@ class USERPREF_PT_input(bpy.types.Panel, InputKeyMapPanel):
         #sub.prop(view, "wheel_scroll_lines", text="Scroll Lines")
 
         col.separator()
-        ''' not implemented yet
         sub = col.column()
         sub.label(text="NDOF Device:")
-        sub.prop(inputs, "ndof_pan_speed", text="Pan Speed")
-        sub.prop(inputs, "ndof_rotate_speed", text="Orbit Speed")
-        '''
+        sub.prop(inputs, "ndof_sensitivity", text="NDOF Sensitivity")
 
         row.separator()
 
@@ -882,7 +879,7 @@ class USERPREF_PT_addons(bpy.types.Panel):
         if not user_addon_paths:
             user_script_path = bpy.utils.user_script_path()
             if user_script_path is not None:
-                user_addon_paths.append(os.path.join(user_script_path(), "addons"))
+                user_addon_paths.append(os.path.join(user_script_path, "addons"))
             user_addon_paths.append(os.path.join(bpy.utils.resource_path('USER'), "scripts", "addons"))
 
         for path in user_addon_paths:
index 85764c5..8fed3a9 100644 (file)
@@ -271,6 +271,8 @@ class InputKeyMapPanel:
             row.prop(kmi, "type", text="", full_event=True)
         elif map_type == 'MOUSE':
             row.prop(kmi, "type", text="", full_event=True)
+        elif map_type == 'NDOF':
+            row.prop(kmi, "type", text="", full_event=True)
         elif map_type == 'TWEAK':
             subrow = row.row()
             subrow.prop(kmi, "type", text="")
@@ -306,7 +308,7 @@ class InputKeyMapPanel:
                 sub = split.column()
                 subrow = sub.row(align=True)
 
-                if map_type == 'KEYBOARD':
+                if map_type in {'KEYBOARD', 'NDOF'}:
                     subrow.prop(kmi, "type", text="", event=True)
                     subrow.prop(kmi, "value", text="")
                 elif map_type == 'MOUSE':
index c1973bc..fdd4833 100644 (file)
@@ -353,6 +353,30 @@ class VIEW3D_MT_view_navigation(bpy.types.Menu):
         layout.operator("view3d.fly")
 
 
+class VIEW3D_MT_ndof_settings(bpy.types.Menu):
+    bl_label = "3D Mouse Settings"
+
+    def draw(self, context):
+        layout = self.layout
+        input_prefs = context.user_preferences.inputs
+
+        layout.separator()
+        layout.prop(input_prefs, "ndof_sensitivity")
+
+        if context.space_data.type == 'VIEW_3D':
+            layout.separator()
+            layout.prop(input_prefs, "ndof_show_guide")
+
+            layout.separator()
+            layout.label(text="orbit options")
+            layout.prop(input_prefs, "ndof_orbit_invert_axes")
+
+            layout.separator()
+            layout.label(text="fly options")
+            layout.prop(input_prefs, "ndof_fly_helicopter", icon='NDOF_FLY')
+            layout.prop(input_prefs, "ndof_lock_horizon", icon='NDOF_DOM')
+
+
 class VIEW3D_MT_view_align(bpy.types.Menu):
     bl_label = "Align View"
 
index 67e0332..98517fd 100644 (file)
@@ -35,7 +35,7 @@ def add_object(self, context):
     mesh.from_pydata(verts, edges, faces)
     # useful for development when the mesh may be invalid.
     # mesh.validate(verbose=True)
-    add_object_data(context, mesh_data, operator=self)
+    add_object_data(context, mesh, operator=self)
 
 
 class OBJECT_OT_add_object(bpy.types.Operator, AddObjectHelper):
index 0491116..557ce41 100644 (file)
@@ -115,5 +115,6 @@ int minmax_curve(struct Curve *cu, float min[3], float max[3]);
 int curve_center_median(struct Curve *cu, float cent[3]);
 int curve_center_bounds(struct Curve *cu, float cent[3]);
 void curve_translate(struct Curve *cu, float offset[3], int do_keys);
+void curve_delete_material_index(struct Curve *cu, int index);
 #endif
 
index d21b042..17876c6 100644 (file)
@@ -92,9 +92,6 @@ typedef struct Global {
     
        /* save the allowed windowstate of blender when using -W or -w */
        int windowstate;
-
-       /* ndof device found ? */
-       int ndofdevice;
 } Global;
 
 /* **************** GLOBAL ********************* */
@@ -174,5 +171,3 @@ extern Global G;
 #endif
        
 #endif
-
-
index c445408..88965d1 100644 (file)
@@ -78,7 +78,7 @@ int object_remove_material_slot(struct Object *ob);
 
 /* rna api */
 void material_append_id(struct ID *id, struct Material *ma);
-struct Material *material_pop_id(struct ID *id, int index);
+struct Material *material_pop_id(struct ID *id, int index, int remove_material_slot);
 
 /* rendering */
 
index d9c98bc..62b8830 100644 (file)
@@ -1883,7 +1883,9 @@ static void mesh_calc_modifiers(Scene *scene, Object *ob, float (*inputVertexCos
                        
                        /* set the DerivedMesh to only copy needed data */
                        mask= (CustomDataMask)GET_INT_FROM_POINTER(curr->link);
-                       DM_set_only_copy(dm, mask);
+                       /* needMapping check here fixes bug [#28112], otherwise its
+                        * possible that it wont be copied */
+                       DM_set_only_copy(dm, mask | (needMapping ? CD_MASK_ORIGINDEX : 0));
                        
                        /* add cloth rest shape key if need */
                        if(mask & CD_MASK_CLOTH_ORCO)
index 202a3f2..eb364af 100644 (file)
@@ -580,46 +580,47 @@ void addNurbPointsBezier(Nurb *nu, int number)
 /* ~~~~~~~~~~~~~~~~~~~~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 */
+static void calcknots(float *knots, const short pnts, const short order, const short flag)
 {
+       /* knots: number of pnts NOT corrected for cyclic */
+       const int pnts_order= pnts + order;
        float k;
-       int a, t;
-
-               t = aantal+order;
-       if(type==0) {
+       int a;
 
-               for(a=0;a<t;a++) {
-                       knots[a]= (float)a;
-               }
-       }
-       else if(type==1) {
+       switch(flag & (CU_NURB_ENDPOINT|CU_NURB_BEZIER)) {
+       case CU_NURB_ENDPOINT:
                k= 0.0;
-               for(a=1;a<=t;a++) {
+               for(a=1; a <= pnts_order; a++) {
                        knots[a-1]= k;
-                       if(a>=order && a<=aantal) k+= 1.0f;
+                       if(a >= order && a <= pnts) k+= 1.0f;
                }
-       }
-       else if(type==2) {
-               /* Warning, the order MUST be 2 or 4, if this is not enforced, the displist will be corrupt */
+               break;
+       case CU_NURB_BEZIER:
+               /* Warning, the order MUST be 2 or 4,
+                * if this is not enforced, the displist will be corrupt */
                if(order==4) {
                        k= 0.34;
-                       for(a=0;a<t;a++) {
+                       for(a=0; a < pnts_order; a++) {
                                knots[a]= floorf(k);
                                k+= (1.0f/3.0f);
                        }
                }
                else if(order==3) {
                        k= 0.6f;
-                       for(a=0;a<t;a++) {
-                               if(a>=order && a<=aantal) k+= 0.5f;
+                       for(a=0; a < pnts_order; a++) {
+                               if(a >= order && a <= pnts) k+= 0.5f;
                                knots[a]= floorf(k);
                        }
                }
                else {
                        printf("bez nurb curve order is not 3 or 4, should never happen\n");
                }
+               break;
+       default:
+               for(a=0; a < pnts_order; a++) {
+                       knots[a]= (float)a;
+               }
+               break;
        }
 }
 
@@ -662,7 +663,7 @@ static void makeknots(Nurb *nu, short uv)
                                        calcknots(nu->knotsu, nu->pntsu, nu->orderu, 0);  /* cyclic should be uniform */
                                        makecyclicknots(nu->knotsu, nu->pntsu, nu->orderu);
                                } else {
-                                       calcknots(nu->knotsu, nu->pntsu, nu->orderu, nu->flagu>>1);
+                                       calcknots(nu->knotsu, nu->pntsu, nu->orderu, nu->flagu);
                                }
                        }
                        else nu->knotsu= NULL;
@@ -675,7 +676,7 @@ static void makeknots(Nurb *nu, short uv)
                                        calcknots(nu->knotsv, nu->pntsv, nu->orderv, 0);  /* cyclic should be uniform */
                                        makecyclicknots(nu->knotsv, nu->pntsv, nu->orderv);
                                } else {
-                                       calcknots(nu->knotsv, nu->pntsv, nu->orderv, nu->flagv>>1);
+                                       calcknots(nu->knotsv, nu->pntsv, nu->orderv, nu->flagv);
                                }
                        }
                        else nu->knotsv= NULL;
@@ -3259,3 +3260,28 @@ void curve_translate(Curve *cu, float offset[3], int do_keys)
                }
        }
 }
+
+void curve_delete_material_index(Curve *cu, int index)
+{
+       const int curvetype= curve_type(cu);
+
+       if(curvetype == OB_FONT) {
+               struct CharInfo *info= cu->strinfo;
+               int i;
+               for(i= cu->len-1; i >= 0; i--, info++) {
+                       if (info->mat_nr && info->mat_nr>=index) {
+                               info->mat_nr--;
+                       }
+               }
+       }
+       else {
+               Nurb *nu;
+
+               for (nu= cu->nurb.first; nu; nu= nu->next) {
+                       if(nu->mat_nr && nu->mat_nr>=index) {
+                               nu->mat_nr--;
+                               if (curvetype == OB_CURVE) nu->charidx--;
+                       }
+               }
+       }
+}
index 50c120a..2aef5b3 100644 (file)
@@ -474,20 +474,20 @@ static int setkeys(float fac, ListBase *lb, KeyBlock *k[], float *t, int cycl)
 
 }
 
-static void flerp(int aantal, float *in, float *f0, float *f1, float *f2, float *f3, float *t) 
+static void flerp(int tot, float *in, float *f0, float *f1, float *f2, float *f3, float *t)
 {
        int a;
 
-       for(a=0; a<aantal; a++) {
+       for(a=0; a<tot; a++) {
                in[a]= t[0]*f0[a]+t[1]*f1[a]+t[2]*f2[a]+t[3]*f3[a];
        }
 }
 
-static void rel_flerp(int aantal, float *in, float *ref, float *out, float fac)
+static void rel_flerp(int tot, float *in, float *ref, float *out, float fac)
 {
        int a;
        
-       for(a=0; a<aantal; a++) {
+       for(a=0; a<tot; a++) {
                in[a]-= fac*(ref[a]-out[a]);
        }
 }
index 3f01c55..9c455e8 100644 (file)
@@ -61,7 +61,7 @@
 #include "BKE_material.h"
 #include "BKE_mesh.h"
 #include "BKE_node.h"
-
+#include "BKE_curve.h"
 
 #include "GPU_material.h"
 
@@ -515,6 +515,21 @@ short *give_totcolp_id(ID *id)
        return NULL;
 }
 
+void data_delete_material_index_id(ID *id, int index)
+{
+       switch(GS(id->name)) {
+       case ID_ME:
+               mesh_delete_material_index((Mesh *)id, index);
+               break;
+       case ID_CU:
+               curve_delete_material_index((Curve *)id, index);
+               break;
+       case ID_MB:
+               /* meta-elems dont have materials atm */
+               break;
+       }
+}
+
 void material_append_id(ID *id, Material *ma)
 {
        Material ***matar;
@@ -532,7 +547,7 @@ void material_append_id(ID *id, Material *ma)
        }
 }
 
-Material *material_pop_id(ID *id, int index)
+Material *material_pop_id(ID *id, int index, int remove_material_slot)
 {
        Material *ret= NULL;
        Material ***matar;
@@ -540,27 +555,36 @@ Material *material_pop_id(ID *id, int index)
                short *totcol= give_totcolp_id(id);
                if(index >= 0 && index < (*totcol)) {
                        ret= (*matar)[index];
-                       id_us_min((ID *)ret);                   
-                       if(*totcol <= 1) {
-                               *totcol= 0;
-                               MEM_freeN(*matar);
-                               *matar= NULL;
-                       }
-                       else {
-                               Material **mat;
-
-                               if(index + 1 != (*totcol))
-                                       memmove((*matar)+index, (*matar)+(index+1), sizeof(void *) * ((*totcol) - (index + 1)));
+                       id_us_min((ID *)ret);
 
-                               (*totcol)--;
-                               
-                               mat= MEM_callocN(sizeof(void *) * (*totcol), "newmatar");
-                               memcpy(mat, *matar, sizeof(void *) * (*totcol));
-                               MEM_freeN(*matar);
+                       if (remove_material_slot) {
+                               if(*totcol <= 1) {
+                                       *totcol= 0;
+                                       MEM_freeN(*matar);
+                                       *matar= NULL;
+                               }
+                               else {
+                                       Material **mat;
+                                       if(index + 1 != (*totcol))
+                                               memmove((*matar)+index, (*matar)+(index+1), sizeof(void *) * ((*totcol) - (index + 1)));
+
+                                       (*totcol)--;
+                                       
+                                       mat= MEM_callocN(sizeof(void *) * (*totcol), "newmatar");
+                                       memcpy(mat, *matar, sizeof(void *) * (*totcol));
+                                       MEM_freeN(*matar);
+
+                                       *matar= mat;
+                                       test_object_materials(id);
+                               }
 
-                               *matar= mat;
-                               test_object_materials(id);
+                               /* decrease mat_nr index */
+                               data_delete_material_index_id(id, index);
                        }
+
+                       /* don't remove material slot, only clear it*/
+                       else
+                               (*matar)[index]= NULL;
                }
        }
        
@@ -1025,8 +1049,6 @@ int object_remove_material_slot(Object *ob)
 {
        Material *mao, ***matarar;
        Object *obt;
-       Curve *cu;
-       Nurb *nu;
        short *totcolp;
        int a, actcol;
        
@@ -1086,23 +1108,8 @@ int object_remove_material_slot(Object *ob)
        }
 
        /* 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;
-               }
+       if (ELEM4(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT)) {
+               data_delete_material_index_id((ID *)ob->data, actcol-1);
                freedisplist(&ob->disp);
        }
 
index 45a60b8..3281922 100644 (file)
@@ -1254,10 +1254,10 @@ void mesh_to_curve(Scene *scene, Object *ob)
 
 void mesh_delete_material_index(Mesh *me, int index)
 {
+       MFace *mf;
        int i;
 
-       for (i=0; i<me->totface; i++) {
-               MFace *mf = &((MFace*) me->mface)[i];
+       for (i=0, mf=me->mface; i<me->totface; i++, mf++) {
                if (mf->mat_nr && mf->mat_nr>=index) 
                        mf->mat_nr--;
        }
index 7bc93a3..5f31565 100644 (file)
@@ -290,8 +290,10 @@ void BLI_argsParse(struct bArgs *ba, int pass, BA_ArgCallback default_cb, void *
                                        }
                                        i += retval;
                                } else if (retval == -1){
-                                       if (a->key->pass != -1)
-                                               ba->passes[i] = pass;
+                                       if (a) {
+                                               if (a->key->pass != -1)
+                                                       ba->passes[i] = pass;
+                                       }
                                        break;
                                }
                        }
index 85d79ae..0613765 100644 (file)
@@ -26,7 +26,6 @@
 
 
 
-
 #include "DNA_meshdata_types.h"
 
 #include "MEM_guardedalloc.h"
@@ -85,25 +84,61 @@ struct PBVHNode {
        /* Opaque handle for drawing code */
        void *draw_buffers;
 
-       int *vert_indices;
-
        /* Voxel bounds */
        BB vb;
        BB orig_vb;
 
-       /* For internal nodes */
+       /* For internal nodes, the offset of the children in the PBVH
+          'nodes' array. */
        int children_offset;
 
-       /* Pointer into bvh prim_indices */
-       int *prim_indices;
-       int *face_vert_indices;
+       /* Pointer into the PBVH prim_indices array and the number of
+          primitives used by this leaf node.
 
+          Used for leaf nodes in both mesh- and multires-based PBVHs.
+       */
+       int *prim_indices;
        unsigned int totprim;
+
+       /* Array of indices into the mesh's MVert array. Contains the
+          indices of all vertices used by faces that are within this
+          node's bounding box.
+
+          Note that a vertex might be used by a multiple faces, and
+          these faces might be in different leaf nodes. Such a vertex
+          will appear in the vert_indices array of each of those leaf
+          nodes.
+
+          In order to support cases where you want access to multiple
+          nodes' vertices without duplication, the vert_indices array
+          is ordered such that the first part of the array, up to
+          index 'uniq_verts', contains "unique" vertex indices. These
+          vertices might not be truly unique to this node, but if
+          they appear in another node's vert_indices array, they will
+          be above that node's 'uniq_verts' value.
+
+          Used for leaf nodes in a mesh-based PBVH (not multires.)
+       */
+       int *vert_indices;
        unsigned int uniq_verts, face_verts;
 
-       char flag;
+       /* An array mapping face corners into the vert_indices
+          array. The array is sized to match 'totprim', and each of
+          the face's corners gets an index into the vert_indices
+          array, in the same order as the corners in the original
+          MFace. The fourth value should not be used if the original
+          face is a triangle.
+
+          Used for leaf nodes in a mesh-based PBVH (not multires.)
+       */
+       int (*face_vert_indices)[4];
+
+       /* Indicates whether this node is a leaf or not; also used for
+          marking various updates that need to be applied. */
+       PBVHNodeFlags flag : 8;
 
-       float tmin; // used for raycasting, is how close bb is to the ray point
+       /* Used for raycasting: how close bb is to the ray point. */
+       float tmin;
 
        int proxy_count;
        PBVHProxyNode* proxies;
@@ -339,15 +374,15 @@ static void build_mesh_leaf_node(PBVH *bvh, PBVHNode *node)
        node->uniq_verts = node->face_verts = 0;
        totface= node->totprim;
 
-       node->face_vert_indices = MEM_callocN(sizeof(int) *
-                                        4*totface, "bvh node face vert indices");
+       node->face_vert_indices = MEM_callocN(sizeof(int) * 4*totface,
+                                             "bvh node face vert indices");
 
        for(i = 0; i < totface; ++i) {
                MFace *f = bvh->faces + node->prim_indices[i];
                int sides = f->v4 ? 4 : 3;
 
                for(j = 0; j < sides; ++j) {
-                       node->face_vert_indices[i*4 + j]= 
+                       node->face_vert_indices[i][j]= 
                                map_insert_vert(bvh, map, &node->face_verts,
                                                &node->uniq_verts, (&f->v1)[j]);
                }
@@ -373,9 +408,17 @@ static void build_mesh_leaf_node(PBVH *bvh, PBVHNode *node)
 
        BLI_ghashIterator_free(iter);
 
-       for(i = 0; i < totface*4; ++i)
-               if(node->face_vert_indices[i] < 0)
-                       node->face_vert_indices[i]= -node->face_vert_indices[i] + node->uniq_verts - 1;
+       for(i = 0; i < totface; ++i) {
+               MFace *f = bvh->faces + node->prim_indices[i];
+               int sides = f->v4 ? 4 : 3;
+               
+               for(j = 0; j < sides; ++j) {
+                       if(node->face_vert_indices[i][j] < 0)
+                               node->face_vert_indices[i][j]=
+                                       -node->face_vert_indices[i][j] +
+                                       node->uniq_verts - 1;
+               }
+       }
 
        if(!G.background) {
                node->draw_buffers =
@@ -1340,20 +1383,20 @@ int BLI_pbvh_node_raycast(PBVH *bvh, PBVHNode *node, float (*origco)[3],
        if(bvh->faces) {
                MVert *vert = bvh->verts;
                int *faces= node->prim_indices;
-               int *face_verts= node->face_vert_indices;
                int totface= node->totprim;
                int i;
 
                for(i = 0; i < totface; ++i) {
                        MFace *f = bvh->faces + faces[i];
+                       int *face_verts = node->face_vert_indices[i];
 
                        if(origco) {
                                /* intersect with backuped original coordinates */
                                hit |= ray_face_intersection(ray_start, ray_normal,
-                                                        origco[face_verts[i*4+0]],
-                                                        origco[face_verts[i*4+1]],
-                                                        origco[face_verts[i*4+2]],
-                                                        f->v4? origco[face_verts[i*4+3]]: NULL,
+                                                        origco[face_verts[0]],
+                                                        origco[face_verts[1]],
+                                                        origco[face_verts[2]],
+                                                        f->v4? origco[face_verts[3]]: NULL,
                                                         dist);
                        }
                        else {
index 18b461e..1737b44 100644 (file)
@@ -3163,7 +3163,7 @@ static void lib_link_particlesettings(FileData *fd, Main *main)
                        if(part->effector_weights)
                                part->effector_weights->group = newlibadr(fd, part->id.lib, part->effector_weights->group);
 
-                       if(part->dupliweights.first) {
+                       if(part->dupliweights.first && part->dup_group) {
                                int index_ok = 0;
                                /* check for old files without indices (all indexes 0) */
                                dw = part->dupliweights.first;
@@ -3194,6 +3194,9 @@ static void lib_link_particlesettings(FileData *fd, Main *main)
                                                dw->ob = newlibadr(fd, part->id.lib, dw->ob);
                                }
                        }
+                       else {
+                               part->dupliweights.first = part->dupliweights.last = NULL;
+                       }
 
                        if(part->boids) {
                                BoidState *state = part->boids->states.first;
index 06d88b1..210f36c 100644 (file)
@@ -3432,7 +3432,6 @@ static int convertspline(short type, Nurb *nu)
                        nu->type = CU_NURBS;
                        nu->orderu= 4;
                        nu->flagu &= CU_NURB_CYCLIC; /* disable all flags except for cyclic */
-                       nu->flagu |= CU_NURB_BEZIER;
                        nurbs_knot_calc_u(nu);
                        a= nu->pntsu*nu->pntsv;
                        bp= nu->bp;
@@ -6544,12 +6543,15 @@ Nurb *add_nurbs_primitive(bContext *C, float mat[4][4], int type, int newob)
                BLI_assert(!"invalid nurbs type");
                return NULL;
        }
-       
-       /* always do: */
-       nu->flag |= CU_SMOOTH;
-       
-       test2DNurb(nu);
-       
+
+       BLI_assert(nu != NULL);
+
+       if(nu) { /* should always be set */
+               nu->flag |= CU_SMOOTH;
+
+               test2DNurb(nu);
+       }
+
        return nu;
 }
 
index f4da734..28a54b2 100644 (file)
@@ -1617,6 +1617,18 @@ static int gpencil_draw_modal (bContext *C, wmOperator *op, wmEvent *event)
        tGPsdata *p= op->customdata;
        int estate = OPERATOR_PASS_THROUGH; /* default exit state - not handled, so let others have a share of the pie */
        
+       // if (event->type == NDOF_MOTION)
+       //      return OPERATOR_PASS_THROUGH;
+       // -------------------------------
+       // [mce] Not quite what I was looking
+       // for, but a good start! GP continues to
+       // draw on the screen while the 3D mouse
+       // moves the viewpoint. Problem is that
+       // the stroke is converted to 3D only after
+       // it is finished. This approach should work
+       // better in tools that immediately apply
+       // in 3D space.
+
        //printf("\tGP - handle modal event...\n");
        
        /* exit painting mode (and/or end current stroke) */
index 2e172c4..1113f90 100644 (file)
@@ -1,3 +1,27 @@
+/*
+ * $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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s):
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
 /** \file blender/editors/interface/interface_anim.c
  *  \ingroup edinterface
  */
index 1aa2fb3..adabfe5 100644 (file)
@@ -1,6 +1,3 @@
-/** \file blender/editors/interface/resources.c
- *  \ingroup edinterface
- */
 /*
  * $Id$
  *
  * ***** END GPL/BL DUAL LICENSE BLOCK *****
  */
 
+/** \file blender/editors/interface/resources.c
+ *  \ingroup edinterface
+ */
+
 #include <math.h>
 #include <stdlib.h>
 #include <string.h>
@@ -1587,6 +1588,12 @@ void init_userdef_do_versions(void)
        if (U.anisotropic_filter <= 0)
                U.anisotropic_filter = 1;
 
+       if (U.ndof_sensitivity == 0.0f) {
+               U.ndof_sensitivity = 1.0f;
+               U.ndof_flag = NDOF_LOCK_HORIZON |
+                       NDOF_SHOULD_PAN | NDOF_SHOULD_ZOOM | NDOF_SHOULD_ROTATE;
+       }
+
        /* funny name, but it is GE stuff, moves userdef stuff to engine */
 // XXX space_set_commmandline_options();
        /* this timer uses U */
index ab9c699..ce1f47c 100644 (file)
@@ -1097,7 +1097,7 @@ static int move_to_layer_exec(bContext *C, wmOperator *op)
        Scene *scene= CTX_data_scene(C);
        View3D *v3d= CTX_wm_view3d(C);
        unsigned int lay, local;
-       int islamp= 0;
+       /* int islamp= 0; */ /* UNUSED */
        
        lay= move_to_layer_init(C, op);
        lay &= 0xFFFFFF;
@@ -1113,7 +1113,7 @@ static int move_to_layer_exec(bContext *C, wmOperator *op)
                        base->object->lay= lay;
                        base->object->flag &= ~SELECT;
                        base->flag &= ~SELECT;
-                       if(base->object->type==OB_LAMP) islamp= 1;
+                       /* if(base->object->type==OB_LAMP) islamp= 1; */
                }
                CTX_DATA_END;
        }
@@ -1125,7 +1125,7 @@ static int move_to_layer_exec(bContext *C, wmOperator *op)
                        local= base->lay & 0xFF000000;  
                        base->lay= lay + local;
                        base->object->lay= lay;
-                       if(base->object->type==OB_LAMP) islamp= 1;
+                       /* if(base->object->type==OB_LAMP) islamp= 1; */
                }
                CTX_DATA_END;
        }
index 68326ed..1410331 100644 (file)
@@ -301,7 +301,7 @@ int ED_operator_object_active_editable(bContext *C)
 int ED_operator_object_active_editable_mesh(bContext *C)
 {
        Object *ob = ED_object_active_context(C);
-       return ((ob != NULL) && !(ob->id.lib) && !(ob->restrictflag & OB_RESTRICT_VIEW) && ob->type == OB_MESH);
+       return ((ob != NULL) && !(ob->id.lib) && !(ob->restrictflag & OB_RESTRICT_VIEW) && ob->type == OB_MESH && !(((ID *)ob->data)->lib));
 }
 
 int ED_operator_object_active_editable_font(bContext *C)
index c9a6aa8..32004fd 100644 (file)
@@ -2187,7 +2187,7 @@ static int IsectPoly2Df_twoside(const float pt[2], float uv[][2], const int tot)
 
 /* One of the most important function for projectiopn painting, since it selects the pixels to be added into each bucket.
  * initialize pixels from this face where it intersects with the bucket_index, optionally initialize pixels for removing seams */
-static void project_paint_face_init(const ProjPaintState *ps, const int thread_index, const int bucket_index, const int face_index, const int image_index, rctf *bucket_bounds, const ImBuf *ibuf)
+static void project_paint_face_init(const ProjPaintState *ps, const int thread_index, const int bucket_index, const int face_index, const int image_index, rctf *bucket_bounds, const ImBuf *ibuf, const short clamp_u, const short clamp_v)
 {
        /* Projection vars, to get the 3D locations into screen space  */
        MemArena *arena = ps->arena_mt[thread_index];
@@ -2304,14 +2304,24 @@ static void project_paint_face_init(const ProjPaintState *ps, const int thread_i
                
 
                if (pixel_bounds_array(uv_clip, &bounds_px, ibuf->x, ibuf->y, uv_clip_tot)) {
-                       
+
+                       if(clamp_u) {
+                               CLAMP(bounds_px.xmin, 0, ibuf->x);
+                               CLAMP(bounds_px.xmax, 0, ibuf->x);
+                       }
+
+                       if(clamp_v) {
+                               CLAMP(bounds_px.ymin, 0, ibuf->y);
+                               CLAMP(bounds_px.ymax, 0, ibuf->y);
+                       }
+
                        /* clip face and */
                        
                        has_isect = 0;
                        for (y = bounds_px.ymin; y < bounds_px.ymax; y++) {
                                //uv[1] = (((float)y) + 0.5f) / (float)ibuf->y;
                                uv[1] = (float)y / ibuf_yf; /* use pixel offset UV coords instead */
-                               
+
                                has_x_isect = 0;
                                for (x = bounds_px.xmin; x < bounds_px.xmax; x++) {
                                        //uv[0] = (((float)x) + 0.5f) / ibuf->x;
@@ -2630,6 +2640,7 @@ static void project_bucket_init(const ProjPaintState *ps, const int thread_index
        LinkNode *node;
        int face_index, image_index=0;
        ImBuf *ibuf = NULL;
+       Image *ima = NULL;
        MTFace *tf;
        
        Image *tpage_last = NULL;
@@ -2638,9 +2649,10 @@ static void project_bucket_init(const ProjPaintState *ps, const int thread_index
        if (ps->image_tot==1) {
                /* Simple loop, no context switching */
                ibuf = ps->projImages[0].ibuf;
-               
+               ima = ps->projImages[0].ima;
+
                for (node = ps->bucketFaces[bucket_index]; node; node= node->next) { 
-                       project_paint_face_init(ps, thread_index, bucket_index, GET_INT_FROM_POINTER(node->link), 0, bucket_bounds, ibuf);
+                       project_paint_face_init(ps, thread_index, bucket_index, GET_INT_FROM_POINTER(node->link), 0, bucket_bounds, ibuf, ima->tpageflag & IMA_CLAMP_U, ima->tpageflag & IMA_CLAMP_V);
                }
        }
        else {
@@ -2659,14 +2671,14 @@ static void project_bucket_init(const ProjPaintState *ps, const int thread_index
                                for (image_index=0; image_index < ps->image_tot; image_index++) {
                                        if (ps->projImages[image_index].ima == tpage_last) {
                                                ibuf = ps->projImages[image_index].ibuf;
+                                               ima = ps->projImages[image_index].ima;
                                                break;
                                        }
                                }
                        }
                        /* context switching done */
                        
-                       project_paint_face_init(ps, thread_index, bucket_index, face_index, image_index, bucket_bounds, ibuf);
-                       
+                       project_paint_face_init(ps, thread_index, bucket_index, face_index, image_index, bucket_bounds, ibuf, ima->tpageflag & IMA_CLAMP_U, ima->tpageflag & IMA_CLAMP_V);
                }
        }
        
index 7ddf5df..0987356 100644 (file)
@@ -832,6 +832,13 @@ int paint_stroke_modal(bContext *C, wmOperator *op, wmEvent *event)
        float mouse[2];
        int first= 0;
 
+       // let NDOF motion pass through to the 3D view so we can paint and rotate simultaneously!
+       // this isn't perfect... even when an extra MOUSEMOVE is spoofed, the stroke discards it
+       // since the 2D deltas are zero -- code in this file needs to be updated to use the
+       // post-NDOF_MOTION MOUSEMOVE
+       if (event->type == NDOF_MOTION)
+               return OPERATOR_PASS_THROUGH;
+
        if(!stroke->stroke_started) {
                stroke->last_mouse_position[0] = event->x;
                stroke->last_mouse_position[1] = event->y;
index e9e77dd..399157d 100644 (file)
@@ -73,6 +73,7 @@ void IMAGE_OT_view_zoom(struct wmOperatorType *ot);
 void IMAGE_OT_view_zoom_in(struct wmOperatorType *ot);
 void IMAGE_OT_view_zoom_out(struct wmOperatorType *ot);
 void IMAGE_OT_view_zoom_ratio(struct wmOperatorType *ot);
+void IMAGE_OT_view_ndof(struct wmOperatorType *ot);
 
 void IMAGE_OT_new(struct wmOperatorType *ot);
 void IMAGE_OT_open(struct wmOperatorType *ot);
index d5515bd..6e84c1a 100644 (file)
@@ -437,6 +437,60 @@ void IMAGE_OT_view_zoom(wmOperatorType *ot)
                "Factor", "Zoom factor, values higher than 1.0 zoom in, lower values zoom out.", -FLT_MAX, FLT_MAX);
 }
 
+/********************** NDOF operator *********************/
+
+/* Combined pan/zoom from a 3D mouse device.
+ * Z zooms, XY pans
+ * "view" (not "paper") control -- user moves the viewpoint, not the image being viewed
+ * that explains the negative signs in the code below
+ */
+
+static int view_ndof_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *event)
+{
+       SpaceImage *sima= CTX_wm_space_image(C);
+       ARegion *ar= CTX_wm_region(C);
+
+       wmNDOFMotionData* ndof = (wmNDOFMotionData*) event->customdata;
+
+       float dt = ndof->dt > 0.25f ? 0.0125f : ndof->dt;
+       /* this is probably the first event for this motion, so set dt to something reasonable
+        * TODO: replace such guesswork with a flag or field from the NDOF manager
+        */
+
+       /* tune these until it feels right */
+       const float zoom_sensitivity = 0.5f;
+       const float pan_sensitivity = 300.f;
+
+       float pan_x = pan_sensitivity * dt * ndof->tvec[0] / sima->zoom;
+       float pan_y = pan_sensitivity * dt * ndof->tvec[1] / sima->zoom;
+
+       /* "mouse zoom" factor = 1 + (dx + dy) / 300
+        * what about "ndof zoom" factor? should behave like this:
+        * at rest -> factor = 1
+        * move forward -> factor > 1
+        * move backward -> factor < 1
+        */
+       float zoom_factor = 1.f + zoom_sensitivity * dt * -ndof->tvec[2];
+
+       sima_zoom_set_factor(sima, ar, zoom_factor);
+       sima->xof += pan_x;
+       sima->yof += pan_y;
+
+       ED_region_tag_redraw(ar);       
+
+       return OPERATOR_FINISHED;
+}
+
+void IMAGE_OT_view_ndof(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "NDOF Pan/Zoom";
+       ot->idname= "IMAGE_OT_view_ndof";
+       
+       /* api callbacks */
+       ot->invoke= view_ndof_invoke;
+}
+
 /********************** view all operator *********************/
 
 /* Updates the fields of the View2D member of the SpaceImage struct.
index 2e9544f..afab4ed 100644 (file)
@@ -469,6 +469,7 @@ static void image_operatortypes(void)
        WM_operatortype_append(IMAGE_OT_view_zoom_in);
        WM_operatortype_append(IMAGE_OT_view_zoom_out);
        WM_operatortype_append(IMAGE_OT_view_zoom_ratio);
+       WM_operatortype_append(IMAGE_OT_view_ndof);
 
        WM_operatortype_append(IMAGE_OT_new);
        WM_operatortype_append(IMAGE_OT_open);
@@ -518,6 +519,9 @@ static void image_keymap(struct wmKeyConfig *keyconf)
        WM_keymap_add_item(keymap, "IMAGE_OT_view_pan", MIDDLEMOUSE, KM_PRESS, KM_SHIFT, 0);
        WM_keymap_add_item(keymap, "IMAGE_OT_view_pan", MOUSEPAN, 0, 0, 0);
 
+       WM_keymap_add_item(keymap, "IMAGE_OT_view_all", NDOF_BUTTON_FIT, KM_PRESS, 0, 0); // or view selected?
+       WM_keymap_add_item(keymap, "IMAGE_OT_view_ndof", NDOF_MOTION, 0, 0, 0);
+
        WM_keymap_add_item(keymap, "IMAGE_OT_view_zoom_in", WHEELINMOUSE, KM_PRESS, 0, 0);
        WM_keymap_add_item(keymap, "IMAGE_OT_view_zoom_out", WHEELOUTMOUSE, KM_PRESS, 0, 0);
        WM_keymap_add_item(keymap, "IMAGE_OT_view_zoom_in", PADPLUSKEY, KM_PRESS, 0, 0);
index d2ff6ee..6e3f654 100644 (file)
@@ -675,6 +675,104 @@ static void draw_view_axis(RegionView3D *rv3d)
        glDisable(GL_BLEND);
 }
 
+/* draw center and axis of rotation for ongoing 3D mouse navigation */
+static void draw_rotation_guide(RegionView3D *rv3d)
+{
+       float o[3]; // center of rotation
+       float end[3]; // endpoints for drawing
+
+       float color[4] = {0.f ,0.4235f, 1.f, 1.f}; // bright blue so it matches device LEDs
+
+       negate_v3_v3(o, rv3d->ofs);
+
+       glEnable(GL_BLEND);
+       glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+       glShadeModel(GL_SMOOTH);
+       glPointSize(5);
+       glEnable(GL_POINT_SMOOTH);
+       glDepthMask(0); // don't overwrite zbuf
+
+       if (rv3d->rot_angle != 0.f) {
+               // -- draw rotation axis --
+               float scaled_axis[3];
+               const float scale = rv3d->dist;
+               mul_v3_v3fl(scaled_axis, rv3d->rot_axis, scale);
+       
+               glBegin(GL_LINE_STRIP);
+                       color[3] = 0.f; // more transparent toward the ends
+                       glColor4fv(color);
+                       add_v3_v3v3(end, o, scaled_axis);
+                       glVertex3fv(end);
+       
+                       // color[3] = 0.2f + fabsf(rv3d->rot_angle); // modulate opacity with angle
+                       // ^^ neat idea, but angle is frame-rate dependent, so it's usually close to 0.2
+
+                       color[3] = 0.5f; // more opaque toward the center
+                       glColor4fv(color);
+                       glVertex3fv(o);
+       
+                       color[3] = 0.f;
+                       glColor4fv(color);
+                       sub_v3_v3v3(end, o, scaled_axis);
+                       glVertex3fv(end);
+               glEnd();
+               
+               // -- draw ring around rotation center --
+               {
+               #define ROT_AXIS_DETAIL 13
+               const float s = 0.05f * scale;
+               const float step = 2.f * M_PI / ROT_AXIS_DETAIL;
+               float angle;
+               int i;
+
+               float q[4]; // rotate ring so it's perpendicular to axis
+               const int upright = fabsf(rv3d->rot_axis[2]) >= 0.95f;
+               if (!upright)
+                       {
+                       const float up[3] = {0.f, 0.f, 1.f};
+                       float vis_angle, vis_axis[3];
+
+                       cross_v3_v3v3(vis_axis, up, rv3d->rot_axis);
+                       vis_angle = acosf(dot_v3v3(up, rv3d->rot_axis));
+                       axis_angle_to_quat(q, vis_axis, vis_angle);
+                       }
+
+               color[3] = 0.25f; // somewhat faint
+               glColor4fv(color);
+               glBegin(GL_LINE_LOOP);
+               for (i = 0, angle = 0.f; i < ROT_AXIS_DETAIL; ++i, angle += step)
+                       {
+                       float p[3] = { s * cosf(angle), s * sinf(angle), 0.f };
+
+                       if (!upright)
+                               mul_qt_v3(q, p);
+
+                       add_v3_v3(p, o);
+                       glVertex3fv(p);
+                       }
+               glEnd();
+               }
+
+               color[3] = 1.f; // solid dot
+       }
+       else
+               color[3] = 0.5f; // see-through dot
+
+       // -- draw rotation center --
+       glColor4fv(color);
+       glBegin(GL_POINTS);
+               glVertex3fv(o);
+       glEnd();
+
+       // find screen coordinates for rotation center, then draw pretty icon
+       // mul_m4_v3(rv3d->persinv, rot_center);
+       // UI_icon_draw(rot_center[0], rot_center[1], ICON_NDOF_TURN);
+       // ^^ just playing around, does not work
+
+       glDisable(GL_BLEND);
+       glDisable(GL_POINT_SMOOTH);
+       glDepthMask(1);
+}
 
 static void draw_view_icon(RegionView3D *rv3d)
 {
@@ -2618,6 +2716,10 @@ void view3d_main_area_draw(const bContext *C, ARegion *ar)
                BDR_drawSketch(C);
        }
 
+       if ((U.ndof_flag & NDOF_SHOW_GUIDE) && (rv3d->viewlock != RV3D_LOCKED) && (rv3d->persp != RV3D_CAMOB))
+               // TODO: draw something else (but not this) during fly mode
+               draw_rotation_guide(rv3d);
+
        ED_region_pixelspace(ar);
        
 //     retopo_paint_view_update(v3d);
index d563c07..e6fd9e8 100644 (file)
@@ -928,6 +928,244 @@ void VIEW3D_OT_rotate(wmOperatorType *ot)
        ot->flag= OPTYPE_BLOCKING|OPTYPE_GRAB_POINTER;
 }
 
+// NDOF utility functions
+// (should these functions live in this file?)
+float ndof_to_axis_angle(struct wmNDOFMotionData* ndof, float axis[3])
+{
+       return ndof->dt * normalize_v3_v3(axis, ndof->rvec);
+}
+
+void ndof_to_quat(struct wmNDOFMotionData* ndof, float q[4])
+{
+       float axis[3];
+       float angle;
+
+       angle= ndof_to_axis_angle(ndof, axis);
+       axis_angle_to_quat(q, axis, angle);
+}
+
+static int ndof_orbit_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *event)
+// -- "orbit" navigation (trackball/turntable)
+// -- zooming
+// -- panning in rotationally-locked views
+{
+       RegionView3D* rv3d = CTX_wm_region_view3d(C);
+       wmNDOFMotionData* ndof = (wmNDOFMotionData*) event->customdata;
+
+       rv3d->rot_angle = 0.f; // off by default, until changed later this function
+
+       if (ndof->progress != P_FINISHING) {
+               const float dt = ndof->dt;
+       
+               // tune these until everything feels right
+               const float rot_sensitivity = 1.f;
+               const float zoom_sensitivity = 1.f;
+               const float pan_sensitivity = 1.f;
+       
+               // rather have bool, but...
+               int has_rotation = rv3d->viewlock != RV3D_LOCKED && !is_zero_v3(ndof->rvec);
+       
+               float view_inv[4];
+               invert_qt_qt(view_inv, rv3d->viewquat);
+       
+               //#define DEBUG_NDOF_MOTION
+               #ifdef DEBUG_NDOF_MOTION
+               printf("ndof: T=(%.2f,%.2f,%.2f) R=(%.2f,%.2f,%.2f) dt=%.3f delivered to 3D view\n",
+                       ndof->tx, ndof->ty, ndof->tz, ndof->rx, ndof->ry, ndof->rz, ndof->dt);
+               #endif
+       
+               if (ndof->tvec[2]) {
+                       // Zoom!
+                       // velocity should be proportional to the linear velocity attained by rotational motion of same strength
+                       // [got that?]
+                       // proportional to arclength = radius * angle
+       
+                       float zoom_distance = zoom_sensitivity * rv3d->dist * dt * ndof->tvec[2];
+                       rv3d->dist += zoom_distance;
+               }
+       
+               if (rv3d->viewlock == RV3D_LOCKED) {
+                       /* rotation not allowed -- explore panning options instead */
+                       float pan_vec[3] = {ndof->tvec[0], ndof->tvec[1], 0.0f};
+                       mul_v3_fl(pan_vec, pan_sensitivity * rv3d->dist * dt);
+       
+                       /* transform motion from view to world coordinates */
+                       invert_qt_qt(view_inv, rv3d->viewquat);
+                       mul_qt_v3(view_inv, pan_vec);
+       
+                       /* move center of view opposite of hand motion (this is camera mode, not object mode) */
+                       sub_v3_v3(rv3d->ofs, pan_vec);
+               }
+       
+               if (has_rotation) {
+       
+                       const int invert = U.ndof_flag & NDOF_ORBIT_INVERT_AXES;
+       
+                       rv3d->view = RV3D_VIEW_USER;
+       
+                       if (U.flag & USER_TRACKBALL) {
+                               float rot[4];
+       #if 0   // -------------------------- Mike's nifty original version
+                               float view_inv_conj[4];
+       
+                               ndof_to_quat(ndof, rot);
+                               // mul_qt_fl(rot, rot_sensitivity);
+                               // ^^ no apparent effect
+       
+                               if (invert)
+                                       invert_qt(rot);
+       
+                               copy_qt_qt(view_inv_conj, view_inv);
+                               conjugate_qt(view_inv_conj);
+       
+                               // transform rotation from view to world coordinates
+                               mul_qt_qtqt(rot, view_inv, rot);
+                               mul_qt_qtqt(rot, rot, view_inv_conj);
+       #else   // ---------------------------------------- Mike's revised version
+                               float axis[3];
+                               float angle = rot_sensitivity * ndof_to_axis_angle(ndof, axis);
+       
+                               if (invert)
+                                       angle = -angle;
+       
+                               // transform rotation axis from view to world coordinates
+                               mul_qt_v3(view_inv, axis);
+       
+                               // update the onscreen doo-dad
+                               rv3d->rot_angle = angle;
+                               copy_v3_v3(rv3d->rot_axis, axis);
+       
+                               axis_angle_to_quat(rot, axis, angle);
+       #endif  // --------------------------------------------
+                               // apply rotation
+                               mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, rot);
+                       } else {
+                               /* turntable view code by John Aughey, adapted for 3D mouse by [mce] */
+                               float angle, rot[4];
+                               float xvec[3] = {1,0,0};
+       
+                               /* Determine the direction of the x vector (for rotating up and down) */
+                               mul_qt_v3(view_inv, xvec);
+       
+                               /* Perform the up/down rotation */
+                               angle = rot_sensitivity * dt * ndof->rvec[0];
+                               if (invert)
+                                       angle = -angle;
+                               rot[0] = cos(angle);
+                               mul_v3_v3fl(rot+1, xvec, sin(angle));
+                               mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, rot);
+       
+                               /* Perform the orbital rotation */
+                               angle = rot_sensitivity * dt * ndof->rvec[1];
+                               if (invert)
+                                       angle = -angle;
+       
+                               // update the onscreen doo-dad
+                               rv3d->rot_angle = angle;
+                               rv3d->rot_axis[0] = 0;
+                               rv3d->rot_axis[1] = 0;
+                               rv3d->rot_axis[2] = 1;
+       
+                               rot[0] = cos(angle);
+                               rot[1] = rot[2] = 0.0;
+                               rot[3] = sin(angle);
+                               mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, rot);
+                       }
+               }
+       }
+
+       ED_region_tag_redraw(CTX_wm_region(C));
+
+       return OPERATOR_FINISHED;
+}
+
+void VIEW3D_OT_ndof_orbit(struct wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name = "NDOF Orbit View";
+       ot->description = "Explore every angle of an object using the 3D mouse.";
+       ot->idname = "VIEW3D_OT_ndof_orbit";
+
+       /* api callbacks */
+       ot->invoke = ndof_orbit_invoke;
+       ot->poll = ED_operator_view3d_active;
+
+       /* flags */
+       ot->flag = 0;
+}
+
+static int ndof_pan_invoke(bContext *C, wmOperator