svn merge -r38804:38971 https://svn.blender.org/svnroot/bf-blender/trunk/blender, manual merge of source/blender/editors/transform/transform.c

This commit is contained in:
Campbell Barton 2011-08-05 08:02:04 +00:00
commit 5c26223106
126 changed files with 3972 additions and 1866 deletions

@ -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++")
@ -896,28 +910,15 @@ elseif(APPLE)
endif()
if(WITH_PYTHON)
set(PYTHON_VERSION 3.2)
if(PYTHON_VERSION MATCHES 3.2)
# we use precompiled libraries for py 3.2 and up by default
# we use precompiled libraries for py 3.2 and up by default
# normally cached but not since we include them with blender
set(PYTHON_INCLUDE_DIR "${LIBDIR}/python/include/python${PYTHON_VERSION}")
# set(PYTHON_BINARY "${LIBDIR}/python/bin/python${PYTHON_VERSION}") # not used yet
set(PYTHON_LIBRARY python${PYTHON_VERSION})
set(PYTHON_LIBPATH "${LIBDIR}/python/lib/python${PYTHON_VERSION}")
# set(PYTHON_LINKFLAGS "-u _PyMac_Error") # won't build with this enabled
else()
# otherwise, use custom system framework
# *not used but maintained incase some dev wants to*
set(PYTHON "/System/Library/Frameworks/Python.framework/Versions/" CACHE PATH)
set(PYTHON_INCLUDE_DIR "${PYTHON}${PYTHON_VERSION}/include/python${PYTHON_VERSION}" CACHE PATH)
# set(PYTHON_BINARY ${PYTHON}${PYTHON_VERSION}/bin/python${PYTHON_VERSION}) # not used yet
set(PYTHON_LIBRARY "" CACHE FILEPATH)
set(PYTHON_LIBPATH "${PYTHON}${PYTHON_VERSION}/lib/python${PYTHON_VERSION}/config" CACHE PATH)
set(PYTHON_LINKFLAGS "-u _PyMac_Error -framework System -framework Python" CACHE STRING)
unset(PYTHON)
endif()
# normally cached but not since we include them with blender
set(PYTHON_VERSION 3.2)
set(PYTHON_INCLUDE_DIR "${LIBDIR}/python/include/python${PYTHON_VERSION}")
# set(PYTHON_BINARY "${LIBDIR}/python/bin/python${PYTHON_VERSION}") # not used yet
set(PYTHON_LIBRARY python${PYTHON_VERSION})
set(PYTHON_LIBPATH "${LIBDIR}/python/lib/python${PYTHON_VERSION}")
# set(PYTHON_LINKFLAGS "-u _PyMac_Error") # won't build with this enabled
# uncached vars
set(PYTHON_INCLUDE_DIRS "${PYTHON_INCLUDE_DIR}")
@ -972,7 +973,17 @@ elseif(APPLE)
set(SAMPLERATE_LIBPATH ${SAMPLERATE}/lib)
endif()
set(PLATFORM_LINKLIBS stdc++ SystemStubs)
find_library(SYSTEMSTUBS_LIBRARY
NAMES
SystemStubs
PATHS
)
mark_as_advanced(SYSTEMSTUBS_LIBRARY)
if(SYSTEMSTUBS_LIBRARY)
set(PLATFORM_LINKLIBS stdc++ SystemStubs)
else()
set(PLATFORM_LINKLIBS stdc++)
endif()
if(WITH_COCOA)
set(PLATFORM_CFLAGS "-pipe -funsigned-char -DGHOST_COCOA")
@ -1029,6 +1040,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 +1069,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 +1335,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)

@ -111,6 +111,11 @@ btools.print_targets(B.targets, B.bc)
# handling cmd line arguments & config file
# bitness stuff
tempbitness = int(B.arguments.get('BF_BITNESS', bitness)) # default to bitness found as per starting python
if tempbitness in (32, 64): # only set if 32 or 64 has been given
bitness = int(tempbitness)
# first check cmdline for toolset and we create env to work on
quickie = B.arguments.get('BF_QUICK', None)
quickdebug = B.arguments.get('BF_QUICKDEBUG', None)
@ -241,6 +246,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():

