diff options
author | Tamito Kajiyama <rd6t-kjym@asahi-net.or.jp> | 2010-10-10 02:30:01 +0400 |
---|---|---|
committer | Tamito Kajiyama <rd6t-kjym@asahi-net.or.jp> | 2010-10-10 02:30:01 +0400 |
commit | d7cd6e349d01f6be60649a013c22330f0ba34c54 (patch) | |
tree | caa99d6a9c1acc076cdf5c570ef8a67c24bd0880 | |
parent | 854ef1770075c6e1579ccbbd30eda57484527760 (diff) | |
parent | d420d09da982e1a874ffe2b0612b8fdd0afc980e (diff) |
Merged changes in the trunk up to revision 32390.
218 files changed, 8151 insertions, 5667 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 4966c1d0bf5..3ace8a771c5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -297,6 +297,7 @@ IF(UNIX AND NOT APPLE) FIND_PACKAGE(X11 REQUIRED) + # OpenSuse needs lutil, ArchLinux not, for now keep, can avoid by using --as-needed SET(LLIBS "-lutil -lc -lm -lpthread -lstdc++ ${X11_X11_LIB} ${X11_Xinput_LIB}") IF(CMAKE_SYSTEM_NAME MATCHES "Linux") @@ -477,13 +478,15 @@ IF(WIN32) SET(OPENCOLLADA_INC ${OPENCOLLADA}/include) SET(OPENCOLLADA_LIBPATH ${OPENCOLLADA}/lib) SET(OPENCOLLADA_LIB OpenCOLLADASaxFrameworkLoader OpenCOLLADAFramework OpenCOLLADABaseUtils OpenCOLLADAStreamWriter MathMLSolver GeneratedSaxParser xml2 buffer ftoa) - #pcre is bundled with openCollada - #SET(PCRE ${LIBDIR}/pcre) - #SET(PCRE_LIBPATH ${PCRE}/lib) SET(PCRE_LIB pcre) ENDIF(WITH_OPENCOLLADA) - # TODO: IF(WITH_LCMS) + IF(WITH_LCMS) + SET(LCMS ${LIBDIR}/lcms) + SET(LCMS_INCLUDE_DIR ${LCMS}/include) + SET(LCMS_LIBPATH ${LCMS}/lib) + SET(LCMS_LIB lcms) + ENDIF(WITH_LCMS) IF(WITH_FFMPEG) SET(FFMPEG ${LIBDIR}/ffmpeg) @@ -547,7 +550,21 @@ IF(WIN32) SET(CXX_WARNINGS "-Wall -Wno-invalid-offsetof -Wno-sign-compare") ADD_DEFINITIONS(-DFREE_WINDOWS) - + + SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -D_DEBUG") + SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -D_DEBUG") + + + SET(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -DNDEBUG") + SET(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -DNDEBUG") + + SET(CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL} -DNDEBUG") + SET(CMAKE_C_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS_MINSIZEREL} -DNDEBUG") + + SET(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -DNDEBUG") + SET(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} -DNDEBUG") + + IF(WITH_OPENMP) SET(LLIBS "${LLIBS} -lgomp") SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fopenmp") @@ -591,9 +608,6 @@ IF(WIN32) SET(OPENCOLLADA_INC ${OPENCOLLADA}/include) SET(OPENCOLLADA_LIBPATH ${OPENCOLLADA}/lib ${OPENCOLLADA}/lib) SET(OPENCOLLADA_LIB OpenCOLLADAStreamWriter OpenCOLLADASaxFrameworkLoader OpenCOLLADAFramework OpenCOLLADABaseUtils GeneratedSaxParser UTF MathMLSolver expat pcre buffer ftoa) - #pcre is bundled with openCollada - #SET(PCRE ${LIBDIR}/pcre) - #SET(PCRE_LIBPATH ${PCRE}/lib) SET(PCRE_LIB pcre) ENDIF(WITH_OPENCOLLADA) diff --git a/build_files/cmake/macros.cmake b/build_files/cmake/macros.cmake index 0957ace301c..08a571cceaf 100644 --- a/build_files/cmake/macros.cmake +++ b/build_files/cmake/macros.cmake @@ -172,11 +172,17 @@ MACRO(SETUP_LIBLINKS TARGET_LINK_LIBRARIES(${target} optimized ${EXPAT_LIB}) ENDIF(EXPAT_LIB) ELSE(WIN32) - TARGET_LINK_LIBRARIES(${target} ${OPENCOLLADA_LIB}) + TARGET_LINK_LIBRARIES(${target} ${OPENCOLLADA_LIB}) TARGET_LINK_LIBRARIES(${target} ${PCRE_LIB}) TARGET_LINK_LIBRARIES(${target} ${EXPAT_LIB}) ENDIF(WIN32) ENDIF(WITH_OPENCOLLADA) + IF(WITH_LCMS) + IF(WIN32) + TARGET_LINK_LIBRARIES(${target} debug ${LCMS_LIB}_d) + TARGET_LINK_LIBRARIES(${target} optimized ${LCMS_LIB}) + ENDIF(WIN32) + ENDIF(WITH_LCMS) IF(WIN32) TARGET_LINK_LIBRARIES(${target} ${PTHREADS_LIB}) ENDIF(WIN32) diff --git a/build_files/scons/config/linux2-config.py b/build_files/scons/config/linux2-config.py index 75428937b39..a9c74d692d7 100644 --- a/build_files/scons/config/linux2-config.py +++ b/build_files/scons/config/linux2-config.py @@ -23,9 +23,11 @@ WITH_BF_STATICCXX = False BF_CXX_LIB_STATIC = '${BF_CXX}/lib/libstdc++.a' BF_LIBSAMPLERATE = '/usr' +WITH_BF_STATICLIBSAMPLERATE = False BF_LIBSAMPLERATE_INC = '${BF_LIBSAMPLERATE}/include' BF_LIBSAMPLERATE_LIB = 'samplerate' BF_LIBSAMPLERATE_LIBPATH = '${BF_LIBSAMPLERATE}/lib' +BF_LIBSAMPLERATE_LIB_STATIC = '${BF_LIBSAMPLERATE}/lib/libsamplerate.a' WITH_BF_JACK = False BF_JACK = '/usr' @@ -34,10 +36,12 @@ BF_JACK_LIB = 'jack' BF_JACK_LIBPATH = '${BF_JACK}/lib' WITH_BF_SNDFILE = False +WITH_BF_STATICSNDFILE = False BF_SNDFILE = '/usr' BF_SNDFILE_INC = '${BF_SNDFILE}/include/sndfile' BF_SNDFILE_LIB = 'sndfile' BF_SNDFILE_LIBPATH = '${BF_SNDFILE}/lib' +BF_SNDFILE_LIB_STATIC = '${BF_SNDFILE}/lib/libsndfile.a ${BF_OGG}/lib/libvorbis.a ${BF_OGG}/lib/libFLAC.a ${BF_OGG}/lib/libvorbisenc.a ${BF_OGG}/lib/libogg.a' WITH_BF_SDL = True BF_SDL = '/usr' #$(shell sdl-config --prefix) @@ -136,10 +140,12 @@ BF_OPENJPEG_INC = '${BF_OPENJPEG}' BF_OPENJPEG_LIBPATH='${BF_OPENJPEG}/lib' WITH_BF_FFTW3 = False -BF_FFTW3 = LIBDIR + '/usr' +WITH_BF_STATICFFTW3 = False +BF_FFTW3 = '/usr' BF_FFTW3_INC = '${BF_FFTW3}/include' BF_FFTW3_LIB = 'fftw3' BF_FFTW3_LIBPATH = '${BF_FFTW3}/lib' +BF_FFTW3_LIB_STATIC = '${BF_FFTW3_LIBPATH}/libfftw3.a' WITH_BF_REDCODE = False BF_REDCODE = '#extern/libredcode' diff --git a/build_files/scons/config/win32-vc-config.py b/build_files/scons/config/win32-vc-config.py index 3572dd113bf..c8c04e74068 100644 --- a/build_files/scons/config/win32-vc-config.py +++ b/build_files/scons/config/win32-vc-config.py @@ -149,6 +149,12 @@ BF_OPENCOLLADA_INC = '${BF_OPENCOLLADA}/include' BF_OPENCOLLADA_LIB = 'OpenCOLLADAStreamWriter OpenCOLLADASaxFrameworkLoader OpenCOLLADAFramework OpenCOLLADABaseUtils GeneratedSaxParser MathMLSolver xml2 pcre buffer ftoa' BF_OPENCOLLADA_LIBPATH = '${BF_OPENCOLLADA}/lib' +WITH_BF_LCMS = True +BF_LCMS = LIBDIR + '/lcms' +BF_LCMS_INC = '${BF_LCMS}/include' +BF_LCMS_LIB = 'lcms' +BF_LCMS_LIBPATH = '${BF_LCMS}/lib' + #Ray trace optimization WITH_BF_RAYOPTIMIZATION = True BF_RAYOPTIMIZATION_SSE_FLAGS = ['/arch:SSE'] @@ -188,7 +194,6 @@ PLATFORM_LINKFLAGS = ['/SUBSYSTEM:CONSOLE','/MACHINE:IX86','/INCREMENTAL:NO','/N # BF_PROFILE_LINKFLAGS = ['-pg'] # BF_PROFILE = False -#turn off makebsc by default ( as 64 bit version does ) .. takes ages to build .. for nothing ( well some M$ addicts may disagree ) BF_BSC=False BF_BUILDDIR = '..\\build\\win32-vc' diff --git a/build_files/scons/config/win64-vc-config.py b/build_files/scons/config/win64-vc-config.py index 0a4b05a28bf..8987d66a7a0 100644 --- a/build_files/scons/config/win64-vc-config.py +++ b/build_files/scons/config/win64-vc-config.py @@ -107,23 +107,6 @@ BF_WINTAB_INC = '${BF_WINTAB}/INCLUDE' WITH_BF_BINRELOC = False -#WITH_BF_NSPR = True -#BF_NSPR = $(LIBDIR)/nspr -#BF_NSPR_INC = -I$(BF_NSPR)/include -I$(BF_NSPR)/include/nspr -#BF_NSPR_LIB = - -# Uncomment the following line to use Mozilla inplace of netscape -#CPPFLAGS += -DMOZ_NOT_NET -# Location of MOZILLA/Netscape header files... -#BF_MOZILLA = $(LIBDIR)/mozilla -#BF_MOZILLA_INC = -I$(BF_MOZILLA)/include/mozilla/nspr -I$(BF_MOZILLA)/include/mozilla -I$(BF_MOZILLA)/include/mozilla/xpcom -I$(BF_MOZILLA)/include/mozilla/idl -#BF_MOZILLA_LIB = -# Will fall back to look in BF_MOZILLA_INC/nspr and BF_MOZILLA_LIB -# if this is not set. -# -# Be paranoid regarding library creation (do not update archives) -#BF_PARANOID = True - # enable freetype2 support for text objects BF_WITH_FREETYPE = True BF_FREETYPE = LIBDIR + '/freetype' @@ -162,6 +145,12 @@ BF_OPENCOLLADA_INC = '${BF_OPENCOLLADA}/include' BF_OPENCOLLADA_LIB = 'OpenCOLLADAStreamWriter OpenCOLLADASaxFrameworkLoader OpenCOLLADAFramework OpenCOLLADABaseUtils GeneratedSaxParser MathMLSolver xml2 pcre buffer ftoa' BF_OPENCOLLADA_LIBPATH = '${BF_OPENCOLLADA}/lib' +WITH_BF_LCMS = True +BF_LCMS = LIBDIR + '/lcms' +BF_LCMS_INC = '${BF_LCMS}/include' +BF_LCMS_LIB = 'lcms' +BF_LCMS_LIBPATH = '${BF_LCMS}/lib' + #Ray trace optimization WITH_BF_RAYOPTIMIZATION = True BF_RAYOPTIMIZATION_SSE_FLAGS = ['/arch:SSE','/arch:SSE2'] @@ -194,9 +183,6 @@ CXX_WARN = [] LLIBS = ['ws2_32', 'vfw32', 'winmm', 'kernel32', 'user32', 'gdi32', 'comdlg32', 'advapi32', 'shfolder', 'shell32', 'ole32', 'oleaut32', 'uuid'] -BF_DEBUG=False -BF_BSC=False - if BF_DEBUG: BF_NUMJOBS=1 else: @@ -207,10 +193,3 @@ PLATFORM_LINKFLAGS = ['/SUBSYSTEM:CONSOLE','/MACHINE:X64','/INCREMENTAL:NO','/NO BF_BUILDDIR = '..\\build\\blender25-win64-vc' BF_INSTALLDIR='..\\install\\blender25-win64-vc' - - -######################### MERGE WITH ABOVE ################################ - - - - diff --git a/build_files/scons/tools/Blender.py b/build_files/scons/tools/Blender.py index cdfd1e10656..1f503a5ea2d 100644 --- a/build_files/scons/tools/Blender.py +++ b/build_files/scons/tools/Blender.py @@ -158,6 +158,8 @@ def setup_staticlibs(lenv): statlibs += Split(lenv['BF_ZLIB_LIB_STATIC']) if lenv['WITH_BF_FFTW3']: libincs += Split(lenv['BF_FFTW3_LIBPATH']) + if lenv['WITH_BF_STATICFFTW3']: + statlibs += Split(lenv['BF_FFTW3_LIB_STATIC']) if lenv['WITH_BF_FFMPEG'] and lenv['WITH_BF_STATICFFMPEG']: statlibs += Split(lenv['BF_FFMPEG_LIB_STATIC']) if lenv['WITH_BF_INTERNATIONAL']: @@ -178,6 +180,9 @@ def setup_staticlibs(lenv): if lenv['WITH_BF_PYTHON'] and lenv['WITH_BF_STATICPYTHON']: statlibs += Split(lenv['BF_PYTHON_LIB_STATIC']) + if lenv['WITH_BF_SNDFILE'] and lenv['WITH_BF_STATICSNDFILE']: + statlibs += Split(lenv['BF_SNDFILE_LIB_STATIC']) + if lenv['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc'): libincs += Split(lenv['BF_PTHREADS_LIBPATH']) @@ -191,6 +196,9 @@ def setup_staticlibs(lenv): if lenv['OURPLATFORM'] == 'linuxcross': libincs += Split(lenv['BF_OPENMP_LIBPATH']) + if lenv['WITH_BF_STATICLIBSAMPLERATE']: + statlibs += Split(lenv['BF_LIBSAMPLERATE_LIB_STATIC']) + # setting this last so any overriding of manually libs could be handled if lenv['OURPLATFORM'] not in ('win32-vc', 'win32-mingw', 'win64-vc', 'linuxcross'): libincs.append('/usr/lib') @@ -202,7 +210,6 @@ def setup_syslibs(lenv): lenv['BF_JPEG_LIB'], lenv['BF_PNG_LIB'], - lenv['BF_LIBSAMPLERATE_LIB'] ] if not lenv['WITH_BF_FREETYPE_STATIC']: @@ -236,9 +243,9 @@ def setup_syslibs(lenv): syslibs += Split(lenv['BF_OGG_LIB']) if lenv['WITH_BF_JACK']: syslibs += Split(lenv['BF_JACK_LIB']) - if lenv['WITH_BF_SNDFILE']: + if lenv['WITH_BF_SNDFILE'] and not lenv['WITH_BF_STATICSNDFILE']: syslibs += Split(lenv['BF_SNDFILE_LIB']) - if lenv['WITH_BF_FFTW3']: + if lenv['WITH_BF_FFTW3'] and not lenv['WITH_BF_STATICFFTW3']: syslibs += Split(lenv['BF_FFTW3_LIB']) if lenv['WITH_BF_SDL']: syslibs += Split(lenv['BF_SDL_LIB']) @@ -253,6 +260,9 @@ def setup_syslibs(lenv): syslibs += Split(lenv['BF_OPENCOLLADA_LIB']) syslibs.append(lenv['BF_EXPAT_LIB']) + if not lenv['WITH_BF_STATICLIBSAMPLERATE']: + syslibs += Split(lenv['BF_LIBSAMPLERATE_LIB']) + syslibs += lenv['LLIBS'] @@ -295,9 +305,12 @@ def buildinfo(lenv, build_type): 'BUILD_TYPE="%s"'%(build_type), 'BUILD_REV="%s"'%(build_rev), 'NAN_BUILDINFO', - 'BUILD_PLATFORM="%s:%s"'%(platform.system(), platform.architecture()[0])]) - obj = [lenv.Object (root_build_dir+'source/creator/%s_buildinfo'%build_type, - [root_build_dir+'source/creator/buildinfo.c'])] + 'BUILD_PLATFORM="%s:%s"'%(platform.system(), platform.architecture()[0])]) + + lenv.Append (CPPPATH = [root_build_dir+'source/blender/blenkernel']) + + obj = [lenv.Object (root_build_dir+'source/creator/%s_buildinfo'%build_type, [root_build_dir+'source/creator/buildinfo.c'])] + return obj ##### END LIB STUFF ############ diff --git a/build_files/scons/tools/btools.py b/build_files/scons/tools/btools.py index da916a8e89c..737ce40d702 100644 --- a/build_files/scons/tools/btools.py +++ b/build_files/scons/tools/btools.py @@ -39,9 +39,9 @@ def validate_arguments(args, bc): 'WITH_BF_PYTHON', 'BF_PYTHON', 'BF_PYTHON_VERSION', 'BF_PYTHON_INC', 'BF_PYTHON_BINARY', 'BF_PYTHON_LIB', 'BF_PYTHON_LIBPATH', 'WITH_BF_STATICPYTHON', 'BF_PYTHON_LIB_STATIC', 'BF_PYTHON_DLL', 'WITH_BF_OPENAL', 'BF_OPENAL', 'BF_OPENAL_INC', 'BF_OPENAL_LIB', 'BF_OPENAL_LIBPATH', 'WITH_BF_STATICOPENAL', 'BF_OPENAL_LIB_STATIC', 'WITH_BF_SDL', 'BF_SDL', 'BF_SDL_INC', 'BF_SDL_LIB', 'BF_SDL_LIBPATH', - 'BF_LIBSAMPLERATE', 'BF_LIBSAMPLERATE_INC', 'BF_LIBSAMPLERATE_LIB', 'BF_LIBSAMPLERATE_LIBPATH', + 'BF_LIBSAMPLERATE', 'BF_LIBSAMPLERATE_INC', 'BF_LIBSAMPLERATE_LIB', 'BF_LIBSAMPLERATE_LIBPATH', 'WITH_BF_STATICLIBSAMPLERATE', 'BF_LIBSAMPLERATE_LIB_STATIC', 'WITH_BF_JACK', 'BF_JACK', 'BF_JACK_INC', 'BF_JACK_LIB', 'BF_JACK_LIBPATH', - 'WITH_BF_SNDFILE', 'BF_SNDFILE', 'BF_SNDFILE_INC', 'BF_SNDFILE_LIB', 'BF_SNDFILE_LIBPATH', + 'WITH_BF_SNDFILE', 'BF_SNDFILE', 'BF_SNDFILE_INC', 'BF_SNDFILE_LIB', 'BF_SNDFILE_LIBPATH', 'WITH_BF_STATICSNDFILE', 'BF_SNDFILE_LIB_STATIC', 'BF_PTHREADS', 'BF_PTHREADS_INC', 'BF_PTHREADS_LIB', 'BF_PTHREADS_LIBPATH', 'WITH_BF_OPENEXR', 'BF_OPENEXR', 'BF_OPENEXR_INC', 'BF_OPENEXR_LIB', 'BF_OPENEXR_LIBPATH', 'WITH_BF_STATICOPENEXR', 'BF_OPENEXR_LIB_STATIC', 'WITH_BF_DDS', 'WITH_BF_CINEON', 'WITH_BF_HDR', @@ -61,7 +61,7 @@ def validate_arguments(args, bc): 'BF_WINTAB', 'BF_WINTAB_INC', 'WITH_BF_FREETYPE', 'BF_FREETYPE', 'BF_FREETYPE_INC', 'BF_FREETYPE_LIB', 'BF_FREETYPE_LIBPATH', 'BF_FREETYPE_LIB_STATIC', 'WITH_BF_FREETYPE_STATIC', 'WITH_BF_QUICKTIME', 'BF_QUICKTIME', 'BF_QUICKTIME_INC', 'BF_QUICKTIME_LIB', 'BF_QUICKTIME_LIBPATH', - 'WITH_BF_FFTW3', 'BF_FFTW3', 'BF_FFTW3_INC', 'BF_FFTW3_LIB', 'BF_FFTW3_LIBPATH', + 'WITH_BF_FFTW3', 'BF_FFTW3', 'BF_FFTW3_INC', 'BF_FFTW3_LIB', 'BF_FFTW3_LIBPATH', 'WITH_BF_STATICFFTW3', 'BF_FFTW3_LIB_STATIC', 'WITH_BF_STATICOPENGL', 'BF_OPENGL', 'BF_OPENGL_INC', 'BF_OPENGL_LIB', 'BF_OPENGL_LIBPATH', 'BF_OPENGL_LIB_STATIC', 'WITH_BF_COLLADA', 'BF_COLLADA', 'BF_COLLADA_INC', 'BF_COLLADA_LIB', 'BF_OPENCOLLADA', 'BF_OPENCOLLADA_INC', 'BF_OPENCOLLADA_LIB', 'BF_OPENCOLLADA_LIBPATH', 'BF_PCRE', 'BF_PCRE_LIB', 'BF_PCRE_LIBPATH', 'BF_EXPAT', 'BF_EXPAT_LIB', 'BF_EXPAT_LIBPATH', 'WITH_BF_PLAYER', @@ -92,6 +92,7 @@ def validate_arguments(args, bc): 'WITH_BF_RAYOPTIMIZATION', 'BF_RAYOPTIMIZATION_SSE_FLAGS', 'BF_NO_ELBEEM', + 'WITH_BF_CXX_GUARDEDALLOC', 'BF_VCREDIST' # Windows-only, and useful only when creating installer ] @@ -206,6 +207,8 @@ def read_opts(env, cfg, args): ('BF_LIBSAMPLERATE_INC', 'libsamplerate aka SRC include path', ''), ('BF_LIBSAMPLERATE_LIB', 'libsamplerate aka SRC library', ''), ('BF_LIBSAMPLERATE_LIBPATH', 'libsamplerate aka SRC library path', ''), + ('BF_LIBSAMPLERATE_LIB_STATIC', 'Path to libsamplerate static library', ''), + (BoolVariable('WITH_BF_STATICLIBSAMPLERATE', 'Staticly link to libsamplerate', False)), (BoolVariable('WITH_BF_JACK', 'Enable jack support if true', True)), ('BF_JACK', 'jack base path', ''), @@ -217,7 +220,9 @@ def read_opts(env, cfg, args): ('BF_SNDFILE', 'sndfile base path', ''), ('BF_SNDFILE_INC', 'sndfile include path', ''), ('BF_SNDFILE_LIB', 'sndfile library', ''), + ('BF_SNDFILE_LIB_STATIC', 'Path to sndfile static library', ''), ('BF_SNDFILE_LIBPATH', 'sndfile library path', ''), + (BoolVariable('WITH_BF_STATICSNDFILE', 'Staticly link to sndfile', False)), ('BF_PTHREADS', 'Pthreads base path', ''), ('BF_PTHREADS_INC', 'Pthreads include path', ''), @@ -352,7 +357,9 @@ def read_opts(env, cfg, args): ('BF_FFTW3', 'FFTW3 base path', ''), ('BF_FFTW3_INC', 'FFTW3 include path', ''), ('BF_FFTW3_LIB', 'FFTW3 library', ''), + ('BF_FFTW3_LIB_STATIC', 'FFTW3 static libraries', ''), ('BF_FFTW3_LIBPATH', 'FFTW3 library path', ''), + (BoolVariable('WITH_BF_STATICFFTW3', 'Staticly link to FFTW3', False)), (BoolVariable('WITH_BF_STATICOPENGL', 'Use MESA if true', True)), ('BF_OPENGL', 'OpenGL base path', ''), @@ -408,7 +415,7 @@ def read_opts(env, cfg, args): ('BF_DEBUG_CCFLAGS', 'C and C++ debug flags', ''), ('BF_DEBUG_CXXFLAGS', 'C++ only debug flags', ''), - (BoolVariable('BF_BSC', 'Create .bsc files (msvc only)', True)), + (BoolVariable('BF_BSC', 'Create .bsc files (msvc only)', False)), ('BF_BUILDDIR', 'Build dir', ''), ('BF_INSTALLDIR', 'Installation dir', ''), @@ -447,6 +454,7 @@ def read_opts(env, cfg, args): (BoolVariable('WITH_BF_RAYOPTIMIZATION', 'Enable raytracer SSE/SIMD optimization.', False)), ('BF_RAYOPTIMIZATION_SSE_FLAGS', 'SSE flags', ''), + (BoolVariable('WITH_BF_CXX_GUARDEDALLOC', 'Enable GuardedAlloc for C++ memory allocation tracking.', False)), ('BF_VCREDIST', 'Full path to vcredist', '') ) # end of opts.AddOptions() diff --git a/extern/bullet2/src/LinearMath/btQuickprof.cpp b/extern/bullet2/src/LinearMath/btQuickprof.cpp index fa45d02b3d3..621d50427d6 100644 --- a/extern/bullet2/src/LinearMath/btQuickprof.cpp +++ b/extern/bullet2/src/LinearMath/btQuickprof.cpp @@ -1,4 +1,4 @@ -/* + /*************************************************************************************************** ** diff --git a/intern/ghost/GHOST_Types.h b/intern/ghost/GHOST_Types.h index f926e72119f..20b69611bfb 100644 --- a/intern/ghost/GHOST_Types.h +++ b/intern/ghost/GHOST_Types.h @@ -96,7 +96,7 @@ typedef enum { GHOST_kModifierKeyRightAlt, GHOST_kModifierKeyLeftControl, GHOST_kModifierKeyRightControl, - GHOST_kModifierKeyCommand, // APPLE only + GHOST_kModifierKeyOS, GHOST_kModifierKeyNumMasks } GHOST_TModifierKeyMask; @@ -283,7 +283,7 @@ typedef enum { GHOST_kKeyRightControl, GHOST_kKeyLeftAlt, GHOST_kKeyRightAlt, - GHOST_kKeyCommand, // Command key on Apple, Windows key(s) on Windows + GHOST_kKeyOS, // Command key on Apple, Windows key(s) on Windows GHOST_kKeyGrLess , // German PC only! GHOST_kKeyCapsLock, diff --git a/intern/ghost/intern/GHOST_EventPrinter.cpp b/intern/ghost/intern/GHOST_EventPrinter.cpp index 645a33ab8c5..697ced64a70 100644 --- a/intern/ghost/intern/GHOST_EventPrinter.cpp +++ b/intern/ghost/intern/GHOST_EventPrinter.cpp @@ -255,9 +255,8 @@ void GHOST_EventPrinter::getKeyString(GHOST_TKey key, STR_String& str) const case GHOST_kKeyRightAlt: str = "RightAlt"; break; - case GHOST_kKeyCommand: - // APPLE only! - str = "Command"; + case GHOST_kKeyOS: + str = "OS"; break; case GHOST_kKeyGrLess: // PC german! diff --git a/intern/ghost/intern/GHOST_ModifierKeys.cpp b/intern/ghost/intern/GHOST_ModifierKeys.cpp index ed884966cb3..361329532f9 100644 --- a/intern/ghost/intern/GHOST_ModifierKeys.cpp +++ b/intern/ghost/intern/GHOST_ModifierKeys.cpp @@ -55,7 +55,7 @@ GHOST_TKey GHOST_ModifierKeys::getModifierKeyCode(GHOST_TModifierKeyMask mask) case GHOST_kModifierKeyRightAlt: key = GHOST_kKeyRightAlt; break; case GHOST_kModifierKeyLeftControl: key = GHOST_kKeyLeftControl; break; case GHOST_kModifierKeyRightControl: key = GHOST_kKeyRightControl; break; - case GHOST_kModifierKeyCommand: key = GHOST_kKeyCommand; break; + case GHOST_kModifierKeyOS: key = GHOST_kKeyOS; break; default: // Should not happen key = GHOST_kKeyUnknown; @@ -80,8 +80,8 @@ bool GHOST_ModifierKeys::get(GHOST_TModifierKeyMask mask) const return m_LeftControl; case GHOST_kModifierKeyRightControl: return m_RightControl; - case GHOST_kModifierKeyCommand: - return m_Command; + case GHOST_kModifierKeyOS: + return m_OS; default: return false; } @@ -103,8 +103,8 @@ void GHOST_ModifierKeys::set(GHOST_TModifierKeyMask mask, bool down) m_LeftControl = down; break; case GHOST_kModifierKeyRightControl: m_RightControl = down; break; - case GHOST_kModifierKeyCommand: - m_Command = down; break; + case GHOST_kModifierKeyOS: + m_OS = down; break; default: break; } @@ -119,7 +119,7 @@ void GHOST_ModifierKeys::clear() m_RightAlt = false; m_LeftControl = false; m_RightControl = false; - m_Command = false; + m_OS = false; } @@ -131,5 +131,5 @@ bool GHOST_ModifierKeys::equals(const GHOST_ModifierKeys& keys) const (m_RightAlt == keys.m_RightAlt) && (m_LeftControl == keys.m_LeftControl) && (m_RightControl == keys.m_RightControl) && - (m_Command == keys.m_Command); + (m_OS == keys.m_OS); } diff --git a/intern/ghost/intern/GHOST_ModifierKeys.h b/intern/ghost/intern/GHOST_ModifierKeys.h index e18899bc939..77d6d5757d9 100644 --- a/intern/ghost/intern/GHOST_ModifierKeys.h +++ b/intern/ghost/intern/GHOST_ModifierKeys.h @@ -96,8 +96,8 @@ struct GHOST_ModifierKeys GHOST_TUns8 m_LeftControl : 1; /** Bitfield that stores the appropriate key state. */ GHOST_TUns8 m_RightControl : 1; - /** Bitfield that stores the appropriate key state. APPLE only! */ - GHOST_TUns8 m_Command : 1; + /** Bitfield that stores the appropriate key state. */ + GHOST_TUns8 m_OS : 1; }; #endif // _GHOST_MODIFIER_KEYS_H_ diff --git a/intern/ghost/intern/GHOST_SystemCarbon.cpp b/intern/ghost/intern/GHOST_SystemCarbon.cpp index ecdc03b4347..75cbe5db574 100644 --- a/intern/ghost/intern/GHOST_SystemCarbon.cpp +++ b/intern/ghost/intern/GHOST_SystemCarbon.cpp @@ -553,7 +553,7 @@ GHOST_TSuccess GHOST_SystemCarbon::getModifierKeys(GHOST_ModifierKeys& keys) con { UInt32 modifiers = ::GetCurrentKeyModifiers(); - keys.set(GHOST_kModifierKeyCommand, (modifiers & cmdKey) ? true : false); + keys.set(GHOST_kModifierKeyOS, (modifiers & cmdKey) ? true : false); keys.set(GHOST_kModifierKeyLeftAlt, (modifiers & optionKey) ? true : false); keys.set(GHOST_kModifierKeyLeftShift, (modifiers & shiftKey) ? true : false); keys.set(GHOST_kModifierKeyLeftControl, (modifiers & controlKey) ? true : false); @@ -941,7 +941,7 @@ OSStatus GHOST_SystemCarbon::handleKeyEvent(EventRef event) pushEvent( new GHOST_EventKey(getMilliSeconds(), (modifiers & optionKey)?GHOST_kEventKeyDown:GHOST_kEventKeyUp, window, GHOST_kKeyLeftAlt) ); } if ((modifiers & cmdKey) != (m_modifierMask & cmdKey)) { - pushEvent( new GHOST_EventKey(getMilliSeconds(), (modifiers & cmdKey)?GHOST_kEventKeyDown:GHOST_kEventKeyUp, window, GHOST_kKeyCommand) ); + pushEvent( new GHOST_EventKey(getMilliSeconds(), (modifiers & cmdKey)?GHOST_kEventKeyDown:GHOST_kEventKeyUp, window, GHOST_kKeyOS) ); } m_modifierMask = modifiers; diff --git a/intern/ghost/intern/GHOST_SystemCocoa.mm b/intern/ghost/intern/GHOST_SystemCocoa.mm index 286c4eda675..97cfcf1006c 100644 --- a/intern/ghost/intern/GHOST_SystemCocoa.mm +++ b/intern/ghost/intern/GHOST_SystemCocoa.mm @@ -853,7 +853,7 @@ GHOST_TSuccess GHOST_SystemCocoa::setMouseCursorPosition(GHOST_TInt32 x, GHOST_T GHOST_TSuccess GHOST_SystemCocoa::getModifierKeys(GHOST_ModifierKeys& keys) const { - keys.set(GHOST_kModifierKeyCommand, (m_modifierMask & NSCommandKeyMask) ? true : false); + keys.set(GHOST_kModifierKeyOS, (m_modifierMask & NSCommandKeyMask) ? true : false); keys.set(GHOST_kModifierKeyLeftAlt, (m_modifierMask & NSAlternateKeyMask) ? true : false); keys.set(GHOST_kModifierKeyLeftShift, (m_modifierMask & NSShiftKeyMask) ? true : false); keys.set(GHOST_kModifierKeyLeftControl, (m_modifierMask & NSControlKeyMask) ? true : false); @@ -1018,7 +1018,7 @@ GHOST_TSuccess GHOST_SystemCocoa::handleApplicationBecomeActiveEvent() pushEvent( new GHOST_EventKey(getMilliSeconds(), (modifiers & NSAlternateKeyMask)?GHOST_kEventKeyDown:GHOST_kEventKeyUp, window, GHOST_kKeyLeftAlt) ); } if ((modifiers & NSCommandKeyMask) != (m_modifierMask & NSCommandKeyMask)) { - pushEvent( new GHOST_EventKey(getMilliSeconds(), (modifiers & NSCommandKeyMask)?GHOST_kEventKeyDown:GHOST_kEventKeyUp, window, GHOST_kKeyCommand) ); + pushEvent( new GHOST_EventKey(getMilliSeconds(), (modifiers & NSCommandKeyMask)?GHOST_kEventKeyDown:GHOST_kEventKeyUp, window, GHOST_kKeyOS) ); } m_modifierMask = modifiers; @@ -1698,7 +1698,7 @@ GHOST_TSuccess GHOST_SystemCocoa::handleKeyEvent(void *eventPtr) pushEvent( new GHOST_EventKey([event timestamp]*1000, (modifiers & NSAlternateKeyMask)?GHOST_kEventKeyDown:GHOST_kEventKeyUp, window, GHOST_kKeyLeftAlt) ); } if ((modifiers & NSCommandKeyMask) != (m_modifierMask & NSCommandKeyMask)) { - pushEvent( new GHOST_EventKey([event timestamp]*1000, (modifiers & NSCommandKeyMask)?GHOST_kEventKeyDown:GHOST_kEventKeyUp, window, GHOST_kKeyCommand) ); + pushEvent( new GHOST_EventKey([event timestamp]*1000, (modifiers & NSCommandKeyMask)?GHOST_kEventKeyDown:GHOST_kEventKeyUp, window, GHOST_kKeyOS) ); } m_modifierMask = modifiers; diff --git a/intern/ghost/intern/GHOST_SystemWin32.cpp b/intern/ghost/intern/GHOST_SystemWin32.cpp index dceecb53dd2..62559953195 100644 --- a/intern/ghost/intern/GHOST_SystemWin32.cpp +++ b/intern/ghost/intern/GHOST_SystemWin32.cpp @@ -303,9 +303,9 @@ GHOST_TSuccess GHOST_SystemWin32::getModifierKeys(GHOST_ModifierKeys& keys) cons bool lwindown = HIBYTE(::GetKeyState(VK_LWIN)) != 0; bool rwindown = HIBYTE(::GetKeyState(VK_RWIN)) != 0; if(lwindown || rwindown) - keys.set(GHOST_kModifierKeyCommand, true); + keys.set(GHOST_kModifierKeyOS, true); else - keys.set(GHOST_kModifierKeyCommand, false); + keys.set(GHOST_kModifierKeyOS, false); } else { bool down = HIBYTE(::GetKeyState(VK_SHIFT)) != 0; @@ -320,9 +320,9 @@ GHOST_TSuccess GHOST_SystemWin32::getModifierKeys(GHOST_ModifierKeys& keys) cons bool lwindown = HIBYTE(::GetKeyState(VK_LWIN)) != 0; bool rwindown = HIBYTE(::GetKeyState(VK_RWIN)) != 0; if(lwindown || rwindown) - keys.set(GHOST_kModifierKeyCommand, true); + keys.set(GHOST_kModifierKeyOS, true); else - keys.set(GHOST_kModifierKeyCommand, false); + keys.set(GHOST_kModifierKeyOS, false); } return GHOST_kSuccess; } diff --git a/intern/ghost/intern/GHOST_SystemX11.cpp b/intern/ghost/intern/GHOST_SystemX11.cpp index b07dba7319f..393761566ba 100644 --- a/intern/ghost/intern/GHOST_SystemX11.cpp +++ b/intern/ghost/intern/GHOST_SystemX11.cpp @@ -891,13 +891,13 @@ getModifierKeys( keys.set(GHOST_kModifierKeyRightAlt,false); } - // Super (Windows) - only one GHOST-kModifierKeyCommand, so mapping + // Super (Windows) - only one GHOST-kModifierKeyOS, so mapping // to either if ( ((m_keyboard_vector[super_l >> 3] >> (super_l & 7)) & 1) || ((m_keyboard_vector[super_r >> 3] >> (super_r & 7)) & 1) ) { - keys.set(GHOST_kModifierKeyCommand,true); + keys.set(GHOST_kModifierKeyOS,true); } else { - keys.set(GHOST_kModifierKeyCommand,false); + keys.set(GHOST_kModifierKeyOS,false); } return GHOST_kSuccess; } @@ -1106,8 +1106,8 @@ convertXKey( GXMAP(type,XK_Control_R, GHOST_kKeyRightControl); GXMAP(type,XK_Alt_L, GHOST_kKeyLeftAlt); GXMAP(type,XK_Alt_R, GHOST_kKeyRightAlt); - GXMAP(type,XK_Super_L, GHOST_kKeyCommand); - GXMAP(type,XK_Super_R, GHOST_kKeyCommand); + GXMAP(type,XK_Super_L, GHOST_kKeyOS); + GXMAP(type,XK_Super_R, GHOST_kKeyOS); GXMAP(type,XK_Insert, GHOST_kKeyInsert); GXMAP(type,XK_Delete, GHOST_kKeyDelete); diff --git a/intern/ghost/test/multitest/EventToBuf.c b/intern/ghost/test/multitest/EventToBuf.c index 1dbaad35994..859600bb783 100644 --- a/intern/ghost/test/multitest/EventToBuf.c +++ b/intern/ghost/test/multitest/EventToBuf.c @@ -125,7 +125,7 @@ static char *keytype_to_string(GHOST_TKey key) { K(KeyRightControl); K(KeyLeftAlt); K(KeyRightAlt); - K(KeyCommand); + K(KeyOS); K(KeyCapsLock); K(KeyNumLock); diff --git a/intern/guardedalloc/SConscript b/intern/guardedalloc/SConscript index 0c9c7d13608..74d6e07269f 100644 --- a/intern/guardedalloc/SConscript +++ b/intern/guardedalloc/SConscript @@ -2,7 +2,14 @@ Import('env') -sources = env.Glob('intern/*.c') +defs = [] + +sources = ['intern/mallocn.c', 'intern/mmap_win.c'] + +if env['WITH_BF_CXX_GUARDEDALLOC']: + sources.append('cpp/mallocn.cpp') + defs.append('WITH_CXX_GUARDEDALLOC') + incs = '.' -env.BlenderLib ('bf_intern_guardedalloc', sources, Split(incs), defines=[], libtype=['intern','player'], priority = [5,150] ) +env.BlenderLib ('bf_intern_guardedalloc', sources, Split(incs), defs, libtype=['intern','player'], priority = [5,150] ) diff --git a/intern/guardedalloc/cpp/mallocn.cpp b/intern/guardedalloc/cpp/mallocn.cpp index bf51409e84f..b4d19a62bdc 100644 --- a/intern/guardedalloc/cpp/mallocn.cpp +++ b/intern/guardedalloc/cpp/mallocn.cpp @@ -26,7 +26,7 @@ void* operator new (size_t size) { - return MEM_mallocN(size, "c++/anonymous"); + return MEM_mallocN(size, "C++/anonymous"); } /* not default but can be used when needing to set a string */ diff --git a/intern/string/SConscript b/intern/string/SConscript index f8342bf12c2..dac0ead8e61 100644 --- a/intern/string/SConscript +++ b/intern/string/SConscript @@ -4,4 +4,10 @@ Import ('env') sources = env.Glob('intern/*.cpp') incs = '.' -env.BlenderLib ('bf_intern_string', sources, Split(incs), [], libtype=['intern','player'], priority = [50,10] ) +defs = [] + +if env['WITH_BF_CXX_GUARDEDALLOC']: + defs.append('WITH_CXX_GUARDEDALLOC') + incs += ' #intern/guardedalloc' + +env.BlenderLib ('bf_intern_string', sources, Split(incs), defs, libtype=['intern','player'], priority = [50,10] ) diff --git a/release/scripts/io/netrender/client.py b/release/scripts/io/netrender/client.py index c17944725b0..128ae99ab1d 100644 --- a/release/scripts/io/netrender/client.py +++ b/release/scripts/io/netrender/client.py @@ -211,7 +211,7 @@ class NetworkRenderEngine(bpy.types.RenderEngine): address = "" if netsettings.server_address == "[default]" else netsettings.server_address - master.runMaster((address, netsettings.server_port), netsettings.use_master_broadcast, netsettings.use_master_clear, netsettings.path, self.update_stats, self.test_break) + master.runMaster((address, netsettings.server_port), netsettings.use_master_broadcast, netsettings.use_master_clear, bpy.path.abspath(netsettings.path), self.update_stats, self.test_break) def render_slave(self, scene): @@ -236,10 +236,11 @@ class NetworkRenderEngine(bpy.types.RenderEngine): # reading back result self.update_stats("", "Network render waiting for results") - + + requestResult(conn, job_id, scene.frame_current) response = conn.getresponse() - response.read() + buf = response.read() if response.status == http.client.NO_CONTENT: new_job = True @@ -248,13 +249,13 @@ class NetworkRenderEngine(bpy.types.RenderEngine): requestResult(conn, job_id, scene.frame_current) response = conn.getresponse() - response.read() - + buf = response.read() + while response.status == http.client.ACCEPTED and not self.test_break(): time.sleep(1) requestResult(conn, job_id, scene.frame_current) response = conn.getresponse() - response.read() + buf = response.read() # cancel new jobs (animate on network) on break if self.test_break() and new_job: @@ -271,18 +272,22 @@ class NetworkRenderEngine(bpy.types.RenderEngine): r = scene.render x= int(r.resolution_x*r.resolution_percentage*0.01) y= int(r.resolution_y*r.resolution_percentage*0.01) + + result_path = os.path.join(bpy.path.abspath(netsettings.path), "output.exr") + + folder = os.path.split(result_path)[0] + + if not os.path.exists(folder): + os.mkdir(folder) - f = open(os.path.join(netsettings.path, "output.exr"), "wb") - buf = response.read(1024) + f = open(result_path, "wb") - while buf: - f.write(buf) - buf = response.read(1024) + f.write(buf) f.close() result = self.begin_result(0, 0, x, y) - result.load_from_file(os.path.join(netsettings.path, "output.exr")) + result.load_from_file(result_path) self.end_result(result) conn.close() diff --git a/release/scripts/io/netrender/operators.py b/release/scripts/io/netrender/operators.py index 2b40cd77125..96601dcf653 100644 --- a/release/scripts/io/netrender/operators.py +++ b/release/scripts/io/netrender/operators.py @@ -417,7 +417,7 @@ class netclientdownload(bpy.types.Operator): for frame in job.frames: client.requestResult(conn, job.id, frame.number) response = conn.getresponse() - response.read() + buf = response.read() if response.status != http.client.OK: print("missing", frame.number) @@ -425,12 +425,9 @@ class netclientdownload(bpy.types.Operator): print("got back", frame.number) - f = open(os.path.join(netsettings.path, "%06d.exr" % frame.number), "wb") - buf = response.read(1024) + f = open(os.path.join(bpy.path.abspath(netsettings.path), "%06d.exr" % frame.number), "wb") - while buf: - f.write(buf) - buf = response.read(1024) + f.write(buf) f.close() diff --git a/release/scripts/io/netrender/slave.py b/release/scripts/io/netrender/slave.py index f017fefa4e3..526bd0b254f 100644 --- a/release/scripts/io/netrender/slave.py +++ b/release/scripts/io/netrender/slave.py @@ -21,6 +21,8 @@ import http, http.client, http.server, urllib import subprocess, time import json +import bpy + from netrender.utils import * import netrender.model import netrender.repath @@ -118,7 +120,7 @@ def render_slave(engine, netsettings, threads): slave_id = response.getheader("slave-id") - NODE_PREFIX = os.path.join(netsettings.path, "slave_" + slave_id) + NODE_PREFIX = os.path.join(bpy.path.abspath(netsettings.path), "slave_" + slave_id) if not os.path.exists(NODE_PREFIX): os.mkdir(NODE_PREFIX) diff --git a/release/scripts/modules/bpy/ops.py b/release/scripts/modules/bpy/ops.py index 7a824ce2e68..ba56fa12fe1 100644 --- a/release/scripts/modules/bpy/ops.py +++ b/release/scripts/modules/bpy/ops.py @@ -182,8 +182,15 @@ class bpy_ops_submodule_op(object): import bpy idname = self.idname() as_string = op_as_string(idname) - descr = getattr(bpy.types, idname).bl_rna.description - return as_string + "\n" + descr + op_class = getattr(bpy.types, idname) + descr = op_class.bl_rna.description + # XXX, workaround for not registering every __doc__ to save time on load. + if not descr: + descr = op_class.__doc__ + if not descr: + descr = "" + + return "# %s\n%s" % (descr, as_string) def __str__(self): # used for print(...) return "<function bpy.ops.%s.%s at 0x%x'>" % \ diff --git a/release/scripts/modules/bpy/utils.py b/release/scripts/modules/bpy/utils.py index 1792425268b..d9229c2e761 100644 --- a/release/scripts/modules/bpy/utils.py +++ b/release/scripts/modules/bpy/utils.py @@ -27,7 +27,7 @@ import bpy as _bpy import os as _os import sys as _sys -from _bpy import blend_paths +from _bpy import blend_paths, user_resource from _bpy import script_paths as _bpy_script_paths @@ -339,7 +339,14 @@ def addon_check(module_name): loaded_default = module_name in _bpy.context.user_preferences.addons mod = _sys.modules.get(module_name) - loaded_state = mod and getattr(mod, "__addon_enabled__") + 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" % + (module_name, getattr(mod, "__file__", "<unknown>"))) + + loaded_state = False return loaded_default, loaded_state diff --git a/release/scripts/op/io_scene_3ds/export_3ds.py b/release/scripts/op/io_scene_3ds/export_3ds.py index 0cbb4347dda..943c94af55f 100644 --- a/release/scripts/op/io_scene_3ds/export_3ds.py +++ b/release/scripts/op/io_scene_3ds/export_3ds.py @@ -431,6 +431,7 @@ def make_material_texture_chunk(id, images): mat_sub = _3ds_chunk(id) def add_image(img): + import os filename = os.path.basename(image.filepath) mat_sub_file = _3ds_chunk(MATMAPFILE) mat_sub_file.add_variable("mapfile", _3ds_string(sane_name(filename))) diff --git a/release/scripts/op/presets.py b/release/scripts/op/presets.py index 07852550ab7..2f6a5b69c20 100644 --- a/release/scripts/op/presets.py +++ b/release/scripts/op/presets.py @@ -66,7 +66,13 @@ class AddPresetBase(): for rna_path in self.preset_values: value = eval(rna_path) - file_preset.write("%s = %s\n" % (rna_path, repr(value))) + # convert thin wrapped sequences to simple lists to repr() + try: + value = value[:] + except: + pass + + file_preset.write("%s = %r\n" % (rna_path, value)) file_preset.close() @@ -250,7 +256,7 @@ class AddPresetKeyconfig(AddPresetBase, bpy.types.Operator): '''Add a Keyconfig Preset''' bl_idname = "wm.keyconfig_preset_add" bl_label = "Add Keyconfig Preset" - preset_menu = "PREFS_MT_keyconfigs" + preset_menu = "USERPREF_MT_keyconfigs" preset_subdir = "keyconfig" def add(self, context, filepath): diff --git a/release/scripts/presets/interaction/maya.py b/release/scripts/presets/keyconfig/maya.py index 4a40326325e..8c67a4ed231 100644 --- a/release/scripts/presets/interaction/maya.py +++ b/release/scripts/presets/keyconfig/maya.py @@ -2,7 +2,7 @@ import bpy wm = bpy.context.window_manager -kc = wm.keyconfigs.new('Maya') +kc = wm.keyconfigs.new('maya') # Map 3D View km = kc.keymaps.new('3D View', space_type='VIEW_3D', region_type='WINDOW', modal=False) diff --git a/release/scripts/ui/properties_object.py b/release/scripts/ui/properties_object.py index dd242723cac..65f1cc2d929 100644 --- a/release/scripts/ui/properties_object.py +++ b/release/scripts/ui/properties_object.py @@ -251,9 +251,6 @@ class OBJECT_PT_animation(ObjectButtonsPanel, bpy.types.Panel): col.label(text="Time Offset:") col.prop(ob, "use_time_offset_edit", text="Edit") row = col.row() - row.prop(ob, "use_time_offset_particle", text="Particle") - row.active = bool(ob.particle_systems) - row = col.row() row.prop(ob, "use_time_offset_parent", text="Parent") row.active = (ob.parent is not None) row = col.row() diff --git a/release/scripts/ui/properties_particle.py b/release/scripts/ui/properties_particle.py index 7f630d6e5ff..ff49b0e4e9f 100644 --- a/release/scripts/ui/properties_particle.py +++ b/release/scripts/ui/properties_particle.py @@ -28,12 +28,10 @@ from properties_physics_common import basic_force_field_falloff_ui def particle_panel_enabled(context, psys): phystype = psys.settings.physics_type - if phystype == 'NO' or phystype == 'KEYED': + if psys.settings.type in ('EMITTER', 'REACTOR') and phystype in ('NO', 'KEYED'): return True - if psys.settings.type in ('EMITTER', 'REACTOR') or (psys.settings.type == 'HAIR' and psys.use_hair_dynamics): - return (psys.point_cache.is_baked is False) and (not psys.is_edited) and (not context.particle_system_editable) else: - return True + return (psys.point_cache.is_baked is False) and (not psys.is_edited) and (not context.particle_system_editable) def particle_panel_poll(cls, context): diff --git a/release/scripts/ui/properties_texture.py b/release/scripts/ui/properties_texture.py index bf0c5d56e4c..ebf4e6cdf80 100644 --- a/release/scripts/ui/properties_texture.py +++ b/release/scripts/ui/properties_texture.py @@ -864,10 +864,11 @@ class TEXTURE_PT_voxeldata(TextureButtonsPanel, bpy.types.Panel): layout.template_image(tex, "image", tex.image_user, compact=True) #layout.prop(vd, "frame_duration") - layout.prop(vd, "use_still_frame") - row = layout.row() - row.active = vd.use_still_frame - row.prop(vd, "still_frame") + if vd.file_format in ('BLENDER_VOXEL', 'RAW_8BIT'): + layout.prop(vd, "use_still_frame") + row = layout.row() + row.active = vd.use_still_frame + row.prop(vd, "still_frame") layout.prop(vd, "interpolation") layout.prop(vd, "extension") diff --git a/release/scripts/ui/space_image.py b/release/scripts/ui/space_image.py index d2e5046c816..d46220ad7b9 100644 --- a/release/scripts/ui/space_image.py +++ b/release/scripts/ui/space_image.py @@ -250,6 +250,47 @@ class IMAGE_MT_uvs(bpy.types.Menu): layout.separator() layout.menu("IMAGE_MT_uvs_showhide") + +class IMAGE_MT_uvs_select_mode(bpy.types.Menu): + bl_label = "UV Select Mode" + + def draw(self, context): + layout = self.layout + + layout.operator_context = 'INVOKE_REGION_WIN' + toolsettings = context.tool_settings + + # do smart things depending on whether uv_select_sync is on + + if toolsettings.use_uv_select_sync: + prop = layout.operator("wm.context_set_value", text="Vertex", icon='VERTEXSEL') + prop.value = "(True, False, False)" + prop.data_path = "tool_settings.mesh_select_mode" + + prop = layout.operator("wm.context_set_value", text="Edge", icon='EDGESEL') + prop.value = "(False, True, False)" + prop.data_path = "tool_settings.mesh_select_mode" + + prop = layout.operator("wm.context_set_value", text="Face", icon='FACESEL') + prop.value = "(False, False, True)" + prop.data_path = "tool_settings.mesh_select_mode" + + else: + prop = layout.operator("wm.context_set_string", text="Vertex", icon='UV_VERTEXSEL') + prop.value = "VERTEX" + prop.data_path = "tool_settings.uv_select_mode" + + prop = layout.operator("wm.context_set_string", text="Edge", icon='UV_EDGESEL') + prop.value = "EDGE" + prop.data_path = "tool_settings.uv_select_mode" + + prop = layout.operator("wm.context_set_string", text="Face", icon='UV_FACESEL') + prop.value = "FACE" + prop.data_path = "tool_settings.uv_select_mode" + + prop = layout.operator("wm.context_set_string", text="Island", icon='UV_ISLANDSEL') + prop.value = "ISLAND" + prop.data_path = "tool_settings.uv_select_mode" class IMAGE_HT_header(bpy.types.Header): diff --git a/release/scripts/ui/space_info.py b/release/scripts/ui/space_info.py index fb700104b14..bd33153d017 100644 --- a/release/scripts/ui/space_info.py +++ b/release/scripts/ui/space_info.py @@ -354,7 +354,7 @@ class HELP_OT_operator_cheat_sheet(bpy.types.Operator): for op_submodule_name in dir(op_module): op = getattr(op_module, op_submodule_name) text = repr(op) - if text.startswith('bpy.ops.'): + if text.split("\n")[-1].startswith('bpy.ops.'): op_strings.append(text) tot += 1 diff --git a/release/scripts/ui/space_userpref.py b/release/scripts/ui/space_userpref.py index 9c1d114da12..df737d5630a 100644 --- a/release/scripts/ui/space_userpref.py +++ b/release/scripts/ui/space_userpref.py @@ -127,7 +127,11 @@ class USERPREF_MT_splash(bpy.types.Menu): row.label("") row = split.row() row.label("Interaction:") - row.menu("USERPREF_MT_interaction_presets", text=bpy.types.USERPREF_MT_interaction_presets.bl_label) + # XXX, no redraws + # text = bpy.path.display_name(context.window_manager.keyconfigs.active.name) + # if not text: + # text = "Blender (default)" + row.menu("USERPREF_MT_keyconfigs", text="Preset") class USERPREF_PT_interface(bpy.types.Panel): @@ -1103,7 +1107,24 @@ class WM_OT_addon_install(bpy.types.Operator): import zipfile pyfile = self.filepath - path_addons = bpy.utils.script_paths("addons")[-1] + # dont use bpy.utils.script_paths("addons") because we may not be able to write to it. + path_addons = bpy.utils.user_resource('SCRIPTS', 'addons') + + # should never happen. + if not path_addons: + self.report({'WARNING'}, "Failed to get addons path\n") + return {'CANCELLED'} + + # create path if not existing. + if not os.path.exists(path_addons): + try: + os.makedirs(path_addons) + except: + self.report({'WARNING'}, "Failed to create %r\n" % path_addons) + + traceback.print_exc() + return {'CANCELLED'} + contents = set(os.listdir(path_addons)) #check to see if the file is in compressed format (.zip) @@ -1122,7 +1143,7 @@ class WM_OT_addon_install(bpy.types.Operator): path_dest = os.path.join(path_addons, os.path.basename(pyfile)) if os.path.exists(path_dest): - self.report({'WARNING'}, "File already installed to '%s'\n" % path_dest) + self.report({'WARNING'}, "File already installed to %r\n" % path_dest) return {'CANCELLED'} #if not compressed file just copy into the addon path @@ -1155,11 +1176,6 @@ class WM_OT_addon_install(bpy.types.Operator): return {'FINISHED'} def invoke(self, context, event): - paths = bpy.utils.script_paths("addons") - if not paths: - self.report({'ERROR'}, "No 'addons' path could be found in " + str(bpy.utils.script_paths())) - return {'CANCELLED'} - wm = context.window_manager wm.add_fileselect(self) return {'RUNNING_MODAL'} diff --git a/release/scripts/ui/space_userpref_keymap.py b/release/scripts/ui/space_userpref_keymap.py index 0cdebd4734c..70fb2c57e9b 100644 --- a/release/scripts/ui/space_userpref_keymap.py +++ b/release/scripts/ui/space_userpref_keymap.py @@ -124,7 +124,7 @@ def _merge_keymaps(kc1, kc2): return merged_keymaps -class PREFS_MT_keyconfigs(bpy.types.Menu): +class USERPREF_MT_keyconfigs(bpy.types.Menu): bl_label = "KeyPresets" preset_subdir = "keyconfig" preset_operator = "wm.keyconfig_activate" @@ -384,7 +384,7 @@ class InputKeyMapPanel(bpy.types.Panel): text = bpy.path.display_name(context.window_manager.keyconfigs.active.name) if not text: text = "Blender (default)" - row.menu("PREFS_MT_keyconfigs", text=text) + row.menu("USERPREF_MT_keyconfigs", text=text) row.operator("wm.keyconfig_preset_add", text="", icon="ZOOMIN") row.operator("wm.keyconfig_preset_add", text="", icon="ZOOMOUT").remove_active = True diff --git a/release/scripts/ui/space_view3d.py b/release/scripts/ui/space_view3d.py index 02f29c7632c..5bd809fea7e 100644 --- a/release/scripts/ui/space_view3d.py +++ b/release/scripts/ui/space_view3d.py @@ -1370,7 +1370,7 @@ class VIEW3D_MT_edit_mesh_specials(bpy.types.Menu): layout.operator("mesh.select_vertex_path") -class VIEW3D_MT_edit_mesh_selection_mode(bpy.types.Menu): +class VIEW3D_MT_edit_mesh_select_mode(bpy.types.Menu): bl_label = "Mesh Select Mode" def draw(self, context): @@ -1397,7 +1397,7 @@ class VIEW3D_MT_edit_mesh_extrude(bpy.types.Menu): @staticmethod def extrude_options(context): mesh = context.object.data - selection_mode = context.tool_settings.mesh_select_mode + select_mode = context.tool_settings.mesh_select_mode totface = mesh.total_face_sel totedge = mesh.total_edge_sel @@ -1405,7 +1405,7 @@ class VIEW3D_MT_edit_mesh_extrude(bpy.types.Menu): # the following is dependent on selection modes # we don't really want that -# if selection_mode[0]: # vert +# if select_mode[0]: # vert # if totvert == 0: # return () # elif totvert == 1: @@ -1418,7 +1418,7 @@ class VIEW3D_MT_edit_mesh_extrude(bpy.types.Menu): # return (0, 2, 3) # else: # return (0, 1, 2, 3) -# elif selection_mode[1]: # edge +# elif select_mode[1]: # edge # if totedge == 0: # return () # elif totedge == 1: @@ -1429,7 +1429,7 @@ class VIEW3D_MT_edit_mesh_extrude(bpy.types.Menu): # return (0, 2) # else: # return (0, 1, 2) -# elif selection_mode[2]: # face +# elif select_mode[2]: # face # if totface == 0: # return () # elif totface == 1: @@ -1479,17 +1479,17 @@ class VIEW3D_OT_edit_mesh_extrude_individual_move(bpy.types.Operator): def execute(self, context): mesh = context.object.data - selection_mode = context.tool_settings.mesh_select_mode + select_mode = context.tool_settings.mesh_select_mode totface = mesh.total_face_sel totedge = mesh.total_edge_sel totvert = mesh.total_vert_sel - if selection_mode[2] and totface == 1: + if select_mode[2] and totface == 1: return bpy.ops.mesh.extrude_region_move('INVOKE_REGION_WIN', TRANSFORM_OT_translate={"constraint_orientation": "NORMAL", "constraint_axis": [False, False, True]}) - elif selection_mode[2] and totface > 1: + elif select_mode[2] and totface > 1: return bpy.ops.mesh.extrude_faces_move('INVOKE_REGION_WIN') - elif selection_mode[1] and totedge >= 1: + elif select_mode[1] and totedge >= 1: return bpy.ops.mesh.extrude_edges_move('INVOKE_REGION_WIN') else: return bpy.ops.mesh.extrude_vertices_move('INVOKE_REGION_WIN') diff --git a/source/Makefile b/source/Makefile index 1055c2a94e9..9768dbc0010 100644 --- a/source/Makefile +++ b/source/Makefile @@ -53,6 +53,7 @@ CPPFLAGS += -I../Physics/Dummy ifdef NAN_BUILDINFO BUILDINFO_O = $(DIR)/$(DEBUG_DIR)buildinfo.o BUILDINFO_C = $(SRCHOME)/creator/buildinfo.c + BUILDINFO_INC = -I$(SRCHOME)/blender/blenkernel BUILD_DATE := $(shell date "+%Y-%m-%d") BUILD_TIME := $(shell date "+%H:%M:%S") BUILD_REV := $(shell svnversion) @@ -528,7 +529,7 @@ endif $(DIR)/$(DEBUG_DIR)bin/blenderstatic: $(OBJS) $(GRPLIB) $(PULIB) $(COMLIB) @echo "****> Link $@" ifdef NAN_BUILDINFO - $(CCC) $(CCFLAGS) $(REL_CCFLAGS) -DBUILD_DATE='"$(BUILD_DATE)"' -DBUILD_TIME='"$(BUILD_TIME)"' -DBUILD_REV='"$(BUILD_REV)"' -DBUILD_PLATFORM='"$(CONFIG_GUESS)"' -DBUILD_TYPE='"static"' $(BUILDINFO_C) -c -o $(BUILDINFO_O) -DNAN_BUILDINFO + $(CCC) $(CCFLAGS) $(REL_CCFLAGS) -DBUILD_DATE='"$(BUILD_DATE)"' -DBUILD_TIME='"$(BUILD_TIME)"' -DBUILD_REV='"$(BUILD_REV)"' -DBUILD_PLATFORM='"$(CONFIG_GUESS)"' -DBUILD_TYPE='"static"' $(BUILDINFO_INC) $(BUILDINFO_C) -c -o $(BUILDINFO_O) -DNAN_BUILDINFO endif mkdir -p $(DIR)/$(DEBUG_DIR)bin $(CCC) $(CCFLAGS) $(LDFLAGS) -o $(DIR)/$(DEBUG_DIR)bin/blenderstatic $(BUILDINFO_O) $(OBJS) $(GRPLIB) $(PULIB) $(COMLIB) $(LLIBS) $(SADD) $(LOPTS) @@ -542,7 +543,7 @@ endif $(DIR)/$(DEBUG_DIR)bin/blender$(EXT): $(OBJS) $(GRPLIB) $(PULIB) $(COMLIB) @echo "****> Link $@" ifdef NAN_BUILDINFO - $(CCC) $(CCFLAGS) $(REL_CCFLAGS) -DBUILD_DATE='"$(BUILD_DATE)"' -DBUILD_TIME='"$(BUILD_TIME)"' -DBUILD_REV='"$(BUILD_REV)"' -DBUILD_PLATFORM='"$(CONFIG_GUESS)"' -DBUILD_TYPE='"dynamic"' $(BUILDINFO_C) -c -o $(BUILDINFO_O) -DNAN_BUILDINFO + $(CCC) $(CCFLAGS) $(REL_CCFLAGS) -DBUILD_DATE='"$(BUILD_DATE)"' -DBUILD_TIME='"$(BUILD_TIME)"' -DBUILD_REV='"$(BUILD_REV)"' -DBUILD_PLATFORM='"$(CONFIG_GUESS)"' -DBUILD_TYPE='"dynamic"' $(BUILDINFO_INC) $(BUILDINFO_C) -c -o $(BUILDINFO_O) -DNAN_BUILDINFO endif mkdir -p $(DIR)/$(DEBUG_DIR)bin $(CCC) $(CCFLAGS) $(LDFLAGS) -o $(DIR)/$(DEBUG_DIR)bin/blender$(EXT) $(BUILDINFO_O) $(OBJS) $(GRPLIB) $(PULIB) $(COMLIB) $(LLIBS) $(DADD) $(LOPTS) @@ -556,7 +557,7 @@ endif $(DIR)/$(DEBUG_DIR)bin/blenderplayer$(EXT): $(OBJS) $(SPLIB1) $(COMLIB) $(SPLIB) @echo "****> Link $@" ifdef NAN_BUILDINFO - $(CCC) $(CCFLAGS) $(REL_CCFLAGS) -DBUILD_DATE='"$(BUILD_DATE)"' -DBUILD_TIME='"$(BUILD_TIME)"' -DBUILD_REV='"$(BUILD_REV)"' -DBUILD_PLATFORM='"$(CONFIG_GUESS)"' -DBUILD_TYPE='"dynamic"' $(BUILDINFO_C) -c -o $(BUILDINFO_O) -DNAN_BUILDINFO + $(CCC) $(CCFLAGS) $(REL_CCFLAGS) -DBUILD_DATE='"$(BUILD_DATE)"' -DBUILD_TIME='"$(BUILD_TIME)"' -DBUILD_REV='"$(BUILD_REV)"' -DBUILD_PLATFORM='"$(CONFIG_GUESS)"' -DBUILD_TYPE='"dynamic"' $(BUILDINFO_INC) $(BUILDINFO_C) -c -o $(BUILDINFO_O) -DNAN_BUILDINFO endif mkdir -p $(DIR)/$(DEBUG_DIR)bin $(CCC) $(CCFLAGS) $(LDFLAGS) -o $(DIR)/$(DEBUG_DIR)bin/blenderplayer$(EXT) $(BUILDINFO_O) $(OBJS) $(SPLIB1) $(COMLIB) $(SPLIB) $(LLIBS) $(DADD) $(LOPTS) @@ -570,7 +571,7 @@ endif $(DIR)/$(DEBUG_DIR)bin/blenderdynplayer$(EXT): $(OBJS) $(COMLIB) $(SPLIB) @echo "****> Link $@" ifdef NAN_BUILDINFO - $(CCC) $(CCFLAGS) $(REL_CCFLAGS) -DBUILD_DATE='"$(BUILD_DATE)"' -DBUILD_TIME='"$(BUILD_TIME)"' -DBUILD_REV='"$(BUILD_REV)"' -DBUILD_PLATFORM='"$(CONFIG_GUESS)"' -DBUILD_TYPE='"dynamic"' $(BUILDINFO_C) -c -o $(BUILDINFO_O) -DNAN_BUILDINFO + $(CCC) $(CCFLAGS) $(REL_CCFLAGS) -DBUILD_DATE='"$(BUILD_DATE)"' -DBUILD_TIME='"$(BUILD_TIME)"' -DBUILD_REV='"$(BUILD_REV)"' -DBUILD_PLATFORM='"$(CONFIG_GUESS)"' -DBUILD_TYPE='"dynamic"' $(BUILDINFO_INC) $(BUILDINFO_C) -c -o $(BUILDINFO_O) -DNAN_BUILDINFO endif mkdir -p $(DIR)/$(DEBUG_DIR)bin $(CCC) $(CCFLAGS) $(LDFLAGS) -o $(DIR)/$(DEBUG_DIR)bin/blenderdynplayer$(EXT) $(BUILDINFO_O) $(OBJS) $(SPLIB1) $(COMLIB) $(SPLIB) $(LLIBS) $(DADD) $(LOPTS) @@ -584,7 +585,7 @@ endif $(DIR)/$(DEBUG_DIR)bin/Blender3DPlugin$(SOEXT): $(PLUGAPPLIB_XPLINK) @echo "****> Link $@" ifdef NAN_BUILDINFO - $(CCC) $(CCFLAGS) $(REL_CCFLAGS) -DBUILD_DATE='"$(BUILD_DATE)"' -DBUILD_TIME='"$(BUILD_TIME)"' -DBUILD_REV='"$(BUILD_REV)"' -DBUILD_PLATFORM='"$(CONFIG_GUESS)"' -DBUILD_TYPE='"dynamic"' $(BUILDINFO_C) -c -o $(BUILDINFO_O) -DNAN_BUILDINFO + $(CCC) $(CCFLAGS) $(REL_CCFLAGS) -DBUILD_DATE='"$(BUILD_DATE)"' -DBUILD_TIME='"$(BUILD_TIME)"' -DBUILD_REV='"$(BUILD_REV)"' -DBUILD_PLATFORM='"$(CONFIG_GUESS)"' -DBUILD_TYPE='"dynamic"' $(BUILDINFO_INC) $(BUILDINFO_C) -c -o $(BUILDINFO_O) -DNAN_BUILDINFO endif mkdir -p $(DIR)/$(DEBUG_DIR)bin $(CCC) $(CCFLAGS) $(DYNLDFLAGS) -o $@ $(PLUGAPPLIB_XPLINK) $(LOPTS) @@ -600,7 +601,7 @@ DEFFILE = ./gameengine/GamePlayer/netscape/src/npB3DPlg.def $(DIR)/$(DEBUG_DIR)npB3DPlg$(SOEXT): $(NSPLUGLIB) $(PLUGAPPLIB) $(COMLIB) $(SPLIB) @echo "****> Link $@" ifdef NAN_BUILDINFO - $(CCC) $(CCFLAGS) $(REL_CCFLAGS) -DBUILD_DATE='"$(BUILD_DATE)"' -DBUILD_TIME='"$(BUILD_TIME)"' -DBUILD_REV='"$(BUILD_REV)"' -DBUILD_PLATFORM='"$(CONFIG_GUESS)"' -DBUILD_TYPE='"dynamic"' $(BUILDINFO_C) -c -o $(BUILDINFO_O) -DNAN_BUILDINFO + $(CCC) $(CCFLAGS) $(REL_CCFLAGS) -DBUILD_DATE='"$(BUILD_DATE)"' -DBUILD_TIME='"$(BUILD_TIME)"' -DBUILD_REV='"$(BUILD_REV)"' -DBUILD_PLATFORM='"$(CONFIG_GUESS)"' -DBUILD_TYPE='"dynamic"' $(BUILDINFO_INC) $(BUILDINFO_C) -c -o $(BUILDINFO_O) -DNAN_BUILDINFO endif # $(CCC) $(DYNLDFLAGS) -o $@ $(NSPLUGLIB) $(PLUGAPPLIB) $(COMLIB) $(SPLIB) $(PLUGREMLIB) $(LLIBS) $(DADD) $(LOPTS) $(CCC) $(DYNLDFLAGS) -o $@ $(NSPLUGLIB) $(PLUGAPPLIB) $(COMLIB) $(SPLIB) $(PLUGREMLIB) $(LLIBS) $(DADD) $(LOPTS) /def:$(DEFFILE) @@ -611,7 +612,7 @@ endif $(DIR)/$(DEBUG_DIR)bin/npBlender3DPlugin$(SOEXT): $(NSPLUGLIB) $(PLUGAPPLIB) $(COMLIB) $(SPLIB) @echo "****> Link $@" ifdef NAN_BUILDINFO - $(CCC) $(CCFLAGS) $(REL_CCFLAGS) -DBUILD_DATE='"$(BUILD_DATE)"' -DBUILD_TIME='"$(BUILD_TIME)"' -DBUILD_REV='"$(BUILD_REV)"' -DBUILD_PLATFORM='"$(CONFIG_GUESS)"' -DBUILD_TYPE='"dynamic"' $(BUILDINFO_C) -c -o $(BUILDINFO_O) -DNAN_BUILDINFO + $(CCC) $(CCFLAGS) $(REL_CCFLAGS) -DBUILD_DATE='"$(BUILD_DATE)"' -DBUILD_TIME='"$(BUILD_TIME)"' -DBUILD_REV='"$(BUILD_REV)"' -DBUILD_PLATFORM='"$(CONFIG_GUESS)"' -DBUILD_TYPE='"dynamic"' $(BUILDINFO_INC) $(BUILDINFO_C) -c -o $(BUILDINFO_O) -DNAN_BUILDINFO endif mkdir -p $(DIR)/$(DEBUG_DIR)bin $(CCC) $(DYNLDFLAGS) -o $@ $(NSPLUGLIB) $(PLUGAPPLIB) $(COMLIB) $(SPLIB) $(PLUGREMLIB) $(LLIBS) $(DADD) $(LOPTS) @@ -622,7 +623,7 @@ endif $(DIR)/$(DEBUG_DIR)bin/npTestPlugin$(SOEXT): $(NSPLUGLIB) @echo "****> Link $@" ifdef NAN_BUILDINFO - $(CCC) $(CCFLAGS) $(REL_CCFLAGS) -DBUILD_DATE='"$(BUILD_DATE)"' -DBUILD_TIME='"$(BUILD_TIME)"' -DBUILD_REV='"$(BUILD_REV)"' -DBUILD_PLATFORM='"$(CONFIG_GUESS)"' -DBUILD_TYPE='"dynamic"' $(BUILDINFO_C) -c -o $(BUILDINFO_O) -DNAN_BUILDINFO + $(CCC) $(CCFLAGS) $(REL_CCFLAGS) -DBUILD_DATE='"$(BUILD_DATE)"' -DBUILD_TIME='"$(BUILD_TIME)"' -DBUILD_REV='"$(BUILD_REV)"' -DBUILD_PLATFORM='"$(CONFIG_GUESS)"' -DBUILD_TYPE='"dynamic"' $(BUILDINFO_INC) $(BUILDINFO_C) -c -o $(BUILDINFO_O) -DNAN_BUILDINFO endif mkdir -p $(DIR)/$(DEBUG_DIR)bin $(CCC) $(DYNLDFLAGS) -o $@ $(NSPLUGLIB) $(PLUGTESTLIB) $(LLIBS) $(DADD) $(LOPTS) diff --git a/source/blender/blenkernel/BKE_DerivedMesh.h b/source/blender/blenkernel/BKE_DerivedMesh.h index 33852a1b923..5b33d9e1c53 100644 --- a/source/blender/blenkernel/BKE_DerivedMesh.h +++ b/source/blender/blenkernel/BKE_DerivedMesh.h @@ -280,7 +280,8 @@ struct DerivedMesh { void (*drawMappedFaces)(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index, int *drawSmooth_r), - void *userData, int useColors); + void *userData, int useColors, + int (*setMaterial)(int, void *attribs)); /* Draw mapped faces using MTFace * o Drawing options too complicated to enumerate, look at code. diff --git a/source/blender/blenkernel/BKE_context.h b/source/blender/blenkernel/BKE_context.h index 9f38c5833a2..7cbaf6bdad2 100644 --- a/source/blender/blenkernel/BKE_context.h +++ b/source/blender/blenkernel/BKE_context.h @@ -28,13 +28,13 @@ #ifndef BKE_CONTEXT_H #define BKE_CONTEXT_H +#include "DNA_listBase.h" +#include "RNA_types.h" + #ifdef __cplusplus extern "C" { #endif -#include "DNA_listBase.h" -#include "RNA_types.h" - struct ARegion; struct bScreen; struct EditMesh; diff --git a/source/blender/blenkernel/BKE_customdata.h b/source/blender/blenkernel/BKE_customdata.h index 84eb8ef5300..5d306e75db9 100644 --- a/source/blender/blenkernel/BKE_customdata.h +++ b/source/blender/blenkernel/BKE_customdata.h @@ -32,6 +32,10 @@ #ifndef BKE_CUSTOMDATA_H #define BKE_CUSTOMDATA_H +#ifdef __cplusplus +extern "C" { +#endif + struct ID; struct CustomData; struct CustomDataLayer; @@ -295,5 +299,9 @@ void CustomData_external_read(struct CustomData *data, void CustomData_external_reload(struct CustomData *data, struct ID *id, CustomDataMask mask, int totelem); +#ifdef __cplusplus +} +#endif + #endif diff --git a/source/blender/blenkernel/BKE_depsgraph.h b/source/blender/blenkernel/BKE_depsgraph.h index 0b78a1206fe..5b2dca5299c 100644 --- a/source/blender/blenkernel/BKE_depsgraph.h +++ b/source/blender/blenkernel/BKE_depsgraph.h @@ -28,6 +28,10 @@ #ifndef DEPSGRAPH_API #define DEPSGRAPH_API +#ifdef __cplusplus +extern "C" { +#endif + /* #define DEPS_DEBUG */ @@ -120,5 +124,9 @@ void DAG_pose_sort(struct Object *ob); /* callback for editors module to do updates */ void DAG_editors_update_cb(void (*func)(struct Main *bmain, struct ID *id)); + +#ifdef __cplusplus +} +#endif #endif diff --git a/source/blender/blenkernel/BKE_fcurve.h b/source/blender/blenkernel/BKE_fcurve.h index 95e0cfc3a91..8dbfb4f2c73 100644 --- a/source/blender/blenkernel/BKE_fcurve.h +++ b/source/blender/blenkernel/BKE_fcurve.h @@ -28,6 +28,10 @@ #ifndef BKE_FCURVE_H #define BKE_FCURVE_H +#ifdef __cplusplus +extern "C" { +#endif + struct FCurve; struct FModifier; struct ChannelDriver; @@ -248,4 +252,8 @@ float fcurve_samplingcb_evalcurve(struct FCurve *fcu, void *data, float evaltime */ void fcurve_store_samples(struct FCurve *fcu, void *data, int start, int end, FcuSampleFunc sample_cb); +#ifdef __cplusplus +} +#endif + #endif /* BKE_FCURVE_H*/ diff --git a/source/blender/blenkernel/BKE_library.h b/source/blender/blenkernel/BKE_library.h index e25c379ded1..b74de66f7b6 100644 --- a/source/blender/blenkernel/BKE_library.h +++ b/source/blender/blenkernel/BKE_library.h @@ -33,6 +33,10 @@ #ifndef BKE_LIBRARY_TYPES_H #define BKE_LIBRARY_TYPES_H +#ifdef __cplusplus +extern "C" { +#endif + struct ListBase; struct ID; struct Main; @@ -85,4 +89,8 @@ void set_free_windowmanager_cb(void (*func)(struct bContext *, struct wmWindowMa /* use when "" is given to new_id() */ #define ID_FALLBACK_NAME "Untitled" +#ifdef __cplusplus +} +#endif + #endif diff --git a/source/blender/blenkernel/BKE_main.h b/source/blender/blenkernel/BKE_main.h index 74d4d114eba..3de2893fb56 100644 --- a/source/blender/blenkernel/BKE_main.h +++ b/source/blender/blenkernel/BKE_main.h @@ -40,6 +40,10 @@ #include "DNA_listBase.h" +#ifdef __cplusplus +extern "C" { +#endif + struct Library; typedef struct Main { @@ -81,5 +85,9 @@ typedef struct Main { } Main; +#ifdef __cplusplus +} +#endif + #endif diff --git a/source/blender/blenkernel/BKE_scene.h b/source/blender/blenkernel/BKE_scene.h index 96ef8d44cf4..8d5ebb64cf0 100644 --- a/source/blender/blenkernel/BKE_scene.h +++ b/source/blender/blenkernel/BKE_scene.h @@ -31,6 +31,10 @@ #ifndef BKE_SCENE_H #define BKE_SCENE_H +#ifdef __cplusplus +extern "C" { +#endif + struct AviCodecData; struct Base; struct bglMats; @@ -93,5 +97,9 @@ int get_render_child_particle_number(struct RenderData *r, int num); int get_render_shadow_samples(struct RenderData *r, int samples); float get_render_aosss_error(struct RenderData *r, float error); +#ifdef __cplusplus +} +#endif + #endif diff --git a/source/blender/blenkernel/BKE_sequencer.h b/source/blender/blenkernel/BKE_sequencer.h index 0766012b4a5..252c9fee8f7 100644 --- a/source/blender/blenkernel/BKE_sequencer.h +++ b/source/blender/blenkernel/BKE_sequencer.h @@ -220,14 +220,14 @@ int shuffle_seq(struct ListBase * seqbasep, struct Sequence *test, struct Scene int shuffle_seq_time(ListBase * seqbasep, struct Scene *evil_scene); int seqbase_isolated_sel_check(struct ListBase *seqbase); void free_imbuf_seq(struct Scene *scene, struct ListBase * seqbasep, int check_mem_usage, int keep_file_handles); -struct Sequence *seq_dupli_recursive(struct Scene *scene, struct Sequence * seq, int dupe_flag); +struct Sequence *seq_dupli_recursive(struct Scene *scene, struct Scene *scene_to, struct Sequence * seq, int dupe_flag); int seq_swap(struct Sequence *seq_a, struct Sequence *seq_b); void seq_update_sound(struct Scene* scene, struct Sequence *seq); void seq_update_muting(struct Scene* scene, struct Editing *ed); void seqbase_sound_reload(struct Scene *scene, ListBase *seqbase); void seqbase_unique_name_recursive(ListBase *seqbasep, struct Sequence *seq); -void seqbase_dupli_recursive(struct Scene *scene, ListBase *nseqbase, ListBase *seqbase, int dupe_flag); +void seqbase_dupli_recursive(struct Scene *scene, struct Scene *scene_to, ListBase *nseqbase, ListBase *seqbase, int dupe_flag); void clear_scene_in_allseqs(struct Main *bmain, struct Scene *sce); diff --git a/source/blender/blenkernel/BKE_texture.h b/source/blender/blenkernel/BKE_texture.h index 99bb8db44ed..cbae90f4c38 100644 --- a/source/blender/blenkernel/BKE_texture.h +++ b/source/blender/blenkernel/BKE_texture.h @@ -31,6 +31,10 @@ #ifndef BKE_TEXTURE_H #define BKE_TEXTURE_H +#ifdef __cplusplus +extern "C" { +#endif + struct bNode; struct Brush; struct ColorBand; @@ -112,5 +116,9 @@ struct VoxelData *BKE_copy_voxeldata(struct VoxelData *vd); int BKE_texture_dependsOnTime(const struct Tex *texture); +#ifdef __cplusplus +} +#endif + #endif diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c index 01b02653a51..eb5d77bb9b0 100644 --- a/source/blender/blenkernel/intern/DerivedMesh.c +++ b/source/blender/blenkernel/intern/DerivedMesh.c @@ -626,7 +626,9 @@ static void emDM_foreachMappedFaceCenter(DerivedMesh *dm, void (*func)(void *use func(userData, i, cent, emdm->vertexCos?emdm->faceNos[i]:efa->n); } } -static void emDM_drawMappedFaces(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index, int *drawSmooth_r), void *userData, int useColors) + +/* note, material function is ignored for now. */ +static void emDM_drawMappedFaces(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index, int *drawSmooth_r), void *userData, int useColors, int (*setMaterial)(int, void *attribs)) { EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm; EditFace *efa; diff --git a/source/blender/blenkernel/intern/anim.c b/source/blender/blenkernel/intern/anim.c index 6da9f2bbabc..b2feb01352e 100644 --- a/source/blender/blenkernel/intern/anim.c +++ b/source/blender/blenkernel/intern/anim.c @@ -648,7 +648,7 @@ int where_on_path(Object *ob, float ctime, float *vec, float *dir, float *quat, totfac= data[1]+data[2]; if(totfac>FLT_EPSILON) interp_qt_qtqt(q2, p1->quat, p2->quat, data[2] / totfac); - else QUATCOPY(q1, p3->quat); + else QUATCOPY(q2, p3->quat); totfac = data[0]+data[1]+data[2]+data[3]; if(totfac>FLT_EPSILON) interp_qt_qtqt(quat, q1, q2, (data[1]+data[2]) / totfac); diff --git a/source/blender/blenkernel/intern/cdderivedmesh.c b/source/blender/blenkernel/intern/cdderivedmesh.c index ca81e216006..b9ca7bfafe3 100644 --- a/source/blender/blenkernel/intern/cdderivedmesh.c +++ b/source/blender/blenkernel/intern/cdderivedmesh.c @@ -777,7 +777,7 @@ static void cdDM_drawFacesTex(DerivedMesh *dm, int (*setDrawOptions)(MTFace *tfa cdDM_drawFacesTex_common(dm, setDrawOptions, NULL, NULL); } -static void cdDM_drawMappedFaces(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index, int *drawSmooth_r), void *userData, int useColors) +static void cdDM_drawMappedFaces(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index, int *drawSmooth_r), void *userData, int useColors, int (*setMaterial)(int, void *attribs)) { CDDerivedMesh *cddm = (CDDerivedMesh*) dm; MVert *mv = cddm->mvert; @@ -798,16 +798,16 @@ static void cdDM_drawMappedFaces(DerivedMesh *dm, int (*setDrawOptions)(void *us DEBUG_VBO( "Using legacy code. cdDM_drawMappedFaces\n" ); for(i = 0; i < dm->numFaceData; i++, mf++) { int drawSmooth = (mf->flag & ME_SMOOTH); + int draw= 1; - if(index) { - orig = *index++; - if(setDrawOptions && orig == ORIGINDEX_NONE) - { if(nors) nors += 3; continue; } - } - else - orig = i; + orig= (index==NULL) ? i : *index++; + + if(orig == ORIGINDEX_NONE) + draw= setMaterial(mf->mat_nr + 1, NULL); + else if (setDrawOptions != NULL) + draw= setDrawOptions(userData, orig, &drawSmooth); - if(!setDrawOptions || setDrawOptions(userData, orig, &drawSmooth)) { + if(draw) { unsigned char *cp = NULL; if(useColors && mc) @@ -872,34 +872,48 @@ static void cdDM_drawMappedFaces(DerivedMesh *dm, int (*setDrawOptions)(void *us if( !GPU_buffer_legacy(dm) ) { int tottri = dm->drawObject->nelements/3; glShadeModel(GL_SMOOTH); - - for( i = 0; i < tottri; i++ ) { - int actualFace = dm->drawObject->faceRemap[i]; - int drawSmooth = (mf[actualFace].flag & ME_SMOOTH); - int draw = 1; - - if(index) { - orig = index[actualFace]; - if(setDrawOptions && orig == ORIGINDEX_NONE) - draw = 0; - } - else - orig = actualFace; - - if(draw && setDrawOptions && !setDrawOptions(userData, orig, &drawSmooth)) - draw = 0; - - /* Goal is to draw as long of a contiguous triangle - array as possible, so draw when we hit either an - invisible triangle or at the end of the array */ - if(!draw || i == tottri - 1) { - if(prevstart != i) - /* Add one to the length (via `draw') - if we're drawing at the end of the array */ - glDrawArrays(GL_TRIANGLES,prevstart*3, (i-prevstart+draw)*3); - prevstart = i + 1; + + if(tottri == 0) { + /* avoid buffer problems in following code */ + } + if(setDrawOptions == NULL) { + /* just draw the entire face array */ + glDrawArrays(GL_TRIANGLES, 0, (tottri-1) * 3); + } + else { + /* we need to check if the next material changes */ + int next_actualFace= dm->drawObject->faceRemap[0]; + + for( i = 0; i < tottri; i++ ) { + //int actualFace = dm->drawObject->faceRemap[i]; + int actualFace = next_actualFace; + MFace *mface= mf + actualFace; + int drawSmooth= (mface->flag & ME_SMOOTH); + int draw = 1; + + if(i != tottri-1) + next_actualFace= dm->drawObject->faceRemap[i+1]; + + orig= (index==NULL) ? actualFace : index[actualFace]; + + if(orig == ORIGINDEX_NONE) + draw= setMaterial(mface->mat_nr + 1, NULL); + else if (setDrawOptions != NULL) + draw= setDrawOptions(userData, orig, &drawSmooth); + + /* Goal is to draw as long of a contiguous triangle + array as possible, so draw when we hit either an + invisible triangle or at the end of the array */ + if(!draw || i == tottri - 1 || mf[actualFace].mat_nr != mf[next_actualFace].mat_nr) { + if(prevstart != i) + /* Add one to the length (via `draw') + if we're drawing at the end of the array */ + glDrawArrays(GL_TRIANGLES,prevstart*3, (i-prevstart+draw)*3); + prevstart = i + 1; + } } } + glShadeModel(GL_FLAT); } GPU_buffer_unbind(); @@ -957,8 +971,12 @@ static void cdDM_drawMappedFacesGLSL(DerivedMesh *dm, int (*setMaterial)(int, vo else if(setDrawOptions) { orig = (index)? index[a]: a; - if(orig == ORIGINDEX_NONE) - continue; + if(orig == ORIGINDEX_NONE) { + /* since the material is set by setMaterial(), faces with no + * origin can be assumed to be generated by a modifier */ + + /* continue */ + } else if(!setDrawOptions(userData, orig)) continue; } diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c index fe69f13bbda..3df395244f4 100644 --- a/source/blender/blenkernel/intern/constraint.c +++ b/source/blender/blenkernel/intern/constraint.c @@ -1201,7 +1201,7 @@ static void followpath_get_tarmat (bConstraint *con, bConstraintOb *cob, bConstr if (VALID_CONS_TARGET(ct)) { Curve *cu= ct->tar->data; - float q[4], vec[4], dir[3], quat[4], radius, x1; + float vec[4], dir[3], radius; float totmat[4][4]; float curvetime; @@ -1217,7 +1217,8 @@ static void followpath_get_tarmat (bConstraint *con, bConstraintOb *cob, bConstr makeDispListCurveTypes(cob->scene, ct->tar, 0); if (cu->path && cu->path->data) { - if ((data->followflag & FOLLOWPATH_STATIC) == 0) { + float quat[4]; + if ((data->followflag & FOLLOWPATH_STATIC) == 0) { /* animated position along curve depending on time */ if (cob->scene) curvetime= bsystem_time(cob->scene, ct->tar, cu->ctime, 0.0) - data->offset; @@ -1238,8 +1239,10 @@ static void followpath_get_tarmat (bConstraint *con, bConstraintOb *cob, bConstr curvetime= data->offset_fac; } - if ( where_on_path(ct->tar, curvetime, vec, dir, NULL, &radius, NULL) ) { + if ( where_on_path(ct->tar, curvetime, vec, dir, (data->followflag & FOLLOWPATH_FOLLOW) ? quat : NULL, &radius, NULL) ) { /* quat_pt is quat or NULL*/ if (data->followflag & FOLLOWPATH_FOLLOW) { +#if 0 + float x1, q[4]; vec_to_quat(quat, dir, (short)data->trackflag, (short)data->upflag); normalize_v3(dir); @@ -1249,10 +1252,13 @@ static void followpath_get_tarmat (bConstraint *con, bConstraintOb *cob, bConstr q[2]= -x1*dir[1]; q[3]= -x1*dir[2]; mul_qt_qtqt(quat, q, quat); - +#else + quat_apply_track(quat, data->trackflag, data->upflag); +#endif + quat_to_mat4(totmat, quat); } - + if (data->followflag & FOLLOWPATH_RADIUS) { float tmat[4][4], rmat[4][4]; scale_m4_fl(tmat, radius); diff --git a/source/blender/blenkernel/intern/fmodifier.c b/source/blender/blenkernel/intern/fmodifier.c index f63b58fe489..5a10f93ac72 100644 --- a/source/blender/blenkernel/intern/fmodifier.c +++ b/source/blender/blenkernel/intern/fmodifier.c @@ -529,7 +529,7 @@ static float fcm_cycles_time (FCurve *fcu, FModifier *fcm, float cvalue, float e FMod_Cycles *data= (FMod_Cycles *)fcm->data; float prevkey[2], lastkey[2], cycyofs=0.0f; short side=0, mode=0; - int cycles=0; + int cycles=0, ofs=0; /* check if modifier is first in stack, otherwise disable ourself... */ // FIXME... @@ -571,6 +571,7 @@ static float fcm_cycles_time (FCurve *fcu, FModifier *fcm, float cvalue, float e side= -1; mode= data->before_mode; cycles= data->before_cycles; + ofs= prevkey[0]; } } else if (evaltime > lastkey[0]) { @@ -578,6 +579,7 @@ static float fcm_cycles_time (FCurve *fcu, FModifier *fcm, float cvalue, float e side= 1; mode= data->after_mode; cycles= data->after_cycles; + ofs= lastkey[0]; } } if ELEM(0, side, mode) @@ -585,11 +587,8 @@ static float fcm_cycles_time (FCurve *fcu, FModifier *fcm, float cvalue, float e /* find relative place within a cycle */ { - float cycdx=0, cycdy=0, ofs=0; - float cycle= 0; - - /* ofs is start frame of cycle */ - ofs= prevkey[0]; + float cycdx=0, cycdy=0; + float cycle= 0, cyct=0; /* calculate period and amplitude (total height) of a cycle */ cycdx= lastkey[0] - prevkey[0]; @@ -601,6 +600,9 @@ static float fcm_cycles_time (FCurve *fcu, FModifier *fcm, float cvalue, float e /* calculate the 'number' of the cycle */ cycle= ((float)side * (evaltime - ofs) / cycdx); + + /* calculate the time inside the cycle */ + cyct= fmod(evaltime - ofs, cycdx); /* check that cyclic is still enabled for the specified time */ if (cycles == 0) { @@ -608,7 +610,7 @@ static float fcm_cycles_time (FCurve *fcu, FModifier *fcm, float cvalue, float e * as this indicates infinite cycles... */ } - else if (cycle > (cycles+1)) { + else if (cycle > cycles) { /* we are too far away from range to evaluate * TODO: but we should still hold last value... */ @@ -617,26 +619,36 @@ static float fcm_cycles_time (FCurve *fcu, FModifier *fcm, float cvalue, float e /* check if 'cyclic extrapolation', and thus calculate y-offset for this cycle */ if (mode == FCM_EXTRAPOLATE_CYCLIC_OFFSET) { - cycyofs = (float)floor((evaltime - ofs) / cycdx); + if(side < 0) + cycyofs = (float)floor((evaltime - ofs) / cycdx); + else + cycyofs = (float)ceil((evaltime - ofs) / cycdx); cycyofs *= cycdy; } - + + /* special case for cycle start/end */ + if(cyct == 0.0f) { + evaltime = (side == 1 ? lastkey[0] : prevkey[0]); + + if((mode == FCM_EXTRAPOLATE_MIRROR) && ((int)cycle % 2)) + evaltime = (side == 1 ? prevkey[0] : lastkey[0]); + } /* calculate where in the cycle we are (overwrite evaltime to reflect this) */ - if ((mode == FCM_EXTRAPOLATE_MIRROR) && ((int)(cycle) % 2)) { + else if ((mode == FCM_EXTRAPOLATE_MIRROR) && ((int)(cycle+1) % 2)) { /* when 'mirror' option is used and cycle number is odd, this cycle is played in reverse * - for 'before' extrapolation, we need to flip in a different way, otherwise values past * then end of the curve get referenced (result of fmod will be negative, and with different phase) */ if (side < 0) - evaltime= (float)(prevkey[0] - fmod(evaltime-ofs, cycdx)); + evaltime= prevkey[0] - cyct; else - evaltime= (float)(lastkey[0] - fmod(evaltime-ofs, cycdx)); + evaltime= lastkey[0] - cyct; } else { /* the cycle is played normally... */ - evaltime= (float)(fmod(evaltime-ofs, cycdx) + ofs); + evaltime= prevkey[0] + cyct; } - if (evaltime < ofs) evaltime += cycdx; + if (evaltime < prevkey[0]) evaltime += cycdx; } /* store temp data if needed */ diff --git a/source/blender/blenkernel/intern/font.c b/source/blender/blenkernel/intern/font.c index 47627d09b97..131b16b319e 100644 --- a/source/blender/blenkernel/intern/font.c +++ b/source/blender/blenkernel/intern/font.c @@ -514,11 +514,12 @@ static void buildchar(Curve *cu, unsigned long character, CharInfo *info, float float *fp, fsize, shear, x, si, co; VFontData *vfd = NULL; VChar *che = NULL; - int i, sel=0; + int i; vfd= vfont_get_data(which_vfont(cu, info)); if (!vfd) return; + /* if (cu->selend < cu->selstart) { if ((charidx >= (cu->selend)) && (charidx <= (cu->selstart-2))) sel= 1; @@ -527,6 +528,7 @@ static void buildchar(Curve *cu, unsigned long character, CharInfo *info, float if ((charidx >= (cu->selstart-1)) && (charidx <= (cu->selend-1))) sel= 1; } + */ /* make a copy at distance ofsx,ofsy with shear*/ fsize= cu->fsize; @@ -1148,14 +1150,12 @@ struct chartrans *BKE_text_to_curve(Scene *scene, Object *ob, int mode) if(mode == FO_EDIT) { /* make nurbdata */ - unsigned long cha; - freeNurblist(&cu->nurb); ct= chartransdata; if (cu->sepchar==0) { for (i= 0; i<slen; i++) { - cha = (uintptr_t) mem[i]; + unsigned long cha = (uintptr_t) mem[i]; info = &(custrinfo[i]); if (info->mat_nr > (ob->totcol)) { /* printf("Error: Illegal material index (%d) in text object, setting to 0\n", info->mat_nr); */ diff --git a/source/blender/blenkernel/intern/idprop.c b/source/blender/blenkernel/intern/idprop.c index a0df73d6c42..639e2062f83 100644 --- a/source/blender/blenkernel/intern/idprop.c +++ b/source/blender/blenkernel/intern/idprop.c @@ -421,9 +421,7 @@ void IDP_SyncGroupValues(IDProperty *dest, IDProperty *src) IDProperty *loop, *prop; for (prop=src->data.group.first; prop; prop=prop->next) { for (loop=dest->data.group.first; loop; loop=loop->next) { - if (BSTR_EQ(loop->name, prop->name)) { - int copy_done= 0; - + if (strcmp(loop->name, prop->name)==0) { if(prop->type==loop->type) { switch (prop->type) { @@ -431,11 +429,9 @@ void IDP_SyncGroupValues(IDProperty *dest, IDProperty *src) case IDP_FLOAT: case IDP_DOUBLE: loop->data= prop->data; - copy_done= 1; break; case IDP_GROUP: IDP_SyncGroupValues(loop, prop); - copy_done= 1; break; default: { @@ -702,7 +698,6 @@ IDProperty *IDP_New(int type, IDPropertyTemplate val, const char *name) case IDP_STRING: { char *st = val.str; - int stlen; prop = MEM_callocN(sizeof(IDProperty), "IDProperty string"); if (st == NULL) { @@ -710,7 +705,7 @@ IDProperty *IDP_New(int type, IDPropertyTemplate val, const char *name) prop->totallen = DEFAULT_ALLOC_FOR_NULL_STRINGS; prop->len = 1; /*NULL string, has len of 1 to account for null byte.*/ } else { - stlen = strlen(st) + 1; + int stlen = strlen(st) + 1; prop->data.pointer = MEM_callocN(stlen, "id property string 2"); prop->len = prop->totallen = stlen; strcpy(prop->data.pointer, st); diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c index cb2261932ce..6dd1d4280ec 100644 --- a/source/blender/blenkernel/intern/image.c +++ b/source/blender/blenkernel/intern/image.c @@ -596,7 +596,7 @@ void BKE_image_free_all_textures(void) { Tex *tex; Image *ima; - unsigned int totsize= 0; + /* unsigned int totsize= 0; */ for(ima= G.main->image.first; ima; ima= ima->id.next) ima->id.flag &= ~LIB_DOIT; @@ -607,13 +607,14 @@ void BKE_image_free_all_textures(void) for(ima= G.main->image.first; ima; ima= ima->id.next) { if(ima->ibufs.first && (ima->id.flag & LIB_DOIT)) { + /* ImBuf *ibuf; for(ibuf= ima->ibufs.first; ibuf; ibuf= ibuf->next) { if(ibuf->mipmap[0]) totsize+= 1.33*ibuf->x*ibuf->y*4; else totsize+= ibuf->x*ibuf->y*4; - } + } */ image_free_buffers(ima); } } @@ -2183,7 +2184,7 @@ ImBuf *BKE_image_get_ibuf(Image *ima, ImageUser *iuser) void BKE_image_user_calc_frame(ImageUser *iuser, int cfra, int fieldnr) { - int imanr, len; + int len; /* here (+fie_ima/2-1) makes sure that division happens correctly */ len= (iuser->fie_ima*iuser->frames)/2; @@ -2192,8 +2193,9 @@ void BKE_image_user_calc_frame(ImageUser *iuser, int cfra, int fieldnr) iuser->framenr= 0; } else { + int imanr; cfra= cfra - iuser->sfra+1; - + /* cyclic */ if(iuser->cycl) { cfra= ( (cfra) % len ); diff --git a/source/blender/blenkernel/intern/lattice.c b/source/blender/blenkernel/intern/lattice.c index 1390f0dbd56..638cab58229 100644 --- a/source/blender/blenkernel/intern/lattice.c +++ b/source/blender/blenkernel/intern/lattice.c @@ -599,16 +599,6 @@ static int calc_curve_deform(Scene *scene, Object *par, float *co, short axis, C } #endif - - static float q_x90d[4] = {0.70710676908493, 0.70710676908493, 0.0, 0.0}; // float rot_axis[3]= {1,0,0}; axis_angle_to_quat(q, rot_axis, 90 * (M_PI / 180)); - static float q_y90d[4] = {0.70710676908493, 0.0, 0.70710676908493, 0.0}; // float rot_axis[3]= {0,1,0}; axis_angle_to_quat(q, rot_axis, 90 * (M_PI / 180)); - static float q_z90d[4] = {0.70710676908493, 0.0, 0.0, 0.70710676908493}; // float rot_axis[3]= {0,0,2}; axis_angle_to_quat(q, rot_axis, 90 * (M_PI / 180)); - - static float q_nx90d[4] = {0.70710676908493, -0.70710676908493, 0.0, 0.0}; // float rot_axis[3]= {1,0,0}; axis_angle_to_quat(q, rot_axis, -90 * (M_PI / 180)); - static float q_ny90d[4] = {0.70710676908493, 0.0, -0.70710676908493, 0.0}; // float rot_axis[3]= {0,1,0}; axis_angle_to_quat(q, rot_axis, -90 * (M_PI / 180)); - static float q_nz90d[4] = {0.70710676908493, 0.0, 0.0, -0.70710676908493}; // float rot_axis[3]= {0,0,2}; axis_angle_to_quat(q, rot_axis, -90 * (M_PI / 180)); - - if(cd->no_rot_axis) { /* set by caller */ /* this is not exactly the same as 2.4x, since the axis is having rotation removed rather then @@ -635,53 +625,18 @@ static int calc_curve_deform(Scene *scene, Object *par, float *co, short axis, C * Notice X,Y,Z Up all have light colors and each ordered CCW. * * Now for Neg Up XYZ, the colors are all dark, and ordered clockwise - Campbell + * + * note: moved functions into quat_apply_track/vec_apply_track * */ + copy_qt_qt(quat, new_quat); + copy_v3_v3(cent, co); + + /* zero the axis which is not used, + * the big block of text above now applies to these 3 lines */ + quat_apply_track(quat, axis-1, (axis==1 || axis==3) ? 1:0); /* up flag is a dummy, set so no rotation is done */ + vec_apply_track(cent, axis-1); + cent[axis < 4 ? axis-1 : axis-4]= 0.0f; - switch(axis) { - case MOD_CURVE_POSX: - mul_qt_qtqt(quat, new_quat, q_y90d); - - cent[0]= 0.0; - cent[1]= co[2]; - cent[2]= co[1]; - break; - case MOD_CURVE_NEGX: - mul_qt_qtqt(quat, new_quat, q_ny90d); - - cent[0]= 0.0; - cent[1]= -co[1]; - cent[2]= co[2]; - - break; - case MOD_CURVE_POSY: - mul_qt_qtqt(quat, new_quat, q_x90d); - - cent[0]= co[2]; - cent[1]= 0.0; - cent[2]= -co[0]; - break; - case MOD_CURVE_NEGY: - mul_qt_qtqt(quat, new_quat, q_nx90d); - - cent[0]= -co[0]; - cent[1]= 0.0; - cent[2]= -co[2]; - break; - case MOD_CURVE_POSZ: - mul_qt_qtqt(quat, new_quat, q_z90d); - - cent[0]= co[1]; - cent[1]= -co[0]; - cent[2]= 0.0; - break; - case MOD_CURVE_NEGZ: - mul_qt_qtqt(quat, new_quat, q_nz90d); - - cent[0]= co[0]; - cent[1]= -co[1]; - cent[2]= 0.0; - break; - } /* scale if enabled */ if(cu->flag & CU_PATH_RADIUS) diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c index 216318d1dbc..5bf41c00bc3 100644 --- a/source/blender/blenkernel/intern/library.c +++ b/source/blender/blenkernel/intern/library.c @@ -39,6 +39,7 @@ #include <string.h> #include <stdlib.h> #include <stddef.h> +#include <assert.h> #include "MEM_guardedalloc.h" @@ -660,11 +661,9 @@ void *copy_libblock(void *rt) lb= which_libbase(G.main, GS(id->name)); idn= alloc_libblock(lb, GS(id->name), id->name+2); - - if(idn==NULL) { - printf("ERROR: Illegal ID name for %s (Crashing now)\n", id->name); - } - + + assert(idn != NULL); + idn_len= MEM_allocN_len(idn); if(idn_len - sizeof(ID) > 0) { cp= (char *)id; diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c index 43d26f26d1f..d7c95a007e5 100644 --- a/source/blender/blenkernel/intern/modifier.c +++ b/source/blender/blenkernel/intern/modifier.c @@ -63,8 +63,8 @@ ModifierTypeInfo *modifierType_getInfo(ModifierType type) types_init= 0; } - if(type >= 0 && type < NUM_MODIFIER_TYPES && - types[type]->name[0] != '\0') { + /* type unsigned, no need to chech < 0 */ + if(type < NUM_MODIFIER_TYPES && types[type]->name[0] != '\0') { return types[type]; } else { diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index d9ee67920eb..0c437db335b 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -1791,9 +1791,10 @@ static void ob_parcurve(Scene *scene, Object *ob, Object *par, float mat[][4]) /* vec: 4 items! */ - if( where_on_path(par, ctime, vec, dir, NULL, &radius, NULL) ) { + if( where_on_path(par, ctime, vec, dir, cu->flag & CU_FOLLOW ? quat:NULL, &radius, NULL) ) { if(cu->flag & CU_FOLLOW) { +#if 0 vec_to_quat( quat,dir, ob->trackflag, ob->upflag); /* the tilt */ @@ -1804,8 +1805,11 @@ static void ob_parcurve(Scene *scene, Object *ob, Object *par, float mat[][4]) q[2]= -x1*dir[1]; q[3]= -x1*dir[2]; mul_qt_qtqt(quat, q, quat); - - quat_to_mat4( mat,quat); +#else + quat_apply_track(quat, ob->trackflag, ob->upflag); +#endif + + quat_to_mat4(mat,quat); } if(cu->flag & CU_PATH_RADIUS) { diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c index 784f6e40706..a15e66ed843 100644 --- a/source/blender/blenkernel/intern/pointcache.c +++ b/source/blender/blenkernel/intern/pointcache.c @@ -1015,8 +1015,9 @@ void BKE_ptcache_ids_from_object(ListBase *lb, Object *ob, Scene *scene, int dup if(ELEM(psys->part->phystype, PART_PHYS_NO, PART_PHYS_KEYED)) continue; - if(psys->part->type == PART_HAIR && (psys->flag & PSYS_HAIR_DYNAMICS)==0) - continue; + /* hair needs to be included in id-list for cache edit mode to work */ + /* if(psys->part->type == PART_HAIR && (psys->flag & PSYS_HAIR_DYNAMICS)==0) */ + /* continue; */ if(psys->part->type == PART_FLUID) continue; @@ -1081,7 +1082,7 @@ void BKE_ptcache_ids_from_object(ListBase *lb, Object *ob, Scene *scene, int dup static int ptcache_path(PTCacheID *pid, char *filename) { - Library *lib= (pid)? pid->ob->id.lib: NULL; + Library *lib= (pid->ob)? pid->ob->id.lib: NULL; const char *blendfilename= (lib && (pid->cache->flag & PTCACHE_IGNORE_LIBPATH)==0) ? lib->filepath: G.sce; size_t i; @@ -1889,7 +1890,7 @@ int BKE_ptcache_write_cache(PTCacheID *pid, int cfra) } if(cache->cached_frames) - cache->cached_frames[cfra] = 1; + cache->cached_frames[cfra-cache->startframe] = 1; if(pf) ptcache_file_close(pf); diff --git a/source/blender/blenkernel/intern/report.c b/source/blender/blenkernel/intern/report.c index 3773757f5d5..f69547fd1da 100644 --- a/source/blender/blenkernel/intern/report.c +++ b/source/blender/blenkernel/intern/report.c @@ -127,6 +127,7 @@ void BKE_reportf(ReportList *reports, ReportType type, const char *format, ...) va_start(args, format); vprintf(format, args); va_end(args); + fprintf(stdout, "\n"); /* otherise each report needs to include a \n */ fflush(stdout); /* this ensures the message is printed before a crash */ } diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c index b08532e6bd3..328f0955271 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -212,6 +212,9 @@ Scene *copy_scene(Main *bmain, Scene *sce, int type) if(type == SCE_COPY_LINK_DATA || type == SCE_COPY_FULL) { ID_NEW(scen->camera); } + + /* before scene copy */ + sound_create_scene(scen); /* world */ if(type == SCE_COPY_FULL) { @@ -223,12 +226,10 @@ Scene *copy_scene(Main *bmain, Scene *sce, int type) if(sce->ed) { scen->ed= MEM_callocN( sizeof(Editing), "addseq"); scen->ed->seqbasep= &scen->ed->seqbase; - seqbase_dupli_recursive(sce, &scen->ed->seqbase, &sce->ed->seqbase, SEQ_DUPE_ALL); + seqbase_dupli_recursive(sce, scen, &scen->ed->seqbase, &sce->ed->seqbase, SEQ_DUPE_ALL); } } - sound_create_scene(scen); - return scen; } diff --git a/source/blender/blenkernel/intern/sequencer.c b/source/blender/blenkernel/intern/sequencer.c index b6bb5c3a51b..8c496fea3b0 100644 --- a/source/blender/blenkernel/intern/sequencer.c +++ b/source/blender/blenkernel/intern/sequencer.c @@ -1861,6 +1861,15 @@ static ImBuf * seq_render_scene_strip_impl( if(rendering) re= RE_NewRender(" do_build_seq_ibuf"); + /* If the top level scene that does the sequencer rendering is included + * as a strip the default render name for the strip will conflict with + * the original render, so override the name in this case. + * See bugs #22236 and #24160 for examples. + * XXX: Somebody with deeper insight to the rendering pipeline should + * probably check if this is the best way to handle this. -jahka + */ + else if(seq->scene == scene) + re= RE_NewRender("scene_conflict_render"); else re= RE_NewRender(sce->id.name); @@ -3531,8 +3540,9 @@ Sequence *sequencer_add_movie_strip(bContext *C, ListBase *seqbasep, SeqLoadInfo } -static Sequence *seq_dupli(struct Scene *scene, Sequence *seq, int dupe_flag) +static Sequence *seq_dupli(struct Scene *scene, struct Scene *scene_to, Sequence *seq, int dupe_flag) { + Scene *sce_audio= scene_to ? scene_to : scene; Sequence *seqn = MEM_dupallocN(seq); seq->tmp = seqn; @@ -3566,7 +3576,7 @@ static Sequence *seq_dupli(struct Scene *scene, Sequence *seq, int dupe_flag) } else if(seq->type == SEQ_SCENE) { seqn->strip->stripdata = 0; if(seq->scene_sound) - seqn->scene_sound = sound_scene_add_scene_sound(scene, seqn, seq->startdisp, seq->enddisp, seq->startofs + seq->anim_startofs); + seqn->scene_sound = sound_scene_add_scene_sound(sce_audio, seqn, seq->startdisp, seq->enddisp, seq->startofs + seq->anim_startofs); } else if(seq->type == SEQ_MOVIE) { seqn->strip->stripdata = MEM_dupallocN(seq->strip->stripdata); @@ -3575,7 +3585,7 @@ static Sequence *seq_dupli(struct Scene *scene, Sequence *seq, int dupe_flag) seqn->strip->stripdata = MEM_dupallocN(seq->strip->stripdata); if(seq->scene_sound) - seqn->scene_sound = sound_add_scene_sound(scene, seqn, seq->startdisp, seq->enddisp, seq->startofs + seq->anim_startofs); + seqn->scene_sound = sound_add_scene_sound(sce_audio, seqn, seq->startdisp, seq->enddisp, seq->startofs + seq->anim_startofs); seqn->sound->id.us++; } else if(seq->type == SEQ_IMAGE) { @@ -3610,13 +3620,13 @@ static Sequence *seq_dupli(struct Scene *scene, Sequence *seq, int dupe_flag) return seqn; } -Sequence * seq_dupli_recursive(struct Scene *scene, Sequence * seq, int dupe_flag) +Sequence * seq_dupli_recursive(struct Scene *scene, struct Scene *scene_to, Sequence * seq, int dupe_flag) { - Sequence * seqn = seq_dupli(scene, seq, dupe_flag); + Sequence * seqn = seq_dupli(scene, scene_to, seq, dupe_flag); if (seq->type == SEQ_META) { Sequence *s; for(s= seq->seqbase.first; s; s = s->next) { - Sequence *n = seq_dupli_recursive(scene, s, dupe_flag); + Sequence *n = seq_dupli_recursive(scene, scene_to, s, dupe_flag); if (n) { BLI_addtail(&seqn->seqbase, n); } @@ -3625,7 +3635,7 @@ Sequence * seq_dupli_recursive(struct Scene *scene, Sequence * seq, int dupe_fla return seqn; } -void seqbase_dupli_recursive(Scene *scene, ListBase *nseqbase, ListBase *seqbase, int dupe_flag) +void seqbase_dupli_recursive(Scene *scene, Scene *scene_to, ListBase *nseqbase, ListBase *seqbase, int dupe_flag) { Sequence *seq; Sequence *seqn = 0; @@ -3634,7 +3644,7 @@ void seqbase_dupli_recursive(Scene *scene, ListBase *nseqbase, ListBase *seqbase for(seq= seqbase->first; seq; seq= seq->next) { seq->tmp= NULL; if((seq->flag & SELECT) || (dupe_flag & SEQ_DUPE_ALL)) { - seqn = seq_dupli(scene, seq, dupe_flag); + seqn = seq_dupli(scene, scene_to, seq, dupe_flag); if (seqn) { /*should never fail */ if(dupe_flag & SEQ_DUPE_CONTEXT) { seq->flag &= ~SEQ_ALLSEL; @@ -3643,7 +3653,7 @@ void seqbase_dupli_recursive(Scene *scene, ListBase *nseqbase, ListBase *seqbase BLI_addtail(nseqbase, seqn); if(seq->type==SEQ_META) - seqbase_dupli_recursive(scene, &seqn->seqbase, &seq->seqbase, dupe_flag); + seqbase_dupli_recursive(scene, scene_to, &seqn->seqbase, &seq->seqbase, dupe_flag); if(dupe_flag & SEQ_DUPE_CONTEXT) { if (seq == last_seq) { diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c index d6486c3ee4d..6323e1e3c79 100644 --- a/source/blender/blenkernel/intern/subsurf_ccg.c +++ b/source/blender/blenkernel/intern/subsurf_ccg.c @@ -1619,9 +1619,12 @@ static void ccgDM_drawFacesTex_common(DerivedMesh *dm, if(drawParams) flag = drawParams(tf, mcol, mat_nr); - else + else if (index != ORIGINDEX_NONE) flag= (drawParamsMapped)? drawParamsMapped(userData, index): 1; - + else + flag= GPU_enable_material(mat_nr, NULL) ? 1:0; + + if (flag == 0) { /* flag 0 == the face is hidden or invisible */ if(tf) tf += gridFaces*gridFaces*numVerts; if(mcol) mcol += gridFaces*gridFaces*numVerts*4; @@ -1761,7 +1764,7 @@ static void ccgDM_drawUVEdges(DerivedMesh *dm) } } -static void ccgDM_drawMappedFaces(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index, int *drawSmooth_r), void *userData, int useColors) { +static void ccgDM_drawMappedFaces(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index, int *drawSmooth_r), void *userData, int useColors, int (*setMaterial)(int, void *attribs)) { CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm; CCGSubSurf *ss = ccgdm->ss; MCol *mcol= NULL; @@ -1793,10 +1796,14 @@ static void ccgDM_drawMappedFaces(DerivedMesh *dm, int (*setDrawOptions)(void *u mcol += gridFaces*gridFaces*numVerts*4; } - if (index!=-1) { - int draw; - draw = setDrawOptions==NULL ? 1 : setDrawOptions(userData, index, &drawSmooth); - + { + int draw= 1; + + if(index == ORIGINDEX_NONE) + draw= setMaterial(faceFlags ? faceFlags[origIndex*2 + 1] + 1: 1, NULL); /* XXX, no faceFlags no material */ + else if (setDrawOptions) + draw= setDrawOptions(userData, index, &drawSmooth); + if (draw) { if (draw==2) { glEnable(GL_POLYGON_STIPPLE); diff --git a/source/blender/blenkernel/intern/unit.c b/source/blender/blenkernel/intern/unit.c index 3d984c7e877..25aab77ba9b 100644 --- a/source/blender/blenkernel/intern/unit.c +++ b/source/blender/blenkernel/intern/unit.c @@ -398,7 +398,6 @@ void bUnit_AsString(char *str, int len_max, double value, int prec, int system, /* split output makes sense only for length, mass and time */ if(split && (type==B_UNIT_LENGTH || type==B_UNIT_MASS || type==B_UNIT_TIME)) { - int i; bUnitDef *unit_a, *unit_b; double value_a, value_b; @@ -406,7 +405,7 @@ void bUnit_AsString(char *str, int len_max, double value, int prec, int system, /* check the 2 is a smaller unit */ if(unit_b > unit_a) { - i= unit_as_string(str, len_max, value_a, prec, usys, unit_a, '\0'); + int i= unit_as_string(str, len_max, value_a, prec, usys, unit_a, '\0'); /* is there enough space for at least 1 char of the next unit? */ if(i+2 < len_max) { diff --git a/source/blender/blenlib/BLI_fileops.h b/source/blender/blenlib/BLI_fileops.h index 6c98d30e4b1..b721a21b1b9 100644 --- a/source/blender/blenlib/BLI_fileops.h +++ b/source/blender/blenlib/BLI_fileops.h @@ -36,6 +36,10 @@ #ifndef BLI_FILEOPS_H #define BLI_FILEOPS_H +#ifdef __cplusplus +extern "C" { +#endif + void BLI_recurdir_fileops(char *dirname); int BLI_link(char *file, char *to); int BLI_is_writable(char *filename); @@ -60,5 +64,9 @@ char *first_slash(char *string); void BLI_setCmdCallBack(int (*f)(char*)); #endif +#ifdef __cplusplus +} +#endif + #endif diff --git a/source/blender/blenlib/BLI_math_rotation.h b/source/blender/blenlib/BLI_math_rotation.h index 1b3f4dced02..321fd28a62f 100644 --- a/source/blender/blenlib/BLI_math_rotation.h +++ b/source/blender/blenlib/BLI_math_rotation.h @@ -169,6 +169,9 @@ void mul_v3m3_dq(float r[3], float R[3][3], DualQuat *dq); void mat4_to_dquat(DualQuat *r, float base[4][4], float M[4][4]); void dquat_to_mat4(float R[4][4], DualQuat *dq); +void quat_apply_track(float quat[4], short axis, short upflag); +void vec_apply_track(float vec[3], short axis); + float lens_to_angle(float lens); float angle_to_lens(float angle); diff --git a/source/blender/blenlib/BLI_math_vector.h b/source/blender/blenlib/BLI_math_vector.h index 215ddf2f2d9..b160097a33d 100644 --- a/source/blender/blenlib/BLI_math_vector.h +++ b/source/blender/blenlib/BLI_math_vector.h @@ -95,6 +95,7 @@ MINLINE void star_m3_v3(float R[3][3],float a[3]); MINLINE float len_v2(const float a[2]); MINLINE float len_v2v2(const float a[2], const float b[2]); +MINLINE float len_squared_v2v2(const float a[3], const float b[3]); MINLINE float len_v3(const float a[3]); MINLINE float len_v3v3(const float a[3], const float b[3]); MINLINE float len_squared_v3v3(const float a[3], const float b[3]); diff --git a/source/blender/blenlib/BLI_path_util.h b/source/blender/blenlib/BLI_path_util.h index f01e1a25d8a..b9a4468fe57 100644 --- a/source/blender/blenlib/BLI_path_util.h +++ b/source/blender/blenlib/BLI_path_util.h @@ -44,6 +44,7 @@ char *BLI_getDefaultDocumentFolder(void); char *BLI_get_folder(int folder_id, char *subfolder); char *BLI_get_folder_create(int folder_id, char *subfolder); +char *BLI_get_user_folder_notest(int folder_id, char *subfolder); /* folder_id */ diff --git a/source/blender/blenlib/intern/freetypefont.c b/source/blender/blenlib/intern/freetypefont.c index 6d6abc88999..fc41839c303 100644 --- a/source/blender/blenlib/intern/freetypefont.c +++ b/source/blender/blenlib/intern/freetypefont.c @@ -252,15 +252,15 @@ static void freetypechar_to_vchar(FT_Face face, FT_ULong charcode, VFontData *vf } // get the handles that are aligned, tricky... - // DistVL2Dfl, check if the three beztriple points are on one line - // VecLenf, see if there's a distance between the three points - // VecLenf again, to check the angle between the handles + // dist_to_line_v2, check if the three beztriple points are on one line + // len_squared_v2v2, see if there's a distance between the three points + // len_squared_v2v2 again, to check the angle between the handles // finally, check if one of them is a vector handle if((dist_to_line_v2(bezt->vec[0],bezt->vec[1],bezt->vec[2]) < 0.001) && - (len_v3v3(bezt->vec[0], bezt->vec[1]) > 0.0001) && - (len_v3v3(bezt->vec[1], bezt->vec[2]) > 0.0001) && - (len_v3v3(bezt->vec[0], bezt->vec[2]) > 0.0002) && - (len_v3v3(bezt->vec[0], bezt->vec[2]) > MAX2(len_v3v3(bezt->vec[0], bezt->vec[1]), len_v3v3(bezt->vec[1], bezt->vec[2]))) && + (len_squared_v2v2(bezt->vec[0], bezt->vec[1]) > 0.0001*0.0001) && + (len_squared_v2v2(bezt->vec[1], bezt->vec[2]) > 0.0001*0.0001) && + (len_squared_v2v2(bezt->vec[0], bezt->vec[2]) > 0.0002*0.0001) && + (len_squared_v2v2(bezt->vec[0], bezt->vec[2]) > MAX2(len_squared_v2v2(bezt->vec[0], bezt->vec[1]), len_squared_v2v2(bezt->vec[1], bezt->vec[2]))) && bezt->h1 != HD_VECT && bezt->h2 != HD_VECT) { bezt->h1= bezt->h2= HD_ALIGN; diff --git a/source/blender/blenlib/intern/math_color.c b/source/blender/blenlib/intern/math_color.c index 2b6a091cc8d..f0ef8b2c93d 100644 --- a/source/blender/blenlib/intern/math_color.c +++ b/source/blender/blenlib/intern/math_color.c @@ -25,6 +25,7 @@ * ***** END GPL LICENSE BLOCK ***** * */ +#include <assert.h> #include "BLI_math.h" @@ -133,6 +134,8 @@ void rgb_to_ycc(float r, float g, float b, float *ly, float *lcb, float *lcr, in cb=(-0.16874f*sr)-(0.33126f*sg)+(0.5f*sb)+128.0f; cr=(0.5f*sr)-(0.41869f*sg)-(0.08131f*sb)+128.0f; break; + default: + assert(!"invalid colorspace"); } *ly=y; @@ -163,6 +166,8 @@ void ycc_to_rgb(float y, float cb, float cr, float *lr, float *lg, float *lb, in g=y-0.34414f*cb - 0.71414f*cr + 135.45984f; b=y+1.772f*cb - 226.816f; break; + default: + assert(!"invalid colorspace"); } *lr=r/255.0f; *lg=g/255.0f; diff --git a/source/blender/blenlib/intern/math_rotation.c b/source/blender/blenlib/intern/math_rotation.c index b8cef511293..3b58fe88bf5 100644 --- a/source/blender/blenlib/intern/math_rotation.c +++ b/source/blender/blenlib/intern/math_rotation.c @@ -1530,6 +1530,73 @@ void copy_dq_dq(DualQuat *dq1, DualQuat *dq2) memcpy(dq1, dq2, sizeof(DualQuat)); } +/* axis matches eTrackToAxis_Modes */ +void quat_apply_track(float quat[4], short axis, short upflag) +{ + /* rotations are hard coded to match vec_to_quat */ + const float quat_track[][4]= {{0.70710676908493, 0.0, -0.70710676908493, 0.0}, /* pos-y90 */ + {0.5, 0.5, 0.5, 0.5}, /* Quaternion((1,0,0), radians(90)) * Quaternion((0,1,0), radians(90)) */ + {0.70710676908493, 0.0, 0.0, 0.70710676908493}, /* pos-z90 */ + {0.70710676908493, 0.0, 0.70710676908493, 0.0}, /* neg-y90 */ + {0.5, -0.5, -0.5, 0.5}, /* Quaternion((1,0,0), radians(-90)) * Quaternion((0,1,0), radians(-90)) */ + {-3.0908619663705394e-08, 0.70710676908493, 0.70710676908493, 3.0908619663705394e-08}}; /* no rotation */ + + mul_qt_qtqt(quat, quat, quat_track[axis]); + + if(axis>2) + axis= axis-3; + + /* there are 2 possible up-axis for each axis used, the 'quat_track' applies so the first + * up axis is used X->Y, Y->X, Z->X, if this first up axis isn used then rotate 90d + * the strange bit shift below just find the low axis {X:Y, Y:X, Z:X} */ + if(upflag != (2-axis)>>1) { + float q[4]= {0.70710676908493, 0.0, 0.0, 0.0}; /* assign 90d rotation axis */ + q[axis+1] = ((axis==1)) ? 0.70710676908493 : -0.70710676908493; /* flip non Y axis */ + mul_qt_qtqt(quat, quat, q); + } +} + + +void vec_apply_track(float vec[3], short axis) +{ + float tvec[3]; + + copy_v3_v3(tvec, vec); + + switch(axis) { + case 0: /* pos-x */ + /* vec[0]= 0.0; */ + vec[1]= tvec[2]; + vec[2]= -tvec[1]; + break; + case 1: /* pos-y */ + /* vec[0]= tvec[0]; */ + /* vec[1]= 0.0; */ + /* vec[2]= tvec[2]; */ + break; + case 2: /* pos-z */ + /* vec[0]= tvec[0]; */ + /* vec[1]= tvec[1]; */ + // vec[2]= 0.0; */ + break; + case 3: /* neg-x */ + /* vec[0]= 0.0; */ + vec[1]= tvec[2]; + vec[2]= -tvec[1]; + break; + case 4: /* neg-y */ + vec[0]= -tvec[2]; + /* vec[1]= 0.0; */ + vec[2]= tvec[0]; + break; + case 5: /* neg-z */ + vec[0]= -tvec[0]; + vec[1]= -tvec[1]; + /* vec[2]= 0.0; */ + break; + } +} + /* lense/angle conversion (radians) */ float lens_to_angle(float lens) { diff --git a/source/blender/blenlib/intern/math_vector_inline.c b/source/blender/blenlib/intern/math_vector_inline.c index 84d96d1d22a..2f75fcead79 100644 --- a/source/blender/blenlib/intern/math_vector_inline.c +++ b/source/blender/blenlib/intern/math_vector_inline.c @@ -302,7 +302,7 @@ MINLINE void star_m3_v3(float mat[][3], float *vec) MINLINE float len_v2(const float v[2]) { - return (float)sqrt(v[0]*v[0] + v[1]*v[1]); + return (float)sqrtf(v[0]*v[0] + v[1]*v[1]); } MINLINE float len_v2v2(const float v1[2], const float v2[2]) @@ -311,7 +311,7 @@ MINLINE float len_v2v2(const float v1[2], const float v2[2]) x = v1[0]-v2[0]; y = v1[1]-v2[1]; - return (float)sqrt(x*x+y*y); + return (float)sqrtf(x*x+y*y); } MINLINE float len_v3(const float a[3]) @@ -319,6 +319,14 @@ MINLINE float len_v3(const float a[3]) return sqrtf(dot_v3v3(a, a)); } +MINLINE float len_squared_v2v2(const float a[3], const float b[3]) +{ + float d[2]; + + sub_v2_v2v2(d, b, a); + return dot_v2v2(d, d); +} + MINLINE float len_v3v3(const float a[3], const float b[3]) { float d[3]; diff --git a/source/blender/blenlib/intern/path_util.c b/source/blender/blenlib/intern/path_util.c index 5c9086cfb90..23972c64ee1 100644 --- a/source/blender/blenlib/intern/path_util.c +++ b/source/blender/blenlib/intern/path_util.c @@ -477,7 +477,7 @@ int BLI_parent_dir(char *path) static char *parent_dir="../"; #endif char tmp[FILE_MAXDIR+FILE_MAXFILE+4]; - BLI_strncpy(tmp, path, sizeof(tmp)); + BLI_strncpy(tmp, path, sizeof(tmp)-4); BLI_add_slash(tmp); strcat(tmp, parent_dir); BLI_cleanup_dir(NULL, tmp); @@ -838,9 +838,6 @@ static int get_path_local(char *targetpath, char *folder_name, char *subfolder_n extern char bprogname[]; /* argv[0] from creator.c */ char bprogdir[FILE_MAX]; char relfolder[FILE_MAX]; - char cwd[FILE_MAX]; - char *s; - int i; #ifdef PATH_DEBUG2 printf("get_path_local...\n"); @@ -853,30 +850,12 @@ static int get_path_local(char *targetpath, char *folder_name, char *subfolder_n } /* use argv[0] (bprogname) to get the path to the executable */ - s = BLI_last_slash(bprogname); - i = s - bprogname + 1; - BLI_strncpy(bprogdir, bprogname, i); - - /* try EXECUTABLE_DIR/folder_name */ - if(test_path(targetpath, bprogdir, "", relfolder)) - return 1; + BLI_split_dirfile(bprogname, bprogdir, NULL); - /* try CWD/release/folder_name */ - if(test_path(targetpath, BLI_getwdN(cwd), "release", relfolder)) - return 1; - - /* try EXECUTABLE_DIR/release/folder_name */ - if(test_path(targetpath, bprogdir, "release", relfolder)) - return 1; - - /* try EXECUTABLE_DIR/2.5/folder_name - new default directory for local blender installed files */ + /* try EXECUTABLE_DIR/2.5x/folder_name - new default directory for local blender installed files */ if(test_path(targetpath, bprogdir, blender_version_decimal(), relfolder)) return 1; - /* try ./.blender/folder_name -- DEPRECATED, need to update build systems */ - if(test_path(targetpath, bprogdir, ".blender", relfolder)) - return 1; - return 0; } @@ -922,6 +901,34 @@ static int get_path_system(char *targetpath, char *folder_name, char *subfolder_ char system_path[FILE_MAX]; const char *system_base_path; + + /* first allow developer only overrides to the system path + * these are only used when running blender from source */ + extern char bprogname[]; /* argv[0] from creator.c */ + char cwd[FILE_MAX]; + char relfolder[FILE_MAX]; + char bprogdir[FILE_MAX]; + + /* use argv[0] (bprogname) to get the path to the executable */ + BLI_split_dirfile(bprogname, bprogdir, NULL); + + if (subfolder_name) { + BLI_join_dirfile(relfolder, folder_name, subfolder_name); + } else { + BLI_strncpy(relfolder, folder_name, FILE_MAX); + } + + /* try CWD/release/folder_name */ + if(test_path(targetpath, BLI_getwdN(cwd), "release", relfolder)) + return 1; + + /* try EXECUTABLE_DIR/release/folder_name */ + if(test_path(targetpath, bprogdir, "release", relfolder)) + return 1; + /* end developer overrides */ + + + system_path[0] = '\0'; if (test_env_path(system_path, envvar)) { @@ -1028,7 +1035,7 @@ char *BLI_get_folder(int folder_id, char *subfolder) return path; } -static char *BLI_get_user_folder_notest(int folder_id, char *subfolder) +char *BLI_get_user_folder_notest(int folder_id, char *subfolder) { static char path[FILE_MAX] = ""; @@ -1042,6 +1049,9 @@ static char *BLI_get_user_folder_notest(int folder_id, char *subfolder) case BLENDER_USER_AUTOSAVE: get_path_user(path, "autosave", subfolder, "BLENDER_USER_AUTOSAVE"); break; + case BLENDER_USER_SCRIPTS: + get_path_user(path, "scripts", subfolder, "BLENDER_USER_SCRIPTS"); + break; } if ('\0' == path[0]) { return NULL; @@ -1054,7 +1064,7 @@ char *BLI_get_folder_create(int folder_id, char *subfolder) char *path; /* only for user folders */ - if (!ELEM3(folder_id, BLENDER_USER_DATAFILES, BLENDER_USER_CONFIG, BLENDER_USER_AUTOSAVE)) + if (!ELEM4(folder_id, BLENDER_USER_DATAFILES, BLENDER_USER_CONFIG, BLENDER_USER_SCRIPTS, BLENDER_USER_AUTOSAVE)) return NULL; path = BLI_get_folder(folder_id, subfolder); @@ -1209,8 +1219,7 @@ void BLI_make_file_string(const char *relabase, char *string, const char *dir, /* Get the file name, chop everything past the last slash (ie. the filename) */ strcpy(string, relabase); - lslash= (strrchr(string, '/')>strrchr(string, '\\'))?strrchr(string, '/'):strrchr(string, '\\'); - + lslash= BLI_last_slash(string); if(lslash) *(lslash+1)= 0; dir+=2; /* Skip over the relative reference */ diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 92dd8edaf21..0d401298420 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -12606,25 +12606,29 @@ static void library_append_end(const bContext *C, Main *mainl, FileData **fd, in { Main *mainvar= CTX_data_main(C); Scene *scene= CTX_data_scene(C); + Library *curlib; /* make main consistent */ expand_main(*fd, mainl); /* do this when expand found other libs */ read_libraries(*fd, &(*fd)->mainlist); + + curlib= mainl->curlib; /* make the lib path relative if required */ if(flag & FILE_RELPATH) { /* use the full path, this could have been read by other library even */ - BLI_strncpy(mainl->curlib->name, mainl->curlib->filepath, sizeof(mainl->curlib->name)); + BLI_strncpy(curlib->name, curlib->filepath, sizeof(curlib->name)); /* uses current .blend file as reference */ - BLI_path_rel(mainl->curlib->name, G.sce); + BLI_path_rel(curlib->name, G.sce); } blo_join_main(&(*fd)->mainlist); mainvar= (*fd)->mainlist.first; + mainl= NULL; /* blo_join_main free's mainl, cant use anymore */ lib_link_all(*fd, mainvar); lib_verify_nodetree(mainvar, 0); @@ -12639,7 +12643,7 @@ static void library_append_end(const bContext *C, Main *mainl, FileData **fd, in if (flag & FILE_LINK) { give_base_to_objects(mainvar, scene, NULL, 0); } else { - give_base_to_objects(mainvar, scene, mainl->curlib, 1); + give_base_to_objects(mainvar, scene, curlib, 1); } if (flag & FILE_GROUP_INSTANCE) { @@ -12659,7 +12663,7 @@ static void library_append_end(const bContext *C, Main *mainl, FileData **fd, in *fd = NULL; } - append_do_cursor(scene, mainl->curlib, flag); + append_do_cursor(scene, curlib, flag); } void BLO_library_append_end(const bContext *C, struct Main *mainl, BlendHandle** bh, int idcode, short flag) diff --git a/source/blender/collada/AnimationImporter.cpp b/source/blender/collada/AnimationImporter.cpp new file mode 100644 index 00000000000..32390fe01eb --- /dev/null +++ b/source/blender/collada/AnimationImporter.cpp @@ -0,0 +1,1149 @@ +/** + * $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): Chingiz Dyussenov, Arystanbek Dyussenov, Nathan Letwory. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "DNA_armature_types.h" + +#include "ED_keyframing.h" + +#include "BLI_listbase.h" +#include "BLI_math.h" +#include "BLI_path_util.h" +#include "BLI_string.h" + +#include "BKE_action.h" +#include "BKE_armature.h" +#include "BKE_fcurve.h" +#include "BKE_object.h" + +#include "MEM_guardedalloc.h" + +#include "collada_utils.h" +#include "AnimationImporter.h" +#include "ArmatureImporter.h" + +#include <algorithm> + +// use this for retrieving bone names, since these must be unique +template<class T> +static const char *bc_get_joint_name(T *node) +{ + const std::string& id = node->getOriginalId(); + return id.size() ? id.c_str() : node->getName().c_str(); +} + +FCurve *AnimationImporter::create_fcurve(int array_index, const char *rna_path) +{ + FCurve *fcu = (FCurve*)MEM_callocN(sizeof(FCurve), "FCurve"); + + fcu->flag = (FCURVE_VISIBLE|FCURVE_AUTO_HANDLES|FCURVE_SELECTED); + fcu->rna_path = BLI_strdupn(rna_path, strlen(rna_path)); + fcu->array_index = array_index; + return fcu; +} + +void AnimationImporter::create_bezt(FCurve *fcu, float frame, float output) +{ + BezTriple bez; + memset(&bez, 0, sizeof(BezTriple)); + bez.vec[1][0] = frame; + bez.vec[1][1] = output; + bez.ipo = U.ipo_new; /* use default interpolation mode here... */ + bez.f1 = bez.f2 = bez.f3 = SELECT; + bez.h1 = bez.h2 = HD_AUTO; + insert_bezt_fcurve(fcu, &bez, 0); + calchandles_fcurve(fcu); +} + +// create one or several fcurves depending on the number of parameters being animated +void AnimationImporter::animation_to_fcurves(COLLADAFW::AnimationCurve *curve) +{ + COLLADAFW::FloatOrDoubleArray& input = curve->getInputValues(); + COLLADAFW::FloatOrDoubleArray& output = curve->getOutputValues(); + // COLLADAFW::FloatOrDoubleArray& intan = curve->getInTangentValues(); + // COLLADAFW::FloatOrDoubleArray& outtan = curve->getOutTangentValues(); + float fps = (float)FPS; + size_t dim = curve->getOutDimension(); + unsigned int i; + + std::vector<FCurve*>& fcurves = curve_map[curve->getUniqueId()]; + + switch (dim) { + case 1: // X, Y, Z or angle + case 3: // XYZ + case 16: // matrix + { + for (i = 0; i < dim; i++ ) { + FCurve *fcu = (FCurve*)MEM_callocN(sizeof(FCurve), "FCurve"); + + fcu->flag = (FCURVE_VISIBLE|FCURVE_AUTO_HANDLES|FCURVE_SELECTED); + // fcu->rna_path = BLI_strdupn(path, strlen(path)); + fcu->array_index = 0; + //fcu->totvert = curve->getKeyCount(); + + // create beztriple for each key + for (unsigned int j = 0; j < curve->getKeyCount(); j++) { + BezTriple bez; + memset(&bez, 0, sizeof(BezTriple)); + + // intangent + // bez.vec[0][0] = get_float_value(intan, j * 6 + i + i) * fps; + // bez.vec[0][1] = get_float_value(intan, j * 6 + i + i + 1); + + // input, output + bez.vec[1][0] = bc_get_float_value(input, j) * fps; + bez.vec[1][1] = bc_get_float_value(output, j * dim + i); + + // outtangent + // bez.vec[2][0] = get_float_value(outtan, j * 6 + i + i) * fps; + // bez.vec[2][1] = get_float_value(outtan, j * 6 + i + i + 1); + + bez.ipo = U.ipo_new; /* use default interpolation mode here... */ + bez.f1 = bez.f2 = bez.f3 = SELECT; + bez.h1 = bez.h2 = HD_AUTO; + insert_bezt_fcurve(fcu, &bez, 0); + } + + calchandles_fcurve(fcu); + + fcurves.push_back(fcu); + } + } + break; + default: + fprintf(stderr, "Output dimension of %d is not yet supported (animation id = %s)\n", dim, curve->getOriginalId().c_str()); + } + + for (std::vector<FCurve*>::iterator it = fcurves.begin(); it != fcurves.end(); it++) + unused_curves.push_back(*it); +} + +void AnimationImporter::fcurve_deg_to_rad(FCurve *cu) +{ + for (unsigned int i = 0; i < cu->totvert; i++) { + // TODO convert handles too + cu->bezt[i].vec[1][1] *= M_PI / 180.0f; + } +} + +void AnimationImporter::add_fcurves_to_object(Object *ob, std::vector<FCurve*>& curves, char *rna_path, int array_index, Animation *animated) +{ + bAction *act; + + if (!ob->adt || !ob->adt->action) act = verify_adt_action((ID*)&ob->id, 1); + else act = ob->adt->action; + + std::vector<FCurve*>::iterator it; + int i; + +#if 0 + char *p = strstr(rna_path, "rotation_euler"); + bool is_rotation = p && *(p + strlen("rotation_euler")) == '\0'; + + // convert degrees to radians for rotation + if (is_rotation) + fcurve_deg_to_rad(fcu); +#endif + + for (it = curves.begin(), i = 0; it != curves.end(); it++, i++) { + FCurve *fcu = *it; + fcu->rna_path = BLI_strdupn(rna_path, strlen(rna_path)); + + if (array_index == -1) fcu->array_index = i; + else fcu->array_index = array_index; + + if (ob->type == OB_ARMATURE) { + bActionGroup *grp = NULL; + const char *bone_name = bc_get_joint_name(animated->node); + + if (bone_name) { + /* try to find group */ + grp = action_groups_find_named(act, bone_name); + + /* no matching groups, so add one */ + if (grp == NULL) { + /* Add a new group, and make it active */ + grp = (bActionGroup*)MEM_callocN(sizeof(bActionGroup), "bActionGroup"); + + grp->flag = AGRP_SELECTED; + BLI_strncpy(grp->name, bone_name, sizeof(grp->name)); + + BLI_addtail(&act->groups, grp); + BLI_uniquename(&act->groups, grp, "Group", '.', offsetof(bActionGroup, name), 64); + } + + /* add F-Curve to group */ + action_groups_add_channel(act, grp, fcu); + + } +#if 0 + if (is_rotation) { + fcurves_actionGroup_map[grp].push_back(fcu); + } +#endif + } + else { + BLI_addtail(&act->curves, fcu); + } + + // curve is used, so remove it from unused_curves + unused_curves.erase(std::remove(unused_curves.begin(), unused_curves.end(), fcu), unused_curves.end()); + } +} + +AnimationImporter::AnimationImporter(UnitConverter *conv, ArmatureImporter *arm, Scene *scene) : + TransformReader(conv), armature_importer(arm), scene(scene) { } + +AnimationImporter::~AnimationImporter() +{ + // free unused FCurves + for (std::vector<FCurve*>::iterator it = unused_curves.begin(); it != unused_curves.end(); it++) + free_fcurve(*it); + + if (unused_curves.size()) + fprintf(stderr, "removed %u unused curves\n", unused_curves.size()); +} + +bool AnimationImporter::write_animation(const COLLADAFW::Animation* anim) +{ + if (anim->getAnimationType() == COLLADAFW::Animation::ANIMATION_CURVE) { + COLLADAFW::AnimationCurve *curve = (COLLADAFW::AnimationCurve*)anim; + + // XXX Don't know if it's necessary + // Should we check outPhysicalDimension? + if (curve->getInPhysicalDimension() != COLLADAFW::PHYSICAL_DIMENSION_TIME) { + fprintf(stderr, "Inputs physical dimension is not time. \n"); + return true; + } + + // a curve can have mixed interpolation type, + // in this case curve->getInterpolationTypes returns a list of interpolation types per key + COLLADAFW::AnimationCurve::InterpolationType interp = curve->getInterpolationType(); + + if (interp != COLLADAFW::AnimationCurve::INTERPOLATION_MIXED) { + switch (interp) { + case COLLADAFW::AnimationCurve::INTERPOLATION_LINEAR: + case COLLADAFW::AnimationCurve::INTERPOLATION_BEZIER: + animation_to_fcurves(curve); + break; + default: + // TODO there're also CARDINAL, HERMITE, BSPLINE and STEP types + fprintf(stderr, "CARDINAL, HERMITE, BSPLINE and STEP anim interpolation types not supported yet.\n"); + break; + } + } + else { + // not supported yet + fprintf(stderr, "MIXED anim interpolation type is not supported yet.\n"); + } + } + else { + fprintf(stderr, "FORMULA animation type is not supported yet.\n"); + } + + return true; +} + +// called on post-process stage after writeVisualScenes +bool AnimationImporter::write_animation_list(const COLLADAFW::AnimationList* animlist) +{ + const COLLADAFW::UniqueId& animlist_id = animlist->getUniqueId(); + + animlist_map[animlist_id] = animlist; + +#if 0 + // should not happen + if (uid_animated_map.find(animlist_id) == uid_animated_map.end()) { + return true; + } + + // for bones rna_path is like: pose.bones["bone-name"].rotation + + // what does this AnimationList animate? + Animation& animated = uid_animated_map[animlist_id]; + Object *ob = animated.ob; + + char rna_path[100]; + char joint_path[100]; + bool is_joint = false; + + // if ob is NULL, it should be a JOINT + if (!ob) { + ob = armature_importer->get_armature_for_joint(animated.node); + + if (!ob) { + fprintf(stderr, "Cannot find armature for node %s\n", get_joint_name(animated.node)); + return true; + } + + armature_importer->get_rna_path_for_joint(animated.node, joint_path, sizeof(joint_path)); + + is_joint = true; + } + + const COLLADAFW::AnimationList::AnimationBindings& bindings = animlist->getAnimationBindings(); + + switch (animated.tm->getTransformationType()) { + case COLLADAFW::Transformation::TRANSLATE: + case COLLADAFW::Transformation::SCALE: + { + bool loc = animated.tm->getTransformationType() == COLLADAFW::Transformation::TRANSLATE; + if (is_joint) + BLI_snprintf(rna_path, sizeof(rna_path), "%s.%s", joint_path, loc ? "location" : "scale"); + else + BLI_strncpy(rna_path, loc ? "location" : "scale", sizeof(rna_path)); + + for (int i = 0; i < bindings.getCount(); i++) { + const COLLADAFW::AnimationList::AnimationBinding& binding = bindings[i]; + COLLADAFW::UniqueId anim_uid = binding.animation; + + if (curve_map.find(anim_uid) == curve_map.end()) { + fprintf(stderr, "Cannot find FCurve by animation UID.\n"); + continue; + } + + std::vector<FCurve*>& fcurves = curve_map[anim_uid]; + + switch (binding.animationClass) { + case COLLADAFW::AnimationList::POSITION_X: + add_fcurves_to_object(ob, fcurves, rna_path, 0, &animated); + break; + case COLLADAFW::AnimationList::POSITION_Y: + add_fcurves_to_object(ob, fcurves, rna_path, 1, &animated); + break; + case COLLADAFW::AnimationList::POSITION_Z: + add_fcurves_to_object(ob, fcurves, rna_path, 2, &animated); + break; + case COLLADAFW::AnimationList::POSITION_XYZ: + add_fcurves_to_object(ob, fcurves, rna_path, -1, &animated); + break; + default: + fprintf(stderr, "AnimationClass %d is not supported for %s.\n", + binding.animationClass, loc ? "TRANSLATE" : "SCALE"); + } + } + } + break; + case COLLADAFW::Transformation::ROTATE: + { + if (is_joint) + BLI_snprintf(rna_path, sizeof(rna_path), "%s.rotation_euler", joint_path); + else + BLI_strncpy(rna_path, "rotation_euler", sizeof(rna_path)); + + COLLADAFW::Rotate* rot = (COLLADAFW::Rotate*)animated.tm; + COLLADABU::Math::Vector3& axis = rot->getRotationAxis(); + + for (int i = 0; i < bindings.getCount(); i++) { + const COLLADAFW::AnimationList::AnimationBinding& binding = bindings[i]; + COLLADAFW::UniqueId anim_uid = binding.animation; + + if (curve_map.find(anim_uid) == curve_map.end()) { + fprintf(stderr, "Cannot find FCurve by animation UID.\n"); + continue; + } + + std::vector<FCurve*>& fcurves = curve_map[anim_uid]; + + switch (binding.animationClass) { + case COLLADAFW::AnimationList::ANGLE: + if (COLLADABU::Math::Vector3::UNIT_X == axis) { + add_fcurves_to_object(ob, fcurves, rna_path, 0, &animated); + } + else if (COLLADABU::Math::Vector3::UNIT_Y == axis) { + add_fcurves_to_object(ob, fcurves, rna_path, 1, &animated); + } + else if (COLLADABU::Math::Vector3::UNIT_Z == axis) { + add_fcurves_to_object(ob, fcurves, rna_path, 2, &animated); + } + break; + case COLLADAFW::AnimationList::AXISANGLE: + // TODO convert axis-angle to quat? or XYZ? + default: + fprintf(stderr, "AnimationClass %d is not supported for ROTATE transformation.\n", + binding.animationClass); + } + } + } + break; + case COLLADAFW::Transformation::MATRIX: + case COLLADAFW::Transformation::SKEW: + case COLLADAFW::Transformation::LOOKAT: + fprintf(stderr, "Animation of MATRIX, SKEW and LOOKAT transformations is not supported yet.\n"); + break; + } +#endif + + return true; +} + +void AnimationImporter::read_node_transform(COLLADAFW::Node *node, Object *ob) +{ + float mat[4][4]; + TransformReader::get_node_mat(mat, node, &uid_animated_map, ob); + if (ob) { + copy_m4_m4(ob->obmat, mat); + object_apply_mat4(ob, ob->obmat); + } +} + +#if 0 +virtual void AnimationImporter::change_eul_to_quat(Object *ob, bAction *act) +{ + bActionGroup *grp; + int i; + + for (grp = (bActionGroup*)act->groups.first; grp; grp = grp->next) { + + FCurve *eulcu[3] = {NULL, NULL, NULL}; + + if (fcurves_actionGroup_map.find(grp) == fcurves_actionGroup_map.end()) + continue; + + std::vector<FCurve*> &rot_fcurves = fcurves_actionGroup_map[grp]; + + if (rot_fcurves.size() > 3) continue; + + for (i = 0; i < rot_fcurves.size(); i++) + eulcu[rot_fcurves[i]->array_index] = rot_fcurves[i]; + + char joint_path[100]; + char rna_path[100]; + + BLI_snprintf(joint_path, sizeof(joint_path), "pose.bones[\"%s\"]", grp->name); + BLI_snprintf(rna_path, sizeof(rna_path), "%s.rotation_quaternion", joint_path); + + FCurve *quatcu[4] = { + create_fcurve(0, rna_path), + create_fcurve(1, rna_path), + create_fcurve(2, rna_path), + create_fcurve(3, rna_path) + }; + + bPoseChannel *chan = get_pose_channel(ob->pose, grp->name); + + float m4[4][4], irest[3][3]; + invert_m4_m4(m4, chan->bone->arm_mat); + copy_m3_m4(irest, m4); + + for (i = 0; i < 3; i++) { + + FCurve *cu = eulcu[i]; + + if (!cu) continue; + + for (int j = 0; j < cu->totvert; j++) { + float frame = cu->bezt[j].vec[1][0]; + + float eul[3] = { + eulcu[0] ? evaluate_fcurve(eulcu[0], frame) : 0.0f, + eulcu[1] ? evaluate_fcurve(eulcu[1], frame) : 0.0f, + eulcu[2] ? evaluate_fcurve(eulcu[2], frame) : 0.0f + }; + + // make eul relative to bone rest pose + float rot[3][3], rel[3][3], quat[4]; + + /*eul_to_mat3(rot, eul); + + mul_m3_m3m3(rel, irest, rot); + + mat3_to_quat(quat, rel); + */ + + eul_to_quat(quat, eul); + + for (int k = 0; k < 4; k++) + create_bezt(quatcu[k], frame, quat[k]); + } + } + + // now replace old Euler curves + + for (i = 0; i < 3; i++) { + if (!eulcu[i]) continue; + + action_groups_remove_channel(act, eulcu[i]); + free_fcurve(eulcu[i]); + } + + chan->rotmode = ROT_MODE_QUAT; + + for (i = 0; i < 4; i++) + action_groups_add_channel(act, grp, quatcu[i]); + } + + bPoseChannel *pchan; + for (pchan = (bPoseChannel*)ob->pose->chanbase.first; pchan; pchan = pchan->next) { + pchan->rotmode = ROT_MODE_QUAT; + } +} +#endif + +// prerequisites: +// animlist_map - map animlist id -> animlist +// curve_map - map anim id -> curve(s) +Object *AnimationImporter::translate_animation(COLLADAFW::Node *node, + std::map<COLLADAFW::UniqueId, Object*>& object_map, + std::map<COLLADAFW::UniqueId, COLLADAFW::Node*>& root_map, + COLLADAFW::Transformation::TransformationType tm_type, + Object *par_job) +{ + bool is_rotation = tm_type == COLLADAFW::Transformation::ROTATE; + bool is_matrix = tm_type == COLLADAFW::Transformation::MATRIX; + bool is_joint = node->getType() == COLLADAFW::Node::JOINT; + + COLLADAFW::Node *root = root_map.find(node->getUniqueId()) == root_map.end() ? node : root_map[node->getUniqueId()]; + Object *ob = is_joint ? armature_importer->get_armature_for_joint(node) : object_map[node->getUniqueId()]; + const char *bone_name = is_joint ? bc_get_joint_name(node) : NULL; + + if (!ob) { + fprintf(stderr, "cannot find Object for Node with id=\"%s\"\n", node->getOriginalId().c_str()); + return NULL; + } + + // frames at which to sample + std::vector<float> frames; + + // for each <rotate>, <translate>, etc. there is a separate Transformation + const COLLADAFW::TransformationPointerArray& tms = node->getTransformations(); + + unsigned int i; + + // find frames at which to sample plus convert all rotation keys to radians + for (i = 0; i < tms.getCount(); i++) { + COLLADAFW::Transformation *tm = tms[i]; + COLLADAFW::Transformation::TransformationType type = tm->getTransformationType(); + + if (type == tm_type) { + const COLLADAFW::UniqueId& listid = tm->getAnimationList(); + + if (animlist_map.find(listid) != animlist_map.end()) { + const COLLADAFW::AnimationList *animlist = animlist_map[listid]; + const COLLADAFW::AnimationList::AnimationBindings& bindings = animlist->getAnimationBindings(); + + if (bindings.getCount()) { + for (unsigned int j = 0; j < bindings.getCount(); j++) { + std::vector<FCurve*>& curves = curve_map[bindings[j].animation]; + bool xyz = ((type == COLLADAFW::Transformation::TRANSLATE || type == COLLADAFW::Transformation::SCALE) && bindings[j].animationClass == COLLADAFW::AnimationList::POSITION_XYZ); + + if ((!xyz && curves.size() == 1) || (xyz && curves.size() == 3) || is_matrix) { + std::vector<FCurve*>::iterator iter; + + for (iter = curves.begin(); iter != curves.end(); iter++) { + FCurve *fcu = *iter; + + if (is_rotation) + fcurve_deg_to_rad(fcu); + + for (unsigned int k = 0; k < fcu->totvert; k++) { + float fra = fcu->bezt[k].vec[1][0]; + if (std::find(frames.begin(), frames.end(), fra) == frames.end()) + frames.push_back(fra); + } + } + } + else { + fprintf(stderr, "expected %d curves, got %u\n", xyz ? 3 : 1, curves.size()); + } + } + } + } + } + } + + float irest_dae[4][4]; + float rest[4][4], irest[4][4]; + + if (is_joint) { + get_joint_rest_mat(irest_dae, root, node); + invert_m4(irest_dae); + + Bone *bone = get_named_bone((bArmature*)ob->data, bone_name); + if (!bone) { + fprintf(stderr, "cannot find bone \"%s\"\n", bone_name); + return NULL; + } + + unit_m4(rest); + copy_m4_m4(rest, bone->arm_mat); + invert_m4_m4(irest, rest); + } + + Object *job = NULL; + +#ifdef ARMATURE_TEST + FCurve *job_curves[10]; + job = get_joint_object(root, node, par_job); +#endif + + if (frames.size() == 0) + return job; + + std::sort(frames.begin(), frames.end()); + + const char *tm_str = NULL; + switch (tm_type) { + case COLLADAFW::Transformation::ROTATE: + tm_str = "rotation_quaternion"; + break; + case COLLADAFW::Transformation::SCALE: + tm_str = "scale"; + break; + case COLLADAFW::Transformation::TRANSLATE: + tm_str = "location"; + break; + case COLLADAFW::Transformation::MATRIX: + break; + default: + return job; + } + + char rna_path[200]; + char joint_path[200]; + + if (is_joint) + armature_importer->get_rna_path_for_joint(node, joint_path, sizeof(joint_path)); + + // new curves + FCurve *newcu[10]; // if tm_type is matrix, then create 10 curves: 4 rot, 3 loc, 3 scale + unsigned int totcu = is_matrix ? 10 : (is_rotation ? 4 : 3); + + for (i = 0; i < totcu; i++) { + + int axis = i; + + if (is_matrix) { + if (i < 4) { + tm_str = "rotation_quaternion"; + axis = i; + } + else if (i < 7) { + tm_str = "location"; + axis = i - 4; + } + else { + tm_str = "scale"; + axis = i - 7; + } + } + + if (is_joint) + BLI_snprintf(rna_path, sizeof(rna_path), "%s.%s", joint_path, tm_str); + else + strcpy(rna_path, tm_str); + + newcu[i] = create_fcurve(axis, rna_path); + +#ifdef ARMATURE_TEST + if (is_joint) + job_curves[i] = create_fcurve(axis, tm_str); +#endif + } + + std::vector<float>::iterator it; + + // sample values at each frame + for (it = frames.begin(); it != frames.end(); it++) { + float fra = *it; + + float mat[4][4]; + float matfra[4][4]; + + unit_m4(matfra); + + // calc object-space mat + evaluate_transform_at_frame(matfra, node, fra); + + // for joints, we need a special matrix + if (is_joint) { + // special matrix: iR * M * iR_dae * R + // where R, iR are bone rest and inverse rest mats in world space (Blender bones), + // iR_dae is joint inverse rest matrix (DAE) and M is an evaluated joint world-space matrix (DAE) + float temp[4][4], par[4][4]; + + // calc M + calc_joint_parent_mat_rest(par, NULL, root, node); + mul_m4_m4m4(temp, matfra, par); + + // evaluate_joint_world_transform_at_frame(temp, NULL, , node, fra); + + // calc special matrix + mul_serie_m4(mat, irest, temp, irest_dae, rest, NULL, NULL, NULL, NULL); + } + else { + copy_m4_m4(mat, matfra); + } + + float val[4], rot[4], loc[3], scale[3]; + + switch (tm_type) { + case COLLADAFW::Transformation::ROTATE: + mat4_to_quat(val, mat); + break; + case COLLADAFW::Transformation::SCALE: + mat4_to_size(val, mat); + break; + case COLLADAFW::Transformation::TRANSLATE: + copy_v3_v3(val, mat[3]); + break; + case COLLADAFW::Transformation::MATRIX: + mat4_to_quat(rot, mat); + copy_v3_v3(loc, mat[3]); + mat4_to_size(scale, mat); + break; + default: + break; + } + + // add keys + for (i = 0; i < totcu; i++) { + if (is_matrix) { + if (i < 4) + add_bezt(newcu[i], fra, rot[i]); + else if (i < 7) + add_bezt(newcu[i], fra, loc[i - 4]); + else + add_bezt(newcu[i], fra, scale[i - 7]); + } + else { + add_bezt(newcu[i], fra, val[i]); + } + } + +#ifdef ARMATURE_TEST + if (is_joint) { + switch (tm_type) { + case COLLADAFW::Transformation::ROTATE: + mat4_to_quat(val, matfra); + break; + case COLLADAFW::Transformation::SCALE: + mat4_to_size(val, matfra); + break; + case COLLADAFW::Transformation::TRANSLATE: + copy_v3_v3(val, matfra[3]); + break; + case MATRIX: + mat4_to_quat(rot, matfra); + copy_v3_v3(loc, matfra[3]); + mat4_to_size(scale, matfra); + break; + default: + break; + } + + for (i = 0; i < totcu; i++) { + if (is_matrix) { + if (i < 4) + add_bezt(job_curves[i], fra, rot[i]); + else if (i < 7) + add_bezt(job_curves[i], fra, loc[i - 4]); + else + add_bezt(job_curves[i], fra, scale[i - 7]); + } + else { + add_bezt(job_curves[i], fra, val[i]); + } + } + } +#endif + } + + verify_adt_action((ID*)&ob->id, 1); + + ListBase *curves = &ob->adt->action->curves; + + // add curves + for (i = 0; i < totcu; i++) { + if (is_joint) + add_bone_fcurve(ob, node, newcu[i]); + else + BLI_addtail(curves, newcu[i]); + +#ifdef ARMATURE_TEST + if (is_joint) + BLI_addtail(&job->adt->action->curves, job_curves[i]); +#endif + } + + if (is_rotation || is_matrix) { + if (is_joint) { + bPoseChannel *chan = get_pose_channel(ob->pose, bone_name); + chan->rotmode = ROT_MODE_QUAT; + } + else { + ob->rotmode = ROT_MODE_QUAT; + } + } + + return job; +} + +// internal, better make it private +// warning: evaluates only rotation +// prerequisites: animlist_map, curve_map +void AnimationImporter::evaluate_transform_at_frame(float mat[4][4], COLLADAFW::Node *node, float fra) +{ + const COLLADAFW::TransformationPointerArray& tms = node->getTransformations(); + + unit_m4(mat); + + for (unsigned int i = 0; i < tms.getCount(); i++) { + COLLADAFW::Transformation *tm = tms[i]; + COLLADAFW::Transformation::TransformationType type = tm->getTransformationType(); + float m[4][4]; + + unit_m4(m); + + if (!evaluate_animation(tm, m, fra, node->getOriginalId().c_str())) { + switch (type) { + case COLLADAFW::Transformation::ROTATE: + dae_rotate_to_mat4(tm, m); + break; + case COLLADAFW::Transformation::TRANSLATE: + dae_translate_to_mat4(tm, m); + break; + case COLLADAFW::Transformation::SCALE: + dae_scale_to_mat4(tm, m); + break; + case COLLADAFW::Transformation::MATRIX: + dae_matrix_to_mat4(tm, m); + break; + default: + fprintf(stderr, "unsupported transformation type %d\n", type); + } + } + + float temp[4][4]; + copy_m4_m4(temp, mat); + + mul_m4_m4m4(mat, m, temp); + } +} + +// return true to indicate that mat contains a sane value +bool AnimationImporter::evaluate_animation(COLLADAFW::Transformation *tm, float mat[4][4], float fra, const char *node_id) +{ + const COLLADAFW::UniqueId& listid = tm->getAnimationList(); + COLLADAFW::Transformation::TransformationType type = tm->getTransformationType(); + + if (type != COLLADAFW::Transformation::ROTATE && + type != COLLADAFW::Transformation::SCALE && + type != COLLADAFW::Transformation::TRANSLATE && + type != COLLADAFW::Transformation::MATRIX) { + fprintf(stderr, "animation of transformation %d is not supported yet\n", type); + return false; + } + + if (animlist_map.find(listid) == animlist_map.end()) + return false; + + const COLLADAFW::AnimationList *animlist = animlist_map[listid]; + const COLLADAFW::AnimationList::AnimationBindings& bindings = animlist->getAnimationBindings(); + + if (bindings.getCount()) { + float vec[3]; + + bool is_scale = (type == COLLADAFW::Transformation::SCALE); + bool is_translate = (type == COLLADAFW::Transformation::TRANSLATE); + + if (type == COLLADAFW::Transformation::SCALE) + dae_scale_to_v3(tm, vec); + else if (type == COLLADAFW::Transformation::TRANSLATE) + dae_translate_to_v3(tm, vec); + + for (unsigned int j = 0; j < bindings.getCount(); j++) { + const COLLADAFW::AnimationList::AnimationBinding& binding = bindings[j]; + std::vector<FCurve*>& curves = curve_map[binding.animation]; + COLLADAFW::AnimationList::AnimationClass animclass = binding.animationClass; + char path[100]; + + switch (type) { + case COLLADAFW::Transformation::ROTATE: + BLI_snprintf(path, sizeof(path), "%s.rotate (binding %u)", node_id, j); + break; + case COLLADAFW::Transformation::SCALE: + BLI_snprintf(path, sizeof(path), "%s.scale (binding %u)", node_id, j); + break; + case COLLADAFW::Transformation::TRANSLATE: + BLI_snprintf(path, sizeof(path), "%s.translate (binding %u)", node_id, j); + break; + case COLLADAFW::Transformation::MATRIX: + BLI_snprintf(path, sizeof(path), "%s.matrix (binding %u)", node_id, j); + break; + default: + break; + } + + if (animclass == COLLADAFW::AnimationList::UNKNOWN_CLASS) { + fprintf(stderr, "%s: UNKNOWN animation class\n", path); + continue; + } + + if (type == COLLADAFW::Transformation::ROTATE) { + if (curves.size() != 1) { + fprintf(stderr, "expected 1 curve, got %u\n", curves.size()); + return false; + } + + // TODO support other animclasses + if (animclass != COLLADAFW::AnimationList::ANGLE) { + fprintf(stderr, "%s: animation class %d is not supported yet\n", path, animclass); + return false; + } + + COLLADABU::Math::Vector3& axis = ((COLLADAFW::Rotate*)tm)->getRotationAxis(); + float ax[3] = {axis[0], axis[1], axis[2]}; + float angle = evaluate_fcurve(curves[0], fra); + axis_angle_to_mat4(mat, ax, angle); + + return true; + } + else if (is_scale || is_translate) { + bool is_xyz = animclass == COLLADAFW::AnimationList::POSITION_XYZ; + + if ((!is_xyz && curves.size() != 1) || (is_xyz && curves.size() != 3)) { + if (is_xyz) + fprintf(stderr, "%s: expected 3 curves, got %u\n", path, curves.size()); + else + fprintf(stderr, "%s: expected 1 curve, got %u\n", path, curves.size()); + return false; + } + + switch (animclass) { + case COLLADAFW::AnimationList::POSITION_X: + vec[0] = evaluate_fcurve(curves[0], fra); + break; + case COLLADAFW::AnimationList::POSITION_Y: + vec[1] = evaluate_fcurve(curves[0], fra); + break; + case COLLADAFW::AnimationList::POSITION_Z: + vec[2] = evaluate_fcurve(curves[0], fra); + break; + case COLLADAFW::AnimationList::POSITION_XYZ: + vec[0] = evaluate_fcurve(curves[0], fra); + vec[1] = evaluate_fcurve(curves[1], fra); + vec[2] = evaluate_fcurve(curves[2], fra); + break; + default: + fprintf(stderr, "%s: animation class %d is not supported yet\n", path, animclass); + break; + } + } + else if (type == COLLADAFW::Transformation::MATRIX) { + // for now, of matrix animation, support only the case when all values are packed into one animation + if (curves.size() != 16) { + fprintf(stderr, "%s: expected 16 curves, got %u\n", path, curves.size()); + return false; + } + + COLLADABU::Math::Matrix4 matrix; + int i = 0, j = 0; + + for (std::vector<FCurve*>::iterator it = curves.begin(); it != curves.end(); it++) { + matrix.setElement(i, j, evaluate_fcurve(*it, fra)); + j++; + if (j == 4) { + i++; + j = 0; + } + } + + COLLADAFW::Matrix tm(matrix); + dae_matrix_to_mat4(&tm, mat); + + return true; + } + } + + if (is_scale) + size_to_mat4(mat, vec); + else + copy_v3_v3(mat[3], vec); + + return is_scale || is_translate; + } + + return false; +} + +// gives a world-space mat of joint at rest position +void AnimationImporter::get_joint_rest_mat(float mat[4][4], COLLADAFW::Node *root, COLLADAFW::Node *node) +{ + // if bind mat is not available, + // use "current" node transform, i.e. all those tms listed inside <node> + if (!armature_importer->get_joint_bind_mat(mat, node)) { + float par[4][4], m[4][4]; + + calc_joint_parent_mat_rest(par, NULL, root, node); + get_node_mat(m, node, NULL, NULL); + mul_m4_m4m4(mat, m, par); + } +} + +// gives a world-space mat, end's mat not included +bool AnimationImporter::calc_joint_parent_mat_rest(float mat[4][4], float par[4][4], COLLADAFW::Node *node, COLLADAFW::Node *end) +{ + float m[4][4]; + + if (node == end) { + par ? copy_m4_m4(mat, par) : unit_m4(mat); + return true; + } + + // use bind matrix if available or calc "current" world mat + if (!armature_importer->get_joint_bind_mat(m, node)) { + if (par) { + float temp[4][4]; + get_node_mat(temp, node, NULL, NULL); + mul_m4_m4m4(m, temp, par); + } + else { + get_node_mat(m, node, NULL, NULL); + } + } + + COLLADAFW::NodePointerArray& children = node->getChildNodes(); + for (unsigned int i = 0; i < children.getCount(); i++) { + if (calc_joint_parent_mat_rest(mat, m, children[i], end)) + return true; + } + + return false; +} + +#ifdef ARMATURE_TEST +Object *AnimationImporter::get_joint_object(COLLADAFW::Node *root, COLLADAFW::Node *node, Object *par_job) +{ + if (joint_objects.find(node->getUniqueId()) == joint_objects.end()) { + Object *job = add_object(scene, OB_EMPTY); + + rename_id((ID*)&job->id, (char*)get_joint_name(node)); + + job->lay = object_in_scene(job, scene)->lay = 2; + + mul_v3_fl(job->size, 0.5f); + job->recalc |= OB_RECALC_OB; + + verify_adt_action((ID*)&job->id, 1); + + job->rotmode = ROT_MODE_QUAT; + + float mat[4][4]; + get_joint_rest_mat(mat, root, node); + + if (par_job) { + float temp[4][4], ipar[4][4]; + invert_m4_m4(ipar, par_job->obmat); + copy_m4_m4(temp, mat); + mul_m4_m4m4(mat, temp, ipar); + } + + TransformBase::decompose(mat, job->loc, NULL, job->quat, job->size); + + if (par_job) { + job->parent = par_job; + + par_job->recalc |= OB_RECALC_OB; + job->parsubstr[0] = 0; + } + + where_is_object(scene, job); + + // after parenting and layer change + DAG_scene_sort(CTX_data_main(C), scene); + + joint_objects[node->getUniqueId()] = job; + } + + return joint_objects[node->getUniqueId()]; +} +#endif + +#if 0 +// recursively evaluates joint tree until end is found, mat then is world-space matrix of end +// mat must be identity on enter, node must be root +bool AnimationImporter::evaluate_joint_world_transform_at_frame(float mat[4][4], float par[4][4], COLLADAFW::Node *node, COLLADAFW::Node *end, float fra) +{ + float m[4][4]; + if (par) { + float temp[4][4]; + evaluate_transform_at_frame(temp, node, node == end ? fra : 0.0f); + mul_m4_m4m4(m, temp, par); + } + else { + evaluate_transform_at_frame(m, node, node == end ? fra : 0.0f); + } + + if (node == end) { + copy_m4_m4(mat, m); + return true; + } + else { + COLLADAFW::NodePointerArray& children = node->getChildNodes(); + for (int i = 0; i < children.getCount(); i++) { + if (evaluate_joint_world_transform_at_frame(mat, m, children[i], end, fra)) + return true; + } + } + + return false; +} +#endif + +void AnimationImporter::add_bone_fcurve(Object *ob, COLLADAFW::Node *node, FCurve *fcu) +{ + const char *bone_name = bc_get_joint_name(node); + bAction *act = ob->adt->action; + + /* try to find group */ + bActionGroup *grp = action_groups_find_named(act, bone_name); + + /* no matching groups, so add one */ + if (grp == NULL) { + /* Add a new group, and make it active */ + grp = (bActionGroup*)MEM_callocN(sizeof(bActionGroup), "bActionGroup"); + + grp->flag = AGRP_SELECTED; + BLI_strncpy(grp->name, bone_name, sizeof(grp->name)); + + BLI_addtail(&act->groups, grp); + BLI_uniquename(&act->groups, grp, "Group", '.', offsetof(bActionGroup, name), 64); + } + + /* add F-Curve to group */ + action_groups_add_channel(act, grp, fcu); +} + +void AnimationImporter::add_bezt(FCurve *fcu, float fra, float value) +{ + BezTriple bez; + memset(&bez, 0, sizeof(BezTriple)); + bez.vec[1][0] = fra; + bez.vec[1][1] = value; + bez.ipo = U.ipo_new; /* use default interpolation mode here... */ + bez.f1 = bez.f2 = bez.f3 = SELECT; + bez.h1 = bez.h2 = HD_AUTO; + insert_bezt_fcurve(fcu, &bez, 0); + calchandles_fcurve(fcu); +} diff --git a/source/blender/collada/AnimationImporter.h b/source/blender/collada/AnimationImporter.h new file mode 100644 index 00000000000..01abac38280 --- /dev/null +++ b/source/blender/collada/AnimationImporter.h @@ -0,0 +1,132 @@ +/** + * $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): Chingiz Dyussenov, Arystanbek Dyussenov, Nathan Letwory. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef __BC_ANIMATIONIMPORTER_H__ +#define __BC_ANIMATIONIMPORTER_H__ + +#include <map> +#include <vector> + +#include "COLLADAFWAnimation.h" +#include "COLLADAFWAnimationCurve.h" +#include "COLLADAFWAnimationList.h" +#include "COLLADAFWNode.h" +#include "COLLADAFWUniqueId.h" + +#include "DNA_anim_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" + +//#include "ArmatureImporter.h" +#include "TransformReader.h" + +#include "collada_internal.h" + +class ArmatureImporter; + +class AnimationImporterBase +{ +public: + // virtual void change_eul_to_quat(Object *ob, bAction *act) = 0; +}; + +class AnimationImporter : private TransformReader, public AnimationImporterBase +{ +private: + + ArmatureImporter *armature_importer; + Scene *scene; + + std::map<COLLADAFW::UniqueId, std::vector<FCurve*> > curve_map; + std::map<COLLADAFW::UniqueId, TransformReader::Animation> uid_animated_map; + // std::map<bActionGroup*, std::vector<FCurve*> > fcurves_actionGroup_map; + std::map<COLLADAFW::UniqueId, const COLLADAFW::AnimationList*> animlist_map; + std::vector<FCurve*> unused_curves; + std::map<COLLADAFW::UniqueId, Object*> joint_objects; + + FCurve *create_fcurve(int array_index, const char *rna_path); + + void create_bezt(FCurve *fcu, float frame, float output); + + // create one or several fcurves depending on the number of parameters being animated + void animation_to_fcurves(COLLADAFW::AnimationCurve *curve); + + void fcurve_deg_to_rad(FCurve *cu); + + void add_fcurves_to_object(Object *ob, std::vector<FCurve*>& curves, char *rna_path, int array_index, Animation *animated); +public: + + AnimationImporter(UnitConverter *conv, ArmatureImporter *arm, Scene *scene); + + ~AnimationImporter(); + + bool write_animation(const COLLADAFW::Animation* anim); + + // called on post-process stage after writeVisualScenes + bool write_animation_list(const COLLADAFW::AnimationList* animlist); + + void read_node_transform(COLLADAFW::Node *node, Object *ob); +#if 0 + virtual void change_eul_to_quat(Object *ob, bAction *act); +#endif + + // prerequisites: + // animlist_map - map animlist id -> animlist + // curve_map - map anim id -> curve(s) + Object *translate_animation(COLLADAFW::Node *node, + std::map<COLLADAFW::UniqueId, Object*>& object_map, + std::map<COLLADAFW::UniqueId, COLLADAFW::Node*>& root_map, + COLLADAFW::Transformation::TransformationType tm_type, + Object *par_job = NULL); + + // internal, better make it private + // warning: evaluates only rotation + // prerequisites: animlist_map, curve_map + void evaluate_transform_at_frame(float mat[4][4], COLLADAFW::Node *node, float fra); + + // return true to indicate that mat contains a sane value + bool evaluate_animation(COLLADAFW::Transformation *tm, float mat[4][4], float fra, const char *node_id); + + // gives a world-space mat of joint at rest position + void get_joint_rest_mat(float mat[4][4], COLLADAFW::Node *root, COLLADAFW::Node *node); + + // gives a world-space mat, end's mat not included + bool calc_joint_parent_mat_rest(float mat[4][4], float par[4][4], COLLADAFW::Node *node, COLLADAFW::Node *end); + +#ifdef ARMATURE_TEST + Object *get_joint_object(COLLADAFW::Node *root, COLLADAFW::Node *node, Object *par_job); +#endif + +#if 0 + // recursively evaluates joint tree until end is found, mat then is world-space matrix of end + // mat must be identity on enter, node must be root + bool evaluate_joint_world_transform_at_frame(float mat[4][4], float par[4][4], COLLADAFW::Node *node, COLLADAFW::Node *end, float fra); +#endif + + void add_bone_fcurve(Object *ob, COLLADAFW::Node *node, FCurve *fcu); + + void add_bezt(FCurve *fcu, float fra, float value); +}; + + #endif diff --git a/source/blender/collada/ArmatureExporter.cpp b/source/blender/collada/ArmatureExporter.cpp new file mode 100644 index 00000000000..255fb03da10 --- /dev/null +++ b/source/blender/collada/ArmatureExporter.cpp @@ -0,0 +1,469 @@ +/** + * $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): Chingiz Dyussenov, Arystanbek Dyussenov, Jan Diederich, Tod Liverseed, + * Nathan Letwory + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "COLLADASWBaseInputElement.h" +#include "COLLADASWInstanceController.h" +#include "COLLADASWPrimitves.h" +#include "COLLADASWSource.h" + +#include "DNA_action_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_modifier_types.h" + +#include "BKE_action.h" +#include "BKE_armature.h" + +#include "BLI_listbase.h" + +#include "GeometryExporter.h" +#include "ArmatureExporter.h" + +// XXX exporter writes wrong data for shared armatures. A separate +// controller should be written for each armature-mesh binding how do +// we make controller ids then? +ArmatureExporter::ArmatureExporter(COLLADASW::StreamWriter *sw) : COLLADASW::LibraryControllers(sw) {} + +// write bone nodes +void ArmatureExporter::add_armature_bones(Object *ob_arm, Scene *sce) +{ + // write bone nodes + bArmature *arm = (bArmature*)ob_arm->data; + for (Bone *bone = (Bone*)arm->bonebase.first; bone; bone = bone->next) { + // start from root bones + if (!bone->parent) + add_bone_node(bone, ob_arm); + } +} + +bool ArmatureExporter::is_skinned_mesh(Object *ob) +{ + return get_assigned_armature(ob) != NULL; +} + +void ArmatureExporter::add_instance_controller(Object *ob) +{ + Object *ob_arm = get_assigned_armature(ob); + bArmature *arm = (bArmature*)ob_arm->data; + + const std::string& controller_id = get_controller_id(ob_arm, ob); + + COLLADASW::InstanceController ins(mSW); + ins.setUrl(COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, controller_id)); + + // write root bone URLs + Bone *bone; + for (bone = (Bone*)arm->bonebase.first; bone; bone = bone->next) { + if (!bone->parent) + ins.addSkeleton(COLLADABU::URI(COLLADABU::Utils::EMPTY_STRING, get_joint_id(bone, ob_arm))); + } + + InstanceWriter::add_material_bindings(ins.getBindMaterial(), ob); + + ins.add(); +} + +void ArmatureExporter::export_controllers(Scene *sce) +{ + scene = sce; + + openLibrary(); + + GeometryFunctor gf; + gf.forEachMeshObjectInScene<ArmatureExporter>(sce, *this); + + closeLibrary(); +} + +void ArmatureExporter::operator()(Object *ob) +{ + Object *ob_arm = get_assigned_armature(ob); + + if (ob_arm /*&& !already_written(ob_arm)*/) + export_controller(ob, ob_arm); +} +#if 0 + +bool ArmatureExporter::already_written(Object *ob_arm) +{ + return std::find(written_armatures.begin(), written_armatures.end(), ob_arm) != written_armatures.end(); +} + +void ArmatureExporter::wrote(Object *ob_arm) +{ + written_armatures.push_back(ob_arm); +} + +void ArmatureExporter::find_objects_using_armature(Object *ob_arm, std::vector<Object *>& objects, Scene *sce) +{ + objects.clear(); + + Base *base= (Base*) sce->base.first; + while(base) { + Object *ob = base->object; + + if (ob->type == OB_MESH && get_assigned_armature(ob) == ob_arm) { + objects.push_back(ob); + } + + base= base->next; + } +} +#endif + +Object *ArmatureExporter::get_assigned_armature(Object *ob) +{ + Object *ob_arm = NULL; + + if (ob->parent && ob->partype == PARSKEL && ob->parent->type == OB_ARMATURE) { + ob_arm = ob->parent; + } + else { + ModifierData *mod = (ModifierData*)ob->modifiers.first; + while (mod) { + if (mod->type == eModifierType_Armature) { + ob_arm = ((ArmatureModifierData*)mod)->object; + } + + mod = mod->next; + } + } + + return ob_arm; +} + +std::string ArmatureExporter::get_joint_sid(Bone *bone, Object *ob_arm) +{ + return get_joint_id(bone, ob_arm); +} + +// parent_mat is armature-space +void ArmatureExporter::add_bone_node(Bone *bone, Object *ob_arm) +{ + std::string node_id = get_joint_id(bone, ob_arm); + std::string node_name = std::string(bone->name); + std::string node_sid = get_joint_sid(bone, ob_arm); + + COLLADASW::Node node(mSW); + + node.setType(COLLADASW::Node::JOINT); + node.setNodeId(node_id); + node.setNodeName(node_name); + node.setNodeSid(node_sid); + + node.start(); + + add_bone_transform(ob_arm, bone, node); + + for (Bone *child = (Bone*)bone->childbase.first; child; child = child->next) { + add_bone_node(child, ob_arm); + } + + node.end(); +} + +void ArmatureExporter::add_bone_transform(Object *ob_arm, Bone *bone, COLLADASW::Node& node) +{ + bPoseChannel *pchan = get_pose_channel(ob_arm->pose, bone->name); + + float mat[4][4]; + + if (bone->parent) { + // get bone-space matrix from armature-space + bPoseChannel *parchan = get_pose_channel(ob_arm->pose, bone->parent->name); + + float invpar[4][4]; + invert_m4_m4(invpar, parchan->pose_mat); + mul_m4_m4m4(mat, pchan->pose_mat, invpar); + } + else { + // get world-space from armature-space + mul_m4_m4m4(mat, pchan->pose_mat, ob_arm->obmat); + } + + TransformWriter::add_node_transform(node, mat, NULL); +} + +std::string ArmatureExporter::get_controller_id(Object *ob_arm, Object *ob) +{ + return translate_id(id_name(ob_arm)) + "_" + translate_id(id_name(ob)) + SKIN_CONTROLLER_ID_SUFFIX; +} + +// ob should be of type OB_MESH +// both args are required +void ArmatureExporter::export_controller(Object* ob, Object *ob_arm) +{ + // joint names + // joint inverse bind matrices + // vertex weights + + // input: + // joint names: ob -> vertex group names + // vertex group weights: me->dvert -> groups -> index, weight + + /* + me->dvert: + + typedef struct MDeformVert { + struct MDeformWeight *dw; + int totweight; + int flag; // flag only in use for weightpaint now + } MDeformVert; + + typedef struct MDeformWeight { + int def_nr; + float weight; + } MDeformWeight; + */ + + Mesh *me = (Mesh*)ob->data; + if (!me->dvert) return; + + std::string controller_name = id_name(ob_arm); + std::string controller_id = get_controller_id(ob_arm, ob); + + openSkin(controller_id, controller_name, + COLLADABU::URI(COLLADABU::Utils::EMPTY_STRING, get_geometry_id(ob))); + + add_bind_shape_mat(ob); + + std::string joints_source_id = add_joints_source(ob_arm, &ob->defbase, controller_id); + std::string inv_bind_mat_source_id = add_inv_bind_mats_source(ob_arm, &ob->defbase, controller_id); + std::string weights_source_id = add_weights_source(me, controller_id); + + add_joints_element(&ob->defbase, joints_source_id, inv_bind_mat_source_id); + add_vertex_weights_element(weights_source_id, joints_source_id, me, ob_arm, &ob->defbase); + + closeSkin(); + closeController(); +} + +void ArmatureExporter::add_joints_element(ListBase *defbase, + const std::string& joints_source_id, const std::string& inv_bind_mat_source_id) +{ + COLLADASW::JointsElement joints(mSW); + COLLADASW::InputList &input = joints.getInputList(); + + input.push_back(COLLADASW::Input(COLLADASW::JOINT, // constant declared in COLLADASWInputList.h + COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, joints_source_id))); + input.push_back(COLLADASW::Input(COLLADASW::BINDMATRIX, + COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, inv_bind_mat_source_id))); + joints.add(); +} + +void ArmatureExporter::add_bind_shape_mat(Object *ob) +{ + double bind_mat[4][4]; + + converter.mat4_to_dae_double(bind_mat, ob->obmat); + + addBindShapeTransform(bind_mat); +} + +std::string ArmatureExporter::add_joints_source(Object *ob_arm, ListBase *defbase, const std::string& controller_id) +{ + std::string source_id = controller_id + JOINTS_SOURCE_ID_SUFFIX; + + int totjoint = 0; + bDeformGroup *def; + for (def = (bDeformGroup*)defbase->first; def; def = def->next) { + if (is_bone_defgroup(ob_arm, def)) + totjoint++; + } + + COLLADASW::NameSource source(mSW); + source.setId(source_id); + source.setArrayId(source_id + ARRAY_ID_SUFFIX); + source.setAccessorCount(totjoint); + source.setAccessorStride(1); + + COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList(); + param.push_back("JOINT"); + + source.prepareToAppendValues(); + + for (def = (bDeformGroup*)defbase->first; def; def = def->next) { + Bone *bone = get_bone_from_defgroup(ob_arm, def); + if (bone) + source.appendValues(get_joint_sid(bone, ob_arm)); + } + + source.finish(); + + return source_id; +} + +std::string ArmatureExporter::add_inv_bind_mats_source(Object *ob_arm, ListBase *defbase, const std::string& controller_id) +{ + std::string source_id = controller_id + BIND_POSES_SOURCE_ID_SUFFIX; + + COLLADASW::FloatSourceF source(mSW); + source.setId(source_id); + source.setArrayId(source_id + ARRAY_ID_SUFFIX); + source.setAccessorCount(BLI_countlist(defbase)); + source.setAccessorStride(16); + + source.setParameterTypeName(&COLLADASW::CSWC::CSW_VALUE_TYPE_FLOAT4x4); + COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList(); + param.push_back("TRANSFORM"); + + source.prepareToAppendValues(); + + bPose *pose = ob_arm->pose; + bArmature *arm = (bArmature*)ob_arm->data; + + int flag = arm->flag; + + // put armature in rest position + if (!(arm->flag & ARM_RESTPOS)) { + arm->flag |= ARM_RESTPOS; + where_is_pose(scene, ob_arm); + } + + for (bDeformGroup *def = (bDeformGroup*)defbase->first; def; def = def->next) { + if (is_bone_defgroup(ob_arm, def)) { + + bPoseChannel *pchan = get_pose_channel(pose, def->name); + + float mat[4][4]; + float world[4][4]; + float inv_bind_mat[4][4]; + + // make world-space matrix, pose_mat is armature-space + mul_m4_m4m4(world, pchan->pose_mat, ob_arm->obmat); + + invert_m4_m4(mat, world); + converter.mat4_to_dae(inv_bind_mat, mat); + + source.appendValues(inv_bind_mat); + } + } + + // back from rest positon + if (!(flag & ARM_RESTPOS)) { + arm->flag = flag; + where_is_pose(scene, ob_arm); + } + + source.finish(); + + return source_id; +} + +Bone *ArmatureExporter::get_bone_from_defgroup(Object *ob_arm, bDeformGroup* def) +{ + bPoseChannel *pchan = get_pose_channel(ob_arm->pose, def->name); + return pchan ? pchan->bone : NULL; +} + +bool ArmatureExporter::is_bone_defgroup(Object *ob_arm, bDeformGroup* def) +{ + return get_bone_from_defgroup(ob_arm, def) != NULL; +} + +std::string ArmatureExporter::add_weights_source(Mesh *me, const std::string& controller_id) +{ + std::string source_id = controller_id + WEIGHTS_SOURCE_ID_SUFFIX; + + int i; + int totweight = 0; + + for (i = 0; i < me->totvert; i++) { + totweight += me->dvert[i].totweight; + } + + COLLADASW::FloatSourceF source(mSW); + source.setId(source_id); + source.setArrayId(source_id + ARRAY_ID_SUFFIX); + source.setAccessorCount(totweight); + source.setAccessorStride(1); + + COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList(); + param.push_back("WEIGHT"); + + source.prepareToAppendValues(); + + // NOTE: COLLADA spec says weights should be normalized + + for (i = 0; i < me->totvert; i++) { + MDeformVert *vert = &me->dvert[i]; + for (int j = 0; j < vert->totweight; j++) { + source.appendValues(vert->dw[j].weight); + } + } + + source.finish(); + + return source_id; +} + +void ArmatureExporter::add_vertex_weights_element(const std::string& weights_source_id, const std::string& joints_source_id, Mesh *me, + Object *ob_arm, ListBase *defbase) +{ + COLLADASW::VertexWeightsElement weights(mSW); + COLLADASW::InputList &input = weights.getInputList(); + + int offset = 0; + input.push_back(COLLADASW::Input(COLLADASW::JOINT, // constant declared in COLLADASWInputList.h + COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, joints_source_id), offset++)); + input.push_back(COLLADASW::Input(COLLADASW::WEIGHT, + COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, weights_source_id), offset++)); + + weights.setCount(me->totvert); + + // write number of deformers per vertex + COLLADASW::PrimitivesBase::VCountList vcount; + int i; + for (i = 0; i < me->totvert; i++) { + vcount.push_back(me->dvert[i].totweight); + } + + weights.prepareToAppendVCountValues(); + weights.appendVertexCount(vcount); + + // def group index -> joint index + std::map<int, int> joint_index_by_def_index; + bDeformGroup *def; + int j; + for (def = (bDeformGroup*)defbase->first, i = 0, j = 0; def; def = def->next, i++) { + if (is_bone_defgroup(ob_arm, def)) + joint_index_by_def_index[i] = j++; + else + joint_index_by_def_index[i] = -1; + } + + weights.CloseVCountAndOpenVElement(); + + // write deformer index - weight index pairs + int weight_index = 0; + for (i = 0; i < me->totvert; i++) { + MDeformVert *dvert = &me->dvert[i]; + for (int j = 0; j < dvert->totweight; j++) { + weights.appendValues(joint_index_by_def_index[dvert->dw[j].def_nr]); + weights.appendValues(weight_index++); + } + } + + weights.finish(); +} diff --git a/source/blender/collada/ArmatureExporter.h b/source/blender/collada/ArmatureExporter.h new file mode 100644 index 00000000000..8d2508282bd --- /dev/null +++ b/source/blender/collada/ArmatureExporter.h @@ -0,0 +1,137 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your 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): Chingiz Dyussenov, Arystanbek Dyussenov, Jan Diederich, Tod Liverseed, + * Nathan Letwory + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef __ARMATUREEXPORTER_H__ +#define __ARMATUREEXPORTER_H__ + +#include <string> +//#include <vector> + +#include "COLLADASWStreamWriter.h" +#include "COLLADASWLibraryControllers.h" +#include "COLLADASWInputList.h" +#include "COLLADASWNode.h" + +#include "DNA_armature_types.h" +#include "DNA_listBase.h" +#include "DNA_mesh_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" + +#include "TransformWriter.h" +#include "InstanceWriter.h" + +// XXX exporter writes wrong data for shared armatures. A separate +// controller should be written for each armature-mesh binding how do +// we make controller ids then? +class ArmatureExporter: public COLLADASW::LibraryControllers, protected TransformWriter, protected InstanceWriter +{ +private: + Scene *scene; + +public: + ArmatureExporter(COLLADASW::StreamWriter *sw); + + // write bone nodes + void add_armature_bones(Object *ob_arm, Scene *sce); + + bool is_skinned_mesh(Object *ob); + + void add_instance_controller(Object *ob); + + void export_controllers(Scene *sce); + + void operator()(Object *ob); + +private: + + UnitConverter converter; + +#if 0 + std::vector<Object*> written_armatures; + + bool already_written(Object *ob_arm); + + void wrote(Object *ob_arm); + + void find_objects_using_armature(Object *ob_arm, std::vector<Object *>& objects, Scene *sce); +#endif + + Object *get_assigned_armature(Object *ob); + + std::string get_joint_sid(Bone *bone, Object *ob_arm); + + // parent_mat is armature-space + void add_bone_node(Bone *bone, Object *ob_arm); + + void add_bone_transform(Object *ob_arm, Bone *bone, COLLADASW::Node& node); + + std::string get_controller_id(Object *ob_arm, Object *ob); + + // ob should be of type OB_MESH + // both args are required + void export_controller(Object* ob, Object *ob_arm); + + void add_joints_element(ListBase *defbase, + const std::string& joints_source_id, const std::string& inv_bind_mat_source_id); + + void add_bind_shape_mat(Object *ob); + + std::string add_joints_source(Object *ob_arm, ListBase *defbase, const std::string& controller_id); + + std::string add_inv_bind_mats_source(Object *ob_arm, ListBase *defbase, const std::string& controller_id); + + Bone *get_bone_from_defgroup(Object *ob_arm, bDeformGroup* def); + + bool is_bone_defgroup(Object *ob_arm, bDeformGroup* def); + + std::string add_weights_source(Mesh *me, const std::string& controller_id); + + void add_vertex_weights_element(const std::string& weights_source_id, const std::string& joints_source_id, Mesh *me, + Object *ob_arm, ListBase *defbase); +}; + +/* +struct GeometryFunctor { + // f should have + // void operator()(Object* ob) + template<class Functor> + void forEachMeshObjectInScene(Scene *sce, Functor &f) + { + + Base *base= (Base*) sce->base.first; + while(base) { + Object *ob = base->object; + + if (ob->type == OB_MESH && ob->data) { + f(ob); + } + base= base->next; + + } + } +};*/ + +#endif diff --git a/source/blender/collada/ArmatureImporter.cpp b/source/blender/collada/ArmatureImporter.cpp new file mode 100644 index 00000000000..a8ac6d8b768 --- /dev/null +++ b/source/blender/collada/ArmatureImporter.cpp @@ -0,0 +1,585 @@ +/** + * $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): Chingiz Dyussenov, Arystanbek Dyussenov, Nathan Letwory. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include <algorithm> + +#include "COLLADAFWUniqueId.h" + +#include "BKE_action.h" +#include "BKE_depsgraph.h" +#include "BKE_object.h" +#include "BLI_string.h" +#include "ED_armature.h" + +#include "ArmatureImporter.h" + +// use this for retrieving bone names, since these must be unique +template<class T> +static const char *bc_get_joint_name(T *node) +{ + const std::string& id = node->getOriginalId(); + return id.size() ? id.c_str() : node->getName().c_str(); +} + +ArmatureImporter::ArmatureImporter(UnitConverter *conv, MeshImporterBase *mesh, AnimationImporterBase *anim, Scene *sce) : + TransformReader(conv), scene(sce), empty(NULL), mesh_importer(mesh), anim_importer(anim) {} + +ArmatureImporter::~ArmatureImporter() +{ + // free skin controller data if we forget to do this earlier + std::map<COLLADAFW::UniqueId, SkinInfo>::iterator it; + for (it = skin_by_data_uid.begin(); it != skin_by_data_uid.end(); it++) { + it->second.free(); + } +} + +#if 0 +JointData *ArmatureImporter::get_joint_data(COLLADAFW::Node *node); +{ + const COLLADAFW::UniqueId& joint_id = node->getUniqueId(); + + if (joint_id_to_joint_index_map.find(joint_id) == joint_id_to_joint_index_map.end()) { + fprintf(stderr, "Cannot find a joint index by joint id for %s.\n", + node->getOriginalId().c_str()); + return NULL; + } + + int joint_index = joint_id_to_joint_index_map[joint_id]; + + return &joint_index_to_joint_info_map[joint_index]; +} +#endif + +void ArmatureImporter::create_bone(SkinInfo& skin, COLLADAFW::Node *node, EditBone *parent, int totchild, + float parent_mat[][4], bArmature *arm) +{ + float joint_inv_bind_mat[4][4]; + + // JointData* jd = get_joint_data(node); + + float mat[4][4]; + + if (skin.get_joint_inv_bind_matrix(joint_inv_bind_mat, node)) { + // get original world-space matrix + invert_m4_m4(mat, joint_inv_bind_mat); + } + // create a bone even if there's no joint data for it (i.e. it has no influence) + else { + float obmat[4][4]; + + // object-space + get_node_mat(obmat, node, NULL, NULL); + + // get world-space + if (parent) + mul_m4_m4m4(mat, obmat, parent_mat); + else + copy_m4_m4(mat, obmat); + } + + // TODO rename from Node "name" attrs later + EditBone *bone = ED_armature_edit_bone_add(arm, (char*)bc_get_joint_name(node)); + totbone++; + + if (parent) bone->parent = parent; + + // set head + copy_v3_v3(bone->head, mat[3]); + + // set tail, don't set it to head because 0-length bones are not allowed + float vec[3] = {0.0f, 0.5f, 0.0f}; + add_v3_v3v3(bone->tail, bone->head, vec); + + // set parent tail + if (parent && totchild == 1) { + copy_v3_v3(parent->tail, bone->head); + + // not setting BONE_CONNECTED because this would lock child bone location with respect to parent + // bone->flag |= BONE_CONNECTED; + + // XXX increase this to prevent "very" small bones? + const float epsilon = 0.000001f; + + // derive leaf bone length + float length = len_v3v3(parent->head, parent->tail); + if ((length < leaf_bone_length || totbone == 0) && length > epsilon) { + leaf_bone_length = length; + } + + // treat zero-sized bone like a leaf bone + if (length <= epsilon) { + add_leaf_bone(parent_mat, parent); + } + + /* +#if 0 + // and which row in mat is bone direction + float vec[3]; + sub_v3_v3v3(vec, parent->tail, parent->head); +#ifdef COLLADA_DEBUG + print_v3("tail - head", vec); + print_m4("matrix", parent_mat); +#endif + for (int i = 0; i < 3; i++) { +#ifdef COLLADA_DEBUG + char *axis_names[] = {"X", "Y", "Z"}; + printf("%s-axis length is %f\n", axis_names[i], len_v3(parent_mat[i])); +#endif + float angle = angle_v2v2(vec, parent_mat[i]); + if (angle < min_angle) { +#ifdef COLLADA_DEBUG + print_v3("picking", parent_mat[i]); + printf("^ %s axis of %s's matrix\n", axis_names[i], get_dae_name(node)); +#endif + bone_direction_row = i; + min_angle = angle; + } + } +#endif + */ + } + + COLLADAFW::NodePointerArray& children = node->getChildNodes(); + for (unsigned int i = 0; i < children.getCount(); i++) { + create_bone(skin, children[i], bone, children.getCount(), mat, arm); + } + + // in second case it's not a leaf bone, but we handle it the same way + if (!children.getCount() || children.getCount() > 1) { + add_leaf_bone(mat, bone); + } +} + +void ArmatureImporter::add_leaf_bone(float mat[][4], EditBone *bone) +{ + LeafBone leaf; + + leaf.bone = bone; + copy_m4_m4(leaf.mat, mat); + BLI_strncpy(leaf.name, bone->name, sizeof(leaf.name)); + + leaf_bones.push_back(leaf); +} + +void ArmatureImporter::fix_leaf_bones() +{ + // just setting tail for leaf bones here + + std::vector<LeafBone>::iterator it; + for (it = leaf_bones.begin(); it != leaf_bones.end(); it++) { + LeafBone& leaf = *it; + + // pointing up + float vec[3] = {0.0f, 0.0f, 1.0f}; + + mul_v3_fl(vec, leaf_bone_length); + + copy_v3_v3(leaf.bone->tail, leaf.bone->head); + add_v3_v3v3(leaf.bone->tail, leaf.bone->head, vec); + } +} + +void ArmatureImporter::set_leaf_bone_shapes(Object *ob_arm) +{ + bPose *pose = ob_arm->pose; + + std::vector<LeafBone>::iterator it; + for (it = leaf_bones.begin(); it != leaf_bones.end(); it++) { + LeafBone& leaf = *it; + + bPoseChannel *pchan = get_pose_channel(pose, leaf.name); + if (pchan) { + pchan->custom = get_empty_for_leaves(); + } + else { + fprintf(stderr, "Cannot find a pose channel for leaf bone %s\n", leaf.name); + } + } +} + +#if 0 +void ArmatureImporter::set_euler_rotmode() +{ + // just set rotmode = ROT_MODE_EUL on pose channel for each joint + + std::map<COLLADAFW::UniqueId, COLLADAFW::Node*>::iterator it; + + for (it = joint_by_uid.begin(); it != joint_by_uid.end(); it++) { + + COLLADAFW::Node *joint = it->second; + + std::map<COLLADAFW::UniqueId, SkinInfo>::iterator sit; + + for (sit = skin_by_data_uid.begin(); sit != skin_by_data_uid.end(); sit++) { + SkinInfo& skin = sit->second; + + if (skin.uses_joint_or_descendant(joint)) { + bPoseChannel *pchan = skin.get_pose_channel_from_node(joint); + + if (pchan) { + pchan->rotmode = ROT_MODE_EUL; + } + else { + fprintf(stderr, "Cannot find pose channel for %s.\n", get_joint_name(joint)); + } + + break; + } + } + } +} +#endif + +Object *ArmatureImporter::get_empty_for_leaves() +{ + if (empty) return empty; + + empty = add_object(scene, OB_EMPTY); + empty->empty_drawtype = OB_EMPTY_SPHERE; + + return empty; +} + +#if 0 +Object *ArmatureImporter::find_armature(COLLADAFW::Node *node) +{ + JointData* jd = get_joint_data(node); + if (jd) return jd->ob_arm; + + COLLADAFW::NodePointerArray& children = node->getChildNodes(); + for (int i = 0; i < children.getCount(); i++) { + Object *ob_arm = find_armature(children[i]); + if (ob_arm) return ob_arm; + } + + return NULL; +} + +ArmatureJoints& ArmatureImporter::get_armature_joints(Object *ob_arm) +{ + // try finding it + std::vector<ArmatureJoints>::iterator it; + for (it = armature_joints.begin(); it != armature_joints.end(); it++) { + if ((*it).ob_arm == ob_arm) return *it; + } + + // not found, create one + ArmatureJoints aj; + aj.ob_arm = ob_arm; + armature_joints.push_back(aj); + + return armature_joints.back(); +} +#endif + +void ArmatureImporter::create_armature_bones(SkinInfo& skin) +{ + // just do like so: + // - get armature + // - enter editmode + // - add edit bones and head/tail properties using matrices and parent-child info + // - exit edit mode + // - set a sphere shape to leaf bones + + Object *ob_arm = NULL; + + /* + * find if there's another skin sharing at least one bone with this skin + * if so, use that skin's armature + */ + + /* + Pseudocode: + + find_node_in_tree(node, root_joint) + + skin::find_root_joints(root_joints): + std::vector root_joints; + for each root in root_joints: + for each joint in joints: + if find_node_in_tree(joint, root): + if (std::find(root_joints.begin(), root_joints.end(), root) == root_joints.end()) + root_joints.push_back(root); + + for (each skin B with armature) { + find all root joints for skin B + + for each joint X in skin A: + for each root joint R in skin B: + if (find_node_in_tree(X, R)) { + shared = 1; + goto endloop; + } + } + + endloop: + */ + + SkinInfo *a = &skin; + Object *shared = NULL; + std::vector<COLLADAFW::Node*> skin_root_joints; + + std::map<COLLADAFW::UniqueId, SkinInfo>::iterator it; + for (it = skin_by_data_uid.begin(); it != skin_by_data_uid.end(); it++) { + SkinInfo *b = &it->second; + if (b == a || b->get_armature() == NULL) + continue; + + skin_root_joints.clear(); + + b->find_root_joints(root_joints, joint_by_uid, skin_root_joints); + + std::vector<COLLADAFW::Node*>::iterator ri; + for (ri = skin_root_joints.begin(); ri != skin_root_joints.end(); ri++) { + if (a->uses_joint_or_descendant(*ri)) { + shared = b->get_armature(); + break; + } + } + + if (shared != NULL) + break; + } + + if (shared) + ob_arm = skin.set_armature(shared); + else + ob_arm = skin.create_armature(scene); + + // enter armature edit mode + ED_armature_to_edit(ob_arm); + + leaf_bones.clear(); + totbone = 0; + // bone_direction_row = 1; // TODO: don't default to Y but use asset and based on it decide on default row + leaf_bone_length = 0.1f; + // min_angle = 360.0f; // minimum angle between bone head-tail and a row of bone matrix + + // create bones + /* + TODO: + check if bones have already been created for a given joint + */ + + std::vector<COLLADAFW::Node*>::iterator ri; + for (ri = root_joints.begin(); ri != root_joints.end(); ri++) { + // for shared armature check if bone tree is already created + if (shared && std::find(skin_root_joints.begin(), skin_root_joints.end(), *ri) != skin_root_joints.end()) + continue; + + // since root_joints may contain joints for multiple controllers, we need to filter + if (skin.uses_joint_or_descendant(*ri)) { + create_bone(skin, *ri, NULL, (*ri)->getChildNodes().getCount(), NULL, (bArmature*)ob_arm->data); + + if (joint_parent_map.find((*ri)->getUniqueId()) != joint_parent_map.end() && !skin.get_parent()) + skin.set_parent(joint_parent_map[(*ri)->getUniqueId()]); + } + } + + fix_leaf_bones(); + + // exit armature edit mode + ED_armature_from_edit(ob_arm); + ED_armature_edit_free(ob_arm); + DAG_id_flush_update(&ob_arm->id, OB_RECALC_OB|OB_RECALC_DATA); + + set_leaf_bone_shapes(ob_arm); + + // set_euler_rotmode(); +} + + +// root - if this joint is the top joint in hierarchy, if a joint +// is a child of a node (not joint), root should be true since +// this is where we build armature bones from +void ArmatureImporter::add_joint(COLLADAFW::Node *node, bool root, Object *parent) +{ + joint_by_uid[node->getUniqueId()] = node; + if (root) { + root_joints.push_back(node); + + if (parent) + joint_parent_map[node->getUniqueId()] = parent; + } +} + +#if 0 +void ArmatureImporter::add_root_joint(COLLADAFW::Node *node) +{ + // root_joints.push_back(node); + Object *ob_arm = find_armature(node); + if (ob_arm) { + get_armature_joints(ob_arm).root_joints.push_back(node); + } +#ifdef COLLADA_DEBUG + else { + fprintf(stderr, "%s cannot be added to armature.\n", get_joint_name(node)); + } +#endif +} +#endif + +// here we add bones to armatures, having armatures previously created in write_controller +void ArmatureImporter::make_armatures(bContext *C) +{ + std::map<COLLADAFW::UniqueId, SkinInfo>::iterator it; + for (it = skin_by_data_uid.begin(); it != skin_by_data_uid.end(); it++) { + + SkinInfo& skin = it->second; + + create_armature_bones(skin); + + // link armature with a mesh object + Object *ob = mesh_importer->get_object_by_geom_uid(*get_geometry_uid(skin.get_controller_uid())); + if (ob) + skin.link_armature(C, ob, joint_by_uid, this); + else + fprintf(stderr, "Cannot find object to link armature with.\n"); + + // set armature parent if any + Object *par = skin.get_parent(); + if (par) + bc_set_parent(skin.get_armature(), par, C, false); + + // free memory stolen from SkinControllerData + skin.free(); + } +} + +#if 0 +// link with meshes, create vertex groups, assign weights +void ArmatureImporter::link_armature(Object *ob_arm, const COLLADAFW::UniqueId& geom_id, const COLLADAFW::UniqueId& controller_data_id) +{ + Object *ob = mesh_importer->get_object_by_geom_uid(geom_id); + + if (!ob) { + fprintf(stderr, "Cannot find object by geometry UID.\n"); + return; + } + + if (skin_by_data_uid.find(controller_data_id) == skin_by_data_uid.end()) { + fprintf(stderr, "Cannot find skin info by controller data UID.\n"); + return; + } + + SkinInfo& skin = skin_by_data_uid[conroller_data_id]; + + // create vertex groups +} +#endif + +bool ArmatureImporter::write_skin_controller_data(const COLLADAFW::SkinControllerData* data) +{ + // at this stage we get vertex influence info that should go into me->verts and ob->defbase + // there's no info to which object this should be long so we associate it with skin controller data UID + + // don't forget to call defgroup_unique_name before we copy + + // controller data uid -> [armature] -> joint data, + // [mesh object] + // + + SkinInfo skin(unit_converter); + skin.borrow_skin_controller_data(data); + + // store join inv bind matrix to use it later in armature construction + const COLLADAFW::Matrix4Array& inv_bind_mats = data->getInverseBindMatrices(); + for (unsigned int i = 0; i < data->getJointsCount(); i++) { + skin.add_joint(inv_bind_mats[i]); + } + + skin_by_data_uid[data->getUniqueId()] = skin; + + return true; +} + +bool ArmatureImporter::write_controller(const COLLADAFW::Controller* controller) +{ + // - create and store armature object + + const COLLADAFW::UniqueId& skin_id = controller->getUniqueId(); + + if (controller->getControllerType() == COLLADAFW::Controller::CONTROLLER_TYPE_SKIN) { + COLLADAFW::SkinController *co = (COLLADAFW::SkinController*)controller; + // to be able to find geom id by controller id + geom_uid_by_controller_uid[skin_id] = co->getSource(); + + const COLLADAFW::UniqueId& data_uid = co->getSkinControllerData(); + if (skin_by_data_uid.find(data_uid) == skin_by_data_uid.end()) { + fprintf(stderr, "Cannot find skin by controller data UID.\n"); + return true; + } + + skin_by_data_uid[data_uid].set_controller(co); + } + // morph controller + else { + // shape keys? :) + fprintf(stderr, "Morph controller is not supported yet.\n"); + } + + return true; +} + +COLLADAFW::UniqueId *ArmatureImporter::get_geometry_uid(const COLLADAFW::UniqueId& controller_uid) +{ + if (geom_uid_by_controller_uid.find(controller_uid) == geom_uid_by_controller_uid.end()) + return NULL; + + return &geom_uid_by_controller_uid[controller_uid]; +} + +Object *ArmatureImporter::get_armature_for_joint(COLLADAFW::Node *node) +{ + std::map<COLLADAFW::UniqueId, SkinInfo>::iterator it; + for (it = skin_by_data_uid.begin(); it != skin_by_data_uid.end(); it++) { + SkinInfo& skin = it->second; + + if (skin.uses_joint_or_descendant(node)) + return skin.get_armature(); + } + + return NULL; +} + +void ArmatureImporter::get_rna_path_for_joint(COLLADAFW::Node *node, char *joint_path, size_t count) +{ + BLI_snprintf(joint_path, count, "pose.bones[\"%s\"]", bc_get_joint_name(node)); +} + +// gives a world-space mat +bool ArmatureImporter::get_joint_bind_mat(float m[][4], COLLADAFW::Node *joint) +{ + std::map<COLLADAFW::UniqueId, SkinInfo>::iterator it; + bool found = false; + for (it = skin_by_data_uid.begin(); it != skin_by_data_uid.end(); it++) { + SkinInfo& skin = it->second; + if ((found = skin.get_joint_inv_bind_matrix(m, joint))) { + invert_m4(m); + break; + } + } + + return found; +} diff --git a/source/blender/collada/ArmatureImporter.h b/source/blender/collada/ArmatureImporter.h new file mode 100644 index 00000000000..a857ab67f12 --- /dev/null +++ b/source/blender/collada/ArmatureImporter.h @@ -0,0 +1,160 @@ +/** + * $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): Chingiz Dyussenov, Arystanbek Dyussenov, Nathan Letwory. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef __BC_ARMATUREIMPORTER_H__ +#define __BC_ARMATUREIMPORTER_H__ + +#include "COLLADAFWNode.h" +#include "COLLADAFWUniqueId.h" + +extern "C" { +#include "BKE_context.h" + +#include "DNA_armature_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" + +#include "ED_armature.h" +} + +#include "AnimationImporter.h" +#include "MeshImporter.h" +#include "SkinInfo.h" +#include "TransformReader.h" + +#include <map> +#include <vector> + +#include "collada_internal.h" +#include "collada_utils.h" + +class ArmatureImporter : private TransformReader +{ +private: + Scene *scene; + UnitConverter *unit_converter; + + // std::map<int, JointData> joint_index_to_joint_info_map; + // std::map<COLLADAFW::UniqueId, int> joint_id_to_joint_index_map; + + struct LeafBone { + // COLLADAFW::Node *node; + EditBone *bone; + char name[32]; + float mat[4][4]; // bone matrix, derived from inv_bind_mat + }; + std::vector<LeafBone> leaf_bones; + // int bone_direction_row; // XXX not used + float leaf_bone_length; + int totbone; + // XXX not used + // float min_angle; // minimum angle between bone head-tail and a row of bone matrix + +#if 0 + struct ArmatureJoints { + Object *ob_arm; + std::vector<COLLADAFW::Node*> root_joints; + }; + std::vector<ArmatureJoints> armature_joints; +#endif + + Object *empty; // empty for leaf bones + + std::map<COLLADAFW::UniqueId, COLLADAFW::UniqueId> geom_uid_by_controller_uid; + std::map<COLLADAFW::UniqueId, COLLADAFW::Node*> joint_by_uid; // contains all joints + std::vector<COLLADAFW::Node*> root_joints; + std::map<COLLADAFW::UniqueId, Object*> joint_parent_map; + + MeshImporterBase *mesh_importer; + AnimationImporterBase *anim_importer; + + // This is used to store data passed in write_controller_data. + // Arrays from COLLADAFW::SkinControllerData lose ownership, so do this class members + // so that arrays don't get freed until we free them explicitly. + + std::map<COLLADAFW::UniqueId, SkinInfo> skin_by_data_uid; // data UID = skin controller data UID +#if 0 + JointData *get_joint_data(COLLADAFW::Node *node); +#endif + + void create_bone(SkinInfo& skin, COLLADAFW::Node *node, EditBone *parent, int totchild, + float parent_mat[][4], bArmature *arm); + + void add_leaf_bone(float mat[][4], EditBone *bone); + + void fix_leaf_bones(); + + void set_leaf_bone_shapes(Object *ob_arm); + +#if 0 + void set_euler_rotmode(); +#endif + + Object *get_empty_for_leaves(); + +#if 0 + Object *find_armature(COLLADAFW::Node *node); + + ArmatureJoints& get_armature_joints(Object *ob_arm); +#endif + + void create_armature_bones(SkinInfo& skin); + +public: + + ArmatureImporter(UnitConverter *conv, MeshImporterBase *mesh, AnimationImporterBase *anim, Scene *sce); + ~ArmatureImporter(); + + // root - if this joint is the top joint in hierarchy, if a joint + // is a child of a node (not joint), root should be true since + // this is where we build armature bones from + void add_joint(COLLADAFW::Node *node, bool root, Object *parent); + +#if 0 + void add_root_joint(COLLADAFW::Node *node); +#endif + + // here we add bones to armatures, having armatures previously created in write_controller + void make_armatures(bContext *C); + +#if 0 + // link with meshes, create vertex groups, assign weights + void link_armature(Object *ob_arm, const COLLADAFW::UniqueId& geom_id, const COLLADAFW::UniqueId& controller_data_id); +#endif + + bool write_skin_controller_data(const COLLADAFW::SkinControllerData* data); + + bool write_controller(const COLLADAFW::Controller* controller); + + COLLADAFW::UniqueId *get_geometry_uid(const COLLADAFW::UniqueId& controller_uid); + + Object *get_armature_for_joint(COLLADAFW::Node *node); + + void get_rna_path_for_joint(COLLADAFW::Node *node, char *joint_path, size_t count); + + // gives a world-space mat + bool get_joint_bind_mat(float m[][4], COLLADAFW::Node *joint); +}; + +#endif diff --git a/source/blender/collada/CameraExporter.cpp b/source/blender/collada/CameraExporter.cpp new file mode 100644 index 00000000000..c3a6cda8b3c --- /dev/null +++ b/source/blender/collada/CameraExporter.cpp @@ -0,0 +1,86 @@ +/** + * $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): Chingiz Dyussenov, Arystanbek Dyussenov, Jan Diederich, Tod Liverseed, + * Nathan Letwory + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include <string> + +#include "COLLADASWCamera.h" +#include "COLLADASWCameraOptic.h" + +#include "DNA_camera_types.h" + +#include "CameraExporter.h" + +#include "collada_internal.h" + +CamerasExporter::CamerasExporter(COLLADASW::StreamWriter *sw): COLLADASW::LibraryCameras(sw){} + +template<class Functor> +void forEachCameraObjectInScene(Scene *sce, Functor &f) +{ + Base *base= (Base*) sce->base.first; + while(base) { + Object *ob = base->object; + + if (ob->type == OB_CAMERA && ob->data) { + f(ob, sce); + } + base= base->next; + } +} + +void CamerasExporter::exportCameras(Scene *sce) +{ + openLibrary(); + + forEachCameraObjectInScene(sce, *this); + + closeLibrary(); +} +void CamerasExporter::operator()(Object *ob, Scene *sce) +{ + // TODO: shiftx, shifty, YF_dofdist + Camera *cam = (Camera*)ob->data; + std::string cam_id(get_camera_id(ob)); + std::string cam_name(id_name(cam)); + + if (cam->type == CAM_PERSP) { + COLLADASW::PerspectiveOptic persp(mSW); + persp.setXFov(lens_to_angle(cam->lens)*(180.0f/M_PI)); + persp.setAspectRatio(1.0); + persp.setZFar(cam->clipend); + persp.setZNear(cam->clipsta); + COLLADASW::Camera ccam(mSW, &persp, cam_id, cam_name); + addCamera(ccam); + } + else { + COLLADASW::OrthographicOptic ortho(mSW); + ortho.setXMag(cam->ortho_scale); + ortho.setAspectRatio(1.0); + ortho.setZFar(cam->clipend); + ortho.setZNear(cam->clipsta); + COLLADASW::Camera ccam(mSW, &ortho, cam_id, cam_name); + addCamera(ccam); + } +} diff --git a/source/blender/collada/CameraExporter.h b/source/blender/collada/CameraExporter.h new file mode 100644 index 00000000000..fd20c934c96 --- /dev/null +++ b/source/blender/collada/CameraExporter.h @@ -0,0 +1,43 @@ +/** + * $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): Chingiz Dyussenov, Arystanbek Dyussenov, Jan Diederich, Tod Liverseed, + * Nathan Letwory + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef __CAMERAEXPORTER_H__ +#define __CAMERAEXPORTER_H__ + +#include "COLLADASWStreamWriter.h" +#include "COLLADASWLibraryCameras.h" + +#include "DNA_object_types.h" +#include "DNA_scene_types.h" + +class CamerasExporter: COLLADASW::LibraryCameras +{ +public: + CamerasExporter(COLLADASW::StreamWriter *sw); + void exportCameras(Scene *sce); + void operator()(Object *ob, Scene *sce); +}; + +#endif diff --git a/source/blender/collada/DocumentExporter.cpp b/source/blender/collada/DocumentExporter.cpp index c2d937f3d43..cbcb3984018 100644 --- a/source/blender/collada/DocumentExporter.cpp +++ b/source/blender/collada/DocumentExporter.cpp @@ -34,8 +34,6 @@ extern "C" #include "DNA_image_types.h" #include "DNA_material_types.h" #include "DNA_texture_types.h" -#include "DNA_camera_types.h" -#include "DNA_lamp_types.h" #include "DNA_anim_types.h" #include "DNA_action_types.h" #include "DNA_curve_types.h" @@ -74,7 +72,6 @@ extern char build_rev[]; #include "COLLADASWAsset.h" #include "COLLADASWLibraryVisualScenes.h" #include "COLLADASWNode.h" -#include "COLLADASWLibraryGeometries.h" #include "COLLADASWSource.h" #include "COLLADASWInstanceGeometry.h" #include "COLLADASWInputList.h" @@ -91,16 +88,12 @@ extern char build_rev[]; #include "COLLADASWSurfaceInitOption.h" #include "COLLADASWSampler.h" #include "COLLADASWScene.h" -//#include "COLLADASWSurface.h" #include "COLLADASWTechnique.h" #include "COLLADASWTexture.h" #include "COLLADASWLibraryMaterials.h" #include "COLLADASWBindMaterial.h" -#include "COLLADASWLibraryCameras.h" -#include "COLLADASWLibraryLights.h" #include "COLLADASWInstanceCamera.h" #include "COLLADASWInstanceLight.h" -#include "COLLADASWCameraOptic.h" #include "COLLADASWConstants.h" #include "COLLADASWLibraryControllers.h" #include "COLLADASWInstanceController.h" @@ -109,35 +102,22 @@ extern char build_rev[]; #include "collada_internal.h" #include "DocumentExporter.h" +// can probably go after refactor is complete +#include "InstanceWriter.h" +#include "TransformWriter.h" + +#include "ArmatureExporter.h" +#include "CameraExporter.h" +#include "EffectExporter.h" +#include "GeometryExporter.h" +#include "ImageExporter.h" +#include "LightExporter.h" +#include "MaterialExporter.h" + #include <vector> #include <algorithm> // std::find -// arithb.c now has QuatToAxisAngle too -#if 0 -// This function assumes that quat is normalized. -// The following document was used as reference: -// http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToAngle/index.htm -void quat_to_axis_angle( float *axis, float *angle,float *q) -{ - // quat to axis angle - *angle = 2 * acos(q[0]); - float divisor = sqrt(1 - q[0] * q[0]); - - // test to avoid divide by zero, divisor is always positive - if (divisor < 0.001f ) { - axis[0] = 1.0f; - axis[1] = 0.0f; - axis[2] = 0.0f; - } - else { - axis[0] = q[1] / divisor; - axis[1] = q[2] / divisor; - axis[2] = q[3] / divisor; - } -} -#endif - -char *CustomData_get_layer_name(const struct CustomData *data, int type, int n) +char *bc_CustomData_get_layer_name(const struct CustomData *data, int type, int n) { int layer_index = CustomData_get_layer_index(data, type); if(layer_index < 0) return NULL; @@ -145,7 +125,7 @@ char *CustomData_get_layer_name(const struct CustomData *data, int type, int n) return data->layers[layer_index+n].name; } -char *CustomData_get_active_layer_name(const CustomData *data, int type) +char *bc_CustomData_get_active_layer_name(const CustomData *data, int type) { /* get the layer index of the active layer of type */ int layer_index = CustomData_get_active_layer_index(data, type); @@ -154,185 +134,12 @@ char *CustomData_get_active_layer_name(const CustomData *data, int type) return data->layers[layer_index].name; } -/** -Translation map. -Used to translate every COLLADA id to a valid id, no matter what "wrong" letters may be -included. Look at the IDREF XSD declaration for more. -Follows strictly the COLLADA XSD declaration which explicitly allows non-english chars, -like special chars (e.g. micro sign), umlauts and so on. -The COLLADA spec also allows additional chars for member access ('.'), these -must obviously be removed too, otherwise they would be heavily misinterpreted. -*/ -const unsigned char translate_start_name_map[256] = { -95, 95, 95, 95, 95, 95, 95, 95, 95, -95, 95, 95, 95, 95, 95, 95, 95, -95, 95, 95, 95, 95, 95, 95, 95, -95, 95, 95, 95, 95, 95, 95, 95, -95, 95, 95, 95, 95, 95, 95, 95, -95, 95, 95, 95, 95, 95, 95, 95, -95, 95, 95, 95, 95, 95, 95, 95, -95, 95, 95, 95, 95, 95, 95, 95, -65, 66, 67, 68, 69, 70, 71, 72, -73, 74, 75, 76, 77, 78, 79, 80, -81, 82, 83, 84, 85, 86, 87, 88, -89, 90, 95, 95, 95, 95, 95, 95, -97, 98, 99, 100, 101, 102, 103, 104, -105, 106, 107, 108, 109, 110, 111, 112, -113, 114, 115, 116, 117, 118, 119, 120, -121, 122, 95, 95, 95, 95, 95, 95, -95, 95, 95, 95, 95, 95, 95, 95, -95, 95, 95, 95, 95, 95, 95, 95, -95, 95, 95, 95, 95, 95, 95, 95, -95, 95, 95, 95, 95, 95, 95, 95, -95, 95, 95, 95, 95, 95, 95, 95, -95, 95, 95, 95, 95, 95, 95, 95, -95, 95, 95, 95, 95, 95, 95, 95, -95, 95, 95, 95, 95, 95, 95, 192, -193, 194, 195, 196, 197, 198, 199, 200, -201, 202, 203, 204, 205, 206, 207, 208, -209, 210, 211, 212, 213, 214, 95, 216, -217, 218, 219, 220, 221, 222, 223, 224, -225, 226, 227, 228, 229, 230, 231, 232, -233, 234, 235, 236, 237, 238, 239, 240, -241, 242, 243, 244, 245, 246, 95, 248, -249, 250, 251, 252, 253, 254, 255}; - -const unsigned char translate_name_map[256] = { -95, 95, 95, 95, 95, 95, 95, 95, 95, -95, 95, 95, 95, 95, 95, 95, 95, -95, 95, 95, 95, 95, 95, 95, 95, -95, 95, 95, 95, 95, 95, 95, 95, -95, 95, 95, 95, 95, 95, 95, 95, -95, 95, 95, 95, 45, 95, 95, 48, -49, 50, 51, 52, 53, 54, 55, 56, -57, 95, 95, 95, 95, 95, 95, 95, -65, 66, 67, 68, 69, 70, 71, 72, -73, 74, 75, 76, 77, 78, 79, 80, -81, 82, 83, 84, 85, 86, 87, 88, -89, 90, 95, 95, 95, 95, 95, 95, -97, 98, 99, 100, 101, 102, 103, 104, -105, 106, 107, 108, 109, 110, 111, 112, -113, 114, 115, 116, 117, 118, 119, 120, -121, 122, 95, 95, 95, 95, 95, 95, -95, 95, 95, 95, 95, 95, 95, 95, -95, 95, 95, 95, 95, 95, 95, 95, -95, 95, 95, 95, 95, 95, 95, 95, -95, 95, 95, 95, 95, 95, 95, 95, -95, 95, 95, 95, 95, 95, 95, 95, -95, 95, 95, 95, 95, 95, 95, 95, -95, 95, 95, 95, 95, 95, 183, 95, -95, 95, 95, 95, 95, 95, 95, 192, -193, 194, 195, 196, 197, 198, 199, 200, -201, 202, 203, 204, 205, 206, 207, 208, -209, 210, 211, 212, 213, 214, 95, 216, -217, 218, 219, 220, 221, 222, 223, 224, -225, 226, 227, 228, 229, 230, 231, 232, -233, 234, 235, 236, 237, 238, 239, 240, -241, 242, 243, 244, 245, 246, 95, 248, -249, 250, 251, 252, 253, 254, 255}; - -typedef std::map< std::string, std::vector<std::string> > map_string_list; -map_string_list global_id_map; - -/** Look at documentation of translate_map */ -static std::string translate_id(const std::string &id) -{ - if (id.size() == 0) - { return id; } - std::string id_translated = id; - id_translated[0] = translate_start_name_map[(unsigned int)id_translated[0]]; - for (unsigned int i=1; i < id_translated.size(); i++) - { - id_translated[i] = translate_name_map[(unsigned int)id_translated[i]]; - } - // It's so much workload now, the if() should speed up things. - if (id_translated != id) - { - // Search duplicates - map_string_list::iterator iter = global_id_map.find(id_translated); - if (iter != global_id_map.end()) - { - unsigned int i = 0; - bool found = false; - for (i=0; i < iter->second.size(); i++) - { - if (id == iter->second[i]) - { - found = true; - break; - } - } - bool convert = false; - if (found) - { - if (i > 0) - { convert = true; } - } - else - { - convert = true; - global_id_map[id_translated].push_back(id); - } - if (convert) - { - std::stringstream out; - out << ++i; - id_translated += out.str(); - } - } - else { global_id_map[id_translated].push_back(id); } - } - return id_translated; -} - -static std::string id_name(void *id) -{ - return ((ID*)id)->name + 2; -} - -static std::string get_geometry_id(Object *ob) -{ - return translate_id(id_name(ob)) + "-mesh"; -} - -static std::string get_light_id(Object *ob) -{ - return translate_id(id_name(ob)) + "-light"; -} - -static std::string get_camera_id(Object *ob) -{ - return translate_id(id_name(ob)) + "-camera"; -} - -std::string get_joint_id(Bone *bone, Object *ob_arm) -{ - return translate_id(id_name(ob_arm) + "_" + bone->name); -} - /* Utilities to avoid code duplication. Definition can take some time to understand, but they should be useful. */ -// f should have -// void operator()(Object* ob) -template<class Functor> -void forEachMeshObjectInScene(Scene *sce, Functor &f) -{ - - Base *base= (Base*) sce->base.first; - while(base) { - Object *ob = base->object; - - if (ob->type == OB_MESH && ob->data) { - f(ob); - } - base= base->next; - - } -} template<class Functor> void forEachObjectInScene(Scene *sce, Functor &f) @@ -347,1078 +154,7 @@ void forEachObjectInScene(Scene *sce, Functor &f) } } -template<class Functor> -void forEachCameraObjectInScene(Scene *sce, Functor &f) -{ - Base *base= (Base*) sce->base.first; - while(base) { - Object *ob = base->object; - - if (ob->type == OB_CAMERA && ob->data) { - f(ob, sce); - } - base= base->next; - } -} - -template<class Functor> -void forEachLampObjectInScene(Scene *sce, Functor &f) -{ - Base *base= (Base*) sce->base.first; - while(base) { - Object *ob = base->object; - - if (ob->type == OB_LAMP && ob->data) { - f(ob); - } - base= base->next; - } -} - -// used in forEachMaterialInScene -template <class MaterialFunctor> -class ForEachMaterialFunctor -{ - std::vector<std::string> mMat; // contains list of material names, to avoid duplicate calling of f - MaterialFunctor *f; -public: - ForEachMaterialFunctor(MaterialFunctor *f) : f(f) { } - void operator ()(Object *ob) - { - int a; - for(a = 0; a < ob->totcol; a++) { - - Material *ma = give_current_material(ob, a+1); - - if (!ma) continue; - - std::string translated_id = translate_id(id_name(ma)); - if (find(mMat.begin(), mMat.end(), translated_id) == mMat.end()) { - (*this->f)(ma, ob); - - mMat.push_back(translated_id); - } - } - } -}; - -// calls f for each unique material linked to each object in sce -// f should have -// void operator()(Material* ma) -template<class Functor> -void forEachMaterialInScene(Scene *sce, Functor &f) -{ - ForEachMaterialFunctor<Functor> matfunc(&f); - forEachMeshObjectInScene(sce, matfunc); -} - -// OB_MESH is assumed -std::string getActiveUVLayerName(Object *ob) -{ - Mesh *me = (Mesh*)ob->data; - - int num_layers = CustomData_number_of_layers(&me->fdata, CD_MTFACE); - if (num_layers) - return std::string(CustomData_get_active_layer_name(&me->fdata, CD_MTFACE)); - - return ""; -} - -// TODO: optimize UV sets by making indexed list with duplicates removed -class GeometryExporter : COLLADASW::LibraryGeometries -{ - struct Face - { - unsigned int v1, v2, v3, v4; - }; - - struct Normal - { - float x, y, z; - }; - - Scene *mScene; - -public: - GeometryExporter(COLLADASW::StreamWriter *sw) : COLLADASW::LibraryGeometries(sw) {} - - void exportGeom(Scene *sce) - { - openLibrary(); - - mScene = sce; - forEachMeshObjectInScene(sce, *this); - - closeLibrary(); - } - - void operator()(Object *ob) - { - // XXX don't use DerivedMesh, Mesh instead? - -#if 0 - DerivedMesh *dm = mesh_get_derived_final(mScene, ob, CD_MASK_BAREMESH); -#endif - Mesh *me = (Mesh*)ob->data; - std::string geom_id = get_geometry_id(ob); - std::vector<Normal> nor; - std::vector<Face> norind; - - bool has_color = (bool)CustomData_has_layer(&me->fdata, CD_MCOL); - - create_normals(nor, norind, me); - - // openMesh(geoId, geoName, meshId) - openMesh(geom_id); - - // writes <source> for vertex coords - createVertsSource(geom_id, me); - - // writes <source> for normal coords - createNormalsSource(geom_id, me, nor); - - bool has_uvs = (bool)CustomData_has_layer(&me->fdata, CD_MTFACE); - - // writes <source> for uv coords if mesh has uv coords - if (has_uvs) - createTexcoordsSource(geom_id, me); - - if (has_color) - createVertexColorSource(geom_id, me); - - // <vertices> - COLLADASW::Vertices verts(mSW); - verts.setId(getIdBySemantics(geom_id, COLLADASW::VERTEX)); - COLLADASW::InputList &input_list = verts.getInputList(); - COLLADASW::Input input(COLLADASW::POSITION, getUrlBySemantics(geom_id, COLLADASW::POSITION)); - input_list.push_back(input); - verts.add(); - - // XXX slow - if (ob->totcol) { - for(int a = 0; a < ob->totcol; a++) { - // account for NULL materials, this should not normally happen? - Material *ma = give_current_material(ob, a + 1); - createPolylist(ma != NULL, a, has_uvs, has_color, ob, geom_id, norind); - } - } - else { - createPolylist(false, 0, has_uvs, has_color, ob, geom_id, norind); - } - - closeMesh(); - closeGeometry(); - -#if 0 - dm->release(dm); -#endif - } - - // powerful because it handles both cases when there is material and when there's not - void createPolylist(bool has_material, - int material_index, - bool has_uvs, - bool has_color, - Object *ob, - std::string& geom_id, - std::vector<Face>& norind) - { - Mesh *me = (Mesh*)ob->data; - MFace *mfaces = me->mface; - int totfaces = me->totface; - - // <vcount> - int i; - int faces_in_polylist = 0; - std::vector<unsigned long> vcount_list; - - // count faces with this material - for (i = 0; i < totfaces; i++) { - MFace *f = &mfaces[i]; - - if ((has_material && f->mat_nr == material_index) || !has_material) { - faces_in_polylist++; - if (f->v4 == 0) { - vcount_list.push_back(3); - } - else { - vcount_list.push_back(4); - } - } - } - - // no faces using this material - if (faces_in_polylist == 0) { - return; - } - - Material *ma = has_material ? give_current_material(ob, material_index + 1) : NULL; - COLLADASW::Polylist polylist(mSW); - - // sets count attribute in <polylist> - polylist.setCount(faces_in_polylist); - - // sets material name - if (has_material) { - polylist.setMaterial(translate_id(id_name(ma))); - } - - COLLADASW::InputList &til = polylist.getInputList(); - - // creates <input> in <polylist> for vertices - COLLADASW::Input input1(COLLADASW::VERTEX, getUrlBySemantics(geom_id, COLLADASW::VERTEX), 0); - - // creates <input> in <polylist> for normals - COLLADASW::Input input2(COLLADASW::NORMAL, getUrlBySemantics(geom_id, COLLADASW::NORMAL), 1); - - til.push_back(input1); - til.push_back(input2); - - // if mesh has uv coords writes <input> for TEXCOORD - int num_layers = CustomData_number_of_layers(&me->fdata, CD_MTFACE); - - for (i = 0; i < num_layers; i++) { - // char *name = CustomData_get_layer_name(&me->fdata, CD_MTFACE, i); - COLLADASW::Input input3(COLLADASW::TEXCOORD, - makeUrl(makeTexcoordSourceId(geom_id, i)), - 2, // offset always 2, this is only until we have optimized UV sets - i // set number equals UV layer index - ); - til.push_back(input3); - } - - if (has_color) { - COLLADASW::Input input4(COLLADASW::COLOR, getUrlBySemantics(geom_id, COLLADASW::COLOR), has_uvs ? 3 : 2); - til.push_back(input4); - } - - // sets <vcount> - polylist.setVCountList(vcount_list); - - // performs the actual writing - polylist.prepareToAppendValues(); - - // <p> - int texindex = 0; - for (i = 0; i < totfaces; i++) { - MFace *f = &mfaces[i]; - - if ((has_material && f->mat_nr == material_index) || !has_material) { - - unsigned int *v = &f->v1; - unsigned int *n = &norind[i].v1; - for (int j = 0; j < (f->v4 == 0 ? 3 : 4); j++) { - polylist.appendValues(v[j]); - polylist.appendValues(n[j]); - - if (has_uvs) - polylist.appendValues(texindex + j); - - if (has_color) - polylist.appendValues(texindex + j); - } - } - - texindex += 3; - if (f->v4 != 0) - texindex++; - } - - polylist.finish(); - } - - // creates <source> for positions - void createVertsSource(std::string geom_id, Mesh *me) - { -#if 0 - int totverts = dm->getNumVerts(dm); - MVert *verts = dm->getVertArray(dm); -#endif - int totverts = me->totvert; - MVert *verts = me->mvert; - - COLLADASW::FloatSourceF source(mSW); - source.setId(getIdBySemantics(geom_id, COLLADASW::POSITION)); - source.setArrayId(getIdBySemantics(geom_id, COLLADASW::POSITION) + - ARRAY_ID_SUFFIX); - source.setAccessorCount(totverts); - source.setAccessorStride(3); - COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList(); - param.push_back("X"); - param.push_back("Y"); - param.push_back("Z"); - /*main function, it creates <source id = "">, <float_array id = "" - count = ""> */ - source.prepareToAppendValues(); - //appends data to <float_array> - int i = 0; - for (i = 0; i < totverts; i++) { - source.appendValues(verts[i].co[0], verts[i].co[1], verts[i].co[2]); - } - - source.finish(); - - } - - void createVertexColorSource(std::string geom_id, Mesh *me) - { - if (!CustomData_has_layer(&me->fdata, CD_MCOL)) - return; - - MFace *f; - int totcolor = 0, i, j; - - for (i = 0, f = me->mface; i < me->totface; i++, f++) - totcolor += f->v4 ? 4 : 3; - - COLLADASW::FloatSourceF source(mSW); - source.setId(getIdBySemantics(geom_id, COLLADASW::COLOR)); - source.setArrayId(getIdBySemantics(geom_id, COLLADASW::COLOR) + ARRAY_ID_SUFFIX); - source.setAccessorCount(totcolor); - source.setAccessorStride(3); - - COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList(); - param.push_back("R"); - param.push_back("G"); - param.push_back("B"); - - source.prepareToAppendValues(); - - int index = CustomData_get_active_layer_index(&me->fdata, CD_MCOL); - - MCol *mcol = (MCol*)me->fdata.layers[index].data; - MCol *c = mcol; - - for (i = 0, f = me->mface; i < me->totface; i++, c += 4, f++) - for (j = 0; j < (f->v4 ? 4 : 3); j++) - source.appendValues(c[j].b / 255.0f, c[j].g / 255.0f, c[j].r / 255.0f); - - source.finish(); - } - - std::string makeTexcoordSourceId(std::string& geom_id, int layer_index) - { - char suffix[20]; - sprintf(suffix, "-%d", layer_index); - return getIdBySemantics(geom_id, COLLADASW::TEXCOORD) + suffix; - } - - //creates <source> for texcoords - void createTexcoordsSource(std::string geom_id, Mesh *me) - { -#if 0 - int totfaces = dm->getNumFaces(dm); - MFace *mfaces = dm->getFaceArray(dm); -#endif - int totfaces = me->totface; - MFace *mfaces = me->mface; - - int totuv = 0; - int i; - - // count totuv - for (i = 0; i < totfaces; i++) { - MFace *f = &mfaces[i]; - if (f->v4 == 0) { - totuv+=3; - } - else { - totuv+=4; - } - } - - int num_layers = CustomData_number_of_layers(&me->fdata, CD_MTFACE); - // write <source> for each layer - // each <source> will get id like meshName + "map-channel-1" - for (int a = 0; a < num_layers; a++) { - MTFace *tface = (MTFace*)CustomData_get_layer_n(&me->fdata, CD_MTFACE, a); - // char *name = CustomData_get_layer_name(&me->fdata, CD_MTFACE, a); - - COLLADASW::FloatSourceF source(mSW); - std::string layer_id = makeTexcoordSourceId(geom_id, a); - source.setId(layer_id); - source.setArrayId(layer_id + ARRAY_ID_SUFFIX); - - source.setAccessorCount(totuv); - source.setAccessorStride(2); - COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList(); - param.push_back("S"); - param.push_back("T"); - - source.prepareToAppendValues(); - - for (i = 0; i < totfaces; i++) { - MFace *f = &mfaces[i]; - - for (int j = 0; j < (f->v4 == 0 ? 3 : 4); j++) { - source.appendValues(tface[i].uv[j][0], - tface[i].uv[j][1]); - } - } - - source.finish(); - } - } - - - //creates <source> for normals - void createNormalsSource(std::string geom_id, Mesh *me, std::vector<Normal>& nor) - { -#if 0 - int totverts = dm->getNumVerts(dm); - MVert *verts = dm->getVertArray(dm); -#endif - - COLLADASW::FloatSourceF source(mSW); - source.setId(getIdBySemantics(geom_id, COLLADASW::NORMAL)); - source.setArrayId(getIdBySemantics(geom_id, COLLADASW::NORMAL) + - ARRAY_ID_SUFFIX); - source.setAccessorCount(nor.size()); - source.setAccessorStride(3); - COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList(); - param.push_back("X"); - param.push_back("Y"); - param.push_back("Z"); - - source.prepareToAppendValues(); - - std::vector<Normal>::iterator it; - for (it = nor.begin(); it != nor.end(); it++) { - Normal& n = *it; - source.appendValues(n.x, n.y, n.z); - } - - source.finish(); - } - - void create_normals(std::vector<Normal> &nor, std::vector<Face> &ind, Mesh *me) - { - int i, j, v; - MVert *vert = me->mvert; - std::map<unsigned int, unsigned int> nshar; - - for (i = 0; i < me->totface; i++) { - MFace *fa = &me->mface[i]; - Face f; - unsigned int *nn = &f.v1; - unsigned int *vv = &fa->v1; - - memset(&f, 0, sizeof(f)); - v = fa->v4 == 0 ? 3 : 4; - - if (!(fa->flag & ME_SMOOTH)) { - Normal n; - if (v == 4) - normal_quad_v3(&n.x, vert[fa->v1].co, vert[fa->v2].co, vert[fa->v3].co, vert[fa->v4].co); - else - normal_tri_v3(&n.x, vert[fa->v1].co, vert[fa->v2].co, vert[fa->v3].co); - nor.push_back(n); - } - - for (j = 0; j < v; j++) { - if (fa->flag & ME_SMOOTH) { - if (nshar.find(*vv) != nshar.end()) - *nn = nshar[*vv]; - else { - Normal n = { - vert[*vv].no[0]/32767.0, - vert[*vv].no[1]/32767.0, - vert[*vv].no[2]/32767.0 - }; - nor.push_back(n); - *nn = nor.size() - 1; - nshar[*vv] = *nn; - } - vv++; - } - else { - *nn = nor.size() - 1; - } - nn++; - } - - ind.push_back(f); - } - } - - std::string getIdBySemantics(std::string geom_id, COLLADASW::Semantics type, std::string other_suffix = "") { - return geom_id + getSuffixBySemantic(type) + other_suffix; - } - - - COLLADASW::URI getUrlBySemantics(std::string geom_id, COLLADASW::Semantics type, std::string other_suffix = "") { - - std::string id(getIdBySemantics(geom_id, type, other_suffix)); - return COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, id); - - } - - COLLADASW::URI makeUrl(std::string id) - { - return COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, id); - } - - - /* int getTriCount(MFace *faces, int totface) { - int i; - int tris = 0; - for (i = 0; i < totface; i++) { - // if quad - if (faces[i].v4 != 0) - tris += 2; - else - tris++; - } - - return tris; - }*/ -}; - -class TransformWriter : protected TransformBase -{ -protected: - void add_node_transform(COLLADASW::Node& node, float mat[][4], float parent_mat[][4]) - { - float loc[3], rot[3], scale[3]; - float local[4][4]; - - if (parent_mat) { - float invpar[4][4]; - invert_m4_m4(invpar, parent_mat); - mul_m4_m4m4(local, mat, invpar); - } - else { - copy_m4_m4(local, mat); - } - - TransformBase::decompose(local, loc, rot, NULL, scale); - - add_transform(node, loc, rot, scale); - } - - void add_node_transform_ob(COLLADASW::Node& node, Object *ob) - { - float rot[3], loc[3], scale[3]; - - if (ob->parent) { - float C[4][4], tmat[4][4], imat[4][4], mat[4][4]; - - // factor out scale from obmat - - copy_v3_v3(scale, ob->size); - - ob->size[0] = ob->size[1] = ob->size[2] = 1.0f; - object_to_mat4(ob, C); - copy_v3_v3(ob->size, scale); - - mul_serie_m4(tmat, ob->parent->obmat, ob->parentinv, C, NULL, NULL, NULL, NULL, NULL); - - // calculate local mat - - invert_m4_m4(imat, ob->parent->obmat); - mul_m4_m4m4(mat, tmat, imat); - - // done - - mat4_to_eul(rot, mat); - copy_v3_v3(loc, mat[3]); - } - else { - copy_v3_v3(loc, ob->loc); - copy_v3_v3(rot, ob->rot); - copy_v3_v3(scale, ob->size); - } - - add_transform(node, loc, rot, scale); - } - - void add_node_transform_identity(COLLADASW::Node& node) - { - float loc[] = {0.0f, 0.0f, 0.0f}, scale[] = {1.0f, 1.0f, 1.0f}, rot[] = {0.0f, 0.0f, 0.0f}; - add_transform(node, loc, rot, scale); - } - -private: - void add_transform(COLLADASW::Node& node, float loc[3], float rot[3], float scale[3]) - { - node.addTranslate("location", loc[0], loc[1], loc[2]); - node.addRotateZ("rotationZ", COLLADABU::Math::Utils::radToDegF(rot[2])); - node.addRotateY("rotationY", COLLADABU::Math::Utils::radToDegF(rot[1])); - node.addRotateX("rotationX", COLLADABU::Math::Utils::radToDegF(rot[0])); - node.addScale("scale", scale[0], scale[1], scale[2]); - } -}; - -class InstanceWriter -{ -protected: - void add_material_bindings(COLLADASW::BindMaterial& bind_material, Object *ob) - { - for(int a = 0; a < ob->totcol; a++) { - Material *ma = give_current_material(ob, a+1); - - COLLADASW::InstanceMaterialList& iml = bind_material.getInstanceMaterialList(); - - if (ma) { - std::string matid(id_name(ma)); - matid = translate_id(matid); - COLLADASW::InstanceMaterial im(matid, COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, matid)); - - // create <bind_vertex_input> for each uv layer - Mesh *me = (Mesh*)ob->data; - int totlayer = CustomData_number_of_layers(&me->fdata, CD_MTFACE); - - for (int b = 0; b < totlayer; b++) { - char *name = CustomData_get_layer_name(&me->fdata, CD_MTFACE, b); - im.push_back(COLLADASW::BindVertexInput(name, "TEXCOORD", b)); - } - - iml.push_back(im); - } - } - } -}; - -// XXX exporter writes wrong data for shared armatures. A separate -// controller should be written for each armature-mesh binding how do -// we make controller ids then? -class ArmatureExporter: public COLLADASW::LibraryControllers, protected TransformWriter, protected InstanceWriter -{ -private: - Scene *scene; - -public: - ArmatureExporter(COLLADASW::StreamWriter *sw) : COLLADASW::LibraryControllers(sw) {} - - // write bone nodes - void add_armature_bones(Object *ob_arm, Scene *sce) - { - // write bone nodes - bArmature *arm = (bArmature*)ob_arm->data; - for (Bone *bone = (Bone*)arm->bonebase.first; bone; bone = bone->next) { - // start from root bones - if (!bone->parent) - add_bone_node(bone, ob_arm); - } - } - - bool is_skinned_mesh(Object *ob) - { - return get_assigned_armature(ob) != NULL; - } - - void add_instance_controller(Object *ob) - { - Object *ob_arm = get_assigned_armature(ob); - bArmature *arm = (bArmature*)ob_arm->data; - - const std::string& controller_id = get_controller_id(ob_arm, ob); - - COLLADASW::InstanceController ins(mSW); - ins.setUrl(COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, controller_id)); - - // write root bone URLs - Bone *bone; - for (bone = (Bone*)arm->bonebase.first; bone; bone = bone->next) { - if (!bone->parent) - ins.addSkeleton(COLLADABU::URI(COLLADABU::Utils::EMPTY_STRING, get_joint_id(bone, ob_arm))); - } - - InstanceWriter::add_material_bindings(ins.getBindMaterial(), ob); - - ins.add(); - } - - void export_controllers(Scene *sce) - { - scene = sce; - - openLibrary(); - - forEachMeshObjectInScene(sce, *this); - - closeLibrary(); - } - - void operator()(Object *ob) - { - Object *ob_arm = get_assigned_armature(ob); - - if (ob_arm /*&& !already_written(ob_arm)*/) - export_controller(ob, ob_arm); - } - -private: - - UnitConverter converter; - -#if 0 - std::vector<Object*> written_armatures; - - bool already_written(Object *ob_arm) - { - return std::find(written_armatures.begin(), written_armatures.end(), ob_arm) != written_armatures.end(); - } - - void wrote(Object *ob_arm) - { - written_armatures.push_back(ob_arm); - } - - void find_objects_using_armature(Object *ob_arm, std::vector<Object *>& objects, Scene *sce) - { - objects.clear(); - - Base *base= (Base*) sce->base.first; - while(base) { - Object *ob = base->object; - - if (ob->type == OB_MESH && get_assigned_armature(ob) == ob_arm) { - objects.push_back(ob); - } - - base= base->next; - } - } -#endif - - Object *get_assigned_armature(Object *ob) - { - Object *ob_arm = NULL; - - if (ob->parent && ob->partype == PARSKEL && ob->parent->type == OB_ARMATURE) { - ob_arm = ob->parent; - } - else { - ModifierData *mod = (ModifierData*)ob->modifiers.first; - while (mod) { - if (mod->type == eModifierType_Armature) { - ob_arm = ((ArmatureModifierData*)mod)->object; - } - - mod = mod->next; - } - } - - return ob_arm; - } - - std::string get_joint_sid(Bone *bone, Object *ob_arm) - { - return get_joint_id(bone, ob_arm); - } - - // parent_mat is armature-space - void add_bone_node(Bone *bone, Object *ob_arm) - { - std::string node_id = get_joint_id(bone, ob_arm); - std::string node_name = std::string(bone->name); - std::string node_sid = get_joint_sid(bone, ob_arm); - - COLLADASW::Node node(mSW); - - node.setType(COLLADASW::Node::JOINT); - node.setNodeId(node_id); - node.setNodeName(node_name); - node.setNodeSid(node_sid); - - node.start(); - - add_bone_transform(ob_arm, bone, node); - - for (Bone *child = (Bone*)bone->childbase.first; child; child = child->next) { - add_bone_node(child, ob_arm); - } - - node.end(); - } - - void add_bone_transform(Object *ob_arm, Bone *bone, COLLADASW::Node& node) - { - bPoseChannel *pchan = get_pose_channel(ob_arm->pose, bone->name); - - float mat[4][4]; - - if (bone->parent) { - // get bone-space matrix from armature-space - bPoseChannel *parchan = get_pose_channel(ob_arm->pose, bone->parent->name); - - float invpar[4][4]; - invert_m4_m4(invpar, parchan->pose_mat); - mul_m4_m4m4(mat, pchan->pose_mat, invpar); - } - else { - // get world-space from armature-space - mul_m4_m4m4(mat, pchan->pose_mat, ob_arm->obmat); - } - - TransformWriter::add_node_transform(node, mat, NULL); - } - - std::string get_controller_id(Object *ob_arm, Object *ob) - { - return translate_id(id_name(ob_arm)) + "_" + translate_id(id_name(ob)) + SKIN_CONTROLLER_ID_SUFFIX; - } - - // ob should be of type OB_MESH - // both args are required - void export_controller(Object* ob, Object *ob_arm) - { - // joint names - // joint inverse bind matrices - // vertex weights - - // input: - // joint names: ob -> vertex group names - // vertex group weights: me->dvert -> groups -> index, weight - - /* - me->dvert: - - typedef struct MDeformVert { - struct MDeformWeight *dw; - int totweight; - int flag; // flag only in use for weightpaint now - } MDeformVert; - - typedef struct MDeformWeight { - int def_nr; - float weight; - } MDeformWeight; - */ - - Mesh *me = (Mesh*)ob->data; - if (!me->dvert) return; - - std::string controller_name = id_name(ob_arm); - std::string controller_id = get_controller_id(ob_arm, ob); - - openSkin(controller_id, controller_name, - COLLADABU::URI(COLLADABU::Utils::EMPTY_STRING, get_geometry_id(ob))); - - add_bind_shape_mat(ob); - - std::string joints_source_id = add_joints_source(ob_arm, &ob->defbase, controller_id); - std::string inv_bind_mat_source_id = add_inv_bind_mats_source(ob_arm, &ob->defbase, controller_id); - std::string weights_source_id = add_weights_source(me, controller_id); - - add_joints_element(&ob->defbase, joints_source_id, inv_bind_mat_source_id); - add_vertex_weights_element(weights_source_id, joints_source_id, me, ob_arm, &ob->defbase); - - closeSkin(); - closeController(); - } - - void add_joints_element(ListBase *defbase, - const std::string& joints_source_id, const std::string& inv_bind_mat_source_id) - { - COLLADASW::JointsElement joints(mSW); - COLLADASW::InputList &input = joints.getInputList(); - - input.push_back(COLLADASW::Input(COLLADASW::JOINT, // constant declared in COLLADASWInputList.h - COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, joints_source_id))); - input.push_back(COLLADASW::Input(COLLADASW::BINDMATRIX, - COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, inv_bind_mat_source_id))); - joints.add(); - } - - void add_bind_shape_mat(Object *ob) - { - double bind_mat[4][4]; - - converter.mat4_to_dae_double(bind_mat, ob->obmat); - - addBindShapeTransform(bind_mat); - } - - std::string add_joints_source(Object *ob_arm, ListBase *defbase, const std::string& controller_id) - { - std::string source_id = controller_id + JOINTS_SOURCE_ID_SUFFIX; - - int totjoint = 0; - bDeformGroup *def; - for (def = (bDeformGroup*)defbase->first; def; def = def->next) { - if (is_bone_defgroup(ob_arm, def)) - totjoint++; - } - - COLLADASW::NameSource source(mSW); - source.setId(source_id); - source.setArrayId(source_id + ARRAY_ID_SUFFIX); - source.setAccessorCount(totjoint); - source.setAccessorStride(1); - - COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList(); - param.push_back("JOINT"); - - source.prepareToAppendValues(); - - for (def = (bDeformGroup*)defbase->first; def; def = def->next) { - Bone *bone = get_bone_from_defgroup(ob_arm, def); - if (bone) - source.appendValues(get_joint_sid(bone, ob_arm)); - } - - source.finish(); - - return source_id; - } - - std::string add_inv_bind_mats_source(Object *ob_arm, ListBase *defbase, const std::string& controller_id) - { - std::string source_id = controller_id + BIND_POSES_SOURCE_ID_SUFFIX; - - COLLADASW::FloatSourceF source(mSW); - source.setId(source_id); - source.setArrayId(source_id + ARRAY_ID_SUFFIX); - source.setAccessorCount(BLI_countlist(defbase)); - source.setAccessorStride(16); - - source.setParameterTypeName(&COLLADASW::CSWC::CSW_VALUE_TYPE_FLOAT4x4); - COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList(); - param.push_back("TRANSFORM"); - - source.prepareToAppendValues(); - - bPose *pose = ob_arm->pose; - bArmature *arm = (bArmature*)ob_arm->data; - - int flag = arm->flag; - - // put armature in rest position - if (!(arm->flag & ARM_RESTPOS)) { - arm->flag |= ARM_RESTPOS; - where_is_pose(scene, ob_arm); - } - - for (bDeformGroup *def = (bDeformGroup*)defbase->first; def; def = def->next) { - if (is_bone_defgroup(ob_arm, def)) { - - bPoseChannel *pchan = get_pose_channel(pose, def->name); - - float mat[4][4]; - float world[4][4]; - float inv_bind_mat[4][4]; - - // make world-space matrix, pose_mat is armature-space - mul_m4_m4m4(world, pchan->pose_mat, ob_arm->obmat); - - invert_m4_m4(mat, world); - converter.mat4_to_dae(inv_bind_mat, mat); - - source.appendValues(inv_bind_mat); - } - } - - // back from rest positon - if (!(flag & ARM_RESTPOS)) { - arm->flag = flag; - where_is_pose(scene, ob_arm); - } - - source.finish(); - - return source_id; - } - - Bone *get_bone_from_defgroup(Object *ob_arm, bDeformGroup* def) - { - bPoseChannel *pchan = get_pose_channel(ob_arm->pose, def->name); - return pchan ? pchan->bone : NULL; - } - - bool is_bone_defgroup(Object *ob_arm, bDeformGroup* def) - { - return get_bone_from_defgroup(ob_arm, def) != NULL; - } - - std::string add_weights_source(Mesh *me, const std::string& controller_id) - { - std::string source_id = controller_id + WEIGHTS_SOURCE_ID_SUFFIX; - - int i; - int totweight = 0; - - for (i = 0; i < me->totvert; i++) { - totweight += me->dvert[i].totweight; - } - - COLLADASW::FloatSourceF source(mSW); - source.setId(source_id); - source.setArrayId(source_id + ARRAY_ID_SUFFIX); - source.setAccessorCount(totweight); - source.setAccessorStride(1); - - COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList(); - param.push_back("WEIGHT"); - - source.prepareToAppendValues(); - - // NOTE: COLLADA spec says weights should be normalized - - for (i = 0; i < me->totvert; i++) { - MDeformVert *vert = &me->dvert[i]; - for (int j = 0; j < vert->totweight; j++) { - source.appendValues(vert->dw[j].weight); - } - } - - source.finish(); - - return source_id; - } - - void add_vertex_weights_element(const std::string& weights_source_id, const std::string& joints_source_id, Mesh *me, - Object *ob_arm, ListBase *defbase) - { - COLLADASW::VertexWeightsElement weights(mSW); - COLLADASW::InputList &input = weights.getInputList(); - - int offset = 0; - input.push_back(COLLADASW::Input(COLLADASW::JOINT, // constant declared in COLLADASWInputList.h - COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, joints_source_id), offset++)); - input.push_back(COLLADASW::Input(COLLADASW::WEIGHT, - COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, weights_source_id), offset++)); - - weights.setCount(me->totvert); - - // write number of deformers per vertex - COLLADASW::PrimitivesBase::VCountList vcount; - int i; - for (i = 0; i < me->totvert; i++) { - vcount.push_back(me->dvert[i].totweight); - } - - weights.prepareToAppendVCountValues(); - weights.appendVertexCount(vcount); - - // def group index -> joint index - std::map<int, int> joint_index_by_def_index; - bDeformGroup *def; - int j; - for (def = (bDeformGroup*)defbase->first, i = 0, j = 0; def; def = def->next, i++) { - if (is_bone_defgroup(ob_arm, def)) - joint_index_by_def_index[i] = j++; - else - joint_index_by_def_index[i] = -1; - } - - weights.CloseVCountAndOpenVElement(); - - // write deformer index - weight index pairs - int weight_index = 0; - for (i = 0; i < me->totvert; i++) { - MDeformVert *dvert = &me->dvert[i]; - for (int j = 0; j < dvert->totweight; j++) { - weights.appendValues(joint_index_by_def_index[dvert->dw[j].def_nr]); - weights.appendValues(weight_index++); - } - } - - weights.finish(); - } -}; class SceneExporter: COLLADASW::LibraryVisualScenes, protected TransformWriter, protected InstanceWriter { @@ -1552,453 +288,6 @@ public: } }; -class ImagesExporter: COLLADASW::LibraryImages -{ - const char *mfilename; - std::vector<std::string> mImages; // contains list of written images, to avoid duplicates -public: - ImagesExporter(COLLADASW::StreamWriter *sw, const char* filename) : COLLADASW::LibraryImages(sw), mfilename(filename) - {} - - void exportImages(Scene *sce) - { - openLibrary(); - - forEachMaterialInScene(sce, *this); - - closeLibrary(); - } - - void operator()(Material *ma, Object *ob) - { - int a; - for (a = 0; a < MAX_MTEX; a++) { - MTex *mtex = ma->mtex[a]; - if (mtex && mtex->tex && mtex->tex->ima) { - - Image *image = mtex->tex->ima; - std::string name(id_name(image)); - name = translate_id(name); - char rel[FILE_MAX]; - char abs[FILE_MAX]; - char src[FILE_MAX]; - char dir[FILE_MAX]; - - BLI_split_dirfile(mfilename, dir, NULL); - - BKE_rebase_path(abs, sizeof(abs), rel, sizeof(rel), G.sce, image->name, dir); - - if (abs[0] != '\0') { - - // make absolute source path - BLI_strncpy(src, image->name, sizeof(src)); - BLI_path_abs(src, G.sce); - - // make dest directory if it doesn't exist - BLI_make_existing_file(abs); - - if (BLI_copy_fileops(src, abs) != 0) { - fprintf(stderr, "Cannot copy image to file's directory. \n"); - } - } - - if (find(mImages.begin(), mImages.end(), name) == mImages.end()) { - COLLADASW::Image img(COLLADABU::URI(COLLADABU::URI::nativePathToUri(rel)), name); - img.add(mSW); - - mImages.push_back(name); - } - } - } - } -}; - -class EffectsExporter: COLLADASW::LibraryEffects -{ -public: - EffectsExporter(COLLADASW::StreamWriter *sw) : COLLADASW::LibraryEffects(sw){} - void exportEffects(Scene *sce) - { - openLibrary(); - - forEachMaterialInScene(sce, *this); - - closeLibrary(); - } - - void operator()(Material *ma, Object *ob) - { - // create a list of indices to textures of type TEX_IMAGE - std::vector<int> tex_indices; - createTextureIndices(ma, tex_indices); - - openEffect(translate_id(id_name(ma)) + "-effect"); - - COLLADASW::EffectProfile ep(mSW); - ep.setProfileType(COLLADASW::EffectProfile::COMMON); - ep.openProfile(); - // set shader type - one of three blinn, phong or lambert - if (ma->spec_shader == MA_SPEC_BLINN) { - ep.setShaderType(COLLADASW::EffectProfile::BLINN); - // shininess - ep.setShininess(ma->har); - } - else if (ma->spec_shader == MA_SPEC_PHONG) { - ep.setShaderType(COLLADASW::EffectProfile::PHONG); - // shininess - ep.setShininess(ma->har); - } - else { - // XXX write warning "Current shader type is not supported" - ep.setShaderType(COLLADASW::EffectProfile::LAMBERT); - } - // index of refraction - if (ma->mode & MA_RAYTRANSP) { - ep.setIndexOfRefraction(ma->ang); - } - else { - ep.setIndexOfRefraction(1.0f); - } - - COLLADASW::ColorOrTexture cot; - - // transparency - if (ma->mode & MA_TRANSP) { - // Tod: because we are in A_ONE mode transparency is calculated like this: - ep.setTransparency(ma->alpha); - // cot = getcol(1.0f, 1.0f, 1.0f, 1.0f); - // ep.setTransparent(cot); - } - - // emission - cot=getcol(ma->emit, ma->emit, ma->emit, 1.0f); - ep.setEmission(cot); - - // diffuse multiplied by diffuse intensity - cot = getcol(ma->r * ma->ref, ma->g * ma->ref, ma->b * ma->ref, 1.0f); - ep.setDiffuse(cot); - - // ambient - cot = getcol(ma->ambr, ma->ambg, ma->ambb, 1.0f); - ep.setAmbient(cot); - - // reflective, reflectivity - if (ma->mode & MA_RAYMIRROR) { - cot = getcol(ma->mirr, ma->mirg, ma->mirb, 1.0f); - ep.setReflective(cot); - ep.setReflectivity(ma->ray_mirror); - } - // else { - // cot = getcol(ma->specr, ma->specg, ma->specb, 1.0f); - // ep.setReflective(cot); - // ep.setReflectivity(ma->spec); - // } - - // specular - if (ep.getShaderType() != COLLADASW::EffectProfile::LAMBERT) { - cot = getcol(ma->specr * ma->spec, ma->specg * ma->spec, ma->specb * ma->spec, 1.0f); - ep.setSpecular(cot); - } - - // XXX make this more readable if possible - - // create <sampler> and <surface> for each image - COLLADASW::Sampler samplers[MAX_MTEX]; - //COLLADASW::Surface surfaces[MAX_MTEX]; - //void *samp_surf[MAX_MTEX][2]; - void *samp_surf[MAX_MTEX][1]; - - // image to index to samp_surf map - // samp_surf[index] stores 2 pointers, sampler and surface - std::map<std::string, int> im_samp_map; - - unsigned int a, b; - for (a = 0, b = 0; a < tex_indices.size(); a++) { - MTex *t = ma->mtex[tex_indices[a]]; - Image *ima = t->tex->ima; - - // Image not set for texture - if(!ima) continue; - - std::string key(id_name(ima)); - key = translate_id(key); - - // create only one <sampler>/<surface> pair for each unique image - if (im_samp_map.find(key) == im_samp_map.end()) { - // //<newparam> <surface> <init_from> - // COLLADASW::Surface surface(COLLADASW::Surface::SURFACE_TYPE_2D, - // key + COLLADASW::Surface::SURFACE_SID_SUFFIX); - // COLLADASW::SurfaceInitOption sio(COLLADASW::SurfaceInitOption::INIT_FROM); - // sio.setImageReference(key); - // surface.setInitOption(sio); - - // COLLADASW::NewParamSurface surface(mSW); - // surface->setParamType(COLLADASW::CSW_SURFACE_TYPE_2D); - - //<newparam> <sampler> <source> - COLLADASW::Sampler sampler(COLLADASW::Sampler::SAMPLER_TYPE_2D, - key + COLLADASW::Sampler::SAMPLER_SID_SUFFIX, - key + COLLADASW::Sampler::SURFACE_SID_SUFFIX); - sampler.setImageId(key); - // copy values to arrays since they will live longer - samplers[a] = sampler; - //surfaces[a] = surface; - - // store pointers so they can be used later when we create <texture>s - samp_surf[b][0] = &samplers[a]; - //samp_surf[b][1] = &surfaces[a]; - - im_samp_map[key] = b; - b++; - } - } - - // used as fallback when MTex->uvname is "" (this is pretty common) - // it is indeed the correct value to use in that case - std::string active_uv(getActiveUVLayerName(ob)); - - // write textures - // XXX very slow - for (a = 0; a < tex_indices.size(); a++) { - MTex *t = ma->mtex[tex_indices[a]]; - Image *ima = t->tex->ima; - - // Image not set for texture - if(!ima) continue; - - // we assume map input is always TEXCO_UV - - std::string key(id_name(ima)); - key = translate_id(key); - int i = im_samp_map[key]; - COLLADASW::Sampler *sampler = (COLLADASW::Sampler*)samp_surf[i][0]; - //COLLADASW::Surface *surface = (COLLADASW::Surface*)samp_surf[i][1]; - - std::string uvname = strlen(t->uvname) ? t->uvname : active_uv; - - // color - if (t->mapto & MAP_COL) { - ep.setDiffuse(createTexture(ima, uvname, sampler)); - } - // ambient - if (t->mapto & MAP_AMB) { - ep.setAmbient(createTexture(ima, uvname, sampler)); - } - // specular - if (t->mapto & MAP_SPEC) { - ep.setSpecular(createTexture(ima, uvname, sampler)); - } - // emission - if (t->mapto & MAP_EMIT) { - ep.setEmission(createTexture(ima, uvname, sampler)); - } - // reflective - if (t->mapto & MAP_REF) { - ep.setReflective(createTexture(ima, uvname, sampler)); - } - // alpha - if (t->mapto & MAP_ALPHA) { - ep.setTransparent(createTexture(ima, uvname, sampler)); - } - // extension: - // Normal map --> Must be stored with <extra> tag as different technique, - // since COLLADA doesn't support normal maps, even in current COLLADA 1.5. - if (t->mapto & MAP_NORM) { - COLLADASW::Texture texture(key); - texture.setTexcoord(uvname); - texture.setSampler(*sampler); - // technique FCOLLADA, with the <bump> tag, is most likely the best understood, - // most widespread de-facto standard. - texture.setProfileName("FCOLLADA"); - texture.setChildElementName("bump"); - ep.addExtraTechniqueColorOrTexture(COLLADASW::ColorOrTexture(texture)); - } - } - // performs the actual writing - ep.addProfileElements(); - bool twoSided = false; - if (ob->type == OB_MESH && ob->data) { - Mesh *me = (Mesh*)ob->data; - if (me->flag & ME_TWOSIDED) - twoSided = true; - } - if (twoSided) - ep.addExtraTechniqueParameter("GOOGLEEARTH", "show_double_sided", 1); - ep.addExtraTechniques(mSW); - - ep.closeProfile(); - if (twoSided) - mSW->appendTextBlock("<extra><technique profile=\"MAX3D\"><double_sided>1</double_sided></technique></extra>"); - closeEffect(); - } - - COLLADASW::ColorOrTexture createTexture(Image *ima, - std::string& uv_layer_name, - COLLADASW::Sampler *sampler - /*COLLADASW::Surface *surface*/) - { - - COLLADASW::Texture texture(translate_id(id_name(ima))); - texture.setTexcoord(uv_layer_name); - //texture.setSurface(*surface); - texture.setSampler(*sampler); - - COLLADASW::ColorOrTexture cot(texture); - return cot; - } - - COLLADASW::ColorOrTexture getcol(float r, float g, float b, float a) - { - COLLADASW::Color color(r,g,b,a); - COLLADASW::ColorOrTexture cot(color); - return cot; - } - - //returns the array of mtex indices which have image - //need this for exporting textures - void createTextureIndices(Material *ma, std::vector<int> &indices) - { - indices.clear(); - - for (int a = 0; a < MAX_MTEX; a++) { - if (ma->mtex[a] && - ma->mtex[a]->tex && - ma->mtex[a]->tex->type == TEX_IMAGE && - ma->mtex[a]->texco == TEXCO_UV){ - indices.push_back(a); - } - } - } -}; - -class MaterialsExporter: COLLADASW::LibraryMaterials -{ -public: - MaterialsExporter(COLLADASW::StreamWriter *sw): COLLADASW::LibraryMaterials(sw){} - void exportMaterials(Scene *sce) - { - openLibrary(); - - forEachMaterialInScene(sce, *this); - - closeLibrary(); - } - - void operator()(Material *ma, Object *ob) - { - std::string name(id_name(ma)); - - openMaterial(translate_id(name), name); - - std::string efid = translate_id(name) + "-effect"; - addInstanceEffect(COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, efid)); - - closeMaterial(); - } -}; - -class CamerasExporter: COLLADASW::LibraryCameras -{ -public: - CamerasExporter(COLLADASW::StreamWriter *sw): COLLADASW::LibraryCameras(sw){} - void exportCameras(Scene *sce) - { - openLibrary(); - - forEachCameraObjectInScene(sce, *this); - - closeLibrary(); - } - void operator()(Object *ob, Scene *sce) - { - // TODO: shiftx, shifty, YF_dofdist - Camera *cam = (Camera*)ob->data; - std::string cam_id(get_camera_id(ob)); - std::string cam_name(id_name(cam)); - - if (cam->type == CAM_PERSP) { - COLLADASW::PerspectiveOptic persp(mSW); - persp.setXFov(lens_to_angle(cam->lens)*(180.0f/M_PI)); - persp.setAspectRatio(1.0); - persp.setZFar(cam->clipend); - persp.setZNear(cam->clipsta); - COLLADASW::Camera ccam(mSW, &persp, cam_id, cam_name); - addCamera(ccam); - } - else { - COLLADASW::OrthographicOptic ortho(mSW); - ortho.setXMag(cam->ortho_scale); - ortho.setAspectRatio(1.0); - ortho.setZFar(cam->clipend); - ortho.setZNear(cam->clipsta); - COLLADASW::Camera ccam(mSW, &ortho, cam_id, cam_name); - addCamera(ccam); - } - } -}; - -class LightsExporter: COLLADASW::LibraryLights -{ -public: - LightsExporter(COLLADASW::StreamWriter *sw): COLLADASW::LibraryLights(sw){} - void exportLights(Scene *sce) - { - openLibrary(); - - forEachLampObjectInScene(sce, *this); - - closeLibrary(); - } - void operator()(Object *ob) - { - Lamp *la = (Lamp*)ob->data; - std::string la_id(get_light_id(ob)); - std::string la_name(id_name(la)); - COLLADASW::Color col(la->r, la->g, la->b); - float e = la->energy; - - // sun - if (la->type == LA_SUN) { - COLLADASW::DirectionalLight cla(mSW, la_id, la_name, e); - cla.setColor(col); - addLight(cla); - } - // hemi - else if (la->type == LA_HEMI) { - COLLADASW::AmbientLight cla(mSW, la_id, la_name, e); - cla.setColor(col); - addLight(cla); - } - // spot - else if (la->type == LA_SPOT) { - COLLADASW::SpotLight cla(mSW, la_id, la_name, e); - cla.setColor(col); - cla.setFallOffAngle(la->spotsize); - cla.setFallOffExponent(la->spotblend); - cla.setLinearAttenuation(la->att1); - cla.setQuadraticAttenuation(la->att2); - addLight(cla); - } - // lamp - else if (la->type == LA_LOCAL) { - COLLADASW::PointLight cla(mSW, la_id, la_name, e); - cla.setColor(col); - cla.setLinearAttenuation(la->att1); - cla.setQuadraticAttenuation(la->att2); - addLight(cla); - } - // area lamp is not supported - // it will be exported as a local lamp - else { - COLLADASW::PointLight cla(mSW, la_id, la_name, e); - cla.setColor(col); - cla.setLinearAttenuation(la->att1); - cla.setQuadraticAttenuation(la->att2); - addLight(cla); - } - } -}; - // TODO: it would be better to instantiate animations rather than create a new one per object // COLLADA allows this through multiple <channel>s in <animation>. // For this to work, we need to know objects that use a certain action. @@ -2582,8 +871,8 @@ protected: find_frames(ob, fra, prefix, "rotation_euler"); else if (rotmode == ROT_MODE_QUAT) find_frames(ob, fra, prefix, "rotation_quaternion"); - else if (rotmode == ROT_MODE_AXISANGLE) - ; + /*else if (rotmode == ROT_MODE_AXISANGLE) + ;*/ } // enable fcurves driving a specific bone, disable all the rest @@ -2612,8 +901,8 @@ protected: void DocumentExporter::exportCurrentScene(Scene *sce, const char* filename) { - global_id_map.clear(); - + clear_global_id_map(); + COLLADABU::NativeString native_filename = COLLADABU::NativeString(std::string(filename)); COLLADASW::StreamWriter sw(native_filename); diff --git a/source/blender/collada/DocumentExporter.h b/source/blender/collada/DocumentExporter.h index bb6d400fdf1..4aac393b1ab 100644 --- a/source/blender/collada/DocumentExporter.h +++ b/source/blender/collada/DocumentExporter.h @@ -21,6 +21,10 @@ * * ***** END GPL LICENSE BLOCK ***** */ + +#ifndef __DOCUMENTEXPORTER_H__ +#define __DOCUMENTEXPORTER_H__ + struct Scene; class DocumentExporter @@ -29,3 +33,5 @@ class DocumentExporter void exportCurrentScene(Scene *sce, const char* filename); void exportScenes(const char* filename); }; + +#endif diff --git a/source/blender/collada/DocumentImporter.cpp b/source/blender/collada/DocumentImporter.cpp index 0b50326ad6c..a406845c8a2 100644 --- a/source/blender/collada/DocumentImporter.cpp +++ b/source/blender/collada/DocumentImporter.cpp @@ -25,3210 +25,76 @@ // * name imported objects // * import object rotation as euler +#include <string> +#include <map> +#include <algorithm> // sort() + +#include <math.h> +#include <float.h> + #include "COLLADAFWRoot.h" #include "COLLADAFWIWriter.h" #include "COLLADAFWStableHeaders.h" -#include "COLLADAFWAnimationCurve.h" -#include "COLLADAFWAnimationList.h" #include "COLLADAFWCamera.h" #include "COLLADAFWColorOrTexture.h" #include "COLLADAFWEffect.h" -#include "COLLADAFWFloatOrDoubleArray.h" -#include "COLLADAFWGeometry.h" #include "COLLADAFWImage.h" #include "COLLADAFWIndexList.h" #include "COLLADAFWInstanceGeometry.h" #include "COLLADAFWLight.h" #include "COLLADAFWMaterial.h" -#include "COLLADAFWMesh.h" #include "COLLADAFWMeshPrimitiveWithFaceVertexCount.h" -#include "COLLADAFWNode.h" #include "COLLADAFWPolygons.h" #include "COLLADAFWSampler.h" -#include "COLLADAFWSkinController.h" -#include "COLLADAFWSkinControllerData.h" -#include "COLLADAFWTransformation.h" -#include "COLLADAFWTranslate.h" -#include "COLLADAFWRotate.h" -#include "COLLADAFWScale.h" -#include "COLLADAFWMatrix.h" #include "COLLADAFWTypes.h" #include "COLLADAFWVisualScene.h" -#include "COLLADAFWFileInfo.h" #include "COLLADAFWArrayPrimitiveType.h" #include "COLLADAFWLibraryNodes.h" #include "COLLADASaxFWLLoader.h" -// TODO move "extern C" into header files -extern "C" -{ -#include "ED_keyframing.h" -#include "ED_armature.h" -#include "ED_mesh.h" // ED_vgroup_vert_add, ... -#include "ED_anim_api.h" -#include "ED_object.h" - -#include "WM_types.h" -#include "WM_api.h" - #include "BKE_main.h" -#include "BKE_customdata.h" #include "BKE_library.h" #include "BKE_texture.h" #include "BKE_fcurve.h" #include "BKE_depsgraph.h" #include "BLI_path_util.h" -#include "BKE_displist.h" -#include "BLI_math.h" #include "BKE_scene.h" -} -#include "BKE_armature.h" -#include "BKE_mesh.h" #include "BKE_global.h" -#include "BKE_context.h" #include "BKE_object.h" -#include "BKE_image.h" #include "BKE_material.h" #include "BKE_utildefines.h" -#include "BKE_action.h" +#include "BKE_image.h" -#include "BLI_math.h" #include "BLI_listbase.h" #include "BLI_string.h" -#include "DNA_lamp_types.h" -#include "DNA_armature_types.h" -#include "DNA_anim_types.h" -#include "DNA_curve_types.h" -#include "DNA_texture_types.h" #include "DNA_camera_types.h" -#include "DNA_object_types.h" -#include "DNA_meshdata_types.h" -#include "DNA_mesh_types.h" -#include "DNA_material_types.h" -#include "DNA_scene_types.h" -#include "DNA_modifier_types.h" +#include "DNA_lamp_types.h" + +#include "RNA_access.h" #include "MEM_guardedalloc.h" #include "DocumentImporter.h" #include "collada_internal.h" -#include <string> -#include <map> -#include <algorithm> // sort() - -#include <math.h> -#include <float.h> - -// #define COLLADA_DEBUG - -// creates empties for each imported bone on layer 2, for debugging -// #define ARMATURE_TEST - -char *CustomData_get_layer_name(const struct CustomData *data, int type, int n); - -static const char *primTypeToStr(COLLADAFW::MeshPrimitive::PrimitiveType type) -{ - using namespace COLLADAFW; - - switch (type) { - case MeshPrimitive::LINES: - return "LINES"; - case MeshPrimitive::LINE_STRIPS: - return "LINESTRIPS"; - case MeshPrimitive::POLYGONS: - return "POLYGONS"; - case MeshPrimitive::POLYLIST: - return "POLYLIST"; - case MeshPrimitive::TRIANGLES: - return "TRIANGLES"; - case MeshPrimitive::TRIANGLE_FANS: - return "TRIANGLE_FANS"; - case MeshPrimitive::TRIANGLE_STRIPS: - return "TRIANGLE_FANS"; - case MeshPrimitive::POINTS: - return "POINTS"; - case MeshPrimitive::UNDEFINED_PRIMITIVE_TYPE: - return "UNDEFINED_PRIMITIVE_TYPE"; - } - return "UNKNOWN"; -} - -static const char *geomTypeToStr(COLLADAFW::Geometry::GeometryType type) -{ - switch (type) { - case COLLADAFW::Geometry::GEO_TYPE_MESH: - return "MESH"; - case COLLADAFW::Geometry::GEO_TYPE_SPLINE: - return "SPLINE"; - case COLLADAFW::Geometry::GEO_TYPE_CONVEX_MESH: - return "CONVEX_MESH"; - case COLLADAFW::Geometry::GEO_TYPE_UNKNOWN: - default: - return "UNKNOWN"; - } -} - -// works for COLLADAFW::Node, COLLADAFW::Geometry -template<class T> -static const char *get_dae_name(T *node) -{ - const std::string& name = node->getName(); - return name.size() ? name.c_str() : node->getOriginalId().c_str(); -} - -// use this for retrieving bone names, since these must be unique -template<class T> -static const char *get_joint_name(T *node) -{ - const std::string& id = node->getOriginalId(); - return id.size() ? id.c_str() : node->getName().c_str(); -} - -static float get_float_value(const COLLADAFW::FloatOrDoubleArray& array, unsigned int index) -{ - if (index >= array.getValuesCount()) - return 0.0f; - - if (array.getType() == COLLADAFW::MeshVertexData::DATA_TYPE_FLOAT) - return array.getFloatValues()->getData()[index]; - else - return array.getDoubleValues()->getData()[index]; -} - -// copied from /editors/object/object_relations.c -static int test_parent_loop(Object *par, Object *ob) -{ - /* test if 'ob' is a parent somewhere in par's parents */ - - if(par == NULL) return 0; - if(ob == par) return 1; - - return test_parent_loop(par->parent, ob); -} - -// a shortened version of parent_set_exec() -// if is_parent_space is true then ob->obmat will be multiplied by par->obmat before parenting -static int set_parent(Object *ob, Object *par, bContext *C, bool is_parent_space=true) -{ - if (!par || test_parent_loop(par, ob)) - return false; - - Object workob; - Main *bmain = CTX_data_main(C); - Scene *sce = CTX_data_scene(C); - - ob->parent = par; - ob->partype = PAROBJECT; - - ob->parsubstr[0] = 0; - - if (is_parent_space) { - // calc par->obmat - where_is_object(sce, par); - - // move child obmat into world space - float mat[4][4]; - mul_m4_m4m4(mat, ob->obmat, par->obmat); - copy_m4_m4(ob->obmat, mat); - } - - // apply child obmat (i.e. decompose it into rot/loc/size) - object_apply_mat4(ob, ob->obmat); - - // compute parentinv - what_does_parent(sce, ob, &workob); - invert_m4_m4(ob->parentinv, workob.obmat); - - ob->recalc |= OB_RECALC_OB | OB_RECALC_DATA; - par->recalc |= OB_RECALC_OB; - - DAG_scene_sort(bmain, sce); - DAG_ids_flush_update(bmain, 0); - WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL); - - return true; -} - -typedef std::map<COLLADAFW::TextureMapId, std::vector<MTex*> > TexIndexTextureArrayMap; - -class TransformReader : public TransformBase -{ -protected: - - UnitConverter *unit_converter; - - struct Animation { - Object *ob; - COLLADAFW::Node *node; - COLLADAFW::Transformation *tm; // which transform is animated by an AnimationList->id - }; - -public: - - TransformReader(UnitConverter* conv) : unit_converter(conv) {} - - void get_node_mat(float mat[][4], COLLADAFW::Node *node, std::map<COLLADAFW::UniqueId, Animation> *animation_map, - Object *ob) - { - float cur[4][4]; - float copy[4][4]; - - unit_m4(mat); - - for (unsigned int i = 0; i < node->getTransformations().getCount(); i++) { - - COLLADAFW::Transformation *tm = node->getTransformations()[i]; - COLLADAFW::Transformation::TransformationType type = tm->getTransformationType(); - - switch(type) { - case COLLADAFW::Transformation::TRANSLATE: - dae_translate_to_mat4(tm, cur); - break; - case COLLADAFW::Transformation::ROTATE: - dae_rotate_to_mat4(tm, cur); - break; - case COLLADAFW::Transformation::SCALE: - dae_scale_to_mat4(tm, cur); - break; - case COLLADAFW::Transformation::MATRIX: - dae_matrix_to_mat4(tm, cur); - break; - case COLLADAFW::Transformation::LOOKAT: - case COLLADAFW::Transformation::SKEW: - fprintf(stderr, "LOOKAT and SKEW transformations are not supported yet.\n"); - break; - } - - copy_m4_m4(copy, mat); - mul_m4_m4m4(mat, cur, copy); - - if (animation_map) { - // AnimationList that drives this Transformation - const COLLADAFW::UniqueId& anim_list_id = tm->getAnimationList(); - - // store this so later we can link animation data with ob - Animation anim = {ob, node, tm}; - (*animation_map)[anim_list_id] = anim; - } - } - } - - void dae_rotate_to_mat4(COLLADAFW::Transformation *tm, float m[][4]) - { - COLLADAFW::Rotate *ro = (COLLADAFW::Rotate*)tm; - COLLADABU::Math::Vector3& axis = ro->getRotationAxis(); - float angle = (float)(ro->getRotationAngle() * M_PI / 180.0f); - float ax[] = {axis[0], axis[1], axis[2]}; - // float quat[4]; - // axis_angle_to_quat(quat, axis, angle); - // quat_to_mat4(m, quat); - axis_angle_to_mat4(m, ax, angle); - } - - void dae_translate_to_mat4(COLLADAFW::Transformation *tm, float m[][4]) - { - COLLADAFW::Translate *tra = (COLLADAFW::Translate*)tm; - COLLADABU::Math::Vector3& t = tra->getTranslation(); - - unit_m4(m); - - m[3][0] = (float)t[0]; - m[3][1] = (float)t[1]; - m[3][2] = (float)t[2]; - } - - void dae_scale_to_mat4(COLLADAFW::Transformation *tm, float m[][4]) - { - COLLADABU::Math::Vector3& s = ((COLLADAFW::Scale*)tm)->getScale(); - float size[3] = {(float)s[0], (float)s[1], (float)s[2]}; - size_to_mat4(m, size); - } - - void dae_matrix_to_mat4(COLLADAFW::Transformation *tm, float m[][4]) - { - unit_converter->dae_matrix_to_mat4(m, ((COLLADAFW::Matrix*)tm)->getMatrix()); - } - - void dae_translate_to_v3(COLLADAFW::Transformation *tm, float v[3]) - { - dae_vector3_to_v3(((COLLADAFW::Translate*)tm)->getTranslation(), v); - } - - void dae_scale_to_v3(COLLADAFW::Transformation *tm, float v[3]) - { - dae_vector3_to_v3(((COLLADAFW::Scale*)tm)->getScale(), v); - } - - void dae_vector3_to_v3(const COLLADABU::Math::Vector3 &v3, float v[3]) - { - v[0] = v3.x; - v[1] = v3.y; - v[2] = v3.z; - } -}; - -// only for ArmatureImporter to "see" MeshImporter::get_object_by_geom_uid -class MeshImporterBase -{ -public: - virtual Object *get_object_by_geom_uid(const COLLADAFW::UniqueId& geom_uid) = 0; -}; - -// ditto as above -class AnimationImporterBase -{ -public: - // virtual void change_eul_to_quat(Object *ob, bAction *act) = 0; -}; - -class ArmatureImporter : private TransformReader -{ -private: - Scene *scene; - UnitConverter *unit_converter; - - // std::map<int, JointData> joint_index_to_joint_info_map; - // std::map<COLLADAFW::UniqueId, int> joint_id_to_joint_index_map; - - struct LeafBone { - // COLLADAFW::Node *node; - EditBone *bone; - char name[32]; - float mat[4][4]; // bone matrix, derived from inv_bind_mat - }; - std::vector<LeafBone> leaf_bones; - // int bone_direction_row; // XXX not used - float leaf_bone_length; - int totbone; - // XXX not used - // float min_angle; // minimum angle between bone head-tail and a row of bone matrix - -#if 0 - struct ArmatureJoints { - Object *ob_arm; - std::vector<COLLADAFW::Node*> root_joints; - }; - std::vector<ArmatureJoints> armature_joints; -#endif - - Object *empty; // empty for leaf bones - - std::map<COLLADAFW::UniqueId, COLLADAFW::UniqueId> geom_uid_by_controller_uid; - std::map<COLLADAFW::UniqueId, COLLADAFW::Node*> joint_by_uid; // contains all joints - std::vector<COLLADAFW::Node*> root_joints; - std::map<COLLADAFW::UniqueId, Object*> joint_parent_map; - - MeshImporterBase *mesh_importer; - AnimationImporterBase *anim_importer; - - // This is used to store data passed in write_controller_data. - // Arrays from COLLADAFW::SkinControllerData lose ownership, so do this class members - // so that arrays don't get freed until we free them explicitly. - class SkinInfo - { - private: - // to build armature bones from inverse bind matrices - struct JointData { - float inv_bind_mat[4][4]; // joint inverse bind matrix - COLLADAFW::UniqueId joint_uid; // joint node UID - // Object *ob_arm; // armature object - }; - - float bind_shape_matrix[4][4]; - - // data from COLLADAFW::SkinControllerData, each array should be freed - COLLADAFW::UIntValuesArray joints_per_vertex; - COLLADAFW::UIntValuesArray weight_indices; - COLLADAFW::IntValuesArray joint_indices; - // COLLADAFW::FloatOrDoubleArray weights; - std::vector<float> weights; - - std::vector<JointData> joint_data; // index to this vector is joint index - - UnitConverter *unit_converter; - - Object *ob_arm; - COLLADAFW::UniqueId controller_uid; - Object *parent; - - public: - - SkinInfo() {} - - SkinInfo(const SkinInfo& skin) : weights(skin.weights), - joint_data(skin.joint_data), - unit_converter(skin.unit_converter), - ob_arm(skin.ob_arm), - controller_uid(skin.controller_uid), - parent(skin.parent) - { - copy_m4_m4(bind_shape_matrix, (float (*)[4])skin.bind_shape_matrix); - - transfer_uint_array_data_const(skin.joints_per_vertex, joints_per_vertex); - transfer_uint_array_data_const(skin.weight_indices, weight_indices); - transfer_int_array_data_const(skin.joint_indices, joint_indices); - } - - SkinInfo(UnitConverter *conv) : unit_converter(conv), ob_arm(NULL), parent(NULL) {} - - // nobody owns the data after this, so it should be freed manually with releaseMemory - template <class T> - void transfer_array_data(T& src, T& dest) - { - dest.setData(src.getData(), src.getCount()); - src.yieldOwnerShip(); - dest.yieldOwnerShip(); - } - - // when src is const we cannot src.yieldOwnerShip, this is used by copy constructor - void transfer_int_array_data_const(const COLLADAFW::IntValuesArray& src, COLLADAFW::IntValuesArray& dest) - { - dest.setData((int*)src.getData(), src.getCount()); - dest.yieldOwnerShip(); - } - - void transfer_uint_array_data_const(const COLLADAFW::UIntValuesArray& src, COLLADAFW::UIntValuesArray& dest) - { - dest.setData((unsigned int*)src.getData(), src.getCount()); - dest.yieldOwnerShip(); - } - - void borrow_skin_controller_data(const COLLADAFW::SkinControllerData* skin) - { - transfer_array_data((COLLADAFW::UIntValuesArray&)skin->getJointsPerVertex(), joints_per_vertex); - transfer_array_data((COLLADAFW::UIntValuesArray&)skin->getWeightIndices(), weight_indices); - transfer_array_data((COLLADAFW::IntValuesArray&)skin->getJointIndices(), joint_indices); - // transfer_array_data(skin->getWeights(), weights); - - // cannot transfer data for FloatOrDoubleArray, copy values manually - const COLLADAFW::FloatOrDoubleArray& weight = skin->getWeights(); - for (unsigned int i = 0; i < weight.getValuesCount(); i++) - weights.push_back(get_float_value(weight, i)); - - unit_converter->dae_matrix_to_mat4(bind_shape_matrix, skin->getBindShapeMatrix()); - } - - void free() - { - joints_per_vertex.releaseMemory(); - weight_indices.releaseMemory(); - joint_indices.releaseMemory(); - // weights.releaseMemory(); - } - - // using inverse bind matrices to construct armature - // it is safe to invert them to get the original matrices - // because if they are inverse matrices, they can be inverted - void add_joint(const COLLADABU::Math::Matrix4& matrix) - { - JointData jd; - unit_converter->dae_matrix_to_mat4(jd.inv_bind_mat, matrix); - joint_data.push_back(jd); - } - - void set_controller(const COLLADAFW::SkinController* co) - { - controller_uid = co->getUniqueId(); - - // fill in joint UIDs - const COLLADAFW::UniqueIdArray& joint_uids = co->getJoints(); - for (unsigned int i = 0; i < joint_uids.getCount(); i++) { - joint_data[i].joint_uid = joint_uids[i]; - - // // store armature pointer - // JointData& jd = joint_index_to_joint_info_map[i]; - // jd.ob_arm = ob_arm; - - // now we'll be able to get inv bind matrix from joint id - // joint_id_to_joint_index_map[joint_ids[i]] = i; - } - } - - // called from write_controller - Object *create_armature(Scene *scene) - { - ob_arm = add_object(scene, OB_ARMATURE); - return ob_arm; - } - - Object* set_armature(Object *ob_arm) - { - if (this->ob_arm) - return this->ob_arm; - - this->ob_arm = ob_arm; - return ob_arm; - } - - bool get_joint_inv_bind_matrix(float inv_bind_mat[][4], COLLADAFW::Node *node) - { - const COLLADAFW::UniqueId& uid = node->getUniqueId(); - std::vector<JointData>::iterator it; - for (it = joint_data.begin(); it != joint_data.end(); it++) { - if ((*it).joint_uid == uid) { - copy_m4_m4(inv_bind_mat, (*it).inv_bind_mat); - return true; - } - } - - return false; - } - - Object *get_armature() - { - return ob_arm; - } - - const COLLADAFW::UniqueId& get_controller_uid() - { - return controller_uid; - } - - // check if this skin controller references a joint or any descendant of it - // - // some nodes may not be referenced by SkinController, - // in this case to determine if the node belongs to this armature, - // we need to search down the tree - bool uses_joint_or_descendant(COLLADAFW::Node *node) - { - const COLLADAFW::UniqueId& uid = node->getUniqueId(); - std::vector<JointData>::iterator it; - for (it = joint_data.begin(); it != joint_data.end(); it++) { - if ((*it).joint_uid == uid) - return true; - } - - COLLADAFW::NodePointerArray& children = node->getChildNodes(); - for (unsigned int i = 0; i < children.getCount(); i++) { - if (uses_joint_or_descendant(children[i])) - return true; - } - - return false; - } - - void link_armature(bContext *C, Object *ob, std::map<COLLADAFW::UniqueId, COLLADAFW::Node*>& joint_by_uid, - TransformReader *tm) - { - Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); - - ModifierData *md = ED_object_modifier_add(NULL, bmain, scene, ob, NULL, eModifierType_Armature); - ((ArmatureModifierData *)md)->object = ob_arm; - - copy_m4_m4(ob->obmat, bind_shape_matrix); - object_apply_mat4(ob, ob->obmat); -#if 1 - ::set_parent(ob, ob_arm, C); -#else - Object workob; - ob->parent = ob_arm; - ob->partype = PAROBJECT; - - what_does_parent(scene, ob, &workob); - invert_m4_m4(ob->parentinv, workob.obmat); - - ob->recalc |= OB_RECALC_OB|OB_RECALC_DATA; - - DAG_scene_sort(bmain, scene); - DAG_ids_flush_update(bmain, 0); - WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL); -#endif - - ((bArmature*)ob_arm->data)->deformflag = ARM_DEF_VGROUP; - - // create all vertex groups - std::vector<JointData>::iterator it; - int joint_index; - for (it = joint_data.begin(), joint_index = 0; it != joint_data.end(); it++, joint_index++) { - const char *name = "Group"; - - // name group by joint node name - if (joint_by_uid.find((*it).joint_uid) != joint_by_uid.end()) { - name = get_joint_name(joint_by_uid[(*it).joint_uid]); - } - - ED_vgroup_add_name(ob, (char*)name); - } - - // <vcount> - number of joints per vertex - joints_per_vertex - // <v> - [[bone index, weight index] * joints per vertex] * vertices - weight indices - // ^ bone index can be -1 meaning weight toward bind shape, how to express this in Blender? - - // for each vertex in weight indices - // for each bone index in vertex - // add vertex to group at group index - // treat group index -1 specially - - // get def group by index with BLI_findlink - - for (unsigned int vertex = 0, weight = 0; vertex < joints_per_vertex.getCount(); vertex++) { - - unsigned int limit = weight + joints_per_vertex[vertex]; - for ( ; weight < limit; weight++) { - int joint = joint_indices[weight], joint_weight = weight_indices[weight]; - - // -1 means "weight towards the bind shape", we just don't assign it to any group - if (joint != -1) { - bDeformGroup *def = (bDeformGroup*)BLI_findlink(&ob->defbase, joint); - - ED_vgroup_vert_add(ob, def, vertex, weights[joint_weight], WEIGHT_REPLACE); - } - } - } - } - - bPoseChannel *get_pose_channel_from_node(COLLADAFW::Node *node) - { - return get_pose_channel(ob_arm->pose, get_joint_name(node)); - } - - void set_parent(Object *_parent) - { - parent = _parent; - } - - Object* get_parent() - { - return parent; - } - - void find_root_joints(const std::vector<COLLADAFW::Node*> &root_joints, - std::map<COLLADAFW::UniqueId, COLLADAFW::Node*>& joint_by_uid, - std::vector<COLLADAFW::Node*>& result) - { - std::vector<COLLADAFW::Node*>::const_iterator it; - for (it = root_joints.begin(); it != root_joints.end(); it++) { - COLLADAFW::Node *root = *it; - std::vector<JointData>::iterator ji; - for (ji = joint_data.begin(); ji != joint_data.end(); ji++) { - COLLADAFW::Node *joint = joint_by_uid[(*ji).joint_uid]; - if (find_node_in_tree(joint, root)) { - if (std::find(result.begin(), result.end(), root) == result.end()) - result.push_back(root); - } - } - } - } - - bool find_node_in_tree(COLLADAFW::Node *node, COLLADAFW::Node *tree_root) - { - if (node == tree_root) - return true; - - COLLADAFW::NodePointerArray& children = tree_root->getChildNodes(); - for (unsigned int i = 0; i < children.getCount(); i++) { - if (find_node_in_tree(node, children[i])) - return true; - } - - return false; - } - - }; - - std::map<COLLADAFW::UniqueId, SkinInfo> skin_by_data_uid; // data UID = skin controller data UID -#if 0 - JointData *get_joint_data(COLLADAFW::Node *node) - { - const COLLADAFW::UniqueId& joint_id = node->getUniqueId(); - - if (joint_id_to_joint_index_map.find(joint_id) == joint_id_to_joint_index_map.end()) { - fprintf(stderr, "Cannot find a joint index by joint id for %s.\n", - node->getOriginalId().c_str()); - return NULL; - } - - int joint_index = joint_id_to_joint_index_map[joint_id]; - - return &joint_index_to_joint_info_map[joint_index]; - } -#endif - - void create_bone(SkinInfo& skin, COLLADAFW::Node *node, EditBone *parent, int totchild, - float parent_mat[][4], bArmature *arm) - { - float joint_inv_bind_mat[4][4]; - - // JointData* jd = get_joint_data(node); - - float mat[4][4]; - - if (skin.get_joint_inv_bind_matrix(joint_inv_bind_mat, node)) { - // get original world-space matrix - invert_m4_m4(mat, joint_inv_bind_mat); - } - // create a bone even if there's no joint data for it (i.e. it has no influence) - else { - float obmat[4][4]; - - // object-space - get_node_mat(obmat, node, NULL, NULL); - - // get world-space - if (parent) - mul_m4_m4m4(mat, obmat, parent_mat); - else - copy_m4_m4(mat, obmat); - } - - // TODO rename from Node "name" attrs later - EditBone *bone = ED_armature_edit_bone_add(arm, (char*)get_joint_name(node)); - totbone++; - - if (parent) bone->parent = parent; - - // set head - copy_v3_v3(bone->head, mat[3]); - - // set tail, don't set it to head because 0-length bones are not allowed - float vec[3] = {0.0f, 0.5f, 0.0f}; - add_v3_v3v3(bone->tail, bone->head, vec); - - // set parent tail - if (parent && totchild == 1) { - copy_v3_v3(parent->tail, bone->head); - - // not setting BONE_CONNECTED because this would lock child bone location with respect to parent - // bone->flag |= BONE_CONNECTED; - - // XXX increase this to prevent "very" small bones? - const float epsilon = 0.000001f; - - // derive leaf bone length - float length = len_v3v3(parent->head, parent->tail); - if ((length < leaf_bone_length || totbone == 0) && length > epsilon) { - leaf_bone_length = length; - } - - // treat zero-sized bone like a leaf bone - if (length <= epsilon) { - add_leaf_bone(parent_mat, parent); - } - - /* -#if 0 - // and which row in mat is bone direction - float vec[3]; - sub_v3_v3v3(vec, parent->tail, parent->head); -#ifdef COLLADA_DEBUG - print_v3("tail - head", vec); - print_m4("matrix", parent_mat); -#endif - for (int i = 0; i < 3; i++) { -#ifdef COLLADA_DEBUG - char *axis_names[] = {"X", "Y", "Z"}; - printf("%s-axis length is %f\n", axis_names[i], len_v3(parent_mat[i])); -#endif - float angle = angle_v2v2(vec, parent_mat[i]); - if (angle < min_angle) { -#ifdef COLLADA_DEBUG - print_v3("picking", parent_mat[i]); - printf("^ %s axis of %s's matrix\n", axis_names[i], get_dae_name(node)); -#endif - bone_direction_row = i; - min_angle = angle; - } - } -#endif - */ - } - - COLLADAFW::NodePointerArray& children = node->getChildNodes(); - for (unsigned int i = 0; i < children.getCount(); i++) { - create_bone(skin, children[i], bone, children.getCount(), mat, arm); - } - - // in second case it's not a leaf bone, but we handle it the same way - if (!children.getCount() || children.getCount() > 1) { - add_leaf_bone(mat, bone); - } - } - - void add_leaf_bone(float mat[][4], EditBone *bone) - { - LeafBone leaf; - - leaf.bone = bone; - copy_m4_m4(leaf.mat, mat); - BLI_strncpy(leaf.name, bone->name, sizeof(leaf.name)); - - leaf_bones.push_back(leaf); - } - - void fix_leaf_bones() - { - // just setting tail for leaf bones here - - std::vector<LeafBone>::iterator it; - for (it = leaf_bones.begin(); it != leaf_bones.end(); it++) { - LeafBone& leaf = *it; - - // pointing up - float vec[3] = {0.0f, 0.0f, 1.0f}; - - mul_v3_fl(vec, leaf_bone_length); - - copy_v3_v3(leaf.bone->tail, leaf.bone->head); - add_v3_v3v3(leaf.bone->tail, leaf.bone->head, vec); - } - } - - void set_leaf_bone_shapes(Object *ob_arm) - { - bPose *pose = ob_arm->pose; - - std::vector<LeafBone>::iterator it; - for (it = leaf_bones.begin(); it != leaf_bones.end(); it++) { - LeafBone& leaf = *it; - - bPoseChannel *pchan = get_pose_channel(pose, leaf.name); - if (pchan) { - pchan->custom = get_empty_for_leaves(); - } - else { - fprintf(stderr, "Cannot find a pose channel for leaf bone %s\n", leaf.name); - } - } - } - -#if 0 - void set_euler_rotmode() - { - // just set rotmode = ROT_MODE_EUL on pose channel for each joint - - std::map<COLLADAFW::UniqueId, COLLADAFW::Node*>::iterator it; - - for (it = joint_by_uid.begin(); it != joint_by_uid.end(); it++) { - - COLLADAFW::Node *joint = it->second; - - std::map<COLLADAFW::UniqueId, SkinInfo>::iterator sit; - - for (sit = skin_by_data_uid.begin(); sit != skin_by_data_uid.end(); sit++) { - SkinInfo& skin = sit->second; - - if (skin.uses_joint_or_descendant(joint)) { - bPoseChannel *pchan = skin.get_pose_channel_from_node(joint); - - if (pchan) { - pchan->rotmode = ROT_MODE_EUL; - } - else { - fprintf(stderr, "Cannot find pose channel for %s.\n", get_joint_name(joint)); - } - - break; - } - } - } - } -#endif - - Object *get_empty_for_leaves() - { - if (empty) return empty; - - empty = add_object(scene, OB_EMPTY); - empty->empty_drawtype = OB_EMPTY_SPHERE; - - return empty; - } - -#if 0 - Object *find_armature(COLLADAFW::Node *node) - { - JointData* jd = get_joint_data(node); - if (jd) return jd->ob_arm; - - COLLADAFW::NodePointerArray& children = node->getChildNodes(); - for (int i = 0; i < children.getCount(); i++) { - Object *ob_arm = find_armature(children[i]); - if (ob_arm) return ob_arm; - } - - return NULL; - } - - ArmatureJoints& get_armature_joints(Object *ob_arm) - { - // try finding it - std::vector<ArmatureJoints>::iterator it; - for (it = armature_joints.begin(); it != armature_joints.end(); it++) { - if ((*it).ob_arm == ob_arm) return *it; - } - - // not found, create one - ArmatureJoints aj; - aj.ob_arm = ob_arm; - armature_joints.push_back(aj); - - return armature_joints.back(); - } -#endif - - void create_armature_bones(SkinInfo& skin) - { - // just do like so: - // - get armature - // - enter editmode - // - add edit bones and head/tail properties using matrices and parent-child info - // - exit edit mode - // - set a sphere shape to leaf bones - - Object *ob_arm = NULL; - - /* - * find if there's another skin sharing at least one bone with this skin - * if so, use that skin's armature - */ - - /* - Pseudocode: - - find_node_in_tree(node, root_joint) - - skin::find_root_joints(root_joints): - std::vector root_joints; - for each root in root_joints: - for each joint in joints: - if find_node_in_tree(joint, root): - if (std::find(root_joints.begin(), root_joints.end(), root) == root_joints.end()) - root_joints.push_back(root); - - for (each skin B with armature) { - find all root joints for skin B - - for each joint X in skin A: - for each root joint R in skin B: - if (find_node_in_tree(X, R)) { - shared = 1; - goto endloop; - } - } - - endloop: - */ - - SkinInfo *a = &skin; - Object *shared = NULL; - std::vector<COLLADAFW::Node*> skin_root_joints; - - std::map<COLLADAFW::UniqueId, SkinInfo>::iterator it; - for (it = skin_by_data_uid.begin(); it != skin_by_data_uid.end(); it++) { - SkinInfo *b = &it->second; - if (b == a || b->get_armature() == NULL) - continue; - - skin_root_joints.clear(); - - b->find_root_joints(root_joints, joint_by_uid, skin_root_joints); - - std::vector<COLLADAFW::Node*>::iterator ri; - for (ri = skin_root_joints.begin(); ri != skin_root_joints.end(); ri++) { - if (a->uses_joint_or_descendant(*ri)) { - shared = b->get_armature(); - break; - } - } - - if (shared != NULL) - break; - } - - if (shared) - ob_arm = skin.set_armature(shared); - else - ob_arm = skin.create_armature(scene); - - // enter armature edit mode - ED_armature_to_edit(ob_arm); - - leaf_bones.clear(); - totbone = 0; - // bone_direction_row = 1; // TODO: don't default to Y but use asset and based on it decide on default row - leaf_bone_length = 0.1f; - // min_angle = 360.0f; // minimum angle between bone head-tail and a row of bone matrix - - // create bones - /* - TODO: - check if bones have already been created for a given joint - */ - - std::vector<COLLADAFW::Node*>::iterator ri; - for (ri = root_joints.begin(); ri != root_joints.end(); ri++) { - // for shared armature check if bone tree is already created - if (shared && std::find(skin_root_joints.begin(), skin_root_joints.end(), *ri) != skin_root_joints.end()) - continue; - - // since root_joints may contain joints for multiple controllers, we need to filter - if (skin.uses_joint_or_descendant(*ri)) { - create_bone(skin, *ri, NULL, (*ri)->getChildNodes().getCount(), NULL, (bArmature*)ob_arm->data); - - if (joint_parent_map.find((*ri)->getUniqueId()) != joint_parent_map.end() && !skin.get_parent()) - skin.set_parent(joint_parent_map[(*ri)->getUniqueId()]); - } - } - - fix_leaf_bones(); - - // exit armature edit mode - ED_armature_from_edit(ob_arm); - ED_armature_edit_free(ob_arm); - DAG_id_flush_update(&ob_arm->id, OB_RECALC_OB|OB_RECALC_DATA); - - set_leaf_bone_shapes(ob_arm); - - // set_euler_rotmode(); - } - - -public: - - ArmatureImporter(UnitConverter *conv, MeshImporterBase *mesh, AnimationImporterBase *anim, Scene *sce) : - TransformReader(conv), scene(sce), empty(NULL), mesh_importer(mesh), anim_importer(anim) {} - - ~ArmatureImporter() - { - // free skin controller data if we forget to do this earlier - std::map<COLLADAFW::UniqueId, SkinInfo>::iterator it; - for (it = skin_by_data_uid.begin(); it != skin_by_data_uid.end(); it++) { - it->second.free(); - } - } - - // root - if this joint is the top joint in hierarchy, if a joint - // is a child of a node (not joint), root should be true since - // this is where we build armature bones from - void add_joint(COLLADAFW::Node *node, bool root, Object *parent) - { - joint_by_uid[node->getUniqueId()] = node; - if (root) { - root_joints.push_back(node); - - if (parent) - joint_parent_map[node->getUniqueId()] = parent; - } - } - -#if 0 - void add_root_joint(COLLADAFW::Node *node) - { - // root_joints.push_back(node); - Object *ob_arm = find_armature(node); - if (ob_arm) { - get_armature_joints(ob_arm).root_joints.push_back(node); - } -#ifdef COLLADA_DEBUG - else { - fprintf(stderr, "%s cannot be added to armature.\n", get_joint_name(node)); - } -#endif - } -#endif - - // here we add bones to armatures, having armatures previously created in write_controller - void make_armatures(bContext *C) - { - std::map<COLLADAFW::UniqueId, SkinInfo>::iterator it; - for (it = skin_by_data_uid.begin(); it != skin_by_data_uid.end(); it++) { - - SkinInfo& skin = it->second; - - create_armature_bones(skin); - - // link armature with a mesh object - Object *ob = mesh_importer->get_object_by_geom_uid(*get_geometry_uid(skin.get_controller_uid())); - if (ob) - skin.link_armature(C, ob, joint_by_uid, this); - else - fprintf(stderr, "Cannot find object to link armature with.\n"); - - // set armature parent if any - Object *par = skin.get_parent(); - if (par) - set_parent(skin.get_armature(), par, C, false); - - // free memory stolen from SkinControllerData - skin.free(); - } - } - -#if 0 - // link with meshes, create vertex groups, assign weights - void link_armature(Object *ob_arm, const COLLADAFW::UniqueId& geom_id, const COLLADAFW::UniqueId& controller_data_id) - { - Object *ob = mesh_importer->get_object_by_geom_uid(geom_id); - - if (!ob) { - fprintf(stderr, "Cannot find object by geometry UID.\n"); - return; - } - - if (skin_by_data_uid.find(controller_data_id) == skin_by_data_uid.end()) { - fprintf(stderr, "Cannot find skin info by controller data UID.\n"); - return; - } - - SkinInfo& skin = skin_by_data_uid[conroller_data_id]; - - // create vertex groups - } -#endif - - bool write_skin_controller_data(const COLLADAFW::SkinControllerData* data) - { - // at this stage we get vertex influence info that should go into me->verts and ob->defbase - // there's no info to which object this should be long so we associate it with skin controller data UID - - // don't forget to call defgroup_unique_name before we copy - - // controller data uid -> [armature] -> joint data, - // [mesh object] - // - - SkinInfo skin(unit_converter); - skin.borrow_skin_controller_data(data); - - // store join inv bind matrix to use it later in armature construction - const COLLADAFW::Matrix4Array& inv_bind_mats = data->getInverseBindMatrices(); - for (unsigned int i = 0; i < data->getJointsCount(); i++) { - skin.add_joint(inv_bind_mats[i]); - } - - skin_by_data_uid[data->getUniqueId()] = skin; - - return true; - } - - bool write_controller(const COLLADAFW::Controller* controller) - { - // - create and store armature object - - const COLLADAFW::UniqueId& skin_id = controller->getUniqueId(); - - if (controller->getControllerType() == COLLADAFW::Controller::CONTROLLER_TYPE_SKIN) { - COLLADAFW::SkinController *co = (COLLADAFW::SkinController*)controller; - // to be able to find geom id by controller id - geom_uid_by_controller_uid[skin_id] = co->getSource(); - - const COLLADAFW::UniqueId& data_uid = co->getSkinControllerData(); - if (skin_by_data_uid.find(data_uid) == skin_by_data_uid.end()) { - fprintf(stderr, "Cannot find skin by controller data UID.\n"); - return true; - } - - skin_by_data_uid[data_uid].set_controller(co); - } - // morph controller - else { - // shape keys? :) - fprintf(stderr, "Morph controller is not supported yet.\n"); - } - - return true; - } - - COLLADAFW::UniqueId *get_geometry_uid(const COLLADAFW::UniqueId& controller_uid) - { - if (geom_uid_by_controller_uid.find(controller_uid) == geom_uid_by_controller_uid.end()) - return NULL; - - return &geom_uid_by_controller_uid[controller_uid]; - } - - Object *get_armature_for_joint(COLLADAFW::Node *node) - { - std::map<COLLADAFW::UniqueId, SkinInfo>::iterator it; - for (it = skin_by_data_uid.begin(); it != skin_by_data_uid.end(); it++) { - SkinInfo& skin = it->second; - - if (skin.uses_joint_or_descendant(node)) - return skin.get_armature(); - } - - return NULL; - } - - void get_rna_path_for_joint(COLLADAFW::Node *node, char *joint_path, size_t count) - { - BLI_snprintf(joint_path, count, "pose.bones[\"%s\"]", get_joint_name(node)); - } - - // gives a world-space mat - bool get_joint_bind_mat(float m[][4], COLLADAFW::Node *joint) - { - std::map<COLLADAFW::UniqueId, SkinInfo>::iterator it; - bool found = false; - for (it = skin_by_data_uid.begin(); it != skin_by_data_uid.end(); it++) { - SkinInfo& skin = it->second; - if ((found = skin.get_joint_inv_bind_matrix(m, joint))) { - invert_m4(m); - break; - } - } - - return found; - } -}; - -class MeshImporter : public MeshImporterBase -{ -private: - - Scene *scene; - ArmatureImporter *armature_importer; - - std::map<COLLADAFW::UniqueId, Mesh*> uid_mesh_map; // geometry unique id-to-mesh map - std::map<COLLADAFW::UniqueId, Object*> uid_object_map; // geom uid-to-object - // this structure is used to assign material indices to faces - // it holds a portion of Mesh faces and corresponds to a DAE primitive list (<triangles>, <polylist>, etc.) - struct Primitive { - MFace *mface; - unsigned int totface; - }; - typedef std::map<COLLADAFW::MaterialId, std::vector<Primitive> > MaterialIdPrimitiveArrayMap; - std::map<COLLADAFW::UniqueId, MaterialIdPrimitiveArrayMap> geom_uid_mat_mapping_map; // crazy name! - - class UVDataWrapper - { - COLLADAFW::MeshVertexData *mVData; - public: - UVDataWrapper(COLLADAFW::MeshVertexData& vdata) : mVData(&vdata) - {} - -#ifdef COLLADA_DEBUG - void print() - { - fprintf(stderr, "UVs:\n"); - switch(mVData->getType()) { - case COLLADAFW::MeshVertexData::DATA_TYPE_FLOAT: - { - COLLADAFW::ArrayPrimitiveType<float>* values = mVData->getFloatValues(); - if (values->getCount()) { - for (int i = 0; i < values->getCount(); i += 2) { - fprintf(stderr, "%.1f, %.1f\n", (*values)[i], (*values)[i+1]); - } - } - } - break; - case COLLADAFW::MeshVertexData::DATA_TYPE_DOUBLE: - { - COLLADAFW::ArrayPrimitiveType<double>* values = mVData->getDoubleValues(); - if (values->getCount()) { - for (int i = 0; i < values->getCount(); i += 2) { - fprintf(stderr, "%.1f, %.1f\n", (float)(*values)[i], (float)(*values)[i+1]); - } - } - } - break; - } - fprintf(stderr, "\n"); - } -#endif - - void getUV(int uv_index[2], float *uv) - { - switch(mVData->getType()) { - case COLLADAFW::MeshVertexData::DATA_TYPE_FLOAT: - { - COLLADAFW::ArrayPrimitiveType<float>* values = mVData->getFloatValues(); - if (values->empty()) return; - uv[0] = (*values)[uv_index[0]]; - uv[1] = (*values)[uv_index[1]]; - - } - break; - case COLLADAFW::MeshVertexData::DATA_TYPE_DOUBLE: - { - COLLADAFW::ArrayPrimitiveType<double>* values = mVData->getDoubleValues(); - if (values->empty()) return; - uv[0] = (float)(*values)[uv_index[0]]; - uv[1] = (float)(*values)[uv_index[1]]; - - } - break; - case COLLADAFW::MeshVertexData::DATA_TYPE_UNKNOWN: - default: - fprintf(stderr, "MeshImporter.getUV(): unknown data type\n"); - } - } - }; - - void set_face_indices(MFace *mface, unsigned int *indices, bool quad) - { - mface->v1 = indices[0]; - mface->v2 = indices[1]; - mface->v3 = indices[2]; - if (quad) mface->v4 = indices[3]; - else mface->v4 = 0; -#ifdef COLLADA_DEBUG - // fprintf(stderr, "%u, %u, %u \n", indices[0], indices[1], indices[2]); -#endif - } - - // not used anymore, test_index_face from blenkernel is better -#if 0 - // change face indices order so that v4 is not 0 - void rotate_face_indices(MFace *mface) { - mface->v4 = mface->v1; - mface->v1 = mface->v2; - mface->v2 = mface->v3; - mface->v3 = 0; - } -#endif - - void set_face_uv(MTFace *mtface, UVDataWrapper &uvs, - COLLADAFW::IndexList& index_list, unsigned int *tris_indices) - { - int uv_indices[4][2]; - - // per face vertex indices, this means for quad we have 4 indices, not 8 - COLLADAFW::UIntValuesArray& indices = index_list.getIndices(); - - // make indices into FloatOrDoubleArray - for (int i = 0; i < 3; i++) { - int uv_index = indices[tris_indices[i]]; - uv_indices[i][0] = uv_index * 2; - uv_indices[i][1] = uv_index * 2 + 1; - } - - uvs.getUV(uv_indices[0], mtface->uv[0]); - uvs.getUV(uv_indices[1], mtface->uv[1]); - uvs.getUV(uv_indices[2], mtface->uv[2]); - } - - void set_face_uv(MTFace *mtface, UVDataWrapper &uvs, - COLLADAFW::IndexList& index_list, int index, bool quad) - { - int uv_indices[4][2]; - - // per face vertex indices, this means for quad we have 4 indices, not 8 - COLLADAFW::UIntValuesArray& indices = index_list.getIndices(); - - // make indices into FloatOrDoubleArray - for (int i = 0; i < (quad ? 4 : 3); i++) { - int uv_index = indices[index + i]; - uv_indices[i][0] = uv_index * 2; - uv_indices[i][1] = uv_index * 2 + 1; - } - - uvs.getUV(uv_indices[0], mtface->uv[0]); - uvs.getUV(uv_indices[1], mtface->uv[1]); - uvs.getUV(uv_indices[2], mtface->uv[2]); - - if (quad) uvs.getUV(uv_indices[3], mtface->uv[3]); - -#ifdef COLLADA_DEBUG - /*if (quad) { - fprintf(stderr, "face uv:\n" - "((%d, %d), (%d, %d), (%d, %d), (%d, %d))\n" - "((%.1f, %.1f), (%.1f, %.1f), (%.1f, %.1f), (%.1f, %.1f))\n", - - uv_indices[0][0], uv_indices[0][1], - uv_indices[1][0], uv_indices[1][1], - uv_indices[2][0], uv_indices[2][1], - uv_indices[3][0], uv_indices[3][1], - - mtface->uv[0][0], mtface->uv[0][1], - mtface->uv[1][0], mtface->uv[1][1], - mtface->uv[2][0], mtface->uv[2][1], - mtface->uv[3][0], mtface->uv[3][1]); - } - else { - fprintf(stderr, "face uv:\n" - "((%d, %d), (%d, %d), (%d, %d))\n" - "((%.1f, %.1f), (%.1f, %.1f), (%.1f, %.1f))\n", - - uv_indices[0][0], uv_indices[0][1], - uv_indices[1][0], uv_indices[1][1], - uv_indices[2][0], uv_indices[2][1], - - mtface->uv[0][0], mtface->uv[0][1], - mtface->uv[1][0], mtface->uv[1][1], - mtface->uv[2][0], mtface->uv[2][1]); - }*/ -#endif - } - -#ifdef COLLADA_DEBUG - void print_index_list(COLLADAFW::IndexList& index_list) - { - fprintf(stderr, "Index list for \"%s\":\n", index_list.getName().c_str()); - for (int i = 0; i < index_list.getIndicesCount(); i += 2) { - fprintf(stderr, "%u, %u\n", index_list.getIndex(i), index_list.getIndex(i + 1)); - } - fprintf(stderr, "\n"); - } -#endif - - bool is_nice_mesh(COLLADAFW::Mesh *mesh) - { - COLLADAFW::MeshPrimitiveArray& prim_arr = mesh->getMeshPrimitives(); - - const char *name = get_dae_name(mesh); - - for (unsigned i = 0; i < prim_arr.getCount(); i++) { - - COLLADAFW::MeshPrimitive *mp = prim_arr[i]; - COLLADAFW::MeshPrimitive::PrimitiveType type = mp->getPrimitiveType(); - - const char *type_str = primTypeToStr(type); - - // OpenCollada passes POLYGONS type for <polylist> - if (type == COLLADAFW::MeshPrimitive::POLYLIST || type == COLLADAFW::MeshPrimitive::POLYGONS) { - - COLLADAFW::Polygons *mpvc = (COLLADAFW::Polygons*)mp; - COLLADAFW::Polygons::VertexCountArray& vca = mpvc->getGroupedVerticesVertexCountArray(); - - for(unsigned int j = 0; j < vca.getCount(); j++){ - int count = vca[j]; - if (count < 3) { - fprintf(stderr, "Primitive %s in %s has at least one face with vertex count < 3\n", - type_str, name); - return false; - } - } - - } - else if(type != COLLADAFW::MeshPrimitive::TRIANGLES) { - fprintf(stderr, "Primitive type %s is not supported.\n", type_str); - return false; - } - } - - if (mesh->getPositions().empty()) { - fprintf(stderr, "Mesh %s has no vertices.\n", name); - return false; - } - - return true; - } - - void read_vertices(COLLADAFW::Mesh *mesh, Mesh *me) - { - // vertices - me->totvert = mesh->getPositions().getFloatValues()->getCount() / 3; - me->mvert = (MVert*)CustomData_add_layer(&me->vdata, CD_MVERT, CD_CALLOC, NULL, me->totvert); - - COLLADAFW::MeshVertexData& pos = mesh->getPositions(); - MVert *mvert; - int i; - - for (i = 0, mvert = me->mvert; i < me->totvert; i++, mvert++) - get_vector(mvert->co, pos, i); - } - - int triangulate_poly(unsigned int *indices, int totvert, MVert *verts, std::vector<unsigned int>& tri) - { - ListBase dispbase; - DispList *dl; - float *vert; - int i = 0; - - dispbase.first = dispbase.last = NULL; - - dl = (DispList*)MEM_callocN(sizeof(DispList), "poly disp"); - dl->nr = totvert; - dl->type = DL_POLY; - dl->parts = 1; - dl->verts = vert = (float*)MEM_callocN(totvert * 3 * sizeof(float), "poly verts"); - dl->index = (int*)MEM_callocN(sizeof(int) * 3 * totvert, "dl index"); - - BLI_addtail(&dispbase, dl); - - for (i = 0; i < totvert; i++) { - copy_v3_v3(vert, verts[indices[i]].co); - vert += 3; - } - - filldisplist(&dispbase, &dispbase, 0); - - int tottri = 0; - dl= (DispList*)dispbase.first; - - if (dl->type == DL_INDEX3) { - tottri = dl->parts; - - int *index = dl->index; - for (i= 0; i < tottri; i++) { - int t[3]= {*index, *(index + 1), *(index + 2)}; - - std::sort(t, t + 3); - - tri.push_back(t[0]); - tri.push_back(t[1]); - tri.push_back(t[2]); - - index += 3; - } - } - - freedisplist(&dispbase); - - return tottri; - } - - int count_new_tris(COLLADAFW::Mesh *mesh, Mesh *me) - { - COLLADAFW::MeshPrimitiveArray& prim_arr = mesh->getMeshPrimitives(); - unsigned int i; - int tottri = 0; - - for (i = 0; i < prim_arr.getCount(); i++) { - - COLLADAFW::MeshPrimitive *mp = prim_arr[i]; - int type = mp->getPrimitiveType(); - size_t prim_totface = mp->getFaceCount(); - unsigned int *indices = mp->getPositionIndices().getData(); - - if (type == COLLADAFW::MeshPrimitive::POLYLIST || - type == COLLADAFW::MeshPrimitive::POLYGONS) { - - COLLADAFW::Polygons *mpvc = (COLLADAFW::Polygons*)mp; - COLLADAFW::Polygons::VertexCountArray& vcounta = mpvc->getGroupedVerticesVertexCountArray(); - - for (unsigned int j = 0; j < prim_totface; j++) { - int vcount = vcounta[j]; - - if (vcount > 4) { - std::vector<unsigned int> tri; - - // tottri += triangulate_poly(indices, vcount, me->mvert, tri) - 1; // XXX why - 1?! - tottri += triangulate_poly(indices, vcount, me->mvert, tri); - } - - indices += vcount; - } - } - } - return tottri; - } - - // TODO: import uv set names - void read_faces(COLLADAFW::Mesh *mesh, Mesh *me, int new_tris) - { - unsigned int i; - - // allocate faces - me->totface = mesh->getFacesCount() + new_tris; - me->mface = (MFace*)CustomData_add_layer(&me->fdata, CD_MFACE, CD_CALLOC, NULL, me->totface); - - // allocate UV layers - unsigned int totuvset = mesh->getUVCoords().getInputInfosArray().getCount(); - - for (i = 0; i < totuvset; i++) { - if (mesh->getUVCoords().getLength(i) == 0) { - totuvset = 0; - break; - } - } - - for (i = 0; i < totuvset; i++) { - COLLADAFW::MeshVertexData::InputInfos *info = mesh->getUVCoords().getInputInfosArray()[i]; - CustomData_add_layer_named(&me->fdata, CD_MTFACE, CD_CALLOC, NULL, me->totface, info->mName.c_str()); - //this->set_layername_map[i] = CustomData_get_layer_name(&me->fdata, CD_MTFACE, i); - } - - // activate the first uv layer - if (totuvset) me->mtface = (MTFace*)CustomData_get_layer_n(&me->fdata, CD_MTFACE, 0); - - UVDataWrapper uvs(mesh->getUVCoords()); - -#ifdef COLLADA_DEBUG - // uvs.print(); -#endif - - MFace *mface = me->mface; - - MaterialIdPrimitiveArrayMap mat_prim_map; - - int face_index = 0; - - COLLADAFW::MeshPrimitiveArray& prim_arr = mesh->getMeshPrimitives(); +#include "TransformReader.h" +#include "AnimationImporter.h" +#include "ArmatureImporter.h" +#include "MeshImporter.h" +#include "collada_utils.h" - bool has_normals = mesh->hasNormals(); - COLLADAFW::MeshVertexData& nor = mesh->getNormals(); - - for (i = 0; i < prim_arr.getCount(); i++) { - - COLLADAFW::MeshPrimitive *mp = prim_arr[i]; - - // faces - size_t prim_totface = mp->getFaceCount(); - unsigned int *indices = mp->getPositionIndices().getData(); - unsigned int *nind = mp->getNormalIndices().getData(); - unsigned int j, k; - int type = mp->getPrimitiveType(); - int index = 0; - - // since we cannot set mface->mat_nr here, we store a portion of me->mface in Primitive - Primitive prim = {mface, 0}; - COLLADAFW::IndexListArray& index_list_array = mp->getUVCoordIndicesArray(); - -#ifdef COLLADA_DEBUG - /* - fprintf(stderr, "Primitive %d:\n", i); - for (int j = 0; j < totuvset; j++) { - print_index_list(*index_list_array[j]); - } - */ -#endif - - if (type == COLLADAFW::MeshPrimitive::TRIANGLES) { - for (j = 0; j < prim_totface; j++){ - - set_face_indices(mface, indices, false); - indices += 3; - -#if 0 - for (k = 0; k < totuvset; k++) { - if (!index_list_array.empty() && index_list_array[k]) { - // get mtface by face index and uv set index - MTFace *mtface = (MTFace*)CustomData_get_layer_n(&me->fdata, CD_MTFACE, k); - set_face_uv(&mtface[face_index], uvs, k, *index_list_array[k], index, false); - } - } -#else - for (k = 0; k < index_list_array.getCount(); k++) { - int uvset_index = index_list_array[k]->getSetIndex(); - - // get mtface by face index and uv set index - MTFace *mtface = (MTFace*)CustomData_get_layer_n(&me->fdata, CD_MTFACE, uvset_index); - set_face_uv(&mtface[face_index], uvs, *index_list_array[k], index, false); - } -#endif - - test_index_face(mface, &me->fdata, face_index, 3); - - if (has_normals) { - if (!flat_face(nind, nor, 3)) - mface->flag |= ME_SMOOTH; - - nind += 3; - } - - index += 3; - mface++; - face_index++; - prim.totface++; - } - } - else if (type == COLLADAFW::MeshPrimitive::POLYLIST || type == COLLADAFW::MeshPrimitive::POLYGONS) { - COLLADAFW::Polygons *mpvc = (COLLADAFW::Polygons*)mp; - COLLADAFW::Polygons::VertexCountArray& vcounta = mpvc->getGroupedVerticesVertexCountArray(); - - for (j = 0; j < prim_totface; j++) { - - // face - int vcount = vcounta[j]; - if (vcount == 3 || vcount == 4) { - - set_face_indices(mface, indices, vcount == 4); - - // set mtface for each uv set - // it is assumed that all primitives have equal number of UV sets - -#if 0 - for (k = 0; k < totuvset; k++) { - if (!index_list_array.empty() && index_list_array[k]) { - // get mtface by face index and uv set index - MTFace *mtface = (MTFace*)CustomData_get_layer_n(&me->fdata, CD_MTFACE, k); - set_face_uv(&mtface[face_index], uvs, k, *index_list_array[k], index, mface->v4 != 0); - } - } -#else - for (k = 0; k < index_list_array.getCount(); k++) { - int uvset_index = index_list_array[k]->getSetIndex(); - - // get mtface by face index and uv set index - MTFace *mtface = (MTFace*)CustomData_get_layer_n(&me->fdata, CD_MTFACE, uvset_index); - set_face_uv(&mtface[face_index], uvs, *index_list_array[k], index, mface->v4 != 0); - } -#endif - - test_index_face(mface, &me->fdata, face_index, vcount); - - if (has_normals) { - if (!flat_face(nind, nor, vcount)) - mface->flag |= ME_SMOOTH; - - nind += vcount; - } - - mface++; - face_index++; - prim.totface++; - - } - else { - std::vector<unsigned int> tri; - - triangulate_poly(indices, vcount, me->mvert, tri); - - for (k = 0; k < tri.size() / 3; k++) { - int v = k * 3; - unsigned int uv_indices[3] = { - index + tri[v], - index + tri[v + 1], - index + tri[v + 2] - }; - unsigned int tri_indices[3] = { - indices[tri[v]], - indices[tri[v + 1]], - indices[tri[v + 2]] - }; - - set_face_indices(mface, tri_indices, false); - -#if 0 - for (unsigned int l = 0; l < totuvset; l++) { - if (!index_list_array.empty() && index_list_array[l]) { - // get mtface by face index and uv set index - MTFace *mtface = (MTFace*)CustomData_get_layer_n(&me->fdata, CD_MTFACE, l); - set_face_uv(&mtface[face_index], uvs, l, *index_list_array[l], uv_indices); - } - } -#else - for (unsigned int l = 0; l < index_list_array.getCount(); l++) { - int uvset_index = index_list_array[l]->getSetIndex(); - - // get mtface by face index and uv set index - MTFace *mtface = (MTFace*)CustomData_get_layer_n(&me->fdata, CD_MTFACE, uvset_index); - set_face_uv(&mtface[face_index], uvs, *index_list_array[l], uv_indices); - } -#endif - - - test_index_face(mface, &me->fdata, face_index, 3); - - if (has_normals) { - unsigned int ntri[3] = {nind[tri[v]], nind[tri[v + 1]], nind[tri[v + 2]]}; - - if (!flat_face(ntri, nor, 3)) - mface->flag |= ME_SMOOTH; - } - - mface++; - face_index++; - prim.totface++; - } - - if (has_normals) - nind += vcount; - } - - index += vcount; - indices += vcount; - } - } - - mat_prim_map[mp->getMaterialId()].push_back(prim); - } - - geom_uid_mat_mapping_map[mesh->getUniqueId()] = mat_prim_map; - } - - void get_vector(float v[3], COLLADAFW::MeshVertexData& arr, int i) - { - i *= 3; - - switch(arr.getType()) { - case COLLADAFW::MeshVertexData::DATA_TYPE_FLOAT: - { - COLLADAFW::ArrayPrimitiveType<float>* values = arr.getFloatValues(); - if (values->empty()) return; - - v[0] = (*values)[i++]; - v[1] = (*values)[i++]; - v[2] = (*values)[i]; - } - break; - case COLLADAFW::MeshVertexData::DATA_TYPE_DOUBLE: - { - COLLADAFW::ArrayPrimitiveType<double>* values = arr.getDoubleValues(); - if (values->empty()) return; - - v[0] = (float)(*values)[i++]; - v[1] = (float)(*values)[i++]; - v[2] = (float)(*values)[i]; - } - break; - default: - break; - } - } - - bool flat_face(unsigned int *nind, COLLADAFW::MeshVertexData& nor, int count) - { - float a[3], b[3]; - - get_vector(a, nor, *nind); - normalize_v3(a); - - nind++; - - for (int i = 1; i < count; i++, nind++) { - get_vector(b, nor, *nind); - normalize_v3(b); - - float dp = dot_v3v3(a, b); - - if (dp < 0.99999f || dp > 1.00001f) - return false; - } - - return true; - } - -public: - - MeshImporter(ArmatureImporter *arm, Scene *sce) : scene(sce), armature_importer(arm) {} - - virtual Object *get_object_by_geom_uid(const COLLADAFW::UniqueId& geom_uid) - { - if (uid_object_map.find(geom_uid) != uid_object_map.end()) - return uid_object_map[geom_uid]; - return NULL; - } - - MTex *assign_textures_to_uvlayer(COLLADAFW::TextureCoordinateBinding &ctexture, - Mesh *me, TexIndexTextureArrayMap& texindex_texarray_map, - MTex *color_texture) - { - const COLLADAFW::TextureMapId texture_index = ctexture.getTextureMapId(); - const size_t setindex = ctexture.getSetIndex(); - std::string uvname = ctexture.getName(); - - const CustomData *data = &me->fdata; - int layer_index = CustomData_get_layer_index(data, CD_MTFACE); - CustomDataLayer *cdl = &data->layers[layer_index+setindex]; - - /* set uvname to bind_vertex_input semantic */ - BLI_strncpy(cdl->name, uvname.c_str(), sizeof(cdl->name)); - - if (texindex_texarray_map.find(texture_index) == texindex_texarray_map.end()) { - - fprintf(stderr, "Cannot find texture array by texture index.\n"); - return color_texture; - } - - std::vector<MTex*> textures = texindex_texarray_map[texture_index]; - - std::vector<MTex*>::iterator it; - - for (it = textures.begin(); it != textures.end(); it++) { - - MTex *texture = *it; - - if (texture) { - BLI_strncpy(texture->uvname, uvname.c_str(), sizeof(texture->uvname)); - if (texture->mapto == MAP_COL) color_texture = texture; - } - } - return color_texture; - } - - MTFace *assign_material_to_geom(COLLADAFW::MaterialBinding cmaterial, - std::map<COLLADAFW::UniqueId, Material*>& uid_material_map, - Object *ob, const COLLADAFW::UniqueId *geom_uid, - MTex **color_texture, char *layername, MTFace *texture_face, - std::map<Material*, TexIndexTextureArrayMap>& material_texture_mapping_map, int mat_index) - { - Mesh *me = (Mesh*)ob->data; - const COLLADAFW::UniqueId& ma_uid = cmaterial.getReferencedMaterial(); - - // do we know this material? - if (uid_material_map.find(ma_uid) == uid_material_map.end()) { - - fprintf(stderr, "Cannot find material by UID.\n"); - return NULL; - } - - Material *ma = uid_material_map[ma_uid]; - assign_material(ob, ma, ob->totcol + 1); - - COLLADAFW::TextureCoordinateBindingArray& tex_array = - cmaterial.getTextureCoordinateBindingArray(); - TexIndexTextureArrayMap texindex_texarray_map = material_texture_mapping_map[ma]; - unsigned int i; - // loop through <bind_vertex_inputs> - for (i = 0; i < tex_array.getCount(); i++) { - - *color_texture = assign_textures_to_uvlayer(tex_array[i], me, texindex_texarray_map, - *color_texture); - } - - // set texture face - if (*color_texture && - strlen((*color_texture)->uvname) && - strcmp(layername, (*color_texture)->uvname) != 0) { - - texture_face = (MTFace*)CustomData_get_layer_named(&me->fdata, CD_MTFACE, - (*color_texture)->uvname); - strcpy(layername, (*color_texture)->uvname); - } - - MaterialIdPrimitiveArrayMap& mat_prim_map = geom_uid_mat_mapping_map[*geom_uid]; - COLLADAFW::MaterialId mat_id = cmaterial.getMaterialId(); - - // assign material indices to mesh faces - if (mat_prim_map.find(mat_id) != mat_prim_map.end()) { - - std::vector<Primitive>& prims = mat_prim_map[mat_id]; - - std::vector<Primitive>::iterator it; - - for (it = prims.begin(); it != prims.end(); it++) { - Primitive& prim = *it; - i = 0; - while (i++ < prim.totface) { - prim.mface->mat_nr = mat_index; - prim.mface++; - // bind texture images to faces - if (texture_face && (*color_texture)) { - texture_face->mode = TF_TEX; - texture_face->tpage = (Image*)(*color_texture)->tex->ima; - texture_face++; - } - } - } - } - - return texture_face; - } - - - Object *create_mesh_object(COLLADAFW::Node *node, COLLADAFW::InstanceGeometry *geom, - bool isController, - std::map<COLLADAFW::UniqueId, Material*>& uid_material_map, - std::map<Material*, TexIndexTextureArrayMap>& material_texture_mapping_map) - { - const COLLADAFW::UniqueId *geom_uid = &geom->getInstanciatedObjectId(); - - // check if node instanciates controller or geometry - if (isController) { - - geom_uid = armature_importer->get_geometry_uid(*geom_uid); - - if (!geom_uid) { - fprintf(stderr, "Couldn't find a mesh UID by controller's UID.\n"); - return NULL; - } - } - else { - - if (uid_mesh_map.find(*geom_uid) == uid_mesh_map.end()) { - // this could happen if a mesh was not created - // (e.g. if it contains unsupported geometry) - fprintf(stderr, "Couldn't find a mesh by UID.\n"); - return NULL; - } - } - if (!uid_mesh_map[*geom_uid]) return NULL; - - Object *ob = add_object(scene, OB_MESH); - - // store object pointer for ArmatureImporter - uid_object_map[*geom_uid] = ob; - - // name Object - const std::string& id = node->getOriginalId(); - if (id.length()) - rename_id(&ob->id, (char*)id.c_str()); - - // replace ob->data freeing the old one - Mesh *old_mesh = (Mesh*)ob->data; - - set_mesh(ob, uid_mesh_map[*geom_uid]); - - if (old_mesh->id.us == 0) free_libblock(&G.main->mesh, old_mesh); - - char layername[100]; - MTFace *texture_face = NULL; - MTex *color_texture = NULL; - - COLLADAFW::MaterialBindingArray& mat_array = - geom->getMaterialBindings(); - - // loop through geom's materials - for (unsigned int i = 0; i < mat_array.getCount(); i++) { - - texture_face = assign_material_to_geom(mat_array[i], uid_material_map, ob, geom_uid, - &color_texture, layername, texture_face, - material_texture_mapping_map, i); - } - - return ob; - } - - // create a mesh storing a pointer in a map so it can be retrieved later by geometry UID - bool write_geometry(const COLLADAFW::Geometry* geom) - { - // TODO: import also uvs, normals - // XXX what to do with normal indices? - // XXX num_normals may be != num verts, then what to do? - - // check geometry->getType() first - if (geom->getType() != COLLADAFW::Geometry::GEO_TYPE_MESH) { - // TODO: report warning - fprintf(stderr, "Mesh type %s is not supported\n", geomTypeToStr(geom->getType())); - return true; - } - - COLLADAFW::Mesh *mesh = (COLLADAFW::Mesh*)geom; - - if (!is_nice_mesh(mesh)) { - fprintf(stderr, "Ignoring mesh %s\n", get_dae_name(mesh)); - return true; - } - - const std::string& str_geom_id = mesh->getOriginalId(); - Mesh *me = add_mesh((char*)str_geom_id.c_str()); - - // store the Mesh pointer to link it later with an Object - this->uid_mesh_map[mesh->getUniqueId()] = me; - - int new_tris = 0; - - read_vertices(mesh, me); - - new_tris = count_new_tris(mesh, me); - - read_faces(mesh, me, new_tris); - - make_edges(me, 0); - - mesh_calc_normals(me->mvert, me->totvert, me->mface, me->totface, NULL); - - return true; - } - -}; - -class AnimationImporter : private TransformReader, public AnimationImporterBase -{ -private: - - ArmatureImporter *armature_importer; - Scene *scene; - - std::map<COLLADAFW::UniqueId, std::vector<FCurve*> > curve_map; - std::map<COLLADAFW::UniqueId, TransformReader::Animation> uid_animated_map; - // std::map<bActionGroup*, std::vector<FCurve*> > fcurves_actionGroup_map; - std::map<COLLADAFW::UniqueId, const COLLADAFW::AnimationList*> animlist_map; - std::vector<FCurve*> unused_curves; - std::map<COLLADAFW::UniqueId, Object*> joint_objects; - - FCurve *create_fcurve(int array_index, const char *rna_path) - { - FCurve *fcu = (FCurve*)MEM_callocN(sizeof(FCurve), "FCurve"); - - fcu->flag = (FCURVE_VISIBLE|FCURVE_AUTO_HANDLES|FCURVE_SELECTED); - fcu->rna_path = BLI_strdupn(rna_path, strlen(rna_path)); - fcu->array_index = array_index; - return fcu; - } - - void create_bezt(FCurve *fcu, float frame, float output) - { - BezTriple bez; - memset(&bez, 0, sizeof(BezTriple)); - bez.vec[1][0] = frame; - bez.vec[1][1] = output; - bez.ipo = U.ipo_new; /* use default interpolation mode here... */ - bez.f1 = bez.f2 = bez.f3 = SELECT; - bez.h1 = bez.h2 = HD_AUTO; - insert_bezt_fcurve(fcu, &bez, 0); - calchandles_fcurve(fcu); - } - - // create one or several fcurves depending on the number of parameters being animated - void animation_to_fcurves(COLLADAFW::AnimationCurve *curve) - { - COLLADAFW::FloatOrDoubleArray& input = curve->getInputValues(); - COLLADAFW::FloatOrDoubleArray& output = curve->getOutputValues(); - // COLLADAFW::FloatOrDoubleArray& intan = curve->getInTangentValues(); - // COLLADAFW::FloatOrDoubleArray& outtan = curve->getOutTangentValues(); - float fps = (float)FPS; - size_t dim = curve->getOutDimension(); - unsigned int i; - - std::vector<FCurve*>& fcurves = curve_map[curve->getUniqueId()]; - - switch (dim) { - case 1: // X, Y, Z or angle - case 3: // XYZ - case 16: // matrix - { - for (i = 0; i < dim; i++ ) { - FCurve *fcu = (FCurve*)MEM_callocN(sizeof(FCurve), "FCurve"); - - fcu->flag = (FCURVE_VISIBLE|FCURVE_AUTO_HANDLES|FCURVE_SELECTED); - // fcu->rna_path = BLI_strdupn(path, strlen(path)); - fcu->array_index = 0; - //fcu->totvert = curve->getKeyCount(); - - // create beztriple for each key - for (unsigned int j = 0; j < curve->getKeyCount(); j++) { - BezTriple bez; - memset(&bez, 0, sizeof(BezTriple)); - - // intangent - // bez.vec[0][0] = get_float_value(intan, j * 6 + i + i) * fps; - // bez.vec[0][1] = get_float_value(intan, j * 6 + i + i + 1); - - // input, output - bez.vec[1][0] = get_float_value(input, j) * fps; - bez.vec[1][1] = get_float_value(output, j * dim + i); - - // outtangent - // bez.vec[2][0] = get_float_value(outtan, j * 6 + i + i) * fps; - // bez.vec[2][1] = get_float_value(outtan, j * 6 + i + i + 1); - - bez.ipo = U.ipo_new; /* use default interpolation mode here... */ - bez.f1 = bez.f2 = bez.f3 = SELECT; - bez.h1 = bez.h2 = HD_AUTO; - insert_bezt_fcurve(fcu, &bez, 0); - } - - calchandles_fcurve(fcu); - - fcurves.push_back(fcu); - } - } - break; - default: - fprintf(stderr, "Output dimension of %d is not yet supported (animation id = %s)\n", dim, curve->getOriginalId().c_str()); - } - - for (std::vector<FCurve*>::iterator it = fcurves.begin(); it != fcurves.end(); it++) - unused_curves.push_back(*it); - } - - void fcurve_deg_to_rad(FCurve *cu) - { - for (unsigned int i = 0; i < cu->totvert; i++) { - // TODO convert handles too - cu->bezt[i].vec[1][1] *= M_PI / 180.0f; - } - } - - void add_fcurves_to_object(Object *ob, std::vector<FCurve*>& curves, char *rna_path, int array_index, Animation *animated) - { - bAction *act; - - if (!ob->adt || !ob->adt->action) act = verify_adt_action((ID*)&ob->id, 1); - else act = ob->adt->action; - - std::vector<FCurve*>::iterator it; - int i; - -#if 0 - char *p = strstr(rna_path, "rotation_euler"); - bool is_rotation = p && *(p + strlen("rotation_euler")) == '\0'; - - // convert degrees to radians for rotation - if (is_rotation) - fcurve_deg_to_rad(fcu); -#endif - - for (it = curves.begin(), i = 0; it != curves.end(); it++, i++) { - FCurve *fcu = *it; - fcu->rna_path = BLI_strdupn(rna_path, strlen(rna_path)); - - if (array_index == -1) fcu->array_index = i; - else fcu->array_index = array_index; - - if (ob->type == OB_ARMATURE) { - bActionGroup *grp = NULL; - const char *bone_name = get_joint_name(animated->node); - - if (bone_name) { - /* try to find group */ - grp = action_groups_find_named(act, bone_name); - - /* no matching groups, so add one */ - if (grp == NULL) { - /* Add a new group, and make it active */ - grp = (bActionGroup*)MEM_callocN(sizeof(bActionGroup), "bActionGroup"); - - grp->flag = AGRP_SELECTED; - BLI_strncpy(grp->name, bone_name, sizeof(grp->name)); - - BLI_addtail(&act->groups, grp); - BLI_uniquename(&act->groups, grp, "Group", '.', offsetof(bActionGroup, name), 64); - } - - /* add F-Curve to group */ - action_groups_add_channel(act, grp, fcu); - - } -#if 0 - if (is_rotation) { - fcurves_actionGroup_map[grp].push_back(fcu); - } -#endif - } - else { - BLI_addtail(&act->curves, fcu); - } - - // curve is used, so remove it from unused_curves - unused_curves.erase(std::remove(unused_curves.begin(), unused_curves.end(), fcu), unused_curves.end()); - } - } -public: - - AnimationImporter(UnitConverter *conv, ArmatureImporter *arm, Scene *scene) : - TransformReader(conv), armature_importer(arm), scene(scene) { } - - ~AnimationImporter() - { - // free unused FCurves - for (std::vector<FCurve*>::iterator it = unused_curves.begin(); it != unused_curves.end(); it++) - free_fcurve(*it); - - if (unused_curves.size()) - fprintf(stderr, "removed %u unused curves\n", unused_curves.size()); - } - - bool write_animation(const COLLADAFW::Animation* anim) - { - if (anim->getAnimationType() == COLLADAFW::Animation::ANIMATION_CURVE) { - COLLADAFW::AnimationCurve *curve = (COLLADAFW::AnimationCurve*)anim; - - // XXX Don't know if it's necessary - // Should we check outPhysicalDimension? - if (curve->getInPhysicalDimension() != COLLADAFW::PHYSICAL_DIMENSION_TIME) { - fprintf(stderr, "Inputs physical dimension is not time. \n"); - return true; - } - - // a curve can have mixed interpolation type, - // in this case curve->getInterpolationTypes returns a list of interpolation types per key - COLLADAFW::AnimationCurve::InterpolationType interp = curve->getInterpolationType(); - - if (interp != COLLADAFW::AnimationCurve::INTERPOLATION_MIXED) { - switch (interp) { - case COLLADAFW::AnimationCurve::INTERPOLATION_LINEAR: - case COLLADAFW::AnimationCurve::INTERPOLATION_BEZIER: - animation_to_fcurves(curve); - break; - default: - // TODO there're also CARDINAL, HERMITE, BSPLINE and STEP types - fprintf(stderr, "CARDINAL, HERMITE, BSPLINE and STEP anim interpolation types not supported yet.\n"); - break; - } - } - else { - // not supported yet - fprintf(stderr, "MIXED anim interpolation type is not supported yet.\n"); - } - } - else { - fprintf(stderr, "FORMULA animation type is not supported yet.\n"); - } - - return true; - } - - // called on post-process stage after writeVisualScenes - bool write_animation_list(const COLLADAFW::AnimationList* animlist) - { - const COLLADAFW::UniqueId& animlist_id = animlist->getUniqueId(); - - animlist_map[animlist_id] = animlist; - -#if 0 - // should not happen - if (uid_animated_map.find(animlist_id) == uid_animated_map.end()) { - return true; - } - - // for bones rna_path is like: pose.bones["bone-name"].rotation - - // what does this AnimationList animate? - Animation& animated = uid_animated_map[animlist_id]; - Object *ob = animated.ob; - - char rna_path[100]; - char joint_path[100]; - bool is_joint = false; - - // if ob is NULL, it should be a JOINT - if (!ob) { - ob = armature_importer->get_armature_for_joint(animated.node); - - if (!ob) { - fprintf(stderr, "Cannot find armature for node %s\n", get_joint_name(animated.node)); - return true; - } - - armature_importer->get_rna_path_for_joint(animated.node, joint_path, sizeof(joint_path)); - - is_joint = true; - } - - const COLLADAFW::AnimationList::AnimationBindings& bindings = animlist->getAnimationBindings(); - - switch (animated.tm->getTransformationType()) { - case COLLADAFW::Transformation::TRANSLATE: - case COLLADAFW::Transformation::SCALE: - { - bool loc = animated.tm->getTransformationType() == COLLADAFW::Transformation::TRANSLATE; - if (is_joint) - BLI_snprintf(rna_path, sizeof(rna_path), "%s.%s", joint_path, loc ? "location" : "scale"); - else - BLI_strncpy(rna_path, loc ? "location" : "scale", sizeof(rna_path)); - - for (int i = 0; i < bindings.getCount(); i++) { - const COLLADAFW::AnimationList::AnimationBinding& binding = bindings[i]; - COLLADAFW::UniqueId anim_uid = binding.animation; - - if (curve_map.find(anim_uid) == curve_map.end()) { - fprintf(stderr, "Cannot find FCurve by animation UID.\n"); - continue; - } - - std::vector<FCurve*>& fcurves = curve_map[anim_uid]; - - switch (binding.animationClass) { - case COLLADAFW::AnimationList::POSITION_X: - add_fcurves_to_object(ob, fcurves, rna_path, 0, &animated); - break; - case COLLADAFW::AnimationList::POSITION_Y: - add_fcurves_to_object(ob, fcurves, rna_path, 1, &animated); - break; - case COLLADAFW::AnimationList::POSITION_Z: - add_fcurves_to_object(ob, fcurves, rna_path, 2, &animated); - break; - case COLLADAFW::AnimationList::POSITION_XYZ: - add_fcurves_to_object(ob, fcurves, rna_path, -1, &animated); - break; - default: - fprintf(stderr, "AnimationClass %d is not supported for %s.\n", - binding.animationClass, loc ? "TRANSLATE" : "SCALE"); - } - } - } - break; - case COLLADAFW::Transformation::ROTATE: - { - if (is_joint) - BLI_snprintf(rna_path, sizeof(rna_path), "%s.rotation_euler", joint_path); - else - BLI_strncpy(rna_path, "rotation_euler", sizeof(rna_path)); - - COLLADAFW::Rotate* rot = (COLLADAFW::Rotate*)animated.tm; - COLLADABU::Math::Vector3& axis = rot->getRotationAxis(); - - for (int i = 0; i < bindings.getCount(); i++) { - const COLLADAFW::AnimationList::AnimationBinding& binding = bindings[i]; - COLLADAFW::UniqueId anim_uid = binding.animation; - - if (curve_map.find(anim_uid) == curve_map.end()) { - fprintf(stderr, "Cannot find FCurve by animation UID.\n"); - continue; - } - - std::vector<FCurve*>& fcurves = curve_map[anim_uid]; - - switch (binding.animationClass) { - case COLLADAFW::AnimationList::ANGLE: - if (COLLADABU::Math::Vector3::UNIT_X == axis) { - add_fcurves_to_object(ob, fcurves, rna_path, 0, &animated); - } - else if (COLLADABU::Math::Vector3::UNIT_Y == axis) { - add_fcurves_to_object(ob, fcurves, rna_path, 1, &animated); - } - else if (COLLADABU::Math::Vector3::UNIT_Z == axis) { - add_fcurves_to_object(ob, fcurves, rna_path, 2, &animated); - } - break; - case COLLADAFW::AnimationList::AXISANGLE: - // TODO convert axis-angle to quat? or XYZ? - default: - fprintf(stderr, "AnimationClass %d is not supported for ROTATE transformation.\n", - binding.animationClass); - } - } - } - break; - case COLLADAFW::Transformation::MATRIX: - case COLLADAFW::Transformation::SKEW: - case COLLADAFW::Transformation::LOOKAT: - fprintf(stderr, "Animation of MATRIX, SKEW and LOOKAT transformations is not supported yet.\n"); - break; - } -#endif - - return true; - } - - void read_node_transform(COLLADAFW::Node *node, Object *ob) - { - float mat[4][4]; - TransformReader::get_node_mat(mat, node, &uid_animated_map, ob); - if (ob) { - copy_m4_m4(ob->obmat, mat); - object_apply_mat4(ob, ob->obmat); - } - } - -#if 0 - virtual void change_eul_to_quat(Object *ob, bAction *act) - { - bActionGroup *grp; - int i; - - for (grp = (bActionGroup*)act->groups.first; grp; grp = grp->next) { - - FCurve *eulcu[3] = {NULL, NULL, NULL}; - - if (fcurves_actionGroup_map.find(grp) == fcurves_actionGroup_map.end()) - continue; - - std::vector<FCurve*> &rot_fcurves = fcurves_actionGroup_map[grp]; - - if (rot_fcurves.size() > 3) continue; - - for (i = 0; i < rot_fcurves.size(); i++) - eulcu[rot_fcurves[i]->array_index] = rot_fcurves[i]; - - char joint_path[100]; - char rna_path[100]; - - BLI_snprintf(joint_path, sizeof(joint_path), "pose.bones[\"%s\"]", grp->name); - BLI_snprintf(rna_path, sizeof(rna_path), "%s.rotation_quaternion", joint_path); - - FCurve *quatcu[4] = { - create_fcurve(0, rna_path), - create_fcurve(1, rna_path), - create_fcurve(2, rna_path), - create_fcurve(3, rna_path) - }; - - bPoseChannel *chan = get_pose_channel(ob->pose, grp->name); - - float m4[4][4], irest[3][3]; - invert_m4_m4(m4, chan->bone->arm_mat); - copy_m3_m4(irest, m4); - - for (i = 0; i < 3; i++) { - - FCurve *cu = eulcu[i]; - - if (!cu) continue; - - for (int j = 0; j < cu->totvert; j++) { - float frame = cu->bezt[j].vec[1][0]; - - float eul[3] = { - eulcu[0] ? evaluate_fcurve(eulcu[0], frame) : 0.0f, - eulcu[1] ? evaluate_fcurve(eulcu[1], frame) : 0.0f, - eulcu[2] ? evaluate_fcurve(eulcu[2], frame) : 0.0f - }; - - // make eul relative to bone rest pose - float rot[3][3], rel[3][3], quat[4]; - - /*eul_to_mat3(rot, eul); - - mul_m3_m3m3(rel, irest, rot); - - mat3_to_quat(quat, rel); - */ - - eul_to_quat(quat, eul); - - for (int k = 0; k < 4; k++) - create_bezt(quatcu[k], frame, quat[k]); - } - } - - // now replace old Euler curves - - for (i = 0; i < 3; i++) { - if (!eulcu[i]) continue; - - action_groups_remove_channel(act, eulcu[i]); - free_fcurve(eulcu[i]); - } - - chan->rotmode = ROT_MODE_QUAT; - - for (i = 0; i < 4; i++) - action_groups_add_channel(act, grp, quatcu[i]); - } - - bPoseChannel *pchan; - for (pchan = (bPoseChannel*)ob->pose->chanbase.first; pchan; pchan = pchan->next) { - pchan->rotmode = ROT_MODE_QUAT; - } - } -#endif - - // prerequisites: - // animlist_map - map animlist id -> animlist - // curve_map - map anim id -> curve(s) - Object *translate_animation(COLLADAFW::Node *node, - std::map<COLLADAFW::UniqueId, Object*>& object_map, - std::map<COLLADAFW::UniqueId, COLLADAFW::Node*>& root_map, - COLLADAFW::Transformation::TransformationType tm_type, - Object *par_job = NULL) - { - bool is_rotation = tm_type == COLLADAFW::Transformation::ROTATE; - bool is_matrix = tm_type == COLLADAFW::Transformation::MATRIX; - bool is_joint = node->getType() == COLLADAFW::Node::JOINT; - - COLLADAFW::Node *root = root_map.find(node->getUniqueId()) == root_map.end() ? node : root_map[node->getUniqueId()]; - Object *ob = is_joint ? armature_importer->get_armature_for_joint(node) : object_map[node->getUniqueId()]; - const char *bone_name = is_joint ? get_joint_name(node) : NULL; - - if (!ob) { - fprintf(stderr, "cannot find Object for Node with id=\"%s\"\n", node->getOriginalId().c_str()); - return NULL; - } - - // frames at which to sample - std::vector<float> frames; - - // for each <rotate>, <translate>, etc. there is a separate Transformation - const COLLADAFW::TransformationPointerArray& tms = node->getTransformations(); - - unsigned int i; - - // find frames at which to sample plus convert all rotation keys to radians - for (i = 0; i < tms.getCount(); i++) { - COLLADAFW::Transformation *tm = tms[i]; - COLLADAFW::Transformation::TransformationType type = tm->getTransformationType(); - - if (type == tm_type) { - const COLLADAFW::UniqueId& listid = tm->getAnimationList(); - - if (animlist_map.find(listid) != animlist_map.end()) { - const COLLADAFW::AnimationList *animlist = animlist_map[listid]; - const COLLADAFW::AnimationList::AnimationBindings& bindings = animlist->getAnimationBindings(); - - if (bindings.getCount()) { - for (unsigned int j = 0; j < bindings.getCount(); j++) { - std::vector<FCurve*>& curves = curve_map[bindings[j].animation]; - bool xyz = ((type == COLLADAFW::Transformation::TRANSLATE || type == COLLADAFW::Transformation::SCALE) && bindings[j].animationClass == COLLADAFW::AnimationList::POSITION_XYZ); - - if ((!xyz && curves.size() == 1) || (xyz && curves.size() == 3) || is_matrix) { - std::vector<FCurve*>::iterator iter; - - for (iter = curves.begin(); iter != curves.end(); iter++) { - FCurve *fcu = *iter; - - if (is_rotation) - fcurve_deg_to_rad(fcu); - - for (unsigned int k = 0; k < fcu->totvert; k++) { - float fra = fcu->bezt[k].vec[1][0]; - if (std::find(frames.begin(), frames.end(), fra) == frames.end()) - frames.push_back(fra); - } - } - } - else { - fprintf(stderr, "expected %d curves, got %u\n", xyz ? 3 : 1, curves.size()); - } - } - } - } - } - } - - float irest_dae[4][4]; - float rest[4][4], irest[4][4]; - - if (is_joint) { - get_joint_rest_mat(irest_dae, root, node); - invert_m4(irest_dae); - - Bone *bone = get_named_bone((bArmature*)ob->data, bone_name); - if (!bone) { - fprintf(stderr, "cannot find bone \"%s\"\n", bone_name); - return NULL; - } - - unit_m4(rest); - copy_m4_m4(rest, bone->arm_mat); - invert_m4_m4(irest, rest); - } - - Object *job = NULL; - -#ifdef ARMATURE_TEST - FCurve *job_curves[10]; - job = get_joint_object(root, node, par_job); -#endif - - if (frames.size() == 0) - return job; - - std::sort(frames.begin(), frames.end()); - - const char *tm_str = NULL; - switch (tm_type) { - case COLLADAFW::Transformation::ROTATE: - tm_str = "rotation_quaternion"; - break; - case COLLADAFW::Transformation::SCALE: - tm_str = "scale"; - break; - case COLLADAFW::Transformation::TRANSLATE: - tm_str = "location"; - break; - case COLLADAFW::Transformation::MATRIX: - break; - default: - return job; - } - - char rna_path[200]; - char joint_path[200]; - - if (is_joint) - armature_importer->get_rna_path_for_joint(node, joint_path, sizeof(joint_path)); - - // new curves - FCurve *newcu[10]; // if tm_type is matrix, then create 10 curves: 4 rot, 3 loc, 3 scale - unsigned int totcu = is_matrix ? 10 : (is_rotation ? 4 : 3); - - for (i = 0; i < totcu; i++) { - - int axis = i; - - if (is_matrix) { - if (i < 4) { - tm_str = "rotation_quaternion"; - axis = i; - } - else if (i < 7) { - tm_str = "location"; - axis = i - 4; - } - else { - tm_str = "scale"; - axis = i - 7; - } - } - - if (is_joint) - BLI_snprintf(rna_path, sizeof(rna_path), "%s.%s", joint_path, tm_str); - else - strcpy(rna_path, tm_str); - - newcu[i] = create_fcurve(axis, rna_path); - -#ifdef ARMATURE_TEST - if (is_joint) - job_curves[i] = create_fcurve(axis, tm_str); -#endif - } - - std::vector<float>::iterator it; - - // sample values at each frame - for (it = frames.begin(); it != frames.end(); it++) { - float fra = *it; - - float mat[4][4]; - float matfra[4][4]; - - unit_m4(matfra); - - // calc object-space mat - evaluate_transform_at_frame(matfra, node, fra); - - // for joints, we need a special matrix - if (is_joint) { - // special matrix: iR * M * iR_dae * R - // where R, iR are bone rest and inverse rest mats in world space (Blender bones), - // iR_dae is joint inverse rest matrix (DAE) and M is an evaluated joint world-space matrix (DAE) - float temp[4][4], par[4][4]; - - // calc M - calc_joint_parent_mat_rest(par, NULL, root, node); - mul_m4_m4m4(temp, matfra, par); - - // evaluate_joint_world_transform_at_frame(temp, NULL, , node, fra); - - // calc special matrix - mul_serie_m4(mat, irest, temp, irest_dae, rest, NULL, NULL, NULL, NULL); - } - else { - copy_m4_m4(mat, matfra); - } - - float val[4], rot[4], loc[3], scale[3]; - - switch (tm_type) { - case COLLADAFW::Transformation::ROTATE: - mat4_to_quat(val, mat); - break; - case COLLADAFW::Transformation::SCALE: - mat4_to_size(val, mat); - break; - case COLLADAFW::Transformation::TRANSLATE: - copy_v3_v3(val, mat[3]); - break; - case COLLADAFW::Transformation::MATRIX: - mat4_to_quat(rot, mat); - copy_v3_v3(loc, mat[3]); - mat4_to_size(scale, mat); - break; - default: - break; - } - - // add keys - for (i = 0; i < totcu; i++) { - if (is_matrix) { - if (i < 4) - add_bezt(newcu[i], fra, rot[i]); - else if (i < 7) - add_bezt(newcu[i], fra, loc[i - 4]); - else - add_bezt(newcu[i], fra, scale[i - 7]); - } - else { - add_bezt(newcu[i], fra, val[i]); - } - } - -#ifdef ARMATURE_TEST - if (is_joint) { - switch (tm_type) { - case COLLADAFW::Transformation::ROTATE: - mat4_to_quat(val, matfra); - break; - case COLLADAFW::Transformation::SCALE: - mat4_to_size(val, matfra); - break; - case COLLADAFW::Transformation::TRANSLATE: - copy_v3_v3(val, matfra[3]); - break; - case MATRIX: - mat4_to_quat(rot, matfra); - copy_v3_v3(loc, matfra[3]); - mat4_to_size(scale, matfra); - break; - default: - break; - } - - for (i = 0; i < totcu; i++) { - if (is_matrix) { - if (i < 4) - add_bezt(job_curves[i], fra, rot[i]); - else if (i < 7) - add_bezt(job_curves[i], fra, loc[i - 4]); - else - add_bezt(job_curves[i], fra, scale[i - 7]); - } - else { - add_bezt(job_curves[i], fra, val[i]); - } - } - } -#endif - } - - verify_adt_action((ID*)&ob->id, 1); - - ListBase *curves = &ob->adt->action->curves; - - // add curves - for (i = 0; i < totcu; i++) { - if (is_joint) - add_bone_fcurve(ob, node, newcu[i]); - else - BLI_addtail(curves, newcu[i]); - -#ifdef ARMATURE_TEST - if (is_joint) - BLI_addtail(&job->adt->action->curves, job_curves[i]); -#endif - } - - if (is_rotation || is_matrix) { - if (is_joint) { - bPoseChannel *chan = get_pose_channel(ob->pose, bone_name); - chan->rotmode = ROT_MODE_QUAT; - } - else { - ob->rotmode = ROT_MODE_QUAT; - } - } - - return job; - } - - // internal, better make it private - // warning: evaluates only rotation - // prerequisites: animlist_map, curve_map - void evaluate_transform_at_frame(float mat[4][4], COLLADAFW::Node *node, float fra) - { - const COLLADAFW::TransformationPointerArray& tms = node->getTransformations(); - - unit_m4(mat); - - for (unsigned int i = 0; i < tms.getCount(); i++) { - COLLADAFW::Transformation *tm = tms[i]; - COLLADAFW::Transformation::TransformationType type = tm->getTransformationType(); - float m[4][4]; - - unit_m4(m); - - if (!evaluate_animation(tm, m, fra, node->getOriginalId().c_str())) { - switch (type) { - case COLLADAFW::Transformation::ROTATE: - dae_rotate_to_mat4(tm, m); - break; - case COLLADAFW::Transformation::TRANSLATE: - dae_translate_to_mat4(tm, m); - break; - case COLLADAFW::Transformation::SCALE: - dae_scale_to_mat4(tm, m); - break; - case COLLADAFW::Transformation::MATRIX: - dae_matrix_to_mat4(tm, m); - break; - default: - fprintf(stderr, "unsupported transformation type %d\n", type); - } - } - - float temp[4][4]; - copy_m4_m4(temp, mat); - - mul_m4_m4m4(mat, m, temp); - } - } - - // return true to indicate that mat contains a sane value - bool evaluate_animation(COLLADAFW::Transformation *tm, float mat[4][4], float fra, const char *node_id) - { - const COLLADAFW::UniqueId& listid = tm->getAnimationList(); - COLLADAFW::Transformation::TransformationType type = tm->getTransformationType(); - - if (type != COLLADAFW::Transformation::ROTATE && - type != COLLADAFW::Transformation::SCALE && - type != COLLADAFW::Transformation::TRANSLATE && - type != COLLADAFW::Transformation::MATRIX) { - fprintf(stderr, "animation of transformation %d is not supported yet\n", type); - return false; - } - - if (animlist_map.find(listid) == animlist_map.end()) - return false; - - const COLLADAFW::AnimationList *animlist = animlist_map[listid]; - const COLLADAFW::AnimationList::AnimationBindings& bindings = animlist->getAnimationBindings(); - - if (bindings.getCount()) { - float vec[3]; - - bool is_scale = (type == COLLADAFW::Transformation::SCALE); - bool is_translate = (type == COLLADAFW::Transformation::TRANSLATE); - - if (type == COLLADAFW::Transformation::SCALE) - dae_scale_to_v3(tm, vec); - else if (type == COLLADAFW::Transformation::TRANSLATE) - dae_translate_to_v3(tm, vec); - - for (unsigned int j = 0; j < bindings.getCount(); j++) { - const COLLADAFW::AnimationList::AnimationBinding& binding = bindings[j]; - std::vector<FCurve*>& curves = curve_map[binding.animation]; - COLLADAFW::AnimationList::AnimationClass animclass = binding.animationClass; - char path[100]; - - switch (type) { - case COLLADAFW::Transformation::ROTATE: - BLI_snprintf(path, sizeof(path), "%s.rotate (binding %u)", node_id, j); - break; - case COLLADAFW::Transformation::SCALE: - BLI_snprintf(path, sizeof(path), "%s.scale (binding %u)", node_id, j); - break; - case COLLADAFW::Transformation::TRANSLATE: - BLI_snprintf(path, sizeof(path), "%s.translate (binding %u)", node_id, j); - break; - case COLLADAFW::Transformation::MATRIX: - BLI_snprintf(path, sizeof(path), "%s.matrix (binding %u)", node_id, j); - break; - default: - break; - } - - if (animclass == COLLADAFW::AnimationList::UNKNOWN_CLASS) { - fprintf(stderr, "%s: UNKNOWN animation class\n", path); - continue; - } - - if (type == COLLADAFW::Transformation::ROTATE) { - if (curves.size() != 1) { - fprintf(stderr, "expected 1 curve, got %u\n", curves.size()); - return false; - } - - // TODO support other animclasses - if (animclass != COLLADAFW::AnimationList::ANGLE) { - fprintf(stderr, "%s: animation class %d is not supported yet\n", path, animclass); - return false; - } - - COLLADABU::Math::Vector3& axis = ((COLLADAFW::Rotate*)tm)->getRotationAxis(); - float ax[3] = {axis[0], axis[1], axis[2]}; - float angle = evaluate_fcurve(curves[0], fra); - axis_angle_to_mat4(mat, ax, angle); - - return true; - } - else if (is_scale || is_translate) { - bool is_xyz = animclass == COLLADAFW::AnimationList::POSITION_XYZ; - - if ((!is_xyz && curves.size() != 1) || (is_xyz && curves.size() != 3)) { - if (is_xyz) - fprintf(stderr, "%s: expected 3 curves, got %u\n", path, curves.size()); - else - fprintf(stderr, "%s: expected 1 curve, got %u\n", path, curves.size()); - return false; - } - - switch (animclass) { - case COLLADAFW::AnimationList::POSITION_X: - vec[0] = evaluate_fcurve(curves[0], fra); - break; - case COLLADAFW::AnimationList::POSITION_Y: - vec[1] = evaluate_fcurve(curves[0], fra); - break; - case COLLADAFW::AnimationList::POSITION_Z: - vec[2] = evaluate_fcurve(curves[0], fra); - break; - case COLLADAFW::AnimationList::POSITION_XYZ: - vec[0] = evaluate_fcurve(curves[0], fra); - vec[1] = evaluate_fcurve(curves[1], fra); - vec[2] = evaluate_fcurve(curves[2], fra); - break; - default: - fprintf(stderr, "%s: animation class %d is not supported yet\n", path, animclass); - break; - } - } - else if (type == COLLADAFW::Transformation::MATRIX) { - // for now, of matrix animation, support only the case when all values are packed into one animation - if (curves.size() != 16) { - fprintf(stderr, "%s: expected 16 curves, got %u\n", path, curves.size()); - return false; - } - - COLLADABU::Math::Matrix4 matrix; - int i = 0, j = 0; - - for (std::vector<FCurve*>::iterator it = curves.begin(); it != curves.end(); it++) { - matrix.setElement(i, j, evaluate_fcurve(*it, fra)); - j++; - if (j == 4) { - i++; - j = 0; - } - } - - COLLADAFW::Matrix tm(matrix); - dae_matrix_to_mat4(&tm, mat); - - return true; - } - } - - if (is_scale) - size_to_mat4(mat, vec); - else - copy_v3_v3(mat[3], vec); - - return is_scale || is_translate; - } - - return false; - } - - // gives a world-space mat of joint at rest position - void get_joint_rest_mat(float mat[4][4], COLLADAFW::Node *root, COLLADAFW::Node *node) - { - // if bind mat is not available, - // use "current" node transform, i.e. all those tms listed inside <node> - if (!armature_importer->get_joint_bind_mat(mat, node)) { - float par[4][4], m[4][4]; - - calc_joint_parent_mat_rest(par, NULL, root, node); - get_node_mat(m, node, NULL, NULL); - mul_m4_m4m4(mat, m, par); - } - } - - // gives a world-space mat, end's mat not included - bool calc_joint_parent_mat_rest(float mat[4][4], float par[4][4], COLLADAFW::Node *node, COLLADAFW::Node *end) - { - float m[4][4]; - - if (node == end) { - par ? copy_m4_m4(mat, par) : unit_m4(mat); - return true; - } - - // use bind matrix if available or calc "current" world mat - if (!armature_importer->get_joint_bind_mat(m, node)) { - if (par) { - float temp[4][4]; - get_node_mat(temp, node, NULL, NULL); - mul_m4_m4m4(m, temp, par); - } - else { - get_node_mat(m, node, NULL, NULL); - } - } - - COLLADAFW::NodePointerArray& children = node->getChildNodes(); - for (unsigned int i = 0; i < children.getCount(); i++) { - if (calc_joint_parent_mat_rest(mat, m, children[i], end)) - return true; - } - - return false; - } - -#ifdef ARMATURE_TEST - Object *get_joint_object(COLLADAFW::Node *root, COLLADAFW::Node *node, Object *par_job) - { - if (joint_objects.find(node->getUniqueId()) == joint_objects.end()) { - Object *job = add_object(scene, OB_EMPTY); - - rename_id((ID*)&job->id, (char*)get_joint_name(node)); - - job->lay = object_in_scene(job, scene)->lay = 2; - - mul_v3_fl(job->size, 0.5f); - job->recalc |= OB_RECALC_OB; - - verify_adt_action((ID*)&job->id, 1); - - job->rotmode = ROT_MODE_QUAT; - - float mat[4][4]; - get_joint_rest_mat(mat, root, node); - - if (par_job) { - float temp[4][4], ipar[4][4]; - invert_m4_m4(ipar, par_job->obmat); - copy_m4_m4(temp, mat); - mul_m4_m4m4(mat, temp, ipar); - } - - TransformBase::decompose(mat, job->loc, NULL, job->quat, job->size); - - if (par_job) { - job->parent = par_job; - - par_job->recalc |= OB_RECALC_OB; - job->parsubstr[0] = 0; - } - - where_is_object(scene, job); - - // after parenting and layer change - DAG_scene_sort(CTX_data_main(C), scene); - - joint_objects[node->getUniqueId()] = job; - } - - return joint_objects[node->getUniqueId()]; - } -#endif - -#if 0 - // recursively evaluates joint tree until end is found, mat then is world-space matrix of end - // mat must be identity on enter, node must be root - bool evaluate_joint_world_transform_at_frame(float mat[4][4], float par[4][4], COLLADAFW::Node *node, COLLADAFW::Node *end, float fra) - { - float m[4][4]; - if (par) { - float temp[4][4]; - evaluate_transform_at_frame(temp, node, node == end ? fra : 0.0f); - mul_m4_m4m4(m, temp, par); - } - else { - evaluate_transform_at_frame(m, node, node == end ? fra : 0.0f); - } - - if (node == end) { - copy_m4_m4(mat, m); - return true; - } - else { - COLLADAFW::NodePointerArray& children = node->getChildNodes(); - for (int i = 0; i < children.getCount(); i++) { - if (evaluate_joint_world_transform_at_frame(mat, m, children[i], end, fra)) - return true; - } - } - - return false; - } -#endif - - void add_bone_fcurve(Object *ob, COLLADAFW::Node *node, FCurve *fcu) - { - const char *bone_name = get_joint_name(node); - bAction *act = ob->adt->action; - - /* try to find group */ - bActionGroup *grp = action_groups_find_named(act, bone_name); - - /* no matching groups, so add one */ - if (grp == NULL) { - /* Add a new group, and make it active */ - grp = (bActionGroup*)MEM_callocN(sizeof(bActionGroup), "bActionGroup"); - - grp->flag = AGRP_SELECTED; - BLI_strncpy(grp->name, bone_name, sizeof(grp->name)); - - BLI_addtail(&act->groups, grp); - BLI_uniquename(&act->groups, grp, "Group", '.', offsetof(bActionGroup, name), 64); - } - - /* add F-Curve to group */ - action_groups_add_channel(act, grp, fcu); - } - - void add_bezt(FCurve *fcu, float fra, float value) - { - BezTriple bez; - memset(&bez, 0, sizeof(BezTriple)); - bez.vec[1][0] = fra; - bez.vec[1][1] = value; - bez.ipo = U.ipo_new; /* use default interpolation mode here... */ - bez.f1 = bez.f2 = bez.f3 = SELECT; - bez.h1 = bez.h2 = HD_AUTO; - insert_bezt_fcurve(fcu, &bez, 0); - calchandles_fcurve(fcu); - } -}; /* - COLLADA Importer limitations: - - no multiple scene import, all objects are added to active scene - */ + +// #define COLLADA_DEBUG +// creates empties for each imported bone on layer 2, for debugging +// #define ARMATURE_TEST + /** Class that needs to be implemented by a writer. IMPORTANT: The write functions are called in arbitrary order.*/ class Writer: public COLLADAFW::IWriter @@ -3266,7 +132,7 @@ public: /** Constructor. */ Writer(bContext *C, const char *filename) : mFilename(filename), mContext(C), armature_importer(&unit_converter, &mesh_importer, &anim_importer, CTX_data_scene(C)), - mesh_importer(&armature_importer, CTX_data_scene(C)), + mesh_importer(&unit_converter, &armature_importer, CTX_data_scene(C)), anim_importer(&unit_converter, &armature_importer, CTX_data_scene(C)) {} /** Destructor. */ @@ -3308,8 +174,30 @@ public: { std::vector<const COLLADAFW::VisualScene*>::iterator it; for (it = vscenes.begin(); it != vscenes.end(); it++) { + PointerRNA sceneptr, unit_settings; + PropertyRNA *system, *scale; // TODO: create a new scene except the selected <visual_scene> - use current blender scene for it Scene *sce = CTX_data_scene(mContext); + + // for scene unit settings: system, scale_length + RNA_id_pointer_create(&sce->id, &sceneptr); + unit_settings = RNA_pointer_get(&sceneptr, "unit_settings"); + system = RNA_struct_find_property(&unit_settings, "system"); + scale = RNA_struct_find_property(&unit_settings, "scale_length"); + + switch(unit_converter.isMetricSystem()) { + case UnitConverter::Metric: + RNA_property_enum_set(&unit_settings, system, USER_UNIT_METRIC); + break; + case UnitConverter::Imperial: + RNA_property_enum_set(&unit_settings, system, USER_UNIT_IMPERIAL); + break; + default: + RNA_property_enum_set(&unit_settings, system, USER_UNIT_NONE); + break; + } + RNA_property_float_set(&unit_settings, scale, unit_converter.getLinearMeter()); + const COLLADAFW::NodePointerArray& roots = (*it)->getRootNodes(); for (unsigned int i = 0; i < roots.getCount(); i++) { @@ -3389,9 +277,6 @@ public: @return The writer should return true, if writing succeeded, false otherwise.*/ virtual bool writeGlobalAsset ( const COLLADAFW::FileInfo* asset ) { - // XXX take up_axis, unit into account - // COLLADAFW::FileInfo::Unit unit = asset->getUnit(); - // COLLADAFW::FileInfo::UpAxisType upAxis = asset->getUpAxisType(); unit_converter.read_asset(asset); return true; @@ -3468,7 +353,7 @@ public: else { new_child = create_instance_node(object_map[child_id], child_node, NULL, sce, is_library_node); } - set_parent(new_child, obn, mContext, true); + bc_set_parent(new_child, obn, mContext, true); if (is_library_node) libnode_ob.push_back(new_child); @@ -3547,7 +432,7 @@ public: if (!is_joint) { // if par was given make this object child of the previous if (par && ob) - set_parent(ob, par, mContext); + bc_set_parent(ob, par, mContext); } // if node has child nodes write them @@ -3650,8 +535,7 @@ public: // phong else if (shader == COLLADAFW::EffectCommon::SHADER_PHONG) { ma->spec_shader = MA_SPEC_PHONG; - // XXX setting specular hardness instead of specularity intensity - ma->har = ef->getShininess().getFloatValue() * 4; + ma->har = ef->getShininess().getFloatValue(); } // lambert else if (shader == COLLADAFW::EffectCommon::SHADER_LAMBERT) { diff --git a/source/blender/collada/DocumentImporter.h b/source/blender/collada/DocumentImporter.h index babf8f65d7f..6a6f1dcb3bc 100644 --- a/source/blender/collada/DocumentImporter.h +++ b/source/blender/collada/DocumentImporter.h @@ -21,6 +21,9 @@ * * ***** END GPL LICENSE BLOCK ***** */ + +#ifndef __DOCUMENTIMPORTER_H__ +#define __DOCUMENTIMPORTER_H__ struct Main; struct bContext; @@ -29,3 +32,5 @@ class DocumentImporter public: void import(bContext *C, const char *filename); }; + +#endif diff --git a/source/blender/collada/EffectExporter.cpp b/source/blender/collada/EffectExporter.cpp new file mode 100644 index 00000000000..45b6450e444 --- /dev/null +++ b/source/blender/collada/EffectExporter.cpp @@ -0,0 +1,306 @@ +/** + * $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): Chingiz Dyussenov, Arystanbek Dyussenov, Jan Diederich, Tod Liverseed, + * Nathan Letwory + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include <map> + +#include "COLLADASWEffectProfile.h" + +#include "EffectExporter.h" +#include "MaterialExporter.h" + +#include "DNA_mesh_types.h" +#include "DNA_texture_types.h" + +#include "BKE_customdata.h" + +#include "collada_internal.h" +#include "collada_utils.h" + +// OB_MESH is assumed +static std::string getActiveUVLayerName(Object *ob) +{ + Mesh *me = (Mesh*)ob->data; + + int num_layers = CustomData_number_of_layers(&me->fdata, CD_MTFACE); + if (num_layers) + return std::string(bc_CustomData_get_active_layer_name(&me->fdata, CD_MTFACE)); + + return ""; +} + + +EffectsExporter::EffectsExporter(COLLADASW::StreamWriter *sw) : COLLADASW::LibraryEffects(sw){} +void EffectsExporter::exportEffects(Scene *sce) +{ + openLibrary(); + MaterialFunctor mf; + mf.forEachMaterialInScene<EffectsExporter>(sce, *this); + + closeLibrary(); +} + +void EffectsExporter::operator()(Material *ma, Object *ob) +{ + // create a list of indices to textures of type TEX_IMAGE + std::vector<int> tex_indices; + createTextureIndices(ma, tex_indices); + + openEffect(translate_id(id_name(ma)) + "-effect"); + + COLLADASW::EffectProfile ep(mSW); + ep.setProfileType(COLLADASW::EffectProfile::COMMON); + ep.openProfile(); + // set shader type - one of three blinn, phong or lambert + if (ma->spec_shader == MA_SPEC_BLINN) { + ep.setShaderType(COLLADASW::EffectProfile::BLINN); + // shininess + ep.setShininess(ma->har); + } + else if (ma->spec_shader == MA_SPEC_PHONG) { + ep.setShaderType(COLLADASW::EffectProfile::PHONG); + // shininess + ep.setShininess(ma->har); + } + else { + // XXX write warning "Current shader type is not supported" + ep.setShaderType(COLLADASW::EffectProfile::LAMBERT); + } + // index of refraction + if (ma->mode & MA_RAYTRANSP) { + ep.setIndexOfRefraction(ma->ang); + } + else { + ep.setIndexOfRefraction(1.0f); + } + + COLLADASW::ColorOrTexture cot; + + // transparency + if (ma->mode & MA_TRANSP) { + // Tod: because we are in A_ONE mode transparency is calculated like this: + ep.setTransparency(ma->alpha); + // cot = getcol(1.0f, 1.0f, 1.0f, 1.0f); + // ep.setTransparent(cot); + } + + // emission + cot=getcol(ma->emit, ma->emit, ma->emit, 1.0f); + ep.setEmission(cot); + + // diffuse multiplied by diffuse intensity + cot = getcol(ma->r * ma->ref, ma->g * ma->ref, ma->b * ma->ref, 1.0f); + ep.setDiffuse(cot); + + // ambient + cot = getcol(ma->ambr, ma->ambg, ma->ambb, 1.0f); + ep.setAmbient(cot); + + // reflective, reflectivity + if (ma->mode & MA_RAYMIRROR) { + cot = getcol(ma->mirr, ma->mirg, ma->mirb, 1.0f); + ep.setReflective(cot); + ep.setReflectivity(ma->ray_mirror); + } + // else { + // cot = getcol(ma->specr, ma->specg, ma->specb, 1.0f); + // ep.setReflective(cot); + // ep.setReflectivity(ma->spec); + // } + + // specular + if (ep.getShaderType() != COLLADASW::EffectProfile::LAMBERT) { + cot = getcol(ma->specr * ma->spec, ma->specg * ma->spec, ma->specb * ma->spec, 1.0f); + ep.setSpecular(cot); + } + + // XXX make this more readable if possible + + // create <sampler> and <surface> for each image + COLLADASW::Sampler samplers[MAX_MTEX]; + //COLLADASW::Surface surfaces[MAX_MTEX]; + //void *samp_surf[MAX_MTEX][2]; + void *samp_surf[MAX_MTEX][1]; + + // image to index to samp_surf map + // samp_surf[index] stores 2 pointers, sampler and surface + std::map<std::string, int> im_samp_map; + + unsigned int a, b; + for (a = 0, b = 0; a < tex_indices.size(); a++) { + MTex *t = ma->mtex[tex_indices[a]]; + Image *ima = t->tex->ima; + + // Image not set for texture + if(!ima) continue; + + std::string key(id_name(ima)); + key = translate_id(key); + + // create only one <sampler>/<surface> pair for each unique image + if (im_samp_map.find(key) == im_samp_map.end()) { + // //<newparam> <surface> <init_from> + // COLLADASW::Surface surface(COLLADASW::Surface::SURFACE_TYPE_2D, + // key + COLLADASW::Surface::SURFACE_SID_SUFFIX); + // COLLADASW::SurfaceInitOption sio(COLLADASW::SurfaceInitOption::INIT_FROM); + // sio.setImageReference(key); + // surface.setInitOption(sio); + + // COLLADASW::NewParamSurface surface(mSW); + // surface->setParamType(COLLADASW::CSW_SURFACE_TYPE_2D); + + //<newparam> <sampler> <source> + COLLADASW::Sampler sampler(COLLADASW::Sampler::SAMPLER_TYPE_2D, + key + COLLADASW::Sampler::SAMPLER_SID_SUFFIX, + key + COLLADASW::Sampler::SURFACE_SID_SUFFIX); + sampler.setImageId(key); + // copy values to arrays since they will live longer + samplers[a] = sampler; + //surfaces[a] = surface; + + // store pointers so they can be used later when we create <texture>s + samp_surf[b][0] = &samplers[a]; + //samp_surf[b][1] = &surfaces[a]; + + im_samp_map[key] = b; + b++; + } + } + + // used as fallback when MTex->uvname is "" (this is pretty common) + // it is indeed the correct value to use in that case + std::string active_uv(getActiveUVLayerName(ob)); + + // write textures + // XXX very slow + for (a = 0; a < tex_indices.size(); a++) { + MTex *t = ma->mtex[tex_indices[a]]; + Image *ima = t->tex->ima; + + // Image not set for texture + if(!ima) continue; + + // we assume map input is always TEXCO_UV + + std::string key(id_name(ima)); + key = translate_id(key); + int i = im_samp_map[key]; + COLLADASW::Sampler *sampler = (COLLADASW::Sampler*)samp_surf[i][0]; + //COLLADASW::Surface *surface = (COLLADASW::Surface*)samp_surf[i][1]; + + std::string uvname = strlen(t->uvname) ? t->uvname : active_uv; + + // color + if (t->mapto & MAP_COL) { + ep.setDiffuse(createTexture(ima, uvname, sampler)); + } + // ambient + if (t->mapto & MAP_AMB) { + ep.setAmbient(createTexture(ima, uvname, sampler)); + } + // specular + if (t->mapto & MAP_SPEC) { + ep.setSpecular(createTexture(ima, uvname, sampler)); + } + // emission + if (t->mapto & MAP_EMIT) { + ep.setEmission(createTexture(ima, uvname, sampler)); + } + // reflective + if (t->mapto & MAP_REF) { + ep.setReflective(createTexture(ima, uvname, sampler)); + } + // alpha + if (t->mapto & MAP_ALPHA) { + ep.setTransparent(createTexture(ima, uvname, sampler)); + } + // extension: + // Normal map --> Must be stored with <extra> tag as different technique, + // since COLLADA doesn't support normal maps, even in current COLLADA 1.5. + if (t->mapto & MAP_NORM) { + COLLADASW::Texture texture(key); + texture.setTexcoord(uvname); + texture.setSampler(*sampler); + // technique FCOLLADA, with the <bump> tag, is most likely the best understood, + // most widespread de-facto standard. + texture.setProfileName("FCOLLADA"); + texture.setChildElementName("bump"); + ep.addExtraTechniqueColorOrTexture(COLLADASW::ColorOrTexture(texture)); + } + } + // performs the actual writing + ep.addProfileElements(); + bool twoSided = false; + if (ob->type == OB_MESH && ob->data) { + Mesh *me = (Mesh*)ob->data; + if (me->flag & ME_TWOSIDED) + twoSided = true; + } + if (twoSided) + ep.addExtraTechniqueParameter("GOOGLEEARTH", "show_double_sided", 1); + ep.addExtraTechniques(mSW); + + ep.closeProfile(); + if (twoSided) + mSW->appendTextBlock("<extra><technique profile=\"MAX3D\"><double_sided>1</double_sided></technique></extra>"); + closeEffect(); +} + +COLLADASW::ColorOrTexture EffectsExporter::createTexture(Image *ima, + std::string& uv_layer_name, + COLLADASW::Sampler *sampler + /*COLLADASW::Surface *surface*/) +{ + + COLLADASW::Texture texture(translate_id(id_name(ima))); + texture.setTexcoord(uv_layer_name); + //texture.setSurface(*surface); + texture.setSampler(*sampler); + + COLLADASW::ColorOrTexture cot(texture); + return cot; +} + +COLLADASW::ColorOrTexture EffectsExporter::getcol(float r, float g, float b, float a) +{ + COLLADASW::Color color(r,g,b,a); + COLLADASW::ColorOrTexture cot(color); + return cot; +} + +//returns the array of mtex indices which have image +//need this for exporting textures +void EffectsExporter::createTextureIndices(Material *ma, std::vector<int> &indices) +{ + indices.clear(); + + for (int a = 0; a < MAX_MTEX; a++) { + if (ma->mtex[a] && + ma->mtex[a]->tex && + ma->mtex[a]->tex->type == TEX_IMAGE && + ma->mtex[a]->texco == TEXCO_UV){ + indices.push_back(a); + } + } +} diff --git a/source/blender/collada/EffectExporter.h b/source/blender/collada/EffectExporter.h new file mode 100644 index 00000000000..e8f8754b20a --- /dev/null +++ b/source/blender/collada/EffectExporter.h @@ -0,0 +1,62 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Chingiz Dyussenov, Arystanbek Dyussenov, Jan Diederich, Tod Liverseed, + * Nathan Letwory + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef __EFFECTEXPORTER_H__ +#define __EFFECTEXPORTER_H__ + +#include <string> +#include <vector> + +#include "COLLADASWColorOrTexture.h" +#include "COLLADASWStreamWriter.h" +#include "COLLADASWSampler.h" +#include "COLLADASWLibraryEffects.h" + +#include "DNA_image_types.h" +#include "DNA_material_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" + +class EffectsExporter: COLLADASW::LibraryEffects +{ +public: + EffectsExporter(COLLADASW::StreamWriter *sw); + void exportEffects(Scene *sce); + + void operator()(Material *ma, Object *ob); + + COLLADASW::ColorOrTexture createTexture(Image *ima, + std::string& uv_layer_name, + COLLADASW::Sampler *sampler + /*COLLADASW::Surface *surface*/); + + COLLADASW::ColorOrTexture getcol(float r, float g, float b, float a); + + //returns the array of mtex indices which have image + //need this for exporting textures + void createTextureIndices(Material *ma, std::vector<int> &indices); +}; + +#endif diff --git a/source/blender/collada/GeometryExporter.cpp b/source/blender/collada/GeometryExporter.cpp new file mode 100644 index 00000000000..1aef6e6489a --- /dev/null +++ b/source/blender/collada/GeometryExporter.cpp @@ -0,0 +1,472 @@ +/** + * $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): Chingiz Dyussenov, Arystanbek Dyussenov, Jan Diederich, Tod Liverseed, + * Nathan Letwory + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "COLLADASWPrimitves.h" +#include "COLLADASWSource.h" +#include "COLLADASWVertices.h" +#include "COLLADABUUtils.h" + +#include "GeometryExporter.h" + +#include "DNA_meshdata_types.h" +#include "BKE_customdata.h" +#include "BKE_material.h" + +#include "collada_internal.h" + +// TODO: optimize UV sets by making indexed list with duplicates removed +GeometryExporter::GeometryExporter(COLLADASW::StreamWriter *sw) : COLLADASW::LibraryGeometries(sw) {} + + +void GeometryExporter::exportGeom(Scene *sce) +{ + openLibrary(); + + mScene = sce; + GeometryFunctor gf; + gf.forEachMeshObjectInScene<GeometryExporter>(sce, *this); + + closeLibrary(); +} + +void GeometryExporter::operator()(Object *ob) +{ + // XXX don't use DerivedMesh, Mesh instead? + +#if 0 + DerivedMesh *dm = mesh_get_derived_final(mScene, ob, CD_MASK_BAREMESH); +#endif + Mesh *me = (Mesh*)ob->data; + std::string geom_id = get_geometry_id(ob); + std::vector<Normal> nor; + std::vector<Face> norind; + + bool has_color = (bool)CustomData_has_layer(&me->fdata, CD_MCOL); + + create_normals(nor, norind, me); + + // openMesh(geoId, geoName, meshId) + openMesh(geom_id); + + // writes <source> for vertex coords + createVertsSource(geom_id, me); + + // writes <source> for normal coords + createNormalsSource(geom_id, me, nor); + + bool has_uvs = (bool)CustomData_has_layer(&me->fdata, CD_MTFACE); + + // writes <source> for uv coords if mesh has uv coords + if (has_uvs) + createTexcoordsSource(geom_id, me); + + if (has_color) + createVertexColorSource(geom_id, me); + + // <vertices> + COLLADASW::Vertices verts(mSW); + verts.setId(getIdBySemantics(geom_id, COLLADASW::VERTEX)); + COLLADASW::InputList &input_list = verts.getInputList(); + COLLADASW::Input input(COLLADASW::POSITION, getUrlBySemantics(geom_id, COLLADASW::POSITION)); + input_list.push_back(input); + verts.add(); + + // XXX slow + if (ob->totcol) { + for(int a = 0; a < ob->totcol; a++) { + createPolylist(a, has_uvs, has_color, ob, geom_id, norind); + } + } + else { + createPolylist(0, has_uvs, has_color, ob, geom_id, norind); + } + + closeMesh(); + closeGeometry(); + +#if 0 + dm->release(dm); +#endif +} + +// powerful because it handles both cases when there is material and when there's not +void GeometryExporter::createPolylist(int material_index, + bool has_uvs, + bool has_color, + Object *ob, + std::string& geom_id, + std::vector<Face>& norind) +{ + Mesh *me = (Mesh*)ob->data; + MFace *mfaces = me->mface; + int totfaces = me->totface; + + // <vcount> + int i; + int faces_in_polylist = 0; + std::vector<unsigned long> vcount_list; + + // count faces with this material + for (i = 0; i < totfaces; i++) { + MFace *f = &mfaces[i]; + + if (f->mat_nr == material_index) { + faces_in_polylist++; + if (f->v4 == 0) { + vcount_list.push_back(3); + } + else { + vcount_list.push_back(4); + } + } + } + + // no faces using this material + if (faces_in_polylist == 0) { + fprintf(stderr, "%s: no faces use material %d\n", id_name(ob).c_str(), material_index); + return; + } + + Material *ma = ob->totcol ? give_current_material(ob, material_index + 1) : NULL; + COLLADASW::Polylist polylist(mSW); + + // sets count attribute in <polylist> + polylist.setCount(faces_in_polylist); + + // sets material name + if (ma) { + polylist.setMaterial(translate_id(id_name(ma))); + } + + COLLADASW::InputList &til = polylist.getInputList(); + + // creates <input> in <polylist> for vertices + COLLADASW::Input input1(COLLADASW::VERTEX, getUrlBySemantics(geom_id, COLLADASW::VERTEX), 0); + + // creates <input> in <polylist> for normals + COLLADASW::Input input2(COLLADASW::NORMAL, getUrlBySemantics(geom_id, COLLADASW::NORMAL), 1); + + til.push_back(input1); + til.push_back(input2); + + // if mesh has uv coords writes <input> for TEXCOORD + int num_layers = CustomData_number_of_layers(&me->fdata, CD_MTFACE); + + for (i = 0; i < num_layers; i++) { + // char *name = CustomData_get_layer_name(&me->fdata, CD_MTFACE, i); + COLLADASW::Input input3(COLLADASW::TEXCOORD, + makeUrl(makeTexcoordSourceId(geom_id, i)), + 2, // offset always 2, this is only until we have optimized UV sets + i // set number equals UV layer index + ); + til.push_back(input3); + } + + if (has_color) { + COLLADASW::Input input4(COLLADASW::COLOR, getUrlBySemantics(geom_id, COLLADASW::COLOR), has_uvs ? 3 : 2); + til.push_back(input4); + } + + // sets <vcount> + polylist.setVCountList(vcount_list); + + // performs the actual writing + polylist.prepareToAppendValues(); + + // <p> + int texindex = 0; + for (i = 0; i < totfaces; i++) { + MFace *f = &mfaces[i]; + + if (f->mat_nr == material_index) { + + unsigned int *v = &f->v1; + unsigned int *n = &norind[i].v1; + for (int j = 0; j < (f->v4 == 0 ? 3 : 4); j++) { + polylist.appendValues(v[j]); + polylist.appendValues(n[j]); + + if (has_uvs) + polylist.appendValues(texindex + j); + + if (has_color) + polylist.appendValues(texindex + j); + } + } + + texindex += 3; + if (f->v4 != 0) + texindex++; + } + + polylist.finish(); +} + +// creates <source> for positions +void GeometryExporter::createVertsSource(std::string geom_id, Mesh *me) +{ +#if 0 + int totverts = dm->getNumVerts(dm); + MVert *verts = dm->getVertArray(dm); +#endif + int totverts = me->totvert; + MVert *verts = me->mvert; + + COLLADASW::FloatSourceF source(mSW); + source.setId(getIdBySemantics(geom_id, COLLADASW::POSITION)); + source.setArrayId(getIdBySemantics(geom_id, COLLADASW::POSITION) + + ARRAY_ID_SUFFIX); + source.setAccessorCount(totverts); + source.setAccessorStride(3); + COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList(); + param.push_back("X"); + param.push_back("Y"); + param.push_back("Z"); + /*main function, it creates <source id = "">, <float_array id = "" + count = ""> */ + source.prepareToAppendValues(); + //appends data to <float_array> + int i = 0; + for (i = 0; i < totverts; i++) { + source.appendValues(verts[i].co[0], verts[i].co[1], verts[i].co[2]); + } + + source.finish(); + +} + +void GeometryExporter::createVertexColorSource(std::string geom_id, Mesh *me) +{ + if (!CustomData_has_layer(&me->fdata, CD_MCOL)) + return; + + MFace *f; + int totcolor = 0, i, j; + + for (i = 0, f = me->mface; i < me->totface; i++, f++) + totcolor += f->v4 ? 4 : 3; + + COLLADASW::FloatSourceF source(mSW); + source.setId(getIdBySemantics(geom_id, COLLADASW::COLOR)); + source.setArrayId(getIdBySemantics(geom_id, COLLADASW::COLOR) + ARRAY_ID_SUFFIX); + source.setAccessorCount(totcolor); + source.setAccessorStride(3); + + COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList(); + param.push_back("R"); + param.push_back("G"); + param.push_back("B"); + + source.prepareToAppendValues(); + + int index = CustomData_get_active_layer_index(&me->fdata, CD_MCOL); + + MCol *mcol = (MCol*)me->fdata.layers[index].data; + MCol *c = mcol; + + for (i = 0, f = me->mface; i < me->totface; i++, c += 4, f++) + for (j = 0; j < (f->v4 ? 4 : 3); j++) + source.appendValues(c[j].b / 255.0f, c[j].g / 255.0f, c[j].r / 255.0f); + + source.finish(); +} + +std::string GeometryExporter::makeTexcoordSourceId(std::string& geom_id, int layer_index) +{ + char suffix[20]; + sprintf(suffix, "-%d", layer_index); + return getIdBySemantics(geom_id, COLLADASW::TEXCOORD) + suffix; +} + +//creates <source> for texcoords +void GeometryExporter::createTexcoordsSource(std::string geom_id, Mesh *me) +{ +#if 0 + int totfaces = dm->getNumFaces(dm); + MFace *mfaces = dm->getFaceArray(dm); +#endif + int totfaces = me->totface; + MFace *mfaces = me->mface; + + int totuv = 0; + int i; + + // count totuv + for (i = 0; i < totfaces; i++) { + MFace *f = &mfaces[i]; + if (f->v4 == 0) { + totuv+=3; + } + else { + totuv+=4; + } + } + + int num_layers = CustomData_number_of_layers(&me->fdata, CD_MTFACE); + + // write <source> for each layer + // each <source> will get id like meshName + "map-channel-1" + for (int a = 0; a < num_layers; a++) { + MTFace *tface = (MTFace*)CustomData_get_layer_n(&me->fdata, CD_MTFACE, a); + // char *name = CustomData_get_layer_name(&me->fdata, CD_MTFACE, a); + + COLLADASW::FloatSourceF source(mSW); + std::string layer_id = makeTexcoordSourceId(geom_id, a); + source.setId(layer_id); + source.setArrayId(layer_id + ARRAY_ID_SUFFIX); + + source.setAccessorCount(totuv); + source.setAccessorStride(2); + COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList(); + param.push_back("S"); + param.push_back("T"); + + source.prepareToAppendValues(); + + for (i = 0; i < totfaces; i++) { + MFace *f = &mfaces[i]; + + for (int j = 0; j < (f->v4 == 0 ? 3 : 4); j++) { + source.appendValues(tface[i].uv[j][0], + tface[i].uv[j][1]); + } + } + + source.finish(); + } +} + + +//creates <source> for normals +void GeometryExporter::createNormalsSource(std::string geom_id, Mesh *me, std::vector<Normal>& nor) +{ +#if 0 + int totverts = dm->getNumVerts(dm); + MVert *verts = dm->getVertArray(dm); +#endif + + COLLADASW::FloatSourceF source(mSW); + source.setId(getIdBySemantics(geom_id, COLLADASW::NORMAL)); + source.setArrayId(getIdBySemantics(geom_id, COLLADASW::NORMAL) + + ARRAY_ID_SUFFIX); + source.setAccessorCount((unsigned long)nor.size()); + source.setAccessorStride(3); + COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList(); + param.push_back("X"); + param.push_back("Y"); + param.push_back("Z"); + + source.prepareToAppendValues(); + + std::vector<Normal>::iterator it; + for (it = nor.begin(); it != nor.end(); it++) { + Normal& n = *it; + source.appendValues(n.x, n.y, n.z); + } + + source.finish(); +} + +void GeometryExporter::create_normals(std::vector<Normal> &nor, std::vector<Face> &ind, Mesh *me) +{ + int i, j, v; + MVert *vert = me->mvert; + std::map<unsigned int, unsigned int> nshar; + + for (i = 0; i < me->totface; i++) { + MFace *fa = &me->mface[i]; + Face f; + unsigned int *nn = &f.v1; + unsigned int *vv = &fa->v1; + + memset(&f, 0, sizeof(f)); + v = fa->v4 == 0 ? 3 : 4; + + if (!(fa->flag & ME_SMOOTH)) { + Normal n; + if (v == 4) + normal_quad_v3(&n.x, vert[fa->v1].co, vert[fa->v2].co, vert[fa->v3].co, vert[fa->v4].co); + else + normal_tri_v3(&n.x, vert[fa->v1].co, vert[fa->v2].co, vert[fa->v3].co); + nor.push_back(n); + } + + for (j = 0; j < v; j++) { + if (fa->flag & ME_SMOOTH) { + if (nshar.find(*vv) != nshar.end()) + *nn = nshar[*vv]; + else { + Normal n = { + vert[*vv].no[0]/32767.0, + vert[*vv].no[1]/32767.0, + vert[*vv].no[2]/32767.0 + }; + nor.push_back(n); + *nn = (unsigned int)nor.size() - 1; + nshar[*vv] = *nn; + } + vv++; + } + else { + *nn = (unsigned int)nor.size() - 1; + } + nn++; + } + + ind.push_back(f); + } +} + +std::string GeometryExporter::getIdBySemantics(std::string geom_id, COLLADASW::Semantics type, std::string other_suffix) { + return geom_id + getSuffixBySemantic(type) + other_suffix; +} + + +COLLADASW::URI GeometryExporter::getUrlBySemantics(std::string geom_id, COLLADASW::Semantics type, std::string other_suffix) { + + std::string id(getIdBySemantics(geom_id, type, other_suffix)); + return COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, id); + +} + +COLLADASW::URI GeometryExporter::makeUrl(std::string id) +{ + return COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, id); +} + + +/* int GeometryExporter::getTriCount(MFace *faces, int totface) { + int i; + int tris = 0; + for (i = 0; i < totface; i++) { + // if quad + if (faces[i].v4 != 0) + tris += 2; + else + tris++; + } + + return tris; + }*/ diff --git a/source/blender/collada/GeometryExporter.h b/source/blender/collada/GeometryExporter.h new file mode 100644 index 00000000000..7a78b676f49 --- /dev/null +++ b/source/blender/collada/GeometryExporter.h @@ -0,0 +1,114 @@ +/** + * $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): Chingiz Dyussenov, Arystanbek Dyussenov, Jan Diederich, Tod Liverseed, + * Nathan Letwory + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef __GEOMETRYEXPORTER_H__ +#define __GEOMETRYEXPORTER_H__ + +#include <string> +#include <vector> + +#include "COLLADASWStreamWriter.h" +#include "COLLADASWLibraryGeometries.h" +#include "COLLADASWInputList.h" + +#include "DNA_mesh_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" + +// TODO: optimize UV sets by making indexed list with duplicates removed +class GeometryExporter : COLLADASW::LibraryGeometries +{ + struct Face + { + unsigned int v1, v2, v3, v4; + }; + + struct Normal + { + float x, y, z; + }; + + Scene *mScene; + +public: + GeometryExporter(COLLADASW::StreamWriter *sw); + + void exportGeom(Scene *sce); + + void operator()(Object *ob); + + // powerful because it handles both cases when there is material and when there's not + void createPolylist(int material_index, + bool has_uvs, + bool has_color, + Object *ob, + std::string& geom_id, + std::vector<Face>& norind); + + // creates <source> for positions + void createVertsSource(std::string geom_id, Mesh *me); + + void createVertexColorSource(std::string geom_id, Mesh *me); + + std::string makeTexcoordSourceId(std::string& geom_id, int layer_index); + + //creates <source> for texcoords + void createTexcoordsSource(std::string geom_id, Mesh *me); + + //creates <source> for normals + void createNormalsSource(std::string geom_id, Mesh *me, std::vector<Normal>& nor); + + void create_normals(std::vector<Normal> &nor, std::vector<Face> &ind, Mesh *me); + + std::string getIdBySemantics(std::string geom_id, COLLADASW::Semantics type, std::string other_suffix = ""); + + COLLADASW::URI getUrlBySemantics(std::string geom_id, COLLADASW::Semantics type, std::string other_suffix = ""); + + COLLADASW::URI makeUrl(std::string id); + + /* int getTriCount(MFace *faces, int totface);*/ +}; + +struct GeometryFunctor { + // f should have + // void operator()(Object* ob) + template<class Functor> + void forEachMeshObjectInScene(Scene *sce, Functor &f) + { + + Base *base= (Base*) sce->base.first; + while(base) { + Object *ob = base->object; + + if (ob->type == OB_MESH && ob->data) { + f(ob); + } + base= base->next; + + } + } +}; + +#endif diff --git a/source/blender/collada/ImageExporter.cpp b/source/blender/collada/ImageExporter.cpp new file mode 100644 index 00000000000..ce40846ba59 --- /dev/null +++ b/source/blender/collada/ImageExporter.cpp @@ -0,0 +1,93 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Chingiz Dyussenov, Arystanbek Dyussenov, Jan Diederich, Tod Liverseed, + * Nathan Letwory + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "COLLADABUURI.h" +#include "COLLADASWImage.h" + +#include "ImageExporter.h" +#include "MaterialExporter.h" + +#include "DNA_texture_types.h" + +#include "BKE_global.h" +#include "BKE_utildefines.h" +#include "BLI_fileops.h" +#include "BLI_path_util.h" +#include "BLI_string.h" + +ImagesExporter::ImagesExporter(COLLADASW::StreamWriter *sw, const char* filename) : COLLADASW::LibraryImages(sw), mfilename(filename) +{} + +void ImagesExporter::exportImages(Scene *sce) +{ + openLibrary(); + MaterialFunctor mf; + mf.forEachMaterialInScene<ImagesExporter>(sce, *this); + + closeLibrary(); +} + +void ImagesExporter::operator()(Material *ma, Object *ob) +{ + int a; + for (a = 0; a < MAX_MTEX; a++) { + MTex *mtex = ma->mtex[a]; + if (mtex && mtex->tex && mtex->tex->ima) { + + Image *image = mtex->tex->ima; + std::string name(id_name(image)); + name = translate_id(name); + char rel[FILE_MAX]; + char abs[FILE_MAX]; + char src[FILE_MAX]; + char dir[FILE_MAX]; + + BLI_split_dirfile(mfilename, dir, NULL); + + BKE_rebase_path(abs, sizeof(abs), rel, sizeof(rel), G.sce, image->name, dir); + + if (abs[0] != '\0') { + + // make absolute source path + BLI_strncpy(src, image->name, sizeof(src)); + BLI_path_abs(src, G.sce); + + // make dest directory if it doesn't exist + BLI_make_existing_file(abs); + + if (BLI_copy_fileops(src, abs) != 0) { + fprintf(stderr, "Cannot copy image to file's directory. \n"); + } + } + + if (find(mImages.begin(), mImages.end(), name) == mImages.end()) { + COLLADASW::Image img(COLLADABU::URI(COLLADABU::URI::nativePathToUri(rel)), name); + img.add(mSW); + + mImages.push_back(name); + } + } + } +} diff --git a/source/blender/collada/ImageExporter.h b/source/blender/collada/ImageExporter.h new file mode 100644 index 00000000000..13854d00730 --- /dev/null +++ b/source/blender/collada/ImageExporter.h @@ -0,0 +1,50 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Chingiz Dyussenov, Arystanbek Dyussenov, Jan Diederich, Tod Liverseed, + * Nathan Letwory + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef __IMAGEEXPORTER_H__ +#define __IMAGEEXPORTER_H__ + +#include <vector> +#include <string> + +#include "COLLADASWStreamWriter.h" +#include "COLLADASWLibraryImages.h" + +#include "DNA_material_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" + +class ImagesExporter: COLLADASW::LibraryImages +{ + const char *mfilename; + std::vector<std::string> mImages; // contains list of written images, to avoid duplicates +public: + ImagesExporter(COLLADASW::StreamWriter *sw, const char* filename); + + void exportImages(Scene *sce); + void operator()(Material *ma, Object *ob); +}; + +#endif diff --git a/source/blender/collada/InstanceWriter.cpp b/source/blender/collada/InstanceWriter.cpp new file mode 100644 index 00000000000..746f41fac00 --- /dev/null +++ b/source/blender/collada/InstanceWriter.cpp @@ -0,0 +1,64 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Chingiz Dyussenov, Arystanbek Dyussenov, Jan Diederich, Tod Liverseed, + * Nathan Letwory + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include <string> + +#include "COLLADASWInstanceMaterial.h" + +#include "BKE_customdata.h" +#include "BKE_material.h" + +#include "DNA_mesh_types.h" + +#include "InstanceWriter.h" + +#include "collada_internal.h" +#include "collada_utils.h" + +void InstanceWriter::add_material_bindings(COLLADASW::BindMaterial& bind_material, Object *ob) +{ + for(int a = 0; a < ob->totcol; a++) { + Material *ma = give_current_material(ob, a+1); + + COLLADASW::InstanceMaterialList& iml = bind_material.getInstanceMaterialList(); + + if (ma) { + std::string matid(id_name(ma)); + matid = translate_id(matid); + COLLADASW::InstanceMaterial im(matid, COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, matid)); + + // create <bind_vertex_input> for each uv layer + Mesh *me = (Mesh*)ob->data; + int totlayer = CustomData_number_of_layers(&me->fdata, CD_MTFACE); + + for (int b = 0; b < totlayer; b++) { + char *name = bc_CustomData_get_layer_name(&me->fdata, CD_MTFACE, b); + im.push_back(COLLADASW::BindVertexInput(name, "TEXCOORD", b)); + } + + iml.push_back(im); + } + } +} diff --git a/source/blender/collada/InstanceWriter.h b/source/blender/collada/InstanceWriter.h new file mode 100644 index 00000000000..810bd04c7de --- /dev/null +++ b/source/blender/collada/InstanceWriter.h @@ -0,0 +1,39 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Chingiz Dyussenov, Arystanbek Dyussenov, Jan Diederich, Tod Liverseed, + * Nathan Letwory + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef __INSTANCEWRITER_H__ +#define __INSTANCEWRITER_H__ + +#include "COLLADASWBindMaterial.h" + +#include "DNA_object_types.h" + +class InstanceWriter +{ +protected: + void add_material_bindings(COLLADASW::BindMaterial& bind_material, Object *ob); +}; + +#endif diff --git a/source/blender/collada/LightExporter.cpp b/source/blender/collada/LightExporter.cpp new file mode 100644 index 00000000000..7327b309889 --- /dev/null +++ b/source/blender/collada/LightExporter.cpp @@ -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): Chingiz Dyussenov, Arystanbek Dyussenov, Jan Diederich, Tod Liverseed, + * Nathan Letwory + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include <string> + +#include "COLLADASWColor.h" +#include "COLLADASWLight.h" + +#include "DNA_lamp_types.h" + +#include "LightExporter.h" +#include "collada_internal.h" + +template<class Functor> +void forEachLampObjectInScene(Scene *sce, Functor &f) +{ + Base *base= (Base*) sce->base.first; + while(base) { + Object *ob = base->object; + + if (ob->type == OB_LAMP && ob->data) { + f(ob); + } + base= base->next; + } +} + +LightsExporter::LightsExporter(COLLADASW::StreamWriter *sw): COLLADASW::LibraryLights(sw){} +void LightsExporter::exportLights(Scene *sce) +{ + openLibrary(); + + forEachLampObjectInScene(sce, *this); + + closeLibrary(); +} +void LightsExporter::operator()(Object *ob) +{ + Lamp *la = (Lamp*)ob->data; + std::string la_id(get_light_id(ob)); + std::string la_name(id_name(la)); + COLLADASW::Color col(la->r, la->g, la->b); + float e = la->energy; + + // sun + if (la->type == LA_SUN) { + COLLADASW::DirectionalLight cla(mSW, la_id, la_name, e); + cla.setColor(col); + addLight(cla); + } + // hemi + else if (la->type == LA_HEMI) { + COLLADASW::AmbientLight cla(mSW, la_id, la_name, e); + cla.setColor(col); + addLight(cla); + } + // spot + else if (la->type == LA_SPOT) { + COLLADASW::SpotLight cla(mSW, la_id, la_name, e); + cla.setColor(col); + cla.setFallOffAngle(la->spotsize); + cla.setFallOffExponent(la->spotblend); + cla.setLinearAttenuation(la->att1); + cla.setQuadraticAttenuation(la->att2); + addLight(cla); + } + // lamp + else if (la->type == LA_LOCAL) { + COLLADASW::PointLight cla(mSW, la_id, la_name, e); + cla.setColor(col); + cla.setLinearAttenuation(la->att1); + cla.setQuadraticAttenuation(la->att2); + addLight(cla); + } + // area lamp is not supported + // it will be exported as a local lamp + else { + COLLADASW::PointLight cla(mSW, la_id, la_name, e); + cla.setColor(col); + cla.setLinearAttenuation(la->att1); + cla.setQuadraticAttenuation(la->att2); + addLight(cla); + } +} diff --git a/source/blender/collada/LightExporter.h b/source/blender/collada/LightExporter.h new file mode 100644 index 00000000000..3a4a481e471 --- /dev/null +++ b/source/blender/collada/LightExporter.h @@ -0,0 +1,43 @@ +/** + * $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): Chingiz Dyussenov, Arystanbek Dyussenov, Jan Diederich, Tod Liverseed, + * Nathan Letwory + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef __LIGHTEXPORTER_H__ +#define __LIGHTEXPORTER_H__ + +#include "COLLADASWStreamWriter.h" +#include "COLLADASWLibraryLights.h" + +#include "DNA_object_types.h" +#include "DNA_scene_types.h" + +class LightsExporter: COLLADASW::LibraryLights +{ +public: + LightsExporter(COLLADASW::StreamWriter *sw); + void exportLights(Scene *sce); + void operator()(Object *ob); +}; + +#endif diff --git a/source/blender/collada/MaterialExporter.cpp b/source/blender/collada/MaterialExporter.cpp new file mode 100644 index 00000000000..d155b2196ff --- /dev/null +++ b/source/blender/collada/MaterialExporter.cpp @@ -0,0 +1,53 @@ +/** + * $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): Chingiz Dyussenov, Arystanbek Dyussenov, Jan Diederich, Tod Liverseed, + * Nathan Letwory + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "COLLADABUUtils.h" + +#include "MaterialExporter.h" +#include "collada_internal.h" + +MaterialsExporter::MaterialsExporter(COLLADASW::StreamWriter *sw): COLLADASW::LibraryMaterials(sw){} + +void MaterialsExporter::exportMaterials(Scene *sce) +{ + openLibrary(); + + MaterialFunctor mf; + mf.forEachMaterialInScene<MaterialsExporter>(sce, *this); + + closeLibrary(); +} + +void MaterialsExporter::operator()(Material *ma, Object *ob) +{ + std::string name(id_name(ma)); + + openMaterial(translate_id(name), name); + + std::string efid = translate_id(name) + "-effect"; + addInstanceEffect(COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, efid)); + + closeMaterial(); +} diff --git a/source/blender/collada/MaterialExporter.h b/source/blender/collada/MaterialExporter.h new file mode 100644 index 00000000000..2138d26e6a8 --- /dev/null +++ b/source/blender/collada/MaterialExporter.h @@ -0,0 +1,94 @@ +/** + * $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): Chingiz Dyussenov, Arystanbek Dyussenov, Jan Diederich, Tod Liverseed, + * Nathan Letwory + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef __MATERIALEXPORTER_H__ +#define __MATERIALEXPORTER_H__ + +#include <string> +#include <vector> + +#include "COLLADASWLibraryMaterials.h" +#include "COLLADASWStreamWriter.h" + +#include "BKE_material.h" + +#include "DNA_material_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" + +#include "GeometryExporter.h" +#include "collada_internal.h" + +class MaterialsExporter: COLLADASW::LibraryMaterials +{ +public: + MaterialsExporter(COLLADASW::StreamWriter *sw); + void exportMaterials(Scene *sce); + void operator()(Material *ma, Object *ob); +}; + +// used in forEachMaterialInScene +template <class Functor> +class ForEachMaterialFunctor +{ + std::vector<std::string> mMat; // contains list of material names, to avoid duplicate calling of f + Functor *f; +public: + ForEachMaterialFunctor(Functor*f) : f(f) {} + + void operator ()(Object *ob) + { + int a; + for(a = 0; a < ob->totcol; a++) { + + Material *ma = give_current_material(ob, a+1); + + if (!ma) continue; + + std::string translated_id = translate_id(id_name(ma)); + if (find(mMat.begin(), mMat.end(), translated_id) == mMat.end()) { + (*this->f)(ma, ob); + + mMat.push_back(translated_id); + } + } + } +}; + +struct MaterialFunctor { + // calls f for each unique material linked to each object in sce + // f should have + // void operator()(Material* ma) + template<class Functor> + void forEachMaterialInScene(Scene *sce, Functor &f) + { + ForEachMaterialFunctor<Functor> matfunc(&f); + GeometryFunctor gf; + gf.forEachMeshObjectInScene<ForEachMaterialFunctor<Functor> >(sce, matfunc); + } +}; + + +#endif diff --git a/source/blender/collada/MeshImporter.cpp b/source/blender/collada/MeshImporter.cpp new file mode 100644 index 00000000000..be7abc3ec4e --- /dev/null +++ b/source/blender/collada/MeshImporter.cpp @@ -0,0 +1,912 @@ +/** + * $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): Chingiz Dyussenov, Arystanbek Dyussenov, Nathan Letwory. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include <algorithm> + +#if !defined(WIN32) || defined(FREE_WINDOWS) +#include <iostream> +#endif + +#include "COLLADAFWMeshPrimitive.h" +#include "COLLADAFWMeshVertexData.h" +#include "COLLADAFWPolygons.h" + +extern "C" { +#include "BKE_blender.h" +#include "BKE_customdata.h" +#include "BKE_displist.h" +#include "BKE_global.h" +#include "BKE_library.h" +#include "BKE_main.h" +#include "BKE_material.h" +#include "BKE_mesh.h" +#include "BKE_object.h" + +#include "BLI_listbase.h" +#include "BLI_math.h" +#include "BLI_string.h" + +#include "MEM_guardedalloc.h" +} + +#include "ArmatureImporter.h" +#include "MeshImporter.h" +#include "collada_utils.h" + +// works for COLLADAFW::Node, COLLADAFW::Geometry +template<class T> +static const char *bc_get_dae_name(T *node) +{ + const std::string& name = node->getName(); + return name.size() ? name.c_str() : node->getOriginalId().c_str(); +} + +static const char *bc_primTypeToStr(COLLADAFW::MeshPrimitive::PrimitiveType type) +{ + switch (type) { + case COLLADAFW::MeshPrimitive::LINES: + return "LINES"; + case COLLADAFW::MeshPrimitive::LINE_STRIPS: + return "LINESTRIPS"; + case COLLADAFW::MeshPrimitive::POLYGONS: + return "POLYGONS"; + case COLLADAFW::MeshPrimitive::POLYLIST: + return "POLYLIST"; + case COLLADAFW::MeshPrimitive::TRIANGLES: + return "TRIANGLES"; + case COLLADAFW::MeshPrimitive::TRIANGLE_FANS: + return "TRIANGLE_FANS"; + case COLLADAFW::MeshPrimitive::TRIANGLE_STRIPS: + return "TRIANGLE_FANS"; + case COLLADAFW::MeshPrimitive::POINTS: + return "POINTS"; + case COLLADAFW::MeshPrimitive::UNDEFINED_PRIMITIVE_TYPE: + return "UNDEFINED_PRIMITIVE_TYPE"; + } + return "UNKNOWN"; +} + +static const char *bc_geomTypeToStr(COLLADAFW::Geometry::GeometryType type) +{ + switch (type) { + case COLLADAFW::Geometry::GEO_TYPE_MESH: + return "MESH"; + case COLLADAFW::Geometry::GEO_TYPE_SPLINE: + return "SPLINE"; + case COLLADAFW::Geometry::GEO_TYPE_CONVEX_MESH: + return "CONVEX_MESH"; + case COLLADAFW::Geometry::GEO_TYPE_UNKNOWN: + default: + return "UNKNOWN"; + } +} + + +UVDataWrapper::UVDataWrapper(COLLADAFW::MeshVertexData& vdata) : mVData(&vdata) +{} + +#ifdef COLLADA_DEBUG +void WVDataWrapper::print() +{ + fprintf(stderr, "UVs:\n"); + switch(mVData->getType()) { + case COLLADAFW::MeshVertexData::DATA_TYPE_FLOAT: + { + COLLADAFW::ArrayPrimitiveType<float>* values = mVData->getFloatValues(); + if (values->getCount()) { + for (int i = 0; i < values->getCount(); i += 2) { + fprintf(stderr, "%.1f, %.1f\n", (*values)[i], (*values)[i+1]); + } + } + } + break; + case COLLADAFW::MeshVertexData::DATA_TYPE_DOUBLE: + { + COLLADAFW::ArrayPrimitiveType<double>* values = mVData->getDoubleValues(); + if (values->getCount()) { + for (int i = 0; i < values->getCount(); i += 2) { + fprintf(stderr, "%.1f, %.1f\n", (float)(*values)[i], (float)(*values)[i+1]); + } + } + } + break; + } + fprintf(stderr, "\n"); +} +#endif + +void UVDataWrapper::getUV(int uv_index[2], float *uv) +{ + switch(mVData->getType()) { + case COLLADAFW::MeshVertexData::DATA_TYPE_FLOAT: + { + COLLADAFW::ArrayPrimitiveType<float>* values = mVData->getFloatValues(); + if (values->empty()) return; + uv[0] = (*values)[uv_index[0]]; + uv[1] = (*values)[uv_index[1]]; + + } + break; + case COLLADAFW::MeshVertexData::DATA_TYPE_DOUBLE: + { + COLLADAFW::ArrayPrimitiveType<double>* values = mVData->getDoubleValues(); + if (values->empty()) return; + uv[0] = (float)(*values)[uv_index[0]]; + uv[1] = (float)(*values)[uv_index[1]]; + + } + break; + case COLLADAFW::MeshVertexData::DATA_TYPE_UNKNOWN: + default: + fprintf(stderr, "MeshImporter.getUV(): unknown data type\n"); + } +} + +void MeshImporter::set_face_indices(MFace *mface, unsigned int *indices, bool quad) +{ + mface->v1 = indices[0]; + mface->v2 = indices[1]; + mface->v3 = indices[2]; + if (quad) mface->v4 = indices[3]; + else mface->v4 = 0; +#ifdef COLLADA_DEBUG + // fprintf(stderr, "%u, %u, %u \n", indices[0], indices[1], indices[2]); +#endif +} + +// not used anymore, test_index_face from blenkernel is better +#if 0 +// change face indices order so that v4 is not 0 +void MeshImporter::rotate_face_indices(MFace *mface) { + mface->v4 = mface->v1; + mface->v1 = mface->v2; + mface->v2 = mface->v3; + mface->v3 = 0; +} +#endif + +void MeshImporter::set_face_uv(MTFace *mtface, UVDataWrapper &uvs, + COLLADAFW::IndexList& index_list, unsigned int *tris_indices) +{ + int uv_indices[4][2]; + + // per face vertex indices, this means for quad we have 4 indices, not 8 + COLLADAFW::UIntValuesArray& indices = index_list.getIndices(); + + // make indices into FloatOrDoubleArray + for (int i = 0; i < 3; i++) { + int uv_index = indices[tris_indices[i]]; + uv_indices[i][0] = uv_index * 2; + uv_indices[i][1] = uv_index * 2 + 1; + } + + uvs.getUV(uv_indices[0], mtface->uv[0]); + uvs.getUV(uv_indices[1], mtface->uv[1]); + uvs.getUV(uv_indices[2], mtface->uv[2]); +} + +void MeshImporter::set_face_uv(MTFace *mtface, UVDataWrapper &uvs, + COLLADAFW::IndexList& index_list, int index, bool quad) +{ + int uv_indices[4][2]; + + // per face vertex indices, this means for quad we have 4 indices, not 8 + COLLADAFW::UIntValuesArray& indices = index_list.getIndices(); + + // make indices into FloatOrDoubleArray + for (int i = 0; i < (quad ? 4 : 3); i++) { + int uv_index = indices[index + i]; + uv_indices[i][0] = uv_index * 2; + uv_indices[i][1] = uv_index * 2 + 1; + } + + uvs.getUV(uv_indices[0], mtface->uv[0]); + uvs.getUV(uv_indices[1], mtface->uv[1]); + uvs.getUV(uv_indices[2], mtface->uv[2]); + + if (quad) uvs.getUV(uv_indices[3], mtface->uv[3]); + +#ifdef COLLADA_DEBUG + /*if (quad) { + fprintf(stderr, "face uv:\n" + "((%d, %d), (%d, %d), (%d, %d), (%d, %d))\n" + "((%.1f, %.1f), (%.1f, %.1f), (%.1f, %.1f), (%.1f, %.1f))\n", + + uv_indices[0][0], uv_indices[0][1], + uv_indices[1][0], uv_indices[1][1], + uv_indices[2][0], uv_indices[2][1], + uv_indices[3][0], uv_indices[3][1], + + mtface->uv[0][0], mtface->uv[0][1], + mtface->uv[1][0], mtface->uv[1][1], + mtface->uv[2][0], mtface->uv[2][1], + mtface->uv[3][0], mtface->uv[3][1]); + } + else { + fprintf(stderr, "face uv:\n" + "((%d, %d), (%d, %d), (%d, %d))\n" + "((%.1f, %.1f), (%.1f, %.1f), (%.1f, %.1f))\n", + + uv_indices[0][0], uv_indices[0][1], + uv_indices[1][0], uv_indices[1][1], + uv_indices[2][0], uv_indices[2][1], + + mtface->uv[0][0], mtface->uv[0][1], + mtface->uv[1][0], mtface->uv[1][1], + mtface->uv[2][0], mtface->uv[2][1]); + }*/ +#endif +} + +#ifdef COLLADA_DEBUG +void MeshImporter::print_index_list(COLLADAFW::IndexList& index_list) +{ + fprintf(stderr, "Index list for \"%s\":\n", index_list.getName().c_str()); + for (int i = 0; i < index_list.getIndicesCount(); i += 2) { + fprintf(stderr, "%u, %u\n", index_list.getIndex(i), index_list.getIndex(i + 1)); + } + fprintf(stderr, "\n"); +} +#endif + +bool MeshImporter::is_nice_mesh(COLLADAFW::Mesh *mesh) +{ + COLLADAFW::MeshPrimitiveArray& prim_arr = mesh->getMeshPrimitives(); + + const char *name = bc_get_dae_name(mesh); + + for (unsigned i = 0; i < prim_arr.getCount(); i++) { + + COLLADAFW::MeshPrimitive *mp = prim_arr[i]; + COLLADAFW::MeshPrimitive::PrimitiveType type = mp->getPrimitiveType(); + + const char *type_str = bc_primTypeToStr(type); + + // OpenCollada passes POLYGONS type for <polylist> + if (type == COLLADAFW::MeshPrimitive::POLYLIST || type == COLLADAFW::MeshPrimitive::POLYGONS) { + + COLLADAFW::Polygons *mpvc = (COLLADAFW::Polygons*)mp; + COLLADAFW::Polygons::VertexCountArray& vca = mpvc->getGroupedVerticesVertexCountArray(); + + for(unsigned int j = 0; j < vca.getCount(); j++){ + int count = vca[j]; + if (count < 3) { + fprintf(stderr, "Primitive %s in %s has at least one face with vertex count < 3\n", + type_str, name); + return false; + } + } + + } + else if(type != COLLADAFW::MeshPrimitive::TRIANGLES) { + fprintf(stderr, "Primitive type %s is not supported.\n", type_str); + return false; + } + } + + if (mesh->getPositions().empty()) { + fprintf(stderr, "Mesh %s has no vertices.\n", name); + return false; + } + + return true; +} + +void MeshImporter::read_vertices(COLLADAFW::Mesh *mesh, Mesh *me) +{ + // vertices + me->totvert = mesh->getPositions().getFloatValues()->getCount() / 3; + me->mvert = (MVert*)CustomData_add_layer(&me->vdata, CD_MVERT, CD_CALLOC, NULL, me->totvert); + + COLLADAFW::MeshVertexData& pos = mesh->getPositions(); + MVert *mvert; + int i; + + for (i = 0, mvert = me->mvert; i < me->totvert; i++, mvert++) { + get_vector(mvert->co, pos, i); + } +} + +int MeshImporter::triangulate_poly(unsigned int *indices, int totvert, MVert *verts, std::vector<unsigned int>& tri) +{ + ListBase dispbase; + DispList *dl; + float *vert; + int i = 0; + + dispbase.first = dispbase.last = NULL; + + dl = (DispList*)MEM_callocN(sizeof(DispList), "poly disp"); + dl->nr = totvert; + dl->type = DL_POLY; + dl->parts = 1; + dl->verts = vert = (float*)MEM_callocN(totvert * 3 * sizeof(float), "poly verts"); + dl->index = (int*)MEM_callocN(sizeof(int) * 3 * totvert, "dl index"); + + BLI_addtail(&dispbase, dl); + + for (i = 0; i < totvert; i++) { + copy_v3_v3(vert, verts[indices[i]].co); + vert += 3; + } + + filldisplist(&dispbase, &dispbase, 0); + + int tottri = 0; + dl= (DispList*)dispbase.first; + + if (dl->type == DL_INDEX3) { + tottri = dl->parts; + + int *index = dl->index; + for (i= 0; i < tottri; i++) { + int t[3]= {*index, *(index + 1), *(index + 2)}; + + std::sort(t, t + 3); + + tri.push_back(t[0]); + tri.push_back(t[1]); + tri.push_back(t[2]); + + index += 3; + } + } + + freedisplist(&dispbase); + + return tottri; +} + +int MeshImporter::count_new_tris(COLLADAFW::Mesh *mesh, Mesh *me) +{ + COLLADAFW::MeshPrimitiveArray& prim_arr = mesh->getMeshPrimitives(); + unsigned int i; + int tottri = 0; + + for (i = 0; i < prim_arr.getCount(); i++) { + + COLLADAFW::MeshPrimitive *mp = prim_arr[i]; + int type = mp->getPrimitiveType(); + size_t prim_totface = mp->getFaceCount(); + unsigned int *indices = mp->getPositionIndices().getData(); + + if (type == COLLADAFW::MeshPrimitive::POLYLIST || + type == COLLADAFW::MeshPrimitive::POLYGONS) { + + COLLADAFW::Polygons *mpvc = (COLLADAFW::Polygons*)mp; + COLLADAFW::Polygons::VertexCountArray& vcounta = mpvc->getGroupedVerticesVertexCountArray(); + + for (unsigned int j = 0; j < prim_totface; j++) { + int vcount = vcounta[j]; + + if (vcount > 4) { + std::vector<unsigned int> tri; + + // tottri += triangulate_poly(indices, vcount, me->mvert, tri) - 1; // XXX why - 1?! + tottri += triangulate_poly(indices, vcount, me->mvert, tri); + } + + indices += vcount; + } + } + } + return tottri; +} + +// TODO: import uv set names +void MeshImporter::read_faces(COLLADAFW::Mesh *mesh, Mesh *me, int new_tris) +{ + unsigned int i; + + // allocate faces + me->totface = mesh->getFacesCount() + new_tris; + me->mface = (MFace*)CustomData_add_layer(&me->fdata, CD_MFACE, CD_CALLOC, NULL, me->totface); + + // allocate UV layers + unsigned int totuvset = mesh->getUVCoords().getInputInfosArray().getCount(); + + for (i = 0; i < totuvset; i++) { + if (mesh->getUVCoords().getLength(i) == 0) { + totuvset = 0; + break; + } + } + + for (i = 0; i < totuvset; i++) { + COLLADAFW::MeshVertexData::InputInfos *info = mesh->getUVCoords().getInputInfosArray()[i]; + CustomData_add_layer_named(&me->fdata, CD_MTFACE, CD_CALLOC, NULL, me->totface, info->mName.c_str()); + //this->set_layername_map[i] = CustomData_get_layer_name(&me->fdata, CD_MTFACE, i); + } + + // activate the first uv layer + if (totuvset) me->mtface = (MTFace*)CustomData_get_layer_n(&me->fdata, CD_MTFACE, 0); + + UVDataWrapper uvs(mesh->getUVCoords()); + +#ifdef COLLADA_DEBUG + // uvs.print(); +#endif + + MFace *mface = me->mface; + + MaterialIdPrimitiveArrayMap mat_prim_map; + + int face_index = 0; + + COLLADAFW::MeshPrimitiveArray& prim_arr = mesh->getMeshPrimitives(); + + bool has_normals = mesh->hasNormals(); + COLLADAFW::MeshVertexData& nor = mesh->getNormals(); + + for (i = 0; i < prim_arr.getCount(); i++) { + + COLLADAFW::MeshPrimitive *mp = prim_arr[i]; + + // faces + size_t prim_totface = mp->getFaceCount(); + unsigned int *indices = mp->getPositionIndices().getData(); + unsigned int *nind = mp->getNormalIndices().getData(); + unsigned int j, k; + int type = mp->getPrimitiveType(); + int index = 0; + + // since we cannot set mface->mat_nr here, we store a portion of me->mface in Primitive + Primitive prim = {mface, 0}; + COLLADAFW::IndexListArray& index_list_array = mp->getUVCoordIndicesArray(); + +#ifdef COLLADA_DEBUG + /* + fprintf(stderr, "Primitive %d:\n", i); + for (int j = 0; j < totuvset; j++) { + print_index_list(*index_list_array[j]); + } + */ +#endif + + if (type == COLLADAFW::MeshPrimitive::TRIANGLES) { + for (j = 0; j < prim_totface; j++){ + + set_face_indices(mface, indices, false); + indices += 3; + +#if 0 + for (k = 0; k < totuvset; k++) { + if (!index_list_array.empty() && index_list_array[k]) { + // get mtface by face index and uv set index + MTFace *mtface = (MTFace*)CustomData_get_layer_n(&me->fdata, CD_MTFACE, k); + set_face_uv(&mtface[face_index], uvs, k, *index_list_array[k], index, false); + } + } +#else + for (k = 0; k < index_list_array.getCount(); k++) { + int uvset_index = index_list_array[k]->getSetIndex(); + + // get mtface by face index and uv set index + MTFace *mtface = (MTFace*)CustomData_get_layer_n(&me->fdata, CD_MTFACE, uvset_index); + set_face_uv(&mtface[face_index], uvs, *index_list_array[k], index, false); + } +#endif + + test_index_face(mface, &me->fdata, face_index, 3); + + if (has_normals) { + if (!flat_face(nind, nor, 3)) + mface->flag |= ME_SMOOTH; + + nind += 3; + } + + index += 3; + mface++; + face_index++; + prim.totface++; + } + } + else if (type == COLLADAFW::MeshPrimitive::POLYLIST || type == COLLADAFW::MeshPrimitive::POLYGONS) { + COLLADAFW::Polygons *mpvc = (COLLADAFW::Polygons*)mp; + COLLADAFW::Polygons::VertexCountArray& vcounta = mpvc->getGroupedVerticesVertexCountArray(); + + for (j = 0; j < prim_totface; j++) { + + // face + int vcount = vcounta[j]; + if (vcount == 3 || vcount == 4) { + + set_face_indices(mface, indices, vcount == 4); + + // set mtface for each uv set + // it is assumed that all primitives have equal number of UV sets + +#if 0 + for (k = 0; k < totuvset; k++) { + if (!index_list_array.empty() && index_list_array[k]) { + // get mtface by face index and uv set index + MTFace *mtface = (MTFace*)CustomData_get_layer_n(&me->fdata, CD_MTFACE, k); + set_face_uv(&mtface[face_index], uvs, k, *index_list_array[k], index, mface->v4 != 0); + } + } +#else + for (k = 0; k < index_list_array.getCount(); k++) { + int uvset_index = index_list_array[k]->getSetIndex(); + + // get mtface by face index and uv set index + MTFace *mtface = (MTFace*)CustomData_get_layer_n(&me->fdata, CD_MTFACE, uvset_index); + set_face_uv(&mtface[face_index], uvs, *index_list_array[k], index, mface->v4 != 0); + } +#endif + + test_index_face(mface, &me->fdata, face_index, vcount); + + if (has_normals) { + if (!flat_face(nind, nor, vcount)) + mface->flag |= ME_SMOOTH; + + nind += vcount; + } + + mface++; + face_index++; + prim.totface++; + + } + else { + std::vector<unsigned int> tri; + + triangulate_poly(indices, vcount, me->mvert, tri); + + for (k = 0; k < tri.size() / 3; k++) { + int v = k * 3; + unsigned int uv_indices[3] = { + index + tri[v], + index + tri[v + 1], + index + tri[v + 2] + }; + unsigned int tri_indices[3] = { + indices[tri[v]], + indices[tri[v + 1]], + indices[tri[v + 2]] + }; + + set_face_indices(mface, tri_indices, false); + +#if 0 + for (unsigned int l = 0; l < totuvset; l++) { + if (!index_list_array.empty() && index_list_array[l]) { + // get mtface by face index and uv set index + MTFace *mtface = (MTFace*)CustomData_get_layer_n(&me->fdata, CD_MTFACE, l); + set_face_uv(&mtface[face_index], uvs, l, *index_list_array[l], uv_indices); + } + } +#else + for (unsigned int l = 0; l < index_list_array.getCount(); l++) { + int uvset_index = index_list_array[l]->getSetIndex(); + + // get mtface by face index and uv set index + MTFace *mtface = (MTFace*)CustomData_get_layer_n(&me->fdata, CD_MTFACE, uvset_index); + set_face_uv(&mtface[face_index], uvs, *index_list_array[l], uv_indices); + } +#endif + + + test_index_face(mface, &me->fdata, face_index, 3); + + if (has_normals) { + unsigned int ntri[3] = {nind[tri[v]], nind[tri[v + 1]], nind[tri[v + 2]]}; + + if (!flat_face(ntri, nor, 3)) + mface->flag |= ME_SMOOTH; + } + + mface++; + face_index++; + prim.totface++; + } + + if (has_normals) + nind += vcount; + } + + index += vcount; + indices += vcount; + } + } + + mat_prim_map[mp->getMaterialId()].push_back(prim); + } + + geom_uid_mat_mapping_map[mesh->getUniqueId()] = mat_prim_map; +} + +void MeshImporter::get_vector(float v[3], COLLADAFW::MeshVertexData& arr, int i) +{ + i *= 3; + + switch(arr.getType()) { + case COLLADAFW::MeshVertexData::DATA_TYPE_FLOAT: + { + COLLADAFW::ArrayPrimitiveType<float>* values = arr.getFloatValues(); + if (values->empty()) return; + + v[0] = (*values)[i++]; + v[1] = (*values)[i++]; + v[2] = (*values)[i]; + } + break; + case COLLADAFW::MeshVertexData::DATA_TYPE_DOUBLE: + { + COLLADAFW::ArrayPrimitiveType<double>* values = arr.getDoubleValues(); + if (values->empty()) return; + + v[0] = (float)(*values)[i++]; + v[1] = (float)(*values)[i++]; + v[2] = (float)(*values)[i]; + } + break; + default: + break; + } +} + +bool MeshImporter::flat_face(unsigned int *nind, COLLADAFW::MeshVertexData& nor, int count) +{ + float a[3], b[3]; + + get_vector(a, nor, *nind); + normalize_v3(a); + + nind++; + + for (int i = 1; i < count; i++, nind++) { + get_vector(b, nor, *nind); + normalize_v3(b); + + float dp = dot_v3v3(a, b); + + if (dp < 0.99999f || dp > 1.00001f) + return false; + } + + return true; +} + +MeshImporter::MeshImporter(UnitConverter *unitconv, ArmatureImporter *arm, Scene *sce) : unitconverter(unitconv), scene(sce), armature_importer(arm) {} + +Object *MeshImporter::get_object_by_geom_uid(const COLLADAFW::UniqueId& geom_uid) +{ + if (uid_object_map.find(geom_uid) != uid_object_map.end()) + return uid_object_map[geom_uid]; + return NULL; +} + +MTex *MeshImporter::assign_textures_to_uvlayer(COLLADAFW::TextureCoordinateBinding &ctexture, + Mesh *me, TexIndexTextureArrayMap& texindex_texarray_map, + MTex *color_texture) +{ + const COLLADAFW::TextureMapId texture_index = ctexture.getTextureMapId(); + const size_t setindex = ctexture.getSetIndex(); + std::string uvname = ctexture.getSemantic(); + + const CustomData *data = &me->fdata; + int layer_index = CustomData_get_layer_index(data, CD_MTFACE); + CustomDataLayer *cdl = &data->layers[layer_index+setindex]; + + /* set uvname to bind_vertex_input semantic */ + BLI_strncpy(cdl->name, uvname.c_str(), sizeof(cdl->name)); + + if (texindex_texarray_map.find(texture_index) == texindex_texarray_map.end()) { + + fprintf(stderr, "Cannot find texture array by texture index.\n"); + return color_texture; + } + + std::vector<MTex*> textures = texindex_texarray_map[texture_index]; + + std::vector<MTex*>::iterator it; + + for (it = textures.begin(); it != textures.end(); it++) { + + MTex *texture = *it; + + if (texture) { + BLI_strncpy(texture->uvname, uvname.c_str(), sizeof(texture->uvname)); + if (texture->mapto == MAP_COL) color_texture = texture; + } + } + return color_texture; +} + +MTFace *MeshImporter::assign_material_to_geom(COLLADAFW::MaterialBinding cmaterial, + std::map<COLLADAFW::UniqueId, Material*>& uid_material_map, + Object *ob, const COLLADAFW::UniqueId *geom_uid, + MTex **color_texture, char *layername, MTFace *texture_face, + std::map<Material*, TexIndexTextureArrayMap>& material_texture_mapping_map, int mat_index) +{ + Mesh *me = (Mesh*)ob->data; + const COLLADAFW::UniqueId& ma_uid = cmaterial.getReferencedMaterial(); + + // do we know this material? + if (uid_material_map.find(ma_uid) == uid_material_map.end()) { + + fprintf(stderr, "Cannot find material by UID.\n"); + return NULL; + } + + Material *ma = uid_material_map[ma_uid]; + assign_material(ob, ma, ob->totcol + 1); + + COLLADAFW::TextureCoordinateBindingArray& tex_array = + cmaterial.getTextureCoordinateBindingArray(); + TexIndexTextureArrayMap texindex_texarray_map = material_texture_mapping_map[ma]; + unsigned int i; + // loop through <bind_vertex_inputs> + for (i = 0; i < tex_array.getCount(); i++) { + + *color_texture = assign_textures_to_uvlayer(tex_array[i], me, texindex_texarray_map, + *color_texture); + } + + // set texture face + if (*color_texture && + strlen((*color_texture)->uvname) && + strcmp(layername, (*color_texture)->uvname) != 0) { + + texture_face = (MTFace*)CustomData_get_layer_named(&me->fdata, CD_MTFACE, + (*color_texture)->uvname); + strcpy(layername, (*color_texture)->uvname); + } + + MaterialIdPrimitiveArrayMap& mat_prim_map = geom_uid_mat_mapping_map[*geom_uid]; + COLLADAFW::MaterialId mat_id = cmaterial.getMaterialId(); + + // assign material indices to mesh faces + if (mat_prim_map.find(mat_id) != mat_prim_map.end()) { + + std::vector<Primitive>& prims = mat_prim_map[mat_id]; + + std::vector<Primitive>::iterator it; + + for (it = prims.begin(); it != prims.end(); it++) { + Primitive& prim = *it; + i = 0; + while (i++ < prim.totface) { + prim.mface->mat_nr = mat_index; + prim.mface++; + // bind texture images to faces + if (texture_face && (*color_texture)) { + texture_face->mode = TF_TEX; + texture_face->tpage = (Image*)(*color_texture)->tex->ima; + texture_face++; + } + } + } + } + + return texture_face; +} + + +Object *MeshImporter::create_mesh_object(COLLADAFW::Node *node, COLLADAFW::InstanceGeometry *geom, + bool isController, + std::map<COLLADAFW::UniqueId, Material*>& uid_material_map, + std::map<Material*, TexIndexTextureArrayMap>& material_texture_mapping_map) +{ + const COLLADAFW::UniqueId *geom_uid = &geom->getInstanciatedObjectId(); + + // check if node instanciates controller or geometry + if (isController) { + + geom_uid = armature_importer->get_geometry_uid(*geom_uid); + + if (!geom_uid) { + fprintf(stderr, "Couldn't find a mesh UID by controller's UID.\n"); + return NULL; + } + } + else { + + if (uid_mesh_map.find(*geom_uid) == uid_mesh_map.end()) { + // this could happen if a mesh was not created + // (e.g. if it contains unsupported geometry) + fprintf(stderr, "Couldn't find a mesh by UID.\n"); + return NULL; + } + } + if (!uid_mesh_map[*geom_uid]) return NULL; + + Object *ob = add_object(scene, OB_MESH); + + // store object pointer for ArmatureImporter + uid_object_map[*geom_uid] = ob; + + // name Object + const std::string& id = node->getOriginalId(); + if (id.length()) + rename_id(&ob->id, (char*)id.c_str()); + + // replace ob->data freeing the old one + Mesh *old_mesh = (Mesh*)ob->data; + + set_mesh(ob, uid_mesh_map[*geom_uid]); + + if (old_mesh->id.us == 0) free_libblock(&G.main->mesh, old_mesh); + + char layername[100]; + MTFace *texture_face = NULL; + MTex *color_texture = NULL; + + COLLADAFW::MaterialBindingArray& mat_array = + geom->getMaterialBindings(); + + // loop through geom's materials + for (unsigned int i = 0; i < mat_array.getCount(); i++) { + + texture_face = assign_material_to_geom(mat_array[i], uid_material_map, ob, geom_uid, + &color_texture, layername, texture_face, + material_texture_mapping_map, i); + } + + return ob; +} + +// create a mesh storing a pointer in a map so it can be retrieved later by geometry UID +bool MeshImporter::write_geometry(const COLLADAFW::Geometry* geom) +{ + // TODO: import also uvs, normals + // XXX what to do with normal indices? + // XXX num_normals may be != num verts, then what to do? + + // check geometry->getType() first + if (geom->getType() != COLLADAFW::Geometry::GEO_TYPE_MESH) { + // TODO: report warning + fprintf(stderr, "Mesh type %s is not supported\n", bc_geomTypeToStr(geom->getType())); + return true; + } + + COLLADAFW::Mesh *mesh = (COLLADAFW::Mesh*)geom; + + if (!is_nice_mesh(mesh)) { + fprintf(stderr, "Ignoring mesh %s\n", bc_get_dae_name(mesh)); + return true; + } + + const std::string& str_geom_id = mesh->getOriginalId(); + Mesh *me = add_mesh((char*)str_geom_id.c_str()); + + // store the Mesh pointer to link it later with an Object + this->uid_mesh_map[mesh->getUniqueId()] = me; + + int new_tris = 0; + + read_vertices(mesh, me); + + new_tris = count_new_tris(mesh, me); + + read_faces(mesh, me, new_tris); + + make_edges(me, 0); + + mesh_calc_normals(me->mvert, me->totvert, me->mface, me->totface, NULL); + + return true; +} diff --git a/source/blender/collada/MeshImporter.h b/source/blender/collada/MeshImporter.h new file mode 100644 index 00000000000..055c4798855 --- /dev/null +++ b/source/blender/collada/MeshImporter.h @@ -0,0 +1,152 @@ +/** + * $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): Chingiz Dyussenov, Arystanbek Dyussenov, Nathan Letwory. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef __BC__MESHIMPORTER_H__ +#define __BC__MESHIMPORTER_H__ + +#include <map> +#include <vector> + +#include "COLLADAFWIndexList.h" +#include "COLLADAFWInstanceGeometry.h" +#include "COLLADAFWMaterialBinding.h" +#include "COLLADAFWMesh.h" +#include "COLLADAFWMeshVertexData.h" +#include "COLLADAFWNode.h" +#include "COLLADAFWTextureCoordinateBinding.h" +#include "COLLADAFWTypes.h" +#include "COLLADAFWUniqueId.h" + +#include "DNA_material_types.h" +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" +#include "DNA_texture_types.h" + +#include "ArmatureImporter.h" +#include "collada_utils.h" + +// only for ArmatureImporter to "see" MeshImporter::get_object_by_geom_uid +class MeshImporterBase +{ +public: + virtual Object *get_object_by_geom_uid(const COLLADAFW::UniqueId& geom_uid) = 0; +}; + +class UVDataWrapper +{ + COLLADAFW::MeshVertexData *mVData; +public: + UVDataWrapper(COLLADAFW::MeshVertexData& vdata); + +#ifdef COLLADA_DEBUG + void print(); +#endif + + void getUV(int uv_index[2], float *uv); +}; + +class MeshImporter : public MeshImporterBase +{ +private: + + Scene *scene; + ArmatureImporter *armature_importer; + + std::map<COLLADAFW::UniqueId, Mesh*> uid_mesh_map; // geometry unique id-to-mesh map + std::map<COLLADAFW::UniqueId, Object*> uid_object_map; // geom uid-to-object + // this structure is used to assign material indices to faces + // it holds a portion of Mesh faces and corresponds to a DAE primitive list (<triangles>, <polylist>, etc.) + struct Primitive { + MFace *mface; + unsigned int totface; + }; + typedef std::map<COLLADAFW::MaterialId, std::vector<Primitive> > MaterialIdPrimitiveArrayMap; + std::map<COLLADAFW::UniqueId, MaterialIdPrimitiveArrayMap> geom_uid_mat_mapping_map; // crazy name! + + + void set_face_indices(MFace *mface, unsigned int *indices, bool quad); + + // not used anymore, test_index_face from blenkernel is better +#if 0 + // change face indices order so that v4 is not 0 + void rotate_face_indices(MFace *mface); +#endif + + void set_face_uv(MTFace *mtface, UVDataWrapper &uvs, + COLLADAFW::IndexList& index_list, unsigned int *tris_indices); + + void set_face_uv(MTFace *mtface, UVDataWrapper &uvs, + COLLADAFW::IndexList& index_list, int index, bool quad); + +#ifdef COLLADA_DEBUG + void print_index_list(COLLADAFW::IndexList& index_list); +#endif + + bool is_nice_mesh(COLLADAFW::Mesh *mesh); + + void read_vertices(COLLADAFW::Mesh *mesh, Mesh *me); + + int triangulate_poly(unsigned int *indices, int totvert, MVert *verts, std::vector<unsigned int>& tri); + + int count_new_tris(COLLADAFW::Mesh *mesh, Mesh *me); + + // TODO: import uv set names + void read_faces(COLLADAFW::Mesh *mesh, Mesh *me, int new_tris); + + void get_vector(float v[3], COLLADAFW::MeshVertexData& arr, int i); + + bool flat_face(unsigned int *nind, COLLADAFW::MeshVertexData& nor, int count); + + UnitConverter *unitconverter; + +public: + + MeshImporter(UnitConverter *unitconv, ArmatureImporter *arm, Scene *sce); + + virtual Object *get_object_by_geom_uid(const COLLADAFW::UniqueId& geom_uid); + + MTex *assign_textures_to_uvlayer(COLLADAFW::TextureCoordinateBinding &ctexture, + Mesh *me, TexIndexTextureArrayMap& texindex_texarray_map, + MTex *color_texture); + + MTFace *assign_material_to_geom(COLLADAFW::MaterialBinding cmaterial, + std::map<COLLADAFW::UniqueId, Material*>& uid_material_map, + Object *ob, const COLLADAFW::UniqueId *geom_uid, + MTex **color_texture, char *layername, MTFace *texture_face, + std::map<Material*, TexIndexTextureArrayMap>& material_texture_mapping_map, int mat_index); + + + Object *create_mesh_object(COLLADAFW::Node *node, COLLADAFW::InstanceGeometry *geom, + bool isController, + std::map<COLLADAFW::UniqueId, Material*>& uid_material_map, + std::map<Material*, TexIndexTextureArrayMap>& material_texture_mapping_map); + + // create a mesh storing a pointer in a map so it can be retrieved later by geometry UID + bool write_geometry(const COLLADAFW::Geometry* geom); + +}; + +#endif diff --git a/source/blender/collada/SkinInfo.cpp b/source/blender/collada/SkinInfo.cpp new file mode 100644 index 00000000000..ba9451ecf84 --- /dev/null +++ b/source/blender/collada/SkinInfo.cpp @@ -0,0 +1,324 @@ +/** + * $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): Chingiz Dyussenov, Arystanbek Dyussenov, Nathan Letwory. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include <algorithm> + +#if !defined(WIN32) || defined(FREE_WINDOWS) +#include <stdint.h> +#endif + +#include "BKE_object.h" +#include "DNA_armature_types.h" +#include "DNA_modifier_types.h" +#include "ED_mesh.h" +#include "ED_object.h" +#include "BKE_action.h" +#include "BLI_listbase.h" +#include "BLI_math.h" + +#include "SkinInfo.h" +#include "collada_utils.h" + +// use this for retrieving bone names, since these must be unique +template<class T> +static const char *bc_get_joint_name(T *node) +{ + const std::string& id = node->getOriginalId(); + return id.size() ? id.c_str() : node->getName().c_str(); +} + +// This is used to store data passed in write_controller_data. +// Arrays from COLLADAFW::SkinControllerData lose ownership, so do this class members +// so that arrays don't get freed until we free them explicitly. +SkinInfo::SkinInfo() {} + +SkinInfo::SkinInfo(const SkinInfo& skin) : weights(skin.weights), + joint_data(skin.joint_data), + unit_converter(skin.unit_converter), + ob_arm(skin.ob_arm), + controller_uid(skin.controller_uid), + parent(skin.parent) +{ + copy_m4_m4(bind_shape_matrix, (float (*)[4])skin.bind_shape_matrix); + + transfer_uint_array_data_const(skin.joints_per_vertex, joints_per_vertex); + transfer_uint_array_data_const(skin.weight_indices, weight_indices); + transfer_int_array_data_const(skin.joint_indices, joint_indices); +} + +SkinInfo::SkinInfo(UnitConverter *conv) : unit_converter(conv), ob_arm(NULL), parent(NULL) {} + +// nobody owns the data after this, so it should be freed manually with releaseMemory +template <class T> +void SkinInfo::transfer_array_data(T& src, T& dest) +{ + dest.setData(src.getData(), src.getCount()); + src.yieldOwnerShip(); + dest.yieldOwnerShip(); +} + +// when src is const we cannot src.yieldOwnerShip, this is used by copy constructor +void SkinInfo::transfer_int_array_data_const(const COLLADAFW::IntValuesArray& src, COLLADAFW::IntValuesArray& dest) +{ + dest.setData((int*)src.getData(), src.getCount()); + dest.yieldOwnerShip(); +} + +void SkinInfo::transfer_uint_array_data_const(const COLLADAFW::UIntValuesArray& src, COLLADAFW::UIntValuesArray& dest) +{ + dest.setData((unsigned int*)src.getData(), src.getCount()); + dest.yieldOwnerShip(); +} + +void SkinInfo::borrow_skin_controller_data(const COLLADAFW::SkinControllerData* skin) +{ + transfer_array_data((COLLADAFW::UIntValuesArray&)skin->getJointsPerVertex(), joints_per_vertex); + transfer_array_data((COLLADAFW::UIntValuesArray&)skin->getWeightIndices(), weight_indices); + transfer_array_data((COLLADAFW::IntValuesArray&)skin->getJointIndices(), joint_indices); + // transfer_array_data(skin->getWeights(), weights); + + // cannot transfer data for FloatOrDoubleArray, copy values manually + const COLLADAFW::FloatOrDoubleArray& weight = skin->getWeights(); + for (unsigned int i = 0; i < weight.getValuesCount(); i++) + weights.push_back(bc_get_float_value(weight, i)); + + unit_converter->dae_matrix_to_mat4_(bind_shape_matrix, skin->getBindShapeMatrix()); +} + +void SkinInfo::free() +{ + joints_per_vertex.releaseMemory(); + weight_indices.releaseMemory(); + joint_indices.releaseMemory(); + // weights.releaseMemory(); +} + +// using inverse bind matrices to construct armature +// it is safe to invert them to get the original matrices +// because if they are inverse matrices, they can be inverted +void SkinInfo::add_joint(const COLLADABU::Math::Matrix4& matrix) +{ + JointData jd; + unit_converter->dae_matrix_to_mat4_(jd.inv_bind_mat, matrix); + joint_data.push_back(jd); +} + +void SkinInfo::set_controller(const COLLADAFW::SkinController* co) +{ + controller_uid = co->getUniqueId(); + + // fill in joint UIDs + const COLLADAFW::UniqueIdArray& joint_uids = co->getJoints(); + for (unsigned int i = 0; i < joint_uids.getCount(); i++) { + joint_data[i].joint_uid = joint_uids[i]; + + // // store armature pointer + // JointData& jd = joint_index_to_joint_info_map[i]; + // jd.ob_arm = ob_arm; + + // now we'll be able to get inv bind matrix from joint id + // joint_id_to_joint_index_map[joint_ids[i]] = i; + } +} + +// called from write_controller +Object *SkinInfo::create_armature(Scene *scene) +{ + ob_arm = add_object(scene, OB_ARMATURE); + return ob_arm; +} + +Object* SkinInfo::set_armature(Object *ob_arm) +{ + if (this->ob_arm) + return this->ob_arm; + + this->ob_arm = ob_arm; + return ob_arm; +} + +bool SkinInfo::get_joint_inv_bind_matrix(float inv_bind_mat[][4], COLLADAFW::Node *node) +{ + const COLLADAFW::UniqueId& uid = node->getUniqueId(); + std::vector<JointData>::iterator it; + for (it = joint_data.begin(); it != joint_data.end(); it++) { + if ((*it).joint_uid == uid) { + copy_m4_m4(inv_bind_mat, (*it).inv_bind_mat); + return true; + } + } + + return false; +} + +Object *SkinInfo::get_armature() +{ + return ob_arm; +} + +const COLLADAFW::UniqueId& SkinInfo::get_controller_uid() +{ + return controller_uid; +} + +// check if this skin controller references a joint or any descendant of it +// +// some nodes may not be referenced by SkinController, +// in this case to determine if the node belongs to this armature, +// we need to search down the tree +bool SkinInfo::uses_joint_or_descendant(COLLADAFW::Node *node) +{ + const COLLADAFW::UniqueId& uid = node->getUniqueId(); + std::vector<JointData>::iterator it; + for (it = joint_data.begin(); it != joint_data.end(); it++) { + if ((*it).joint_uid == uid) + return true; + } + + COLLADAFW::NodePointerArray& children = node->getChildNodes(); + for (unsigned int i = 0; i < children.getCount(); i++) { + if (uses_joint_or_descendant(children[i])) + return true; + } + + return false; +} + +void SkinInfo::link_armature(bContext *C, Object *ob, std::map<COLLADAFW::UniqueId, COLLADAFW::Node*>& joint_by_uid, + TransformReader *tm) +{ + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + + ModifierData *md = ED_object_modifier_add(NULL, bmain, scene, ob, NULL, eModifierType_Armature); + ((ArmatureModifierData *)md)->object = ob_arm; + + copy_m4_m4(ob->obmat, bind_shape_matrix); + object_apply_mat4(ob, ob->obmat); +#if 1 + bc_set_parent(ob, ob_arm, C); +#else + Object workob; + ob->parent = ob_arm; + ob->partype = PAROBJECT; + + what_does_parent(scene, ob, &workob); + invert_m4_m4(ob->parentinv, workob.obmat); + + ob->recalc |= OB_RECALC_OB|OB_RECALC_DATA; + + DAG_scene_sort(bmain, scene); + DAG_ids_flush_update(bmain, 0); + WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL); +#endif + + ((bArmature*)ob_arm->data)->deformflag = ARM_DEF_VGROUP; + + // create all vertex groups + std::vector<JointData>::iterator it; + int joint_index; + for (it = joint_data.begin(), joint_index = 0; it != joint_data.end(); it++, joint_index++) { + const char *name = "Group"; + + // name group by joint node name + if (joint_by_uid.find((*it).joint_uid) != joint_by_uid.end()) { + name = bc_get_joint_name(joint_by_uid[(*it).joint_uid]); + } + + ED_vgroup_add_name(ob, (char*)name); + } + + // <vcount> - number of joints per vertex - joints_per_vertex + // <v> - [[bone index, weight index] * joints per vertex] * vertices - weight indices + // ^ bone index can be -1 meaning weight toward bind shape, how to express this in Blender? + + // for each vertex in weight indices + // for each bone index in vertex + // add vertex to group at group index + // treat group index -1 specially + + // get def group by index with BLI_findlink + + for (unsigned int vertex = 0, weight = 0; vertex < joints_per_vertex.getCount(); vertex++) { + + unsigned int limit = weight + joints_per_vertex[vertex]; + for ( ; weight < limit; weight++) { + int joint = joint_indices[weight], joint_weight = weight_indices[weight]; + + // -1 means "weight towards the bind shape", we just don't assign it to any group + if (joint != -1) { + bDeformGroup *def = (bDeformGroup*)BLI_findlink(&ob->defbase, joint); + + ED_vgroup_vert_add(ob, def, vertex, weights[joint_weight], WEIGHT_REPLACE); + } + } + } +} + +bPoseChannel *SkinInfo::get_pose_channel_from_node(COLLADAFW::Node *node) +{ + return get_pose_channel(ob_arm->pose, bc_get_joint_name(node)); +} + +void SkinInfo::set_parent(Object *_parent) +{ + parent = _parent; +} + +Object* SkinInfo::get_parent() +{ + return parent; +} + +void SkinInfo::find_root_joints(const std::vector<COLLADAFW::Node*> &root_joints, + std::map<COLLADAFW::UniqueId, COLLADAFW::Node*>& joint_by_uid, + std::vector<COLLADAFW::Node*>& result) +{ + std::vector<COLLADAFW::Node*>::const_iterator it; + for (it = root_joints.begin(); it != root_joints.end(); it++) { + COLLADAFW::Node *root = *it; + std::vector<JointData>::iterator ji; + for (ji = joint_data.begin(); ji != joint_data.end(); ji++) { + COLLADAFW::Node *joint = joint_by_uid[(*ji).joint_uid]; + if (find_node_in_tree(joint, root)) { + if (std::find(result.begin(), result.end(), root) == result.end()) + result.push_back(root); + } + } + } +} + +bool SkinInfo::find_node_in_tree(COLLADAFW::Node *node, COLLADAFW::Node *tree_root) +{ + if (node == tree_root) + return true; + + COLLADAFW::NodePointerArray& children = tree_root->getChildNodes(); + for (unsigned int i = 0; i < children.getCount(); i++) { + if (find_node_in_tree(node, children[i])) + return true; + } + + return false; +} diff --git a/source/blender/collada/SkinInfo.h b/source/blender/collada/SkinInfo.h new file mode 100644 index 00000000000..1e31baff2a9 --- /dev/null +++ b/source/blender/collada/SkinInfo.h @@ -0,0 +1,133 @@ +/** + * $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): Chingiz Dyussenov, Arystanbek Dyussenov, Nathan Letwory. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef __BC_SKININFO_H__ +#define __BC_SKININFO_H__ + +#include <map> +#include <vector> + +#include "COLLADAFWUniqueId.h" +#include "COLLADAFWTypes.h" +#include "COLLADAFWNode.h" +#include "COLLADAFWSkinController.h" +#include "COLLADAFWSkinControllerData.h" + +#include "DNA_object_types.h" +#include "BKE_context.h" + +#include "TransformReader.h" +#include "collada_internal.h" + +// This is used to store data passed in write_controller_data. +// Arrays from COLLADAFW::SkinControllerData lose ownership, so do this class members +// so that arrays don't get freed until we free them explicitly. +class SkinInfo +{ +private: + // to build armature bones from inverse bind matrices + struct JointData { + float inv_bind_mat[4][4]; // joint inverse bind matrix + COLLADAFW::UniqueId joint_uid; // joint node UID + // Object *ob_arm; // armature object + }; + + float bind_shape_matrix[4][4]; + + // data from COLLADAFW::SkinControllerData, each array should be freed + COLLADAFW::UIntValuesArray joints_per_vertex; + COLLADAFW::UIntValuesArray weight_indices; + COLLADAFW::IntValuesArray joint_indices; + // COLLADAFW::FloatOrDoubleArray weights; + std::vector<float> weights; + + std::vector<JointData> joint_data; // index to this vector is joint index + + UnitConverter *unit_converter; + + Object *ob_arm; + COLLADAFW::UniqueId controller_uid; + Object *parent; + +public: + + SkinInfo(); + SkinInfo(const SkinInfo& skin); + SkinInfo(UnitConverter *conv); + + // nobody owns the data after this, so it should be freed manually with releaseMemory + template <typename T> + void transfer_array_data(T& src, T& dest); + + // when src is const we cannot src.yieldOwnerShip, this is used by copy constructor + void transfer_int_array_data_const(const COLLADAFW::IntValuesArray& src, COLLADAFW::IntValuesArray& dest); + + void transfer_uint_array_data_const(const COLLADAFW::UIntValuesArray& src, COLLADAFW::UIntValuesArray& dest); + + void borrow_skin_controller_data(const COLLADAFW::SkinControllerData* skin); + + void free(); + + // using inverse bind matrices to construct armature + // it is safe to invert them to get the original matrices + // because if they are inverse matrices, they can be inverted + void add_joint(const COLLADABU::Math::Matrix4& matrix); + + void set_controller(const COLLADAFW::SkinController* co); + + // called from write_controller + Object *create_armature(Scene *scene); + + Object* set_armature(Object *ob_arm); + + bool get_joint_inv_bind_matrix(float inv_bind_mat[][4], COLLADAFW::Node *node); + + Object *get_armature(); + + const COLLADAFW::UniqueId& get_controller_uid(); + + // check if this skin controller references a joint or any descendant of it + // + // some nodes may not be referenced by SkinController, + // in this case to determine if the node belongs to this armature, + // we need to search down the tree + bool uses_joint_or_descendant(COLLADAFW::Node *node); + + void link_armature(bContext *C, Object *ob, std::map<COLLADAFW::UniqueId, COLLADAFW::Node*>& joint_by_uid, TransformReader *tm); + + bPoseChannel *get_pose_channel_from_node(COLLADAFW::Node *node); + + void set_parent(Object *_parent); + + Object* get_parent(); + + void find_root_joints(const std::vector<COLLADAFW::Node*> &root_joints, + std::map<COLLADAFW::UniqueId, COLLADAFW::Node*>& joint_by_uid, + std::vector<COLLADAFW::Node*>& result); + + bool find_node_in_tree(COLLADAFW::Node *node, COLLADAFW::Node *tree_root); + +}; + +#endif diff --git a/source/blender/collada/TransformReader.cpp b/source/blender/collada/TransformReader.cpp new file mode 100644 index 00000000000..814fda58e3c --- /dev/null +++ b/source/blender/collada/TransformReader.cpp @@ -0,0 +1,125 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Chingiz Dyussenov, Arystanbek Dyussenov, Nathan Letwory. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "TransformReader.h" + +TransformReader::TransformReader(UnitConverter* conv) : unit_converter(conv) {} + +void TransformReader::get_node_mat(float mat[][4], COLLADAFW::Node *node, std::map<COLLADAFW::UniqueId, Animation> *animation_map, Object *ob) +{ + float cur[4][4]; + float copy[4][4]; + + unit_m4(mat); + + for (unsigned int i = 0; i < node->getTransformations().getCount(); i++) { + + COLLADAFW::Transformation *tm = node->getTransformations()[i]; + COLLADAFW::Transformation::TransformationType type = tm->getTransformationType(); + + switch(type) { + case COLLADAFW::Transformation::TRANSLATE: + dae_translate_to_mat4(tm, cur); + break; + case COLLADAFW::Transformation::ROTATE: + dae_rotate_to_mat4(tm, cur); + break; + case COLLADAFW::Transformation::SCALE: + dae_scale_to_mat4(tm, cur); + break; + case COLLADAFW::Transformation::MATRIX: + dae_matrix_to_mat4(tm, cur); + break; + case COLLADAFW::Transformation::LOOKAT: + case COLLADAFW::Transformation::SKEW: + fprintf(stderr, "LOOKAT and SKEW transformations are not supported yet.\n"); + break; + } + + copy_m4_m4(copy, mat); + mul_m4_m4m4(mat, cur, copy); + + if (animation_map) { + // AnimationList that drives this Transformation + const COLLADAFW::UniqueId& anim_list_id = tm->getAnimationList(); + + // store this so later we can link animation data with ob + Animation anim = {ob, node, tm}; + (*animation_map)[anim_list_id] = anim; + } + } +} + +void TransformReader::dae_rotate_to_mat4(COLLADAFW::Transformation *tm, float m[][4]) +{ + COLLADAFW::Rotate *ro = (COLLADAFW::Rotate*)tm; + COLLADABU::Math::Vector3& axis = ro->getRotationAxis(); + float angle = (float)(ro->getRotationAngle() * M_PI / 180.0f); + float ax[] = {axis[0], axis[1], axis[2]}; + // float quat[4]; + // axis_angle_to_quat(quat, axis, angle); + // quat_to_mat4(m, quat); + axis_angle_to_mat4(m, ax, angle); +} + +void TransformReader::dae_translate_to_mat4(COLLADAFW::Transformation *tm, float m[][4]) +{ + COLLADAFW::Translate *tra = (COLLADAFW::Translate*)tm; + COLLADABU::Math::Vector3& t = tra->getTranslation(); + + unit_m4(m); + + m[3][0] = (float)t[0]; + m[3][1] = (float)t[1]; + m[3][2] = (float)t[2]; +} + +void TransformReader::dae_scale_to_mat4(COLLADAFW::Transformation *tm, float m[][4]) +{ + COLLADABU::Math::Vector3& s = ((COLLADAFW::Scale*)tm)->getScale(); + float size[3] = {(float)s[0], (float)s[1], (float)s[2]}; + size_to_mat4(m, size); +} + +void TransformReader::dae_matrix_to_mat4(COLLADAFW::Transformation *tm, float m[][4]) +{ + unit_converter->dae_matrix_to_mat4_(m, ((COLLADAFW::Matrix*)tm)->getMatrix()); +} + +void TransformReader::dae_translate_to_v3(COLLADAFW::Transformation *tm, float v[3]) +{ + dae_vector3_to_v3(((COLLADAFW::Translate*)tm)->getTranslation(), v); +} + +void TransformReader::dae_scale_to_v3(COLLADAFW::Transformation *tm, float v[3]) +{ + dae_vector3_to_v3(((COLLADAFW::Scale*)tm)->getScale(), v); +} + +void TransformReader::dae_vector3_to_v3(const COLLADABU::Math::Vector3 &v3, float v[3]) +{ + v[0] = v3.x; + v[1] = v3.y; + v[2] = v3.z; +} diff --git a/source/blender/collada/TransformReader.h b/source/blender/collada/TransformReader.h new file mode 100644 index 00000000000..4dff8884a44 --- /dev/null +++ b/source/blender/collada/TransformReader.h @@ -0,0 +1,70 @@ +/** + * $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): Chingiz Dyussenov, Arystanbek Dyussenov, Nathan Letwory. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef __BC_TRANSFORMREADER_H__ +#define __BC_TRANSFORMREADER_H__ + +#include "COLLADAFWNode.h" +#include "COLLADAFWTransformation.h" +#include "COLLADAFWTranslate.h" +#include "COLLADAFWRotate.h" +#include "COLLADAFWScale.h" +#include "COLLADAFWMatrix.h" +#include "COLLADAFWUniqueId.h" +#include "Math/COLLADABUMathVector3.h" + +#include "DNA_object_types.h" +#include "BLI_math.h" + +#include "collada_internal.h" + +//struct Object; + +class TransformReader : public TransformBase +{ +protected: + + UnitConverter *unit_converter; + +public: + struct Animation { + Object *ob; + COLLADAFW::Node *node; + COLLADAFW::Transformation *tm; // which transform is animated by an AnimationList->id + }; + + TransformReader(UnitConverter* conv); + + void get_node_mat(float mat[][4], COLLADAFW::Node *node, std::map<COLLADAFW::UniqueId, Animation> *animation_map, Object *ob); + + void dae_rotate_to_mat4(COLLADAFW::Transformation *tm, float m[][4]); + void dae_translate_to_mat4(COLLADAFW::Transformation *tm, float m[][4]); + void dae_scale_to_mat4(COLLADAFW::Transformation *tm, float m[][4]); + void dae_matrix_to_mat4(COLLADAFW::Transformation *tm, float m[][4]); + void dae_translate_to_v3(COLLADAFW::Transformation *tm, float v[3]); + void dae_scale_to_v3(COLLADAFW::Transformation *tm, float v[3]); + void dae_vector3_to_v3(const COLLADABU::Math::Vector3 &v3, float v[3]); +}; + +#endif diff --git a/source/blender/collada/TransformWriter.cpp b/source/blender/collada/TransformWriter.cpp new file mode 100644 index 00000000000..a373191e773 --- /dev/null +++ b/source/blender/collada/TransformWriter.cpp @@ -0,0 +1,100 @@ +/** + * $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): Chingiz Dyussenov, Arystanbek Dyussenov, Jan Diederich, Tod Liverseed, + * Nathan Letwory + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "BKE_object.h" + +#include "TransformWriter.h" + +#include "BLI_math.h" + +void TransformWriter::add_node_transform(COLLADASW::Node& node, float mat[][4], float parent_mat[][4]) +{ + float loc[3], rot[3], scale[3]; + float local[4][4]; + + if (parent_mat) { + float invpar[4][4]; + invert_m4_m4(invpar, parent_mat); + mul_m4_m4m4(local, mat, invpar); + } + else { + copy_m4_m4(local, mat); + } + + TransformBase::decompose(local, loc, rot, NULL, scale); + + add_transform(node, loc, rot, scale); +} + +void TransformWriter::add_node_transform_ob(COLLADASW::Node& node, Object *ob) +{ + float rot[3], loc[3], scale[3]; + + if (ob->parent) { + float C[4][4], tmat[4][4], imat[4][4], mat[4][4]; + + // factor out scale from obmat + + copy_v3_v3(scale, ob->size); + + ob->size[0] = ob->size[1] = ob->size[2] = 1.0f; + object_to_mat4(ob, C); + copy_v3_v3(ob->size, scale); + + mul_serie_m4(tmat, ob->parent->obmat, ob->parentinv, C, NULL, NULL, NULL, NULL, NULL); + + // calculate local mat + + invert_m4_m4(imat, ob->parent->obmat); + mul_m4_m4m4(mat, tmat, imat); + + // done + + mat4_to_eul(rot, mat); + copy_v3_v3(loc, mat[3]); + } + else { + copy_v3_v3(loc, ob->loc); + copy_v3_v3(rot, ob->rot); + copy_v3_v3(scale, ob->size); + } + + add_transform(node, loc, rot, scale); +} + +void TransformWriter::add_node_transform_identity(COLLADASW::Node& node) +{ + float loc[] = {0.0f, 0.0f, 0.0f}, scale[] = {1.0f, 1.0f, 1.0f}, rot[] = {0.0f, 0.0f, 0.0f}; + add_transform(node, loc, rot, scale); +} + +void TransformWriter::add_transform(COLLADASW::Node& node, float loc[3], float rot[3], float scale[3]) +{ + node.addTranslate("location", loc[0], loc[1], loc[2]); + node.addRotateZ("rotationZ", COLLADABU::Math::Utils::radToDegF(rot[2])); + node.addRotateY("rotationY", COLLADABU::Math::Utils::radToDegF(rot[1])); + node.addRotateX("rotationX", COLLADABU::Math::Utils::radToDegF(rot[0])); + node.addScale("scale", scale[0], scale[1], scale[2]); +} diff --git a/source/blender/collada/TransformWriter.h b/source/blender/collada/TransformWriter.h new file mode 100644 index 00000000000..054a28c08a1 --- /dev/null +++ b/source/blender/collada/TransformWriter.h @@ -0,0 +1,48 @@ +/** + * $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): Chingiz Dyussenov, Arystanbek Dyussenov, Jan Diederich, Tod Liverseed, + * Nathan Letwory + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef __TRANSFORMWRITER_H__ +#define __TRANSFORMWRITER_H__ + +#include "COLLADASWNode.h" + +#include "DNA_object_types.h" + +#include "collada_internal.h" + +class TransformWriter : protected TransformBase +{ +protected: + void add_node_transform(COLLADASW::Node& node, float mat[][4], float parent_mat[][4]); + + void add_node_transform_ob(COLLADASW::Node& node, Object *ob); + + void add_node_transform_identity(COLLADASW::Node& node); + +private: + void add_transform(COLLADASW::Node& node, float loc[3], float rot[3], float scale[3]); +}; + +#endif diff --git a/source/blender/collada/collada.cpp b/source/blender/collada/collada.cpp index a519db3332c..d499249cfa2 100644 --- a/source/blender/collada/collada.cpp +++ b/source/blender/collada/collada.cpp @@ -21,15 +21,15 @@ * * ***** END GPL LICENSE BLOCK ***** */ -#include "BKE_main.h" -#include "BKE_scene.h" -#include "BKE_context.h" #include "DocumentExporter.h" #include "DocumentImporter.h" extern "C" { +#include "BKE_scene.h" +#include "BKE_context.h" + int collada_import(bContext *C, const char *filepath) { DocumentImporter imp; diff --git a/source/blender/collada/collada_internal.cpp b/source/blender/collada/collada_internal.cpp new file mode 100644 index 00000000000..6f401c1856f --- /dev/null +++ b/source/blender/collada/collada_internal.cpp @@ -0,0 +1,266 @@ +/** + * $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): Chingiz Dyussenov, Arystanbek Dyussenov. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "collada_internal.h" + +UnitConverter::UnitConverter() : unit(), up_axis(COLLADAFW::FileInfo::Z_UP) {} + +void UnitConverter::read_asset(const COLLADAFW::FileInfo* asset) +{ + unit = asset->getUnit(); + up_axis = asset->getUpAxisType(); +} + +UnitConverter::UnitSystem UnitConverter::isMetricSystem() +{ + switch(unit.getLinearUnitUnit()) { + case COLLADAFW::FileInfo::Unit::MILLIMETER: + case COLLADAFW::FileInfo::Unit::CENTIMETER: + case COLLADAFW::FileInfo::Unit::DECIMETER: + case COLLADAFW::FileInfo::Unit::METER: + case COLLADAFW::FileInfo::Unit::KILOMETER: + return UnitConverter::Metric; + case COLLADAFW::FileInfo::Unit::INCH: + case COLLADAFW::FileInfo::Unit::FOOT: + case COLLADAFW::FileInfo::Unit::YARD: + return UnitConverter::Imperial; + default: + return UnitConverter::None; + } +} + +float UnitConverter::getLinearMeter() +{ + return (float)unit.getLinearUnitMeter(); +} + +void UnitConverter::convertVector3(COLLADABU::Math::Vector3 &vec, float *v) +{ + v[0] = vec.x; + v[1] = vec.y; + v[2] = vec.z; +} + +// TODO need also for angle conversion, time conversion... + +void UnitConverter::dae_matrix_to_mat4_(float out[][4], const COLLADABU::Math::Matrix4& in) +{ + // in DAE, matrices use columns vectors, (see comments in COLLADABUMathMatrix4.h) + // so here, to make a blender matrix, we swap columns and rows + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 4; j++) { + out[i][j] = in[j][i]; + } + } +} + +void UnitConverter::mat4_to_dae(float out[][4], float in[][4]) +{ + copy_m4_m4(out, in); + transpose_m4(out); +} + +void UnitConverter::mat4_to_dae_double(double out[][4], float in[][4]) +{ + float mat[4][4]; + + mat4_to_dae(mat, in); + + for (int i = 0; i < 4; i++) + for (int j = 0; j < 4; j++) + out[i][j] = mat[i][j]; +} + +void TransformBase::decompose(float mat[][4], float *loc, float eul[3], float quat[4], float *size) +{ + mat4_to_size(size, mat); + if (eul) { + mat4_to_eul(eul, mat); + } + if (quat) { + mat4_to_quat(quat, mat); + } + copy_v3_v3(loc, mat[3]); +} + +/** +Translation map. +Used to translate every COLLADA id to a valid id, no matter what "wrong" letters may be +included. Look at the IDREF XSD declaration for more. +Follows strictly the COLLADA XSD declaration which explicitly allows non-english chars, +like special chars (e.g. micro sign), umlauts and so on. +The COLLADA spec also allows additional chars for member access ('.'), these +must obviously be removed too, otherwise they would be heavily misinterpreted. +*/ +const unsigned char translate_start_name_map[256] = { +95, 95, 95, 95, 95, 95, 95, 95, 95, +95, 95, 95, 95, 95, 95, 95, 95, +95, 95, 95, 95, 95, 95, 95, 95, +95, 95, 95, 95, 95, 95, 95, 95, +95, 95, 95, 95, 95, 95, 95, 95, +95, 95, 95, 95, 95, 95, 95, 95, +95, 95, 95, 95, 95, 95, 95, 95, +95, 95, 95, 95, 95, 95, 95, 95, +65, 66, 67, 68, 69, 70, 71, 72, +73, 74, 75, 76, 77, 78, 79, 80, +81, 82, 83, 84, 85, 86, 87, 88, +89, 90, 95, 95, 95, 95, 95, 95, +97, 98, 99, 100, 101, 102, 103, 104, +105, 106, 107, 108, 109, 110, 111, 112, +113, 114, 115, 116, 117, 118, 119, 120, +121, 122, 95, 95, 95, 95, 95, 95, +95, 95, 95, 95, 95, 95, 95, 95, +95, 95, 95, 95, 95, 95, 95, 95, +95, 95, 95, 95, 95, 95, 95, 95, +95, 95, 95, 95, 95, 95, 95, 95, +95, 95, 95, 95, 95, 95, 95, 95, +95, 95, 95, 95, 95, 95, 95, 95, +95, 95, 95, 95, 95, 95, 95, 95, +95, 95, 95, 95, 95, 95, 95, 192, +193, 194, 195, 196, 197, 198, 199, 200, +201, 202, 203, 204, 205, 206, 207, 208, +209, 210, 211, 212, 213, 214, 95, 216, +217, 218, 219, 220, 221, 222, 223, 224, +225, 226, 227, 228, 229, 230, 231, 232, +233, 234, 235, 236, 237, 238, 239, 240, +241, 242, 243, 244, 245, 246, 95, 248, +249, 250, 251, 252, 253, 254, 255}; + +const unsigned char translate_name_map[256] = { +95, 95, 95, 95, 95, 95, 95, 95, 95, +95, 95, 95, 95, 95, 95, 95, 95, +95, 95, 95, 95, 95, 95, 95, 95, +95, 95, 95, 95, 95, 95, 95, 95, +95, 95, 95, 95, 95, 95, 95, 95, +95, 95, 95, 95, 45, 95, 95, 48, +49, 50, 51, 52, 53, 54, 55, 56, +57, 95, 95, 95, 95, 95, 95, 95, +65, 66, 67, 68, 69, 70, 71, 72, +73, 74, 75, 76, 77, 78, 79, 80, +81, 82, 83, 84, 85, 86, 87, 88, +89, 90, 95, 95, 95, 95, 95, 95, +97, 98, 99, 100, 101, 102, 103, 104, +105, 106, 107, 108, 109, 110, 111, 112, +113, 114, 115, 116, 117, 118, 119, 120, +121, 122, 95, 95, 95, 95, 95, 95, +95, 95, 95, 95, 95, 95, 95, 95, +95, 95, 95, 95, 95, 95, 95, 95, +95, 95, 95, 95, 95, 95, 95, 95, +95, 95, 95, 95, 95, 95, 95, 95, +95, 95, 95, 95, 95, 95, 95, 95, +95, 95, 95, 95, 95, 95, 95, 95, +95, 95, 95, 95, 95, 95, 183, 95, +95, 95, 95, 95, 95, 95, 95, 192, +193, 194, 195, 196, 197, 198, 199, 200, +201, 202, 203, 204, 205, 206, 207, 208, +209, 210, 211, 212, 213, 214, 95, 216, +217, 218, 219, 220, 221, 222, 223, 224, +225, 226, 227, 228, 229, 230, 231, 232, +233, 234, 235, 236, 237, 238, 239, 240, +241, 242, 243, 244, 245, 246, 95, 248, +249, 250, 251, 252, 253, 254, 255}; + +typedef std::map< std::string, std::vector<std::string> > map_string_list; +map_string_list global_id_map; + +void clear_global_id_map() +{ + global_id_map.clear(); +} + +/** Look at documentation of translate_map */ +std::string translate_id(const std::string &id) +{ + if (id.size() == 0) + { return id; } + std::string id_translated = id; + id_translated[0] = translate_start_name_map[(unsigned int)id_translated[0]]; + for (unsigned int i=1; i < id_translated.size(); i++) + { + id_translated[i] = translate_name_map[(unsigned int)id_translated[i]]; + } + // It's so much workload now, the if() should speed up things. + if (id_translated != id) + { + // Search duplicates + map_string_list::iterator iter = global_id_map.find(id_translated); + if (iter != global_id_map.end()) + { + unsigned int i = 0; + bool found = false; + for (i=0; i < iter->second.size(); i++) + { + if (id == iter->second[i]) + { + found = true; + break; + } + } + bool convert = false; + if (found) + { + if (i > 0) + { convert = true; } + } + else + { + convert = true; + global_id_map[id_translated].push_back(id); + } + if (convert) + { + std::stringstream out; + out << ++i; + id_translated += out.str(); + } + } + else { global_id_map[id_translated].push_back(id); } + } + return id_translated; +} + +std::string id_name(void *id) +{ + return ((ID*)id)->name + 2; +} + +std::string get_geometry_id(Object *ob) +{ + return translate_id(id_name(ob)) + "-mesh"; +} + +std::string get_light_id(Object *ob) +{ + return translate_id(id_name(ob)) + "-light"; +} + +std::string get_joint_id(Bone *bone, Object *ob_arm) +{ + return translate_id(id_name(ob_arm) + "_" + bone->name); +} + +std::string get_camera_id(Object *ob) +{ + return translate_id(id_name(ob)) + "-camera"; +} diff --git a/source/blender/collada/collada_internal.h b/source/blender/collada/collada_internal.h index 242fce749c4..72b03a3d090 100644 --- a/source/blender/collada/collada_internal.h +++ b/source/blender/collada/collada_internal.h @@ -24,9 +24,17 @@ #ifndef BLENDER_COLLADA_H #define BLENDER_COLLADA_H +#include <string> +#include <vector> +#include <map> + #include "COLLADAFWFileInfo.h" #include "Math/COLLADABUMathMatrix4.h" +#include "DNA_armature_types.h" +#include "DNA_object_types.h" +#include "BLI_math.h" + class UnitConverter { private: @@ -35,61 +43,50 @@ private: public: - UnitConverter() : unit(), up_axis(COLLADAFW::FileInfo::Z_UP) {} + enum UnitSystem { + None, + Metric, + Imperial + }; + + // Initialize with Z_UP, since Blender uses right-handed, z-up + UnitConverter(); - void read_asset(const COLLADAFW::FileInfo* asset) - { - } + void read_asset(const COLLADAFW::FileInfo* asset); - // TODO - // convert vector vec from COLLADA format to Blender - void convertVec3(float *vec) - { - } + void convertVector3(COLLADABU::Math::Vector3 &vec, float *v); + + UnitConverter::UnitSystem isMetricSystem(void); + + float getLinearMeter(void); // TODO need also for angle conversion, time conversion... - void dae_matrix_to_mat4(float out[][4], const COLLADABU::Math::Matrix4& in) - { - // in DAE, matrices use columns vectors, (see comments in COLLADABUMathMatrix4.h) - // so here, to make a blender matrix, we swap columns and rows - for (int i = 0; i < 4; i++) { - for (int j = 0; j < 4; j++) { - out[i][j] = in[j][i]; - } - } - } - - void mat4_to_dae(float out[][4], float in[][4]) - { - copy_m4_m4(out, in); - transpose_m4(out); - } - - void mat4_to_dae_double(double out[][4], float in[][4]) - { - float mat[4][4]; - - mat4_to_dae(mat, in); - - for (int i = 0; i < 4; i++) - for (int j = 0; j < 4; j++) - out[i][j] = mat[i][j]; - } + void dae_matrix_to_mat4_(float out[][4], const COLLADABU::Math::Matrix4& in); + + void mat4_to_dae(float out[][4], float in[][4]); + + void mat4_to_dae_double(double out[][4], float in[][4]); }; class TransformBase { public: - void decompose(float mat[][4], float *loc, float eul[3], float quat[4], float *size) - { - mat4_to_size(size, mat); - if (eul) - mat4_to_eul(eul, mat); - if (quat) - mat4_to_quat(quat, mat); - copy_v3_v3(loc, mat[3]); - } + void decompose(float mat[][4], float *loc, float eul[3], float quat[4], float *size); }; +extern void clear_global_id_map(); +/** Look at documentation of translate_map */ +extern std::string translate_id(const std::string &id); + +extern std::string id_name(void *id); + +extern std::string get_geometry_id(Object *ob); + +extern std::string get_light_id(Object *ob); + +extern std::string get_joint_id(Bone *bone, Object *ob_arm); + +extern std::string get_camera_id(Object *ob); + #endif diff --git a/source/blender/collada/collada_utils.cpp b/source/blender/collada/collada_utils.cpp new file mode 100644 index 00000000000..0634c910e96 --- /dev/null +++ b/source/blender/collada/collada_utils.cpp @@ -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): Chingiz Dyussenov, Arystanbek Dyussenov, Nathan Letwory. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "COLLADAFWGeometry.h" +#include "COLLADAFWMeshPrimitive.h" +#include "COLLADAFWMeshVertexData.h" + +#include "DNA_customdata_types.h" +#include "DNA_object_types.h" + +#include "BLI_math.h" + +#include "BKE_context.h" +#include "BKE_customdata.h" +#include "BKE_depsgraph.h" +#include "BKE_object.h" + +#include "WM_api.h" // XXX hrm, see if we can do without this +#include "WM_types.h" + +float bc_get_float_value(const COLLADAFW::FloatOrDoubleArray& array, unsigned int index) +{ + if (index >= array.getValuesCount()) + return 0.0f; + + if (array.getType() == COLLADAFW::MeshVertexData::DATA_TYPE_FLOAT) + return array.getFloatValues()->getData()[index]; + else + return array.getDoubleValues()->getData()[index]; +} + +// copied from /editors/object/object_relations.c +int bc_test_parent_loop(Object *par, Object *ob) +{ + /* test if 'ob' is a parent somewhere in par's parents */ + + if(par == NULL) return 0; + if(ob == par) return 1; + + return bc_test_parent_loop(par->parent, ob); +} + +// a shortened version of parent_set_exec() +// if is_parent_space is true then ob->obmat will be multiplied by par->obmat before parenting +int bc_set_parent(Object *ob, Object *par, bContext *C, bool is_parent_space) +{ + Object workob; + Main *bmain = CTX_data_main(C); + Scene *sce = CTX_data_scene(C); + + if (!par || bc_test_parent_loop(par, ob)) + return false; + + ob->parent = par; + ob->partype = PAROBJECT; + + ob->parsubstr[0] = 0; + + if (is_parent_space) { + float mat[4][4]; + // calc par->obmat + where_is_object(sce, par); + + // move child obmat into world space + mul_m4_m4m4(mat, ob->obmat, par->obmat); + copy_m4_m4(ob->obmat, mat); + } + + // apply child obmat (i.e. decompose it into rot/loc/size) + object_apply_mat4(ob, ob->obmat); + + // compute parentinv + what_does_parent(sce, ob, &workob); + invert_m4_m4(ob->parentinv, workob.obmat); + + ob->recalc |= OB_RECALC_OB | OB_RECALC_DATA; + par->recalc |= OB_RECALC_OB; + + DAG_scene_sort(bmain, sce); + DAG_ids_flush_update(bmain, 0); + WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL); + + return true; +} + diff --git a/source/blender/collada/collada_utils.h b/source/blender/collada/collada_utils.h new file mode 100644 index 00000000000..ba5ba7f3cf5 --- /dev/null +++ b/source/blender/collada/collada_utils.h @@ -0,0 +1,50 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Chingiz Dyussenov, Arystanbek Dyussenov, Nathan Letwory. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef __BC_UTILS_H__ +#define __BC_UTILS_H__ + +#include "COLLADAFWMeshPrimitive.h" +#include "COLLADAFWGeometry.h" +#include "COLLADAFWFloatOrDoubleArray.h" +#include "COLLADAFWTypes.h" + +#include <vector> +#include <map> + +#include "DNA_object_types.h" +#include "DNA_customdata_types.h" +#include "DNA_texture_types.h" +#include "BKE_context.h" + +typedef std::map<COLLADAFW::TextureMapId, std::vector<MTex*> > TexIndexTextureArrayMap; + +extern float bc_get_float_value(const COLLADAFW::FloatOrDoubleArray& array, unsigned int index); + +extern int bc_test_parent_loop(Object *par, Object *ob); +extern int bc_set_parent(Object *ob, Object *par, bContext *C, bool is_parent_space=true); +extern char *bc_CustomData_get_layer_name(const CustomData *data, int type, int n); +extern char *bc_CustomData_get_active_layer_name(const CustomData *data, int type); + +#endif diff --git a/source/blender/editors/armature/editarmature.c b/source/blender/editors/armature/editarmature.c index ead5d44d393..26a89c4de02 100644 --- a/source/blender/editors/armature/editarmature.c +++ b/source/blender/editors/armature/editarmature.c @@ -558,7 +558,7 @@ static void applyarmature_fix_boneparents (Scene *scene, Object *armob) static int apply_armature_pose2bones_exec (bContext *C, wmOperator *op) { Scene *scene= CTX_data_scene(C); - Object *ob= CTX_data_active_object(C); // must be active object, not edit-object + Object *ob= ED_object_pose_armature(CTX_data_active_object(C)); // must be active object, not edit-object bArmature *arm= get_armature(ob); bPose *pose; bPoseChannel *pchan; @@ -658,7 +658,7 @@ void POSE_OT_armature_apply (wmOperatorType *ot) static int pose_visual_transform_apply_exec (bContext *C, wmOperator *op) { Scene *scene= CTX_data_scene(C); - Object *ob= CTX_data_active_object(C); // must be active object, not edit-object + Object *ob= ED_object_pose_armature(CTX_data_active_object(C)); // must be active object, not edit-object /* don't check if editmode (should be done by caller) */ if (ob->type!=OB_ARMATURE) @@ -1389,7 +1389,7 @@ static int pose_setflag_exec (bContext *C, wmOperator *op) CTX_DATA_END; /* note, notifier might evolve */ - WM_event_add_notifier(C, NC_OBJECT|ND_POSE, CTX_data_active_object(C)); + WM_event_add_notifier(C, NC_OBJECT|ND_POSE, ED_object_pose_armature(CTX_data_active_object(C))); return OPERATOR_FINISHED; } @@ -4917,7 +4917,7 @@ void create_vgroups_from_armature(Scene *scene, Object *ob, Object *par, int mod static int pose_clear_scale_exec(bContext *C, wmOperator *op) { Scene *scene= CTX_data_scene(C); - Object *ob= CTX_data_active_object(C); + Object *ob= ED_object_pose_armature(CTX_data_active_object(C)); short autokey = 0; /* only clear those channels that are not locked */ @@ -4985,7 +4985,7 @@ void POSE_OT_scale_clear(wmOperatorType *ot) static int pose_clear_loc_exec(bContext *C, wmOperator *op) { Scene *scene= CTX_data_scene(C); - Object *ob= CTX_data_active_object(C); + Object *ob= ED_object_pose_armature(CTX_data_active_object(C)); short autokey = 0; /* only clear those channels that are not locked */ @@ -5054,7 +5054,7 @@ void POSE_OT_loc_clear(wmOperatorType *ot) static int pose_clear_rot_exec(bContext *C, wmOperator *op) { Scene *scene= CTX_data_scene(C); - Object *ob= CTX_data_active_object(C); + Object *ob= ED_object_pose_armature(CTX_data_active_object(C)); short autokey = 0; /* only clear those channels that are not locked */ @@ -5306,7 +5306,7 @@ void POSE_OT_select_all(wmOperatorType *ot) static int pose_select_parent_exec(bContext *C, wmOperator *op) { - Object *ob= CTX_data_active_object(C); + Object *ob= ED_object_pose_armature(CTX_data_active_object(C)); bPoseChannel *pchan,*parent; /* Determine if there is an active bone */ @@ -5381,7 +5381,7 @@ static int hide_unselected_pose_bone(Object *ob, Bone *bone, void *ptr) /* active object is armature in posemode, poll checked */ static int pose_hide_exec(bContext *C, wmOperator *op) { - Object *ob= CTX_data_active_object(C); + Object *ob= ED_object_pose_armature(CTX_data_active_object(C)); bArmature *arm= ob->data; if(RNA_boolean_get(op->ptr, "unselected")) @@ -5431,7 +5431,7 @@ static int show_pose_bone(Object *ob, Bone *bone, void *ptr) /* active object is armature in posemode, poll checked */ static int pose_reveal_exec(bContext *C, wmOperator *op) { - Object *ob= CTX_data_active_object(C); + Object *ob= ED_object_pose_armature(CTX_data_active_object(C)); bArmature *arm= ob->data; bone_looper(ob, arm->bonebase.first, NULL, show_pose_bone); diff --git a/source/blender/editors/armature/poseSlide.c b/source/blender/editors/armature/poseSlide.c index 8d8f1bf24ee..482d97811a3 100644 --- a/source/blender/editors/armature/poseSlide.c +++ b/source/blender/editors/armature/poseSlide.c @@ -119,7 +119,7 @@ static int pose_slide_init (bContext *C, wmOperator *op, short mode) /* get info from context */ pso->scene= CTX_data_scene(C); - pso->ob= CTX_data_active_object(C); + pso->ob= ED_object_pose_armature(CTX_data_active_object(C)); pso->arm= (pso->ob)? pso->ob->data : NULL; pso->ar= CTX_wm_region(C); /* only really needed when doing modal() */ diff --git a/source/blender/editors/armature/poselib.c b/source/blender/editors/armature/poselib.c index 6083616044e..9292c92294b 100644 --- a/source/blender/editors/armature/poselib.c +++ b/source/blender/editors/armature/poselib.c @@ -270,7 +270,7 @@ static KeyingSet *poselib_ks_locrotscale = NULL; /* the only keyingset we'll ne static void poselib_add_menu_invoke__replacemenu (bContext *C, uiLayout *layout, void *arg) { - Object *ob= CTX_data_active_object(C); + Object *ob= ED_object_pose_armature(CTX_data_active_object(C)); bAction *act= ob->poselib; TimeMarker *marker; @@ -293,7 +293,7 @@ static void poselib_add_menu_invoke__replacemenu (bContext *C, uiLayout *layout, static int poselib_add_menu_invoke (bContext *C, wmOperator *op, wmEvent *evt) { Scene *scene= CTX_data_scene(C); - Object *ob= CTX_data_active_object(C); + Object *ob= ED_object_pose_armature(CTX_data_active_object(C)); bArmature *arm= (ob) ? ob->data : NULL; bPose *pose= (ob) ? ob->pose : NULL; uiPopupMenu *pup; @@ -329,7 +329,7 @@ static int poselib_add_menu_invoke (bContext *C, wmOperator *op, wmEvent *evt) static int poselib_add_exec (bContext *C, wmOperator *op) { - Object *ob= CTX_data_active_object(C); + Object *ob= ED_object_pose_armature(CTX_data_active_object(C)); bAction *act = poselib_validate(ob); bArmature *arm= (ob) ? ob->data : NULL; bPose *pose= (ob) ? ob->pose : NULL; @@ -404,7 +404,7 @@ void POSELIB_OT_pose_add (wmOperatorType *ot) static EnumPropertyItem *poselib_stored_pose_itemf(bContext *C, PointerRNA *ptr, int *free) { - Object *ob= CTX_data_active_object(C); + Object *ob= ED_object_pose_armature(CTX_data_active_object(C)); bAction *act= (ob) ? ob->poselib : NULL; TimeMarker *marker; EnumPropertyItem *item= NULL, item_tmp; @@ -436,7 +436,7 @@ static EnumPropertyItem *poselib_stored_pose_itemf(bContext *C, PointerRNA *ptr, static int poselib_remove_exec (bContext *C, wmOperator *op) { - Object *ob= CTX_data_active_object(C); + Object *ob= ED_object_pose_armature(CTX_data_active_object(C)); bAction *act= (ob) ? ob->poselib : NULL; TimeMarker *marker; FCurve *fcu; @@ -505,7 +505,7 @@ void POSELIB_OT_pose_remove (wmOperatorType *ot) static int poselib_rename_invoke (bContext *C, wmOperator *op, wmEvent *evt) { - Object *ob= CTX_data_active_object(C); + Object *ob= ED_object_pose_armature(CTX_data_active_object(C)); bAction *act= (ob) ? ob->poselib : NULL; TimeMarker *marker; @@ -533,7 +533,7 @@ static int poselib_rename_invoke (bContext *C, wmOperator *op, wmEvent *evt) static int poselib_rename_exec (bContext *C, wmOperator *op) { - Object *ob= CTX_data_active_object(C); + Object *ob= ED_object_pose_armature(CTX_data_active_object(C)); bAction *act= (ob) ? ob->poselib : NULL; TimeMarker *marker; char newname[64]; @@ -1237,7 +1237,7 @@ static int poselib_preview_handle_event (bContext *C, wmOperator *op, wmEvent *e static void poselib_preview_init_data (bContext *C, wmOperator *op) { tPoseLib_PreviewData *pld; - Object *ob= CTX_data_active_object(C); + Object *ob= ED_object_pose_armature(CTX_data_active_object(C)); int pose_index = RNA_int_get(op->ptr, "pose_index"); /* set up preview state info */ diff --git a/source/blender/editors/armature/poseobject.c b/source/blender/editors/armature/poseobject.c index b94b3e68318..4aff2f1e915 100644 --- a/source/blender/editors/armature/poseobject.c +++ b/source/blender/editors/armature/poseobject.c @@ -76,6 +76,38 @@ static void error(const char *dummy) {}; static void BIF_undo_push(const char *dummy) {} /* ************* XXX *************** */ + +static int object_pose_context(Object *ob) +{ + if( (ob) && + (ob->type == OB_ARMATURE) && + (ob->pose) && + (ob->mode & OB_MODE_POSE) + ) { + return 1; + } + else { + return 0; + } +} + +Object *ED_object_pose_armature(Object *ob) +{ + if(ob==NULL) + return NULL; + + if(object_pose_context(ob)) + return ob; + + ob= modifiers_isDeformedByArmature(ob); + + if(object_pose_context(ob)) + return ob; + + return NULL; +} + + /* This function is used to indicate that a bone is selected and needs keyframes inserted */ void set_pose_keys (Object *ob) { @@ -220,7 +252,7 @@ static int pose_calculate_paths_exec (bContext *C, wmOperator *op) if (sa->spacetype == SPACE_BUTS) ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data; else - ob= CTX_data_active_object(C); + ob= ED_object_pose_armature(CTX_data_active_object(C)); if (ELEM(NULL, ob, ob->pose)) return OPERATOR_CANCELLED; @@ -296,7 +328,7 @@ static int pose_clear_paths_exec (bContext *C, wmOperator *op) if (sa->spacetype == SPACE_BUTS) ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data; else - ob= CTX_data_active_object(C); + ob= ED_object_pose_armature(CTX_data_active_object(C)); /* only continue if there's an object */ if ELEM(NULL, ob, ob->pose) @@ -330,7 +362,7 @@ void POSE_OT_paths_clear (wmOperatorType *ot) static int pose_select_constraint_target_exec(bContext *C, wmOperator *op) { - Object *ob= CTX_data_active_object(C); + Object *ob= ED_object_pose_armature(CTX_data_active_object(C)); bArmature *arm= ob->data; bConstraint *con; int found= 0; @@ -390,7 +422,7 @@ void POSE_OT_select_constraint_target(wmOperatorType *ot) static int pose_select_hierarchy_exec(bContext *C, wmOperator *op) { - Object *ob= CTX_data_active_object(C); + Object *ob= ED_object_pose_armature(CTX_data_active_object(C)); bArmature *arm= ob->data; Bone *curbone, *pabone, *chbone; int direction = RNA_enum_get(op->ptr, "direction"); @@ -570,7 +602,7 @@ static short pose_select_same_layer (bContext *C, Object *ob, short extend) static int pose_select_grouped_exec (bContext *C, wmOperator *op) { - Object *ob= CTX_data_active_object(C); + Object *ob= ED_object_pose_armature(CTX_data_active_object(C)); short extend= RNA_boolean_get(op->ptr, "extend"); short changed = 0; @@ -856,7 +888,7 @@ void free_posebuf(void) static int pose_copy_exec (bContext *C, wmOperator *op) { - Object *ob= CTX_data_active_object(C); + Object *ob= ED_object_pose_armature(CTX_data_active_object(C)); /* sanity checking */ if ELEM(NULL, ob, ob->pose) { @@ -895,7 +927,7 @@ void POSE_OT_copy (wmOperatorType *ot) static int pose_paste_exec (bContext *C, wmOperator *op) { Scene *scene= CTX_data_scene(C); - Object *ob= CTX_data_active_object(C); + Object *ob= ED_object_pose_armature(CTX_data_active_object(C)); bPoseChannel *chan, *pchan; int flip= RNA_boolean_get(op->ptr, "flipped"); @@ -1077,7 +1109,7 @@ static int pose_group_add_exec (bContext *C, wmOperator *op) if (sa->spacetype == SPACE_BUTS) ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data; else - ob= CTX_data_active_object(C); + ob= ED_object_pose_armature(CTX_data_active_object(C)); /* only continue if there's an object */ if (ob == NULL) @@ -1117,7 +1149,7 @@ static int pose_group_remove_exec (bContext *C, wmOperator *op) if (sa->spacetype == SPACE_BUTS) ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data; else - ob= CTX_data_active_object(C); + ob= ED_object_pose_armature(CTX_data_active_object(C)); /* only continue if there's an object */ if (ob == NULL) @@ -1165,7 +1197,7 @@ static int pose_groups_menu_invoke (bContext *C, wmOperator *op, wmEvent *evt) if (sa->spacetype == SPACE_BUTS) ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data; else - ob= CTX_data_active_object(C); + ob= ED_object_pose_armature(CTX_data_active_object(C)); /* only continue if there's an object, and a pose there too */ if (ELEM(NULL, ob, ob->pose)) @@ -1215,7 +1247,7 @@ static int pose_group_assign_exec (bContext *C, wmOperator *op) if (sa->spacetype == SPACE_BUTS) ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data; else - ob= CTX_data_active_object(C); + ob= ED_object_pose_armature(CTX_data_active_object(C)); /* only continue if there's an object, and a pose there too */ if (ELEM(NULL, ob, ob->pose)) @@ -1280,7 +1312,7 @@ static int pose_group_unassign_exec (bContext *C, wmOperator *op) if (sa->spacetype == SPACE_BUTS) ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data; else - ob= CTX_data_active_object(C); + ob= ED_object_pose_armature(CTX_data_active_object(C)); /* only continue if there's an object, and a pose there too */ if (ELEM(NULL, ob, ob->pose)) @@ -1352,7 +1384,7 @@ static int pose_group_select_exec (bContext *C, wmOperator *op) if (sa->spacetype == SPACE_BUTS) ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data; else - ob= CTX_data_active_object(C); + ob= ED_object_pose_armature(CTX_data_active_object(C)); /* only continue if there's an object, and a pose there too */ if (ELEM(NULL, ob, ob->pose)) @@ -1390,7 +1422,7 @@ static int pose_group_deselect_exec (bContext *C, wmOperator *op) if (sa->spacetype == SPACE_BUTS) ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data; else - ob= CTX_data_active_object(C); + ob= ED_object_pose_armature(CTX_data_active_object(C)); /* only continue if there's an object, and a pose there too */ if (ELEM(NULL, ob, ob->pose)) @@ -1423,7 +1455,7 @@ void POSE_OT_group_deselect (wmOperatorType *ot) static int pose_flip_names_exec (bContext *C, wmOperator *op) { - Object *ob= CTX_data_active_object(C); + Object *ob= ED_object_pose_armature(CTX_data_active_object(C)); bArmature *arm; /* paranoia checks */ @@ -1468,7 +1500,7 @@ void POSE_OT_flip_names (wmOperatorType *ot) static int pose_autoside_names_exec (bContext *C, wmOperator *op) { - Object *ob= CTX_data_active_object(C); + Object *ob= ED_object_pose_armature(CTX_data_active_object(C)); bArmature *arm; char newname[32]; short axis= RNA_enum_get(op->ptr, "axis"); @@ -1567,7 +1599,7 @@ void pose_activate_flipped_bone(Scene *scene) /* Present a popup to get the layers that should be used */ static int pose_armature_layers_invoke (bContext *C, wmOperator *op, wmEvent *evt) { - Object *ob= CTX_data_active_object(C); + Object *ob= ED_object_pose_armature(CTX_data_active_object(C)); bArmature *arm= (ob)? ob->data : NULL; PointerRNA ptr; int layers[32]; /* hardcoded for now - we can only have 32 armature layers, so this should be fine... */ @@ -1588,7 +1620,7 @@ static int pose_armature_layers_invoke (bContext *C, wmOperator *op, wmEvent *ev /* Set the visible layers for the active armature (edit and pose modes) */ static int pose_armature_layers_exec (bContext *C, wmOperator *op) { - Object *ob= CTX_data_active_object(C); + Object *ob= ED_object_pose_armature(CTX_data_active_object(C)); bArmature *arm= (ob)? ob->data : NULL; PointerRNA ptr; int layers[32]; /* hardcoded for now - we can only have 32 armature layers, so this should be fine... */ @@ -1677,7 +1709,7 @@ static int pose_bone_layers_invoke (bContext *C, wmOperator *op, wmEvent *evt) /* Set the visible layers for the active armature (edit and pose modes) */ static int pose_bone_layers_exec (bContext *C, wmOperator *op) { - Object *ob= CTX_data_active_object(C); + Object *ob= ED_object_pose_armature(CTX_data_active_object(C)); bArmature *arm= (ob)? ob->data : NULL; PointerRNA ptr; int layers[32]; /* hardcoded for now - we can only have 32 armature layers, so this should be fine... */ @@ -1798,7 +1830,7 @@ void ARMATURE_OT_bone_layers (wmOperatorType *ot) static int pose_flip_quats_exec (bContext *C, wmOperator *op) { Scene *scene= CTX_data_scene(C); - Object *ob= CTX_data_active_object(C); + Object *ob= ED_object_pose_armature(CTX_data_active_object(C)); KeyingSet *ks = ANIM_builtin_keyingset_get_named(NULL, "LocRotScale"); /* loop through all selected pchans, flipping and keying (as needed) */ diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c index 6193b6eb916..4c869d25869 100644 --- a/source/blender/editors/curve/editcurve.c +++ b/source/blender/editors/curve/editcurve.c @@ -732,7 +732,7 @@ static void calc_shapeKeys(Object *obedit) int totvert= count_curveverts(&editnurb->nurbs); float (*ofs)[3] = NULL; - float *oldkey, *newkey, *fp, *ofp; + float *oldkey, *newkey, *ofp; /* editing the base key should update others */ if(cu->key->type==KEY_RELATIVE) { @@ -776,7 +776,7 @@ static void calc_shapeKeys(Object *obedit) for (j= 0; j < 3; ++j) { VECSUB(ofs[i], bezt->vec[j], oldbezt->vec[j]); i++; - fp+= 3; + // fp+= 3; // unused } ofs[i++][0]= bezt->alfa - oldbezt->alfa; } else { @@ -796,7 +796,7 @@ static void calc_shapeKeys(Object *obedit) } i += 2; ++bp; - fp += 4; + // fp += 4; //unused } } @@ -809,7 +809,7 @@ static void calc_shapeKeys(Object *obedit) while(currkey) { int apply_offset = (ofs && (currkey != actkey) && (editnurb->shapenr-1 == currkey->relative)); - fp= newkey= MEM_callocN(cu->key->elemsize * totvert, "currkey->data"); + float *fp= newkey= MEM_callocN(cu->key->elemsize * totvert, "currkey->data"); ofp= oldkey = currkey->data; nu= editnurb->nurbs.first; diff --git a/source/blender/editors/include/ED_armature.h b/source/blender/editors/include/ED_armature.h index 6055b9eecb3..809b86d65f3 100644 --- a/source/blender/editors/include/ED_armature.h +++ b/source/blender/editors/include/ED_armature.h @@ -27,6 +27,10 @@ #ifndef ED_ARMATURE_H #define ED_ARMATURE_H +#ifdef __cplusplus +extern "C" { +#endif + struct bArmature; struct Base; struct bContext; @@ -137,6 +141,7 @@ void ED_armature_bone_rename(struct bArmature *arm, char *oldnamep, char *newnam void undo_push_armature(struct bContext *C, char *name); /* poseobject.c */ +struct Object *ED_object_pose_armature(struct Object *ob); void ED_armature_exit_posemode(struct bContext *C, struct Base *base); void ED_armature_enter_posemode(struct bContext *C, struct Base *base); int ED_pose_channel_in_IK_chain(struct Object *ob, struct bPoseChannel *pchan); @@ -168,6 +173,10 @@ int BDR_drawSketchNames(struct ViewContext *vc); void mesh_deform_bind(struct Scene *scene, struct MeshDeformModifierData *mmd, float *vertexcos, int totvert, float cagemat[][4]); + +#ifdef __cplusplus +} +#endif #endif /* ED_ARMATURE_H */ diff --git a/source/blender/editors/include/ED_keyframing.h b/source/blender/editors/include/ED_keyframing.h index 8718d39dd18..b3aac489852 100644 --- a/source/blender/editors/include/ED_keyframing.h +++ b/source/blender/editors/include/ED_keyframing.h @@ -28,6 +28,10 @@ #ifndef ED_KEYFRAMING_H #define ED_KEYFRAMING_H +#ifdef __cplusplus +extern "C" { +#endif + struct ListBase; struct ID; struct Scene; @@ -280,4 +284,8 @@ typedef enum eAnimFilterFlags { ANIMFILTER_KEYS_NOSKEY = (1<<10), /* don't include shape keys (for geometry) */ } eAnimFilterFlags; +#ifdef __cplusplus +} +#endif + #endif /* ED_KEYFRAMING_H */ diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h index 564fe04ca4d..c4477ee5a8e 100644 --- a/source/blender/editors/include/ED_mesh.h +++ b/source/blender/editors/include/ED_mesh.h @@ -28,6 +28,10 @@ #ifndef ED_MESH_H #define ED_MESH_H +#ifdef __cplusplus +extern "C" { +#endif + struct ID; struct View3D; struct ARegion; @@ -224,5 +228,9 @@ int ED_mesh_uv_texture_remove(struct bContext *C, struct Object *ob, struct Mesh int ED_mesh_color_add(struct bContext *C, struct Scene *scene, struct Object *ob, struct Mesh *me, const char *name, int active_set); int ED_mesh_color_remove(struct bContext *C, struct Object *ob, struct Mesh *me); +#ifdef __cplusplus +} +#endif + #endif /* ED_MESH_H */ diff --git a/source/blender/editors/include/ED_object.h b/source/blender/editors/include/ED_object.h index f243b4cc497..64e72a5e2fa 100644 --- a/source/blender/editors/include/ED_object.h +++ b/source/blender/editors/include/ED_object.h @@ -28,6 +28,10 @@ #ifndef ED_OBJECT_H #define ED_OBJECT_H +#ifdef __cplusplus +extern "C" { +#endif + struct Base; struct bConstraint; struct bContext; @@ -141,5 +145,9 @@ int ED_object_modifier_convert(struct ReportList *reports, struct Main *bmain, s int ED_object_modifier_apply(struct ReportList *reports, struct Scene *scene, struct Object *ob, struct ModifierData *md, int mode); int ED_object_modifier_copy(struct ReportList *reports, struct Object *ob, struct ModifierData *md); +#ifdef __cplusplus +} +#endif + #endif /* ED_OBJECT_H */ diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index 54a627da2da..4689153c9f5 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -77,17 +77,18 @@ typedef struct uiLayout uiLayout; #define UI_EMBOSST 3 /* Table */ /* uiBlock->direction */ +#define UI_DIRECTION (UI_TOP|UI_DOWN|UI_LEFT|UI_RIGHT) #define UI_TOP 1 #define UI_DOWN 2 #define UI_LEFT 4 #define UI_RIGHT 8 -#define UI_DIRECTION 15 + #define UI_CENTER 16 #define UI_SHIFT_FLIPPED 32 /* uiBlock->autofill (not yet used) */ -#define UI_BLOCK_COLLUMNS 1 -#define UI_BLOCK_ROWS 2 +// #define UI_BLOCK_COLLUMNS 1 +// #define UI_BLOCK_ROWS 2 /* uiBlock->flag (controls) */ #define UI_BLOCK_LOOP 1 @@ -316,7 +317,7 @@ void uiDrawBlock(const struct bContext *C, struct uiBlock *block); uiBlock *uiGetBlock(char *name, struct ARegion *ar); -void uiBlockSetEmboss(uiBlock *block, short dt); +void uiBlockSetEmboss(uiBlock *block, char dt); void uiFreeBlock(const struct bContext *C, uiBlock *block); void uiFreeBlocks(const struct bContext *C, struct ListBase *lb); diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c index b7ec5565d80..f4866237f46 100644 --- a/source/blender/editors/interface/interface.c +++ b/source/blender/editors/interface/interface.c @@ -937,7 +937,7 @@ void uiComposeLinks(uiBlock *block) void uiBlockSetButLock(uiBlock *block, int val, char *lockstr) { if(val) { - block->lock |= val; + block->lock= val ? 1:0; block->lockstr= lockstr; } } @@ -1947,7 +1947,7 @@ uiBlock *uiGetBlock(char *name, ARegion *ar) return NULL; } -void uiBlockSetEmboss(uiBlock *block, short dt) +void uiBlockSetEmboss(uiBlock *block, char dt) { block->dt= dt; } diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index c789c721aea..6d8c368db3f 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -1816,6 +1816,7 @@ static void ui_do_but_textedit(bContext *C, uiBlock *block, uiBut *but, uiHandle /* only update when typing for TAB key */ if(update && data->interactive) ui_apply_button(C, block, but, data, 1); else ui_check_but(but); + but->changed= TRUE; if(data->searchbox) ui_searchbox_update(C, data->searchbox, but, 1); /* 1 = reset */ diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c index 482eece42f6..3fa53b73015 100644 --- a/source/blender/editors/interface/interface_icons.c +++ b/source/blender/editors/interface/interface_icons.c @@ -622,20 +622,30 @@ static void init_iconfile_list(struct ListBase *list) char *filename = dir[i].relname; if(BLI_testextensie(filename, ".png")) { - + /* check to see if the image is the right size, continue if not */ /* copying strings here should go ok, assuming that we never get back a complete path to file longer than 256 chars */ sprintf(iconfilestr, "%s/%s", icondirstr, filename); - if(BLI_exists(iconfilestr)) bbuf = IMB_loadiffname(iconfilestr, IB_rect); - - ifilex = bbuf->x; - ifiley = bbuf->y; - IMB_freeImBuf(bbuf); + if(BLI_exists(iconfilestr)) + bbuf= IMB_loadiffname(iconfilestr, IB_rect); + else + bbuf= NULL; + + + if(bbuf) { + ifilex = bbuf->x; + ifiley = bbuf->y; + IMB_freeImBuf(bbuf); + } + else { + ifilex= ifiley= 0; + } + /* bad size or failed to load */ if ((ifilex != ICON_IMAGE_W) || (ifiley != ICON_IMAGE_H)) continue; - + /* found a potential icon file, so make an entry for it in the cache list */ ifile = MEM_callocN(sizeof(IconFile), "IconFile"); diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h index 3873c5c9092..eb28df54b13 100644 --- a/source/blender/editors/interface/interface_intern.h +++ b/source/blender/editors/interface/interface_intern.h @@ -206,10 +206,11 @@ struct uiBut { char *tip, *lockstr; BIFIconID icon; - short but_align; /* aligning buttons, horiz/vertical */ - short lock; + char lock; + char dt; + short changed; /* could be made into a single flag */ short modifier_key; - short iconadd, dt; + short iconadd; /* IDPOIN data */ uiIDPoinFuncFP idpoin_func; @@ -296,13 +297,14 @@ struct uiBlock { void *drawextra_arg1; void *drawextra_arg2; - int afterval, flag; - - short direction, dt; - short auto_open, in_use; + int flag; + char direction, dt; + short auto_open; double auto_open_last; - int lock; + char active; // to keep blocks while drawing and free them afterwards + char tooltipdisabled; // to avoid tooltip after click + short lock; char *lockstr; float xofs, yofs; // offset to parent button @@ -314,9 +316,7 @@ struct uiBlock { ListBase saferct; // uiSafetyRct list uiPopupBlockHandle *handle; // handle - int tooltipdisabled; // to avoid tooltip after click - int active; // to keep blocks while drawing and free them afterwards int puphash; // popup menu hash for memory int color_profile; // color profile for correcting linear colors for display diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c index e268120fa07..45b38a8c9a9 100644 --- a/source/blender/editors/interface/interface_layout.c +++ b/source/blender/editors/interface/interface_layout.c @@ -1109,6 +1109,7 @@ static void rna_search_cb(const struct bContext *C, void *arg_but, char *str, ui int i=0, iconid=0, flag= RNA_property_flag(but->rnaprop); ListBase *items_list= MEM_callocN(sizeof(ListBase), "items_list"); CollItemSearch *cis; + const int skip_filter= !but->changed; /* build a temporary list of relevant items first */ RNA_PROP_BEGIN(&but->rnasearchpoin, itemptr, but->rnasearchprop) { @@ -1140,7 +1141,7 @@ static void rna_search_cb(const struct bContext *C, void *arg_but, char *str, ui } if(name) { - if(BLI_strcasestr(name, str)) { + if(skip_filter || BLI_strcasestr(name, str)) { cis = MEM_callocN(sizeof(CollItemSearch), "CollectionItemSearch"); cis->name = MEM_dupallocN(name); cis->index = i; @@ -2168,6 +2169,7 @@ uiLayout *uiLayoutSplit(uiLayout *layout, float percentage, int align) split->litem.enabled= 1; split->litem.context= layout->context; split->litem.space= layout->root->style->columnspace; + split->litem.w= layout->w; split->percentage= percentage; BLI_addtail(&layout->items, split); diff --git a/source/blender/editors/interface/interface_regions.c b/source/blender/editors/interface/interface_regions.c index 50b85360196..a0f852239c4 100644 --- a/source/blender/editors/interface/interface_regions.c +++ b/source/blender/editors/interface/interface_regions.c @@ -27,6 +27,7 @@ #include <stdarg.h> #include <stdlib.h> #include <string.h> +#include <assert.h> #include "MEM_guardedalloc.h" @@ -300,7 +301,7 @@ typedef struct uiTooltipData { rcti bbox; uiFontStyle fstyle; char lines[MAX_TOOLTIP_LINES][512]; - int linedark[MAX_TOOLTIP_LINES]; + unsigned int color[MAX_TOOLTIP_LINES]; int totline; int toth, spaceh, lineh; } uiTooltipData; @@ -320,9 +321,7 @@ static void ui_tooltip_region_draw(const bContext *C, ARegion *ar) bbox.ymin= bbox.ymax - data->lineh; for(a=0; a<data->totline; a++) { - if(!data->linedark[a]) glColor4f(1.0f, 1.0f, 1.0f, 1.0f); - else glColor4f(0.5f, 0.5f, 0.5f, 1.0f); - + cpack(data->color[a]); uiStyleFontDraw(&data->fstyle, &bbox, data->lines[a]); bbox.ymin -= data->lineh + data->spaceh; bbox.ymax -= data->lineh + data->spaceh; @@ -358,6 +357,7 @@ ARegion *ui_tooltip_create(bContext *C, ARegion *butregion, uiBut *but) if(but->tip && strlen(but->tip)) { BLI_strncpy(data->lines[data->totline], but->tip, sizeof(data->lines[0])); + data->color[data->totline]= 0xFFFFFF; data->totline++; } @@ -367,7 +367,7 @@ ARegion *ui_tooltip_create(bContext *C, ARegion *butregion, uiBut *but) if(WM_key_event_operator_string(C, but->optype->idname, but->opcontext, prop, buf, sizeof(buf))) { BLI_snprintf(data->lines[data->totline], sizeof(data->lines[0]), "Shortcut: %s", buf); - data->linedark[data->totline]= 1; + data->color[data->totline]= 0x888888; data->totline++; } } @@ -377,7 +377,7 @@ ARegion *ui_tooltip_create(bContext *C, ARegion *butregion, uiBut *but) ui_get_but_string(but, buf, sizeof(buf)); if(buf[0]) { BLI_snprintf(data->lines[data->totline], sizeof(data->lines[0]), "Value: %s", buf); - data->linedark[data->totline]= 1; + data->color[data->totline]= 0x888888; data->totline++; } } @@ -388,7 +388,7 @@ ARegion *ui_tooltip_create(bContext *C, ARegion *butregion, uiBut *but) if (unit_type == PROP_UNIT_ROTATION) { if (RNA_property_type(but->rnaprop) == PROP_FLOAT) { BLI_snprintf(data->lines[data->totline], sizeof(data->lines[0]), "Radians: %f", RNA_property_float_get_index(&but->rnapoin, but->rnaprop, but->rnaindex)); - data->linedark[data->totline]= 1; + data->color[data->totline]= 0x888888; data->totline++; } } @@ -397,21 +397,21 @@ ARegion *ui_tooltip_create(bContext *C, ARegion *butregion, uiBut *but) if(ui_but_anim_expression_get(but, buf, sizeof(buf))) { /* expression */ BLI_snprintf(data->lines[data->totline], sizeof(data->lines[0]), "Expression: %s", buf); - data->linedark[data->totline]= 1; + data->color[data->totline]= 0x888888; data->totline++; } } /* rna info */ BLI_snprintf(data->lines[data->totline], sizeof(data->lines[0]), "Python: %s.%s", RNA_struct_identifier(but->rnapoin.type), RNA_property_identifier(but->rnaprop)); - data->linedark[data->totline]= 1; + data->color[data->totline]= 0x888888; data->totline++; if(but->rnapoin.id.data) { ID *id= but->rnapoin.id.data; if(id->lib && id->lib->name) { BLI_snprintf(data->lines[data->totline], sizeof(data->lines[0]), "Library: %s", id->lib->name); - data->linedark[data->totline]= 1; + data->color[data->totline]= 0x888888; data->totline++; } } @@ -425,12 +425,27 @@ ARegion *ui_tooltip_create(bContext *C, ARegion *butregion, uiBut *but) /* operator info */ BLI_snprintf(data->lines[data->totline], sizeof(data->lines[0]), "Python: %s", str); - data->linedark[data->totline]= 1; + data->color[data->totline]= 0x888888; data->totline++; MEM_freeN(str); + + /* second check if we are disabled - why */ + if(but->flag & UI_BUT_DISABLED) { + const char *poll_msg; + CTX_wm_operator_poll_msg_set(C, NULL); + WM_operator_poll(C, but->optype); + poll_msg= CTX_wm_operator_poll_msg_get(C); + if(poll_msg) { + BLI_snprintf(data->lines[data->totline], sizeof(data->lines[0]), "Disabled: %s", poll_msg); + data->color[data->totline]= 0x6666ff; /* alert */ + data->totline++; + } + } } + assert(data->totline < MAX_TOOLTIP_LINES); + if(data->totline == 0) { MEM_freeN(data); return NULL; @@ -1008,7 +1023,7 @@ ARegion *ui_searchbox_create(bContext *C, ARegion *butregion, uiBut *but) x2= winx; } } - if(y1 < 0) { + if(y1 < 0) { /* XXX butregion NULL check?, there is one above */ int newy1; UI_view2d_to_region_no_clip(&butregion->v2d, 0, but->y2 + ofsy, 0, &newy1); newy1 += butregion->winrct.ymin; @@ -1116,6 +1131,7 @@ static void ui_block_position(wmWindow *window, ARegion *butregion, uiBut *but, if(but) { int left=0, right=0, top=0, down=0; int winx, winy; + int offscreen; wm_window_get_size(window, &winx, &winy); @@ -1206,6 +1222,12 @@ static void ui_block_position(wmWindow *window, ARegion *butregion, uiBut *but, // apply requested offset in the block xof += block->xofs/block->aspect; yof += block->yofs/block->aspect; + + /* clamp to window bounds, could be made into an option if its ever annoying */ + if( (offscreen= (block->miny+yof)) < 0) yof -= offscreen; /* bottom */ + else if((offscreen= (block->maxy+yof)-winy) > 0) yof -= offscreen; /* top */ + if( (offscreen= (block->minx+xof)) < 0) xof -= offscreen; /* left */ + else if((offscreen= (block->maxx+xof)-winx) > 0) xof -= offscreen; /* right */ } /* apply */ diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c index b892ce1ca6d..134ab70e4ca 100644 --- a/source/blender/editors/interface/interface_widgets.c +++ b/source/blender/editors/interface/interface_widgets.c @@ -284,8 +284,10 @@ static void round_box__edges(uiWidgetBase *wt, int roundboxalign, rcti *rect, fl float facxi= (maxxi!=minxi) ? 1.0f/(maxxi-minxi) : 0.0f; /* for uv, can divide by zero */ float facyi= (maxyi!=minyi) ? 1.0f/(maxyi-minyi) : 0.0f; int a, tot= 0, minsize; + const int hnum= ((roundboxalign & (1|2))==(1|2) || (roundboxalign & (4|8))==(4|8)) ? 1 : 2; + const int vnum= ((roundboxalign & (1|8))==(1|8) || (roundboxalign & (2|4))==(2|4)) ? 1 : 2; - minsize= MIN2(rect->xmax-rect->xmin, rect->ymax-rect->ymin); + minsize= MIN2((rect->xmax-rect->xmin)*hnum, (rect->ymax-rect->ymin)*vnum); if(2.0f*rad > minsize) rad= 0.5f*minsize; @@ -2219,7 +2221,7 @@ static void widget_numslider(uiBut *but, uiWidgetColors *wcol, rcti *rect, int s uiWidgetBase wtb, wtb1; rcti rect1; double value; - float offs, fac; + float offs, toffs, fac; char outline[3]; widget_init(&wtb); @@ -2229,6 +2231,7 @@ static void widget_numslider(uiBut *but, uiWidgetColors *wcol, rcti *rect, int s /* fully rounded */ offs= 0.5f*(rect->ymax - rect->ymin); + toffs = offs*0.75f; round_box_edges(&wtb, roundboxalign, rect, offs); wtb.outline= 0; @@ -2274,8 +2277,8 @@ static void widget_numslider(uiBut *but, uiWidgetColors *wcol, rcti *rect, int s widgetbase_draw(&wtb, wcol); /* text space */ - rect->xmin += offs*0.75f; - rect->xmax -= offs*0.75f; + rect->xmin += toffs; + rect->xmax -= toffs; } /* I think 3 is sufficient border to indicate keyed status */ diff --git a/source/blender/editors/interface/view2d_ops.c b/source/blender/editors/interface/view2d_ops.c index de1b26e987b..e10f0f20938 100644 --- a/source/blender/editors/interface/view2d_ops.c +++ b/source/blender/editors/interface/view2d_ops.c @@ -146,7 +146,6 @@ static void view_pan_apply(bContext *C, wmOperator *op) ED_region_tag_redraw(vpd->ar); UI_view2d_sync(vpd->sc, vpd->sa, v2d, V2D_LOCK_COPY); - WM_event_add_mousemove(C); /* exceptions */ if (vpd->sa->spacetype==SPACE_OUTLINER) { @@ -628,7 +627,6 @@ static void view_zoomstep_apply(bContext *C, wmOperator *op) /* request updates to be done... */ ED_region_tag_redraw(vzd->ar); UI_view2d_sync(CTX_wm_screen(C), CTX_wm_area(C), v2d, V2D_LOCK_COPY); - WM_event_add_mousemove(C); } /* --------------- Individual Operators ------------------- */ @@ -822,7 +820,6 @@ static void view_zoomdrag_apply(bContext *C, wmOperator *op) /* request updates to be done... */ ED_region_tag_redraw(vzd->ar); UI_view2d_sync(CTX_wm_screen(C), CTX_wm_area(C), v2d, V2D_LOCK_COPY); - WM_event_add_mousemove(C); } /* cleanup temp customdata */ @@ -1095,7 +1092,6 @@ static int view_borderzoom_exec(bContext *C, wmOperator *op) /* request updates to be done... */ ED_region_tag_redraw(ar); UI_view2d_sync(CTX_wm_screen(C), CTX_wm_area(C), v2d, V2D_LOCK_COPY); - WM_event_add_mousemove(C); return OPERATOR_FINISHED; } @@ -1355,7 +1351,6 @@ static void scroller_activate_apply(bContext *C, wmOperator *op) /* request updates to be done... */ ED_region_tag_redraw(vsm->ar); UI_view2d_sync(CTX_wm_screen(C), CTX_wm_area(C), v2d, V2D_LOCK_COPY); - WM_event_add_mousemove(C); } /* handle user input for scrollers - calculations of mouse-movement need to be done here, not in the apply callback! */ @@ -1560,7 +1555,6 @@ static int reset_exec(bContext *C, wmOperator *op) /* request updates to be done... */ ED_region_tag_redraw(ar); UI_view2d_sync(CTX_wm_screen(C), CTX_wm_area(C), v2d, V2D_LOCK_COPY); - WM_event_add_mousemove(C); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/mesh/editmesh_mods.c b/source/blender/editors/mesh/editmesh_mods.c index f8018c686f5..164e8980b83 100644 --- a/source/blender/editors/mesh/editmesh_mods.c +++ b/source/blender/editors/mesh/editmesh_mods.c @@ -2113,7 +2113,7 @@ void MESH_OT_loop_select(wmOperatorType *ot) /* api callbacks */ ot->invoke= mesh_select_loop_invoke; - ot->poll= ED_operator_editmesh_region_view3d; + ot->poll= ED_operator_editmesh_view3d; /* flags */ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; diff --git a/source/blender/editors/mesh/loopcut.c b/source/blender/editors/mesh/loopcut.c index 7f1a7d0e1fc..13538a6f218 100644 --- a/source/blender/editors/mesh/loopcut.c +++ b/source/blender/editors/mesh/loopcut.c @@ -506,7 +506,7 @@ void MESH_OT_loopcut (wmOperatorType *ot) ot->invoke= ringcut_invoke; ot->modal= ringcut_modal; ot->cancel= ringcut_cancel; - ot->poll= ED_operator_editmesh_region_view3d; + ot->poll= ED_operator_editmesh_view3d; /* flags */ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO|OPTYPE_BLOCKING; diff --git a/source/blender/editors/mesh/mesh_ops.c b/source/blender/editors/mesh/mesh_ops.c index 9e071aa4a21..fa055a385f3 100644 --- a/source/blender/editors/mesh/mesh_ops.c +++ b/source/blender/editors/mesh/mesh_ops.c @@ -251,7 +251,7 @@ void ED_keymap_mesh(wmKeyConfig *keyconf) WM_keymap_add_item(keymap, "MESH_OT_select_similar", GKEY, KM_PRESS, KM_SHIFT, 0); /* selection mode */ - WM_keymap_add_menu(keymap, "VIEW3D_MT_edit_mesh_selection_mode", TABKEY, KM_PRESS, KM_CTRL, 0); + WM_keymap_add_menu(keymap, "VIEW3D_MT_edit_mesh_select_mode", TABKEY, KM_PRESS, KM_CTRL, 0); /* hide */ WM_keymap_add_item(keymap, "MESH_OT_hide", HKEY, KM_PRESS, 0, 0); diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c index e0608f03274..3ae1941035d 100644 --- a/source/blender/editors/object/object_add.c +++ b/source/blender/editors/object/object_add.c @@ -1010,6 +1010,9 @@ static int object_duplicates_make_real_exec(bContext *C, wmOperator *op) CTX_DATA_BEGIN(C, Base*, base, selected_editable_bases) { make_object_duplilist_real(C, scene, base); + + /* dependencies were changed */ + WM_event_add_notifier(C, NC_OBJECT|ND_PARENT, base->object); } CTX_DATA_END; diff --git a/source/blender/editors/object/object_constraint.c b/source/blender/editors/object/object_constraint.c index f5d87df10a1..fd3c8b165c0 100644 --- a/source/blender/editors/object/object_constraint.c +++ b/source/blender/editors/object/object_constraint.c @@ -65,6 +65,7 @@ #include "RNA_enum_types.h" #include "ED_object.h" +#include "ED_armature.h" #include "ED_screen.h" #include "UI_interface.h" @@ -935,7 +936,7 @@ static int pose_constraints_clear_exec(bContext *C, wmOperator *op) { Main *bmain= CTX_data_main(C); Scene *scene= CTX_data_scene(C); - Object *ob= CTX_data_active_object(C); + Object *ob= ED_object_pose_armature(CTX_data_active_object(C)); /* free constraints for all selected bones */ CTX_DATA_BEGIN(C, bPoseChannel*, pchan, selected_pose_bones) @@ -1364,7 +1365,7 @@ static int object_constraint_add_exec(bContext *C, wmOperator *op) /* dummy operator callback */ static int pose_constraint_add_exec(bContext *C, wmOperator *op) { - Object *ob= ED_object_active_context(C); + Object *ob= ED_object_pose_armature(ED_object_active_context(C)); int type= RNA_enum_get(op->ptr, "type"); short with_targets= 0; @@ -1467,7 +1468,7 @@ void POSE_OT_constraint_add_with_targets(wmOperatorType *ot) /* present menu with options + validation for targets to use */ static int pose_ik_add_invoke(bContext *C, wmOperator *op, wmEvent *evt) { - Object *ob= CTX_data_active_object(C); + Object *ob= ED_object_pose_armature(CTX_data_active_object(C)); bPoseChannel *pchan= get_active_posechannel(ob); bConstraint *con= NULL; @@ -1551,7 +1552,7 @@ void POSE_OT_ik_add(wmOperatorType *ot) /* remove IK constraints from selected bones */ static int pose_ik_clear_exec(bContext *C, wmOperator *op) { - Object *ob= CTX_data_active_object(C); + Object *ob= ED_object_pose_armature(CTX_data_active_object(C)); /* only remove IK Constraints */ CTX_DATA_BEGIN(C, bPoseChannel*, pchan, selected_pose_bones) diff --git a/source/blender/editors/object/object_select.c b/source/blender/editors/object/object_select.c index 818bb50a1fb..20346ab080e 100644 --- a/source/blender/editors/object/object_select.c +++ b/source/blender/editors/object/object_select.c @@ -660,7 +660,7 @@ static int object_select_by_layer_exec(bContext *C, wmOperator *op) void OBJECT_OT_select_by_layer(wmOperatorType *ot) { /* identifiers */ - ot->name= "select by layer"; + ot->name= "Select by Layer"; ot->description = "Select all visible objects on a layer"; ot->idname= "OBJECT_OT_select_by_layer"; @@ -809,7 +809,7 @@ void OBJECT_OT_select_same_group(wmOperatorType *ot) { /* identifiers */ - ot->name= "select same group"; + ot->name= "Select Same Group"; ot->description = "Select object in the same group"; ot->idname= "OBJECT_OT_select_same_group"; diff --git a/source/blender/editors/render/render_shading.c b/source/blender/editors/render/render_shading.c index 39eb6921379..af09ddd8858 100644 --- a/source/blender/editors/render/render_shading.c +++ b/source/blender/editors/render/render_shading.c @@ -267,6 +267,7 @@ static int material_slot_add_exec(bContext *C, wmOperator *op) object_add_material_slot(ob); WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob); + WM_event_add_notifier(C, NC_OBJECT|ND_OB_SHADING, ob); return OPERATOR_FINISHED; } @@ -294,6 +295,7 @@ static int material_slot_remove_exec(bContext *C, wmOperator *op) object_remove_material_slot(ob); WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob); + WM_event_add_notifier(C, NC_OBJECT|ND_OB_SHADING, ob); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/screen/screen_context.c b/source/blender/editors/screen/screen_context.c index fbc83b1de65..b619398d985 100644 --- a/source/blender/editors/screen/screen_context.c +++ b/source/blender/editors/screen/screen_context.c @@ -209,14 +209,15 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult } } else if(CTX_data_equals(member, "visible_pose_bones")) { - bArmature *arm= (obact) ? obact->data : NULL; + Object *obpose= ED_object_pose_armature(obact); + bArmature *arm= (obpose) ? obpose->data : NULL; bPoseChannel *pchan; - if (obact && obact->pose && arm) { - for (pchan= obact->pose->chanbase.first; pchan; pchan= pchan->next) { + if (obpose && obpose->pose && arm) { + for (pchan= obpose->pose->chanbase.first; pchan; pchan= pchan->next) { /* ensure that PoseChannel is on visible layer and is not hidden in PoseMode */ if ((pchan->bone) && (arm->layer & pchan->bone->layer) && !(pchan->bone->flag & BONE_HIDDEN_P)) { - CTX_data_list_add(result, &obact->id, &RNA_PoseBone, pchan); + CTX_data_list_add(result, &obpose->id, &RNA_PoseBone, pchan); } } CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION); @@ -224,15 +225,16 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult } } else if(CTX_data_equals(member, "selected_pose_bones")) { - bArmature *arm= (obact) ? obact->data : NULL; + Object *obpose= ED_object_pose_armature(obact); + bArmature *arm= (obpose) ? obpose->data : NULL; bPoseChannel *pchan; - if (obact && obact->pose && arm) { - for (pchan= obact->pose->chanbase.first; pchan; pchan= pchan->next) { + if (obpose && obpose->pose && arm) { + for (pchan= obpose->pose->chanbase.first; pchan; pchan= pchan->next) { /* ensure that PoseChannel is on visible layer and is not hidden in PoseMode */ if ((pchan->bone) && (arm->layer & pchan->bone->layer) && !(pchan->bone->flag & BONE_HIDDEN_P)) { if (pchan->bone->flag & BONE_SELECTED || pchan->bone == arm->act_bone) - CTX_data_list_add(result, &obact->id, &RNA_PoseBone, pchan); + CTX_data_list_add(result, &obpose->id, &RNA_PoseBone, pchan); } } CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION); @@ -258,10 +260,11 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult } else if(CTX_data_equals(member, "active_pose_bone")) { bPoseChannel *pchan; + Object *obpose= ED_object_pose_armature(obact); - pchan= get_active_posechannel(obact); + pchan= get_active_posechannel(obpose); if (pchan) { - CTX_data_pointer_set(result, &obact->id, &RNA_PoseBone, pchan); + CTX_data_pointer_set(result, &obpose->id, &RNA_PoseBone, pchan); return 1; } } diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c index 7638d576d9d..613c8bc0178 100644 --- a/source/blender/editors/screen/screen_ops.c +++ b/source/blender/editors/screen/screen_ops.c @@ -56,6 +56,7 @@ #include "ED_util.h" #include "ED_screen.h" #include "ED_object.h" +#include "ED_armature.h" #include "ED_screen_types.h" #include "ED_keyframes_draw.h" @@ -243,7 +244,11 @@ int ED_operator_editmesh_view3d(bContext *C) int ED_operator_editmesh_region_view3d(bContext *C) { - return ED_operator_editmesh(C) && CTX_wm_region_view3d(C); + if(ED_operator_editmesh(C) && CTX_wm_region_view3d(C)) + return 1; + + CTX_wm_operator_poll_msg_set(C, "expected a view3d region & editmesh"); + return 0; } int ED_operator_editarmature(bContext *C) @@ -259,8 +264,8 @@ int ED_operator_posemode(bContext *C) Object *obact= CTX_data_active_object(C); Object *obedit= CTX_data_edit_object(C); - if ((obact != obedit) && (obact) && (obact->type==OB_ARMATURE)) - return (obact->mode & OB_MODE_POSE)!=0; + if ((obact != obedit) && ED_object_pose_armature(obact)) + return 1; return 0; } diff --git a/source/blender/editors/space_console/console_draw.c b/source/blender/editors/space_console/console_draw.c index d1fa4e17e6f..d5ffb34b3a2 100644 --- a/source/blender/editors/space_console/console_draw.c +++ b/source/blender/editors/space_console/console_draw.c @@ -286,6 +286,24 @@ static int console_draw_string(ConsoleDrawContext *cdc, char *str, int str_len, #undef STEP_SEL } +void console_scrollback_prompt_begin(struct SpaceConsole *sc, ConsoleLine *cl_dummy) +{ + /* fake the edit line being in the scroll buffer */ + ConsoleLine *cl= sc->history.last; + cl_dummy->type= CONSOLE_LINE_INPUT; + cl_dummy->len= cl_dummy->len_alloc= strlen(sc->prompt) + cl->len; + cl_dummy->len_alloc= cl_dummy->len + 1; + cl_dummy->line= MEM_mallocN(cl_dummy->len_alloc, "cl_dummy"); + memcpy(cl_dummy->line, sc->prompt, (cl_dummy->len_alloc - cl->len)); + memcpy(cl_dummy->line + ((cl_dummy->len_alloc - cl->len)) - 1, cl->line, cl->len + 1); + BLI_addtail(&sc->scrollback, cl_dummy); +} +void console_scrollback_prompt_end(struct SpaceConsole *sc, ConsoleLine *cl_dummy) +{ + MEM_freeN(cl_dummy->line); + BLI_remlink(&sc->scrollback, cl_dummy); +} + #define CONSOLE_DRAW_MARGIN 4 #define CONSOLE_DRAW_SCROLL 16 @@ -349,15 +367,7 @@ static int console_text_main__internal(struct SpaceConsole *sc, struct ARegion * xy[0]= x_orig; /* remove prompt offset */ } - /* fake the edit line being in the scroll buffer */ - cl_dummy.type= CONSOLE_LINE_INPUT; - cl_dummy.len= cl_dummy.len_alloc= prompt_len + cl->len; - cl_dummy.len_alloc= cl_dummy.len + 1; - cl_dummy.line= MEM_mallocN(cl_dummy.len_alloc, "cl_dummy"); - memcpy(cl_dummy.line, sc->prompt, (cl_dummy.len_alloc - cl->len)); - memcpy(cl_dummy.line + ((cl_dummy.len_alloc - cl->len)) - 1, cl->line, cl->len + 1); - BLI_addtail(&sc->scrollback, &cl_dummy); - + console_scrollback_prompt_begin(sc, &cl_dummy); for(cl= sc->scrollback.last; cl; cl= cl->prev) { y_prev= xy[1]; @@ -378,9 +388,7 @@ static int console_text_main__internal(struct SpaceConsole *sc, struct ARegion * } } - /* temp line end */ - MEM_freeN(cl_dummy.line); - BLI_remlink(&sc->scrollback, &cl_dummy); + console_scrollback_prompt_end(sc, &cl_dummy); } else { Report *report; diff --git a/source/blender/editors/space_console/console_intern.h b/source/blender/editors/space_console/console_intern.h index c74d39f25e3..0e2c35bcf83 100644 --- a/source/blender/editors/space_console/console_intern.h +++ b/source/blender/editors/space_console/console_intern.h @@ -41,6 +41,9 @@ int console_text_height(struct SpaceConsole *sc, struct ARegion *ar, struct Repo void *console_text_pick(struct SpaceConsole *sc, struct ARegion *ar, struct ReportList *reports, int mouse_y); /* needed for selection */ int console_char_pick(struct SpaceConsole *sc, struct ARegion *ar, ReportList *reports, int mval[2]); +void console_scrollback_prompt_begin(struct SpaceConsole *sc, ConsoleLine *cl_dummy); +void console_scrollback_prompt_end(struct SpaceConsole *sc, ConsoleLine *cl_dummy); + /* console_ops.c */ void console_history_free(SpaceConsole *sc, ConsoleLine *cl); void console_scrollback_free(SpaceConsole *sc, ConsoleLine *cl); diff --git a/source/blender/editors/space_console/console_ops.c b/source/blender/editors/space_console/console_ops.c index a49581cb417..4e50b589bc6 100644 --- a/source/blender/editors/space_console/console_ops.c +++ b/source/blender/editors/space_console/console_ops.c @@ -403,8 +403,14 @@ static int insert_exec(bContext *C, wmOperator *op) static int insert_invoke(bContext *C, wmOperator *op, wmEvent *event) { - if(!RNA_property_is_set(op->ptr, "text")) { + // if(!RNA_property_is_set(op->ptr, "text")) { /* always set from keymap XXX */ + if(!RNA_string_length(op->ptr, "text")) { char str[2] = {event->ascii, '\0'}; + + /* if alt/ctrl/super are pressed pass through */ + if(event->alt || event->ctrl || event->oskey) + return OPERATOR_PASS_THROUGH; + RNA_string_set(op->ptr, "text", str); } return insert_exec(C, op); @@ -705,6 +711,8 @@ static int copy_exec(bContext *C, wmOperator *op) int sel[2]; int offset= 0; + ConsoleLine cl_dummy= {0}; + #if 0 /* copy whole file */ for(cl= sc->scrollback.first; cl; cl= cl->next) { @@ -716,14 +724,16 @@ static int copy_exec(bContext *C, wmOperator *op) if(sc->sel_start == sc->sel_end) return OPERATOR_CANCELLED; + console_scrollback_prompt_begin(sc, &cl_dummy); for(cl= sc->scrollback.first; cl; cl= cl->next) { offset += cl->len + 1; } - if(offset==0) + if(offset==0) { + console_scrollback_prompt_end(sc, &cl_dummy); return OPERATOR_CANCELLED; - + } offset -= 1; sel[0]= offset - sc->sel_end; @@ -750,6 +760,9 @@ static int copy_exec(bContext *C, wmOperator *op) WM_clipboard_text_set(buf_str, 0); MEM_freeN(buf_str); + + console_scrollback_prompt_end(sc, &cl_dummy); + return OPERATOR_FINISHED; } @@ -769,6 +782,7 @@ void CONSOLE_OT_copy(wmOperatorType *ot) static int paste_exec(bContext *C, wmOperator *op) { + SpaceConsole *sc= CTX_wm_space_console(C); ConsoleLine *ci= console_history_verify(C); char *buf_str= WM_clipboard_text_get(0); @@ -792,7 +806,7 @@ static int paste_exec(bContext *C, wmOperator *op) ci= console_history_verify(C); } - console_line_insert(ci, buf_next); + console_select_offset(sc, console_line_insert(ci, buf_next)); } MEM_freeN(buf_str); diff --git a/source/blender/editors/space_image/image_draw.c b/source/blender/editors/space_image/image_draw.c index 6a77d4da067..f29d1bc033f 100644 --- a/source/blender/editors/space_image/image_draw.c +++ b/source/blender/editors/space_image/image_draw.c @@ -49,6 +49,10 @@ #include "BKE_image.h" #include "BKE_paint.h" +#ifdef WITH_LCMS +#include "BKE_colortools.h" +#endif + #include "BIF_gl.h" #include "BIF_glutil.h" diff --git a/source/blender/editors/space_logic/logic_window.c b/source/blender/editors/space_logic/logic_window.c index 4b778e80b0e..148bcf1459f 100644 --- a/source/blender/editors/space_logic/logic_window.c +++ b/source/blender/editors/space_logic/logic_window.c @@ -3712,7 +3712,7 @@ static void draw_actuator_armature(uiLayout *layout, PointerRNA *ptr) break; case ACT_ARM_ENABLE: case ACT_ARM_DISABLE: - if (&pose_ptr.data) { + if (ob->pose) { uiItemPointerR(layout, ptr, "bone", &pose_ptr, "bones", NULL, ICON_BONE_DATA); if (RNA_property_collection_lookup_string(&pose_ptr, bones_prop, aa->posechannel, &pchan_ptr)) @@ -3720,7 +3720,7 @@ static void draw_actuator_armature(uiLayout *layout, PointerRNA *ptr) } break; case ACT_ARM_SETTARGET: - if (&pose_ptr.data) { + if (ob->pose) { uiItemPointerR(layout, ptr, "bone", &pose_ptr, "bones", NULL, ICON_BONE_DATA); if (RNA_property_collection_lookup_string(&pose_ptr, bones_prop, aa->posechannel, &pchan_ptr)) @@ -3731,7 +3731,7 @@ static void draw_actuator_armature(uiLayout *layout, PointerRNA *ptr) uiItemR(layout, ptr, "secondary_target", 0, NULL, 0); break; case ACT_ARM_SETWEIGHT: - if (&pose_ptr.data) { + if (ob->pose) { uiItemPointerR(layout, ptr, "bone", &pose_ptr, "bones", NULL, ICON_BONE_DATA); if (RNA_property_collection_lookup_string(&pose_ptr, bones_prop, aa->posechannel, &pchan_ptr)) diff --git a/source/blender/editors/space_node/node_draw.c b/source/blender/editors/space_node/node_draw.c index 0b33196c646..dfc63e032d9 100644 --- a/source/blender/editors/space_node/node_draw.c +++ b/source/blender/editors/space_node/node_draw.c @@ -1031,9 +1031,14 @@ static void node_draw_group(const bContext *C, ARegion *ar, SpaceNode *snode, bN else BLI_strncpy(showname, ngroup->id.name+2, sizeof(showname)); - // XXX this shows some scaling artifacts - UI_DrawString(rect.xmin+8.0f, rect.ymax+5.0f, showname); - + + uiDefBut(gnode->block, LABEL, 0, showname, (short)(rect.xmin+15), (short)(rect.ymax), + (int)(rect.xmax - rect.xmin-18.0f), NODE_DY, NULL, 0, 0, 0, 0, ""); + uiEndBlock(C, gnode->block); + uiDrawBlock(C, gnode->block); + gnode->block= NULL; + + /* links from groupsockets to the internal nodes */ node_draw_group_links(&ar->v2d, snode, gnode); @@ -1045,6 +1050,8 @@ static void node_draw_group(const bContext *C, ARegion *ar, SpaceNode *snode, bN if(!(sock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL))) socket_circle_draw(sock, NODE_SOCKSIZE); + + /* and finally the whole tree */ node_draw_nodetree(C, ar, snode, ngroup); } diff --git a/source/blender/editors/space_outliner/outliner.c b/source/blender/editors/space_outliner/outliner.c index fafc9024a28..d80291e199b 100644 --- a/source/blender/editors/space_outliner/outliner.c +++ b/source/blender/editors/space_outliner/outliner.c @@ -1931,15 +1931,14 @@ static void tree_element_set_active_object(bContext *C, Scene *scene, SpaceOops scene_deselect_all(scene); ED_base_object_select(base, BA_SELECT); } - if(C) + if(C) { ED_base_object_activate(C, base); /* adds notifier */ + WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, scene); + } } if(ob!=scene->obedit) ED_object_exit_editmode(C, EM_FREEDATA|EM_FREEUNDO|EM_WAITCURSOR|EM_DO_UNDO); - - WM_event_add_notifier(C, NC_SCENE|ND_OB_ACTIVE, scene); - } static int tree_element_active_material(bContext *C, Scene *scene, SpaceOops *soops, TreeElement *te, int set) @@ -2050,7 +2049,9 @@ static int tree_element_active_texture(bContext *C, Scene *scene, SpaceOops *soo } } - WM_event_add_notifier(C, NC_TEXTURE, NULL); + if(set) + WM_event_add_notifier(C, NC_TEXTURE, NULL); + return 0; } @@ -5538,7 +5539,7 @@ static void outliner_draw_keymapbuts(uiBlock *block, ARegion *ar, SpaceOops *soo uiDefButS(block, OPTION, 0, "Shift", xstart, (int)te->ys+1, butw3+5, OL_H-1, &kmi->shift, 0, 0, 0, 0, "Modifier"); xstart+= butw3+5; uiDefButS(block, OPTION, 0, "Ctrl", xstart, (int)te->ys+1, butw3, OL_H-1, &kmi->ctrl, 0, 0, 0, 0, "Modifier"); xstart+= butw3; uiDefButS(block, OPTION, 0, "Alt", xstart, (int)te->ys+1, butw3, OL_H-1, &kmi->alt, 0, 0, 0, 0, "Modifier"); xstart+= butw3; - uiDefButS(block, OPTION, 0, "Cmd", xstart, (int)te->ys+1, butw3, OL_H-1, &kmi->oskey, 0, 0, 0, 0, "Modifier"); xstart+= butw3; + uiDefButS(block, OPTION, 0, "OS", xstart, (int)te->ys+1, butw3, OL_H-1, &kmi->oskey, 0, 0, 0, 0, "Modifier"); xstart+= butw3; xstart+= 5; uiDefKeyevtButS(block, 0, "", xstart, (int)te->ys+1, butw3, OL_H-1, &kmi->keymodifier, "Key Modifier code"); xstart+= butw3+5; diff --git a/source/blender/editors/space_outliner/space_outliner.c b/source/blender/editors/space_outliner/space_outliner.c index d91c8caa14c..f0f9ac945ef 100644 --- a/source/blender/editors/space_outliner/space_outliner.c +++ b/source/blender/editors/space_outliner/space_outliner.c @@ -116,6 +116,7 @@ static void outliner_main_area_listener(ARegion *ar, wmNotifier *wmn) case ND_BONE_ACTIVE: case ND_BONE_SELECT: case ND_PARENT: + case ND_OB_SHADING: ED_region_tag_redraw(ar); break; case ND_CONSTRAINT: @@ -150,6 +151,17 @@ static void outliner_main_area_listener(ARegion *ar, wmNotifier *wmn) if(wmn->action == NA_RENAME) ED_region_tag_redraw(ar); break; + case NC_MATERIAL: + switch(wmn->data) { + case ND_SHADING: + case ND_SHADING_DRAW: + ED_region_tag_redraw(ar); + break; + } + break; + case NC_TEXTURE: + ED_region_tag_redraw(ar); + break; } } diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c index d1654dc5d37..d96b8a27c99 100644 --- a/source/blender/editors/space_sequencer/sequencer_edit.c +++ b/source/blender/editors/space_sequencer/sequencer_edit.c @@ -159,7 +159,7 @@ static void change_plugin_seq(Scene *scene, char *str) /* called from fileselect struct SeqEffectHandle sh; Sequence *last_seq= seq_active_get(scene); - if(last_seq && last_seq->type != SEQ_PLUGIN) return; + if(last_seq==NULL || last_seq->type != SEQ_PLUGIN) return; sh = get_sequence_effect(last_seq); sh.free(last_seq); @@ -788,7 +788,7 @@ static Sequence *cut_seq_hard(Main *bmain, Scene *scene, Sequence * seq, int cut if (!skip_dup) { /* Duplicate AFTER the first change */ - seqn = seq_dupli_recursive(scene, seq, SEQ_DUPE_UNIQUE_NAME | SEQ_DUPE_ANIM); + seqn = seq_dupli_recursive(scene, NULL, seq, SEQ_DUPE_UNIQUE_NAME | SEQ_DUPE_ANIM); } if (seqn) { @@ -879,7 +879,7 @@ static Sequence *cut_seq_soft(Main *bmain, Scene *scene, Sequence * seq, int cut if (!skip_dup) { /* Duplicate AFTER the first change */ - seqn = seq_dupli_recursive(scene, seq, SEQ_DUPE_UNIQUE_NAME | SEQ_DUPE_ANIM); + seqn = seq_dupli_recursive(scene, NULL, seq, SEQ_DUPE_UNIQUE_NAME | SEQ_DUPE_ANIM); } if (seqn) { @@ -1619,7 +1619,7 @@ static int sequencer_add_duplicate_exec(bContext *C, wmOperator *op) if(ed==NULL) return OPERATOR_CANCELLED; - seqbase_dupli_recursive(scene, &nseqbase, ed->seqbasep, SEQ_DUPE_CONTEXT); + seqbase_dupli_recursive(scene, NULL, &nseqbase, ed->seqbasep, SEQ_DUPE_CONTEXT); if(nseqbase.first) { Sequence * seq= nseqbase.first; @@ -2595,7 +2595,7 @@ static int sequencer_copy_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - seqbase_dupli_recursive(scene, &seqbase_clipboard, ed->seqbasep, SEQ_DUPE_UNIQUE_NAME); + seqbase_dupli_recursive(scene, NULL, &seqbase_clipboard, ed->seqbasep, SEQ_DUPE_UNIQUE_NAME); seqbase_clipboard_frame= scene->r.cfra; /* Need to remove anything that references the current scene */ @@ -2649,7 +2649,7 @@ static int sequencer_paste_exec(bContext *C, wmOperator *op) deselect_all_seq(scene); ofs = scene->r.cfra - seqbase_clipboard_frame; - seqbase_dupli_recursive(scene, &nseqbase, &seqbase_clipboard, SEQ_DUPE_UNIQUE_NAME); + seqbase_dupli_recursive(scene, NULL, &nseqbase, &seqbase_clipboard, SEQ_DUPE_UNIQUE_NAME); /* transform pasted strips before adding */ if(ofs) { diff --git a/source/blender/editors/space_text/text_ops.c b/source/blender/editors/space_text/text_ops.c index ed70f31f970..e3bf390dba8 100644 --- a/source/blender/editors/space_text/text_ops.c +++ b/source/blender/editors/space_text/text_ops.c @@ -2317,18 +2317,19 @@ static int insert_exec(bContext *C, wmOperator *op) static int insert_invoke(bContext *C, wmOperator *op, wmEvent *event) { - char str[2]; int ret; - /* XXX old code from winqreadtextspace, is it still needed somewhere? */ - /* smartass code to prevent the CTRL/ALT events below from not working! */ - /*if(qual & (LR_ALTKEY|LR_CTRLKEY)) - if(!ispunct(ascii)) - ascii= 0;*/ - str[0]= event->ascii; - str[1]= '\0'; + // if(!RNA_property_is_set(op->ptr, "text")) { /* always set from keymap XXX */ + if(!RNA_string_length(op->ptr, "text")) { + char str[2] = {event->ascii, '\0'}; + + /* if alt/ctrl/super are pressed pass through */ + if(event->alt || event->ctrl || event->oskey) + return OPERATOR_PASS_THROUGH; + + RNA_string_set(op->ptr, "text", str); + } - RNA_string_set(op->ptr, "text", str); ret = insert_exec(C, op); /* run the script while editing, evil but useful */ diff --git a/source/blender/editors/space_text/text_python.c b/source/blender/editors/space_text/text_python.c index aee1a7ecfd6..9be554924c9 100644 --- a/source/blender/editors/space_text/text_python.c +++ b/source/blender/editors/space_text/text_python.c @@ -182,7 +182,7 @@ static void confirm_suggestion(Text *text, int skipleft) #define LR_SHIFTKEY 0 #define LR_ALTKEY 0 #define LR_CTRLKEY 0 -#define LR_COMMANDKEY 0 +#define LR_OSKEY 0 // XXX static int doc_scroll= 0; diff --git a/source/blender/editors/space_time/space_time.c b/source/blender/editors/space_time/space_time.c index ca7dc29ad85..0d3b0514122 100644 --- a/source/blender/editors/space_time/space_time.c +++ b/source/blender/editors/space_time/space_time.c @@ -519,6 +519,7 @@ static void time_main_area_listener(ARegion *ar, wmNotifier *wmn) case NC_SCENE: switch (wmn->data) { case ND_OB_SELECT: + case ND_OB_ACTIVE: case ND_FRAME: case ND_FRAME_RANGE: case ND_KEYINGSET: diff --git a/source/blender/editors/space_view3d/drawmesh.c b/source/blender/editors/space_view3d/drawmesh.c index 372ac976342..cf511a8ad9b 100644 --- a/source/blender/editors/space_view3d/drawmesh.c +++ b/source/blender/editors/space_view3d/drawmesh.c @@ -523,7 +523,7 @@ static int draw_em_tf_mapped__set_draw(void *userData, int index) MCol *mcol; int matnr; - if (efa==NULL || efa->h) + if (efa->h) return 0; tface = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); @@ -536,12 +536,13 @@ static int draw_em_tf_mapped__set_draw(void *userData, int index) static int wpaint__setSolidDrawOptions(void *userData, int index, int *drawSmooth_r) { Mesh *me = (Mesh*)userData; - MTFace *tface = (me->mtface)? &me->mtface[index]: NULL; - MFace *mface = (me->mface)? &me->mface[index]: NULL; - - if ((mface->flag&ME_HIDE) || (tface && (tface->mode&TF_INVISIBLE))) - return 0; - + + if ( (me->mface && me->mface[index].flag & ME_HIDE) || + (me->mtface && (me->mtface[index].mode & TF_INVISIBLE)) + ) { + return 0; + } + *drawSmooth_r = 1; return 1; } @@ -647,7 +648,7 @@ void draw_mesh_textured(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object *o dm->drawMappedFacesTex(dm, draw_em_tf_mapped__set_draw, me->edit_mesh); } else if(faceselect) { if(ob->mode & OB_MODE_WEIGHT_PAINT) - dm->drawMappedFaces(dm, wpaint__setSolidDrawOptions, me, 1); + dm->drawMappedFaces(dm, wpaint__setSolidDrawOptions, me, 1, GPU_enable_material); else dm->drawMappedFacesTex(dm, draw_tface_mapped__set_draw, me); } diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c index 30b12b96ed5..d28813f7522 100644 --- a/source/blender/editors/space_view3d/drawobject.c +++ b/source/blender/editors/space_view3d/drawobject.c @@ -917,6 +917,9 @@ static void drawlamp(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base, copy_m4_m4(imat, rv3d->viewinv); normalize_v3(imat[0]); normalize_v3(imat[1]); + + /* lamp center */ + copy_v3_v3(vec, ob->obmat[3]); /* for AA effects */ glGetFloatv(GL_CURRENT_COLOR, curcol); @@ -931,7 +934,6 @@ static void drawlamp(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base, } /* Inner Circle */ - copy_v3_v3(vec, ob->obmat[3]); glEnable(GL_BLEND); drawcircball(GL_LINE_LOOP, vec, lampsize, imat); glDisable(GL_BLEND); @@ -1867,7 +1869,7 @@ static void draw_dm_faces_sel(DerivedMesh *dm, unsigned char *baseCol, unsigned data.cols[2] = actCol; data.efa_act = efa_act; - dm->drawMappedFaces(dm, draw_dm_faces_sel__setDrawOptions, &data, 0); + dm->drawMappedFaces(dm, draw_dm_faces_sel__setDrawOptions, &data, 0, GPU_enable_material); } static int draw_dm_creases__setDrawOptions(void *userData, int index) @@ -2287,7 +2289,7 @@ static void draw_em_fancy(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object glEnable(GL_LIGHTING); glFrontFace((ob->transflag&OB_NEG_SCALE)?GL_CW:GL_CCW); - finalDM->drawMappedFaces(finalDM, draw_em_fancy__setFaceOpts, 0, 0); + finalDM->drawMappedFaces(finalDM, draw_em_fancy__setFaceOpts, 0, 0, GPU_enable_material); glFrontFace(GL_CCW); glDisable(GL_LIGHTING); @@ -2517,7 +2519,7 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D /* weight paint in solid mode, special case. focus on making the weights clear * rather then the shading, this is also forced in wire view */ GPU_enable_material(0, NULL); - dm->drawMappedFaces(dm, wpaint__setSolidDrawOptions, me->mface, 1); + dm->drawMappedFaces(dm, wpaint__setSolidDrawOptions, me->mface, 1, GPU_enable_material); bglPolygonOffset(rv3d->dist, 1.0); glDepthMask(0); // disable write in zbuffer, selected edge wires show better @@ -2599,7 +2601,7 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D glEnable(GL_LIGHTING); glEnable(GL_COLOR_MATERIAL); - dm->drawMappedFaces(dm, wpaint__setSolidDrawOptions, me->mface, 1); + dm->drawMappedFaces(dm, wpaint__setSolidDrawOptions, me->mface, 1, GPU_enable_material); glDisable(GL_COLOR_MATERIAL); glDisable(GL_LIGHTING); @@ -2607,10 +2609,10 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D } else if(ob->mode & (OB_MODE_VERTEX_PAINT|OB_MODE_TEXTURE_PAINT)) { if(me->mcol) - dm->drawMappedFaces(dm, wpaint__setSolidDrawOptions, NULL, 1); + dm->drawMappedFaces(dm, wpaint__setSolidDrawOptions, NULL, 1, GPU_enable_material); else { glColor3f(1.0f, 1.0f, 1.0f); - dm->drawMappedFaces(dm, wpaint__setSolidDrawOptions, NULL, 0); + dm->drawMappedFaces(dm, wpaint__setSolidDrawOptions, NULL, 0, GPU_enable_material); } } else do_draw= 1; @@ -6328,7 +6330,7 @@ static void bbs_mesh_solid_EM(Scene *scene, View3D *v3d, Object *ob, DerivedMesh cpack(0); if (facecol) { - dm->drawMappedFaces(dm, bbs_mesh_solid__setSolidDrawOptions, (void*)(intptr_t) 1, 0); + dm->drawMappedFaces(dm, bbs_mesh_solid__setSolidDrawOptions, (void*)(intptr_t) 1, 0, GPU_enable_material); if(check_ob_drawface_dot(scene, v3d, ob->dt)) { glPointSize(UI_GetThemeValuef(TH_FACEDOT_SIZE)); @@ -6339,7 +6341,7 @@ static void bbs_mesh_solid_EM(Scene *scene, View3D *v3d, Object *ob, DerivedMesh } } else { - dm->drawMappedFaces(dm, bbs_mesh_solid__setSolidDrawOptions, (void*) 0, 0); + dm->drawMappedFaces(dm, bbs_mesh_solid__setSolidDrawOptions, (void*) 0, 0, GPU_enable_material); } } @@ -6369,8 +6371,8 @@ static void bbs_mesh_solid(Scene *scene, View3D *v3d, Object *ob) glColor3ub(0, 0, 0); - if(face_sel_mode) dm->drawMappedFaces(dm, bbs_mesh_solid_hide__setDrawOpts, me, 0); - else dm->drawMappedFaces(dm, bbs_mesh_solid__setDrawOpts, me, 0); + if(face_sel_mode) dm->drawMappedFaces(dm, bbs_mesh_solid_hide__setDrawOpts, me, 0, GPU_enable_material); + else dm->drawMappedFaces(dm, bbs_mesh_solid__setDrawOpts, me, 0, GPU_enable_material); dm->release(dm); } @@ -6477,7 +6479,7 @@ static void draw_object_mesh_instance(Scene *scene, View3D *v3d, RegionView3D *r GPU_end_object_materials(); } else if(edm) - edm->drawMappedFaces(edm, NULL, NULL, 0); + edm->drawMappedFaces(edm, NULL, NULL, 0, GPU_enable_material); glDisable(GL_LIGHTING); } diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c index 06d93f01e02..9f1b55ee2ce 100644 --- a/source/blender/editors/space_view3d/view3d_edit.c +++ b/source/blender/editors/space_view3d/view3d_edit.c @@ -1274,7 +1274,7 @@ void VIEW3D_OT_zoom(wmOperatorType *ot) RNA_def_int(ot->srna, "my", 0, 0, INT_MAX, "Zoom Position Y", "", 0, INT_MAX); } -static int viewhome_exec(bContext *C, wmOperator *op) /* was view3d_home() in 2.4x */ +static int view3d_all_exec(bContext *C, wmOperator *op) /* was view3d_home() in 2.4x */ { ARegion *ar= CTX_wm_region(C); View3D *v3d = CTX_wm_view3d(C); @@ -1289,12 +1289,11 @@ static int viewhome_exec(bContext *C, wmOperator *op) /* was view3d_home() in 2. int ok= 1, onedone=0; if(center) { - min[0]= min[1]= min[2]= 0.0f; - max[0]= max[1]= max[2]= 0.0f; - /* in 2.4x this also move the cursor to (0, 0, 0) (with shift+c). */ curs= give_cursor(scene, v3d); - curs[0]= curs[1]= curs[2]= 0.0; + zero_v3(min); + zero_v3(max); + zero_v3(curs); } else { INIT_MINMAX(min, max); @@ -1318,9 +1317,7 @@ static int viewhome_exec(bContext *C, wmOperator *op) /* was view3d_home() in 2. return OPERATOR_FINISHED; } - afm[0]= (max[0]-min[0]); - afm[1]= (max[1]-min[1]); - afm[2]= (max[2]-min[2]); + sub_v3_v3v3(afm, max, min); size= 0.7f*MAX3(afm[0], afm[1], afm[2]); if(size==0.0) ok= 0; @@ -1342,7 +1339,7 @@ static int viewhome_exec(bContext *C, wmOperator *op) /* was view3d_home() in 2. if (rv3d->persp==RV3D_CAMOB) { rv3d->persp= RV3D_PERSP; - smooth_view(C, NULL, v3d->camera, new_ofs, NULL, &new_dist, NULL); + smooth_view(C, v3d->camera, NULL, new_ofs, NULL, &new_dist, NULL); } else { smooth_view(C, NULL, NULL, new_ofs, NULL, &new_dist, NULL); @@ -1358,17 +1355,6 @@ static int viewhome_exec(bContext *C, wmOperator *op) /* was view3d_home() in 2. return OPERATOR_FINISHED; } -static int viewhome_poll(bContext *C) -{ - if(ED_operator_view3d_active(C)) { - RegionView3D *rv3d= CTX_wm_region_view3d(C); //XXX, when accessed from a header menu this doesnt work! - if(rv3d && rv3d->persp!=RV3D_CAMOB) { - return 1; - } - } - - return 0; -} void VIEW3D_OT_view_all(wmOperatorType *ot) { @@ -1378,8 +1364,8 @@ void VIEW3D_OT_view_all(wmOperatorType *ot) ot->idname= "VIEW3D_OT_view_all"; /* api callbacks */ - ot->exec= viewhome_exec; - ot->poll= viewhome_poll; + ot->exec= view3d_all_exec; + ot->poll= ED_operator_view3d_active; /* flags */ ot->flag= 0; @@ -2135,14 +2121,11 @@ static int viewpan_exec(bContext *C, wmOperator *op) pandir = RNA_enum_get(op->ptr, "type"); initgrabz(rv3d, 0.0, 0.0, 0.0); - if(pandir == V3D_VIEW_PANRIGHT) window_to_3d_delta(ar, vec, -32, 0); else if(pandir == V3D_VIEW_PANLEFT) window_to_3d_delta(ar, vec, 32, 0); else if(pandir == V3D_VIEW_PANUP) window_to_3d_delta(ar, vec, 0, -25); else if(pandir == V3D_VIEW_PANDOWN) window_to_3d_delta(ar, vec, 0, 25); - rv3d->ofs[0]+= vec[0]; - rv3d->ofs[1]+= vec[1]; - rv3d->ofs[2]+= vec[2]; + add_v3_v3(rv3d->ofs, vec); if(rv3d->viewlock & RV3D_BOXVIEW) view3d_boxview_sync(CTX_wm_area(C), ar); diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c index d66144b2c30..860f9f461c4 100644 --- a/source/blender/editors/space_view3d/view3d_view.c +++ b/source/blender/editors/space_view3d/view3d_view.c @@ -205,7 +205,7 @@ void smooth_view(bContext *C, Object *oldcamera, Object *camera, float *ofs, flo if(quat) copy_qt_qt(sms.new_quat, quat); if(dist) sms.new_dist= *dist; if(lens) sms.new_lens= *lens; - + if (camera) { view3d_settings_from_ob(camera, sms.new_ofs, sms.new_quat, &sms.new_dist, &sms.new_lens); sms.to_camera= 1; /* restore view3d values in end */ @@ -214,15 +214,15 @@ void smooth_view(bContext *C, Object *oldcamera, Object *camera, float *ofs, flo if (C && U.smooth_viewtx) { int changed = 0; /* zero means no difference */ - if (sms.new_dist != rv3d->dist) + if (oldcamera != camera) changed = 1; - if (sms.new_lens != v3d->lens) + else if (sms.new_dist != rv3d->dist) changed = 1; - - if (!equals_v3v3(sms.new_ofs, rv3d->ofs)) + else if (sms.new_lens != v3d->lens) changed = 1; - - if (!equals_v4v4(sms.new_quat, rv3d->viewquat)) + else if (!equals_v3v3(sms.new_ofs, rv3d->ofs)) + changed = 1; + else if (!equals_v4v4(sms.new_quat, rv3d->viewquat)) changed = 1; /* The new view is different from the old one @@ -449,17 +449,21 @@ static int view3d_setobjectascamera_exec(bContext *C, wmOperator *op) View3D *v3d = CTX_wm_view3d(C); RegionView3D *rv3d= CTX_wm_region_view3d(C); Scene *scene= CTX_data_scene(C); - - if(BASACT) { + Object *ob = CTX_data_active_object(C); + + if(ob) { + Object *camera_old= (rv3d->persp == RV3D_CAMOB && scene->camera) ? scene->camera : NULL; rv3d->persp= RV3D_CAMOB; - v3d->camera= OBACT; + v3d->camera= ob; if(v3d->scenelock) - scene->camera= OBACT; - smooth_view(C, NULL, v3d->camera, rv3d->ofs, rv3d->viewquat, &rv3d->dist, &v3d->lens); + scene->camera= ob; + + if(camera_old != ob) /* unlikely but looks like a glitch when set to the same */ + smooth_view(C, camera_old, v3d->camera, rv3d->ofs, rv3d->viewquat, &rv3d->dist, &v3d->lens); + + WM_event_add_notifier(C, NC_SCENE|ND_RENDER_OPTIONS|NC_OBJECT|ND_DRAW, CTX_data_scene(C)); } - WM_event_add_notifier(C, NC_SCENE|ND_RENDER_OPTIONS|NC_OBJECT|ND_DRAW, CTX_data_scene(C)); - return OPERATOR_FINISHED; } diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index 215cbab8f1b..cc0916a8893 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -1531,7 +1531,7 @@ int initTransform(bContext *C, TransInfo *t, wmOperator *op, wmEvent *event, int if ((ELEM(kmi->type, LEFTCTRLKEY, RIGHTCTRLKEY) && event->ctrl) || (ELEM(kmi->type, LEFTSHIFTKEY, RIGHTSHIFTKEY) && event->shift) || (ELEM(kmi->type, LEFTALTKEY, RIGHTALTKEY) && event->alt) || - (kmi->type == COMMANDKEY && event->oskey)) { + (kmi->type == OSKEY && event->oskey)) { t->modifiers |= MOD_SNAP_INVERT; } break; diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c index 0187a3b3567..95e167053ec 100644 --- a/source/blender/editors/transform/transform_ops.c +++ b/source/blender/editors/transform/transform_ops.c @@ -445,9 +445,9 @@ void Transform_Properties(struct wmOperatorType *ot, int flags) } } - // Add confirm method all the time. At the end because it's not really that important and should be hidden + // Add confirm method all the time. At the end because it's not really that important and should be hidden only in log, not in keymap edit prop = RNA_def_boolean(ot->srna, "release_confirm", 0, "Confirm on Release", "Always confirm operation when releasing button"); - RNA_def_property_flag(prop, PROP_HIDDEN); + //RNA_def_property_flag(prop, PROP_HIDDEN); } void TRANSFORM_OT_translate(struct wmOperatorType *ot) diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c index 93331dd0ee3..09c04168a71 100644 --- a/source/blender/editors/transform/transform_snap.c +++ b/source/blender/editors/transform/transform_snap.c @@ -784,6 +784,10 @@ void CalcSnapGeometry(TransInfo *t, float *vec) if (dist != FLT_MAX) { VECCOPY(loc, p); + /* XXX, is there a correct normal in this case ???, for now just z up */ + no[0]= 0.0; + no[1]= 0.0; + no[2]= 1.0; found = 1; } @@ -1297,15 +1301,18 @@ int snapDerivedMesh(short snap_mode, ARegion *ar, Object *ob, DerivedMesh *dm, E BVHTreeRayHit hit; BVHTreeFromMesh treeData; + /* local scale in normal direction */ + float local_scale = len_v3(ray_normal_local); + bvhtree_from_mesh_faces(&treeData, dm, 0.0f, 4, 6); hit.index = -1; - hit.dist = *depth; + hit.dist = *depth * (*depth == FLT_MAX ? 1.0f : local_scale); if(treeData.tree && BLI_bvhtree_ray_cast(treeData.tree, ray_start_local, ray_normal_local, 0.0f, &hit, treeData.raycast_callback, &treeData) != -1) { - if(hit.dist<=*depth) { - *depth= hit.dist; + if(hit.dist/local_scale <= *depth) { + *depth= hit.dist/local_scale; copy_v3_v3(loc, hit.co); copy_v3_v3(no, hit.no); diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c index 565bad987e3..5c4564f1946 100644 --- a/source/blender/editors/uvedit/uvedit_ops.c +++ b/source/blender/editors/uvedit/uvedit_ops.c @@ -3239,6 +3239,7 @@ void ED_keymap_uvedit(wmKeyConfig *keyconf) /* menus */ WM_keymap_add_menu(keymap, "IMAGE_MT_uvs_snap", SKEY, KM_PRESS, KM_SHIFT, 0); + WM_keymap_add_menu(keymap, "IMAGE_MT_uvs_select_mode", TABKEY, KM_PRESS, KM_CTRL, 0); ED_object_generic_keymap(keyconf, keymap, 2); diff --git a/source/blender/gpu/intern/gpu_draw.c b/source/blender/gpu/intern/gpu_draw.c index e8701793e5d..55522ea18b9 100644 --- a/source/blender/gpu/intern/gpu_draw.c +++ b/source/blender/gpu/intern/gpu_draw.c @@ -911,10 +911,10 @@ static void gpu_material_to_fixed(GPUMaterialFixed *smat, const Material *bmat, } } else { - madd_v3_v3fl(smat->diff, &bmat->r, bmat->ref + bmat->emit); + mul_v3_v3fl(smat->diff, &bmat->r, bmat->ref + bmat->emit); smat->diff[3]= 1.0; /* caller may set this to bmat->alpha */ - madd_v3_v3fl(smat->spec, &bmat->specr, bmat->spec); + mul_v3_v3fl(smat->spec, &bmat->specr, bmat->spec); smat->spec[3]= 1.0; /* always 1 */ smat->hard= CLAMPIS(bmat->har, 0, 128); @@ -1043,10 +1043,10 @@ int GPU_enable_material(int nr, void *attribs) memset(&GMS, 0, sizeof(GMS)); - madd_v3_v3fl(diff, &defmaterial.r, defmaterial.ref + defmaterial.emit); + mul_v3_v3fl(diff, &defmaterial.r, defmaterial.ref + defmaterial.emit); diff[3]= 1.0; - madd_v3_v3fl(spec, &defmaterial.specr, defmaterial.spec); + mul_v3_v3fl(spec, &defmaterial.specr, defmaterial.spec); spec[3]= 1.0; glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, diff); @@ -1286,7 +1286,7 @@ int GPU_scene_object_lights(Scene *scene, Object *ob, int lay, float viewmat[][4 } /* setup energy */ - madd_v3_v3fl(energy, &la->r, la->energy); + mul_v3_v3fl(energy, &la->r, la->energy); energy[3]= 1.0; glLightfv(GL_LIGHT0+count, GL_DIFFUSE, energy); diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c index 5f8015be52f..a31ec950711 100644 --- a/source/blender/gpu/intern/gpu_material.c +++ b/source/blender/gpu/intern/gpu_material.c @@ -605,7 +605,7 @@ static void shade_one_light(GPUShadeInput *shi, GPUShadeResult *shr, GPULamp *la Material *ma= shi->mat; GPUMaterial *mat= shi->gpumat; GPUNodeLink *lv, *dist, *visifac, *is, *inp, *i, *vn, *view; - GPUNodeLink *outcol, *specfac, *t, *shadfac; + GPUNodeLink *outcol, *specfac, *t, *shadfac= NULL; float one = 1.0f; if((lamp->mode & LA_ONLYSHADOW) && !(ma->mode & MA_SHADOW)) diff --git a/source/blender/imbuf/intern/thumbs_blend.c b/source/blender/imbuf/intern/thumbs_blend.c index 2fef230f1c2..f1f8383b85e 100644 --- a/source/blender/imbuf/intern/thumbs_blend.c +++ b/source/blender/imbuf/intern/thumbs_blend.c @@ -161,11 +161,11 @@ void IMB_overlayblend_thumb(unsigned int *thumb, int width, int height, float as { int x, y; - int hline, vline; int stride_x= (margin_r - margin_l) - 2; for(y=0; y < height; y++) { for(x=0; x < width; x++, px+=4) { + int hline= 0, vline= 0; if((x > margin_l && x < margin_r) && (y > margin_b && y < margin_t)) { /* interior. skip */ x += stride_x; diff --git a/source/blender/makesdna/DNA_customdata_types.h b/source/blender/makesdna/DNA_customdata_types.h index 8908143946a..6c0b4db221d 100644 --- a/source/blender/makesdna/DNA_customdata_types.h +++ b/source/blender/makesdna/DNA_customdata_types.h @@ -30,6 +30,10 @@ #ifndef DNA_CUSTOMDATA_TYPES_H #define DNA_CUSTOMDATA_TYPES_H +#ifdef __cplusplus +extern "C" { +#endif + /* descriptor and storage for a custom data layer */ typedef struct CustomDataLayer { int type; /* type of data in layer */ @@ -128,4 +132,8 @@ typedef struct CustomData { #define MAX_MTFACE 8 #define MAX_MCOL 8 +#ifdef __cplusplus +} +#endif + #endif diff --git a/source/blender/makesdna/DNA_texture_types.h b/source/blender/makesdna/DNA_texture_types.h index e9e058cbbd6..19aacaa8108 100644 --- a/source/blender/makesdna/DNA_texture_types.h +++ b/source/blender/makesdna/DNA_texture_types.h @@ -34,6 +34,10 @@ #include "DNA_ID.h" #include "DNA_image_types.h" /* ImageUser */ +#ifdef __cplusplus +extern "C" { +#endif + struct AnimData; struct Ipo; struct PluginTex; @@ -554,5 +558,9 @@ typedef struct TexMapping { #define TEX_VD_SMOKEHEAT 1 #define TEX_VD_SMOKEVEL 2 +#ifdef __cplusplus +} +#endif + #endif diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h index 52e82eb743d..4e3a957d775 100644 --- a/source/blender/makesdna/DNA_userdef_types.h +++ b/source/blender/makesdna/DNA_userdef_types.h @@ -35,6 +35,10 @@ #include "DNA_listBase.h" #include "DNA_texture_types.h" /* ColorBand */ +#ifdef __cplusplus +extern "C" { +#endif + /* themes; defines in BIF_resource.h */ struct ColorBand; @@ -558,4 +562,8 @@ extern UserDef U; /* from blenkernel blender.c */ #define TH_OLDSKOOL 3 #define TH_SHADED 4 +#ifdef __cplusplus +} +#endif + #endif diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h index a7dbec72273..58e4101421f 100644 --- a/source/blender/makesrna/RNA_access.h +++ b/source/blender/makesrna/RNA_access.h @@ -851,7 +851,11 @@ char *RNA_string_get_alloc(PointerRNA *ptr, const char *name, char *fixedbuf, in int RNA_string_length(PointerRNA *ptr, const char *name); void RNA_string_set(PointerRNA *ptr, const char *name, const char *value); +/** + * Retrieve the named property from PointerRNA. + */ PointerRNA RNA_pointer_get(PointerRNA *ptr, const char *name); +/* Set the property name of PointerRNA ptr to ptr_value */ void RNA_pointer_set(PointerRNA *ptr, const char *name, PointerRNA ptr_value); void RNA_pointer_add(PointerRNA *ptr, const char *name); diff --git a/source/blender/makesrna/intern/rna_curve.c b/source/blender/makesrna/intern/rna_curve.c index 37be1d89d30..7983b8f8a7f 100644 --- a/source/blender/makesrna/intern/rna_curve.c +++ b/source/blender/makesrna/intern/rna_curve.c @@ -399,12 +399,24 @@ void rna_Curve_body_set(PointerRNA *ptr, const char *value) BLI_strncpy(cu->str, value, len+1); } -static void rna_Nurb_update_handle_data(Main *bmain, Scene *scene, PointerRNA *ptr) +static void rna_Nurb_update_cyclic_u(Main *bmain, Scene *scene, PointerRNA *ptr) { Nurb *nu= (Nurb*)ptr->data; - if(nu->type == CU_BEZIER) + if(nu->type == CU_BEZIER) { calchandlesNurb(nu); + } else { + nurbs_knot_calc_u(nu); + } + + rna_Curve_update_data(bmain, scene, ptr); +} + +static void rna_Nurb_update_cyclic_v(Main *bmain, Scene *scene, PointerRNA *ptr) +{ + Nurb *nu= (Nurb*)ptr->data; + + nurbs_knot_calc_v(nu); rna_Curve_update_data(bmain, scene, ptr); } @@ -1356,12 +1368,12 @@ static void rna_def_curve_nurb(BlenderRNA *brna) prop= RNA_def_property(srna, "use_cyclic_u", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flagu", CU_NURB_CYCLIC); RNA_def_property_ui_text(prop, "Cyclic U", "Make this curve or surface a closed loop in the U direction"); - RNA_def_property_update(prop, 0, "rna_Nurb_update_handle_data"); /* only needed for cyclic_u because cyclic_v cant do bezier */ + RNA_def_property_update(prop, 0, "rna_Nurb_update_cyclic_u"); prop= RNA_def_property(srna, "use_cyclic_v", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flagv", CU_NURB_CYCLIC); RNA_def_property_ui_text(prop, "Cyclic V", "Make this surface a closed loop in the V direction"); - RNA_def_property_update(prop, 0, "rna_Curve_update_data"); + RNA_def_property_update(prop, 0, "rna_Nurb_update_cyclic_v"); /* Note, endpoint and bezier flags should never be on at the same time! */ diff --git a/source/blender/makesrna/intern/rna_mesh.c b/source/blender/makesrna/intern/rna_mesh.c index db5a2062359..dc3cb675f7a 100644 --- a/source/blender/makesrna/intern/rna_mesh.c +++ b/source/blender/makesrna/intern/rna_mesh.c @@ -955,7 +955,7 @@ static char *rna_VertexGroupElement_path(PointerRNA *ptr) for(a=0, dvert=me->dvert; a<me->totvert; a++, dvert++) for(b=0; b<dvert->totweight; b++) if(dw == &dvert->dw[b]) - return BLI_sprintfN("verts[%d].groups[%d]", a, b); + return BLI_sprintfN("vertices[%d].groups[%d]", a, b); return NULL; } @@ -972,7 +972,7 @@ static char *rna_MeshEdge_path(PointerRNA *ptr) static char *rna_MeshVertex_path(PointerRNA *ptr) { - return BLI_sprintfN("verts[%d]", (MVert*)ptr->data - ((Mesh*)ptr->id.data)->mvert); + return BLI_sprintfN("vertices[%d]", (MVert*)ptr->data - ((Mesh*)ptr->id.data)->mvert); } static char *rna_MeshTextureFaceLayer_path(PointerRNA *ptr) diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c index 3f07d953e0b..e74bec566d5 100644 --- a/source/blender/makesrna/intern/rna_object.c +++ b/source/blender/makesrna/intern/rna_object.c @@ -769,6 +769,12 @@ static void rna_MaterialSlot_name_get(PointerRNA *ptr, char *str) strcpy(str, ""); } +static void rna_MaterialSlot_update(Main *bmain, Scene *scene, PointerRNA *ptr) +{ + rna_Object_internal_update(bmain, scene, ptr); + WM_main_add_notifier(NC_OBJECT|ND_OB_SHADING, ptr->id.data); +} + /* why does this have to be so complicated?, can't all this crap be * moved to in BGE conversion function? - Campbell * * @@ -1143,13 +1149,13 @@ static void rna_def_material_slot(BlenderRNA *brna) RNA_def_property_flag(prop, PROP_EDITABLE); RNA_def_property_pointer_funcs(prop, "rna_MaterialSlot_material_get", "rna_MaterialSlot_material_set", NULL, NULL); RNA_def_property_ui_text(prop, "Material", "Material datablock used by this material slot"); - RNA_def_property_update(prop, NC_OBJECT|ND_DRAW, "rna_Object_internal_update"); + RNA_def_property_update(prop, NC_OBJECT|ND_DRAW, "rna_MaterialSlot_update"); prop= RNA_def_property(srna, "link", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, link_items); RNA_def_property_enum_funcs(prop, "rna_MaterialSlot_link_get", "rna_MaterialSlot_link_set", NULL); RNA_def_property_ui_text(prop, "Link", "Link material to object or the object's data"); - RNA_def_property_update(prop, NC_OBJECT|ND_DRAW, "rna_Object_internal_update"); + RNA_def_property_update(prop, NC_OBJECT|ND_DRAW, "rna_MaterialSlot_update"); prop= RNA_def_property(srna, "name", PROP_STRING, PROP_NONE); RNA_def_property_string_funcs(prop, "rna_MaterialSlot_name_get", "rna_MaterialSlot_name_length", NULL); @@ -1739,14 +1745,14 @@ static void rna_def_object(BlenderRNA *brna) RNA_def_property_pointer_funcs(prop, "rna_Object_active_material_get", "rna_Object_active_material_set", NULL, NULL); RNA_def_property_flag(prop, PROP_EDITABLE); RNA_def_property_ui_text(prop, "Active Material", "Active material being displayed"); - RNA_def_property_update(prop, NC_OBJECT|ND_DRAW, "rna_Object_internal_update"); + RNA_def_property_update(prop, NC_OBJECT|ND_DRAW, "rna_MaterialSlot_update"); prop= RNA_def_property(srna, "active_material_index", PROP_INT, PROP_UNSIGNED); RNA_def_property_int_sdna(prop, NULL, "actcol"); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_int_funcs(prop, "rna_Object_active_material_index_get", "rna_Object_active_material_index_set", "rna_Object_active_material_index_range"); RNA_def_property_ui_text(prop, "Active Material Index", "Index of active material slot"); - RNA_def_property_update(prop, NC_OBJECT|ND_DRAW, NULL); + RNA_def_property_update(prop, NC_MATERIAL|ND_SHADING, NULL); /* transform */ prop= RNA_def_property(srna, "location", PROP_FLOAT, PROP_TRANSLATION); diff --git a/source/blender/makesrna/intern/rna_particle.c b/source/blender/makesrna/intern/rna_particle.c index 1151215f5f7..7a8165e9aa5 100644 --- a/source/blender/makesrna/intern/rna_particle.c +++ b/source/blender/makesrna/intern/rna_particle.c @@ -325,15 +325,21 @@ static PointerRNA rna_particle_settings_get(PointerRNA *ptr) static void rna_particle_settings_set(PointerRNA *ptr, PointerRNA value) { ParticleSystem *psys= (ParticleSystem*)ptr->data; + int old_type = 0; - if(psys->part) + + if(psys->part) { + old_type = psys->part->type; psys->part->id.us--; + } psys->part = (ParticleSettings *)value.data; if(psys->part) { psys->part->id.us++; psys_check_boid_data(psys); + if(old_type != psys->part->type) + psys->recalc |= PSYS_RECALC_TYPE; } } static void rna_Particle_abspathtime_update(Main *bmain, Scene *scene, PointerRNA *ptr) diff --git a/source/blender/makesrna/intern/rna_screen.c b/source/blender/makesrna/intern/rna_screen.c index 93b38499673..d6964f5d569 100644 --- a/source/blender/makesrna/intern/rna_screen.c +++ b/source/blender/makesrna/intern/rna_screen.c @@ -44,10 +44,10 @@ EnumPropertyItem region_type_items[] = { {RGN_TYPE_PREVIEW, "PREVIEW", 0, "Preview", ""}, {0, NULL, 0, NULL, NULL}}; -#ifdef RNA_RUNTIME - #include "ED_screen.h" +#ifdef RNA_RUNTIME + #include "WM_api.h" #include "WM_types.h" diff --git a/source/blender/makesrna/intern/rna_sequencer.c b/source/blender/makesrna/intern/rna_sequencer.c index b6a09b9c217..c004f32f586 100644 --- a/source/blender/makesrna/intern/rna_sequencer.c +++ b/source/blender/makesrna/intern/rna_sequencer.c @@ -677,13 +677,13 @@ static void rna_def_strip_crop(BlenderRNA *brna) RNA_def_property_ui_range(prop, 0, 4096, 1, 0); RNA_def_property_update(prop, NC_SCENE|ND_SEQUENCER, "rna_Sequence_update"); - prop= RNA_def_property(srna, "min_x", PROP_INT, PROP_UNSIGNED); + prop= RNA_def_property(srna, "min_y", PROP_INT, PROP_UNSIGNED); RNA_def_property_int_sdna(prop, NULL, "bottom"); RNA_def_property_ui_text(prop, "Bottom", ""); RNA_def_property_ui_range(prop, 0, 4096, 1, 0); RNA_def_property_update(prop, NC_SCENE|ND_SEQUENCER, "rna_Sequence_update"); - prop= RNA_def_property(srna, "min_y", PROP_INT, PROP_UNSIGNED); + prop= RNA_def_property(srna, "min_x", PROP_INT, PROP_UNSIGNED); RNA_def_property_int_sdna(prop, NULL, "left"); RNA_def_property_ui_text(prop, "Left", ""); RNA_def_property_ui_range(prop, 0, 4096, 1, 0); diff --git a/source/blender/makesrna/intern/rna_wm.c b/source/blender/makesrna/intern/rna_wm.c index 62d0c99f6c5..7e54a3b14fa 100644 --- a/source/blender/makesrna/intern/rna_wm.c +++ b/source/blender/makesrna/intern/rna_wm.c @@ -175,7 +175,7 @@ EnumPropertyItem event_type_items[] = { {RIGHTCTRLKEY, "RIGHT_CTRL", 0, "Right Ctrl", ""}, {RIGHTSHIFTKEY, "RIGHT_SHIFT", 0, "Right Shift", ""}, {0, "", 0, NULL, NULL}, - {COMMANDKEY, "COMMAND", 0, "Command", ""}, + {OSKEY, "OSKEY", 0, "OS Key", ""}, {0, "", 0, NULL, NULL}, {ESCKEY, "ESC", 0, "Esc", ""}, {TABKEY, "TAB", 0, "Tab", ""}, diff --git a/source/blender/python/generic/IDProp.c b/source/blender/python/generic/IDProp.c index 2a07ab3bc90..9d865b1c63e 100644 --- a/source/blender/python/generic/IDProp.c +++ b/source/blender/python/generic/IDProp.c @@ -34,7 +34,7 @@ #endif PyObject * PyC_UnicodeFromByte(const char *str); -const char * PuC_UnicodeAsByte(PyObject *py_str, PyObject **coerce); /* coerce must be NULL */ +const char * PyC_UnicodeAsByte(PyObject *py_str, PyObject **coerce); /* coerce must be NULL */ /*** Function to wrap ID properties ***/ PyObject *BPy_Wrap_IDProperty(ID *id, IDProperty *prop, IDProperty *parent); @@ -123,7 +123,7 @@ int BPy_IDGroup_SetData(BPy_IDProperty *self, IDProperty *prop, PyObject *value) int alloc_len; PyObject *value_coerce= NULL; - st= (char *)PuC_UnicodeAsByte(value, &value_coerce); + st= (char *)PyC_UnicodeAsByte(value, &value_coerce); alloc_len= strlen(st) + 1; st = _PyUnicode_AsString(value); @@ -311,7 +311,7 @@ char *BPy_IDProperty_Map_ValidateAndCreate(char *name, IDProperty *group, PyObje } else if (PyUnicode_Check(ob)) { #ifdef USE_STRING_COERCE PyObject *value_coerce= NULL; - val.str = (char *)PuC_UnicodeAsByte(ob, &value_coerce); + val.str = (char *)PyC_UnicodeAsByte(ob, &value_coerce); prop = IDP_New(IDP_STRING, val, name); Py_XDECREF(value_coerce); #else diff --git a/source/blender/python/generic/bpy_internal_import.c b/source/blender/python/generic/bpy_internal_import.c index 11f8ff49ffe..394c388394a 100644 --- a/source/blender/python/generic/bpy_internal_import.c +++ b/source/blender/python/generic/bpy_internal_import.c @@ -281,8 +281,8 @@ static PyObject *blender_reload( PyObject * self, PyObject * module ) return newmodule; } -PyMethodDef bpy_import_meth[] = { {"bpy_import_meth", (PyCFunction)blender_import, METH_VARARGS | METH_KEYWORDS, "blenders import"} }; -PyMethodDef bpy_reload_meth[] = { {"bpy_reload_meth", (PyCFunction)blender_reload, METH_O, "blenders reload"} }; +PyMethodDef bpy_import_meth = {"bpy_import_meth", (PyCFunction)blender_import, METH_VARARGS | METH_KEYWORDS, "blenders import"}; +PyMethodDef bpy_reload_meth = {"bpy_reload_meth", (PyCFunction)blender_reload, METH_O, "blenders reload"}; /* Clear user modules. diff --git a/source/blender/python/generic/bpy_internal_import.h b/source/blender/python/generic/bpy_internal_import.h index 09e1fa629d3..f191ab22651 100644 --- a/source/blender/python/generic/bpy_internal_import.h +++ b/source/blender/python/generic/bpy_internal_import.h @@ -53,8 +53,8 @@ PyObject* bpy_text_reimport( PyObject *module, int *found ); void bpy_text_filename_get(char *fn, struct Text *text); -extern PyMethodDef bpy_import_meth[]; -extern PyMethodDef bpy_reload_meth[]; +extern PyMethodDef bpy_import_meth; +extern PyMethodDef bpy_reload_meth; /* The game engine has its own Main struct, if this is set search this rather then G.main */ struct Main *bpy_import_main_get(void); diff --git a/source/blender/python/generic/py_capi_utils.c b/source/blender/python/generic/py_capi_utils.c index d59624b54ab..6544523079d 100644 --- a/source/blender/python/generic/py_capi_utils.c +++ b/source/blender/python/generic/py_capi_utils.c @@ -217,7 +217,7 @@ error_cleanup: /* string conversion, escape non-unicode chars, coerce must be set to NULL */ -const char *PuC_UnicodeAsByte(PyObject *py_str, PyObject **coerce) +const char *PyC_UnicodeAsByte(PyObject *py_str, PyObject **coerce) { char *result; diff --git a/source/blender/python/generic/py_capi_utils.h b/source/blender/python/generic/py_capi_utils.h index b378f7a5a34..0544697ab68 100644 --- a/source/blender/python/generic/py_capi_utils.h +++ b/source/blender/python/generic/py_capi_utils.h @@ -34,7 +34,7 @@ int PyC_AsArray(void *array, PyObject *value, int length, PyTypeObject *type, /* follow http://www.python.org/dev/peps/pep-0383/ */ PyObject * PyC_UnicodeFromByte(const char *str); -const char * PuC_UnicodeAsByte(PyObject *py_str, PyObject **coerce); /* coerce must be NULL */ +const char * PyC_UnicodeAsByte(PyObject *py_str, PyObject **coerce); /* coerce must be NULL */ /* name namespace function for bpy & bge */ PyObject * PyC_DefaultNameSpace(const char *filename); diff --git a/source/blender/python/intern/bpy.c b/source/blender/python/intern/bpy.c index a95f56e800c..ffb949f9296 100644 --- a/source/blender/python/intern/bpy.c +++ b/source/blender/python/intern/bpy.c @@ -114,8 +114,52 @@ static PyObject *bpy_blend_paths(PyObject * self, PyObject *args, PyObject *kw) return list; } -static PyMethodDef meth_bpy_script_paths[] = {{ "script_paths", (PyCFunction)bpy_script_paths, METH_NOARGS, bpy_script_paths_doc}}; -static PyMethodDef meth_bpy_blend_paths[] = {{ "blend_paths", (PyCFunction)bpy_blend_paths, METH_VARARGS|METH_KEYWORDS, bpy_blend_paths_doc}}; + +static char bpy_user_resource_doc[] = +".. function:: user_resource(type, subdir)\n" +"\n" +" Returns a list of paths to external files referenced by the loaded .blend file.\n" +"\n" +" :arg type: Resource type in ['DATAFILES', 'CONFIG', 'SCRIPTS', 'AUTOSAVE'].\n" +" :type type: string\n" +" :arg subdir: Optional subdirectory.\n" +" :type subdir: string\n" +" :return: a path.\n" +" :rtype: string\n"; +static PyObject *bpy_user_resource(PyObject * self, PyObject *args, PyObject *kw) +{ + char *type; + char *subdir= NULL; + int folder_id; + static char *kwlist[] = {"type", "subdir", NULL}; + + char *path; + + if (!PyArg_ParseTupleAndKeywords(args, kw, "s|s:user_resource", kwlist, &type, &subdir)) + return NULL; + + /* stupid string compare */ + if (!strcmp(type, "DATAFILES")) folder_id= BLENDER_USER_DATAFILES; + else if(!strcmp(type, "CONFIG")) folder_id= BLENDER_USER_CONFIG; + else if(!strcmp(type, "SCRIPTS")) folder_id= BLENDER_USER_SCRIPTS; + else if(!strcmp(type, "AUTOSAVE")) folder_id= BLENDER_USER_AUTOSAVE; + else { + PyErr_SetString(PyExc_ValueError, "invalid resource argument"); + return NULL; + } + + /* same logic as BLI_get_folder_create(), but best leave it up to the script author to create */ + path= BLI_get_folder(folder_id, subdir); + + if (!path) + path = BLI_get_user_folder_notest(folder_id, subdir); + + return PyUnicode_FromString(path ? path : ""); +} + +static PyMethodDef meth_bpy_script_paths = {"script_paths", (PyCFunction)bpy_script_paths, METH_NOARGS, bpy_script_paths_doc}; +static PyMethodDef meth_bpy_blend_paths = {"blend_paths", (PyCFunction)bpy_blend_paths, METH_VARARGS|METH_KEYWORDS, bpy_blend_paths_doc}; +static PyMethodDef meth_bpy_user_resource = {"user_resource", (PyCFunction)bpy_user_resource, METH_VARARGS|METH_KEYWORDS, bpy_user_resource_doc}; static void bpy_import_test(char *modname) { @@ -189,8 +233,9 @@ void BPy_init_modules( void ) PyModule_AddObject(mod, "context", (PyObject *)bpy_context_module); /* utility func's that have nowhere else to go */ - PyModule_AddObject(mod, meth_bpy_script_paths->ml_name, (PyObject *)PyCFunction_New(meth_bpy_script_paths, NULL)); - PyModule_AddObject(mod, meth_bpy_blend_paths->ml_name, (PyObject *)PyCFunction_New(meth_bpy_blend_paths, NULL)); + PyModule_AddObject(mod, meth_bpy_script_paths.ml_name, (PyObject *)PyCFunction_New(&meth_bpy_script_paths, NULL)); + PyModule_AddObject(mod, meth_bpy_blend_paths.ml_name, (PyObject *)PyCFunction_New(&meth_bpy_blend_paths, NULL)); + PyModule_AddObject(mod, meth_bpy_user_resource.ml_name, (PyObject *)PyCFunction_New(&meth_bpy_user_resource, NULL)); /* add our own modules dir, this is a python package */ bpy_import_test("bpy"); diff --git a/source/blender/python/intern/bpy_interface.c b/source/blender/python/intern/bpy_interface.c index 6aaac3cd0e8..bc79ba94756 100644 --- a/source/blender/python/intern/bpy_interface.c +++ b/source/blender/python/intern/bpy_interface.c @@ -213,25 +213,10 @@ void BPY_start_python( int argc, char **argv ) /* sigh, why do python guys not have a char** version anymore? :( */ { int i; -#if 0 PyObject *py_argv= PyList_New(argc); for (i=0; i<argc; i++) - PyList_SET_ITEM(py_argv, i, PyUnicode_FromString(argv[i])); - -#else // should fix bug #20021 - utf path name problems - PyObject *py_argv= PyList_New(0); - for (i=0; i<argc; i++) { - PyObject *item= PyUnicode_Decode(argv[i], strlen(argv[i]), Py_FileSystemDefaultEncoding, NULL); - if(item==NULL) { // should never happen - PyErr_Print(); - PyErr_Clear(); - } - else { - PyList_Append(py_argv, item); - Py_DECREF(item); - } - } -#endif + PyList_SET_ITEM(py_argv, i, PyC_UnicodeFromByte(argv[i])); /* should fix bug #20021 - utf path name problems, by replacing PyUnicode_FromString */ + PySys_SetObject("argv", py_argv); Py_DECREF(py_argv); } @@ -248,8 +233,8 @@ void BPY_start_python( int argc, char **argv ) //PyObject *m = PyImport_AddModule("__builtin__"); //PyObject *d = PyModule_GetDict(m); PyObject *d = PyEval_GetBuiltins( ); - PyDict_SetItemString(d, "reload", item=PyCFunction_New(bpy_reload_meth, NULL)); Py_DECREF(item); - PyDict_SetItemString(d, "__import__", item=PyCFunction_New(bpy_import_meth, NULL)); Py_DECREF(item); + PyDict_SetItemString(d, "reload", item=PyCFunction_New(&bpy_reload_meth, NULL)); Py_DECREF(item); + PyDict_SetItemString(d, "__import__", item=PyCFunction_New(&bpy_import_meth, NULL)); Py_DECREF(item); } pyrna_alloc_types(); diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c index 238201c7cf0..166213fa07c 100644 --- a/source/blender/python/intern/bpy_rna.c +++ b/source/blender/python/intern/bpy_rna.c @@ -1012,7 +1012,7 @@ static int pyrna_py_to_prop(PointerRNA *ptr, PropertyRNA *prop, ParameterList *p PyObject *value_coerce= NULL; int subtype= RNA_property_subtype(prop); if(ELEM3(subtype, PROP_FILEPATH, PROP_DIRPATH, PROP_FILENAME)) { - param= PuC_UnicodeAsByte(value, &value_coerce); + param= PyC_UnicodeAsByte(value, &value_coerce); } else { param= _PyUnicode_AsString(value); @@ -3459,10 +3459,9 @@ PyObject *pyrna_param_to_py(PointerRNA *ptr, ParameterList *parms, PropertyRNA * PyObject *ret; int type = RNA_property_type(prop); int flag = RNA_property_flag(prop); - int a; if(RNA_property_array_check(ptr, prop)) { - int len; + int a, len; if (flag & PROP_DYNAMIC) { ParameterDynAlloc *data_alloc= data; diff --git a/source/blender/render/intern/source/convertblender.c b/source/blender/render/intern/source/convertblender.c index 01dafd2ce4a..e741c622380 100644 --- a/source/blender/render/intern/source/convertblender.c +++ b/source/blender/render/intern/source/convertblender.c @@ -2341,7 +2341,7 @@ static void init_render_mball(Render *re, ObjectRen *obr) VertRen *ver; VlakRen *vlr, *vlr1; Material *ma; - float *data, *nors, *orco, mat[4][4], imat[3][3], xn, yn, zn; + float *data, *nors, *orco=NULL, mat[4][4], imat[3][3], xn, yn, zn; int a, need_orco, vlakindex, *index; ListBase dispbase= {NULL, NULL}; @@ -2375,7 +2375,7 @@ static void init_render_mball(Render *re, ObjectRen *obr) } } - for(a=0; a<dl->nr; a++, data+=3, nors+=3, orco+=3) { + for(a=0; a<dl->nr; a++, data+=3, nors+=3) { ver= RE_findOrAddVert(obr, obr->totvert++); VECCOPY(ver->co, data); @@ -2393,7 +2393,7 @@ static void init_render_mball(Render *re, ObjectRen *obr) normalize_v3(ver->n); //if(ob->transflag & OB_NEG_SCALE) negate_v3(ver->n); - if(need_orco) ver->orco= orco; + if(need_orco) ver->orco= orco+=3; } index= dl->index; diff --git a/source/blender/render/intern/source/rayshade.c b/source/blender/render/intern/source/rayshade.c index 724fd9a3110..1172bee7d67 100644 --- a/source/blender/render/intern/source/rayshade.c +++ b/source/blender/render/intern/source/rayshade.c @@ -697,17 +697,9 @@ static void ray_fadeout(Isect *is, ShadeInput *shi, float *col, float *blendcol, * note: 'col' must be initialized */ static void traceray(ShadeInput *origshi, ShadeResult *origshr, short depth, float *start, float *vec, float *col, ObjectInstanceRen *obi, VlakRen *vlr, int traflag) { - ShadeInput shi; - ShadeResult shr; + ShadeInput shi= {0}; Isect isec; - float f, f1, fr, fg, fb; - float ref[3]; float dist_mir = origshi->mat->dist_mir; - - /* Warning, This is not that nice, and possibly a bit slow for every ray, - however some variables were not initialized properly in, unless using shade_input_initialize(...), we need to do a memset */ - memset(&shi, 0, sizeof(ShadeInput)); - /* end warning! - Campbell */ VECCOPY(isec.start, start); VECCOPY(isec.vec, vec ); @@ -721,8 +713,9 @@ static void traceray(ShadeInput *origshi, ShadeResult *origshr, short depth, flo RE_RC_INIT(isec, shi); if(RE_rayobject_raycast(R.raytree, &isec)) { + ShadeResult shr= {{0}}; float d= 1.0f; - + shi.mask= origshi->mask; shi.osatex= origshi->osatex; shi.depth= 1; /* only used to indicate tracing */ @@ -737,16 +730,15 @@ static void traceray(ShadeInput *origshi, ShadeResult *origshr, short depth, flo shi.light_override= origshi->light_override; shi.mat_override= origshi->mat_override; - memset(&shr, 0, sizeof(ShadeResult)); - shade_ray(&isec, &shi, &shr); if (traflag & RAY_TRA) d= shade_by_transmission(&isec, &shi, &shr); if(depth>0) { + float fr, fg, fb, f, f1; if((shi.mat->mode_l & MA_TRANSP) && shr.alpha < 1.0f) { - float nf, f, f1, refract[3], tracol[4]; + float nf, f, refract[3], tracol[4]; tracol[0]= shi.r; tracol[1]= shi.g; @@ -799,6 +791,7 @@ static void traceray(ShadeInput *origshi, ShadeResult *origshr, short depth, flo if(f!=0.0f) { float mircol[4]; + float ref[3]; reflection(ref, shi.vn, shi.view, NULL); traceray(origshi, origshr, depth-1, shi.co, ref, mircol, shi.obi, shi.vlr, 0); diff --git a/source/blender/render/intern/source/volumetric.c b/source/blender/render/intern/source/volumetric.c index a58d96736d5..d15ea0c792c 100644 --- a/source/blender/render/intern/source/volumetric.c +++ b/source/blender/render/intern/source/volumetric.c @@ -743,7 +743,6 @@ void shade_volume_shadow(struct ShadeInput *shi, struct ShadeResult *shr, struct float tr[3] = {1.0,1.0,1.0}; Isect is; float *startco, *endco; - float density=0.f; memset(shr, 0, sizeof(ShadeResult)); @@ -764,8 +763,7 @@ void shade_volume_shadow(struct ShadeInput *shi, struct ShadeResult *shr, struct shr->alpha = shr->combined[3] = 1.f; return; } - - density = vol_get_density(shi, startco); + vol_get_transmittance(shi, tr, startco, endco); copy_v3_v3(shr->combined, tr); diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h index 690d8ad0f75..f103cbe2d4e 100644 --- a/source/blender/windowmanager/WM_api.h +++ b/source/blender/windowmanager/WM_api.h @@ -31,6 +31,10 @@ /* dna-savable wmStructs here */ #include "DNA_windowmanager_types.h" +#ifdef __cplusplus +extern "C" { +#endif + struct bContext; struct IDProperty; struct wmEvent; @@ -338,5 +342,9 @@ void WM_clipboard_text_set(char *buf, int selection); void WM_progress_set(struct wmWindow *win, float progress); void WM_progress_clear(struct wmWindow *win); +#ifdef __cplusplus +} +#endif + #endif /* WM_API_H */ diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h index 73f1fe8cbd3..0447524255f 100644 --- a/source/blender/windowmanager/WM_types.h +++ b/source/blender/windowmanager/WM_types.h @@ -28,6 +28,10 @@ #ifndef WM_TYPES_H #define WM_TYPES_H +#ifdef __cplusplus +extern "C" { +#endif + struct bContext; struct wmEvent; struct wmWindowManager; @@ -511,5 +515,9 @@ typedef struct RecentFile { } RecentFile; +#ifdef __cplusplus +} +#endif + #endif /* WM_TYPES_H */ diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index 590d28012f9..334bc79b96a 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -2067,7 +2067,7 @@ static int convert_key(GHOST_TKey key) case GHOST_kKeyRightShift: return RIGHTSHIFTKEY; case GHOST_kKeyLeftControl: return LEFTCTRLKEY; case GHOST_kKeyRightControl: return RIGHTCTRLKEY; - case GHOST_kKeyCommand: return COMMANDKEY; + case GHOST_kKeyOS: return OSKEY; case GHOST_kKeyLeftAlt: return LEFTALTKEY; case GHOST_kKeyRightAlt: return RIGHTALTKEY; @@ -2324,7 +2324,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int t if(event.val==KM_PRESS && (evt->ctrl || evt->shift || evt->oskey)) event.alt= evt->alt = 3; // define? } - else if (event.type==COMMANDKEY) { + else if (event.type==OSKEY) { event.oskey= evt->oskey= (event.val==KM_PRESS); if(event.val==KM_PRESS && (evt->ctrl || evt->alt || evt->shift)) event.oskey= evt->oskey = 3; // define? diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c index 33564834bcb..67decd6292e 100644 --- a/source/blender/windowmanager/intern/wm_files.c +++ b/source/blender/windowmanager/intern/wm_files.c @@ -681,15 +681,20 @@ int WM_write_homefile(bContext *C, wmOperator *op) wm_window_close(C, wm, win); BLI_make_file_string("/", tstr, BLI_get_folder_create(BLENDER_USER_CONFIG, NULL), BLENDER_STARTUP_FILE); - printf("trying to save homefile at %s \n", tstr); + printf("trying to save homefile at %s ", tstr); /* force save as regular blend file */ fileflags = G.fileflags & ~(G_FILE_COMPRESS | G_FILE_AUTOPLAY | G_FILE_LOCK | G_FILE_SIGN); - BLO_write_file(CTX_data_main(C), tstr, fileflags, op->reports, NULL); + if(BLO_write_file(CTX_data_main(C), tstr, fileflags, op->reports, NULL) == 0) { + printf("fail\n"); + return OPERATOR_CANCELLED; + } + printf("ok\n"); + G.save_over= 0; - + return OPERATOR_FINISHED; } diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c index 5b7d952de77..f0962584801 100644 --- a/source/blender/windowmanager/intern/wm_operators.c +++ b/source/blender/windowmanager/intern/wm_operators.c @@ -1153,7 +1153,6 @@ static uiBlock *wm_block_create_splash(bContext *C, ARegion *ar, void *arg_unuse uiStyle *style= U.uistyles.first; struct RecentFile *recent; int i; - Menu menu= {0}; MenuType *mt= WM_menutype_find("USERPREF_MT_splash", TRUE); char url[64]; @@ -1193,9 +1192,13 @@ static uiBlock *wm_block_create_splash(bContext *C, ARegion *ar, void *arg_unuse uiBlockSetEmboss(block, UI_EMBOSS); /* show the splash menu (containing interaction presets), using python */ if (mt) { + Menu menu= {0}; menu.layout= layout; menu.type= mt; mt->draw(C, &menu); + +// wmWindowManager *wm= CTX_wm_manager(C); +// uiItemM(layout, C, "USERPREF_MT_keyconfigs", U.keyconfigstr, 0); } uiBlockSetEmboss(block, UI_EMBOSSP); diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c index 328c3e80259..d9d7abd3a68 100644 --- a/source/blender/windowmanager/intern/wm_window.c +++ b/source/blender/windowmanager/intern/wm_window.c @@ -528,7 +528,7 @@ static int query_qual(char qual) left= GHOST_kModifierKeyLeftControl; right= GHOST_kModifierKeyRightControl; } else if (qual=='C') { - left= right= GHOST_kModifierKeyCommand; + left= right= GHOST_kModifierKeyOS; } else { left= GHOST_kModifierKeyLeftAlt; right= GHOST_kModifierKeyRightAlt; @@ -613,7 +613,7 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr private) wm_event_add_ghostevent(wm, win, GHOST_kEventKeyUp, time, &kdata); } if (win->eventstate->oskey && !query_qual('C')) { - kdata.key= GHOST_kKeyCommand; + kdata.key= GHOST_kKeyOS; wm_event_add_ghostevent(wm, win, GHOST_kEventKeyUp, time, &kdata); } /* keymodifier zero, it hangs on hotkeys that open windows otherwise */ diff --git a/source/blender/windowmanager/wm_event_types.h b/source/blender/windowmanager/wm_event_types.h index e4b56080b03..efc31f6f7c3 100644 --- a/source/blender/windowmanager/wm_event_types.h +++ b/source/blender/windowmanager/wm_event_types.h @@ -204,7 +204,7 @@ #define ENDKEY 170 #define UNKNOWNKEY 171 -#define COMMANDKEY 172 +#define OSKEY 172 #define GRLESSKEY 173 /* for event checks */ @@ -215,7 +215,7 @@ #define ISKEYBOARD(event) (event >=' ' && event <=320) /* test whether the event is a modifier key */ -#define ISKEYMODIFIER(event) ((event >= LEFTCTRLKEY && event <= LEFTSHIFTKEY) || event == COMMANDKEY) +#define ISKEYMODIFIER(event) ((event >= LEFTCTRLKEY && event <= LEFTSHIFTKEY) || event == OSKEY) /* test whether the event is a mouse button */ #define ISMOUSE(event) (event >= LEFTMOUSE && event <= MOUSEROTATE) diff --git a/source/blenderplayer/bad_level_call_stubs/CMakeLists.txt b/source/blenderplayer/bad_level_call_stubs/CMakeLists.txt index dbcf4d96942..50be3c91dbe 100644 --- a/source/blenderplayer/bad_level_call_stubs/CMakeLists.txt +++ b/source/blenderplayer/bad_level_call_stubs/CMakeLists.txt @@ -37,6 +37,7 @@ SET(INC ../../../intern/guardedalloc ../../../source/blender/makesdna ../../../source/blender/makesrna + ../../../source/blender/blenkernel ) IF(WITH_GAMEENGINE) diff --git a/source/blenderplayer/bad_level_call_stubs/stubs.c b/source/blenderplayer/bad_level_call_stubs/stubs.c index b341f798478..f563cacf8a8 100644 --- a/source/blenderplayer/bad_level_call_stubs/stubs.c +++ b/source/blenderplayer/bad_level_call_stubs/stubs.c @@ -162,6 +162,7 @@ void ED_node_composit_default(struct Scene *sce){} void *ED_region_draw_cb_activate(struct ARegionType *art, void(*draw)(const struct bContext *, struct ARegion *, void *), void *custumdata, int type){return 0;} /* XXX this one looks weird */ void *ED_region_draw_cb_customdata(void *handle){return 0;} /* XXX This one looks wrong also */ void ED_region_draw_cb_exit(struct ARegionType *art, void *handle){} +void ED_area_headerprint(struct ScrArea *sa, char *str){} struct EditBone *ED_armature_bone_get_mirrored(struct ListBase *edbo, struct EditBone *ebo){return (struct EditBone *) NULL;} struct EditBone *ED_armature_edit_bone_add(struct bArmature *arm, char *name){return (struct EditBone*) NULL;} diff --git a/source/creator/CMakeLists.txt b/source/creator/CMakeLists.txt index bc3e4c623ef..a979cb7a515 100644 --- a/source/creator/CMakeLists.txt +++ b/source/creator/CMakeLists.txt @@ -255,16 +255,17 @@ IF(WITH_INSTALL) COMMAND cp -Rf ${SOURCEDIR}/Contents/PkgInfo ${TARGETDIR}/blender.app/Contents/ COMMAND cp -Rf ${SOURCEDIR}/Contents/Resources ${TARGETDIR}/blender.app/Contents/ COMMAND cat ${SOURCEINFO} | sed s/VERSION/`cat ${CMAKE_SOURCE_DIR}/release/VERSION`/ | sed s/DATE/`date +'%Y-%b-%d'`/ > ${TARGETINFO} - COMMAND rm -Rf ${TARGETDIR}/blender.app/Contents/MacOS/datafiles - COMMAND mkdir ${TARGETDIR}/blender.app/Contents/MacOS/datafiles/ - COMMAND cp ${CMAKE_SOURCE_DIR}/release/bin/.blender/.bfont.ttf ${TARGETDIR}/blender.app/Contents/MacOS/datafiles/ + COMMAND rm -Rf ${TARGETDIR}/blender.app/Contents/MacOS/${BLENDER_VERSION} + COMMAND mkdir ${TARGETDIR}/blender.app/Contents/MacOS/${BLENDER_VERSION} + COMMAND mkdir ${TARGETDIR}/blender.app/Contents/MacOS/${BLENDER_VERSION}/datafiles/ + COMMAND cp ${CMAKE_SOURCE_DIR}/release/bin/.blender/.bfont.ttf ${TARGETDIR}/blender.app/Contents/MacOS/${BLENDER_VERSION}/datafiles/ ) IF(WITH_INTERNATIONAL) ADD_CUSTOM_COMMAND( TARGET blender POST_BUILD MAIN_DEPENDENCY blender - COMMAND cp ${CMAKE_SOURCE_DIR}/release/bin/.blender/.Blanguages ${TARGETDIR}/blender.app/Contents/MacOS/datafiles/ - COMMAND cp -Rf ${CMAKE_SOURCE_DIR}/release/bin/.blender/locale ${TARGETDIR}/blender.app/Contents/MacOS/datafiles/ + COMMAND cp ${CMAKE_SOURCE_DIR}/release/bin/.blender/.Blanguages ${TARGETDIR}/blender.app/Contents/MacOS/${BLENDER_VERSION}/datafiles/ + COMMAND cp -Rf ${CMAKE_SOURCE_DIR}/release/bin/.blender/locale ${TARGETDIR}/blender.app/Contents/MacOS/${BLENDER_VERSION}/datafiles/ ) ENDIF(WITH_INTERNATIONAL) @@ -272,10 +273,9 @@ IF(WITH_INSTALL) SET(PYTHON_ZIP "python_${CMAKE_OSX_ARCHITECTURES}.zip") ADD_CUSTOM_COMMAND( TARGET blender POST_BUILD MAIN_DEPENDENCY blender - COMMAND cp -Rf ${CMAKE_SOURCE_DIR}/release/scripts ${TARGETDIR}/blender.app/Contents/MacOS/ - COMMAND rm -Rf ${TARGETDIR}/blender.app/Contents/MacOS/python/ - COMMAND mkdir ${TARGETDIR}/blender.app/Contents/MacOS/python/ - COMMAND unzip -q ${LIBDIR}/release/${PYTHON_ZIP} -d ${TARGETDIR}/blender.app/Contents/MacOS/python/ + COMMAND cp -Rf ${CMAKE_SOURCE_DIR}/release/scripts ${TARGETDIR}/blender.app/Contents/MacOS/${BLENDER_VERSION}/ + COMMAND mkdir ${TARGETDIR}/blender.app/Contents/MacOS/${BLENDER_VERSION}/python/ + COMMAND unzip -q ${LIBDIR}/release/${PYTHON_ZIP} -d ${TARGETDIR}/blender.app/Contents/MacOS/${BLENDER_VERSION}/python/ COMMAND find ${TARGETDIR}/blender.app -name "*.py?" -prune -exec rm -rf {} "\;" ) ENDIF(WITH_PYTHON) @@ -289,6 +289,7 @@ IF(WITH_INSTALL) ENDIF(APPLE) IF(WIN32) + # notice 'xcopy /Y /H' on .bfont.ttf, this is needed when building over samba ADD_CUSTOM_COMMAND(TARGET blender POST_BUILD MAIN_DEPENDENCY blender @@ -296,7 +297,7 @@ IF(WITH_INSTALL) COMMAND if not exist \"${TARGETDIR}\\${BLENDER_VERSION}\\scripts\" mkdir \"${TARGETDIR}\\${BLENDER_VERSION}\\scripts\" COMMAND if not exist \"${TARGETDIR}\\${BLENDER_VERSION}\\config\" mkdir \"${TARGETDIR}\\${BLENDER_VERSION}\\config\" COMMAND if not exist \"${TARGETDIR}\\plugins\" mkdir \"${TARGETDIR}\\plugins\" - COMMAND copy /Y \"${CMAKE_SOURCE_DIR}\\release\\bin\\.blender\\.bfont.ttf\" \"${TARGETDIR}\\${BLENDER_VERSION}\\config\\\" + COMMAND xcopy /Y /H \"${CMAKE_SOURCE_DIR}\\release\\bin\\.blender\\.bfont.ttf\" \"${TARGETDIR}\\${BLENDER_VERSION}\\config\\\" COMMAND xcopy /E /Y \"${CMAKE_SOURCE_DIR}\\release\\scripts\\*.*\" \"${TARGETDIR}\\${BLENDER_VERSION}\\scripts\\\" COMMAND xcopy /E /Y \"${CMAKE_SOURCE_DIR}\\release\\plugins\\*.*\" \"${TARGETDIR}\\${BLENDER_VERSION}\\plugins\\\" COMMAND copy /Y \"${CMAKE_SOURCE_DIR}\\release\\text\\*.*\" \"${TARGETDIR}\\\" diff --git a/source/creator/creator.c b/source/creator/creator.c index 6b08c3c6a51..963bd4775a1 100644 --- a/source/creator/creator.c +++ b/source/creator/creator.c @@ -899,7 +899,10 @@ static int load_file(int argc, char **argv, void *data) } else { /* we are not running in background mode here, but start blender in UI mode with a file - this should do everything a 'load file' does */ - WM_read_file(C, filename, NULL); + ReportList reports; + BKE_reports_init(&reports, RPT_PRINT); + WM_read_file(C, filename, &reports); + BKE_reports_clear(&reports); } G.file_loaded = 1; diff --git a/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp b/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp index 5a0522a9aa6..2bc24aab526 100644 --- a/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp +++ b/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp @@ -425,7 +425,7 @@ extern "C" void StartKetsjiShell(struct bContext *C, struct ARegion *ar, rcti *c ketsjiengine->SetAnimFrameRate(FPS); // the mainloop - printf("\nBlender Game Engine Started\n\n"); + printf("\nBlender Game Engine Started\n"); while (!exitrequested) { // first check if we want to exit @@ -472,7 +472,7 @@ extern "C" void StartKetsjiShell(struct bContext *C, struct ARegion *ar, rcti *c } } - printf("\nBlender Game Engine Finished\n\n"); + printf("Blender Game Engine Finished\n"); exitstring = ketsjiengine->GetExitString(); diff --git a/source/gameengine/BlenderRoutines/KX_BlenderCanvas.cpp b/source/gameengine/BlenderRoutines/KX_BlenderCanvas.cpp index b04e951028d..f1e30ed4227 100644 --- a/source/gameengine/BlenderRoutines/KX_BlenderCanvas.cpp +++ b/source/gameengine/BlenderRoutines/KX_BlenderCanvas.cpp @@ -203,5 +203,11 @@ void KX_BlenderCanvas::SetMousePosition(int x,int y) void KX_BlenderCanvas::MakeScreenShot(const char* filename) { -// BL_MakeScreenShot(m_ar, filename); + ScrArea area_dummy= {0}; + area_dummy.totrct.xmin = m_frame_rect.GetLeft(); + area_dummy.totrct.xmax = m_frame_rect.GetRight(); + area_dummy.totrct.ymin = m_frame_rect.GetBottom(); + area_dummy.totrct.ymax = m_frame_rect.GetTop(); + + BL_MakeScreenShot(&area_dummy, filename); } diff --git a/source/gameengine/BlenderRoutines/KX_BlenderGL.cpp b/source/gameengine/BlenderRoutines/KX_BlenderGL.cpp index 55a687c0baa..662222bf990 100644 --- a/source/gameengine/BlenderRoutines/KX_BlenderGL.cpp +++ b/source/gameengine/BlenderRoutines/KX_BlenderGL.cpp @@ -49,6 +49,8 @@ extern "C" { #include "GL/glew.h" +#include "MEM_guardedalloc.h" + #include "BL_Material.h" // MAXTEX /* Data types encoding the game world: */ @@ -68,7 +70,11 @@ extern "C" { #include "BKE_bmfont.h" #include "BKE_image.h" +#include "BLI_path_util.h" + extern "C" { +#include "IMB_imbuf_types.h" +#include "IMB_imbuf.h" #include "WM_api.h" #include "WM_types.h" #include "wm_event_system.h" @@ -206,18 +212,53 @@ void BL_NormalMouse(wmWindow *win) } #define MAX_FILE_LENGTH 512 +/* get shot from frontbuffer sort of a copy from screendump.c */ +static unsigned int *screenshot(ScrArea *curarea, int *dumpsx, int *dumpsy) +{ + int x=0, y=0; + unsigned int *dumprect= NULL; + + x= curarea->totrct.xmin; + y= curarea->totrct.ymin; + *dumpsx= curarea->totrct.xmax-x; + *dumpsy= curarea->totrct.ymax-y; + + if (*dumpsx && *dumpsy) { + + dumprect= (unsigned int *)MEM_mallocN(sizeof(int) * (*dumpsx) * (*dumpsy), "dumprect"); + glReadBuffer(GL_FRONT); + glReadPixels(x, y, *dumpsx, *dumpsy, GL_RGBA, GL_UNSIGNED_BYTE, dumprect); + glFinish(); + glReadBuffer(GL_BACK); + } -void BL_MakeScreenShot(struct ARegion *ar, const char* filename) + return dumprect; +} + +/* based on screendump.c::screenshot_exec */ +void BL_MakeScreenShot(ScrArea *curarea, const char* filename) { - char copyfilename[MAX_FILE_LENGTH]; - strcpy(copyfilename,filename); + char path[MAX_FILE_LENGTH]; + strcpy(path,filename); - // filename read - only + unsigned int *dumprect; + int dumpsx, dumpsy; - /* XXX will need to change at some point */ - //XXX BIF_screendump(0); - - // write+read filename - //XXX write_screendump((char*) copyfilename); + dumprect= screenshot(curarea, &dumpsx, &dumpsy); + if(dumprect) { + ImBuf *ibuf; + BLI_path_abs(path, G.sce); + /* BKE_add_image_extension() checks for if extension was already set */ + BKE_add_image_extension(path, R_PNG); /* scene->r.imtype */ + ibuf= IMB_allocImBuf(dumpsx, dumpsy, 24, 0, 0); + ibuf->rect= dumprect; + ibuf->ftype= PNG; + + IMB_saveiff(ibuf, path, IB_rect); + + ibuf->rect= NULL; + IMB_freeImBuf(ibuf); + MEM_freeN(dumprect); + } } diff --git a/source/gameengine/BlenderRoutines/KX_BlenderGL.h b/source/gameengine/BlenderRoutines/KX_BlenderGL.h index 84d174cec68..9c5254dd661 100644 --- a/source/gameengine/BlenderRoutines/KX_BlenderGL.h +++ b/source/gameengine/BlenderRoutines/KX_BlenderGL.h @@ -41,7 +41,7 @@ void BL_SwapBuffers(struct wmWindow *win); void BL_warp_pointer(struct wmWindow *win,int x,int y); -void BL_MakeScreenShot(struct ARegion *ar, const char* filename); +void BL_MakeScreenShot(struct ScrArea *curarea, const char* filename); void BL_HideMouse(struct wmWindow *win); void BL_NormalMouse(struct wmWindow *win); diff --git a/source/gameengine/BlenderRoutines/SConscript b/source/gameengine/BlenderRoutines/SConscript index f53fc509c6d..1a774fc8aba 100644 --- a/source/gameengine/BlenderRoutines/SConscript +++ b/source/gameengine/BlenderRoutines/SConscript @@ -30,6 +30,9 @@ if env['WITH_BF_PYTHON']: else: defs.append('DISABLE_PYTHON') +if env['WITH_BF_CXX_GUARDEDALLOC']: + defs.append('WITH_CXX_GUARDEDALLOC') + incs += ' ' + env['BF_BULLET_INC'] incs += ' ' + env['BF_OPENGL_INC'] diff --git a/source/gameengine/Converter/KX_BlenderSceneConverter.cpp b/source/gameengine/Converter/KX_BlenderSceneConverter.cpp index f50fb6838e3..6f64f4e33af 100644 --- a/source/gameengine/Converter/KX_BlenderSceneConverter.cpp +++ b/source/gameengine/Converter/KX_BlenderSceneConverter.cpp @@ -40,6 +40,7 @@ #include "KX_KetsjiEngine.h" #include "KX_IPhysicsController.h" #include "BL_Material.h" +#include "BL_ActionActuator.h" #include "KX_BlenderMaterial.h" #include "KX_PolygonMaterial.h" @@ -960,7 +961,7 @@ bool KX_BlenderSceneConverter::LinkBlendFile(BlendHandle *bpy_openlib, const cha static char err_local[255]; /* only scene and mesh supported right now */ - if(idcode!=ID_SCE && idcode!=ID_ME) { + if(idcode!=ID_SCE && idcode!=ID_ME &&idcode!=ID_AC) { snprintf(err_local, sizeof(err_local), "invalid ID type given \"%s\"\n", group); return false; } @@ -1018,6 +1019,16 @@ bool KX_BlenderSceneConverter::LinkBlendFile(BlendHandle *bpy_openlib, const cha kx_scene->GetLogicManager()->RegisterMeshName(meshobj->GetName(),meshobj); } } + else if(idcode==ID_AC) { + /* Convert all actions */ + ID *action; + KX_Scene *kx_scene= m_currentScene; + + for(action= (ID *)main_newlib->action.first; action; action= (ID *)action->next) { + printf("ActionName: %s\n", action->name); + kx_scene->GetLogicManager()->RegisterActionName(action->name+2, action); + } + } else if(idcode==ID_SCE) { /* Merge all new linked in scene into the existing one */ ID *scene; @@ -1092,6 +1103,23 @@ bool KX_BlenderSceneConverter::FreeBlendFile(struct Main *maggie) } } } + + /* Now unregister actions */ + { + GEN_Map<STR_HashedString,void*> &mapStringToActions = scene->GetLogicManager()->GetActionMap(); + + for(int i=0; i<mapStringToActions.size(); i++) + { + ID *action= (ID*) *mapStringToActions.at(i); + + if(IS_TAGGED(action)) + { + STR_HashedString an = action->name+2; + mapStringToActions.remove(an); + i--; + } + } + } //scene->FreeTagged(); /* removed tagged objects and meshes*/ CListValue *obj_lists[] = {scene->GetObjectList(), scene->GetInactiveList(), NULL}; @@ -1128,6 +1156,17 @@ bool KX_BlenderSceneConverter::FreeBlendFile(struct Main *maggie) break; } } + + /* make sure action actuators are not referencing tagged actions */ + for (int act_idx=0; act_idx<gameobj->GetActuators().size(); act_idx++) + { + if (gameobj->GetActuators()[act_idx]->IsType(SCA_IActuator::KX_ACT_ACTION)) + { + BL_ActionActuator *act = (BL_ActionActuator*)gameobj->GetActuators()[act_idx]; + if(IS_TAGGED(act->GetAction())) + act->SetAction(NULL); + } + } } } } diff --git a/source/gameengine/Converter/SConscript b/source/gameengine/Converter/SConscript index ab1d7574d89..7701d27730b 100644 --- a/source/gameengine/Converter/SConscript +++ b/source/gameengine/Converter/SConscript @@ -32,4 +32,7 @@ if env['WITH_BF_PYTHON']: else: defs.append('DISABLE_PYTHON') +if env['WITH_BF_CXX_GUARDEDALLOC']: + defs.append('WITH_CXX_GUARDEDALLOC') + env.BlenderLib ( 'bf_converter', sources, Split(incs), defs, libtype=['core','player'], priority=[305,40], cxx_compileflags=env['BGE_CXXFLAGS']) diff --git a/source/gameengine/Expressions/SConscript b/source/gameengine/Expressions/SConscript index 007d6373c77..85db689a9ba 100644 --- a/source/gameengine/Expressions/SConscript +++ b/source/gameengine/Expressions/SConscript @@ -12,4 +12,7 @@ if env['WITH_BF_PYTHON']: else: defs.append('DISABLE_PYTHON') +if env['WITH_BF_CXX_GUARDEDALLOC']: + defs.append('WITH_CXX_GUARDEDALLOC') + env.BlenderLib ( 'bf_expressions', sources, Split(incs), defs, libtype=['core','player'], priority = [360,80], cxx_compileflags=env['BGE_CXXFLAGS']) diff --git a/source/gameengine/GameLogic/SCA_LogicManager.h b/source/gameengine/GameLogic/SCA_LogicManager.h index 9ddb62df361..f92b27f641a 100644 --- a/source/gameengine/GameLogic/SCA_LogicManager.h +++ b/source/gameengine/GameLogic/SCA_LogicManager.h @@ -127,6 +127,7 @@ public: void RegisterMeshName(const STR_String& meshname,void* mesh); void UnregisterMeshName(const STR_String& meshname,void* mesh); GEN_Map<STR_HashedString,void*>& GetMeshMap() { return m_mapStringToMeshes; }; + GEN_Map<STR_HashedString,void*>& GetActionMap() { return m_mapStringToActions; }; void RegisterActionName(const STR_String& actname,void* action); diff --git a/source/gameengine/GameLogic/SConscript b/source/gameengine/GameLogic/SConscript index 507bb7f0bdd..c9d1fed875d 100644 --- a/source/gameengine/GameLogic/SConscript +++ b/source/gameengine/GameLogic/SConscript @@ -23,4 +23,8 @@ if env['OURPLATFORM'] in ('win32-vc', 'win64-vc'): if env['BF_DEBUG']: defs.append('_DEBUG') +if env['WITH_BF_CXX_GUARDEDALLOC']: + defs.append('WITH_CXX_GUARDEDALLOC') + incs += ' #/intern/guardedalloc' + env.BlenderLib ( 'bf_logic', sources, Split(incs), defs, libtype=['core','player'], priority=[330,65], cxx_compileflags=env['BGE_CXXFLAGS']) diff --git a/source/gameengine/Ketsji/KX_Dome.cpp b/source/gameengine/Ketsji/KX_Dome.cpp index c7f27316cce..64ef06a4e09 100644 --- a/source/gameengine/Ketsji/KX_Dome.cpp +++ b/source/gameengine/Ketsji/KX_Dome.cpp @@ -18,7 +18,7 @@ http://www.gnu.org/copyleft/lesser.txt. Contributor(s): Dalai Felinto This code is originally inspired on some of the ideas and codes from Paul Bourke. -Developed as part of a Research and Development project for SAT - La Socidegtdeg des arts technologiques. +Developed as part of a Research and Development project for SAT - La Société des arts technologiques. ----------------------------------------------------------------------------- */ diff --git a/source/gameengine/Ketsji/KX_PythonInit.cpp b/source/gameengine/Ketsji/KX_PythonInit.cpp index 3a754f1f466..88993f20132 100644 --- a/source/gameengine/Ketsji/KX_PythonInit.cpp +++ b/source/gameengine/Ketsji/KX_PythonInit.cpp @@ -141,6 +141,8 @@ static char gp_GamePythonPathOrig[FILE_MAXDIR + FILE_MAXFILE] = ""; // not super static KX_Scene* gp_KetsjiScene = NULL; static KX_KetsjiEngine* gp_KetsjiEngine = NULL; static RAS_IRasterizer* gp_Rasterizer = NULL; +static SCA_PythonKeyboard* gp_PythonKeyboard = NULL; +static SCA_PythonMouse* gp_PythonMouse = NULL; void KX_SetActiveScene(class KX_Scene* scene) { @@ -1296,11 +1298,13 @@ PyObject* initGameLogic(KX_KetsjiEngine *engine, KX_Scene* scene) // quick hack PyDict_SetItemString(d, "globalDict", item=PyDict_New()); Py_DECREF(item); // Add keyboard and mouse attributes to this module - SCA_PythonKeyboard* pykeyb = new SCA_PythonKeyboard(gp_KetsjiEngine->GetKeyboardDevice()); - PyDict_SetItemString(d, "keyboard", pykeyb->NewProxy(true)); + MT_assert(!gp_PythonKeyboard); + gp_PythonKeyboard = new SCA_PythonKeyboard(gp_KetsjiEngine->GetKeyboardDevice()); + PyDict_SetItemString(d, "keyboard", gp_PythonKeyboard->NewProxy(true)); - SCA_PythonMouse* pymouse = new SCA_PythonMouse(gp_KetsjiEngine->GetMouseDevice(), gp_Canvas); - PyDict_SetItemString(d, "mouse", pymouse->NewProxy(true)); + MT_assert(!gp_PythonMouse); + gp_PythonMouse = new SCA_PythonMouse(gp_KetsjiEngine->GetMouseDevice(), gp_Canvas); + PyDict_SetItemString(d, "mouse", gp_PythonMouse->NewProxy(true)); ErrorObject = PyUnicode_FromString("GameLogic.error"); PyDict_SetItemString(d, "error", ErrorObject); @@ -1760,8 +1764,8 @@ static void setSandbox(TPythonSecurityLevel level) */ default: /* Allow importing internal text, from bpy_internal_import.py */ - PyDict_SetItemString(d, "reload", item=PyCFunction_New(bpy_reload_meth, NULL)); Py_DECREF(item); - PyDict_SetItemString(d, "__import__", item=PyCFunction_New(bpy_import_meth, NULL)); Py_DECREF(item); + PyDict_SetItemString(d, "reload", item=PyCFunction_New(&bpy_reload_meth, NULL)); Py_DECREF(item); + PyDict_SetItemString(d, "__import__", item=PyCFunction_New(&bpy_import_meth, NULL)); Py_DECREF(item); break; } } @@ -1926,6 +1930,13 @@ PyObject* initGamePlayerPythonScripting(const STR_String& progname, TPythonSecur void exitGamePlayerPythonScripting() { + /* Clean up the Python mouse and keyboard */ + delete gp_PythonKeyboard; + gp_PythonKeyboard = NULL; + + delete gp_PythonMouse; + gp_PythonMouse = NULL; + /* since python restarts we cant let the python backup of the sys.path hang around in a global pointer */ restorePySysObjects(); /* get back the original sys.path and clear the backup */ @@ -1962,6 +1973,13 @@ PyObject* initGamePythonScripting(const STR_String& progname, TPythonSecurityLev void exitGamePythonScripting() { + /* Clean up the Python mouse and keyboard */ + delete gp_PythonKeyboard; + gp_PythonKeyboard = NULL; + + delete gp_PythonMouse; + gp_PythonMouse = NULL; + restorePySysObjects(); /* get back the original sys.path and clear the backup */ bpy_import_main_set(NULL); PyObjectPlus::ClearDeprecationWarning(); @@ -2214,6 +2232,7 @@ PyObject* initGameKeys() KX_MACRO_addTypesToDict(d, ESCKEY, SCA_IInputDevice::KX_ESCKEY); KX_MACRO_addTypesToDict(d, TABKEY, SCA_IInputDevice::KX_TABKEY); KX_MACRO_addTypesToDict(d, RETKEY, SCA_IInputDevice::KX_RETKEY); + KX_MACRO_addTypesToDict(d, ENTERKEY, SCA_IInputDevice::KX_RETKEY); KX_MACRO_addTypesToDict(d, SPACEKEY, SCA_IInputDevice::KX_SPACEKEY); KX_MACRO_addTypesToDict(d, LINEFEEDKEY, SCA_IInputDevice::KX_LINEFEEDKEY); KX_MACRO_addTypesToDict(d, BACKSPACEKEY, SCA_IInputDevice::KX_BACKSPACEKEY); diff --git a/source/gameengine/Ketsji/SConscript b/source/gameengine/Ketsji/SConscript index 8d54452be0d..49e4528594f 100644 --- a/source/gameengine/Ketsji/SConscript +++ b/source/gameengine/Ketsji/SConscript @@ -40,4 +40,7 @@ if env['OURPLATFORM'] in ('win32-vc', 'win64-vc', 'win32-mingw'): if env['BF_DEBUG']: defs.append('_DEBUG') # for Python +if env['WITH_BF_CXX_GUARDEDALLOC']: + defs.append('WITH_CXX_GUARDEDALLOC') + env.BlenderLib ( 'bf_ketsji', sources, Split(incs), defs, libtype=['core','player'], priority=[320,45], cxx_compileflags=env['BGE_CXXFLAGS']) diff --git a/source/gameengine/Network/SConscript b/source/gameengine/Network/SConscript index 3883dc71c9c..3cf1747d013 100644 --- a/source/gameengine/Network/SConscript +++ b/source/gameengine/Network/SConscript @@ -5,4 +5,10 @@ sources = env.Glob('*.cpp') #'NG_NetworkMessage.cpp NG_NetworkObject.cpp NG_Netw incs = '. #source/kernel/gen_system #intern/string #intern/moto/include' -env.BlenderLib ( 'bf_ngnetwork', sources, Split(incs), [], libtype=['core','player'], priority=[400,130] ) +defs = [] + +if env['WITH_BF_CXX_GUARDEDALLOC']: + defs.append('WITH_CXX_GUARDEDALLOC') + incs += ' #intern/guardedalloc' + +env.BlenderLib ( 'bf_ngnetwork', sources, Split(incs), defs, libtype=['core','player'], priority=[400,130] ) diff --git a/source/gameengine/Physics/Bullet/SConscript b/source/gameengine/Physics/Bullet/SConscript index f58085ab354..6beb044671c 100644 --- a/source/gameengine/Physics/Bullet/SConscript +++ b/source/gameengine/Physics/Bullet/SConscript @@ -27,4 +27,7 @@ if env['WITH_BF_PYTHON']: else: defs.append('DISABLE_PYTHON') +if env['WITH_BF_CXX_GUARDEDALLOC']: + defs.append('WITH_CXX_GUARDEDALLOC') + env.BlenderLib ( 'bf_bullet', Split(sources), Split(incs), defs, libtype=['core','player'], priority=[350,50], cxx_compileflags=env['BGE_CXXFLAGS']) diff --git a/source/gameengine/Physics/Dummy/SConscript b/source/gameengine/Physics/Dummy/SConscript index dc76e8046a0..496092133c3 100644 --- a/source/gameengine/Physics/Dummy/SConscript +++ b/source/gameengine/Physics/Dummy/SConscript @@ -5,4 +5,10 @@ sources = 'DummyPhysicsEnvironment.cpp' incs = '. ../common' -env.BlenderLib ( 'bf_dummy', Split(sources), Split(incs), [], libtype=['core','player'], priority=[350,60] ) +defs = [] + +if env['WITH_BF_CXX_GUARDEDALLOC']: + defs.append('WITH_CXX_GUARDEDALLOC') + incs += ' #intern/guardedalloc' + +env.BlenderLib ( 'bf_dummy', Split(sources), Split(incs), defs, libtype=['core','player'], priority=[350,60] ) diff --git a/source/gameengine/Physics/common/SConscript b/source/gameengine/Physics/common/SConscript index 719c028ee8f..38bb7a11309 100644 --- a/source/gameengine/Physics/common/SConscript +++ b/source/gameengine/Physics/common/SConscript @@ -5,4 +5,10 @@ sources = 'PHY_IMotionState.cpp PHY_IController.cpp PHY_IPhysicsController.cpp P incs = '. ../Dummy #intern/moto/include' -env.BlenderLib ( 'bf_physics_common', Split(sources), Split(incs), [], libtype=['core','player'], priority=[360,55], cxx_compileflags=env['BGE_CXXFLAGS']) +defs = [] + +if env['WITH_BF_CXX_GUARDEDALLOC']: + defs.append('WITH_CXX_GUARDEDALLOC') + incs += ' #intern/guardedalloc' + +env.BlenderLib ( 'bf_physics_common', Split(sources), Split(incs), defs, libtype=['core','player'], priority=[360,55], cxx_compileflags=env['BGE_CXXFLAGS']) diff --git a/source/gameengine/PyDoc/bge.events.rst b/source/gameengine/PyDoc/bge.events.rst index f642291fe97..7215902a828 100644 --- a/source/gameengine/PyDoc/bge.events.rst +++ b/source/gameengine/PyDoc/bge.events.rst @@ -18,7 +18,7 @@ This module holds key constants for the SCA_KeyboardSensor. co = bge.logic.getCurrentController() # 'Keyboard' is a keyboard sensor sensor = co.sensors["Keyboard"] - sensor.key = bge.keys.F1KEY + sensor.key = bge.events.F1KEY .. code-block:: python @@ -30,17 +30,37 @@ This module holds key constants for the SCA_KeyboardSensor. sensor = co.sensors["Keyboard"] for key,status in sensor.events: - # key[0] == bge.keys.keycode, key[1] = status + # key[0] == bge.events.keycode, key[1] = status if status == bge.logic.KX_INPUT_JUST_ACTIVATED: - if key == bge.keys.WKEY: + if key == bge.events.WKEY: # Activate Forward! - if key == bge.keys.SKEY: + if key == bge.events.SKEY: # Activate Backward! - if key == bge.keys.AKEY: + if key == bge.events.AKEY: # Activate Left! - if key == bge.keys.DKEY: + if key == bge.events.DKEY: # Activate Right! +.. code-block:: python + + # The all keys thing without a keyboard sensor (but you will + # need an always sensor with pulse mode on) + import bge + + # Just shortening names here + keyboard = bge.logic.keyboard + JUST_ACTIVATED = bge.logic.KX_INPUT_JUST_ACTIVATED + + if keyboard.events[bge.events.WKEY] == JUST_ACTIVATED: + print("Activate Forward!") + if keyboard.events[bge.events.SKEY] == JUST_ACTIVATED: + print("Activate Backward!") + if keyboard.events[bge.events.AKEY] == JUST_ACTIVATED: + print("Activate Left!") + if keyboard.events[bge.events.DKEY] == JUST_ACTIVATED: + print("Activate Right!") + + ********* Functions ********* @@ -222,7 +242,8 @@ Other Keys .. data:: PERIODKEY .. data:: QUOTEKEY .. data:: RIGHTBRACKETKEY -.. data:: RETKEY +.. data:: RETKEY (Deprecated: use bge.events.ENTERKEY) +.. data:: ENTERKEY .. data:: SEMICOLONKEY .. data:: SLASHKEY .. data:: SPACEKEY diff --git a/source/gameengine/PyDoc/bge.logic.rst b/source/gameengine/PyDoc/bge.logic.rst index a7eb5635d0f..d3261f5747b 100644 --- a/source/gameengine/PyDoc/bge.logic.rst +++ b/source/gameengine/PyDoc/bge.logic.rst @@ -179,7 +179,7 @@ General functions :arg blend: The path to the blend file (or the name to use for the library if data is supplied) :type blend: string - :arg type: The datablock type (currently only "Scene" and "Mesh" are supported) + :arg type: The datablock type (currently only "Action", "Mesh" and "Scene" are supported) :type type: string :arg data: Binary data from a blend file (optional) :type data: bytes diff --git a/source/gameengine/PyDoc/bge.types.rst b/source/gameengine/PyDoc/bge.types.rst index 24b87e97286..6dc5488af32 100644 --- a/source/gameengine/PyDoc/bge.types.rst +++ b/source/gameengine/PyDoc/bge.types.rst @@ -929,9 +929,9 @@ Game Engine bge.types Module .. attribute:: color - The object color of the object. + The object color of the object. [r, g, b, a] - :type: list [r, g, b, a] + :type: :class:`mathutils.Vector` .. attribute:: occlusion @@ -941,63 +941,87 @@ Game Engine bge.types Module .. attribute:: position - The object's position. + The object's position. [x, y, z] On write: local position, on read: world position .. deprecated:: use :data:`localPosition` and :data:`worldPosition`. - :type: list [x, y, z] On write: local position, on read: world position + :type: :class:`mathurils.Vector` .. attribute:: orientation - The object's orientation. 3x3 Matrix. You can also write a Quaternion or Euler vector. + The object's orientation. 3x3 Matrix. You can also write a Quaternion or Euler vector. On write: local orientation, on read: world orientation .. deprecated:: use :data:`localOrientation` and :data:`worldOrientation`. - :type: 3x3 Matrix [[float]] On write: local orientation, on read: world orientation + :type: :class:`mathutils.Matrix` .. attribute:: scaling - The object's scaling factor. list [sx, sy, sz] + The object's scaling factor. [sx, sy, sz] On write: local scaling, on read: world scaling .. deprecated:: use :data:`localScale` and :data:`worldScale`. - :type: list [sx, sy, sz] On write: local scaling, on read: world scaling + :type: :class:`mathutils.Vector` .. attribute:: localOrientation The object's local orientation. 3x3 Matrix. You can also write a Quaternion or Euler vector. - :type: 3x3 Matrix [[float]] + :type: :class:`mathutils.Matrix` .. attribute:: worldOrientation - The object's world orientation. + The object's world orientation. 3x3 Matrix. - :type: 3x3 Matrix [[float]] + :type: :class:`mathutils.Matrix` .. attribute:: localScale - The object's local scaling factor. + The object's local scaling factor. [sx, sy, sz] - :type: list [sx, sy, sz] + :type: :class:`mathutils.Vector` .. attribute:: worldScale - The object's world scaling factor. Read-only. + The object's world scaling factor. Read-only. [sx, sy, sz] - :type: list [sx, sy, sz] + :type: :class:`mathutils.Vector` .. attribute:: localPosition - The object's local position. + The object's local position. [x, y, z] - :type: list [x, y, z] + :type: :class:`mathutils.Vector` .. attribute:: worldPosition - The object's world position. + The object's world position. [x, y, z] - :type: list [x, y, z] + :type: :class:`mathutils.Vector` + + .. attribute:: localLinearVelocity + + The object's local linear velocity. [x, y, z] + + :type: :class:`mathutils.Vector` + + .. attribute:: worldLinearVelocity + + The object's world linear velocity. [x, y, z] + + :type: :class:`mathutils.Vector` + + .. attribute:: localAngularVelocity + + The object's local angular velocity. [x, y, z] + + :type: :class:`mathutils.Vector` + + .. attribute:: worldAngularVelocity + + The object's world angular velocity. [x, y, z] + + :type: :class:`mathutils.Vector` .. attribute:: timeOffset diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/SConscript b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/SConscript index 68e6789c05e..8ad6a8b28a2 100644 --- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/SConscript +++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/SConscript @@ -10,4 +10,7 @@ incs += ' #source/blender/gpu #extern/glew/include ' + env['BF_OPENGL_INC'] incs += ' #source/blender/gameengine/Ketsji #source/gameengine/SceneGraph #source/blender/makesdna #source/blender/blenkernel' incs += ' #intern/guardedalloc #source/blender/blenlib' +if env['WITH_BF_CXX_GUARDEDALLOC']: + defs.append('WITH_CXX_GUARDEDALLOC') + env.BlenderLib ( 'bf_oglrasterizer', Split(sources), Split(incs), defines = defs, libtype=['core','player'], priority=[350,75], cxx_compileflags=env['BGE_CXXFLAGS']) diff --git a/source/gameengine/Rasterizer/SConscript b/source/gameengine/Rasterizer/SConscript index a78a0289d98..dc189c54a40 100644 --- a/source/gameengine/Rasterizer/SConscript +++ b/source/gameengine/Rasterizer/SConscript @@ -13,4 +13,7 @@ if env['WITH_BF_PYTHON']: else: defs.append('DISABLE_PYTHON') +if env['WITH_BF_CXX_GUARDEDALLOC']: + defs.append('WITH_CXX_GUARDEDALLOC') + env.BlenderLib ( 'bf_rasterizer', sources, Split(incs), defs, libtype=['core','player'], priority=[350,70], cxx_compileflags=env['BGE_CXXFLAGS']) diff --git a/source/gameengine/SceneGraph/SConscript b/source/gameengine/SceneGraph/SConscript index 2a33cd67b5e..992a10befa2 100644 --- a/source/gameengine/SceneGraph/SConscript +++ b/source/gameengine/SceneGraph/SConscript @@ -6,4 +6,10 @@ sources = env.Glob('*.cpp') incs = '. #intern/moto/include' -env.BlenderLib ( 'bf_scenegraph', sources, Split(incs), [], libtype=['core','player'], priority=[325,85], cxx_compileflags=env['BGE_CXXFLAGS']) +defs = [] + +if env['WITH_BF_CXX_GUARDEDALLOC']: + defs.append('WITH_CXX_GUARDEDALLOC') + incs += ' #intern/guardedalloc' + +env.BlenderLib ( 'bf_scenegraph', sources, Split(incs), defs, libtype=['core','player'], priority=[325,85], cxx_compileflags=env['BGE_CXXFLAGS']) |