Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt53
-rw-r--r--SConstruct1
-rw-r--r--build_files/cmake/Modules/FindSpacenav.cmake70
-rwxr-xr-xbuild_files/cmake/cmake_consistency_check.py2
-rwxr-xr-xbuild_files/cmake/cmake_netbeans_project.py2
-rwxr-xr-xbuild_files/cmake/cmake_qtcreator_project.py2
-rw-r--r--build_files/cmake/macros.cmake4
-rw-r--r--build_files/scons/config/darwin-config.py7
-rw-r--r--build_files/scons/config/linux2-config.py6
-rw-r--r--build_files/scons/config/win32-vc-config.py2
-rw-r--r--build_files/scons/config/win64-vc-config.py2
-rw-r--r--build_files/scons/tools/btools.py4
-rw-r--r--doc/python_api/rst/bge.constraints.rst238
-rw-r--r--doc/python_api/rst/bge.events.rst4
-rw-r--r--doc/python_api/rst/bge.logic.rst5
-rw-r--r--doc/python_api/rst/bge.render.rst14
-rw-r--r--doc/python_api/rst/bge.texture.rst8
-rw-r--r--doc/python_api/rst/bge.types.rst4
-rw-r--r--doc/python_api/rst/bgl.rst9
-rw-r--r--doc/python_api/sphinx_doc_gen.py19
-rw-r--r--intern/ghost/CMakeLists.txt34
-rw-r--r--intern/ghost/GHOST_C-api.h15
-rw-r--r--intern/ghost/GHOST_ISystem.h16
-rw-r--r--intern/ghost/GHOST_Types.h57
-rw-r--r--intern/ghost/SConscript19
-rw-r--r--intern/ghost/intern/GHOST_C-api.cpp17
-rw-r--r--intern/ghost/intern/GHOST_DisplayManagerWin32.cpp5
-rw-r--r--intern/ghost/intern/GHOST_DropTargetWin32.cpp1
-rw-r--r--intern/ghost/intern/GHOST_DropTargetWin32.h1
-rw-r--r--intern/ghost/intern/GHOST_EventManager.cpp2
-rw-r--r--intern/ghost/intern/GHOST_EventNDOF.h56
-rw-r--r--intern/ghost/intern/GHOST_NDOFManager.cpp566
-rw-r--r--intern/ghost/intern/GHOST_NDOFManager.h145
-rw-r--r--intern/ghost/intern/GHOST_NDOFManagerCocoa.h50
-rw-r--r--intern/ghost/intern/GHOST_NDOFManagerCocoa.mm174
-rw-r--r--intern/ghost/intern/GHOST_NDOFManagerWin32.cpp39
-rw-r--r--intern/ghost/intern/GHOST_NDOFManagerWin32.h40
-rw-r--r--intern/ghost/intern/GHOST_NDOFManagerX11.cpp112
-rw-r--r--intern/ghost/intern/GHOST_NDOFManagerX11.h49
-rw-r--r--intern/ghost/intern/GHOST_System.cpp43
-rw-r--r--intern/ghost/intern/GHOST_System.h29
-rw-r--r--intern/ghost/intern/GHOST_SystemCocoa.h7
-rw-r--r--intern/ghost/intern/GHOST_SystemCocoa.mm14
-rw-r--r--intern/ghost/intern/GHOST_SystemPathsWin32.cpp7
-rw-r--r--intern/ghost/intern/GHOST_SystemPathsWin32.h2
-rw-r--r--intern/ghost/intern/GHOST_SystemWin32.cpp431
-rw-r--r--intern/ghost/intern/GHOST_SystemWin32.h133
-rw-r--r--intern/ghost/intern/GHOST_SystemX11.cpp73
-rw-r--r--intern/ghost/intern/GHOST_SystemX11.h5
-rw-r--r--intern/ghost/intern/GHOST_TaskbarWin32.h10
-rw-r--r--intern/ghost/intern/GHOST_WindowWin32.h14
-rw-r--r--release/scripts/modules/addon_utils.py45
-rw-r--r--release/scripts/modules/bpy/__init__.py7
-rw-r--r--release/scripts/modules/bpy/path.py86
-rw-r--r--release/scripts/modules/bpy/utils.py81
-rw-r--r--release/scripts/modules/bpy_extras/__init__.py4
-rw-r--r--release/scripts/modules/bpy_extras/image_utils.py19
-rw-r--r--release/scripts/modules/bpy_extras/io_utils.py169
-rw-r--r--release/scripts/modules/bpy_extras/mesh_utils.py2
-rw-r--r--release/scripts/modules/bpy_extras/object_utils.py41
-rw-r--r--release/scripts/modules/bpy_extras/view3d_utils.py18
-rw-r--r--release/scripts/modules/keyingsets_utils.py9
-rw-r--r--release/scripts/startup/bl_ui/space_userpref.py7
-rw-r--r--release/scripts/startup/bl_ui/space_userpref_keymap.py4
-rw-r--r--release/scripts/startup/bl_ui/space_view3d.py24
-rw-r--r--release/scripts/templates/addon_add_object.py2
-rw-r--r--source/blender/blenkernel/BKE_curve.h1
-rw-r--r--source/blender/blenkernel/BKE_global.h5
-rw-r--r--source/blender/blenkernel/BKE_material.h2
-rw-r--r--source/blender/blenkernel/intern/DerivedMesh.c4
-rw-r--r--source/blender/blenkernel/intern/curve.c70
-rw-r--r--source/blender/blenkernel/intern/key.c8
-rw-r--r--source/blender/blenkernel/intern/material.c85
-rw-r--r--source/blender/blenkernel/intern/mesh.c4
-rw-r--r--source/blender/blenlib/intern/BLI_args.c6
-rw-r--r--source/blender/blenlib/intern/pbvh.c83
-rw-r--r--source/blender/blenloader/intern/readfile.c5
-rw-r--r--source/blender/editors/curve/editcurve.c16
-rw-r--r--source/blender/editors/gpencil/gpencil_paint.c12
-rw-r--r--source/blender/editors/interface/interface_anim.c24
-rw-r--r--source/blender/editors/interface/resources.c13
-rw-r--r--source/blender/editors/object/object_relations.c6
-rw-r--r--source/blender/editors/screen/screen_ops.c2
-rw-r--r--source/blender/editors/sculpt_paint/paint_image.c26
-rw-r--r--source/blender/editors/sculpt_paint/paint_stroke.c7
-rw-r--r--source/blender/editors/space_image/image_intern.h1
-rw-r--r--source/blender/editors/space_image/image_ops.c54
-rw-r--r--source/blender/editors/space_image/space_image.c4
-rw-r--r--source/blender/editors/space_view3d/view3d_draw.c102
-rw-r--r--source/blender/editors/space_view3d/view3d_edit.c630
-rw-r--r--source/blender/editors/space_view3d/view3d_fly.c480
-rw-r--r--source/blender/editors/space_view3d/view3d_header.c3
-rw-r--r--source/blender/editors/space_view3d/view3d_intern.h5
-rw-r--r--source/blender/editors/space_view3d/view3d_ops.c24
-rw-r--r--source/blender/editors/space_view3d/view3d_select.c6
-rw-r--r--source/blender/editors/transform/transform.c129
-rw-r--r--source/blender/editors/transform/transform_ops.c6
-rw-r--r--source/blender/makesdna/DNA_userdef_types.h29
-rw-r--r--source/blender/makesdna/DNA_view3d_types.h13
-rw-r--r--source/blender/makesrna/intern/rna_ID.c4
-rw-r--r--source/blender/makesrna/intern/rna_action.c5
-rw-r--r--source/blender/makesrna/intern/rna_userdef.c33
-rw-r--r--source/blender/makesrna/intern/rna_wm.c88
-rw-r--r--source/blender/makesrna/intern/rna_wm_api.c2
-rw-r--r--source/blender/modifiers/intern/MOD_uvproject.c2
-rw-r--r--source/blender/python/intern/bpy_props.c26
-rw-r--r--source/blender/python/intern/bpy_rna.c14
-rw-r--r--source/blender/windowmanager/WM_types.h20
-rw-r--r--source/blender/windowmanager/intern/wm_event_system.c69
-rw-r--r--source/blender/windowmanager/intern/wm_init_exit.c2
-rw-r--r--source/blender/windowmanager/intern/wm_operators.c69
-rw-r--r--source/blender/windowmanager/intern/wm_window.c4
-rw-r--r--source/blender/windowmanager/wm_event_types.h56
-rw-r--r--source/gameengine/Ketsji/KX_PyConstraintBinding.cpp285
114 files changed, 3857 insertions, 1827 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index d4489a8c76b..d95cbb6e536 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -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)
diff --git a/SConstruct b/SConstruct
index 053f414c954..e27f8eae367 100644
--- a/SConstruct
+++ b/SConstruct
@@ -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
index 00000000000..206f3611ed6
--- /dev/null
+++ b/build_files/cmake/Modules/FindSpacenav.cmake
@@ -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
+)
diff --git a/build_files/cmake/cmake_consistency_check.py b/build_files/cmake/cmake_consistency_check.py
index ba71603b007..880cb582f1e 100755
--- a/build_files/cmake/cmake_consistency_check.py
+++ b/build_files/cmake/cmake_consistency_check.py
@@ -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())]
diff --git a/build_files/cmake/cmake_netbeans_project.py b/build_files/cmake/cmake_netbeans_project.py
index 8060574580c..02dfec06c0b 100755
--- a/build_files/cmake/cmake_netbeans_project.py
+++ b/build_files/cmake/cmake_netbeans_project.py
@@ -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,
)
diff --git a/build_files/cmake/cmake_qtcreator_project.py b/build_files/cmake/cmake_qtcreator_project.py
index d8993c3197a..2a2774c9944 100755
--- a/build_files/cmake/cmake_qtcreator_project.py
+++ b/build_files/cmake/cmake_qtcreator_project.py
@@ -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,
diff --git a/build_files/cmake/macros.cmake b/build_files/cmake/macros.cmake
index 34301458a06..ed200abd419 100644
--- a/build_files/cmake/macros.cmake
+++ b/build_files/cmake/macros.cmake
@@ -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()
diff --git a/build_files/scons/config/darwin-config.py b/build_files/scons/config/darwin-config.py
index 0c51476a6d0..4a4bc4acd67 100644
--- a/build_files/scons/config/darwin-config.py
+++ b/build_files/scons/config/darwin-config.py
@@ -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']
diff --git a/build_files/scons/config/linux2-config.py b/build_files/scons/config/linux2-config.py
index 328cd4cdb28..6fb9090b022 100644
--- a/build_files/scons/config/linux2-config.py
+++ b/build_files/scons/config/linux2-config.py
@@ -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)
diff --git a/build_files/scons/config/win32-vc-config.py b/build_files/scons/config/win32-vc-config.py
index 89b246cb39f..5a91852052d 100644
--- a/build_files/scons/config/win32-vc-config.py
+++ b/build_files/scons/config/win32-vc-config.py
@@ -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']
diff --git a/build_files/scons/config/win64-vc-config.py b/build_files/scons/config/win64-vc-config.py
index 67db1c441d7..6717f12fcf8 100644
--- a/build_files/scons/config/win64-vc-config.py
+++ b/build_files/scons/config/win64-vc-config.py
@@ -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']
diff --git a/build_files/scons/tools/btools.py b/build_files/scons/tools/btools.py
index 677ddab8db5..a96bf8ce4cc 100644
--- a/build_files/scons/tools/btools.py
+++ b/build_files/scons/tools/btools.py
@@ -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', []),
diff --git a/doc/python_api/rst/bge.constraints.rst b/doc/python_api/rst/bge.constraints.rst
index 882bbc39b9f..12ce8617457 100644
--- a/doc/python_api/rst/bge.constraints.rst
+++ b/doc/python_api/rst/bge.constraints.rst
@@ -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
diff --git a/doc/python_api/rst/bge.events.rst b/doc/python_api/rst/bge.events.rst
index cc76ecded85..074e928f0d8 100644
--- a/doc/python_api/rst/bge.events.rst
+++ b/doc/python_api/rst/bge.events.rst
@@ -1,6 +1,6 @@
-Game Engine bge.events Module
-=============================
+Game Keys (bge.events)
+======================
*****
Intro
diff --git a/doc/python_api/rst/bge.logic.rst b/doc/python_api/rst/bge.logic.rst
index f7163ea928e..128f87f76bd 100644
--- a/doc/python_api/rst/bge.logic.rst
+++ b/doc/python_api/rst/bge.logic.rst
@@ -1,6 +1,7 @@
-Game Engine bge.logic Module
-============================
+Game Logic (bge.logic)
+======================
+
*****
Intro
*****
diff --git a/doc/python_api/rst/bge.render.rst b/doc/python_api/rst/bge.render.rst
index 9f17455601b..10514049a8a 100644
--- a/doc/python_api/rst/bge.render.rst
+++ b/doc/python_api/rst/bge.render.rst
@@ -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
diff --git a/doc/python_api/rst/bge.texture.rst b/doc/python_api/rst/bge.texture.rst
index 996f79a313a..f3e9f98dded 100644
--- a/doc/python_api/rst/bge.texture.rst
+++ b/doc/python_api/rst/bge.texture.rst
@@ -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
diff --git a/doc/python_api/rst/bge.types.rst b/doc/python_api/rst/bge.types.rst
index 367f6470f19..d1fc8593e42 100644
--- a/doc/python_api/rst/bge.types.rst
+++ b/doc/python_api/rst/bge.types.rst
@@ -1,6 +1,6 @@
-Game Engine bge.types Module
-=============================
+Game Types (bge.types)
+======================
.. module:: bge.types
diff --git a/doc/python_api/rst/bgl.rst b/doc/python_api/rst/bgl.rst
index 76b7442f2c5..236bfafb295 100644
--- a/doc/python_api/rst/bgl.rst
+++ b/doc/python_api/rst/bgl.rst
@@ -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.
-
diff --git a/doc/python_api/sphinx_doc_gen.py b/doc/python_api/sphinx_doc_gen.py
index 6b514cf9eb1..f8561c719bc 100644
--- a/doc/python_api/sphinx_doc_gen.py
+++ b/doc/python_api/sphinx_doc_gen.py
@@ -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
diff --git a/intern/ghost/CMakeLists.txt b/intern/ghost/CMakeLists.txt
index ccd763ef42c..2180ddbe567 100644
--- a/intern/ghost/CMakeLists.txt
+++ b/intern/ghost/CMakeLists.txt
@@ -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}")
diff --git a/intern/ghost/GHOST_C-api.h b/intern/ghost/GHOST_C-api.h
index 75837239c4a..a315dfa85e9 100644
--- a/intern/ghost/GHOST_C-api.h
+++ b/intern/ghost/GHOST_C-api.h
@@ -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
diff --git a/intern/ghost/GHOST_ISystem.h b/intern/ghost/GHOST_ISystem.h
index 69e10070be5..015ae780bea 100644
--- a/intern/ghost/GHOST_ISystem.h
+++ b/intern/ghost/GHOST_ISystem.h
@@ -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
***************************************************************************************/
diff --git a/intern/ghost/GHOST_Types.h b/intern/ghost/GHOST_Types.h
index 6a4da5c9d38..f24ab00acd3 100644
--- a/intern/ghost/GHOST_Types.h
+++ b/intern/ghost/GHOST_Types.h
@@ -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. */
diff --git a/intern/ghost/SConscript b/intern/ghost/SConscript
index c65ec58a97b..45a1f44d579 100644
--- a/intern/ghost/SConscript
+++ b/intern/ghost/SConscript
@@ -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
diff --git a/intern/ghost/intern/GHOST_C-api.cpp b/intern/ghost/intern/GHOST_C-api.cpp
index 7ba8d7db411..6332d72a42f 100644
--- a/intern/ghost/intern/GHOST_C-api.cpp
+++ b/intern/ghost/intern/GHOST_C-api.cpp
@@ -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;
diff --git a/intern/ghost/intern/GHOST_DisplayManagerWin32.cpp b/intern/ghost/intern/GHOST_DisplayManagerWin32.cpp
index 30d9aa31207..47f748927ab 100644
--- a/intern/ghost/intern/GHOST_DisplayManagerWin32.cpp
+++ b/intern/ghost/intern/GHOST_DisplayManagerWin32.cpp
@@ -35,8 +35,11 @@
#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>
diff --git a/intern/ghost/intern/GHOST_DropTargetWin32.cpp b/intern/ghost/intern/GHOST_DropTargetWin32.cpp
index 2e77da42b31..99990a46c2a 100644
--- a/intern/ghost/intern/GHOST_DropTargetWin32.cpp
+++ b/intern/ghost/intern/GHOST_DropTargetWin32.cpp
@@ -33,6 +33,7 @@
#include "GHOST_Debug.h"
#include "GHOST_DropTargetWin32.h"
+#include <ShellApi.h>
#ifdef GHOST_DEBUG
// utility
diff --git a/intern/ghost/intern/GHOST_DropTargetWin32.h b/intern/ghost/intern/GHOST_DropTargetWin32.h
index 0a553b6701e..980e9f9fe9b 100644
--- a/intern/ghost/intern/GHOST_DropTargetWin32.h
+++ b/intern/ghost/intern/GHOST_DropTargetWin32.h
@@ -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"
diff --git a/intern/ghost/intern/GHOST_EventManager.cpp b/intern/ghost/intern/GHOST_EventManager.cpp
index 1483555c362..86b87973038 100644
--- a/intern/ghost/intern/GHOST_EventManager.cpp
+++ b/intern/ghost/intern/GHOST_EventManager.cpp
@@ -42,7 +42,7 @@
#include "GHOST_EventManager.h"
#include <algorithm>
#include "GHOST_Debug.h"
-
+#include <stdio.h> // [mce] temp debug
GHOST_EventManager::GHOST_EventManager()
{
diff --git a/intern/ghost/intern/GHOST_EventNDOF.h b/intern/ghost/intern/GHOST_EventNDOF.h
index 70861b08fc6..394aff0493f 100644
--- a/intern/ghost/intern/GHOST_EventNDOF.h
+++ b/intern/ghost/intern/GHOST_EventNDOF.h
@@ -19,11 +19,6 @@
*
* ***** END GPL LICENSE BLOCK *****
*/
-
-/** \file ghost/intern/GHOST_EventNDOF.h
- * \ingroup GHOST
- */
-
#ifndef _GHOST_EVENT_NDOF_H_
@@ -31,32 +26,33 @@
#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_
-
diff --git a/intern/ghost/intern/GHOST_NDOFManager.cpp b/intern/ghost/intern/GHOST_NDOFManager.cpp
index dae6cb5b544..5a0f14c85a3 100644
--- a/intern/ghost/intern/GHOST_NDOFManager.cpp
+++ b/intern/ghost/intern/GHOST_NDOFManager.cpp
@@ -1,4 +1,6 @@
/*
+ * $Id$
+ *
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
@@ -15,122 +17,472 @@
* 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;
+ }
diff --git a/intern/ghost/intern/GHOST_NDOFManager.h b/intern/ghost/intern/GHOST_NDOFManager.h
index c9e09370e09..5bdbe7a6833 100644
--- a/intern/ghost/intern/GHOST_NDOFManager.h
+++ b/intern/ghost/intern/GHOST_NDOFManager.h
@@ -1,4 +1,6 @@
/*
+ * $Id$
+ *
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
@@ -15,43 +17,144 @@
* 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
index 00000000000..27397b711b7
--- /dev/null
+++ b/intern/ghost/intern/GHOST_NDOFManagerCocoa.h
@@ -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
index 00000000000..07811c563ec
--- /dev/null
+++ b/intern/ghost/intern/GHOST_NDOFManagerCocoa.mm
@@ -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
index 00000000000..099b163edeb
--- /dev/null
+++ b/intern/ghost/intern/GHOST_NDOFManagerWin32.cpp
@@ -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
index 00000000000..31f7e074cd6
--- /dev/null
+++ b/intern/ghost/intern/GHOST_NDOFManagerWin32.h
@@ -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
index 00000000000..8043af2760e
--- /dev/null
+++ b/intern/ghost/intern/GHOST_NDOFManagerX11.cpp
@@ -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
index 00000000000..175041b21e9
--- /dev/null
+++ b/intern/ghost/intern/GHOST_NDOFManagerX11.h
@@ -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
+
diff --git a/intern/ghost/intern/GHOST_System.cpp b/intern/ghost/intern/GHOST_System.cpp
index cb3e97fc574..64c2c218a07 100644
--- a/intern/ghost/intern/GHOST_System.cpp
+++ b/intern/ghost/intern/GHOST_System.cpp
@@ -46,7 +46,13 @@
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;
}
diff --git a/intern/ghost/intern/GHOST_System.h b/intern/ghost/intern/GHOST_System.h
index b5c64bfceb6..c1e70916be6 100644
--- a/intern/ghost/intern/GHOST_System.h
+++ b/intern/ghost/intern/GHOST_System.h
@@ -191,25 +191,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_
diff --git a/intern/ghost/intern/GHOST_SystemCocoa.h b/intern/ghost/intern/GHOST_SystemCocoa.h
index ce777358389..d20aed63f42 100644
--- a/intern/ghost/intern/GHOST_SystemCocoa.h
+++ b/intern/ghost/intern/GHOST_SystemCocoa.h
@@ -221,6 +221,11 @@ public:
GHOST_TSuccess handleApplicationBecomeActiveEvent();
/**
+ * External objects should call this when they send an event outside processEvents.
+ */
+ void notifyExternalEventProcessed();
+
+ /**
* @see GHOST_ISystem
*/
int toggleConsole(int action) { return 0; }
@@ -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 */
diff --git a/intern/ghost/intern/GHOST_SystemCocoa.mm b/intern/ghost/intern/GHOST_SystemCocoa.mm
index bb3d6e3aee3..17f0f2d6ecd 100644
--- a/intern/ghost/intern/GHOST_SystemCocoa.mm
+++ b/intern/ghost/intern/GHOST_SystemCocoa.mm
@@ -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;
diff --git a/intern/ghost/intern/GHOST_SystemPathsWin32.cpp b/intern/ghost/intern/GHOST_SystemPathsWin32.cpp
index becccc2c29f..523d119c7e7 100644
--- a/intern/ghost/intern/GHOST_SystemPathsWin32.cpp
+++ b/intern/ghost/intern/GHOST_SystemPathsWin32.cpp
@@ -32,12 +32,9 @@
#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__)
diff --git a/intern/ghost/intern/GHOST_SystemPathsWin32.h b/intern/ghost/intern/GHOST_SystemPathsWin32.h
index 67cc2140e0e..3de7bbf934e 100644
--- a/intern/ghost/intern/GHOST_SystemPathsWin32.h
+++ b/intern/ghost/intern/GHOST_SystemPathsWin32.h
@@ -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"
diff --git a/intern/ghost/intern/GHOST_SystemWin32.cpp b/intern/ghost/intern/GHOST_SystemWin32.cpp
index 4f0e7d8e604..c985c6dd0a6 100644
--- a/intern/ghost/intern/GHOST_SystemWin32.cpp
+++ b/intern/ghost/intern/GHOST_SystemWin32.cpp
@@ -39,22 +39,20 @@
* @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
@@ -64,48 +62,17 @@
#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
@@ -158,18 +125,25 @@
#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
diff --git a/intern/ghost/intern/GHOST_SystemWin32.h b/intern/ghost/intern/GHOST_SystemWin32.h
index 729ad56d875..c5dff27dace 100644
--- a/intern/ghost/intern/GHOST_SystemWin32.h
+++ b/intern/ghost/intern/GHOST_SystemWin32.h
@@ -38,7 +38,10 @@
#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"
@@ -46,95 +49,6 @@
# 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.
@@ -413,11 +335,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
* 1 - Shows
@@ -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_
-
diff --git a/intern/ghost/intern/GHOST_SystemX11.cpp b/intern/ghost/intern/GHOST_SystemX11.cpp
index dd296fa979c..105f71b514f 100644
--- a/intern/ghost/intern/GHOST_SystemX11.cpp
+++ b/intern/ghost/intern/GHOST_SystemX11.cpp
@@ -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"
@@ -79,19 +78,6 @@
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(
diff --git a/intern/ghost/intern/GHOST_SystemX11.h b/intern/ghost/intern/GHOST_SystemX11.h
index 746cd4ebdf4..845243f92e5 100644
--- a/intern/ghost/intern/GHOST_SystemX11.h
+++ b/intern/ghost/intern/GHOST_SystemX11.h
@@ -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,
diff --git a/intern/ghost/intern/GHOST_TaskbarWin32.h b/intern/ghost/intern/GHOST_TaskbarWin32.h
index ef9ebdf5860..eddff8bb91b 100644
--- a/intern/ghost/intern/GHOST_TaskbarWin32.h
+++ b/intern/ghost/intern/GHOST_TaskbarWin32.h
@@ -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
diff --git a/intern/ghost/intern/GHOST_WindowWin32.h b/intern/ghost/intern/GHOST_WindowWin32.h
index 4055c3acf56..70914d9d2ef 100644
--- a/intern/ghost/intern/GHOST_WindowWin32.h
+++ b/intern/ghost/intern/GHOST_WindowWin32.h
@@ -39,19 +39,11 @@
#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>
diff --git a/release/scripts/modules/addon_utils.py b/release/scripts/modules/addon_utils.py
index 5aed0581ea9..22936f4c209 100644
--- a/release/scripts/modules/addon_utils.py
+++ b/release/scripts/modules/addon_utils.py
@@ -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
diff --git a/release/scripts/modules/bpy/__init__.py b/release/scripts/modules/bpy/__init__.py
index 0add2b3e6cd..a43b42e49a1 100644
--- a/release/scripts/modules/bpy/__init__.py
+++ b/release/scripts/modules/bpy/__init__.py
@@ -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:
diff --git a/release/scripts/modules/bpy/path.py b/release/scripts/modules/bpy/path.py
index eb1a5ffc455..a01745fec0a 100644
--- a/release/scripts/modules/bpy/path.py
+++ b/release/scripts/modules/bpy/path.py
@@ -16,26 +16,44 @@
#
# ##### 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
diff --git a/release/scripts/modules/bpy/utils.py b/release/scripts/modules/bpy/utils.py
index 57d3e6dd703..a6304378cc4 100644
--- a/release/scripts/modules/bpy/utils.py
+++ b/release/scripts/modules/bpy/utils.py
@@ -16,13 +16,33 @@
#
# ##### 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:
diff --git a/release/scripts/modules/bpy_extras/__init__.py b/release/scripts/modules/bpy_extras/__init__.py
index 06d41fa670e..d853d5fda10 100644
--- a/release/scripts/modules/bpy_extras/__init__.py
+++ b/release/scripts/modules/bpy_extras/__init__.py
@@ -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",
-)
+ )
diff --git a/release/scripts/modules/bpy_extras/image_utils.py b/release/scripts/modules/bpy_extras/image_utils.py
index e56c1c651c4..eab75c3bd16 100644
--- a/release/scripts/modules/bpy_extras/image_utils.py
+++ b/release/scripts/modules/bpy_extras/image_utils.py
@@ -16,11 +16,11 @@
#
# ##### 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, )
diff --git a/release/scripts/modules/bpy_extras/io_utils.py b/release/scripts/modules/bpy_extras/io_utils.py
index 0a3f1392653..f476b371d0c 100644
--- a/release/scripts/modules/bpy_extras/io_utils.py
+++ b/release/scripts/modules/bpy_extras/io_utils.py
@@ -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
diff --git a/release/scripts/modules/bpy_extras/mesh_utils.py b/release/scripts/modules/bpy_extras/mesh_utils.py
index ecd620ff2c9..f9400674138 100644
--- a/release/scripts/modules/bpy_extras/mesh_utils.py
+++ b/release/scripts/modules/bpy_extras/mesh_utils.py
@@ -26,7 +26,7 @@ __all__ = (
"edge_loops_from_edges",
"ngon_tesselate",
"face_random_points",
-)
+ )
def mesh_linked_faces(mesh):
diff --git a/release/scripts/modules/bpy_extras/object_utils.py b/release/scripts/modules/bpy_extras/object_utils.py
index 51a8d4b5e23..790f5ba48cb 100644
--- a/release/scripts/modules/bpy_extras/object_utils.py
+++ b/release/scripts/modules/bpy_extras/object_utils.py
@@ -16,12 +16,12 @@
#
# ##### 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:
diff --git a/release/scripts/modules/bpy_extras/view3d_utils.py b/release/scripts/modules/bpy_extras/view3d_utils.py
index 5796abce72c..26325633a05 100644
--- a/release/scripts/modules/bpy_extras/view3d_utils.py
+++ b/release/scripts/modules/bpy_extras/view3d_utils.py
@@ -16,13 +16,13 @@
#
# ##### 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):
diff --git a/release/scripts/modules/keyingsets_utils.py b/release/scripts/modules/keyingsets_utils.py
index dc61ce2a4af..03400edc904 100644
--- a/release/scripts/modules/keyingsets_utils.py
+++ b/release/scripts/modules/keyingsets_utils.py
@@ -16,14 +16,14 @@
#
# ##### 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
diff --git a/release/scripts/startup/bl_ui/space_userpref.py b/release/scripts/startup/bl_ui/space_userpref.py
index fed776a23e9..411060a302c 100644
--- a/release/scripts/startup/bl_ui/space_userpref.py
+++ b/release/scripts/startup/bl_ui/space_userpref.py
@@ -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:
diff --git a/release/scripts/startup/bl_ui/space_userpref_keymap.py b/release/scripts/startup/bl_ui/space_userpref_keymap.py
index 85764c55304..8fed3a934d9 100644
--- a/release/scripts/startup/bl_ui/space_userpref_keymap.py
+++ b/release/scripts/startup/bl_ui/space_userpref_keymap.py
@@ -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':
diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py
index c1973bc8555..fdd4833f096 100644
--- a/release/scripts/startup/bl_ui/space_view3d.py
+++ b/release/scripts/startup/bl_ui/space_view3d.py
@@ -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"
diff --git a/release/scripts/templates/addon_add_object.py b/release/scripts/templates/addon_add_object.py
index 67e033271f4..98517fd97a0 100644
--- a/release/scripts/templates/addon_add_object.py
+++ b/release/scripts/templates/addon_add_object.py
@@ -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):
diff --git a/source/blender/blenkernel/BKE_curve.h b/source/blender/blenkernel/BKE_curve.h
index 0491116d199..557ce417b14 100644
--- a/source/blender/blenkernel/BKE_curve.h
+++ b/source/blender/blenkernel/BKE_curve.h
@@ -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
diff --git a/source/blender/blenkernel/BKE_global.h b/source/blender/blenkernel/BKE_global.h
index d21b0428d76..17876c6ec9d 100644
--- a/source/blender/blenkernel/BKE_global.h
+++ b/source/blender/blenkernel/BKE_global.h
@@ -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
-
-
diff --git a/source/blender/blenkernel/BKE_material.h b/source/blender/blenkernel/BKE_material.h
index c445408609c..88965d12e4a 100644
--- a/source/blender/blenkernel/BKE_material.h
+++ b/source/blender/blenkernel/BKE_material.h
@@ -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 */
diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c
index d9c98bc0200..62b8830de20 100644
--- a/source/blender/blenkernel/intern/DerivedMesh.c
+++ b/source/blender/blenkernel/intern/DerivedMesh.c
@@ -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)
diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c
index 202a3f28d9a..eb364af6ff8 100644
--- a/source/blender/blenkernel/intern/curve.c
+++ b/source/blender/blenkernel/intern/curve.c
@@ -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--;
+ }
+ }
+ }
+}
diff --git a/source/blender/blenkernel/intern/key.c b/source/blender/blenkernel/intern/key.c
index 50c120a3ec1..2aef5b39c71 100644
--- a/source/blender/blenkernel/intern/key.c
+++ b/source/blender/blenkernel/intern/key.c
@@ -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]);
}
}
diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c
index 3f01c55e935..9c455e84109 100644
--- a/source/blender/blenkernel/intern/material.c
+++ b/source/blender/blenkernel/intern/material.c
@@ -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);
}
diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c
index 45a60b842a7..32819226361 100644
--- a/source/blender/blenkernel/intern/mesh.c
+++ b/source/blender/blenkernel/intern/mesh.c
@@ -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--;
}
diff --git a/source/blender/blenlib/intern/BLI_args.c b/source/blender/blenlib/intern/BLI_args.c
index 7bc93a3d3a0..5f31565d65b 100644
--- a/source/blender/blenlib/intern/BLI_args.c
+++ b/source/blender/blenlib/intern/BLI_args.c
@@ -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;
}
}
diff --git a/source/blender/blenlib/intern/pbvh.c b/source/blender/blenlib/intern/pbvh.c
index 85d79ae3b85..0613765b868 100644
--- a/source/blender/blenlib/intern/pbvh.c
+++ b/source/blender/blenlib/intern/pbvh.c
@@ -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 {
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index 18b461eb31d..1737b44a56f 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -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;
diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c
index 06d88b16fa8..210f36ca074 100644
--- a/source/blender/editors/curve/editcurve.c
+++ b/source/blender/editors/curve/editcurve.c
@@ -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;
}
diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c
index f4da734473d..28a54b20277 100644
--- a/source/blender/editors/gpencil/gpencil_paint.c
+++ b/source/blender/editors/gpencil/gpencil_paint.c
@@ -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) */
diff --git a/source/blender/editors/interface/interface_anim.c b/source/blender/editors/interface/interface_anim.c
index 2e172c496a3..1113f90a652 100644
--- a/source/blender/editors/interface/interface_anim.c
+++ b/source/blender/editors/interface/interface_anim.c
@@ -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
*/
diff --git a/source/blender/editors/interface/resources.c b/source/blender/editors/interface/resources.c
index 1aa2fb391db..adabfe5f230 100644
--- a/source/blender/editors/interface/resources.c
+++ b/source/blender/editors/interface/resources.c
@@ -1,6 +1,3 @@
-/** \file blender/editors/interface/resources.c
- * \ingroup edinterface
- */
/*
* $Id$
*
@@ -33,6 +30,10 @@
* ***** 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 */
diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c
index ab9c69988fe..ce1f47c1b7b 100644
--- a/source/blender/editors/object/object_relations.c
+++ b/source/blender/editors/object/object_relations.c
@@ -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;
}
diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c
index 68326edfb11..1410331700f 100644
--- a/source/blender/editors/screen/screen_ops.c
+++ b/source/blender/editors/screen/screen_ops.c
@@ -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)
diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c
index c9a6aa87cd0..32004fd4525 100644
--- a/source/blender/editors/sculpt_paint/paint_image.c
+++ b/source/blender/editors/sculpt_paint/paint_image.c
@@ -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);
}
}
diff --git a/source/blender/editors/sculpt_paint/paint_stroke.c b/source/blender/editors/sculpt_paint/paint_stroke.c
index 7ddf5dff000..09873566d4a 100644
--- a/source/blender/editors/sculpt_paint/paint_stroke.c
+++ b/source/blender/editors/sculpt_paint/paint_stroke.c
@@ -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;
diff --git a/source/blender/editors/space_image/image_intern.h b/source/blender/editors/space_image/image_intern.h
index e9e77ddf430..399157da85c 100644
--- a/source/blender/editors/space_image/image_intern.h
+++ b/source/blender/editors/space_image/image_intern.h
@@ -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);
diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c
index d5515bd1cf8..6e84c1a7f0c 100644
--- a/source/blender/editors/space_image/image_ops.c
+++ b/source/blender/editors/space_image/image_ops.c
@@ -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.
diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c
index 2e9544f5d20..afab4ede229 100644
--- a/source/blender/editors/space_image/space_image.c
+++ b/source/blender/editors/space_image/space_image.c
@@ -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);
diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c
index d2ff6eef097..6e3f6549ba3 100644
--- a/source/blender/editors/space_view3d/view3d_draw.c
+++ b/source/blender/editors/space_view3d/view3d_draw.c
@@ -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);
diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c
index d563c07baf3..e6fd9e8867b 100644
--- a/source/blender/editors/space_view3d/view3d_edit.c
+++ b/source/blender/editors/space_view3d/view3d_edit.c
@@ -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 *UNUSED(op), wmEvent *event)
+// -- "pan" navigation
+// -- zoom or dolly?
+{
+ RegionView3D* rv3d = CTX_wm_region_view3d(C);
+ wmNDOFMotionData* ndof = (wmNDOFMotionData*) event->customdata;
+
+ rv3d->rot_angle = 0.f; // we're panning here! so erase any leftover rotation from other operators
+
+ if (ndof->progress != P_FINISHING) {
+ const float dt = ndof->dt;
+ float view_inv[4];
+#if 0 // ------------------------------------------- zoom with Z
+ // tune these until everything feels right
+ const float zoom_sensitivity = 1.f;
+ const float pan_sensitivity = 1.f;
+
+ float pan_vec[3] = {
+ ndof->tx, ndof->ty, 0
+ };
+
+ // "zoom in" or "translate"? depends on zoom mode in user settings?
+ if (ndof->tz) {
+ float zoom_distance = zoom_sensitivity * rv3d->dist * dt * ndof->tz;
+ rv3d->dist += zoom_distance;
+ }
+
+ mul_v3_fl(pan_vec, pan_sensitivity * rv3d->dist * dt);
+#else // ------------------------------------------------------- dolly with Z
+ float speed = 10.f; // blender units per second
+ // ^^ this is ok for default cube scene, but should scale with.. something
+
+ // tune these until everything feels right
+ const float forward_sensitivity = 1.f;
+ const float vertical_sensitivity = 0.4f;
+ const float lateral_sensitivity = 0.6f;
+
+ float pan_vec[3] = {lateral_sensitivity * ndof->tvec[0],
+ vertical_sensitivity * ndof->tvec[1],
+ forward_sensitivity * ndof->tvec[2]
+ };
+
+ mul_v3_fl(pan_vec, speed * dt);
+#endif
+ /* 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);
+ }
+
+ ED_region_tag_redraw(CTX_wm_region(C));
+
+ return OPERATOR_FINISHED;
+}
+
+void VIEW3D_OT_ndof_pan(struct wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "NDOF Pan View";
+ ot->description = "Position your viewpoint with the 3D mouse.";
+ ot->idname = "VIEW3D_OT_ndof_pan";
+
+ /* api callbacks */
+ ot->invoke = ndof_pan_invoke;
+ ot->poll = ED_operator_view3d_active;
+
+ /* flags */
+ ot->flag = 0;
+}
+
/* ************************ viewmove ******************************** */
@@ -3195,398 +3433,6 @@ int ED_view3d_autodist_depth_seg(struct ARegion *ar, const int mval_sta[2], cons
return (*depth==FLT_MAX) ? 0:1;
}
-/* ********************* NDOF ************************ */
-/* note: this code is confusing and unclear... (ton) */
-/* **************************************************** */
-
-// ndof scaling will be moved to user setting.
-// In the mean time this is just a place holder.
-
-// Note: scaling in the plugin and ghostwinlay.c
-// should be removed. With driver default setting,
-// each axis returns approx. +-200 max deflection.
-
-// The values I selected are based on the older
-// polling i/f. With event i/f, the sensistivity
-// can be increased for improved response from
-// small deflections of the device input.
-
-
-// lukep notes : i disagree on the range.
-// the normal 3Dconnection driver give +/-400
-// on defaut range in other applications
-// and up to +/- 1000 if set to maximum
-// because i remove the scaling by delta,
-// which was a bad idea as it depend of the system
-// speed and os, i changed the scaling values, but
-// those are still not ok
-
-#if 0
-static float ndof_axis_scale[6] = {
- +0.01, // Tx
- +0.01, // Tz
- +0.01, // Ty
- +0.0015, // Rx
- +0.0015, // Rz
- +0.0015 // Ry
-};
-
-static void filterNDOFvalues(float *sbval)
-{
- int i=0;
- float max = 0.0;
-
- for (i =0; i<6;i++)
- if (fabs(sbval[i]) > max)
- max = fabs(sbval[i]);
- for (i =0; i<6;i++)
- if (fabs(sbval[i]) != max )
- sbval[i]=0.0;
-}
-
-// statics for controlling rv3d->dist corrections.
-// viewmoveNDOF zeros and adjusts rv3d->ofs.
-// viewmove restores based on dz_flag state.
-
-int dz_flag = 0;
-float m_dist;
-
-void viewmoveNDOFfly(ARegion *ar, View3D *v3d, int UNUSED(mode))
-{
- RegionView3D *rv3d= ar->regiondata;
- int i;
- float phi;
- float dval[7];
- // static fval[6] for low pass filter; device input vector is dval[6]
- static float fval[6];
- float tvec[3],rvec[3];
- float q1[4];
- float mat[3][3];
- float upvec[3];
-
-
- /*----------------------------------------------------
- * sometimes this routine is called from headerbuttons
- * viewmove needs to refresh the screen
- */
-// XXX areawinset(ar->win);
-
-
- // fetch the current state of the ndof device
-// XXX getndof(dval);
-
- if (v3d->ndoffilter)
- filterNDOFvalues(fval);
-
- // Scale input values
-
-// if(dval[6] == 0) return; // guard against divide by zero
-
- for(i=0;i<6;i++) {
-
- // user scaling
- dval[i] = dval[i] * ndof_axis_scale[i];
- }
-
-
- // low pass filter with zero crossing reset
-
- for(i=0;i<6;i++) {
- if((dval[i] * fval[i]) >= 0)
- dval[i] = (fval[i] * 15 + dval[i]) / 16;
- else
- fval[i] = 0;
- }
-
-
- // force perspective mode. This is a hack and is
- // incomplete. It doesn't actually effect the view
- // until the first draw and doesn't update the menu
- // to reflect persp mode.
-
- rv3d->persp = RV3D_PERSP;
-
-
- // Correct the distance jump if rv3d->dist != 0
-
- // This is due to a side effect of the original
- // mouse view rotation code. The rotation point is
- // set a distance in front of the viewport to
- // make rotating with the mouse look better.
- // The distance effect is written at a low level
- // in the view management instead of the mouse
- // view function. This means that all other view
- // movement devices must subtract this from their
- // view transformations.
-
- if(rv3d->dist != 0.0) {
- dz_flag = 1;
- m_dist = rv3d->dist;
- upvec[0] = upvec[1] = 0;
- upvec[2] = rv3d->dist;
- copy_m3_m4(mat, rv3d->viewinv);
- mul_m3_v3(mat, upvec);
- sub_v3_v3(rv3d->ofs, upvec);
- rv3d->dist = 0.0;
- }
-
-
- // Apply rotation
- // Rotations feel relatively faster than translations only in fly mode, so
- // we have no choice but to fix that here (not in the plugins)
- rvec[0] = -0.5 * dval[3];
- rvec[1] = -0.5 * dval[4];
- rvec[2] = -0.5 * dval[5];
-
- // rotate device x and y by view z
-
- copy_m3_m4(mat, rv3d->viewinv);
- mat[2][2] = 0.0f;
- mul_m3_v3(mat, rvec);
-
- // rotate the view
-
- phi = normalize_v3(rvec);
- if(phi != 0) {
- axis_angle_to_quat(q1,rvec,phi);
- mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, q1);
- }
-
-
- // Apply translation
-
- tvec[0] = dval[0];
- tvec[1] = dval[1];
- tvec[2] = -dval[2];
-
- // the next three lines rotate the x and y translation coordinates
- // by the current z axis angle
-
- copy_m3_m4(mat, rv3d->viewinv);
- mat[2][2] = 0.0f;
- mul_m3_v3(mat, tvec);
-
- // translate the view
-
- sub_v3_v3(rv3d->ofs, tvec);
-
-
- /*----------------------------------------------------
- * refresh the screen XXX
- */
-
- // update render preview window
-
-// XXX BIF_view3d_previewrender_signal(ar, PR_DBASE|PR_DISPRECT);
-}
-
-void viewmoveNDOF(Scene *scene, ARegion *ar, View3D *v3d, int UNUSED(mode))
-{
- RegionView3D *rv3d= ar->regiondata;
- float fval[7];
- float dvec[3];
- float sbadjust = 1.0f;
- float len;
- short use_sel = 0;
- Object *ob = OBACT;
- float m[3][3];
- float m_inv[3][3];
- float xvec[3] = {1,0,0};
- float yvec[3] = {0,-1,0};
- float zvec[3] = {0,0,1};
- float phi;
- float q1[4];
- float obofs[3];
- float reverse;
- //float diff[4];
- float d, curareaX, curareaY;
- float mat[3][3];
- float upvec[3];
-
- /* Sensitivity will control how fast the view rotates. The value was
- * obtained experimentally by tweaking until the author didn't get dizzy watching.
- * Perhaps this should be a configurable user parameter.
- */
- float psens = 0.005f * (float) U.ndof_pan; /* pan sensitivity */
- float rsens = 0.005f * (float) U.ndof_rotate; /* rotate sensitivity */
- float zsens = 0.3f; /* zoom sensitivity */
-
- const float minZoom = -30.0f;
- const float maxZoom = 300.0f;
-
- //reset view type
- rv3d->view = 0;
-//printf("passing here \n");
-//
- if (scene->obedit==NULL && ob && !(ob->mode & OB_MODE_POSE)) {
- use_sel = 1;
- }
-
- if((dz_flag)||rv3d->dist==0) {
- dz_flag = 0;
- rv3d->dist = m_dist;
- upvec[0] = upvec[1] = 0;
- upvec[2] = rv3d->dist;
- copy_m3_m4(mat, rv3d->viewinv);
- mul_m3_v3(mat, upvec);
- add_v3_v3(rv3d->ofs, upvec);
- }
-
- /*----------------------------------------------------
- * sometimes this routine is called from headerbuttons
- * viewmove needs to refresh the screen
- */
-// XXX areawinset(curarea->win);
-
- /*----------------------------------------------------
- * record how much time has passed. clamp at 10 Hz
- * pretend the previous frame occurred at the clamped time
- */
-// now = PIL_check_seconds_timer();
- // frametime = (now - prevTime);
- // if (frametime > 0.1f){ /* if more than 1/10s */
- // frametime = 1.0f/60.0; /* clamp at 1/60s so no jumps when starting to move */
-// }
-// prevTime = now;
- // sbadjust *= 60 * frametime; /* normalize ndof device adjustments to 100Hz for framerate independence */
-
- /* fetch the current state of the ndof device & enforce dominant mode if selected */
-// XXX getndof(fval);
- if (v3d->ndoffilter)
- filterNDOFvalues(fval);
-
-
- // put scaling back here, was previously in ghostwinlay
- fval[0] = fval[0] * (1.0f/600.0f);
- fval[1] = fval[1] * (1.0f/600.0f);
- fval[2] = fval[2] * (1.0f/1100.0f);
- fval[3] = fval[3] * 0.00005f;
- fval[4] =-fval[4] * 0.00005f;
- fval[5] = fval[5] * 0.00005f;
- fval[6] = fval[6] / 1000000.0f;
-
- // scale more if not in perspective mode
- if (rv3d->persp == RV3D_ORTHO) {
- fval[0] = fval[0] * 0.05f;
- fval[1] = fval[1] * 0.05f;
- fval[2] = fval[2] * 0.05f;
- fval[3] = fval[3] * 0.9f;
- fval[4] = fval[4] * 0.9f;
- fval[5] = fval[5] * 0.9f;
- zsens *= 8;
- }
-
- /* set object offset */
- if (ob) {
- obofs[0] = -ob->obmat[3][0];
- obofs[1] = -ob->obmat[3][1];
- obofs[2] = -ob->obmat[3][2];
- }
- else {
- copy_v3_v3(obofs, rv3d->ofs);
- }
-
- /* calc an adjustment based on distance from camera
- disabled per patch 14402 */
- d = 1.0f;
-
-/* if (ob) {
- sub_v3_v3v3(diff, obofs, rv3d->ofs);
- d = len_v3(diff);
- }
-*/
-
- reverse = (rv3d->persmat[2][1] < 0.0f) ? -1.0f : 1.0f;
-
- /*----------------------------------------------------
- * ndof device pan
- */
- psens *= 1.0f + d;
- curareaX = sbadjust * psens * fval[0];
- curareaY = sbadjust * psens * fval[1];
- dvec[0] = curareaX * rv3d->persinv[0][0] + curareaY * rv3d->persinv[1][0];
- dvec[1] = curareaX * rv3d->persinv[0][1] + curareaY * rv3d->persinv[1][1];
- dvec[2] = curareaX * rv3d->persinv[0][2] + curareaY * rv3d->persinv[1][2];
- add_v3_v3(rv3d->ofs, dvec);
-
- /*----------------------------------------------------
- * ndof device dolly
- */
- len = zsens * sbadjust * fval[2];
-
- if (rv3d->persp==RV3D_CAMOB) {
- if(rv3d->persp==RV3D_CAMOB) { /* This is stupid, please fix - TODO */
- rv3d->camzoom+= 10.0f * -len;
- }
- if (rv3d->camzoom < minZoom) rv3d->camzoom = minZoom;
- else if (rv3d->camzoom > maxZoom) rv3d->camzoom = maxZoom;
- }
- else if ((rv3d->dist> 0.001*v3d->grid) && (rv3d->dist<10.0*v3d->far)) {
- rv3d->dist*=(1.0 + len);
- }
-
-
- /*----------------------------------------------------
- * ndof device turntable
- * derived from the turntable code in viewmove
- */
-
- /* Get the 3x3 matrix and its inverse from the quaternion */
- quat_to_mat3( m,rv3d->viewquat);
- invert_m3_m3(m_inv,m);
-
- /* Determine the direction of the x vector (for rotating up and down) */
- /* This can likely be compuated directly from the quaternion. */
- mul_m3_v3(m_inv,xvec);
- mul_m3_v3(m_inv,yvec);
- mul_m3_v3(m_inv,zvec);
-
- /* Perform the up/down rotation */
- phi = sbadjust * rsens * /*0.5f * */ fval[3]; /* spin vertically half as fast as horizontally */
- q1[0] = cos(phi);
- mul_v3_v3fl(q1+1, xvec, sin(phi));
- mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, q1);
-
- if (use_sel) {
- conjugate_qt(q1); /* conj == inv for unit quat */
- sub_v3_v3(rv3d->ofs, obofs);
- mul_qt_v3(q1, rv3d->ofs);
- add_v3_v3(rv3d->ofs, obofs);
- }
-
- /* Perform the orbital rotation */
- /* Perform the orbital rotation
- If the seen Up axis is parallel to the zoom axis, rotation should be
- achieved with a pure Roll motion (no Spin) on the device. When you start
- to tilt, moving from Top to Side view, Spinning will increasingly become
- more relevant while the Roll component will decrease. When a full
- Side view is reached, rotations around the world's Up axis are achieved
- with a pure Spin-only motion. In other words the control of the spinning
- around the world's Up axis should move from the device's Spin axis to the
- device's Roll axis depending on the orientation of the world's Up axis
- relative to the screen. */
- //phi = sbadjust * rsens * reverse * fval[4]; /* spin the knob, y axis */
- phi = sbadjust * rsens * (yvec[2] * fval[4] + zvec[2] * fval[5]);
- q1[0] = cos(phi);
- q1[1] = q1[2] = 0.0;
- q1[3] = sin(phi);
- mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, q1);
-
- if (use_sel) {
- conjugate_qt(q1);
- sub_v3_v3(rv3d->ofs, obofs);
- mul_qt_v3(q1, rv3d->ofs);
- add_v3_v3(rv3d->ofs, obofs);
- }
-
- /*----------------------------------------------------
- * refresh the screen
- */
-// XXX scrarea_do_windraw(curarea);
-}
-#endif // if 0, unused NDof code
-
-
/* Gets the view trasnformation from a camera
* currently dosnt take camzoom into account
*
diff --git a/source/blender/editors/space_view3d/view3d_fly.c b/source/blender/editors/space_view3d/view3d_fly.c
index ed1ed5b3881..046037a092f 100644
--- a/source/blender/editors/space_view3d/view3d_fly.c
+++ b/source/blender/editors/space_view3d/view3d_fly.c
@@ -29,6 +29,9 @@
/* defines VIEW3D_OT_fly modal operator */
+//#define NDOF_FLY_DEBUG
+//#define NDOF_FLY_DRAW_TOOMUCH // is this needed for ndof? - commented so redraw doesnt thrash - campbell
+
#include "DNA_anim_types.h"
#include "DNA_scene_types.h"
#include "DNA_object_types.h"
@@ -106,7 +109,7 @@ void fly_modal_keymap(wmKeyConfig *keyconf)
wmKeyMap *keymap= WM_modalkeymap_get(keyconf, "View3D Fly Modal");
/* this function is called for each spacetype, only needs to add map once */
- if(keymap) return;
+ if (keymap) return;
keymap= WM_modalkeymap_add(keyconf, "View3D Fly Modal", modal_items);
@@ -143,7 +146,6 @@ void fly_modal_keymap(wmKeyConfig *keyconf)
/* assign map to operators */
WM_modalkeymap_assign(keymap, "VIEW3D_OT_fly");
-
}
typedef struct FlyInfo {
@@ -158,7 +160,9 @@ typedef struct FlyInfo {
short state;
short use_precision;
short redraw;
- int mval[2];
+
+ int mval[2]; /* latest 2D mouse values */
+ wmNDOFMotionData* ndof; /* latest 3D mouse values */
/* fly state state */
float speed; /* the speed the view is moving per redraw */
@@ -257,17 +261,21 @@ static int initFlyInfo (bContext *C, FlyInfo *fly, wmOperator *op, wmEvent *even
fly->ar = CTX_wm_region(C);
fly->scene= CTX_data_scene(C);
- if(fly->rv3d->persp==RV3D_CAMOB && fly->v3d->camera->id.lib) {
+#ifdef NDOF_FLY_DEBUG
+ puts("\n-- fly begin --");
+#endif
+
+ if (fly->rv3d->persp==RV3D_CAMOB && fly->v3d->camera->id.lib) {
BKE_report(op->reports, RPT_ERROR, "Cannot fly a camera from an external library");
return FALSE;
}
- if(fly->v3d->ob_centre) {
+ if (fly->v3d->ob_centre) {
BKE_report(op->reports, RPT_ERROR, "Cannot fly when the view is locked to an object");
return FALSE;
}
- if(fly->rv3d->persp==RV3D_CAMOB && fly->v3d->camera->constraints.first) {
+ if (fly->rv3d->persp==RV3D_CAMOB && fly->v3d->camera->constraints.first) {
BKE_report(op->reports, RPT_ERROR, "Cannot fly an object with constraints");
return FALSE;
}
@@ -283,11 +291,15 @@ static int initFlyInfo (bContext *C, FlyInfo *fly, wmOperator *op, wmEvent *even
fly->grid= 1.0f;
fly->use_precision= 0;
+#ifdef NDOF_FLY_DRAW_TOOMUCH
+ fly->redraw= 1;
+#endif
fly->dvec_prev[0]= fly->dvec_prev[1]= fly->dvec_prev[2]= 0.0f;
fly->timer= WM_event_add_timer(CTX_wm_manager(C), CTX_wm_window(C), TIMER, 0.01f);
VECCOPY2D(fly->mval, event->mval)
+ fly->ndof = NULL;
fly->time_lastdraw= fly->time_lastwheel= PIL_check_seconds_timer();
@@ -307,7 +319,7 @@ static int initFlyInfo (bContext *C, FlyInfo *fly, wmOperator *op, wmEvent *even
fly->dist_backup= fly->rv3d->dist;
if (fly->rv3d->persp==RV3D_CAMOB) {
Object *ob_back;
- if((U.uiflag & USER_CAM_LOCK_NO_PARENT)==0 && (fly->root_parent=fly->v3d->camera->parent)) {
+ if ((U.uiflag & USER_CAM_LOCK_NO_PARENT)==0 && (fly->root_parent=fly->v3d->camera->parent)) {
while(fly->root_parent->parent)
fly->root_parent= fly->root_parent->parent;
ob_back= fly->root_parent;
@@ -325,12 +337,22 @@ static int initFlyInfo (bContext *C, FlyInfo *fly, wmOperator *op, wmEvent *even
negate_v3_v3(fly->rv3d->ofs, fly->v3d->camera->obmat[3]);
fly->rv3d->dist=0.0;
- } else {
+ }
+ else {
/* perspective or ortho */
if (fly->rv3d->persp==RV3D_ORTHO)
fly->rv3d->persp= RV3D_PERSP; /*if ortho projection, make perspective */
+
copy_qt_qt(fly->rot_backup, fly->rv3d->viewquat);
copy_v3_v3(fly->ofs_backup, fly->rv3d->ofs);
+
+ /* the dist defines a vector that is infront of the offset
+ to rotate the view about.
+ this is no good for fly mode because we
+ want to rotate about the viewers center.
+ but to correct the dist removal we must
+ alter offset so the view doesn't jump. */
+
fly->rv3d->dist= 0.0f;
upvec[2]= fly->dist_backup; /*x and y are 0*/
@@ -338,7 +360,6 @@ static int initFlyInfo (bContext *C, FlyInfo *fly, wmOperator *op, wmEvent *even
sub_v3_v3(fly->rv3d->ofs, upvec);
/*Done with correcting for the dist*/
}
-
/* center the mouse, probably the UI mafia are against this but without its quite annoying */
WM_cursor_warp(CTX_wm_window(C), fly->ar->winrct.xmin + fly->ar->winx/2, fly->ar->winrct.ymin + fly->ar->winy/2);
@@ -353,9 +374,13 @@ static int flyEnd(bContext *C, FlyInfo *fly)
float upvec[3];
- if(fly->state == FLY_RUNNING)
+ if (fly->state == FLY_RUNNING)
return OPERATOR_RUNNING_MODAL;
+#ifdef NDOF_FLY_DEBUG
+ puts("\n-- fly end --");
+#endif
+
WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), fly->timer);
ED_region_draw_cb_exit(fly->ar->type, fly->draw_handle_pixel);
@@ -366,14 +391,14 @@ static int flyEnd(bContext *C, FlyInfo *fly)
/* Revert to original view? */
if (fly->persp_backup==RV3D_CAMOB) { /* a camera view */
Object *ob_back;
- if(fly->root_parent)ob_back= fly->root_parent;
- else ob_back= fly->v3d->camera;
+ ob_back= (fly->root_parent) ? fly->root_parent : fly->v3d->camera;
/* store the original camera loc and rot */
object_tfm_restore(ob_back, fly->obtfm);
DAG_id_tag_update(&ob_back->id, OB_RECALC_OB);
- } else {
+ }
+ else {
/* Non Camera we need to reset the view back to the original location bacause the user canceled*/
copy_qt_qt(rv3d->viewquat, fly->rot_backup);
copy_v3_v3(rv3d->ofs, fly->ofs_backup);
@@ -398,10 +423,13 @@ static int flyEnd(bContext *C, FlyInfo *fly)
rv3d->rflag &= ~RV3D_NAVIGATING;
//XXX2.5 BIF_view3d_previewrender_signal(fly->sa, PR_DBASE|PR_DISPRECT); /* not working at the moment not sure why */
- if(fly->obtfm)
+ if (fly->obtfm)
MEM_freeN(fly->obtfm);
- if(fly->state == FLY_CONFIRM) {
+ if (fly->ndof)
+ MEM_freeN(fly->ndof);
+
+ if (fly->state == FLY_CONFIRM) {
MEM_freeN(fly);
return OPERATOR_FINISHED;
}
@@ -417,7 +445,52 @@ static void flyEvent(FlyInfo *fly, wmEvent *event)
}
else if (event->type == MOUSEMOVE) {
VECCOPY2D(fly->mval, event->mval);
- } /* handle modal keymap first */
+ }
+ else if (event->type == NDOF_MOTION) {
+ // do these automagically get delivered? yes.
+ // puts("ndof motion detected in fly mode!");
+ // static const char* tag_name = "3D mouse position";
+
+ wmNDOFMotionData* incoming_ndof = (wmNDOFMotionData*) event->customdata;
+ switch (incoming_ndof->progress) {
+ case P_STARTING:
+ // start keeping track of 3D mouse position
+#ifdef NDOF_FLY_DEBUG
+ puts("start keeping track of 3D mouse position");
+#endif
+ // fall through...
+ case P_IN_PROGRESS:
+ // update 3D mouse position
+#ifdef NDOF_FLY_DEBUG
+ putchar('.'); fflush(stdout);
+#endif
+ if (fly->ndof == NULL) {
+ // fly->ndof = MEM_mallocN(sizeof(wmNDOFMotionData), tag_name);
+ fly->ndof = MEM_dupallocN(incoming_ndof);
+ // fly->ndof = malloc(sizeof(wmNDOFMotionData));
+ }
+ else {
+ memcpy(fly->ndof, incoming_ndof, sizeof(wmNDOFMotionData));
+ }
+ break;
+ case P_FINISHING:
+ // stop keeping track of 3D mouse position
+#ifdef NDOF_FLY_DEBUG
+ puts("stop keeping track of 3D mouse position");
+#endif
+ if (fly->ndof) {
+ MEM_freeN(fly->ndof);
+ // free(fly->ndof);
+ fly->ndof = NULL;
+ }
+ /* update the time else the view will jump when 2D mouse/timer resume */
+ fly->time_lastdraw= PIL_check_seconds_timer();
+ break;
+ default:
+ ; // should always be one of the above 3
+ }
+ }
+ /* handle modal keymap first */
else if (event->type == EVT_MODAL_MAP) {
switch (event->val) {
case FLY_MODAL_CANCEL:
@@ -439,7 +512,9 @@ static void flyEvent(FlyInfo *fly, wmEvent *event)
/*Mouse wheel delays range from 0.5==slow to 0.01==fast*/
time_wheel = 1.0f + (10.0f - (20.0f * MIN2(time_wheel, 0.5f))); /* 0-0.5 -> 0-5.0 */
- if (fly->speed<0.0f) fly->speed= 0.0f;
+ if (fly->speed < 0.0f) {
+ fly->speed= 0.0f;
+ }
else {
if (event->shift)
fly->speed += fly->grid*time_wheel * 0.1f;
@@ -458,7 +533,9 @@ static void flyEvent(FlyInfo *fly, wmEvent *event)
fly->time_lastwheel = time_currwheel;
time_wheel = 1.0f + (10.0f - (20.0f * MIN2(time_wheel, 0.5f))); /* 0-0.5 -> 0-5.0 */
- if (fly->speed>0) fly->speed=0;
+ if (fly->speed > 0.0f) {
+ fly->speed=0;
+ }
else {
if (event->shift)
fly->speed-= fly->grid*time_wheel * 0.1f;
@@ -528,14 +605,81 @@ static void flyEvent(FlyInfo *fly, wmEvent *event)
case FLY_MODAL_PRECISION_DISABLE:
fly->use_precision= FALSE;
break;
+ }
+ }
+}
+
+static void move_camera(bContext* C, RegionView3D* rv3d, FlyInfo* fly, int orientationChanged, int positionChanged)
+{
+ /* we are in camera view so apply the view ofs and quat to the view matrix and set the camera to the view */
+
+ View3D* v3d = fly->v3d;
+ Scene *scene= fly->scene;
+ ID *id_key;
+
+ /* transform the parent or the camera? */
+ if (fly->root_parent) {
+ Object *ob_update;
+
+ float view_mat[4][4];
+ float prev_view_mat[4][4];
+ float prev_view_imat[4][4];
+ float diff_mat[4][4];
+ float parent_mat[4][4];
+
+ ED_view3d_to_m4(prev_view_mat, fly->rv3d->ofs, fly->rv3d->viewquat, fly->rv3d->dist);
+ invert_m4_m4(prev_view_imat, prev_view_mat);
+ ED_view3d_to_m4(view_mat, rv3d->ofs, rv3d->viewquat, rv3d->dist);
+ mul_m4_m4m4(diff_mat, prev_view_imat, view_mat);
+ mul_m4_m4m4(parent_mat, fly->root_parent->obmat, diff_mat);
+ object_apply_mat4(fly->root_parent, parent_mat, TRUE, FALSE);
+
+ // where_is_object(scene, fly->root_parent);
+
+ ob_update= v3d->camera->parent;
+ while(ob_update) {
+ DAG_id_tag_update(&ob_update->id, OB_RECALC_OB);
+ ob_update= ob_update->parent;
}
+
+ id_key= &fly->root_parent->id;
+ }
+ else {
+ float view_mat[4][4];
+ ED_view3d_to_m4(view_mat, rv3d->ofs, rv3d->viewquat, rv3d->dist);
+ object_apply_mat4(v3d->camera, view_mat, TRUE, FALSE);
+ id_key= &v3d->camera->id;
+ }
+
+ /* record the motion */
+ if (autokeyframe_cfra_can_key(scene, id_key)) {
+ ListBase dsources = {NULL, NULL};
+
+ /* add datasource override for the camera object */
+ ANIM_relative_keyingset_add_source(&dsources, id_key, NULL, NULL);
+
+ /* insert keyframes
+ * 1) on the first frame
+ * 2) on each subsequent frame
+ * TODO: need to check in future that frame changed before doing this
+ */
+ if (orientationChanged) {
+ KeyingSet *ks= ANIM_builtin_keyingset_get_named(NULL, "Rotation");
+ ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, (float)CFRA);
+ }
+ if (positionChanged) {
+ KeyingSet *ks= ANIM_builtin_keyingset_get_named(NULL, "Location");
+ ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, (float)CFRA);
+ }
+
+ /* free temp data */
+ BLI_freelistN(&dsources);
}
}
static int flyApply(bContext *C, FlyInfo *fly)
{
-
#define FLY_ROTATE_FAC 2.5f /* more is faster */
#define FLY_ZUP_CORRECT_FAC 0.1f /* amount to correct per step */
#define FLY_ZUP_CORRECT_ACCEL 0.05f /* increase upright momentum each step */
@@ -545,11 +689,7 @@ static int flyApply(bContext *C, FlyInfo *fly)
a fly loop where the user can move move the view as if they are flying
*/
RegionView3D *rv3d= fly->rv3d;
- View3D *v3d = fly->v3d;
ARegion *ar = fly->ar;
- Scene *scene= fly->scene;
-
- float prev_view_mat[4][4];
float mat[3][3], /* 3x3 copy of the view matrix so we can move allong the view axis */
dvec[3]={0,0,0}, /* this is the direction thast added to the view offset per redraw */
@@ -567,15 +707,11 @@ static int flyApply(bContext *C, FlyInfo *fly)
unsigned char
apply_rotation= 1; /* if the user presses shift they can look about without movinf the direction there looking*/
- if(fly->root_parent)
- ED_view3d_to_m4(prev_view_mat, fly->rv3d->ofs, fly->rv3d->viewquat, fly->rv3d->dist);
+#ifdef NDOF_FLY_DEBUG
+ static unsigned int iteration = 1;
+ printf("fly timer %d\n", iteration++);
+#endif
- /* the dist defines a vector that is infront of the offset
- to rotate the view about.
- this is no good for fly mode because we
- want to rotate about the viewers center.
- but to correct the dist removal we must
- alter offset so the view doesn't jump. */
xmargin= ar->winx/20.0f;
ymargin= ar->winy/20.0f;
@@ -605,23 +741,25 @@ static int flyApply(bContext *C, FlyInfo *fly)
*
* the mouse moves isnt linear */
- if(moffset[0]) {
+ if (moffset[0]) {
moffset[0] /= ar->winx - (xmargin*2);
moffset[0] *= fabsf(moffset[0]);
}
- if(moffset[1]) {
+ if (moffset[1]) {
moffset[1] /= ar->winy - (ymargin*2);
moffset[1] *= fabsf(moffset[1]);
}
/* Should we redraw? */
- if(fly->speed != 0.0f || moffset[0] || moffset[1] || fly->zlock || fly->xlock || dvec[0] || dvec[1] || dvec[2] ) {
+ if (fly->speed != 0.0f || moffset[0] || moffset[1] || fly->zlock || fly->xlock || dvec[0] || dvec[1] || dvec[2] ) {
float dvec_tmp[3];
double time_current; /*time how fast it takes for us to redraw, this is so simple scenes dont fly too fast */
float time_redraw;
float time_redraw_clamped;
-
+#ifdef NDOF_FLY_DRAW_TOOMUCH
+ fly->redraw= 1;
+#endif
time_current= PIL_check_seconds_timer();
time_redraw= (float)(time_current - fly->time_lastdraw);
time_redraw_clamped= MIN2(0.05f, time_redraw); /* clamt the redraw time to avoid jitter in roll correction */
@@ -648,8 +786,8 @@ static int flyApply(bContext *C, FlyInfo *fly)
mul_m3_v3(mat, dvec_tmp);
mul_v3_fl(dvec_tmp, time_redraw * 200.0f * fly->grid);
-
- } else {
+ }
+ else {
float roll; /* similar to the angle between the camera's up and the Z-up, but its very rough so just roll*/
/* rotate about the X axis- look up/down */
@@ -670,27 +808,28 @@ static int flyApply(bContext *C, FlyInfo *fly)
if (moffset[0]) {
/* if we're upside down invert the moffset */
- upvec[0]=0;
- upvec[1]=1;
- upvec[2]=0;
+ upvec[0]= 0.0f;
+ upvec[1]= 1.0f;
+ upvec[2]= 0.0f;
mul_m3_v3(mat, upvec);
- if(upvec[2] < 0.0f)
+ if (upvec[2] < 0.0f)
moffset[0]= -moffset[0];
/* make the lock vectors */
if (fly->zlock) {
- upvec[0]=0;
- upvec[1]=0;
- upvec[2]=1;
- } else {
- upvec[0]=0;
- upvec[1]=1;
- upvec[2]=0;
+ upvec[0]= 0.0f;
+ upvec[1]= 0.0f;
+ upvec[2]= 1.0f;
+ }
+ else {
+ upvec[0]= 0.0f;
+ upvec[1]= 1.0f;
+ upvec[2]= 0.0f;
mul_m3_v3(mat, upvec);
}
- axis_angle_to_quat( tmp_quat, upvec, (float)moffset[0] * time_redraw * FLY_ROTATE_FAC); /* Rotate about the relative up vec */
+ axis_angle_to_quat(tmp_quat, upvec, (float)moffset[0] * time_redraw * FLY_ROTATE_FAC); /* Rotate about the relative up vec */
mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, tmp_quat);
if (fly->xlock) fly->xlock = 2;/*check for rotation*/
@@ -698,25 +837,26 @@ static int flyApply(bContext *C, FlyInfo *fly)
}
if (fly->zlock==2) {
- upvec[0]=1;
- upvec[1]=0;
- upvec[2]=0;
+ upvec[0]= 1.0f;
+ upvec[1]= 0.0f;
+ upvec[2]= 0.0f;
mul_m3_v3(mat, upvec);
/*make sure we have some z rolling*/
if (fabsf(upvec[2]) > 0.00001f) {
- roll= upvec[2]*5;
- upvec[0]=0; /*rotate the view about this axis*/
- upvec[1]=0;
- upvec[2]=1;
+ roll= upvec[2] * 5.0f;
+ upvec[0]= 0.0f; /*rotate the view about this axis*/
+ upvec[1]= 0.0f;
+ upvec[2]= 1.0f;
mul_m3_v3(mat, upvec);
axis_angle_to_quat( tmp_quat, upvec, roll*time_redraw_clamped*fly->zlock_momentum * FLY_ZUP_CORRECT_FAC); /* Rotate about the relative up vec */
mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, tmp_quat);
fly->zlock_momentum += FLY_ZUP_CORRECT_ACCEL;
- } else {
- fly->zlock=1; /* dont check until the view rotates again */
+ }
+ else {
+ fly->zlock= 1; /* dont check until the view rotates again */
fly->zlock_momentum= 0.0f;
}
}
@@ -727,8 +867,8 @@ static int flyApply(bContext *C, FlyInfo *fly)
upvec[2]=1;
mul_m3_v3(mat, upvec);
/*make sure we have some z rolling*/
- if (fabs(upvec[2]) > 0.00001) {
- roll= upvec[2] * -5;
+ if (fabs(upvec[2]) > 0.00001f) {
+ roll= upvec[2] * -5.0f;
upvec[0]= 1.0f; /*rotate the view about this axis*/
upvec[1]= 0.0f;
@@ -740,7 +880,8 @@ static int flyApply(bContext *C, FlyInfo *fly)
mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, tmp_quat);
fly->xlock_momentum += 0.05f;
- } else {
+ }
+ else {
fly->xlock=1; /* see above */
fly->xlock_momentum= 0.0f;
}
@@ -784,96 +925,164 @@ static int flyApply(bContext *C, FlyInfo *fly)
ED_area_headerprint(fly->ar, "FlyKeys Speed:(+/- | Wheel), Upright Axis:X off/Z off, Slow:Shift, Direction:WASDRF, Ok:LMB, Pan:MMB, Cancel:RMB");
#endif
- /* we are in camera view so apply the view ofs and quat to the view matrix and set the camera to the view */
- if (rv3d->persp==RV3D_CAMOB) {
- ID *id_key;
- /* transform the parent or the camera? */
- if(fly->root_parent) {
- Object *ob_update;
-
- float view_mat[4][4];
- float prev_view_imat[4][4];
- float diff_mat[4][4];
- float parent_mat[4][4];
-
- invert_m4_m4(prev_view_imat, prev_view_mat);
- ED_view3d_to_m4(view_mat, rv3d->ofs, rv3d->viewquat, rv3d->dist);
- mul_m4_m4m4(diff_mat, prev_view_imat, view_mat);
- mul_m4_m4m4(parent_mat, fly->root_parent->obmat, diff_mat);
- object_apply_mat4(fly->root_parent, parent_mat, TRUE, FALSE);
-
- // where_is_object(scene, fly->root_parent);
-
- ob_update= v3d->camera->parent;
- while(ob_update) {
- DAG_id_tag_update(&ob_update->id, OB_RECALC_OB);
- ob_update= ob_update->parent;
- }
+ if (rv3d->persp==RV3D_CAMOB)
+ move_camera(C, rv3d, fly, (fly->xlock || fly->zlock || moffset[0] || moffset[1]), fly->speed);
- copy_m4_m4(prev_view_mat, view_mat);
+ }
+ else {
+ /* we're not redrawing but we need to update the time else the view will jump */
+ fly->time_lastdraw= PIL_check_seconds_timer();
+ }
+ /* end drawing */
+ copy_v3_v3(fly->dvec_prev, dvec);
+ }
- id_key= &fly->root_parent->id;
+ return OPERATOR_FINISHED;
+}
- }
- else {
- float view_mat[4][4];
- ED_view3d_to_m4(view_mat, rv3d->ofs, rv3d->viewquat, rv3d->dist);
- object_apply_mat4(v3d->camera, view_mat, TRUE, FALSE);
- id_key= &v3d->camera->id;
- }
+static int flyApply_ndof(bContext *C, FlyInfo *fly)
+{
+ /* shorthand for oft-used variables */
+ wmNDOFMotionData* ndof = fly->ndof;
+ const float dt = ndof->dt;
+ RegionView3D* rv3d = fly->rv3d;
+ const int flag = U.ndof_flag;
- /* record the motion */
- if (autokeyframe_cfra_can_key(scene, id_key)) {
- ListBase dsources = {NULL, NULL};
-
- /* add datasource override for the camera object */
- ANIM_relative_keyingset_add_source(&dsources, id_key, NULL, NULL);
-
- /* insert keyframes
- * 1) on the first frame
- * 2) on each subsequent frame
- * TODO: need to check in future that frame changed before doing this
- */
- if (fly->xlock || fly->zlock || moffset[0] || moffset[1]) {
- KeyingSet *ks= ANIM_builtin_keyingset_get_named(NULL, "Rotation");
- ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, (float)CFRA);
- }
- if (fly->speed) {
- KeyingSet *ks= ANIM_builtin_keyingset_get_named(NULL, "Location");
- ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, (float)CFRA);
- }
-
- /* free temp data */
- BLI_freelistN(&dsources);
- }
+/* int shouldRotate = (flag & NDOF_SHOULD_ROTATE) && (fly->pan_view == FALSE),
+ shouldTranslate = (flag & (NDOF_SHOULD_PAN | NDOF_SHOULD_ZOOM)); */
+
+ int shouldRotate = (fly->pan_view == FALSE),
+ shouldTranslate = TRUE;
+
+ float view_inv[4];
+ invert_qt_qt(view_inv, rv3d->viewquat);
+
+ rv3d->rot_angle = 0.f; // disable onscreen rotation doo-dad
+
+ if (shouldTranslate) {
+ const float forward_sensitivity = 1.f;
+ const float vertical_sensitivity = 0.4f;
+ const float lateral_sensitivity = 0.6f;
+
+ float speed = 10.f; /* blender units per second */
+ /* ^^ this is ok for default cube scene, but should scale with.. something */
+
+ float trans[3] = {
+ lateral_sensitivity * ndof->tvec[0],
+ vertical_sensitivity * ndof->tvec[1],
+ forward_sensitivity * ndof->tvec[2]
+ };
+
+ if (fly->use_precision)
+ speed *= 0.2f;
+
+ mul_v3_fl(trans, speed * dt);
+
+ // transform motion from view to world coordinates
+ mul_qt_v3(view_inv, trans);
+
+ if (flag & NDOF_FLY_HELICOPTER) {
+ /* replace world z component with device y (yes it makes sense) */
+ trans[2] = speed * dt * vertical_sensitivity * ndof->tvec[1];
+ }
+
+ if (rv3d->persp==RV3D_CAMOB) {
+ // respect camera position locks
+ Object *lock_ob= fly->root_parent ? fly->root_parent : fly->v3d->camera;
+ if (lock_ob->protectflag & OB_LOCK_LOCX) trans[0] = 0.f;
+ if (lock_ob->protectflag & OB_LOCK_LOCY) trans[1] = 0.f;
+ if (lock_ob->protectflag & OB_LOCK_LOCZ) trans[2] = 0.f;
+ }
+
+ if (!is_zero_v3(trans)) {
+ // move center of view opposite of hand motion (this is camera mode, not object mode)
+ sub_v3_v3(rv3d->ofs, trans);
+ shouldTranslate = TRUE;
+ }
+ else {
+ shouldTranslate = FALSE;
+ }
+ }
+
+ if (shouldRotate) {
+ const float turn_sensitivity = 1.f;
+
+ float rotation[4];
+ float axis[3];
+ float angle = turn_sensitivity * ndof_to_axis_angle(ndof, axis);
+
+ if (fabsf(angle) > 0.0001f) {
+ shouldRotate = TRUE;
+
+ if (fly->use_precision)
+ angle *= 0.2f;
+
+ /* transform rotation axis from view to world coordinates */
+ mul_qt_v3(view_inv, axis);
+
+ // apply rotation to view
+ axis_angle_to_quat(rotation, axis, angle);
+ mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, rotation);
+
+ if (flag & NDOF_LOCK_HORIZON) {
+ /* force an upright viewpoint
+ * TODO: make this less... sudden */
+ float view_horizon[3] = {1.f, 0.f, 0.f}; /* view +x */
+ float view_direction[3] = {0.f, 0.f, -1.f}; /* view -z (into screen) */
+
+ /* find new inverse since viewquat has changed */
+ invert_qt_qt(view_inv, rv3d->viewquat);
+ /* could apply reverse rotation to existing view_inv to save a few cycles */
+
+ /* transform view vectors to world coordinates */
+ mul_qt_v3(view_inv, view_horizon);
+ mul_qt_v3(view_inv, view_direction);
+
+ /* find difference between view & world horizons
+ * true horizon lives in world xy plane, so look only at difference in z */
+ angle = -asinf(view_horizon[2]);
+
+#ifdef NDOF_FLY_DEBUG
+ printf("lock horizon: adjusting %.1f degrees\n\n", RAD2DEG(angle));
+#endif
+
+ /* rotate view so view horizon = world horizon */
+ axis_angle_to_quat(rotation, view_direction, angle);
+ mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, rotation);
}
- } else
- /*were not redrawing but we need to update the time else the view will jump */
- fly->time_lastdraw= PIL_check_seconds_timer();
- /* end drawing */
- copy_v3_v3(fly->dvec_prev, dvec);
+
+ rv3d->view = RV3D_VIEW_USER;
+ }
+ else {
+ shouldRotate = FALSE;
+ }
}
-/* moved to flyEnd() */
+ if (shouldTranslate || shouldRotate) {
+ fly->redraw = TRUE;
+
+ if (rv3d->persp==RV3D_CAMOB) {
+ move_camera(C, rv3d, fly, shouldRotate, shouldTranslate);
+ }
+ }
return OPERATOR_FINISHED;
}
-
static int fly_invoke(bContext *C, wmOperator *op, wmEvent *event)
{
RegionView3D *rv3d= CTX_wm_region_view3d(C);
FlyInfo *fly;
- if(rv3d->viewlock)
+ if (rv3d->viewlock)
return OPERATOR_CANCELLED;
fly= MEM_callocN(sizeof(FlyInfo), "FlyOperation");
op->customdata= fly;
- if(initFlyInfo(C, fly, op, event)==FALSE) {
+ if (initFlyInfo(C, fly, op, event)==FALSE) {
MEM_freeN(op->customdata);
return OPERATOR_CANCELLED;
}
@@ -908,21 +1117,28 @@ static int fly_modal(bContext *C, wmOperator *op, wmEvent *event)
flyEvent(fly, event);
- if(event->type==TIMER && event->customdata == fly->timer)
+ if (fly->ndof) { /* 3D mouse overrules [2D mouse + timer] */
+ if (event->type==NDOF_MOTION) {
+ flyApply_ndof(C, fly);
+ }
+ }
+ else if (event->type==TIMER && event->customdata == fly->timer) {
flyApply(C, fly);
+ }
do_draw |= fly->redraw;
exit_code = flyEnd(C, fly);
- if(exit_code!=OPERATOR_RUNNING_MODAL)
+ if (exit_code!=OPERATOR_RUNNING_MODAL)
do_draw= TRUE;
- if(do_draw) {
- if(rv3d->persp==RV3D_CAMOB) {
+ if (do_draw) {
+ if (rv3d->persp==RV3D_CAMOB) {
WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, fly_object);
}
+ // puts("redraw!"); // too frequent, commented with NDOF_FLY_DRAW_TOOMUCH for now
ED_region_tag_redraw(CTX_wm_region(C));
}
diff --git a/source/blender/editors/space_view3d/view3d_header.c b/source/blender/editors/space_view3d/view3d_header.c
index ae80a554e08..5b95ae63e56 100644
--- a/source/blender/editors/space_view3d/view3d_header.c
+++ b/source/blender/editors/space_view3d/view3d_header.c
@@ -280,7 +280,8 @@ static char *view3d_modeselect_pup(Scene *scene)
str += sprintf(str, formatstr, "Object Mode", OB_MODE_OBJECT, ICON_OBJECT_DATA);
- if(ob==NULL) return string;
+ if(ob==NULL || ob->data==NULL) return string;
+ if(ob->id.lib || ((ID *)ob->data)->lib) return string;
/* if active object is editable */
if ( ((ob->type == OB_MESH)
diff --git a/source/blender/editors/space_view3d/view3d_intern.h b/source/blender/editors/space_view3d/view3d_intern.h
index d3886d48873..ab3ce37ff15 100644
--- a/source/blender/editors/space_view3d/view3d_intern.h
+++ b/source/blender/editors/space_view3d/view3d_intern.h
@@ -51,6 +51,7 @@ struct ARegionType;
struct bPoseChannel;
struct bAnimVizSettings;
struct bMotionPath;
+struct wmNDOFMotionData;
#define BL_NEAR_CLIP 0.001
@@ -72,6 +73,8 @@ void VIEW3D_OT_dolly(struct wmOperatorType *ot);
void VIEW3D_OT_zoom_camera_1_to_1(struct wmOperatorType *ot);
void VIEW3D_OT_move(struct wmOperatorType *ot);
void VIEW3D_OT_rotate(struct wmOperatorType *ot);
+void VIEW3D_OT_ndof_orbit(struct wmOperatorType *ot);
+void VIEW3D_OT_ndof_pan(struct wmOperatorType *ot);
void VIEW3D_OT_view_all(struct wmOperatorType *ot);
void VIEW3D_OT_viewnumpad(struct wmOperatorType *ot);
void VIEW3D_OT_view_selected(struct wmOperatorType *ot);
@@ -91,6 +94,8 @@ void VIEW3D_OT_zoom_border(struct wmOperatorType *ot);
void VIEW3D_OT_drawtype(struct wmOperatorType *ot);
void view3d_boxview_copy(ScrArea *sa, ARegion *ar);
+void ndof_to_quat(struct wmNDOFMotionData* ndof, float q[4]);
+float ndof_to_axis_angle(struct wmNDOFMotionData* ndof, float axis[3]);
/* view3d_fly.c */
void view3d_keymap(struct wmKeyConfig *keyconf);
diff --git a/source/blender/editors/space_view3d/view3d_ops.c b/source/blender/editors/space_view3d/view3d_ops.c
index 05ef79a9f29..e47cb1db753 100644
--- a/source/blender/editors/space_view3d/view3d_ops.c
+++ b/source/blender/editors/space_view3d/view3d_ops.c
@@ -64,6 +64,8 @@ void view3d_operatortypes(void)
WM_operatortype_append(VIEW3D_OT_zoom);
WM_operatortype_append(VIEW3D_OT_zoom_camera_1_to_1);
WM_operatortype_append(VIEW3D_OT_dolly);
+ WM_operatortype_append(VIEW3D_OT_ndof_orbit);
+ WM_operatortype_append(VIEW3D_OT_ndof_pan);
WM_operatortype_append(VIEW3D_OT_view_all);
WM_operatortype_append(VIEW3D_OT_viewnumpad);
WM_operatortype_append(VIEW3D_OT_view_orbit);
@@ -161,6 +163,17 @@ void view3d_keymap(wmKeyConfig *keyconf)
RNA_boolean_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_all", HOMEKEY, KM_PRESS, 0, 0)->ptr, "center", 0); /* only without camera view */
RNA_boolean_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_all", CKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "center", 1);
+ /* 3D mouse */
+ WM_keymap_add_item(keymap, "VIEW3D_OT_ndof_orbit", NDOF_MOTION, 0, 0, 0);
+ WM_keymap_add_item(keymap, "VIEW3D_OT_ndof_pan", NDOF_MOTION, 0, KM_SHIFT, 0);
+ WM_keymap_add_item(keymap, "VIEW3D_OT_view_selected", NDOF_BUTTON_FIT, KM_PRESS, 0, 0);
+ RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", NDOF_BUTTON_FRONT, KM_PRESS, 0, 0)->ptr, "type", RV3D_VIEW_FRONT);
+ RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", NDOF_BUTTON_BACK, KM_PRESS, 0, 0)->ptr, "type", RV3D_VIEW_BACK);
+ RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", NDOF_BUTTON_LEFT, KM_PRESS, 0, 0)->ptr, "type", RV3D_VIEW_LEFT);
+ RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", NDOF_BUTTON_RIGHT, KM_PRESS, 0, 0)->ptr, "type", RV3D_VIEW_RIGHT);
+ RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", NDOF_BUTTON_TOP, KM_PRESS, 0, 0)->ptr, "type", RV3D_VIEW_TOP);
+ RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", NDOF_BUTTON_BOTTOM, KM_PRESS, 0, 0)->ptr, "type", RV3D_VIEW_BOTTOM);
+
/* numpad view hotkeys*/
RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", PAD0, KM_PRESS, 0, 0)->ptr, "type", RV3D_VIEW_CAMERA);
RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", PAD1, KM_PRESS, 0, 0)->ptr, "type", RV3D_VIEW_FRONT);
@@ -210,6 +223,17 @@ void view3d_keymap(wmKeyConfig *keyconf)
RNA_enum_set(kmi->ptr, "type", RV3D_VIEW_BOTTOM);
RNA_boolean_set(kmi->ptr, "align_active", TRUE);
+ /* 3D mouse align */
+ kmi= WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", NDOF_BUTTON_FRONT, KM_PRESS, KM_SHIFT, 0);
+ RNA_enum_set(kmi->ptr, "type", RV3D_VIEW_FRONT);
+ RNA_boolean_set(kmi->ptr, "align_active", TRUE);
+ kmi= WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", NDOF_BUTTON_RIGHT, KM_PRESS, KM_SHIFT, 0);
+ RNA_enum_set(kmi->ptr, "type", RV3D_VIEW_RIGHT);
+ RNA_boolean_set(kmi->ptr, "align_active", TRUE);
+ kmi= WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", NDOF_BUTTON_TOP, KM_PRESS, KM_SHIFT, 0);
+ RNA_enum_set(kmi->ptr, "type", RV3D_VIEW_TOP);
+ RNA_boolean_set(kmi->ptr, "align_active", TRUE);
+
WM_keymap_add_item(keymap, "VIEW3D_OT_localview", PADSLASHKEY, KM_PRESS, 0, 0);
/* layers, shift + alt are properties set in invoke() */
diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c
index 9290e1fc631..c6835b0cad3 100644
--- a/source/blender/editors/space_view3d/view3d_select.c
+++ b/source/blender/editors/space_view3d/view3d_select.c
@@ -889,14 +889,14 @@ static unsigned int samplerect(unsigned int *buf, int size, unsigned int dontdo)
{
Base *base;
unsigned int *bufmin,*bufmax;
- int a,b,rc,tel,aantal,dirvec[4][2],maxob;
+ int a,b,rc,tel,len,dirvec[4][2],maxob;
unsigned int retval=0;
base= LASTBASE;
if(base==0) return 0;
maxob= base->selcol;
- aantal= (size-1)/2;
+ len= (size-1)/2;
rc= 0;
dirvec[0][0]= 1;
@@ -910,7 +910,7 @@ static unsigned int samplerect(unsigned int *buf, int size, unsigned int dontdo)
bufmin= buf;
bufmax= buf+ size*size;
- buf+= aantal*size+ aantal;
+ buf+= len*size+ len;
for(tel=1;tel<=size;tel++) {
diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c
index 65a0657d2f3..cb3b72468fe 100644
--- a/source/blender/editors/transform/transform.c
+++ b/source/blender/editors/transform/transform.c
@@ -1006,9 +1006,11 @@ int transformEvent(TransInfo *t, wmEvent *event)
else view_editmove(event->type);
t->redraw= 1;
break;
-// case NDOFMOTION:
-// viewmoveNDOF(1);
- // break;
+#if 0
+ case NDOF_MOTION:
+ // should have been caught by tranform_modal
+ return OPERATOR_PASS_THROUGH;
+#endif
default:
handled = 0;
break;
@@ -1017,43 +1019,6 @@ int transformEvent(TransInfo *t, wmEvent *event)
// Numerical input events
t->redraw |= handleNumInput(&(t->num), event);
- // NDof input events
- switch(handleNDofInput(&(t->ndof), event))
- {
- case NDOF_CONFIRM:
- if ((t->options & CTX_NDOF) == 0)
- {
- /* Confirm on normal transform only */
- t->state = TRANS_CONFIRM;
- }
- break;
- case NDOF_CANCEL:
- if (t->options & CTX_NDOF)
- {
- /* Cancel on pure NDOF transform */
- t->state = TRANS_CANCEL;
- }
- else
- {
- /* Otherwise, just redraw, NDof input was cancelled */
- t->redraw |= TREDRAW_HARD;
- }
- break;
- case NDOF_NOMOVE:
- if (t->options & CTX_NDOF)
- {
- /* Confirm on pure NDOF transform */
- t->state = TRANS_CONFIRM;
- }
- break;
- case NDOF_REFRESH:
- t->redraw |= TREDRAW_HARD;
- break;
- default:
- handled = 0;
- break;
- }
-
// Snapping events
t->redraw |= handleSnapping(t, event);
@@ -2907,10 +2872,6 @@ void initRotation(TransInfo *t)
setInputPostFct(&t->mouse, postInputRotation);
initMouseInputMode(t, &t->mouse, INPUT_ANGLE);
- t->ndof.axis = 16;
- /* Scale down and flip input for rotation */
- t->ndof.factor[0] = -0.2f;
-
t->idx_max = 0;
t->num.idx_max = 0;
t->snap[0] = 0.0f;
@@ -3182,8 +3143,6 @@ int Rotation(TransInfo *t, const int UNUSED(mval[2]))
final = t->values[0];
- applyNDofInput(&t->ndof, &final);
-
snapGrid(t, &final);
if ((t->con.mode & CON_APPLY) && t->con.applyRot) {
@@ -3237,11 +3196,6 @@ void initTrackball(TransInfo *t)
initMouseInputMode(t, &t->mouse, INPUT_TRACKBALL);
- t->ndof.axis = 40;
- /* Scale down input for rotation */
- t->ndof.factor[0] = 0.2f;
- t->ndof.factor[1] = 0.2f;
-
t->idx_max = 1;
t->num.idx_max = 1;
t->snap[0] = 0.0f;
@@ -3297,8 +3251,6 @@ int Trackball(TransInfo *t, const int UNUSED(mval[2]))
phi[0] = t->values[0];
phi[1] = t->values[1];
- applyNDofInput(&t->ndof, phi);
-
snapGrid(t, phi);
if (hasNumInput(&t->num)) {
@@ -3352,8 +3304,6 @@ void initTranslation(TransInfo *t)
t->num.flag = 0;
t->num.idx_max = t->idx_max;
- t->ndof.axis = (t->flag & T_2D_EDIT)? 1|2: 1|2|4;
-
if(t->spacetype == SPACE_VIEW3D) {
RegionView3D *rv3d = t->ar->regiondata;
@@ -3528,7 +3478,6 @@ int Translation(TransInfo *t, const int UNUSED(mval[2]))
headerTranslation(t, pvec, str);
}
else {
- applyNDofInput(&t->ndof, t->values);
snapGrid(t, t->values);
applyNumInput(&t->num, t->values);
if (hasNumInput(&t->num)) {
@@ -3637,10 +3586,6 @@ void initTilt(TransInfo *t)
initMouseInputMode(t, &t->mouse, INPUT_ANGLE);
- t->ndof.axis = 16;
- /* Scale down and flip input for rotation */
- t->ndof.factor[0] = -0.2f;
-
t->idx_max = 0;
t->num.idx_max = 0;
t->snap[0] = 0.0f;
@@ -3664,8 +3609,6 @@ int Tilt(TransInfo *t, const int UNUSED(mval[2]))
final = t->values[0];
- applyNDofInput(&t->ndof, &final);
-
snapGrid(t, &final);
if (hasNumInput(&t->num)) {
@@ -3780,10 +3723,6 @@ void initPushPull(TransInfo *t)
initMouseInputMode(t, &t->mouse, INPUT_VERTICAL_ABSOLUTE);
- t->ndof.axis = 4;
- /* Flip direction */
- t->ndof.factor[0] = -1.0f;
-
t->idx_max = 0;
t->num.idx_max = 0;
t->snap[0] = 0.0f;
@@ -3804,8 +3743,6 @@ int PushPull(TransInfo *t, const int UNUSED(mval[2]))
distance = t->values[0];
- applyNDofInput(&t->ndof, &distance);
-
snapGrid(t, &distance);
applyNumInput(&t->num, &distance);
@@ -4680,7 +4617,7 @@ static int createSlideVerts(TransInfo *t)
#define EDGE_SLIDE_MIN 30
if (len_squared_v2v2(start, end) < (EDGE_SLIDE_MIN * EDGE_SLIDE_MIN)) {
if(ABS(start[0]-end[0]) + ABS(start[1]-end[1]) < 4.0f) {
- /* even more exceptional case, points are ontop of eachother */
+ /* even more exceptional case, points are ontop of each other */
end[0]= start[0];
end[1]= start[1] + EDGE_SLIDE_MIN;
}
@@ -5330,8 +5267,6 @@ void initSeqSlide(TransInfo *t)
t->num.flag = 0;
t->num.idx_max = t->idx_max;
- t->ndof.axis = 1|2;
-
t->snap[0] = 0.0f;
t->snap[1] = floor(t->scene->r.frs_sec / t->scene->r.frs_sec_base);
t->snap[2] = 10.0f;
@@ -5386,7 +5321,6 @@ int SeqSlide(TransInfo *t, const int UNUSED(mval[2]))
VECCOPY(t->values, tvec);
}
else {
- applyNDofInput(&t->ndof, t->values);
snapGrid(t, t->values);
applyNumInput(&t->num, t->values);
}
@@ -5946,54 +5880,3 @@ void BIF_TransformSetUndo(char *UNUSED(str))
// TRANSFORM_FIX_ME
//Trans.undostr= str;
}
-
-
-#if 0 // TRANSFORM_FIX_ME
-static void NDofTransform(void)
-{
- float fval[7];
- float maxval = 50.0f; // also serves as threshold
- int axis = -1;
- int mode = 0;
- int i;
-
- getndof(fval);
-
- for(i = 0; i < 6; i++)
- {
- float val = fabs(fval[i]);
- if (val > maxval)
- {
- axis = i;
- maxval = val;
- }
- }
-
- switch(axis)
- {
- case -1:
- /* No proper axis found */
- break;
- case 0:
- case 1:
- case 2:
- mode = TFM_TRANSLATION;
- break;
- case 4:
- mode = TFM_ROTATION;
- break;
- case 3:
- case 5:
- mode = TFM_TRACKBALL;
- break;
- default:
- printf("ndof: what we are doing here ?");
- }
-
- if (mode != 0)
- {
- initTransform(mode, CTX_NDOF);
- Transform();
- }
-}
-#endif
diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c
index 62a55e2b7c9..4765bc77bf1 100644
--- a/source/blender/editors/transform/transform_ops.c
+++ b/source/blender/editors/transform/transform_ops.c
@@ -360,6 +360,12 @@ static int transform_modal(bContext *C, wmOperator *op, wmEvent *event)
TransInfo *t = op->customdata;
+ if (event->type == NDOF_MOTION)
+ {
+ /* puts("transform_modal: passing through NDOF_MOTION"); */
+ return OPERATOR_PASS_THROUGH;
+ }
+
/* XXX insert keys are called here, and require context */
t->context= C;
exit_code = transformEvent(t, event);
diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h
index 4cf744a7878..b5a1a36e126 100644
--- a/source/blender/makesdna/DNA_userdef_types.h
+++ b/source/blender/makesdna/DNA_userdef_types.h
@@ -365,7 +365,6 @@ typedef struct UserDef {
short recent_files; /* maximum number of recently used files to remember */
short smooth_viewtx; /* miliseconds to spend spinning the view */
short glreslimit;
- short ndof_pan, ndof_rotate;
short curssize;
short color_picker_type;
short ipo_new; /* interpolation mode for newly added F-Curves */
@@ -376,6 +375,10 @@ typedef struct UserDef {
short widget_unit; /* defaults to 20 for 72 DPI setting */
short anisotropic_filter;
+ /*short pad[3]; */
+
+ float ndof_sensitivity; /* overall sensitivity of 3D mouse */
+ int ndof_flag; /* flags for 3D mouse */
char versemaster[160];
char verseuser[160];
@@ -384,7 +387,7 @@ typedef struct UserDef {
short autokey_mode; /* autokeying mode */
short autokey_flag; /* flags for autokeying */
- short text_render, pad9; /*options for text rendering*/
+ short text_render, pad9[3]; /*options for text rendering*/
struct ColorBand coba_weight; /* from texture.h */
@@ -578,6 +581,28 @@ extern UserDef U; /* from blenkernel blender.c */
#define TH_OLDSKOOL 3
#define TH_SHADED 4
+/* ndof_flag (3D mouse options) */
+#define NDOF_SHOW_GUIDE (1 << 0)
+#define NDOF_FLY_HELICOPTER (1 << 1)
+#define NDOF_LOCK_HORIZON (1 << 2)
+/* the following might not need to be saved between sessions,
+ but they do need to live somewhere accessible... */
+#define NDOF_SHOULD_PAN (1 << 3)
+#define NDOF_SHOULD_ZOOM (1 << 4)
+#define NDOF_SHOULD_ROTATE (1 << 5)
+/* orbit navigation modes
+ only two options, so it's sort of a hyrbrid bool/enum
+ if ((U.ndof_flag & NDOF_ORBIT_MODE) == NDOF_OM_OBJECT)... */
+/*
+#define NDOF_ORBIT_MODE (1 << 6)
+#define NDOF_OM_TARGETCAMERA 0
+#define NDOF_OM_OBJECT NDOF_ORBIT_MODE
+*/
+/* actually... users probably don't care about what the mode
+ is called, just that it feels right */
+#define NDOF_ORBIT_INVERT_AXES (1 << 6)
+
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/makesdna/DNA_view3d_types.h b/source/blender/makesdna/DNA_view3d_types.h
index 7379493003d..89b8bad2806 100644
--- a/source/blender/makesdna/DNA_view3d_types.h
+++ b/source/blender/makesdna/DNA_view3d_types.h
@@ -130,7 +130,11 @@ typedef struct RegionView3D {
float twangle[3];
- float padf;
+ /* active rotation from NDOF or elsewhere */
+ float rot_angle;
+ float rot_axis[3];
+
+ char pad2[4];
} RegionView3D;
@@ -190,11 +194,10 @@ typedef struct View3D {
/* drawflags, denoting state */
short zbuf, transp, xray;
- char ndofmode; /* mode of transform for 6DOF devices -1 not found, 0 normal, 1 fly, 2 ob transform */
- char ndoffilter; /* filter for 6DOF devices 0 normal, 1 dominant */
-
+ char pad3[2];
+
void *properties_storage; /* Nkey panel stores stuff here (runtime only!) */
-
+
/* XXX depricated? */
struct bGPdata *gpd; /* Grease-Pencil Data (annotation layers) */
diff --git a/source/blender/makesrna/intern/rna_ID.c b/source/blender/makesrna/intern/rna_ID.c
index 48b5592dbfc..82217cdc3e4 100644
--- a/source/blender/makesrna/intern/rna_ID.c
+++ b/source/blender/makesrna/intern/rna_ID.c
@@ -35,6 +35,7 @@
#include "DNA_ID.h"
#include "DNA_vfont_types.h"
+#include "DNA_material_types.h"
#include "DNA_object_types.h"
#include "WM_types.h"
@@ -419,8 +420,9 @@ static void rna_def_ID_materials(BlenderRNA *brna)
func= RNA_def_function(srna, "pop", "material_pop_id");
RNA_def_function_ui_description(func, "Remove a material from the data block.");
- parm= RNA_def_int(func, "index", 0, 0, INT_MAX, "", "Index of material to remove.", 0, INT_MAX);
+ parm= RNA_def_int(func, "index", 0, 0, MAXMAT, "", "Index of material to remove.", 0, MAXMAT);
RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_boolean(func, "update_data", 0, "", "Update data by re-adjusting the material slots assigned.");
parm= RNA_def_pointer(func, "material", "Material", "", "Material to remove.");
RNA_def_function_return(func, parm);
}
diff --git a/source/blender/makesrna/intern/rna_action.c b/source/blender/makesrna/intern/rna_action.c
index 31a9d57bc93..25c08a57889 100644
--- a/source/blender/makesrna/intern/rna_action.c
+++ b/source/blender/makesrna/intern/rna_action.c
@@ -191,8 +191,9 @@ static void rna_Action_active_pose_marker_index_range(PointerRNA *ptr, int *min,
static void rna_Action_frame_range_get(PointerRNA *ptr,float *values)
-{
- calc_action_range(ptr->id.data, values, values+1, 1);
+{ /* don't include modifiers because they too easily can have very large
+ * ranges: MINAFRAMEF to MAXFRAMEF. */
+ calc_action_range(ptr->id.data, values, values+1, FALSE);
}
diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c
index 36a6762074c..64cd7dc646f 100644
--- a/source/blender/makesrna/intern/rna_userdef.c
+++ b/source/blender/makesrna/intern/rna_userdef.c
@@ -2742,17 +2742,30 @@ static void rna_def_userdef_input(BlenderRNA *brna)
RNA_def_property_int_sdna(prop, NULL, "dragthreshold");
RNA_def_property_range(prop, 3, 40);
RNA_def_property_ui_text(prop, "Drag Threshold", "Amount of pixels you have to drag before dragging UI items happens");
-
- prop= RNA_def_property(srna, "ndof_pan_speed", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "ndof_pan");
- RNA_def_property_range(prop, 0, 200);
- RNA_def_property_ui_text(prop, "NDof Pan Speed", "The overall panning speed of an NDOF device, as percent of standard");
- prop= RNA_def_property(srna, "ndof_rotate_speed", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "ndof_rotate");
- RNA_def_property_range(prop, 0, 200);
- RNA_def_property_ui_text(prop, "NDof Rotation Speed", "The overall rotation speed of an NDOF device, as percent of standard");
-
+ /* 3D mouse settings */
+ prop= RNA_def_property(srna, "ndof_sensitivity", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.25f, 4.0f);
+ RNA_def_property_ui_text(prop, "Sensitivity", "Overall sensitivity of the 3D Mouse");
+
+ prop= RNA_def_property(srna, "ndof_show_guide", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "ndof_flag", NDOF_SHOW_GUIDE);
+ RNA_def_property_ui_text(prop, "Show Navigation Guide", "Display the center and axis during rotation");
+ /* TODO: update description when fly-mode visuals are in place ("projected position in fly mode")*/
+
+ prop= RNA_def_property(srna, "ndof_orbit_invert_axes", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "ndof_flag", NDOF_ORBIT_INVERT_AXES);
+ RNA_def_property_ui_text(prop, "Invert Axes", "Toggle between moving the viewpoint or moving the scene being viewed");
+
+ prop= RNA_def_property(srna, "ndof_lock_horizon", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "ndof_flag", NDOF_LOCK_HORIZON);
+ RNA_def_property_ui_text(prop, "Lock Horizon", "Keep horizon level while flying with 3D Mouse");
+
+ prop= RNA_def_property(srna, "ndof_fly_helicopter", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "ndof_flag", NDOF_FLY_HELICOPTER);
+ RNA_def_property_ui_text(prop, "Helicopter Mode", "Device up/down directly controls your Z position");
+
+
prop= RNA_def_property(srna, "mouse_double_click_time", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "dbl_click_time");
RNA_def_property_range(prop, 1, 1000);
diff --git a/source/blender/makesrna/intern/rna_wm.c b/source/blender/makesrna/intern/rna_wm.c
index 73221c47c90..a046be59ab5 100644
--- a/source/blender/makesrna/intern/rna_wm.c
+++ b/source/blender/makesrna/intern/rna_wm.c
@@ -106,6 +106,46 @@ EnumPropertyItem event_timer_type_items[]= {
{TIMER2, "TIMER2", 0, "Timer 2", ""},
{0, NULL, 0, NULL, NULL}};
+EnumPropertyItem event_ndof_type_items[]= {
+ /* buttons on all 3dconnexion devices */
+ {NDOF_BUTTON_MENU, "NDOF_BUTTON_MENU", 0, "Menu", ""},
+ {NDOF_BUTTON_FIT, "NDOF_BUTTON_FIT", 0, "Fit", ""},
+ /* view buttons */
+ {NDOF_BUTTON_TOP, "NDOF_BUTTON_TOP", 0, "Top", ""},
+ {NDOF_BUTTON_BOTTOM, "NDOF_BUTTON_BOTTOM", 0, "Bottom", ""},
+ {NDOF_BUTTON_LEFT, "NDOF_BUTTON_LEFT", 0, "Left", ""},
+ {NDOF_BUTTON_RIGHT, "NDOF_BUTTON_RIGHT", 0, "Right", ""},
+ {NDOF_BUTTON_FRONT, "NDOF_BUTTON_FRONT", 0, "Front", ""},
+ {NDOF_BUTTON_BACK, "NDOF_BUTTON_BACK", 0, "Back", ""},
+ /* more views */
+ {NDOF_BUTTON_ISO1, "NDOF_BUTTON_ISO1", 0, "ISO 1", ""},
+ {NDOF_BUTTON_ISO2, "NDOF_BUTTON_ISO2", 0, "ISO 2", ""},
+ /* 90 degree rotations */
+ {NDOF_BUTTON_ROLL_CW, "NDOF_BUTTON_ROLL_CW", 0, "Roll CW", ""},
+ {NDOF_BUTTON_ROLL_CCW, "NDOF_BUTTON_ROLL_CCW", 0, "Roll CCW", ""},
+ {NDOF_BUTTON_SPIN_CW, "NDOF_BUTTON_SPIN_CW", 0, "Spin CW", ""},
+ {NDOF_BUTTON_SPIN_CCW, "NDOF_BUTTON_SPIN_CCW", 0, "Spin CCW", ""},
+ {NDOF_BUTTON_TILT_CW, "NDOF_BUTTON_TILT_CW", 0, "Tilt CW", ""},
+ {NDOF_BUTTON_TILT_CCW, "NDOF_BUTTON_TILT_CCW", 0, "Tilt CCW", ""},
+ /* device control */
+ {NDOF_BUTTON_ROTATE, "NDOF_BUTTON_ROTATE", 0, "Rotate", ""},
+ {NDOF_BUTTON_PANZOOM, "NDOF_BUTTON_PANZOOM", 0, "Pan/Zoom", ""},
+ {NDOF_BUTTON_DOMINANT, "NDOF_BUTTON_DOMINANT", 0, "Dominant", ""},
+ {NDOF_BUTTON_PLUS, "NDOF_BUTTON_PLUS", 0, "Plus", ""},
+ {NDOF_BUTTON_MINUS, "NDOF_BUTTON_MINUS", 0, "Minus", ""},
+ /* general-purpose buttons */
+ {NDOF_BUTTON_1, "NDOF_BUTTON_1", 0, "Button 1", ""},
+ {NDOF_BUTTON_2, "NDOF_BUTTON_2", 0, "Button 2", ""},
+ {NDOF_BUTTON_3, "NDOF_BUTTON_3", 0, "Button 3", ""},
+ {NDOF_BUTTON_4, "NDOF_BUTTON_4", 0, "Button 4", ""},
+ {NDOF_BUTTON_5, "NDOF_BUTTON_5", 0, "Button 5", ""},
+ {NDOF_BUTTON_6, "NDOF_BUTTON_6", 0, "Button 6", ""},
+ {NDOF_BUTTON_7, "NDOF_BUTTON_7", 0, "Button 7", ""},
+ {NDOF_BUTTON_8, "NDOF_BUTTON_8", 0, "Button 8", ""},
+ {NDOF_BUTTON_9, "NDOF_BUTTON_9", 0, "Button 9", ""},
+ {NDOF_BUTTON_10, "NDOF_BUTTON_10", 0, "Button 10", ""},
+ {0, NULL, 0, NULL, NULL}};
+
/* not returned: CAPSLOCKKEY, UNKNOWNKEY */
EnumPropertyItem event_type_items[] = {
@@ -256,6 +296,44 @@ EnumPropertyItem event_type_items[] = {
{TIMER0, "TIMER0", 0, "Timer 0", ""},
{TIMER1, "TIMER1", 0, "Timer 1", ""},
{TIMER2, "TIMER2", 0, "Timer 2", ""},
+ {0, "", 0, NULL, NULL},
+ /* buttons on all 3dconnexion devices */
+ {NDOF_BUTTON_MENU, "NDOF_BUTTON_MENU", 0, "Menu", ""},
+ {NDOF_BUTTON_FIT, "NDOF_BUTTON_FIT", 0, "Fit", ""},
+ /* view buttons */
+ {NDOF_BUTTON_TOP, "NDOF_BUTTON_TOP", 0, "Top", ""},
+ {NDOF_BUTTON_BOTTOM, "NDOF_BUTTON_BOTTOM", 0, "Bottom", ""},
+ {NDOF_BUTTON_LEFT, "NDOF_BUTTON_LEFT", 0, "Left", ""},
+ {NDOF_BUTTON_RIGHT, "NDOF_BUTTON_RIGHT", 0, "Right", ""},
+ {NDOF_BUTTON_FRONT, "NDOF_BUTTON_FRONT", 0, "Front", ""},
+ {NDOF_BUTTON_BACK, "NDOF_BUTTON_BACK", 0, "Back", ""},
+ /* more views */
+ {NDOF_BUTTON_ISO1, "NDOF_BUTTON_ISO1", 0, "ISO 1", ""},
+ {NDOF_BUTTON_ISO2, "NDOF_BUTTON_ISO2", 0, "ISO 2", ""},
+ /* 90 degree rotations */
+ {NDOF_BUTTON_ROLL_CW, "NDOF_BUTTON_ROLL_CW", 0, "Roll CW", ""},
+ {NDOF_BUTTON_ROLL_CCW, "NDOF_BUTTON_ROLL_CCW", 0, "Roll CCW", ""},
+ {NDOF_BUTTON_SPIN_CW, "NDOF_BUTTON_SPIN_CW", 0, "Spin CW", ""},
+ {NDOF_BUTTON_SPIN_CCW, "NDOF_BUTTON_SPIN_CCW", 0, "Spin CCW", ""},
+ {NDOF_BUTTON_TILT_CW, "NDOF_BUTTON_TILT_CW", 0, "Tilt CW", ""},
+ {NDOF_BUTTON_TILT_CCW, "NDOF_BUTTON_TILT_CCW", 0, "Tilt CCW", ""},
+ /* device control */
+ {NDOF_BUTTON_ROTATE, "NDOF_BUTTON_ROTATE", 0, "Rotate", ""},
+ {NDOF_BUTTON_PANZOOM, "NDOF_BUTTON_PANZOOM", 0, "Pan/Zoom", ""},
+ {NDOF_BUTTON_DOMINANT, "NDOF_BUTTON_DOMINANT", 0, "Dominant", ""},
+ {NDOF_BUTTON_PLUS, "NDOF_BUTTON_PLUS", 0, "Plus", ""},
+ {NDOF_BUTTON_MINUS, "NDOF_BUTTON_MINUS", 0, "Minus", ""},
+ /* general-purpose buttons */
+ {NDOF_BUTTON_1, "NDOF_BUTTON_1", 0, "Button 1", ""},
+ {NDOF_BUTTON_2, "NDOF_BUTTON_2", 0, "Button 2", ""},
+ {NDOF_BUTTON_3, "NDOF_BUTTON_3", 0, "Button 3", ""},
+ {NDOF_BUTTON_4, "NDOF_BUTTON_4", 0, "Button 4", ""},
+ {NDOF_BUTTON_5, "NDOF_BUTTON_5", 0, "Button 5", ""},
+ {NDOF_BUTTON_6, "NDOF_BUTTON_6", 0, "Button 6", ""},
+ {NDOF_BUTTON_7, "NDOF_BUTTON_7", 0, "Button 7", ""},
+ {NDOF_BUTTON_8, "NDOF_BUTTON_8", 0, "Button 8", ""},
+ {NDOF_BUTTON_9, "NDOF_BUTTON_9", 0, "Button 9", ""},
+ {NDOF_BUTTON_10, "NDOF_BUTTON_10", 0, "Button 10", ""},
{0, NULL, 0, NULL, NULL}};
EnumPropertyItem keymap_propvalue_items[] = {
@@ -303,6 +381,7 @@ EnumPropertyItem wm_report_items[] = {
#define KMI_TYPE_TWEAK 2
#define KMI_TYPE_TEXTINPUT 3
#define KMI_TYPE_TIMER 4
+#define KMI_TYPE_NDOF 5
#ifdef RNA_RUNTIME
@@ -433,6 +512,7 @@ static int rna_wmKeyMapItem_map_type_get(PointerRNA *ptr)
if(ISKEYBOARD(kmi->type)) return KMI_TYPE_KEYBOARD;
if(ISTWEAK(kmi->type)) return KMI_TYPE_TWEAK;
if(ISMOUSE(kmi->type)) return KMI_TYPE_MOUSE;
+ if(ISNDOF(kmi->type)) return KMI_TYPE_NDOF;
if(kmi->type == KM_TEXTINPUT) return KMI_TYPE_TEXTINPUT;
return KMI_TYPE_KEYBOARD;
}
@@ -464,6 +544,10 @@ static void rna_wmKeyMapItem_map_type_set(PointerRNA *ptr, int value)
kmi->type= TIMER;
kmi->val= KM_NOTHING;
break;
+ case KMI_TYPE_NDOF:
+ kmi->type = NDOF_BUTTON_MENU;
+ kmi->val = KM_NOTHING;
+ break;
}
}
}
@@ -475,6 +559,7 @@ static EnumPropertyItem *rna_KeyMapItem_type_itemf(bContext *UNUSED(C), PointerR
if(map_type == KMI_TYPE_MOUSE) return event_mouse_type_items;
if(map_type == KMI_TYPE_TWEAK) return event_tweak_type_items;
if(map_type == KMI_TYPE_TIMER) return event_timer_type_items;
+ if(map_type == KMI_TYPE_NDOF) return event_ndof_type_items;
else return event_type_items;
}
@@ -482,7 +567,7 @@ static EnumPropertyItem *rna_KeyMapItem_value_itemf(bContext *UNUSED(C), Pointer
{
int map_type= rna_wmKeyMapItem_map_type_get(ptr);
- if(map_type == KMI_TYPE_MOUSE || map_type == KMI_TYPE_KEYBOARD) return event_keymouse_value_items;
+ if(map_type == KMI_TYPE_MOUSE || map_type == KMI_TYPE_KEYBOARD || map_type == KMI_TYPE_NDOF) return event_keymouse_value_items;
if(map_type == KMI_TYPE_TWEAK) return event_tweak_value_items;
else return event_value_items;
}
@@ -1653,6 +1738,7 @@ static void rna_def_keyconfig(BlenderRNA *brna)
{KMI_TYPE_KEYBOARD, "KEYBOARD", 0, "Keyboard", ""},
{KMI_TYPE_TWEAK, "TWEAK", 0, "Tweak", ""},
{KMI_TYPE_MOUSE, "MOUSE", 0, "Mouse", ""},
+ {KMI_TYPE_NDOF, "NDOF", 0, "NDOF", ""},
{KMI_TYPE_TEXTINPUT, "TEXTINPUT", 0, "Text Input", ""},
{KMI_TYPE_TIMER, "TIMER", 0, "Timer", ""},
{0, NULL, 0, NULL, NULL}};
diff --git a/source/blender/makesrna/intern/rna_wm_api.c b/source/blender/makesrna/intern/rna_wm_api.c
index e250cc84aa3..d44b68950f7 100644
--- a/source/blender/makesrna/intern/rna_wm_api.c
+++ b/source/blender/makesrna/intern/rna_wm_api.c
@@ -205,7 +205,7 @@ void RNA_api_operator(StructRNA *srna)
/* check */
func= RNA_def_function(srna, "check", NULL);
- RNA_def_function_ui_description(func, "Check the operator settings.");
+ RNA_def_function_ui_description(func, "Check the operator settings, return True to signal a change to redraw.");
RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL);
parm= RNA_def_pointer(func, "context", "Context", "", "");
RNA_def_property_flag(parm, PROP_REQUIRED|PROP_NEVER_NULL);
diff --git a/source/blender/modifiers/intern/MOD_uvproject.c b/source/blender/modifiers/intern/MOD_uvproject.c
index a5d2e0b38c7..922ae8c1e92 100644
--- a/source/blender/modifiers/intern/MOD_uvproject.c
+++ b/source/blender/modifiers/intern/MOD_uvproject.c
@@ -42,6 +42,7 @@
#include "DNA_object_types.h"
#include "BLI_math.h"
+#include "BLI_string.h"
#include "BLI_uvproject.h"
#include "BLI_utildefines.h"
@@ -83,6 +84,7 @@ static void copyData(ModifierData *md, ModifierData *target)
tumd->aspecty = umd->aspecty;
tumd->scalex = umd->scalex;
tumd->scaley = umd->scaley;
+ BLI_strncpy(tumd->uvlayer_name, umd->uvlayer_name, sizeof(umd->uvlayer_name));
}
static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *UNUSED(md))
diff --git a/source/blender/python/intern/bpy_props.c b/source/blender/python/intern/bpy_props.c
index 0ba80bf0850..a0ad1ff7850 100644
--- a/source/blender/python/intern/bpy_props.c
+++ b/source/blender/python/intern/bpy_props.c
@@ -326,6 +326,11 @@ static int bpy_prop_callback_assign(struct PropertyRNA *prop, PyObject *update_c
" :type description: string\n" \
+#define BPY_PROPDEF_UNIT_DOC \
+" :arg unit: Enumerator in ['NONE', 'LENGTH', 'AREA', 'VOLUME', 'ROTATION', 'TIME', 'VELOCITY', 'ACCELERATION'].\n" \
+" :type unit: string\n" \
+
+
#define BPY_PROPDEF_UPDATE_DOC \
" :arg update: function to be called when this value is modified,\n" \
" This function must take 2 values (self, context) and return None.\n" \
@@ -639,8 +644,7 @@ BPY_PROPDEF_DESC_DOC
" :type options: set\n"
" :arg subtype: Enumerator in ['UNSIGNED', 'PERCENTAGE', 'FACTOR', 'ANGLE', 'TIME', 'DISTANCE', 'NONE'].\n"
" :type subtype: string\n"
-" :arg unit: Enumerator in ['NONE', 'LENGTH', 'AREA', 'VOLUME', 'ROTATION', 'TIME', 'VELOCITY', 'ACCELERATION'].\n"
-" :type unit: string\n"
+BPY_PROPDEF_UNIT_DOC
BPY_PROPDEF_UPDATE_DOC
);
static PyObject *BPy_FloatProperty(PyObject *self, PyObject *args, PyObject *kw)
@@ -679,7 +683,7 @@ static PyObject *BPy_FloatProperty(PyObject *self, PyObject *args, PyObject *kw)
BPY_PROPDEF_SUBTYPE_CHECK(FloatProperty, property_flag_items, property_subtype_number_items)
if(pyunit && RNA_enum_value_from_id(property_unit_items, pyunit, &unit)==0) {
- PyErr_Format(PyExc_TypeError, "FloatProperty(unit='%s'): invalid unit");
+ PyErr_Format(PyExc_TypeError, "FloatProperty(unit='%s'): invalid unit", pyunit);
return NULL;
}
@@ -716,6 +720,7 @@ BPY_PROPDEF_DESC_DOC
" :type options: set\n"
" :arg subtype: Enumerator in ['COLOR', 'TRANSLATION', 'DIRECTION', 'VELOCITY', 'ACCELERATION', 'MATRIX', 'EULER', 'QUATERNION', 'AXISANGLE', 'XYZ', 'COLOR_GAMMA', 'LAYER', 'NONE'].\n"
" :type subtype: string\n"
+BPY_PROPDEF_UNIT_DOC
" :arg size: Vector dimensions in [1, and " STRINGIFY(PYRNA_STACK_ARRAY) "].\n"
" :type size: int\n"
BPY_PROPDEF_UPDATE_DOC
@@ -727,7 +732,7 @@ static PyObject *BPy_FloatVectorProperty(PyObject *self, PyObject *args, PyObjec
BPY_PROPDEF_HEAD(FloatVectorProperty)
if(srna) {
- static const char *kwlist[]= {"attr", "name", "description", "default", "min", "max", "soft_min", "soft_max", "step", "precision", "options", "subtype", "size", "update", NULL};
+ static const char *kwlist[]= {"attr", "name", "description", "default", "min", "max", "soft_min", "soft_max", "step", "precision", "options", "subtype", "unit", "size", "update", NULL};
const char *id=NULL, *name="", *description="";
int id_len;
float min=-FLT_MAX, max=FLT_MAX, soft_min=-FLT_MAX, soft_max=FLT_MAX, step=3, def[PYRNA_STACK_ARRAY]={0.0f};
@@ -738,15 +743,17 @@ static PyObject *BPy_FloatVectorProperty(PyObject *self, PyObject *args, PyObjec
int opts=0;
char *pysubtype= NULL;
int subtype= PROP_NONE;
+ char *pyunit= NULL;
+ int unit= PROP_UNIT_NONE;
PyObject *update_cb= NULL;
if (!PyArg_ParseTupleAndKeywords(args, kw,
- "s#|ssOfffffiO!siO:FloatVectorProperty",
+ "s#|ssOfffffiO!ssiO:FloatVectorProperty",
(char **)kwlist, &id, &id_len,
&name, &description, &pydef,
&min, &max, &soft_min, &soft_max,
&step, &precision, &PySet_Type,
- &pyopts, &pysubtype, &size,
+ &pyopts, &pysubtype, &pyunit, &size,
&update_cb))
{
return NULL;
@@ -754,6 +761,11 @@ static PyObject *BPy_FloatVectorProperty(PyObject *self, PyObject *args, PyObjec
BPY_PROPDEF_SUBTYPE_CHECK(FloatVectorProperty, property_flag_items, property_subtype_array_items)
+ if(pyunit && RNA_enum_value_from_id(property_unit_items, pyunit, &unit)==0) {
+ PyErr_Format(PyExc_TypeError, "FloatVectorProperty(unit='%s'): invalid unit", pyunit);
+ return NULL;
+ }
+
if(size < 1 || size > PYRNA_STACK_ARRAY) {
PyErr_Format(PyExc_TypeError, "FloatVectorProperty(size=%d): size must be between 0 and " STRINGIFY(PYRNA_STACK_ARRAY), size);
return NULL;
@@ -766,7 +778,7 @@ static PyObject *BPy_FloatVectorProperty(PyObject *self, PyObject *args, PyObjec
return NULL;
}
- prop= RNA_def_property(srna, id, PROP_FLOAT, subtype);
+ prop= RNA_def_property(srna, id, PROP_FLOAT, subtype | unit);
RNA_def_property_array(prop, size);
if(pydef) RNA_def_property_float_array_default(prop, def);
RNA_def_property_range(prop, min, max);
diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c
index 6e1b9c807f3..502b25842de 100644
--- a/source/blender/python/intern/bpy_rna.c
+++ b/source/blender/python/intern/bpy_rna.c
@@ -3262,11 +3262,15 @@ static PyObject *pyrna_prop_dir(BPy_PropertyRNA *self)
* */
ret= PyList_New(0);
- if (!BPy_PropertyRNA_CheckExact(self))
+ if (!BPy_PropertyRNA_CheckExact(self)) {
pyrna_dir_members_py(ret, (PyObject *)self);
+ }
- if(RNA_property_collection_type_get(&self->ptr, self->prop, &r_ptr))
- pyrna_dir_members_rna(ret, &r_ptr);
+ if(RNA_property_type(self->prop) == PROP_COLLECTION) {
+ if(RNA_property_collection_type_get(&self->ptr, self->prop, &r_ptr)) {
+ pyrna_dir_members_rna(ret, &r_ptr);
+ }
+ }
return ret;
}
@@ -6407,7 +6411,9 @@ PyDoc_STRVAR(pyrna_register_class_doc,
" If the class has a *register* class method it will be called\n"
" before registration.\n"
"\n"
-" .. note:: :exc:`ValueError` exception is raised if the class is not a\n"
+" .. note::\n"
+"\n"
+" :exc:`ValueError` exception is raised if the class is not a\n"
" subclass of a registerable blender class.\n"
"\n"
);
diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h
index 49bd3ede37d..7fd52e89a5f 100644
--- a/source/blender/windowmanager/WM_types.h
+++ b/source/blender/windowmanager/WM_types.h
@@ -377,6 +377,26 @@ typedef struct wmTabletData {
float Ytilt; /* as above */
} wmTabletData;
+typedef enum { // motion progress, for modal handlers
+ P_NOT_STARTED,
+ P_STARTING, // <--
+ P_IN_PROGRESS, // <-- only these are sent for NDOF motion
+ P_FINISHING, // <--
+ P_FINISHED
+ } wmProgress;
+
+typedef struct wmNDOFMotionData {
+ /* awfully similar to GHOST_TEventNDOFMotionData... */
+ // 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 tvec[3]; // translation
+ float rvec[3]; // 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
+ wmProgress progress; // is this the first event, the last, or one of many in between?
+} wmNDOFMotionData;
+
typedef struct wmTimer {
struct wmTimer *next, *prev;
diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c
index ce3830b059c..0abae2e06b7 100644
--- a/source/blender/windowmanager/intern/wm_event_system.c
+++ b/source/blender/windowmanager/intern/wm_event_system.c
@@ -1815,7 +1815,10 @@ void wm_event_do_handlers(bContext *C)
/* for regions having custom cursors */
wm_paintcursor_test(C, event);
}
-
+ else if (event->type==NDOF_MOTION) {
+ win->addmousemove = TRUE;
+ }
+
for(sa= win->screen->areabase.first; sa; sa= sa->next) {
if(wm_event_inside_i(event, &sa->totrct)) {
CTX_wm_area_set(C, sa);
@@ -1879,7 +1882,10 @@ void wm_event_do_handlers(bContext *C)
if(doit && win->screen && win->screen->subwinactive != win->screen->mainwin) {
win->eventstate->prevx= event->x;
win->eventstate->prevy= event->y;
+ //printf("win->eventstate->prev = %d %d\n", event->x, event->y);
}
+ else
+ ;//printf("not setting prev to %d %d\n", event->x, event->y);
}
/* store last event for this window */
@@ -1922,6 +1928,7 @@ void wm_event_do_handlers(bContext *C)
/* only add mousemove when queue was read entirely */
if(win->addmousemove && win->eventstate) {
wmEvent tevent= *(win->eventstate);
+ //printf("adding MOUSEMOVE %d %d\n", tevent.x, tevent.y);
tevent.type= MOUSEMOVE;
tevent.prevx= tevent.x;
tevent.prevy= tevent.y;
@@ -2309,6 +2316,30 @@ static void update_tablet_data(wmWindow *win, wmEvent *event)
}
}
+/* adds customdata to event */
+static void attach_ndof_data(wmEvent* event, const GHOST_TEventNDOFMotionData* ghost)
+{
+ wmNDOFMotionData* data = MEM_mallocN(sizeof(wmNDOFMotionData), "customdata NDOF");
+
+ const float s = U.ndof_sensitivity;
+
+ data->tvec[0]= s * ghost->tx;
+ data->tvec[1]= s * ghost->ty;
+ data->tvec[2]= s * ghost->tz;
+
+ data->rvec[0]= s * ghost->rx;
+ data->rvec[1]= s * ghost->ry;
+ data->rvec[2]= s * ghost->rz;
+
+ data->dt = ghost->dt;
+
+ data->progress = (wmProgress) ghost->progress;
+
+ event->custom = EVT_DATA_NDOF_MOTION;
+ event->customdata = data;
+ event->customdatafree = 1;
+}
+
/* imperfect but probably usable... draw/enable drags to other windows */
static wmWindow *wm_event_cursor_other_windows(wmWindowManager *wm, wmWindow *win, wmEvent *evt)
{
@@ -2355,7 +2386,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int U
{
wmWindow *owin;
wmEvent event, *evt= win->eventstate;
-
+
/* initialize and copy state (only mouse x y and modifiers) */
event= *evt;
@@ -2384,6 +2415,8 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int U
update_tablet_data(win, &event);
wm_event_add(win, &event);
+
+ //printf("sending MOUSEMOVE %d %d\n", event.x, event.y);
/* also add to other window if event is there, this makes overdraws disappear nicely */
/* it remaps mousecoord to other window in event */
@@ -2557,6 +2590,38 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int U
break;
}
+ case GHOST_kEventNDOFMotion: {
+ event.type = NDOF_MOTION;
+ attach_ndof_data(&event, customdata);
+ wm_event_add(win, &event);
+
+ //printf("sending NDOF_MOTION, prev = %d %d\n", event.x, event.y);
+
+ break;
+ }
+
+ case GHOST_kEventNDOFButton: {
+ GHOST_TEventNDOFButtonData* e = customdata;
+
+ event.type = NDOF_BUTTON_NONE + e->button;
+
+ switch (e->action) {
+ case GHOST_kPress:
+ event.val = KM_PRESS;
+ break;
+ case GHOST_kRelease:
+ event.val = KM_RELEASE;
+ break;
+ }
+
+ event.custom = 0;
+ event.customdata = NULL;
+
+ wm_event_add(win, &event);
+
+ break;
+ }
+
case GHOST_kEventUnknown:
case GHOST_kNumEventTypes:
break;
diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c
index 4c280fe4341..e22829577f4 100644
--- a/source/blender/windowmanager/intern/wm_init_exit.c
+++ b/source/blender/windowmanager/intern/wm_init_exit.c
@@ -183,8 +183,6 @@ void WM_init(bContext *C, int argc, const char **argv)
ED_preview_init_dbase();
- G.ndofdevice = -1; /* XXX bad initializer, needs set otherwise buttons show! */
-
WM_read_history();
/* allow a path of "", this is what happens when making a new file */
diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c
index 29afdb570ea..a47dfacf358 100644
--- a/source/blender/windowmanager/intern/wm_operators.c
+++ b/source/blender/windowmanager/intern/wm_operators.c
@@ -3416,7 +3416,49 @@ static void WM_OT_memory_statistics(wmOperatorType *ot)
}
/* ******************************************************* */
-
+
+static int wm_ndof_sensitivity_exec(bContext *UNUSED(C), wmOperator *op)
+{
+ const float min = 0.25f, max = 4.f; // TODO: get these from RNA property
+ float change;
+ float sensitivity = U.ndof_sensitivity;
+
+ if(RNA_boolean_get(op->ptr, "fast"))
+ change = 0.5f; // 50% change
+ else
+ change = 0.1f; // 10%
+
+ if(RNA_boolean_get(op->ptr, "decrease")) {
+ sensitivity -= sensitivity * change;
+ if (sensitivity < min)
+ sensitivity = min;
+ }
+ else {
+ sensitivity += sensitivity * change;
+ if (sensitivity > max)
+ sensitivity = max;
+ }
+
+ if (sensitivity != U.ndof_sensitivity) {
+ U.ndof_sensitivity = sensitivity;
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+static void WM_OT_ndof_sensitivity_change(wmOperatorType *ot)
+{
+ ot->name= "Change NDOF sensitivity";
+ ot->idname= "WM_OT_ndof_sensitivity_change";
+ ot->description="Change NDOF sensitivity";
+
+ ot->exec= wm_ndof_sensitivity_exec;
+
+ RNA_def_boolean(ot->srna, "decrease", 1, "Decrease NDOF sensitivity", "If true then action decreases NDOF sensitivity instead of increasing");
+ RNA_def_boolean(ot->srna, "fast", 0, "Fast NDOF sensitivity change", "If true then sensitivity changes 50%, otherwise 10%");
+}
+
+/* ******************************************************* */
/* called on initialize WM_exit() */
void wm_operatortype_free(void)
{
@@ -3455,6 +3497,7 @@ void wm_operatortype_init(void)
WM_operatortype_append(WM_OT_search_menu);
WM_operatortype_append(WM_OT_call_menu);
WM_operatortype_append(WM_OT_radial_control);
+ WM_operatortype_append(WM_OT_ndof_sensitivity_change);
#if defined(WIN32)
WM_operatortype_append(WM_OT_console_toggle);
#endif
@@ -3674,11 +3717,12 @@ void wm_window_keymap(wmKeyConfig *keyconf)
/* debug/testing */
WM_keymap_verify_item(keymap, "WM_OT_redraw_timer", TKEY, KM_PRESS, KM_ALT|KM_CTRL, 0);
WM_keymap_verify_item(keymap, "WM_OT_debug_menu", DKEY, KM_PRESS, KM_ALT|KM_CTRL, 0);
- WM_keymap_verify_item(keymap, "WM_OT_search_menu", SPACEKEY, KM_PRESS, 0, 0);
-
- /* Space switching */
+ /* menus that can be accessed anywhere in blender */
+ WM_keymap_verify_item(keymap, "WM_OT_search_menu", SPACEKEY, KM_PRESS, 0, 0);
+ WM_keymap_add_menu(keymap, "VIEW3D_MT_ndof_settings", NDOF_BUTTON_MENU, KM_PRESS, 0, 0);
+ /* Space switching */
kmi = WM_keymap_add_item(keymap, "WM_OT_context_set_enum", F2KEY, KM_PRESS, KM_SHIFT, 0); /* new in 2.5x, was DXF export */
RNA_string_set(kmi->ptr, "data_path", "area.type");
RNA_string_set(kmi->ptr, "value", "LOGIC_EDITOR");
@@ -3722,6 +3766,23 @@ void wm_window_keymap(wmKeyConfig *keyconf)
kmi = WM_keymap_add_item(keymap, "WM_OT_context_set_enum", F12KEY, KM_PRESS, KM_SHIFT, 0);
RNA_string_set(kmi->ptr, "data_path", "area.type");
RNA_string_set(kmi->ptr, "value", "DOPESHEET_EDITOR");
+
+ /* ndof speed */
+ kmi= WM_keymap_add_item(keymap, "WM_OT_ndof_sensitivity_change", NDOF_BUTTON_PLUS, KM_PRESS, 0, 0);
+ RNA_boolean_set(kmi->ptr, "decrease", FALSE);
+ RNA_boolean_set(kmi->ptr, "fast", FALSE);
+
+ kmi= WM_keymap_add_item(keymap, "WM_OT_ndof_sensitivity_change", NDOF_BUTTON_MINUS, KM_PRESS, 0, 0);
+ RNA_boolean_set(kmi->ptr, "decrease", TRUE);
+ RNA_boolean_set(kmi->ptr, "fast", FALSE);
+
+ kmi= WM_keymap_add_item(keymap, "WM_OT_ndof_sensitivity_change", NDOF_BUTTON_PLUS, KM_PRESS, KM_SHIFT, 0);
+ RNA_boolean_set(kmi->ptr, "decrease", FALSE);
+ RNA_boolean_set(kmi->ptr, "fast", TRUE);
+
+ kmi= WM_keymap_add_item(keymap, "WM_OT_ndof_sensitivity_change", NDOF_BUTTON_MINUS, KM_PRESS, KM_SHIFT, 0);
+ RNA_boolean_set(kmi->ptr, "decrease", TRUE);
+ RNA_boolean_set(kmi->ptr, "fast", TRUE);
gesture_circle_modal_keymap(keyconf);
gesture_border_modal_keymap(keyconf);
diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c
index 9b1695be67a..7d6010786d2 100644
--- a/source/blender/windowmanager/intern/wm_window.c
+++ b/source/blender/windowmanager/intern/wm_window.c
@@ -621,12 +621,12 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr private)
if (!ghostwin) {
// XXX - should be checked, why are we getting an event here, and
// what is it?
-
+ puts("<!> event has no window");
return 1;
} else if (!GHOST_ValidWindow(g_system, ghostwin)) {
// XXX - should be checked, why are we getting an event here, and
// what is it?
-
+ puts("<!> event has invalid window");
return 1;
} else {
win= GHOST_GetWindowUserData(ghostwin);
diff --git a/source/blender/windowmanager/wm_event_types.h b/source/blender/windowmanager/wm_event_types.h
index ee080e7c0aa..579f20ca605 100644
--- a/source/blender/windowmanager/wm_event_types.h
+++ b/source/blender/windowmanager/wm_event_types.h
@@ -45,6 +45,7 @@
#define EVT_DATA_GESTURE 2
#define EVT_DATA_TIMER 3
#define EVT_DATA_LISTBASE 4
+#define EVT_DATA_NDOF_MOTION 5
/* tablet active, matches GHOST_TTabletMode */
#define EVT_TABLET_NONE 0
@@ -78,6 +79,56 @@
#define INBETWEEN_MOUSEMOVE 17
+/* NDOF (from SpaceNavigator & friends)
+ These should be kept in sync with GHOST_NDOFManager.h
+ Ordering matters, exact values do not. */
+
+#define NDOF_MOTION 400
+
+enum {
+ // used internally, never sent
+ NDOF_BUTTON_NONE = NDOF_MOTION,
+ // 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,
+ NDOF_LAST
+ };
+
+
/* SYSTEM : 0x01xx */
#define INPUTCHANGE 0x0103 /* input connected or disconnected */
#define WINDEACTIVATE 0x0104 /* window is deactivated, focus lost */
@@ -240,8 +291,11 @@
/* test whether the event is tweak event */
#define ISTWEAK(event) (event >= EVT_TWEAK_L && event <= EVT_GESTURE)
+ /* test whether the event is a NDOF event */
+#define ISNDOF(event) (event >= NDOF_MOTION && event < NDOF_LAST)
+
/* test whether event type is acceptable as hotkey, excluding modifiers */
-#define ISHOTKEY(event) ((ISKEYBOARD(event) || ISMOUSE(event)) && event!=ESCKEY && !(event>=LEFTCTRLKEY && event<=LEFTSHIFTKEY) && !(event>=UNKNOWNKEY && event<=GRLESSKEY))
+#define ISHOTKEY(event) ((ISKEYBOARD(event) || ISMOUSE(event) || ISNDOF(event)) && event!=ESCKEY && !(event>=LEFTCTRLKEY && event<=LEFTSHIFTKEY) && !(event>=UNKNOWNKEY && event<=GRLESSKEY))
/* **************** BLENDER GESTURE EVENTS (0x5000) **************** */
diff --git a/source/gameengine/Ketsji/KX_PyConstraintBinding.cpp b/source/gameengine/Ketsji/KX_PyConstraintBinding.cpp
index 12024657149..fde127b7ef5 100644
--- a/source/gameengine/Ketsji/KX_PyConstraintBinding.cpp
+++ b/source/gameengine/Ketsji/KX_PyConstraintBinding.cpp
@@ -38,12 +38,20 @@
#include "KX_PhysicsObjectWrapper.h"
#include "PHY_IPhysicsController.h"
#include "PHY_IVehicle.h"
+#include "PHY_DynamicTypes.h"
#include "MT_Matrix3x3.h"
#include "PyObjectPlus.h"
+#ifdef USE_BULLET
+# include "LinearMath/btIDebugDraw.h"
+#endif
+
#ifdef WITH_PYTHON
+// macro copied from KX_PythonInit.cpp
+#define KX_MACRO_addTypesToDict(dict, name, name2) PyDict_SetItemString(dict, #name, item=PyLong_FromSsize_t(name2)); Py_DECREF(item)
+
// nasty glob variable to connect scripting language
// if there is a better way (without global), please do so!
static PHY_IPhysicsEnvironment* g_CurrentActivePhysicsEnvironment = NULL;
@@ -84,8 +92,8 @@ static char gPyGetAppliedImpulse__doc__[] = "getAppliedImpulse(int constraintId)
static PyObject* gPySetGravity(PyObject* self,
- PyObject* args,
- PyObject* kwds)
+ PyObject* args,
+ PyObject* kwds)
{
float x,y,z;
if (PyArg_ParseTuple(args,"fff",&x,&y,&z))
@@ -101,8 +109,8 @@ static PyObject* gPySetGravity(PyObject* self,
}
static PyObject* gPySetDebugMode(PyObject* self,
- PyObject* args,
- PyObject* kwds)
+ PyObject* args,
+ PyObject* kwds)
{
int mode;
if (PyArg_ParseTuple(args,"i",&mode))
@@ -124,8 +132,8 @@ static PyObject* gPySetDebugMode(PyObject* self,
static PyObject* gPySetNumTimeSubSteps(PyObject* self,
- PyObject* args,
- PyObject* kwds)
+ PyObject* args,
+ PyObject* kwds)
{
int substep;
if (PyArg_ParseTuple(args,"i",&substep))
@@ -143,8 +151,8 @@ static PyObject* gPySetNumTimeSubSteps(PyObject* self,
static PyObject* gPySetNumIterations(PyObject* self,
- PyObject* args,
- PyObject* kwds)
+ PyObject* args,
+ PyObject* kwds)
{
int iter;
if (PyArg_ParseTuple(args,"i",&iter))
@@ -161,10 +169,9 @@ static PyObject* gPySetNumIterations(PyObject* self,
}
-
static PyObject* gPySetDeactivationTime(PyObject* self,
- PyObject* args,
- PyObject* kwds)
+ PyObject* args,
+ PyObject* kwds)
{
float deactive_time;
if (PyArg_ParseTuple(args,"f",&deactive_time))
@@ -182,8 +189,8 @@ static PyObject* gPySetDeactivationTime(PyObject* self,
static PyObject* gPySetDeactivationLinearTreshold(PyObject* self,
- PyObject* args,
- PyObject* kwds)
+ PyObject* args,
+ PyObject* kwds)
{
float linearDeactivationTreshold;
if (PyArg_ParseTuple(args,"f",&linearDeactivationTreshold))
@@ -201,8 +208,8 @@ static PyObject* gPySetDeactivationLinearTreshold(PyObject* self,
static PyObject* gPySetDeactivationAngularTreshold(PyObject* self,
- PyObject* args,
- PyObject* kwds)
+ PyObject* args,
+ PyObject* kwds)
{
float angularDeactivationTreshold;
if (PyArg_ParseTuple(args,"f",&angularDeactivationTreshold))
@@ -219,8 +226,8 @@ static PyObject* gPySetDeactivationAngularTreshold(PyObject* self,
}
static PyObject* gPySetContactBreakingTreshold(PyObject* self,
- PyObject* args,
- PyObject* kwds)
+ PyObject* args,
+ PyObject* kwds)
{
float contactBreakingTreshold;
if (PyArg_ParseTuple(args,"f",&contactBreakingTreshold))
@@ -238,8 +245,8 @@ static PyObject* gPySetContactBreakingTreshold(PyObject* self,
static PyObject* gPySetCcdMode(PyObject* self,
- PyObject* args,
- PyObject* kwds)
+ PyObject* args,
+ PyObject* kwds)
{
float ccdMode;
if (PyArg_ParseTuple(args,"f",&ccdMode))
@@ -256,8 +263,8 @@ static PyObject* gPySetCcdMode(PyObject* self,
}
static PyObject* gPySetSorConstant(PyObject* self,
- PyObject* args,
- PyObject* kwds)
+ PyObject* args,
+ PyObject* kwds)
{
float sor;
if (PyArg_ParseTuple(args,"f",&sor))
@@ -274,8 +281,8 @@ static PyObject* gPySetSorConstant(PyObject* self,
}
static PyObject* gPySetSolverTau(PyObject* self,
- PyObject* args,
- PyObject* kwds)
+ PyObject* args,
+ PyObject* kwds)
{
float tau;
if (PyArg_ParseTuple(args,"f",&tau))
@@ -293,8 +300,8 @@ static PyObject* gPySetSolverTau(PyObject* self,
static PyObject* gPySetSolverDamping(PyObject* self,
- PyObject* args,
- PyObject* kwds)
+ PyObject* args,
+ PyObject* kwds)
{
float damping;
if (PyArg_ParseTuple(args,"f",&damping))
@@ -311,8 +318,8 @@ static PyObject* gPySetSolverDamping(PyObject* self,
}
static PyObject* gPySetLinearAirDamping(PyObject* self,
- PyObject* args,
- PyObject* kwds)
+ PyObject* args,
+ PyObject* kwds)
{
float damping;
if (PyArg_ParseTuple(args,"f",&damping))
@@ -330,8 +337,8 @@ static PyObject* gPySetLinearAirDamping(PyObject* self,
static PyObject* gPySetUseEpa(PyObject* self,
- PyObject* args,
- PyObject* kwds)
+ PyObject* args,
+ PyObject* kwds)
{
int epa;
if (PyArg_ParseTuple(args,"i",&epa))
@@ -347,8 +354,8 @@ static PyObject* gPySetUseEpa(PyObject* self,
Py_RETURN_NONE;
}
static PyObject* gPySetSolverType(PyObject* self,
- PyObject* args,
- PyObject* kwds)
+ PyObject* args,
+ PyObject* kwds)
{
int solverType;
if (PyArg_ParseTuple(args,"i",&solverType))
@@ -367,8 +374,8 @@ static PyObject* gPySetSolverType(PyObject* self,
static PyObject* gPyGetVehicleConstraint(PyObject* self,
- PyObject* args,
- PyObject* kwds)
+ PyObject* args,
+ PyObject* kwds)
{
#if defined(_WIN64)
__int64 constraintid;
@@ -398,9 +405,6 @@ static PyObject* gPyGetVehicleConstraint(PyObject* self,
}
-
-
-
static PyObject* gPyCreateConstraint(PyObject* self,
PyObject* args,
PyObject* kwds)
@@ -425,39 +429,39 @@ static PyObject* gPyCreateConstraint(PyObject* self,
success = PyArg_ParseTuple(args,"lli",&physicsid,&physicsid2,&constrainttype);
#endif
}
- else
- if (len ==6)
+ else if (len == 6)
{
#if defined(_WIN64)
success = PyArg_ParseTuple(args,"LLifff",&physicsid,&physicsid2,&constrainttype,
- &pivotX,&pivotY,&pivotZ);
+ &pivotX,&pivotY,&pivotZ);
#else
success = PyArg_ParseTuple(args,"llifff",&physicsid,&physicsid2,&constrainttype,
- &pivotX,&pivotY,&pivotZ);
+ &pivotX,&pivotY,&pivotZ);
#endif
}
else if (len == 9)
{
#if defined(_WIN64)
success = PyArg_ParseTuple(args,"LLiffffff",&physicsid,&physicsid2,&constrainttype,
- &pivotX,&pivotY,&pivotZ,&axisX,&axisY,&axisZ);
+ &pivotX,&pivotY,&pivotZ,&axisX,&axisY,&axisZ);
#else
success = PyArg_ParseTuple(args,"lliffffff",&physicsid,&physicsid2,&constrainttype,
- &pivotX,&pivotY,&pivotZ,&axisX,&axisY,&axisZ);
+ &pivotX,&pivotY,&pivotZ,&axisX,&axisY,&axisZ);
#endif
-
}
else if (len == 10)
{
#if defined(_WIN64)
success = PyArg_ParseTuple(args,"LLiffffffi",&physicsid,&physicsid2,&constrainttype,
- &pivotX,&pivotY,&pivotZ,&axisX,&axisY,&axisZ,&flag);
+ &pivotX,&pivotY,&pivotZ,&axisX,&axisY,&axisZ,&flag);
#else
success = PyArg_ParseTuple(args,"lliffffffi",&physicsid,&physicsid2,&constrainttype,
- &pivotX,&pivotY,&pivotZ,&axisX,&axisY,&axisZ,&flag);
+ &pivotX,&pivotY,&pivotZ,&axisX,&axisY,&axisZ,&flag);
#endif
}
- else if (len==4)
+
+ /* XXX extrainfo seems to be nothing implemented. right now it works as a pivot with [X,0,0] */
+ else if (len == 4)
{
#if defined(_WIN64)
success = PyArg_ParseTuple(args,"LLii",&physicsid,&physicsid2,&constrainttype,&extrainfo);
@@ -466,7 +470,7 @@ static PyObject* gPyCreateConstraint(PyObject* self,
#endif
pivotX=extrainfo;
}
-
+
if (success)
{
if (PHY_GetActiveEnvironment())
@@ -490,20 +494,18 @@ static PyObject* gPyCreateConstraint(PyObject* self,
MT_Vector3 axis0 = localCFrame.getColumn(0);
MT_Vector3 axis1 = localCFrame.getColumn(1);
MT_Vector3 axis2 = localCFrame.getColumn(2);
-
- constraintid = PHY_GetActiveEnvironment()->createConstraint(physctrl,physctrl2,(enum PHY_ConstraintType)constrainttype,
- pivotX,pivotY,pivotZ,
- (float)axis0.x(),(float)axis0.y(),(float)axis0.z(),
- (float)axis1.x(),(float)axis1.y(),(float)axis1.z(),
- (float)axis2.x(),(float)axis2.y(),(float)axis2.z(),flag);
- } else
- {
+ constraintid = PHY_GetActiveEnvironment()->createConstraint(physctrl,physctrl2,(enum PHY_ConstraintType)constrainttype,
+ pivotX,pivotY,pivotZ,
+ (float)axis0.x(),(float)axis0.y(),(float)axis0.z(),
+ (float)axis1.x(),(float)axis1.y(),(float)axis1.z(),
+ (float)axis2.x(),(float)axis2.y(),(float)axis2.z(),flag);
+ }
+ else {
constraintid = PHY_GetActiveEnvironment()->createConstraint(physctrl,physctrl2,(enum PHY_ConstraintType)constrainttype,pivotX,pivotY,pivotZ,axisX,axisY,axisZ,0);
}
KX_ConstraintWrapper* wrap = new KX_ConstraintWrapper((enum PHY_ConstraintType)constrainttype,constraintid,PHY_GetActiveEnvironment());
-
return wrap->NewProxy(true);
}
@@ -522,8 +524,8 @@ static PyObject* gPyCreateConstraint(PyObject* self,
static PyObject* gPyGetAppliedImpulse(PyObject* self,
- PyObject* args,
- PyObject* kwds)
+ PyObject* args,
+ PyObject* kwds)
{
float appliedImpulse = 0.f;
@@ -549,8 +551,8 @@ static PyObject* gPyGetAppliedImpulse(PyObject* self,
static PyObject* gPyRemoveConstraint(PyObject* self,
- PyObject* args,
- PyObject* kwds)
+ PyObject* args,
+ PyObject* kwds)
{
#if defined(_WIN64)
__int64 constraintid;
@@ -577,7 +579,7 @@ static PyObject* gPyExportBulletFile(PyObject*, PyObject* args)
char* filename;
if (!PyArg_ParseTuple(args,"s:exportBulletFile",&filename))
return NULL;
-
+
if (PHY_GetActiveEnvironment())
{
PHY_GetActiveEnvironment()->exportFile(filename);
@@ -586,62 +588,61 @@ static PyObject* gPyExportBulletFile(PyObject*, PyObject* args)
}
static struct PyMethodDef physicsconstraints_methods[] = {
- {"setGravity",(PyCFunction) gPySetGravity,
- METH_VARARGS, (const char *)gPySetGravity__doc__},
- {"setDebugMode",(PyCFunction) gPySetDebugMode,
- METH_VARARGS, (const char *)gPySetDebugMode__doc__},
-
- /// settings that influence quality of the rigidbody dynamics
- {"setNumIterations",(PyCFunction) gPySetNumIterations,
- METH_VARARGS, (const char *)gPySetNumIterations__doc__},
-
- {"setNumTimeSubSteps",(PyCFunction) gPySetNumTimeSubSteps,
- METH_VARARGS, (const char *)gPySetNumTimeSubSteps__doc__},
-
- {"setDeactivationTime",(PyCFunction) gPySetDeactivationTime,
- METH_VARARGS, (const char *)gPySetDeactivationTime__doc__},
-
- {"setDeactivationLinearTreshold",(PyCFunction) gPySetDeactivationLinearTreshold,
- METH_VARARGS, (const char *)gPySetDeactivationLinearTreshold__doc__},
- {"setDeactivationAngularTreshold",(PyCFunction) gPySetDeactivationAngularTreshold,
- METH_VARARGS, (const char *)gPySetDeactivationAngularTreshold__doc__},
-
- {"setContactBreakingTreshold",(PyCFunction) gPySetContactBreakingTreshold,
- METH_VARARGS, (const char *)gPySetContactBreakingTreshold__doc__},
- {"setCcdMode",(PyCFunction) gPySetCcdMode,
- METH_VARARGS, (const char *)gPySetCcdMode__doc__},
- {"setSorConstant",(PyCFunction) gPySetSorConstant,
- METH_VARARGS, (const char *)gPySetSorConstant__doc__},
- {"setSolverTau",(PyCFunction) gPySetSolverTau,
- METH_VARARGS, (const char *)gPySetSolverTau__doc__},
- {"setSolverDamping",(PyCFunction) gPySetSolverDamping,
- METH_VARARGS, (const char *)gPySetSolverDamping__doc__},
-
- {"setLinearAirDamping",(PyCFunction) gPySetLinearAirDamping,
- METH_VARARGS, (const char *)gPySetLinearAirDamping__doc__},
-
- {"setUseEpa",(PyCFunction) gPySetUseEpa,
- METH_VARARGS, (const char *)gPySetUseEpa__doc__},
+ {"setGravity",(PyCFunction) gPySetGravity,
+ METH_VARARGS, (const char*)gPySetGravity__doc__},
+ {"setDebugMode",(PyCFunction) gPySetDebugMode,
+ METH_VARARGS, (const char *)gPySetDebugMode__doc__},
+
+ /// settings that influence quality of the rigidbody dynamics
+ {"setNumIterations",(PyCFunction) gPySetNumIterations,
+ METH_VARARGS, (const char *)gPySetNumIterations__doc__},
+
+ {"setNumTimeSubSteps",(PyCFunction) gPySetNumTimeSubSteps,
+ METH_VARARGS, (const char *)gPySetNumTimeSubSteps__doc__},
+
+ {"setDeactivationTime",(PyCFunction) gPySetDeactivationTime,
+ METH_VARARGS, (const char *)gPySetDeactivationTime__doc__},
+
+ {"setDeactivationLinearTreshold",(PyCFunction) gPySetDeactivationLinearTreshold,
+ METH_VARARGS, (const char *)gPySetDeactivationLinearTreshold__doc__},
+ {"setDeactivationAngularTreshold",(PyCFunction) gPySetDeactivationAngularTreshold,
+ METH_VARARGS, (const char *)gPySetDeactivationAngularTreshold__doc__},
+
+ {"setContactBreakingTreshold",(PyCFunction) gPySetContactBreakingTreshold,
+ METH_VARARGS, (const char *)gPySetContactBreakingTreshold__doc__},
+ {"setCcdMode",(PyCFunction) gPySetCcdMode,
+ METH_VARARGS, (const char *)gPySetCcdMode__doc__},
+ {"setSorConstant",(PyCFunction) gPySetSorConstant,
+ METH_VARARGS, (const char *)gPySetSorConstant__doc__},
+ {"setSolverTau",(PyCFunction) gPySetSolverTau,
+ METH_VARARGS, (const char *)gPySetSolverTau__doc__},
+ {"setSolverDamping",(PyCFunction) gPySetSolverDamping,
+ METH_VARARGS, (const char *)gPySetSolverDamping__doc__},
+
+ {"setLinearAirDamping",(PyCFunction) gPySetLinearAirDamping,
+ METH_VARARGS, (const char *)gPySetLinearAirDamping__doc__},
+
+ {"setUseEpa",(PyCFunction) gPySetUseEpa,
+ METH_VARARGS, (const char *)gPySetUseEpa__doc__},
{"setSolverType",(PyCFunction) gPySetSolverType,
- METH_VARARGS, (const char *)gPySetSolverType__doc__},
+ METH_VARARGS, (const char *)gPySetSolverType__doc__},
- {"createConstraint",(PyCFunction) gPyCreateConstraint,
- METH_VARARGS, (const char *)gPyCreateConstraint__doc__},
- {"getVehicleConstraint",(PyCFunction) gPyGetVehicleConstraint,
- METH_VARARGS, (const char *)gPyGetVehicleConstraint__doc__},
+ {"createConstraint",(PyCFunction) gPyCreateConstraint,
+ METH_VARARGS, (const char *)gPyCreateConstraint__doc__},
+ {"getVehicleConstraint",(PyCFunction) gPyGetVehicleConstraint,
+ METH_VARARGS, (const char *)gPyGetVehicleConstraint__doc__},
- {"removeConstraint",(PyCFunction) gPyRemoveConstraint,
- METH_VARARGS, (const char *)gPyRemoveConstraint__doc__},
+ {"removeConstraint",(PyCFunction) gPyRemoveConstraint,
+ METH_VARARGS, (const char *)gPyRemoveConstraint__doc__},
{"getAppliedImpulse",(PyCFunction) gPyGetAppliedImpulse,
- METH_VARARGS, (const char *)gPyGetAppliedImpulse__doc__},
+ METH_VARARGS, (const char *)gPyGetAppliedImpulse__doc__},
- {"exportBulletFile",(PyCFunction)gPyExportBulletFile,
- METH_VARARGS, "export a .bullet file"},
+ {"exportBulletFile",(PyCFunction)gPyExportBulletFile,
+ METH_VARARGS, "export a .bullet file"},
-
- //sentinel
- { NULL, (PyCFunction) NULL, 0, NULL }
+ //sentinel
+ { NULL, (PyCFunction) NULL, 0, NULL }
};
static struct PyModuleDef PhysicsConstraints_module_def = {
@@ -656,12 +657,13 @@ static struct PyModuleDef PhysicsConstraints_module_def = {
0, /* m_free */
};
-PyObject* initPythonConstraintBinding()
+PyObject* initPythonConstraintBinding()
{
- PyObject* ErrorObject;
- PyObject* m;
- PyObject* d;
+ PyObject* ErrorObject;
+ PyObject* m;
+ PyObject* d;
+ PyObject* item;
/* Use existing module where possible
* be careful not to init any runtime vars after this */
@@ -677,21 +679,43 @@ PyObject* initPythonConstraintBinding()
PyDict_SetItemString(PySys_GetObject("modules"), PhysicsConstraints_module_def.m_name, m);
}
- // Add some symbolic constants to the module
- d = PyModule_GetDict(m);
- ErrorObject = PyUnicode_FromString("PhysicsConstraints.error");
- PyDict_SetItemString(d, "error", ErrorObject);
- Py_DECREF(ErrorObject);
-
- // XXXX Add constants here
-
- // Check for errors
- if (PyErr_Occurred())
- {
- Py_FatalError("can't initialize module PhysicsConstraints");
- }
-
- return d;
+ // Add some symbolic constants to the module
+ d = PyModule_GetDict(m);
+ ErrorObject = PyUnicode_FromString("PhysicsConstraints.error");
+ PyDict_SetItemString(d, "error", ErrorObject);
+ Py_DECREF(ErrorObject);
+
+#ifdef USE_BULLET
+ //Debug Modes constants to be used with setDebugMode() python function
+ KX_MACRO_addTypesToDict(d, DBG_NODEBUG, btIDebugDraw::DBG_NoDebug);
+ KX_MACRO_addTypesToDict(d, DBG_DRAWWIREFRAME, btIDebugDraw::DBG_DrawWireframe);
+ KX_MACRO_addTypesToDict(d, DBG_DRAWAABB, btIDebugDraw::DBG_DrawAabb);
+ KX_MACRO_addTypesToDict(d, DBG_DRAWFREATURESTEXT, btIDebugDraw::DBG_DrawFeaturesText);
+ KX_MACRO_addTypesToDict(d, DBG_DRAWCONTACTPOINTS, btIDebugDraw::DBG_DrawContactPoints);
+ KX_MACRO_addTypesToDict(d, DBG_NOHELPTEXT, btIDebugDraw::DBG_NoHelpText);
+ KX_MACRO_addTypesToDict(d, DBG_DRAWTEXT, btIDebugDraw::DBG_DrawText);
+ KX_MACRO_addTypesToDict(d, DBG_PROFILETIMINGS, btIDebugDraw::DBG_ProfileTimings);
+ KX_MACRO_addTypesToDict(d, DBG_ENABLESATCOMPARISION, btIDebugDraw::DBG_EnableSatComparison);
+ KX_MACRO_addTypesToDict(d, DBG_DISABLEBULLETLCP, btIDebugDraw::DBG_DisableBulletLCP);
+ KX_MACRO_addTypesToDict(d, DBG_ENABLECDD, btIDebugDraw::DBG_EnableCCD);
+ KX_MACRO_addTypesToDict(d, DBG_DRAWCONSTRAINTS, btIDebugDraw::DBG_DrawConstraints);
+ KX_MACRO_addTypesToDict(d, DBG_DRAWCONSTRAINTLIMITS, btIDebugDraw::DBG_DrawConstraintLimits);
+ KX_MACRO_addTypesToDict(d, DBG_FASTWIREFRAME, btIDebugDraw::DBG_FastWireframe);
+#endif // USE_BULLET
+
+ //Constraint types to be used with createConstraint() python function
+ KX_MACRO_addTypesToDict(d, POINTTOPOINT_CONSTRAINT, PHY_POINT2POINT_CONSTRAINT);
+ KX_MACRO_addTypesToDict(d, LINEHINGE_CONSTRAINT, PHY_LINEHINGE_CONSTRAINT);
+ KX_MACRO_addTypesToDict(d, ANGULAR_CONSTRAINT, PHY_ANGULAR_CONSTRAINT);
+ KX_MACRO_addTypesToDict(d, CONETWIST_CONSTRAINT, PHY_CONE_TWIST_CONSTRAINT);
+ KX_MACRO_addTypesToDict(d, VEHICLE_CONSTRAINT, PHY_VEHICLE_CONSTRAINT);
+
+ // Check for errors
+ if (PyErr_Occurred()) {
+ Py_FatalError("can't initialize module PhysicsConstraints");
+ }
+
+ return d;
}
@@ -709,7 +733,4 @@ PHY_IPhysicsEnvironment* PHY_GetActiveEnvironment()
return g_CurrentActivePhysicsEnvironment;
}
-
-
#endif // WITH_PYTHON
-