@ -81,6 +81,12 @@ WITH_BF_STATICJEMALLOC = True
BF_JEMALLOC = '/home/sources/staticlibs/jemalloc'
BF_JEMALLOC_LIBPATH = '${BF_JEMALLOC}/lib32'
# Use 3d mouse library
WITH_BF_3DMOUSE = True
WITH_BF_STATIC3DMOUSE = True
BF_3DMOUSE = '/home/sources/staticlibs/spnav'
BF_3DMOUSE_LIBPATH = '${BF_3DMOUSE}/lib32'
# Compilation and optimization
BF_DEBUG = False
REL_CFLAGS = ['-O2']

@ -65,6 +65,12 @@ WITH_BF_STATICJEMALLOC = True
BF_JEMALLOC = '/home/sources/staticlibs/jemalloc'
BF_JEMALLOC_LIBPATH = '${BF_JEMALLOC}/lib32'
# Use 3d mouse library
WITH_BF_3DMOUSE = True
WITH_BF_STATIC3DMOUSE = True
BF_3DMOUSE = '/home/sources/staticlibs/spnav'
BF_3DMOUSE_LIBPATH = '${BF_3DMOUSE}/lib32'
# Compilation and optimization
BF_DEBUG = False
REL_CFLAGS = ['-O2']

@ -65,6 +65,12 @@ WITH_BF_STATICJEMALLOC = True
BF_JEMALLOC = '/home/sources/staticlibs/jemalloc'
BF_JEMALLOC_LIBPATH = '${BF_JEMALLOC}/lib64'
# Use 3d mouse library
WITH_BF_3DMOUSE = True
WITH_BF_STATIC3DMOUSE = True
BF_3DMOUSE = '/home/sources/staticlibs/spnav'
BF_3DMOUSE_LIBPATH = '${BF_3DMOUSE}/lib64'
# Compilation and optimization
BF_DEBUG = False
REL_CFLAGS = ['-O2']

@ -81,6 +81,12 @@ WITH_BF_STATICJEMALLOC = True
BF_JEMALLOC = '/home/sources/staticlibs/jemalloc'
BF_JEMALLOC_LIBPATH = '${BF_JEMALLOC}/lib64'
# Use 3d mouse library
WITH_BF_3DMOUSE = True
WITH_BF_STATIC3DMOUSE = True
BF_3DMOUSE = '/home/sources/staticlibs/spnav'
BF_3DMOUSE_LIBPATH = '${BF_3DMOUSE}/lib64'
# Compilation and optimization
BF_DEBUG = False
REL_CFLAGS = ['-O2']

@ -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
)

@ -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())]

@ -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,
)

@ -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,

@ -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()

@ -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']

@ -192,6 +192,14 @@ WITH_BF_OPENMP = True
WITH_BF_RAYOPTIMIZATION = True
BF_RAYOPTIMIZATION_SSE_FLAGS = ['-msse','-pthread']
#SpaceNavigator and friends
WITH_BF_3DMOUSE = True
BF_3DMOUSE = '/usr'
BF_3DMOUSE_INC = '${BF_3DMOUSE}/include'
BF_3DMOUSE_LIBPATH = '${BF_3DMOUSE}/lib'
BF_3DMOUSE_LIB = 'spnav'
BF_3DMOUSE_LIB_STATIC = '${BF_3DMOUSE_LIBPATH}/libspnav.a'
##
CC = 'gcc'
CXX = 'g++'

@ -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']

@ -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']

@ -206,6 +206,12 @@ def setup_staticlibs(lenv):
if lenv['WITH_BF_STATICJEMALLOC']:
statlibs += Split(lenv['BF_JEMALLOC_LIB_STATIC'])
if lenv['OURPLATFORM']=='linux2':
if lenv['WITH_BF_3DMOUSE']:
libincs += Split(lenv['BF_3DMOUSE_LIBPATH'])
if lenv['WITH_BF_STATIC3DMOUSE']:
statlibs += Split(lenv['BF_3DMOUSE_LIB_STATIC'])
return statlibs, libincs
def setup_syslibs(lenv):
@ -271,6 +277,11 @@ def setup_syslibs(lenv):
if not lenv['WITH_BF_STATICJEMALLOC']:
syslibs += Split(lenv['BF_JEMALLOC_LIB'])
if lenv['OURPLATFORM']=='linux2':
if lenv['WITH_BF_3DMOUSE']:
if not lenv['WITH_BF_STATIC3DMOUSE']:
syslibs += Split(lenv['BF_3DMOUSE_LIB'])
syslibs += lenv['LLIBS']
return syslibs

@ -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
@ -159,7 +159,7 @@ def validate_arguments(args, bc):
'BF_BSC', 'BF_CONFIG',
'BF_PRIORITYLIST', 'BF_BUILDINFO','CC', 'CXX', 'BF_QUICKDEBUG',
'BF_LISTDEBUG', 'LCGDIR', 'BF_X264_CONFIG', 'BF_XVIDCORE_CONFIG',
'BF_UNIT_TEST']
'BF_UNIT_TEST', 'BF_BITNESS']
okdict = {}
@ -437,6 +437,14 @@ 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)),
(BoolVariable('WITH_BF_STATIC3DMOUSE', 'Staticly link to 3d mouse library', False)),
('BF_3DMOUSE', '3d mouse library base path', ''),
('BF_3DMOUSE_INC', '3d mouse library include path', ''),
('BF_3DMOUSE_LIB', '3d mouse library', ''),
('BF_3DMOUSE_LIBPATH', '3d mouse library path', ''),
('BF_3DMOUSE_LIB_STATIC', '3d mouse static library', ''),
('CFLAGS', 'C only flags', []),
('CCFLAGS', 'Generic C and C++ flags', []),
('CXXFLAGS', 'C++ only flags', []),

@ -219,7 +219,7 @@ div.sphinxsidebarwrapper.fixed {
}
{%- if theme_stickysidebar|tobool %}
/* this is nice, but it it leads to hidden headings when jumping
/* this is nice, but it leads to hidden headings when jumping
to an anchor */
/*
div.related {

@ -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

@ -1,6 +1,6 @@
Game Engine bge.events Module
=============================
Game Keys (bge.events)
======================
*****
Intro

@ -1,6 +1,7 @@
Game Engine bge.logic Module
============================
Game Logic (bge.logic)
======================
*****
Intro
*****

@ -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

@ -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

@ -1,6 +1,6 @@
Game Engine bge.types Module
=============================
Game Types (bge.types)
======================
.. module:: bge.types

@ -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.

@ -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

@ -44,7 +44,6 @@ set(SRC
intern/GHOST_ISystem.cpp
intern/GHOST_ISystemPaths.cpp
intern/GHOST_ModifierKeys.cpp
intern/GHOST_NDOFManager.cpp
intern/GHOST_Path-api.cpp
intern/GHOST_Path-api.cpp
intern/GHOST_Rect.cpp
@ -74,12 +73,10 @@ set(SRC
intern/GHOST_EventDragnDrop.h
intern/GHOST_EventKey.h
intern/GHOST_EventManager.h
intern/GHOST_EventNDOF.h
intern/GHOST_EventString.h
intern/GHOST_EventTrackpad.h
intern/GHOST_EventWheel.h
intern/GHOST_ModifierKeys.h
intern/GHOST_NDOFManager.h
intern/GHOST_System.h
intern/GHOST_SystemPaths.h
intern/GHOST_TimerManager.h
@ -97,6 +94,20 @@ if(WITH_GHOST_DEBUG)
add_definitions(-DWITH_GHOST_DEBUG)
endif()
if(WITH_INPUT_NDOF)
add_definitions(-DWITH_INPUT_NDOF)
list(APPEND SRC
intern/GHOST_NDOFManager.cpp
intern/GHOST_EventNDOF.h
intern/GHOST_NDOFManager.h
)
list(APPEND INC_SYS
${NDOF_INCLUDE_DIRS}
)
endif()
if(WITH_HEADLESS OR WITH_GHOST_SDL)
if(WITH_HEADLESS)
@ -158,12 +169,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 +235,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 +266,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}")

@ -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

@ -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
***************************************************************************************/

@ -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;
/* 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 enum {
GHOST_kNotStarted,
GHOST_kStarting,
GHOST_kInProgress,
GHOST_kFinishing,
GHOST_kFinished
} GHOST_TProgress;
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;
/** 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 int (*GHOST_NDOFLibraryInit_fp)(void);
typedef void (*GHOST_NDOFLibraryShutdown_fp)(void* deviceHandle);
typedef void* (*GHOST_NDOFDeviceOpen_fp)(void* platformData);
typedef enum { GHOST_kPress, GHOST_kRelease } GHOST_TButtonAction;
// good for mouse or other buttons too, hmmm?
// 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);
typedef struct {
GHOST_TButtonAction action;
short button;
} GHOST_TEventNDOFButtonData;
typedef struct {
/** The key code. */

@ -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,25 @@ 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')
if env['OURPLATFORM']=='linux2':
incs += ' ' + env['BF_3DMOUSE_INC']
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.cpp')
except ValueError:
pass
if window_system in ('win32-vc', 'win32-mingw', 'cygwin', 'linuxcross', 'win64-vc'):
incs = env['BF_WINTAB_INC'] + ' ' + incs

@ -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;

@ -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>

@ -33,6 +33,7 @@
#include "GHOST_Debug.h"
#include "GHOST_DropTargetWin32.h"
#include <ShellApi.h>
#ifdef GHOST_DEBUG
// utility

@ -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"

@ -42,7 +42,7 @@
#include "GHOST_EventManager.h"
#include <algorithm>
#include "GHOST_Debug.h"
#include <stdio.h> // [mce] temp debug
GHOST_EventManager::GHOST_EventManager()
{

@ -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_

@ -1,4 +1,6 @@
/*
* $Id$
*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
@ -15,122 +17,458 @@
* 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 <stdio.h> /* just for printf */
#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>
// 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};
#if !defined(_WIN32) && !defined(__APPLE__)
#include "GHOST_SystemX11.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
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);
#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
#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);
#endif
return (Pid > 0) ? 0 : 1;
} else
return 1;
}
static const NDOF_ButtonT SpaceNavigator_HID_map[] = {
NDOF_BUTTON_MENU,
NDOF_BUTTON_FIT
};
bool
GHOST_NDOFManager::available() const
{
return m_DeviceHandle != 0;
}
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
};
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;
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
};
}
/* this is the older SpacePilot (sans Pro)
* thanks to polosson for the info in this table */
static const NDOF_ButtonT SpacePilot_HID_map[] = {
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?
};
void GHOST_NDOFManager::GHOST_NDOFGetDatas(GHOST_TEventNDOFData &datas) const
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)
{
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;
// 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));
}
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 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);
#undef HOME
}
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);
#undef HOME1
}
}
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;
default:
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;
}

@ -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();
GHOST_NDOFManager(GHOST_System&);
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;
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

@ -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

@ -0,0 +1,172 @@
/*
* $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
}

@ -0,0 +1,41 @@
/*
* $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)
{
setDeadZone(0.1f);
}
// 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;
}

@ -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

@ -0,0 +1,106 @@
/*
* $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;
}

@ -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

@ -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;
}

@ -190,25 +190,6 @@ public:
*/
virtual GHOST_TSuccess removeEventConsumer(GHOST_IEventConsumer* consumer);
/***************************************************************************************
** N-degree of freedom devcice management functionality
***************************************************************************************/
/** Inherited from GHOST_ISystem
* Opens the N-degree of freedom device manager
* return 0 if device found, 1 otherwise
*/
virtual int openNDOF(GHOST_IWindow* w,
GHOST_NDOFLibraryInit_fp setNdofLibraryInit,
GHOST_NDOFLibraryShutdown_fp setNdofLibraryShutdown,
GHOST_NDOFDeviceOpen_fp setNdofDeviceOpen);
// original patch only
// GHOST_NDOFEventHandler_fp setNdofEventHandler);
/***************************************************************************************
** Cursor management functionality
***************************************************************************************/
@ -268,11 +249,13 @@ public:
*/
virtual inline GHOST_WindowManager* getWindowManager() const;
#ifdef WITH_INPUT_NDOF
/**
* Returns a pointer to our n-degree of freedeom manager.
* @return A pointer to our n-degree of freedeom manager.
*/
virtual inline GHOST_NDOFManager* getNDOFManager() const;
#endif
/**
* Returns the state of all modifier keys.
@ -337,8 +320,10 @@ protected:
/** The event manager. */
GHOST_EventManager* m_eventManager;
/** The N-degree of freedom device manager */
GHOST_NDOFManager* m_ndofManager;
#ifdef WITH_INPUT_NDOF
/** The N-degree of freedom device manager */
GHOST_NDOFManager* m_ndofManager;
#endif
/** Prints all the events. */
#ifdef GHOST_DEBUG
@ -364,10 +349,12 @@ inline GHOST_WindowManager* GHOST_System::getWindowManager() const
return m_windowManager;
}
#ifdef WITH_INPUT_NDOF
inline GHOST_NDOFManager* GHOST_System::getNDOFManager() const
{
return m_ndofManager;
}
#endif
#endif // _GHOST_SYSTEM_H_

@ -220,6 +220,11 @@ public:
*/
GHOST_TSuccess handleApplicationBecomeActiveEvent();
/**
* External objects should call this when they send an event outside processEvents.
*/
void notifyExternalEventProcessed();
/**
* @see GHOST_ISystem
*/
@ -267,7 +272,7 @@ protected:
/** Start time at initialization. */
GHOST_TUns64 m_start_time;
/** Event has been processed directly by Cocoa and has sent a ghost event to be dispatched */
/** Event has been processed directly by Cocoa (or NDOF manager) and has sent a ghost event to be dispatched */
bool m_outsideLoopEventProcessed;
/** Raised window is not yet known by the window manager, so delay application become active event handling */

@ -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;

@ -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__)

@ -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"

@ -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));
return RegisterRawInputDevices(&device, 1, sizeof(device));
};
// multi-axis mouse (SpaceNavigator, etc.)
devices[0].usUsagePage = 0x01;
devices[0].usUsage = 0x08;
// 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)))
{
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;
}
if(changed)
{
modifiers.set(modifier, (bool)*keyDown);
system->storeModifierKeys(modifiers);
}
else
{
key = GHOST_kKeyUnknown;
}
}
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)
{
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;
}
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,13 @@ 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) {
system->getWindowManager()->setActiveWindow(window);
}
return new GHOST_Event(system->getMilliSeconds(), type, window);
}
GHOST_TSuccess GHOST_SystemWin32::pushDragDropEvent(GHOST_TEventType eventType,
@ -799,9 +757,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 +869,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 +910,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
@ -989,11 +1060,16 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam,
* procedure of the top-level window being activated. If the windows use different input queues,
* the message is sent asynchronously, so the window is activated immediately.
*/
{
GHOST_ModifierKeys modifiers;
modifiers.clear();
system->storeModifierKeys(modifiers);
event = processWindowEvent(LOWORD(wParam) ? GHOST_kEventWindowActivate : GHOST_kEventWindowDeactivate, window);
/* WARNING: Let DefWindowProc handle WM_ACTIVATE, otherwise WM_MOUSEWHEEL
will not be dispatched to OUR active window if we minimize one of OUR windows. */
lResult = ::DefWindowProc(hwnd, msg, wParam, lParam);
break;
}
case WM_PAINT:
/* An application sends the WM_PAINT message when the system or another application
* makes a request to paint a portion of an application's window. The message is sent
@ -1122,28 +1198,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 {
@ -1165,10 +1219,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;
}
@ -1237,8 +1293,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

@ -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.
@ -412,11 +334,6 @@ protected:
*/
static LRESULT WINAPI s_wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
/**
* Initiates WM_INPUT messages from keyboard
*/
GHOST_TInt32 initKeyboardRawInput(void);
/**
* Toggles console
* @action 0 - Hides
@ -445,15 +362,6 @@ protected:
/** Console status */
int m_consoleStatus;
/** handle for user32.dll*/
HMODULE user32;
#ifdef NEED_RAW_PROC
/* pointer to RegisterRawInputDevices function */
LPFNDLLRRID pRegisterRawInputDevices;
/* pointer to GetRawInputData function */
LPFNDLLGRID pGetRawInputData;
#endif
};
inline void GHOST_SystemWin32::retrieveModifierKeys(GHOST_ModifierKeys& keys) const
@ -487,4 +395,3 @@ inline void GHOST_SystemWin32::handleKeyboardChange(void)
}
}
#endif // _GHOST_SYSTEM_WIN32_H_

@ -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(

@ -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,

@ -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

@ -39,20 +39,12 @@
#endif // WIN32
#include "GHOST_Window.h"
/* MinGW needs it */
#ifdef FREE_WINDOWS
#ifdef WINVER
#undef WINVER
#endif
#define WINVER 0x0501
#endif
#include <windows.h>
#include "GHOST_TaskbarWin32.h"
#define _WIN32_WINNT 0x501 // require Windows XP or newer
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <wintab.h>
#define PACKETDATA (PK_BUTTONS | PK_NORMAL_PRESSURE | PK_ORIENTATION | PK_CURSOR)

@ -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

@ -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:

@ -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"
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 unclean_chars:
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 directory 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
@ -180,7 +204,7 @@ def resolve_ncase(path):
def ensure_ext(filepath, ext, case_sensitive=False):
"""
Return the path with the extension added its its not alredy set.
Return the path with the extension added if it is not already set.
:arg ext: The extension to check for.
:type ext: string
@ -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

@ -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:

@ -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",
)
)

@ -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, )

@ -16,7 +16,7 @@
#
# ##### END GPL LICENSE BLOCK #####
# <pep8 compliant>
# <pep8-80 compliant>
__all__ = (
"ExportHelper",
@ -31,15 +31,34 @@ __all__ = (
"path_reference_copy",
"path_reference_mode",
"unique_name"
)
)
import bpy
from bpy.props import StringProperty, BoolProperty, EnumProperty
def _check_axis_conversion(op):
if hasattr(op, "axis_forward") and hasattr(op, "axis_up"):
return axis_conversion_ensure(op,
"axis_forward",
"axis_up",
)
return False
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.
@ -60,27 +79,39 @@ class ExportHelper:
return {'RUNNING_MODAL'}
def check(self, context):
change_ext = False
change_axis = _check_axis_conversion(self)
check_extension = self.check_extension
if check_extension is None:
return False
if check_extension is not None:
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
change_ext = True
if filepath != self.filepath:
self.filepath = filepath
return True
return False
return (change_ext or change_axis)
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)
return {'RUNNING_MODAL'}
def check(self, context):
return _check_axis_conversion(self)
# Axis conversion function, not pretty LUT
# use lookup tabes to convert between any axis
@ -116,29 +147,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 +283,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 +332,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 +384,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 +461,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 +472,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

@ -26,7 +26,7 @@ __all__ = (
"edge_loops_from_edges",
"ngon_tesselate",
"face_random_points",
)
)
def mesh_linked_faces(mesh):

@ -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:

@ -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):

@ -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

@ -1,8 +1,7 @@
import bpy
is_ntsc = (bpy.context.scene.render.fps != 25)
bpy.context.scene.render.ffmpeg_format = "AVI"
bpy.context.scene.render.ffmpeg_codec = "XVID"
bpy.context.scene.render.ffmpeg_format = "XVID"
if is_ntsc:
bpy.context.scene.render.ffmpeg_gopsize = 18

@ -247,15 +247,17 @@ class MATERIAL_PT_diffuse(MaterialButtonsPanel, bpy.types.Panel):
row.prop(mat, "diffuse_fresnel_factor", text="Factor")
if mat.use_diffuse_ramp:
layout.separator()
layout.template_color_ramp(mat, "diffuse_ramp", expand=True)
layout.separator()
col = layout.column()
col.active = (not mat.use_shadeless)
col.separator()
col.template_color_ramp(mat, "diffuse_ramp", expand=True)
col.separator()
row = layout.row()
row = col.row()
row.prop(mat, "diffuse_ramp_input", text="Input")
row.prop(mat, "diffuse_ramp_blend", text="Blend")
layout.prop(mat, "diffuse_ramp_factor", text="Factor")
col.prop(mat, "diffuse_ramp_factor", text="Factor")
class MATERIAL_PT_specular(MaterialButtonsPanel, bpy.types.Panel):

@ -817,12 +817,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()
@ -881,7 +878,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:

@ -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':

@ -349,6 +349,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"

@ -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):

@ -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

@ -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

@ -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 */

@ -1262,7 +1262,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)

@ -581,46 +581,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;
int a;
t = aantal+order;
if(type==0) {
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;
}
}
@ -663,7 +664,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;
@ -676,7 +677,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;
@ -3260,3 +3261,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--;
}
}
}
}

@ -518,7 +518,7 @@ static const char *material_adrcodes_to_paths (int adrcode, int *array_index)
return "alpha";
case MA_REF:
return "diffuse_reflection";
return "diffuse_intensity";
case MA_EMIT:
return "emit";
@ -527,7 +527,7 @@ static const char *material_adrcodes_to_paths (int adrcode, int *array_index)
return "ambient";
case MA_SPEC:
return "specular_reflection";
return "specular_intensity";
case MA_HARD:
return "specular_hardness";
@ -551,13 +551,13 @@ static const char *material_adrcodes_to_paths (int adrcode, int *array_index)
return "raytrace_mirror.fresnel";
case MA_FRESMIRI:
return "raytrace_mirror.fresnel_fac";
return "raytrace_mirror.fresnel_factor";
case MA_FRESTRA:
return "raytrace_transparency.fresnel";
case MA_FRESTRAI:
return "raytrace_transparency.fresnel_fac";
return "raytrace_transparency.fresnel_factor";
case MA_ADD:
return "halo.add";

@ -517,20 +517,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]);
}
}

@ -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;
id_us_min((ID *)ret);
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);
}
/* decrease mat_nr index */
data_delete_material_index_id(id, index);
}
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);
}
/* 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);
}

@ -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;
}
}

@ -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.
float tmin; // used for raycasting, is how close bb is to the ray point
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;
/* 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 {

@ -3174,7 +3174,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;
@ -3205,6 +3205,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;

@ -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;
}

@ -1616,6 +1616,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) */

@ -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
*/

@ -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>
@ -1584,6 +1585,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 */

@ -1093,7 +1093,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;
@ -1109,7 +1109,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;
}
@ -1121,7 +1121,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;
}

@ -302,7 +302,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)

@ -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);
}
}

@ -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;

@ -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);

@ -437,6 +437,56 @@ 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;
/* tune these until it feels right */
const float zoom_sensitivity = 0.5f; // 50% per second (I think)
const float pan_sensitivity = 300.f; // screen pixels per second
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.

@ -467,6 +467,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);
@ -516,6 +517,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);

@ -2216,6 +2216,12 @@ static int node_link_modal(bContext *C, wmOperator *op, wmEvent *event)
/* we might need to remove a link */
if(in_out==SOCK_OUT)
node_remove_extra_links(snode, link->tosock, link);
/* when linking to group outputs, update the socket type */
/* XXX this should all be part of a generic update system */
if (!link->tonode) {
link->tosock->type = link->fromsock->type;
}
}
else if (outside_group_rect(snode) && (link->tonode || link->fromnode)) {
/* automatically add new group socket */

@ -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);

@ -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
*

@ -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,81 +925,149 @@ 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;
if (rv3d->persp==RV3D_CAMOB)
move_camera(C, rv3d, fly, (fly->xlock || fly->zlock || moffset[0] || moffset[1]), fly->speed);
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;
}
copy_m4_m4(prev_view_mat, view_mat);
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 (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);
}
}
} else
/*were not redrawing but we need to update the time else the view will jump */
}
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);
}
/* moved to flyEnd() */
return OPERATOR_FINISHED;
}
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;
/* 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);
}
rv3d->view = RV3D_VIEW_USER;
}
else {
shouldRotate = FALSE;
}
}
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)
@ -866,14 +1075,14 @@ 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));
}

Some files were not shown because too many files have changed in this diff Show More