diff options
author | Dalai Felinto <dfelinto@gmail.com> | 2016-10-20 19:03:44 +0300 |
---|---|---|
committer | Dalai Felinto <dfelinto@gmail.com> | 2016-10-20 20:00:49 +0300 |
commit | 418b24551e1b8a4458deceedca945a631f0684ac (patch) | |
tree | cfb1f42ff1eb58e36f714132d3ed623c18bfc6f7 | |
parent | a84794b39960029a61d7c2c79e4ad7e2fda06bb7 (diff) | |
parent | 9269574089a742130f02c0a1184a19d94f0e665d (diff) |
Merge commit '9269574089a742130f02c0a1184a19d94f0e665d' into pbr-online
Merge conflicts fixes include fix on ob->reflectionplane for write and
read, and a few manual fixes to account for the ID remap changes
Conflicts:
source/blender/blenkernel/intern/object.c
source/blender/blenkernel/intern/world.c
source/blender/blenloader/intern/writefile.c
source/blender/editors/space_view3d/view3d_draw.c
source/blender/gpu/GPU_draw.h
source/blender/gpu/intern/gpu_draw.c
source/blender/gpu/intern/gpu_material.c
source/blender/gpu/intern/gpu_texture.c
source/blender/gpu/shaders/gpu_shader_vertex_world.glsl
693 files changed, 40222 insertions, 10762 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index b558fe14820..1c933d38ab9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -229,6 +229,11 @@ option(WITH_BULLET "Enable Bullet (Physics Engine)" ON) option(WITH_SYSTEM_BULLET "Use the systems bullet library (currently unsupported due to missing features in upstream!)" ) mark_as_advanced(WITH_SYSTEM_BULLET) option(WITH_GAMEENGINE "Enable Game Engine" ${_init_GAMEENGINE}) +if(APPLE) + set(WITH_GAMEENGINE_DECKLINK OFF) +else() + option(WITH_GAMEENGINE_DECKLINK "Support BlackMagicDesign DeckLink cards in the Game Engine" ON) +endif() option(WITH_PLAYER "Build Player" OFF) option(WITH_OPENCOLORIO "Enable OpenColorIO color management" ${_init_OPENCOLORIO}) @@ -273,6 +278,7 @@ endif() if(WITH_X11) option(WITH_X11_XINPUT "Enable X11 Xinput (tablet support and unicode input)" ON) option(WITH_X11_XF86VMODE "Enable X11 video mode switching" ON) + option(WITH_X11_ALPHA "Enable X11 transparent background" ON) endif() if(UNIX AND NOT APPLE) @@ -723,6 +729,7 @@ if(WITH_GHOST_SDL OR WITH_HEADLESS) set(WITH_X11 OFF) set(WITH_X11_XINPUT OFF) set(WITH_X11_XF86VMODE OFF) + set(WITH_X11_ALPHA OFF) set(WITH_GHOST_XDND OFF) set(WITH_INPUT_IME OFF) endif() @@ -862,6 +869,16 @@ if(WITH_X11) endif() endif() + if(WITH_X11_ALPHA) + find_library(X11_Xrender_LIB Xrender ${X11_LIB_SEARCH_PATH}) + mark_as_advanced(X11_Xrender_LIB) + if (X11_Xrender_LIB) + list(APPEND PLATFORM_LINKLIBS ${X11_Xrender_LIB}) + else() + set(WITH_X11_ALPHA OFF) + endif() + endif() + endif() @@ -3199,6 +3216,7 @@ if(FIRST_RUN) info_cfg_text("System Options:") info_cfg_option(WITH_INSTALL_PORTABLE) + info_cfg_option(WITH_X11_ALPHA) info_cfg_option(WITH_X11_XF86VMODE) info_cfg_option(WITH_X11_XINPUT) info_cfg_option(WITH_MEM_JEMALLOC) diff --git a/build_files/build_environment/install_deps.sh b/build_files/build_environment/install_deps.sh index b3d659313d4..068ac665623 100755 --- a/build_files/build_environment/install_deps.sh +++ b/build_files/build_environment/install_deps.sh @@ -25,7 +25,7 @@ ARGS=$( \ getopt \ -o s:i:t:h \ ---long source:,install:,tmp:,info:,threads:,help,show-deps,no-sudo,no-confirm,with-all,with-opencollada,\ +--long source:,install:,tmp:,info:,threads:,help,show-deps,no-sudo,no-build,no-confirm,with-all,with-opencollada,\ ver-ocio:,ver-oiio:,ver-llvm:,ver-osl:,ver-osd:,ver-openvdb:,\ force-all,force-python,force-numpy,force-boost,\ force-ocio,force-openexr,force-oiio,force-llvm,force-osl,force-osd,force-openvdb,\ @@ -97,6 +97,9 @@ ARGUMENTS_INFO="\"COMMAND LINE ARGUMENTS: --no-sudo Disable use of sudo (this script won't be able to do much though, will just print needed packages...). + --no-build + Do not build (compile) anything, dependencies not installable with the package manager will remain missing. + --no-confirm Disable any interaction with user (suitable for automated run). @@ -267,6 +270,7 @@ DO_SHOW_DEPS=false SUDO="sudo" +NO_BUILD=false NO_CONFIRM=false PYTHON_VERSION="3.5.1" @@ -317,7 +321,7 @@ LLVM_FORCE_REBUILD=false LLVM_SKIP=false # OSL needs to be compiled for now! -OSL_VERSION="1.7.1" +OSL_VERSION="1.7.3" OSL_VERSION_MIN=$OSL_VERSION OSL_FORCE_BUILD=false OSL_FORCE_REBUILD=false @@ -463,6 +467,12 @@ while true; do PRINT "" SUDO=""; shift; continue ;; + --no-build) + PRINT "" + WARNING "--no-build enabled, this script will not be able to install all dependencies..." + PRINT "" + NO_BUILD=true; shift; continue + ;; --no-confirm) NO_CONFIRM=true; shift; continue ;; @@ -967,6 +977,11 @@ clean_Python() { } compile_Python() { + if [ "$NO_BUILD" = true ]; then + WARNING "--no-build enabled, Python will not be compiled!" + return + fi + # To be changed each time we make edits that would modify the compiled result! py_magic=1 _init_python @@ -1032,6 +1047,11 @@ clean_Numpy() { } compile_Numpy() { + if [ "$NO_BUILD" = true ]; then + WARNING "--no-build enabled, Numpy will not be compiled!" + return + fi + # To be changed each time we make edits that would modify the compiled result! numpy_magic=0 _init_numpy @@ -1092,6 +1112,11 @@ clean_Boost() { } compile_Boost() { + if [ "$NO_BUILD" = true ]; then + WARNING "--no-build enabled, Boost will not be compiled!" + return + fi + # To be changed each time we make edits that would modify the compiled result! boost_magic=10 @@ -1165,6 +1190,11 @@ clean_OCIO() { } compile_OCIO() { + if [ "$NO_BUILD" = true ]; then + WARNING "--no-build enabled, OpenColorIO will not be compiled!" + return + fi + # To be changed each time we make edits that would modify the compiled result! ocio_magic=1 _init_ocio @@ -1256,6 +1286,11 @@ clean_ILMBASE() { } compile_ILMBASE() { + if [ "$NO_BUILD" = true ]; then + WARNING "--no-build enabled, ILMBase will not be compiled!" + return + fi + # To be changed each time we make edits that would modify the compiled result! ilmbase_magic=10 _init_ilmbase @@ -1343,6 +1378,11 @@ clean_OPENEXR() { } compile_OPENEXR() { + if [ "$NO_BUILD" = true ]; then + WARNING "--no-build enabled, OpenEXR will not be compiled!" + return + fi + # To be changed each time we make edits that would modify the compiled result! openexr_magic=14 @@ -1458,6 +1498,11 @@ clean_OIIO() { } compile_OIIO() { + if [ "$NO_BUILD" = true ]; then + WARNING "--no-build enabled, OpenImageIO will not be compiled!" + return + fi + # To be changed each time we make edits that would modify the compiled result! oiio_magic=16 _init_oiio @@ -1589,6 +1634,11 @@ clean_LLVM() { } compile_LLVM() { + if [ "$NO_BUILD" = true ]; then + WARNING "--no-build enabled, LLVM will not be compiled!" + return + fi + # To be changed each time we make edits that would modify the compiled result! llvm_magic=3 _init_llvm @@ -1686,8 +1736,13 @@ clean_OSL() { } compile_OSL() { + if [ "$NO_BUILD" = true ]; then + WARNING "--no-build enabled, OpenShadingLanguage will not be compiled!" + return + fi + # To be changed each time we make edits that would modify the compiled result! - osl_magic=20 + osl_magic=21 _init_osl # Clean install if needed! @@ -1812,6 +1867,11 @@ clean_OSD() { } compile_OSD() { + if [ "$NO_BUILD" = true ]; then + WARNING "--no-build enabled, OpenSubdiv will not be compiled!" + return + fi + # To be changed each time we make edits that would modify the compiled result! osd_magic=1 _init_osd @@ -1904,6 +1964,11 @@ clean_BLOSC() { } compile_BLOSC() { + if [ "$NO_BUILD" = true ]; then + WARNING "--no-build enabled, Blosc will not be compiled!" + return + fi + # To be changed each time we make edits that would modify the compiled result! blosc_magic=0 _init_blosc @@ -1986,6 +2051,11 @@ clean_OPENVDB() { } compile_OPENVDB() { + if [ "$NO_BUILD" = true ]; then + WARNING "--no-build enabled, OpenVDB will not be compiled!" + return + fi + compile_BLOSC PRINT "" @@ -2082,6 +2152,11 @@ clean_OpenCOLLADA() { } compile_OpenCOLLADA() { + if [ "$NO_BUILD" = true ]; then + WARNING "--no-build enabled, OpenCOLLADA will not be compiled!" + return + fi + # To be changed each time we make edits that would modify the compiled results! opencollada_magic=9 _init_opencollada @@ -2161,6 +2236,11 @@ clean_FFmpeg() { } compile_FFmpeg() { + if [ "$NO_BUILD" = true ]; then + WARNING "--no-build enabled, ffmpeg will not be compiled!" + return + fi + # To be changed each time we make edits that would modify the compiled result! ffmpeg_magic=5 _init_ffmpeg diff --git a/build_files/buildbot/master.cfg b/build_files/buildbot/master.cfg index 70dcbfbc1df..8bd23357fc6 100644 --- a/build_files/buildbot/master.cfg +++ b/build_files/buildbot/master.cfg @@ -285,7 +285,7 @@ def generic_builder(id, libdir='', branch='', rsync=False): maxsize=150 * 1024 * 1024, workdir='install')) f.addStep(MasterShellCommand(name='unpack', - command=['python', unpack_script, filename], + command=['python2.7', unpack_script, filename], description='unpacking', descriptionDone='unpacked')) return f diff --git a/build_files/buildbot/slave_compile.py b/build_files/buildbot/slave_compile.py index 4fb879aea3b..5e06c7057ce 100644 --- a/build_files/buildbot/slave_compile.py +++ b/build_files/buildbot/slave_compile.py @@ -75,18 +75,20 @@ if 'cmake' in builder: cmake_extra_options.append('-DCUDA_NVCC_EXECUTABLE=/usr/local/cuda-hack/bin/nvcc') elif builder.startswith('win'): - if builder.endswith('_vc2015'): - if builder.startswith('win64'): - cmake_options.extend(['-G', 'Visual Studio 14 2015 Win64', b'-DCUDA_NVCC_FLAGS="-ccbin C:\\Program Files (x86)\\Microsoft Visual Studio 12.0\\VC\\bin\\amd64\\"']) - elif builder.startswith('win32'): - bits = 32 - cmake_options.extend(['-G', 'Visual Studio 14 2015', b'-DCUDA_NVCC_FLAGS="-ccbin C:\\Program Files (x86)\\Microsoft Visual Studio 12.0\\VC\\bin\\"']) - else: - if builder.startswith('win64'): - cmake_options.extend(['-G', 'Visual Studio 12 2013 Win64']) - elif builder.startswith('win32'): - bits = 32 - cmake_options.extend(['-G', 'Visual Studio 12 2013']) + if builder.endswith('_vc2015'): + if builder.startswith('win64'): + cmake_options.extend(['-G', 'Visual Studio 14 2015 Win64']) + elif builder.startswith('win32'): + bits = 32 + cmake_options.extend(['-G', 'Visual Studio 14 2015']) + cmake_extra_options.append('-DCUDA_NVCC_FLAGS=--cl-version;2013;' + + '--compiler-bindir;C:\\Program Files (x86)\\Microsoft Visual Studio 12.0\\VC\\bin') + else: + if builder.startswith('win64'): + cmake_options.extend(['-G', 'Visual Studio 12 2013 Win64']) + elif builder.startswith('win32'): + bits = 32 + cmake_options.extend(['-G', 'Visual Studio 12 2013']) elif builder.startswith('linux'): tokens = builder.split("_") diff --git a/build_files/buildbot/slave_pack.py b/build_files/buildbot/slave_pack.py index b27017568cb..490f0456045 100644 --- a/build_files/buildbot/slave_pack.py +++ b/build_files/buildbot/slave_pack.py @@ -108,6 +108,8 @@ if builder.find('cmake') != -1: platform += 'i386' elif builder.endswith('ppc_10_6_cmake'): platform += 'ppc' + if builder.endswith('vc2015'): + platform += "-vc14" builderified_name = 'blender-{}-{}-{}'.format(blender_full_version, git_hash, platform) if branch != '': builderified_name = branch + "-" + builderified_name diff --git a/build_files/cmake/macros.cmake b/build_files/cmake/macros.cmake index d34b55e14e0..d29f086069a 100644 --- a/build_files/cmake/macros.cmake +++ b/build_files/cmake/macros.cmake @@ -552,11 +552,11 @@ function(SETUP_BLENDER_SORTED_LIBS) bf_modifiers bf_bmesh bf_gpu + bf_blenloader bf_blenkernel bf_physics bf_nodes bf_rna - bf_blenloader bf_imbuf bf_blenlib bf_depsgraph @@ -685,6 +685,14 @@ function(SETUP_BLENDER_SORTED_LIBS) list_insert_after(BLENDER_SORTED_LIBS "ge_logic_ngnetwork" "extern_bullet") endif() + if(WITH_GAMEENGINE_DECKLINK) + list(APPEND BLENDER_SORTED_LIBS bf_intern_decklink) + endif() + + if(WIN32) + list(APPEND BLENDER_SORTED_LIBS bf_intern_gpudirect) + endif() + if(WITH_OPENSUBDIV) list(APPEND BLENDER_SORTED_LIBS bf_intern_opensubdiv) endif() diff --git a/build_files/package_spec/pacman/PKGBUILD b/build_files/package_spec/pacman/PKGBUILD index 961e35578b9..aea5acd13e4 100644 --- a/build_files/package_spec/pacman/PKGBUILD +++ b/build_files/package_spec/pacman/PKGBUILD @@ -2,11 +2,9 @@ # custom blender vars blender_srcdir=$(dirname $startdir)"/../.." -# value may be formatted: 35042:35051M -blender_revision=$(svnversion $blender_srcdir | cut -d: -f2 | awk '{print $3}') -blender_version=$(grep "BLENDER_VERSION\s" $blender_srcdir/source/blender/blenkernel/BKE_blender.h | awk '{print $3}') +blender_version=$(grep "BLENDER_VERSION\s" $blender_srcdir/source/blender/blenkernel/BKE_blender_version.h | awk '{print $3}') blender_version=$(expr $blender_version / 100).$(expr $blender_version % 100) # 256 -> 2.56 -blender_version_char=$(sed -ne 's/.*BLENDER_VERSION_CHAR.*\([a-z]\)$/\1/p' $blender_srcdir/source/blender/blenkernel/BKE_blender.h) +blender_version_char=$(sed -ne 's/.*BLENDER_VERSION_CHAR.*\([a-z]\)$/\1/p' $blender_srcdir/source/blender/blenkernel/BKE_blender_version.h) # blender_subversion=$(grep BLENDER_SUBVERSION $blender_srcdir/source/blender/blenkernel/BKE_blender.h | awk '{print $3}') # map the version a -> 1 @@ -27,7 +25,9 @@ arch=('i686' 'x86_64') url="www.blender.org" license=('GPL') groups=() -depends=('libjpeg' 'libpng' 'openjpeg' 'libtiff' 'openexr' 'python>=3.4' 'gettext' 'libxi' 'libxmu' 'mesa' 'freetype2' 'openal' 'sdl' 'libsndfile' 'ffmpeg') +depends=('libjpeg' 'libpng' 'openjpeg' 'libtiff' 'openexr' 'python>=3.5' + 'gettext' 'libxi' 'libxmu' 'mesa' 'freetype2' 'openal' 'sdl' + 'libsndfile' 'ffmpeg') makedepends=('cmake' 'git') optdepends=() provides=() diff --git a/doc/python_api/examples/bge.texture.2.py b/doc/python_api/examples/bge.texture.2.py new file mode 100644 index 00000000000..96619007fba --- /dev/null +++ b/doc/python_api/examples/bge.texture.2.py @@ -0,0 +1,237 @@ +""" +Video Capture with DeckLink ++++++++++++++++++++++++++++ +Video frames captured with DeckLink cards have pixel formats that are generally not directly +usable by OpenGL, they must be processed by a shader. The three shaders presented here should +cover all common video capture cases. + +This file reflects the current video transfer method implemented in the Decklink module: +whenever possible the video images are transferred as float texture because this is more +compatible with GPUs. Of course, only the pixel formats that have a correspondant GL format +can be transferred as float. Look for fg_shaders in this file for an exhaustive list. + +Other pixel formats will be transferred as 32 bits integer red-channel texture but this +won't work with certain GPU (Intel GMA); the corresponding shaders are not shown here. +However, it should not be necessary to use any of them as the list below covers all practical +cases of video capture with all types of Decklink product. + +In other words, only use one of the pixel format below and you will be fine. Note that depending +on the video stream, only certain pixel formats will be allowed (others will throw an exception). +For example, to capture a PAL video stream, you must use one of the YUV formats. + +To find which pixel format is suitable for a particular video stream, use the 'Media Express' +utility that comes with the Decklink software : if you see the video in the 'Log and Capture' +Window, you have selected the right pixel format and you can use the same in Blender. + +Notes: * these shaders only decode the RGB channel and set the alpha channel to a fixed +value (look for color.a = ). It's up to you to add postprocessing to the color. + * these shaders are compatible with 2D and 3D video stream +""" +import bge +from bge import logic +from bge import texture as vt + +# The default vertex shader, because we need one +# +VertexShader = """ +#version 130 + void main() + { + gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; + gl_TexCoord[0] = gl_MultiTexCoord0; + } + +""" + +# For use with RGB video stream: the pixel is directly usable +# +FragmentShader_R10l = """ + #version 130 + uniform sampler2D tex; + // stereo = 1.0 if 2D image, =0.5 if 3D (left eye below, right eye above) + uniform float stereo; + // eye = 0.0 for the left eye, 0.5 for the right eye + uniform float eye; + + void main(void) + { + vec4 color; + float tx, ty; + tx = gl_TexCoord[0].x; + ty = eye+gl_TexCoord[0].y*stereo; + color = texture(tex, vec2(tx,ty)); + color.a = 0.7; + gl_FragColor = color; + } +""" + +# For use with YUV video stream +# +FragmentShader_2vuy = """ + #version 130 + uniform sampler2D tex; + // stereo = 1.0 if 2D image, =0.5 if 3D (left eye below, right eye above) + uniform float stereo; + // eye = 0.0 for the left eye, 0.5 for the right eye + uniform float eye; + + void main(void) + { + vec4 color; + float tx, ty, width, Y, Cb, Cr; + int px; + tx = gl_TexCoord[0].x; + ty = eye+gl_TexCoord[0].y*stereo; + width = float(textureSize(tex, 0).x); + color = texture(tex, vec2(tx, ty)); + px = int(floor(fract(tx*width)*2.0)); + switch (px) { + case 0: + Y = color.g; + break; + case 1: + Y = color.a; + break; + } + Y = (Y - 0.0625) * 1.168949772; + Cb = (color.b - 0.0625) * 1.142857143 - 0.5; + Cr = (color.r - 0.0625) * 1.142857143 - 0.5; + color.r = Y + 1.5748 * Cr; + color.g = Y - 0.1873 * Cb - 0.4681 * Cr; + color.b = Y + 1.8556 * Cb; + color.a = 0.7; + gl_FragColor = color; + } +""" + +# For use with high resolution YUV +# +FragmentShader_v210 = """ + #version 130 + uniform sampler2D tex; + // stereo = 1.0 if 2D image, =0.5 if 3D (left eye below, right eye above) + uniform float stereo; + // eye = 0.0 for the left eye, 0.5 for the right eye + uniform float eye; + + void main(void) + { + vec4 color, color1, color2, color3; + int px; + float tx, ty, width, sx, dx, bx, Y, Cb, Cr; + tx = gl_TexCoord[0].x; + ty = eye+gl_TexCoord[0].y*stereo; + width = float(textureSize(tex, 0).x); + // to sample macro pixels (6 pixels in 4 words) + sx = tx*width*0.25+0.01; + // index of display pixel in the macro pixel 0..5 + px = int(floor(fract(sx)*6.0)); + // increment as we sample the macro pixel + dx = 1.0/width; + // base x coord of macro pixel + bx = (floor(sx)+0.01)*dx*4.0; + color = texture(tex, vec2(bx, ty)); + color1 = texture(tex, vec2(bx+dx, ty)); + color2 = texture(tex, vec2(bx+dx*2.0, ty)); + color3 = texture(tex, vec2(bx+dx*3.0, ty)); + switch (px) { + case 0: + case 1: + Cb = color.b; + Cr = color.r; + break; + case 2: + case 3: + Cb = color1.g; + Cr = color2.b; + break; + default: + Cb = color2.r; + Cr = color3.g; + break; + } + switch (px) { + case 0: + Y = color.g; + break; + case 1: + Y = color1.b; + break; + case 2: + Y = color1.r; + break; + case 3: + Y = color2.g; + break; + case 4: + Y = color3.b; + break; + default: + Y = color3.r; + break; + } + Y = (Y - 0.0625) * 1.168949772; + Cb = (Cb - 0.0625) * 1.142857143 - 0.5; + Cr = (Cr - 0.0625) * 1.142857143 - 0.5; + color.r = Y + 1.5748 * Cr; + color.g = Y - 0.1873 * Cb - 0.4681 * Cr; + color.b = Y + 1.8556 * Cb; + color.a = 0.7; + gl_FragColor = color; + } +""" + +# The exhausitve list of pixel formats that are transferred as float texture +# Only use those for greater efficiency and compatiblity. +# +fg_shaders = { + '2vuy' :FragmentShader_2vuy, + '8BitYUV' :FragmentShader_2vuy, + 'v210' :FragmentShader_v210, + '10BitYUV' :FragmentShader_v210, + '8BitBGRA' :FragmentShader_R10l, + 'BGRA' :FragmentShader_R10l, + '8BitARGB' :FragmentShader_R10l, + '10BitRGBXLE':FragmentShader_R10l, + 'R10l' :FragmentShader_R10l + } + + +# +# Helper function to attach a pixel shader to the material that receives the video frame. +# + +def config_video(obj, format, pixel, is3D=False, mat=0, card=0): + if pixel not in fg_shaders: + raise('Unsuported shader') + shader = obj.meshes[0].materials[mat].getShader() + if shader is not None and not shader.isValid(): + shader.setSource(VertexShader, fg_shaders[pixel], True) + shader.setSampler('tex', 0) + shader.setUniformEyef("eye") + shader.setUniform1f("stereo", 0.5 if is3D else 1.0) + tex = vt.Texture(obj, mat) + tex.source = vt.VideoDeckLink(format + "/" + pixel + ("/3D" if is3D else ""), card) + print("frame rate: ", tex.source.framerate) + tex.source.play() + obj["video"] = tex + +# +# Attach this function to an object that has a material with texture +# and call it once to initialize the object +# +def init(cont): + # config_video(cont.owner, 'HD720p5994', '8BitBGRA') + # config_video(cont.owner, 'HD720p5994', '8BitYUV') + # config_video(cont.owner, 'pal ', '10BitYUV') + config_video(cont.owner, 'pal ', '8BitYUV') + + +# +# To be called on every frame +# +def play(cont): + obj = cont.owner + video = obj.get("video") + if video is not None: + video.refresh(True) diff --git a/doc/python_api/rst/bge.constraints.rst b/doc/python_api/rst/bge.constraints.rst index bf015057dcb..ed965c3dfc1 100644 --- a/doc/python_api/rst/bge.constraints.rst +++ b/doc/python_api/rst/bge.constraints.rst @@ -8,11 +8,11 @@ Physics Constraints (bge.constraints) Examples -------- -.. include:: ../examples/bge.constraints.py +.. include:: __/examples/bge.constraints.py :start-line: 1 :end-line: 4 -.. literalinclude:: ../examples/bge.constraints.py +.. literalinclude:: __/examples/bge.constraints.py :lines: 6- diff --git a/doc/python_api/rst/bge.events.rst b/doc/python_api/rst/bge.events.rst index 8dbded6a3fe..42135926fda 100644 --- a/doc/python_api/rst/bge.events.rst +++ b/doc/python_api/rst/bge.events.rst @@ -12,53 +12,53 @@ This module holds key constants for the SCA_KeyboardSensor. .. code-block:: python - # Set a connected keyboard sensor to accept F1 - import bge - - co = bge.logic.getCurrentController() - # 'Keyboard' is a keyboard sensor - sensor = co.sensors["Keyboard"] - sensor.key = bge.events.F1KEY - -.. code-block:: python - - # Do the all keys thing - import bge - - co = bge.logic.getCurrentController() - # 'Keyboard' is a keyboard sensor - sensor = co.sensors["Keyboard"] - - for key,status in sensor.events: - # key[0] == bge.events.keycode, key[1] = status - if status == bge.logic.KX_INPUT_JUST_ACTIVATED: - if key == bge.events.WKEY: - # Activate Forward! - if key == bge.events.SKEY: - # Activate Backward! - if key == bge.events.AKEY: - # Activate Left! - 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!") + # Set a connected keyboard sensor to accept F1 + import bge + + co = bge.logic.getCurrentController() + # 'Keyboard' is a keyboard sensor + sensor = co.sensors["Keyboard"] + sensor.key = bge.events.F1KEY + + code-block:: python + + # Do the all keys thing + import bge + + co = bge.logic.getCurrentController() + # 'Keyboard' is a keyboard sensor + sensor = co.sensors["Keyboard"] + + for key,status in sensor.events: + # key[0] == bge.events.keycode, key[1] = status + if status == bge.logic.KX_INPUT_JUST_ACTIVATED: + if key == bge.events.WKEY: + # Activate Forward! + if key == bge.events.SKEY: + # Activate Backward! + if key == bge.events.AKEY: + # Activate Left! + 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!") ********* diff --git a/doc/python_api/rst/bge.logic.rst b/doc/python_api/rst/bge.logic.rst index 3f35901234a..5cdb8ebfee9 100644 --- a/doc/python_api/rst/bge.logic.rst +++ b/doc/python_api/rst/bge.logic.rst @@ -378,6 +378,28 @@ General functions Render next frame (if Python has control) +.. function:: setRender(render) + + Sets the global flag that controls the render of the scene. + If True, the render is done after the logic frame. + If False, the render is skipped and another logic frame starts immediately. + + .. note:: + + GPU VSync no longer limits the number of frame per second when render is off, + but the *Use Frame Rate* option still regulates the fps. To run as many frames + as possible, untick this option (Render Properties, System panel). + + :arg render: the render flag + :type render: bool + +.. function:: getRender() + + Get the current value of the global render flag + + :return: The flag value + :rtype: bool + ********************** Time related functions ********************** diff --git a/doc/python_api/rst/bge.render.rst b/doc/python_api/rst/bge.render.rst index 3b565e294dd..02c3beef672 100644 --- a/doc/python_api/rst/bge.render.rst +++ b/doc/python_api/rst/bge.render.rst @@ -90,6 +90,48 @@ Constants Right eye being used during stereoscopic rendering. +.. data:: RAS_OFS_RENDER_BUFFER + + The pixel buffer for offscreen render is a RenderBuffer. Argument to :func:`offScreenCreate` + +.. data:: RAS_OFS_RENDER_TEXTURE + + The pixel buffer for offscreen render is a Texture. Argument to :func:`offScreenCreate` + + +***** +Types +***** + +.. class:: RASOffScreen + + An off-screen render buffer object. + + Use :func:`offScreenCreate` to create it. + Currently it can only be used in the :class:`bge.texture.ImageRender` + constructor to render on a FBO rather than the default viewport. + + .. attribute:: width + + The width in pixel of the FBO + + :type: integer + + .. attribute:: height + + The height in pixel of the FBO + + :type: integer + + .. attribute:: color + + The underlying OpenGL bind code of the texture object that holds + the rendered image, 0 if the FBO is using RenderBuffer. + The choice between RenderBuffer and Texture is determined + by the target argument of :func:`offScreenCreate`. + + :type: integer + ********* Functions @@ -362,3 +404,22 @@ Functions Get the current vsync value :rtype: One of VSYNC_OFF, VSYNC_ON, VSYNC_ADAPTIVE + +.. function:: offScreenCreate(width,height[,samples=0][,target=bge.render.RAS_OFS_RENDER_BUFFER]) + + Create a Off-screen render buffer object. + + :arg width: the width of the buffer in pixels + :type width: integer + :arg height: the height of the buffer in pixels + :type height: integer + :arg samples: the number of multisample for anti-aliasing (MSAA), 0 to disable MSAA + :type samples: integer + :arg target: the pixel storage: :data:`RAS_OFS_RENDER_BUFFER` to render on RenderBuffers (the default), + :data:`RAS_OFS_RENDER_TEXTURE` to render on texture. + The later is interesting if you want to access the texture directly (see :attr:`RASOffScreen.color`). + Otherwise the default is preferable as it's more widely supported by GPUs and more efficient. + If the GPU does not support MSAA+Texture (e.g. Intel HD GPU), MSAA will be disabled. + :type target: integer + :rtype: :class:`RASOffScreen` + diff --git a/doc/python_api/rst/bge.texture.rst b/doc/python_api/rst/bge.texture.rst index 4588a3e1800..49f6c4469a4 100644 --- a/doc/python_api/rst/bge.texture.rst +++ b/doc/python_api/rst/bge.texture.rst @@ -8,13 +8,16 @@ Introduction The bge.texture module allows you to manipulate textures during the game. -Several sources for texture are possible: video files, image files, video capture, memory buffer, camera render or a mix of that. +Several sources for texture are possible: video files, image files, video capture, memory buffer, +camera render or a mix of that. The video and image files can be loaded from the internet using an URL instead of a file name. -In addition, you can apply filters on the images before sending them to the GPU, allowing video effect: blue screen, color band, gray, normal map. +In addition, you can apply filters on the images before sending them to the GPU, allowing video effect: +blue screen, color band, gray, normal map. -bge.texture uses FFmpeg to load images and videos. All the formats and codecs that FFmpeg supports are supported by this module, including but not limited to: +bge.texture uses FFmpeg to load images and videos. +All the formats and codecs that FFmpeg supports are supported by this module, including but not limited to: * AVI * Ogg @@ -36,21 +39,29 @@ When the texture object is deleted, the new texture is deleted and the old textu .. module:: bge.texture -.. include:: ../examples/bge.texture.py +.. include:: __/examples/bge.texture.py :start-line: 1 :end-line: 5 - -.. literalinclude:: ../examples/bge.texture.py + +.. literalinclude:: __/examples/bge.texture.py :lines: 7- -.. include:: ../examples/bge.texture.1.py +.. include:: __/examples/bge.texture.1.py + :start-line: 1 + :end-line: 6 + +.. literalinclude:: __/examples/bge.texture.1.py + :lines: 8- + + +.. include:: __/examples/bge.texture.2.py :start-line: 1 :end-line: 6 - -.. literalinclude:: ../examples/bge.texture.1.py + +.. literalinclude:: __/examples/bge.texture.2.py :lines: 8- - - + + ************* Video classes ************* @@ -58,7 +69,7 @@ Video classes .. class:: VideoFFmpeg(file, capture=-1, rate=25.0, width=0, height=0) FFmpeg video source. - + :arg file: Path to the video to load; if capture >= 0 on Windows, this parameter will not be used. :type file: str :arg capture: Capture device number; if >= 0, the corresponding webcam will be used. (optional) @@ -73,14 +84,14 @@ Video classes .. attribute:: status Video status. (readonly) - + :type: int :value: see `FFmpeg Video and Image Status`_. .. attribute:: range Replay range. - + :type: sequence of two floats .. attribute:: repeat @@ -104,33 +115,33 @@ Video classes .. attribute:: image Image data. (readonly) - + :type: :class:`~bgl.Buffer` or None .. attribute:: size Image size. (readonly) - + :type: tuple of two ints .. attribute:: scale Fast scale of image (near neighbour). - + :type: bool .. attribute:: flip Flip image vertically. - + :type: bool .. attribute:: filter Pixel filter. - + :type: one of... - + * :class:`FilterBGR24` * :class:`FilterBlueScreen` * :class:`FilterColor` @@ -155,32 +166,41 @@ Video classes .. method:: play() Play (restart) video. - + :return: Whether the video was ready or stopped. :rtype: bool .. method:: pause() Pause video. - + :return: Whether the video was playing. :rtype: bool .. method:: stop() Stop video (play will replay it from start). - + :return: Whether the video was playing. :rtype: bool - .. method:: refresh() + .. method:: refresh(buffer=None, format="RGBA", timestamp=-1.0) - Refresh video - get its status. - - :value: see `FFmpeg Video and Image Status`_. + Refresh video - get its status and optionally copy the frame to an external buffer. + :arg buffer: An optional object that implements the buffer protocol. + If specified, the image is copied to the buffer, which must be big enough or an exception is thrown. + :type buffer: any buffer type + :arg format: An optional image format specifier for the image that will be copied to the buffer. + Only valid values are "RGBA" or "BGRA" + :type format: str + :arg timestamp: An optional timestamp (in seconds from the start of the movie) + of the frame to be copied to the buffer. + :type timestamp: float + :return: see `FFmpeg Video and Image Status`_. :rtype: int + ************* Image classes ************* @@ -188,14 +208,14 @@ Image classes .. class:: ImageFFmpeg(file) FFmpeg image source. - + :arg file: Path to the image to load. :type file: str .. attribute:: status Image status. (readonly) - + :type: int :value: see `FFmpeg Video and Image Status`_. @@ -208,33 +228,33 @@ Image classes .. attribute:: image Image data. (readonly) - + :type: :class:`~bgl.Buffer` or None .. attribute:: size Image size. (readonly) - + :type: tuple of two ints .. attribute:: scale Fast scale of image (near neighbour). - + :type: bool .. attribute:: flip Flip image vertically. - + :type: bool .. attribute:: filter Pixel filter. - + :type: one of... - + * :class:`FilterBGR24` * :class:`FilterBlueScreen` * :class:`FilterColor` @@ -244,25 +264,30 @@ Image classes * :class:`FilterRGB24` * :class:`FilterRGBA32` - .. method:: refresh() + .. method:: refresh(buffer=None, format="RGBA") - Refresh image, i.e. load it. - - :value: see `FFmpeg Video and Image Status`_. + Refresh image, get its status and optionally copy the frame to an external buffer. + :arg buffer: An optional object that implements the buffer protocol. + If specified, the image is copied to the buffer, which must be big enough or an exception is thrown. + :type buffer: any buffer type + :arg format: An optional image format specifier for the image that will be copied to the buffer. + Only valid values are "RGBA" or "BGRA" + :type format: str + :return: see `FFmpeg Video and Image Status`_. :rtype: int .. method:: reload(newname=None) Reload image, i.e. reopen it. - + :arg newname: Path to a new image. (optional) :type newname: str .. class:: ImageBuff(width, height, color=0, scale=False) Image source from image buffer. - + :arg width: Width of the image. :type width: int :arg height: Height of the image. @@ -276,9 +301,9 @@ Image classes .. attribute:: filter Pixel filter. - + :type: one of... - + * :class:`FilterBGR24` * :class:`FilterBlueScreen` * :class:`FilterColor` @@ -291,19 +316,19 @@ Image classes .. attribute:: flip Flip image vertically. - + :type: bool .. attribute:: image Image data. (readonly) - + :type: :class:`~bgl.Buffer` or None .. method:: load(imageBuffer, width, height) Load image from buffer. - + :arg imageBuffer: Buffer to load the image from. :type imageBuffer: :class:`~bgl.Buffer` or Python object implementing the buffer protocol (f.ex. bytes) :arg width: Width of the image to load. @@ -314,9 +339,10 @@ Image classes .. method:: plot(imageBuffer, width, height, positionX, positionY, mode=IMB_BLEND_COPY) Update image buffer. - + :arg imageBuffer: Buffer to load the new data from. - :type imageBuffer: :class:`~bgl.Buffer`, :class:`ImageBuff` or Python object implementing the buffer protocol (f.ex. bytes) + :type imageBuffer: :class:`~bgl.Buffer`, :class:`ImageBuff` + or Python object implementing the buffer protocol (f.ex. bytes) :arg width: Width of the data to load. :type width: int :arg height: Height of the data to load. @@ -327,18 +353,18 @@ Image classes :type positionY: int :arg mode: Drawing mode, see `Image Blending Modes`_. :type mode: int - + .. attribute:: scale Fast scale of image (near neighbour). - + :type: bool .. attribute:: size Image size. (readonly) - + :type: tuple of two ints .. attribute:: valid @@ -350,10 +376,11 @@ Image classes .. class:: ImageMirror(scene, observer, mirror, material=0) Image source from mirror. - + :arg scene: Scene in which the image has to be taken. :type scene: :class:`~bge.types.KX_Scene` - :arg observer: Reference object for the mirror (the object from which the mirror has to be looked at, for example a camera). + :arg observer: Reference object for the mirror + (the object from which the mirror has to be looked at, for example a camera). :type observer: :class:`~bge.types.KX_GameObject` :arg mirror: Object holding the mirror. :type mirror: :class:`~bge.types.KX_GameObject` @@ -363,33 +390,33 @@ Image classes .. attribute:: alpha Use alpha in texture. - + :type: bool .. attribute:: background Background color. - + :type: int or float list [r, g, b, a] in [0.0, 255.0] .. attribute:: capsize Size of render area. - + :type: sequence of two ints .. attribute:: clip Clipping distance. - + :type: float in [0.01, 5000.0] .. attribute:: filter Pixel filter. - + :type: one of... - + * :class:`FilterBGR24` * :class:`FilterBlueScreen` * :class:`FilterColor` @@ -402,29 +429,38 @@ Image classes .. attribute:: flip Flip image vertically. - + :type: bool .. attribute:: image Image data. (readonly) - + :type: :class:`~bgl.Buffer` or None - .. method:: refresh() + .. method:: refresh(buffer=None, format="RGBA") + + Refresh image - render and copy the image to an external buffer (optional) + then invalidate its current content. - Refresh image - invalidate its current content. + :arg buffer: An optional object that implements the buffer protocol. + If specified, the image is rendered and copied to the buffer, + which must be big enough or an exception is thrown. + :type buffer: any buffer type + :arg format: An optional image format specifier for the image that will be copied to the buffer. + Only valid values are "RGBA" or "BGRA" + :type format: str .. attribute:: scale Fast scale of image (near neighbour). - + :type: bool .. attribute:: size Image size (readonly). - + :type: tuple of two ints .. attribute:: valid @@ -436,7 +472,7 @@ Image classes .. attribute:: whole Use whole viewport to render. - + :type: bool .. class:: ImageMix @@ -446,9 +482,9 @@ Image classes .. attribute:: filter Pixel filter. - + :type: one of... - + * :class:`FilterBGR24` * :class:`FilterBlueScreen` * :class:`FilterColor` @@ -461,19 +497,19 @@ Image classes .. attribute:: flip Flip image vertically. - + :type: bool .. method:: getSource(id) Get image source. - + :arg id: Identifier of the source to get. :type id: str - + :return: Image source. :rtype: one of... - + * :class:`VideoFFmpeg` * :class:`ImageFFmpeg` * :class:`ImageBuff` @@ -485,43 +521,52 @@ Image classes .. method:: getWeight(id) Get image source weight. - + :arg id: Identifier of the source. :type id: str - + :return: Weight of the source. :rtype: int .. attribute:: image Image data. (readonly) - + :type: :class:`~bgl.Buffer` or None - .. method:: refresh() + .. method:: refresh(buffer=None, format="RGBA") - Refresh image - invalidate its current content. + Refresh image - calculate and copy the image to an external buffer (optional) + then invalidate its current content. + + :arg buffer: An optional object that implements the buffer protocol. + If specified, the image is calculated and copied to the buffer, + which must be big enough or an exception is thrown. + :type buffer: any buffer type + :arg format: An optional image format specifier for the image that will be copied to the buffer. + Only valid values are "RGBA" or "BGRA" + :type format: str .. attribute:: scale Fast scale of image (near neighbour). - + :type: bool - + .. attribute:: size Image size. (readonly) - + :type: tuple of two ints .. method:: setSource(id, image) Set image source - all sources must have the same size. - + :arg id: Identifier of the source to set. :type id: str :arg image: Image source of type... - + * :class:`VideoFFmpeg` * :class:`ImageFFmpeg` * :class:`ImageBuff` @@ -533,7 +578,7 @@ Image classes .. method:: setWeight(id, weight) Set image source weight - the sum of the weights should be 256 to get full color intensity in the output. - + :arg id: Identifier of the source. :type id: str :arg weight: Weight of the source. @@ -548,36 +593,40 @@ Image classes .. class:: ImageRender(scene, camera) Image source from render. - + The render is done on a custom framebuffer object if fbo is specified, + otherwise on the default framebuffer. + :arg scene: Scene in which the image has to be taken. :type scene: :class:`~bge.types.KX_Scene` :arg camera: Camera from which the image has to be taken. :type camera: :class:`~bge.types.KX_Camera` + :arg fbo: Off-screen render buffer object (optional) + :type fbo: :class:`~bge.render.RASOffScreen` .. attribute:: alpha Use alpha in texture. - + :type: bool .. attribute:: background Background color. - + :type: int or float list [r, g, b, a] in [0.0, 255.0] .. attribute:: capsize Size of render area. - + :type: sequence of two ints .. attribute:: filter Pixel filter. - + :type: one of... - + * :class:`FilterBGR24` * :class:`FilterBlueScreen` * :class:`FilterColor` @@ -590,29 +639,25 @@ Image classes .. attribute:: flip Flip image vertically. - + :type: bool .. attribute:: image Image data. (readonly) - - :type: :class:`~bgl.Buffer` or None - - .. method:: refresh() - Refresh image - invalidate its current content. + :type: :class:`~bgl.Buffer` or None .. attribute:: scale Fast scale of image (near neighbour). - + :type: bool .. attribute:: size Image size. (readonly) - + :type: tuple of two ints .. attribute:: valid @@ -624,22 +669,58 @@ Image classes .. attribute:: whole Use whole viewport to render. - + :type: bool .. attribute:: depth Use depth component of render as array of float - not suitable for texture source, should only be used with bge.texture.imageToArray(mode='F'). - + :type: bool .. attribute:: zbuff Use depth component of render as grey scale color - suitable for texture source. - + :type: bool + .. method:: render() + + Render the scene but do not extract the pixels yet. + The function returns as soon as the render commands have been send to the GPU. + The render will proceed asynchronously in the GPU while the host can perform other tasks. + To complete the render, you can either call :func:`refresh` + directly of refresh the texture of which this object is the source. + This method is useful to implement asynchronous render for optimal performance: call render() + on frame n and refresh() on frame n+1 to give as much as time as possible to the GPU + to render the frame while the game engine can perform other tasks. + + :return: True if the render was initiated, False if the render cannot be performed (e.g. the camera is active) + :rtype: bool + + .. method:: refresh() + .. method:: refresh(buffer, format="RGBA") + + Refresh video - render and optionally copy the image to an external buffer then invalidate its current content. + The render may have been started earlier with the :func:`render` method, + in which case this function simply waits for the render operations to complete. + When called without argument, the pixels are not extracted but the render is guaranteed + to be completed when the function returns. + This only makes sense with offscreen render on texture target (see :func:`~bge.render.offScreenCreate`). + + :arg buffer: An object that implements the buffer protocol. + If specified, the image is copied to the buffer, which must be big enough or an exception is thrown. + The transfer to the buffer is optimal if no processing of the image is needed. + This is the case if ``flip=False, alpha=True, scale=False, whole=True, depth=False, zbuff=False`` + and no filter is set. + :type buffer: any buffer type of sufficient size + :arg format: An optional image format specifier for the image that will be copied to the buffer. + Only valid values are "RGBA" or "BGRA" + :type format: str + :return: True if the render is complete, False if the render cannot be performed (e.g. the camera is active) + :rtype: bool + .. class:: ImageViewport Image source from viewport. @@ -647,21 +728,21 @@ Image classes .. attribute:: alpha Use alpha in texture. - + :type: bool .. attribute:: capsize Size of viewport area being captured. - + :type: sequence of two ints .. attribute:: filter Pixel filter. - + :type: one of... - + * :class:`FilterBGR24` * :class:`FilterBlueScreen` * :class:`FilterColor` @@ -674,35 +755,45 @@ Image classes .. attribute:: flip Flip image vertically. - + :type: bool .. attribute:: image Image data. (readonly) - + :type: :class:`~bgl.Buffer` or None .. attribute:: position Upper left corner of the captured area. - + :type: sequence of two ints - .. method:: refresh() + .. method:: refresh(buffer=None, format="RGBA") + + Refresh video - copy the viewport to an external buffer (optional) then invalidate its current content. - Refresh image - invalidate its current content. + :arg buffer: An optional object that implements the buffer protocol. + If specified, the image is copied to the buffer, which must be big enough or an exception is thrown. + The transfer to the buffer is optimal if no processing of the image is needed. + This is the case if ``flip=False, alpha=True, scale=False, whole=True, depth=False, zbuff=False`` + and no filter is set. + :type buffer: any buffer type + :arg format: An optional image format specifier for the image that will be copied to the buffer. + Only valid values are "RGBA" or "BGRA" + :type format: str .. attribute:: scale Fast scale of image (near neighbour). - + :type: bool .. attribute:: size Image size. (readonly) - + :type: tuple of two ints .. attribute:: valid @@ -714,23 +805,201 @@ Image classes .. attribute:: whole Use whole viewport to capture. - + :type: bool .. attribute:: depth Use depth component of viewport as array of float - not suitable for texture source, - should only be used with bge.texture.imageToArray(mode='F'). - + should only be used with ``bge.texture.imageToArray(mode='F')``. + :type: bool .. attribute:: zbuff - Use depth component of viewport as grey scale color - suitable for texture source. - + Use depth component of viewport as grey scale color - suitable for texture source. + :type: bool - +.. class:: VideoDeckLink(format, capture=0) + + Image source from an external video stream captured with a DeckLink video card from + Black Magic Design. + Before this source can be used, a DeckLink hardware device must be installed, it can be a PCIe card + or a USB device, and the 'Desktop Video' software package (version 10.4 or above must be installed) + on the host as described in the DeckLink documentation. + If in addition you have a recent nVideo Quadro card, you can benefit from the 'GPUDirect' technology + to push the captured video frame very efficiently to the GPU. For this you need to install the + 'DeckLink SDK' version 10.4 or above and copy the 'dvp.dll' runtime library to Blender's + installation directory or to any other place where Blender can load a DLL from. + + :arg format: string describing the video format to be captured. + :type format: str + :arg capture: Card number from which the input video must be captured. + :type capture: int + + The format argument must be written as ``<displayMode>/<pixelFormat>[/3D][:<cacheSize>]`` where ``<displayMode>`` + describes the frame size and rate and <pixelFormat> the encoding of the pixels. + The optional ``/3D`` suffix is to be used if the video stream is stereo with a left and right eye feed. + The optional ``:<cacheSize>`` suffix determines the number of the video frames kept in cache, by default 8. + Some DeckLink cards won't work below a certain cache size. + The default value 8 should be sufficient for all cards. + You may try to reduce the cache size to reduce the memory footprint. For example the The 4K Extreme is known + to work with 3 frames only, the Extreme 2 needs 4 frames and the Intensity Shuttle needs 6 frames, etc. + Reducing the cache size may be useful when Decklink is used in conjunction with GPUDirect: + all frames must be locked in memory in that case and that puts a lot of pressure on memory. + If you reduce the cache size too much, + you'll get no error but no video feed either. + + The valid ``<displayMode>`` values are copied from the ``BMDDisplayMode`` enum in the DeckLink API + without the 'bmdMode' prefix. In case a mode that is not in this list is added in a later version + of the SDK, it is also possible to specify the 4 letters of the internal code for that mode. + You will find the internal code in the ``DeckLinkAPIModes.h`` file that is part of the SDK. + Here is for reference the full list of supported display modes with their equivalent internal code: + + Internal Codes + - NTSC 'ntsc' + - NTSC2398 'nt23' + - PAL 'pal ' + - NTSCp 'ntsp' + - PALp 'palp' + HD 1080 Modes + - HD1080p2398 '23ps' + - HD1080p24 '24ps' + - HD1080p25 'Hp25' + - HD1080p2997 'Hp29' + - HD1080p30 'Hp30' + - HD1080i50 'Hi50' + - HD1080i5994 'Hi59' + - HD1080i6000 'Hi60' + - HD1080p50 'Hp50' + - HD1080p5994 'Hp59' + - HD1080p6000 'Hp60' + HD 720 Modes + - HD720p50 'hp50' + - HD720p5994 'hp59' + - HD720p60 'hp60' + 2k Modes + - 2k2398 '2k23' + - 2k24 '2k24' + - 2k25 '2k25' + 4k Modes + - 4K2160p2398 '4k23' + - 4K2160p24 '4k24' + - 4K2160p25 '4k25' + - 4K2160p2997 '4k29' + - 4K2160p30 '4k30' + - 4K2160p50 '4k50' + - 4K2160p5994 '4k59' + - 4K2160p60 '4k60' + + Most of names are self explanatory. If necessary refer to the DeckLink API documentation for more information. + + Similarly, <pixelFormat> is copied from the BMDPixelFormat enum. + + Here is for reference the full list of supported pixel format and their equivalent internal code: + + Pixel Formats + - 8BitYUV '2vuy' + - 10BitYUV 'v210' + - 8BitARGB * no equivalent code * + - 8BitBGRA 'BGRA' + - 10BitRGB 'r210' + - 12BitRGB 'R12B' + - 12BitRGBLE 'R12L' + - 10BitRGBXLE 'R10l' + - 10BitRGBX 'R10b' + + Refer to the DeckLink SDK documentation for a full description of these pixel format. + It is important to understand them as the decoding of the pixels is NOT done in VideoTexture + for performance reason. Instead a specific shader must be used to decode the pixel in the GPU. + Only the '8BitARGB', '8BitBGRA' and '10BitRGBXLE' pixel formats are mapped directly to OpenGL RGB float textures. + The '8BitYUV' and '10BitYUV' pixel formats are mapped to openGL RGB float texture but require a shader to decode. + The other pixel formats are sent as a ``GL_RED_INTEGER`` texture (i.e. a texture with only the + red channel coded as an unsigned 32 bit integer) and are not recommended for use. + + Example: ``HD1080p24/10BitYUV/3D:4`` is equivalent to ``24ps/v210/3D:4`` + and represents a full HD stereo feed at 24 frame per second and 4 frames cache size. + + Although video format auto detection is possible with certain DeckLink devices, the corresponding + API is NOT implemented in the BGE. Therefore it is important to specify the format string that + matches exactly the video feed. If the format is wrong, no frame will be captured. + It should be noted that the pixel format that you need to specify is not necessarily the actual + format in the video feed. For example, the 4K Extreme card delivers 8bit RGBs pixels in the + '10BitRGBXLE' format. Use the 'Media Express' application included in 'Desktop Video' to discover + which pixel format works for a particular video stream. + + .. attribute:: status + + Status of the capture: 1=ready to use, 2=capturing, 3=stopped + + :type: int + + .. attribute:: framerate + + Capture frame rate as computed from the video format. + + :type: float + + .. attribute:: valid + + Tells if the image attribute can be used to retrieve the image. + Always False in this implementation (the image is not available at python level) + + :type: bool + + .. attribute:: image + + The image data. Always None in this implementation. + + :type: :class:`~bgl.Buffer` or None + + .. attribute:: size + + The size of the frame in pixel. + Stereo frames have double the height of the video frame, i.e. 3D is delivered to the GPU + as a single image in top-bottom order, left eye on top. + + :type: (int,int) + + .. attribute:: scale + + Not used in this object. + + :type: bool + + .. attribute:: flip + + Not used in this object. + + :type: bool + + .. attribute:: filter + + Not used in this object. + + .. method:: play() + + Kick-off the capture after creation of the object. + + :return: True if the capture could be started, False otherwise. + :rtype: bool + + .. method:: pause() + + Temporary stops the capture. Use play() to restart it. + + :return: True if the capture could be paused, False otherwise. + :rtype: bool + + .. method:: stop() + + Stops the capture. + + :return: True if the capture could be stopped, False otherwise. + :rtype: bool + + *************** Texture classes *************** @@ -738,7 +1007,7 @@ Texture classes .. class:: Texture(gameObj, materialID=0, textureID=0, textureObj=None) Texture object. - + :arg gameObj: Game object to be created a video texture on. :type gameObj: :class:`~bge.types.KX_GameObject` :arg materialID: Material ID. (optional) @@ -751,7 +1020,7 @@ Texture classes .. attribute:: bindId OpenGL Bind Name. (readonly) - + :type: int .. method:: close() @@ -761,27 +1030,28 @@ Texture classes .. attribute:: mipmap Mipmap texture. - + :type: bool - .. method:: refresh(refresh_source=True, ts=-1.0) + .. method:: refresh(refresh_source, timestamp=-1.0) Refresh texture from source. - + :arg refresh_source: Whether to also refresh the image source of the texture. :type refresh_source: bool - :arg ts: If the texture controls a VideoFFmpeg object: - timestamp (in seconds from the start of the movie) of the frame to be loaded; this can be - used for video-sound synchonization by passing :attr:`~bge.types.KX_SoundActuator.time` to it. (optional) - :type ts: float + :arg timestamp: If the texture controls a VideoFFmpeg object: + timestamp (in seconds from the start of the movie) of the frame to be loaded; this can be + used for video-sound synchonization by passing :attr:`~bge.types.KX_SoundActuator.time` to it. (optional) + :type timestamp: float .. attribute:: source Source of texture. - + :type: one of... - + * :class:`VideoFFmpeg` + * :class:`VideoDeckLink` * :class:`ImageFFmpeg` * :class:`ImageBuff` * :class:`ImageMirror` @@ -789,47 +1059,168 @@ Texture classes * :class:`ImageRender` * :class:`ImageViewport` - +.. class:: DeckLink(cardIdx=0, format="") + + Certain DeckLink devices can be used to playback video: the host sends video frames regularly + for immediate or scheduled playback. The video feed is outputted on HDMI or SDI interfaces. + This class supports the immediate playback mode: it has a source attribute that is assigned + one of the source object in the bge.texture module. Refreshing the DeckLink object causes + the image source to be computed and sent to the DeckLink device for immediate transmission + on the output interfaces. Keying is supported: it allows to composite the frame with an + input video feed that transits through the DeckLink card. + + :arg cardIdx: Number of the card to be used for output (0=first card). + It should be noted that DeckLink devices are usually half duplex: + they can either be used for capture or playback but not both at the same time. + :type cardIdx: int + :arg format: String representing the display mode of the output feed. + :type format: str + + The default value of the format argument is reserved for auto detection but it is currently + not supported (it will generate a runtime error) and thus the video format must be explicitly + specified. If keying is the goal (see keying attributes), the format must match exactly the + input video feed, otherwise it can be any format supported by the device (there will be a + runtime error if not). + The format of the string is ``<displayMode>[/3D]``. + + Refer to :class:`VideoDeckLink` to get the list of acceptable ``<displayMode>``. + The optional ``/3D`` suffix is used to create a stereo 3D feed. + In that case the 'right' attribute must also be set to specify the image source for the right eye. + + Note: The pixel format is not specified here because it is always BGRA. The alpha channel is + used in keying to mix the source with the input video feed, otherwise it is not used. + If a conversion is needed to match the native video format, it is done inside the DeckLink driver + or device. + + .. attribute:: source + + This attribute must be set to one of the image source. If the image size does not fit exactly + the frame size, the extend attribute determines what to do. + + For best performance, the source image should match exactly the size of the output frame. + A further optimization is achieved if the image source object is ImageViewport or ImageRender + set for whole viewport, flip disabled and no filter: the GL frame buffer is copied directly + to the image buffer and directly from there to the DeckLink card (hence no buffer to buffer + copy inside VideoTexture). + + :type: one of... + - :class:`VideoFFmpeg` + - :class:`VideoDeckLink` + - :class:`ImageFFmpeg` + - :class:`ImageBuff` + - :class:`ImageMirror` + - :class:`ImageMix` + - :class:`ImageRender` + - :class:`ImageViewport` + + .. attribute:: right + + If the video format is stereo 3D, this attribute should be set to an image source object + that will produce the right eye images. If the goal is to render the BGE scene in 3D, + it can be achieved with 2 cameras, one for each eye, used by 2 ImageRender with an offscreen + render buffer that is just the size of the video frame. + + :type: one of... + - :class:`VideoFFmpeg` + - :class:`VideoDeckLink` + - :class:`ImageFFmpeg` + - :class:`ImageBuff` + - :class:`ImageMirror` + - :class:`ImageMix` + - :class:`ImageRender` + - :class:`ImageViewport` + + .. attribute:: keying + + Specify if keying is enabled. False (default): the output frame is sent unmodified on + the output interface (in that case no input video is required). True: the output frame + is mixed with the input video, using the alpha channel to blend the two images and the + combination is sent on the output interface. + + :type: bool + + .. attribute:: level + + If keying is enabled, sets the keying level from 0 to 255. This value is a global alpha value + that multiplies the alpha channel of the image source. Use 255 (the default) to keep the alpha + channel unmodified, 0 to make the output frame totally transparent. + + :type: int + + .. attribute:: extend + + Determines how the image source should be mapped if the size does not fit the video frame size. + * False (the default): map the image pixel by pixel. + If the image size is smaller than the frame size, extra space around the image is filled with + 0-alpha black. If it is larger, the image is cropped to fit the frame size. + * True: the image is scaled by the nearest neighbor algorithm to fit the frame size. + The scaling is fast but poor quality. For best results, always adjust the image source to + match the size of the output video. + + :type: bool + + .. method:: close() + + Close the DeckLink device and release all resources. After calling this method, + the object cannot be reactivated, it must be destroyed and a new DeckLink object + created from fresh to restart the output. + + .. method:: refresh(refresh_source,ts) + + This method must be called frequently to update the output frame in the DeckLink device. + + :arg refresh_source: True if the source objects image buffer should be invalidated after being + used to compute the output frame. This triggers the recomputing of the + source image on next refresh, which is normally the desired effect. + False if the image source buffer should stay valid and reused on next refresh. + Note that the DeckLink device stores the output frame and replays until a + new frame is sent from the host. Thus, it is not necessary to refresh the + DeckLink object if it is known that the image source has not changed. + :type refresh_source: bool + :arg ts: The timestamp value passed to the image source object to compute the image. + If unspecified, the BGE clock is used. + :type ts: float + + ************** Filter classes ************** - .. class:: FilterBGR24 Source filter BGR24. .. class:: FilterBlueScreen - Filter for Blue Screen. The RGB channels of the color are left unchanged, while the output alpha is obtained as follows: - - * if the square of the euclidian distance between the RGB color and the filter's reference color is smaller than the filter's lower limit, + Filter for Blue Screen. + The RGB channels of the color are left unchanged, while the output alpha is obtained as follows: + + - if the square of the euclidian distance between the RGB color + and the filter's reference color is smaller than the filter's lower limit, the output alpha is set to 0; - - * if that square is bigger than the filter's upper limit, the output alpha is set to 255; - - * otherwise the output alpha is linarly extrapoled between 0 and 255 in the interval of the limits. + - if that square is bigger than the filter's upper limit, the output alpha is set to 255; + - otherwise the output alpha is linarly extrapoled between 0 and 255 in the interval of the limits. .. attribute:: color Reference color. - + :type: sequence of three ints :default: (0, 0, 255) .. attribute:: limits Reference color limits. - + :type: sequence of two ints :default: (64, 64) .. attribute:: previous Previous pixel filter. - + :type: one of... - + * :class:`FilterBGR24` * :class:`FilterBlueScreen` * :class:`FilterColor` @@ -841,22 +1232,23 @@ Filter classes .. class:: FilterColor - Filter for color calculations. The output color is obtained by multiplying the reduced 4x4 matrix with the input color + Filter for color calculations. + The output color is obtained by multiplying the reduced 4x4 matrix with the input color and adding the remaining column to the result. .. attribute:: matrix Matrix [4][5] for color calculation. - + :type: sequence of four sequences of five ints :default: ((256, 0, 0, 0, 0), (0, 256, 0, 0, 0), (0, 0, 256, 0, 0), (0, 0, 0, 256, 0)) .. attribute:: previous Previous pixel filter. - + :type: one of... - + * :class:`FilterBGR24` * :class:`FilterBlueScreen` * :class:`FilterColor` @@ -868,14 +1260,15 @@ Filter classes .. class:: FilterGray - Filter for gray scale effect. Proportions of R, G and B contributions in the output gray scale are 28:151:77. + Filter for gray scale effect. + Proportions of R, G and B contributions in the output gray scale are 28:151:77. .. attribute:: previous Previous pixel filter. - + :type: one of... - + * :class:`FilterBGR24` * :class:`FilterBlueScreen` * :class:`FilterColor` @@ -888,26 +1281,26 @@ Filter classes .. class:: FilterLevel Filter for levels calculations. Each output color component is obtained as follows: - + * if it is smaller than its corresponding min value, it is set to 0; - + * if it is bigger than its corresponding max value, it is set to 255; - + * Otherwise it is linearly extrapoled between 0 and 255 in the (min, max) interval. .. attribute:: levels Levels matrix [4] (min, max). - + :type: sequence of four sequences of two ints :default: ((0, 255), (0, 255), (0, 255), (0, 255)) .. attribute:: previous Previous pixel filter. - + :type: one of... - + * :class:`FilterBGR24` * :class:`FilterBlueScreen` * :class:`FilterColor` @@ -924,23 +1317,23 @@ Filter classes .. attribute:: colorIdx Index of color used to calculate normal (0 - red, 1 - green, 2 - blue, 3 - alpha). - + :type: int in [0, 3] :default: 0 .. attribute:: depth Depth of relief. - + :type: float :default: 4.0 .. attribute:: previous Previous pixel filter. - + :type: one of... - + * :class:`FilterBGR24` * :class:`FilterBlueScreen` * :class:`FilterColor` @@ -984,25 +1377,29 @@ Functions * :class:`ImageMix` * :class:`ImageRender` * :class:`ImageViewport` - + :arg mode: Optional argument representing the pixel format. - - * You can use the characters R, G, B for the 3 color channels, A for the alpha channel, + + - You can use the characters R, G, B for the 3 color channels, A for the alpha channel, 0 to force a fixed 0 color channel and 1 to force a fixed 255 color channel. - + Examples: - * "BGR" will return 3 bytes per pixel with the Blue, Green and Red channels in that order. - * "RGB1" will return 4 bytes per pixel with the Red, Green, Blue channels in that order and the alpha channel forced to 255. - - * A special mode "F" allows to return the image as an array of float. This mode should only be used to retrieve - the depth buffer of the class:`ImageViewport` and :class:`ImageRender` objects. + + - "BGR" will return 3 bytes per pixel with the + Blue, Green and Red channels in that order. + - "RGB1" will return 4 bytes per pixel with the + Red, Green, Blue channels in that order and the alpha channel forced to 255. + + - A special mode "F" allows to return the image as an array of float. + This mode should only be used to retrieve the depth buffer of the + class:`ImageViewport` and :class:`ImageRender` objects. The default mode is "RGBA". - + :type mode: str - + :return: An object representing the image as one dimensional array of bytes of size (pixel_size*width*height), - line by line starting from the bottom of the image. The pixel size and format is determined by the mode - parameter. For mode 'F', the array is a one dimensional array of float of size (width*height). + line by line starting from the bottom of the image. The pixel size and format is determined by the mode + parameter. For mode 'F', the array is a one dimensional array of float of size (width*height). :rtype: :class:`~bgl.Buffer` .. function:: materialID(object, name) @@ -1017,7 +1414,8 @@ Functions the texture by material. In that case the material must have a texture channel in first position. - If the object has no material that matches name, it generates a runtime error. Use try/except to catch the exception. + If the object has no material that matches name, it generates a runtime error. + Use try/except to catch the exception. Ex: ``bge.texture.materialID(obj, 'IMvideo.png')`` @@ -1025,7 +1423,7 @@ Functions :type object: :class:`~bge.types.KX_GameObject` :arg name: Name of the texture/material you want to make dynamic. :type name: str - + :return: The internal material number. :rtype: int @@ -1037,11 +1435,11 @@ Functions :arg filename: Name of the error log file. :type filename: str - + :return: -1 if the parameter name is invalid (not of type string), else 0. :rtype: int - + ********* Constants ********* diff --git a/doc/python_api/rst/bge_types/bge.types.BL_Shader.rst b/doc/python_api/rst/bge_types/bge.types.BL_Shader.rst index f4f5c0d62ba..a389f68ee04 100644 --- a/doc/python_api/rst/bge_types/bge.types.BL_Shader.rst +++ b/doc/python_api/rst/bge_types/bge.types.BL_Shader.rst @@ -214,6 +214,16 @@ base class --- :class:`PyObjectPlus` :arg iList: a list (2, 3 or 4 elements) of integer values :type iList: list[integer] + .. method:: setUniformEyef(name) + + Set a uniform with a float value that reflects the eye being render in stereo mode: + 0.0 for the left eye, 0.5 for the right eye. In non stereo mode, the value of the uniform + is fixed to 0.0. The typical use of this uniform is in stereo mode to sample stereo textures + containing the left and right eye images in a top-bottom order. + + :arg name: the uniform name + :type name: string + .. method:: validate() Validate the shader object. diff --git a/doc/python_api/rst/bge_types/bge.types.SCA_PythonJoystick.rst b/doc/python_api/rst/bge_types/bge.types.SCA_PythonJoystick.rst index 2b97b5939e2..bcec751929d 100644 --- a/doc/python_api/rst/bge_types/bge.types.SCA_PythonJoystick.rst +++ b/doc/python_api/rst/bge_types/bge.types.SCA_PythonJoystick.rst @@ -12,13 +12,13 @@ base class --- :class:`PyObjectPlus` .. attribute:: name The name assigned to the joystick by the operating system. (read-only) - + :type: string .. attribute:: activeButtons A list of active button values. (read-only) - + :type: list .. attribute:: axisValues @@ -27,8 +27,10 @@ base class --- :class:`PyObjectPlus` :type: list of ints. - Each specifying the value of an axis between -1.0 and 1.0 depending on how far the axis is pushed, 0 for nothing. - The first 2 values are used by most joysticks and gamepads for directional control. 3rd and 4th values are only on some joysticks and can be used for arbitary controls. + Each specifying the value of an axis between -1.0 and 1.0 + depending on how far the axis is pushed, 0 for nothing. + The first 2 values are used by most joysticks and gamepads for directional control. + 3rd and 4th values are only on some joysticks and can be used for arbitary controls. * left:[-1.0, 0.0, ...] * right:[1.0, 0.0, ...] diff --git a/doc/python_api/rst/include__bmesh.rst b/doc/python_api/rst/include__bmesh.rst index 070dc34c964..dc43d2c016e 100644 --- a/doc/python_api/rst/include__bmesh.rst +++ b/doc/python_api/rst/include__bmesh.rst @@ -1,7 +1,8 @@ .. This document is appended to the auto generated bmesh api doc to avoid clogging up the C files with details. to test this run: - ./blender.bin -b -noaudio -P doc/python_api/sphinx_doc_gen.py -- --partial bmesh* ; cd doc/python_api ; sphinx-build sphinx-in sphinx-out ; cd ../../ + ./blender.bin -b -noaudio -P doc/python_api/sphinx_doc_gen.py -- \ + --partial bmesh* ; cd doc/python_api ; sphinx-build sphinx-in sphinx-out ; cd ../../ Submodules: @@ -40,7 +41,7 @@ For an overview of BMesh data types and how they reference each other see: Example Script -------------- -.. literalinclude:: ../../../release/scripts/templates_py/bmesh_simple.py +.. literalinclude:: __/__/__/release/scripts/templates_py/bmesh_simple.py Stand-Alone Module @@ -59,9 +60,9 @@ There are 2 ways to access BMesh data, you can create a new BMesh by converting :class:`bpy.types.BlendData.meshes` or by accessing the current edit mode mesh. see: :class:`bmesh.types.BMesh.from_mesh` and :mod:`bmesh.from_edit_mesh` respectively. -When explicitly converting from mesh data python **owns** the data, that is to say - that the mesh only exists while -python holds a reference to it, and the script is responsible for putting it back into a mesh data-block when the edits -are done. +When explicitly converting from mesh data python **owns** the data, that is to say - +that the mesh only exists while python holds a reference to it, +and the script is responsible for putting it back into a mesh data-block when the edits are done. Note that unlike :mod:`bpy`, a BMesh does not necessarily correspond to data in the currently open blend file, a BMesh can be created, edited and freed without the user ever seeing or having access to it. diff --git a/doc/python_api/rst/info_quickstart.rst b/doc/python_api/rst/info_quickstart.rst index 164196c0ac2..f0e1bee58e7 100644 --- a/doc/python_api/rst/info_quickstart.rst +++ b/doc/python_api/rst/info_quickstart.rst @@ -151,7 +151,7 @@ Data Creation/Removal ^^^^^^^^^^^^^^^^^^^^^ Those of you familiar with other Python API's may be surprised that -new datablocks in the bpy API can't be created by calling the class: +new data-blocks in the bpy API can't be created by calling the class: >>> bpy.types.Mesh() Traceback (most recent call last): @@ -305,7 +305,7 @@ In Python, this is done by defining a class, which is a subclass of an existing Example Operator ---------------- -.. literalinclude:: ../../../release/scripts/templates_py/operator_simple.py +.. literalinclude:: __/__/__/release/scripts/templates_py/operator_simple.py Once this script runs, ``SimpleOperator`` is registered with Blender and can be called from the operator search popup or added to the toolbar. @@ -336,7 +336,7 @@ Example Panel Panels register themselves as a class, like an operator. Notice the extra ``bl_`` variables used to set the context they display in. -.. literalinclude:: ../../../release/scripts/templates_py/ui_panel_simple.py +.. literalinclude:: __/__/__/release/scripts/templates_py/ui_panel_simple.py To run the script: @@ -393,11 +393,11 @@ so these are accessed as normal Python types. Internal Types -------------- -Used for Blender datablocks and collections: :class:`bpy.types.bpy_struct` +Used for Blender data-blocks and collections: :class:`bpy.types.bpy_struct` For data that contains its own attributes groups/meshes/bones/scenes... etc. -There are 2 main types that wrap Blenders data, one for datablocks +There are 2 main types that wrap Blenders data, one for data-blocks (known internally as ``bpy_struct``), another for properties. >>> bpy.context.object diff --git a/doc/python_api/rst_from_bmesh_opdefines.py b/doc/python_api/rst_from_bmesh_opdefines.py index ebcedbf71f1..cdbed88cc88 100644 --- a/doc/python_api/rst_from_bmesh_opdefines.py +++ b/doc/python_api/rst_from_bmesh_opdefines.py @@ -57,7 +57,7 @@ Operator Example ++++++++++++++++ This script shows how operators can be used to model a link of a chain. -.. literalinclude:: ../examples/bmesh.ops.1.py +.. literalinclude:: __/examples/bmesh.ops.1.py """ diff --git a/doc/python_api/sphinx_doc_gen.py b/doc/python_api/sphinx_doc_gen.py index 9d0d358305b..74ff23ee2a3 100644 --- a/doc/python_api/sphinx_doc_gen.py +++ b/doc/python_api/sphinx_doc_gen.py @@ -325,6 +325,24 @@ except ImportError: "freestyle.types", "freestyle.utils"] +# Source files we use, and need to copy to the OUTPUT_DIR +# to have working out-of-source builds. +# Note that ".." is replaced by "__" in the RST files, +# to avoid having to match Blender's source tree. +EXTRA_SOURCE_FILES = ( + "../../../release/scripts/templates_py/bmesh_simple.py", + "../../../release/scripts/templates_py/operator_simple.py", + "../../../release/scripts/templates_py/ui_panel_simple.py", + "../../../release/scripts/templates_py/ui_previews_custom_icon.py", + "../examples/bge.constraints.py", + "../examples/bge.texture.1.py", + "../examples/bge.texture.2.py", + "../examples/bge.texture.py", + "../examples/bmesh.ops.1.py", + "../examples/bpy.app.translations.py", + ) + + # examples EXAMPLES_DIR = os.path.abspath(os.path.join(SCRIPT_DIR, "examples")) EXAMPLE_SET = set() @@ -1890,6 +1908,21 @@ def copy_handwritten_rsts(basepath): shutil.copy2(os.path.join(RST_DIR, f), basepath) +def copy_handwritten_extra(basepath): + for f_src in EXTRA_SOURCE_FILES: + if os.sep != "/": + f_src = os.sep.join(f_src.split("/")) + + f_dst = f_src.replace("..", "__") + + f_src = os.path.join(RST_DIR, f_src) + f_dst = os.path.join(basepath, f_dst) + + os.makedirs(os.path.dirname(f_dst), exist_ok=True) + + shutil.copy2(f_src, f_dst) + + def rna2sphinx(basepath): try: @@ -1921,35 +1954,48 @@ def rna2sphinx(basepath): # copy the other rsts copy_handwritten_rsts(basepath) + # copy source files referenced + copy_handwritten_extra(basepath) + -def align_sphinx_in_to_sphinx_in_tmp(): +def align_sphinx_in_to_sphinx_in_tmp(dir_src, dir_dst): ''' Move changed files from SPHINX_IN_TMP to SPHINX_IN ''' import filecmp - sphinx_in_files = set(os.listdir(SPHINX_IN)) - sphinx_in_tmp_files = set(os.listdir(SPHINX_IN_TMP)) + # possible the dir doesn't exist when running recursively + os.makedirs(dir_dst, exist_ok=True) + + sphinx_dst_files = set(os.listdir(dir_dst)) + sphinx_src_files = set(os.listdir(dir_src)) # remove deprecated files that have been removed - for f in sorted(sphinx_in_files): - if f not in sphinx_in_tmp_files: + for f in sorted(sphinx_dst_files): + if f not in sphinx_src_files: BPY_LOGGER.debug("\tdeprecated: %s" % f) - os.remove(os.path.join(SPHINX_IN, f)) + f_dst = os.path.join(dir_dst, f) + if os.path.isdir(f_dst): + shutil.rmtree(f_dst, True) + else: + os.remove(f_dst) # freshen with new files. - for f in sorted(sphinx_in_tmp_files): - f_from = os.path.join(SPHINX_IN_TMP, f) - f_to = os.path.join(SPHINX_IN, f) + for f in sorted(sphinx_src_files): + f_src = os.path.join(dir_src, f) + f_dst = os.path.join(dir_dst, f) - do_copy = True - if f in sphinx_in_files: - if filecmp.cmp(f_from, f_to): - do_copy = False + if os.path.isdir(f_src): + align_sphinx_in_to_sphinx_in_tmp(f_src, f_dst) + else: + do_copy = True + if f in sphinx_dst_files: + if filecmp.cmp(f_src, f_dst): + do_copy = False - if do_copy: - BPY_LOGGER.debug("\tupdating: %s" % f) - shutil.copy(f_from, f_to) + if do_copy: + BPY_LOGGER.debug("\tupdating: %s" % f) + shutil.copy(f_src, f_dst) def refactor_sphinx_log(sphinx_logfile): @@ -2036,7 +2082,7 @@ def main(): shutil.rmtree(SPHINX_OUT_PDF, True) else: # move changed files in SPHINX_IN - align_sphinx_in_to_sphinx_in_tmp() + align_sphinx_in_to_sphinx_in_tmp(SPHINX_IN_TMP, SPHINX_IN) # report which example files weren't used EXAMPLE_SET_UNUSED = EXAMPLE_SET - EXAMPLE_SET_USED diff --git a/doc/python_api/sphinx_doc_gen.sh b/doc/python_api/sphinx_doc_gen.sh index 7095808f251..b3bdd386f8c 100755 --- a/doc/python_api/sphinx_doc_gen.sh +++ b/doc/python_api/sphinx_doc_gen.sh @@ -3,11 +3,6 @@ # bash doc/python_api/sphinx_doc_gen.sh # ssh upload means you need an account on the server -if [ "$1" == "" ] ; then - echo "Expected a single argument for the username on blender.org, aborting" - exit 1 -fi - # ---------------------------------------------------------------------------- # Upload vars @@ -22,9 +17,15 @@ if [ -z $BLENDER_BIN ] ; then BLENDER_BIN="./blender.bin" fi -SSH_USER=$1 -SSH_HOST=$SSH_USER"@blender.org" -SSH_UPLOAD="/data/www/vhosts/www.blender.org/api" # blender_python_api_VERSION, added after +if [ "$1" == "" ] ; then + echo "Expected a single argument for the username on blender.org, skipping upload step!" + DO_UPLOAD=false +else + SSH_USER=$1 + SSH_HOST=$SSH_USER"@blender.org" + SSH_UPLOAD="/data/www/vhosts/www.blender.org/api" # blender_python_api_VERSION, added after +fi + # ---------------------------------------------------------------------------- # Blender Version & Info @@ -33,10 +34,12 @@ SSH_UPLOAD="/data/www/vhosts/www.blender.org/api" # blender_python_api_VERSION, # "_".join(str(v) for v in bpy.app.version) # custom blender vars blender_srcdir=$(dirname -- $0)/../.. -blender_version=$(grep "BLENDER_VERSION\s" "$blender_srcdir/source/blender/blenkernel/BKE_blender_version.h" | awk '{print $3}') -blender_version_char=$(grep "BLENDER_VERSION_CHAR\s" "$blender_srcdir/source/blender/blenkernel/BKE_blender_version.h" | awk '{print $3}') -blender_version_cycle=$(grep "BLENDER_VERSION_CYCLE\s" "$blender_srcdir/source/blender/blenkernel/BKE_blender_version.h" | awk '{print $3}') -blender_subversion=$(grep "BLENDER_SUBVERSION\s" "$blender_srcdir/source/blender/blenkernel/BKE_blender_version.h" | awk '{print $3}') +blender_version_header="$blender_srcdir/source/blender/blenkernel/BKE_blender_version.h" +blender_version=$(grep "BLENDER_VERSION\s" "$blender_version_header" | awk '{print $3}') +blender_version_char=$(grep "BLENDER_VERSION_CHAR\s" "$blender_version_header" | awk '{print $3}') +blender_version_cycle=$(grep "BLENDER_VERSION_CYCLE\s" "$blender_version_header" | awk '{print $3}') +blender_subversion=$(grep "BLENDER_SUBVERSION\s" "$blender_version_header" | awk '{print $3}') +unset blender_version_header if [ "$blender_version_cycle" = "release" ] ; then BLENDER_VERSION=$(expr $blender_version / 100)_$(expr $blender_version % 100)$blender_version_char"_release" @@ -48,6 +51,8 @@ SSH_UPLOAD_FULL=$SSH_UPLOAD/"blender_python_api_"$BLENDER_VERSION SPHINXBASE=doc/python_api +SPHINX_WORKDIR="$(mktemp --directory --suffix=.sphinx)" + # ---------------------------------------------------------------------------- # Generate reStructuredText (blender/python only) @@ -59,23 +64,25 @@ if $DO_EXE_BLENDER ; then -noaudio \ --factory-startup \ --python-exit-code 1 \ - --python $SPHINXBASE/sphinx_doc_gen.py + --python $SPHINXBASE/sphinx_doc_gen.py \ + -- \ + --output=$SPHINX_WORKDIR + - if (($? == 1)) ; then + if (($? != 0)) ; then echo "Generating documentation failed, aborting" exit 1 fi fi - # ---------------------------------------------------------------------------- # Generate HTML (sphinx) if $DO_OUT_HTML ; then - # sphinx-build -n -b html $SPHINXBASE/sphinx-in $SPHINXBASE/sphinx-out + # sphinx-build -n -b html $SPHINX_WORKDIR/sphinx-in $SPHINX_WORKDIR/sphinx-out # annoying bug in sphinx makes it very slow unless we do this. should report. - cd $SPHINXBASE + cd $SPHINX_WORKDIR sphinx-build -b html sphinx-in sphinx-out # XXX, saves space on upload and zip, should move HTML outside @@ -103,20 +110,21 @@ fi # Generate PDF (sphinx/laytex) if $DO_OUT_PDF ; then - sphinx-build -n -b latex $SPHINXBASE/sphinx-in $SPHINXBASE/sphinx-out - make -C $SPHINXBASE/sphinx-out - mv $SPHINXBASE/sphinx-out/contents.pdf $SPHINXBASE/sphinx-out/blender_python_reference_$BLENDER_VERSION.pdf + cd $SPHINX_WORKDIR + sphinx-build -n -b latex $SPHINX_WORKDIR/sphinx-in $SPHINX_WORKDIR/sphinx-out + make -C $SPHINX_WORKDIR/sphinx-out + mv $SPHINX_WORKDIR/sphinx-out/contents.pdf \ + $SPHINX_WORKDIR/sphinx-out/blender_python_reference_$BLENDER_VERSION.pdf fi - # ---------------------------------------------------------------------------- # Upload to blender servers, comment this section for testing if $DO_UPLOAD ; then - cp $SPHINXBASE/sphinx-out/contents.html $SPHINXBASE/sphinx-out/index.html + cp $SPHINX_WORKDIR/sphinx-out/contents.html $SPHINX_WORKDIR/sphinx-out/index.html ssh $SSH_USER@blender.org 'rm -rf '$SSH_UPLOAD_FULL'/*' - rsync --progress -ave "ssh -p 22" $SPHINXBASE/sphinx-out/* $SSH_HOST:$SSH_UPLOAD_FULL/ + rsync --progress -ave "ssh -p 22" $SPHINX_WORKDIR/sphinx-out/* $SSH_HOST:$SSH_UPLOAD_FULL/ ## symlink the dir to a static URL #ssh $SSH_USER@blender.org 'rm '$SSH_UPLOAD'/250PythonDoc && ln -s '$SSH_UPLOAD_FULL' '$SSH_UPLOAD'/250PythonDoc' @@ -134,11 +142,15 @@ if $DO_UPLOAD ; then if $DO_OUT_PDF ; then # rename so local PDF has matching name. - rsync --progress -ave "ssh -p 22" $SPHINXBASE/sphinx-out/blender_python_reference_$BLENDER_VERSION.pdf $SSH_HOST:$SSH_UPLOAD_FULL/blender_python_reference_$BLENDER_VERSION.pdf + rsync --progress -ave "ssh -p 22" \ + $SPHINX_WORKDIR/sphinx-out/blender_python_reference_$BLENDER_VERSION.pdf \ + $SSH_HOST:$SSH_UPLOAD_FULL/blender_python_reference_$BLENDER_VERSION.pdf fi if $DO_OUT_HTML_ZIP ; then - rsync --progress -ave "ssh -p 22" $SPHINXBASE/blender_python_reference_$BLENDER_VERSION.zip $SSH_HOST:$SSH_UPLOAD_FULL/blender_python_reference_$BLENDER_VERSION.zip + rsync --progress -ave "ssh -p 22" \ + $SPHINX_WORKDIR/blender_python_reference_$BLENDER_VERSION.zip \ + $SSH_HOST:$SSH_UPLOAD_FULL/blender_python_reference_$BLENDER_VERSION.zip fi fi @@ -149,5 +161,5 @@ fi echo "" echo "Finished! view the docs from: " -if $DO_OUT_HTML ; then echo " html:" $SPHINXBASE/sphinx-out/contents.html ; fi -if $DO_OUT_PDF ; then echo " pdf:" $SPHINXBASE/sphinx-out/blender_python_reference_$BLENDER_VERSION.pdf ; fi +if $DO_OUT_HTML ; then echo " html:" $SPHINX_WORKDIR/sphinx-out/contents.html ; fi +if $DO_OUT_PDF ; then echo " pdf:" $SPHINX_WORKDIR/sphinx-out/blender_python_reference_$BLENDER_VERSION.pdf ; fi diff --git a/extern/curve_fit_nd/curve_fit_nd.h b/extern/curve_fit_nd/curve_fit_nd.h index ff6b9513a9b..3649802a425 100644 --- a/extern/curve_fit_nd/curve_fit_nd.h +++ b/extern/curve_fit_nd/curve_fit_nd.h @@ -60,6 +60,7 @@ int curve_fit_cubic_to_points_db( const unsigned int points_len, const unsigned int dims, const double error_threshold, + const unsigned int calc_flag, const unsigned int *corners, unsigned int corners_len, @@ -72,6 +73,7 @@ int curve_fit_cubic_to_points_fl( const unsigned int points_len, const unsigned int dims, const float error_threshold, + const unsigned int calc_flag, const unsigned int *corners, const unsigned int corners_len, @@ -117,6 +119,10 @@ int curve_fit_cubic_to_points_single_fl( float r_handle_r[], float *r_error_sq); +enum { + CURVE_FIT_CALC_HIGH_QUALIY = (1 << 0), +}; + /* curve_fit_corners_detect.c */ /** diff --git a/extern/curve_fit_nd/intern/curve_fit_cubic.c b/extern/curve_fit_nd/intern/curve_fit_cubic.c index 1f42dd59304..1a0f7dcfdee 100644 --- a/extern/curve_fit_nd/intern/curve_fit_cubic.c +++ b/extern/curve_fit_nd/intern/curve_fit_cubic.c @@ -46,6 +46,12 @@ /* Take curvature into account when calculating the least square solution isn't usable. */ #define USE_CIRCULAR_FALLBACK +/* Use the maximum distance of any points from the direct line between 2 points + * to calculate how long the handles need to be. + * Can do a 'perfect' reversal of subdivision when for curve has symmetrical handles and doesn't change direction + * (as with an 'S' shape). */ +#define USE_OFFSET_FALLBACK + /* avoid re-calculating lengths multiple times */ #define USE_LENGTH_CACHE @@ -339,6 +345,44 @@ static double cubic_calc_error( return error_max_sq; } +#ifdef USE_OFFSET_FALLBACK +/** + * A version #cubic_calc_error where we don't need the split-index and can exit early when over the limit. + */ +static double cubic_calc_error_simple( + const Cubic *cubic, + const double *points_offset, + const uint points_offset_len, + const double *u, + const double error_threshold_sq, + const uint dims) + +{ + double error_max_sq = 0.0; + + const double *pt_real = points_offset + dims; +#ifdef USE_VLA + double pt_eval[dims]; +#else + double *pt_eval = alloca(sizeof(double) * dims); +#endif + + for (uint i = 1; i < points_offset_len - 1; i++, pt_real += dims) { + cubic_evaluate(cubic, u[i], dims, pt_eval); + + const double err_sq = len_squared_vnvn(pt_real, pt_eval, dims); + if (err_sq >= error_threshold_sq) { + return error_threshold_sq; + } + else if (err_sq >= error_max_sq) { + error_max_sq = err_sq; + } + } + + return error_max_sq; +} +#endif + /** * Bezier multipliers */ @@ -530,6 +574,85 @@ static void cubic_from_points_fallback( } #endif /* USE_CIRCULAR_FALLBACK */ + +#ifdef USE_OFFSET_FALLBACK + +static void cubic_from_points_offset_fallback( + const double *points_offset, + const uint points_offset_len, + const double tan_l[], + const double tan_r[], + const uint dims, + + Cubic *r_cubic) +{ + const double *p0 = &points_offset[0]; + const double *p3 = &points_offset[(points_offset_len - 1) * dims]; + +#ifdef USE_VLA + double dir_unit[dims]; + double a[2][dims]; + double tmp[dims]; +#else + double *dir_unit = alloca(sizeof(double) * dims); + double *a[2] = { + alloca(sizeof(double) * dims), + alloca(sizeof(double) * dims), + }; + double *tmp = alloca(sizeof(double) * dims); +#endif + + const double dir_dist = normalize_vn_vnvn(dir_unit, p3, p0, dims); + project_plane_vn_vnvn_normalized(a[0], tan_l, dir_unit, dims); + project_plane_vn_vnvn_normalized(a[1], tan_r, dir_unit, dims); + + /* only for better accuracy, not essential */ + normalize_vn(a[0], dims); + normalize_vn(a[1], dims); + + mul_vnvn_fl(a[1], a[1], -1, dims); + + double dists[2] = {0, 0}; + + const double *pt = points_offset; + for (uint i = 1; i < points_offset_len - 1; i++, pt += dims) { + for (uint k = 0; k < 2; k++) { + sub_vn_vnvn(tmp, p0, pt, dims); + project_vn_vnvn_normalized(tmp, tmp, a[k], dims); + dists[k] = max(dists[k], dot_vnvn(tmp, a[k], dims)); + } + } + + float alpha_l = (dists[0] / 0.75) / dot_vnvn(tan_l, a[0], dims); + float alpha_r = (dists[1] / 0.75) / -dot_vnvn(tan_r, a[1], dims); + + if (!(alpha_l > 0.0f)) { + alpha_l = dir_dist / 3.0; + } + if (!(alpha_r > 0.0f)) { + alpha_r = dir_dist / 3.0; + } + + double *p1 = CUBIC_PT(r_cubic, 1, dims); + double *p2 = CUBIC_PT(r_cubic, 2, dims); + + copy_vnvn(CUBIC_PT(r_cubic, 0, dims), p0, dims); + copy_vnvn(CUBIC_PT(r_cubic, 3, dims), p3, dims); + +#ifdef USE_ORIG_INDEX_DATA + r_cubic->orig_span = (points_offset_len - 1); +#endif + + /* p1 = p0 - (tan_l * alpha_l); + * p2 = p3 + (tan_r * alpha_r); + */ + msub_vn_vnvn_fl(p1, p0, tan_l, alpha_l, dims); + madd_vn_vnvn_fl(p2, p3, tan_r, alpha_r, dims); +} + +#endif /* USE_OFFSET_FALLBACK */ + + /** * Use least-squares method to find Bezier control points for region. */ @@ -918,6 +1041,8 @@ static bool fit_cubic_to_points( Cubic *cubic_test = alloca(cubic_alloc_size(dims)); + /* Run this so we use the non-circular calculation when the circular-fallback + * in 'cubic_from_points' failed to give a close enough result. */ #ifdef USE_CIRCULAR_FALLBACK if (!(error_max_sq < error_threshold_sq)) { /* Don't use the cubic calculated above, instead calculate a new fallback cubic, @@ -940,14 +1065,28 @@ static bool fit_cubic_to_points( } #endif + /* Test the offset fallback */ +#ifdef USE_OFFSET_FALLBACK + if (!(error_max_sq < error_threshold_sq)) { + /* Using the offset from the curve to calculate cubic handle length may give better results + * try this as a second fallback. */ + cubic_from_points_offset_fallback( + points_offset, points_offset_len, + tan_l, tan_r, dims, cubic_test); + const double error_max_sq_test = cubic_calc_error_simple( + cubic_test, points_offset, points_offset_len, u, error_max_sq, dims); + + if (error_max_sq > error_max_sq_test) { + error_max_sq = error_max_sq_test; + cubic_copy(r_cubic, cubic_test, dims); + } + } +#endif + *r_error_max_sq = error_max_sq; *r_split_index = split_index; - if (error_max_sq < error_threshold_sq) { - free(u); - return true; - } - else { + if (!(error_max_sq < error_threshold_sq)) { cubic_copy(cubic_test, r_cubic, dims); /* If error not too large, try some reparameterization and iteration */ @@ -965,25 +1104,28 @@ static bool fit_cubic_to_points( points_offset_coords_length, #endif u_prime, tan_l, tan_r, dims, cubic_test); - error_max_sq = cubic_calc_error( + + const double error_max_sq_test = cubic_calc_error( cubic_test, points_offset, points_offset_len, u_prime, dims, &split_index); - if (error_max_sq < error_threshold_sq) { - free(u_prime); - free(u); - - cubic_copy(r_cubic, cubic_test, dims); - *r_error_max_sq = error_max_sq; - *r_split_index = split_index; - return true; - } - else if (error_max_sq < *r_error_max_sq) { + if (error_max_sq > error_max_sq_test) { + error_max_sq = error_max_sq_test; cubic_copy(r_cubic, cubic_test, dims); *r_error_max_sq = error_max_sq; *r_split_index = split_index; } + if (!(error_max_sq < error_threshold_sq)) { + /* continue */ + } + else { + assert((error_max_sq < error_threshold_sq)); + free(u_prime); + free(u); + return true; + } + SWAP(double *, u, u_prime); } free(u_prime); @@ -991,6 +1133,10 @@ static bool fit_cubic_to_points( return false; } + else { + free(u); + return true; + } } static void fit_cubic_to_points_recursive( @@ -1002,6 +1148,7 @@ static void fit_cubic_to_points_recursive( const double tan_l[], const double tan_r[], const double error_threshold_sq, + const uint calc_flag, const uint dims, /* fill in the list */ CubicList *clist) @@ -1015,8 +1162,11 @@ static void fit_cubic_to_points_recursive( #ifdef USE_LENGTH_CACHE points_length_cache, #endif - tan_l, tan_r, error_threshold_sq, dims, - cubic, &error_max_sq, &split_index)) + tan_l, tan_r, + (calc_flag & CURVE_FIT_CALC_HIGH_QUALIY) ? DBL_EPSILON : error_threshold_sq, + dims, + cubic, &error_max_sq, &split_index) || + (error_max_sq < error_threshold_sq)) { cubic_list_prepend(clist, cubic); return; @@ -1068,13 +1218,13 @@ static void fit_cubic_to_points_recursive( #ifdef USE_LENGTH_CACHE points_length_cache, #endif - tan_l, tan_center, error_threshold_sq, dims, clist); + tan_l, tan_center, error_threshold_sq, calc_flag, dims, clist); fit_cubic_to_points_recursive( &points_offset[split_index * dims], points_offset_len - split_index, #ifdef USE_LENGTH_CACHE points_length_cache + split_index, #endif - tan_center, tan_r, error_threshold_sq, dims, clist); + tan_center, tan_r, error_threshold_sq, calc_flag, dims, clist); } @@ -1097,6 +1247,7 @@ int curve_fit_cubic_to_points_db( const uint points_len, const uint dims, const double error_threshold, + const uint calc_flag, const uint *corners, uint corners_len, @@ -1172,7 +1323,7 @@ int curve_fit_cubic_to_points_db( #ifdef USE_LENGTH_CACHE points_length_cache, #endif - tan_l, tan_r, error_threshold_sq, dims, &clist); + tan_l, tan_r, error_threshold_sq, calc_flag, dims, &clist); } else if (points_len == 1) { assert(points_offset_len == 1); @@ -1239,6 +1390,7 @@ int curve_fit_cubic_to_points_fl( const uint points_len, const uint dims, const float error_threshold, + const uint calc_flag, const uint *corners, const uint corners_len, @@ -1256,7 +1408,7 @@ int curve_fit_cubic_to_points_fl( uint cubic_array_len = 0; int result = curve_fit_cubic_to_points_db( - points_db, points_len, dims, error_threshold, corners, corners_len, + points_db, points_len, dims, error_threshold, calc_flag, corners, corners_len, &cubic_array_db, &cubic_array_len, r_cubic_orig_index, r_corner_index_array, r_corner_index_len); diff --git a/extern/curve_fit_nd/intern/curve_fit_inline.h b/extern/curve_fit_nd/intern/curve_fit_inline.h index f6656c0f9e9..c77e5c6e062 100644 --- a/extern/curve_fit_nd/intern/curve_fit_inline.h +++ b/extern/curve_fit_nd/intern/curve_fit_inline.h @@ -290,4 +290,28 @@ MINLINE bool equals_vnvn( return true; } +#if 0 +MINLINE void project_vn_vnvn( + double v_out[], const double p[], const double v_proj[], const uint dims) +{ + const double mul = dot_vnvn(p, v_proj, dims) / dot_vnvn(v_proj, v_proj, dims); + mul_vnvn_fl(v_out, v_proj, mul, dims); +} +#endif + +MINLINE void project_vn_vnvn_normalized( + double v_out[], const double p[], const double v_proj[], const uint dims) +{ + const double mul = dot_vnvn(p, v_proj, dims); + mul_vnvn_fl(v_out, v_proj, mul, dims); +} + +MINLINE void project_plane_vn_vnvn_normalized( + double v_out[], const double v[], const double v_plane[], const uint dims) +{ + assert(v != v_out); + project_vn_vnvn_normalized(v_out, v, v_plane, dims); + sub_vn_vnvn(v_out, v, v_out, dims); +} + /** \} */ diff --git a/intern/CMakeLists.txt b/intern/CMakeLists.txt index 43e5b6bff3e..9a5476772ab 100644 --- a/intern/CMakeLists.txt +++ b/intern/CMakeLists.txt @@ -34,6 +34,10 @@ add_subdirectory(mikktspace) add_subdirectory(glew-mx) add_subdirectory(eigen) +if (WITH_GAMEENGINE_DECKLINK) + add_subdirectory(decklink) +endif() + if(WITH_AUDASPACE) add_subdirectory(audaspace) endif() @@ -79,8 +83,10 @@ if(WITH_OPENSUBDIV) endif() # only windows needs utf16 converter +# gpudirect is a runtime interface to the nVidia's DVP driver, only for windows if(WIN32) add_subdirectory(utfconv) + add_subdirectory(gpudirect) endif() if(WITH_OPENVDB) diff --git a/intern/atomic/intern/atomic_ops_unix.h b/intern/atomic/intern/atomic_ops_unix.h index bf54750ea0d..55c00024244 100644 --- a/intern/atomic/intern/atomic_ops_unix.h +++ b/intern/atomic/intern/atomic_ops_unix.h @@ -129,23 +129,24 @@ ATOMIC_INLINE uint32_t atomic_cas_uint32(uint32_t *v, uint32_t old, uint32_t _ne #elif (defined(__i386__) || defined(__amd64__) || defined(__x86_64__)) ATOMIC_INLINE uint32_t atomic_add_uint32(uint32_t *p, uint32_t x) { + uint32_t ret = x; asm volatile ( "lock; xaddl %0, %1;" - : "+r" (x), "=m" (*p) /* Outputs. */ + : "+r" (ret), "=m" (*p) /* Outputs. */ : "m" (*p) /* Inputs. */ ); - return x; + return ret+x; } ATOMIC_INLINE uint32_t atomic_sub_uint32(uint32_t *p, uint32_t x) { - x = (uint32_t)(-(int32_t)x); + ret = (uint32_t)(-(int32_t)x); asm volatile ( "lock; xaddl %0, %1;" - : "+r" (x), "=m" (*p) /* Outputs. */ + : "+r" (ret), "=m" (*p) /* Outputs. */ : "m" (*p) /* Inputs. */ ); - return x; + return ret-x; } ATOMIC_INLINE uint32_t atomic_cas_uint32(uint32_t *v, uint32_t old, uint32_t _new) diff --git a/intern/cycles/app/cycles_xml.cpp b/intern/cycles/app/cycles_xml.cpp index 9f967a4bde9..3aca46e2dc7 100644 --- a/intern/cycles/app/cycles_xml.cpp +++ b/intern/cycles/app/cycles_xml.cpp @@ -73,18 +73,6 @@ struct XMLReadState : public XMLReader { /* Attribute Reading */ -static bool xml_read_bool(bool *value, pugi::xml_node node, const char *name) -{ - pugi::xml_attribute attr = node.attribute(name); - - if(attr) { - *value = (string_iequals(attr.value(), "true")) || (atoi(attr.value()) != 0); - return true; - } - - return false; -} - static bool xml_read_int(int *value, pugi::xml_node node, const char *name) { pugi::xml_attribute attr = node.attribute(name); @@ -193,18 +181,6 @@ static bool xml_read_string(string *str, pugi::xml_node node, const char *name) return false; } -static bool xml_read_ustring(ustring *str, pugi::xml_node node, const char *name) -{ - pugi::xml_attribute attr = node.attribute(name); - - if(attr) { - *str = ustring(attr.value()); - return true; - } - - return false; -} - static bool xml_equal_string(pugi::xml_node node, const char *name, const char *value) { pugi::xml_attribute attr = node.attribute(name); @@ -215,24 +191,6 @@ static bool xml_equal_string(pugi::xml_node node, const char *name, const char * return false; } -static bool xml_read_enum_value(int *value, NodeEnum& enm, pugi::xml_node node, const char *name) -{ - pugi::xml_attribute attr = node.attribute(name); - - if(attr) { - ustring ustr(attr.value()); - - if(enm.exists(ustr)) { - *value = enm[ustr]; - return true; - } - else - fprintf(stderr, "Unknown value \"%s\" for attribute \"%s\".\n", ustr.c_str(), name); - } - - return false; -} - /* Camera */ static void xml_read_camera(XMLReadState& state, pugi::xml_node node) @@ -267,47 +225,74 @@ static void xml_read_shader_graph(XMLReadState& state, Shader *shader, pugi::xml { xml_read_node(state, shader, graph_node); - ShaderManager *manager = state.scene->shader_manager; ShaderGraph *graph = new ShaderGraph(); - map<string, ShaderNode*> nodemap; - - nodemap["output"] = graph->output(); + /* local state, shader nodes can't link to nodes outside the shader graph */ + XMLReader graph_reader; + graph_reader.node_map[ustring("output")] = graph->output(); for(pugi::xml_node node = graph_node.first_child(); node; node = node.next_sibling()) { - ShaderNode *snode = NULL; + ustring node_name(node.name()); - /* ToDo: Add missing nodes - * RGBCurvesNode, VectorCurvesNode, RGBRampNode and ConvertNode (RGB -> BW). - */ + if(node_name == "connect") { + /* connect nodes */ + vector<string> from_tokens, to_tokens; - if(string_iequals(node.name(), "image_texture")) { - ImageTextureNode *img = new ImageTextureNode(); + string_split(from_tokens, node.attribute("from").value()); + string_split(to_tokens, node.attribute("to").value()); - xml_read_string(&img->filename, node, "src"); - img->filename = path_join(state.base, img->filename); - - xml_read_enum_value((int*)&img->color_space, ImageTextureNode::color_space_enum, node, "color_space"); - xml_read_enum_value((int*)&img->projection, ImageTextureNode::projection_enum, node, "projection"); - xml_read_float(&img->projection_blend, node, "projection_blend"); + if(from_tokens.size() == 2 && to_tokens.size() == 2) { + ustring from_node_name(from_tokens[0]); + ustring from_socket_name(from_tokens[1]); + ustring to_node_name(to_tokens[0]); + ustring to_socket_name(to_tokens[1]); - /* ToDo: Interpolation */ + /* find nodes and sockets */ + ShaderOutput *output = NULL; + ShaderInput *input = NULL; - snode = img; - } - else if(string_iequals(node.name(), "environment_texture")) { - EnvironmentTextureNode *env = new EnvironmentTextureNode(); + if(graph_reader.node_map.find(from_node_name) != graph_reader.node_map.end()) { + ShaderNode *fromnode = (ShaderNode*)graph_reader.node_map[from_node_name]; - xml_read_string(&env->filename, node, "src"); - env->filename = path_join(state.base, env->filename); - - xml_read_enum_value((int*)&env->color_space, EnvironmentTextureNode::color_space_enum, node, "color_space"); - xml_read_enum_value((int*)&env->projection, EnvironmentTextureNode::projection_enum, node, "projection"); + foreach(ShaderOutput *out, fromnode->outputs) + if(string_iequals(xml_socket_name(out->name().c_str()), from_socket_name.c_str())) + output = out; + + if(!output) + fprintf(stderr, "Unknown output socket name \"%s\" on \"%s\".\n", from_node_name.c_str(), from_socket_name.c_str()); + } + else + fprintf(stderr, "Unknown shader node name \"%s\".\n", from_node_name.c_str()); + + if(graph_reader.node_map.find(to_node_name) != graph_reader.node_map.end()) { + ShaderNode *tonode = (ShaderNode*)graph_reader.node_map[to_node_name]; + + foreach(ShaderInput *in, tonode->inputs) + if(string_iequals(xml_socket_name(in->name().c_str()), to_socket_name.c_str())) + input = in; + + if(!input) + fprintf(stderr, "Unknown input socket name \"%s\" on \"%s\".\n", to_socket_name.c_str(), to_node_name.c_str()); + } + else + fprintf(stderr, "Unknown shader node name \"%s\".\n", to_node_name.c_str()); - snode = env; + /* connect */ + if(output && input) + graph->connect(output, input); + } + else + fprintf(stderr, "Invalid from or to value for connect node.\n"); + + continue; } + + ShaderNode *snode = NULL; + #ifdef WITH_OSL - else if(string_iequals(node.name(), "osl_shader")) { + if(node_name == "osl_shader") { + ShaderManager *manager = state.scene->shader_manager; + if(manager->use_osl()) { std::string filepath; @@ -320,390 +305,54 @@ static void xml_read_shader_graph(XMLReadState& state, Shader *shader, pugi::xml if(!snode) { fprintf(stderr, "Failed to create OSL node from \"%s\".\n", filepath.c_str()); + continue; } } else { fprintf(stderr, "OSL node missing \"src\" attribute.\n"); + continue; } } else { fprintf(stderr, "OSL node without using --shadingsys osl.\n"); + continue; } } + else #endif - else if(string_iequals(node.name(), "sky_texture")) { - SkyTextureNode *sky = new SkyTextureNode(); - - xml_read_enum_value((int*)&sky->type, SkyTextureNode::type_enum, node, "type"); - xml_read_float3(&sky->sun_direction, node, "sun_direction"); - xml_read_float(&sky->turbidity, node, "turbidity"); - xml_read_float(&sky->ground_albedo, node, "ground_albedo"); - - snode = sky; - } - else if(string_iequals(node.name(), "noise_texture")) { - snode = new NoiseTextureNode(); - } - else if(string_iequals(node.name(), "checker_texture")) { - snode = new CheckerTextureNode(); - } - else if(string_iequals(node.name(), "brick_texture")) { - BrickTextureNode *brick = new BrickTextureNode(); + { + /* exception for name collision */ + if(node_name == "background") + node_name = "background_shader"; - xml_read_float(&brick->offset, node, "offset"); - xml_read_int(&brick->offset_frequency, node, "offset_frequency"); - xml_read_float(&brick->squash, node, "squash"); - xml_read_int(&brick->squash_frequency, node, "squash_frequency"); + const NodeType *node_type = NodeType::find(node_name); - snode = brick; - } - else if(string_iequals(node.name(), "gradient_texture")) { - GradientTextureNode *blend = new GradientTextureNode(); - xml_read_enum_value((int*)&blend->type, GradientTextureNode::type_enum, node, "type"); - snode = blend; - } - else if(string_iequals(node.name(), "voronoi_texture")) { - VoronoiTextureNode *voronoi = new VoronoiTextureNode(); - xml_read_enum_value((int*)&voronoi->coloring, VoronoiTextureNode::coloring_enum, node, "coloring"); - snode = voronoi; - } - else if(string_iequals(node.name(), "musgrave_texture")) { - MusgraveTextureNode *musgrave = new MusgraveTextureNode(); - xml_read_enum_value((int*)&musgrave->type, MusgraveTextureNode::type_enum, node, "type"); - snode = musgrave; - } - else if(string_iequals(node.name(), "magic_texture")) { - MagicTextureNode *magic = new MagicTextureNode(); - xml_read_int(&magic->depth, node, "depth"); - snode = magic; - } - else if(string_iequals(node.name(), "wave_texture")) { - WaveTextureNode *wave = new WaveTextureNode(); - xml_read_enum_value((int*)&wave->type, WaveTextureNode::type_enum, node, "type"); - xml_read_enum_value((int*)&wave->profile, WaveTextureNode::profile_enum, node, "profile"); - snode = wave; - } - else if(string_iequals(node.name(), "normal")) { - NormalNode *normal = new NormalNode(); - xml_read_float3(&normal->direction, node, "direction"); - snode = normal; - } - else if(string_iequals(node.name(), "bump")) { - BumpNode *bump = new BumpNode(); - xml_read_bool(&bump->invert, node, "invert"); - snode = bump; - } - else if(string_iequals(node.name(), "mapping")) { - MappingNode *map = new MappingNode(); - - TextureMapping *texmap = &map->tex_mapping; - xml_read_enum_value((int*) &texmap->type, TextureMapping::type_enum, node, "type"); - xml_read_enum_value((int*) &texmap->projection, TextureMapping::projection_enum, node, "projection"); - xml_read_enum_value((int*) &texmap->x_mapping, TextureMapping::mapping_enum, node, "x_mapping"); - xml_read_enum_value((int*) &texmap->y_mapping, TextureMapping::mapping_enum, node, "y_mapping"); - xml_read_enum_value((int*) &texmap->z_mapping, TextureMapping::mapping_enum, node, "z_mapping"); - xml_read_bool(&texmap->use_minmax, node, "use_minmax"); - if(texmap->use_minmax) { - xml_read_float3(&texmap->min, node, "min"); - xml_read_float3(&texmap->max, node, "max"); + if(!node_type) { + fprintf(stderr, "Unknown shader node \"%s\".\n", node.name()); + continue; + } + else if(node_type->type != NodeType::SHADER) { + fprintf(stderr, "Node type \"%s\" is not a shader node.\n", node_type->name.c_str()); + continue; } - xml_read_float3(&texmap->translation, node, "translation"); - xml_read_float3(&texmap->rotation, node, "rotation"); - xml_read_float3(&texmap->scale, node, "scale"); - snode = map; - } - else if(string_iequals(node.name(), "anisotropic_bsdf")) { - AnisotropicBsdfNode *aniso = new AnisotropicBsdfNode(); - xml_read_enum_value((int*)&aniso->distribution, AnisotropicBsdfNode::distribution_enum, node, "distribution"); - snode = aniso; - } - else if(string_iequals(node.name(), "diffuse_bsdf")) { - snode = new DiffuseBsdfNode(); - } - else if(string_iequals(node.name(), "translucent_bsdf")) { - snode = new TranslucentBsdfNode(); - } - else if(string_iequals(node.name(), "transparent_bsdf")) { - snode = new TransparentBsdfNode(); - } - else if(string_iequals(node.name(), "velvet_bsdf")) { - snode = new VelvetBsdfNode(); + snode = (ShaderNode*) node_type->create(node_type); } - else if(string_iequals(node.name(), "toon_bsdf")) { - ToonBsdfNode *toon = new ToonBsdfNode(); - xml_read_enum_value((int*)&toon->component, ToonBsdfNode::component_enum, node, "component"); - snode = toon; - } - else if(string_iequals(node.name(), "glossy_bsdf")) { - GlossyBsdfNode *glossy = new GlossyBsdfNode(); - xml_read_enum_value((int*)&glossy->distribution, GlossyBsdfNode::distribution_enum, node, "distribution"); - snode = glossy; - } - else if(string_iequals(node.name(), "glass_bsdf")) { - GlassBsdfNode *diel = new GlassBsdfNode(); - xml_read_enum_value((int*)&diel->distribution, GlassBsdfNode::distribution_enum, node, "distribution"); - snode = diel; - } - else if(string_iequals(node.name(), "refraction_bsdf")) { - RefractionBsdfNode *diel = new RefractionBsdfNode(); - xml_read_enum_value((int*)&diel->distribution, RefractionBsdfNode::distribution_enum, node, "distribution"); - snode = diel; - } - else if(string_iequals(node.name(), "hair_bsdf")) { - HairBsdfNode *hair = new HairBsdfNode(); - xml_read_enum_value((int*)&hair->component, HairBsdfNode::component_enum, node, "component"); - snode = hair; - } - else if(string_iequals(node.name(), "emission")) { - snode = new EmissionNode(); - } - else if(string_iequals(node.name(), "ambient_occlusion")) { - snode = new AmbientOcclusionNode(); - } - else if(string_iequals(node.name(), "background")) { - snode = new BackgroundNode(); - } - else if(string_iequals(node.name(), "holdout")) { - snode = new HoldoutNode(); - } - else if(string_iequals(node.name(), "absorption_volume")) { - snode = new AbsorptionVolumeNode(); - } - else if(string_iequals(node.name(), "scatter_volume")) { - snode = new ScatterVolumeNode(); - } - else if(string_iequals(node.name(), "subsurface_scattering")) { - SubsurfaceScatteringNode *sss = new SubsurfaceScatteringNode(); - - string falloff; - xml_read_string(&falloff, node, "falloff"); - if(falloff == "cubic") - sss->closure = CLOSURE_BSSRDF_CUBIC_ID; - else if(falloff == "gaussian") - sss->closure = CLOSURE_BSSRDF_GAUSSIAN_ID; - else /*if(falloff == "burley")*/ - sss->closure = CLOSURE_BSSRDF_BURLEY_ID; - - snode = sss; - } - else if(string_iequals(node.name(), "geometry")) { - snode = new GeometryNode(); - } - else if(string_iequals(node.name(), "texture_coordinate")) { - snode = new TextureCoordinateNode(); - } - else if(string_iequals(node.name(), "light_path")) { - snode = new LightPathNode(); - } - else if(string_iequals(node.name(), "light_falloff")) { - snode = new LightFalloffNode(); - } - else if(string_iequals(node.name(), "object_info")) { - snode = new ObjectInfoNode(); - } - else if(string_iequals(node.name(), "particle_info")) { - snode = new ParticleInfoNode(); - } - else if(string_iequals(node.name(), "hair_info")) { - snode = new HairInfoNode(); - } - else if(string_iequals(node.name(), "value")) { - ValueNode *value = new ValueNode(); - xml_read_float(&value->value, node, "value"); - snode = value; - } - else if(string_iequals(node.name(), "color")) { - ColorNode *color = new ColorNode(); - xml_read_float3(&color->value, node, "value"); - snode = color; - } - else if(string_iequals(node.name(), "mix_closure")) { - snode = new MixClosureNode(); - } - else if(string_iequals(node.name(), "add_closure")) { - snode = new AddClosureNode(); - } - else if(string_iequals(node.name(), "invert")) { - snode = new InvertNode(); - } - else if(string_iequals(node.name(), "mix")) { - /* ToDo: Tag Mix case for optimization */ - MixNode *mix = new MixNode(); - xml_read_enum_value((int*)&mix->type, MixNode::type_enum, node, "type"); - xml_read_bool(&mix->use_clamp, node, "use_clamp"); - snode = mix; - } - else if(string_iequals(node.name(), "gamma")) { - snode = new GammaNode(); - } - else if(string_iequals(node.name(), "brightness")) { - snode = new BrightContrastNode(); - } - else if(string_iequals(node.name(), "combine_rgb")) { - snode = new CombineRGBNode(); - } - else if(string_iequals(node.name(), "separate_rgb")) { - snode = new SeparateRGBNode(); - } - else if(string_iequals(node.name(), "combine_hsv")) { - snode = new CombineHSVNode(); - } - else if(string_iequals(node.name(), "separate_hsv")) { - snode = new SeparateHSVNode(); - } - else if(string_iequals(node.name(), "combine_xyz")) { - snode = new CombineXYZNode(); - } - else if(string_iequals(node.name(), "separate_xyz")) { - snode = new SeparateXYZNode(); - } - else if(string_iequals(node.name(), "hsv")) { - snode = new HSVNode(); - } - else if(string_iequals(node.name(), "wavelength")) { - snode = new WavelengthNode(); - } - else if(string_iequals(node.name(), "blackbody")) { - snode = new BlackbodyNode(); - } - else if(string_iequals(node.name(), "attribute")) { - AttributeNode *attr = new AttributeNode(); - xml_read_ustring(&attr->attribute, node, "attribute"); - snode = attr; - } - else if(string_iequals(node.name(), "uv_map")) { - UVMapNode *uvm = new UVMapNode(); - xml_read_ustring(&uvm->attribute, node, "uv_map"); - snode = uvm; - } - else if(string_iequals(node.name(), "camera")) { - snode = new CameraNode(); - } - else if(string_iequals(node.name(), "fresnel")) { - snode = new FresnelNode(); - } - else if(string_iequals(node.name(), "layer_weight")) { - snode = new LayerWeightNode(); - } - else if(string_iequals(node.name(), "wireframe")) { - WireframeNode *wire = new WireframeNode; - xml_read_bool(&wire->use_pixel_size, node, "use_pixel_size"); - snode = wire; - } - else if(string_iequals(node.name(), "normal_map")) { - NormalMapNode *nmap = new NormalMapNode; - xml_read_ustring(&nmap->attribute, node, "attribute"); - xml_read_enum_value((int*)&nmap->space, NormalMapNode::space_enum, node, "space"); - snode = nmap; - } - else if(string_iequals(node.name(), "tangent")) { - TangentNode *tangent = new TangentNode; - xml_read_ustring(&tangent->attribute, node, "attribute"); - xml_read_enum_value((int*)&tangent->direction_type, TangentNode::direction_type_enum, node, "direction_type"); - xml_read_enum_value((int*)&tangent->axis, TangentNode::axis_enum, node, "axis"); - snode = tangent; - } - else if(string_iequals(node.name(), "math")) { - MathNode *math = new MathNode(); - xml_read_enum_value((int*)&math->type, MathNode::type_enum, node, "type"); - xml_read_bool(&math->use_clamp, node, "use_clamp"); - snode = math; - } - else if(string_iequals(node.name(), "vector_math")) { - VectorMathNode *vmath = new VectorMathNode(); - xml_read_enum_value((int*)&vmath->type, VectorMathNode::type_enum, node, "type"); - snode = vmath; - } - else if(string_iequals(node.name(), "vector_transform")) { - VectorTransformNode *vtransform = new VectorTransformNode(); - xml_read_enum_value((int*)&vtransform->type, VectorTransformNode::type_enum, node, "type"); - xml_read_enum_value((int*)&vtransform->convert_from, VectorTransformNode::convert_space_enum, node, "convert_from"); - xml_read_enum_value((int*)&vtransform->convert_to, VectorTransformNode::convert_space_enum, node, "convert_to"); - snode = vtransform; - } - else if(string_iequals(node.name(), "connect")) { - /* connect nodes */ - vector<string> from_tokens, to_tokens; - - string_split(from_tokens, node.attribute("from").value()); - string_split(to_tokens, node.attribute("to").value()); - if(from_tokens.size() == 2 && to_tokens.size() == 2) { - /* find nodes and sockets */ - ShaderOutput *output = NULL; - ShaderInput *input = NULL; - - if(nodemap.find(from_tokens[0]) != nodemap.end()) { - ShaderNode *fromnode = nodemap[from_tokens[0]]; + xml_read_node(graph_reader, snode, node); - foreach(ShaderOutput *out, fromnode->outputs) - if(string_iequals(xml_socket_name(out->name().c_str()), from_tokens[1])) - output = out; - - if(!output) - fprintf(stderr, "Unknown output socket name \"%s\" on \"%s\".\n", from_tokens[1].c_str(), from_tokens[0].c_str()); - } - else - fprintf(stderr, "Unknown shader node name \"%s\".\n", from_tokens[0].c_str()); - - if(nodemap.find(to_tokens[0]) != nodemap.end()) { - ShaderNode *tonode = nodemap[to_tokens[0]]; - - foreach(ShaderInput *in, tonode->inputs) - if(string_iequals(xml_socket_name(in->name().c_str()), to_tokens[1])) - input = in; - - if(!input) - fprintf(stderr, "Unknown input socket name \"%s\" on \"%s\".\n", to_tokens[1].c_str(), to_tokens[0].c_str()); - } - else - fprintf(stderr, "Unknown shader node name \"%s\".\n", to_tokens[0].c_str()); - - /* connect */ - if(output && input) - graph->connect(output, input); - } - else - fprintf(stderr, "Invalid from or to value for connect node.\n"); + if(node_name == "image_texture") { + ImageTextureNode *img = (ImageTextureNode*) snode; + img->filename = path_join(state.base, img->filename.string()); + } + else if(node_name == "environment_texture") { + EnvironmentTextureNode *env = (EnvironmentTextureNode*) snode; + env->filename = path_join(state.base, env->filename.string()); } - else - fprintf(stderr, "Unknown shader node \"%s\".\n", node.name()); if(snode) { /* add to graph */ graph->add(snode); - - /* add to map for name lookups */ - string name = ""; - xml_read_string(&name, node, "name"); - - nodemap[name] = snode; - - /* read input values */ - for(pugi::xml_attribute attr = node.first_attribute(); attr; attr = attr.next_attribute()) { - foreach(ShaderInput *in, snode->inputs) { - if(string_iequals(in->name().c_str(), attr.name())) { - switch(in->type()) { - case SocketType::FLOAT: - case SocketType::INT: - xml_read_float(&in->value_float(), node, attr.name()); - break; - case SocketType::COLOR: - case SocketType::VECTOR: - case SocketType::POINT: - case SocketType::NORMAL: - xml_read_float3(&in->value(), node, attr.name()); - break; - case SocketType::STRING: - xml_read_ustring( &in->value_string(), node, attr.name() ); - break; - default: - break; - } - } - } - } } } diff --git a/intern/cycles/blender/blender_mesh.cpp b/intern/cycles/blender/blender_mesh.cpp index 80db51148e6..4bd385c4200 100644 --- a/intern/cycles/blender/blender_mesh.cpp +++ b/intern/cycles/blender/blender_mesh.cpp @@ -801,7 +801,7 @@ Mesh *BlenderSync::sync_mesh(BL::Object& b_ob, } /* free derived mesh */ - b_data.meshes.remove(b_mesh); + b_data.meshes.remove(b_mesh, false); } } mesh->geometry_flags = requested_geometry_flags; @@ -1013,7 +1013,7 @@ void BlenderSync::sync_mesh_motion(BL::Object& b_ob, sync_curves(mesh, b_mesh, b_ob, true, time_index); /* free derived mesh */ - b_data.meshes.remove(b_mesh); + b_data.meshes.remove(b_mesh, false); } CCL_NAMESPACE_END diff --git a/intern/cycles/blender/blender_shader.cpp b/intern/cycles/blender/blender_shader.cpp index 7a13641a312..7ca23f23cb4 100644 --- a/intern/cycles/blender/blender_shader.cpp +++ b/intern/cycles/blender/blender_shader.cpp @@ -153,28 +153,31 @@ static void set_default_value(ShaderInput *input, BL::BlendData& b_data, BL::ID& b_id) { + Node *node = input->parent; + const SocketType& socket = input->socket_type; + /* copy values for non linked inputs */ switch(input->type()) { case SocketType::FLOAT: { - input->set(get_float(b_sock.ptr, "default_value")); + node->set(socket, get_float(b_sock.ptr, "default_value")); break; } case SocketType::INT: { - input->set(get_int(b_sock.ptr, "default_value")); + node->set(socket, get_int(b_sock.ptr, "default_value")); break; } case SocketType::COLOR: { - input->set(float4_to_float3(get_float4(b_sock.ptr, "default_value"))); + node->set(socket, float4_to_float3(get_float4(b_sock.ptr, "default_value"))); break; } case SocketType::NORMAL: case SocketType::POINT: case SocketType::VECTOR: { - input->set(get_float3(b_sock.ptr, "default_value")); + node->set(socket, get_float3(b_sock.ptr, "default_value")); break; } case SocketType::STRING: { - input->set((ustring)blender_absolute_path(b_data, b_id, get_string(b_sock.ptr, "default_value"))); + node->set(socket, (ustring)blender_absolute_path(b_data, b_id, get_string(b_sock.ptr, "default_value"))); break; } default: @@ -390,6 +393,9 @@ static ShaderNode *add_node(Scene *scene, case BL::ShaderNodeBsdfAnisotropic::distribution_GGX: aniso->distribution = CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID; break; + case BL::ShaderNodeBsdfAnisotropic::distribution_MULTI_GGX: + aniso->distribution = CLOSURE_BSDF_MICROFACET_MULTI_GGX_ANISO_ID; + break; case BL::ShaderNodeBsdfAnisotropic::distribution_ASHIKHMIN_SHIRLEY: aniso->distribution = CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ANISO_ID; break; @@ -436,6 +442,9 @@ static ShaderNode *add_node(Scene *scene, case BL::ShaderNodeBsdfGlossy::distribution_ASHIKHMIN_SHIRLEY: glossy->distribution = CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ANISO_ID; break; + case BL::ShaderNodeBsdfGlossy::distribution_MULTI_GGX: + glossy->distribution = CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID; + break; } node = glossy; } @@ -452,6 +461,9 @@ static ShaderNode *add_node(Scene *scene, case BL::ShaderNodeBsdfGlass::distribution_GGX: glass->distribution = CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID; break; + case BL::ShaderNodeBsdfGlass::distribution_MULTI_GGX: + glass->distribution = CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID; + break; } node = glass; } @@ -616,7 +628,7 @@ static ShaderNode *add_node(Scene *scene, /* TODO(sergey): Does not work properly when we change builtin type. */ if(b_image.is_updated()) { scene->image_manager->tag_reload_image( - image->filename, + image->filename.string(), image->builtin_data, get_image_interpolation(b_image_node), get_image_extension(b_image_node)); @@ -662,7 +674,7 @@ static ShaderNode *add_node(Scene *scene, /* TODO(sergey): Does not work properly when we change builtin type. */ if(b_image.is_updated()) { scene->image_manager->tag_reload_image( - env->filename, + env->filename.string(), env->builtin_data, get_image_interpolation(b_env_node), EXTENSION_REPEAT); @@ -799,7 +811,7 @@ static ShaderNode *add_node(Scene *scene, if(true) { b_point_density_node.cache_point_density(b_scene, settings); scene->image_manager->tag_reload_image( - point_density->filename, + point_density->filename.string(), point_density->builtin_data, point_density->interpolation, EXTENSION_CLIP); @@ -1153,13 +1165,12 @@ void BlenderSync::sync_materials(bool update_all) add_nodes(scene, b_engine, b_data, b_scene, !preview, graph, b_ntree); } else { - ShaderNode *closure, *out; - - closure = graph->add(new DiffuseBsdfNode()); - closure->input("Color")->set(get_float3(b_mat->diffuse_color())); - out = graph->output(); + DiffuseBsdfNode *diffuse = new DiffuseBsdfNode(); + diffuse->color = get_float3(b_mat->diffuse_color()); + graph->add(diffuse); - graph->connect(closure->output("BSDF"), out->input("Surface")); + ShaderNode *out = graph->output(); + graph->connect(diffuse->output("BSDF"), out->input("Surface")); } /* settings */ @@ -1202,13 +1213,12 @@ void BlenderSync::sync_world(bool update_all) shader->volume_interpolation_method = get_volume_interpolation(cworld); } else if(b_world) { - ShaderNode *closure, *out; - - closure = graph->add(new BackgroundNode()); - closure->input("Color")->set(get_float3(b_world.horizon_color())); - out = graph->output(); + BackgroundNode *background = new BackgroundNode(); + background->color = get_float3(b_world.horizon_color()); + graph->add(background); - graph->connect(closure->output("Background"), out->input("Surface")); + ShaderNode *out = graph->output(); + graph->connect(background->output("Background"), out->input("Surface")); } if(b_world) { @@ -1287,7 +1297,6 @@ void BlenderSync::sync_lamps(bool update_all) add_nodes(scene, b_engine, b_data, b_scene, !preview, graph, b_ntree); } else { - ShaderNode *closure, *out; float strength = 1.0f; if(b_lamp->type() == BL::Lamp::type_POINT || @@ -1297,12 +1306,13 @@ void BlenderSync::sync_lamps(bool update_all) strength = 100.0f; } - closure = graph->add(new EmissionNode()); - closure->input("Color")->set(get_float3(b_lamp->color())); - closure->input("Strength")->set(strength); - out = graph->output(); + EmissionNode *emission = new EmissionNode(); + emission->color = get_float3(b_lamp->color()); + emission->strength = strength; + graph->add(emission); - graph->connect(closure->output("Emission"), out->input("Surface")); + ShaderNode *out = graph->output(); + graph->connect(emission->output("Emission"), out->input("Surface")); } shader->set_graph(graph); diff --git a/intern/cycles/bvh/bvh_build.cpp b/intern/cycles/bvh/bvh_build.cpp index 87a889955fe..3f687224eee 100644 --- a/intern/cycles/bvh/bvh_build.cpp +++ b/intern/cycles/bvh/bvh_build.cpp @@ -205,6 +205,9 @@ void BVHBuild::add_references(BVHRange& root) foreach(Object *ob, objects) { if(params.top_level) { + if(!ob->is_traceable()) { + continue; + } if(!ob->mesh->is_instanced()) { num_alloc_references += ob->mesh->num_triangles(); num_alloc_references += count_curve_segments(ob->mesh); @@ -226,6 +229,10 @@ void BVHBuild::add_references(BVHRange& root) foreach(Object *ob, objects) { if(params.top_level) { + if(!ob->is_traceable()) { + ++i; + continue; + } if(!ob->mesh->is_instanced()) add_reference_mesh(bounds, center, ob->mesh, i); else diff --git a/intern/cycles/bvh/bvh_split.cpp b/intern/cycles/bvh/bvh_split.cpp index 3665fb42bc2..bf68b41021f 100644 --- a/intern/cycles/bvh/bvh_split.cpp +++ b/intern/cycles/bvh/bvh_split.cpp @@ -404,7 +404,7 @@ void BVHSpatialSplit::split_object_reference(const Object *object, BoundBox& right_bounds) { Mesh *mesh = object->mesh; - for(int tri_idx = 0; tri_idx < mesh->triangles.size(); ++tri_idx) { + for(int tri_idx = 0; tri_idx < mesh->num_triangles(); ++tri_idx) { split_triangle_primitive(mesh, &object->tfm, tri_idx, diff --git a/intern/cycles/device/device_memory.h b/intern/cycles/device/device_memory.h index 8c32d03135e..5b5b4dc6802 100644 --- a/intern/cycles/device/device_memory.h +++ b/intern/cycles/device/device_memory.h @@ -150,6 +150,11 @@ template<> struct device_type_traits<float4> { static const int num_elements = 4; }; +template<> struct device_type_traits<half> { + static const DataType data_type = TYPE_HALF; + static const int num_elements = 1; +}; + template<> struct device_type_traits<half4> { static const DataType data_type = TYPE_HALF; static const int num_elements = 4; diff --git a/intern/cycles/graph/node.cpp b/intern/cycles/graph/node.cpp index 941a66741c5..3c228a716d5 100644 --- a/intern/cycles/graph/node.cpp +++ b/intern/cycles/graph/node.cpp @@ -82,6 +82,12 @@ void Node::set(const SocketType& input, int value) get_socket_value<int>(this, input) = value; } +void Node::set(const SocketType& input, uint value) +{ + assert(input.type == SocketType::UINT); + get_socket_value<uint>(this, input) = value; +} + void Node::set(const SocketType& input, float value) { assert(input.type == SocketType::FLOAT); @@ -198,6 +204,12 @@ int Node::get_int(const SocketType& input) const return get_socket_value<int>(this, input); } +uint Node::get_uint(const SocketType& input) const +{ + assert(input.type == SocketType::UINT); + return get_socket_value<uint>(this, input); +} + float Node::get_float(const SocketType& input) const { assert(input.type == SocketType::FLOAT); diff --git a/intern/cycles/graph/node.h b/intern/cycles/graph/node.h index bb84f982fb3..64410f4539b 100644 --- a/intern/cycles/graph/node.h +++ b/intern/cycles/graph/node.h @@ -38,6 +38,7 @@ struct Node /* set values */ void set(const SocketType& input, bool value); void set(const SocketType& input, int value); + void set(const SocketType& input, uint value); void set(const SocketType& input, float value); void set(const SocketType& input, float2 value); void set(const SocketType& input, float3 value); @@ -60,6 +61,7 @@ struct Node /* get values */ bool get_bool(const SocketType& input) const; int get_int(const SocketType& input) const; + uint get_uint(const SocketType& input) const; float get_float(const SocketType& input) const; float2 get_float2(const SocketType& input) const; float3 get_float3(const SocketType& input) const; diff --git a/intern/cycles/graph/node_type.cpp b/intern/cycles/graph/node_type.cpp index 7f68ae9c7c7..5b98de778ad 100644 --- a/intern/cycles/graph/node_type.cpp +++ b/intern/cycles/graph/node_type.cpp @@ -41,6 +41,7 @@ size_t SocketType::size(Type type) case BOOLEAN: return sizeof(bool); case FLOAT: return sizeof(float); case INT: return sizeof(int); + case UINT: return sizeof(uint); case COLOR: return sizeof(float3); case VECTOR: return sizeof(float3); case POINT: return sizeof(float3); @@ -88,6 +89,7 @@ ustring SocketType::type_name(Type type) ustring("boolean"), ustring("float"), ustring("int"), + ustring("uint"), ustring("color"), ustring("vector"), ustring("point"), diff --git a/intern/cycles/graph/node_type.h b/intern/cycles/graph/node_type.h index 20816f634cd..60c3244028d 100644 --- a/intern/cycles/graph/node_type.h +++ b/intern/cycles/graph/node_type.h @@ -39,6 +39,7 @@ struct SocketType BOOLEAN, FLOAT, INT, + UINT, COLOR, VECTOR, POINT, @@ -154,7 +155,7 @@ const NodeType *structname::register_type() #define SOCKET_DEFINE(name, ui_name, default_value, datatype, TYPE, flags, ...) \ { \ static datatype defval = default_value; \ - assert(SOCKET_SIZEOF(T, name) == sizeof(datatype)); \ + CHECK_TYPE(((T *)1)->name, datatype); \ type->register_input(ustring(#name), ustring(ui_name), TYPE, SOCKET_OFFSETOF(T, name), &defval, NULL, NULL, flags, ##__VA_ARGS__); \ } @@ -162,6 +163,8 @@ const NodeType *structname::register_type() SOCKET_DEFINE(name, ui_name, default_value, bool, SocketType::BOOLEAN, 0, ##__VA_ARGS__) #define SOCKET_INT(name, ui_name, default_value, ...) \ SOCKET_DEFINE(name, ui_name, default_value, int, SocketType::INT, 0, ##__VA_ARGS__) +#define SOCKET_UINT(name, ui_name, default_value, ...) \ + SOCKET_DEFINE(name, ui_name, default_value, uint, SocketType::UINT, 0, ##__VA_ARGS__) #define SOCKET_FLOAT(name, ui_name, default_value, ...) \ SOCKET_DEFINE(name, ui_name, default_value, float, SocketType::FLOAT, 0, ##__VA_ARGS__) #define SOCKET_COLOR(name, ui_name, default_value, ...) \ diff --git a/intern/cycles/graph/node_xml.cpp b/intern/cycles/graph/node_xml.cpp index 022de7cf32a..590e09645ed 100644 --- a/intern/cycles/graph/node_xml.cpp +++ b/intern/cycles/graph/node_xml.cpp @@ -108,6 +108,11 @@ void xml_read_node(XMLReader& reader, Node *node, pugi::xml_node xml_node) node->set(socket, (int)atoi(attr.value())); break; } + case SocketType::UINT: + { + node->set(socket, (uint)atoi(attr.value())); + break; + } case SocketType::INT_ARRAY: { vector<string> tokens; @@ -310,6 +315,11 @@ pugi::xml_node xml_write_node(Node *node, pugi::xml_node xml_root) attr = node->get_int(socket); break; } + case SocketType::UINT: + { + attr = node->get_uint(socket); + break; + } case SocketType::INT_ARRAY: { std::stringstream ss; diff --git a/intern/cycles/kernel/CMakeLists.txt b/intern/cycles/kernel/CMakeLists.txt index 61c484df094..f0adbc03e22 100644 --- a/intern/cycles/kernel/CMakeLists.txt +++ b/intern/cycles/kernel/CMakeLists.txt @@ -76,6 +76,8 @@ set(SRC_CLOSURE_HEADERS closure/bsdf_diffuse.h closure/bsdf_diffuse_ramp.h closure/bsdf_microfacet.h + closure/bsdf_microfacet_multi.h + closure/bsdf_microfacet_multi_impl.h closure/bsdf_oren_nayar.h closure/bsdf_phong_ramp.h closure/bsdf_reflection.h @@ -98,6 +100,7 @@ set(SRC_SVM_HEADERS svm/svm_closure.h svm/svm_convert.h svm/svm_checker.h + svm/svm_color_util.h svm/svm_brick.h svm/svm_displace.h svm/svm_fresnel.h diff --git a/intern/cycles/kernel/closure/bsdf.h b/intern/cycles/kernel/closure/bsdf.h index f0add804c32..f318a61f3a3 100644 --- a/intern/cycles/kernel/closure/bsdf.h +++ b/intern/cycles/kernel/closure/bsdf.h @@ -20,6 +20,7 @@ #include "../closure/bsdf_phong_ramp.h" #include "../closure/bsdf_diffuse_ramp.h" #include "../closure/bsdf_microfacet.h" +#include "../closure/bsdf_microfacet_multi.h" #include "../closure/bsdf_reflection.h" #include "../closure/bsdf_refraction.h" #include "../closure/bsdf_transparent.h" @@ -35,7 +36,7 @@ CCL_NAMESPACE_BEGIN -ccl_device int bsdf_sample(KernelGlobals *kg, const ShaderData *sd, const ShaderClosure *sc, float randu, float randv, float3 *eval, float3 *omega_in, differential3 *domega_in, float *pdf) +ccl_device int bsdf_sample(KernelGlobals *kg, ShaderData *sd, const ShaderClosure *sc, float randu, float randv, float3 *eval, float3 *omega_in, differential3 *domega_in, float *pdf) { int label; @@ -85,6 +86,14 @@ ccl_device int bsdf_sample(KernelGlobals *kg, const ShaderData *sd, const Shader label = bsdf_microfacet_ggx_sample(kg, sc, ccl_fetch(sd, Ng), ccl_fetch(sd, I), ccl_fetch(sd, dI).dx, ccl_fetch(sd, dI).dy, randu, randv, eval, omega_in, &domega_in->dx, &domega_in->dy, pdf); break; + case CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID: + label = bsdf_microfacet_multi_ggx_sample(kg, sc, ccl_fetch(sd, Ng), ccl_fetch(sd, I), ccl_fetch(sd, dI).dx, ccl_fetch(sd, dI).dy, randu, randv, + eval, omega_in, &domega_in->dx, &domega_in->dy, pdf, &ccl_fetch(sd, lcg_state)); + break; + case CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID: + label = bsdf_microfacet_multi_ggx_glass_sample(kg, sc, ccl_fetch(sd, Ng), ccl_fetch(sd, I), ccl_fetch(sd, dI).dx, ccl_fetch(sd, dI).dy, randu, randv, + eval, omega_in, &domega_in->dx, &domega_in->dy, pdf, &ccl_fetch(sd, lcg_state)); + break; case CLOSURE_BSDF_MICROFACET_BECKMANN_ID: case CLOSURE_BSDF_MICROFACET_BECKMANN_ANISO_ID: case CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID: @@ -130,7 +139,7 @@ ccl_device int bsdf_sample(KernelGlobals *kg, const ShaderData *sd, const Shader return label; } -ccl_device float3 bsdf_eval(KernelGlobals *kg, const ShaderData *sd, const ShaderClosure *sc, const float3 omega_in, float *pdf) +ccl_device float3 bsdf_eval(KernelGlobals *kg, ShaderData *sd, const ShaderClosure *sc, const float3 omega_in, float *pdf) { float3 eval; @@ -172,6 +181,12 @@ ccl_device float3 bsdf_eval(KernelGlobals *kg, const ShaderData *sd, const Shade case CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID: eval = bsdf_microfacet_ggx_eval_reflect(sc, ccl_fetch(sd, I), omega_in, pdf); break; + case CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID: + eval = bsdf_microfacet_multi_ggx_eval_reflect(sc, ccl_fetch(sd, I), omega_in, pdf, &ccl_fetch(sd, lcg_state)); + break; + case CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID: + eval = bsdf_microfacet_multi_ggx_glass_eval_reflect(sc, ccl_fetch(sd, I), omega_in, pdf, &ccl_fetch(sd, lcg_state)); + break; case CLOSURE_BSDF_MICROFACET_BECKMANN_ID: case CLOSURE_BSDF_MICROFACET_BECKMANN_ANISO_ID: case CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID: @@ -234,6 +249,12 @@ ccl_device float3 bsdf_eval(KernelGlobals *kg, const ShaderData *sd, const Shade case CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID: eval = bsdf_microfacet_ggx_eval_transmit(sc, ccl_fetch(sd, I), omega_in, pdf); break; + case CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID: + eval = bsdf_microfacet_multi_ggx_eval_transmit(sc, ccl_fetch(sd, I), omega_in, pdf, &ccl_fetch(sd, lcg_state)); + break; + case CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID: + eval = bsdf_microfacet_multi_ggx_glass_eval_transmit(sc, ccl_fetch(sd, I), omega_in, pdf, &ccl_fetch(sd, lcg_state)); + break; case CLOSURE_BSDF_MICROFACET_BECKMANN_ID: case CLOSURE_BSDF_MICROFACET_BECKMANN_ANISO_ID: case CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID: @@ -286,6 +307,10 @@ ccl_device void bsdf_blur(KernelGlobals *kg, ShaderClosure *sc, float roughness) #ifdef __SVM__ switch(sc->type) { + case CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID: + case CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID: + bsdf_microfacet_multi_ggx_blur(sc, roughness); + break; case CLOSURE_BSDF_MICROFACET_GGX_ID: case CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID: case CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID: diff --git a/intern/cycles/kernel/closure/bsdf_microfacet.h b/intern/cycles/kernel/closure/bsdf_microfacet.h index 2a0e8f62e7c..aa21633070a 100644 --- a/intern/cycles/kernel/closure/bsdf_microfacet.h +++ b/intern/cycles/kernel/closure/bsdf_microfacet.h @@ -276,7 +276,7 @@ ccl_device float3 bsdf_microfacet_ggx_eval_reflect(const ShaderClosure *sc, cons bool m_refractive = sc->type == CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID; float3 N = sc->N; - if(m_refractive || fmaxf(alpha_x, alpha_y) <= 1e-4f) + if(m_refractive || alpha_x*alpha_y <= 1e-7f) return make_float3(0.0f, 0.0f, 0.0f); float cosNO = dot(N, I); @@ -367,7 +367,7 @@ ccl_device float3 bsdf_microfacet_ggx_eval_transmit(const ShaderClosure *sc, con bool m_refractive = sc->type == CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID; float3 N = sc->N; - if(!m_refractive || fmaxf(alpha_x, alpha_y) <= 1e-4f) + if(!m_refractive || alpha_x*alpha_y <= 1e-7f) return make_float3(0.0f, 0.0f, 0.0f); float cosNO = dot(N, I); @@ -450,7 +450,7 @@ ccl_device int bsdf_microfacet_ggx_sample(KernelGlobals *kg, const ShaderClosure *omega_in = 2 * cosMO * m - I; if(dot(Ng, *omega_in) > 0) { - if(fmaxf(alpha_x, alpha_y) <= 1e-4f) { + if(alpha_x*alpha_y <= 1e-7f) { /* some high number for MIS */ *pdf = 1e6f; *eval = make_float3(1e6f, 1e6f, 1e6f); @@ -539,7 +539,7 @@ ccl_device int bsdf_microfacet_ggx_sample(KernelGlobals *kg, const ShaderClosure *domega_in_dy = dTdy; #endif - if(fmaxf(alpha_x, alpha_y) <= 1e-4f || fabsf(m_eta - 1.0f) < 1e-4f) { + if(alpha_x*alpha_y <= 1e-7f || fabsf(m_eta - 1.0f) < 1e-4f) { /* some high number for MIS */ *pdf = 1e6f; *eval = make_float3(1e6f, 1e6f, 1e6f); @@ -622,7 +622,7 @@ ccl_device float3 bsdf_microfacet_beckmann_eval_reflect(const ShaderClosure *sc, bool m_refractive = sc->type == CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID; float3 N = sc->N; - if(m_refractive || fmaxf(alpha_x, alpha_y) <= 1e-4f) + if(m_refractive || alpha_x*alpha_y <= 1e-7f) return make_float3(0.0f, 0.0f, 0.0f); float cosNO = dot(N, I); @@ -716,7 +716,7 @@ ccl_device float3 bsdf_microfacet_beckmann_eval_transmit(const ShaderClosure *sc bool m_refractive = sc->type == CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID; float3 N = sc->N; - if(!m_refractive || fmaxf(alpha_x, alpha_y) <= 1e-4f) + if(!m_refractive || alpha_x*alpha_y <= 1e-7f) return make_float3(0.0f, 0.0f, 0.0f); float cosNO = dot(N, I); @@ -798,7 +798,7 @@ ccl_device int bsdf_microfacet_beckmann_sample(KernelGlobals *kg, const ShaderCl *omega_in = 2 * cosMO * m - I; if(dot(Ng, *omega_in) > 0) { - if(fmaxf(alpha_x, alpha_y) <= 1e-4f) { + if(alpha_x*alpha_y <= 1e-7f) { /* some high number for MIS */ *pdf = 1e6f; *eval = make_float3(1e6f, 1e6f, 1e6f); @@ -889,7 +889,7 @@ ccl_device int bsdf_microfacet_beckmann_sample(KernelGlobals *kg, const ShaderCl *domega_in_dy = dTdy; #endif - if(fmaxf(alpha_x, alpha_y) <= 1e-4f || fabsf(m_eta - 1.0f) < 1e-4f) { + if(alpha_x*alpha_y <= 1e-7f || fabsf(m_eta - 1.0f) < 1e-4f) { /* some high number for MIS */ *pdf = 1e6f; *eval = make_float3(1e6f, 1e6f, 1e6f); diff --git a/intern/cycles/kernel/closure/bsdf_microfacet_multi.h b/intern/cycles/kernel/closure/bsdf_microfacet_multi.h new file mode 100644 index 00000000000..6060d7d8ccb --- /dev/null +++ b/intern/cycles/kernel/closure/bsdf_microfacet_multi.h @@ -0,0 +1,476 @@ +/* + * Copyright 2011-2016 Blender Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +CCL_NAMESPACE_BEGIN + +/* Most of the code is based on the supplemental implementations from https://eheitzresearch.wordpress.com/240-2/. */ + +/* === GGX Microfacet distribution functions === */ + +/* Isotropic GGX microfacet distribution */ +ccl_device_inline float D_ggx(float3 wm, float alpha) +{ + wm.z *= wm.z; + alpha *= alpha; + float tmp = (1.0f - wm.z) + alpha * wm.z; + return alpha / max(M_PI_F * tmp*tmp, 1e-7f); +} + +/* Anisotropic GGX microfacet distribution */ +ccl_device_inline float D_ggx_aniso(const float3 wm, const float2 alpha) +{ + float slope_x = -wm.x/alpha.x; + float slope_y = -wm.y/alpha.y; + float tmp = wm.z*wm.z + slope_x*slope_x + slope_y*slope_y; + + return 1.0f / max(M_PI_F * tmp*tmp * alpha.x*alpha.y, 1e-7f); +} + +/* Sample slope distribution (based on page 14 of the supplemental implementation). */ +ccl_device_inline float2 mf_sampleP22_11(const float cosI, const float2 randU) +{ + if(cosI > 0.9999f) { + const float r = sqrtf(randU.x / (1.0f - randU.x)); + const float phi = M_2PI_F * randU.y; + return make_float2(r*cosf(phi), r*sinf(phi)); + } + + const float sinI = sqrtf(1.0f - cosI*cosI); + const float tanI = sinI/cosI; + const float projA = 0.5f * (cosI + 1.0f); + if(projA < 0.0001f) + return make_float2(0.0f, 0.0f); + const float A = 2.0f*randU.x*projA / cosI - 1.0f; + float tmp = A*A-1.0f; + if(fabsf(tmp) < 1e-7f) + return make_float2(0.0f, 0.0f); + tmp = 1.0f / tmp; + const float D = safe_sqrtf(tanI*tanI*tmp*tmp - (A*A-tanI*tanI)*tmp); + + const float slopeX2 = tanI*tmp + D; + const float slopeX = (A < 0.0f || slopeX2 > 1.0f/tanI)? (tanI*tmp - D) : slopeX2; + + float U2; + if(randU.y >= 0.5f) + U2 = 2.0f*(randU.y - 0.5f); + else + U2 = 2.0f*(0.5f - randU.y); + const float z = (U2*(U2*(U2*0.27385f-0.73369f)+0.46341f)) / (U2*(U2*(U2*0.093073f+0.309420f)-1.0f)+0.597999f); + const float slopeY = z * sqrtf(1.0f + slopeX*slopeX); + + if(randU.y >= 0.5f) + return make_float2(slopeX, slopeY); + else + return make_float2(slopeX, -slopeY); +} + +/* Visible normal sampling for the GGX distribution (based on page 7 of the supplemental implementation). */ +ccl_device_inline float3 mf_sample_vndf(const float3 wi, const float2 alpha, const float2 randU) +{ + const float3 wi_11 = normalize(make_float3(alpha.x*wi.x, alpha.y*wi.y, wi.z)); + const float2 slope_11 = mf_sampleP22_11(wi_11.z, randU); + + const float2 cossin_phi = normalize(make_float2(wi_11.x, wi_11.y)); + const float slope_x = alpha.x*(cossin_phi.x * slope_11.x - cossin_phi.y * slope_11.y); + const float slope_y = alpha.y*(cossin_phi.y * slope_11.x + cossin_phi.x * slope_11.y); + + kernel_assert(isfinite(slope_x)); + return normalize(make_float3(-slope_x, -slope_y, 1.0f)); +} + +/* === Phase functions: Glossy, Diffuse and Glass === */ + +/* Phase function for reflective materials, either without a fresnel term (for compatibility) or with the conductive fresnel term. */ +ccl_device_inline float3 mf_sample_phase_glossy(const float3 wi, float3 *n, float3 *k, float3 *weight, const float3 wm) +{ + if(n && k) + *weight *= fresnel_conductor(dot(wi, wm), *n, *k); + + return -wi + 2.0f * wm * dot(wi, wm); +} + +ccl_device_inline float3 mf_eval_phase_glossy(const float3 w, const float lambda, const float3 wo, const float2 alpha, float3 *n, float3 *k) +{ + if(w.z > 0.9999f) + return make_float3(0.0f, 0.0f, 0.0f); + + const float3 wh = normalize(wo - w); + if(wh.z < 0.0f) + return make_float3(0.0f, 0.0f, 0.0f); + + float pArea = (w.z < -0.9999f)? 1.0f: lambda*w.z; + + const float dotW_WH = dot(-w, wh); + if(dotW_WH < 0.0f) + return make_float3(0.0f, 0.0f, 0.0f); + + float phase = max(0.0f, dotW_WH) * 0.25f / (pArea * dotW_WH); + if(alpha.x == alpha.y) + phase *= D_ggx(wh, alpha.x); + else + phase *= D_ggx_aniso(wh, alpha); + + if(n && k) { + /* Apply conductive fresnel term. */ + return phase * fresnel_conductor(dotW_WH, *n, *k); + } + + return make_float3(phase, phase, phase); +} + +/* Phase function for rough lambertian diffuse surfaces. */ +ccl_device_inline float3 mf_sample_phase_diffuse(const float3 wm, const float randu, const float randv) +{ + float3 tm, bm; + make_orthonormals(wm, &tm, &bm); + + float2 disk = concentric_sample_disk(randu, randv); + return disk.x*tm + disk.y*bm + safe_sqrtf(1.0f - disk.x*disk.x - disk.y*disk.y)*wm; +} + +ccl_device_inline float3 mf_eval_phase_diffuse(const float3 w, const float3 wm) +{ + const float v = max(0.0f, dot(w, wm)) * M_1_PI_F; + return make_float3(v, v, v); +} + +/* Phase function for dielectric transmissive materials, including both reflection and refraction according to the dielectric fresnel term. */ +ccl_device_inline float3 mf_sample_phase_glass(const float3 wi, const float eta, const float3 wm, const float randV, bool *outside) +{ + float cosI = dot(wi, wm); + float f = fresnel_dielectric_cos(cosI, eta); + if(randV < f) { + *outside = true; + return -wi + 2.0f * wm * cosI; + } + *outside = false; + float inv_eta = 1.0f/eta; + float cosT = -safe_sqrtf(1.0f - (1.0f - cosI*cosI) * inv_eta*inv_eta); + return normalize(wm*(cosI*inv_eta + cosT) - wi*inv_eta); +} + +ccl_device_inline float3 mf_eval_phase_glass(const float3 w, const float lambda, const float3 wo, const bool wo_outside, const float2 alpha, const float eta) +{ + if(w.z > 0.9999f) + return make_float3(0.0f, 0.0f, 0.0f); + + float pArea = (w.z < -0.9999f)? 1.0f: lambda*w.z; + float v; + if(wo_outside) { + const float3 wh = normalize(wo - w); + if(wh.z < 0.0f) + return make_float3(0.0f, 0.0f, 0.0f); + + const float dotW_WH = dot(-w, wh); + v = fresnel_dielectric_cos(dotW_WH, eta) * max(0.0f, dotW_WH) * D_ggx(wh, alpha.x) * 0.25f / (pArea * dotW_WH); + } + else { + float3 wh = normalize(wo*eta - w); + if(wh.z < 0.0f) + wh = -wh; + const float dotW_WH = dot(-w, wh), dotWO_WH = dot(wo, wh); + if(dotW_WH < 0.0f) + return make_float3(0.0f, 0.0f, 0.0f); + + float temp = dotW_WH + eta*dotWO_WH; + v = (1.0f - fresnel_dielectric_cos(dotW_WH, eta)) * max(0.0f, dotW_WH) * max(0.0f, -dotWO_WH) * D_ggx(wh, alpha.x) / (pArea * temp * temp); + } + + return make_float3(v, v, v); +} + +/* === Utility functions for the random walks === */ + +/* Smith Lambda function for GGX (based on page 12 of the supplemental implementation). */ +ccl_device_inline float mf_lambda(const float3 w, const float2 alpha) +{ + if(w.z > 0.9999f) + return 0.0f; + else if(w.z < -0.9999f) + return -1.0f; + + const float inv_wz2 = 1.0f / (w.z*w.z); + const float2 wa = make_float2(w.x, w.y)*alpha; + float v = sqrtf(1.0f + dot(wa, wa) * inv_wz2); + if(w.z <= 0.0f) + v = -v; + + return 0.5f*(v - 1.0f); +} + +/* Height distribution CDF (based on page 4 of the supplemental implementation). */ +ccl_device_inline float mf_invC1(const float h) +{ + return 2.0f * saturate(h) - 1.0f; +} + +ccl_device_inline float mf_C1(const float h) +{ + return saturate(0.5f * (h + 1.0f)); +} + +/* Masking function (based on page 16 of the supplemental implementation). */ +ccl_device_inline float mf_G1(const float3 w, const float C1, const float lambda) +{ + if(w.z > 0.9999f) + return 1.0f; + if(w.z < 1e-5f) + return 0.0f; + return powf(C1, lambda); +} + +/* Sampling from the visible height distribution (based on page 17 of the supplemental implementation). */ +ccl_device_inline bool mf_sample_height(const float3 w, float *h, float *C1, float *G1, float *lambda, const float U) +{ + if(w.z > 0.9999f) + return false; + if(w.z < -0.9999f) { + *C1 *= U; + *h = mf_invC1(*C1); + *G1 = mf_G1(w, *C1, *lambda); + } + else if(fabsf(w.z) >= 0.0001f) { + if(U > 1.0f - *G1) + return false; + if(*lambda >= 0.0f) { + *C1 = 1.0f; + } + else { + *C1 *= powf(1.0f-U, -1.0f / *lambda); + } + *h = mf_invC1(*C1); + *G1 = mf_G1(w, *C1, *lambda); + } + return true; +} + +/* === PDF approximations for the different phase functions. === + * As explained in bsdf_microfacet_multi_impl.h, using approximations with MIS still produces an unbiased result. */ + +/* Approximation for the albedo of the single-scattering GGX distribution, + * the missing energy is then approximated as a diffuse reflection for the PDF. */ +ccl_device_inline float mf_ggx_albedo(float r) +{ + float albedo = 0.806495f*expf(-1.98712f*r*r) + 0.199531f; + albedo -= ((((((1.76741f*r - 8.43891f)*r + 15.784f)*r - 14.398f)*r + 6.45221f)*r - 1.19722f)*r + 0.027803f)*r + 0.00568739f; + return saturate(albedo); +} + +ccl_device_inline float mf_ggx_pdf(const float3 wi, const float3 wo, const float alpha) +{ + return 0.25f * D_ggx(normalize(wi+wo), alpha) / ((1.0f + mf_lambda(wi, make_float2(alpha, alpha))) * wi.z) + (1.0f - mf_ggx_albedo(alpha)) * wo.z; +} + +ccl_device_inline float mf_ggx_aniso_pdf(const float3 wi, const float3 wo, const float2 alpha) +{ + return 0.25f * D_ggx_aniso(normalize(wi+wo), alpha) / ((1.0f + mf_lambda(wi, alpha)) * wi.z) + (1.0f - mf_ggx_albedo(sqrtf(alpha.x*alpha.y))) * wo.z; +} + +ccl_device_inline float mf_diffuse_pdf(const float3 wo) +{ + return M_1_PI_F * wo.z; +} + +ccl_device_inline float mf_glass_pdf(const float3 wi, const float3 wo, const float alpha, const float eta) +{ + float3 wh; + float fresnel; + if(wi.z*wo.z > 0.0f) { + wh = normalize(wi + wo); + fresnel = fresnel_dielectric_cos(dot(wi, wh), eta); + } + else { + wh = normalize(wi + wo*eta); + fresnel = 1.0f - fresnel_dielectric_cos(dot(wi, wh), eta); + } + if(wh.z < 0.0f) + wh = -wh; + float3 r_wi = (wi.z < 0.0f)? -wi: wi; + return fresnel * max(0.0f, dot(r_wi, wh)) * D_ggx(wh, alpha) / ((1.0f + mf_lambda(r_wi, make_float2(alpha, alpha))) * r_wi.z) + fabsf(wo.z); +} + +/* === Actual random walk implementations, one version of mf_eval and mf_sample per phase function. === */ + +#define MF_NAME_JOIN(x,y) x ## _ ## y +#define MF_NAME_EVAL(x,y) MF_NAME_JOIN(x,y) +#define MF_FUNCTION_FULL_NAME(prefix) MF_NAME_EVAL(prefix, MF_PHASE_FUNCTION) + +#define MF_PHASE_FUNCTION glass +#define MF_MULTI_GLASS +#include "bsdf_microfacet_multi_impl.h" + +/* The diffuse phase function is not implemented as a node yet. */ +#if 0 +#define MF_PHASE_FUNCTION diffuse +#define MF_MULTI_DIFFUSE +#include "bsdf_microfacet_multi_impl.h" +#endif + +#define MF_PHASE_FUNCTION glossy +#define MF_MULTI_GLOSSY +#include "bsdf_microfacet_multi_impl.h" + +ccl_device void bsdf_microfacet_multi_ggx_blur(ShaderClosure *sc, float roughness) +{ + sc->data0 = fmaxf(roughness, sc->data0); /* alpha_x */ + sc->data1 = fmaxf(roughness, sc->data1); /* alpha_y */ +} + +/* === Closure implementations === */ + +/* Multiscattering GGX Glossy closure */ + +ccl_device int bsdf_microfacet_multi_ggx_common_setup(ShaderClosure *sc) +{ + sc->data0 = clamp(sc->data0, 1e-4f, 1.0f); /* alpha */ + sc->data1 = clamp(sc->data1, 1e-4f, 1.0f); + sc->custom1 = saturate(sc->custom1); /* color */ + sc->custom2 = saturate(sc->custom2); + sc->custom3 = saturate(sc->custom3); + + sc->type = CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID; + + return SD_BSDF|SD_BSDF_HAS_EVAL|SD_BSDF_NEEDS_LCG|SD_BSDF_HAS_CUSTOM; +} + +ccl_device int bsdf_microfacet_multi_ggx_aniso_setup(ShaderClosure *sc) +{ +#ifdef __KERNEL_OPENCL__ + if(all(sc->T == 0.0f)) +#else + if(sc->T == make_float3(0.0f, 0.0f, 0.0f)) +#endif + sc->T = make_float3(1.0f, 0.0f, 0.0f); + + return bsdf_microfacet_multi_ggx_common_setup(sc); +} + +ccl_device int bsdf_microfacet_multi_ggx_setup(ShaderClosure *sc) +{ + sc->data1 = sc->data0; + + return bsdf_microfacet_multi_ggx_common_setup(sc); +} + +ccl_device float3 bsdf_microfacet_multi_ggx_eval_transmit(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf, ccl_addr_space uint *lcg_state) { + *pdf = 0.0f; + return make_float3(0.0f, 0.0f, 0.0f); +} + +ccl_device float3 bsdf_microfacet_multi_ggx_eval_reflect(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf, ccl_addr_space uint *lcg_state) { + bool is_aniso = (sc->data0 != sc->data1); + float3 X, Y, Z; + Z = sc->N; + if(is_aniso) + make_orthonormals_tangent(Z, sc->T, &X, &Y); + else + make_orthonormals(Z, &X, &Y); + + float3 localI = make_float3(dot(I, X), dot(I, Y), dot(I, Z)); + float3 localO = make_float3(dot(omega_in, X), dot(omega_in, Y), dot(omega_in, Z)); + + if(is_aniso) + *pdf = mf_ggx_aniso_pdf(localI, localO, make_float2(sc->data0, sc->data1)); + else + *pdf = mf_ggx_pdf(localI, localO, sc->data0); + return mf_eval_glossy(localI, localO, true, make_float3(sc->custom1, sc->custom2, sc->custom3), sc->data0, sc->data1, lcg_state, NULL, NULL); +} + +ccl_device int bsdf_microfacet_multi_ggx_sample(KernelGlobals *kg, const ShaderClosure *sc, float3 Ng, float3 I, float3 dIdx, float3 dIdy, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf, ccl_addr_space uint *lcg_state) +{ + bool is_aniso = (sc->data0 != sc->data1); + float3 X, Y, Z; + Z = sc->N; + if(is_aniso) + make_orthonormals_tangent(Z, sc->T, &X, &Y); + else + make_orthonormals(Z, &X, &Y); + + float3 localI = make_float3(dot(I, X), dot(I, Y), dot(I, Z)); + float3 localO; + + *eval = mf_sample_glossy(localI, &localO, make_float3(sc->custom1, sc->custom2, sc->custom3), sc->data0, sc->data1, lcg_state, NULL, NULL); + if(is_aniso) + *pdf = mf_ggx_aniso_pdf(localI, localO, make_float2(sc->data0, sc->data1)); + else + *pdf = mf_ggx_pdf(localI, localO, sc->data0); + *eval *= *pdf; + + *omega_in = X*localO.x + Y*localO.y + Z*localO.z; + return LABEL_REFLECT|LABEL_GLOSSY; +} + +/* Multiscattering GGX Glass closure */ + +ccl_device int bsdf_microfacet_multi_ggx_glass_setup(ShaderClosure *sc) +{ + sc->data0 = clamp(sc->data0, 1e-4f, 1.0f); /* alpha */ + sc->data1 = sc->data0; + sc->data2 = max(0.0f, sc->data2); /* ior */ + sc->custom1 = saturate(sc->custom1); /* color */ + sc->custom2 = saturate(sc->custom2); + sc->custom3 = saturate(sc->custom3); + + sc->type = CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID; + + return SD_BSDF|SD_BSDF_HAS_EVAL|SD_BSDF_NEEDS_LCG|SD_BSDF_HAS_CUSTOM; +} + +ccl_device float3 bsdf_microfacet_multi_ggx_glass_eval_transmit(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf, ccl_addr_space uint *lcg_state) { + float3 X, Y, Z; + Z = sc->N; + make_orthonormals(Z, &X, &Y); + + float3 localI = make_float3(dot(I, X), dot(I, Y), dot(I, Z)); + float3 localO = make_float3(dot(omega_in, X), dot(omega_in, Y), dot(omega_in, Z)); + + *pdf = mf_glass_pdf(localI, localO, sc->data0, sc->data2); + return mf_eval_glass(localI, localO, false, make_float3(sc->custom1, sc->custom2, sc->custom3), sc->data0, sc->data1, lcg_state, sc->data2); +} + +ccl_device float3 bsdf_microfacet_multi_ggx_glass_eval_reflect(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf, ccl_addr_space uint *lcg_state) { + float3 X, Y, Z; + Z = sc->N; + make_orthonormals(Z, &X, &Y); + + float3 localI = make_float3(dot(I, X), dot(I, Y), dot(I, Z)); + float3 localO = make_float3(dot(omega_in, X), dot(omega_in, Y), dot(omega_in, Z)); + + *pdf = mf_glass_pdf(localI, localO, sc->data0, sc->data2); + return mf_eval_glass(localI, localO, true, make_float3(sc->custom1, sc->custom2, sc->custom3), sc->data0, sc->data1, lcg_state, sc->data2); +} + +ccl_device int bsdf_microfacet_multi_ggx_glass_sample(KernelGlobals *kg, const ShaderClosure *sc, float3 Ng, float3 I, float3 dIdx, float3 dIdy, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf, ccl_addr_space uint *lcg_state) +{ + float3 X, Y, Z; + Z = sc->N; + make_orthonormals(Z, &X, &Y); + + float3 localI = make_float3(dot(I, X), dot(I, Y), dot(I, Z)); + float3 localO; + + *eval = mf_sample_glass(localI, &localO, make_float3(sc->custom1, sc->custom2, sc->custom3), sc->data0, sc->data1, lcg_state, sc->data2); + *pdf = mf_glass_pdf(localI, localO, sc->data0, sc->data2); + *eval *= *pdf; + + *omega_in = X*localO.x + Y*localO.y + Z*localO.z; + if(localO.z*localI.z > 0.0f) + return LABEL_REFLECT|LABEL_GLOSSY; + else + return LABEL_TRANSMIT|LABEL_GLOSSY; +} + +CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/closure/bsdf_microfacet_multi_impl.h b/intern/cycles/kernel/closure/bsdf_microfacet_multi_impl.h new file mode 100644 index 00000000000..afd4a8da62a --- /dev/null +++ b/intern/cycles/kernel/closure/bsdf_microfacet_multi_impl.h @@ -0,0 +1,226 @@ +/* + * Copyright 2011-2016 Blender Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* Evaluate the BSDF from wi to wo. + * Evaluation is split into the analytical single-scattering BSDF and the multi-scattering BSDF, + * which is evaluated stochastically through a random walk. At each bounce (except for the first one), + * the amount of reflection from here towards wo is evaluated before bouncing again. + * + * Because of the random walk, the evaluation is not deterministic, but its expected value is equal to + * the correct BSDF, which is enough for Monte-Carlo rendering. The PDF also can't be determined + * analytically, so the single-scattering PDF plus a diffuse term to account for the multi-scattered + * energy is used. In combination with MIS, that is enough to produce an unbiased result, although + * the balance heuristic isn't necessarily optimal anymore. + */ +ccl_device float3 MF_FUNCTION_FULL_NAME(mf_eval)(float3 wi, float3 wo, const bool wo_outside, const float3 color, const float alpha_x, const float alpha_y, ccl_addr_space uint* lcg_state +#ifdef MF_MULTI_GLASS + , const float eta +#elif defined(MF_MULTI_GLOSSY) + , float3 *n, float3 *k +#endif +) +{ + /* Evaluating for a shallower incoming direction produces less noise, and the properties of the BSDF guarantee reciprocity. */ + bool swapped = false; +#ifdef MF_MULTI_GLASS + if(wi.z*wo.z < 0.0f) { + /* Glass transmission is a special case and requires the directions to change hemisphere. */ + if(-wo.z < wi.z) { + swapped = true; + float3 tmp = -wo; + wo = -wi; + wi = tmp; + } + } + else +#endif + if(wo.z < wi.z) { + swapped = true; + float3 tmp = wo; + wo = wi; + wi = tmp; + } + + if(wi.z < 1e-5f || (wo.z < 1e-5f && wo_outside) || (wo.z > -1e-5f && !wo_outside)) + return make_float3(0.0f, 0.0f, 0.0f); + + const float2 alpha = make_float2(alpha_x, alpha_y); + + float lambda_r = mf_lambda(-wi, alpha); + float shadowing_lambda = mf_lambda(wo_outside? wo: -wo, alpha); + + /* Analytically compute single scattering for lower noise. */ + float3 eval; +#ifdef MF_MULTI_GLASS + eval = mf_eval_phase_glass(-wi, lambda_r, wo, wo_outside, alpha, eta); + if(wo_outside) + eval *= -lambda_r / (shadowing_lambda - lambda_r); + else + eval *= -lambda_r * beta(-lambda_r, shadowing_lambda+1.0f); +#elif defined(MF_MULTI_DIFFUSE) + /* Diffuse has no special closed form for the single scattering bounce */ + eval = make_float3(0.0f, 0.0f, 0.0f); +#else /* MF_MULTI_GLOSSY */ + const float3 wh = normalize(wi+wo); + const float G2 = 1.0f / (1.0f - (lambda_r + 1.0f) + shadowing_lambda); + float val = G2 * 0.25f / wi.z; + if(alpha.x == alpha.y) + val *= D_ggx(wh, alpha.x); + else + val *= D_ggx_aniso(wh, alpha); + if(n && k) { + eval = fresnel_conductor(dot(wh, wi), *n, *k) * val; + } + else { + eval = make_float3(val, val, val); + } +#endif + + float3 wr = -wi; + float hr = 1.0f; + float C1_r = 1.0f; + float G1_r = 0.0f; + bool outside = true; + float3 throughput = make_float3(1.0f, 1.0f, 1.0f); + + for(int order = 0; order < 10; order++) { + /* Sample microfacet height and normal */ + if(!mf_sample_height(wr, &hr, &C1_r, &G1_r, &lambda_r, lcg_step_float_addrspace(lcg_state))) + break; + float3 wm = mf_sample_vndf(-wr, alpha, make_float2(lcg_step_float_addrspace(lcg_state), + lcg_step_float_addrspace(lcg_state))); + +#ifdef MF_MULTI_DIFFUSE + if(order == 0) { + /* Compute single-scattering for diffuse. */ + const float G2_G1 = -lambda_r / (shadowing_lambda - lambda_r); + eval += throughput * G2_G1 * mf_eval_phase_diffuse(wo, wm); + } +#endif + if(order > 0) { + /* Evaluate amount of scattering towards wo on this microfacet. */ + float3 phase; +#ifdef MF_MULTI_GLASS + if(outside) + phase = mf_eval_phase_glass(wr, lambda_r, wo, wo_outside, alpha, eta); + else + phase = mf_eval_phase_glass(wr, lambda_r, -wo, !wo_outside, alpha, 1.0f/eta); +#elif defined(MF_MULTI_DIFFUSE) + phase = mf_eval_phase_diffuse(wo, wm); +#else /* MF_MULTI_GLOSSY */ + phase = mf_eval_phase_glossy(wr, lambda_r, wo, alpha, n, k) * throughput; +#endif + eval += throughput * phase * mf_G1(wo_outside? wo: -wo, mf_C1((outside == wo_outside)? hr: -hr), shadowing_lambda); + } + if(order+1 < 10) { + /* Bounce from the microfacet. */ +#ifdef MF_MULTI_GLASS + bool next_outside; + wr = mf_sample_phase_glass(-wr, outside? eta: 1.0f/eta, wm, lcg_step_float_addrspace(lcg_state), &next_outside); + if(!next_outside) { + outside = !outside; + wr = -wr; + hr = -hr; + } +#elif defined(MF_MULTI_DIFFUSE) + wr = mf_sample_phase_diffuse(wm, + lcg_step_float_addrspace(lcg_state), + lcg_step_float_addrspace(lcg_state)); +#else /* MF_MULTI_GLOSSY */ + wr = mf_sample_phase_glossy(-wr, n, k, &throughput, wm); +#endif + + lambda_r = mf_lambda(wr, alpha); + + throughput *= color; + + C1_r = mf_C1(hr); + G1_r = mf_G1(wr, C1_r, lambda_r); + } + } + + if(swapped) + eval *= fabsf(wi.z / wo.z); + return eval; +} + +/* Perform a random walk on the microsurface starting from wi, returning the direction in which the walk + * escaped the surface in wo. The function returns the throughput between wi and wo. + * Without reflection losses due to coloring or fresnel absorption in conductors, the sampling is optimal. + */ +ccl_device float3 MF_FUNCTION_FULL_NAME(mf_sample)(float3 wi, float3 *wo, const float3 color, const float alpha_x, const float alpha_y, ccl_addr_space uint *lcg_state +#ifdef MF_MULTI_GLASS + , const float eta +#elif defined(MF_MULTI_GLOSSY) + , float3 *n, float3 *k +#endif +) +{ + const float2 alpha = make_float2(alpha_x, alpha_y); + + float3 throughput = make_float3(1.0f, 1.0f, 1.0f); + float3 wr = -wi; + float lambda_r = mf_lambda(wr, alpha); + float hr = 1.0f; + float C1_r = 1.0f; + float G1_r = 0.0f; + bool outside = true; + + int order; + for(order = 0; order < 10; order++) { + /* Sample microfacet height. */ + if(!mf_sample_height(wr, &hr, &C1_r, &G1_r, &lambda_r, lcg_step_float_addrspace(lcg_state))) { + /* The random walk has left the surface. */ + *wo = outside? wr: -wr; + return throughput; + } + /* Sample microfacet normal. */ + float3 wm = mf_sample_vndf(-wr, alpha, make_float2(lcg_step_float_addrspace(lcg_state), + lcg_step_float_addrspace(lcg_state))); + + /* First-bounce color is already accounted for in mix weight. */ + if(order > 0) + throughput *= color; + + /* Bounce from the microfacet. */ +#ifdef MF_MULTI_GLASS + bool next_outside; + wr = mf_sample_phase_glass(-wr, outside? eta: 1.0f/eta, wm, lcg_step_float_addrspace(lcg_state), &next_outside); + if(!next_outside) { + hr = -hr; + wr = -wr; + outside = !outside; + } +#elif defined(MF_MULTI_DIFFUSE) + wr = mf_sample_phase_diffuse(wm, + lcg_step_float_addrspace(lcg_state), + lcg_step_float_addrspace(lcg_state)); +#else /* MF_MULTI_GLOSSY */ + wr = mf_sample_phase_glossy(-wr, n, k, &throughput, wm); +#endif + + /* Update random walk parameters. */ + lambda_r = mf_lambda(wr, alpha); + G1_r = mf_G1(wr, C1_r, lambda_r); + } + *wo = make_float3(0.0f, 0.0f, 1.0f); + return make_float3(0.0f, 0.0f, 0.0f); +} + +#undef MF_MULTI_GLASS +#undef MF_MULTI_DIFFUSE +#undef MF_MULTI_GLOSSY +#undef MF_PHASE_FUNCTION diff --git a/intern/cycles/kernel/closure/bsdf_util.h b/intern/cycles/kernel/closure/bsdf_util.h index 05816bac2c1..89b1998d1ce 100644 --- a/intern/cycles/kernel/closure/bsdf_util.h +++ b/intern/cycles/kernel/closure/bsdf_util.h @@ -111,10 +111,9 @@ ccl_device float fresnel_dielectric_cos(float cosi, float eta) return 1.0f; // TIR(no refracted component) } -#if 0 ccl_device float3 fresnel_conductor(float cosi, const float3 eta, const float3 k) { - float3 cosi2 = make_float3(cosi*cosi); + float3 cosi2 = make_float3(cosi*cosi, cosi*cosi, cosi*cosi); float3 one = make_float3(1.0f, 1.0f, 1.0f); float3 tmp_f = eta * eta + k * k; float3 tmp = tmp_f * cosi2; @@ -124,7 +123,6 @@ ccl_device float3 fresnel_conductor(float cosi, const float3 eta, const float3 k (tmp_f + (2.0f * eta * cosi) + cosi2); return(Rparl2 + Rperp2) * 0.5f; } -#endif ccl_device float smooth_step(float edge0, float edge1, float x) { diff --git a/intern/cycles/kernel/geom/geom_curve.h b/intern/cycles/kernel/geom/geom_curve.h index 8894843997c..292e1bfca0e 100644 --- a/intern/cycles/kernel/geom/geom_curve.h +++ b/intern/cycles/kernel/geom/geom_curve.h @@ -450,8 +450,8 @@ ccl_device_inline bool bvh_cardinal_curve_intersect(KernelGlobals *kg, Intersect else if(level == 1) { /* the maximum recursion depth is reached. - * check if dP0.(Q-P0)>=0 and dPn.(Pn-Q)>=0. - * dP* is reversed if necessary.*/ + * check if dP0.(Q-P0)>=0 and dPn.(Pn-Q)>=0. + * dP* is reversed if necessary.*/ float t = isect->t; float u = 0.0f; float gd = 0.0f; diff --git a/intern/cycles/kernel/geom/geom_triangle_intersect.h b/intern/cycles/kernel/geom/geom_triangle_intersect.h index 4e2f46d58d3..b6dfc769012 100644 --- a/intern/cycles/kernel/geom/geom_triangle_intersect.h +++ b/intern/cycles/kernel/geom/geom_triangle_intersect.h @@ -159,7 +159,7 @@ ccl_device_inline bool triangle_intersect(KernelGlobals *kg, if(kernel_tex_fetch(__prim_visibility, triAddr) & visibility) #endif { -#ifdef __KERNEL_GPU__ +#ifdef __KERNEL_CUDA__ if(A == B && B == C) { return false; } diff --git a/intern/cycles/kernel/kernel_bake.h b/intern/cycles/kernel/kernel_bake.h index 8d05befe1d4..9ee0b09529e 100644 --- a/intern/cycles/kernel/kernel_bake.h +++ b/intern/cycles/kernel/kernel_bake.h @@ -48,7 +48,7 @@ ccl_device void compute_light_pass(KernelGlobals *kg, ShaderData *sd, PathRadian /* evaluate surface shader */ float rbsdf = path_state_rng_1D(kg, &rng, &state, PRNG_BSDF); - shader_eval_surface(kg, sd, &state, rbsdf, state.flag, SHADER_CONTEXT_MAIN); + shader_eval_surface(kg, sd, &rng, &state, rbsdf, state.flag, SHADER_CONTEXT_MAIN); /* TODO, disable the closures we won't need */ @@ -220,6 +220,7 @@ ccl_device_inline float3 kernel_bake_shader_bsdf(KernelGlobals *kg, ccl_device float3 kernel_bake_evaluate_direct_indirect(KernelGlobals *kg, ShaderData *sd, + RNG *rng, PathState *state, float3 direct, float3 indirect, @@ -239,12 +240,12 @@ ccl_device float3 kernel_bake_evaluate_direct_indirect(KernelGlobals *kg, } else { /* surface color of the pass only */ - shader_eval_surface(kg, sd, state, 0.0f, 0, SHADER_CONTEXT_MAIN); + shader_eval_surface(kg, sd, rng, state, 0.0f, 0, SHADER_CONTEXT_MAIN); return kernel_bake_shader_bsdf(kg, sd, type); } } else { - shader_eval_surface(kg, sd, state, 0.0f, 0, SHADER_CONTEXT_MAIN); + shader_eval_surface(kg, sd, rng, state, 0.0f, 0, SHADER_CONTEXT_MAIN); color = kernel_bake_shader_bsdf(kg, sd, type); } @@ -336,7 +337,7 @@ ccl_device void kernel_bake_evaluate(KernelGlobals *kg, ccl_global uint4 *input, case SHADER_EVAL_NORMAL: { if((sd.flag & SD_HAS_BUMP)) { - shader_eval_surface(kg, &sd, &state, 0.f, 0, SHADER_CONTEXT_MAIN); + shader_eval_surface(kg, &sd, &rng, &state, 0.f, 0, SHADER_CONTEXT_MAIN); } /* compression: normal = (2 * color) - 1 */ @@ -350,7 +351,7 @@ ccl_device void kernel_bake_evaluate(KernelGlobals *kg, ccl_global uint4 *input, } case SHADER_EVAL_EMISSION: { - shader_eval_surface(kg, &sd, &state, 0.f, 0, SHADER_CONTEXT_EMISSION); + shader_eval_surface(kg, &sd, &rng, &state, 0.f, 0, SHADER_CONTEXT_EMISSION); out = shader_emissive_eval(kg, &sd); break; } @@ -403,6 +404,7 @@ ccl_device void kernel_bake_evaluate(KernelGlobals *kg, ccl_global uint4 *input, { out = kernel_bake_evaluate_direct_indirect(kg, &sd, + &rng, &state, L.direct_diffuse, L.indirect_diffuse, @@ -414,6 +416,7 @@ ccl_device void kernel_bake_evaluate(KernelGlobals *kg, ccl_global uint4 *input, { out = kernel_bake_evaluate_direct_indirect(kg, &sd, + &rng, &state, L.direct_glossy, L.indirect_glossy, @@ -425,6 +428,7 @@ ccl_device void kernel_bake_evaluate(KernelGlobals *kg, ccl_global uint4 *input, { out = kernel_bake_evaluate_direct_indirect(kg, &sd, + &rng, &state, L.direct_transmission, L.indirect_transmission, @@ -437,6 +441,7 @@ ccl_device void kernel_bake_evaluate(KernelGlobals *kg, ccl_global uint4 *input, #ifdef __SUBSURFACE__ out = kernel_bake_evaluate_direct_indirect(kg, &sd, + &rng, &state, L.direct_subsurface, L.indirect_subsurface, diff --git a/intern/cycles/kernel/kernel_compat_cpu.h b/intern/cycles/kernel/kernel_compat_cpu.h index bb303b32705..c882b477c35 100644 --- a/intern/cycles/kernel/kernel_compat_cpu.h +++ b/intern/cycles/kernel/kernel_compat_cpu.h @@ -122,6 +122,17 @@ template<typename T> struct texture_image { return make_float4(r, r, r, 1.0f); } + ccl_always_inline float4 read(half4 r) + { + return half4_to_float4(r); + } + + ccl_always_inline float4 read(half r) + { + float f = half_to_float(r); + return make_float4(f, f, f, 1.0f); + } + ccl_always_inline int wrap_periodic(int x, int width) { x %= width; @@ -486,8 +497,10 @@ typedef texture<uint4> texture_uint4; typedef texture<uchar4> texture_uchar4; typedef texture_image<float> texture_image_float; typedef texture_image<uchar> texture_image_uchar; +typedef texture_image<half> texture_image_half; typedef texture_image<float4> texture_image_float4; typedef texture_image<uchar4> texture_image_uchar4; +typedef texture_image<half4> texture_image_half4; /* Macros to handle different memory storage on different devices */ diff --git a/intern/cycles/kernel/kernel_emission.h b/intern/cycles/kernel/kernel_emission.h index 4de8e0f698a..149ac3ed4f9 100644 --- a/intern/cycles/kernel/kernel_emission.h +++ b/intern/cycles/kernel/kernel_emission.h @@ -57,7 +57,7 @@ ccl_device_noinline float3 direct_emissive_eval(KernelGlobals *kg, /* no path flag, we're evaluating this for all closures. that's weak but * we'd have to do multiple evaluations otherwise */ path_state_modify_bounce(state, true); - shader_eval_surface(kg, emission_sd, state, 0.0f, 0, SHADER_CONTEXT_EMISSION); + shader_eval_surface(kg, emission_sd, NULL, state, 0.0f, 0, SHADER_CONTEXT_EMISSION); path_state_modify_bounce(state, false); /* evaluate emissive closure */ @@ -124,8 +124,10 @@ ccl_device_noinline bool direct_emission(KernelGlobals *kg, #ifdef __PASSES__ /* use visibility flag to skip lights */ if(ls->shader & SHADER_EXCLUDE_ANY) { - if(ls->shader & SHADER_EXCLUDE_DIFFUSE) + if(ls->shader & SHADER_EXCLUDE_DIFFUSE) { eval->diffuse = make_float3(0.0f, 0.0f, 0.0f); + eval->subsurface = make_float3(0.0f, 0.0f, 0.0f); + } if(ls->shader & SHADER_EXCLUDE_GLOSSY) eval->glossy = make_float3(0.0f, 0.0f, 0.0f); if(ls->shader & SHADER_EXCLUDE_TRANSMIT) diff --git a/intern/cycles/kernel/kernel_globals.h b/intern/cycles/kernel/kernel_globals.h index e06c68f2fc9..8e66a3a0340 100644 --- a/intern/cycles/kernel/kernel_globals.h +++ b/intern/cycles/kernel/kernel_globals.h @@ -37,8 +37,10 @@ struct VolumeStep; typedef struct KernelGlobals { texture_image_uchar4 texture_byte4_images[TEX_NUM_BYTE4_CPU]; texture_image_float4 texture_float4_images[TEX_NUM_FLOAT4_CPU]; + texture_image_half4 texture_half4_images[TEX_NUM_HALF4_CPU]; texture_image_float texture_float_images[TEX_NUM_FLOAT_CPU]; texture_image_uchar texture_byte_images[TEX_NUM_BYTE_CPU]; + texture_image_half texture_half_images[TEX_NUM_HALF_CPU]; # define KERNEL_TEX(type, ttype, name) ttype name; # define KERNEL_IMAGE_TEX(type, ttype, name) diff --git a/intern/cycles/kernel/kernel_light.h b/intern/cycles/kernel/kernel_light.h index 675eacfc5ee..93c4bd3f7d5 100644 --- a/intern/cycles/kernel/kernel_light.h +++ b/intern/cycles/kernel/kernel_light.h @@ -51,8 +51,8 @@ ccl_device float area_light_sample(float3 P, bool sample_coord) { /* In our name system we're using P for the center, - * which is o in the paper. - */ + * which is o in the paper. + */ float3 corner = *light_p - axisu * 0.5f - axisv * 0.5f; float axisu_len, axisv_len; @@ -291,24 +291,13 @@ ccl_device float background_portal_pdf(KernelGlobals *kg, } num_possible++; - float t = -(dot(P, dir) - dot(lightpos, dir)) / dot(direction, dir); - if(t <= 1e-4f) { - /* Either behind the portal or too close. */ - continue; - } - float4 data1 = kernel_tex_fetch(__light_data, (p + kernel_data.integrator.portal_offset)*LIGHT_SIZE + 1); float4 data2 = kernel_tex_fetch(__light_data, (p + kernel_data.integrator.portal_offset)*LIGHT_SIZE + 2); float3 axisu = make_float3(data1.y, data1.z, data1.w); float3 axisv = make_float3(data2.y, data2.z, data2.w); - float3 hit = P + t*direction; - float3 inplane = hit - lightpos; - /* Skip if the the ray doesn't pass through portal. */ - if(fabsf(dot(inplane, axisu) / dot(axisu, axisu)) > 0.5f) - continue; - if(fabsf(dot(inplane, axisv) / dot(axisv, axisv)) > 0.5f) + if(!ray_quad_intersect(P, direction, 1e-4f, FLT_MAX, lightpos, axisu, axisv, dir, NULL, NULL)) continue; portal_pdf += area_light_sample(P, &lightpos, axisu, axisv, 0.0f, 0.0f, false); @@ -729,8 +718,8 @@ ccl_device bool lamp_light_eval(KernelGlobals *kg, int lamp, float3 P, float3 D, float3 light_P = make_float3(data0.y, data0.z, data0.w); - if(!ray_quad_intersect(P, D, t, - light_P, axisu, axisv, &ls->P, &ls->t)) + if(!ray_quad_intersect(P, D, 0.0f, t, + light_P, axisu, axisv, Ng, &ls->P, &ls->t)) { return false; } diff --git a/intern/cycles/kernel/kernel_path.h b/intern/cycles/kernel/kernel_path.h index 0dded397ffa..3c3503eab8b 100644 --- a/intern/cycles/kernel/kernel_path.h +++ b/intern/cycles/kernel/kernel_path.h @@ -253,7 +253,7 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, &isect, ray); float rbsdf = path_state_rng_1D_for_decision(kg, rng, state, PRNG_BSDF); - shader_eval_surface(kg, sd, state, rbsdf, state->flag, SHADER_CONTEXT_INDIRECT); + shader_eval_surface(kg, sd, rng, state, rbsdf, state->flag, SHADER_CONTEXT_INDIRECT); #ifdef __BRANCHED_PATH__ shader_merge_closures(sd); #endif @@ -791,7 +791,7 @@ ccl_device_inline float4 kernel_path_integrate(KernelGlobals *kg, /* setup shading */ shader_setup_from_ray(kg, &sd, &isect, &ray); float rbsdf = path_state_rng_1D_for_decision(kg, rng, &state, PRNG_BSDF); - shader_eval_surface(kg, &sd, &state, rbsdf, state.flag, SHADER_CONTEXT_MAIN); + shader_eval_surface(kg, &sd, rng, &state, rbsdf, state.flag, SHADER_CONTEXT_MAIN); /* holdout */ #ifdef __HOLDOUT__ diff --git a/intern/cycles/kernel/kernel_path_branched.h b/intern/cycles/kernel/kernel_path_branched.h index fdba1a7b025..56516967d8f 100644 --- a/intern/cycles/kernel/kernel_path_branched.h +++ b/intern/cycles/kernel/kernel_path_branched.h @@ -463,7 +463,7 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in /* setup shading */ shader_setup_from_ray(kg, &sd, &isect, &ray); - shader_eval_surface(kg, &sd, &state, 0.0f, state.flag, SHADER_CONTEXT_MAIN); + shader_eval_surface(kg, &sd, rng, &state, 0.0f, state.flag, SHADER_CONTEXT_MAIN); shader_merge_closures(&sd); /* holdout */ diff --git a/intern/cycles/kernel/kernel_random.h b/intern/cycles/kernel/kernel_random.h index 631a2cb75de..94598e2565e 100644 --- a/intern/cycles/kernel/kernel_random.h +++ b/intern/cycles/kernel/kernel_random.h @@ -309,10 +309,26 @@ ccl_device_inline void path_state_branch(PathState *state, int branch, int num_b state->num_samples = state->num_samples*num_branches; } -ccl_device_inline uint lcg_state_init(RNG *rng, const PathState *state, uint scramble) +ccl_device_inline uint lcg_state_init(RNG *rng, const ccl_addr_space PathState *state, uint scramble) { return lcg_init(*rng + state->rng_offset + state->sample*scramble); } +/* TODO(sergey): For until we can use generic address space from OpenCL 2.0. */ + +ccl_device_inline uint lcg_state_init_addrspace(ccl_addr_space RNG *rng, + const ccl_addr_space PathState *state, + uint scramble) +{ + return lcg_init(*rng + state->rng_offset + state->sample*scramble); +} + +ccl_device float lcg_step_float_addrspace(ccl_addr_space uint *rng) +{ + /* implicit mod 2^32 */ + *rng = (1103515245*(*rng) + 12345); + return (float)*rng * (1.0f/(float)0xFFFFFFFF); +} + CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/kernel_shader.h b/intern/cycles/kernel/kernel_shader.h index a0b56118ab7..765baa2a5ba 100644 --- a/intern/cycles/kernel/kernel_shader.h +++ b/intern/cycles/kernel/kernel_shader.h @@ -468,6 +468,9 @@ ccl_device void shader_merge_closures(ShaderData *sd) continue; } + if((sd->flag & SD_BSDF_HAS_CUSTOM) && !(sci->custom1 == scj->custom1 && sci->custom2 == scj->custom2 && sci->custom3 == scj->custom3)) + continue; + sci->weight += scj->weight; sci->sample_weight += scj->sample_weight; @@ -488,7 +491,7 @@ ccl_device void shader_merge_closures(ShaderData *sd) /* BSDF */ -ccl_device_inline void _shader_bsdf_multi_eval(KernelGlobals *kg, const ShaderData *sd, const float3 omega_in, float *pdf, +ccl_device_inline void _shader_bsdf_multi_eval(KernelGlobals *kg, ShaderData *sd, const float3 omega_in, float *pdf, int skip_bsdf, BsdfEval *result_eval, float sum_pdf, float sum_sample_weight) { /* this is the veach one-sample model with balance heuristic, some pdf @@ -517,7 +520,7 @@ ccl_device_inline void _shader_bsdf_multi_eval(KernelGlobals *kg, const ShaderDa #ifdef __BRANCHED_PATH__ ccl_device_inline void _shader_bsdf_multi_eval_branched(KernelGlobals *kg, - const ShaderData *sd, + ShaderData *sd, const float3 omega_in, BsdfEval *result_eval, float light_pdf, @@ -563,7 +566,7 @@ ccl_device void shader_bsdf_eval(KernelGlobals *kg, } } -ccl_device int shader_bsdf_sample(KernelGlobals *kg, const ShaderData *sd, +ccl_device int shader_bsdf_sample(KernelGlobals *kg, ShaderData *sd, float randu, float randv, BsdfEval *bsdf_eval, float3 *omega_in, differential3 *domega_in, float *pdf) { @@ -620,7 +623,7 @@ ccl_device int shader_bsdf_sample(KernelGlobals *kg, const ShaderData *sd, return label; } -ccl_device int shader_bsdf_sample_closure(KernelGlobals *kg, const ShaderData *sd, +ccl_device int shader_bsdf_sample_closure(KernelGlobals *kg, ShaderData *sd, const ShaderClosure *sc, float randu, float randv, BsdfEval *bsdf_eval, float3 *omega_in, differential3 *domega_in, float *pdf) { @@ -824,7 +827,7 @@ ccl_device float3 shader_holdout_eval(KernelGlobals *kg, ShaderData *sd) /* Surface Evaluation */ -ccl_device void shader_eval_surface(KernelGlobals *kg, ShaderData *sd, +ccl_device void shader_eval_surface(KernelGlobals *kg, ShaderData *sd, ccl_addr_space RNG *rng, ccl_addr_space PathState *state, float randb, int path_flag, ShaderContext ctx) { ccl_fetch(sd, num_closure) = 0; @@ -846,6 +849,10 @@ ccl_device void shader_eval_surface(KernelGlobals *kg, ShaderData *sd, ccl_fetch(sd, flag) |= bsdf_diffuse_setup(ccl_fetch_array(sd, closure, 0)); #endif } + + if(rng && (ccl_fetch(sd, flag) & SD_BSDF_NEEDS_LCG)) { + ccl_fetch(sd, lcg_state) = lcg_state_init_addrspace(rng, state, 0xb4bc3953); + } } /* Background Evaluation */ diff --git a/intern/cycles/kernel/kernel_shadow.h b/intern/cycles/kernel/kernel_shadow.h index 1abbbb2ddad..db2fc84834a 100644 --- a/intern/cycles/kernel/kernel_shadow.h +++ b/intern/cycles/kernel/kernel_shadow.h @@ -117,7 +117,7 @@ ccl_device_inline bool shadow_blocked(KernelGlobals *kg, ShaderData *shadow_sd, /* attenuation from transparent surface */ if(!(shadow_sd->flag & SD_HAS_ONLY_VOLUME)) { path_state_modify_bounce(state, true); - shader_eval_surface(kg, shadow_sd, state, 0.0f, PATH_RAY_SHADOW, SHADER_CONTEXT_SHADOW); + shader_eval_surface(kg, shadow_sd, NULL, state, 0.0f, PATH_RAY_SHADOW, SHADER_CONTEXT_SHADOW); path_state_modify_bounce(state, false); throughput *= shader_bsdf_transparency(kg, shadow_sd); @@ -252,7 +252,7 @@ ccl_device_noinline bool shadow_blocked(KernelGlobals *kg, /* attenuation from transparent surface */ if(!(ccl_fetch(shadow_sd, flag) & SD_HAS_ONLY_VOLUME)) { path_state_modify_bounce(state, true); - shader_eval_surface(kg, shadow_sd, state, 0.0f, PATH_RAY_SHADOW, SHADER_CONTEXT_SHADOW); + shader_eval_surface(kg, shadow_sd, NULL, state, 0.0f, PATH_RAY_SHADOW, SHADER_CONTEXT_SHADOW); path_state_modify_bounce(state, false); throughput *= shader_bsdf_transparency(kg, shadow_sd); diff --git a/intern/cycles/kernel/kernel_subsurface.h b/intern/cycles/kernel/kernel_subsurface.h index 705b57ba6ff..b048bd38fc9 100644 --- a/intern/cycles/kernel/kernel_subsurface.h +++ b/intern/cycles/kernel/kernel_subsurface.h @@ -198,7 +198,7 @@ ccl_device void subsurface_color_bump_blur(KernelGlobals *kg, if(bump || texture_blur > 0.0f) { /* average color and normal at incoming point */ - shader_eval_surface(kg, sd, state, 0.0f, state_flag, SHADER_CONTEXT_SSS); + shader_eval_surface(kg, sd, NULL, state, 0.0f, state_flag, SHADER_CONTEXT_SSS); float3 in_color = shader_bssrdf_sum(sd, (bump)? N: NULL, NULL); /* we simply divide out the average color and multiply with the average diff --git a/intern/cycles/kernel/kernel_types.h b/intern/cycles/kernel/kernel_types.h index 1ffcfb94a15..2187e3c9812 100644 --- a/intern/cycles/kernel/kernel_types.h +++ b/intern/cycles/kernel/kernel_types.h @@ -292,7 +292,6 @@ enum PathRayFlag { PATH_RAY_CURVE = 512, /* visibility flag to define curve segments */ PATH_RAY_VOLUME_SCATTER = 1024, /* volume scattering */ - /* note that these can use maximum 12 bits, the other are for layers */ PATH_RAY_ALL_VISIBILITY = (1|2|4|8|16|32|64|128|256|512|1024), PATH_RAY_MIS_SKIP = 2048, @@ -680,31 +679,34 @@ typedef enum ShaderContext { enum ShaderDataFlag { /* runtime flags */ - SD_BACKFACING = (1 << 0), /* backside of surface? */ - SD_EMISSION = (1 << 1), /* have emissive closure? */ - SD_BSDF = (1 << 2), /* have bsdf closure? */ - SD_BSDF_HAS_EVAL = (1 << 3), /* have non-singular bsdf closure? */ - SD_BSSRDF = (1 << 4), /* have bssrdf */ - SD_HOLDOUT = (1 << 5), /* have holdout closure? */ - SD_ABSORPTION = (1 << 6), /* have volume absorption closure? */ - SD_SCATTER = (1 << 7), /* have volume phase closure? */ - SD_AO = (1 << 8), /* have ao closure? */ - SD_TRANSPARENT = (1 << 9), /* have transparent closure? */ + SD_BACKFACING = (1 << 0), /* backside of surface? */ + SD_EMISSION = (1 << 1), /* have emissive closure? */ + SD_BSDF = (1 << 2), /* have bsdf closure? */ + SD_BSDF_HAS_EVAL = (1 << 3), /* have non-singular bsdf closure? */ + SD_BSSRDF = (1 << 4), /* have bssrdf */ + SD_HOLDOUT = (1 << 5), /* have holdout closure? */ + SD_ABSORPTION = (1 << 6), /* have volume absorption closure? */ + SD_SCATTER = (1 << 7), /* have volume phase closure? */ + SD_AO = (1 << 8), /* have ao closure? */ + SD_TRANSPARENT = (1 << 9), /* have transparent closure? */ + SD_BSDF_NEEDS_LCG = (1 << 10), + SD_BSDF_HAS_CUSTOM = (1 << 11), /* are the custom variables relevant? */ SD_CLOSURE_FLAGS = (SD_EMISSION|SD_BSDF|SD_BSDF_HAS_EVAL|SD_BSSRDF| - SD_HOLDOUT|SD_ABSORPTION|SD_SCATTER|SD_AO), + SD_HOLDOUT|SD_ABSORPTION|SD_SCATTER|SD_AO| + SD_BSDF_NEEDS_LCG|SD_BSDF_HAS_CUSTOM), /* shader flags */ - SD_USE_MIS = (1 << 10), /* direct light sample */ - SD_HAS_TRANSPARENT_SHADOW = (1 << 11), /* has transparent shadow */ - SD_HAS_VOLUME = (1 << 12), /* has volume shader */ - SD_HAS_ONLY_VOLUME = (1 << 13), /* has only volume shader, no surface */ - SD_HETEROGENEOUS_VOLUME = (1 << 14), /* has heterogeneous volume */ - SD_HAS_BSSRDF_BUMP = (1 << 15), /* bssrdf normal uses bump */ - SD_VOLUME_EQUIANGULAR = (1 << 16), /* use equiangular sampling */ - SD_VOLUME_MIS = (1 << 17), /* use multiple importance sampling */ - SD_VOLUME_CUBIC = (1 << 18), /* use cubic interpolation for voxels */ - SD_HAS_BUMP = (1 << 19), /* has data connected to the displacement input */ + SD_USE_MIS = (1 << 12), /* direct light sample */ + SD_HAS_TRANSPARENT_SHADOW = (1 << 13), /* has transparent shadow */ + SD_HAS_VOLUME = (1 << 14), /* has volume shader */ + SD_HAS_ONLY_VOLUME = (1 << 15), /* has only volume shader, no surface */ + SD_HETEROGENEOUS_VOLUME = (1 << 16), /* has heterogeneous volume */ + SD_HAS_BSSRDF_BUMP = (1 << 17), /* bssrdf normal uses bump */ + SD_VOLUME_EQUIANGULAR = (1 << 18), /* use equiangular sampling */ + SD_VOLUME_MIS = (1 << 19), /* use multiple importance sampling */ + SD_VOLUME_CUBIC = (1 << 20), /* use cubic interpolation for voxels */ + SD_HAS_BUMP = (1 << 21), /* has data connected to the displacement input */ SD_SHADER_FLAGS = (SD_USE_MIS|SD_HAS_TRANSPARENT_SHADOW|SD_HAS_VOLUME| SD_HAS_ONLY_VOLUME|SD_HETEROGENEOUS_VOLUME| @@ -712,13 +714,13 @@ enum ShaderDataFlag { SD_VOLUME_CUBIC|SD_HAS_BUMP), /* object flags */ - SD_HOLDOUT_MASK = (1 << 20), /* holdout for camera rays */ - SD_OBJECT_MOTION = (1 << 21), /* has object motion blur */ - SD_TRANSFORM_APPLIED = (1 << 22), /* vertices have transform applied */ - SD_NEGATIVE_SCALE_APPLIED = (1 << 23), /* vertices have negative scale applied */ - SD_OBJECT_HAS_VOLUME = (1 << 24), /* object has a volume shader */ - SD_OBJECT_INTERSECTS_VOLUME = (1 << 25), /* object intersects AABB of an object with volume shader */ - SD_OBJECT_HAS_VERTEX_MOTION = (1 << 26), /* has position for motion vertices */ + SD_HOLDOUT_MASK = (1 << 22), /* holdout for camera rays */ + SD_OBJECT_MOTION = (1 << 23), /* has object motion blur */ + SD_TRANSFORM_APPLIED = (1 << 24), /* vertices have transform applied */ + SD_NEGATIVE_SCALE_APPLIED = (1 << 25), /* vertices have negative scale applied */ + SD_OBJECT_HAS_VOLUME = (1 << 26), /* object has a volume shader */ + SD_OBJECT_INTERSECTS_VOLUME = (1 << 27), /* object intersects AABB of an object with volume shader */ + SD_OBJECT_HAS_VERTEX_MOTION = (1 << 28), /* has position for motion vertices */ SD_OBJECT_FLAGS = (SD_HOLDOUT_MASK|SD_OBJECT_MOTION|SD_TRANSFORM_APPLIED| SD_NEGATIVE_SCALE_APPLIED|SD_OBJECT_HAS_VOLUME| @@ -767,7 +769,7 @@ typedef ccl_addr_space struct ShaderData { int type; /* parametric coordinates - * - barycentric weights for triangles */ + * - barycentric weights for triangles */ float u; float v; /* object id if there is one, ~0 otherwise */ @@ -790,14 +792,14 @@ typedef ccl_addr_space struct ShaderData { #endif #ifdef __DPDU__ /* differential of P w.r.t. parametric coordinates. note that dPdu is - * not readily suitable as a tangent for shading on triangles. */ + * not readily suitable as a tangent for shading on triangles. */ float3 dPdu; float3 dPdv; #endif #ifdef __OBJECT_MOTION__ /* object <-> world space transformations, cached to avoid - * re-interpolating them constantly for shading */ + * re-interpolating them constantly for shading */ Transform ob_tfm; Transform ob_itfm; #endif @@ -807,6 +809,9 @@ typedef ccl_addr_space struct ShaderData { int num_closure; float randb_closure; + /* LCG state for closures that require additional random numbers. */ + uint lcg_state; + /* ray start position, only set for backgrounds */ float3 ray_P; differential3 ray_dP; @@ -1166,11 +1171,11 @@ typedef ccl_addr_space struct DebugData { #define QUEUE_EMPTY_SLOT -1 /* -* Queue 1 - Active rays -* Queue 2 - Background queue -* Queue 3 - Shadow ray cast kernel - AO -* Queeu 4 - Shadow ray cast kernel - direct lighting -*/ + * Queue 1 - Active rays + * Queue 2 - Background queue + * Queue 3 - Shadow ray cast kernel - AO + * Queeu 4 - Shadow ray cast kernel - direct lighting + */ #define NUM_QUEUES 4 /* Queue names */ diff --git a/intern/cycles/kernel/kernel_volume.h b/intern/cycles/kernel/kernel_volume.h index e1ea60f372e..bf8301fe5fb 100644 --- a/intern/cycles/kernel/kernel_volume.h +++ b/intern/cycles/kernel/kernel_volume.h @@ -276,7 +276,7 @@ ccl_device float kernel_volume_distance_sample(float max_t, float3 sigma_t, int float sample_t = min(max_t, -logf(1.0f - xi*(1.0f - sample_transmittance))/sample_sigma_t); *transmittance = volume_color_transmittance(sigma_t, sample_t); - *pdf = (sigma_t * *transmittance)/(make_float3(1.0f, 1.0f, 1.0f) - full_transmittance); + *pdf = safe_divide_color(sigma_t * *transmittance, make_float3(1.0f, 1.0f, 1.0f) - full_transmittance); /* todo: optimization: when taken together with hit/miss decision, * the full_transmittance cancels out drops out and xi does not @@ -290,7 +290,7 @@ ccl_device float3 kernel_volume_distance_pdf(float max_t, float3 sigma_t, float float3 full_transmittance = volume_color_transmittance(sigma_t, max_t); float3 transmittance = volume_color_transmittance(sigma_t, sample_t); - return (sigma_t * transmittance)/(make_float3(1.0f, 1.0f, 1.0f) - full_transmittance); + return safe_divide_color(sigma_t * transmittance, make_float3(1.0f, 1.0f, 1.0f) - full_transmittance); } /* Emission */ @@ -625,11 +625,13 @@ ccl_device void kernel_volume_decoupled_record(KernelGlobals *kg, PathState *sta const int global_max_steps = kernel_data.integrator.volume_max_steps; step_size = kernel_data.integrator.volume_step_size; /* compute exact steps in advance for malloc */ - max_steps = max((int)ceilf(ray->t/step_size), 1); - if(max_steps > global_max_steps) { + if(ray->t > global_max_steps*step_size) { max_steps = global_max_steps; step_size = ray->t / (float)max_steps; } + else { + max_steps = max((int)ceilf(ray->t/step_size), 1); + } #ifdef __KERNEL_CPU__ /* NOTE: For the branched path tracing it's possible to have direct * and indirect light integration both having volume segments allocated. @@ -1216,6 +1218,7 @@ ccl_device void kernel_volume_stack_update_for_subsurface(KernelGlobals *kg, # else Intersection isect; int step = 0; + float3 Pend = ray->P + ray->D*ray->t; while(step < 2 * VOLUME_STACK_SIZE && scene_intersect_volume(kg, &volume_ray, @@ -1227,7 +1230,9 @@ ccl_device void kernel_volume_stack_update_for_subsurface(KernelGlobals *kg, /* Move ray forward. */ volume_ray.P = ray_offset(stack_sd->P, -stack_sd->Ng); - volume_ray.t -= stack_sd->ray_length; + if(volume_ray.t != FLT_MAX) { + volume_ray.D = normalize_len(Pend - volume_ray.P, &volume_ray.t); + } ++step; } # endif diff --git a/intern/cycles/kernel/kernels/cpu/kernel.cpp b/intern/cycles/kernel/kernels/cpu/kernel.cpp index d8a83f69685..f11c85d5f6a 100644 --- a/intern/cycles/kernel/kernels/cpu/kernel.cpp +++ b/intern/cycles/kernel/kernels/cpu/kernel.cpp @@ -154,6 +154,38 @@ void kernel_tex_copy(KernelGlobals *kg, tex->extension = extension; } } + else if(strstr(name, "__tex_image_half4")) { + texture_image_half4 *tex = NULL; + int id = atoi(name + strlen("__tex_image_half4_")); + int array_index = id - TEX_START_HALF4_CPU; + + if(array_index >= 0 && array_index < TEX_NUM_HALF4_CPU) { + tex = &kg->texture_half4_images[array_index]; + } + + if(tex) { + tex->data = (half4*)mem; + tex->dimensions_set(width, height, depth); + tex->interpolation = interpolation; + tex->extension = extension; + } + } + else if(strstr(name, "__tex_image_half")) { + texture_image_half *tex = NULL; + int id = atoi(name + strlen("__tex_image_half_")); + int array_index = id - TEX_START_HALF_CPU; + + if(array_index >= 0 && array_index < TEX_NUM_HALF_CPU) { + tex = &kg->texture_half_images[array_index]; + } + + if(tex) { + tex->data = (half*)mem; + tex->dimensions_set(width, height, depth); + tex->interpolation = interpolation; + tex->extension = extension; + } + } else assert(0); } diff --git a/intern/cycles/kernel/kernels/cpu/kernel_cpu_image.h b/intern/cycles/kernel/kernels/cpu/kernel_cpu_image.h index b10861ab857..47383140170 100644 --- a/intern/cycles/kernel/kernels/cpu/kernel_cpu_image.h +++ b/intern/cycles/kernel/kernels/cpu/kernel_cpu_image.h @@ -23,7 +23,11 @@ CCL_NAMESPACE_BEGIN ccl_device float4 kernel_tex_image_interp_impl(KernelGlobals *kg, int tex, float x, float y) { - if(tex >= TEX_START_BYTE_CPU) + if(tex >= TEX_START_HALF_CPU) + return kg->texture_half_images[tex - TEX_START_HALF_CPU].interp(x, y); + else if(tex >= TEX_START_HALF4_CPU) + return kg->texture_half4_images[tex - TEX_START_HALF4_CPU].interp(x, y); + else if(tex >= TEX_START_BYTE_CPU) return kg->texture_byte_images[tex - TEX_START_BYTE_CPU].interp(x, y); else if(tex >= TEX_START_FLOAT_CPU) return kg->texture_float_images[tex - TEX_START_FLOAT_CPU].interp(x, y); @@ -35,7 +39,11 @@ ccl_device float4 kernel_tex_image_interp_impl(KernelGlobals *kg, int tex, float ccl_device float4 kernel_tex_image_interp_3d_impl(KernelGlobals *kg, int tex, float x, float y, float z) { - if(tex >= TEX_START_BYTE_CPU) + if(tex >= TEX_START_HALF_CPU) + return kg->texture_half_images[tex - TEX_START_HALF_CPU].interp_3d(x, y, z); + else if(tex >= TEX_START_HALF4_CPU) + return kg->texture_half4_images[tex - TEX_START_HALF4_CPU].interp_3d(x, y, z); + else if(tex >= TEX_START_BYTE_CPU) return kg->texture_byte_images[tex - TEX_START_BYTE_CPU].interp_3d(x, y, z); else if(tex >= TEX_START_FLOAT_CPU) return kg->texture_float_images[tex - TEX_START_FLOAT_CPU].interp_3d(x, y, z); @@ -48,7 +56,11 @@ ccl_device float4 kernel_tex_image_interp_3d_impl(KernelGlobals *kg, int tex, fl ccl_device float4 kernel_tex_image_interp_3d_ex_impl(KernelGlobals *kg, int tex, float x, float y, float z, int interpolation) { - if(tex >= TEX_START_BYTE_CPU) + if(tex >= TEX_START_HALF_CPU) + return kg->texture_half4_images[tex - TEX_START_HALF_CPU].interp_3d_ex(x, y, z, interpolation); + else if(tex >= TEX_START_HALF4_CPU) + return kg->texture_half_images[tex - TEX_START_HALF4_CPU].interp_3d_ex(x, y, z, interpolation); + else if(tex >= TEX_START_BYTE_CPU) return kg->texture_byte_images[tex - TEX_START_BYTE_CPU].interp_3d_ex(x, y, z, interpolation); else if(tex >= TEX_START_FLOAT_CPU) return kg->texture_float_images[tex - TEX_START_FLOAT_CPU].interp_3d_ex(x, y, z, interpolation); diff --git a/intern/cycles/kernel/kernels/cuda/kernel.cu b/intern/cycles/kernel/kernels/cuda/kernel.cu index 37fae54faf0..eb2b6ea5414 100644 --- a/intern/cycles/kernel/kernels/cuda/kernel.cu +++ b/intern/cycles/kernel/kernels/cuda/kernel.cu @@ -77,8 +77,8 @@ # define CUDA_KERNEL_MAX_REGISTERS 63 # define CUDA_KERNEL_BRANCHED_MAX_REGISTERS 63 -/* 5.0, 5.2 and 5.3 */ -#elif __CUDA_ARCH__ == 500 || __CUDA_ARCH__ == 520 || __CUDA_ARCH__ == 530 +/* 5.0, 5.2, 5.3, 6.0, 6.1 */ +#elif __CUDA_ARCH__ >= 500 # define CUDA_MULTIPRESSOR_MAX_REGISTERS 65536 # define CUDA_MULTIPROCESSOR_MAX_BLOCKS 32 # define CUDA_BLOCK_MAX_THREADS 1024 @@ -86,7 +86,7 @@ /* tunable parameters */ # define CUDA_THREADS_BLOCK_WIDTH 16 -# define CUDA_KERNEL_MAX_REGISTERS 40 +# define CUDA_KERNEL_MAX_REGISTERS 48 # define CUDA_KERNEL_BRANCHED_MAX_REGISTERS 63 /* unknown architecture */ diff --git a/intern/cycles/kernel/osl/osl_closures.cpp b/intern/cycles/kernel/osl/osl_closures.cpp index 95b8cea0922..02b1491489c 100644 --- a/intern/cycles/kernel/osl/osl_closures.cpp +++ b/intern/cycles/kernel/osl/osl_closures.cpp @@ -44,11 +44,13 @@ #include "kernel_compat_cpu.h" #include "kernel_globals.h" #include "kernel_montecarlo.h" +#include "kernel_random.h" #include "closure/bsdf_util.h" #include "closure/bsdf_ashikhmin_velvet.h" #include "closure/bsdf_diffuse.h" #include "closure/bsdf_microfacet.h" +#include "closure/bsdf_microfacet_multi.h" #include "closure/bsdf_oren_nayar.h" #include "closure/bsdf_reflection.h" #include "closure/bsdf_refraction.h" @@ -205,6 +207,12 @@ void OSLShader::register_closures(OSLShadingSystem *ss_) bsdf_microfacet_ggx_aniso_params(), bsdf_microfacet_ggx_aniso_prepare); register_closure(ss, "microfacet_ggx_refraction", id++, bsdf_microfacet_ggx_refraction_params(), bsdf_microfacet_ggx_refraction_prepare); + register_closure(ss, "microfacet_multi_ggx", id++, + closure_bsdf_microfacet_multi_ggx_params(), closure_bsdf_microfacet_multi_ggx_prepare); + register_closure(ss, "microfacet_multi_ggx_glass", id++, + closure_bsdf_microfacet_multi_ggx_glass_params(), closure_bsdf_microfacet_multi_ggx_glass_prepare); + register_closure(ss, "microfacet_multi_ggx_aniso", id++, + closure_bsdf_microfacet_multi_ggx_aniso_params(), closure_bsdf_microfacet_multi_ggx_aniso_prepare); register_closure(ss, "microfacet_beckmann", id++, bsdf_microfacet_beckmann_params(), bsdf_microfacet_beckmann_prepare); register_closure(ss, "microfacet_beckmann_aniso", id++, @@ -250,5 +258,127 @@ void OSLShader::register_closures(OSLShadingSystem *ss_) volume_absorption_params(), volume_absorption_prepare); } +/* Multiscattering GGX closures */ + +class MicrofacetMultiClosure : public CBSDFClosure { +public: + float3 color; + + /* Technically, the MultiGGX Glass closure may also transmit. + * However, since this is set statically and only used for caustic flags, this is probably as good as it gets. */ + MicrofacetMultiClosure() : CBSDFClosure(LABEL_GLOSSY|LABEL_REFLECT) + { + } + + void setup() + { + sc.prim = NULL; + sc.custom1 = color.x; + sc.custom2 = color.y; + sc.custom3 = color.z; + } + + void blur(float roughness) + { + } + + float3 eval_reflect(const float3 &omega_out, const float3 &omega_in, float& pdf) const + { + pdf = 0.0f; + return make_float3(0.0f, 0.0f, 0.0f); + } + + float3 eval_transmit(const float3 &omega_out, const float3 &omega_in, float& pdf) const + { + pdf = 0.0f; + return make_float3(0.0f, 0.0f, 0.0f); + } + + int sample(const float3 &Ng, + const float3 &omega_out, const float3 &domega_out_dx, const float3 &domega_out_dy, + float randu, float randv, + float3 &omega_in, float3 &domega_in_dx, float3 &domega_in_dy, + float &pdf, float3 &eval) const + { + pdf = 0; + return LABEL_NONE; + } +}; + +class MicrofacetMultiGGXClosure : public MicrofacetMultiClosure { +public: + MicrofacetMultiGGXClosure() : MicrofacetMultiClosure() {} + + void setup() + { + MicrofacetMultiClosure::setup(); + m_shaderdata_flag = bsdf_microfacet_multi_ggx_setup(&sc); + } +}; + +ClosureParam *closure_bsdf_microfacet_multi_ggx_params() +{ + static ClosureParam params[] = { + CLOSURE_FLOAT3_PARAM(MicrofacetMultiGGXClosure, sc.N), + CLOSURE_FLOAT_PARAM(MicrofacetMultiGGXClosure, sc.data0), + CLOSURE_FLOAT3_PARAM(MicrofacetMultiGGXClosure, color), + CLOSURE_STRING_KEYPARAM(MicrofacetMultiGGXClosure, label, "label"), + CLOSURE_FINISH_PARAM(MicrofacetMultiGGXClosure) + }; + return params; +} +CCLOSURE_PREPARE(closure_bsdf_microfacet_multi_ggx_prepare, MicrofacetMultiGGXClosure); + +class MicrofacetMultiGGXAnisoClosure : public MicrofacetMultiClosure { +public: + MicrofacetMultiGGXAnisoClosure() : MicrofacetMultiClosure() {} + + void setup() + { + MicrofacetMultiClosure::setup(); + m_shaderdata_flag = bsdf_microfacet_multi_ggx_aniso_setup(&sc); + } +}; + +ClosureParam *closure_bsdf_microfacet_multi_ggx_aniso_params() +{ + static ClosureParam params[] = { + CLOSURE_FLOAT3_PARAM(MicrofacetMultiGGXClosure, sc.N), + CLOSURE_FLOAT3_PARAM(MicrofacetMultiGGXClosure, sc.T), + CLOSURE_FLOAT_PARAM(MicrofacetMultiGGXClosure, sc.data0), + CLOSURE_FLOAT_PARAM(MicrofacetMultiGGXClosure, sc.data1), + CLOSURE_FLOAT3_PARAM(MicrofacetMultiGGXClosure, color), + CLOSURE_STRING_KEYPARAM(MicrofacetMultiGGXClosure, label, "label"), + CLOSURE_FINISH_PARAM(MicrofacetMultiGGXClosure) + }; + return params; +} +CCLOSURE_PREPARE(closure_bsdf_microfacet_multi_ggx_aniso_prepare, MicrofacetMultiGGXAnisoClosure); + +class MicrofacetMultiGGXGlassClosure : public MicrofacetMultiClosure { +public: + MicrofacetMultiGGXGlassClosure() : MicrofacetMultiClosure() {} + + void setup() + { + MicrofacetMultiClosure::setup(); + m_shaderdata_flag = bsdf_microfacet_multi_ggx_glass_setup(&sc); + } +}; + +ClosureParam *closure_bsdf_microfacet_multi_ggx_glass_params() +{ + static ClosureParam params[] = { + CLOSURE_FLOAT3_PARAM(MicrofacetMultiGGXClosure, sc.N), + CLOSURE_FLOAT_PARAM(MicrofacetMultiGGXClosure, sc.data0), + CLOSURE_FLOAT_PARAM(MicrofacetMultiGGXClosure, sc.data2), + CLOSURE_FLOAT3_PARAM(MicrofacetMultiGGXClosure, color), + CLOSURE_STRING_KEYPARAM(MicrofacetMultiGGXClosure, label, "label"), + CLOSURE_FINISH_PARAM(MicrofacetMultiGGXClosure) + }; + return params; +} +CCLOSURE_PREPARE(closure_bsdf_microfacet_multi_ggx_glass_prepare, MicrofacetMultiGGXGlassClosure); + CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/osl/osl_closures.h b/intern/cycles/kernel/osl/osl_closures.h index 1578d06cd56..c5a1a29b6af 100644 --- a/intern/cycles/kernel/osl/osl_closures.h +++ b/intern/cycles/kernel/osl/osl_closures.h @@ -52,6 +52,9 @@ OSL::ClosureParam *closure_bssrdf_cubic_params(); OSL::ClosureParam *closure_bssrdf_gaussian_params(); OSL::ClosureParam *closure_bssrdf_burley_params(); OSL::ClosureParam *closure_henyey_greenstein_volume_params(); +OSL::ClosureParam *closure_bsdf_microfacet_multi_ggx_params(); +OSL::ClosureParam *closure_bsdf_microfacet_multi_ggx_glass_params(); +OSL::ClosureParam *closure_bsdf_microfacet_multi_ggx_aniso_params(); void closure_emission_prepare(OSL::RendererServices *, int id, void *data); void closure_background_prepare(OSL::RendererServices *, int id, void *data); @@ -63,6 +66,9 @@ void closure_bssrdf_cubic_prepare(OSL::RendererServices *, int id, void *data); void closure_bssrdf_gaussian_prepare(OSL::RendererServices *, int id, void *data); void closure_bssrdf_burley_prepare(OSL::RendererServices *, int id, void *data); void closure_henyey_greenstein_volume_prepare(OSL::RendererServices *, int id, void *data); +void closure_bsdf_microfacet_multi_ggx_prepare(OSL::RendererServices *, int id, void *data); +void closure_bsdf_microfacet_multi_ggx_glass_prepare(OSL::RendererServices *, int id, void *data); +void closure_bsdf_microfacet_multi_ggx_aniso_prepare(OSL::RendererServices *, int id, void *data); #define CCLOSURE_PREPARE(name, classname) \ void name(RendererServices *, int id, void *data) \ diff --git a/intern/cycles/kernel/osl/osl_services.cpp b/intern/cycles/kernel/osl/osl_services.cpp index ebe739ebd0e..acc6887cb17 100644 --- a/intern/cycles/kernel/osl/osl_services.cpp +++ b/intern/cycles/kernel/osl/osl_services.cpp @@ -912,7 +912,7 @@ bool OSLRenderServices::texture(ustring filename, #endif bool status; - if(filename[0] == '@') { + if(filename.length() && filename[0] == '@') { int slot = atoi(filename.c_str() + 1); float4 rgba = kernel_tex_image_interp(slot, s, 1.0f - t); @@ -993,7 +993,7 @@ bool OSLRenderServices::texture3d(ustring filename, } bool status; - if(filename[0] == '@') { + if(filename.length() && filename[0] == '@') { int slot = atoi(filename.c_str() + 1); float4 rgba = kernel_tex_image_interp_3d(slot, P.x, P.y, P.z); diff --git a/intern/cycles/kernel/osl/osl_shader.cpp b/intern/cycles/kernel/osl/osl_shader.cpp index f58368e6789..6cde7419e10 100644 --- a/intern/cycles/kernel/osl/osl_shader.cpp +++ b/intern/cycles/kernel/osl/osl_shader.cpp @@ -177,6 +177,7 @@ static void flatten_surface_closure_tree(ShaderData *sd, int path_flag, case CClosurePrimitive::BSDF: { CBSDFClosure *bsdf = (CBSDFClosure *)prim; int scattering = bsdf->scattering(); + int shaderdata_flag = bsdf->shaderdata_flag(); /* caustic options */ if((scattering & LABEL_GLOSSY) && (path_flag & PATH_RAY_DIFFUSE)) { @@ -201,11 +202,16 @@ static void flatten_surface_closure_tree(ShaderData *sd, int path_flag, sc.data1 = bsdf->sc.data1; sc.data2 = bsdf->sc.data2; sc.prim = bsdf->sc.prim; + if(shaderdata_flag & SD_BSDF_HAS_CUSTOM) { + sc.custom1 = bsdf->sc.custom1; + sc.custom2 = bsdf->sc.custom2; + sc.custom3 = bsdf->sc.custom3; + } /* add */ if(sc.sample_weight > CLOSURE_WEIGHT_CUTOFF && sd->num_closure < MAX_CLOSURE) { sd->closure[sd->num_closure++] = sc; - sd->flag |= bsdf->shaderdata_flag(); + sd->flag |= shaderdata_flag; } break; } diff --git a/intern/cycles/kernel/shaders/CMakeLists.txt b/intern/cycles/kernel/shaders/CMakeLists.txt index 49030f33c26..b43f8402d42 100644 --- a/intern/cycles/kernel/shaders/CMakeLists.txt +++ b/intern/cycles/kernel/shaders/CMakeLists.txt @@ -81,6 +81,7 @@ set(SRC_OSL node_wireframe.osl node_hair_bsdf.osl node_uv_map.osl + node_rgb_to_bw.osl ) set(SRC_OSL_HEADERS diff --git a/intern/cycles/kernel/shaders/node_anisotropic_bsdf.osl b/intern/cycles/kernel/shaders/node_anisotropic_bsdf.osl index 281ed4e8726..bef6d7e8809 100644 --- a/intern/cycles/kernel/shaders/node_anisotropic_bsdf.osl +++ b/intern/cycles/kernel/shaders/node_anisotropic_bsdf.osl @@ -45,12 +45,14 @@ shader node_anisotropic_bsdf( RoughnessV = Roughness / (1.0 - aniso); } - if (distribution == "Sharp") + if (distribution == "sharp") BSDF = Color * reflection(Normal); - else if (distribution == "Beckmann") + else if (distribution == "beckmann") BSDF = Color * microfacet_beckmann_aniso(Normal, T, RoughnessU, RoughnessV); else if (distribution == "GGX") BSDF = Color * microfacet_ggx_aniso(Normal, T, RoughnessU, RoughnessV); + else if (distribution == "Multiscatter GGX") + BSDF = Color * microfacet_multi_ggx_aniso(Normal, T, RoughnessU, RoughnessV, Color); else BSDF = Color * ashikhmin_shirley(Normal, T, RoughnessU, RoughnessV); } diff --git a/intern/cycles/kernel/shaders/node_environment_texture.osl b/intern/cycles/kernel/shaders/node_environment_texture.osl index 3a0b782c98e..0a7f602226d 100644 --- a/intern/cycles/kernel/shaders/node_environment_texture.osl +++ b/intern/cycles/kernel/shaders/node_environment_texture.osl @@ -44,7 +44,7 @@ shader node_environment_texture( matrix mapping = matrix(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), vector Vector = P, string filename = "", - string projection = "Equirectangular", + string projection = "equirectangular", string interpolation = "linear", string color_space = "sRGB", int is_float = 1, @@ -59,7 +59,7 @@ shader node_environment_texture( p = normalize(p); - if (projection == "Equirectangular") + if (projection == "equirectangular") p = environment_texture_direction_to_equirectangular(p); else p = environment_texture_direction_to_mirrorball(p); diff --git a/intern/cycles/kernel/shaders/node_glass_bsdf.osl b/intern/cycles/kernel/shaders/node_glass_bsdf.osl index 68bc107cc5e..a9723a8300a 100644 --- a/intern/cycles/kernel/shaders/node_glass_bsdf.osl +++ b/intern/cycles/kernel/shaders/node_glass_bsdf.osl @@ -19,7 +19,7 @@ shader node_glass_bsdf( color Color = 0.8, - string distribution = "Sharp", + string distribution = "sharp", float Roughness = 0.2, float IOR = 1.45, normal Normal = N, @@ -30,11 +30,13 @@ shader node_glass_bsdf( float cosi = dot(I, Normal); float Fr = fresnel_dielectric_cos(cosi, eta); - if (distribution == "Sharp") + if (distribution == "sharp") BSDF = Color * (Fr * reflection(Normal) + (1.0 - Fr) * refraction(Normal, eta)); - else if (distribution == "Beckmann") + else if (distribution == "beckmann") BSDF = Color * (Fr * microfacet_beckmann(Normal, Roughness) + (1.0 - Fr) * microfacet_beckmann_refraction(Normal, Roughness, eta)); + else if (distribution == "Multiscatter GGX") + BSDF = Color * microfacet_multi_ggx_glass(Normal, Roughness, eta, Color); else if (distribution == "GGX") BSDF = Color * (Fr * microfacet_ggx(Normal, Roughness) + (1.0 - Fr) * microfacet_ggx_refraction(Normal, Roughness, eta)); diff --git a/intern/cycles/kernel/shaders/node_glossy_bsdf.osl b/intern/cycles/kernel/shaders/node_glossy_bsdf.osl index d3250b32d0b..f4ea7e7dc6a 100644 --- a/intern/cycles/kernel/shaders/node_glossy_bsdf.osl +++ b/intern/cycles/kernel/shaders/node_glossy_bsdf.osl @@ -24,12 +24,14 @@ shader node_glossy_bsdf( normal Normal = N, output closure color BSDF = 0) { - if (distribution == "Sharp") + if (distribution == "sharp") BSDF = Color * reflection(Normal); - else if (distribution == "Beckmann") + else if (distribution == "beckmann") BSDF = Color * microfacet_beckmann(Normal, Roughness); else if (distribution == "GGX") BSDF = Color * microfacet_ggx(Normal, Roughness); + else if (distribution == "Multiscatter GGX") + BSDF = Color * microfacet_multi_ggx(Normal, Roughness, Color); else BSDF = Color * ashikhmin_shirley(Normal, vector(0, 0, 0), Roughness, Roughness); diff --git a/intern/cycles/kernel/shaders/node_gradient_texture.osl b/intern/cycles/kernel/shaders/node_gradient_texture.osl index 69e2ee54bdf..f458937a18f 100644 --- a/intern/cycles/kernel/shaders/node_gradient_texture.osl +++ b/intern/cycles/kernel/shaders/node_gradient_texture.osl @@ -29,31 +29,31 @@ float gradient(point p, string type) float result = 0.0; - if (type == "Linear") { + if (type == "linear") { result = x; } - else if (type == "Quadratic") { + else if (type == "quadratic") { float r = max(x, 0.0); result = r * r; } - else if (type == "Easing") { + else if (type == "easing") { float r = min(max(x, 0.0), 1.0); float t = r * r; result = (3.0 * t - 2.0 * t * r); } - else if (type == "Diagonal") { + else if (type == "diagonal") { result = (x + y) * 0.5; } - else if (type == "Radial") { + else if (type == "radial") { result = atan2(y, x) / M_2PI + 0.5; } else { float r = max(1.0 - sqrt(x * x + y * y + z * z), 0.0); - if (type == "Quadratic Sphere") + if (type == "quadratic_sphere") result = r * r; - else if (type == "Spherical") + else if (type == "spherical") result = r; } @@ -63,7 +63,7 @@ float gradient(point p, string type) shader node_gradient_texture( int use_mapping = 0, matrix mapping = matrix(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), - string type = "Linear", + string type = "linear", point Vector = P, output float Fac = 0.0, output color Color = 0.0) diff --git a/intern/cycles/kernel/shaders/node_hair_bsdf.osl b/intern/cycles/kernel/shaders/node_hair_bsdf.osl index 54d4cb67c3b..c8cb88f0c0b 100644 --- a/intern/cycles/kernel/shaders/node_hair_bsdf.osl +++ b/intern/cycles/kernel/shaders/node_hair_bsdf.osl @@ -20,7 +20,7 @@ shader node_hair_bsdf( color Color = 0.8, - string component = "Reflection", + string component = "reflection", float Offset = 0.0, float RoughnessU = 0.1, float RoughnessV = 1.0, @@ -37,7 +37,7 @@ shader node_hair_bsdf( BSDF = transparent(); } else { - if (component == "Reflection") + if (component == "reflection") BSDF = Color * hair_reflection(Normal, roughnessh, roughnessv, normalize(dPdv), 0.0); else BSDF = Color * hair_transmission(Normal, roughnessh, roughnessv, normalize(dPdv), 0.0); @@ -48,7 +48,7 @@ shader node_hair_bsdf( BSDF = transparent(); } else { - if (component == "Reflection") + if (component == "reflection") BSDF = Color * hair_reflection(Normal, roughnessh, roughnessv, dPdu, -Offset); else BSDF = Color * hair_transmission(Normal, roughnessh, roughnessv, dPdu, -Offset); diff --git a/intern/cycles/kernel/shaders/node_image_texture.osl b/intern/cycles/kernel/shaders/node_image_texture.osl index d09174ff5d3..7cd2922dd4f 100644 --- a/intern/cycles/kernel/shaders/node_image_texture.osl +++ b/intern/cycles/kernel/shaders/node_image_texture.osl @@ -86,9 +86,9 @@ shader node_image_texture( point Vector = P, string filename = "", string color_space = "sRGB", - string projection = "Flat", + string projection = "flat", string interpolation = "smartcubic", - string wrap = "periodic", + string extension = "periodic", float projection_blend = 0.0, int is_float = 1, int use_alpha = 1, @@ -100,7 +100,7 @@ shader node_image_texture( if (use_mapping) p = transform(mapping, p); - if (projection == "Flat") { + if (projection == "flat") { Color = image_texture_lookup(filename, color_space, p[0], p[1], @@ -108,9 +108,9 @@ shader node_image_texture( use_alpha, is_float, interpolation, - wrap); + extension); } - else if (projection == "Box") { + else if (projection == "box") { /* object space normal */ vector Nob = transform("world", "object", N); @@ -184,7 +184,7 @@ shader node_image_texture( use_alpha, is_float, interpolation, - wrap); + extension); Alpha += weight[0] * tmp_alpha; } if (weight[1] > 0.0) { @@ -195,7 +195,7 @@ shader node_image_texture( use_alpha, is_float, interpolation, - wrap); + extension); Alpha += weight[1] * tmp_alpha; } if (weight[2] > 0.0) { @@ -206,11 +206,11 @@ shader node_image_texture( use_alpha, is_float, interpolation, - wrap); + extension); Alpha += weight[2] * tmp_alpha; } } - else if (projection == "Sphere") { + else if (projection == "sphere") { point projected = map_to_sphere(texco_remap_square(p)); Color = image_texture_lookup(filename, color_space, @@ -219,9 +219,9 @@ shader node_image_texture( use_alpha, is_float, interpolation, - wrap); + extension); } - else if (projection == "Tube") { + else if (projection == "tube") { point projected = map_to_tube(texco_remap_square(p)); Color = image_texture_lookup(filename, color_space, @@ -230,6 +230,6 @@ shader node_image_texture( use_alpha, is_float, interpolation, - wrap); + extension); } } diff --git a/intern/cycles/kernel/shaders/node_math.osl b/intern/cycles/kernel/shaders/node_math.osl index 85eac0b97a6..f309ef7c6f3 100644 --- a/intern/cycles/kernel/shaders/node_math.osl +++ b/intern/cycles/kernel/shaders/node_math.osl @@ -49,7 +49,7 @@ float safe_log(float a, float b) } shader node_math( - string type = "Add", + string type = "add", int use_clamp = 0, float Value1 = 0.0, float Value2 = 0.0, @@ -57,43 +57,43 @@ shader node_math( { /* OSL asin, acos, pow check for values that could give rise to nan */ - if (type == "Add") + if (type == "add") Value = Value1 + Value2; - else if (type == "Subtract") + else if (type == "subtract") Value = Value1 - Value2; - else if (type == "Multiply") + else if (type == "multiply") Value = Value1 * Value2; - else if (type == "Divide") + else if (type == "divide") Value = safe_divide(Value1, Value2); - else if (type == "Sine") + else if (type == "sine") Value = sin(Value1); - else if (type == "Cosine") + else if (type == "cosine") Value = cos(Value1); - else if (type == "Tangent") + else if (type == "tangent") Value = tan(Value1); - else if (type == "Arcsine") + else if (type == "arcsine") Value = asin(Value1); - else if (type == "Arccosine") + else if (type == "arccosine") Value = acos(Value1); - else if (type == "Arctangent") + else if (type == "arctangent") Value = atan(Value1); - else if (type == "Power") + else if (type == "power") Value = pow(Value1, Value2); - else if (type == "Logarithm") + else if (type == "logarithm") Value = safe_log(Value1, Value2); - else if (type == "Minimum") + else if (type == "minimum") Value = min(Value1, Value2); - else if (type == "Maximum") + else if (type == "maximum") Value = max(Value1, Value2); - else if (type == "Round") + else if (type == "round") Value = floor(Value1 + 0.5); - else if (type == "Less Than") + else if (type == "less_than") Value = Value1 < Value2; - else if (type == "Greater Than") + else if (type == "greater_than") Value = Value1 > Value2; - else if (type == "Modulo") + else if (type == "modulo") Value = safe_modulo(Value1, Value2); - else if (type == "Absolute") + else if (type == "absolute") Value = fabs(Value1); if (use_clamp) diff --git a/intern/cycles/kernel/shaders/node_mix.osl b/intern/cycles/kernel/shaders/node_mix.osl index 4a66748ed6a..0862c34b6e1 100644 --- a/intern/cycles/kernel/shaders/node_mix.osl +++ b/intern/cycles/kernel/shaders/node_mix.osl @@ -277,7 +277,7 @@ color node_mix_clamp(color col) } shader node_mix( - string type = "Mix", + string type = "mix", int use_clamp = 0, float Fac = 0.5, color Color1 = 0.0, @@ -286,41 +286,41 @@ shader node_mix( { float t = clamp(Fac, 0.0, 1.0); - if (type == "Mix") + if (type == "mix") Color = node_mix_blend(t, Color1, Color2); - if (type == "Add") + if (type == "add") Color = node_mix_add(t, Color1, Color2); - if (type == "Multiply") + if (type == "multiply") Color = node_mix_mul(t, Color1, Color2); - if (type == "Screen") + if (type == "screen") Color = node_mix_screen(t, Color1, Color2); - if (type == "Overlay") + if (type == "overlay") Color = node_mix_overlay(t, Color1, Color2); - if (type == "Subtract") + if (type == "subtract") Color = node_mix_sub(t, Color1, Color2); - if (type == "Divide") + if (type == "divide") Color = node_mix_div(t, Color1, Color2); - if (type == "Difference") + if (type == "difference") Color = node_mix_diff(t, Color1, Color2); - if (type == "Darken") + if (type == "darken") Color = node_mix_dark(t, Color1, Color2); - if (type == "Lighten") + if (type == "lighten") Color = node_mix_light(t, Color1, Color2); - if (type == "Dodge") + if (type == "dodge") Color = node_mix_dodge(t, Color1, Color2); - if (type == "Burn") + if (type == "burn") Color = node_mix_burn(t, Color1, Color2); - if (type == "Hue") + if (type == "hue") Color = node_mix_hue(t, Color1, Color2); - if (type == "Saturation") + if (type == "saturation") Color = node_mix_sat(t, Color1, Color2); - if (type == "Value") + if (type == "value") Color = node_mix_val (t, Color1, Color2); - if (type == "Color") + if (type == "color") Color = node_mix_color(t, Color1, Color2); - if (type == "Soft Light") + if (type == "soft_light") Color = node_mix_soft(t, Color1, Color2); - if (type == "Linear Light") + if (type == "linear_light") Color = node_mix_linear(t, Color1, Color2); if (use_clamp) diff --git a/intern/cycles/kernel/shaders/node_musgrave_texture.osl b/intern/cycles/kernel/shaders/node_musgrave_texture.osl index 2f9f62bcfe8..91f4fba5898 100644 --- a/intern/cycles/kernel/shaders/node_musgrave_texture.osl +++ b/intern/cycles/kernel/shaders/node_musgrave_texture.osl @@ -210,15 +210,15 @@ shader node_musgrave_texture( p = p * Scale; - if (type == "Multifractal") + if (type == "multifractal") Fac = intensity * noise_musgrave_multi_fractal(p, dimension, lacunarity, octaves); else if (type == "fBM") Fac = intensity * noise_musgrave_fBm(p, dimension, lacunarity, octaves); - else if (type == "Hybrid Multifractal") + else if (type == "hybrid_multifractal") Fac = intensity * noise_musgrave_hybrid_multi_fractal(p, dimension, lacunarity, octaves, Offset, Gain); - else if (type == "Ridged Multifractal") + else if (type == "ridged_multifractal") Fac = intensity * noise_musgrave_ridged_multi_fractal(p, dimension, lacunarity, octaves, Offset, Gain); - else if (type == "Hetero Terrain") + else if (type == "hetero_terrain") Fac = intensity * noise_musgrave_hetero_terrain(p, dimension, lacunarity, octaves, Offset); Color = color(Fac, Fac, Fac); diff --git a/intern/cycles/kernel/shaders/node_normal_map.osl b/intern/cycles/kernel/shaders/node_normal_map.osl index 01be566fb20..f95e9fcfe3c 100644 --- a/intern/cycles/kernel/shaders/node_normal_map.osl +++ b/intern/cycles/kernel/shaders/node_normal_map.osl @@ -20,14 +20,14 @@ shader node_normal_map( normal NormalIn = N, float Strength = 1.0, color Color = color(0.5, 0.5, 1.0), - string space = "Tangent", + string space = "tangent", string attr_name = "geom:tangent", string attr_sign_name = "geom:tangent_sign", output normal Normal = NormalIn) { color mcolor = 2.0 * color(Color[0] - 0.5, Color[1] - 0.5, Color[2] - 0.5); - if (space == "Tangent") { + if (space == "tangent") { vector tangent; vector ninterp; float tangent_sign; @@ -53,20 +53,20 @@ shader node_normal_map( Normal = normal(0, 0, 0); } } - else if (space == "Object") { + else if (space == "object") { Normal = normalize(transform("object", "world", vector(mcolor))); } - else if (space == "World") { + else if (space == "world") { Normal = normalize(vector(mcolor)); } - else if (space == "Blender Object") { + else if (space == "blender_object") { /* strange blender convention */ mcolor[1] = -mcolor[1]; mcolor[2] = -mcolor[2]; Normal = normalize(transform("object", "world", vector(mcolor))); } - else if (space == "Blender World") { + else if (space == "blender_world") { /* strange blender convention */ mcolor[1] = -mcolor[1]; mcolor[2] = -mcolor[2]; diff --git a/intern/cycles/kernel/shaders/node_refraction_bsdf.osl b/intern/cycles/kernel/shaders/node_refraction_bsdf.osl index d458ca730a4..828becf1818 100644 --- a/intern/cycles/kernel/shaders/node_refraction_bsdf.osl +++ b/intern/cycles/kernel/shaders/node_refraction_bsdf.osl @@ -18,7 +18,7 @@ shader node_refraction_bsdf( color Color = 0.8, - string distribution = "Sharp", + string distribution = "sharp", float Roughness = 0.2, float IOR = 1.45, normal Normal = N, @@ -27,9 +27,9 @@ shader node_refraction_bsdf( float f = max(IOR, 1e-5); float eta = backfacing() ? 1.0 / f : f; - if (distribution == "Sharp") + if (distribution == "sharp") BSDF = Color * refraction(Normal, eta); - else if (distribution == "Beckmann") + else if (distribution == "beckmann") BSDF = Color * microfacet_beckmann_refraction(Normal, Roughness, eta); else if (distribution == "GGX") BSDF = Color * microfacet_ggx_refraction(Normal, Roughness, eta); diff --git a/intern/cycles/kernel/shaders/node_rgb_to_bw.osl b/intern/cycles/kernel/shaders/node_rgb_to_bw.osl new file mode 100644 index 00000000000..903dfcdc881 --- /dev/null +++ b/intern/cycles/kernel/shaders/node_rgb_to_bw.osl @@ -0,0 +1,25 @@ +/* + * Copyright 2011-2013 Blender Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "stdosl.h" + +shader node_rgb_to_bw( + color Color = 0.0, + output float Val = 0.0) +{ + Val = Color[0] * 0.2126 + Color[1] * 0.7152 + Color[2] * 0.0722; +} + diff --git a/intern/cycles/kernel/shaders/node_sky_texture.osl b/intern/cycles/kernel/shaders/node_sky_texture.osl index 05eed23bea8..a6c187d15f2 100644 --- a/intern/cycles/kernel/shaders/node_sky_texture.osl +++ b/intern/cycles/kernel/shaders/node_sky_texture.osl @@ -111,7 +111,7 @@ shader node_sky_texture( int use_mapping = 0, matrix mapping = matrix(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), vector Vector = P, - string sky_model = "Hosek / Wilkie", + string type = "hosek_wilkie", float theta = 0.0, float phi = 0.0, color radiance = color(0.0, 0.0, 0.0), @@ -125,7 +125,7 @@ shader node_sky_texture( if (use_mapping) p = transform(mapping, p); - if (sky_model == "Hosek / Wilkie") + if (type == "hosek_wilkie") Color = sky_radiance_new(p, phi, theta, radiance, config_x, config_y, config_z); else Color = sky_radiance_old(p, phi, theta, radiance, config_x, config_y, config_z); diff --git a/intern/cycles/kernel/shaders/node_subsurface_scattering.osl b/intern/cycles/kernel/shaders/node_subsurface_scattering.osl index 1877c7e595f..5ba8f34021d 100644 --- a/intern/cycles/kernel/shaders/node_subsurface_scattering.osl +++ b/intern/cycles/kernel/shaders/node_subsurface_scattering.osl @@ -22,13 +22,13 @@ shader node_subsurface_scattering( vector Radius = vector(0.1, 0.1, 0.1), float TextureBlur = 0.0, float Sharpness = 0.0, - string falloff = "Cubic", + string falloff = "cubic", normal Normal = N, output closure color BSSRDF = 0) { - if (falloff == "Gaussian") + if (falloff == "gaussian") BSSRDF = Color * bssrdf_gaussian(Normal, Scale * Radius, TextureBlur); - else if (falloff == "Cubic") + else if (falloff == "cubic") BSSRDF = Color * bssrdf_cubic(Normal, Scale * Radius, TextureBlur, Sharpness); else BSSRDF = Color * bssrdf_burley(Normal, Scale * Radius, TextureBlur, Color); diff --git a/intern/cycles/kernel/shaders/node_tangent.osl b/intern/cycles/kernel/shaders/node_tangent.osl index 53a47396f9f..c527070a2c8 100644 --- a/intern/cycles/kernel/shaders/node_tangent.osl +++ b/intern/cycles/kernel/shaders/node_tangent.osl @@ -19,24 +19,24 @@ shader node_tangent( normal NormalIn = N, string attr_name = "geom:tangent", - string direction_type = "Radial", - string axis = "Z", + string direction_type = "radial", + string axis = "z", output normal Tangent = normalize(dPdu)) { vector T; - if (direction_type == "UV Map") { + if (direction_type == "uv_map") { getattribute(attr_name, T); } - else if (direction_type == "Radial") { + else if (direction_type == "radial") { point generated; if (!getattribute("geom:generated", generated)) generated = P; - if (axis == "X") + if (axis == "x") T = vector(0.0, -(generated[2] - 0.5), (generated[1] - 0.5)); - else if (axis == "Y") + else if (axis == "y") T = vector(-(generated[2] - 0.5), 0.0, (generated[0] - 0.5)); else T = vector(-(generated[1] - 0.5), (generated[0] - 0.5), 0.0); diff --git a/intern/cycles/kernel/shaders/node_toon_bsdf.osl b/intern/cycles/kernel/shaders/node_toon_bsdf.osl index 75c5d06f847..ae68a463e46 100644 --- a/intern/cycles/kernel/shaders/node_toon_bsdf.osl +++ b/intern/cycles/kernel/shaders/node_toon_bsdf.osl @@ -18,15 +18,15 @@ shader node_toon_bsdf( color Color = 0.8, - string component = "Diffuse", + string component = "diffuse", float Size = 0.5, float Smooth = 0.0, normal Normal = N, output closure color BSDF = 0) { - if (component == "Diffuse") + if (component == "diffuse") BSDF = Color * diffuse_toon(Normal, Size, Smooth); - else if (component == "Glossy") + else if (component == "glossy") BSDF = Color * glossy_toon(Normal, Size, Smooth); } diff --git a/intern/cycles/kernel/shaders/node_uv_map.osl b/intern/cycles/kernel/shaders/node_uv_map.osl index 77e2e8d12d7..b46b2e73457 100644 --- a/intern/cycles/kernel/shaders/node_uv_map.osl +++ b/intern/cycles/kernel/shaders/node_uv_map.osl @@ -18,7 +18,7 @@ shader node_uv_map( int from_dupli = 0, - string name = "", + string attribute = "", string bump_offset = "center", output point UV = point(0.0, 0.0, 0.0)) { @@ -26,10 +26,10 @@ shader node_uv_map( getattribute("geom:dupli_uv", UV); } else { - if (name == "") + if (attribute == "") getattribute("geom:uv", UV); else - getattribute(name, UV); + getattribute(attribute, UV); } if (bump_offset == "dx") { diff --git a/intern/cycles/kernel/shaders/node_vector_math.osl b/intern/cycles/kernel/shaders/node_vector_math.osl index f83412dc0f7..a7e3637402e 100644 --- a/intern/cycles/kernel/shaders/node_vector_math.osl +++ b/intern/cycles/kernel/shaders/node_vector_math.osl @@ -17,33 +17,33 @@ #include "stdosl.h" shader node_vector_math( - string type = "Add", + string type = "add", vector Vector1 = vector(0.0, 0.0, 0.0), vector Vector2 = vector(0.0, 0.0, 0.0), output float Value = 0.0, output vector Vector = vector(0.0, 0.0, 0.0)) { - if (type == "Add") { + if (type == "add") { Vector = Vector1 + Vector2; Value = (abs(Vector[0]) + abs(Vector[1]) + abs(Vector[2])) / 3.0; } - else if (type == "Subtract") { + else if (type == "subtract") { Vector = Vector1 - Vector2; Value = (abs(Vector[0]) + abs(Vector[1]) + abs(Vector[2])) / 3.0; } - else if (type == "Average") { + else if (type == "average") { Value = length(Vector1 + Vector2); Vector = normalize(Vector1 + Vector2); } - else if (type == "Dot Product") { + else if (type == "dot_product") { Value = dot(Vector1, Vector2); } - else if (type == "Cross Product") { + else if (type == "cross_product") { vector c = cross(Vector1, Vector2); Value = length(c); Vector = normalize(c); } - else if (type == "Normalize") { + else if (type == "normalize") { Value = length(Vector1); Vector = normalize(Vector1); } diff --git a/intern/cycles/kernel/shaders/node_vector_transform.osl b/intern/cycles/kernel/shaders/node_vector_transform.osl index 8ebaa31ab25..afb95b340d1 100644 --- a/intern/cycles/kernel/shaders/node_vector_transform.osl +++ b/intern/cycles/kernel/shaders/node_vector_transform.osl @@ -17,18 +17,18 @@ #include "stdosl.h" shader node_vector_transform( - string type = "Vector", + string type = "vector", string convert_from = "world", string convert_to = "object", vector VectorIn = vector(0.0, 0.0, 0.0), output vector VectorOut = vector(0.0, 0.0, 0.0)) { - if (type == "Vector" || type == "Normal") { + if (type == "vector" || type == "normal") { VectorOut = transform(convert_from, convert_to, VectorIn); - if (type == "Normal") + if (type == "normal") VectorOut = normalize(VectorOut); } - else if (type == "Point") { + else if (type == "point") { point Point = (point)VectorIn; VectorOut = transform(convert_from, convert_to, Point); } diff --git a/intern/cycles/kernel/shaders/node_voronoi_texture.osl b/intern/cycles/kernel/shaders/node_voronoi_texture.osl index bacdd593c7c..0c3b95ae4d0 100644 --- a/intern/cycles/kernel/shaders/node_voronoi_texture.osl +++ b/intern/cycles/kernel/shaders/node_voronoi_texture.osl @@ -22,7 +22,7 @@ shader node_voronoi_texture( int use_mapping = 0, matrix mapping = matrix(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), - string coloring = "Intensity", + string coloring = "intensity", float Scale = 5.0, point Vector = P, output float Fac = 0.0, @@ -40,7 +40,7 @@ shader node_voronoi_texture( voronoi(p * Scale, 1.0, da, pa); /* Colored output */ - if (coloring == "Intensity") { + if (coloring == "intensity") { Fac = fabs(da[0]); Color = color(Fac); } diff --git a/intern/cycles/kernel/shaders/node_wave_texture.osl b/intern/cycles/kernel/shaders/node_wave_texture.osl index a07742faefc..71bc9324705 100644 --- a/intern/cycles/kernel/shaders/node_wave_texture.osl +++ b/intern/cycles/kernel/shaders/node_wave_texture.osl @@ -23,10 +23,10 @@ float wave(point p, string type, string profile, float detail, float distortion, { float n = 0.0; - if (type == "Bands") { + if (type == "bands") { n = (p[0] + p[1] + p[2]) * 10.0; } - else if (type == "Rings") { + else if (type == "rings") { n = length(p) * 20.0; } @@ -34,7 +34,7 @@ float wave(point p, string type, string profile, float detail, float distortion, n = n + (distortion * noise_turbulence(p * dscale, detail, 0)); } - if (profile == "Sine") { + if (profile == "sine") { return 0.5 + 0.5 * sin(n); } else { @@ -48,8 +48,8 @@ float wave(point p, string type, string profile, float detail, float distortion, shader node_wave_texture( int use_mapping = 0, matrix mapping = matrix(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), - string type = "Bands", - string profile = "Sine", + string type = "bands", + string profile = "sine", float Scale = 5.0, float Distortion = 0.0, float Detail = 2.0, diff --git a/intern/cycles/kernel/shaders/stdosl.h b/intern/cycles/kernel/shaders/stdosl.h index 8d5d3746caf..a8dda8a12c9 100644 --- a/intern/cycles/kernel/shaders/stdosl.h +++ b/intern/cycles/kernel/shaders/stdosl.h @@ -527,6 +527,9 @@ closure color transparent() BUILTIN; closure color microfacet_ggx(normal N, float ag) BUILTIN; closure color microfacet_ggx_aniso(normal N, vector T, float ax, float ay) BUILTIN; closure color microfacet_ggx_refraction(normal N, float ag, float eta) BUILTIN; +closure color microfacet_multi_ggx(normal N, float ag, color C) BUILTIN; +closure color microfacet_multi_ggx_aniso(normal N, vector T, float ax, float ay, color C) BUILTIN; +closure color microfacet_multi_ggx_glass(normal N, float ag, float eta, color C) BUILTIN; closure color microfacet_beckmann(normal N, float ab) BUILTIN; closure color microfacet_beckmann_aniso(normal N, vector T, float ax, float ay) BUILTIN; closure color microfacet_beckmann_refraction(normal N, float ab, float eta) BUILTIN; diff --git a/intern/cycles/kernel/split/kernel_shader_eval.h b/intern/cycles/kernel/split/kernel_shader_eval.h index e816a818915..cef64bf5f36 100644 --- a/intern/cycles/kernel/split/kernel_shader_eval.h +++ b/intern/cycles/kernel/split/kernel_shader_eval.h @@ -65,6 +65,6 @@ ccl_device void kernel_shader_eval( isect, &ray); float rbsdf = path_state_rng_1D_for_decision(kg, rng, state, PRNG_BSDF); - shader_eval_surface(kg, sd, state, rbsdf, state->flag, SHADER_CONTEXT_MAIN); + shader_eval_surface(kg, sd, rng, state, rbsdf, state->flag, SHADER_CONTEXT_MAIN); } } diff --git a/intern/cycles/kernel/svm/svm.h b/intern/cycles/kernel/svm/svm.h index 543e31bcb35..de7e03e5a19 100644 --- a/intern/cycles/kernel/svm/svm.h +++ b/intern/cycles/kernel/svm/svm.h @@ -142,6 +142,7 @@ CCL_NAMESPACE_END #include "svm_noise.h" #include "svm_texture.h" +#include "svm_color_util.h" #include "svm_math_util.h" #include "svm_attribute.h" diff --git a/intern/cycles/kernel/svm/svm_brightness.h b/intern/cycles/kernel/svm/svm_brightness.h index e4d545a00ae..d71b0ee0b61 100644 --- a/intern/cycles/kernel/svm/svm_brightness.h +++ b/intern/cycles/kernel/svm/svm_brightness.h @@ -25,12 +25,7 @@ ccl_device void svm_node_brightness(ShaderData *sd, float *stack, uint in_color, float brightness = stack_load_float(stack, bright_offset); float contrast = stack_load_float(stack, contrast_offset); - float a = 1.0f + contrast; - float b = brightness - contrast*0.5f; - - color.x = max(a*color.x + b, 0.0f); - color.y = max(a*color.y + b, 0.0f); - color.z = max(a*color.z + b, 0.0f); + color = svm_brightness_contrast(color, brightness, contrast); if(stack_valid(out_color)) stack_store_float3(stack, out_color, color); diff --git a/intern/cycles/kernel/svm/svm_closure.h b/intern/cycles/kernel/svm/svm_closure.h index 65512a0105c..fae89aade60 100644 --- a/intern/cycles/kernel/svm/svm_closure.h +++ b/intern/cycles/kernel/svm/svm_closure.h @@ -186,7 +186,8 @@ ccl_device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float * case CLOSURE_BSDF_REFLECTION_ID: case CLOSURE_BSDF_MICROFACET_GGX_ID: case CLOSURE_BSDF_MICROFACET_BECKMANN_ID: - case CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID: { + case CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID: + case CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID: { #ifdef __CAUSTICS_TRICKS__ if(!kernel_data.integrator.caustics_reflective && (path_flag & PATH_RAY_DIFFUSE)) break; @@ -206,6 +207,14 @@ ccl_device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float * ccl_fetch(sd, flag) |= bsdf_microfacet_beckmann_setup(sc); else if(type == CLOSURE_BSDF_MICROFACET_GGX_ID) ccl_fetch(sd, flag) |= bsdf_microfacet_ggx_setup(sc); + else if(type == CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID) { + kernel_assert(stack_valid(data_node.z)); + float3 color = stack_load_float3(stack, data_node.z); + sc->custom1 = color.x; + sc->custom2 = color.y; + sc->custom3 = color.z; + ccl_fetch(sd, flag) |= bsdf_microfacet_multi_ggx_setup(sc); + } else ccl_fetch(sd, flag) |= bsdf_ashikhmin_shirley_setup(sc); } @@ -307,8 +316,36 @@ ccl_device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float * break; } + case CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID: { +#ifdef __CAUSTICS_TRICKS__ + if(!kernel_data.integrator.caustics_reflective && !kernel_data.integrator.caustics_refractive && (path_flag & PATH_RAY_DIFFUSE)) + break; +#endif + ShaderClosure *sc = svm_node_closure_get_bsdf(sd, mix_weight); + + if(sc) { + sc->N = N; + + sc->data0 = param1; + sc->data1 = param1; + float eta = fmaxf(param2, 1e-5f); + sc->data2 = (ccl_fetch(sd, flag) & SD_BACKFACING)? 1.0f/eta: eta; + + kernel_assert(stack_valid(data_node.z)); + float3 color = stack_load_float3(stack, data_node.z); + sc->custom1 = color.x; + sc->custom2 = color.y; + sc->custom3 = color.z; + + /* setup bsdf */ + ccl_fetch(sd, flag) |= bsdf_microfacet_multi_ggx_glass_setup(sc); + } + + break; + } case CLOSURE_BSDF_MICROFACET_BECKMANN_ANISO_ID: case CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID: + case CLOSURE_BSDF_MICROFACET_MULTI_GGX_ANISO_ID: case CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ANISO_ID: { #ifdef __CAUSTICS_TRICKS__ if(!kernel_data.integrator.caustics_reflective && (path_flag & PATH_RAY_DIFFUSE)) @@ -346,6 +383,14 @@ ccl_device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float * ccl_fetch(sd, flag) |= bsdf_microfacet_beckmann_aniso_setup(sc); else if(type == CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID) ccl_fetch(sd, flag) |= bsdf_microfacet_ggx_aniso_setup(sc); + else if(type == CLOSURE_BSDF_MICROFACET_MULTI_GGX_ANISO_ID) { + kernel_assert(stack_valid(data_node.w)); + float3 color = stack_load_float3(stack, data_node.w); + sc->custom1 = color.x; + sc->custom2 = color.y; + sc->custom3 = color.z; + ccl_fetch(sd, flag) |= bsdf_microfacet_multi_ggx_aniso_setup(sc); + } else ccl_fetch(sd, flag) |= bsdf_ashikhmin_shirley_aniso_setup(sc); } diff --git a/intern/cycles/kernel/svm/svm_color_util.h b/intern/cycles/kernel/svm/svm_color_util.h new file mode 100644 index 00000000000..258cdeb630e --- /dev/null +++ b/intern/cycles/kernel/svm/svm_color_util.h @@ -0,0 +1,306 @@ +/* + * Copyright 2011-2013 Blender Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +CCL_NAMESPACE_BEGIN + +ccl_device float3 svm_mix_blend(float t, float3 col1, float3 col2) +{ + return interp(col1, col2, t); +} + +ccl_device float3 svm_mix_add(float t, float3 col1, float3 col2) +{ + return interp(col1, col1 + col2, t); +} + +ccl_device float3 svm_mix_mul(float t, float3 col1, float3 col2) +{ + return interp(col1, col1 * col2, t); +} + +ccl_device float3 svm_mix_screen(float t, float3 col1, float3 col2) +{ + float tm = 1.0f - t; + float3 one = make_float3(1.0f, 1.0f, 1.0f); + float3 tm3 = make_float3(tm, tm, tm); + + return one - (tm3 + t*(one - col2))*(one - col1); +} + +ccl_device float3 svm_mix_overlay(float t, float3 col1, float3 col2) +{ + float tm = 1.0f - t; + + float3 outcol = col1; + + if(outcol.x < 0.5f) + outcol.x *= tm + 2.0f*t*col2.x; + else + outcol.x = 1.0f - (tm + 2.0f*t*(1.0f - col2.x))*(1.0f - outcol.x); + + if(outcol.y < 0.5f) + outcol.y *= tm + 2.0f*t*col2.y; + else + outcol.y = 1.0f - (tm + 2.0f*t*(1.0f - col2.y))*(1.0f - outcol.y); + + if(outcol.z < 0.5f) + outcol.z *= tm + 2.0f*t*col2.z; + else + outcol.z = 1.0f - (tm + 2.0f*t*(1.0f - col2.z))*(1.0f - outcol.z); + + return outcol; +} + +ccl_device float3 svm_mix_sub(float t, float3 col1, float3 col2) +{ + return interp(col1, col1 - col2, t); +} + +ccl_device float3 svm_mix_div(float t, float3 col1, float3 col2) +{ + float tm = 1.0f - t; + + float3 outcol = col1; + + if(col2.x != 0.0f) outcol.x = tm*outcol.x + t*outcol.x/col2.x; + if(col2.y != 0.0f) outcol.y = tm*outcol.y + t*outcol.y/col2.y; + if(col2.z != 0.0f) outcol.z = tm*outcol.z + t*outcol.z/col2.z; + + return outcol; +} + +ccl_device float3 svm_mix_diff(float t, float3 col1, float3 col2) +{ + return interp(col1, fabs(col1 - col2), t); +} + +ccl_device float3 svm_mix_dark(float t, float3 col1, float3 col2) +{ + return min(col1, col2)*t + col1*(1.0f - t); +} + +ccl_device float3 svm_mix_light(float t, float3 col1, float3 col2) +{ + return max(col1, col2*t); +} + +ccl_device float3 svm_mix_dodge(float t, float3 col1, float3 col2) +{ + float3 outcol = col1; + + if(outcol.x != 0.0f) { + float tmp = 1.0f - t*col2.x; + if(tmp <= 0.0f) + outcol.x = 1.0f; + else if((tmp = outcol.x/tmp) > 1.0f) + outcol.x = 1.0f; + else + outcol.x = tmp; + } + if(outcol.y != 0.0f) { + float tmp = 1.0f - t*col2.y; + if(tmp <= 0.0f) + outcol.y = 1.0f; + else if((tmp = outcol.y/tmp) > 1.0f) + outcol.y = 1.0f; + else + outcol.y = tmp; + } + if(outcol.z != 0.0f) { + float tmp = 1.0f - t*col2.z; + if(tmp <= 0.0f) + outcol.z = 1.0f; + else if((tmp = outcol.z/tmp) > 1.0f) + outcol.z = 1.0f; + else + outcol.z = tmp; + } + + return outcol; +} + +ccl_device float3 svm_mix_burn(float t, float3 col1, float3 col2) +{ + float tmp, tm = 1.0f - t; + + float3 outcol = col1; + + tmp = tm + t*col2.x; + if(tmp <= 0.0f) + outcol.x = 0.0f; + else if((tmp = (1.0f - (1.0f - outcol.x)/tmp)) < 0.0f) + outcol.x = 0.0f; + else if(tmp > 1.0f) + outcol.x = 1.0f; + else + outcol.x = tmp; + + tmp = tm + t*col2.y; + if(tmp <= 0.0f) + outcol.y = 0.0f; + else if((tmp = (1.0f - (1.0f - outcol.y)/tmp)) < 0.0f) + outcol.y = 0.0f; + else if(tmp > 1.0f) + outcol.y = 1.0f; + else + outcol.y = tmp; + + tmp = tm + t*col2.z; + if(tmp <= 0.0f) + outcol.z = 0.0f; + else if((tmp = (1.0f - (1.0f - outcol.z)/tmp)) < 0.0f) + outcol.z = 0.0f; + else if(tmp > 1.0f) + outcol.z = 1.0f; + else + outcol.z = tmp; + + return outcol; +} + +ccl_device float3 svm_mix_hue(float t, float3 col1, float3 col2) +{ + float3 outcol = col1; + + float3 hsv2 = rgb_to_hsv(col2); + + if(hsv2.y != 0.0f) { + float3 hsv = rgb_to_hsv(outcol); + hsv.x = hsv2.x; + float3 tmp = hsv_to_rgb(hsv); + + outcol = interp(outcol, tmp, t); + } + + return outcol; +} + +ccl_device float3 svm_mix_sat(float t, float3 col1, float3 col2) +{ + float tm = 1.0f - t; + + float3 outcol = col1; + + float3 hsv = rgb_to_hsv(outcol); + + if(hsv.y != 0.0f) { + float3 hsv2 = rgb_to_hsv(col2); + + hsv.y = tm*hsv.y + t*hsv2.y; + outcol = hsv_to_rgb(hsv); + } + + return outcol; +} + +ccl_device float3 svm_mix_val(float t, float3 col1, float3 col2) +{ + float tm = 1.0f - t; + + float3 hsv = rgb_to_hsv(col1); + float3 hsv2 = rgb_to_hsv(col2); + + hsv.z = tm*hsv.z + t*hsv2.z; + + return hsv_to_rgb(hsv); +} + +ccl_device float3 svm_mix_color(float t, float3 col1, float3 col2) +{ + float3 outcol = col1; + float3 hsv2 = rgb_to_hsv(col2); + + if(hsv2.y != 0.0f) { + float3 hsv = rgb_to_hsv(outcol); + hsv.x = hsv2.x; + hsv.y = hsv2.y; + float3 tmp = hsv_to_rgb(hsv); + + outcol = interp(outcol, tmp, t); + } + + return outcol; +} + +ccl_device float3 svm_mix_soft(float t, float3 col1, float3 col2) +{ + float tm = 1.0f - t; + + float3 one = make_float3(1.0f, 1.0f, 1.0f); + float3 scr = one - (one - col2)*(one - col1); + + return tm*col1 + t*((one - col1)*col2*col1 + col1*scr); +} + +ccl_device float3 svm_mix_linear(float t, float3 col1, float3 col2) +{ + return col1 + t*(2.0f*col2 + make_float3(-1.0f, -1.0f, -1.0f)); +} + +ccl_device float3 svm_mix_clamp(float3 col) +{ + float3 outcol = col; + + outcol.x = saturate(col.x); + outcol.y = saturate(col.y); + outcol.z = saturate(col.z); + + return outcol; +} + +ccl_device_noinline float3 svm_mix(NodeMix type, float fac, float3 c1, float3 c2) +{ + float t = saturate(fac); + + switch(type) { + case NODE_MIX_BLEND: return svm_mix_blend(t, c1, c2); + case NODE_MIX_ADD: return svm_mix_add(t, c1, c2); + case NODE_MIX_MUL: return svm_mix_mul(t, c1, c2); + case NODE_MIX_SCREEN: return svm_mix_screen(t, c1, c2); + case NODE_MIX_OVERLAY: return svm_mix_overlay(t, c1, c2); + case NODE_MIX_SUB: return svm_mix_sub(t, c1, c2); + case NODE_MIX_DIV: return svm_mix_div(t, c1, c2); + case NODE_MIX_DIFF: return svm_mix_diff(t, c1, c2); + case NODE_MIX_DARK: return svm_mix_dark(t, c1, c2); + case NODE_MIX_LIGHT: return svm_mix_light(t, c1, c2); + case NODE_MIX_DODGE: return svm_mix_dodge(t, c1, c2); + case NODE_MIX_BURN: return svm_mix_burn(t, c1, c2); + case NODE_MIX_HUE: return svm_mix_hue(t, c1, c2); + case NODE_MIX_SAT: return svm_mix_sat(t, c1, c2); + case NODE_MIX_VAL: return svm_mix_val (t, c1, c2); + case NODE_MIX_COLOR: return svm_mix_color(t, c1, c2); + case NODE_MIX_SOFT: return svm_mix_soft(t, c1, c2); + case NODE_MIX_LINEAR: return svm_mix_linear(t, c1, c2); + case NODE_MIX_CLAMP: return svm_mix_clamp(c1); + } + + return make_float3(0.0f, 0.0f, 0.0f); +} + +ccl_device_inline float3 svm_brightness_contrast(float3 color, float brightness, float contrast) +{ + float a = 1.0f + contrast; + float b = brightness - contrast*0.5f; + + color.x = max(a*color.x + b, 0.0f); + color.y = max(a*color.y + b, 0.0f); + color.z = max(a*color.z + b, 0.0f); + + return color; +} + +CCL_NAMESPACE_END + diff --git a/intern/cycles/kernel/svm/svm_image.h b/intern/cycles/kernel/svm/svm_image.h index 3d9ab405849..6a2248865d7 100644 --- a/intern/cycles/kernel/svm/svm_image.h +++ b/intern/cycles/kernel/svm/svm_image.h @@ -72,8 +72,16 @@ ccl_device float4 svm_image_texture(KernelGlobals *kg, int id, float x, float y, uint width = info.x; uint height = info.y; uint offset = info.z; - uint periodic = (info.w & 0x1); - uint interpolation = info.w >> 1; + + /* Image Options */ + uint interpolation = (info.w & (1 << 0)) ? INTERPOLATION_CLOSEST : INTERPOLATION_LINEAR; + uint extension; + if(info.w & (1 << 1)) + extension = EXTENSION_REPEAT; + else if(info.w & (1 << 2)) + extension = EXTENSION_EXTEND; + else + extension = EXTENSION_CLIP; float4 r; int ix, iy, nix, niy; @@ -81,29 +89,37 @@ ccl_device float4 svm_image_texture(KernelGlobals *kg, int id, float x, float y, svm_image_texture_frac(x*width, &ix); svm_image_texture_frac(y*height, &iy); - if(periodic) { + if(extension == EXTENSION_REPEAT) { ix = svm_image_texture_wrap_periodic(ix, width); iy = svm_image_texture_wrap_periodic(iy, height); } - else { + else if(extension == EXTENSION_CLIP) { + if(x < 0.0f || y < 0.0f || x > 1.0f || y > 1.0f) + return make_float4(0.0f, 0.0f, 0.0f, 0.0f); + } + else { /* EXTENSION_EXTEND */ ix = svm_image_texture_wrap_clamp(ix, width); iy = svm_image_texture_wrap_clamp(iy, height); - } + r = svm_image_texture_read(kg, id, offset + ix + iy*width); } - else { /* We default to linear interpolation if it is not closest */ - float tx = svm_image_texture_frac(x*width, &ix); - float ty = svm_image_texture_frac(y*height, &iy); + else { /* INTERPOLATION_LINEAR */ + float tx = svm_image_texture_frac(x*width - 0.5f, &ix); + float ty = svm_image_texture_frac(y*height - 0.5f, &iy); - if(periodic) { + if(extension == EXTENSION_REPEAT) { ix = svm_image_texture_wrap_periodic(ix, width); iy = svm_image_texture_wrap_periodic(iy, height); nix = svm_image_texture_wrap_periodic(ix+1, width); niy = svm_image_texture_wrap_periodic(iy+1, height); } - else { + else if(extension == EXTENSION_CLIP) { + if(x < 0.0f || y < 0.0f || x > 1.0f || y > 1.0f) + return make_float4(0.0f, 0.0f, 0.0f, 0.0f); + } + else { /* EXTENSION_EXTEND */ ix = svm_image_texture_wrap_clamp(ix, width); iy = svm_image_texture_wrap_clamp(iy, height); @@ -111,7 +127,6 @@ ccl_device float4 svm_image_texture(KernelGlobals *kg, int id, float x, float y, niy = svm_image_texture_wrap_clamp(iy+1, height); } - r = (1.0f - ty)*(1.0f - tx)*svm_image_texture_read(kg, id, offset + ix + iy*width); r += (1.0f - ty)*tx*svm_image_texture_read(kg, id, offset + nix + iy*width); r += ty*(1.0f - tx)*svm_image_texture_read(kg, id, offset + ix + niy*width); diff --git a/intern/cycles/kernel/svm/svm_mix.h b/intern/cycles/kernel/svm/svm_mix.h index 7cbda111d81..022a68d1928 100644 --- a/intern/cycles/kernel/svm/svm_mix.h +++ b/intern/cycles/kernel/svm/svm_mix.h @@ -16,280 +16,6 @@ CCL_NAMESPACE_BEGIN -ccl_device float3 svm_mix_blend(float t, float3 col1, float3 col2) -{ - return interp(col1, col2, t); -} - -ccl_device float3 svm_mix_add(float t, float3 col1, float3 col2) -{ - return interp(col1, col1 + col2, t); -} - -ccl_device float3 svm_mix_mul(float t, float3 col1, float3 col2) -{ - return interp(col1, col1 * col2, t); -} - -ccl_device float3 svm_mix_screen(float t, float3 col1, float3 col2) -{ - float tm = 1.0f - t; - float3 one = make_float3(1.0f, 1.0f, 1.0f); - float3 tm3 = make_float3(tm, tm, tm); - - return one - (tm3 + t*(one - col2))*(one - col1); -} - -ccl_device float3 svm_mix_overlay(float t, float3 col1, float3 col2) -{ - float tm = 1.0f - t; - - float3 outcol = col1; - - if(outcol.x < 0.5f) - outcol.x *= tm + 2.0f*t*col2.x; - else - outcol.x = 1.0f - (tm + 2.0f*t*(1.0f - col2.x))*(1.0f - outcol.x); - - if(outcol.y < 0.5f) - outcol.y *= tm + 2.0f*t*col2.y; - else - outcol.y = 1.0f - (tm + 2.0f*t*(1.0f - col2.y))*(1.0f - outcol.y); - - if(outcol.z < 0.5f) - outcol.z *= tm + 2.0f*t*col2.z; - else - outcol.z = 1.0f - (tm + 2.0f*t*(1.0f - col2.z))*(1.0f - outcol.z); - - return outcol; -} - -ccl_device float3 svm_mix_sub(float t, float3 col1, float3 col2) -{ - return interp(col1, col1 - col2, t); -} - -ccl_device float3 svm_mix_div(float t, float3 col1, float3 col2) -{ - float tm = 1.0f - t; - - float3 outcol = col1; - - if(col2.x != 0.0f) outcol.x = tm*outcol.x + t*outcol.x/col2.x; - if(col2.y != 0.0f) outcol.y = tm*outcol.y + t*outcol.y/col2.y; - if(col2.z != 0.0f) outcol.z = tm*outcol.z + t*outcol.z/col2.z; - - return outcol; -} - -ccl_device float3 svm_mix_diff(float t, float3 col1, float3 col2) -{ - return interp(col1, fabs(col1 - col2), t); -} - -ccl_device float3 svm_mix_dark(float t, float3 col1, float3 col2) -{ - return min(col1, col2)*t + col1*(1.0f - t); -} - -ccl_device float3 svm_mix_light(float t, float3 col1, float3 col2) -{ - return max(col1, col2*t); -} - -ccl_device float3 svm_mix_dodge(float t, float3 col1, float3 col2) -{ - float3 outcol = col1; - - if(outcol.x != 0.0f) { - float tmp = 1.0f - t*col2.x; - if(tmp <= 0.0f) - outcol.x = 1.0f; - else if((tmp = outcol.x/tmp) > 1.0f) - outcol.x = 1.0f; - else - outcol.x = tmp; - } - if(outcol.y != 0.0f) { - float tmp = 1.0f - t*col2.y; - if(tmp <= 0.0f) - outcol.y = 1.0f; - else if((tmp = outcol.y/tmp) > 1.0f) - outcol.y = 1.0f; - else - outcol.y = tmp; - } - if(outcol.z != 0.0f) { - float tmp = 1.0f - t*col2.z; - if(tmp <= 0.0f) - outcol.z = 1.0f; - else if((tmp = outcol.z/tmp) > 1.0f) - outcol.z = 1.0f; - else - outcol.z = tmp; - } - - return outcol; -} - -ccl_device float3 svm_mix_burn(float t, float3 col1, float3 col2) -{ - float tmp, tm = 1.0f - t; - - float3 outcol = col1; - - tmp = tm + t*col2.x; - if(tmp <= 0.0f) - outcol.x = 0.0f; - else if((tmp = (1.0f - (1.0f - outcol.x)/tmp)) < 0.0f) - outcol.x = 0.0f; - else if(tmp > 1.0f) - outcol.x = 1.0f; - else - outcol.x = tmp; - - tmp = tm + t*col2.y; - if(tmp <= 0.0f) - outcol.y = 0.0f; - else if((tmp = (1.0f - (1.0f - outcol.y)/tmp)) < 0.0f) - outcol.y = 0.0f; - else if(tmp > 1.0f) - outcol.y = 1.0f; - else - outcol.y = tmp; - - tmp = tm + t*col2.z; - if(tmp <= 0.0f) - outcol.z = 0.0f; - else if((tmp = (1.0f - (1.0f - outcol.z)/tmp)) < 0.0f) - outcol.z = 0.0f; - else if(tmp > 1.0f) - outcol.z = 1.0f; - else - outcol.z = tmp; - - return outcol; -} - -ccl_device float3 svm_mix_hue(float t, float3 col1, float3 col2) -{ - float3 outcol = col1; - - float3 hsv2 = rgb_to_hsv(col2); - - if(hsv2.y != 0.0f) { - float3 hsv = rgb_to_hsv(outcol); - hsv.x = hsv2.x; - float3 tmp = hsv_to_rgb(hsv); - - outcol = interp(outcol, tmp, t); - } - - return outcol; -} - -ccl_device float3 svm_mix_sat(float t, float3 col1, float3 col2) -{ - float tm = 1.0f - t; - - float3 outcol = col1; - - float3 hsv = rgb_to_hsv(outcol); - - if(hsv.y != 0.0f) { - float3 hsv2 = rgb_to_hsv(col2); - - hsv.y = tm*hsv.y + t*hsv2.y; - outcol = hsv_to_rgb(hsv); - } - - return outcol; -} - -ccl_device float3 svm_mix_val(float t, float3 col1, float3 col2) -{ - float tm = 1.0f - t; - - float3 hsv = rgb_to_hsv(col1); - float3 hsv2 = rgb_to_hsv(col2); - - hsv.z = tm*hsv.z + t*hsv2.z; - - return hsv_to_rgb(hsv); -} - -ccl_device float3 svm_mix_color(float t, float3 col1, float3 col2) -{ - float3 outcol = col1; - float3 hsv2 = rgb_to_hsv(col2); - - if(hsv2.y != 0.0f) { - float3 hsv = rgb_to_hsv(outcol); - hsv.x = hsv2.x; - hsv.y = hsv2.y; - float3 tmp = hsv_to_rgb(hsv); - - outcol = interp(outcol, tmp, t); - } - - return outcol; -} - -ccl_device float3 svm_mix_soft(float t, float3 col1, float3 col2) -{ - float tm = 1.0f - t; - - float3 one = make_float3(1.0f, 1.0f, 1.0f); - float3 scr = one - (one - col2)*(one - col1); - - return tm*col1 + t*((one - col1)*col2*col1 + col1*scr); -} - -ccl_device float3 svm_mix_linear(float t, float3 col1, float3 col2) -{ - return col1 + t*(2.0f*col2 + make_float3(-1.0f, -1.0f, -1.0f)); -} - -ccl_device float3 svm_mix_clamp(float3 col) -{ - float3 outcol = col; - - outcol.x = saturate(col.x); - outcol.y = saturate(col.y); - outcol.z = saturate(col.z); - - return outcol; -} - -ccl_device_noinline float3 svm_mix(NodeMix type, float fac, float3 c1, float3 c2) -{ - float t = saturate(fac); - - switch(type) { - case NODE_MIX_BLEND: return svm_mix_blend(t, c1, c2); - case NODE_MIX_ADD: return svm_mix_add(t, c1, c2); - case NODE_MIX_MUL: return svm_mix_mul(t, c1, c2); - case NODE_MIX_SCREEN: return svm_mix_screen(t, c1, c2); - case NODE_MIX_OVERLAY: return svm_mix_overlay(t, c1, c2); - case NODE_MIX_SUB: return svm_mix_sub(t, c1, c2); - case NODE_MIX_DIV: return svm_mix_div(t, c1, c2); - case NODE_MIX_DIFF: return svm_mix_diff(t, c1, c2); - case NODE_MIX_DARK: return svm_mix_dark(t, c1, c2); - case NODE_MIX_LIGHT: return svm_mix_light(t, c1, c2); - case NODE_MIX_DODGE: return svm_mix_dodge(t, c1, c2); - case NODE_MIX_BURN: return svm_mix_burn(t, c1, c2); - case NODE_MIX_HUE: return svm_mix_hue(t, c1, c2); - case NODE_MIX_SAT: return svm_mix_sat(t, c1, c2); - case NODE_MIX_VAL: return svm_mix_val (t, c1, c2); - case NODE_MIX_COLOR: return svm_mix_color(t, c1, c2); - case NODE_MIX_SOFT: return svm_mix_soft(t, c1, c2); - case NODE_MIX_LINEAR: return svm_mix_linear(t, c1, c2); - case NODE_MIX_CLAMP: return svm_mix_clamp(c1); - } - - return make_float3(0.0f, 0.0f, 0.0f); -} - /* Node */ ccl_device void svm_node_mix(KernelGlobals *kg, ShaderData *sd, float *stack, uint fac_offset, uint c1_offset, uint c2_offset, int *offset) diff --git a/intern/cycles/kernel/svm/svm_ramp.h b/intern/cycles/kernel/svm/svm_ramp.h index 59dec409a70..24275d05c4a 100644 --- a/intern/cycles/kernel/svm/svm_ramp.h +++ b/intern/cycles/kernel/svm/svm_ramp.h @@ -92,11 +92,11 @@ ccl_device void svm_node_rgb_curves(KernelGlobals *kg, ShaderData *sd, float *st const float min_x = __int_as_float(node.z), max_x = __int_as_float(node.w); const float range_x = max_x - min_x; - color = (color - make_float3(min_x, min_x, min_x)) / range_x; + const float3 relpos = (color - make_float3(min_x, min_x, min_x)) / range_x; - float r = rgb_ramp_lookup(kg, *offset, color.x, true, true, table_size).x; - float g = rgb_ramp_lookup(kg, *offset, color.y, true, true, table_size).y; - float b = rgb_ramp_lookup(kg, *offset, color.z, true, true, table_size).z; + float r = rgb_ramp_lookup(kg, *offset, relpos.x, true, true, table_size).x; + float g = rgb_ramp_lookup(kg, *offset, relpos.y, true, true, table_size).y; + float b = rgb_ramp_lookup(kg, *offset, relpos.z, true, true, table_size).z; color = (1.0f - fac)*color + fac*make_float3(r, g, b); stack_store_float3(stack, out_offset, color); @@ -121,11 +121,11 @@ ccl_device void svm_node_vector_curves(KernelGlobals *kg, ShaderData *sd, float const float min_x = __int_as_float(node.z), max_x = __int_as_float(node.w); const float range_x = max_x - min_x; - color = (color - make_float3(min_x, min_x, min_x)) / range_x; + const float3 relpos = (color - make_float3(min_x, min_x, min_x)) / range_x; - float r = rgb_ramp_lookup(kg, *offset, color.x, true, true, table_size).x; - float g = rgb_ramp_lookup(kg, *offset, color.y, true, true, table_size).y; - float b = rgb_ramp_lookup(kg, *offset, color.z, true, true, table_size).z; + float r = rgb_ramp_lookup(kg, *offset, relpos.x, true, true, table_size).x; + float g = rgb_ramp_lookup(kg, *offset, relpos.y, true, true, table_size).y; + float b = rgb_ramp_lookup(kg, *offset, relpos.z, true, true, table_size).z; color = (1.0f - fac)*color + fac*make_float3(r, g, b); stack_store_float3(stack, out_offset, color); diff --git a/intern/cycles/kernel/svm/svm_types.h b/intern/cycles/kernel/svm/svm_types.h index e57d22b1b13..e1a8ced6a34 100644 --- a/intern/cycles/kernel/svm/svm_types.h +++ b/intern/cycles/kernel/svm/svm_types.h @@ -396,8 +396,10 @@ typedef enum ClosureType { CLOSURE_BSDF_REFLECTION_ID, CLOSURE_BSDF_MICROFACET_GGX_ID, CLOSURE_BSDF_MICROFACET_BECKMANN_ID, + CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID, CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID, CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID, + CLOSURE_BSDF_MICROFACET_MULTI_GGX_ANISO_ID, CLOSURE_BSDF_MICROFACET_BECKMANN_ANISO_ID, CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ANISO_ID, CLOSURE_BSDF_ASHIKHMIN_VELVET_ID, @@ -413,6 +415,7 @@ typedef enum ClosureType { CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID, CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID, CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID, + CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID, CLOSURE_BSDF_SHARP_GLASS_ID, CLOSURE_BSDF_HAIR_TRANSMISSION_ID, diff --git a/intern/cycles/render/background.cpp b/intern/cycles/render/background.cpp index 20536b74e87..8d7d7b847fd 100644 --- a/intern/cycles/render/background.cpp +++ b/intern/cycles/render/background.cpp @@ -32,12 +32,12 @@ NODE_DEFINE(Background) { NodeType* type = NodeType::add("background", create); - SOCKET_INT(ao_factor, "AO Factor", 0.0f); + SOCKET_FLOAT(ao_factor, "AO Factor", 0.0f); SOCKET_FLOAT(ao_distance, "AO Distance", FLT_MAX); SOCKET_BOOLEAN(use_shader, "Use Shader", true); SOCKET_BOOLEAN(use_ao, "Use AO", false); - SOCKET_INT(visibility, "Visibility", PATH_RAY_ALL_VISIBILITY); + SOCKET_UINT(visibility, "Visibility", PATH_RAY_ALL_VISIBILITY); SOCKET_BOOLEAN(transparent, "Transparent", false); SOCKET_NODE(shader, "Shader", &Shader::node_type); diff --git a/intern/cycles/render/camera.cpp b/intern/cycles/render/camera.cpp index 2310798be2e..a6df656d220 100644 --- a/intern/cycles/render/camera.cpp +++ b/intern/cycles/render/camera.cpp @@ -68,7 +68,7 @@ NODE_DEFINE(Camera) SOCKET_FLOAT(aperturesize, "Aperture Size", 0.0f); SOCKET_FLOAT(focaldistance, "Focal Distance", 10.0f); - SOCKET_INT(blades, "Blades", 0); + SOCKET_UINT(blades, "Blades", 0); SOCKET_FLOAT(bladesrotation, "Blades Rotation", 0.0f); SOCKET_TRANSFORM(matrix, "Matrix", transform_identity()); diff --git a/intern/cycles/render/graph.cpp b/intern/cycles/render/graph.cpp index 29c0eec9b97..fd48bf2631e 100644 --- a/intern/cycles/render/graph.cpp +++ b/intern/cycles/render/graph.cpp @@ -51,72 +51,19 @@ bool check_node_inputs_traversed(const ShaderNode *node, return true; } -bool check_node_inputs_equals(const ShaderNode *node_a, - const ShaderNode *node_b) -{ - if(node_a->inputs.size() != node_b->inputs.size()) { - /* Happens with BSDF closure nodes which are currently sharing the same - * name for all the BSDF types, making it impossible to filter out - * incompatible nodes. - */ - return false; - } - for(int i = 0; i < node_a->inputs.size(); ++i) { - ShaderInput *input_a = node_a->inputs[i], - *input_b = node_b->inputs[i]; - if(input_a->link == NULL && input_b->link == NULL) { - /* Unconnected inputs are expected to have the same value. */ - if(input_a->value() != input_b->value()) { - return false; - } - } - else if(input_a->link != NULL && input_b->link != NULL) { - /* Expect links are to come from the same exact socket. */ - if(input_a->link != input_b->link) { - return false; - } - } - else { - /* One socket has a link and another has not, inputs can't be - * considered equal. - */ - return false; - } - } - return true; -} - } /* namespace */ -/* Input and Output */ - -ShaderInput::ShaderInput(ShaderNode *parent_, const char *name, SocketType::Type type) -{ - parent = parent_; - name_ = name; - type_ = type; - link = NULL; - value_ = make_float3(0.0f, 0.0f, 0.0f); - stack_offset = SVM_STACK_INVALID; - flags_ = 0; -} - -ShaderOutput::ShaderOutput(ShaderNode *parent_, const char *name, SocketType::Type type) -{ - parent = parent_; - name_ = name; - type_ = type; - stack_offset = SVM_STACK_INVALID; -} - /* Node */ -ShaderNode::ShaderNode(const char *name_) +ShaderNode::ShaderNode(const NodeType *type) +: Node(type) { - name = name_; + name = type->name; id = -1; bump = SHADER_BUMP_NONE; special_type = SHADER_SPECIAL_TYPE_NONE; + + create_inputs_outputs(type); } ShaderNode::~ShaderNode() @@ -128,6 +75,19 @@ ShaderNode::~ShaderNode() delete socket; } +void ShaderNode::create_inputs_outputs(const NodeType *type) +{ + foreach(const SocketType& socket, type->inputs) { + if(socket.flags & SocketType::LINKABLE) { + inputs.push_back(new ShaderInput(socket, this)); + } + } + + foreach(const SocketType& socket, type->outputs) { + outputs.push_back(new ShaderOutput(socket, this)); + } +} + ShaderInput *ShaderNode::input(const char *name) { foreach(ShaderInput *socket, inputs) { @@ -166,29 +126,15 @@ ShaderOutput *ShaderNode::output(ustring name) return NULL; } -ShaderInput *ShaderNode::add_input(const char *name, SocketType::Type type, float value, int flags) +bool ShaderNode::all_inputs_constant() const { - ShaderInput *input = new ShaderInput(this, name, type); - input->value_.x = value; - input->flags_ = flags; - inputs.push_back(input); - return input; -} - -ShaderInput *ShaderNode::add_input(const char *name, SocketType::Type type, float3 value, int flags) -{ - ShaderInput *input = new ShaderInput(this, name, type); - input->value_ = value; - input->flags_ = flags; - inputs.push_back(input); - return input; -} + foreach(ShaderInput *input, inputs) { + if(input->link) { + return false; + } + } -ShaderOutput *ShaderNode::add_output(const char *name, SocketType::Type type) -{ - ShaderOutput *output = new ShaderOutput(this, name, type); - outputs.push_back(output); - return output; + return true; } void ShaderNode::attributes(Shader *shader, AttributeRequestSet *attributes) @@ -209,6 +155,49 @@ void ShaderNode::attributes(Shader *shader, AttributeRequestSet *attributes) } } +bool ShaderNode::equals(const ShaderNode& other) +{ + if (type != other.type || bump != other.bump) + return false; + + assert(inputs.size() == other.inputs.size()); + + /* Compare unlinkable sockets */ + foreach(const SocketType& socket, type->inputs) { + if(!(socket.flags & SocketType::LINKABLE)) { + if(!Node::equals_value(other, socket)) { + return false; + } + } + } + + /* Compare linkable input sockets */ + for(int i = 0; i < inputs.size(); ++i) { + ShaderInput *input_a = inputs[i], + *input_b = other.inputs[i]; + if(input_a->link == NULL && input_b->link == NULL) { + /* Unconnected inputs are expected to have the same value. */ + if(!Node::equals_value(other, input_a->socket_type)) { + return false; + } + } + else if(input_a->link != NULL && input_b->link != NULL) { + /* Expect links are to come from the same exact socket. */ + if(input_a->link != input_b->link) { + return false; + } + } + else { + /* One socket has a link and another has not, inputs can't be + * considered equal. + */ + return false; + } + } + + return true; +} + /* Graph */ ShaderGraph::ShaderGraph() @@ -470,8 +459,7 @@ void ShaderGraph::remove_proxy_nodes() disconnect(to); /* transfer the default input value to the target socket */ - to->set(input->value()); - to->set(input->value_string()); + tonode->copy_value(to->socket_type, *proxy, input->socket_type); } } @@ -542,7 +530,7 @@ void ShaderGraph::constant_fold() vector<ShaderInput*> links(output->links); for(size_t i = 0; i < links.size(); i++) { if(i > 0) - links[i]->set(links[0]->value()); + links[i]->parent->copy_value(links[i]->socket_type, *links[0]->parent, links[0]->socket_type); disconnect(links[i]); } } @@ -570,8 +558,8 @@ void ShaderGraph::deduplicate_nodes() * already deduplicated. */ - ShaderNodeSet scheduled; - map<ustring, ShaderNodeSet> done; + ShaderNodeSet scheduled, done; + map<ustring, ShaderNodeSet> candidates; queue<ShaderNode*> traverse_queue; /* Schedule nodes which doesn't have any dependencies. */ @@ -585,7 +573,7 @@ void ShaderGraph::deduplicate_nodes() while(!traverse_queue.empty()) { ShaderNode *node = traverse_queue.front(); traverse_queue.pop(); - done[node->name].insert(node); + done.insert(node); /* Schedule the nodes which were depending on the current node. */ foreach(ShaderOutput *output, node->outputs) { foreach(ShaderInput *input, output->links) { @@ -596,35 +584,28 @@ void ShaderGraph::deduplicate_nodes() continue; } /* Schedule node if its inputs are fully done. */ - if(check_node_inputs_traversed(input->parent, done[input->parent->name])) { + if(check_node_inputs_traversed(input->parent, done)) { traverse_queue.push(input->parent); scheduled.insert(input->parent); } } } /* Try to merge this node with another one. */ - foreach(ShaderNode *other_node, done[node->name]) { - if(node == other_node) { - /* Don't merge with self. */ - continue; - } - if(node->name != other_node->name) { - /* Can only de-duplicate nodes of the same type. */ - continue; - } - if(!check_node_inputs_equals(node, other_node)) { - /* Node inputs are different, can't merge them, */ - continue; + ShaderNode *merge_with = NULL; + foreach(ShaderNode *other_node, candidates[node->type->name]) { + if (node != other_node && node->equals(*other_node)) { + merge_with = other_node; + break; } - if(!node->equals(other_node)) { - /* Node settings are different. */ - continue; - } - /* TODO(sergey): Consider making it an utility function. */ + } + /* If found an equivalent, merge; otherwise keep node for later merges */ + if (merge_with != NULL) { for(int i = 0; i < node->outputs.size(); ++i) { - relink(node, node->outputs[i], other_node->outputs[i]); + relink(node, node->outputs[i], merge_with->outputs[i]); } - break; + } + else { + candidates[node->type->name].insert(node); } } } @@ -927,14 +908,15 @@ void ShaderGraph::transform_multi_closure(ShaderNode *node, ShaderOutput *weight if(fin) { /* mix closure: add node to mix closure weights */ - ShaderNode *mix_node = add(new MixClosureWeightNode()); + MixClosureWeightNode *mix_node = new MixClosureWeightNode(); + add(mix_node); ShaderInput *fac_in = mix_node->input("Fac"); ShaderInput *weight_in = mix_node->input("Weight"); if(fin->link) connect(fin->link, fac_in); else - fac_in->set(fin->value_float()); + mix_node->fac = node->get_float(fin->socket_type); if(weight_out) connect(weight_out, weight_in); @@ -961,20 +943,20 @@ void ShaderGraph::transform_multi_closure(ShaderNode *node, ShaderOutput *weight return; /* already has a weight connected to it? add weights */ - if(weight_in->link || weight_in->value_float() != 0.0f) { - ShaderNode *math_node = add(new MathNode()); - ShaderInput *value1_in = math_node->input("Value1"); - ShaderInput *value2_in = math_node->input("Value2"); + float weight_value = node->get_float(weight_in->socket_type); + if(weight_in->link || weight_value != 0.0f) { + MathNode *math_node = new MathNode(); + add(math_node); if(weight_in->link) - connect(weight_in->link, value1_in); + connect(weight_in->link, math_node->input("Value1")); else - value1_in->set(weight_in->value_float()); + math_node->value1 = weight_value; if(weight_out) - connect(weight_out, value2_in); + connect(weight_out, math_node->input("Value2")); else - value2_in->set(1.0f); + math_node->value2 = 1.0f; weight_out = math_node->output("Value"); if(weight_in->link) @@ -985,7 +967,7 @@ void ShaderGraph::transform_multi_closure(ShaderNode *node, ShaderOutput *weight if(weight_out) connect(weight_out, weight_in); else - weight_in->set(weight_in->value_float() + 1.0f); + node->set(weight_in->socket_type, weight_value + 1.0f); } } diff --git a/intern/cycles/render/graph.h b/intern/cycles/render/graph.h index 882e495df20..61100cda60b 100644 --- a/intern/cycles/render/graph.h +++ b/intern/cycles/render/graph.h @@ -18,6 +18,7 @@ #define __GRAPH_H__ #include "node.h" +#include "node_type.h" #include "kernel_types.h" @@ -79,32 +80,21 @@ enum ShaderNodeSpecialType { class ShaderInput { public: - ShaderInput(ShaderNode *parent, const char *name, SocketType::Type type); + ShaderInput(const SocketType& socket_type_, ShaderNode* parent_) + : socket_type(socket_type_), parent(parent_), link(NULL), stack_offset(SVM_STACK_INVALID) + {} - ustring name() { return name_; } - int flags() { return flags_; } - SocketType::Type type() { return type_; } + ustring name() { return socket_type.ui_name; } + int flags() { return socket_type.flags; } + SocketType::Type type() { return socket_type.type; } - void set(float f) { value_.x = f; } - void set(float3 f) { value_ = f; } - void set(int i) { value_.x = (float)i; } - void set(ustring s) { value_string_ = s; } - - float3& value() { return value_; } - float& value_float() { return value_.x; } - ustring& value_string() { return value_string_; } - - ustring name_; - SocketType::Type type_; + void set(float f) { ((Node*)parent)->set(socket_type, f); } + void set(float3 f) { ((Node*)parent)->set(socket_type, f); } + const SocketType& socket_type; ShaderNode *parent; ShaderOutput *link; - - float3 value_; - ustring value_string_; - int stack_offset; /* for SVM compiler */ - int flags_; }; /* Output @@ -113,17 +103,16 @@ public: class ShaderOutput { public: - ShaderOutput(ShaderNode *parent, const char *name, SocketType::Type type); - - ustring name() { return name_; } - SocketType::Type type() { return type_; } + ShaderOutput(const SocketType& socket_type_, ShaderNode* parent_) + : socket_type(socket_type_), parent(parent_), stack_offset(SVM_STACK_INVALID) + {} - ustring name_; - SocketType::Type type_; + ustring name() { return socket_type.ui_name; } + SocketType::Type type() { return socket_type.type; } + const SocketType& socket_type; ShaderNode *parent; vector<ShaderInput*> links; - int stack_offset; /* for SVM compiler */ }; @@ -132,20 +121,18 @@ public: * Shader node in graph, with input and output sockets. This is the virtual * base class for all node types. */ -class ShaderNode { +class ShaderNode : public Node { public: - explicit ShaderNode(const char *name); + explicit ShaderNode(const NodeType *type); virtual ~ShaderNode(); + void create_inputs_outputs(const NodeType *type); + ShaderInput *input(const char *name); ShaderOutput *output(const char *name); ShaderInput *input(ustring name); ShaderOutput *output(ustring name); - ShaderInput *add_input(const char *name, SocketType::Type type, float value=0.0f, int flags=0); - ShaderInput *add_input(const char *name, SocketType::Type type, float3 value, int flags=0); - ShaderOutput *add_output(const char *name, SocketType::Type type); - virtual ShaderNode *clone() const = 0; virtual void attributes(Shader *shader, AttributeRequestSet *attributes); virtual void compile(SVMCompiler& compiler) = 0; @@ -155,6 +142,8 @@ public: /* Check whether the node can be replaced with single constant. */ virtual bool constant_fold(ShaderGraph * /*graph*/, ShaderOutput * /*socket*/, ShaderInput * /*optimized*/) { return false; } + bool all_inputs_constant() const; + /* Simplify settings used by artists to the ones which are simpler to * evaluate in the kernel but keep the final result unchanged. */ @@ -171,7 +160,6 @@ public: vector<ShaderInput*> inputs; vector<ShaderOutput*> outputs; - ustring name; /* name, not required to be unique */ int id; /* index in graph node array */ ShaderBump bump; /* for bump mapping utility */ @@ -207,23 +195,21 @@ public: * NOTE: If some node can't be de-duplicated for whatever reason it * is to be handled in the subclass. */ - virtual bool equals(const ShaderNode *other) - { - return name == other->name && - bump == other->bump; - } + virtual bool equals(const ShaderNode& other); }; /* Node definition utility macros */ #define SHADER_NODE_CLASS(type) \ + NODE_DECLARE; \ type(); \ virtual ShaderNode *clone() const { return new type(*this); } \ virtual void compile(SVMCompiler& compiler); \ virtual void compile(OSLCompiler& compiler); \ #define SHADER_NODE_NO_CLONE_CLASS(type) \ + NODE_DECLARE; \ type(); \ virtual void compile(SVMCompiler& compiler); \ virtual void compile(OSLCompiler& compiler); \ diff --git a/intern/cycles/render/image.cpp b/intern/cycles/render/image.cpp index 71dc85f5f03..614620c14af 100644 --- a/intern/cycles/render/image.cpp +++ b/intern/cycles/render/image.cpp @@ -54,10 +54,14 @@ ImageManager::ImageManager(const DeviceInfo& info) tex_num_images[IMAGE_DATA_TYPE_BYTE4] = TEX_NUM_BYTE4_ ## ARCH; \ tex_num_images[IMAGE_DATA_TYPE_FLOAT] = TEX_NUM_FLOAT_ ## ARCH; \ tex_num_images[IMAGE_DATA_TYPE_BYTE] = TEX_NUM_BYTE_ ## ARCH; \ + tex_num_images[IMAGE_DATA_TYPE_HALF4] = TEX_NUM_HALF4_ ## ARCH; \ + tex_num_images[IMAGE_DATA_TYPE_HALF] = TEX_NUM_HALF_ ## ARCH; \ tex_start_images[IMAGE_DATA_TYPE_FLOAT4] = TEX_START_FLOAT4_ ## ARCH; \ tex_start_images[IMAGE_DATA_TYPE_BYTE4] = TEX_START_BYTE4_ ## ARCH; \ tex_start_images[IMAGE_DATA_TYPE_FLOAT] = TEX_START_FLOAT_ ## ARCH; \ tex_start_images[IMAGE_DATA_TYPE_BYTE] = TEX_START_BYTE_ ## ARCH; \ + tex_start_images[IMAGE_DATA_TYPE_HALF4] = TEX_START_HALF4_ ## ARCH; \ + tex_start_images[IMAGE_DATA_TYPE_HALF] = TEX_START_HALF_ ## ARCH; \ } if(device_type == DEVICE_CPU) { @@ -80,10 +84,14 @@ ImageManager::ImageManager(const DeviceInfo& info) tex_num_images[IMAGE_DATA_TYPE_BYTE4] = 0; tex_num_images[IMAGE_DATA_TYPE_FLOAT] = 0; tex_num_images[IMAGE_DATA_TYPE_BYTE] = 0; + tex_num_images[IMAGE_DATA_TYPE_HALF4] = 0; + tex_num_images[IMAGE_DATA_TYPE_HALF] = 0; tex_start_images[IMAGE_DATA_TYPE_FLOAT4] = 0; tex_start_images[IMAGE_DATA_TYPE_BYTE4] = 0; tex_start_images[IMAGE_DATA_TYPE_FLOAT] = 0; tex_start_images[IMAGE_DATA_TYPE_BYTE] = 0; + tex_start_images[IMAGE_DATA_TYPE_HALF4] = 0; + tex_start_images[IMAGE_DATA_TYPE_HALF] = 0; assert(0); } @@ -128,7 +136,7 @@ ImageManager::ImageDataType ImageManager::get_image_metadata(const string& filen void *builtin_data, bool& is_linear) { - bool is_float = false; + bool is_float = false, is_half = false; is_linear = false; int channels = 4; @@ -167,6 +175,10 @@ ImageManager::ImageDataType ImageManager::get_image_metadata(const string& filen } } + /* check if it's half float */ + if(spec.format == TypeDesc::HALF) + is_half = true; + channels = spec.nchannels; /* basic color space detection, not great but better than nothing @@ -192,7 +204,10 @@ ImageManager::ImageDataType ImageManager::get_image_metadata(const string& filen delete in; } - if(is_float) { + if(is_half) { + return (channels > 1) ? IMAGE_DATA_TYPE_HALF4 : IMAGE_DATA_TYPE_HALF; + } + else if(is_float) { return (channels > 1) ? IMAGE_DATA_TYPE_FLOAT4 : IMAGE_DATA_TYPE_FLOAT; } else { @@ -230,6 +245,10 @@ string ImageManager::name_from_type(int type) return "float"; else if(type == IMAGE_DATA_TYPE_BYTE) return "byte"; + else if(type == IMAGE_DATA_TYPE_HALF4) + return "half4"; + else if(type == IMAGE_DATA_TYPE_HALF) + return "half"; else return "byte4"; } @@ -265,11 +284,16 @@ int ImageManager::add_image(const string& filename, if(type == IMAGE_DATA_TYPE_FLOAT || type == IMAGE_DATA_TYPE_FLOAT4) is_float = true; - /* No single channel textures on CUDA (Fermi) and OpenCL, use available slots */ - if(type == IMAGE_DATA_TYPE_FLOAT && tex_num_images[type] == 0) + /* No single channel and half textures on CUDA (Fermi) and OpenCL, use available slots */ + if((type == IMAGE_DATA_TYPE_FLOAT || + type == IMAGE_DATA_TYPE_HALF4 || + type == IMAGE_DATA_TYPE_HALF) && + tex_num_images[type] == 0) { type = IMAGE_DATA_TYPE_FLOAT4; - if(type == IMAGE_DATA_TYPE_BYTE && tex_num_images[type] == 0) + } + if(type == IMAGE_DATA_TYPE_BYTE && tex_num_images[type] == 0) { type = IMAGE_DATA_TYPE_BYTE4; + } /* Fnd existing image. */ for(slot = 0; slot < images[type].size(); slot++) { @@ -645,6 +669,107 @@ bool ImageManager::file_load_float_image(Image *img, ImageDataType type, device_ return true; } +template<typename T> +bool ImageManager::file_load_half_image(Image *img, ImageDataType type, device_vector<T>& tex_img) +{ + ImageInput *in = NULL; + int width, height, depth, components; + + if(!file_load_image_generic(img, &in, width, height, depth, components)) + return false; + + /* read RGBA pixels */ + half *pixels = (half*)tex_img.resize(width, height, depth); + if(pixels == NULL) { + return false; + } + + if(in) { + half *readpixels = pixels; + vector<half> tmppixels; + + if(components > 4) { + tmppixels.resize(((size_t)width)*height*components); + readpixels = &tmppixels[0]; + } + + if(depth <= 1) { + int scanlinesize = width*components*sizeof(half); + + in->read_image(TypeDesc::HALF, + (uchar*)readpixels + (height-1)*scanlinesize, + AutoStride, + -scanlinesize, + AutoStride); + } + else { + in->read_image(TypeDesc::HALF, (uchar*)readpixels); + } + + if(components > 4) { + size_t dimensions = ((size_t)width)*height; + for(size_t i = dimensions-1, pixel = 0; pixel < dimensions; pixel++, i--) { + pixels[i*4+3] = tmppixels[i*components+3]; + pixels[i*4+2] = tmppixels[i*components+2]; + pixels[i*4+1] = tmppixels[i*components+1]; + pixels[i*4+0] = tmppixels[i*components+0]; + } + + tmppixels.clear(); + } + + in->close(); + delete in; + } +#if 0 + /* TODO(dingto): Support half for ImBuf. */ + else { + builtin_image_float_pixels_cb(img->filename, img->builtin_data, pixels); + } +#endif + + /* Check if we actually have a half4 slot, in case components == 1, but device + * doesn't support single channel textures. */ + if(type == IMAGE_DATA_TYPE_HALF4) { + size_t num_pixels = ((size_t)width) * height * depth; + if(components == 2) { + /* grayscale + alpha */ + for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) { + pixels[i*4+3] = pixels[i*2+1]; + pixels[i*4+2] = pixels[i*2+0]; + pixels[i*4+1] = pixels[i*2+0]; + pixels[i*4+0] = pixels[i*2+0]; + } + } + else if(components == 3) { + /* RGB */ + for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) { + pixels[i*4+3] = 1.0f; + pixels[i*4+2] = pixels[i*3+2]; + pixels[i*4+1] = pixels[i*3+1]; + pixels[i*4+0] = pixels[i*3+0]; + } + } + else if(components == 1) { + /* grayscale */ + for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) { + pixels[i*4+3] = 1.0f; + pixels[i*4+2] = pixels[i]; + pixels[i*4+1] = pixels[i]; + pixels[i*4+0] = pixels[i]; + } + } + + if(img->use_alpha == false) { + for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) { + pixels[i*4+3] = 1.0f; + } + } + } + + return true; +} + void ImageManager::device_load_image(Device *device, DeviceScene *dscene, ImageDataType type, int slot, Progress *progress) { if(progress->get_cancel()) @@ -744,7 +869,7 @@ void ImageManager::device_load_image(Device *device, DeviceScene *dscene, ImageD img->extension); } } - else { + else if(type == IMAGE_DATA_TYPE_BYTE){ device_vector<uchar>& tex_img = dscene->tex_byte_image[slot]; if(tex_img.device_pointer) { @@ -767,6 +892,55 @@ void ImageManager::device_load_image(Device *device, DeviceScene *dscene, ImageD img->extension); } } + else if(type == IMAGE_DATA_TYPE_HALF4){ + device_vector<half4>& tex_img = dscene->tex_half4_image[slot]; + + if(tex_img.device_pointer) { + thread_scoped_lock device_lock(device_mutex); + device->tex_free(tex_img); + } + + if(!file_load_half_image(img, type, tex_img)) { + /* on failure to load, we set a 1x1 pixels pink image */ + half *pixels = (half*)tex_img.resize(1, 1); + + pixels[0] = TEX_IMAGE_MISSING_R; + pixels[1] = TEX_IMAGE_MISSING_G; + pixels[2] = TEX_IMAGE_MISSING_B; + pixels[3] = TEX_IMAGE_MISSING_A; + } + + if(!pack_images) { + thread_scoped_lock device_lock(device_mutex); + device->tex_alloc(name.c_str(), + tex_img, + img->interpolation, + img->extension); + } + } + else if(type == IMAGE_DATA_TYPE_HALF){ + device_vector<half>& tex_img = dscene->tex_half_image[slot]; + + if(tex_img.device_pointer) { + thread_scoped_lock device_lock(device_mutex); + device->tex_free(tex_img); + } + + if(!file_load_half_image(img, type, tex_img)) { + /* on failure to load, we set a 1x1 pixels pink image */ + half *pixels = (half*)tex_img.resize(1, 1); + + pixels[0] = TEX_IMAGE_MISSING_R; + } + + if(!pack_images) { + thread_scoped_lock device_lock(device_mutex); + device->tex_alloc(name.c_str(), + tex_img, + img->interpolation, + img->extension); + } + } img->need_load = false; } @@ -812,7 +986,7 @@ void ImageManager::device_free_image(Device *device, DeviceScene *dscene, ImageD tex_img.clear(); } - else { + else if(type == IMAGE_DATA_TYPE_BYTE){ device_vector<uchar>& tex_img = dscene->tex_byte_image[slot]; if(tex_img.device_pointer) { @@ -822,6 +996,26 @@ void ImageManager::device_free_image(Device *device, DeviceScene *dscene, ImageD tex_img.clear(); } + else if(type == IMAGE_DATA_TYPE_HALF4){ + device_vector<half4>& tex_img = dscene->tex_half4_image[slot]; + + if(tex_img.device_pointer) { + thread_scoped_lock device_lock(device_mutex); + device->tex_free(tex_img); + } + + tex_img.clear(); + } + else if(type == IMAGE_DATA_TYPE_HALF){ + device_vector<half>& tex_img = dscene->tex_half_image[slot]; + + if(tex_img.device_pointer) { + thread_scoped_lock device_lock(device_mutex); + device->tex_free(tex_img); + } + + tex_img.clear(); + } delete images[type][slot]; images[type][slot] = NULL; @@ -882,6 +1076,26 @@ void ImageManager::device_update_slot(Device *device, } } +uint8_t ImageManager::pack_image_options(ImageDataType type, size_t slot) +{ + uint8_t options = 0; + + /* Image Options are packed into one uint: + * bit 0 -> Interpolation + * bit 1 + 2 + 3-> Extension */ + if(images[type][slot]->interpolation == INTERPOLATION_CLOSEST) + options |= (1 << 0); + + if(images[type][slot]->extension == EXTENSION_REPEAT) + options |= (1 << 1); + else if(images[type][slot]->extension == EXTENSION_EXTEND) + options |= (1 << 2); + else /* EXTENSION_CLIP */ + options |= (1 << 3); + + return options; +} + void ImageManager::device_pack_images(Device *device, DeviceScene *dscene, Progress& /*progess*/) @@ -913,11 +1127,9 @@ void ImageManager::device_pack_images(Device *device, device_vector<uchar4>& tex_img = dscene->tex_byte4_image[slot]; - /* The image options are packed - bit 0 -> periodic - bit 1 + 2 -> interpolation type */ - uint8_t interpolation = (images[type][slot]->interpolation << 1) + 1; - info[type_index_to_flattened_slot(slot, type)] = make_uint4(tex_img.data_width, tex_img.data_height, offset, interpolation); + uint8_t options = pack_image_options(type, slot); + + info[type_index_to_flattened_slot(slot, type)] = make_uint4(tex_img.data_width, tex_img.data_height, offset, options); memcpy(pixels_byte+offset, (void*)tex_img.data_pointer, tex_img.memory_size()); offset += tex_img.size(); @@ -945,11 +1157,8 @@ void ImageManager::device_pack_images(Device *device, /* todo: support 3D textures, only CPU for now */ - /* The image options are packed - bit 0 -> periodic - bit 1 + 2 -> interpolation type */ - uint8_t interpolation = (images[type][slot]->interpolation << 1) + 1; - info[type_index_to_flattened_slot(slot, type)] = make_uint4(tex_img.data_width, tex_img.data_height, offset, interpolation); + uint8_t options = pack_image_options(type, slot); + info[type_index_to_flattened_slot(slot, type)] = make_uint4(tex_img.data_width, tex_img.data_height, offset, options); memcpy(pixels_float+offset, (void*)tex_img.data_pointer, tex_img.memory_size()); offset += tex_img.size(); diff --git a/intern/cycles/render/image.h b/intern/cycles/render/image.h index 8735133fd91..07998684b23 100644 --- a/intern/cycles/render/image.h +++ b/intern/cycles/render/image.h @@ -41,6 +41,8 @@ public: IMAGE_DATA_TYPE_BYTE4 = 1, IMAGE_DATA_TYPE_FLOAT = 2, IMAGE_DATA_TYPE_BYTE = 3, + IMAGE_DATA_TYPE_HALF4 = 4, + IMAGE_DATA_TYPE_HALF = 5, IMAGE_DATA_NUM_TYPES }; @@ -113,10 +115,15 @@ private: template<typename T> bool file_load_float_image(Image *img, ImageDataType type, device_vector<T>& tex_img); + template<typename T> + bool file_load_half_image(Image *img, ImageDataType type, device_vector<T>& tex_img); + int type_index_to_flattened_slot(int slot, ImageDataType type); int flattened_slot_to_type_index(int flat_slot, ImageDataType *type); string name_from_type(int type); + uint8_t pack_image_options(ImageDataType type, size_t slot); + void device_load_image(Device *device, DeviceScene *dscene, ImageDataType type, int slot, Progress *progess); void device_free_image(Device *device, DeviceScene *dscene, ImageDataType type, int slot); diff --git a/intern/cycles/render/mesh.cpp b/intern/cycles/render/mesh.cpp index 755b16a51c7..764a925983e 100644 --- a/intern/cycles/render/mesh.cpp +++ b/intern/cycles/render/mesh.cpp @@ -85,7 +85,7 @@ NODE_DEFINE(Mesh) displacement_method_enum.insert("both", DISPLACE_BOTH); SOCKET_ENUM(displacement_method, "Displacement Method", displacement_method_enum, DISPLACE_BUMP); - SOCKET_INT(motion_steps, "Motion Steps", 3); + SOCKET_UINT(motion_steps, "Motion Steps", 3); SOCKET_BOOLEAN(use_motion_blur, "Use Motion Blur", false); SOCKET_INT_ARRAY(triangles, "Triangles", array<int>()); @@ -1485,7 +1485,7 @@ bool Mesh::need_attribute(Scene * /*scene*/, ustring name) void Mesh::tessellate(DiagSplit *split) { - int num_faces = triangles.size(); + int num_faces = num_triangles(); add_face_normals(); add_vertex_normals(); diff --git a/intern/cycles/render/nodes.cpp b/intern/cycles/render/nodes.cpp index df0fee63113..15b55d17301 100644 --- a/intern/cycles/render/nodes.cpp +++ b/intern/cycles/render/nodes.cpp @@ -19,6 +19,7 @@ #include "nodes.h" #include "scene.h" #include "svm.h" +#include "svm_color_util.h" #include "svm_math_util.h" #include "osl.h" @@ -30,64 +31,40 @@ CCL_NAMESPACE_BEGIN /* Texture Mapping */ -static NodeEnum texture_mapping_type_init() -{ - NodeEnum enm; - - enm.insert("Point", TextureMapping::POINT); - enm.insert("Texture", TextureMapping::TEXTURE); - enm.insert("Vector", TextureMapping::VECTOR); - enm.insert("Normal", TextureMapping::NORMAL); - - return enm; -} - -static NodeEnum texture_mapping_mapping_init() -{ - NodeEnum enm; - - enm.insert("None", TextureMapping::NONE); - enm.insert("X", TextureMapping::X); - enm.insert("Y", TextureMapping::Y); - enm.insert("Z", TextureMapping::Z); - - return enm; -} - -static NodeEnum texture_mapping_projection_init() -{ - NodeEnum enm; - - enm.insert("Flat", TextureMapping::FLAT); - enm.insert("Cube", TextureMapping::CUBE); - enm.insert("Tube", TextureMapping::TUBE); - enm.insert("Sphere", TextureMapping::SPHERE); - - return enm; -} - -NodeEnum TextureMapping::type_enum = texture_mapping_type_init(); -NodeEnum TextureMapping::mapping_enum = texture_mapping_mapping_init(); -NodeEnum TextureMapping::projection_enum = texture_mapping_projection_init(); +#define TEXTURE_MAPPING_DEFINE(TextureNode) \ + SOCKET_POINT(tex_mapping.translation, "Translation", make_float3(0.0f, 0.0f, 0.0f)); \ + SOCKET_VECTOR(tex_mapping.rotation, "Rotation", make_float3(0.0f, 0.0f, 0.0f)); \ + SOCKET_VECTOR(tex_mapping.scale, "Scale", make_float3(1.0f, 1.0f, 1.0f)); \ + \ + SOCKET_VECTOR(tex_mapping.min, "Min", make_float3(-FLT_MAX, -FLT_MAX, -FLT_MAX)); \ + SOCKET_VECTOR(tex_mapping.max, "Max", make_float3(FLT_MAX, FLT_MAX, FLT_MAX)); \ + SOCKET_BOOLEAN(tex_mapping.use_minmax, "Use Min Max", false); \ + \ + static NodeEnum mapping_axis_enum; \ + mapping_axis_enum.insert("none", TextureMapping::NONE); \ + mapping_axis_enum.insert("x", TextureMapping::X); \ + mapping_axis_enum.insert("y", TextureMapping::Y); \ + mapping_axis_enum.insert("z", TextureMapping::Z); \ + SOCKET_ENUM(tex_mapping.x_mapping, "x_mapping", mapping_axis_enum, TextureMapping::X); \ + SOCKET_ENUM(tex_mapping.y_mapping, "y_mapping", mapping_axis_enum, TextureMapping::Y); \ + SOCKET_ENUM(tex_mapping.z_mapping, "z_mapping", mapping_axis_enum, TextureMapping::Z); \ + \ + static NodeEnum mapping_type_enum; \ + mapping_type_enum.insert("point", TextureMapping::POINT); \ + mapping_type_enum.insert("texture", TextureMapping::TEXTURE); \ + mapping_type_enum.insert("vector", TextureMapping::VECTOR); \ + mapping_type_enum.insert("normal", TextureMapping::NORMAL); \ + SOCKET_ENUM(tex_mapping.type, "Type", mapping_type_enum, TextureMapping::TEXTURE); \ + \ + static NodeEnum mapping_projection_enum; \ + mapping_projection_enum.insert("flat", TextureMapping::FLAT); \ + mapping_projection_enum.insert("cube", TextureMapping::CUBE); \ + mapping_projection_enum.insert("tube", TextureMapping::TUBE); \ + mapping_projection_enum.insert("sphere", TextureMapping::SPHERE); \ + SOCKET_ENUM(tex_mapping.projection, "Projection", mapping_projection_enum, TextureMapping::FLAT); TextureMapping::TextureMapping() { - translation = make_float3(0.0f, 0.0f, 0.0f); - rotation = make_float3(0.0f, 0.0f, 0.0f); - scale = make_float3(1.0f, 1.0f, 1.0f); - - min = make_float3(-FLT_MAX, -FLT_MAX, -FLT_MAX); - max = make_float3(FLT_MAX, FLT_MAX, FLT_MAX); - - use_minmax = false; - - x_mapping = X; - y_mapping = Y; - z_mapping = Z; - - type = TEXTURE; - - projection = FLAT; } Transform TextureMapping::compute_transform() @@ -222,72 +199,66 @@ void TextureMapping::compile(OSLCompiler &compiler) /* Image Texture */ -static NodeEnum color_space_init() +NODE_DEFINE(ImageTextureNode) { - NodeEnum enm; + NodeType* type = NodeType::add("image_texture", create, NodeType::SHADER); - enm.insert("None", 0); - enm.insert("Color", 1); + TEXTURE_MAPPING_DEFINE(ImageTextureNode); - return enm; -} + SOCKET_STRING(filename, "Filename", ustring("")); -static NodeEnum image_projection_init() -{ - NodeEnum enm; + static NodeEnum color_space_enum; + color_space_enum.insert("none", NODE_COLOR_SPACE_NONE); + color_space_enum.insert("color", NODE_COLOR_SPACE_COLOR); + SOCKET_ENUM(color_space, "Color Space", color_space_enum, NODE_COLOR_SPACE_COLOR); - enm.insert("Flat", NODE_IMAGE_PROJ_FLAT); - enm.insert("Box", NODE_IMAGE_PROJ_BOX); - enm.insert("Sphere", NODE_IMAGE_PROJ_SPHERE); - enm.insert("Tube", NODE_IMAGE_PROJ_TUBE); + SOCKET_BOOLEAN(use_alpha, "Use Alpha", true); - return enm; -} + static NodeEnum interpolation_enum; + interpolation_enum.insert("closest", INTERPOLATION_CLOSEST); + interpolation_enum.insert("linear", INTERPOLATION_LINEAR); + interpolation_enum.insert("cubic", INTERPOLATION_CUBIC); + interpolation_enum.insert("smart", INTERPOLATION_SMART); + SOCKET_ENUM(interpolation, "Interpolation", interpolation_enum, INTERPOLATION_LINEAR); -static const char* get_osl_interpolation_parameter(InterpolationType interpolation) -{ - switch(interpolation) { - case INTERPOLATION_CLOSEST: - return "closest"; - case INTERPOLATION_CUBIC: - return "cubic"; - case INTERPOLATION_SMART: - return "smart"; - case INTERPOLATION_LINEAR: - default: - return "linear"; - } -} + static NodeEnum extension_enum; + extension_enum.insert("periodic", EXTENSION_REPEAT); + extension_enum.insert("clamp", EXTENSION_EXTEND); + extension_enum.insert("black", EXTENSION_CLIP); + SOCKET_ENUM(extension, "Extension", extension_enum, EXTENSION_REPEAT); + + static NodeEnum projection_enum; + projection_enum.insert("flat", NODE_IMAGE_PROJ_FLAT); + projection_enum.insert("box", NODE_IMAGE_PROJ_BOX); + projection_enum.insert("sphere", NODE_IMAGE_PROJ_SPHERE); + projection_enum.insert("tube", NODE_IMAGE_PROJ_TUBE); + SOCKET_ENUM(projection, "Projection", projection_enum, NODE_IMAGE_PROJ_FLAT); + + SOCKET_FLOAT(projection_blend, "Projection Blend", 0.0f); + + SOCKET_IN_POINT(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_UV); -NodeEnum ImageTextureNode::color_space_enum = color_space_init(); -NodeEnum ImageTextureNode::projection_enum = image_projection_init(); + SOCKET_OUT_COLOR(color, "Color"); + SOCKET_OUT_FLOAT(alpha, "Alpha"); + + return type; +} ImageTextureNode::ImageTextureNode() -: ImageSlotTextureNode("image_texture") +: ImageSlotTextureNode(node_type) { image_manager = NULL; slot = -1; is_float = -1; is_linear = false; - use_alpha = true; - filename = ""; builtin_data = NULL; - color_space = NODE_COLOR_SPACE_COLOR; - projection = NODE_IMAGE_PROJ_FLAT; - interpolation = INTERPOLATION_LINEAR; - extension = EXTENSION_REPEAT; - projection_blend = 0.0f; animated = false; - - add_input("Vector", SocketType::POINT, make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_UV); - add_output("Color", SocketType::COLOR); - add_output("Alpha", SocketType::FLOAT); } ImageTextureNode::~ImageTextureNode() { if(image_manager) { - image_manager->remove_image(filename, + image_manager->remove_image(filename.string(), builtin_data, interpolation, extension); @@ -328,7 +299,7 @@ void ImageTextureNode::compile(SVMCompiler& compiler) image_manager = compiler.image_manager; if(is_float == -1) { bool is_float_bool; - slot = image_manager->add_image(filename, + slot = image_manager->add_image(filename.string(), builtin_data, animated, 0, @@ -390,13 +361,13 @@ void ImageTextureNode::compile(OSLCompiler& compiler) if(is_float == -1) { if(builtin_data == NULL) { ImageManager::ImageDataType type; - type = image_manager->get_image_metadata(filename, NULL, is_linear); + type = image_manager->get_image_metadata(filename.string(), NULL, is_linear); if(type == ImageManager::IMAGE_DATA_TYPE_FLOAT || type == ImageManager::IMAGE_DATA_TYPE_FLOAT4) is_float = 1; } else { bool is_float_bool; - slot = image_manager->add_image(filename, + slot = image_manager->add_image(filename.string(), builtin_data, animated, 0, @@ -410,7 +381,7 @@ void ImageTextureNode::compile(OSLCompiler& compiler) } if(slot == -1) { - compiler.parameter("filename", filename.c_str()); + compiler.parameter(this, "filename"); } else { /* TODO(sergey): It's not so simple to pass custom attribute @@ -422,70 +393,71 @@ void ImageTextureNode::compile(OSLCompiler& compiler) compiler.parameter("filename", string_printf("@%d", slot).c_str()); } if(is_linear || color_space != NODE_COLOR_SPACE_COLOR) - compiler.parameter("color_space", "Linear"); + compiler.parameter("color_space", "linear"); else compiler.parameter("color_space", "sRGB"); - compiler.parameter("projection", projection); - compiler.parameter("projection_blend", projection_blend); + compiler.parameter(this, "projection"); + compiler.parameter(this, "projection_blend"); compiler.parameter("is_float", is_float); compiler.parameter("use_alpha", !alpha_out->links.empty()); - compiler.parameter("interpolation", get_osl_interpolation_parameter(interpolation)); - - switch(extension) { - case EXTENSION_EXTEND: - compiler.parameter("extension", "clamp"); - break; - case EXTENSION_CLIP: - compiler.parameter("extension", "black"); - break; - case EXTENSION_REPEAT: - default: - compiler.parameter("extension", "periodic"); - break; - } + compiler.parameter(this, "interpolation"); + compiler.parameter(this, "extension"); compiler.add(this, "node_image_texture"); } /* Environment Texture */ -static NodeEnum env_projection_init() +NODE_DEFINE(EnvironmentTextureNode) { - NodeEnum enm; + NodeType* type = NodeType::add("environment_texture", create, NodeType::SHADER); - enm.insert("Equirectangular", 0); - enm.insert("Mirror Ball", 1); + TEXTURE_MAPPING_DEFINE(EnvironmentTextureNode); - return enm; -} + SOCKET_STRING(filename, "Filename", ustring("")); + + static NodeEnum color_space_enum; + color_space_enum.insert("none", NODE_COLOR_SPACE_NONE); + color_space_enum.insert("color", NODE_COLOR_SPACE_COLOR); + SOCKET_ENUM(color_space, "Color Space", color_space_enum, NODE_COLOR_SPACE_COLOR); + + SOCKET_BOOLEAN(use_alpha, "Use Alpha", true); + + static NodeEnum interpolation_enum; + interpolation_enum.insert("closest", INTERPOLATION_CLOSEST); + interpolation_enum.insert("linear", INTERPOLATION_LINEAR); + interpolation_enum.insert("cubic", INTERPOLATION_CUBIC); + interpolation_enum.insert("smart", INTERPOLATION_SMART); + SOCKET_ENUM(interpolation, "Interpolation", interpolation_enum, INTERPOLATION_LINEAR); -NodeEnum EnvironmentTextureNode::color_space_enum = color_space_init(); -NodeEnum EnvironmentTextureNode::projection_enum = env_projection_init(); + static NodeEnum projection_enum; + projection_enum.insert("equirectangular", NODE_ENVIRONMENT_EQUIRECTANGULAR); + projection_enum.insert("mirror_ball", NODE_ENVIRONMENT_MIRROR_BALL); + SOCKET_ENUM(projection, "Projection", projection_enum, NODE_ENVIRONMENT_EQUIRECTANGULAR); + + SOCKET_IN_POINT(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_POSITION); + + SOCKET_OUT_COLOR(color, "Color"); + SOCKET_OUT_FLOAT(alpha, "Alpha"); + + return type; +} EnvironmentTextureNode::EnvironmentTextureNode() -: ImageSlotTextureNode("environment_texture") +: ImageSlotTextureNode(node_type) { image_manager = NULL; slot = -1; is_float = -1; is_linear = false; - use_alpha = true; - filename = ""; builtin_data = NULL; - color_space = NODE_COLOR_SPACE_COLOR; - interpolation = INTERPOLATION_LINEAR; - projection = NODE_ENVIRONMENT_EQUIRECTANGULAR; animated = false; - - add_input("Vector", SocketType::VECTOR, make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_POSITION); - add_output("Color", SocketType::COLOR); - add_output("Alpha", SocketType::FLOAT); } EnvironmentTextureNode::~EnvironmentTextureNode() { if(image_manager) { - image_manager->remove_image(filename, + image_manager->remove_image(filename.string(), builtin_data, interpolation, EXTENSION_REPEAT); @@ -524,7 +496,7 @@ void EnvironmentTextureNode::compile(SVMCompiler& compiler) image_manager = compiler.image_manager; if(slot == -1) { bool is_float_bool; - slot = image_manager->add_image(filename, + slot = image_manager->add_image(filename.string(), builtin_data, animated, 0, @@ -577,13 +549,13 @@ void EnvironmentTextureNode::compile(OSLCompiler& compiler) if(is_float == -1) { if(builtin_data == NULL) { ImageManager::ImageDataType type; - type = image_manager->get_image_metadata(filename, NULL, is_linear); + type = image_manager->get_image_metadata(filename.string(), NULL, is_linear); if(type == ImageManager::IMAGE_DATA_TYPE_FLOAT || type == ImageManager::IMAGE_DATA_TYPE_FLOAT4) is_float = 1; } else { bool is_float_bool; - slot = image_manager->add_image(filename, + slot = image_manager->add_image(filename.string(), builtin_data, animated, 0, @@ -597,19 +569,18 @@ void EnvironmentTextureNode::compile(OSLCompiler& compiler) } if(slot == -1) { - compiler.parameter("filename", filename.c_str()); + compiler.parameter(this, "filename"); } else { compiler.parameter("filename", string_printf("@%d", slot).c_str()); } - compiler.parameter("projection", projection_enum[projection]); + compiler.parameter(this, "projection"); if(is_linear || color_space != NODE_COLOR_SPACE_COLOR) - compiler.parameter("color_space", "Linear"); + compiler.parameter("color_space", "linear"); else compiler.parameter("color_space", "sRGB"); - compiler.parameter("interpolation", get_osl_interpolation_parameter(interpolation)); - + compiler.parameter(this, "interpolation"); compiler.parameter("is_float", is_float); compiler.parameter("use_alpha", !alpha_out->links.empty()); compiler.add(this, "node_environment_texture"); @@ -640,10 +611,10 @@ static float sky_perez_function(float lam[6], float theta, float gamma) static void sky_texture_precompute_old(SunSky *sunsky, float3 dir, float turbidity) { /* - * We re-use the SunSky struct of the new model, to avoid extra variables - * zenith_Y/x/y is now radiance_x/y/z - * perez_Y/x/y is now config_x/y/z - */ + * We re-use the SunSky struct of the new model, to avoid extra variables + * zenith_Y/x/y is now radiance_x/y/z + * perez_Y/x/y is now config_x/y/z + */ float2 spherical = sky_spherical_coordinates(dir); float theta = spherical.x; @@ -738,29 +709,31 @@ static void sky_texture_precompute_new(SunSky *sunsky, float3 dir, float turbidi arhosekskymodelstate_free(sky_state); } -static NodeEnum sky_type_init() +NODE_DEFINE(SkyTextureNode) { - NodeEnum enm; + NodeType* type = NodeType::add("sky_texture", create, NodeType::SHADER); - enm.insert("Preetham", NODE_SKY_OLD); - enm.insert("Hosek / Wilkie", NODE_SKY_NEW); + TEXTURE_MAPPING_DEFINE(SkyTextureNode); - return enm; -} + static NodeEnum type_enum; + type_enum.insert("preetham", NODE_SKY_OLD); + type_enum.insert("hosek_wilkie", NODE_SKY_NEW); + SOCKET_ENUM(type, "Type", type_enum, NODE_SKY_NEW); + + SOCKET_VECTOR(sun_direction, "Sun Direction", make_float3(0.0f, 0.0f, 1.0f)); + SOCKET_FLOAT(turbidity, "Turbidity", 2.2f); + SOCKET_FLOAT(ground_albedo, "Ground Albedo", 0.3f); + + SOCKET_IN_POINT(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED); + + SOCKET_OUT_COLOR(color, "Color"); -NodeEnum SkyTextureNode::type_enum = sky_type_init(); + return type; +} SkyTextureNode::SkyTextureNode() -: TextureNode("sky_texture") +: TextureNode(node_type) { - type = NODE_SKY_NEW; - - sun_direction = make_float3(0.0f, 0.0f, 1.0f); - turbidity = 2.2f; - ground_albedo = 0.3f; - - add_input("Vector", SocketType::VECTOR, make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_POSITION); - add_output("Color", SocketType::COLOR); } void SkyTextureNode::compile(SVMCompiler& compiler) @@ -777,10 +750,9 @@ void SkyTextureNode::compile(SVMCompiler& compiler) assert(false); int vector_offset = tex_mapping.compile_begin(compiler, vector_in); - int sky_model = type; compiler.stack_assign(color_out); - compiler.add_node(NODE_TEX_SKY, vector_offset, compiler.stack_assign(color_out), sky_model); + compiler.add_node(NODE_TEX_SKY, vector_offset, compiler.stack_assign(color_out), type); compiler.add_node(__float_as_uint(sunsky.phi), __float_as_uint(sunsky.theta), __float_as_uint(sunsky.radiance_x), __float_as_uint(sunsky.radiance_y)); compiler.add_node(__float_as_uint(sunsky.radiance_z), __float_as_uint(sunsky.config_x[0]), __float_as_uint(sunsky.config_x[1]), __float_as_uint(sunsky.config_x[2])); compiler.add_node(__float_as_uint(sunsky.config_x[3]), __float_as_uint(sunsky.config_x[4]), __float_as_uint(sunsky.config_x[5]), __float_as_uint(sunsky.config_x[6])); @@ -798,7 +770,6 @@ void SkyTextureNode::compile(OSLCompiler& compiler) tex_mapping.compile(compiler); SunSky sunsky; - if(type == NODE_SKY_OLD) sky_texture_precompute_old(&sunsky, sun_direction, turbidity); else if(type == NODE_SKY_NEW) @@ -806,7 +777,7 @@ void SkyTextureNode::compile(OSLCompiler& compiler) else assert(false); - compiler.parameter("sky_model", type_enum[type]); + compiler.parameter(this, "type"); compiler.parameter("theta", sunsky.theta); compiler.parameter("phi", sunsky.phi); compiler.parameter_color("radiance", make_float3(sunsky.radiance_x, sunsky.radiance_y, sunsky.radiance_z)); @@ -818,31 +789,33 @@ void SkyTextureNode::compile(OSLCompiler& compiler) /* Gradient Texture */ -static NodeEnum gradient_type_init() +NODE_DEFINE(GradientTextureNode) { - NodeEnum enm; + NodeType* type = NodeType::add("gradient_texture", create, NodeType::SHADER); - enm.insert("Linear", NODE_BLEND_LINEAR); - enm.insert("Quadratic", NODE_BLEND_QUADRATIC); - enm.insert("Easing", NODE_BLEND_EASING); - enm.insert("Diagonal", NODE_BLEND_DIAGONAL); - enm.insert("Radial", NODE_BLEND_RADIAL); - enm.insert("Quadratic Sphere", NODE_BLEND_QUADRATIC_SPHERE); - enm.insert("Spherical", NODE_BLEND_SPHERICAL); + TEXTURE_MAPPING_DEFINE(GradientTextureNode); - return enm; -} + static NodeEnum type_enum; + type_enum.insert("linear", NODE_BLEND_LINEAR); + type_enum.insert("quadratic", NODE_BLEND_QUADRATIC); + type_enum.insert("easing", NODE_BLEND_EASING); + type_enum.insert("diagonal", NODE_BLEND_DIAGONAL); + type_enum.insert("radial", NODE_BLEND_RADIAL); + type_enum.insert("quadratic_sphere", NODE_BLEND_QUADRATIC_SPHERE); + type_enum.insert("spherical", NODE_BLEND_SPHERICAL); + SOCKET_ENUM(type, "Type", type_enum, NODE_BLEND_LINEAR); + + SOCKET_IN_POINT(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED); -NodeEnum GradientTextureNode::type_enum = gradient_type_init(); + SOCKET_OUT_COLOR(color, "Color"); + SOCKET_OUT_FLOAT(fac, "Fac"); + + return type; +} GradientTextureNode::GradientTextureNode() -: TextureNode("gradient_texture") +: TextureNode(node_type) { - type = NODE_BLEND_LINEAR; - - add_input("Vector", SocketType::POINT, make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED); - add_output("Color", SocketType::COLOR); - add_output("Fac", SocketType::FLOAT); } void GradientTextureNode::compile(SVMCompiler& compiler) @@ -867,22 +840,32 @@ void GradientTextureNode::compile(OSLCompiler& compiler) { tex_mapping.compile(compiler); - compiler.parameter("type", type_enum[type]); + compiler.parameter(this, "type"); compiler.add(this, "node_gradient_texture"); } /* Noise Texture */ -NoiseTextureNode::NoiseTextureNode() -: TextureNode("noise_texture") +NODE_DEFINE(NoiseTextureNode) { - add_input("Vector", SocketType::POINT, make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED); - add_input("Scale", SocketType::FLOAT, 1.0f); - add_input("Detail", SocketType::FLOAT, 2.0f); - add_input("Distortion", SocketType::FLOAT, 0.0f); + NodeType* type = NodeType::add("noise_texture", create, NodeType::SHADER); + + TEXTURE_MAPPING_DEFINE(NoiseTextureNode); + + SOCKET_IN_FLOAT(scale, "Scale", 1.0f); + SOCKET_IN_FLOAT(detail, "Detail", 2.0f); + SOCKET_IN_FLOAT(distortion, "Distortion", 0.0f); + SOCKET_IN_POINT(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED); - add_output("Color", SocketType::COLOR); - add_output("Fac", SocketType::FLOAT); + SOCKET_OUT_COLOR(color, "Color"); + SOCKET_OUT_FLOAT(fac, "Fac"); + + return type; +} + +NoiseTextureNode::NoiseTextureNode() +: TextureNode(node_type) +{ } void NoiseTextureNode::compile(SVMCompiler& compiler) @@ -906,9 +889,9 @@ void NoiseTextureNode::compile(SVMCompiler& compiler) compiler.stack_assign_if_linked(color_out), compiler.stack_assign_if_linked(fac_out))); compiler.add_node( - __float_as_int(scale_in->value_float()), - __float_as_int(detail_in->value_float()), - __float_as_int(distortion_in->value_float())); + __float_as_int(scale), + __float_as_int(detail), + __float_as_int(distortion)); tex_mapping.compile_end(compiler, vector_in, vector_offset); } @@ -922,28 +905,29 @@ void NoiseTextureNode::compile(OSLCompiler& compiler) /* Voronoi Texture */ -static NodeEnum voronoi_coloring_init() +NODE_DEFINE(VoronoiTextureNode) { - NodeEnum enm; + NodeType* type = NodeType::add("voronoi_texture", create, NodeType::SHADER); - enm.insert("Intensity", NODE_VORONOI_INTENSITY); - enm.insert("Cells", NODE_VORONOI_CELLS); + TEXTURE_MAPPING_DEFINE(VoronoiTextureNode); - return enm; -} + static NodeEnum coloring_enum; + coloring_enum.insert("intensity", NODE_VORONOI_INTENSITY); + coloring_enum.insert("cells", NODE_VORONOI_CELLS); + SOCKET_ENUM(coloring, "Coloring", coloring_enum, NODE_VORONOI_INTENSITY); -NodeEnum VoronoiTextureNode::coloring_enum = voronoi_coloring_init(); + SOCKET_IN_FLOAT(scale, "Scale", 1.0f); + SOCKET_IN_POINT(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED); -VoronoiTextureNode::VoronoiTextureNode() -: TextureNode("voronoi_texture") -{ - coloring = NODE_VORONOI_INTENSITY; + SOCKET_OUT_COLOR(color, "Color"); + SOCKET_OUT_FLOAT(fac, "Fac"); - add_input("Scale", SocketType::FLOAT, 1.0f); - add_input("Vector", SocketType::POINT, make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED); + return type; +} - add_output("Color", SocketType::COLOR); - add_output("Fac", SocketType::FLOAT); +VoronoiTextureNode::VoronoiTextureNode() +: TextureNode(node_type) +{ } void VoronoiTextureNode::compile(SVMCompiler& compiler) @@ -962,7 +946,7 @@ void VoronoiTextureNode::compile(SVMCompiler& compiler) vector_offset, compiler.stack_assign(fac_out), compiler.stack_assign(color_out)), - __float_as_int(scale_in->value_float())); + __float_as_int(scale)); tex_mapping.compile_end(compiler, vector_in, vector_offset); } @@ -971,42 +955,43 @@ void VoronoiTextureNode::compile(OSLCompiler& compiler) { tex_mapping.compile(compiler); - compiler.parameter("coloring", coloring_enum[coloring]); + compiler.parameter(this, "coloring"); compiler.add(this, "node_voronoi_texture"); } /* Musgrave Texture */ -static NodeEnum musgrave_type_init() +NODE_DEFINE(MusgraveTextureNode) { - NodeEnum enm; + NodeType* type = NodeType::add("musgrave_texture", create, NodeType::SHADER); - enm.insert("Multifractal", NODE_MUSGRAVE_MULTIFRACTAL); - enm.insert("fBM", NODE_MUSGRAVE_FBM); - enm.insert("Hybrid Multifractal", NODE_MUSGRAVE_HYBRID_MULTIFRACTAL); - enm.insert("Ridged Multifractal", NODE_MUSGRAVE_RIDGED_MULTIFRACTAL); - enm.insert("Hetero Terrain", NODE_MUSGRAVE_HETERO_TERRAIN); + TEXTURE_MAPPING_DEFINE(MusgraveTextureNode); - return enm; -} + static NodeEnum type_enum; + type_enum.insert("multifractal", NODE_MUSGRAVE_MULTIFRACTAL); + type_enum.insert("fBM", NODE_MUSGRAVE_FBM); + type_enum.insert("hybrid_multifractal", NODE_MUSGRAVE_HYBRID_MULTIFRACTAL); + type_enum.insert("ridged_multifractal", NODE_MUSGRAVE_RIDGED_MULTIFRACTAL); + type_enum.insert("hetero_terrain", NODE_MUSGRAVE_HETERO_TERRAIN); + SOCKET_ENUM(type, "Type", type_enum, NODE_MUSGRAVE_FBM); -NodeEnum MusgraveTextureNode::type_enum = musgrave_type_init(); + SOCKET_IN_FLOAT(scale, "Scale", 1.0f); + SOCKET_IN_FLOAT(detail, "Detail", 2.0f); + SOCKET_IN_FLOAT(dimension, "Dimension", 2.0f); + SOCKET_IN_FLOAT(lacunarity, "Lacunarity", 1.0f); + SOCKET_IN_FLOAT(offset, "Offset", 0.0f); + SOCKET_IN_FLOAT(gain, "Gain", 1.0f); + SOCKET_IN_POINT(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED); -MusgraveTextureNode::MusgraveTextureNode() -: TextureNode("musgrave_texture") -{ - type = NODE_MUSGRAVE_FBM; + SOCKET_OUT_COLOR(color, "Color"); + SOCKET_OUT_FLOAT(fac, "Fac"); - add_input("Scale", SocketType::FLOAT, 1.0f); - add_input("Detail", SocketType::FLOAT, 2.0f); - add_input("Vector", SocketType::POINT, make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED); - add_input("Dimension", SocketType::FLOAT, 2.0f); - add_input("Lacunarity", SocketType::FLOAT, 1.0f); - add_input("Offset", SocketType::FLOAT, 0.0f); - add_input("Gain", SocketType::FLOAT, 1.0f); + return type; +} - add_output("Fac", SocketType::FLOAT); - add_output("Color", SocketType::COLOR); +MusgraveTextureNode::MusgraveTextureNode() +: TextureNode(node_type) +{ } void MusgraveTextureNode::compile(SVMCompiler& compiler) @@ -1037,12 +1022,12 @@ void MusgraveTextureNode::compile(SVMCompiler& compiler) compiler.encode_uchar4( compiler.stack_assign_if_linked(gain_in), compiler.stack_assign_if_linked(scale_in))); - compiler.add_node(__float_as_int(dimension_in->value_float()), - __float_as_int(lacunarity_in->value_float()), - __float_as_int(detail_in->value_float()), - __float_as_int(offset_in->value_float())); - compiler.add_node(__float_as_int(gain_in->value_float()), - __float_as_int(scale_in->value_float())); + compiler.add_node(__float_as_int(dimension), + __float_as_int(lacunarity), + __float_as_int(detail), + __float_as_int(offset)); + compiler.add_node(__float_as_int(gain), + __float_as_int(scale)); tex_mapping.compile_end(compiler, vector_in, vector_offset); } @@ -1051,50 +1036,43 @@ void MusgraveTextureNode::compile(OSLCompiler& compiler) { tex_mapping.compile(compiler); - compiler.parameter("type", type_enum[type]); - + compiler.parameter(this, "type"); compiler.add(this, "node_musgrave_texture"); } /* Wave Texture */ -static NodeEnum wave_type_init() +NODE_DEFINE(WaveTextureNode) { - NodeEnum enm; + NodeType* type = NodeType::add("wave_texture", create, NodeType::SHADER); - enm.insert("Bands", NODE_WAVE_BANDS); - enm.insert("Rings", NODE_WAVE_RINGS); + TEXTURE_MAPPING_DEFINE(WaveTextureNode); - return enm; -} + static NodeEnum type_enum; + type_enum.insert("bands", NODE_WAVE_BANDS); + type_enum.insert("rings", NODE_WAVE_RINGS); + SOCKET_ENUM(type, "Type", type_enum, NODE_WAVE_BANDS); -static NodeEnum wave_profile_init() -{ - NodeEnum enm; + static NodeEnum profile_enum; + profile_enum.insert("sine", NODE_WAVE_PROFILE_SIN); + profile_enum.insert("saw", NODE_WAVE_PROFILE_SAW); + SOCKET_ENUM(profile, "Profile", profile_enum, NODE_WAVE_PROFILE_SIN); - enm.insert("Sine", NODE_WAVE_PROFILE_SIN); - enm.insert("Saw", NODE_WAVE_PROFILE_SAW); + SOCKET_IN_FLOAT(scale, "Scale", 1.0f); + SOCKET_IN_FLOAT(distortion, "Distortion", 0.0f); + SOCKET_IN_FLOAT(detail, "Detail", 2.0f); + SOCKET_IN_FLOAT(detail_scale, "Detail Scale", 0.0f); + SOCKET_IN_POINT(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED); - return enm; -} + SOCKET_OUT_COLOR(color, "Color"); + SOCKET_OUT_FLOAT(fac, "Fac"); -NodeEnum WaveTextureNode::type_enum = wave_type_init(); -NodeEnum WaveTextureNode::profile_enum = wave_profile_init(); + return type; +} WaveTextureNode::WaveTextureNode() -: TextureNode("wave_texture") +: TextureNode(node_type) { - type = NODE_WAVE_BANDS; - profile = NODE_WAVE_PROFILE_SIN; - - add_input("Scale", SocketType::FLOAT, 1.0f); - add_input("Distortion", SocketType::FLOAT, 0.0f); - add_input("Detail", SocketType::FLOAT, 2.0f); - add_input("Detail Scale", SocketType::FLOAT, 1.0f); - add_input("Vector", SocketType::POINT, make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED); - - add_output("Color", SocketType::COLOR); - add_output("Fac", SocketType::FLOAT); } void WaveTextureNode::compile(SVMCompiler& compiler) @@ -1123,10 +1101,10 @@ void WaveTextureNode::compile(SVMCompiler& compiler) profile); compiler.add_node( - __float_as_int(scale_in->value_float()), - __float_as_int(detail_in->value_float()), - __float_as_int(distortion_in->value_float()), - __float_as_int(dscale_in->value_float())); + __float_as_int(scale), + __float_as_int(detail), + __float_as_int(distortion), + __float_as_int(detail_scale)); tex_mapping.compile_end(compiler, vector_in, vector_offset); } @@ -1135,25 +1113,35 @@ void WaveTextureNode::compile(OSLCompiler& compiler) { tex_mapping.compile(compiler); - compiler.parameter("type", type_enum[type]); - compiler.parameter("profile", profile_enum[profile]); + compiler.parameter(this, "type"); + compiler.parameter(this, "profile"); compiler.add(this, "node_wave_texture"); } /* Magic Texture */ -MagicTextureNode::MagicTextureNode() -: TextureNode("magic_texture") +NODE_DEFINE(MagicTextureNode) { - depth = 2; + NodeType* type = NodeType::add("magic_texture", create, NodeType::SHADER); + + TEXTURE_MAPPING_DEFINE(MagicTextureNode); + + SOCKET_INT(depth, "Depth", 2); + + SOCKET_IN_POINT(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED); + SOCKET_IN_FLOAT(scale, "Scale", 5.0f); + SOCKET_IN_FLOAT(distortion, "Distortion", 1.0f); - add_input("Vector", SocketType::POINT, make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED); - add_input("Scale", SocketType::FLOAT, 5.0f); - add_input("Distortion", SocketType::FLOAT, 1.0f); + SOCKET_OUT_COLOR(color, "Color"); + SOCKET_OUT_FLOAT(fac, "Fac"); - add_output("Color", SocketType::COLOR); - add_output("Fac", SocketType::FLOAT); + return type; +} + +MagicTextureNode::MagicTextureNode() +: TextureNode(node_type) +{ } void MagicTextureNode::compile(SVMCompiler& compiler) @@ -1176,8 +1164,8 @@ void MagicTextureNode::compile(SVMCompiler& compiler) compiler.stack_assign_if_linked(scale_in), compiler.stack_assign_if_linked(distortion_in))); compiler.add_node( - __float_as_int(scale_in->value_float()), - __float_as_int(distortion_in->value_float())); + __float_as_int(scale), + __float_as_int(distortion)); tex_mapping.compile_end(compiler, vector_in, vector_offset); } @@ -1186,22 +1174,32 @@ void MagicTextureNode::compile(OSLCompiler& compiler) { tex_mapping.compile(compiler); - compiler.parameter("depth", depth); + compiler.parameter(this, "depth"); compiler.add(this, "node_magic_texture"); } /* Checker Texture */ -CheckerTextureNode::CheckerTextureNode() -: TextureNode("checker_texture") +NODE_DEFINE(CheckerTextureNode) { - add_input("Vector", SocketType::POINT, make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED); - add_input("Color1", SocketType::COLOR); - add_input("Color2", SocketType::COLOR); - add_input("Scale", SocketType::FLOAT, 1.0f); + NodeType* type = NodeType::add("checker_texture", create, NodeType::SHADER); + + TEXTURE_MAPPING_DEFINE(CheckerTextureNode); - add_output("Color", SocketType::COLOR); - add_output("Fac", SocketType::FLOAT); + SOCKET_IN_POINT(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED); + SOCKET_IN_COLOR(color1, "Color1", make_float3(0.0f, 0.0f, 0.0f)); + SOCKET_IN_COLOR(color2, "Color2", make_float3(0.0f, 0.0f, 0.0f)); + SOCKET_IN_FLOAT(scale, "Scale", 1.0f); + + SOCKET_OUT_COLOR(color, "Color"); + SOCKET_OUT_FLOAT(fac, "Fac"); + + return type; +} + +CheckerTextureNode::CheckerTextureNode() +: TextureNode(node_type) +{ } void CheckerTextureNode::compile(SVMCompiler& compiler) @@ -1225,7 +1223,7 @@ void CheckerTextureNode::compile(SVMCompiler& compiler) compiler.encode_uchar4( compiler.stack_assign_if_linked(color_out), compiler.stack_assign_if_linked(fac_out)), - __float_as_int(scale_in->value_float())); + __float_as_int(scale)); tex_mapping.compile_end(compiler, vector_in, vector_offset); } @@ -1239,26 +1237,37 @@ void CheckerTextureNode::compile(OSLCompiler& compiler) /* Brick Texture */ -BrickTextureNode::BrickTextureNode() -: TextureNode("brick_texture") +NODE_DEFINE(BrickTextureNode) { - offset = 0.5f; - offset_frequency = 2; - squash = 1.0f; - squash_frequency = 2; - - add_input("Vector", SocketType::POINT, make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED); - add_input("Color1", SocketType::COLOR); - add_input("Color2", SocketType::COLOR); - add_input("Mortar", SocketType::COLOR); - add_input("Scale", SocketType::FLOAT, 5.0f); - add_input("Mortar Size", SocketType::FLOAT, 0.02f); - add_input("Bias", SocketType::FLOAT, 0.0f); - add_input("Brick Width", SocketType::FLOAT, 0.5f); - add_input("Row Height", SocketType::FLOAT, 0.25f); + NodeType* type = NodeType::add("brick_texture", create, NodeType::SHADER); + + TEXTURE_MAPPING_DEFINE(BrickTextureNode); + + SOCKET_FLOAT(offset, "Offset", 0.5f); + SOCKET_INT(offset_frequency, "Offset Frequency", 2); + SOCKET_FLOAT(squash, "Squash", 1.0f); + SOCKET_INT(squash_frequency, "Squash Frequency", 2); + + SOCKET_IN_POINT(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED); + + SOCKET_IN_COLOR(color1, "Color1", make_float3(0.0f, 0.0f, 0.0f)); + SOCKET_IN_COLOR(color2, "Color2", make_float3(0.0f, 0.0f, 0.0f)); + SOCKET_IN_COLOR(mortar, "Mortar", make_float3(0.0f, 0.0f, 0.0f)); + SOCKET_IN_FLOAT(scale, "Scale", 5.0f); + SOCKET_IN_FLOAT(mortar_size, "Mortar Size", 0.02f); + SOCKET_IN_FLOAT(bias, "Bias", 0.0f); + SOCKET_IN_FLOAT(brick_width, "Brick Width", 0.5f); + SOCKET_IN_FLOAT(row_height, "Row Height", 0.25f); - add_output("Color", SocketType::COLOR); - add_output("Fac", SocketType::FLOAT); + SOCKET_OUT_COLOR(color, "Color"); + SOCKET_OUT_FLOAT(fac, "Fac"); + + return type; +} + +BrickTextureNode::BrickTextureNode() +: TextureNode(node_type) +{ } void BrickTextureNode::compile(SVMCompiler& compiler) @@ -1295,12 +1304,12 @@ void BrickTextureNode::compile(SVMCompiler& compiler) compiler.stack_assign_if_linked(fac_out))); compiler.add_node(compiler.encode_uchar4(offset_frequency, squash_frequency), - __float_as_int(scale_in->value_float()), - __float_as_int(mortar_size_in->value_float()), - __float_as_int(bias_in->value_float())); + __float_as_int(scale), + __float_as_int(mortar_size), + __float_as_int(bias)); - compiler.add_node(__float_as_int(brick_width_in->value_float()), - __float_as_int(row_height_in->value_float()), + compiler.add_node(__float_as_int(brick_width), + __float_as_int(row_height), __float_as_int(offset), __float_as_int(squash)); @@ -1311,48 +1320,55 @@ void BrickTextureNode::compile(OSLCompiler& compiler) { tex_mapping.compile(compiler); - compiler.parameter("offset", offset); - compiler.parameter("offset_frequency", offset_frequency); - compiler.parameter("squash", squash); - compiler.parameter("squash_frequency", squash_frequency); + compiler.parameter(this, "offset"); + compiler.parameter(this, "offset_frequency"); + compiler.parameter(this, "squash"); + compiler.parameter(this, "squash_frequency"); compiler.add(this, "node_brick_texture"); } /* Point Density Texture */ -static NodeEnum point_density_space_init() +NODE_DEFINE(PointDensityTextureNode) { - NodeEnum enm; + NodeType* type = NodeType::add("point_density_texture", create, NodeType::SHADER); - enm.insert("Object", NODE_TEX_VOXEL_SPACE_OBJECT); - enm.insert("World", NODE_TEX_VOXEL_SPACE_WORLD); + SOCKET_STRING(filename, "Filename", ustring("")); - return enm; -} + static NodeEnum space_enum; + space_enum.insert("object", NODE_TEX_VOXEL_SPACE_OBJECT); + space_enum.insert("world", NODE_TEX_VOXEL_SPACE_WORLD); + SOCKET_ENUM(space, "Space", space_enum, NODE_TEX_VOXEL_SPACE_OBJECT); + + static NodeEnum interpolation_enum; + interpolation_enum.insert("closest", INTERPOLATION_CLOSEST); + interpolation_enum.insert("linear", INTERPOLATION_LINEAR); + interpolation_enum.insert("cubic", INTERPOLATION_CUBIC); + interpolation_enum.insert("smart", INTERPOLATION_SMART); + SOCKET_ENUM(interpolation, "Interpolation", interpolation_enum, INTERPOLATION_LINEAR); + + SOCKET_TRANSFORM(tfm, "Transform", transform_identity()); -NodeEnum PointDensityTextureNode::space_enum = point_density_space_init(); + SOCKET_IN_POINT(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_POSITION); + + SOCKET_OUT_FLOAT(density, "Density"); + SOCKET_OUT_COLOR(color, "Color"); + + return type; +} PointDensityTextureNode::PointDensityTextureNode() -: ShaderNode("point_density") +: ShaderNode(node_type) { image_manager = NULL; slot = -1; - filename = ""; - space = NODE_TEX_VOXEL_SPACE_OBJECT; builtin_data = NULL; - interpolation = INTERPOLATION_LINEAR; - - tfm = transform_identity(); - - add_input("Vector", SocketType::POINT, make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_POSITION); - add_output("Density", SocketType::FLOAT); - add_output("Color", SocketType::COLOR); } PointDensityTextureNode::~PointDensityTextureNode() { if(image_manager) { - image_manager->remove_image(filename, + image_manager->remove_image(filename.string(), builtin_data, interpolation, EXTENSION_CLIP); @@ -1390,7 +1406,7 @@ void PointDensityTextureNode::compile(SVMCompiler& compiler) if(use_density || use_color) { if(slot == -1) { bool is_float, is_linear; - slot = image_manager->add_image(filename, builtin_data, + slot = image_manager->add_image(filename.string(), builtin_data, false, 0, is_float, is_linear, interpolation, @@ -1442,7 +1458,7 @@ void PointDensityTextureNode::compile(OSLCompiler& compiler) if(use_density || use_color) { if(slot == -1) { bool is_float, is_linear; - slot = image_manager->add_image(filename, builtin_data, + slot = image_manager->add_image(filename.string(), builtin_data, false, 0, is_float, is_linear, interpolation, @@ -1457,33 +1473,30 @@ void PointDensityTextureNode::compile(OSLCompiler& compiler) compiler.parameter("mapping", transform_transpose(tfm)); compiler.parameter("use_mapping", 1); } - switch(interpolation) { - case INTERPOLATION_CLOSEST: - compiler.parameter("interpolation", "closest"); - break; - case INTERPOLATION_CUBIC: - compiler.parameter("interpolation", "cubic"); - break; - case INTERPOLATION_LINEAR: - default: - compiler.parameter("interpolation", "linear"); - break; - } - + compiler.parameter(this, "interpolation"); compiler.add(this, "node_voxel_texture"); } } /* Normal */ -NormalNode::NormalNode() -: ShaderNode("normal") +NODE_DEFINE(NormalNode) { - direction = make_float3(0.0f, 0.0f, 1.0f); + NodeType* type = NodeType::add("normal", create, NodeType::SHADER); + + SOCKET_VECTOR(direction, "direction", make_float3(0.0f, 0.0f, 0.0f)); - add_input("Normal", SocketType::NORMAL); - add_output("Normal", SocketType::NORMAL); - add_output("Dot", SocketType::FLOAT); + SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f)); + + SOCKET_OUT_NORMAL(normal, "Normal"); + SOCKET_OUT_FLOAT(dot, "Dot"); + + return type; +} + +NormalNode::NormalNode() +: ShaderNode(node_type) +{ } void NormalNode::compile(SVMCompiler& compiler) @@ -1504,17 +1517,27 @@ void NormalNode::compile(SVMCompiler& compiler) void NormalNode::compile(OSLCompiler& compiler) { - compiler.parameter_normal("direction", direction); + compiler.parameter(this, "direction"); compiler.add(this, "node_normal"); } /* Mapping */ +NODE_DEFINE(MappingNode) +{ + NodeType* type = NodeType::add("mapping", create, NodeType::SHADER); + + TEXTURE_MAPPING_DEFINE(MappingNode); + + SOCKET_IN_POINT(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f)); + SOCKET_OUT_POINT(vector, "Vector"); + + return type; +} + MappingNode::MappingNode() -: ShaderNode("mapping") +: ShaderNode(node_type) { - add_input("Vector", SocketType::POINT); - add_output("Vector", SocketType::POINT); } void MappingNode::compile(SVMCompiler& compiler) @@ -1538,17 +1561,25 @@ void MappingNode::compile(OSLCompiler& compiler) /* RGBToBW */ +NODE_DEFINE(RGBToBWNode) +{ + NodeType* type = NodeType::add("rgb_to_bw", create, NodeType::SHADER); + + SOCKET_IN_COLOR(color, "Color", make_float3(0.0f, 0.0f, 0.0f)); + SOCKET_OUT_FLOAT(val, "Val"); + + return type; +} + RGBToBWNode::RGBToBWNode() -: ShaderNode("rgb_to_bw") +: ShaderNode(node_type) { - add_input("Color", SocketType::COLOR); - add_output("Val", SocketType::FLOAT); } bool RGBToBWNode::constant_fold(ShaderGraph *, ShaderOutput *, ShaderInput *optimized) { - if(inputs[0]->link == NULL) { - optimized->set(linear_rgb_to_gray(inputs[0]->value())); + if(all_inputs_constant()) { + optimized->set(linear_rgb_to_gray(color)); return true; } @@ -1565,87 +1596,97 @@ void RGBToBWNode::compile(SVMCompiler& compiler) void RGBToBWNode::compile(OSLCompiler& compiler) { - compiler.add(this, "node_convert_from_color"); + compiler.add(this, "node_rgb_to_bw"); } /* Convert */ -ConvertNode::ConvertNode(SocketType::Type from_, SocketType::Type to_, bool autoconvert) -: ShaderNode("convert") +const NodeType* ConvertNode::node_types[ConvertNode::MAX_TYPE][ConvertNode::MAX_TYPE]; +bool ConvertNode::initialized = ConvertNode::register_types(); + +Node* ConvertNode::create(const NodeType *type) { - from = from_; - to = to_; + return new ConvertNode(type->inputs[0].type, type->outputs[0].type); +} - if(autoconvert) { - if(from == to) - special_type = SHADER_SPECIAL_TYPE_PROXY; - else - special_type = SHADER_SPECIAL_TYPE_AUTOCONVERT; +bool ConvertNode::register_types() +{ + const int num_types = 8; + SocketType::Type types[num_types] = {SocketType::FLOAT, + SocketType::INT, + SocketType::COLOR, + SocketType::VECTOR, + SocketType::POINT, + SocketType::NORMAL, + SocketType::STRING, + SocketType::CLOSURE}; + + for(size_t i = 0; i < num_types; i++) { + SocketType::Type from = types[i]; + ustring from_name(SocketType::type_name(from)); + ustring from_value_name("value_" + from_name.string()); + + for(size_t j = 0; j < num_types; j++) { + SocketType::Type to = types[j]; + ustring to_name(SocketType::type_name(to)); + ustring to_value_name("value_" + to_name.string()); + + string node_name = "convert_" + from_name.string() + "_to_" + to_name.string(); + NodeType* type = NodeType::add(node_name.c_str(), create, NodeType::SHADER); + + type->register_input(from_value_name, from_value_name, from, + SOCKET_OFFSETOF(ConvertNode, value_float), SocketType::zero_default_value(), + NULL, NULL, SocketType::LINKABLE); + type->register_output(to_value_name, to_value_name, to); + + assert(from < MAX_TYPE); + assert(to < MAX_TYPE); + + node_types[from][to] = type; + } } - if(from == SocketType::FLOAT) - add_input("value_float", SocketType::FLOAT); - else if(from == SocketType::INT) - add_input("value_int", SocketType::INT); - else if(from == SocketType::COLOR) - add_input("value_color", SocketType::COLOR); - else if(from == SocketType::VECTOR) - add_input("value_vector", SocketType::VECTOR); - else if(from == SocketType::POINT) - add_input("value_point", SocketType::POINT); - else if(from == SocketType::NORMAL) - add_input("value_normal", SocketType::NORMAL); - else if(from == SocketType::STRING) - add_input("value_string", SocketType::STRING); - else if(from == SocketType::CLOSURE) - add_input("value_closure", SocketType::CLOSURE); - else - assert(0); + return true; +} - if(to == SocketType::FLOAT) - add_output("value_float", SocketType::FLOAT); - else if(to == SocketType::INT) - add_output("value_int", SocketType::INT); - else if(to == SocketType::COLOR) - add_output("value_color", SocketType::COLOR); - else if(to == SocketType::VECTOR) - add_output("value_vector", SocketType::VECTOR); - else if(to == SocketType::POINT) - add_output("value_point", SocketType::POINT); - else if(to == SocketType::NORMAL) - add_output("value_normal", SocketType::NORMAL); - else if(to == SocketType::STRING) - add_output("value_string", SocketType::STRING); - else if(to == SocketType::CLOSURE) - add_output("value_closure", SocketType::CLOSURE); - else - assert(0); +ConvertNode::ConvertNode(SocketType::Type from_, SocketType::Type to_, bool autoconvert) +: ShaderNode(node_types[from_][to_]) +{ + from = from_; + to = to_; + + if(from == to) + special_type = SHADER_SPECIAL_TYPE_PROXY; + else if(autoconvert) + special_type = SHADER_SPECIAL_TYPE_AUTOCONVERT; } bool ConvertNode::constant_fold(ShaderGraph *, ShaderOutput *, ShaderInput *optimized) { - ShaderInput *in = inputs[0]; - float3 value = in->value(); + /* proxy nodes should have been removed at this point */ + assert(special_type != SHADER_SPECIAL_TYPE_PROXY); /* TODO(DingTo): conversion from/to int is not supported yet, don't fold in that case */ - if(in->link == NULL) { + if(all_inputs_constant()) { if(from == SocketType::FLOAT) { if(SocketType::is_float3(to)) { - optimized->set(make_float3(value.x, value.x, value.x)); + optimized->set(make_float3(value_float, value_float, value_float)); return true; } } else if(SocketType::is_float3(from)) { if(to == SocketType::FLOAT) { if(from == SocketType::COLOR) - optimized->set(linear_rgb_to_gray(value)); + /* color to float */ + optimized->set(linear_rgb_to_gray(value_color)); else - optimized->set(average(value)); + /* vector/point/normal to float */ + optimized->set(average(value_vector)); return true; } else if(SocketType::is_float3(to)) { - optimized->set(value); + optimized->set(value_color); return true; } } @@ -1656,8 +1697,8 @@ bool ConvertNode::constant_fold(ShaderGraph *, ShaderOutput *, ShaderInput *opti void ConvertNode::compile(SVMCompiler& compiler) { - /* constant folding should eliminate proxy nodes */ - assert(from != to); + /* proxy nodes should have been removed at this point */ + assert(special_type != SHADER_SPECIAL_TYPE_PROXY); ShaderInput *in = inputs[0]; ShaderOutput *out = outputs[0]; @@ -1703,15 +1744,15 @@ void ConvertNode::compile(SVMCompiler& compiler) else { /* set 0,0,0 value */ compiler.add_node(NODE_VALUE_V, compiler.stack_assign(out)); - compiler.add_node(NODE_VALUE_V, in->value()); + compiler.add_node(NODE_VALUE_V, value_color); } } } void ConvertNode::compile(OSLCompiler& compiler) { - /* constant folding should eliminate proxy nodes */ - assert(from != to); + /* proxy nodes should have been removed at this point */ + assert(special_type != SHADER_SPECIAL_TYPE_PROXY); if(from == SocketType::FLOAT) compiler.add(this, "node_convert_from_float"); @@ -1731,23 +1772,10 @@ void ConvertNode::compile(OSLCompiler& compiler) /* BSDF Closure */ -BsdfNode::BsdfNode(bool scattering_) -: ShaderNode("bsdf"), scattering(scattering_) +BsdfNode::BsdfNode(const NodeType *node_type) +: ShaderNode(node_type) { special_type = SHADER_SPECIAL_TYPE_CLOSURE; - - add_input("Color", SocketType::COLOR, make_float3(0.8f, 0.8f, 0.8f)); - add_input("Normal", SocketType::NORMAL, make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL); - add_input("SurfaceMixWeight", SocketType::FLOAT, 0.0f, SocketType::SVM_INTERNAL); - - if(scattering) { - closure = CLOSURE_BSSRDF_CUBIC_ID; - add_output("BSSRDF", SocketType::CLOSURE); - } - else { - closure = CLOSURE_BSDF_DIFFUSE_ID; - add_output("BSDF", SocketType::CLOSURE); - } } void BsdfNode::compile(SVMCompiler& compiler, ShaderInput *param1, ShaderInput *param2, ShaderInput *param3, ShaderInput *param4) @@ -1759,9 +1787,9 @@ void BsdfNode::compile(SVMCompiler& compiler, ShaderInput *param1, ShaderInput * if(color_in->link) compiler.add_node(NODE_CLOSURE_WEIGHT, compiler.stack_assign(color_in)); else - compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color_in->value()); + compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color); - int normal_offset = compiler.stack_assign_if_linked(normal_in); + int normal_offset = (normal_in) ? compiler.stack_assign_if_linked(normal_in) : SVM_STACK_INVALID; int tangent_offset = (tangent_in) ? compiler.stack_assign_if_linked(tangent_in) : SVM_STACK_INVALID; int param3_offset = (param3) ? compiler.stack_assign(param3) : SVM_STACK_INVALID; int param4_offset = (param4) ? compiler.stack_assign(param4) : SVM_STACK_INVALID; @@ -1771,8 +1799,8 @@ void BsdfNode::compile(SVMCompiler& compiler, ShaderInput *param1, ShaderInput * (param1)? compiler.stack_assign(param1): SVM_STACK_INVALID, (param2)? compiler.stack_assign(param2): SVM_STACK_INVALID, compiler.closure_mix_weight_offset()), - __float_as_int((param1)? param1->value_float(): 0.0f), - __float_as_int((param2)? param2->value_float(): 0.0f)); + __float_as_int((param1)? get_float(param1->socket_type): 0.0f), + __float_as_int((param2)? get_float(param2->socket_type): 0.0f)); compiler.add_node(normal_offset, tangent_offset, param3_offset, param4_offset); } @@ -1789,29 +1817,36 @@ void BsdfNode::compile(OSLCompiler& /*compiler*/) /* Anisotropic BSDF Closure */ -static NodeEnum aniso_distribution_init() +NODE_DEFINE(AnisotropicBsdfNode) { - NodeEnum enm; + NodeType* type = NodeType::add("anisotropic_bsdf", create, NodeType::SHADER); - enm.insert("Beckmann", CLOSURE_BSDF_MICROFACET_BECKMANN_ANISO_ID); - enm.insert("GGX", CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID); - enm.insert("Ashikhmin-Shirley", CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ANISO_ID); + SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f)); + SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL); + SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL); - return enm; -} + static NodeEnum distribution_enum; + distribution_enum.insert("beckmann", CLOSURE_BSDF_MICROFACET_BECKMANN_ANISO_ID); + distribution_enum.insert("GGX", CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID); + distribution_enum.insert("Multiscatter GGX", CLOSURE_BSDF_MICROFACET_MULTI_GGX_ANISO_ID); + distribution_enum.insert("ashikhmin_shirley", CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ANISO_ID); + SOCKET_ENUM(distribution, "Distribution", distribution_enum, CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID); + + SOCKET_IN_VECTOR(tangent, "Tangent", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TANGENT); + + SOCKET_IN_FLOAT(roughness, "Roughness", 0.2f); + SOCKET_IN_FLOAT(anisotropy, "Anisotropy", 0.5f); + SOCKET_IN_FLOAT(rotation, "Rotation", 0.0f); -NodeEnum AnisotropicBsdfNode::distribution_enum = aniso_distribution_init(); + SOCKET_OUT_CLOSURE(BSDF, "BSDF"); + + return type; +} AnisotropicBsdfNode::AnisotropicBsdfNode() +: BsdfNode(node_type) { closure = CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID; - distribution = CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID; - - add_input("Tangent", SocketType::VECTOR, make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TANGENT); - - add_input("Roughness", SocketType::FLOAT, 0.2f); - add_input("Anisotropy", SocketType::FLOAT, 0.5f); - add_input("Rotation", SocketType::FLOAT, 0.0f); } void AnisotropicBsdfNode::attributes(Shader *shader, AttributeRequestSet *attributes) @@ -1830,38 +1865,47 @@ void AnisotropicBsdfNode::compile(SVMCompiler& compiler) { closure = distribution; - BsdfNode::compile(compiler, input("Roughness"), input("Anisotropy"), input("Rotation")); + if(closure == CLOSURE_BSDF_MICROFACET_MULTI_GGX_ANISO_ID) + BsdfNode::compile(compiler, input("Roughness"), input("Anisotropy"), input("Rotation"), input("Color")); + else + BsdfNode::compile(compiler, input("Roughness"), input("Anisotropy"), input("Rotation")); } void AnisotropicBsdfNode::compile(OSLCompiler& compiler) { - compiler.parameter("distribution", distribution_enum[distribution]); + compiler.parameter(this, "distribution"); compiler.add(this, "node_anisotropic_bsdf"); } /* Glossy BSDF Closure */ -static NodeEnum glossy_distribution_init() +NODE_DEFINE(GlossyBsdfNode) { - NodeEnum enm; + NodeType* type = NodeType::add("glossy_bsdf", create, NodeType::SHADER); - enm.insert("Sharp", CLOSURE_BSDF_REFLECTION_ID); - enm.insert("Beckmann", CLOSURE_BSDF_MICROFACET_BECKMANN_ID); - enm.insert("GGX", CLOSURE_BSDF_MICROFACET_GGX_ID); - enm.insert("Ashikhmin-Shirley", CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID); + SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f)); + SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL); + SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL); - return enm; -} + static NodeEnum distribution_enum; + distribution_enum.insert("sharp", CLOSURE_BSDF_REFLECTION_ID); + distribution_enum.insert("beckmann", CLOSURE_BSDF_MICROFACET_BECKMANN_ID); + distribution_enum.insert("GGX", CLOSURE_BSDF_MICROFACET_GGX_ID); + distribution_enum.insert("ashikhmin_shirley", CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID); + distribution_enum.insert("Multiscatter GGX", CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID); + SOCKET_ENUM(distribution, "Distribution", distribution_enum, CLOSURE_BSDF_MICROFACET_GGX_ID); + SOCKET_IN_FLOAT(roughness, "Roughness", 0.2f); -NodeEnum GlossyBsdfNode::distribution_enum = glossy_distribution_init(); + SOCKET_OUT_CLOSURE(BSDF, "BSDF"); + + return type; +} GlossyBsdfNode::GlossyBsdfNode() +: BsdfNode(node_type) { closure = CLOSURE_BSDF_MICROFACET_GGX_ID; - distribution = CLOSURE_BSDF_MICROFACET_GGX_ID; distribution_orig = NBUILTIN_CLOSURES; - - add_input("Roughness", SocketType::FLOAT, 0.2f); } void GlossyBsdfNode::simplify_settings(Scene *scene) @@ -1875,7 +1919,7 @@ void GlossyBsdfNode::simplify_settings(Scene *scene) * Note: Keep the epsilon in sync with kernel! */ ShaderInput *roughness_input = input("Roughness"); - if(!roughness_input->link && roughness_input->value_float() <= 1e-4f) { + if(!roughness_input->link && roughness <= 1e-4f) { distribution = CLOSURE_BSDF_REFLECTION_ID; } } @@ -1889,7 +1933,7 @@ void GlossyBsdfNode::simplify_settings(Scene *scene) bool GlossyBsdfNode::has_integrator_dependency() { ShaderInput *roughness_input = input("Roughness"); - return !roughness_input->link && roughness_input->value_float() <= 1e-4f; + return !roughness_input->link && roughness <= 1e-4f; } void GlossyBsdfNode::compile(SVMCompiler& compiler) @@ -1898,39 +1942,47 @@ void GlossyBsdfNode::compile(SVMCompiler& compiler) if(closure == CLOSURE_BSDF_REFLECTION_ID) BsdfNode::compile(compiler, NULL, NULL); + else if(closure == CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID) + BsdfNode::compile(compiler, input("Roughness"), NULL, input("Color")); else BsdfNode::compile(compiler, input("Roughness"), NULL); } void GlossyBsdfNode::compile(OSLCompiler& compiler) { - compiler.parameter("distribution", distribution_enum[distribution]); + compiler.parameter(this, "distribution"); compiler.add(this, "node_glossy_bsdf"); } /* Glass BSDF Closure */ -static NodeEnum glass_distribution_init() +NODE_DEFINE(GlassBsdfNode) { - NodeEnum enm; + NodeType* type = NodeType::add("glass_bsdf", create, NodeType::SHADER); - enm.insert("Sharp", CLOSURE_BSDF_SHARP_GLASS_ID); - enm.insert("Beckmann", CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID); - enm.insert("GGX", CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID); + SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f)); + SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL); + SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL); - return enm; -} + static NodeEnum distribution_enum; + distribution_enum.insert("sharp", CLOSURE_BSDF_SHARP_GLASS_ID); + distribution_enum.insert("beckmann", CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID); + distribution_enum.insert("GGX", CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID); + distribution_enum.insert("Multiscatter GGX", CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID); + SOCKET_ENUM(distribution, "Distribution", distribution_enum, CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID); + SOCKET_IN_FLOAT(roughness, "Roughness", 0.0f); + SOCKET_IN_FLOAT(IOR, "IOR", 0.3f); + + SOCKET_OUT_CLOSURE(BSDF, "BSDF"); -NodeEnum GlassBsdfNode::distribution_enum = glass_distribution_init(); + return type; +} GlassBsdfNode::GlassBsdfNode() +: BsdfNode(node_type) { closure = CLOSURE_BSDF_SHARP_GLASS_ID; - distribution = CLOSURE_BSDF_SHARP_GLASS_ID; distribution_orig = NBUILTIN_CLOSURES; - - add_input("Roughness", SocketType::FLOAT, 0.0f); - add_input("IOR", SocketType::FLOAT, 0.3f); } void GlassBsdfNode::simplify_settings(Scene *scene) @@ -1944,7 +1996,7 @@ void GlassBsdfNode::simplify_settings(Scene *scene) * Note: Keep the epsilon in sync with kernel! */ ShaderInput *roughness_input = input("Roughness"); - if(!roughness_input->link && roughness_input->value_float() <= 1e-4f) { + if(!roughness_input->link && roughness <= 1e-4f) { distribution = CLOSURE_BSDF_SHARP_GLASS_ID; } } @@ -1958,7 +2010,7 @@ void GlassBsdfNode::simplify_settings(Scene *scene) bool GlassBsdfNode::has_integrator_dependency() { ShaderInput *roughness_input = input("Roughness"); - return !roughness_input->link && roughness_input->value_float() <= 1e-4f; + return !roughness_input->link && roughness <= 1e-4f; } void GlassBsdfNode::compile(SVMCompiler& compiler) @@ -1967,39 +2019,47 @@ void GlassBsdfNode::compile(SVMCompiler& compiler) if(closure == CLOSURE_BSDF_SHARP_GLASS_ID) BsdfNode::compile(compiler, NULL, input("IOR")); + else if(closure == CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID) + BsdfNode::compile(compiler, input("Roughness"), input("IOR"), input("Color")); else BsdfNode::compile(compiler, input("Roughness"), input("IOR")); } void GlassBsdfNode::compile(OSLCompiler& compiler) { - compiler.parameter("distribution", distribution_enum[distribution]); + compiler.parameter(this, "distribution"); compiler.add(this, "node_glass_bsdf"); } /* Refraction BSDF Closure */ -static NodeEnum refraction_distribution_init() +NODE_DEFINE(RefractionBsdfNode) { - NodeEnum enm; + NodeType* type = NodeType::add("refraction_bsdf", create, NodeType::SHADER); - enm.insert("Sharp", CLOSURE_BSDF_REFRACTION_ID); - enm.insert("Beckmann", CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID); - enm.insert("GGX", CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID); + SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f)); + SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL); + SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL); - return enm; -} + static NodeEnum distribution_enum; + distribution_enum.insert("sharp", CLOSURE_BSDF_REFRACTION_ID); + distribution_enum.insert("beckmann", CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID); + distribution_enum.insert("GGX", CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID); + SOCKET_ENUM(distribution, "Distribution", distribution_enum, CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID); + + SOCKET_IN_FLOAT(roughness, "Roughness", 0.0f); + SOCKET_IN_FLOAT(IOR, "IOR", 0.3f); -NodeEnum RefractionBsdfNode::distribution_enum = refraction_distribution_init(); + SOCKET_OUT_CLOSURE(BSDF, "BSDF"); + + return type; +} RefractionBsdfNode::RefractionBsdfNode() +: BsdfNode(node_type) { closure = CLOSURE_BSDF_REFRACTION_ID; - distribution = CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID; distribution_orig = NBUILTIN_CLOSURES; - - add_input("Roughness", SocketType::FLOAT, 0.0f); - add_input("IOR", SocketType::FLOAT, 0.3f); } void RefractionBsdfNode::simplify_settings(Scene *scene) @@ -2013,7 +2073,7 @@ void RefractionBsdfNode::simplify_settings(Scene *scene) * Note: Keep the epsilon in sync with kernel! */ ShaderInput *roughness_input = input("Roughness"); - if(!roughness_input->link && roughness_input->value_float() <= 1e-4f) { + if(!roughness_input->link && roughness <= 1e-4f) { distribution = CLOSURE_BSDF_REFRACTION_ID; } } @@ -2027,7 +2087,7 @@ void RefractionBsdfNode::simplify_settings(Scene *scene) bool RefractionBsdfNode::has_integrator_dependency() { ShaderInput *roughness_input = input("Roughness"); - return !roughness_input->link && roughness_input->value_float() <= 1e-4f; + return !roughness_input->link && roughness <= 1e-4f; } void RefractionBsdfNode::compile(SVMCompiler& compiler) @@ -2042,31 +2102,36 @@ void RefractionBsdfNode::compile(SVMCompiler& compiler) void RefractionBsdfNode::compile(OSLCompiler& compiler) { - compiler.parameter("distribution", distribution_enum[distribution]); + compiler.parameter(this, "distribution"); compiler.add(this, "node_refraction_bsdf"); } /* Toon BSDF Closure */ -static NodeEnum toon_component_init() +NODE_DEFINE(ToonBsdfNode) { - NodeEnum enm; + NodeType* type = NodeType::add("toon_bsdf", create, NodeType::SHADER); - enm.insert("Diffuse", CLOSURE_BSDF_DIFFUSE_TOON_ID); - enm.insert("Glossy", CLOSURE_BSDF_GLOSSY_TOON_ID); + SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f)); + SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL); + SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL); - return enm; -} + static NodeEnum component_enum; + component_enum.insert("diffuse", CLOSURE_BSDF_DIFFUSE_TOON_ID); + component_enum.insert("glossy", CLOSURE_BSDF_GLOSSY_TOON_ID); + SOCKET_ENUM(component, "Component", component_enum, CLOSURE_BSDF_DIFFUSE_TOON_ID); + SOCKET_IN_FLOAT(size, "Size", 0.5f); + SOCKET_IN_FLOAT(smooth, "Smooth", 0.0f); + + SOCKET_OUT_CLOSURE(BSDF, "BSDF"); -NodeEnum ToonBsdfNode::component_enum = toon_component_init(); + return type; +} ToonBsdfNode::ToonBsdfNode() +: BsdfNode(node_type) { closure = CLOSURE_BSDF_DIFFUSE_TOON_ID; - component = CLOSURE_BSDF_DIFFUSE_TOON_ID; - - add_input("Size", SocketType::FLOAT, 0.5f); - add_input("Smooth", SocketType::FLOAT, 0.0f); } void ToonBsdfNode::compile(SVMCompiler& compiler) @@ -2078,17 +2143,30 @@ void ToonBsdfNode::compile(SVMCompiler& compiler) void ToonBsdfNode::compile(OSLCompiler& compiler) { - compiler.parameter("component", component_enum[component]); + compiler.parameter(this, "component"); compiler.add(this, "node_toon_bsdf"); } /* Velvet BSDF Closure */ +NODE_DEFINE(VelvetBsdfNode) +{ + NodeType* type = NodeType::add("velvet_bsdf", create, NodeType::SHADER); + + SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f)); + SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL); + SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL); + SOCKET_IN_FLOAT(sigma, "Sigma", 1.0f); + + SOCKET_OUT_CLOSURE(BSDF, "BSDF"); + + return type; +} + VelvetBsdfNode::VelvetBsdfNode() +: BsdfNode(node_type) { closure = CLOSURE_BSDF_ASHIKHMIN_VELVET_ID; - - add_input("Sigma", SocketType::FLOAT, 1.0f); } void VelvetBsdfNode::compile(SVMCompiler& compiler) @@ -2103,10 +2181,24 @@ void VelvetBsdfNode::compile(OSLCompiler& compiler) /* Diffuse BSDF Closure */ +NODE_DEFINE(DiffuseBsdfNode) +{ + NodeType* type = NodeType::add("diffuse_bsdf", create, NodeType::SHADER); + + SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f)); + SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL); + SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL); + SOCKET_IN_FLOAT(roughness, "Roughness", 0.0f); + + SOCKET_OUT_CLOSURE(BSDF, "BSDF"); + + return type; +} + DiffuseBsdfNode::DiffuseBsdfNode() +: BsdfNode(node_type) { closure = CLOSURE_BSDF_DIFFUSE_ID; - add_input("Roughness", SocketType::FLOAT, 0.0f); } void DiffuseBsdfNode::compile(SVMCompiler& compiler) @@ -2121,7 +2213,21 @@ void DiffuseBsdfNode::compile(OSLCompiler& compiler) /* Translucent BSDF Closure */ +NODE_DEFINE(TranslucentBsdfNode) +{ + NodeType* type = NodeType::add("translucent_bsdf", create, NodeType::SHADER); + + SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f)); + SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL); + SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL); + + SOCKET_OUT_CLOSURE(BSDF, "BSDF"); + + return type; +} + TranslucentBsdfNode::TranslucentBsdfNode() +: BsdfNode(node_type) { closure = CLOSURE_BSDF_TRANSLUCENT_ID; } @@ -2138,9 +2244,21 @@ void TranslucentBsdfNode::compile(OSLCompiler& compiler) /* Transparent BSDF Closure */ +NODE_DEFINE(TransparentBsdfNode) +{ + NodeType* type = NodeType::add("transparent_bsdf", create, NodeType::SHADER); + + SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f)); + SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL); + + SOCKET_OUT_CLOSURE(BSDF, "BSDF"); + + return type; +} + TransparentBsdfNode::TransparentBsdfNode() +: BsdfNode(node_type) { - name = "transparent"; closure = CLOSURE_BSDF_TRANSPARENT_ID; } @@ -2156,29 +2274,32 @@ void TransparentBsdfNode::compile(OSLCompiler& compiler) /* Subsurface Scattering Closure */ -static NodeEnum subsurface_falloff_init() +NODE_DEFINE(SubsurfaceScatteringNode) { - NodeEnum enm; + NodeType* type = NodeType::add("subsurface_scattering", create, NodeType::SHADER); - enm.insert("Cubic", CLOSURE_BSSRDF_CUBIC_ID); - enm.insert("Gaussian", CLOSURE_BSSRDF_GAUSSIAN_ID); - enm.insert("Burley", CLOSURE_BSSRDF_BURLEY_ID); + SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f)); + SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL); + SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL); - return enm; -} + static NodeEnum falloff_enum; + falloff_enum.insert("cubic", CLOSURE_BSSRDF_CUBIC_ID); + falloff_enum.insert("gaussian", CLOSURE_BSSRDF_GAUSSIAN_ID); + falloff_enum.insert("burley", CLOSURE_BSSRDF_BURLEY_ID); + SOCKET_ENUM(falloff, "Falloff", falloff_enum, CLOSURE_BSSRDF_BURLEY_ID); + SOCKET_IN_FLOAT(scale, "Scale", 0.01f); + SOCKET_IN_VECTOR(radius, "Radius", make_float3(0.1f, 0.1f, 0.1f)); + SOCKET_IN_FLOAT(sharpness, "Sharpness", 0.0f); + SOCKET_IN_FLOAT(texture_blur, "Texture Blur", 1.0f); + + SOCKET_OUT_CLOSURE(BSSRDF, "BSSRDF"); -NodeEnum SubsurfaceScatteringNode::falloff_enum = subsurface_falloff_init(); + return type; +} SubsurfaceScatteringNode::SubsurfaceScatteringNode() -: BsdfNode(true) +: BsdfNode(node_type) { - name = "subsurface_scattering"; - falloff = CLOSURE_BSSRDF_CUBIC_ID; - - add_input("Scale", SocketType::FLOAT, 0.01f); - add_input("Radius", SocketType::VECTOR, make_float3(0.1f, 0.1f, 0.1f)); - add_input("Sharpness", SocketType::FLOAT, 0.0f); - add_input("Texture Blur", SocketType::FLOAT, 1.0f); } void SubsurfaceScatteringNode::compile(SVMCompiler& compiler) @@ -2189,7 +2310,7 @@ void SubsurfaceScatteringNode::compile(SVMCompiler& compiler) void SubsurfaceScatteringNode::compile(OSLCompiler& compiler) { - compiler.parameter("falloff", falloff_enum[closure]); + compiler.parameter(this, "falloff"); compiler.add(this, "node_subsurface_scattering"); } @@ -2202,14 +2323,22 @@ bool SubsurfaceScatteringNode::has_bssrdf_bump() /* Emissive Closure */ -EmissionNode::EmissionNode() -: ShaderNode("emission") +NODE_DEFINE(EmissionNode) { - add_input("Color", SocketType::COLOR, make_float3(0.8f, 0.8f, 0.8f)); - add_input("Strength", SocketType::FLOAT, 10.0f); - add_input("SurfaceMixWeight", SocketType::FLOAT, 0.0f, SocketType::SVM_INTERNAL); + NodeType* type = NodeType::add("emission", create, NodeType::SHADER); - add_output("Emission", SocketType::CLOSURE); + SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f)); + SOCKET_IN_FLOAT(strength, "Strength", 1.0f); + SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL); + + SOCKET_OUT_CLOSURE(emission, "Emission"); + + return type; +} + +EmissionNode::EmissionNode() +: ShaderNode(node_type) +{ } void EmissionNode::compile(SVMCompiler& compiler) @@ -2223,7 +2352,7 @@ void EmissionNode::compile(SVMCompiler& compiler) compiler.stack_assign(strength_in)); } else - compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color_in->value() * strength_in->value_float()); + compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color * strength); compiler.add_node(NODE_CLOSURE_EMISSION, compiler.closure_mix_weight_offset()); } @@ -2238,20 +2367,28 @@ bool EmissionNode::constant_fold(ShaderGraph *, ShaderOutput *, ShaderInput *) ShaderInput *color_in = input("Color"); ShaderInput *strength_in = input("Strength"); - return ((!color_in->link && color_in->value() == make_float3(0.0f, 0.0f, 0.0f)) || - (!strength_in->link && strength_in->value_float() == 0.0f)); + return ((!color_in->link && color == make_float3(0.0f, 0.0f, 0.0f)) || + (!strength_in->link && strength == 0.0f)); } /* Background Closure */ -BackgroundNode::BackgroundNode() -: ShaderNode("background") +NODE_DEFINE(BackgroundNode) { - add_input("Color", SocketType::COLOR, make_float3(0.8f, 0.8f, 0.8f)); - add_input("Strength", SocketType::FLOAT, 1.0f); - add_input("SurfaceMixWeight", SocketType::FLOAT, 0.0f, SocketType::SVM_INTERNAL); + NodeType* type = NodeType::add("background_shader", create, NodeType::SHADER); + + SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f)); + SOCKET_IN_FLOAT(strength, "Strength", 1.0f); + SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL); + + SOCKET_OUT_CLOSURE(background, "Background"); - add_output("Background", SocketType::CLOSURE); + return type; +} + +BackgroundNode::BackgroundNode() +: ShaderNode(node_type) +{ } void BackgroundNode::compile(SVMCompiler& compiler) @@ -2265,7 +2402,7 @@ void BackgroundNode::compile(SVMCompiler& compiler) compiler.stack_assign(strength_in)); } else - compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color_in->value()*strength_in->value_float()); + compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color*strength); compiler.add_node(NODE_CLOSURE_BACKGROUND, compiler.closure_mix_weight_offset()); } @@ -2280,19 +2417,27 @@ bool BackgroundNode::constant_fold(ShaderGraph *, ShaderOutput *, ShaderInput *) ShaderInput *color_in = input("Color"); ShaderInput *strength_in = input("Strength"); - return ((!color_in->link && color_in->value() == make_float3(0.0f, 0.0f, 0.0f)) || - (!strength_in->link && strength_in->value_float() == 0.0f)); + return ((!color_in->link && color == make_float3(0.0f, 0.0f, 0.0f)) || + (!strength_in->link && strength == 0.0f)); } /* Holdout Closure */ -HoldoutNode::HoldoutNode() -: ShaderNode("holdout") +NODE_DEFINE(HoldoutNode) { - add_input("SurfaceMixWeight", SocketType::FLOAT, 0.0f, SocketType::SVM_INTERNAL); - add_input("VolumeMixWeight", SocketType::FLOAT, 0.0f, SocketType::SVM_INTERNAL); + NodeType* type = NodeType::add("holdout", create, NodeType::SHADER); + + SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL); + SOCKET_IN_FLOAT(volume_mix_weight, "VolumeMixWeight", 0.0f, SocketType::SVM_INTERNAL); + + SOCKET_OUT_CLOSURE(holdout, "Holdout"); + + return type; +} - add_output("Holdout", SocketType::CLOSURE); +HoldoutNode::HoldoutNode() +: ShaderNode(node_type) +{ } void HoldoutNode::compile(SVMCompiler& compiler) @@ -2310,14 +2455,22 @@ void HoldoutNode::compile(OSLCompiler& compiler) /* Ambient Occlusion */ -AmbientOcclusionNode::AmbientOcclusionNode() -: ShaderNode("ambient_occlusion") +NODE_DEFINE(AmbientOcclusionNode) { - add_input("NormalIn", SocketType::NORMAL, make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL | SocketType::OSL_INTERNAL); - add_input("Color", SocketType::COLOR, make_float3(0.8f, 0.8f, 0.8f)); - add_input("SurfaceMixWeight", SocketType::FLOAT, 0.0f, SocketType::SVM_INTERNAL); + NodeType* type = NodeType::add("ambient_occlusion", create, NodeType::SHADER); + + SOCKET_IN_NORMAL(normal_osl, "NormalIn", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL | SocketType::OSL_INTERNAL); + SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f)); + SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL); + + SOCKET_OUT_CLOSURE(AO, "AO"); - add_output("AO", SocketType::CLOSURE); + return type; +} + +AmbientOcclusionNode::AmbientOcclusionNode() +: ShaderNode(node_type) +{ } void AmbientOcclusionNode::compile(SVMCompiler& compiler) @@ -2327,7 +2480,7 @@ void AmbientOcclusionNode::compile(SVMCompiler& compiler) if(color_in->link) compiler.add_node(NODE_CLOSURE_WEIGHT, compiler.stack_assign(color_in)); else - compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color_in->value()); + compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color); compiler.add_node(NODE_CLOSURE_AMBIENT_OCCLUSION, compiler.closure_mix_weight_offset()); } @@ -2339,16 +2492,10 @@ void AmbientOcclusionNode::compile(OSLCompiler& compiler) /* Volume Closure */ -VolumeNode::VolumeNode() -: ShaderNode("volume") +VolumeNode::VolumeNode(const NodeType *node_type) +: ShaderNode(node_type) { closure = CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID; - - add_input("Color", SocketType::COLOR, make_float3(0.8f, 0.8f, 0.8f)); - add_input("Density", SocketType::FLOAT, 1.0f); - add_input("VolumeMixWeight", SocketType::FLOAT, 0.0f, SocketType::SVM_INTERNAL); - - add_output("Volume", SocketType::CLOSURE); } void VolumeNode::compile(SVMCompiler& compiler, ShaderInput *param1, ShaderInput *param2) @@ -2358,15 +2505,15 @@ void VolumeNode::compile(SVMCompiler& compiler, ShaderInput *param1, ShaderInput if(color_in->link) compiler.add_node(NODE_CLOSURE_WEIGHT, compiler.stack_assign(color_in)); else - compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color_in->value()); + compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color); compiler.add_node(NODE_CLOSURE_VOLUME, compiler.encode_uchar4(closure, (param1)? compiler.stack_assign(param1): SVM_STACK_INVALID, (param2)? compiler.stack_assign(param2): SVM_STACK_INVALID, compiler.closure_mix_weight_offset()), - __float_as_int((param1)? param1->value_float(): 0.0f), - __float_as_int((param2)? param2->value_float(): 0.0f)); + __float_as_int((param1)? get_float(param1->socket_type): 0.0f), + __float_as_int((param2)? get_float(param2->socket_type): 0.0f)); } void VolumeNode::compile(SVMCompiler& compiler) @@ -2381,7 +2528,21 @@ void VolumeNode::compile(OSLCompiler& /*compiler*/) /* Absorption Volume Closure */ +NODE_DEFINE(AbsorptionVolumeNode) +{ + NodeType* type = NodeType::add("absorption_volume", create, NodeType::SHADER); + + SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f)); + SOCKET_IN_FLOAT(density, "Density", 1.0f); + SOCKET_IN_FLOAT(volume_mix_weight, "VolumeMixWeight", 0.0f, SocketType::SVM_INTERNAL); + + SOCKET_OUT_CLOSURE(volume, "Volume"); + + return type; +} + AbsorptionVolumeNode::AbsorptionVolumeNode() +: VolumeNode(node_type) { closure = CLOSURE_VOLUME_ABSORPTION_ID; } @@ -2398,11 +2559,24 @@ void AbsorptionVolumeNode::compile(OSLCompiler& compiler) /* Scatter Volume Closure */ +NODE_DEFINE(ScatterVolumeNode) +{ + NodeType* type = NodeType::add("scatter_volume", create, NodeType::SHADER); + + SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f)); + SOCKET_IN_FLOAT(density, "Density", 1.0f); + SOCKET_IN_FLOAT(anisotropy, "Anisotropy", 0.0f); + SOCKET_IN_FLOAT(volume_mix_weight, "VolumeMixWeight", 0.0f, SocketType::SVM_INTERNAL); + + SOCKET_OUT_CLOSURE(volume, "Volume"); + + return type; +} + ScatterVolumeNode::ScatterVolumeNode() +: VolumeNode(node_type) { closure = CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID; - - add_input("Anisotropy", SocketType::FLOAT, 0.0f); } void ScatterVolumeNode::compile(SVMCompiler& compiler) @@ -2417,27 +2591,32 @@ void ScatterVolumeNode::compile(OSLCompiler& compiler) /* Hair BSDF Closure */ -static NodeEnum hair_component_init() +NODE_DEFINE(HairBsdfNode) { - NodeEnum enm; + NodeType* type = NodeType::add("hair_bsdf", create, NodeType::SHADER); - enm.insert("Reflection", CLOSURE_BSDF_HAIR_REFLECTION_ID); - enm.insert("Transmission", CLOSURE_BSDF_HAIR_TRANSMISSION_ID); + SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f)); + SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL); + SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL); - return enm; -} + static NodeEnum component_enum; + component_enum.insert("reflection", CLOSURE_BSDF_HAIR_REFLECTION_ID); + component_enum.insert("transmission", CLOSURE_BSDF_HAIR_TRANSMISSION_ID); + SOCKET_ENUM(component, "Component", component_enum, CLOSURE_BSDF_HAIR_REFLECTION_ID); + SOCKET_IN_FLOAT(offset, "Offset", 0.0f); + SOCKET_IN_FLOAT(roughness_u, "RoughnessU", 0.2f); + SOCKET_IN_FLOAT(roughness_v, "RoughnessV", 0.2f); + SOCKET_IN_VECTOR(tangent, "Tangent", make_float3(0.0f, 0.0f, 0.0f)); -NodeEnum HairBsdfNode::component_enum = hair_component_init(); + SOCKET_OUT_CLOSURE(BSDF, "BSDF"); + + return type; +} HairBsdfNode::HairBsdfNode() +: BsdfNode(node_type) { closure = CLOSURE_BSDF_HAIR_REFLECTION_ID; - component = CLOSURE_BSDF_HAIR_REFLECTION_ID; - - add_input("Offset", SocketType::FLOAT); - add_input("RoughnessU", SocketType::FLOAT); - add_input("RoughnessV", SocketType::FLOAT); - add_input("Tangent", SocketType::VECTOR); } void HairBsdfNode::compile(SVMCompiler& compiler) @@ -2449,27 +2628,34 @@ void HairBsdfNode::compile(SVMCompiler& compiler) void HairBsdfNode::compile(OSLCompiler& compiler) { - compiler.parameter("component", component_enum[component]); - + compiler.parameter(this, "component"); compiler.add(this, "node_hair_bsdf"); } /* Geometry */ +NODE_DEFINE(GeometryNode) +{ + NodeType* type = NodeType::add("geometry", create, NodeType::SHADER); + + SOCKET_IN_NORMAL(normal_osl, "NormalIn", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL | SocketType::OSL_INTERNAL); + + SOCKET_OUT_POINT(position, "Position"); + SOCKET_OUT_NORMAL(normal, "Normal"); + SOCKET_OUT_NORMAL(tangent, "Tangent"); + SOCKET_OUT_NORMAL(true_normal, "True Normal"); + SOCKET_OUT_VECTOR(incoming, "Incoming"); + SOCKET_OUT_POINT(parametric, "Parametric"); + SOCKET_OUT_FLOAT(backfacing, "Backfacing"); + SOCKET_OUT_FLOAT(pointiness, "Pointiness"); + + return type; +} + GeometryNode::GeometryNode() -: ShaderNode("geometry") +: ShaderNode(node_type) { special_type = SHADER_SPECIAL_TYPE_GEOMETRY; - - add_input("NormalIn", SocketType::NORMAL, make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL | SocketType::OSL_INTERNAL); - add_output("Position", SocketType::POINT); - add_output("Normal", SocketType::NORMAL); - add_output("Tangent", SocketType::NORMAL); - add_output("True Normal", SocketType::NORMAL); - add_output("Incoming", SocketType::VECTOR); - add_output("Parametric", SocketType::POINT); - add_output("Backfacing", SocketType::FLOAT); - add_output("Pointiness", SocketType::FLOAT); } void GeometryNode::attributes(Shader *shader, AttributeRequestSet *attributes) @@ -2564,21 +2750,30 @@ void GeometryNode::compile(OSLCompiler& compiler) /* TextureCoordinate */ -TextureCoordinateNode::TextureCoordinateNode() -: ShaderNode("texture_coordinate") +NODE_DEFINE(TextureCoordinateNode) { - add_input("NormalIn", SocketType::NORMAL, make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL | SocketType::OSL_INTERNAL); - add_output("Generated", SocketType::POINT); - add_output("Normal", SocketType::NORMAL); - add_output("UV", SocketType::POINT); - add_output("Object", SocketType::POINT); - add_output("Camera", SocketType::POINT); - add_output("Window", SocketType::POINT); - add_output("Reflection", SocketType::NORMAL); + NodeType* type = NodeType::add("texture_coordinate", create, NodeType::SHADER); + + SOCKET_BOOLEAN(from_dupli, "From Dupli", false); + SOCKET_BOOLEAN(use_transform, "Use Transform", false); + SOCKET_TRANSFORM(ob_tfm, "Object Transform", transform_identity()); + + SOCKET_IN_NORMAL(normal_osl, "NormalIn", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL | SocketType::OSL_INTERNAL); + + SOCKET_OUT_POINT(generated, "Generated"); + SOCKET_OUT_NORMAL(normal, "Normal"); + SOCKET_OUT_POINT(UV, "UV"); + SOCKET_OUT_POINT(object, "Object"); + SOCKET_OUT_POINT(camera, "Camera"); + SOCKET_OUT_POINT(window, "Window"); + SOCKET_OUT_NORMAL(reflection, "Reflection"); - from_dupli = false; - use_transform = false; - ob_tfm = transform_identity(); + return type; +} + +TextureCoordinateNode::TextureCoordinateNode() +: ShaderNode(node_type) +{ } void TextureCoordinateNode::attributes(Shader *shader, AttributeRequestSet *attributes) @@ -2702,22 +2897,32 @@ void TextureCoordinateNode::compile(OSLCompiler& compiler) compiler.parameter("is_background", true); if(compiler.output_type() == SHADER_TYPE_VOLUME) compiler.parameter("is_volume", true); - compiler.parameter("use_transform", use_transform); + compiler.parameter(this, "use_transform"); Transform ob_itfm = transform_transpose(transform_inverse(ob_tfm)); compiler.parameter("object_itfm", ob_itfm); - compiler.parameter("from_dupli", from_dupli); + compiler.parameter(this, "from_dupli"); compiler.add(this, "node_texture_coordinate"); } -UVMapNode::UVMapNode() -: ShaderNode("uvmap") +/* UV Map */ + +NODE_DEFINE(UVMapNode) { - attribute = ""; - from_dupli = false; + NodeType* type = NodeType::add("uvmap", create, NodeType::SHADER); + + SOCKET_IN_STRING(attribute, "attribute", ustring("")); + SOCKET_IN_BOOLEAN(from_dupli, "from dupli", false); + + SOCKET_OUT_POINT(UV, "UV"); - add_output("UV", SocketType::POINT); + return type; +} + +UVMapNode::UVMapNode() +: ShaderNode(node_type) +{ } void UVMapNode::attributes(Shader *shader, AttributeRequestSet *attributes) @@ -2776,28 +2981,36 @@ void UVMapNode::compile(OSLCompiler& compiler) else compiler.parameter("bump_offset", "center"); - compiler.parameter("from_dupli", from_dupli); - compiler.parameter("name", attribute.c_str()); + compiler.parameter(this, "from_dupli"); + compiler.parameter(this, "attribute"); compiler.add(this, "node_uv_map"); } /* Light Path */ +NODE_DEFINE(LightPathNode) +{ + NodeType* type = NodeType::add("light_path", create, NodeType::SHADER); + + SOCKET_OUT_FLOAT(is_camera_ray, "Is Camera Ray"); + SOCKET_OUT_FLOAT(is_shadow_ray, "Is Shadow Ray"); + SOCKET_OUT_FLOAT(is_diffuse_ray, "Is Diffuse Ray"); + SOCKET_OUT_FLOAT(is_glossy_ray, "Is Glossy Ray"); + SOCKET_OUT_FLOAT(is_singular_ray, "Is Singular Ray"); + SOCKET_OUT_FLOAT(is_reflection_ray, "Is Reflection Ray"); + SOCKET_OUT_FLOAT(is_transmission_ray, "Is Transmission Ray"); + SOCKET_OUT_FLOAT(is_volume_scatter_ray, "Is Volume Scatter Ray"); + SOCKET_OUT_FLOAT(ray_length, "Ray Length"); + SOCKET_OUT_FLOAT(ray_depth, "Ray Depth"); + SOCKET_OUT_FLOAT(transparent_depth, "Transparent Depth"); + SOCKET_OUT_FLOAT(transmission_depth, "Transmission Depth"); + + return type; +} + LightPathNode::LightPathNode() -: ShaderNode("light_path") -{ - add_output("Is Camera Ray", SocketType::FLOAT); - add_output("Is Shadow Ray", SocketType::FLOAT); - add_output("Is Diffuse Ray", SocketType::FLOAT); - add_output("Is Glossy Ray", SocketType::FLOAT); - add_output("Is Singular Ray", SocketType::FLOAT); - add_output("Is Reflection Ray", SocketType::FLOAT); - add_output("Is Transmission Ray", SocketType::FLOAT); - add_output("Is Volume Scatter Ray", SocketType::FLOAT); - add_output("Ray Length", SocketType::FLOAT); - add_output("Ray Depth", SocketType::FLOAT); - add_output("Transparent Depth", SocketType::FLOAT); - add_output("Transmission Depth", SocketType::FLOAT); +: ShaderNode(node_type) +{ } void LightPathNode::compile(SVMCompiler& compiler) @@ -2873,14 +3086,23 @@ void LightPathNode::compile(OSLCompiler& compiler) /* Light Falloff */ +NODE_DEFINE(LightFalloffNode) +{ + NodeType* type = NodeType::add("light_fallof", create, NodeType::SHADER); + + SOCKET_IN_FLOAT(strength, "Strength", 100.0f); + SOCKET_IN_FLOAT(smooth, "Smooth", 0.0f); + + SOCKET_OUT_FLOAT(quadratic, "Quadratic"); + SOCKET_OUT_FLOAT(linear, "Linear"); + SOCKET_OUT_FLOAT(constant, "Constant"); + + return type; +} + LightFalloffNode::LightFalloffNode() -: ShaderNode("light_fallof") +: ShaderNode(node_type) { - add_input("Strength", SocketType::FLOAT, 100.0f); - add_input("Smooth", SocketType::FLOAT, 0.0f); - add_output("Quadratic", SocketType::FLOAT); - add_output("Linear", SocketType::FLOAT); - add_output("Constant", SocketType::FLOAT); } void LightFalloffNode::compile(SVMCompiler& compiler) @@ -2923,13 +3145,21 @@ void LightFalloffNode::compile(OSLCompiler& compiler) /* Object Info */ +NODE_DEFINE(ObjectInfoNode) +{ + NodeType* type = NodeType::add("object_info", create, NodeType::SHADER); + + SOCKET_OUT_VECTOR(location, "Location"); + SOCKET_OUT_FLOAT(object_index, "Object Index"); + SOCKET_OUT_FLOAT(material_index, "Material Index"); + SOCKET_OUT_FLOAT(random, "Random"); + + return type; +} + ObjectInfoNode::ObjectInfoNode() -: ShaderNode("object_info") +: ShaderNode(node_type) { - add_output("Location", SocketType::VECTOR); - add_output("Object Index", SocketType::FLOAT); - add_output("Material Index", SocketType::FLOAT); - add_output("Random", SocketType::FLOAT); } void ObjectInfoNode::compile(SVMCompiler& compiler) @@ -2962,19 +3192,27 @@ void ObjectInfoNode::compile(OSLCompiler& compiler) /* Particle Info */ -ParticleInfoNode::ParticleInfoNode() -: ShaderNode("particle_info") +NODE_DEFINE(ParticleInfoNode) { - add_output("Index", SocketType::FLOAT); - add_output("Age", SocketType::FLOAT); - add_output("Lifetime", SocketType::FLOAT); - add_output("Location", SocketType::POINT); + NodeType* type = NodeType::add("particle_info", create, NodeType::SHADER); + + SOCKET_OUT_FLOAT(index, "Index"); + SOCKET_OUT_FLOAT(age, "Age"); + SOCKET_OUT_FLOAT(lifetime, "Lifetime"); + SOCKET_OUT_POINT(location, "Location"); #if 0 /* not yet supported */ - add_output("Rotation", SHADER_SOCKET_QUATERNION); + SOCKET_OUT_QUATERNION(rotation, "Rotation"); #endif - add_output("Size", SocketType::FLOAT); - add_output("Velocity", SocketType::VECTOR); - add_output("Angular Velocity", SocketType::VECTOR); + SOCKET_OUT_FLOAT(size, "Size"); + SOCKET_OUT_VECTOR(velocity, "Velocity"); + SOCKET_OUT_VECTOR(angular_velocity, "Angular Velocity"); + + return type; +} + +ParticleInfoNode::ParticleInfoNode() +: ShaderNode(node_type) +{ } void ParticleInfoNode::attributes(Shader *shader, AttributeRequestSet *attributes) @@ -3056,15 +3294,24 @@ void ParticleInfoNode::compile(OSLCompiler& compiler) /* Hair Info */ +NODE_DEFINE(HairInfoNode) +{ + NodeType* type = NodeType::add("hair_info", create, NodeType::SHADER); + + SOCKET_OUT_FLOAT(is_strand, "Is Strand"); + SOCKET_OUT_FLOAT(intercept, "Intercept"); + SOCKET_OUT_FLOAT(thickness, "Thickness"); + SOCKET_OUT_NORMAL(tangent Normal, "Tangent Normal"); +#if 0 /*output for minimum hair width transparency - deactivated */ + SOCKET_OUT_FLOAT(fade, "Fade"); +#endif + + return type; +} + HairInfoNode::HairInfoNode() -: ShaderNode("hair_info") +: ShaderNode(node_type) { - add_output("Is Strand", SocketType::FLOAT); - add_output("Intercept", SocketType::FLOAT); - add_output("Thickness", SocketType::FLOAT); - add_output("Tangent Normal", SocketType::NORMAL); - /*output for minimum hair width transparency - deactivated*/ - /*add_output("Fade", SocketType::FLOAT);*/ } void HairInfoNode::attributes(Shader *shader, AttributeRequestSet *attributes) @@ -3118,12 +3365,19 @@ void HairInfoNode::compile(OSLCompiler& compiler) /* Value */ -ValueNode::ValueNode() -: ShaderNode("value") +NODE_DEFINE(ValueNode) { - value = 0.0f; + NodeType* type = NodeType::add("value", create, NodeType::SHADER); - add_output("Value", SocketType::FLOAT); + SOCKET_FLOAT(value, "Value", 0.0f); + SOCKET_OUT_FLOAT(value, "Value"); + + return type; +} + +ValueNode::ValueNode() +: ShaderNode(node_type) +{ } bool ValueNode::constant_fold(ShaderGraph *, ShaderOutput *, ShaderInput *optimized) @@ -3147,12 +3401,19 @@ void ValueNode::compile(OSLCompiler& compiler) /* Color */ -ColorNode::ColorNode() -: ShaderNode("color") +NODE_DEFINE(ColorNode) { - value = make_float3(0.0f, 0.0f, 0.0f); + NodeType* type = NodeType::add("color", create, NodeType::SHADER); + + SOCKET_COLOR(value, "Value", make_float3(0.0f, 0.0f, 0.0f)); + SOCKET_OUT_COLOR(color, "Color"); + + return type; +} - add_output("Color", SocketType::COLOR); +ColorNode::ColorNode() +: ShaderNode(node_type) +{ } bool ColorNode::constant_fold(ShaderGraph *, ShaderOutput *, ShaderInput *optimized) @@ -3180,14 +3441,21 @@ void ColorNode::compile(OSLCompiler& compiler) /* Add Closure */ +NODE_DEFINE(AddClosureNode) +{ + NodeType* type = NodeType::add("add_closure", create, NodeType::SHADER); + + SOCKET_IN_CLOSURE(closure1, "Closure1"); + SOCKET_IN_CLOSURE(closure2, "Closure2"); + SOCKET_OUT_CLOSURE(closure, "Closure"); + + return type; +} + AddClosureNode::AddClosureNode() -: ShaderNode("add_closure") +: ShaderNode(node_type) { special_type = SHADER_SPECIAL_TYPE_COMBINE_CLOSURE; - - add_input("Closure1", SocketType::CLOSURE); - add_input("Closure2", SocketType::CLOSURE); - add_output("Closure", SocketType::CLOSURE); } void AddClosureNode::compile(SVMCompiler& /*compiler*/) @@ -3202,15 +3470,23 @@ void AddClosureNode::compile(OSLCompiler& compiler) /* Mix Closure */ +NODE_DEFINE(MixClosureNode) +{ + NodeType* type = NodeType::add("mix_closure", create, NodeType::SHADER); + + SOCKET_IN_FLOAT(fac, "Fac", 0.5f); + SOCKET_IN_CLOSURE(closure1, "Closure1"); + SOCKET_IN_CLOSURE(closure2, "Closure2"); + + SOCKET_OUT_CLOSURE(closure, "Closure"); + + return type; +} + MixClosureNode::MixClosureNode() -: ShaderNode("mix_closure") +: ShaderNode(node_type) { special_type = SHADER_SPECIAL_TYPE_COMBINE_CLOSURE; - - add_input("Fac", SocketType::FLOAT, 0.5f); - add_input("Closure1", SocketType::CLOSURE); - add_input("Closure2", SocketType::CLOSURE); - add_output("Closure", SocketType::CLOSURE); } void MixClosureNode::compile(SVMCompiler& /*compiler*/) @@ -3240,12 +3516,12 @@ bool MixClosureNode::constant_fold(ShaderGraph *graph, ShaderOutput *, ShaderInp /* check for closure links and make sure factor link is disconnected */ if(closure1_in->link && closure2_in->link && !fac_in->link) { /* factor 0.0 */ - if(fac_in->value_float() == 0.0f) { + if(fac == 0.0f) { graph->relink(this, closure_out, closure1_in->link); return true; } /* factor 1.0 */ - else if(fac_in->value_float() == 1.0f) { + else if(fac == 1.0f) { graph->relink(this, closure_out, closure2_in->link); return true; } @@ -3256,13 +3532,22 @@ bool MixClosureNode::constant_fold(ShaderGraph *graph, ShaderOutput *, ShaderInp /* Mix Closure */ +NODE_DEFINE(MixClosureWeightNode) +{ + NodeType* type = NodeType::add("mix_closure_weight", create, NodeType::SHADER); + + SOCKET_IN_FLOAT(weight, "Weight", 1.0f); + SOCKET_IN_FLOAT(fac, "Fac", 1.0f); + + SOCKET_OUT_FLOAT(weight1, "Weight1"); + SOCKET_OUT_FLOAT(weight2, "Weight2"); + + return type; +} + MixClosureWeightNode::MixClosureWeightNode() -: ShaderNode("mix_closure_weight") +: ShaderNode(node_type) { - add_input("Weight", SocketType::FLOAT, 1.0f); - add_input("Fac", SocketType::FLOAT, 1.0f); - add_output("Weight1", SocketType::FLOAT); - add_output("Weight2", SocketType::FLOAT); } void MixClosureWeightNode::compile(SVMCompiler& compiler) @@ -3287,12 +3572,43 @@ void MixClosureWeightNode::compile(OSLCompiler& /*compiler*/) /* Invert */ +NODE_DEFINE(InvertNode) +{ + NodeType* type = NodeType::add("invert", create, NodeType::SHADER); + + SOCKET_IN_FLOAT(fac, "Fac", 1.0f); + SOCKET_IN_COLOR(color, "Color", make_float3(0.0f, 0.0f, 0.0f)); + + SOCKET_OUT_COLOR(color, "Color"); + + return type; +} + InvertNode::InvertNode() -: ShaderNode("invert") +: ShaderNode(node_type) { - add_input("Fac", SocketType::FLOAT, 1.0f); - add_input("Color", SocketType::COLOR); - add_output("Color", SocketType::COLOR); +} + +bool InvertNode::constant_fold(ShaderGraph *graph, ShaderOutput *, ShaderInput *optimized) +{ + ShaderInput *fac_in = input("Fac"); + ShaderInput *color_in = input("Color"); + ShaderOutput *color_out = output("Color"); + + if(!fac_in->link) { + /* evaluate fully constant node */ + if(!color_in->link) { + optimized->set(interp(color, make_float3(1.0f, 1.0f, 1.0f) - color, fac)); + return true; + } + /* remove no-op node */ + else if(fac == 0.0f) { + graph->relink(this, color_out, color_in->link); + return true; + } + } + + return false; } void InvertNode::compile(SVMCompiler& compiler) @@ -3314,46 +3630,46 @@ void InvertNode::compile(OSLCompiler& compiler) /* Mix */ -MixNode::MixNode() -: ShaderNode("mix") +NODE_DEFINE(MixNode) { - type = NODE_MIX_BLEND; + NodeType* type = NodeType::add("mix", create, NodeType::SHADER); - use_clamp = false; + static NodeEnum type_enum; + type_enum.insert("mix", NODE_MIX_BLEND); + type_enum.insert("add", NODE_MIX_ADD); + type_enum.insert("multiply", NODE_MIX_MUL); + type_enum.insert("screen", NODE_MIX_SCREEN); + type_enum.insert("overlay", NODE_MIX_OVERLAY); + type_enum.insert("subtract", NODE_MIX_SUB); + type_enum.insert("divide", NODE_MIX_DIV); + type_enum.insert("difference", NODE_MIX_DIFF); + type_enum.insert("darken", NODE_MIX_DARK); + type_enum.insert("lighten", NODE_MIX_LIGHT); + type_enum.insert("dodge", NODE_MIX_DODGE); + type_enum.insert("burn", NODE_MIX_BURN); + type_enum.insert("hue", NODE_MIX_HUE); + type_enum.insert("saturation", NODE_MIX_SAT); + type_enum.insert("value", NODE_MIX_VAL); + type_enum.insert("color", NODE_MIX_COLOR); + type_enum.insert("soft_light", NODE_MIX_SOFT); + type_enum.insert("linear_light", NODE_MIX_LINEAR); + SOCKET_ENUM(type, "Type", type_enum, NODE_MIX_BLEND); - add_input("Fac", SocketType::FLOAT, 0.5f); - add_input("Color1", SocketType::COLOR); - add_input("Color2", SocketType::COLOR); - add_output("Color", SocketType::COLOR); -} + SOCKET_BOOLEAN(use_clamp, "Use Clamp", false); -static NodeEnum mix_type_init() -{ - NodeEnum enm; + SOCKET_IN_FLOAT(fac, "Fac", 0.5f); + SOCKET_IN_COLOR(color1, "Color1", make_float3(0.0f, 0.0f, 0.0f)); + SOCKET_IN_COLOR(color2, "Color2", make_float3(0.0f, 0.0f, 0.0f)); - enm.insert("Mix", NODE_MIX_BLEND); - enm.insert("Add", NODE_MIX_ADD); - enm.insert("Multiply", NODE_MIX_MUL); - enm.insert("Screen", NODE_MIX_SCREEN); - enm.insert("Overlay", NODE_MIX_OVERLAY); - enm.insert("Subtract", NODE_MIX_SUB); - enm.insert("Divide", NODE_MIX_DIV); - enm.insert("Difference", NODE_MIX_DIFF); - enm.insert("Darken", NODE_MIX_DARK); - enm.insert("Lighten", NODE_MIX_LIGHT); - enm.insert("Dodge", NODE_MIX_DODGE); - enm.insert("Burn", NODE_MIX_BURN); - enm.insert("Hue", NODE_MIX_HUE); - enm.insert("Saturation", NODE_MIX_SAT); - enm.insert("Value", NODE_MIX_VAL); - enm.insert("Color", NODE_MIX_COLOR); - enm.insert("Soft Light", NODE_MIX_SOFT); - enm.insert("Linear Light", NODE_MIX_LINEAR); + SOCKET_OUT_COLOR(color, "Color"); - return enm; + return type; } -NodeEnum MixNode::type_enum = mix_type_init(); +MixNode::MixNode() +: ShaderNode(node_type) +{ +} void MixNode::compile(SVMCompiler& compiler) { @@ -3376,44 +3692,61 @@ void MixNode::compile(SVMCompiler& compiler) void MixNode::compile(OSLCompiler& compiler) { - compiler.parameter("type", type_enum[type]); - compiler.parameter("use_clamp", use_clamp); + compiler.parameter(this, "type"); + compiler.parameter(this, "use_clamp"); compiler.add(this, "node_mix"); } bool MixNode::constant_fold(ShaderGraph *graph, ShaderOutput *, ShaderInput *optimized) { - if(type != NODE_MIX_BLEND) { - return false; - } - ShaderInput *fac_in = input("Fac"); ShaderInput *color1_in = input("Color1"); ShaderInput *color2_in = input("Color2"); ShaderOutput *color_out = output("Color"); + /* evaluate fully constant node */ + if(all_inputs_constant()) { + float3 result = svm_mix(type, fac, color1, color2); + optimized->set(use_clamp ? svm_mix_clamp(result) : result); + return true; + } + + /* remove no-op node when factor is 0.0 */ + if(!fac_in->link && fac <= 0.0f) { + /* note that some of the modes will clamp out of bounds values even without use_clamp */ + if(!color1_in->link) { + float3 result = svm_mix(type, 0.0f, color1, color1); + optimized->set(use_clamp ? svm_mix_clamp(result) : result); + return true; + } + else if(!use_clamp && type != NODE_MIX_LIGHT && type != NODE_MIX_DODGE && type != NODE_MIX_BURN) { + graph->relink(this, color_out, color1_in->link); + return true; + } + } + + if(type != NODE_MIX_BLEND) { + return false; + } + /* remove useless mix colors nodes */ - if(color1_in->link && color1_in->link == color2_in->link) { + if(color1_in->link && color1_in->link == color2_in->link && !use_clamp) { graph->relink(this, color_out, color1_in->link); return true; } + if(!color1_in->link && !color2_in->link && color1 == color2) { + optimized->set(use_clamp ? svm_mix_clamp(color1) : color1); + return true; + } - /* remove unused mix color input when factor is 0.0 or 1.0 */ - if(!fac_in->link) { - /* factor 0.0 */ - if(fac_in->value_float() == 0.0f) { - if(color1_in->link) - graph->relink(this, color_out, color1_in->link); - else - optimized->set(color1_in->value()); + /* remove no-op mix color node when factor is 1.0 */ + if(!fac_in->link && fac >= 1.0f) { + if(!color2_in->link) { + optimized->set(use_clamp ? svm_mix_clamp(color2) : color2); return true; } - /* factor 1.0 */ - else if(fac_in->value_float() == 1.0f) { - if(color2_in->link) - graph->relink(this, color_out, color2_in->link); - else - optimized->set(color2_in->value()); + else if(!use_clamp) { + graph->relink(this, color_out, color2_in->link); return true; } } @@ -3422,13 +3755,33 @@ bool MixNode::constant_fold(ShaderGraph *graph, ShaderOutput *, ShaderInput *opt } /* Combine RGB */ + +NODE_DEFINE(CombineRGBNode) +{ + NodeType* type = NodeType::add("combine_rgb", create, NodeType::SHADER); + + SOCKET_IN_FLOAT(r, "R", 0.0f); + SOCKET_IN_FLOAT(g, "G", 0.0f); + SOCKET_IN_FLOAT(b, "B", 0.0f); + + SOCKET_OUT_COLOR(image, "Image"); + + return type; +} + CombineRGBNode::CombineRGBNode() -: ShaderNode("combine_rgb") +: ShaderNode(node_type) { - add_input("R", SocketType::FLOAT); - add_input("G", SocketType::FLOAT); - add_input("B", SocketType::FLOAT); - add_output("Image", SocketType::COLOR); +} + +bool CombineRGBNode::constant_fold(ShaderGraph *, ShaderOutput *, ShaderInput *optimized) +{ + if(all_inputs_constant()) { + optimized->set(make_float3(r, g, b)); + return true; + } + + return false; } void CombineRGBNode::compile(SVMCompiler& compiler) @@ -3457,13 +3810,33 @@ void CombineRGBNode::compile(OSLCompiler& compiler) } /* Combine XYZ */ + +NODE_DEFINE(CombineXYZNode) +{ + NodeType* type = NodeType::add("combine_xyz", create, NodeType::SHADER); + + SOCKET_IN_FLOAT(x, "X", 0.0f); + SOCKET_IN_FLOAT(y, "Y", 0.0f); + SOCKET_IN_FLOAT(z, "Z", 0.0f); + + SOCKET_OUT_VECTOR(vector, "Vector"); + + return type; +} + CombineXYZNode::CombineXYZNode() -: ShaderNode("combine_xyz") +: ShaderNode(node_type) +{ +} + +bool CombineXYZNode::constant_fold(ShaderGraph *, ShaderOutput *, ShaderInput *optimized) { - add_input("X", SocketType::FLOAT); - add_input("Y", SocketType::FLOAT); - add_input("Z", SocketType::FLOAT); - add_output("Vector", SocketType::VECTOR); + if(all_inputs_constant()) { + optimized->set(make_float3(x, y, z)); + return true; + } + + return false; } void CombineXYZNode::compile(SVMCompiler& compiler) @@ -3492,13 +3865,33 @@ void CombineXYZNode::compile(OSLCompiler& compiler) } /* Combine HSV */ + +NODE_DEFINE(CombineHSVNode) +{ + NodeType* type = NodeType::add("combine_hsv", create, NodeType::SHADER); + + SOCKET_IN_FLOAT(h, "H", 0.0f); + SOCKET_IN_FLOAT(s, "S", 0.0f); + SOCKET_IN_FLOAT(v, "V", 0.0f); + + SOCKET_OUT_COLOR(color, "Color"); + + return type; +} + CombineHSVNode::CombineHSVNode() -: ShaderNode("combine_hsv") +: ShaderNode(node_type) { - add_input("H", SocketType::FLOAT); - add_input("S", SocketType::FLOAT); - add_input("V", SocketType::FLOAT); - add_output("Color", SocketType::COLOR); +} + +bool CombineHSVNode::constant_fold(ShaderGraph *, ShaderOutput *, ShaderInput *optimized) +{ + if(all_inputs_constant()) { + optimized->set(hsv_to_rgb(make_float3(h, s, v))); + return true; + } + + return false; } void CombineHSVNode::compile(SVMCompiler& compiler) @@ -3522,25 +3915,28 @@ void CombineHSVNode::compile(OSLCompiler& compiler) } /* Gamma */ -GammaNode::GammaNode() -: ShaderNode("gamma") + +NODE_DEFINE(GammaNode) { - add_input("Color", SocketType::COLOR); - add_input("Gamma", SocketType::FLOAT); - add_output("Color", SocketType::COLOR); + NodeType* type = NodeType::add("gamma", create, NodeType::SHADER); + + SOCKET_IN_COLOR(color, "Color", make_float3(0.0f, 0.0f, 0.0f)); + SOCKET_IN_FLOAT(gamma, "Gamma", 1.0f); + SOCKET_OUT_COLOR(color, "Color"); + + return type; } -bool GammaNode::constant_fold(ShaderGraph *, ShaderOutput *socket, ShaderInput *optimized) +GammaNode::GammaNode() +: ShaderNode(node_type) { - ShaderInput *color_in = input("Color"); - ShaderInput *gamma_in = input("Gamma"); +} - if(socket == output("Color")) { - if(color_in->link == NULL && gamma_in->link == NULL) { - optimized->set(svm_math_gamma_color(color_in->value(), - gamma_in->value_float())); - return true; - } +bool GammaNode::constant_fold(ShaderGraph *, ShaderOutput *, ShaderInput *optimized) +{ + if(all_inputs_constant()) { + optimized->set(svm_math_gamma_color(color, gamma)); + return true; } return false; @@ -3564,13 +3960,33 @@ void GammaNode::compile(OSLCompiler& compiler) } /* Bright Contrast */ + +NODE_DEFINE(BrightContrastNode) +{ + NodeType* type = NodeType::add("brightness_contrast", create, NodeType::SHADER); + + SOCKET_IN_COLOR(color, "Color", make_float3(0.0f, 0.0f, 0.0f)); + SOCKET_IN_FLOAT(bright, "Bright", 0.0f); + SOCKET_IN_FLOAT(contrast, "Contrast", 0.0f); + + SOCKET_OUT_COLOR(color, "Color"); + + return type; +} + BrightContrastNode::BrightContrastNode() -: ShaderNode("brightness") +: ShaderNode(node_type) { - add_input("Color", SocketType::COLOR); - add_input("Bright", SocketType::FLOAT); - add_input("Contrast", SocketType::FLOAT); - add_output("Color", SocketType::COLOR); +} + +bool BrightContrastNode::constant_fold(ShaderGraph *, ShaderOutput *, ShaderInput *optimized) +{ + if(all_inputs_constant()) { + optimized->set(svm_brightness_contrast(color, bright, contrast)); + return true; + } + + return false; } void BrightContrastNode::compile(SVMCompiler& compiler) @@ -3594,13 +4010,37 @@ void BrightContrastNode::compile(OSLCompiler& compiler) } /* Separate RGB */ + +NODE_DEFINE(SeparateRGBNode) +{ + NodeType* type = NodeType::add("separate_rgb", create, NodeType::SHADER); + + SOCKET_IN_COLOR(color, "Image", make_float3(0.0f, 0.0f, 0.0f)); + + SOCKET_OUT_FLOAT(g, "R"); + SOCKET_OUT_FLOAT(g, "G"); + SOCKET_OUT_FLOAT(b, "B"); + + return type; +} + SeparateRGBNode::SeparateRGBNode() -: ShaderNode("separate_rgb") +: ShaderNode(node_type) { - add_input("Image", SocketType::COLOR); - add_output("R", SocketType::FLOAT); - add_output("G", SocketType::FLOAT); - add_output("B", SocketType::FLOAT); +} + +bool SeparateRGBNode::constant_fold(ShaderGraph *, ShaderOutput *socket, ShaderInput *optimized) +{ + if(all_inputs_constant()) { + for(int channel = 0; channel < 3; channel++) { + if(outputs[channel] == socket) { + optimized->set(color[channel]); + return true; + } + } + } + + return false; } void SeparateRGBNode::compile(SVMCompiler& compiler) @@ -3629,13 +4069,37 @@ void SeparateRGBNode::compile(OSLCompiler& compiler) } /* Separate XYZ */ + +NODE_DEFINE(SeparateXYZNode) +{ + NodeType* type = NodeType::add("separate_xyz", create, NodeType::SHADER); + + SOCKET_IN_COLOR(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f)); + + SOCKET_OUT_FLOAT(x, "X"); + SOCKET_OUT_FLOAT(y, "Y"); + SOCKET_OUT_FLOAT(z, "Z"); + + return type; +} + SeparateXYZNode::SeparateXYZNode() -: ShaderNode("separate_xyz") +: ShaderNode(node_type) +{ +} + +bool SeparateXYZNode::constant_fold(ShaderGraph *, ShaderOutput *socket, ShaderInput *optimized) { - add_input("Vector", SocketType::VECTOR); - add_output("X", SocketType::FLOAT); - add_output("Y", SocketType::FLOAT); - add_output("Z", SocketType::FLOAT); + if(all_inputs_constant()) { + for(int channel = 0; channel < 3; channel++) { + if(outputs[channel] == socket) { + optimized->set(vector[channel]); + return true; + } + } + } + + return false; } void SeparateXYZNode::compile(SVMCompiler& compiler) @@ -3664,13 +4128,39 @@ void SeparateXYZNode::compile(OSLCompiler& compiler) } /* Separate HSV */ + +NODE_DEFINE(SeparateHSVNode) +{ + NodeType* type = NodeType::add("separate_hsv", create, NodeType::SHADER); + + SOCKET_IN_COLOR(color, "Color", make_float3(0.0f, 0.0f, 0.0f)); + + SOCKET_OUT_FLOAT(h, "H"); + SOCKET_OUT_FLOAT(s, "S"); + SOCKET_OUT_FLOAT(v, "V"); + + return type; +} + SeparateHSVNode::SeparateHSVNode() -: ShaderNode("separate_hsv") +: ShaderNode(node_type) { - add_input("Color", SocketType::COLOR); - add_output("H", SocketType::FLOAT); - add_output("S", SocketType::FLOAT); - add_output("V", SocketType::FLOAT); +} + +bool SeparateHSVNode::constant_fold(ShaderGraph *, ShaderOutput *socket, ShaderInput *optimized) +{ + if(all_inputs_constant()) { + float3 hsv = rgb_to_hsv(color); + + for(int channel = 0; channel < 3; channel++) { + if(outputs[channel] == socket) { + optimized->set(hsv[channel]); + return true; + } + } + } + + return false; } void SeparateHSVNode::compile(SVMCompiler& compiler) @@ -3694,15 +4184,25 @@ void SeparateHSVNode::compile(OSLCompiler& compiler) } /* Hue Saturation Value */ + +NODE_DEFINE(HSVNode) +{ + NodeType* type = NodeType::add("hsv", create, NodeType::SHADER); + + SOCKET_IN_FLOAT(hue, "Hue", 0.5f); + SOCKET_IN_FLOAT(saturation, "Saturation", 1.0f); + SOCKET_IN_FLOAT(value, "Value", 1.0f); + SOCKET_IN_FLOAT(fac, "Fac", 1.0f); + SOCKET_IN_COLOR(color, "Color", make_float3(0.0f, 0.0f, 0.0f)); + + SOCKET_OUT_COLOR(color, "Color"); + + return type; +} + HSVNode::HSVNode() -: ShaderNode("hsv") +: ShaderNode(node_type) { - add_input("Hue", SocketType::FLOAT); - add_input("Saturation", SocketType::FLOAT); - add_input("Value", SocketType::FLOAT); - add_input("Fac", SocketType::FLOAT); - add_input("Color", SocketType::COLOR); - add_output("Color", SocketType::COLOR); } void HSVNode::compile(SVMCompiler& compiler) @@ -3732,14 +4232,22 @@ void HSVNode::compile(OSLCompiler& compiler) /* Attribute */ -AttributeNode::AttributeNode() -: ShaderNode("attribute") +NODE_DEFINE(AttributeNode) { - attribute = ""; + NodeType* type = NodeType::add("attribute", create, NodeType::SHADER); + + SOCKET_STRING(attribute, "Attribute", ustring("")); - add_output("Color", SocketType::COLOR); - add_output("Vector", SocketType::VECTOR); - add_output("Fac", SocketType::FLOAT); + SOCKET_OUT_COLOR(color, "Color"); + SOCKET_OUT_VECTOR(vector, "Vector"); + SOCKET_OUT_FLOAT(fac, "Fac"); + + return type; +} + +AttributeNode::AttributeNode() +: ShaderNode(node_type) +{ } void AttributeNode::attributes(Shader *shader, AttributeRequestSet *attributes) @@ -3815,12 +4323,20 @@ void AttributeNode::compile(OSLCompiler& compiler) /* Camera */ +NODE_DEFINE(CameraNode) +{ + NodeType* type = NodeType::add("camera_info", create, NodeType::SHADER); + + SOCKET_OUT_VECTOR(view_vector, "View Vector"); + SOCKET_OUT_FLOAT(view_z_depth, "View Z Depth"); + SOCKET_OUT_FLOAT(view_distance, "View Distance"); + + return type; +} + CameraNode::CameraNode() -: ShaderNode("camera") +: ShaderNode(node_type) { - add_output("View Vector", SocketType::VECTOR); - add_output("View Z Depth", SocketType::FLOAT); - add_output("View Distance", SocketType::FLOAT); } void CameraNode::compile(SVMCompiler& compiler) @@ -3842,12 +4358,21 @@ void CameraNode::compile(OSLCompiler& compiler) /* Fresnel */ +NODE_DEFINE(FresnelNode) +{ + NodeType* type = NodeType::add("fresnel", create, NodeType::SHADER); + + SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL | SocketType::OSL_INTERNAL); + SOCKET_IN_FLOAT(IOR, "IOR", 1.45f); + + SOCKET_OUT_FLOAT(fac, "Fac"); + + return type; +} + FresnelNode::FresnelNode() -: ShaderNode("fresnel") +: ShaderNode(node_type) { - add_input("Normal", SocketType::NORMAL, make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL | SocketType::OSL_INTERNAL); - add_input("IOR", SocketType::FLOAT, 1.45f); - add_output("Fac", SocketType::FLOAT); } void FresnelNode::compile(SVMCompiler& compiler) @@ -3858,7 +4383,7 @@ void FresnelNode::compile(SVMCompiler& compiler) compiler.add_node(NODE_FRESNEL, compiler.stack_assign(IOR_in), - __float_as_int(IOR_in->value_float()), + __float_as_int(IOR), compiler.encode_uchar4( compiler.stack_assign_if_linked(normal_in), compiler.stack_assign(fac_out))); @@ -3871,14 +4396,22 @@ void FresnelNode::compile(OSLCompiler& compiler) /* Layer Weight */ -LayerWeightNode::LayerWeightNode() -: ShaderNode("layer_weight") +NODE_DEFINE(LayerWeightNode) { - add_input("Normal", SocketType::NORMAL, make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL | SocketType::OSL_INTERNAL); - add_input("Blend", SocketType::FLOAT, 0.5f); + NodeType* type = NodeType::add("layer_weight", create, NodeType::SHADER); - add_output("Fresnel", SocketType::FLOAT); - add_output("Facing", SocketType::FLOAT); + SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL | SocketType::OSL_INTERNAL); + SOCKET_IN_FLOAT(blend, "Blend", 0.5f); + + SOCKET_OUT_FLOAT(fresnel, "Fresnel"); + SOCKET_OUT_FLOAT(facing, "Facing"); + + return type; +} + +LayerWeightNode::LayerWeightNode() +: ShaderNode(node_type) +{ } void LayerWeightNode::compile(SVMCompiler& compiler) @@ -3891,7 +4424,7 @@ void LayerWeightNode::compile(SVMCompiler& compiler) if(!fresnel_out->links.empty()) { compiler.add_node(NODE_LAYER_WEIGHT, compiler.stack_assign_if_linked(blend_in), - __float_as_int(blend_in->value_float()), + __float_as_int(blend), compiler.encode_uchar4(NODE_LAYER_WEIGHT_FRESNEL, compiler.stack_assign_if_linked(normal_in), compiler.stack_assign(fresnel_out))); @@ -3900,7 +4433,7 @@ void LayerWeightNode::compile(SVMCompiler& compiler) if(!facing_out->links.empty()) { compiler.add_node(NODE_LAYER_WEIGHT, compiler.stack_assign_if_linked(blend_in), - __float_as_int(blend_in->value_float()), + __float_as_int(blend), compiler.encode_uchar4(NODE_LAYER_WEIGHT_FACING, compiler.stack_assign_if_linked(normal_in), compiler.stack_assign(facing_out))); @@ -3914,13 +4447,20 @@ void LayerWeightNode::compile(OSLCompiler& compiler) /* Wireframe */ +NODE_DEFINE(WireframeNode) +{ + NodeType* type = NodeType::add("wireframe", create, NodeType::SHADER); + + SOCKET_BOOLEAN(use_pixel_size, "Use Pixel Size", false); + SOCKET_IN_FLOAT(size, "Size", 0.01f); + SOCKET_OUT_FLOAT(fac, "Fac"); + + return type; +} + WireframeNode::WireframeNode() -: ShaderNode("wireframe") +: ShaderNode(node_type) { - add_input("Size", SocketType::FLOAT, 0.01f); - add_output("Fac", SocketType::FLOAT); - - use_pixel_size = false; } void WireframeNode::compile(SVMCompiler& compiler) @@ -3953,17 +4493,25 @@ void WireframeNode::compile(OSLCompiler& compiler) else { compiler.parameter("bump_offset", "center"); } - compiler.parameter("use_pixel_size", use_pixel_size); + compiler.parameter(this, "use_pixel_size"); compiler.add(this, "node_wireframe"); } /* Wavelength */ +NODE_DEFINE(WavelengthNode) +{ + NodeType* type = NodeType::add("wavelength", create, NodeType::SHADER); + + SOCKET_IN_FLOAT(wavelength, "Wavelength", 500.0f); + SOCKET_OUT_COLOR(color, "Color"); + + return type; +} + WavelengthNode::WavelengthNode() -: ShaderNode("wavelength") +: ShaderNode(node_type) { - add_input("Wavelength", SocketType::FLOAT, 500.0f); - add_output("Color", SocketType::COLOR); } void WavelengthNode::compile(SVMCompiler& compiler) @@ -3983,22 +4531,26 @@ void WavelengthNode::compile(OSLCompiler& compiler) /* Blackbody */ -BlackbodyNode::BlackbodyNode() -: ShaderNode("blackbody") +NODE_DEFINE(BlackbodyNode) { - add_input("Temperature", SocketType::FLOAT, 1200.0f); - add_output("Color", SocketType::COLOR); + NodeType* type = NodeType::add("blackbody", create, NodeType::SHADER); + + SOCKET_IN_FLOAT(temperature, "Temperature", 1200.0f); + SOCKET_OUT_COLOR(color, "Color"); + + return type; } -bool BlackbodyNode::constant_fold(ShaderGraph *, ShaderOutput *socket, ShaderInput *optimized) +BlackbodyNode::BlackbodyNode() +: ShaderNode(node_type) { - ShaderInput *temperature_in = input("Temperature"); +} - if(socket == output("Color")) { - if(temperature_in->link == NULL) { - optimized->set(svm_math_blackbody_color(temperature_in->value_float())); - return true; - } +bool BlackbodyNode::constant_fold(ShaderGraph *, ShaderOutput *, ShaderInput *optimized) +{ + if(all_inputs_constant()) { + optimized->set(svm_math_blackbody_color(temperature)); + return true; } return false; @@ -4021,15 +4573,22 @@ void BlackbodyNode::compile(OSLCompiler& compiler) /* Output */ +NODE_DEFINE(OutputNode) +{ + NodeType* type = NodeType::add("output", create, NodeType::SHADER); + + SOCKET_IN_CLOSURE(surface, "Surface"); + SOCKET_IN_CLOSURE(volume, "Volume"); + SOCKET_IN_FLOAT(displacement, "Displacement", 0.0f); + SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f)); + + return type; +} + OutputNode::OutputNode() -: ShaderNode("output") +: ShaderNode(node_type) { special_type = SHADER_SPECIAL_TYPE_OUTPUT; - - add_input("Surface", SocketType::CLOSURE); - add_input("Volume", SocketType::CLOSURE); - add_input("Displacement", SocketType::FLOAT); - add_input("Normal", SocketType::NORMAL); } void OutputNode::compile(SVMCompiler& compiler) @@ -4055,66 +4614,53 @@ void OutputNode::compile(OSLCompiler& compiler) /* Math */ -MathNode::MathNode() -: ShaderNode("math") +NODE_DEFINE(MathNode) { - type = NODE_MATH_ADD; + NodeType* type = NodeType::add("math", create, NodeType::SHADER); - use_clamp = false; + static NodeEnum type_enum; + type_enum.insert("add", NODE_MATH_ADD); + type_enum.insert("subtract", NODE_MATH_SUBTRACT); + type_enum.insert("multiply", NODE_MATH_MULTIPLY); + type_enum.insert("divide", NODE_MATH_DIVIDE); + type_enum.insert("sine", NODE_MATH_SINE); + type_enum.insert("cosine", NODE_MATH_COSINE); + type_enum.insert("tangent", NODE_MATH_TANGENT); + type_enum.insert("arcsine", NODE_MATH_ARCSINE); + type_enum.insert("arccosine", NODE_MATH_ARCCOSINE); + type_enum.insert("arctangent", NODE_MATH_ARCTANGENT); + type_enum.insert("power", NODE_MATH_POWER); + type_enum.insert("logarithm", NODE_MATH_LOGARITHM); + type_enum.insert("minimum", NODE_MATH_MINIMUM); + type_enum.insert("maximum", NODE_MATH_MAXIMUM); + type_enum.insert("round", NODE_MATH_ROUND); + type_enum.insert("less_than", NODE_MATH_LESS_THAN); + type_enum.insert("greater_than", NODE_MATH_GREATER_THAN); + type_enum.insert("modulo", NODE_MATH_MODULO); + type_enum.insert("absolute", NODE_MATH_ABSOLUTE); + SOCKET_ENUM(type, "Type", type_enum, NODE_MATH_ADD); - add_input("Value1", SocketType::FLOAT); - add_input("Value2", SocketType::FLOAT); - add_output("Value", SocketType::FLOAT); -} + SOCKET_BOOLEAN(use_clamp, "Use Clamp", false); -static NodeEnum math_type_init() -{ - NodeEnum enm; + SOCKET_IN_FLOAT(value1, "Value1", 0.0f); + SOCKET_IN_FLOAT(value2, "Value2", 0.0f); - enm.insert("Add", NODE_MATH_ADD); - enm.insert("Subtract", NODE_MATH_SUBTRACT); - enm.insert("Multiply", NODE_MATH_MULTIPLY); - enm.insert("Divide", NODE_MATH_DIVIDE); - enm.insert("Sine", NODE_MATH_SINE); - enm.insert("Cosine", NODE_MATH_COSINE); - enm.insert("Tangent", NODE_MATH_TANGENT); - enm.insert("Arcsine", NODE_MATH_ARCSINE); - enm.insert("Arccosine", NODE_MATH_ARCCOSINE); - enm.insert("Arctangent", NODE_MATH_ARCTANGENT); - enm.insert("Power", NODE_MATH_POWER); - enm.insert("Logarithm", NODE_MATH_LOGARITHM); - enm.insert("Minimum", NODE_MATH_MINIMUM); - enm.insert("Maximum", NODE_MATH_MAXIMUM); - enm.insert("Round", NODE_MATH_ROUND); - enm.insert("Less Than", NODE_MATH_LESS_THAN); - enm.insert("Greater Than", NODE_MATH_GREATER_THAN); - enm.insert("Modulo", NODE_MATH_MODULO); - enm.insert("Absolute", NODE_MATH_ABSOLUTE); + SOCKET_OUT_FLOAT(value, "Value"); - return enm; + return type; } -NodeEnum MathNode::type_enum = math_type_init(); - -bool MathNode::constant_fold(ShaderGraph *, ShaderOutput *socket, ShaderInput *optimized) +MathNode::MathNode() +: ShaderNode(node_type) { - ShaderInput *value1_in = input("Value1"); - ShaderInput *value2_in = input("Value2"); - - if(socket == output("Value")) { - if(value1_in->link == NULL && value2_in->link == NULL) { - float value = svm_math(type, - value1_in->value_float(), - value2_in->value_float()); - - if(use_clamp) { - value = saturate(value); - } - - optimized->set(value); +} - return true; - } +bool MathNode::constant_fold(ShaderGraph *, ShaderOutput *, ShaderInput *optimized) +{ + if(all_inputs_constant()) { + float value = svm_math(type, value1, value2); + optimized->set(use_clamp ? saturate(value) : value); + return true; } return false; @@ -4137,54 +4683,51 @@ void MathNode::compile(SVMCompiler& compiler) void MathNode::compile(OSLCompiler& compiler) { - compiler.parameter("type", type_enum[type]); - compiler.parameter("use_clamp", use_clamp); + compiler.parameter(this, "type"); + compiler.parameter(this, "use_clamp"); compiler.add(this, "node_math"); } /* VectorMath */ -VectorMathNode::VectorMathNode() -: ShaderNode("vector_math") +NODE_DEFINE(VectorMathNode) { - type = NODE_VECTOR_MATH_ADD; + NodeType* type = NodeType::add("vector_math", create, NodeType::SHADER); - add_input("Vector1", SocketType::VECTOR); - add_input("Vector2", SocketType::VECTOR); - add_output("Value", SocketType::FLOAT); - add_output("Vector", SocketType::VECTOR); -} + static NodeEnum type_enum; + type_enum.insert("add", NODE_VECTOR_MATH_ADD); + type_enum.insert("subtract", NODE_VECTOR_MATH_SUBTRACT); + type_enum.insert("average", NODE_VECTOR_MATH_AVERAGE); + type_enum.insert("dot_product", NODE_VECTOR_MATH_DOT_PRODUCT); + type_enum.insert("cross_product", NODE_VECTOR_MATH_CROSS_PRODUCT); + type_enum.insert("normalize", NODE_VECTOR_MATH_NORMALIZE); + SOCKET_ENUM(type, "Type", type_enum, NODE_VECTOR_MATH_ADD); -static NodeEnum vector_math_type_init() -{ - NodeEnum enm; + SOCKET_IN_VECTOR(vector1, "Vector1", make_float3(0.0f, 0.0f, 0.0f)); + SOCKET_IN_VECTOR(vector2, "Vector2", make_float3(0.0f, 0.0f, 0.0f)); - enm.insert("Add", NODE_VECTOR_MATH_ADD); - enm.insert("Subtract", NODE_VECTOR_MATH_SUBTRACT); - enm.insert("Average", NODE_VECTOR_MATH_AVERAGE); - enm.insert("Dot Product", NODE_VECTOR_MATH_DOT_PRODUCT); - enm.insert("Cross Product", NODE_VECTOR_MATH_CROSS_PRODUCT); - enm.insert("Normalize", NODE_VECTOR_MATH_NORMALIZE); + SOCKET_OUT_FLOAT(value, "Value"); + SOCKET_OUT_VECTOR(vector, "Vector"); - return enm; + return type; } -NodeEnum VectorMathNode::type_enum = vector_math_type_init(); +VectorMathNode::VectorMathNode() +: ShaderNode(node_type) +{ +} bool VectorMathNode::constant_fold(ShaderGraph *, ShaderOutput *socket, ShaderInput *optimized) { - ShaderInput *vector1_in = input("Vector1"); - ShaderInput *vector2_in = input("Vector2"); - float value; float3 vector; - if(vector1_in->link == NULL && vector2_in->link == NULL) { + if(all_inputs_constant()) { svm_vector_math(&value, &vector, type, - vector1_in->value(), - vector2_in->value()); + vector1, + vector2); if(socket == output("Value")) { optimized->set(value); @@ -4217,48 +4760,40 @@ void VectorMathNode::compile(SVMCompiler& compiler) void VectorMathNode::compile(OSLCompiler& compiler) { - compiler.parameter("type", type_enum[type]); + compiler.parameter(this, "type"); compiler.add(this, "node_vector_math"); } /* VectorTransform */ -VectorTransformNode::VectorTransformNode() -: ShaderNode("vector_transform") +NODE_DEFINE(VectorTransformNode) { - type = NODE_VECTOR_TRANSFORM_TYPE_VECTOR; - convert_from = NODE_VECTOR_TRANSFORM_CONVERT_SPACE_WORLD; - convert_to = NODE_VECTOR_TRANSFORM_CONVERT_SPACE_OBJECT; + NodeType* type = NodeType::add("vector_transform", create, NodeType::SHADER); - add_input("Vector", SocketType::VECTOR); - add_output("Vector", SocketType::VECTOR); -} + static NodeEnum type_enum; + type_enum.insert("vector", NODE_VECTOR_TRANSFORM_TYPE_VECTOR); + type_enum.insert("point", NODE_VECTOR_TRANSFORM_TYPE_POINT); + type_enum.insert("normal", NODE_VECTOR_TRANSFORM_TYPE_NORMAL); + SOCKET_ENUM(type, "Type", type_enum, NODE_VECTOR_TRANSFORM_TYPE_VECTOR); -static NodeEnum vector_transform_type_init() -{ - NodeEnum enm; + static NodeEnum space_enum; + space_enum.insert("world", NODE_VECTOR_TRANSFORM_CONVERT_SPACE_WORLD); + space_enum.insert("object", NODE_VECTOR_TRANSFORM_CONVERT_SPACE_OBJECT); + space_enum.insert("camera", NODE_VECTOR_TRANSFORM_CONVERT_SPACE_CAMERA); + SOCKET_ENUM(convert_from, "Convert From", space_enum, NODE_VECTOR_TRANSFORM_CONVERT_SPACE_WORLD); + SOCKET_ENUM(convert_to, "Convert To", space_enum, NODE_VECTOR_TRANSFORM_CONVERT_SPACE_OBJECT); - enm.insert("Vector", NODE_VECTOR_TRANSFORM_TYPE_VECTOR); - enm.insert("Point", NODE_VECTOR_TRANSFORM_TYPE_POINT); - enm.insert("Normal", NODE_VECTOR_TRANSFORM_TYPE_NORMAL); + SOCKET_IN_VECTOR(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f)); + SOCKET_OUT_VECTOR(vector, "Vector"); - return enm; + return type; } -static NodeEnum vector_transform_convert_space_init() +VectorTransformNode::VectorTransformNode() +: ShaderNode(node_type) { - NodeEnum enm; - - enm.insert("world", NODE_VECTOR_TRANSFORM_CONVERT_SPACE_WORLD); - enm.insert("object", NODE_VECTOR_TRANSFORM_CONVERT_SPACE_OBJECT); - enm.insert("camera", NODE_VECTOR_TRANSFORM_CONVERT_SPACE_CAMERA); - - return enm; } -NodeEnum VectorTransformNode::type_enum = vector_transform_type_init(); -NodeEnum VectorTransformNode::convert_space_enum = vector_transform_convert_space_init(); - void VectorTransformNode::compile(SVMCompiler& compiler) { ShaderInput *vector_in = input("Vector"); @@ -4272,33 +4807,40 @@ void VectorTransformNode::compile(SVMCompiler& compiler) void VectorTransformNode::compile(OSLCompiler& compiler) { - compiler.parameter("type", type_enum[type]); - compiler.parameter("convert_from", convert_space_enum[convert_from]); - compiler.parameter("convert_to", convert_space_enum[convert_to]); + compiler.parameter(this, "type"); + compiler.parameter(this, "convert_from"); + compiler.parameter(this, "convert_to"); compiler.add(this, "node_vector_transform"); } /* BumpNode */ -BumpNode::BumpNode() -: ShaderNode("bump") +NODE_DEFINE(BumpNode) { - invert = false; + NodeType* type = NodeType::add("bump", create, NodeType::SHADER); - special_type = SHADER_SPECIAL_TYPE_BUMP; + SOCKET_BOOLEAN(invert, "Invert", false); /* this input is used by the user, but after graph transform it is no longer * used and moved to sampler center/x/y instead */ - add_input("Height", SocketType::FLOAT); + SOCKET_IN_FLOAT(height, "Height", 1.0f); + + SOCKET_IN_FLOAT(sample_center, "SampleCenter", 0.0f); + SOCKET_IN_FLOAT(sample_x, "SampleX", 0.0f); + SOCKET_IN_FLOAT(sample_y, "SampleY", 0.0f); + SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL); + SOCKET_IN_FLOAT(strength, "Strength", 1.0f); + SOCKET_IN_FLOAT(distance, "Distance", 0.1f); - add_input("SampleCenter", SocketType::FLOAT); - add_input("SampleX", SocketType::FLOAT); - add_input("SampleY", SocketType::FLOAT); - add_input("Normal", SocketType::NORMAL, make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL); - add_input("Strength", SocketType::FLOAT, 1.0f); - add_input("Distance", SocketType::FLOAT, 0.1f); + SOCKET_OUT_NORMAL(normal, "Normal"); - add_output("Normal", SocketType::NORMAL); + return type; +} + +BumpNode::BumpNode() +: ShaderNode(node_type) +{ + special_type = SHADER_SPECIAL_TYPE_BUMP; } void BumpNode::compile(SVMCompiler& compiler) @@ -4327,7 +4869,7 @@ void BumpNode::compile(SVMCompiler& compiler) void BumpNode::compile(OSLCompiler& compiler) { - compiler.parameter("invert", invert); + compiler.parameter(this, "invert"); compiler.add(this, "node_bump"); } @@ -4353,32 +4895,25 @@ bool BumpNode::constant_fold(ShaderGraph *graph, ShaderOutput *, ShaderInput *) return false; } -/* RGBCurvesNode */ -RGBCurvesNode::RGBCurvesNode() -: ShaderNode("rgb_curves") -{ - add_input("Fac", SocketType::FLOAT); - add_input("Color", SocketType::COLOR); - add_output("Color", SocketType::COLOR); +/* Curve node */ - min_x = 0.0f; - max_x = 1.0f; +CurvesNode::CurvesNode(const NodeType *node_type) +: ShaderNode(node_type) +{ } -void RGBCurvesNode::compile(SVMCompiler& compiler) +void CurvesNode::compile(SVMCompiler& compiler, int type, ShaderInput *value_in, ShaderOutput *value_out) { if(curves.size() == 0) return; ShaderInput *fac_in = input("Fac"); - ShaderInput *color_in = input("Color"); - ShaderOutput *color_out = output("Color"); - compiler.add_node(NODE_RGB_CURVES, + compiler.add_node(type, compiler.encode_uchar4(compiler.stack_assign(fac_in), - compiler.stack_assign(color_in), - compiler.stack_assign(color_out)), + compiler.stack_assign(value_in), + compiler.stack_assign(value_out)), __float_as_int(min_x), __float_as_int(max_x)); @@ -4387,72 +4922,114 @@ void RGBCurvesNode::compile(SVMCompiler& compiler) compiler.add_node(float3_to_float4(curves[i])); } -void RGBCurvesNode::compile(OSLCompiler& compiler) +void CurvesNode::compile(OSLCompiler& compiler, const char* name) { if(curves.size() == 0) return; compiler.parameter_color_array("ramp", curves); - compiler.parameter("min_x", min_x); - compiler.parameter("max_x", max_x); - compiler.add(this, "node_rgb_curves"); + compiler.parameter(this, "min_x"); + compiler.parameter(this, "max_x"); + compiler.add(this, name); } -/* VectorCurvesNode */ +void CurvesNode::compile(SVMCompiler& /*compiler*/) +{ + assert(0); +} -VectorCurvesNode::VectorCurvesNode() -: ShaderNode("vector_curves") +void CurvesNode::compile(OSLCompiler& /*compiler*/) +{ + assert(0); +} + +/* RGBCurvesNode */ + +NODE_DEFINE(RGBCurvesNode) { - add_input("Fac", SocketType::FLOAT); - add_input("Vector", SocketType::VECTOR); - add_output("Vector", SocketType::VECTOR); + NodeType* type = NodeType::add("rgb_curves", create, NodeType::SHADER); + + SOCKET_COLOR_ARRAY(curves, "Curves", array<float3>()); + SOCKET_FLOAT(min_x, "Min X", 0.0f); + SOCKET_FLOAT(max_x, "Max X", 1.0f); + + SOCKET_IN_FLOAT(fac, "Fac", 0.0f); + SOCKET_IN_COLOR(value, "Color", make_float3(0.0f, 0.0f, 0.0f)); - min_x = 0.0f; - max_x = 1.0f; + SOCKET_OUT_COLOR(value, "Color"); + + return type; } -void VectorCurvesNode::compile(SVMCompiler& compiler) +RGBCurvesNode::RGBCurvesNode() +: CurvesNode(node_type) { - if(curves.size() == 0) - return; +} - ShaderInput *fac_in = input("Fac"); - ShaderInput *vector_in = input("Vector"); - ShaderOutput *vector_out = output("Vector"); +void RGBCurvesNode::compile(SVMCompiler& compiler) +{ + CurvesNode::compile(compiler, NODE_RGB_CURVES, input("Color"), output("Color")); +} - compiler.add_node(NODE_VECTOR_CURVES, - compiler.encode_uchar4(compiler.stack_assign(fac_in), - compiler.stack_assign(vector_in), - compiler.stack_assign(vector_out)), - __float_as_int(min_x), - __float_as_int(max_x)); +void RGBCurvesNode::compile(OSLCompiler& compiler) +{ + CurvesNode::compile(compiler, "node_rgb_curves"); +} - compiler.add_node(curves.size()); - for(int i = 0; i < curves.size(); i++) - compiler.add_node(float3_to_float4(curves[i])); +/* VectorCurvesNode */ + +NODE_DEFINE(VectorCurvesNode) +{ + NodeType* type = NodeType::add("vector_curves", create, NodeType::SHADER); + + SOCKET_VECTOR_ARRAY(curves, "Curves", array<float3>()); + SOCKET_FLOAT(min_x, "Min X", 0.0f); + SOCKET_FLOAT(max_x, "Max X", 1.0f); + + SOCKET_IN_FLOAT(fac, "Fac", 0.0f); + SOCKET_IN_VECTOR(value, "Vector", make_float3(0.0f, 0.0f, 0.0f)); + + SOCKET_OUT_VECTOR(value, "Vector"); + + return type; } -void VectorCurvesNode::compile(OSLCompiler& compiler) +VectorCurvesNode::VectorCurvesNode() +: CurvesNode(node_type) { - if(curves.size() == 0) - return; +} - compiler.parameter_color_array("ramp", curves); - compiler.parameter("min_x", min_x); - compiler.parameter("max_x", max_x); - compiler.add(this, "node_vector_curves"); +void VectorCurvesNode::compile(SVMCompiler& compiler) +{ + CurvesNode::compile(compiler, NODE_VECTOR_CURVES, input("Vector"), output("Vector")); +} + +void VectorCurvesNode::compile(OSLCompiler& compiler) +{ + CurvesNode::compile(compiler, "node_vector_curves"); } /* RGBRampNode */ -RGBRampNode::RGBRampNode() -: ShaderNode("rgb_ramp") +NODE_DEFINE(RGBRampNode) { - add_input("Fac", SocketType::FLOAT); - add_output("Color", SocketType::COLOR); - add_output("Alpha", SocketType::FLOAT); + NodeType* type = NodeType::add("rgb_ramp", create, NodeType::SHADER); + + SOCKET_COLOR_ARRAY(ramp, "Ramp", array<float3>()); + SOCKET_FLOAT_ARRAY(ramp_alpha, "Ramp Alpha", array<float>()); + SOCKET_BOOLEAN(interpolate, "Interpolate", true); + + SOCKET_IN_FLOAT(fac, "Fac", 0.0f); - interpolate = true; + SOCKET_OUT_COLOR(color, "Color"); + SOCKET_OUT_FLOAT(alpha, "Alpha"); + + return type; +} + +RGBRampNode::RGBRampNode() +: ShaderNode(node_type) +{ } void RGBRampNode::compile(SVMCompiler& compiler) @@ -4483,18 +5060,26 @@ void RGBRampNode::compile(OSLCompiler& compiler) compiler.parameter_color_array("ramp_color", ramp); compiler.parameter_array("ramp_alpha", ramp_alpha.data(), ramp_alpha.size()); - compiler.parameter("interpolate", interpolate); + compiler.parameter(this, "interpolate"); compiler.add(this, "node_rgb_ramp"); } /* Set Normal Node */ +NODE_DEFINE(SetNormalNode) +{ + NodeType* type = NodeType::add("set_normal", create, NodeType::SHADER); + + SOCKET_IN_VECTOR(direction, "Direction", make_float3(0.0f, 0.0f, 0.0f)); + SOCKET_OUT_NORMAL(normal, "Normal"); + + return type; +} + SetNormalNode::SetNormalNode() -: ShaderNode("set_normal") +: ShaderNode(node_type) { - add_input("Direction", SocketType::VECTOR); - add_output("Normal", SocketType::NORMAL); } void SetNormalNode::compile(SVMCompiler& compiler) @@ -4515,18 +5100,54 @@ void SetNormalNode::compile(OSLCompiler& compiler) /* OSLNode */ OSLNode::OSLNode() -: ShaderNode("osl_shader") +: ShaderNode(new NodeType(NodeType::SHADER)) { special_type = SHADER_SPECIAL_TYPE_SCRIPT; } OSLNode::~OSLNode() { + delete type; } -OSLNode* OSLNode::create(size_t) +ShaderNode *OSLNode::clone() const { - return new OSLNode(); + OSLNode *node = new OSLNode(*this); + node->type = new NodeType(*type); + return node; +} + +OSLNode* OSLNode::create(size_t num_inputs) +{ + /* allocate space for the node itself and parameters, aligned to 16 bytes + * assuming that's the most parameter types need */ + size_t node_size = align_up(sizeof(OSLNode), 16); + size_t inputs_size = align_up(SocketType::max_size(), 16) * num_inputs; + + char *node_memory = (char*) operator new(node_size + inputs_size); + memset(node_memory, 0, node_size + inputs_size); + + return new(node_memory) OSLNode(); +} + +char* OSLNode::input_default_value() +{ + /* pointer to default value storage, which is the same as our actual value */ + size_t num_inputs = type->inputs.size(); + size_t inputs_size = align_up(SocketType::max_size(), 16) * num_inputs; + return (char*)this + align_up(sizeof(OSLNode), 16) + inputs_size; +} + +void OSLNode::add_input(ustring name, SocketType::Type socket_type) +{ + char *memory = input_default_value(); + size_t offset = memory - (char*)this; + const_cast<NodeType*>(type)->register_input(name, name, socket_type, offset, memory, NULL, NULL, SocketType::LINKABLE); +} + +void OSLNode::add_output(ustring name, SocketType::Type socket_type) +{ + const_cast<NodeType*>(type)->register_output(name, name, socket_type); } void OSLNode::compile(SVMCompiler&) @@ -4544,32 +5165,32 @@ void OSLNode::compile(OSLCompiler& compiler) /* Normal Map */ -static NodeEnum normal_map_space_init() +NODE_DEFINE(NormalMapNode) { - NodeEnum enm; + NodeType* type = NodeType::add("normal_map", create, NodeType::SHADER); - enm.insert("Tangent", NODE_NORMAL_MAP_TANGENT); - enm.insert("Object", NODE_NORMAL_MAP_OBJECT); - enm.insert("World", NODE_NORMAL_MAP_WORLD); - enm.insert("Blender Object", NODE_NORMAL_MAP_BLENDER_OBJECT); - enm.insert("Blender World", NODE_NORMAL_MAP_BLENDER_WORLD); + static NodeEnum space_enum; + space_enum.insert("tangent", NODE_NORMAL_MAP_TANGENT); + space_enum.insert("object", NODE_NORMAL_MAP_OBJECT); + space_enum.insert("world", NODE_NORMAL_MAP_WORLD); + space_enum.insert("blender_object", NODE_NORMAL_MAP_BLENDER_OBJECT); + space_enum.insert("blender_world", NODE_NORMAL_MAP_BLENDER_WORLD); + SOCKET_ENUM(space, "Space", space_enum, NODE_TANGENT_RADIAL); - return enm; -} + SOCKET_STRING(attribute, "Attribute", ustring("")); -NodeEnum NormalMapNode::space_enum = normal_map_space_init(); + SOCKET_IN_NORMAL(normal_osl, "NormalIn", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL | SocketType::OSL_INTERNAL); + SOCKET_IN_FLOAT(strength, "Strength", 1.0f); + SOCKET_IN_COLOR(color, "Color", make_float3(0.5f, 0.5f, 1.0f)); -NormalMapNode::NormalMapNode() -: ShaderNode("normal_map") -{ - space = NODE_NORMAL_MAP_TANGENT; - attribute = ustring(""); + SOCKET_OUT_NORMAL(normal, "Normal"); - add_input("NormalIn", SocketType::NORMAL, make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL | SocketType::OSL_INTERNAL); - add_input("Strength", SocketType::FLOAT, 1.0f); - add_input("Color", SocketType::COLOR); + return type; +} - add_output("Normal", SocketType::NORMAL); +NormalMapNode::NormalMapNode() +: ShaderNode(node_type) +{ } void NormalMapNode::attributes(Shader *shader, AttributeRequestSet *attributes) @@ -4630,46 +5251,38 @@ void NormalMapNode::compile(OSLCompiler& compiler) } } - compiler.parameter("space", space_enum[space]); - + compiler.parameter(this, "space"); compiler.add(this, "node_normal_map"); } /* Tangent */ -static NodeEnum tangent_direction_type_init() +NODE_DEFINE(TangentNode) { - NodeEnum enm; + NodeType* type = NodeType::add("tangent", create, NodeType::SHADER); - enm.insert("Radial", NODE_TANGENT_RADIAL); - enm.insert("UV Map", NODE_TANGENT_UVMAP); + static NodeEnum direction_type_enum; + direction_type_enum.insert("radial", NODE_TANGENT_RADIAL); + direction_type_enum.insert("uv_map", NODE_TANGENT_UVMAP); + SOCKET_ENUM(direction_type, "Direction Type", direction_type_enum, NODE_TANGENT_RADIAL); - return enm; -} + static NodeEnum axis_enum; + axis_enum.insert("x", NODE_TANGENT_AXIS_X); + axis_enum.insert("y", NODE_TANGENT_AXIS_Y); + axis_enum.insert("z", NODE_TANGENT_AXIS_Z); + SOCKET_ENUM(axis, "Axis", axis_enum, NODE_TANGENT_AXIS_X); -static NodeEnum tangent_axis_init() -{ - NodeEnum enm; + SOCKET_STRING(attribute, "Attribute", ustring("")); - enm.insert("X", NODE_TANGENT_AXIS_X); - enm.insert("Y", NODE_TANGENT_AXIS_Y); - enm.insert("Z", NODE_TANGENT_AXIS_Z); + SOCKET_IN_NORMAL(normal_osl, "NormalIn", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL | SocketType::OSL_INTERNAL); + SOCKET_OUT_NORMAL(tangent, "Tangent"); - return enm; + return type; } -NodeEnum TangentNode::direction_type_enum = tangent_direction_type_init(); -NodeEnum TangentNode::axis_enum = tangent_axis_init(); - TangentNode::TangentNode() -: ShaderNode("tangent") +: ShaderNode(node_type) { - direction_type = NODE_TANGENT_RADIAL; - axis = NODE_TANGENT_AXIS_X; - attribute = ustring(""); - - add_input("NormalIn", SocketType::NORMAL, make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL | SocketType::OSL_INTERNAL); - add_output("Tangent", SocketType::NORMAL); } void TangentNode::attributes(Shader *shader, AttributeRequestSet *attributes) @@ -4718,8 +5331,8 @@ void TangentNode::compile(OSLCompiler& compiler) compiler.parameter("attr_name", ustring((string(attribute.c_str()) + ".tangent").c_str())); } - compiler.parameter("direction_type", direction_type_enum[direction_type]); - compiler.parameter("axis", axis_enum[axis]); + compiler.parameter(this, "direction_type"); + compiler.parameter(this, "axis"); compiler.add(this, "node_tangent"); } diff --git a/intern/cycles/render/nodes.h b/intern/cycles/render/nodes.h index 8b17e455f7a..3245fdfb6d9 100644 --- a/intern/cycles/render/nodes.h +++ b/intern/cycles/render/nodes.h @@ -18,6 +18,7 @@ #define __NODES_H__ #include "graph.h" +#include "node.h" #include "util_string.h" @@ -35,6 +36,7 @@ public: Transform compute_transform(); bool skip(); void compile(SVMCompiler& compiler, int offset_in, int offset_out); + int compile(SVMCompiler& compiler, ShaderInput *vector_in); void compile(OSLCompiler &compiler); int compile_begin(SVMCompiler& compiler, ShaderInput *vector_in); @@ -49,48 +51,26 @@ public: enum Type { POINT = 0, TEXTURE = 1, VECTOR = 2, NORMAL = 3 }; Type type; - static NodeEnum type_enum; enum Mapping { NONE = 0, X = 1, Y = 2, Z = 3 }; Mapping x_mapping, y_mapping, z_mapping; - static NodeEnum mapping_enum; enum Projection { FLAT, CUBE, TUBE, SPHERE }; Projection projection; - static NodeEnum projection_enum; - - bool equals(const TextureMapping& other) { - return translation == other.translation && - rotation == other.rotation && - scale == other.scale && - use_minmax == other.use_minmax && - min == other.min && - max == other.max && - type == other.type && - x_mapping == other.x_mapping && - y_mapping == other.y_mapping && - z_mapping == other.z_mapping && - projection == other.projection; - } }; /* Nodes */ class TextureNode : public ShaderNode { public: - explicit TextureNode(const char *name_) : ShaderNode(name_) {} + explicit TextureNode(const NodeType *node_type) : ShaderNode(node_type) {} TextureMapping tex_mapping; - - virtual bool equals(const ShaderNode *other) { - return ShaderNode::equals(other) && - tex_mapping.equals(((const TextureNode*)other)->tex_mapping); - } }; /* Any node which uses image manager's slot should be a subclass of this one. */ class ImageSlotTextureNode : public TextureNode { public: - explicit ImageSlotTextureNode(const char *name_) : TextureNode(name_) { + explicit ImageSlotTextureNode(const NodeType *node_type) : TextureNode(node_type) { special_type = SHADER_SPECIAL_TYPE_IMAGE_SLOT; } int slot; @@ -107,7 +87,7 @@ public: int is_float; bool is_linear; bool use_alpha; - string filename; + ustring filename; void *builtin_data; NodeImageColorSpace color_space; NodeImageProjection projection; @@ -115,22 +95,14 @@ public: ExtensionType extension; float projection_blend; bool animated; + float3 vector; - static NodeEnum color_space_enum; - static NodeEnum projection_enum; - - virtual bool equals(const ShaderNode *other) { - const ImageTextureNode *image_node = (const ImageTextureNode*)other; + virtual bool equals(const ShaderNode& other) + { + const ImageTextureNode& image_node = (const ImageTextureNode&)other; return ImageSlotTextureNode::equals(other) && - use_alpha == image_node->use_alpha && - filename == image_node->filename && - builtin_data == image_node->builtin_data && - color_space == image_node->color_space && - projection == image_node->projection && - interpolation == image_node->interpolation && - extension == image_node->extension && - projection_blend == image_node->projection_blend && - animated == image_node->animated; + builtin_data == image_node.builtin_data && + animated == image_node.animated; } }; @@ -146,26 +118,20 @@ public: int is_float; bool is_linear; bool use_alpha; - string filename; + ustring filename; void *builtin_data; NodeImageColorSpace color_space; NodeEnvironmentProjection projection; InterpolationType interpolation; bool animated; + float3 vector; - static NodeEnum color_space_enum; - static NodeEnum projection_enum; - - virtual bool equals(const ShaderNode *other) { - const EnvironmentTextureNode *env_node = (const EnvironmentTextureNode*)other; + virtual bool equals(const ShaderNode& other) + { + const EnvironmentTextureNode& env_node = (const EnvironmentTextureNode&)other; return ImageSlotTextureNode::equals(other) && - use_alpha == env_node->use_alpha && - filename == env_node->filename && - builtin_data == env_node->builtin_data && - color_space == env_node->color_space && - projection == env_node->projection && - interpolation == env_node->interpolation && - animated == env_node->animated; + builtin_data == env_node.builtin_data && + animated == env_node.animated; } }; @@ -179,25 +145,20 @@ public: float3 sun_direction; float turbidity; float ground_albedo; - - static NodeEnum type_enum; - - virtual bool equals(const ShaderNode *other) { - const SkyTextureNode *sky_node = (const SkyTextureNode*)other; - return TextureNode::equals(other) && - sun_direction == sky_node->sun_direction && - turbidity == sky_node->turbidity && - ground_albedo == sky_node->ground_albedo && - type == sky_node->type; - } + float3 vector; }; class OutputNode : public ShaderNode { public: SHADER_NODE_CLASS(OutputNode) + void* surface; + void* volume; + float displacement; + float3 normal; + /* Don't allow output node de-duplication. */ - virtual bool equals(const ShaderNode * /*other*/) { return false; } + virtual bool equals(const ShaderNode& /*other*/) { return false; } }; class GradientTextureNode : public TextureNode { @@ -207,18 +168,15 @@ public: virtual int get_group() { return NODE_GROUP_LEVEL_2; } NodeGradientType type; - static NodeEnum type_enum; - - virtual bool equals(const ShaderNode *other) { - const GradientTextureNode *gradient_node = (const GradientTextureNode*)other; - return TextureNode::equals(other) && - type == gradient_node->type; - } + float3 vector; }; class NoiseTextureNode : public TextureNode { public: SHADER_NODE_CLASS(NoiseTextureNode) + + float scale, detail, distortion; + float3 vector; }; class VoronoiTextureNode : public TextureNode { @@ -228,13 +186,8 @@ public: virtual int get_group() { return NODE_GROUP_LEVEL_2; } NodeVoronoiColoring coloring; - static NodeEnum coloring_enum; - - virtual bool equals(const ShaderNode *other) { - const VoronoiTextureNode *voronoi_node = (const VoronoiTextureNode*)other; - return TextureNode::equals(other) && - coloring == voronoi_node->coloring; - } + float scale; + float3 vector; }; class MusgraveTextureNode : public TextureNode { @@ -244,13 +197,8 @@ public: virtual int get_group() { return NODE_GROUP_LEVEL_2; } NodeMusgraveType type; - static NodeEnum type_enum; - - virtual bool equals(const ShaderNode *other) { - const MusgraveTextureNode *musgrave_node = (const MusgraveTextureNode*)other; - return TextureNode::equals(other) && - type == musgrave_node->type; - } + float scale, detail, dimension, lacunarity, offset, gain; + float3 vector; }; class WaveTextureNode : public TextureNode { @@ -261,15 +209,9 @@ public: NodeWaveType type; NodeWaveProfile profile; - static NodeEnum type_enum; - static NodeEnum profile_enum; - - virtual bool equals(const ShaderNode *other) { - const WaveTextureNode *wave_node = (const WaveTextureNode*)other; - return TextureNode::equals(other) && - type == wave_node->type && - profile == wave_node->profile; - } + + float scale, distortion, detail, detail_scale; + float3 vector; }; class MagicTextureNode : public TextureNode { @@ -279,18 +221,17 @@ public: virtual int get_group() { return NODE_GROUP_LEVEL_2; } int depth; - - virtual bool equals(const ShaderNode *other) { - const MagicTextureNode *magic_node = (const MagicTextureNode*)other; - return TextureNode::equals(other) && - depth == magic_node->depth; - } + float3 vector; + float scale, distortion; }; class CheckerTextureNode : public TextureNode { public: SHADER_NODE_CLASS(CheckerTextureNode) + float3 vector, color1, color2; + float scale; + virtual int get_group() { return NODE_GROUP_LEVEL_2; } }; @@ -301,16 +242,11 @@ public: float offset, squash; int offset_frequency, squash_frequency; - virtual int get_group() { return NODE_GROUP_LEVEL_2; } + float3 color1, color2, mortar; + float scale, mortar_size, bias, brick_width, row_height; + float3 vector; - virtual bool equals(const ShaderNode *other) { - const BrickTextureNode *brick_node = (const BrickTextureNode*)other; - return TextureNode::equals(other) && - offset == brick_node->offset && - squash == brick_node->squash && - offset_frequency == brick_node->offset_frequency && - squash_frequency == brick_node->squash_frequency; - } + virtual int get_group() { return NODE_GROUP_LEVEL_2; } }; class PointDensityTextureNode : public ShaderNode { @@ -324,25 +260,20 @@ public: bool has_spatial_varying() { return true; } bool has_object_dependency() { return true; } - ImageManager *image_manager; - int slot; - string filename; + ustring filename; NodeTexVoxelSpace space; - void *builtin_data; InterpolationType interpolation; - Transform tfm; + float3 vector; - static NodeEnum space_enum; + ImageManager *image_manager; + int slot; + void *builtin_data; - virtual bool equals(const ShaderNode *other) { - const PointDensityTextureNode *point_dendity_node = (const PointDensityTextureNode*)other; + virtual bool equals(const ShaderNode& other) { + const PointDensityTextureNode& point_dendity_node = (const PointDensityTextureNode&)other; return ShaderNode::equals(other) && - filename == point_dendity_node->filename && - space == point_dendity_node->space && - builtin_data == point_dendity_node->builtin_data && - interpolation == point_dendity_node->interpolation && - tfm == point_dendity_node->tfm; + builtin_data == point_dendity_node.builtin_data; } }; @@ -351,20 +282,16 @@ public: SHADER_NODE_CLASS(MappingNode) virtual int get_group() { return NODE_GROUP_LEVEL_2; } + float3 vector; TextureMapping tex_mapping; - - virtual bool equals(const ShaderNode *other) { - const MappingNode *mapping_node = (const MappingNode*)other; - return ShaderNode::equals(other) && - tex_mapping.equals(mapping_node->tex_mapping); - } }; class RGBToBWNode : public ShaderNode { public: SHADER_NODE_CLASS(RGBToBWNode) - bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized); + + float3 color; }; class ConvertNode : public ShaderNode { @@ -376,28 +303,39 @@ public: SocketType::Type from, to; - virtual bool equals(const ShaderNode *other) - { - const ConvertNode *convert_node = (const ConvertNode*)other; - return ShaderNode::equals(other) && - from == convert_node->from && - to == convert_node->to; - } + union { + float value_float; + int value_int; + float3 value_color; + float3 value_vector; + float3 value_point; + float3 value_normal; + }; + ustring value_string; + +private: + static const int MAX_TYPE = 12; + static bool register_types(); + static Node* create(const NodeType *type); + static const NodeType *node_types[MAX_TYPE][MAX_TYPE]; + static bool initialized; }; class BsdfNode : public ShaderNode { public: - explicit BsdfNode(bool scattering = false); + explicit BsdfNode(const NodeType *node_type); SHADER_NODE_BASE_CLASS(BsdfNode); bool has_spatial_varying() { return true; } void compile(SVMCompiler& compiler, ShaderInput *param1, ShaderInput *param2, ShaderInput *param3 = NULL, ShaderInput *param4 = NULL); virtual ClosureType get_closure_type() { return closure; } + float3 color; + float3 normal; + float surface_mix_weight; ClosureType closure; - bool scattering; - virtual bool equals(const ShaderNode * /*other*/) + virtual bool equals(const ShaderNode& /*other*/) { /* TODO(sergey): With some care BSDF nodes can be de-duplicated. */ return false; @@ -408,8 +346,9 @@ class AnisotropicBsdfNode : public BsdfNode { public: SHADER_NODE_CLASS(AnisotropicBsdfNode) + float3 tangent; + float roughness, anisotropy, rotation; ClosureType distribution; - static NodeEnum distribution_enum; void attributes(Shader *shader, AttributeRequestSet *attributes); }; @@ -417,6 +356,8 @@ public: class DiffuseBsdfNode : public BsdfNode { public: SHADER_NODE_CLASS(DiffuseBsdfNode) + + float roughness; }; class TranslucentBsdfNode : public BsdfNode { @@ -434,6 +375,8 @@ public: class VelvetBsdfNode : public BsdfNode { public: SHADER_NODE_CLASS(VelvetBsdfNode) + + float sigma; }; class GlossyBsdfNode : public BsdfNode { @@ -443,8 +386,8 @@ public: void simplify_settings(Scene *scene); bool has_integrator_dependency(); + float roughness; ClosureType distribution, distribution_orig; - static NodeEnum distribution_enum; }; class GlassBsdfNode : public BsdfNode { @@ -454,8 +397,8 @@ public: void simplify_settings(Scene *scene); bool has_integrator_dependency(); + float roughness, IOR; ClosureType distribution, distribution_orig; - static NodeEnum distribution_enum; }; class RefractionBsdfNode : public BsdfNode { @@ -465,16 +408,16 @@ public: void simplify_settings(Scene *scene); bool has_integrator_dependency(); + float roughness, IOR; ClosureType distribution, distribution_orig; - static NodeEnum distribution_enum; }; class ToonBsdfNode : public BsdfNode { public: SHADER_NODE_CLASS(ToonBsdfNode) + float smooth, size; ClosureType component; - static NodeEnum component_enum; }; class SubsurfaceScatteringNode : public BsdfNode { @@ -483,8 +426,11 @@ public: bool has_surface_bssrdf() { return true; } bool has_bssrdf_bump(); + float scale; + float3 radius; + float sharpness; + float texture_blur; ClosureType falloff; - static NodeEnum falloff_enum; }; class EmissionNode : public ShaderNode { @@ -494,6 +440,10 @@ public: virtual ClosureType get_closure_type() { return CLOSURE_EMISSION_ID; } bool has_surface_emission() { return true; } + + float3 color; + float strength; + float surface_mix_weight; }; class BackgroundNode : public ShaderNode { @@ -501,6 +451,10 @@ public: SHADER_NODE_CLASS(BackgroundNode) bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized); virtual ClosureType get_closure_type() { return CLOSURE_BACKGROUND_ID; } + + float3 color; + float strength; + float surface_mix_weight; }; class HoldoutNode : public ShaderNode { @@ -508,6 +462,9 @@ public: SHADER_NODE_CLASS(HoldoutNode) virtual int get_group() { return NODE_GROUP_LEVEL_1; } virtual ClosureType get_closure_type() { return CLOSURE_HOLDOUT_ID; } + + float surface_mix_weight; + float volume_mix_weight; }; class AmbientOcclusionNode : public ShaderNode { @@ -517,11 +474,16 @@ public: bool has_spatial_varying() { return true; } virtual int get_group() { return NODE_GROUP_LEVEL_1; } virtual ClosureType get_closure_type() { return CLOSURE_AMBIENT_OCCLUSION_ID; } + + float3 normal_osl; + float3 color; + float surface_mix_weight; }; class VolumeNode : public ShaderNode { public: - SHADER_NODE_CLASS(VolumeNode) + VolumeNode(const NodeType *node_type); + SHADER_NODE_BASE_CLASS(VolumeNode) void compile(SVMCompiler& compiler, ShaderInput *param1, ShaderInput *param2); virtual int get_group() { return NODE_GROUP_LEVEL_1; } @@ -530,9 +492,12 @@ public: } virtual ClosureType get_closure_type() { return closure; } + float3 color; + float density; + float volume_mix_weight; ClosureType closure; - virtual bool equals(const ShaderNode * /*other*/) + virtual bool equals(const ShaderNode& /*other*/) { /* TODO(sergey): With some care Volume nodes can be de-duplicated. */ return false; @@ -547,6 +512,8 @@ public: class ScatterVolumeNode : public VolumeNode { public: SHADER_NODE_CLASS(ScatterVolumeNode) + + float anisotropy; }; class HairBsdfNode : public BsdfNode { @@ -554,8 +521,10 @@ public: SHADER_NODE_CLASS(HairBsdfNode) ClosureType component; - static NodeEnum component_enum; - + float offset; + float roughness_u; + float roughness_v; + float3 tangent; }; class GeometryNode : public ShaderNode { @@ -563,6 +532,8 @@ public: SHADER_NODE_CLASS(GeometryNode) void attributes(Shader *shader, AttributeRequestSet *attributes); bool has_spatial_varying() { return true; } + + float3 normal_osl; }; class TextureCoordinateNode : public ShaderNode { @@ -572,17 +543,10 @@ public: bool has_spatial_varying() { return true; } bool has_object_dependency() { return use_transform; } + float3 normal_osl; bool from_dupli; bool use_transform; Transform ob_tfm; - - virtual bool equals(const ShaderNode *other) { - const TextureCoordinateNode *texco_node = (const TextureCoordinateNode*)other; - return ShaderNode::equals(other) && - from_dupli == texco_node->from_dupli && - use_transform == texco_node->use_transform && - ob_tfm == texco_node->ob_tfm; - } }; class UVMapNode : public ShaderNode { @@ -594,13 +558,6 @@ public: ustring attribute; bool from_dupli; - - virtual bool equals(const ShaderNode *other) { - const UVMapNode *uv_map_node = (const UVMapNode*)other; - return ShaderNode::equals(other) && - attribute == uv_map_node->attribute && - from_dupli == uv_map_node->from_dupli; - } }; class LightPathNode : public ShaderNode { @@ -614,6 +571,9 @@ public: SHADER_NODE_CLASS(LightFalloffNode) bool has_spatial_varying() { return true; } virtual int get_group() { return NODE_GROUP_LEVEL_2; } + + float strength; + float smooth; }; class ObjectInfoNode : public ShaderNode { @@ -648,12 +608,6 @@ public: bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized); float value; - - virtual bool equals(const ShaderNode *other) { - const ValueNode *value_node = (const ValueNode*)other; - return ShaderNode::equals(other) && - value == value_node->value; - } }; class ColorNode : public ShaderNode { @@ -663,12 +617,6 @@ public: bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized); float3 value; - - virtual bool equals(const ShaderNode *other) { - const ColorNode *color_node = (const ColorNode*)other; - return ShaderNode::equals(other) && - value == color_node->value; - } }; class AddClosureNode : public ShaderNode { @@ -680,18 +628,26 @@ class MixClosureNode : public ShaderNode { public: SHADER_NODE_CLASS(MixClosureNode) bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized); + + float fac; }; class MixClosureWeightNode : public ShaderNode { public: SHADER_NODE_CLASS(MixClosureWeightNode); + + float weight; + float fac; }; class InvertNode : public ShaderNode { public: SHADER_NODE_CLASS(InvertNode) - + bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized); virtual int get_group() { return NODE_GROUP_LEVEL_3; } + + float fac; + float3 color; }; class MixNode : public ShaderNode { @@ -701,80 +657,97 @@ public: virtual int get_group() { return NODE_GROUP_LEVEL_3; } - bool use_clamp; - NodeMix type; - static NodeEnum type_enum; - - virtual bool equals(const ShaderNode *other) - { - const MixNode *mix_node = (const MixNode*)other; - return ShaderNode::equals(other) && - use_clamp == mix_node->use_clamp && - type == mix_node->type; - } + bool use_clamp; + float3 color1; + float3 color2; + float fac; }; class CombineRGBNode : public ShaderNode { public: SHADER_NODE_CLASS(CombineRGBNode) - + bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized); virtual int get_group() { return NODE_GROUP_LEVEL_3; } + + float r, g, b; }; class CombineHSVNode : public ShaderNode { public: SHADER_NODE_CLASS(CombineHSVNode) - + bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized); virtual int get_group() { return NODE_GROUP_LEVEL_3; } + + float h, s, v; }; class CombineXYZNode : public ShaderNode { public: SHADER_NODE_CLASS(CombineXYZNode) - + bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized); virtual int get_group() { return NODE_GROUP_LEVEL_3; } + + float x, y, z; }; class GammaNode : public ShaderNode { public: SHADER_NODE_CLASS(GammaNode) - bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized); - virtual int get_group() { return NODE_GROUP_LEVEL_1; } + + float3 color; + float gamma; }; class BrightContrastNode : public ShaderNode { public: SHADER_NODE_CLASS(BrightContrastNode) + bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized); virtual int get_group() { return NODE_GROUP_LEVEL_1; } + + float3 color; + float bright; + float contrast; }; class SeparateRGBNode : public ShaderNode { public: SHADER_NODE_CLASS(SeparateRGBNode) - + bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized); virtual int get_group() { return NODE_GROUP_LEVEL_3; } + + float3 color; }; class SeparateHSVNode : public ShaderNode { public: SHADER_NODE_CLASS(SeparateHSVNode) - + bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized); virtual int get_group() { return NODE_GROUP_LEVEL_3; } + + float3 color; }; class SeparateXYZNode : public ShaderNode { public: SHADER_NODE_CLASS(SeparateXYZNode) - + bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized); virtual int get_group() { return NODE_GROUP_LEVEL_3; } + + float3 vector; }; class HSVNode : public ShaderNode { public: SHADER_NODE_CLASS(HSVNode) + + float hue; + float saturation; + float value; + float fac; + float3 color; }; class AttributeNode : public ShaderNode { @@ -784,12 +757,6 @@ public: bool has_spatial_varying() { return true; } ustring attribute; - - virtual bool equals(const ShaderNode *other) { - const AttributeNode *color_node = (const AttributeNode*)other; - return ShaderNode::equals(other) && - attribute == color_node->attribute; - } }; class CameraNode : public ShaderNode { @@ -803,6 +770,9 @@ public: SHADER_NODE_CLASS(FresnelNode) bool has_spatial_varying() { return true; } virtual int get_group() { return NODE_GROUP_LEVEL_1; } + + float3 normal; + float IOR; }; class LayerWeightNode : public ShaderNode { @@ -810,6 +780,9 @@ public: SHADER_NODE_CLASS(LayerWeightNode) bool has_spatial_varying() { return true; } virtual int get_group() { return NODE_GROUP_LEVEL_1; } + + float3 normal; + float blend; }; class WireframeNode : public ShaderNode { @@ -818,22 +791,25 @@ public: bool has_spatial_varying() { return true; } virtual int get_group() { return NODE_GROUP_LEVEL_3; } + float size; bool use_pixel_size; }; class WavelengthNode : public ShaderNode { public: SHADER_NODE_CLASS(WavelengthNode) - virtual int get_group() { return NODE_GROUP_LEVEL_3; } + + float wavelength; }; class BlackbodyNode : public ShaderNode { public: SHADER_NODE_CLASS(BlackbodyNode) bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized); - virtual int get_group() { return NODE_GROUP_LEVEL_3; } + + float temperature; }; class MathNode : public ShaderNode { @@ -842,18 +818,10 @@ public: virtual int get_group() { return NODE_GROUP_LEVEL_1; } bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized); - bool use_clamp; - + float value1; + float value2; NodeMath type; - static NodeEnum type_enum; - - virtual bool equals(const ShaderNode *other) - { - const MathNode *math_node = (const MathNode*)other; - return ShaderNode::equals(other) && - use_clamp == math_node->use_clamp && - type == math_node->type; - } + bool use_clamp; }; class NormalNode : public ShaderNode { @@ -862,13 +830,7 @@ public: virtual int get_group() { return NODE_GROUP_LEVEL_2; } float3 direction; - - virtual bool equals(const ShaderNode *other) - { - const NormalNode *normal_node = (const NormalNode*)other; - return ShaderNode::equals(other) && - direction == normal_node->direction; - } + float3 normal; }; class VectorMathNode : public ShaderNode { @@ -877,15 +839,9 @@ public: virtual int get_group() { return NODE_GROUP_LEVEL_1; } bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized); + float3 vector1; + float3 vector2; NodeVectorMath type; - static NodeEnum type_enum; - - virtual bool equals(const ShaderNode *other) - { - const VectorMathNode *math_node = (const VectorMathNode*)other; - return ShaderNode::equals(other) && - type == math_node->type; - } }; class VectorTransformNode : public ShaderNode { @@ -897,17 +853,7 @@ public: NodeVectorTransformType type; NodeVectorTransformConvertSpace convert_from; NodeVectorTransformConvertSpace convert_to; - - static NodeEnum type_enum; - static NodeEnum convert_space_enum; - - virtual bool equals(const ShaderNode *other) { - const VectorTransformNode *vector_transform_node = (const VectorTransformNode*)other; - return ShaderNode::equals(other) && - type == vector_transform_node->type && - convert_from == vector_transform_node->convert_from && - convert_to == vector_transform_node->convert_to; - } + float3 vector; }; class BumpNode : public ShaderNode { @@ -920,49 +866,56 @@ public: } bool invert; - - virtual bool equals(const ShaderNode *other) { - const BumpNode *bump_node = (const BumpNode*)other; - return ShaderNode::equals(other) && - invert == bump_node->invert; - } + float height; + float sample_center; + float sample_x; + float sample_y; + float3 normal; + float strength; + float distance; }; -class RGBCurvesNode : public ShaderNode { +class CurvesNode : public ShaderNode { public: - SHADER_NODE_CLASS(RGBCurvesNode) + explicit CurvesNode(const NodeType *node_type); + SHADER_NODE_BASE_CLASS(CurvesNode); virtual int get_group() { return NODE_GROUP_LEVEL_3; } - virtual bool equals(const ShaderNode * /*other*/) { return false; } + + bool has_spatial_varying() { return true; } + void compile(SVMCompiler& compiler, int type, ShaderInput *value_in, ShaderOutput *value_out); + void compile(OSLCompiler& compiler, const char *name); array<float3> curves; - float min_x, max_x; + float min_x, max_x, fac; + float3 value; }; -class VectorCurvesNode : public ShaderNode { +class RGBCurvesNode : public CurvesNode { public: - SHADER_NODE_CLASS(VectorCurvesNode) - - virtual int get_group() { return NODE_GROUP_LEVEL_3; } - virtual bool equals(const ShaderNode * /*other*/) { return false; } + SHADER_NODE_CLASS(RGBCurvesNode) +}; - array<float3> curves; - float min_x, max_x; +class VectorCurvesNode : public CurvesNode { +public: + SHADER_NODE_CLASS(VectorCurvesNode) }; class RGBRampNode : public ShaderNode { public: SHADER_NODE_CLASS(RGBRampNode) + virtual int get_group() { return NODE_GROUP_LEVEL_1; } + array<float3> ramp; array<float> ramp_alpha; + float fac; bool interpolate; - virtual int get_group() { return NODE_GROUP_LEVEL_1; } - virtual bool equals(const ShaderNode * /*other*/) { return false; } }; class SetNormalNode : public ShaderNode { public: SHADER_NODE_CLASS(SetNormalNode) + float3 direction; }; class OSLNode : public ShaderNode { @@ -970,17 +923,20 @@ public: static OSLNode *create(size_t num_inputs); ~OSLNode(); - SHADER_NODE_BASE_CLASS(OSLNode) + ShaderNode *clone() const; + + char* input_default_value(); + void add_input(ustring name, SocketType::Type type); + void add_output(ustring name, SocketType::Type type); + + SHADER_NODE_NO_CLONE_CLASS(OSLNode) /* ideally we could beter detect this, but we can't query this now */ bool has_spatial_varying() { return true; } - virtual bool equals(const ShaderNode * /*other*/) { return false; } + virtual bool equals(const ShaderNode& /*other*/) { return false; } string filepath; string bytecode_hash; - -private: - OSLNode(); }; class NormalMapNode : public ShaderNode { @@ -991,17 +947,10 @@ public: virtual int get_group() { return NODE_GROUP_LEVEL_3; } NodeNormalMapSpace space; - static NodeEnum space_enum; - ustring attribute; - - virtual bool equals(const ShaderNode *other) - { - const NormalMapNode *normal_map_node = (const NormalMapNode*)other; - return ShaderNode::equals(other) && - space == normal_map_node->space && - attribute == normal_map_node->attribute; - } + float strength; + float3 color; + float3 normal_osl; }; class TangentNode : public ShaderNode { @@ -1013,19 +962,8 @@ public: NodeTangentDirectionType direction_type; NodeTangentAxis axis; - static NodeEnum direction_type_enum; - static NodeEnum axis_enum; - ustring attribute; - - virtual bool equals(const ShaderNode *other) - { - const TangentNode *tangent_node = (const TangentNode*)other; - return ShaderNode::equals(other) && - direction_type == tangent_node->direction_type && - axis == tangent_node->axis && - attribute == tangent_node->attribute; - } + float3 normal_osl; }; CCL_NAMESPACE_END diff --git a/intern/cycles/render/object.cpp b/intern/cycles/render/object.cpp index 9ee1a9ef7a6..ff1f678c2d2 100644 --- a/intern/cycles/render/object.cpp +++ b/intern/cycles/render/object.cpp @@ -39,8 +39,8 @@ NODE_DEFINE(Object) SOCKET_NODE(mesh, "Mesh", &Mesh::node_type); SOCKET_TRANSFORM(tfm, "Transform", transform_identity()); - SOCKET_INT(visibility, "Visibility", ~0); - SOCKET_INT(random_id, "Random ID", 0); + SOCKET_UINT(visibility, "Visibility", ~0); + SOCKET_UINT(random_id, "Random ID", 0); SOCKET_INT(pass_id, "Pass ID", 0); SOCKET_BOOLEAN(use_holdout, "Use Holdout", false); SOCKET_POINT(dupli_generated, "Dupli Generated", make_float3(0.0f, 0.0f, 0.0f)); @@ -225,6 +225,16 @@ vector<float> Object::motion_times() return times; } +bool Object::is_traceable() +{ + /* Mesh itself can be empty,can skip all such objects. */ + if (bounds.size() == make_float3(0.0f, 0.0f, 0.0f)) { + return false; + } + /* TODO(sergey): Check for mesh vertices/curves. visibility flags. */ + return true; +} + /* Object Manager */ ObjectManager::ObjectManager() diff --git a/intern/cycles/render/object.h b/intern/cycles/render/object.h index 57614c95580..7ab73f3c91a 100644 --- a/intern/cycles/render/object.h +++ b/intern/cycles/render/object.h @@ -68,6 +68,11 @@ public: void apply_transform(bool apply_to_motion); vector<float> motion_times(); + + /* Check whether object is traceable and it worth adding it to + * kernel scene. + */ + bool is_traceable(); }; /* Object Manager */ diff --git a/intern/cycles/render/osl.cpp b/intern/cycles/render/osl.cpp index 1cfe3fb38e2..676afad997e 100644 --- a/intern/cycles/render/osl.cpp +++ b/intern/cycles/render/osl.cpp @@ -477,8 +477,10 @@ OSLNode *OSLShaderManager::osl_node(const std::string& filepath, continue; if(!param->isoutput && param->validdefault) { - node->add_input(param->name.c_str(), socket_type, make_float3(param->fdefault[0], param->fdefault[1], param->fdefault[2])); - continue; + float3 *default_value = (float3*)node->input_default_value(); + default_value->x = param->fdefault[0]; + default_value->y = param->fdefault[1]; + default_value->z = param->fdefault[2]; } } else if(param->type.aggregate == TypeDesc::SCALAR) { @@ -486,24 +488,21 @@ OSLNode *OSLShaderManager::osl_node(const std::string& filepath, socket_type = SocketType::INT; if(!param->isoutput && param->validdefault) { - node->add_input(param->name.c_str(), socket_type, (float)param->idefault[0]); - continue; + *(int*)node->input_default_value() = param->idefault[0]; } } else if(param->type.basetype == TypeDesc::FLOAT) { socket_type = SocketType::FLOAT; if(!param->isoutput && param->validdefault) { - node->add_input(param->name.c_str(), socket_type, param->fdefault[0]); - continue; + *(float*)node->input_default_value() = param->fdefault[0]; } } else if(param->type.basetype == TypeDesc::STRING) { socket_type = SocketType::STRING; if(!param->isoutput && param->validdefault) { - node->add_input(param->name.c_str(), socket_type); - continue; + *(ustring*)node->input_default_value() = param->sdefault[0]; } } else @@ -513,10 +512,10 @@ OSLNode *OSLShaderManager::osl_node(const std::string& filepath, continue; if(param->isoutput) { - node->add_output(param->name.c_str(), socket_type); + node->add_output(param->name, socket_type); } else { - node->add_input(param->name.c_str(), socket_type); + node->add_input(param->name, socket_type); } } @@ -528,6 +527,9 @@ OSLNode *OSLShaderManager::osl_node(const std::string& filepath, node->filepath = filepath; } + /* Generate inputs and outputs */ + node->create_inputs_outputs(node->type); + return node; } @@ -643,27 +645,28 @@ void OSLCompiler::add(ShaderNode *node, const char *name, bool isfilepath) continue; string param_name = compatible_name(node, input); + const SocketType& socket = input->socket_type; switch(input->type()) { case SocketType::COLOR: - parameter_color(param_name.c_str(), input->value()); + parameter_color(param_name.c_str(), node->get_float3(socket)); break; case SocketType::POINT: - parameter_point(param_name.c_str(), input->value()); + parameter_point(param_name.c_str(), node->get_float3(socket)); break; case SocketType::VECTOR: - parameter_vector(param_name.c_str(), input->value()); + parameter_vector(param_name.c_str(), node->get_float3(socket)); break; case SocketType::NORMAL: - parameter_normal(param_name.c_str(), input->value()); + parameter_normal(param_name.c_str(), node->get_float3(socket)); break; case SocketType::FLOAT: - parameter(param_name.c_str(), input->value_float()); + parameter(param_name.c_str(), node->get_float(socket)); break; case SocketType::INT: - parameter(param_name.c_str(), (int)input->value_float()); + parameter(param_name.c_str(), node->get_int(socket)); break; case SocketType::STRING: - parameter(param_name.c_str(), input->value_string()); + parameter(param_name.c_str(), node->get_string(socket)); break; case SocketType::CLOSURE: case SocketType::UNDEFINED: @@ -733,6 +736,169 @@ void OSLCompiler::add(ShaderNode *node, const char *name, bool isfilepath) } } +static TypeDesc array_typedesc(TypeDesc typedesc, int arraylength) +{ + return TypeDesc((TypeDesc::BASETYPE)typedesc.basetype, + (TypeDesc::AGGREGATE)typedesc.aggregate, + (TypeDesc::VECSEMANTICS)typedesc.vecsemantics, + arraylength); +} + +void OSLCompiler::parameter(ShaderNode* node, const char *name) +{ + OSL::ShadingSystem *ss = (OSL::ShadingSystem*)shadingsys; + ustring uname = ustring(name); + const SocketType& socket = *(node->type->find_input(uname)); + + switch(socket.type) + { + case SocketType::BOOLEAN: + { + int value = node->get_bool(socket); + ss->Parameter(name, TypeDesc::TypeInt, &value); + break; + } + case SocketType::FLOAT: + { + float value = node->get_float(socket); + ss->Parameter(uname, TypeDesc::TypeFloat, &value); + break; + } + case SocketType::INT: + { + int value = node->get_int(socket); + ss->Parameter(uname, TypeDesc::TypeInt, &value); + break; + } + case SocketType::COLOR: + { + float3 value = node->get_float3(socket); + ss->Parameter(uname, TypeDesc::TypeColor, &value); + break; + } + case SocketType::VECTOR: + { + float3 value = node->get_float3(socket); + ss->Parameter(uname, TypeDesc::TypeVector, &value); + break; + } + case SocketType::POINT: + { + float3 value = node->get_float3(socket); + ss->Parameter(uname, TypeDesc::TypePoint, &value); + break; + } + case SocketType::NORMAL: + { + float3 value = node->get_float3(socket); + ss->Parameter(uname, TypeDesc::TypeNormal, &value); + break; + } + case SocketType::POINT2: + { + float2 value = node->get_float2(socket); + ss->Parameter(uname, TypeDesc(TypeDesc::FLOAT, TypeDesc::VEC2, TypeDesc::POINT), &value); + break; + } + case SocketType::STRING: + { + ustring value = node->get_string(socket); + ss->Parameter(uname, TypeDesc::TypeString, &value); + break; + } + case SocketType::ENUM: + { + ustring value = node->get_string(socket); + ss->Parameter(uname, TypeDesc::TypeString, &value); + break; + } + case SocketType::TRANSFORM: + { + Transform value = node->get_transform(socket); + ss->Parameter(uname, TypeDesc::TypeMatrix, &value); + break; + } + case SocketType::BOOLEAN_ARRAY: + { + // OSL does not support booleans, so convert to int + const array<bool>& value = node->get_bool_array(socket); + array<int> intvalue(value.size()); + for (size_t i = 0; i < value.size(); i++) + intvalue[i] = value[i]; + ss->Parameter(uname, array_typedesc(TypeDesc::TypeInt, value.size()), intvalue.data()); + break; + } + case SocketType::FLOAT_ARRAY: + { + const array<float>& value = node->get_float_array(socket); + ss->Parameter(uname, array_typedesc(TypeDesc::TypeFloat, value.size()), value.data()); + break; + } + case SocketType::INT_ARRAY: + { + const array<int>& value = node->get_int_array(socket); + ss->Parameter(uname, array_typedesc(TypeDesc::TypeInt, value.size()), value.data()); + break; + } + case SocketType::COLOR_ARRAY: + case SocketType::VECTOR_ARRAY: + case SocketType::POINT_ARRAY: + case SocketType::NORMAL_ARRAY: + { + TypeDesc typedesc; + + switch(socket.type) + { + case SocketType::COLOR_ARRAY: typedesc = TypeDesc::TypeColor; break; + case SocketType::VECTOR_ARRAY: typedesc = TypeDesc::TypeVector; break; + case SocketType::POINT_ARRAY: typedesc = TypeDesc::TypePoint; break; + case SocketType::NORMAL_ARRAY: typedesc = TypeDesc::TypeNormal; break; + default: assert(0); break; + } + + // convert to tightly packed array since float3 has padding + const array<float3>& value = node->get_float3_array(socket); + array<float> fvalue(value.size() * 3); + for (size_t i = 0, j = 0; i < value.size(); i++) + { + fvalue[j++] = value[i].x; + fvalue[j++] = value[i].y; + fvalue[j++] = value[i].z; + } + + ss->Parameter(uname, array_typedesc(typedesc, value.size()), fvalue.data()); + break; + } + case SocketType::POINT2_ARRAY: + { + const array<float2>& value = node->get_float2_array(socket); + ss->Parameter(uname, array_typedesc(TypeDesc(TypeDesc::FLOAT, TypeDesc::VEC2, TypeDesc::POINT), value.size()), value.data()); + break; + } + case SocketType::STRING_ARRAY: + { + const array<ustring>& value = node->get_string_array(socket); + ss->Parameter(uname, array_typedesc(TypeDesc::TypeString, value.size()), value.data()); + break; + } + case SocketType::TRANSFORM_ARRAY: + { + const array<Transform>& value = node->get_transform_array(socket); + ss->Parameter(uname, array_typedesc(TypeDesc::TypeMatrix, value.size()), value.data()); + break; + } + case SocketType::CLOSURE: + case SocketType::NODE: + case SocketType::NODE_ARRAY: + case SocketType::UNDEFINED: + case SocketType::UINT: + { + assert(0); + break; + } + } +} + void OSLCompiler::parameter(const char *name, float f) { OSL::ShadingSystem *ss = (OSL::ShadingSystem*)shadingsys; @@ -996,6 +1162,10 @@ void OSLCompiler::add(ShaderNode * /*node*/, const char * /*name*/, bool /*isfil { } +void OSLCompiler::parameter(ShaderNode * /*node*/, const char * /*name*/) +{ +} + void OSLCompiler::parameter(const char * /*name*/, float /*f*/) { } diff --git a/intern/cycles/render/osl.h b/intern/cycles/render/osl.h index 13b9d6307f9..b131b672b8c 100644 --- a/intern/cycles/render/osl.h +++ b/intern/cycles/render/osl.h @@ -125,6 +125,8 @@ public: void add(ShaderNode *node, const char *name, bool isfilepath = false); + void parameter(ShaderNode *node, const char *name); + void parameter(const char *name, float f); void parameter_color(const char *name, float3 f); void parameter_vector(const char *name, float3 f); diff --git a/intern/cycles/render/scene.h b/intern/cycles/render/scene.h index b34d6127118..b821e2b6475 100644 --- a/intern/cycles/render/scene.h +++ b/intern/cycles/render/scene.h @@ -113,6 +113,8 @@ public: device_vector<float4> tex_float4_image[TEX_NUM_FLOAT4_CPU]; device_vector<float> tex_float_image[TEX_NUM_FLOAT_CPU]; device_vector<uchar> tex_byte_image[TEX_NUM_BYTE_CPU]; + device_vector<half4> tex_half4_image[TEX_NUM_HALF4_CPU]; + device_vector<half> tex_half_image[TEX_NUM_HALF_CPU]; /* opencl images */ device_vector<uchar4> tex_image_byte4_packed; diff --git a/intern/cycles/render/shader.cpp b/intern/cycles/render/shader.cpp index 708eeef3b50..4cdb878df45 100644 --- a/intern/cycles/render/shader.cpp +++ b/intern/cycles/render/shader.cpp @@ -449,17 +449,15 @@ void ShaderManager::device_free_common(Device *device, DeviceScene *dscene, Scen void ShaderManager::add_default(Scene *scene) { - ShaderNode *closure, *out; - /* default surface */ { ShaderGraph *graph = new ShaderGraph(); - closure = graph->add(new DiffuseBsdfNode()); - closure->input("Color")->set(make_float3(0.8f, 0.8f, 0.8f)); - out = graph->output(); + DiffuseBsdfNode *diffuse = new DiffuseBsdfNode(); + diffuse->color = make_float3(0.8f, 0.8f, 0.8f); + graph->add(diffuse); - graph->connect(closure->output("BSDF"), out->input("Surface")); + graph->connect(diffuse->output("BSDF"), graph->output()->input("Surface")); Shader *shader = new Shader(); shader->name = "default_surface"; @@ -472,12 +470,12 @@ void ShaderManager::add_default(Scene *scene) { ShaderGraph *graph = new ShaderGraph(); - closure = graph->add(new EmissionNode()); - closure->input("Color")->set(make_float3(0.8f, 0.8f, 0.8f)); - closure->input("Strength")->set(0.0f); - out = graph->output(); + EmissionNode *emission = new EmissionNode(); + emission->color = make_float3(0.8f, 0.8f, 0.8f); + emission->strength = 0.0f; + graph->add(emission); - graph->connect(closure->output("Emission"), out->input("Surface")); + graph->connect(emission->output("Emission"), graph->output()->input("Surface")); Shader *shader = new Shader(); shader->name = "default_light"; diff --git a/intern/cycles/render/svm.cpp b/intern/cycles/render/svm.cpp index d54afd1ba6f..f0e7ee2bd49 100644 --- a/intern/cycles/render/svm.cpp +++ b/intern/cycles/render/svm.cpp @@ -192,14 +192,16 @@ int SVMCompiler::stack_assign(ShaderInput *input) input->stack_offset = input->link->stack_offset; } else { + Node *node = input->parent; + /* not linked to output -> add nodes to load default value */ input->stack_offset = stack_find_offset(input->type()); if(input->type() == SocketType::FLOAT) { - add_node(NODE_VALUE_F, __float_as_int(input->value_float()), input->stack_offset); + add_node(NODE_VALUE_F, __float_as_int(node->get_float(input->socket_type)), input->stack_offset); } else if(input->type() == SocketType::INT) { - add_node(NODE_VALUE_F, (int)input->value_float(), input->stack_offset); + add_node(NODE_VALUE_F, node->get_int(input->socket_type), input->stack_offset); } else if(input->type() == SocketType::VECTOR || input->type() == SocketType::NORMAL || @@ -208,7 +210,7 @@ int SVMCompiler::stack_assign(ShaderInput *input) { add_node(NODE_VALUE_V, input->stack_offset); - add_node(NODE_VALUE_V, input->value()); + add_node(NODE_VALUE_V, node->get_float3(input->socket_type)); } else /* should not get called for closure */ assert(0); @@ -446,7 +448,7 @@ void SVMCompiler::generate_closure_node(ShaderNode *node, const char *weight_name = (current_type == SHADER_TYPE_VOLUME)? "VolumeMixWeight": "SurfaceMixWeight"; ShaderInput *weight_in = node->input(weight_name); - if(weight_in && (weight_in->link || weight_in->value_float() != 1.0f)) + if(weight_in && (weight_in->link || node->get_float(weight_in->socket_type) != 1.0f)) mix_weight_offset = stack_assign(weight_in); else mix_weight_offset = SVM_STACK_INVALID; diff --git a/intern/cycles/subd/subd_dice.cpp b/intern/cycles/subd/subd_dice.cpp index 8dba1379855..7c74f21950e 100644 --- a/intern/cycles/subd/subd_dice.cpp +++ b/intern/cycles/subd/subd_dice.cpp @@ -46,7 +46,7 @@ void EdgeDice::reserve(int num_verts) Mesh *mesh = params.mesh; vert_offset = mesh->verts.size(); - tri_offset = mesh->triangles.size(); + tri_offset = mesh->num_triangles(); mesh->resize_mesh(vert_offset + num_verts, tri_offset); @@ -84,7 +84,7 @@ void EdgeDice::add_triangle(Patch *patch, int v0, int v1, int v2) /* todo: optimize so we can reserve in advance, this is like push_back_slow() */ if(mesh->triangles.size() == mesh->triangles.capacity()) - mesh->reserve_mesh(mesh->verts.size(), size_t(max(mesh->triangles.size() + 1, 1) * 1.2)); + mesh->reserve_mesh(mesh->verts.size(), size_t(max(mesh->num_triangles() + 1, 1) * 1.2)); mesh->add_triangle(v0, v1, v2, params.shader, params.smooth, false); diff --git a/intern/cycles/util/CMakeLists.txt b/intern/cycles/util/CMakeLists.txt index cceec8d444c..e6140b3ed09 100644 --- a/intern/cycles/util/CMakeLists.txt +++ b/intern/cycles/util/CMakeLists.txt @@ -19,8 +19,10 @@ set(SRC util_simd.cpp util_system.cpp util_task.cpp + util_thread.cpp util_time.cpp util_transform.cpp + util_windows.cpp ) if(NOT CYCLES_STANDALONE_REPOSITORY) diff --git a/intern/cycles/util/util_half.h b/intern/cycles/util/util_half.h index f4bac9888a5..ae85ab3a915 100644 --- a/intern/cycles/util/util_half.h +++ b/intern/cycles/util/util_half.h @@ -85,6 +85,27 @@ ccl_device_inline void float4_store_half(half *h, float4 f, float scale) #endif } +ccl_device_inline float half_to_float(half h) +{ + float f; + + *((int*) &f) = ((h & 0x8000) << 16) | (((h & 0x7c00) + 0x1C000) << 13) | ((h & 0x03FF) << 13); + + return f; +} + +ccl_device_inline float4 half4_to_float4(half4 h) +{ + float4 f; + + f.x = half_to_float(h.x); + f.y = half_to_float(h.y); + f.z = half_to_float(h.z); + f.w = half_to_float(h.w); + + return f; +} + #endif #endif diff --git a/intern/cycles/util/util_math.h b/intern/cycles/util/util_math.h index 32924f9a8c2..cfe6fa65143 100644 --- a/intern/cycles/util/util_math.h +++ b/intern/cycles/util/util_math.h @@ -545,6 +545,11 @@ ccl_device_inline float3 normalize(const float3 a) #endif +ccl_device_inline float3 saturate3(float3 a) +{ + return make_float3(saturate(a.x), saturate(a.y), saturate(a.z)); +} + ccl_device_inline float3 normalize_len(const float3 a, float *t) { *t = len(a); @@ -1329,6 +1334,15 @@ ccl_device float safe_modulo(float a, float b) return (b != 0.0f)? fmodf(a, b): 0.0f; } +ccl_device_inline float beta(float x, float y) +{ +#ifndef __KERNEL_OPENCL__ + return expf(lgammaf(x) + lgammaf(y) - lgammaf(x+y)); +#else + return expf(lgamma(x) + lgamma(y) - lgamma(x+y)); +#endif +} + /* Ray Intersection */ ccl_device bool ray_sphere_intersect( @@ -1479,21 +1493,25 @@ ccl_device bool ray_triangle_intersect_uv( return true; } -ccl_device bool ray_quad_intersect(float3 ray_P, float3 ray_D, float ray_t, - float3 quad_P, float3 quad_u, float3 quad_v, +ccl_device bool ray_quad_intersect(float3 ray_P, float3 ray_D, float ray_mint, float ray_maxt, + float3 quad_P, float3 quad_u, float3 quad_v, float3 quad_n, float3 *isect_P, float *isect_t) { - float3 v0 = quad_P - quad_u*0.5f - quad_v*0.5f; - float3 v1 = quad_P + quad_u*0.5f - quad_v*0.5f; - float3 v2 = quad_P + quad_u*0.5f + quad_v*0.5f; - float3 v3 = quad_P - quad_u*0.5f + quad_v*0.5f; + float t = -(dot(ray_P, quad_n) - dot(quad_P, quad_n)) / dot(ray_D, quad_n); + if(t < ray_mint || t > ray_maxt) + return false; - if(ray_triangle_intersect(ray_P, ray_D, ray_t, v0, v1, v2, isect_P, isect_t)) - return true; - else if(ray_triangle_intersect(ray_P, ray_D, ray_t, v0, v2, v3, isect_P, isect_t)) - return true; - - return false; + float3 hit = ray_P + t*ray_D; + float3 inplane = hit - quad_P; + if(fabsf(dot(inplane, quad_u) / dot(quad_u, quad_u)) > 0.5f) + return false; + if(fabsf(dot(inplane, quad_v) / dot(quad_v, quad_v)) > 0.5f) + return false; + + if(isect_P) *isect_P = hit; + if(isect_t) *isect_t = t; + + return true; } /* projections */ diff --git a/intern/cycles/util/util_string.cpp b/intern/cycles/util/util_string.cpp index e16a83d56d0..c1c5a6b084b 100644 --- a/intern/cycles/util/util_string.cpp +++ b/intern/cycles/util/util_string.cpp @@ -260,7 +260,11 @@ string string_human_readable_size(size_t size) string string_human_readable_number(size_t num) { - /* add thousands separators */ + if(num == 0) { + return "0"; + } + + /* Add thousands separators. */ char buf[32]; char* p = buf+31; diff --git a/intern/cycles/util/util_system.cpp b/intern/cycles/util/util_system.cpp index 4ff0ee91d73..d5fac9a0e34 100644 --- a/intern/cycles/util/util_system.cpp +++ b/intern/cycles/util/util_system.cpp @@ -15,7 +15,9 @@ */ #include "util_system.h" + #include "util_debug.h" +#include "util_logging.h" #include "util_types.h" #include "util_string.h" @@ -33,28 +35,56 @@ CCL_NAMESPACE_BEGIN -int system_cpu_thread_count() +int system_cpu_group_count() { - static uint count = 0; - - if(count > 0) - return count; +#ifdef _WIN32 + util_windows_init_numa_groups(); + return GetActiveProcessorGroupCount(); +#else + /* TODO(sergey): Need to adopt for other platforms. */ + return 1; +#endif +} +int system_cpu_group_thread_count(int group) +{ + /* TODO(sergey): Need make other platforms aware of groups. */ #ifdef _WIN32 - SYSTEM_INFO info; - GetSystemInfo(&info); - count = (uint)info.dwNumberOfProcessors; + util_windows_init_numa_groups(); + return GetActiveProcessorCount(group); #elif defined(__APPLE__) + (void)group; + int count; size_t len = sizeof(count); int mib[2] = { CTL_HW, HW_NCPU }; - sysctl(mib, 2, &count, &len, NULL, 0); + return count; #else - count = (uint)sysconf(_SC_NPROCESSORS_ONLN); + (void)group; + return sysconf(_SC_NPROCESSORS_ONLN); #endif +} + +int system_cpu_thread_count() +{ + static uint count = 0; - if(count < 1) + if(count > 0) { + return count; + } + + int max_group = system_cpu_group_count(); + VLOG(1) << "Detected " << max_group << " CPU groups."; + for(int group = 0; group < max_group; ++group) { + int num_threads = system_cpu_group_thread_count(group); + VLOG(1) << "Group " << group + << " has " << num_threads << " threads."; + count += num_threads; + } + + if(count < 1) { count = 1; + } return count; } diff --git a/intern/cycles/util/util_system.h b/intern/cycles/util/util_system.h index 4e7e00f85fd..557aab6cbae 100644 --- a/intern/cycles/util/util_system.h +++ b/intern/cycles/util/util_system.h @@ -21,7 +21,15 @@ CCL_NAMESPACE_BEGIN +/* Get number of available CPU groups. */ +int system_cpu_group_count(); + +/* Get number of threads/processors in the specified group. */ +int system_cpu_group_thread_count(int group); + +/* Get total number of threads in all groups. */ int system_cpu_thread_count(); + string system_cpu_brand_string(); int system_cpu_bits(); bool system_cpu_support_sse2(); diff --git a/intern/cycles/util/util_task.cpp b/intern/cycles/util/util_task.cpp index d86aa8a4a46..352ba81c95a 100644 --- a/intern/cycles/util/util_task.cpp +++ b/intern/cycles/util/util_task.cpp @@ -16,6 +16,7 @@ #include "util_debug.h" #include "util_foreach.h" +#include "util_logging.h" #include "util_system.h" #include "util_task.h" #include "util_time.h" @@ -198,12 +199,30 @@ void TaskScheduler::init(int num_threads) /* automatic number of threads */ num_threads = system_cpu_thread_count(); } + VLOG(1) << "Creating pool of " << num_threads << " threads."; /* launch threads that will be waiting for work */ threads.resize(num_threads); - for(size_t i = 0; i < threads.size(); i++) - threads[i] = new thread(function_bind(&TaskScheduler::thread_run, i + 1)); + int num_groups = system_cpu_group_count(); + int thread_index = 0; + for(int group = 0; group < num_groups; ++group) { + /* NOTE: That's not really efficient from threading point of view, + * but it is simple to read and it doesn't make sense to use more + * user-specified threads than logical threads anyway. + */ + int num_group_threads = (group == num_groups - 1) + ? (threads.size() - thread_index) + : system_cpu_group_thread_count(group); + for(int group_thread = 0; + group_thread < num_group_threads && thread_index < threads.size(); + ++group_thread, ++thread_index) + { + threads[thread_index] = new thread(function_bind(&TaskScheduler::thread_run, + thread_index + 1), + group); + } + } } users++; diff --git a/intern/cycles/util/util_texture.h b/intern/cycles/util/util_texture.h index e00edc046f7..2ef47283029 100644 --- a/intern/cycles/util/util_texture.h +++ b/intern/cycles/util/util_texture.h @@ -26,40 +26,56 @@ CCL_NAMESPACE_BEGIN #define TEX_NUM_BYTE4_CPU 1024 #define TEX_NUM_FLOAT_CPU 1024 #define TEX_NUM_BYTE_CPU 1024 +#define TEX_NUM_HALF4_CPU 1024 +#define TEX_NUM_HALF_CPU 1024 #define TEX_START_FLOAT4_CPU 0 #define TEX_START_BYTE4_CPU TEX_NUM_FLOAT4_CPU #define TEX_START_FLOAT_CPU (TEX_NUM_FLOAT4_CPU + TEX_NUM_BYTE4_CPU) -#define TEX_START_BYTE_CPU (TEX_NUM_FLOAT4_CPU + TEX_NUM_BYTE4_CPU + TEX_NUM_BYTE_CPU) +#define TEX_START_BYTE_CPU (TEX_NUM_FLOAT4_CPU + TEX_NUM_BYTE4_CPU + TEX_NUM_FLOAT_CPU) +#define TEX_START_HALF4_CPU (TEX_NUM_FLOAT4_CPU + TEX_NUM_BYTE4_CPU + TEX_NUM_FLOAT_CPU + TEX_NUM_BYTE_CPU) +#define TEX_START_HALF_CPU (TEX_NUM_FLOAT4_CPU + TEX_NUM_BYTE4_CPU + TEX_NUM_FLOAT_CPU + TEX_NUM_BYTE_CPU + TEX_NUM_HALF4_CPU) /* CUDA (Geforce 4xx and 5xx) */ #define TEX_NUM_FLOAT4_CUDA 5 #define TEX_NUM_BYTE4_CUDA 88 #define TEX_NUM_FLOAT_CUDA 0 #define TEX_NUM_BYTE_CUDA 0 +#define TEX_NUM_HALF4_CUDA 0 +#define TEX_NUM_HALF_CUDA 0 #define TEX_START_FLOAT4_CUDA 0 #define TEX_START_BYTE4_CUDA TEX_NUM_FLOAT4_CUDA #define TEX_START_FLOAT_CUDA (TEX_NUM_FLOAT4_CUDA + TEX_NUM_BYTE4_CUDA) -#define TEX_START_BYTE_CUDA (TEX_NUM_FLOAT4_CUDA + TEX_NUM_BYTE4_CUDA + TEX_NUM_BYTE_CUDA) +#define TEX_START_BYTE_CUDA (TEX_NUM_FLOAT4_CUDA + TEX_NUM_BYTE4_CUDA + TEX_NUM_FLOAT_CUDA) +#define TEX_START_HALF4_CUDA (TEX_NUM_FLOAT4_CUDA + TEX_NUM_BYTE4_CUDA + TEX_NUM_FLOAT_CUDA + TEX_NUM_BYTE_CUDA) +#define TEX_START_HALF_CUDA (TEX_NUM_FLOAT4_CUDA + TEX_NUM_BYTE4_CUDA + TEX_NUM_FLOAT_CUDA + TEX_NUM_BYTE_CUDA + TEX_NUM_HALF4_CUDA) /* CUDA (Kepler, Geforce 6xx and above) */ #define TEX_NUM_FLOAT4_CUDA_KEPLER 1024 #define TEX_NUM_BYTE4_CUDA_KEPLER 1024 #define TEX_NUM_FLOAT_CUDA_KEPLER 1024 #define TEX_NUM_BYTE_CUDA_KEPLER 1024 +#define TEX_NUM_HALF4_CUDA_KEPLER 0 +#define TEX_NUM_HALF_CUDA_KEPLER 0 #define TEX_START_FLOAT4_CUDA_KEPLER 0 #define TEX_START_BYTE4_CUDA_KEPLER TEX_NUM_FLOAT4_CUDA_KEPLER #define TEX_START_FLOAT_CUDA_KEPLER (TEX_NUM_FLOAT4_CUDA_KEPLER + TEX_NUM_BYTE4_CUDA_KEPLER) -#define TEX_START_BYTE_CUDA_KEPLER (TEX_NUM_FLOAT4_CUDA_KEPLER + TEX_NUM_BYTE4_CUDA_KEPLER + TEX_NUM_BYTE_CUDA_KEPLER) +#define TEX_START_BYTE_CUDA_KEPLER (TEX_NUM_FLOAT4_CUDA_KEPLER + TEX_NUM_BYTE4_CUDA_KEPLER + TEX_NUM_FLOAT_CUDA_KEPLER) +#define TEX_START_HALF4_CUDA_KEPLER (TEX_NUM_FLOAT4_CUDA_KEPLER + TEX_NUM_BYTE4_CUDA_KEPLER + TEX_NUM_FLOAT_CUDA_KEPLER + TEX_NUM_BYTE_CUDA_KEPLER) +#define TEX_START_HALF_CUDA_KEPLER (TEX_NUM_FLOAT4_CUDA_KEPLER + TEX_NUM_BYTE4_CUDA_KEPLER + TEX_NUM_FLOAT_CUDA_KEPLER + TEX_NUM_BYTE_CUDA_KEPLER + TEX_NUM_HALF4_CUDA_KEPLER) /* OpenCL */ #define TEX_NUM_FLOAT4_OPENCL 1024 #define TEX_NUM_BYTE4_OPENCL 1024 #define TEX_NUM_FLOAT_OPENCL 0 #define TEX_NUM_BYTE_OPENCL 0 +#define TEX_NUM_HALF4_OPENCL 0 +#define TEX_NUM_HALF_OPENCL 0 #define TEX_START_FLOAT4_OPENCL 0 #define TEX_START_BYTE4_OPENCL TEX_NUM_FLOAT4_OPENCL #define TEX_START_FLOAT_OPENCL (TEX_NUM_FLOAT4_OPENCL + TEX_NUM_BYTE4_OPENCL) -#define TEX_START_BYTE_OPENCL (TEX_NUM_FLOAT4_OPENCL + TEX_NUM_BYTE4_OPENCL + TEX_NUM_BYTE_OPENCL) +#define TEX_START_BYTE_OPENCL (TEX_NUM_FLOAT4_OPENCL + TEX_NUM_BYTE4_OPENCL + TEX_NUM_FLOAT_OPENCL) +#define TEX_START_HALF4_OPENCL (TEX_NUM_FLOAT4_OPENCL + TEX_NUM_BYTE4_OPENCL + TEX_NUM_FLOAT_OPENCL + TEX_NUM_BYTE_OPENCL) +#define TEX_START_HALF_OPENCL (TEX_NUM_FLOAT4_OPENCL + TEX_NUM_BYTE4_OPENCL + TEX_NUM_FLOAT_OPENCL + TEX_NUM_BYTE_OPENCL + TEX_NUM_HALF4_OPENCL) /* Color to use when textures are not found. */ diff --git a/intern/cycles/util/util_thread.cpp b/intern/cycles/util/util_thread.cpp new file mode 100644 index 00000000000..3db8b4bd197 --- /dev/null +++ b/intern/cycles/util/util_thread.cpp @@ -0,0 +1,66 @@ +/* + * Copyright 2011-2016 Blender Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "util_thread.h" + +#include "util_system.h" +#include "util_windows.h" + +CCL_NAMESPACE_BEGIN + +thread::thread(function<void(void)> run_cb, int group) + : run_cb_(run_cb), + joined_(false), + group_(group) +{ + pthread_create(&pthread_id_, NULL, run, (void*)this); +} + +thread::~thread() +{ + if(!joined_) { + join(); + } +} + +void *thread::run(void *arg) +{ + thread *self = (thread*)(arg); + if(self->group_ != -1) { +#ifdef _WIN32 + HANDLE thread_handle = GetCurrentThread(); + GROUP_AFFINITY group_affinity = { 0 }; + int num_threads = system_cpu_group_thread_count(self->group_); + group_affinity.Group = self->group_; + group_affinity.Mask = (num_threads == 64) + ? -1 + : (1ull << num_threads) - 1; + if(SetThreadGroupAffinity(thread_handle, &group_affinity, NULL) == 0) { + fprintf(stderr, "Error setting thread affinity.\n"); + } +#endif + } + self->run_cb_(); + return NULL; +} + +bool thread::join() +{ + joined_ = true; + return pthread_join(pthread_id_, NULL) == 0; +} + +CCL_NAMESPACE_END diff --git a/intern/cycles/util/util_thread.h b/intern/cycles/util/util_thread.h index 59575f31c13..427c633d2ce 100644 --- a/intern/cycles/util/util_thread.h +++ b/intern/cycles/util/util_thread.h @@ -52,37 +52,17 @@ typedef boost::condition_variable thread_condition_variable; class thread { public: - thread(function<void(void)> run_cb_) + thread(function<void(void)> run_cb, int group = -1); + ~thread(); - { - joined = false; - run_cb = run_cb_; - - pthread_create(&pthread_id, NULL, run, (void*)this); - } - - ~thread() - { - if(!joined) - join(); - } - - static void *run(void *arg) - { - ((thread*)arg)->run_cb(); - return NULL; - } - - bool join() - { - joined = true; - return pthread_join(pthread_id, NULL) == 0; - } + static void *run(void *arg); + bool join(); protected: - function<void(void)> run_cb; - pthread_t pthread_id; - bool joined; + function<void(void)> run_cb_; + pthread_t pthread_id_; + bool joined_; + int group_; }; /* Own wrapper around pthread's spin lock to make it's use easier. */ diff --git a/intern/cycles/util/util_windows.cpp b/intern/cycles/util/util_windows.cpp new file mode 100644 index 00000000000..ee5b3fd73c0 --- /dev/null +++ b/intern/cycles/util/util_windows.cpp @@ -0,0 +1,88 @@ +/* + * Copyright 2011-2016 Blender Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "util_windows.h" + +#ifdef _WIN32 + +CCL_NAMESPACE_BEGIN + +#ifdef _M_X64 +# include <VersionHelpers.h> +#endif + +#if _WIN32_WINNT < 0x0601 +tGetActiveProcessorGroupCount *GetActiveProcessorGroupCount; +tGetActiveProcessorCount *GetActiveProcessorCount; +tSetThreadGroupAffinity *SetThreadGroupAffinity; +#endif + +static WORD GetActiveProcessorGroupCount_stub() +{ + return 1; +} + +static DWORD GetActiveProcessorCount_stub(WORD /*GroupNumber*/) +{ + SYSTEM_INFO info; + GetSystemInfo(&info); + return info.dwNumberOfProcessors; +} + +static BOOL SetThreadGroupAffinity_stub( + HANDLE /*hThread*/, + const GROUP_AFFINITY * /*GroupAffinity*/, + PGROUP_AFFINITY /*PreviousGroupAffinity*/) +{ + return TRUE; +} + +static bool supports_numa() +{ +#ifndef _M_X64 + return false; +#else + return IsWindows7OrGreater(); +#endif +} + +void util_windows_init_numa_groups() +{ + static bool initialized = false; + if(initialized) { + return; + } + initialized = true; +#if _WIN32_WINNT < 0x0601 + if(!supports_numa()) { + /* Use stubs on platforms which doesn't have rean NUMA/Groups. */ + GetActiveProcessorGroupCount = GetActiveProcessorGroupCount_stub; + GetActiveProcessorCount = GetActiveProcessorCount_stub; + SetThreadGroupAffinity = SetThreadGroupAffinity_stub; + return; + } + HMODULE kernel = GetModuleHandleA("kernel32.dll"); +# define READ_SYMBOL(sym) sym = (t##sym*)GetProcAddress(kernel, #sym) + READ_SYMBOL(GetActiveProcessorGroupCount); + READ_SYMBOL(GetActiveProcessorCount); + READ_SYMBOL(SetThreadGroupAffinity); +# undef READ_SUMBOL +#endif +} + +CCL_NAMESPACE_END + +#endif /* _WIN32 */ diff --git a/intern/cycles/util/util_windows.h b/intern/cycles/util/util_windows.h index f67e34d0f31..ac61d5348c3 100644 --- a/intern/cycles/util/util_windows.h +++ b/intern/cycles/util/util_windows.h @@ -31,6 +31,25 @@ #include <windows.h> +CCL_NAMESPACE_BEGIN + +#if _WIN32_WINNT < 0x0601 +typedef WORD tGetActiveProcessorGroupCount(); +typedef DWORD tGetActiveProcessorCount(WORD GroupNumber); +typedef BOOL tSetThreadGroupAffinity(HANDLE hThread, + const GROUP_AFFINITY *GroupAffinity, + PGROUP_AFFINITY PreviousGroupAffinity); + +extern tGetActiveProcessorGroupCount *GetActiveProcessorGroupCount; +extern tGetActiveProcessorCount *GetActiveProcessorCount; +extern tSetThreadGroupAffinity *SetThreadGroupAffinity; +#endif + +/* Make sure NUMA and processor groups API is initialized. */ +void util_windows_init_numa_groups(); + +CCL_NAMESPACE_END + #endif /* WIN32 */ #endif /* __UTIL_WINDOWS_H__ */ diff --git a/intern/decklink/CMakeLists.txt b/intern/decklink/CMakeLists.txt new file mode 100644 index 00000000000..fbef65cdba4 --- /dev/null +++ b/intern/decklink/CMakeLists.txt @@ -0,0 +1,58 @@ +# ***** 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. +# +# The Original Code is Copyright (C) 2015, Blender Foundation +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): Blender Foundation. +# +# ***** END GPL LICENSE BLOCK ***** + +set(INC +) + +set(INC_SYS +) + +set(SRC + DeckLinkAPI.cpp + DeckLinkAPI.h +) + +if (WIN32) + list(APPEND SRC + win/DeckLinkAPI_h.h + win/DeckLinkAPI_i.c + ) +endif() + +if (UNIX AND NOT APPLE) + list(APPEND SRC + linux/DeckLinkAPI.h + linux/DeckLinkAPIConfiguration.h + linux/DeckLinkAPIDeckControl.h + linux/DeckLinkAPIDiscovery.h + linux/DeckLinkAPIDispatch.cpp + linux/DeckLinkAPIModes.h + linux/DeckLinkAPIVersion.h + linux/DeckLinkAPITypes.h + linux/LinuxCOM.h + ) +endif() + +blender_add_lib(bf_intern_decklink "${SRC}" "${INC}" "${INC_SYS}") diff --git a/intern/decklink/DeckLinkAPI.cpp b/intern/decklink/DeckLinkAPI.cpp new file mode 100644 index 00000000000..aff25af70eb --- /dev/null +++ b/intern/decklink/DeckLinkAPI.cpp @@ -0,0 +1,50 @@ +/* + * ***** 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. + * + * The Original Code is Copyright (C) 2015, Blender Foundation + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Blender Foundation. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file decklink/DeckLinkAPI.cpp + * \ingroup decklink + */ + +#include "DeckLinkAPI.h" + +#ifdef WIN32 +IDeckLinkIterator* BMD_CreateDeckLinkIterator(void) +{ + HRESULT result; + IDeckLinkIterator* pDLIterator = NULL; + + result = CoCreateInstance(CLSID_CDeckLinkIterator, NULL, CLSCTX_ALL, IID_IDeckLinkIterator, (void**)&pDLIterator); + if (FAILED(result)) + return NULL; + return pDLIterator; +} +#else +IDeckLinkIterator* BMD_CreateDeckLinkIterator(void) +{ + return CreateDeckLinkIteratorInstance(); +} +#endif // WIN32 diff --git a/intern/decklink/DeckLinkAPI.h b/intern/decklink/DeckLinkAPI.h new file mode 100644 index 00000000000..2a429c18c3c --- /dev/null +++ b/intern/decklink/DeckLinkAPI.h @@ -0,0 +1,56 @@ +/* + * ***** 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. + * + * The Original Code is Copyright (C) 2015, Blender Foundation + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Blender Foundation. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file decklink/DeckLinkAPI.h + * \ingroup decklink + */ + +#ifndef __DECKLINKAPI_H__ +#define __DECKLINKAPI_H__ + +/* Include the OS specific Declink headers */ + +#ifdef WIN32 +# include <windows.h> +# include <objbase.h> +# include <comutil.h> +# include "win/DeckLinkAPI_h.h" + typedef unsigned int dl_size_t; +#elif defined(__APPLE__) +# error "Decklink not supported in OSX" +#else +# include "linux/DeckLinkAPI.h" + /* Windows COM API uses BOOL, linux uses bool */ +# define BOOL bool + typedef uint32_t dl_size_t; +#endif + + +/* OS independent function to get the device iterator */ +IDeckLinkIterator* BMD_CreateDeckLinkIterator(void); + +#endif /* __DECKLINKAPI_H__ */ diff --git a/intern/decklink/linux/DeckLinkAPI.h b/intern/decklink/linux/DeckLinkAPI.h new file mode 100644 index 00000000000..08bfba39994 --- /dev/null +++ b/intern/decklink/linux/DeckLinkAPI.h @@ -0,0 +1,767 @@ +/* -LICENSE-START- +** Copyright (c) 2014 Blackmagic Design +** +** Permission is hereby granted, free of charge, to any person or organization +** obtaining a copy of the software and accompanying documentation covered by +** this license (the "Software") to use, reproduce, display, distribute, +** execute, and transmit the Software, and to prepare derivative works of the +** Software, and to permit third-parties to whom the Software is furnished to +** do so, all subject to the following: +** +** The copyright notices in the Software and this entire statement, including +** the above license grant, this restriction and the following disclaimer, +** must be included in all copies of the Software, in whole or in part, and +** all derivative works of the Software, unless such copies or derivative +** works are solely in the form of machine-executable object code generated by +** a source language processor. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +** DEALINGS IN THE SOFTWARE. +** -LICENSE-END- +*/ + +#ifndef BMD_DECKLINKAPI_H +#define BMD_DECKLINKAPI_H + + +#ifndef BMD_CONST + #if defined(_MSC_VER) + #define BMD_CONST __declspec(selectany) static const + #else + #define BMD_CONST static const + #endif +#endif + +/* DeckLink API */ + +#include <stdint.h> +#include "LinuxCOM.h" + +#include "DeckLinkAPITypes.h" +#include "DeckLinkAPIModes.h" +#include "DeckLinkAPIDiscovery.h" +#include "DeckLinkAPIConfiguration.h" +#include "DeckLinkAPIDeckControl.h" + +#define BLACKMAGIC_DECKLINK_API_MAGIC 1 + +// Type Declarations + + +// Interface ID Declarations + +BMD_CONST REFIID IID_IDeckLinkVideoOutputCallback = /* 20AA5225-1958-47CB-820B-80A8D521A6EE */ {0x20,0xAA,0x52,0x25,0x19,0x58,0x47,0xCB,0x82,0x0B,0x80,0xA8,0xD5,0x21,0xA6,0xEE}; +BMD_CONST REFIID IID_IDeckLinkInputCallback = /* DD04E5EC-7415-42AB-AE4A-E80C4DFC044A */ {0xDD,0x04,0xE5,0xEC,0x74,0x15,0x42,0xAB,0xAE,0x4A,0xE8,0x0C,0x4D,0xFC,0x04,0x4A}; +BMD_CONST REFIID IID_IDeckLinkMemoryAllocator = /* B36EB6E7-9D29-4AA8-92EF-843B87A289E8 */ {0xB3,0x6E,0xB6,0xE7,0x9D,0x29,0x4A,0xA8,0x92,0xEF,0x84,0x3B,0x87,0xA2,0x89,0xE8}; +BMD_CONST REFIID IID_IDeckLinkAudioOutputCallback = /* 403C681B-7F46-4A12-B993-2BB127084EE6 */ {0x40,0x3C,0x68,0x1B,0x7F,0x46,0x4A,0x12,0xB9,0x93,0x2B,0xB1,0x27,0x08,0x4E,0xE6}; +BMD_CONST REFIID IID_IDeckLinkIterator = /* 50FB36CD-3063-4B73-BDBB-958087F2D8BA */ {0x50,0xFB,0x36,0xCD,0x30,0x63,0x4B,0x73,0xBD,0xBB,0x95,0x80,0x87,0xF2,0xD8,0xBA}; +BMD_CONST REFIID IID_IDeckLinkAPIInformation = /* 7BEA3C68-730D-4322-AF34-8A7152B532A4 */ {0x7B,0xEA,0x3C,0x68,0x73,0x0D,0x43,0x22,0xAF,0x34,0x8A,0x71,0x52,0xB5,0x32,0xA4}; +BMD_CONST REFIID IID_IDeckLinkOutput = /* CC5C8A6E-3F2F-4B3A-87EA-FD78AF300564 */ {0xCC,0x5C,0x8A,0x6E,0x3F,0x2F,0x4B,0x3A,0x87,0xEA,0xFD,0x78,0xAF,0x30,0x05,0x64}; +BMD_CONST REFIID IID_IDeckLinkInput = /* AF22762B-DFAC-4846-AA79-FA8883560995 */ {0xAF,0x22,0x76,0x2B,0xDF,0xAC,0x48,0x46,0xAA,0x79,0xFA,0x88,0x83,0x56,0x09,0x95}; +BMD_CONST REFIID IID_IDeckLinkVideoFrame = /* 3F716FE0-F023-4111-BE5D-EF4414C05B17 */ {0x3F,0x71,0x6F,0xE0,0xF0,0x23,0x41,0x11,0xBE,0x5D,0xEF,0x44,0x14,0xC0,0x5B,0x17}; +BMD_CONST REFIID IID_IDeckLinkMutableVideoFrame = /* 69E2639F-40DA-4E19-B6F2-20ACE815C390 */ {0x69,0xE2,0x63,0x9F,0x40,0xDA,0x4E,0x19,0xB6,0xF2,0x20,0xAC,0xE8,0x15,0xC3,0x90}; +BMD_CONST REFIID IID_IDeckLinkVideoFrame3DExtensions = /* DA0F7E4A-EDC7-48A8-9CDD-2DB51C729CD7 */ {0xDA,0x0F,0x7E,0x4A,0xED,0xC7,0x48,0xA8,0x9C,0xDD,0x2D,0xB5,0x1C,0x72,0x9C,0xD7}; +BMD_CONST REFIID IID_IDeckLinkVideoInputFrame = /* 05CFE374-537C-4094-9A57-680525118F44 */ {0x05,0xCF,0xE3,0x74,0x53,0x7C,0x40,0x94,0x9A,0x57,0x68,0x05,0x25,0x11,0x8F,0x44}; +BMD_CONST REFIID IID_IDeckLinkVideoFrameAncillary = /* 732E723C-D1A4-4E29-9E8E-4A88797A0004 */ {0x73,0x2E,0x72,0x3C,0xD1,0xA4,0x4E,0x29,0x9E,0x8E,0x4A,0x88,0x79,0x7A,0x00,0x04}; +BMD_CONST REFIID IID_IDeckLinkAudioInputPacket = /* E43D5870-2894-11DE-8C30-0800200C9A66 */ {0xE4,0x3D,0x58,0x70,0x28,0x94,0x11,0xDE,0x8C,0x30,0x08,0x00,0x20,0x0C,0x9A,0x66}; +BMD_CONST REFIID IID_IDeckLinkScreenPreviewCallback = /* B1D3F49A-85FE-4C5D-95C8-0B5D5DCCD438 */ {0xB1,0xD3,0xF4,0x9A,0x85,0xFE,0x4C,0x5D,0x95,0xC8,0x0B,0x5D,0x5D,0xCC,0xD4,0x38}; +BMD_CONST REFIID IID_IDeckLinkGLScreenPreviewHelper = /* 504E2209-CAC7-4C1A-9FB4-C5BB6274D22F */ {0x50,0x4E,0x22,0x09,0xCA,0xC7,0x4C,0x1A,0x9F,0xB4,0xC5,0xBB,0x62,0x74,0xD2,0x2F}; +BMD_CONST REFIID IID_IDeckLinkNotificationCallback = /* B002A1EC-070D-4288-8289-BD5D36E5FF0D */ {0xB0,0x02,0xA1,0xEC,0x07,0x0D,0x42,0x88,0x82,0x89,0xBD,0x5D,0x36,0xE5,0xFF,0x0D}; +BMD_CONST REFIID IID_IDeckLinkNotification = /* 0A1FB207-E215-441B-9B19-6FA1575946C5 */ {0x0A,0x1F,0xB2,0x07,0xE2,0x15,0x44,0x1B,0x9B,0x19,0x6F,0xA1,0x57,0x59,0x46,0xC5}; +BMD_CONST REFIID IID_IDeckLinkAttributes = /* ABC11843-D966-44CB-96E2-A1CB5D3135C4 */ {0xAB,0xC1,0x18,0x43,0xD9,0x66,0x44,0xCB,0x96,0xE2,0xA1,0xCB,0x5D,0x31,0x35,0xC4}; +BMD_CONST REFIID IID_IDeckLinkKeyer = /* 89AFCAF5-65F8-421E-98F7-96FE5F5BFBA3 */ {0x89,0xAF,0xCA,0xF5,0x65,0xF8,0x42,0x1E,0x98,0xF7,0x96,0xFE,0x5F,0x5B,0xFB,0xA3}; +BMD_CONST REFIID IID_IDeckLinkVideoConversion = /* 3BBCB8A2-DA2C-42D9-B5D8-88083644E99A */ {0x3B,0xBC,0xB8,0xA2,0xDA,0x2C,0x42,0xD9,0xB5,0xD8,0x88,0x08,0x36,0x44,0xE9,0x9A}; +BMD_CONST REFIID IID_IDeckLinkDeviceNotificationCallback = /* 4997053B-0ADF-4CC8-AC70-7A50C4BE728F */ {0x49,0x97,0x05,0x3B,0x0A,0xDF,0x4C,0xC8,0xAC,0x70,0x7A,0x50,0xC4,0xBE,0x72,0x8F}; +BMD_CONST REFIID IID_IDeckLinkDiscovery = /* CDBF631C-BC76-45FA-B44D-C55059BC6101 */ {0xCD,0xBF,0x63,0x1C,0xBC,0x76,0x45,0xFA,0xB4,0x4D,0xC5,0x50,0x59,0xBC,0x61,0x01}; + +/* Enum BMDVideoOutputFlags - Flags to control the output of ancillary data along with video. */ + +typedef uint32_t BMDVideoOutputFlags; +enum _BMDVideoOutputFlags { + bmdVideoOutputFlagDefault = 0, + bmdVideoOutputVANC = 1 << 0, + bmdVideoOutputVITC = 1 << 1, + bmdVideoOutputRP188 = 1 << 2, + bmdVideoOutputDualStream3D = 1 << 4 +}; + +/* Enum BMDFrameFlags - Frame flags */ + +typedef uint32_t BMDFrameFlags; +enum _BMDFrameFlags { + bmdFrameFlagDefault = 0, + bmdFrameFlagFlipVertical = 1 << 0, + + /* Flags that are applicable only to instances of IDeckLinkVideoInputFrame */ + + bmdFrameHasNoInputSource = 1 << 31 +}; + +/* Enum BMDVideoInputFlags - Flags applicable to video input */ + +typedef uint32_t BMDVideoInputFlags; +enum _BMDVideoInputFlags { + bmdVideoInputFlagDefault = 0, + bmdVideoInputEnableFormatDetection = 1 << 0, + bmdVideoInputDualStream3D = 1 << 1 +}; + +/* Enum BMDVideoInputFormatChangedEvents - Bitmask passed to the VideoInputFormatChanged notification to identify the properties of the input signal that have changed */ + +typedef uint32_t BMDVideoInputFormatChangedEvents; +enum _BMDVideoInputFormatChangedEvents { + bmdVideoInputDisplayModeChanged = 1 << 0, + bmdVideoInputFieldDominanceChanged = 1 << 1, + bmdVideoInputColorspaceChanged = 1 << 2 +}; + +/* Enum BMDDetectedVideoInputFormatFlags - Flags passed to the VideoInputFormatChanged notification to describe the detected video input signal */ + +typedef uint32_t BMDDetectedVideoInputFormatFlags; +enum _BMDDetectedVideoInputFormatFlags { + bmdDetectedVideoInputYCbCr422 = 1 << 0, + bmdDetectedVideoInputRGB444 = 1 << 1, + bmdDetectedVideoInputDualStream3D = 1 << 2 +}; + +/* Enum BMDDeckLinkCapturePassthroughMode - Enumerates whether the video output is electrically connected to the video input or if the clean switching mode is enabled */ + +typedef uint32_t BMDDeckLinkCapturePassthroughMode; +enum _BMDDeckLinkCapturePassthroughMode { + bmdDeckLinkCapturePassthroughModeDirect = /* 'pdir' */ 0x70646972, + bmdDeckLinkCapturePassthroughModeCleanSwitch = /* 'pcln' */ 0x70636C6E +}; + +/* Enum BMDOutputFrameCompletionResult - Frame Completion Callback */ + +typedef uint32_t BMDOutputFrameCompletionResult; +enum _BMDOutputFrameCompletionResult { + bmdOutputFrameCompleted, + bmdOutputFrameDisplayedLate, + bmdOutputFrameDropped, + bmdOutputFrameFlushed +}; + +/* Enum BMDReferenceStatus - GenLock input status */ + +typedef uint32_t BMDReferenceStatus; +enum _BMDReferenceStatus { + bmdReferenceNotSupportedByHardware = 1 << 0, + bmdReferenceLocked = 1 << 1 +}; + +/* Enum BMDAudioSampleRate - Audio sample rates supported for output/input */ + +typedef uint32_t BMDAudioSampleRate; +enum _BMDAudioSampleRate { + bmdAudioSampleRate48kHz = 48000 +}; + +/* Enum BMDAudioSampleType - Audio sample sizes supported for output/input */ + +typedef uint32_t BMDAudioSampleType; +enum _BMDAudioSampleType { + bmdAudioSampleType16bitInteger = 16, + bmdAudioSampleType32bitInteger = 32 +}; + +/* Enum BMDAudioOutputStreamType - Audio output stream type */ + +typedef uint32_t BMDAudioOutputStreamType; +enum _BMDAudioOutputStreamType { + bmdAudioOutputStreamContinuous, + bmdAudioOutputStreamContinuousDontResample, + bmdAudioOutputStreamTimestamped +}; + +/* Enum BMDDisplayModeSupport - Output mode supported flags */ + +typedef uint32_t BMDDisplayModeSupport; +enum _BMDDisplayModeSupport { + bmdDisplayModeNotSupported = 0, + bmdDisplayModeSupported, + bmdDisplayModeSupportedWithConversion +}; + +/* Enum BMDTimecodeFormat - Timecode formats for frame metadata */ + +typedef uint32_t BMDTimecodeFormat; +enum _BMDTimecodeFormat { + bmdTimecodeRP188VITC1 = /* 'rpv1' */ 0x72707631, // RP188 timecode where DBB1 equals VITC1 (line 9) + bmdTimecodeRP188VITC2 = /* 'rp12' */ 0x72703132, // RP188 timecode where DBB1 equals VITC2 (line 9 for progressive or line 571 for interlaced/PsF) + bmdTimecodeRP188LTC = /* 'rplt' */ 0x72706C74, // RP188 timecode where DBB1 equals LTC (line 10) + bmdTimecodeRP188Any = /* 'rp18' */ 0x72703138, // For capture: return the first valid timecode in {VITC1, LTC ,VITC2} - For playback: set the timecode as VITC1 + bmdTimecodeVITC = /* 'vitc' */ 0x76697463, + bmdTimecodeVITCField2 = /* 'vit2' */ 0x76697432, + bmdTimecodeSerial = /* 'seri' */ 0x73657269 +}; + +/* Enum BMDAnalogVideoFlags - Analog video display flags */ + +typedef uint32_t BMDAnalogVideoFlags; +enum _BMDAnalogVideoFlags { + bmdAnalogVideoFlagCompositeSetup75 = 1 << 0, + bmdAnalogVideoFlagComponentBetacamLevels = 1 << 1 +}; + +/* Enum BMDAudioOutputAnalogAESSwitch - Audio output Analog/AESEBU switch */ + +typedef uint32_t BMDAudioOutputAnalogAESSwitch; +enum _BMDAudioOutputAnalogAESSwitch { + bmdAudioOutputSwitchAESEBU = /* 'aes ' */ 0x61657320, + bmdAudioOutputSwitchAnalog = /* 'anlg' */ 0x616E6C67 +}; + +/* Enum BMDVideoOutputConversionMode - Video/audio conversion mode */ + +typedef uint32_t BMDVideoOutputConversionMode; +enum _BMDVideoOutputConversionMode { + bmdNoVideoOutputConversion = /* 'none' */ 0x6E6F6E65, + bmdVideoOutputLetterboxDownconversion = /* 'ltbx' */ 0x6C746278, + bmdVideoOutputAnamorphicDownconversion = /* 'amph' */ 0x616D7068, + bmdVideoOutputHD720toHD1080Conversion = /* '720c' */ 0x37323063, + bmdVideoOutputHardwareLetterboxDownconversion = /* 'HWlb' */ 0x48576C62, + bmdVideoOutputHardwareAnamorphicDownconversion = /* 'HWam' */ 0x4857616D, + bmdVideoOutputHardwareCenterCutDownconversion = /* 'HWcc' */ 0x48576363, + bmdVideoOutputHardware720p1080pCrossconversion = /* 'xcap' */ 0x78636170, + bmdVideoOutputHardwareAnamorphic720pUpconversion = /* 'ua7p' */ 0x75613770, + bmdVideoOutputHardwareAnamorphic1080iUpconversion = /* 'ua1i' */ 0x75613169, + bmdVideoOutputHardwareAnamorphic149To720pUpconversion = /* 'u47p' */ 0x75343770, + bmdVideoOutputHardwareAnamorphic149To1080iUpconversion = /* 'u41i' */ 0x75343169, + bmdVideoOutputHardwarePillarbox720pUpconversion = /* 'up7p' */ 0x75703770, + bmdVideoOutputHardwarePillarbox1080iUpconversion = /* 'up1i' */ 0x75703169 +}; + +/* Enum BMDVideoInputConversionMode - Video input conversion mode */ + +typedef uint32_t BMDVideoInputConversionMode; +enum _BMDVideoInputConversionMode { + bmdNoVideoInputConversion = /* 'none' */ 0x6E6F6E65, + bmdVideoInputLetterboxDownconversionFromHD1080 = /* '10lb' */ 0x31306C62, + bmdVideoInputAnamorphicDownconversionFromHD1080 = /* '10am' */ 0x3130616D, + bmdVideoInputLetterboxDownconversionFromHD720 = /* '72lb' */ 0x37326C62, + bmdVideoInputAnamorphicDownconversionFromHD720 = /* '72am' */ 0x3732616D, + bmdVideoInputLetterboxUpconversion = /* 'lbup' */ 0x6C627570, + bmdVideoInputAnamorphicUpconversion = /* 'amup' */ 0x616D7570 +}; + +/* Enum BMDVideo3DPackingFormat - Video 3D packing format */ + +typedef uint32_t BMDVideo3DPackingFormat; +enum _BMDVideo3DPackingFormat { + bmdVideo3DPackingSidebySideHalf = /* 'sbsh' */ 0x73627368, + bmdVideo3DPackingLinebyLine = /* 'lbyl' */ 0x6C62796C, + bmdVideo3DPackingTopAndBottom = /* 'tabo' */ 0x7461626F, + bmdVideo3DPackingFramePacking = /* 'frpk' */ 0x6672706B, + bmdVideo3DPackingLeftOnly = /* 'left' */ 0x6C656674, + bmdVideo3DPackingRightOnly = /* 'righ' */ 0x72696768 +}; + +/* Enum BMDIdleVideoOutputOperation - Video output operation when not playing video */ + +typedef uint32_t BMDIdleVideoOutputOperation; +enum _BMDIdleVideoOutputOperation { + bmdIdleVideoOutputBlack = /* 'blac' */ 0x626C6163, + bmdIdleVideoOutputLastFrame = /* 'lafa' */ 0x6C616661, + bmdIdleVideoOutputDesktop = /* 'desk' */ 0x6465736B +}; + +/* Enum BMDDeckLinkAttributeID - DeckLink Attribute ID */ + +typedef uint32_t BMDDeckLinkAttributeID; +enum _BMDDeckLinkAttributeID { + + /* Flags */ + + BMDDeckLinkSupportsInternalKeying = /* 'keyi' */ 0x6B657969, + BMDDeckLinkSupportsExternalKeying = /* 'keye' */ 0x6B657965, + BMDDeckLinkSupportsHDKeying = /* 'keyh' */ 0x6B657968, + BMDDeckLinkSupportsInputFormatDetection = /* 'infd' */ 0x696E6664, + BMDDeckLinkHasReferenceInput = /* 'hrin' */ 0x6872696E, + BMDDeckLinkHasSerialPort = /* 'hspt' */ 0x68737074, + BMDDeckLinkHasAnalogVideoOutputGain = /* 'avog' */ 0x61766F67, + BMDDeckLinkCanOnlyAdjustOverallVideoOutputGain = /* 'ovog' */ 0x6F766F67, + BMDDeckLinkHasVideoInputAntiAliasingFilter = /* 'aafl' */ 0x6161666C, + BMDDeckLinkHasBypass = /* 'byps' */ 0x62797073, + BMDDeckLinkSupportsDesktopDisplay = /* 'extd' */ 0x65787464, + BMDDeckLinkSupportsClockTimingAdjustment = /* 'ctad' */ 0x63746164, + BMDDeckLinkSupportsFullDuplex = /* 'fdup' */ 0x66647570, + BMDDeckLinkSupportsFullFrameReferenceInputTimingOffset = /* 'frin' */ 0x6672696E, + BMDDeckLinkSupportsSMPTELevelAOutput = /* 'lvla' */ 0x6C766C61, + BMDDeckLinkSupportsDualLinkSDI = /* 'sdls' */ 0x73646C73, + BMDDeckLinkSupportsIdleOutput = /* 'idou' */ 0x69646F75, + + /* Integers */ + + BMDDeckLinkMaximumAudioChannels = /* 'mach' */ 0x6D616368, + BMDDeckLinkMaximumAnalogAudioChannels = /* 'aach' */ 0x61616368, + BMDDeckLinkNumberOfSubDevices = /* 'nsbd' */ 0x6E736264, + BMDDeckLinkSubDeviceIndex = /* 'subi' */ 0x73756269, + BMDDeckLinkPersistentID = /* 'peid' */ 0x70656964, + BMDDeckLinkTopologicalID = /* 'toid' */ 0x746F6964, + BMDDeckLinkVideoOutputConnections = /* 'vocn' */ 0x766F636E, + BMDDeckLinkVideoInputConnections = /* 'vicn' */ 0x7669636E, + BMDDeckLinkAudioOutputConnections = /* 'aocn' */ 0x616F636E, + BMDDeckLinkAudioInputConnections = /* 'aicn' */ 0x6169636E, + BMDDeckLinkDeviceBusyState = /* 'dbst' */ 0x64627374, + BMDDeckLinkVideoIOSupport = /* 'vios' */ 0x76696F73, // Returns a BMDVideoIOSupport bit field + + /* Floats */ + + BMDDeckLinkVideoInputGainMinimum = /* 'vigm' */ 0x7669676D, + BMDDeckLinkVideoInputGainMaximum = /* 'vigx' */ 0x76696778, + BMDDeckLinkVideoOutputGainMinimum = /* 'vogm' */ 0x766F676D, + BMDDeckLinkVideoOutputGainMaximum = /* 'vogx' */ 0x766F6778, + + /* Strings */ + + BMDDeckLinkSerialPortDeviceName = /* 'slpn' */ 0x736C706E +}; + +/* Enum BMDDeckLinkAPIInformationID - DeckLinkAPI information ID */ + +typedef uint32_t BMDDeckLinkAPIInformationID; +enum _BMDDeckLinkAPIInformationID { + BMDDeckLinkAPIVersion = /* 'vers' */ 0x76657273 +}; + +/* Enum BMDDeviceBusyState - Current device busy state */ + +typedef uint32_t BMDDeviceBusyState; +enum _BMDDeviceBusyState { + bmdDeviceCaptureBusy = 1 << 0, + bmdDevicePlaybackBusy = 1 << 1, + bmdDeviceSerialPortBusy = 1 << 2 +}; + +/* Enum BMDVideoIOSupport - Device video input/output support */ + +typedef uint32_t BMDVideoIOSupport; +enum _BMDVideoIOSupport { + bmdDeviceSupportsCapture = 1 << 0, + bmdDeviceSupportsPlayback = 1 << 1 +}; + +/* Enum BMD3DPreviewFormat - Linked Frame preview format */ + +typedef uint32_t BMD3DPreviewFormat; +enum _BMD3DPreviewFormat { + bmd3DPreviewFormatDefault = /* 'defa' */ 0x64656661, + bmd3DPreviewFormatLeftOnly = /* 'left' */ 0x6C656674, + bmd3DPreviewFormatRightOnly = /* 'righ' */ 0x72696768, + bmd3DPreviewFormatSideBySide = /* 'side' */ 0x73696465, + bmd3DPreviewFormatTopBottom = /* 'topb' */ 0x746F7062 +}; + +/* Enum BMDNotifications - Events that can be subscribed through IDeckLinkNotification */ + +typedef uint32_t BMDNotifications; +enum _BMDNotifications { + bmdPreferencesChanged = /* 'pref' */ 0x70726566 +}; + +#if defined(__cplusplus) + +// Forward Declarations + +class IDeckLinkVideoOutputCallback; +class IDeckLinkInputCallback; +class IDeckLinkMemoryAllocator; +class IDeckLinkAudioOutputCallback; +class IDeckLinkIterator; +class IDeckLinkAPIInformation; +class IDeckLinkOutput; +class IDeckLinkInput; +class IDeckLinkVideoFrame; +class IDeckLinkMutableVideoFrame; +class IDeckLinkVideoFrame3DExtensions; +class IDeckLinkVideoInputFrame; +class IDeckLinkVideoFrameAncillary; +class IDeckLinkAudioInputPacket; +class IDeckLinkScreenPreviewCallback; +class IDeckLinkGLScreenPreviewHelper; +class IDeckLinkNotificationCallback; +class IDeckLinkNotification; +class IDeckLinkAttributes; +class IDeckLinkKeyer; +class IDeckLinkVideoConversion; +class IDeckLinkDeviceNotificationCallback; +class IDeckLinkDiscovery; + +/* Interface IDeckLinkVideoOutputCallback - Frame completion callback. */ + +class IDeckLinkVideoOutputCallback : public IUnknown +{ +public: + virtual HRESULT ScheduledFrameCompleted (/* in */ IDeckLinkVideoFrame *completedFrame, /* in */ BMDOutputFrameCompletionResult result) = 0; + virtual HRESULT ScheduledPlaybackHasStopped (void) = 0; + +protected: + virtual ~IDeckLinkVideoOutputCallback () {} // call Release method to drop reference count +}; + +/* Interface IDeckLinkInputCallback - Frame arrival callback. */ + +class IDeckLinkInputCallback : public IUnknown +{ +public: + virtual HRESULT VideoInputFormatChanged (/* in */ BMDVideoInputFormatChangedEvents notificationEvents, /* in */ IDeckLinkDisplayMode *newDisplayMode, /* in */ BMDDetectedVideoInputFormatFlags detectedSignalFlags) = 0; + virtual HRESULT VideoInputFrameArrived (/* in */ IDeckLinkVideoInputFrame* videoFrame, /* in */ IDeckLinkAudioInputPacket* audioPacket) = 0; + +protected: + virtual ~IDeckLinkInputCallback () {} // call Release method to drop reference count +}; + +/* Interface IDeckLinkMemoryAllocator - Memory allocator for video frames. */ + +class IDeckLinkMemoryAllocator : public IUnknown +{ +public: + virtual HRESULT AllocateBuffer (/* in */ uint32_t bufferSize, /* out */ void **allocatedBuffer) = 0; + virtual HRESULT ReleaseBuffer (/* in */ void *buffer) = 0; + + virtual HRESULT Commit (void) = 0; + virtual HRESULT Decommit (void) = 0; +}; + +/* Interface IDeckLinkAudioOutputCallback - Optional callback to allow audio samples to be pulled as required. */ + +class IDeckLinkAudioOutputCallback : public IUnknown +{ +public: + virtual HRESULT RenderAudioSamples (/* in */ bool preroll) = 0; +}; + +/* Interface IDeckLinkIterator - enumerates installed DeckLink hardware */ + +class IDeckLinkIterator : public IUnknown +{ +public: + virtual HRESULT Next (/* out */ IDeckLink **deckLinkInstance) = 0; +}; + +/* Interface IDeckLinkAPIInformation - DeckLinkAPI attribute interface */ + +class IDeckLinkAPIInformation : public IUnknown +{ +public: + virtual HRESULT GetFlag (/* in */ BMDDeckLinkAPIInformationID cfgID, /* out */ bool *value) = 0; + virtual HRESULT GetInt (/* in */ BMDDeckLinkAPIInformationID cfgID, /* out */ int64_t *value) = 0; + virtual HRESULT GetFloat (/* in */ BMDDeckLinkAPIInformationID cfgID, /* out */ double *value) = 0; + virtual HRESULT GetString (/* in */ BMDDeckLinkAPIInformationID cfgID, /* out */ const char **value) = 0; + +protected: + virtual ~IDeckLinkAPIInformation () {} // call Release method to drop reference count +}; + +/* Interface IDeckLinkOutput - Created by QueryInterface from IDeckLink. */ + +class IDeckLinkOutput : public IUnknown +{ +public: + virtual HRESULT DoesSupportVideoMode (/* in */ BMDDisplayMode displayMode, /* in */ BMDPixelFormat pixelFormat, /* in */ BMDVideoOutputFlags flags, /* out */ BMDDisplayModeSupport *result, /* out */ IDeckLinkDisplayMode **resultDisplayMode) = 0; + virtual HRESULT GetDisplayModeIterator (/* out */ IDeckLinkDisplayModeIterator **iterator) = 0; + + virtual HRESULT SetScreenPreviewCallback (/* in */ IDeckLinkScreenPreviewCallback *previewCallback) = 0; + + /* Video Output */ + + virtual HRESULT EnableVideoOutput (/* in */ BMDDisplayMode displayMode, /* in */ BMDVideoOutputFlags flags) = 0; + virtual HRESULT DisableVideoOutput (void) = 0; + + virtual HRESULT SetVideoOutputFrameMemoryAllocator (/* in */ IDeckLinkMemoryAllocator *theAllocator) = 0; + virtual HRESULT CreateVideoFrame (/* in */ int32_t width, /* in */ int32_t height, /* in */ int32_t rowBytes, /* in */ BMDPixelFormat pixelFormat, /* in */ BMDFrameFlags flags, /* out */ IDeckLinkMutableVideoFrame **outFrame) = 0; + virtual HRESULT CreateAncillaryData (/* in */ BMDPixelFormat pixelFormat, /* out */ IDeckLinkVideoFrameAncillary **outBuffer) = 0; + + virtual HRESULT DisplayVideoFrameSync (/* in */ IDeckLinkVideoFrame *theFrame) = 0; + virtual HRESULT ScheduleVideoFrame (/* in */ IDeckLinkVideoFrame *theFrame, /* in */ BMDTimeValue displayTime, /* in */ BMDTimeValue displayDuration, /* in */ BMDTimeScale timeScale) = 0; + virtual HRESULT SetScheduledFrameCompletionCallback (/* in */ IDeckLinkVideoOutputCallback *theCallback) = 0; + virtual HRESULT GetBufferedVideoFrameCount (/* out */ uint32_t *bufferedFrameCount) = 0; + + /* Audio Output */ + + virtual HRESULT EnableAudioOutput (/* in */ BMDAudioSampleRate sampleRate, /* in */ BMDAudioSampleType sampleType, /* in */ uint32_t channelCount, /* in */ BMDAudioOutputStreamType streamType) = 0; + virtual HRESULT DisableAudioOutput (void) = 0; + + virtual HRESULT WriteAudioSamplesSync (/* in */ void *buffer, /* in */ uint32_t sampleFrameCount, /* out */ uint32_t *sampleFramesWritten) = 0; + + virtual HRESULT BeginAudioPreroll (void) = 0; + virtual HRESULT EndAudioPreroll (void) = 0; + virtual HRESULT ScheduleAudioSamples (/* in */ void *buffer, /* in */ uint32_t sampleFrameCount, /* in */ BMDTimeValue streamTime, /* in */ BMDTimeScale timeScale, /* out */ uint32_t *sampleFramesWritten) = 0; + + virtual HRESULT GetBufferedAudioSampleFrameCount (/* out */ uint32_t *bufferedSampleFrameCount) = 0; + virtual HRESULT FlushBufferedAudioSamples (void) = 0; + + virtual HRESULT SetAudioCallback (/* in */ IDeckLinkAudioOutputCallback *theCallback) = 0; + + /* Output Control */ + + virtual HRESULT StartScheduledPlayback (/* in */ BMDTimeValue playbackStartTime, /* in */ BMDTimeScale timeScale, /* in */ double playbackSpeed) = 0; + virtual HRESULT StopScheduledPlayback (/* in */ BMDTimeValue stopPlaybackAtTime, /* out */ BMDTimeValue *actualStopTime, /* in */ BMDTimeScale timeScale) = 0; + virtual HRESULT IsScheduledPlaybackRunning (/* out */ bool *active) = 0; + virtual HRESULT GetScheduledStreamTime (/* in */ BMDTimeScale desiredTimeScale, /* out */ BMDTimeValue *streamTime, /* out */ double *playbackSpeed) = 0; + virtual HRESULT GetReferenceStatus (/* out */ BMDReferenceStatus *referenceStatus) = 0; + + /* Hardware Timing */ + + virtual HRESULT GetHardwareReferenceClock (/* in */ BMDTimeScale desiredTimeScale, /* out */ BMDTimeValue *hardwareTime, /* out */ BMDTimeValue *timeInFrame, /* out */ BMDTimeValue *ticksPerFrame) = 0; + virtual HRESULT GetFrameCompletionReferenceTimestamp (/* in */ IDeckLinkVideoFrame *theFrame, /* in */ BMDTimeScale desiredTimeScale, /* out */ BMDTimeValue *frameCompletionTimestamp) = 0; + +protected: + virtual ~IDeckLinkOutput () {} // call Release method to drop reference count +}; + +/* Interface IDeckLinkInput - Created by QueryInterface from IDeckLink. */ + +class IDeckLinkInput : public IUnknown +{ +public: + virtual HRESULT DoesSupportVideoMode (/* in */ BMDDisplayMode displayMode, /* in */ BMDPixelFormat pixelFormat, /* in */ BMDVideoInputFlags flags, /* out */ BMDDisplayModeSupport *result, /* out */ IDeckLinkDisplayMode **resultDisplayMode) = 0; + virtual HRESULT GetDisplayModeIterator (/* out */ IDeckLinkDisplayModeIterator **iterator) = 0; + + virtual HRESULT SetScreenPreviewCallback (/* in */ IDeckLinkScreenPreviewCallback *previewCallback) = 0; + + /* Video Input */ + + virtual HRESULT EnableVideoInput (/* in */ BMDDisplayMode displayMode, /* in */ BMDPixelFormat pixelFormat, /* in */ BMDVideoInputFlags flags) = 0; + virtual HRESULT DisableVideoInput (void) = 0; + virtual HRESULT GetAvailableVideoFrameCount (/* out */ uint32_t *availableFrameCount) = 0; + virtual HRESULT SetVideoInputFrameMemoryAllocator (/* in */ IDeckLinkMemoryAllocator *theAllocator) = 0; + + /* Audio Input */ + + virtual HRESULT EnableAudioInput (/* in */ BMDAudioSampleRate sampleRate, /* in */ BMDAudioSampleType sampleType, /* in */ uint32_t channelCount) = 0; + virtual HRESULT DisableAudioInput (void) = 0; + virtual HRESULT GetAvailableAudioSampleFrameCount (/* out */ uint32_t *availableSampleFrameCount) = 0; + + /* Input Control */ + + virtual HRESULT StartStreams (void) = 0; + virtual HRESULT StopStreams (void) = 0; + virtual HRESULT PauseStreams (void) = 0; + virtual HRESULT FlushStreams (void) = 0; + virtual HRESULT SetCallback (/* in */ IDeckLinkInputCallback *theCallback) = 0; + + /* Hardware Timing */ + + virtual HRESULT GetHardwareReferenceClock (/* in */ BMDTimeScale desiredTimeScale, /* out */ BMDTimeValue *hardwareTime, /* out */ BMDTimeValue *timeInFrame, /* out */ BMDTimeValue *ticksPerFrame) = 0; + +protected: + virtual ~IDeckLinkInput () {} // call Release method to drop reference count +}; + +/* Interface IDeckLinkVideoFrame - Interface to encapsulate a video frame; can be caller-implemented. */ + +class IDeckLinkVideoFrame : public IUnknown +{ +public: + virtual long GetWidth (void) = 0; + virtual long GetHeight (void) = 0; + virtual long GetRowBytes (void) = 0; + virtual BMDPixelFormat GetPixelFormat (void) = 0; + virtual BMDFrameFlags GetFlags (void) = 0; + virtual HRESULT GetBytes (/* out */ void **buffer) = 0; + + virtual HRESULT GetTimecode (/* in */ BMDTimecodeFormat format, /* out */ IDeckLinkTimecode **timecode) = 0; + virtual HRESULT GetAncillaryData (/* out */ IDeckLinkVideoFrameAncillary **ancillary) = 0; + +protected: + virtual ~IDeckLinkVideoFrame () {} // call Release method to drop reference count +}; + +/* Interface IDeckLinkMutableVideoFrame - Created by IDeckLinkOutput::CreateVideoFrame. */ + +class IDeckLinkMutableVideoFrame : public IDeckLinkVideoFrame +{ +public: + virtual HRESULT SetFlags (/* in */ BMDFrameFlags newFlags) = 0; + + virtual HRESULT SetTimecode (/* in */ BMDTimecodeFormat format, /* in */ IDeckLinkTimecode *timecode) = 0; + virtual HRESULT SetTimecodeFromComponents (/* in */ BMDTimecodeFormat format, /* in */ uint8_t hours, /* in */ uint8_t minutes, /* in */ uint8_t seconds, /* in */ uint8_t frames, /* in */ BMDTimecodeFlags flags) = 0; + virtual HRESULT SetAncillaryData (/* in */ IDeckLinkVideoFrameAncillary *ancillary) = 0; + virtual HRESULT SetTimecodeUserBits (/* in */ BMDTimecodeFormat format, /* in */ BMDTimecodeUserBits userBits) = 0; + +protected: + virtual ~IDeckLinkMutableVideoFrame () {} // call Release method to drop reference count +}; + +/* Interface IDeckLinkVideoFrame3DExtensions - Optional interface implemented on IDeckLinkVideoFrame to support 3D frames */ + +class IDeckLinkVideoFrame3DExtensions : public IUnknown +{ +public: + virtual BMDVideo3DPackingFormat Get3DPackingFormat (void) = 0; + virtual HRESULT GetFrameForRightEye (/* out */ IDeckLinkVideoFrame* *rightEyeFrame) = 0; + +protected: + virtual ~IDeckLinkVideoFrame3DExtensions () {} // call Release method to drop reference count +}; + +/* Interface IDeckLinkVideoInputFrame - Provided by the IDeckLinkVideoInput frame arrival callback. */ + +class IDeckLinkVideoInputFrame : public IDeckLinkVideoFrame +{ +public: + virtual HRESULT GetStreamTime (/* out */ BMDTimeValue *frameTime, /* out */ BMDTimeValue *frameDuration, /* in */ BMDTimeScale timeScale) = 0; + virtual HRESULT GetHardwareReferenceTimestamp (/* in */ BMDTimeScale timeScale, /* out */ BMDTimeValue *frameTime, /* out */ BMDTimeValue *frameDuration) = 0; + +protected: + virtual ~IDeckLinkVideoInputFrame () {} // call Release method to drop reference count +}; + +/* Interface IDeckLinkVideoFrameAncillary - Obtained through QueryInterface() on an IDeckLinkVideoFrame object. */ + +class IDeckLinkVideoFrameAncillary : public IUnknown +{ +public: + + virtual HRESULT GetBufferForVerticalBlankingLine (/* in */ uint32_t lineNumber, /* out */ void **buffer) = 0; + virtual BMDPixelFormat GetPixelFormat (void) = 0; + virtual BMDDisplayMode GetDisplayMode (void) = 0; + +protected: + virtual ~IDeckLinkVideoFrameAncillary () {} // call Release method to drop reference count +}; + +/* Interface IDeckLinkAudioInputPacket - Provided by the IDeckLinkInput callback. */ + +class IDeckLinkAudioInputPacket : public IUnknown +{ +public: + virtual long GetSampleFrameCount (void) = 0; + virtual HRESULT GetBytes (/* out */ void **buffer) = 0; + virtual HRESULT GetPacketTime (/* out */ BMDTimeValue *packetTime, /* in */ BMDTimeScale timeScale) = 0; + +protected: + virtual ~IDeckLinkAudioInputPacket () {} // call Release method to drop reference count +}; + +/* Interface IDeckLinkScreenPreviewCallback - Screen preview callback */ + +class IDeckLinkScreenPreviewCallback : public IUnknown +{ +public: + virtual HRESULT DrawFrame (/* in */ IDeckLinkVideoFrame *theFrame) = 0; + +protected: + virtual ~IDeckLinkScreenPreviewCallback () {} // call Release method to drop reference count +}; + +/* Interface IDeckLinkGLScreenPreviewHelper - Created with CoCreateInstance(). */ + +class IDeckLinkGLScreenPreviewHelper : public IUnknown +{ +public: + + /* Methods must be called with OpenGL context set */ + + virtual HRESULT InitializeGL (void) = 0; + virtual HRESULT PaintGL (void) = 0; + virtual HRESULT SetFrame (/* in */ IDeckLinkVideoFrame *theFrame) = 0; + virtual HRESULT Set3DPreviewFormat (/* in */ BMD3DPreviewFormat previewFormat) = 0; + +protected: + virtual ~IDeckLinkGLScreenPreviewHelper () {} // call Release method to drop reference count +}; + +/* Interface IDeckLinkNotificationCallback - DeckLink Notification Callback Interface */ + +class IDeckLinkNotificationCallback : public IUnknown +{ +public: + virtual HRESULT Notify (/* in */ BMDNotifications topic, /* in */ uint64_t param1, /* in */ uint64_t param2) = 0; +}; + +/* Interface IDeckLinkNotification - DeckLink Notification interface */ + +class IDeckLinkNotification : public IUnknown +{ +public: + virtual HRESULT Subscribe (/* in */ BMDNotifications topic, /* in */ IDeckLinkNotificationCallback *theCallback) = 0; + virtual HRESULT Unsubscribe (/* in */ BMDNotifications topic, /* in */ IDeckLinkNotificationCallback *theCallback) = 0; +}; + +/* Interface IDeckLinkAttributes - DeckLink Attribute interface */ + +class IDeckLinkAttributes : public IUnknown +{ +public: + virtual HRESULT GetFlag (/* in */ BMDDeckLinkAttributeID cfgID, /* out */ bool *value) = 0; + virtual HRESULT GetInt (/* in */ BMDDeckLinkAttributeID cfgID, /* out */ int64_t *value) = 0; + virtual HRESULT GetFloat (/* in */ BMDDeckLinkAttributeID cfgID, /* out */ double *value) = 0; + virtual HRESULT GetString (/* in */ BMDDeckLinkAttributeID cfgID, /* out */ const char **value) = 0; + +protected: + virtual ~IDeckLinkAttributes () {} // call Release method to drop reference count +}; + +/* Interface IDeckLinkKeyer - DeckLink Keyer interface */ + +class IDeckLinkKeyer : public IUnknown +{ +public: + virtual HRESULT Enable (/* in */ bool isExternal) = 0; + virtual HRESULT SetLevel (/* in */ uint8_t level) = 0; + virtual HRESULT RampUp (/* in */ uint32_t numberOfFrames) = 0; + virtual HRESULT RampDown (/* in */ uint32_t numberOfFrames) = 0; + virtual HRESULT Disable (void) = 0; + +protected: + virtual ~IDeckLinkKeyer () {} // call Release method to drop reference count +}; + +/* Interface IDeckLinkVideoConversion - Created with CoCreateInstance(). */ + +class IDeckLinkVideoConversion : public IUnknown +{ +public: + virtual HRESULT ConvertFrame (/* in */ IDeckLinkVideoFrame* srcFrame, /* in */ IDeckLinkVideoFrame* dstFrame) = 0; + +protected: + virtual ~IDeckLinkVideoConversion () {} // call Release method to drop reference count +}; + +/* Interface IDeckLinkDeviceNotificationCallback - DeckLink device arrival/removal notification callbacks */ + +class IDeckLinkDeviceNotificationCallback : public IUnknown +{ +public: + virtual HRESULT DeckLinkDeviceArrived (/* in */ IDeckLink* deckLinkDevice) = 0; + virtual HRESULT DeckLinkDeviceRemoved (/* in */ IDeckLink* deckLinkDevice) = 0; + +protected: + virtual ~IDeckLinkDeviceNotificationCallback () {} // call Release method to drop reference count +}; + +/* Interface IDeckLinkDiscovery - DeckLink device discovery */ + +class IDeckLinkDiscovery : public IUnknown +{ +public: + virtual HRESULT InstallDeviceNotifications (/* in */ IDeckLinkDeviceNotificationCallback* deviceNotificationCallback) = 0; + virtual HRESULT UninstallDeviceNotifications (void) = 0; + +protected: + virtual ~IDeckLinkDiscovery () {} // call Release method to drop reference count +}; + +/* Functions */ + +extern "C" { + + IDeckLinkIterator* CreateDeckLinkIteratorInstance (void); + IDeckLinkDiscovery* CreateDeckLinkDiscoveryInstance (void); + IDeckLinkAPIInformation* CreateDeckLinkAPIInformationInstance (void); + IDeckLinkGLScreenPreviewHelper* CreateOpenGLScreenPreviewHelper (void); + IDeckLinkVideoConversion* CreateVideoConversionInstance (void); + bool IsDeckLinkAPIPresent (void); +} + + +#endif // defined(__cplusplus) +#endif /* defined(BMD_DECKLINKAPI_H) */ diff --git a/intern/decklink/linux/DeckLinkAPIConfiguration.h b/intern/decklink/linux/DeckLinkAPIConfiguration.h new file mode 100644 index 00000000000..9d5bc9a9e1b --- /dev/null +++ b/intern/decklink/linux/DeckLinkAPIConfiguration.h @@ -0,0 +1,192 @@ +/* -LICENSE-START- +** Copyright (c) 2014 Blackmagic Design +** +** Permission is hereby granted, free of charge, to any person or organization +** obtaining a copy of the software and accompanying documentation covered by +** this license (the "Software") to use, reproduce, display, distribute, +** execute, and transmit the Software, and to prepare derivative works of the +** Software, and to permit third-parties to whom the Software is furnished to +** do so, all subject to the following: +** +** The copyright notices in the Software and this entire statement, including +** the above license grant, this restriction and the following disclaimer, +** must be included in all copies of the Software, in whole or in part, and +** all derivative works of the Software, unless such copies or derivative +** works are solely in the form of machine-executable object code generated by +** a source language processor. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +** DEALINGS IN THE SOFTWARE. +** -LICENSE-END- +*/ + +#ifndef BMD_DECKLINKAPICONFIGURATION_H +#define BMD_DECKLINKAPICONFIGURATION_H + + +#ifndef BMD_CONST + #if defined(_MSC_VER) + #define BMD_CONST __declspec(selectany) static const + #else + #define BMD_CONST static const + #endif +#endif + +// Type Declarations + + +// Interface ID Declarations + +BMD_CONST REFIID IID_IDeckLinkConfiguration = /* 1E69FCF6-4203-4936-8076-2A9F4CFD50CB */ {0x1E,0x69,0xFC,0xF6,0x42,0x03,0x49,0x36,0x80,0x76,0x2A,0x9F,0x4C,0xFD,0x50,0xCB}; + +/* Enum BMDDeckLinkConfigurationID - DeckLink Configuration ID */ + +typedef uint32_t BMDDeckLinkConfigurationID; +enum _BMDDeckLinkConfigurationID { + + /* Serial port Flags */ + + bmdDeckLinkConfigSwapSerialRxTx = /* 'ssrt' */ 0x73737274, + + /* Video Input/Output Flags */ + + bmdDeckLinkConfigUse1080pNotPsF = /* 'fpro' */ 0x6670726F, + + /* Video Input/Output Integers */ + + bmdDeckLinkConfigHDMI3DPackingFormat = /* '3dpf' */ 0x33647066, + bmdDeckLinkConfigBypass = /* 'byps' */ 0x62797073, + bmdDeckLinkConfigClockTimingAdjustment = /* 'ctad' */ 0x63746164, + + /* Audio Input/Output Flags */ + + bmdDeckLinkConfigAnalogAudioConsumerLevels = /* 'aacl' */ 0x6161636C, + + /* Video output flags */ + + bmdDeckLinkConfigFieldFlickerRemoval = /* 'fdfr' */ 0x66646672, + bmdDeckLinkConfigHD1080p24ToHD1080i5994Conversion = /* 'to59' */ 0x746F3539, + bmdDeckLinkConfig444SDIVideoOutput = /* '444o' */ 0x3434346F, + bmdDeckLinkConfigSingleLinkVideoOutput = /* 'sglo' */ 0x73676C6F, + bmdDeckLinkConfigBlackVideoOutputDuringCapture = /* 'bvoc' */ 0x62766F63, + bmdDeckLinkConfigLowLatencyVideoOutput = /* 'llvo' */ 0x6C6C766F, + bmdDeckLinkConfigDownConversionOnAllAnalogOutput = /* 'caao' */ 0x6361616F, + bmdDeckLinkConfigSMPTELevelAOutput = /* 'smta' */ 0x736D7461, + + /* Video Output Integers */ + + bmdDeckLinkConfigVideoOutputConnection = /* 'vocn' */ 0x766F636E, + bmdDeckLinkConfigVideoOutputConversionMode = /* 'vocm' */ 0x766F636D, + bmdDeckLinkConfigAnalogVideoOutputFlags = /* 'avof' */ 0x61766F66, + bmdDeckLinkConfigReferenceInputTimingOffset = /* 'glot' */ 0x676C6F74, + bmdDeckLinkConfigVideoOutputIdleOperation = /* 'voio' */ 0x766F696F, + bmdDeckLinkConfigDefaultVideoOutputMode = /* 'dvom' */ 0x64766F6D, + bmdDeckLinkConfigDefaultVideoOutputModeFlags = /* 'dvof' */ 0x64766F66, + + /* Video Output Floats */ + + bmdDeckLinkConfigVideoOutputComponentLumaGain = /* 'oclg' */ 0x6F636C67, + bmdDeckLinkConfigVideoOutputComponentChromaBlueGain = /* 'occb' */ 0x6F636362, + bmdDeckLinkConfigVideoOutputComponentChromaRedGain = /* 'occr' */ 0x6F636372, + bmdDeckLinkConfigVideoOutputCompositeLumaGain = /* 'oilg' */ 0x6F696C67, + bmdDeckLinkConfigVideoOutputCompositeChromaGain = /* 'oicg' */ 0x6F696367, + bmdDeckLinkConfigVideoOutputSVideoLumaGain = /* 'oslg' */ 0x6F736C67, + bmdDeckLinkConfigVideoOutputSVideoChromaGain = /* 'oscg' */ 0x6F736367, + + /* Video Input Flags */ + + bmdDeckLinkConfigVideoInputScanning = /* 'visc' */ 0x76697363, // Applicable to H264 Pro Recorder only + bmdDeckLinkConfigUseDedicatedLTCInput = /* 'dltc' */ 0x646C7463, // Use timecode from LTC input instead of SDI stream + + /* Video Input Integers */ + + bmdDeckLinkConfigVideoInputConnection = /* 'vicn' */ 0x7669636E, + bmdDeckLinkConfigAnalogVideoInputFlags = /* 'avif' */ 0x61766966, + bmdDeckLinkConfigVideoInputConversionMode = /* 'vicm' */ 0x7669636D, + bmdDeckLinkConfig32PulldownSequenceInitialTimecodeFrame = /* 'pdif' */ 0x70646966, + bmdDeckLinkConfigVANCSourceLine1Mapping = /* 'vsl1' */ 0x76736C31, + bmdDeckLinkConfigVANCSourceLine2Mapping = /* 'vsl2' */ 0x76736C32, + bmdDeckLinkConfigVANCSourceLine3Mapping = /* 'vsl3' */ 0x76736C33, + bmdDeckLinkConfigCapturePassThroughMode = /* 'cptm' */ 0x6370746D, + + /* Video Input Floats */ + + bmdDeckLinkConfigVideoInputComponentLumaGain = /* 'iclg' */ 0x69636C67, + bmdDeckLinkConfigVideoInputComponentChromaBlueGain = /* 'iccb' */ 0x69636362, + bmdDeckLinkConfigVideoInputComponentChromaRedGain = /* 'iccr' */ 0x69636372, + bmdDeckLinkConfigVideoInputCompositeLumaGain = /* 'iilg' */ 0x69696C67, + bmdDeckLinkConfigVideoInputCompositeChromaGain = /* 'iicg' */ 0x69696367, + bmdDeckLinkConfigVideoInputSVideoLumaGain = /* 'islg' */ 0x69736C67, + bmdDeckLinkConfigVideoInputSVideoChromaGain = /* 'iscg' */ 0x69736367, + + /* Audio Input Integers */ + + bmdDeckLinkConfigAudioInputConnection = /* 'aicn' */ 0x6169636E, + + /* Audio Input Floats */ + + bmdDeckLinkConfigAnalogAudioInputScaleChannel1 = /* 'ais1' */ 0x61697331, + bmdDeckLinkConfigAnalogAudioInputScaleChannel2 = /* 'ais2' */ 0x61697332, + bmdDeckLinkConfigAnalogAudioInputScaleChannel3 = /* 'ais3' */ 0x61697333, + bmdDeckLinkConfigAnalogAudioInputScaleChannel4 = /* 'ais4' */ 0x61697334, + bmdDeckLinkConfigDigitalAudioInputScale = /* 'dais' */ 0x64616973, + + /* Audio Output Integers */ + + bmdDeckLinkConfigAudioOutputAESAnalogSwitch = /* 'aoaa' */ 0x616F6161, + + /* Audio Output Floats */ + + bmdDeckLinkConfigAnalogAudioOutputScaleChannel1 = /* 'aos1' */ 0x616F7331, + bmdDeckLinkConfigAnalogAudioOutputScaleChannel2 = /* 'aos2' */ 0x616F7332, + bmdDeckLinkConfigAnalogAudioOutputScaleChannel3 = /* 'aos3' */ 0x616F7333, + bmdDeckLinkConfigAnalogAudioOutputScaleChannel4 = /* 'aos4' */ 0x616F7334, + bmdDeckLinkConfigDigitalAudioOutputScale = /* 'daos' */ 0x64616F73, + + /* Device Information Strings */ + + bmdDeckLinkConfigDeviceInformationLabel = /* 'dila' */ 0x64696C61, + bmdDeckLinkConfigDeviceInformationSerialNumber = /* 'disn' */ 0x6469736E, + bmdDeckLinkConfigDeviceInformationCompany = /* 'dico' */ 0x6469636F, + bmdDeckLinkConfigDeviceInformationPhone = /* 'diph' */ 0x64697068, + bmdDeckLinkConfigDeviceInformationEmail = /* 'diem' */ 0x6469656D, + bmdDeckLinkConfigDeviceInformationDate = /* 'dida' */ 0x64696461 +}; + +// Forward Declarations + +class IDeckLinkConfiguration; + +/* Interface IDeckLinkConfiguration - DeckLink Configuration interface */ + +class IDeckLinkConfiguration : public IUnknown +{ +public: + virtual HRESULT SetFlag (/* in */ BMDDeckLinkConfigurationID cfgID, /* in */ bool value) = 0; + virtual HRESULT GetFlag (/* in */ BMDDeckLinkConfigurationID cfgID, /* out */ bool *value) = 0; + virtual HRESULT SetInt (/* in */ BMDDeckLinkConfigurationID cfgID, /* in */ int64_t value) = 0; + virtual HRESULT GetInt (/* in */ BMDDeckLinkConfigurationID cfgID, /* out */ int64_t *value) = 0; + virtual HRESULT SetFloat (/* in */ BMDDeckLinkConfigurationID cfgID, /* in */ double value) = 0; + virtual HRESULT GetFloat (/* in */ BMDDeckLinkConfigurationID cfgID, /* out */ double *value) = 0; + virtual HRESULT SetString (/* in */ BMDDeckLinkConfigurationID cfgID, /* in */ const char *value) = 0; + virtual HRESULT GetString (/* in */ BMDDeckLinkConfigurationID cfgID, /* out */ const char **value) = 0; + virtual HRESULT WriteConfigurationToPreferences (void) = 0; + +protected: + virtual ~IDeckLinkConfiguration () {} // call Release method to drop reference count +}; + +/* Functions */ + +extern "C" { + + +} + + +#endif /* defined(BMD_DECKLINKAPICONFIGURATION_H) */ diff --git a/intern/decklink/linux/DeckLinkAPIDeckControl.h b/intern/decklink/linux/DeckLinkAPIDeckControl.h new file mode 100644 index 00000000000..b83d013129e --- /dev/null +++ b/intern/decklink/linux/DeckLinkAPIDeckControl.h @@ -0,0 +1,215 @@ +/* -LICENSE-START- +** Copyright (c) 2014 Blackmagic Design +** +** Permission is hereby granted, free of charge, to any person or organization +** obtaining a copy of the software and accompanying documentation covered by +** this license (the "Software") to use, reproduce, display, distribute, +** execute, and transmit the Software, and to prepare derivative works of the +** Software, and to permit third-parties to whom the Software is furnished to +** do so, all subject to the following: +** +** The copyright notices in the Software and this entire statement, including +** the above license grant, this restriction and the following disclaimer, +** must be included in all copies of the Software, in whole or in part, and +** all derivative works of the Software, unless such copies or derivative +** works are solely in the form of machine-executable object code generated by +** a source language processor. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +** DEALINGS IN THE SOFTWARE. +** -LICENSE-END- +*/ + +#ifndef BMD_DECKLINKAPIDECKCONTROL_H +#define BMD_DECKLINKAPIDECKCONTROL_H + + +#ifndef BMD_CONST + #if defined(_MSC_VER) + #define BMD_CONST __declspec(selectany) static const + #else + #define BMD_CONST static const + #endif +#endif + +// Type Declarations + + +// Interface ID Declarations + +BMD_CONST REFIID IID_IDeckLinkDeckControlStatusCallback = /* 53436FFB-B434-4906-BADC-AE3060FFE8EF */ {0x53,0x43,0x6F,0xFB,0xB4,0x34,0x49,0x06,0xBA,0xDC,0xAE,0x30,0x60,0xFF,0xE8,0xEF}; +BMD_CONST REFIID IID_IDeckLinkDeckControl = /* 8E1C3ACE-19C7-4E00-8B92-D80431D958BE */ {0x8E,0x1C,0x3A,0xCE,0x19,0xC7,0x4E,0x00,0x8B,0x92,0xD8,0x04,0x31,0xD9,0x58,0xBE}; + +/* Enum BMDDeckControlMode - DeckControl mode */ + +typedef uint32_t BMDDeckControlMode; +enum _BMDDeckControlMode { + bmdDeckControlNotOpened = /* 'ntop' */ 0x6E746F70, + bmdDeckControlVTRControlMode = /* 'vtrc' */ 0x76747263, + bmdDeckControlExportMode = /* 'expm' */ 0x6578706D, + bmdDeckControlCaptureMode = /* 'capm' */ 0x6361706D +}; + +/* Enum BMDDeckControlEvent - DeckControl event */ + +typedef uint32_t BMDDeckControlEvent; +enum _BMDDeckControlEvent { + bmdDeckControlAbortedEvent = /* 'abte' */ 0x61627465, // This event is triggered when a capture or edit-to-tape operation is aborted. + + /* Export-To-Tape events */ + + bmdDeckControlPrepareForExportEvent = /* 'pfee' */ 0x70666565, // This event is triggered a few frames before reaching the in-point. IDeckLinkInput::StartScheduledPlayback() should be called at this point. + bmdDeckControlExportCompleteEvent = /* 'exce' */ 0x65786365, // This event is triggered a few frames after reaching the out-point. At this point, it is safe to stop playback. + + /* Capture events */ + + bmdDeckControlPrepareForCaptureEvent = /* 'pfce' */ 0x70666365, // This event is triggered a few frames before reaching the in-point. The serial timecode attached to IDeckLinkVideoInputFrames is now valid. + bmdDeckControlCaptureCompleteEvent = /* 'ccev' */ 0x63636576 // This event is triggered a few frames after reaching the out-point. +}; + +/* Enum BMDDeckControlVTRControlState - VTR Control state */ + +typedef uint32_t BMDDeckControlVTRControlState; +enum _BMDDeckControlVTRControlState { + bmdDeckControlNotInVTRControlMode = /* 'nvcm' */ 0x6E76636D, + bmdDeckControlVTRControlPlaying = /* 'vtrp' */ 0x76747270, + bmdDeckControlVTRControlRecording = /* 'vtrr' */ 0x76747272, + bmdDeckControlVTRControlStill = /* 'vtra' */ 0x76747261, + bmdDeckControlVTRControlShuttleForward = /* 'vtsf' */ 0x76747366, + bmdDeckControlVTRControlShuttleReverse = /* 'vtsr' */ 0x76747372, + bmdDeckControlVTRControlJogForward = /* 'vtjf' */ 0x76746A66, + bmdDeckControlVTRControlJogReverse = /* 'vtjr' */ 0x76746A72, + bmdDeckControlVTRControlStopped = /* 'vtro' */ 0x7674726F +}; + +/* Enum BMDDeckControlStatusFlags - Deck Control status flags */ + +typedef uint32_t BMDDeckControlStatusFlags; +enum _BMDDeckControlStatusFlags { + bmdDeckControlStatusDeckConnected = 1 << 0, + bmdDeckControlStatusRemoteMode = 1 << 1, + bmdDeckControlStatusRecordInhibited = 1 << 2, + bmdDeckControlStatusCassetteOut = 1 << 3 +}; + +/* Enum BMDDeckControlExportModeOpsFlags - Export mode flags */ + +typedef uint32_t BMDDeckControlExportModeOpsFlags; +enum _BMDDeckControlExportModeOpsFlags { + bmdDeckControlExportModeInsertVideo = 1 << 0, + bmdDeckControlExportModeInsertAudio1 = 1 << 1, + bmdDeckControlExportModeInsertAudio2 = 1 << 2, + bmdDeckControlExportModeInsertAudio3 = 1 << 3, + bmdDeckControlExportModeInsertAudio4 = 1 << 4, + bmdDeckControlExportModeInsertAudio5 = 1 << 5, + bmdDeckControlExportModeInsertAudio6 = 1 << 6, + bmdDeckControlExportModeInsertAudio7 = 1 << 7, + bmdDeckControlExportModeInsertAudio8 = 1 << 8, + bmdDeckControlExportModeInsertAudio9 = 1 << 9, + bmdDeckControlExportModeInsertAudio10 = 1 << 10, + bmdDeckControlExportModeInsertAudio11 = 1 << 11, + bmdDeckControlExportModeInsertAudio12 = 1 << 12, + bmdDeckControlExportModeInsertTimeCode = 1 << 13, + bmdDeckControlExportModeInsertAssemble = 1 << 14, + bmdDeckControlExportModeInsertPreview = 1 << 15, + bmdDeckControlUseManualExport = 1 << 16 +}; + +/* Enum BMDDeckControlError - Deck Control error */ + +typedef uint32_t BMDDeckControlError; +enum _BMDDeckControlError { + bmdDeckControlNoError = /* 'noer' */ 0x6E6F6572, + bmdDeckControlModeError = /* 'moer' */ 0x6D6F6572, + bmdDeckControlMissedInPointError = /* 'mier' */ 0x6D696572, + bmdDeckControlDeckTimeoutError = /* 'dter' */ 0x64746572, + bmdDeckControlCommandFailedError = /* 'cfer' */ 0x63666572, + bmdDeckControlDeviceAlreadyOpenedError = /* 'dalo' */ 0x64616C6F, + bmdDeckControlFailedToOpenDeviceError = /* 'fder' */ 0x66646572, + bmdDeckControlInLocalModeError = /* 'lmer' */ 0x6C6D6572, + bmdDeckControlEndOfTapeError = /* 'eter' */ 0x65746572, + bmdDeckControlUserAbortError = /* 'uaer' */ 0x75616572, + bmdDeckControlNoTapeInDeckError = /* 'nter' */ 0x6E746572, + bmdDeckControlNoVideoFromCardError = /* 'nvfc' */ 0x6E766663, + bmdDeckControlNoCommunicationError = /* 'ncom' */ 0x6E636F6D, + bmdDeckControlBufferTooSmallError = /* 'btsm' */ 0x6274736D, + bmdDeckControlBadChecksumError = /* 'chks' */ 0x63686B73, + bmdDeckControlUnknownError = /* 'uner' */ 0x756E6572 +}; + +// Forward Declarations + +class IDeckLinkDeckControlStatusCallback; +class IDeckLinkDeckControl; + +/* Interface IDeckLinkDeckControlStatusCallback - Deck control state change callback. */ + +class IDeckLinkDeckControlStatusCallback : public IUnknown +{ +public: + virtual HRESULT TimecodeUpdate (/* in */ BMDTimecodeBCD currentTimecode) = 0; + virtual HRESULT VTRControlStateChanged (/* in */ BMDDeckControlVTRControlState newState, /* in */ BMDDeckControlError error) = 0; + virtual HRESULT DeckControlEventReceived (/* in */ BMDDeckControlEvent event, /* in */ BMDDeckControlError error) = 0; + virtual HRESULT DeckControlStatusChanged (/* in */ BMDDeckControlStatusFlags flags, /* in */ uint32_t mask) = 0; + +protected: + virtual ~IDeckLinkDeckControlStatusCallback () {} // call Release method to drop reference count +}; + +/* Interface IDeckLinkDeckControl - Deck Control main interface */ + +class IDeckLinkDeckControl : public IUnknown +{ +public: + virtual HRESULT Open (/* in */ BMDTimeScale timeScale, /* in */ BMDTimeValue timeValue, /* in */ bool timecodeIsDropFrame, /* out */ BMDDeckControlError *error) = 0; + virtual HRESULT Close (/* in */ bool standbyOn) = 0; + virtual HRESULT GetCurrentState (/* out */ BMDDeckControlMode *mode, /* out */ BMDDeckControlVTRControlState *vtrControlState, /* out */ BMDDeckControlStatusFlags *flags) = 0; + virtual HRESULT SetStandby (/* in */ bool standbyOn) = 0; + virtual HRESULT SendCommand (/* in */ uint8_t *inBuffer, /* in */ uint32_t inBufferSize, /* out */ uint8_t *outBuffer, /* out */ uint32_t *outDataSize, /* in */ uint32_t outBufferSize, /* out */ BMDDeckControlError *error) = 0; + virtual HRESULT Play (/* out */ BMDDeckControlError *error) = 0; + virtual HRESULT Stop (/* out */ BMDDeckControlError *error) = 0; + virtual HRESULT TogglePlayStop (/* out */ BMDDeckControlError *error) = 0; + virtual HRESULT Eject (/* out */ BMDDeckControlError *error) = 0; + virtual HRESULT GoToTimecode (/* in */ BMDTimecodeBCD timecode, /* out */ BMDDeckControlError *error) = 0; + virtual HRESULT FastForward (/* in */ bool viewTape, /* out */ BMDDeckControlError *error) = 0; + virtual HRESULT Rewind (/* in */ bool viewTape, /* out */ BMDDeckControlError *error) = 0; + virtual HRESULT StepForward (/* out */ BMDDeckControlError *error) = 0; + virtual HRESULT StepBack (/* out */ BMDDeckControlError *error) = 0; + virtual HRESULT Jog (/* in */ double rate, /* out */ BMDDeckControlError *error) = 0; + virtual HRESULT Shuttle (/* in */ double rate, /* out */ BMDDeckControlError *error) = 0; + virtual HRESULT GetTimecodeString (/* out */ const char **currentTimeCode, /* out */ BMDDeckControlError *error) = 0; + virtual HRESULT GetTimecode (/* out */ IDeckLinkTimecode **currentTimecode, /* out */ BMDDeckControlError *error) = 0; + virtual HRESULT GetTimecodeBCD (/* out */ BMDTimecodeBCD *currentTimecode, /* out */ BMDDeckControlError *error) = 0; + virtual HRESULT SetPreroll (/* in */ uint32_t prerollSeconds) = 0; + virtual HRESULT GetPreroll (/* out */ uint32_t *prerollSeconds) = 0; + virtual HRESULT SetExportOffset (/* in */ int32_t exportOffsetFields) = 0; + virtual HRESULT GetExportOffset (/* out */ int32_t *exportOffsetFields) = 0; + virtual HRESULT GetManualExportOffset (/* out */ int32_t *deckManualExportOffsetFields) = 0; + virtual HRESULT SetCaptureOffset (/* in */ int32_t captureOffsetFields) = 0; + virtual HRESULT GetCaptureOffset (/* out */ int32_t *captureOffsetFields) = 0; + virtual HRESULT StartExport (/* in */ BMDTimecodeBCD inTimecode, /* in */ BMDTimecodeBCD outTimecode, /* in */ BMDDeckControlExportModeOpsFlags exportModeOps, /* out */ BMDDeckControlError *error) = 0; + virtual HRESULT StartCapture (/* in */ bool useVITC, /* in */ BMDTimecodeBCD inTimecode, /* in */ BMDTimecodeBCD outTimecode, /* out */ BMDDeckControlError *error) = 0; + virtual HRESULT GetDeviceID (/* out */ uint16_t *deviceId, /* out */ BMDDeckControlError *error) = 0; + virtual HRESULT Abort (void) = 0; + virtual HRESULT CrashRecordStart (/* out */ BMDDeckControlError *error) = 0; + virtual HRESULT CrashRecordStop (/* out */ BMDDeckControlError *error) = 0; + virtual HRESULT SetCallback (/* in */ IDeckLinkDeckControlStatusCallback *callback) = 0; + +protected: + virtual ~IDeckLinkDeckControl () {} // call Release method to drop reference count +}; + +/* Functions */ + +extern "C" { + + +} + + +#endif /* defined(BMD_DECKLINKAPIDECKCONTROL_H) */ diff --git a/intern/decklink/linux/DeckLinkAPIDiscovery.h b/intern/decklink/linux/DeckLinkAPIDiscovery.h new file mode 100644 index 00000000000..424d9d54b39 --- /dev/null +++ b/intern/decklink/linux/DeckLinkAPIDiscovery.h @@ -0,0 +1,71 @@ +/* -LICENSE-START- +** Copyright (c) 2014 Blackmagic Design +** +** Permission is hereby granted, free of charge, to any person or organization +** obtaining a copy of the software and accompanying documentation covered by +** this license (the "Software") to use, reproduce, display, distribute, +** execute, and transmit the Software, and to prepare derivative works of the +** Software, and to permit third-parties to whom the Software is furnished to +** do so, all subject to the following: +** +** The copyright notices in the Software and this entire statement, including +** the above license grant, this restriction and the following disclaimer, +** must be included in all copies of the Software, in whole or in part, and +** all derivative works of the Software, unless such copies or derivative +** works are solely in the form of machine-executable object code generated by +** a source language processor. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +** DEALINGS IN THE SOFTWARE. +** -LICENSE-END- +*/ + +#ifndef BMD_DECKLINKAPIDISCOVERY_H +#define BMD_DECKLINKAPIDISCOVERY_H + + +#ifndef BMD_CONST + #if defined(_MSC_VER) + #define BMD_CONST __declspec(selectany) static const + #else + #define BMD_CONST static const + #endif +#endif + +// Type Declarations + + +// Interface ID Declarations + +BMD_CONST REFIID IID_IDeckLink = /* C418FBDD-0587-48ED-8FE5-640F0A14AF91 */ {0xC4,0x18,0xFB,0xDD,0x05,0x87,0x48,0xED,0x8F,0xE5,0x64,0x0F,0x0A,0x14,0xAF,0x91}; + +// Forward Declarations + +class IDeckLink; + +/* Interface IDeckLink - represents a DeckLink device */ + +class IDeckLink : public IUnknown +{ +public: + virtual HRESULT GetModelName (/* out */ const char **modelName) = 0; + virtual HRESULT GetDisplayName (/* out */ const char **displayName) = 0; + +protected: + virtual ~IDeckLink () {} // call Release method to drop reference count +}; + +/* Functions */ + +extern "C" { + + +} + + +#endif /* defined(BMD_DECKLINKAPIDISCOVERY_H) */ diff --git a/intern/decklink/linux/DeckLinkAPIDispatch.cpp b/intern/decklink/linux/DeckLinkAPIDispatch.cpp new file mode 100644 index 00000000000..3cf53f109ac --- /dev/null +++ b/intern/decklink/linux/DeckLinkAPIDispatch.cpp @@ -0,0 +1,148 @@ +/* -LICENSE-START- +** Copyright (c) 2009 Blackmagic Design +** +** Permission is hereby granted, free of charge, to any person or organization +** obtaining a copy of the software and accompanying documentation covered by +** this license (the "Software") to use, reproduce, display, distribute, +** execute, and transmit the Software, and to prepare derivative works of the +** Software, and to permit third-parties to whom the Software is furnished to +** do so, all subject to the following: +** +** The copyright notices in the Software and this entire statement, including +** the above license grant, this restriction and the following disclaimer, +** must be included in all copies of the Software, in whole or in part, and +** all derivative works of the Software, unless such copies or derivative +** works are solely in the form of machine-executable object code generated by +** a source language processor. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +** DEALINGS IN THE SOFTWARE. +** -LICENSE-END- +**/ + +#include <stdlib.h> +#include <stdio.h> +#include <pthread.h> +#include <dlfcn.h> +#include <ctype.h> + +#include "DeckLinkAPI.h" + +#define kDeckLinkAPI_Name "libDeckLinkAPI.so" +#define KDeckLinkPreviewAPI_Name "libDeckLinkPreviewAPI.so" + +typedef IDeckLinkIterator* (*CreateIteratorFunc)(void); +typedef IDeckLinkAPIInformation* (*CreateAPIInformationFunc)(void); +typedef IDeckLinkGLScreenPreviewHelper* (*CreateOpenGLScreenPreviewHelperFunc)(void); +typedef IDeckLinkVideoConversion* (*CreateVideoConversionInstanceFunc)(void); +typedef IDeckLinkDiscovery* (*CreateDeckLinkDiscoveryInstanceFunc)(void); + +static pthread_once_t gDeckLinkOnceControl = PTHREAD_ONCE_INIT; +static pthread_once_t gPreviewOnceControl = PTHREAD_ONCE_INIT; + +static bool gLoadedDeckLinkAPI = false; + +static CreateIteratorFunc gCreateIteratorFunc = NULL; +static CreateAPIInformationFunc gCreateAPIInformationFunc = NULL; +static CreateOpenGLScreenPreviewHelperFunc gCreateOpenGLPreviewFunc = NULL; +static CreateVideoConversionInstanceFunc gCreateVideoConversionFunc = NULL; +static CreateDeckLinkDiscoveryInstanceFunc gCreateDeckLinkDiscoveryFunc = NULL; + +static void InitDeckLinkAPI (void) +{ + void *libraryHandle; + + libraryHandle = dlopen(kDeckLinkAPI_Name, RTLD_NOW|RTLD_GLOBAL); + if (!libraryHandle) + { + fprintf(stderr, "%s\n", dlerror()); + return; + } + + gLoadedDeckLinkAPI = true; + + gCreateIteratorFunc = (CreateIteratorFunc)dlsym(libraryHandle, "CreateDeckLinkIteratorInstance_0002"); + if (!gCreateIteratorFunc) + fprintf(stderr, "%s\n", dlerror()); + gCreateAPIInformationFunc = (CreateAPIInformationFunc)dlsym(libraryHandle, "CreateDeckLinkAPIInformationInstance_0001"); + if (!gCreateAPIInformationFunc) + fprintf(stderr, "%s\n", dlerror()); + gCreateVideoConversionFunc = (CreateVideoConversionInstanceFunc)dlsym(libraryHandle, "CreateVideoConversionInstance_0001"); + if (!gCreateVideoConversionFunc) + fprintf(stderr, "%s\n", dlerror()); + gCreateDeckLinkDiscoveryFunc = (CreateDeckLinkDiscoveryInstanceFunc)dlsym(libraryHandle, "CreateDeckLinkDiscoveryInstance_0001"); + if (!gCreateDeckLinkDiscoveryFunc) + fprintf(stderr, "%s\n", dlerror()); +} + +static void InitDeckLinkPreviewAPI (void) +{ + void *libraryHandle; + + libraryHandle = dlopen(KDeckLinkPreviewAPI_Name, RTLD_NOW|RTLD_GLOBAL); + if (!libraryHandle) + { + fprintf(stderr, "%s\n", dlerror()); + return; + } + gCreateOpenGLPreviewFunc = (CreateOpenGLScreenPreviewHelperFunc)dlsym(libraryHandle, "CreateOpenGLScreenPreviewHelper_0001"); + if (!gCreateOpenGLPreviewFunc) + fprintf(stderr, "%s\n", dlerror()); +} + +bool IsDeckLinkAPIPresent (void) +{ + // If the DeckLink API dynamic library was successfully loaded, return this knowledge to the caller + return gLoadedDeckLinkAPI; +} + +IDeckLinkIterator* CreateDeckLinkIteratorInstance (void) +{ + pthread_once(&gDeckLinkOnceControl, InitDeckLinkAPI); + + if (gCreateIteratorFunc == NULL) + return NULL; + return gCreateIteratorFunc(); +} + +IDeckLinkAPIInformation* CreateDeckLinkAPIInformationInstance (void) +{ + pthread_once(&gDeckLinkOnceControl, InitDeckLinkAPI); + + if (gCreateAPIInformationFunc == NULL) + return NULL; + return gCreateAPIInformationFunc(); +} + +IDeckLinkGLScreenPreviewHelper* CreateOpenGLScreenPreviewHelper (void) +{ + pthread_once(&gDeckLinkOnceControl, InitDeckLinkAPI); + pthread_once(&gPreviewOnceControl, InitDeckLinkPreviewAPI); + + if (gCreateOpenGLPreviewFunc == NULL) + return NULL; + return gCreateOpenGLPreviewFunc(); +} + +IDeckLinkVideoConversion* CreateVideoConversionInstance (void) +{ + pthread_once(&gDeckLinkOnceControl, InitDeckLinkAPI); + + if (gCreateVideoConversionFunc == NULL) + return NULL; + return gCreateVideoConversionFunc(); +} + +IDeckLinkDiscovery* CreateDeckLinkDiscoveryInstance (void) +{ + pthread_once(&gDeckLinkOnceControl, InitDeckLinkAPI); + + if (gCreateDeckLinkDiscoveryFunc == NULL) + return NULL; + return gCreateDeckLinkDiscoveryFunc(); +} diff --git a/intern/decklink/linux/DeckLinkAPIModes.h b/intern/decklink/linux/DeckLinkAPIModes.h new file mode 100644 index 00000000000..394d68c3078 --- /dev/null +++ b/intern/decklink/linux/DeckLinkAPIModes.h @@ -0,0 +1,191 @@ +/* -LICENSE-START- +** Copyright (c) 2014 Blackmagic Design +** +** Permission is hereby granted, free of charge, to any person or organization +** obtaining a copy of the software and accompanying documentation covered by +** this license (the "Software") to use, reproduce, display, distribute, +** execute, and transmit the Software, and to prepare derivative works of the +** Software, and to permit third-parties to whom the Software is furnished to +** do so, all subject to the following: +** +** The copyright notices in the Software and this entire statement, including +** the above license grant, this restriction and the following disclaimer, +** must be included in all copies of the Software, in whole or in part, and +** all derivative works of the Software, unless such copies or derivative +** works are solely in the form of machine-executable object code generated by +** a source language processor. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +** DEALINGS IN THE SOFTWARE. +** -LICENSE-END- +*/ + +#ifndef BMD_DECKLINKAPIMODES_H +#define BMD_DECKLINKAPIMODES_H + + +#ifndef BMD_CONST + #if defined(_MSC_VER) + #define BMD_CONST __declspec(selectany) static const + #else + #define BMD_CONST static const + #endif +#endif + +// Type Declarations + + +// Interface ID Declarations + +BMD_CONST REFIID IID_IDeckLinkDisplayModeIterator = /* 9C88499F-F601-4021-B80B-032E4EB41C35 */ {0x9C,0x88,0x49,0x9F,0xF6,0x01,0x40,0x21,0xB8,0x0B,0x03,0x2E,0x4E,0xB4,0x1C,0x35}; +BMD_CONST REFIID IID_IDeckLinkDisplayMode = /* 3EB2C1AB-0A3D-4523-A3AD-F40D7FB14E78 */ {0x3E,0xB2,0xC1,0xAB,0x0A,0x3D,0x45,0x23,0xA3,0xAD,0xF4,0x0D,0x7F,0xB1,0x4E,0x78}; + +/* Enum BMDDisplayMode - Video display modes */ + +typedef uint32_t BMDDisplayMode; +enum _BMDDisplayMode { + + /* SD Modes */ + + bmdModeNTSC = /* 'ntsc' */ 0x6E747363, + bmdModeNTSC2398 = /* 'nt23' */ 0x6E743233, // 3:2 pulldown + bmdModePAL = /* 'pal ' */ 0x70616C20, + bmdModeNTSCp = /* 'ntsp' */ 0x6E747370, + bmdModePALp = /* 'palp' */ 0x70616C70, + + /* HD 1080 Modes */ + + bmdModeHD1080p2398 = /* '23ps' */ 0x32337073, + bmdModeHD1080p24 = /* '24ps' */ 0x32347073, + bmdModeHD1080p25 = /* 'Hp25' */ 0x48703235, + bmdModeHD1080p2997 = /* 'Hp29' */ 0x48703239, + bmdModeHD1080p30 = /* 'Hp30' */ 0x48703330, + bmdModeHD1080i50 = /* 'Hi50' */ 0x48693530, + bmdModeHD1080i5994 = /* 'Hi59' */ 0x48693539, + bmdModeHD1080i6000 = /* 'Hi60' */ 0x48693630, // N.B. This _really_ is 60.00 Hz. + bmdModeHD1080p50 = /* 'Hp50' */ 0x48703530, + bmdModeHD1080p5994 = /* 'Hp59' */ 0x48703539, + bmdModeHD1080p6000 = /* 'Hp60' */ 0x48703630, // N.B. This _really_ is 60.00 Hz. + + /* HD 720 Modes */ + + bmdModeHD720p50 = /* 'hp50' */ 0x68703530, + bmdModeHD720p5994 = /* 'hp59' */ 0x68703539, + bmdModeHD720p60 = /* 'hp60' */ 0x68703630, + + /* 2k Modes */ + + bmdMode2k2398 = /* '2k23' */ 0x326B3233, + bmdMode2k24 = /* '2k24' */ 0x326B3234, + bmdMode2k25 = /* '2k25' */ 0x326B3235, + + /* DCI Modes (output only) */ + + bmdMode2kDCI2398 = /* '2d23' */ 0x32643233, + bmdMode2kDCI24 = /* '2d24' */ 0x32643234, + bmdMode2kDCI25 = /* '2d25' */ 0x32643235, + + /* 4k Modes */ + + bmdMode4K2160p2398 = /* '4k23' */ 0x346B3233, + bmdMode4K2160p24 = /* '4k24' */ 0x346B3234, + bmdMode4K2160p25 = /* '4k25' */ 0x346B3235, + bmdMode4K2160p2997 = /* '4k29' */ 0x346B3239, + bmdMode4K2160p30 = /* '4k30' */ 0x346B3330, + bmdMode4K2160p50 = /* '4k50' */ 0x346B3530, + bmdMode4K2160p5994 = /* '4k59' */ 0x346B3539, + bmdMode4K2160p60 = /* '4k60' */ 0x346B3630, + + /* DCI Modes (output only) */ + + bmdMode4kDCI2398 = /* '4d23' */ 0x34643233, + bmdMode4kDCI24 = /* '4d24' */ 0x34643234, + bmdMode4kDCI25 = /* '4d25' */ 0x34643235, + + /* Special Modes */ + + bmdModeUnknown = /* 'iunk' */ 0x69756E6B +}; + +/* Enum BMDFieldDominance - Video field dominance */ + +typedef uint32_t BMDFieldDominance; +enum _BMDFieldDominance { + bmdUnknownFieldDominance = 0, + bmdLowerFieldFirst = /* 'lowr' */ 0x6C6F7772, + bmdUpperFieldFirst = /* 'uppr' */ 0x75707072, + bmdProgressiveFrame = /* 'prog' */ 0x70726F67, + bmdProgressiveSegmentedFrame = /* 'psf ' */ 0x70736620 +}; + +/* Enum BMDPixelFormat - Video pixel formats supported for output/input */ + +typedef uint32_t BMDPixelFormat; +enum _BMDPixelFormat { + bmdFormat8BitYUV = /* '2vuy' */ 0x32767579, + bmdFormat10BitYUV = /* 'v210' */ 0x76323130, + bmdFormat8BitARGB = 32, + bmdFormat8BitBGRA = /* 'BGRA' */ 0x42475241, + bmdFormat10BitRGB = /* 'r210' */ 0x72323130, // Big-endian RGB 10-bit per component with SMPTE video levels (64-960). Packed as 2:10:10:10 + bmdFormat12BitRGB = /* 'R12B' */ 0x52313242, // Big-endian RGB 12-bit per component with full range (0-4095). Packed as 12-bit per component + bmdFormat12BitRGBLE = /* 'R12L' */ 0x5231324C, // Little-endian RGB 12-bit per component with full range (0-4095). Packed as 12-bit per component + bmdFormat10BitRGBXLE = /* 'R10l' */ 0x5231306C, // Little-endian 10-bit RGB with SMPTE video levels (64-940) + bmdFormat10BitRGBX = /* 'R10b' */ 0x52313062 // Big-endian 10-bit RGB with SMPTE video levels (64-940) +}; + +/* Enum BMDDisplayModeFlags - Flags to describe the characteristics of an IDeckLinkDisplayMode. */ + +typedef uint32_t BMDDisplayModeFlags; +enum _BMDDisplayModeFlags { + bmdDisplayModeSupports3D = 1 << 0, + bmdDisplayModeColorspaceRec601 = 1 << 1, + bmdDisplayModeColorspaceRec709 = 1 << 2 +}; + +// Forward Declarations + +class IDeckLinkDisplayModeIterator; +class IDeckLinkDisplayMode; + +/* Interface IDeckLinkDisplayModeIterator - enumerates over supported input/output display modes. */ + +class IDeckLinkDisplayModeIterator : public IUnknown +{ +public: + virtual HRESULT Next (/* out */ IDeckLinkDisplayMode **deckLinkDisplayMode) = 0; + +protected: + virtual ~IDeckLinkDisplayModeIterator () {} // call Release method to drop reference count +}; + +/* Interface IDeckLinkDisplayMode - represents a display mode */ + +class IDeckLinkDisplayMode : public IUnknown +{ +public: + virtual HRESULT GetName (/* out */ const char **name) = 0; + virtual BMDDisplayMode GetDisplayMode (void) = 0; + virtual long GetWidth (void) = 0; + virtual long GetHeight (void) = 0; + virtual HRESULT GetFrameRate (/* out */ BMDTimeValue *frameDuration, /* out */ BMDTimeScale *timeScale) = 0; + virtual BMDFieldDominance GetFieldDominance (void) = 0; + virtual BMDDisplayModeFlags GetFlags (void) = 0; + +protected: + virtual ~IDeckLinkDisplayMode () {} // call Release method to drop reference count +}; + +/* Functions */ + +extern "C" { + + +} + + +#endif /* defined(BMD_DECKLINKAPIMODES_H) */ diff --git a/intern/decklink/linux/DeckLinkAPITypes.h b/intern/decklink/linux/DeckLinkAPITypes.h new file mode 100644 index 00000000000..55e015f2a3c --- /dev/null +++ b/intern/decklink/linux/DeckLinkAPITypes.h @@ -0,0 +1,110 @@ +/* -LICENSE-START- +** Copyright (c) 2014 Blackmagic Design +** +** Permission is hereby granted, free of charge, to any person or organization +** obtaining a copy of the software and accompanying documentation covered by +** this license (the "Software") to use, reproduce, display, distribute, +** execute, and transmit the Software, and to prepare derivative works of the +** Software, and to permit third-parties to whom the Software is furnished to +** do so, all subject to the following: +** +** The copyright notices in the Software and this entire statement, including +** the above license grant, this restriction and the following disclaimer, +** must be included in all copies of the Software, in whole or in part, and +** all derivative works of the Software, unless such copies or derivative +** works are solely in the form of machine-executable object code generated by +** a source language processor. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +** DEALINGS IN THE SOFTWARE. +** -LICENSE-END- +*/ + +#ifndef BMD_DECKLINKAPITYPES_H +#define BMD_DECKLINKAPITYPES_H + + +#ifndef BMD_CONST + #if defined(_MSC_VER) + #define BMD_CONST __declspec(selectany) static const + #else + #define BMD_CONST static const + #endif +#endif + +// Type Declarations + +typedef int64_t BMDTimeValue; +typedef int64_t BMDTimeScale; +typedef uint32_t BMDTimecodeBCD; +typedef uint32_t BMDTimecodeUserBits; + +// Interface ID Declarations + +BMD_CONST REFIID IID_IDeckLinkTimecode = /* BC6CFBD3-8317-4325-AC1C-1216391E9340 */ {0xBC,0x6C,0xFB,0xD3,0x83,0x17,0x43,0x25,0xAC,0x1C,0x12,0x16,0x39,0x1E,0x93,0x40}; + +/* Enum BMDTimecodeFlags - Timecode flags */ + +typedef uint32_t BMDTimecodeFlags; +enum _BMDTimecodeFlags { + bmdTimecodeFlagDefault = 0, + bmdTimecodeIsDropFrame = 1 << 0, + bmdTimecodeFieldMark = 1 << 1 +}; + +/* Enum BMDVideoConnection - Video connection types */ + +typedef uint32_t BMDVideoConnection; +enum _BMDVideoConnection { + bmdVideoConnectionSDI = 1 << 0, + bmdVideoConnectionHDMI = 1 << 1, + bmdVideoConnectionOpticalSDI = 1 << 2, + bmdVideoConnectionComponent = 1 << 3, + bmdVideoConnectionComposite = 1 << 4, + bmdVideoConnectionSVideo = 1 << 5 +}; + +/* Enum BMDAudioConnection - Audio connection types */ + +typedef uint32_t BMDAudioConnection; +enum _BMDAudioConnection { + bmdAudioConnectionEmbedded = 1 << 0, + bmdAudioConnectionAESEBU = 1 << 1, + bmdAudioConnectionAnalog = 1 << 2, + bmdAudioConnectionAnalogXLR = 1 << 3, + bmdAudioConnectionAnalogRCA = 1 << 4 +}; + +// Forward Declarations + +class IDeckLinkTimecode; + +/* Interface IDeckLinkTimecode - Used for video frame timecode representation. */ + +class IDeckLinkTimecode : public IUnknown +{ +public: + virtual BMDTimecodeBCD GetBCD (void) = 0; + virtual HRESULT GetComponents (/* out */ uint8_t *hours, /* out */ uint8_t *minutes, /* out */ uint8_t *seconds, /* out */ uint8_t *frames) = 0; + virtual HRESULT GetString (/* out */ const char **timecode) = 0; + virtual BMDTimecodeFlags GetFlags (void) = 0; + virtual HRESULT GetTimecodeUserBits (/* out */ BMDTimecodeUserBits *userBits) = 0; + +protected: + virtual ~IDeckLinkTimecode () {} // call Release method to drop reference count +}; + +/* Functions */ + +extern "C" { + + +} + + +#endif /* defined(BMD_DECKLINKAPITYPES_H) */ diff --git a/intern/decklink/linux/DeckLinkAPIVersion.h b/intern/decklink/linux/DeckLinkAPIVersion.h new file mode 100644 index 00000000000..cfcc701c427 --- /dev/null +++ b/intern/decklink/linux/DeckLinkAPIVersion.h @@ -0,0 +1,37 @@ +/* -LICENSE-START- + * ** Copyright (c) 2014 Blackmagic Design + * ** + * ** Permission is hereby granted, free of charge, to any person or organization + * ** obtaining a copy of the software and accompanying documentation covered by + * ** this license (the "Software") to use, reproduce, display, distribute, + * ** execute, and transmit the Software, and to prepare derivative works of the + * ** Software, and to permit third-parties to whom the Software is furnished to + * ** do so, all subject to the following: + * ** + * ** The copyright notices in the Software and this entire statement, including + * ** the above license grant, this restriction and the following disclaimer, + * ** must be included in all copies of the Software, in whole or in part, and + * ** all derivative works of the Software, unless such copies or derivative + * ** works are solely in the form of machine-executable object code generated by + * ** a source language processor. + * ** + * ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * ** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * ** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT + * ** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE + * ** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, + * ** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * ** DEALINGS IN THE SOFTWARE. + * ** -LICENSE-END- + * */ + +/* DeckLinkAPIVersion.h */ + +#ifndef __DeckLink_API_Version_h__ +#define __DeckLink_API_Version_h__ + +#define BLACKMAGIC_DECKLINK_API_VERSION 0x0a040000 +#define BLACKMAGIC_DECKLINK_API_VERSION_STRING "10.4" + +#endif // __DeckLink_API_Version_h__ + diff --git a/intern/decklink/linux/LinuxCOM.h b/intern/decklink/linux/LinuxCOM.h new file mode 100644 index 00000000000..ee783bbd58f --- /dev/null +++ b/intern/decklink/linux/LinuxCOM.h @@ -0,0 +1,100 @@ +/* -LICENSE-START- +** Copyright (c) 2009 Blackmagic Design +** +** Permission is hereby granted, free of charge, to any person or organization +** obtaining a copy of the software and accompanying documentation covered by +** this license (the "Software") to use, reproduce, display, distribute, +** execute, and transmit the Software, and to prepare derivative works of the +** Software, and to permit third-parties to whom the Software is furnished to +** do so, all subject to the following: +** +** The copyright notices in the Software and this entire statement, including +** the above license grant, this restriction and the following disclaimer, +** must be included in all copies of the Software, in whole or in part, and +** all derivative works of the Software, unless such copies or derivative +** works are solely in the form of machine-executable object code generated by +** a source language processor. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +** DEALINGS IN THE SOFTWARE. +** -LICENSE-END- +*/ + +#ifndef __LINUX_COM_H_ +#define __LINUX_COM_H_ + +struct REFIID +{ + unsigned char byte0; + unsigned char byte1; + unsigned char byte2; + unsigned char byte3; + unsigned char byte4; + unsigned char byte5; + unsigned char byte6; + unsigned char byte7; + unsigned char byte8; + unsigned char byte9; + unsigned char byte10; + unsigned char byte11; + unsigned char byte12; + unsigned char byte13; + unsigned char byte14; + unsigned char byte15; +}; + +typedef REFIID CFUUIDBytes; +#define CFUUIDGetUUIDBytes(x) x + +#define _HRESULT_DEFINED +typedef int HRESULT; +typedef unsigned long ULONG; +typedef void *LPVOID; + +#define SUCCEEDED(Status) ((HRESULT)(Status) >= 0) +#define FAILED(Status) ((HRESULT)(Status)<0) + +#define IS_ERROR(Status) ((unsigned long)(Status) >> 31 == SEVERITY_ERROR) +#define HRESULT_CODE(hr) ((hr) & 0xFFFF) +#define HRESULT_FACILITY(hr) (((hr) >> 16) & 0x1fff) +#define HRESULT_SEVERITY(hr) (((hr) >> 31) & 0x1) +#define SEVERITY_SUCCESS 0 +#define SEVERITY_ERROR 1 + +#define MAKE_HRESULT(sev,fac,code) ((HRESULT) (((unsigned long)(sev)<<31) | ((unsigned long)(fac)<<16) | ((unsigned long)(code))) ) + +#define S_OK ((HRESULT)0x00000000L) +#define S_FALSE ((HRESULT)0x00000001L) +#define E_UNEXPECTED ((HRESULT)0x8000FFFFL) +#define E_NOTIMPL ((HRESULT)0x80000001L) +#define E_OUTOFMEMORY ((HRESULT)0x80000002L) +#define E_INVALIDARG ((HRESULT)0x80000003L) +#define E_NOINTERFACE ((HRESULT)0x80000004L) +#define E_POINTER ((HRESULT)0x80000005L) +#define E_HANDLE ((HRESULT)0x80000006L) +#define E_ABORT ((HRESULT)0x80000007L) +#define E_FAIL ((HRESULT)0x80000008L) +#define E_ACCESSDENIED ((HRESULT)0x80000009L) + +#define STDMETHODCALLTYPE + +#define IID_IUnknown (REFIID){0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46} +#define IUnknownUUID IID_IUnknown + +#ifdef __cplusplus +class IUnknown +{ + public: + virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, LPVOID *ppv) = 0; + virtual ULONG STDMETHODCALLTYPE AddRef(void) = 0; + virtual ULONG STDMETHODCALLTYPE Release(void) = 0; +}; +#endif + +#endif + diff --git a/intern/decklink/win/DeckLinkAPI_h.h b/intern/decklink/win/DeckLinkAPI_h.h new file mode 100644 index 00000000000..1bd80b6dc95 --- /dev/null +++ b/intern/decklink/win/DeckLinkAPI_h.h @@ -0,0 +1,13323 @@ + + +/* this ALWAYS GENERATED file contains the definitions for the interfaces */ + + + /* File created by MIDL compiler version 8.00.0603 */ +/* at Mon Apr 13 20:57:05 2015 + */ +/* Compiler settings for ..\..\include\DeckLinkAPI.idl: + Oicf, W1, Zp8, env=Win64 (32b run), target_arch=AMD64 8.00.0603 + protocol : dce , ms_ext, c_ext, robust + error checks: allocation ref bounds_check enum stub_data + VC __declspec() decoration level: + __declspec(uuid()), __declspec(selectany), __declspec(novtable) + DECLSPEC_UUID(), MIDL_INTERFACE() +*/ +/* @@MIDL_FILE_HEADING( ) */ + +#pragma warning( disable: 4049 ) /* more than 64k source lines */ + + +/* verify that the <rpcndr.h> version is high enough to compile this file*/ +#ifndef __REQUIRED_RPCNDR_H_VERSION__ +#define __REQUIRED_RPCNDR_H_VERSION__ 475 +#endif + +#include "rpc.h" +#include "rpcndr.h" + +#ifndef __RPCNDR_H_VERSION__ +#error this stub requires an updated version of <rpcndr.h> +#endif // __RPCNDR_H_VERSION__ + + +#ifndef __DeckLinkAPI_h_h__ +#define __DeckLinkAPI_h_h__ + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +/* Forward Declarations */ + +#ifndef __IDeckLinkTimecode_FWD_DEFINED__ +#define __IDeckLinkTimecode_FWD_DEFINED__ +typedef interface IDeckLinkTimecode IDeckLinkTimecode; + +#endif /* __IDeckLinkTimecode_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkDisplayModeIterator_FWD_DEFINED__ +#define __IDeckLinkDisplayModeIterator_FWD_DEFINED__ +typedef interface IDeckLinkDisplayModeIterator IDeckLinkDisplayModeIterator; + +#endif /* __IDeckLinkDisplayModeIterator_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkDisplayMode_FWD_DEFINED__ +#define __IDeckLinkDisplayMode_FWD_DEFINED__ +typedef interface IDeckLinkDisplayMode IDeckLinkDisplayMode; + +#endif /* __IDeckLinkDisplayMode_FWD_DEFINED__ */ + + +#ifndef __IDeckLink_FWD_DEFINED__ +#define __IDeckLink_FWD_DEFINED__ +typedef interface IDeckLink IDeckLink; + +#endif /* __IDeckLink_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkConfiguration_FWD_DEFINED__ +#define __IDeckLinkConfiguration_FWD_DEFINED__ +typedef interface IDeckLinkConfiguration IDeckLinkConfiguration; + +#endif /* __IDeckLinkConfiguration_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkDeckControlStatusCallback_FWD_DEFINED__ +#define __IDeckLinkDeckControlStatusCallback_FWD_DEFINED__ +typedef interface IDeckLinkDeckControlStatusCallback IDeckLinkDeckControlStatusCallback; + +#endif /* __IDeckLinkDeckControlStatusCallback_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkDeckControl_FWD_DEFINED__ +#define __IDeckLinkDeckControl_FWD_DEFINED__ +typedef interface IDeckLinkDeckControl IDeckLinkDeckControl; + +#endif /* __IDeckLinkDeckControl_FWD_DEFINED__ */ + + +#ifndef __IBMDStreamingDeviceNotificationCallback_FWD_DEFINED__ +#define __IBMDStreamingDeviceNotificationCallback_FWD_DEFINED__ +typedef interface IBMDStreamingDeviceNotificationCallback IBMDStreamingDeviceNotificationCallback; + +#endif /* __IBMDStreamingDeviceNotificationCallback_FWD_DEFINED__ */ + + +#ifndef __IBMDStreamingH264InputCallback_FWD_DEFINED__ +#define __IBMDStreamingH264InputCallback_FWD_DEFINED__ +typedef interface IBMDStreamingH264InputCallback IBMDStreamingH264InputCallback; + +#endif /* __IBMDStreamingH264InputCallback_FWD_DEFINED__ */ + + +#ifndef __IBMDStreamingDiscovery_FWD_DEFINED__ +#define __IBMDStreamingDiscovery_FWD_DEFINED__ +typedef interface IBMDStreamingDiscovery IBMDStreamingDiscovery; + +#endif /* __IBMDStreamingDiscovery_FWD_DEFINED__ */ + + +#ifndef __IBMDStreamingVideoEncodingMode_FWD_DEFINED__ +#define __IBMDStreamingVideoEncodingMode_FWD_DEFINED__ +typedef interface IBMDStreamingVideoEncodingMode IBMDStreamingVideoEncodingMode; + +#endif /* __IBMDStreamingVideoEncodingMode_FWD_DEFINED__ */ + + +#ifndef __IBMDStreamingMutableVideoEncodingMode_FWD_DEFINED__ +#define __IBMDStreamingMutableVideoEncodingMode_FWD_DEFINED__ +typedef interface IBMDStreamingMutableVideoEncodingMode IBMDStreamingMutableVideoEncodingMode; + +#endif /* __IBMDStreamingMutableVideoEncodingMode_FWD_DEFINED__ */ + + +#ifndef __IBMDStreamingVideoEncodingModePresetIterator_FWD_DEFINED__ +#define __IBMDStreamingVideoEncodingModePresetIterator_FWD_DEFINED__ +typedef interface IBMDStreamingVideoEncodingModePresetIterator IBMDStreamingVideoEncodingModePresetIterator; + +#endif /* __IBMDStreamingVideoEncodingModePresetIterator_FWD_DEFINED__ */ + + +#ifndef __IBMDStreamingDeviceInput_FWD_DEFINED__ +#define __IBMDStreamingDeviceInput_FWD_DEFINED__ +typedef interface IBMDStreamingDeviceInput IBMDStreamingDeviceInput; + +#endif /* __IBMDStreamingDeviceInput_FWD_DEFINED__ */ + + +#ifndef __IBMDStreamingH264NALPacket_FWD_DEFINED__ +#define __IBMDStreamingH264NALPacket_FWD_DEFINED__ +typedef interface IBMDStreamingH264NALPacket IBMDStreamingH264NALPacket; + +#endif /* __IBMDStreamingH264NALPacket_FWD_DEFINED__ */ + + +#ifndef __IBMDStreamingAudioPacket_FWD_DEFINED__ +#define __IBMDStreamingAudioPacket_FWD_DEFINED__ +typedef interface IBMDStreamingAudioPacket IBMDStreamingAudioPacket; + +#endif /* __IBMDStreamingAudioPacket_FWD_DEFINED__ */ + + +#ifndef __IBMDStreamingMPEG2TSPacket_FWD_DEFINED__ +#define __IBMDStreamingMPEG2TSPacket_FWD_DEFINED__ +typedef interface IBMDStreamingMPEG2TSPacket IBMDStreamingMPEG2TSPacket; + +#endif /* __IBMDStreamingMPEG2TSPacket_FWD_DEFINED__ */ + + +#ifndef __IBMDStreamingH264NALParser_FWD_DEFINED__ +#define __IBMDStreamingH264NALParser_FWD_DEFINED__ +typedef interface IBMDStreamingH264NALParser IBMDStreamingH264NALParser; + +#endif /* __IBMDStreamingH264NALParser_FWD_DEFINED__ */ + + +#ifndef __CBMDStreamingDiscovery_FWD_DEFINED__ +#define __CBMDStreamingDiscovery_FWD_DEFINED__ + +#ifdef __cplusplus +typedef class CBMDStreamingDiscovery CBMDStreamingDiscovery; +#else +typedef struct CBMDStreamingDiscovery CBMDStreamingDiscovery; +#endif /* __cplusplus */ + +#endif /* __CBMDStreamingDiscovery_FWD_DEFINED__ */ + + +#ifndef __CBMDStreamingH264NALParser_FWD_DEFINED__ +#define __CBMDStreamingH264NALParser_FWD_DEFINED__ + +#ifdef __cplusplus +typedef class CBMDStreamingH264NALParser CBMDStreamingH264NALParser; +#else +typedef struct CBMDStreamingH264NALParser CBMDStreamingH264NALParser; +#endif /* __cplusplus */ + +#endif /* __CBMDStreamingH264NALParser_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkVideoOutputCallback_FWD_DEFINED__ +#define __IDeckLinkVideoOutputCallback_FWD_DEFINED__ +typedef interface IDeckLinkVideoOutputCallback IDeckLinkVideoOutputCallback; + +#endif /* __IDeckLinkVideoOutputCallback_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkInputCallback_FWD_DEFINED__ +#define __IDeckLinkInputCallback_FWD_DEFINED__ +typedef interface IDeckLinkInputCallback IDeckLinkInputCallback; + +#endif /* __IDeckLinkInputCallback_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkMemoryAllocator_FWD_DEFINED__ +#define __IDeckLinkMemoryAllocator_FWD_DEFINED__ +typedef interface IDeckLinkMemoryAllocator IDeckLinkMemoryAllocator; + +#endif /* __IDeckLinkMemoryAllocator_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkAudioOutputCallback_FWD_DEFINED__ +#define __IDeckLinkAudioOutputCallback_FWD_DEFINED__ +typedef interface IDeckLinkAudioOutputCallback IDeckLinkAudioOutputCallback; + +#endif /* __IDeckLinkAudioOutputCallback_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkIterator_FWD_DEFINED__ +#define __IDeckLinkIterator_FWD_DEFINED__ +typedef interface IDeckLinkIterator IDeckLinkIterator; + +#endif /* __IDeckLinkIterator_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkAPIInformation_FWD_DEFINED__ +#define __IDeckLinkAPIInformation_FWD_DEFINED__ +typedef interface IDeckLinkAPIInformation IDeckLinkAPIInformation; + +#endif /* __IDeckLinkAPIInformation_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkOutput_FWD_DEFINED__ +#define __IDeckLinkOutput_FWD_DEFINED__ +typedef interface IDeckLinkOutput IDeckLinkOutput; + +#endif /* __IDeckLinkOutput_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkInput_FWD_DEFINED__ +#define __IDeckLinkInput_FWD_DEFINED__ +typedef interface IDeckLinkInput IDeckLinkInput; + +#endif /* __IDeckLinkInput_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkVideoFrame_FWD_DEFINED__ +#define __IDeckLinkVideoFrame_FWD_DEFINED__ +typedef interface IDeckLinkVideoFrame IDeckLinkVideoFrame; + +#endif /* __IDeckLinkVideoFrame_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkMutableVideoFrame_FWD_DEFINED__ +#define __IDeckLinkMutableVideoFrame_FWD_DEFINED__ +typedef interface IDeckLinkMutableVideoFrame IDeckLinkMutableVideoFrame; + +#endif /* __IDeckLinkMutableVideoFrame_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkVideoFrame3DExtensions_FWD_DEFINED__ +#define __IDeckLinkVideoFrame3DExtensions_FWD_DEFINED__ +typedef interface IDeckLinkVideoFrame3DExtensions IDeckLinkVideoFrame3DExtensions; + +#endif /* __IDeckLinkVideoFrame3DExtensions_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkVideoInputFrame_FWD_DEFINED__ +#define __IDeckLinkVideoInputFrame_FWD_DEFINED__ +typedef interface IDeckLinkVideoInputFrame IDeckLinkVideoInputFrame; + +#endif /* __IDeckLinkVideoInputFrame_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkVideoFrameAncillary_FWD_DEFINED__ +#define __IDeckLinkVideoFrameAncillary_FWD_DEFINED__ +typedef interface IDeckLinkVideoFrameAncillary IDeckLinkVideoFrameAncillary; + +#endif /* __IDeckLinkVideoFrameAncillary_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkAudioInputPacket_FWD_DEFINED__ +#define __IDeckLinkAudioInputPacket_FWD_DEFINED__ +typedef interface IDeckLinkAudioInputPacket IDeckLinkAudioInputPacket; + +#endif /* __IDeckLinkAudioInputPacket_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkScreenPreviewCallback_FWD_DEFINED__ +#define __IDeckLinkScreenPreviewCallback_FWD_DEFINED__ +typedef interface IDeckLinkScreenPreviewCallback IDeckLinkScreenPreviewCallback; + +#endif /* __IDeckLinkScreenPreviewCallback_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkGLScreenPreviewHelper_FWD_DEFINED__ +#define __IDeckLinkGLScreenPreviewHelper_FWD_DEFINED__ +typedef interface IDeckLinkGLScreenPreviewHelper IDeckLinkGLScreenPreviewHelper; + +#endif /* __IDeckLinkGLScreenPreviewHelper_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkDX9ScreenPreviewHelper_FWD_DEFINED__ +#define __IDeckLinkDX9ScreenPreviewHelper_FWD_DEFINED__ +typedef interface IDeckLinkDX9ScreenPreviewHelper IDeckLinkDX9ScreenPreviewHelper; + +#endif /* __IDeckLinkDX9ScreenPreviewHelper_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkNotificationCallback_FWD_DEFINED__ +#define __IDeckLinkNotificationCallback_FWD_DEFINED__ +typedef interface IDeckLinkNotificationCallback IDeckLinkNotificationCallback; + +#endif /* __IDeckLinkNotificationCallback_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkNotification_FWD_DEFINED__ +#define __IDeckLinkNotification_FWD_DEFINED__ +typedef interface IDeckLinkNotification IDeckLinkNotification; + +#endif /* __IDeckLinkNotification_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkAttributes_FWD_DEFINED__ +#define __IDeckLinkAttributes_FWD_DEFINED__ +typedef interface IDeckLinkAttributes IDeckLinkAttributes; + +#endif /* __IDeckLinkAttributes_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkKeyer_FWD_DEFINED__ +#define __IDeckLinkKeyer_FWD_DEFINED__ +typedef interface IDeckLinkKeyer IDeckLinkKeyer; + +#endif /* __IDeckLinkKeyer_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkVideoConversion_FWD_DEFINED__ +#define __IDeckLinkVideoConversion_FWD_DEFINED__ +typedef interface IDeckLinkVideoConversion IDeckLinkVideoConversion; + +#endif /* __IDeckLinkVideoConversion_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkDeviceNotificationCallback_FWD_DEFINED__ +#define __IDeckLinkDeviceNotificationCallback_FWD_DEFINED__ +typedef interface IDeckLinkDeviceNotificationCallback IDeckLinkDeviceNotificationCallback; + +#endif /* __IDeckLinkDeviceNotificationCallback_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkDiscovery_FWD_DEFINED__ +#define __IDeckLinkDiscovery_FWD_DEFINED__ +typedef interface IDeckLinkDiscovery IDeckLinkDiscovery; + +#endif /* __IDeckLinkDiscovery_FWD_DEFINED__ */ + + +#ifndef __CDeckLinkIterator_FWD_DEFINED__ +#define __CDeckLinkIterator_FWD_DEFINED__ + +#ifdef __cplusplus +typedef class CDeckLinkIterator CDeckLinkIterator; +#else +typedef struct CDeckLinkIterator CDeckLinkIterator; +#endif /* __cplusplus */ + +#endif /* __CDeckLinkIterator_FWD_DEFINED__ */ + + +#ifndef __CDeckLinkAPIInformation_FWD_DEFINED__ +#define __CDeckLinkAPIInformation_FWD_DEFINED__ + +#ifdef __cplusplus +typedef class CDeckLinkAPIInformation CDeckLinkAPIInformation; +#else +typedef struct CDeckLinkAPIInformation CDeckLinkAPIInformation; +#endif /* __cplusplus */ + +#endif /* __CDeckLinkAPIInformation_FWD_DEFINED__ */ + + +#ifndef __CDeckLinkGLScreenPreviewHelper_FWD_DEFINED__ +#define __CDeckLinkGLScreenPreviewHelper_FWD_DEFINED__ + +#ifdef __cplusplus +typedef class CDeckLinkGLScreenPreviewHelper CDeckLinkGLScreenPreviewHelper; +#else +typedef struct CDeckLinkGLScreenPreviewHelper CDeckLinkGLScreenPreviewHelper; +#endif /* __cplusplus */ + +#endif /* __CDeckLinkGLScreenPreviewHelper_FWD_DEFINED__ */ + + +#ifndef __CDeckLinkDX9ScreenPreviewHelper_FWD_DEFINED__ +#define __CDeckLinkDX9ScreenPreviewHelper_FWD_DEFINED__ + +#ifdef __cplusplus +typedef class CDeckLinkDX9ScreenPreviewHelper CDeckLinkDX9ScreenPreviewHelper; +#else +typedef struct CDeckLinkDX9ScreenPreviewHelper CDeckLinkDX9ScreenPreviewHelper; +#endif /* __cplusplus */ + +#endif /* __CDeckLinkDX9ScreenPreviewHelper_FWD_DEFINED__ */ + + +#ifndef __CDeckLinkVideoConversion_FWD_DEFINED__ +#define __CDeckLinkVideoConversion_FWD_DEFINED__ + +#ifdef __cplusplus +typedef class CDeckLinkVideoConversion CDeckLinkVideoConversion; +#else +typedef struct CDeckLinkVideoConversion CDeckLinkVideoConversion; +#endif /* __cplusplus */ + +#endif /* __CDeckLinkVideoConversion_FWD_DEFINED__ */ + + +#ifndef __CDeckLinkDiscovery_FWD_DEFINED__ +#define __CDeckLinkDiscovery_FWD_DEFINED__ + +#ifdef __cplusplus +typedef class CDeckLinkDiscovery CDeckLinkDiscovery; +#else +typedef struct CDeckLinkDiscovery CDeckLinkDiscovery; +#endif /* __cplusplus */ + +#endif /* __CDeckLinkDiscovery_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkConfiguration_v10_2_FWD_DEFINED__ +#define __IDeckLinkConfiguration_v10_2_FWD_DEFINED__ +typedef interface IDeckLinkConfiguration_v10_2 IDeckLinkConfiguration_v10_2; + +#endif /* __IDeckLinkConfiguration_v10_2_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkOutput_v9_9_FWD_DEFINED__ +#define __IDeckLinkOutput_v9_9_FWD_DEFINED__ +typedef interface IDeckLinkOutput_v9_9 IDeckLinkOutput_v9_9; + +#endif /* __IDeckLinkOutput_v9_9_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkInput_v9_2_FWD_DEFINED__ +#define __IDeckLinkInput_v9_2_FWD_DEFINED__ +typedef interface IDeckLinkInput_v9_2 IDeckLinkInput_v9_2; + +#endif /* __IDeckLinkInput_v9_2_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkDeckControlStatusCallback_v8_1_FWD_DEFINED__ +#define __IDeckLinkDeckControlStatusCallback_v8_1_FWD_DEFINED__ +typedef interface IDeckLinkDeckControlStatusCallback_v8_1 IDeckLinkDeckControlStatusCallback_v8_1; + +#endif /* __IDeckLinkDeckControlStatusCallback_v8_1_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkDeckControl_v8_1_FWD_DEFINED__ +#define __IDeckLinkDeckControl_v8_1_FWD_DEFINED__ +typedef interface IDeckLinkDeckControl_v8_1 IDeckLinkDeckControl_v8_1; + +#endif /* __IDeckLinkDeckControl_v8_1_FWD_DEFINED__ */ + + +#ifndef __IDeckLink_v8_0_FWD_DEFINED__ +#define __IDeckLink_v8_0_FWD_DEFINED__ +typedef interface IDeckLink_v8_0 IDeckLink_v8_0; + +#endif /* __IDeckLink_v8_0_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkIterator_v8_0_FWD_DEFINED__ +#define __IDeckLinkIterator_v8_0_FWD_DEFINED__ +typedef interface IDeckLinkIterator_v8_0 IDeckLinkIterator_v8_0; + +#endif /* __IDeckLinkIterator_v8_0_FWD_DEFINED__ */ + + +#ifndef __CDeckLinkIterator_v8_0_FWD_DEFINED__ +#define __CDeckLinkIterator_v8_0_FWD_DEFINED__ + +#ifdef __cplusplus +typedef class CDeckLinkIterator_v8_0 CDeckLinkIterator_v8_0; +#else +typedef struct CDeckLinkIterator_v8_0 CDeckLinkIterator_v8_0; +#endif /* __cplusplus */ + +#endif /* __CDeckLinkIterator_v8_0_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkDeckControl_v7_9_FWD_DEFINED__ +#define __IDeckLinkDeckControl_v7_9_FWD_DEFINED__ +typedef interface IDeckLinkDeckControl_v7_9 IDeckLinkDeckControl_v7_9; + +#endif /* __IDeckLinkDeckControl_v7_9_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkDisplayModeIterator_v7_6_FWD_DEFINED__ +#define __IDeckLinkDisplayModeIterator_v7_6_FWD_DEFINED__ +typedef interface IDeckLinkDisplayModeIterator_v7_6 IDeckLinkDisplayModeIterator_v7_6; + +#endif /* __IDeckLinkDisplayModeIterator_v7_6_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkDisplayMode_v7_6_FWD_DEFINED__ +#define __IDeckLinkDisplayMode_v7_6_FWD_DEFINED__ +typedef interface IDeckLinkDisplayMode_v7_6 IDeckLinkDisplayMode_v7_6; + +#endif /* __IDeckLinkDisplayMode_v7_6_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkOutput_v7_6_FWD_DEFINED__ +#define __IDeckLinkOutput_v7_6_FWD_DEFINED__ +typedef interface IDeckLinkOutput_v7_6 IDeckLinkOutput_v7_6; + +#endif /* __IDeckLinkOutput_v7_6_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkInput_v7_6_FWD_DEFINED__ +#define __IDeckLinkInput_v7_6_FWD_DEFINED__ +typedef interface IDeckLinkInput_v7_6 IDeckLinkInput_v7_6; + +#endif /* __IDeckLinkInput_v7_6_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkTimecode_v7_6_FWD_DEFINED__ +#define __IDeckLinkTimecode_v7_6_FWD_DEFINED__ +typedef interface IDeckLinkTimecode_v7_6 IDeckLinkTimecode_v7_6; + +#endif /* __IDeckLinkTimecode_v7_6_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkVideoFrame_v7_6_FWD_DEFINED__ +#define __IDeckLinkVideoFrame_v7_6_FWD_DEFINED__ +typedef interface IDeckLinkVideoFrame_v7_6 IDeckLinkVideoFrame_v7_6; + +#endif /* __IDeckLinkVideoFrame_v7_6_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkMutableVideoFrame_v7_6_FWD_DEFINED__ +#define __IDeckLinkMutableVideoFrame_v7_6_FWD_DEFINED__ +typedef interface IDeckLinkMutableVideoFrame_v7_6 IDeckLinkMutableVideoFrame_v7_6; + +#endif /* __IDeckLinkMutableVideoFrame_v7_6_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkVideoInputFrame_v7_6_FWD_DEFINED__ +#define __IDeckLinkVideoInputFrame_v7_6_FWD_DEFINED__ +typedef interface IDeckLinkVideoInputFrame_v7_6 IDeckLinkVideoInputFrame_v7_6; + +#endif /* __IDeckLinkVideoInputFrame_v7_6_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkScreenPreviewCallback_v7_6_FWD_DEFINED__ +#define __IDeckLinkScreenPreviewCallback_v7_6_FWD_DEFINED__ +typedef interface IDeckLinkScreenPreviewCallback_v7_6 IDeckLinkScreenPreviewCallback_v7_6; + +#endif /* __IDeckLinkScreenPreviewCallback_v7_6_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkGLScreenPreviewHelper_v7_6_FWD_DEFINED__ +#define __IDeckLinkGLScreenPreviewHelper_v7_6_FWD_DEFINED__ +typedef interface IDeckLinkGLScreenPreviewHelper_v7_6 IDeckLinkGLScreenPreviewHelper_v7_6; + +#endif /* __IDeckLinkGLScreenPreviewHelper_v7_6_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkVideoConversion_v7_6_FWD_DEFINED__ +#define __IDeckLinkVideoConversion_v7_6_FWD_DEFINED__ +typedef interface IDeckLinkVideoConversion_v7_6 IDeckLinkVideoConversion_v7_6; + +#endif /* __IDeckLinkVideoConversion_v7_6_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkConfiguration_v7_6_FWD_DEFINED__ +#define __IDeckLinkConfiguration_v7_6_FWD_DEFINED__ +typedef interface IDeckLinkConfiguration_v7_6 IDeckLinkConfiguration_v7_6; + +#endif /* __IDeckLinkConfiguration_v7_6_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkVideoOutputCallback_v7_6_FWD_DEFINED__ +#define __IDeckLinkVideoOutputCallback_v7_6_FWD_DEFINED__ +typedef interface IDeckLinkVideoOutputCallback_v7_6 IDeckLinkVideoOutputCallback_v7_6; + +#endif /* __IDeckLinkVideoOutputCallback_v7_6_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkInputCallback_v7_6_FWD_DEFINED__ +#define __IDeckLinkInputCallback_v7_6_FWD_DEFINED__ +typedef interface IDeckLinkInputCallback_v7_6 IDeckLinkInputCallback_v7_6; + +#endif /* __IDeckLinkInputCallback_v7_6_FWD_DEFINED__ */ + + +#ifndef __CDeckLinkGLScreenPreviewHelper_v7_6_FWD_DEFINED__ +#define __CDeckLinkGLScreenPreviewHelper_v7_6_FWD_DEFINED__ + +#ifdef __cplusplus +typedef class CDeckLinkGLScreenPreviewHelper_v7_6 CDeckLinkGLScreenPreviewHelper_v7_6; +#else +typedef struct CDeckLinkGLScreenPreviewHelper_v7_6 CDeckLinkGLScreenPreviewHelper_v7_6; +#endif /* __cplusplus */ + +#endif /* __CDeckLinkGLScreenPreviewHelper_v7_6_FWD_DEFINED__ */ + + +#ifndef __CDeckLinkVideoConversion_v7_6_FWD_DEFINED__ +#define __CDeckLinkVideoConversion_v7_6_FWD_DEFINED__ + +#ifdef __cplusplus +typedef class CDeckLinkVideoConversion_v7_6 CDeckLinkVideoConversion_v7_6; +#else +typedef struct CDeckLinkVideoConversion_v7_6 CDeckLinkVideoConversion_v7_6; +#endif /* __cplusplus */ + +#endif /* __CDeckLinkVideoConversion_v7_6_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkInputCallback_v7_3_FWD_DEFINED__ +#define __IDeckLinkInputCallback_v7_3_FWD_DEFINED__ +typedef interface IDeckLinkInputCallback_v7_3 IDeckLinkInputCallback_v7_3; + +#endif /* __IDeckLinkInputCallback_v7_3_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkOutput_v7_3_FWD_DEFINED__ +#define __IDeckLinkOutput_v7_3_FWD_DEFINED__ +typedef interface IDeckLinkOutput_v7_3 IDeckLinkOutput_v7_3; + +#endif /* __IDeckLinkOutput_v7_3_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkInput_v7_3_FWD_DEFINED__ +#define __IDeckLinkInput_v7_3_FWD_DEFINED__ +typedef interface IDeckLinkInput_v7_3 IDeckLinkInput_v7_3; + +#endif /* __IDeckLinkInput_v7_3_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkVideoInputFrame_v7_3_FWD_DEFINED__ +#define __IDeckLinkVideoInputFrame_v7_3_FWD_DEFINED__ +typedef interface IDeckLinkVideoInputFrame_v7_3 IDeckLinkVideoInputFrame_v7_3; + +#endif /* __IDeckLinkVideoInputFrame_v7_3_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkDisplayModeIterator_v7_1_FWD_DEFINED__ +#define __IDeckLinkDisplayModeIterator_v7_1_FWD_DEFINED__ +typedef interface IDeckLinkDisplayModeIterator_v7_1 IDeckLinkDisplayModeIterator_v7_1; + +#endif /* __IDeckLinkDisplayModeIterator_v7_1_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkDisplayMode_v7_1_FWD_DEFINED__ +#define __IDeckLinkDisplayMode_v7_1_FWD_DEFINED__ +typedef interface IDeckLinkDisplayMode_v7_1 IDeckLinkDisplayMode_v7_1; + +#endif /* __IDeckLinkDisplayMode_v7_1_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkVideoFrame_v7_1_FWD_DEFINED__ +#define __IDeckLinkVideoFrame_v7_1_FWD_DEFINED__ +typedef interface IDeckLinkVideoFrame_v7_1 IDeckLinkVideoFrame_v7_1; + +#endif /* __IDeckLinkVideoFrame_v7_1_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkVideoInputFrame_v7_1_FWD_DEFINED__ +#define __IDeckLinkVideoInputFrame_v7_1_FWD_DEFINED__ +typedef interface IDeckLinkVideoInputFrame_v7_1 IDeckLinkVideoInputFrame_v7_1; + +#endif /* __IDeckLinkVideoInputFrame_v7_1_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkAudioInputPacket_v7_1_FWD_DEFINED__ +#define __IDeckLinkAudioInputPacket_v7_1_FWD_DEFINED__ +typedef interface IDeckLinkAudioInputPacket_v7_1 IDeckLinkAudioInputPacket_v7_1; + +#endif /* __IDeckLinkAudioInputPacket_v7_1_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkVideoOutputCallback_v7_1_FWD_DEFINED__ +#define __IDeckLinkVideoOutputCallback_v7_1_FWD_DEFINED__ +typedef interface IDeckLinkVideoOutputCallback_v7_1 IDeckLinkVideoOutputCallback_v7_1; + +#endif /* __IDeckLinkVideoOutputCallback_v7_1_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkInputCallback_v7_1_FWD_DEFINED__ +#define __IDeckLinkInputCallback_v7_1_FWD_DEFINED__ +typedef interface IDeckLinkInputCallback_v7_1 IDeckLinkInputCallback_v7_1; + +#endif /* __IDeckLinkInputCallback_v7_1_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkOutput_v7_1_FWD_DEFINED__ +#define __IDeckLinkOutput_v7_1_FWD_DEFINED__ +typedef interface IDeckLinkOutput_v7_1 IDeckLinkOutput_v7_1; + +#endif /* __IDeckLinkOutput_v7_1_FWD_DEFINED__ */ + + +#ifndef __IDeckLinkInput_v7_1_FWD_DEFINED__ +#define __IDeckLinkInput_v7_1_FWD_DEFINED__ +typedef interface IDeckLinkInput_v7_1 IDeckLinkInput_v7_1; + +#endif /* __IDeckLinkInput_v7_1_FWD_DEFINED__ */ + + +/* header files for imported files */ +#include "unknwn.h" + +#ifdef __cplusplus +extern "C"{ +#endif + + + +#ifndef __DeckLinkAPI_LIBRARY_DEFINED__ +#define __DeckLinkAPI_LIBRARY_DEFINED__ + +/* library DeckLinkAPI */ +/* [helpstring][version][uuid] */ + +typedef LONGLONG BMDTimeValue; + +typedef LONGLONG BMDTimeScale; + +typedef unsigned int BMDTimecodeBCD; + +typedef unsigned int BMDTimecodeUserBits; + +typedef unsigned int BMDTimecodeFlags; +#if 0 +typedef enum _BMDTimecodeFlags BMDTimecodeFlags; + +#endif +/* [v1_enum] */ +enum _BMDTimecodeFlags + { + bmdTimecodeFlagDefault = 0, + bmdTimecodeIsDropFrame = ( 1 << 0 ) , + bmdTimecodeFieldMark = ( 1 << 1 ) + } ; +typedef /* [v1_enum] */ +enum _BMDVideoConnection + { + bmdVideoConnectionSDI = ( 1 << 0 ) , + bmdVideoConnectionHDMI = ( 1 << 1 ) , + bmdVideoConnectionOpticalSDI = ( 1 << 2 ) , + bmdVideoConnectionComponent = ( 1 << 3 ) , + bmdVideoConnectionComposite = ( 1 << 4 ) , + bmdVideoConnectionSVideo = ( 1 << 5 ) + } BMDVideoConnection; + +typedef /* [v1_enum] */ +enum _BMDAudioConnection + { + bmdAudioConnectionEmbedded = ( 1 << 0 ) , + bmdAudioConnectionAESEBU = ( 1 << 1 ) , + bmdAudioConnectionAnalog = ( 1 << 2 ) , + bmdAudioConnectionAnalogXLR = ( 1 << 3 ) , + bmdAudioConnectionAnalogRCA = ( 1 << 4 ) + } BMDAudioConnection; + + +typedef unsigned int BMDDisplayModeFlags; +#if 0 +typedef enum _BMDDisplayModeFlags BMDDisplayModeFlags; + +#endif +typedef /* [v1_enum] */ +enum _BMDDisplayMode + { + bmdModeNTSC = 0x6e747363, + bmdModeNTSC2398 = 0x6e743233, + bmdModePAL = 0x70616c20, + bmdModeNTSCp = 0x6e747370, + bmdModePALp = 0x70616c70, + bmdModeHD1080p2398 = 0x32337073, + bmdModeHD1080p24 = 0x32347073, + bmdModeHD1080p25 = 0x48703235, + bmdModeHD1080p2997 = 0x48703239, + bmdModeHD1080p30 = 0x48703330, + bmdModeHD1080i50 = 0x48693530, + bmdModeHD1080i5994 = 0x48693539, + bmdModeHD1080i6000 = 0x48693630, + bmdModeHD1080p50 = 0x48703530, + bmdModeHD1080p5994 = 0x48703539, + bmdModeHD1080p6000 = 0x48703630, + bmdModeHD720p50 = 0x68703530, + bmdModeHD720p5994 = 0x68703539, + bmdModeHD720p60 = 0x68703630, + bmdMode2k2398 = 0x326b3233, + bmdMode2k24 = 0x326b3234, + bmdMode2k25 = 0x326b3235, + bmdMode2kDCI2398 = 0x32643233, + bmdMode2kDCI24 = 0x32643234, + bmdMode2kDCI25 = 0x32643235, + bmdMode4K2160p2398 = 0x346b3233, + bmdMode4K2160p24 = 0x346b3234, + bmdMode4K2160p25 = 0x346b3235, + bmdMode4K2160p2997 = 0x346b3239, + bmdMode4K2160p30 = 0x346b3330, + bmdMode4K2160p50 = 0x346b3530, + bmdMode4K2160p5994 = 0x346b3539, + bmdMode4K2160p60 = 0x346b3630, + bmdMode4kDCI2398 = 0x34643233, + bmdMode4kDCI24 = 0x34643234, + bmdMode4kDCI25 = 0x34643235, + bmdModeUnknown = 0x69756e6b + } BMDDisplayMode; + +typedef /* [v1_enum] */ +enum _BMDFieldDominance + { + bmdUnknownFieldDominance = 0, + bmdLowerFieldFirst = 0x6c6f7772, + bmdUpperFieldFirst = 0x75707072, + bmdProgressiveFrame = 0x70726f67, + bmdProgressiveSegmentedFrame = 0x70736620 + } BMDFieldDominance; + +typedef /* [v1_enum] */ +enum _BMDPixelFormat + { + bmdFormat8BitYUV = 0x32767579, + bmdFormat10BitYUV = 0x76323130, + bmdFormat8BitARGB = 32, + bmdFormat8BitBGRA = 0x42475241, + bmdFormat10BitRGB = 0x72323130, + bmdFormat12BitRGB = 0x52313242, + bmdFormat12BitRGBLE = 0x5231324c, + bmdFormat10BitRGBXLE = 0x5231306c, + bmdFormat10BitRGBX = 0x52313062 + } BMDPixelFormat; + +/* [v1_enum] */ +enum _BMDDisplayModeFlags + { + bmdDisplayModeSupports3D = ( 1 << 0 ) , + bmdDisplayModeColorspaceRec601 = ( 1 << 1 ) , + bmdDisplayModeColorspaceRec709 = ( 1 << 2 ) + } ; + + +#if 0 +#endif + +#if 0 +#endif +typedef /* [v1_enum] */ +enum _BMDDeckLinkConfigurationID + { + bmdDeckLinkConfigSwapSerialRxTx = 0x73737274, + bmdDeckLinkConfigUse1080pNotPsF = 0x6670726f, + bmdDeckLinkConfigHDMI3DPackingFormat = 0x33647066, + bmdDeckLinkConfigBypass = 0x62797073, + bmdDeckLinkConfigClockTimingAdjustment = 0x63746164, + bmdDeckLinkConfigAnalogAudioConsumerLevels = 0x6161636c, + bmdDeckLinkConfigFieldFlickerRemoval = 0x66646672, + bmdDeckLinkConfigHD1080p24ToHD1080i5994Conversion = 0x746f3539, + bmdDeckLinkConfig444SDIVideoOutput = 0x3434346f, + bmdDeckLinkConfigSingleLinkVideoOutput = 0x73676c6f, + bmdDeckLinkConfigBlackVideoOutputDuringCapture = 0x62766f63, + bmdDeckLinkConfigLowLatencyVideoOutput = 0x6c6c766f, + bmdDeckLinkConfigDownConversionOnAllAnalogOutput = 0x6361616f, + bmdDeckLinkConfigSMPTELevelAOutput = 0x736d7461, + bmdDeckLinkConfigVideoOutputConnection = 0x766f636e, + bmdDeckLinkConfigVideoOutputConversionMode = 0x766f636d, + bmdDeckLinkConfigAnalogVideoOutputFlags = 0x61766f66, + bmdDeckLinkConfigReferenceInputTimingOffset = 0x676c6f74, + bmdDeckLinkConfigVideoOutputIdleOperation = 0x766f696f, + bmdDeckLinkConfigDefaultVideoOutputMode = 0x64766f6d, + bmdDeckLinkConfigDefaultVideoOutputModeFlags = 0x64766f66, + bmdDeckLinkConfigVideoOutputComponentLumaGain = 0x6f636c67, + bmdDeckLinkConfigVideoOutputComponentChromaBlueGain = 0x6f636362, + bmdDeckLinkConfigVideoOutputComponentChromaRedGain = 0x6f636372, + bmdDeckLinkConfigVideoOutputCompositeLumaGain = 0x6f696c67, + bmdDeckLinkConfigVideoOutputCompositeChromaGain = 0x6f696367, + bmdDeckLinkConfigVideoOutputSVideoLumaGain = 0x6f736c67, + bmdDeckLinkConfigVideoOutputSVideoChromaGain = 0x6f736367, + bmdDeckLinkConfigVideoInputScanning = 0x76697363, + bmdDeckLinkConfigUseDedicatedLTCInput = 0x646c7463, + bmdDeckLinkConfigVideoInputConnection = 0x7669636e, + bmdDeckLinkConfigAnalogVideoInputFlags = 0x61766966, + bmdDeckLinkConfigVideoInputConversionMode = 0x7669636d, + bmdDeckLinkConfig32PulldownSequenceInitialTimecodeFrame = 0x70646966, + bmdDeckLinkConfigVANCSourceLine1Mapping = 0x76736c31, + bmdDeckLinkConfigVANCSourceLine2Mapping = 0x76736c32, + bmdDeckLinkConfigVANCSourceLine3Mapping = 0x76736c33, + bmdDeckLinkConfigCapturePassThroughMode = 0x6370746d, + bmdDeckLinkConfigVideoInputComponentLumaGain = 0x69636c67, + bmdDeckLinkConfigVideoInputComponentChromaBlueGain = 0x69636362, + bmdDeckLinkConfigVideoInputComponentChromaRedGain = 0x69636372, + bmdDeckLinkConfigVideoInputCompositeLumaGain = 0x69696c67, + bmdDeckLinkConfigVideoInputCompositeChromaGain = 0x69696367, + bmdDeckLinkConfigVideoInputSVideoLumaGain = 0x69736c67, + bmdDeckLinkConfigVideoInputSVideoChromaGain = 0x69736367, + bmdDeckLinkConfigAudioInputConnection = 0x6169636e, + bmdDeckLinkConfigAnalogAudioInputScaleChannel1 = 0x61697331, + bmdDeckLinkConfigAnalogAudioInputScaleChannel2 = 0x61697332, + bmdDeckLinkConfigAnalogAudioInputScaleChannel3 = 0x61697333, + bmdDeckLinkConfigAnalogAudioInputScaleChannel4 = 0x61697334, + bmdDeckLinkConfigDigitalAudioInputScale = 0x64616973, + bmdDeckLinkConfigAudioOutputAESAnalogSwitch = 0x616f6161, + bmdDeckLinkConfigAnalogAudioOutputScaleChannel1 = 0x616f7331, + bmdDeckLinkConfigAnalogAudioOutputScaleChannel2 = 0x616f7332, + bmdDeckLinkConfigAnalogAudioOutputScaleChannel3 = 0x616f7333, + bmdDeckLinkConfigAnalogAudioOutputScaleChannel4 = 0x616f7334, + bmdDeckLinkConfigDigitalAudioOutputScale = 0x64616f73, + bmdDeckLinkConfigDeviceInformationLabel = 0x64696c61, + bmdDeckLinkConfigDeviceInformationSerialNumber = 0x6469736e, + bmdDeckLinkConfigDeviceInformationCompany = 0x6469636f, + bmdDeckLinkConfigDeviceInformationPhone = 0x64697068, + bmdDeckLinkConfigDeviceInformationEmail = 0x6469656d, + bmdDeckLinkConfigDeviceInformationDate = 0x64696461 + } BMDDeckLinkConfigurationID; + + +typedef unsigned int BMDDeckControlStatusFlags; +typedef unsigned int BMDDeckControlExportModeOpsFlags; +#if 0 +typedef enum _BMDDeckControlStatusFlags BMDDeckControlStatusFlags; + +typedef enum _BMDDeckControlExportModeOpsFlags BMDDeckControlExportModeOpsFlags; + +#endif +typedef /* [v1_enum] */ +enum _BMDDeckControlMode + { + bmdDeckControlNotOpened = 0x6e746f70, + bmdDeckControlVTRControlMode = 0x76747263, + bmdDeckControlExportMode = 0x6578706d, + bmdDeckControlCaptureMode = 0x6361706d + } BMDDeckControlMode; + +typedef /* [v1_enum] */ +enum _BMDDeckControlEvent + { + bmdDeckControlAbortedEvent = 0x61627465, + bmdDeckControlPrepareForExportEvent = 0x70666565, + bmdDeckControlExportCompleteEvent = 0x65786365, + bmdDeckControlPrepareForCaptureEvent = 0x70666365, + bmdDeckControlCaptureCompleteEvent = 0x63636576 + } BMDDeckControlEvent; + +typedef /* [v1_enum] */ +enum _BMDDeckControlVTRControlState + { + bmdDeckControlNotInVTRControlMode = 0x6e76636d, + bmdDeckControlVTRControlPlaying = 0x76747270, + bmdDeckControlVTRControlRecording = 0x76747272, + bmdDeckControlVTRControlStill = 0x76747261, + bmdDeckControlVTRControlShuttleForward = 0x76747366, + bmdDeckControlVTRControlShuttleReverse = 0x76747372, + bmdDeckControlVTRControlJogForward = 0x76746a66, + bmdDeckControlVTRControlJogReverse = 0x76746a72, + bmdDeckControlVTRControlStopped = 0x7674726f + } BMDDeckControlVTRControlState; + +/* [v1_enum] */ +enum _BMDDeckControlStatusFlags + { + bmdDeckControlStatusDeckConnected = ( 1 << 0 ) , + bmdDeckControlStatusRemoteMode = ( 1 << 1 ) , + bmdDeckControlStatusRecordInhibited = ( 1 << 2 ) , + bmdDeckControlStatusCassetteOut = ( 1 << 3 ) + } ; +/* [v1_enum] */ +enum _BMDDeckControlExportModeOpsFlags + { + bmdDeckControlExportModeInsertVideo = ( 1 << 0 ) , + bmdDeckControlExportModeInsertAudio1 = ( 1 << 1 ) , + bmdDeckControlExportModeInsertAudio2 = ( 1 << 2 ) , + bmdDeckControlExportModeInsertAudio3 = ( 1 << 3 ) , + bmdDeckControlExportModeInsertAudio4 = ( 1 << 4 ) , + bmdDeckControlExportModeInsertAudio5 = ( 1 << 5 ) , + bmdDeckControlExportModeInsertAudio6 = ( 1 << 6 ) , + bmdDeckControlExportModeInsertAudio7 = ( 1 << 7 ) , + bmdDeckControlExportModeInsertAudio8 = ( 1 << 8 ) , + bmdDeckControlExportModeInsertAudio9 = ( 1 << 9 ) , + bmdDeckControlExportModeInsertAudio10 = ( 1 << 10 ) , + bmdDeckControlExportModeInsertAudio11 = ( 1 << 11 ) , + bmdDeckControlExportModeInsertAudio12 = ( 1 << 12 ) , + bmdDeckControlExportModeInsertTimeCode = ( 1 << 13 ) , + bmdDeckControlExportModeInsertAssemble = ( 1 << 14 ) , + bmdDeckControlExportModeInsertPreview = ( 1 << 15 ) , + bmdDeckControlUseManualExport = ( 1 << 16 ) + } ; +typedef /* [v1_enum] */ +enum _BMDDeckControlError + { + bmdDeckControlNoError = 0x6e6f6572, + bmdDeckControlModeError = 0x6d6f6572, + bmdDeckControlMissedInPointError = 0x6d696572, + bmdDeckControlDeckTimeoutError = 0x64746572, + bmdDeckControlCommandFailedError = 0x63666572, + bmdDeckControlDeviceAlreadyOpenedError = 0x64616c6f, + bmdDeckControlFailedToOpenDeviceError = 0x66646572, + bmdDeckControlInLocalModeError = 0x6c6d6572, + bmdDeckControlEndOfTapeError = 0x65746572, + bmdDeckControlUserAbortError = 0x75616572, + bmdDeckControlNoTapeInDeckError = 0x6e746572, + bmdDeckControlNoVideoFromCardError = 0x6e766663, + bmdDeckControlNoCommunicationError = 0x6e636f6d, + bmdDeckControlBufferTooSmallError = 0x6274736d, + bmdDeckControlBadChecksumError = 0x63686b73, + bmdDeckControlUnknownError = 0x756e6572 + } BMDDeckControlError; + + + +#if 0 +#endif +typedef /* [v1_enum] */ +enum _BMDStreamingDeviceMode + { + bmdStreamingDeviceIdle = 0x69646c65, + bmdStreamingDeviceEncoding = 0x656e636f, + bmdStreamingDeviceStopping = 0x73746f70, + bmdStreamingDeviceUnknown = 0x6d756e6b + } BMDStreamingDeviceMode; + +typedef /* [v1_enum] */ +enum _BMDStreamingEncodingFrameRate + { + bmdStreamingEncodedFrameRate50i = 0x65353069, + bmdStreamingEncodedFrameRate5994i = 0x65353969, + bmdStreamingEncodedFrameRate60i = 0x65363069, + bmdStreamingEncodedFrameRate2398p = 0x65323370, + bmdStreamingEncodedFrameRate24p = 0x65323470, + bmdStreamingEncodedFrameRate25p = 0x65323570, + bmdStreamingEncodedFrameRate2997p = 0x65323970, + bmdStreamingEncodedFrameRate30p = 0x65333070, + bmdStreamingEncodedFrameRate50p = 0x65353070, + bmdStreamingEncodedFrameRate5994p = 0x65353970, + bmdStreamingEncodedFrameRate60p = 0x65363070 + } BMDStreamingEncodingFrameRate; + +typedef /* [v1_enum] */ +enum _BMDStreamingEncodingSupport + { + bmdStreamingEncodingModeNotSupported = 0, + bmdStreamingEncodingModeSupported = ( bmdStreamingEncodingModeNotSupported + 1 ) , + bmdStreamingEncodingModeSupportedWithChanges = ( bmdStreamingEncodingModeSupported + 1 ) + } BMDStreamingEncodingSupport; + +typedef /* [v1_enum] */ +enum _BMDStreamingVideoCodec + { + bmdStreamingVideoCodecH264 = 0x48323634 + } BMDStreamingVideoCodec; + +typedef /* [v1_enum] */ +enum _BMDStreamingH264Profile + { + bmdStreamingH264ProfileHigh = 0x68696768, + bmdStreamingH264ProfileMain = 0x6d61696e, + bmdStreamingH264ProfileBaseline = 0x62617365 + } BMDStreamingH264Profile; + +typedef /* [v1_enum] */ +enum _BMDStreamingH264Level + { + bmdStreamingH264Level12 = 0x6c763132, + bmdStreamingH264Level13 = 0x6c763133, + bmdStreamingH264Level2 = 0x6c763220, + bmdStreamingH264Level21 = 0x6c763231, + bmdStreamingH264Level22 = 0x6c763232, + bmdStreamingH264Level3 = 0x6c763320, + bmdStreamingH264Level31 = 0x6c763331, + bmdStreamingH264Level32 = 0x6c763332, + bmdStreamingH264Level4 = 0x6c763420, + bmdStreamingH264Level41 = 0x6c763431, + bmdStreamingH264Level42 = 0x6c763432 + } BMDStreamingH264Level; + +typedef /* [v1_enum] */ +enum _BMDStreamingH264EntropyCoding + { + bmdStreamingH264EntropyCodingCAVLC = 0x45564c43, + bmdStreamingH264EntropyCodingCABAC = 0x45424143 + } BMDStreamingH264EntropyCoding; + +typedef /* [v1_enum] */ +enum _BMDStreamingAudioCodec + { + bmdStreamingAudioCodecAAC = 0x41414320 + } BMDStreamingAudioCodec; + +typedef /* [v1_enum] */ +enum _BMDStreamingEncodingModePropertyID + { + bmdStreamingEncodingPropertyVideoFrameRate = 0x76667274, + bmdStreamingEncodingPropertyVideoBitRateKbps = 0x76627274, + bmdStreamingEncodingPropertyH264Profile = 0x68707266, + bmdStreamingEncodingPropertyH264Level = 0x686c766c, + bmdStreamingEncodingPropertyH264EntropyCoding = 0x68656e74, + bmdStreamingEncodingPropertyH264HasBFrames = 0x68426672, + bmdStreamingEncodingPropertyAudioCodec = 0x61636463, + bmdStreamingEncodingPropertyAudioSampleRate = 0x61737274, + bmdStreamingEncodingPropertyAudioChannelCount = 0x61636863, + bmdStreamingEncodingPropertyAudioBitRateKbps = 0x61627274 + } BMDStreamingEncodingModePropertyID; + + + + + + + + + + + + +typedef unsigned int BMDFrameFlags; +typedef unsigned int BMDVideoInputFlags; +typedef unsigned int BMDVideoInputFormatChangedEvents; +typedef unsigned int BMDDetectedVideoInputFormatFlags; +typedef unsigned int BMDDeckLinkCapturePassthroughMode; +typedef unsigned int BMDAnalogVideoFlags; +typedef unsigned int BMDDeviceBusyState; +#if 0 +typedef enum _BMDFrameFlags BMDFrameFlags; + +typedef enum _BMDVideoInputFlags BMDVideoInputFlags; + +typedef enum _BMDVideoInputFormatChangedEvents BMDVideoInputFormatChangedEvents; + +typedef enum _BMDDetectedVideoInputFormatFlags BMDDetectedVideoInputFormatFlags; + +typedef enum _BMDDeckLinkCapturePassthroughMode BMDDeckLinkCapturePassthroughMode; + +typedef enum _BMDAnalogVideoFlags BMDAnalogVideoFlags; + +typedef enum _BMDDeviceBusyState BMDDeviceBusyState; + +#endif +typedef /* [v1_enum] */ +enum _BMDVideoOutputFlags + { + bmdVideoOutputFlagDefault = 0, + bmdVideoOutputVANC = ( 1 << 0 ) , + bmdVideoOutputVITC = ( 1 << 1 ) , + bmdVideoOutputRP188 = ( 1 << 2 ) , + bmdVideoOutputDualStream3D = ( 1 << 4 ) + } BMDVideoOutputFlags; + +/* [v1_enum] */ +enum _BMDFrameFlags + { + bmdFrameFlagDefault = 0, + bmdFrameFlagFlipVertical = ( 1 << 0 ) , + bmdFrameHasNoInputSource = ( 1 << 31 ) + } ; +/* [v1_enum] */ +enum _BMDVideoInputFlags + { + bmdVideoInputFlagDefault = 0, + bmdVideoInputEnableFormatDetection = ( 1 << 0 ) , + bmdVideoInputDualStream3D = ( 1 << 1 ) + } ; +/* [v1_enum] */ +enum _BMDVideoInputFormatChangedEvents + { + bmdVideoInputDisplayModeChanged = ( 1 << 0 ) , + bmdVideoInputFieldDominanceChanged = ( 1 << 1 ) , + bmdVideoInputColorspaceChanged = ( 1 << 2 ) + } ; +/* [v1_enum] */ +enum _BMDDetectedVideoInputFormatFlags + { + bmdDetectedVideoInputYCbCr422 = ( 1 << 0 ) , + bmdDetectedVideoInputRGB444 = ( 1 << 1 ) , + bmdDetectedVideoInputDualStream3D = ( 1 << 2 ) + } ; +/* [v1_enum] */ +enum _BMDDeckLinkCapturePassthroughMode + { + bmdDeckLinkCapturePassthroughModeDirect = 0x70646972, + bmdDeckLinkCapturePassthroughModeCleanSwitch = 0x70636c6e + } ; +typedef /* [v1_enum] */ +enum _BMDOutputFrameCompletionResult + { + bmdOutputFrameCompleted = 0, + bmdOutputFrameDisplayedLate = ( bmdOutputFrameCompleted + 1 ) , + bmdOutputFrameDropped = ( bmdOutputFrameDisplayedLate + 1 ) , + bmdOutputFrameFlushed = ( bmdOutputFrameDropped + 1 ) + } BMDOutputFrameCompletionResult; + +typedef /* [v1_enum] */ +enum _BMDReferenceStatus + { + bmdReferenceNotSupportedByHardware = ( 1 << 0 ) , + bmdReferenceLocked = ( 1 << 1 ) + } BMDReferenceStatus; + +typedef /* [v1_enum] */ +enum _BMDAudioSampleRate + { + bmdAudioSampleRate48kHz = 48000 + } BMDAudioSampleRate; + +typedef /* [v1_enum] */ +enum _BMDAudioSampleType + { + bmdAudioSampleType16bitInteger = 16, + bmdAudioSampleType32bitInteger = 32 + } BMDAudioSampleType; + +typedef /* [v1_enum] */ +enum _BMDAudioOutputStreamType + { + bmdAudioOutputStreamContinuous = 0, + bmdAudioOutputStreamContinuousDontResample = ( bmdAudioOutputStreamContinuous + 1 ) , + bmdAudioOutputStreamTimestamped = ( bmdAudioOutputStreamContinuousDontResample + 1 ) + } BMDAudioOutputStreamType; + +typedef /* [v1_enum] */ +enum _BMDDisplayModeSupport + { + bmdDisplayModeNotSupported = 0, + bmdDisplayModeSupported = ( bmdDisplayModeNotSupported + 1 ) , + bmdDisplayModeSupportedWithConversion = ( bmdDisplayModeSupported + 1 ) + } BMDDisplayModeSupport; + +typedef /* [v1_enum] */ +enum _BMDTimecodeFormat + { + bmdTimecodeRP188VITC1 = 0x72707631, + bmdTimecodeRP188VITC2 = 0x72703132, + bmdTimecodeRP188LTC = 0x72706c74, + bmdTimecodeRP188Any = 0x72703138, + bmdTimecodeVITC = 0x76697463, + bmdTimecodeVITCField2 = 0x76697432, + bmdTimecodeSerial = 0x73657269 + } BMDTimecodeFormat; + +/* [v1_enum] */ +enum _BMDAnalogVideoFlags + { + bmdAnalogVideoFlagCompositeSetup75 = ( 1 << 0 ) , + bmdAnalogVideoFlagComponentBetacamLevels = ( 1 << 1 ) + } ; +typedef /* [v1_enum] */ +enum _BMDAudioOutputAnalogAESSwitch + { + bmdAudioOutputSwitchAESEBU = 0x61657320, + bmdAudioOutputSwitchAnalog = 0x616e6c67 + } BMDAudioOutputAnalogAESSwitch; + +typedef /* [v1_enum] */ +enum _BMDVideoOutputConversionMode + { + bmdNoVideoOutputConversion = 0x6e6f6e65, + bmdVideoOutputLetterboxDownconversion = 0x6c746278, + bmdVideoOutputAnamorphicDownconversion = 0x616d7068, + bmdVideoOutputHD720toHD1080Conversion = 0x37323063, + bmdVideoOutputHardwareLetterboxDownconversion = 0x48576c62, + bmdVideoOutputHardwareAnamorphicDownconversion = 0x4857616d, + bmdVideoOutputHardwareCenterCutDownconversion = 0x48576363, + bmdVideoOutputHardware720p1080pCrossconversion = 0x78636170, + bmdVideoOutputHardwareAnamorphic720pUpconversion = 0x75613770, + bmdVideoOutputHardwareAnamorphic1080iUpconversion = 0x75613169, + bmdVideoOutputHardwareAnamorphic149To720pUpconversion = 0x75343770, + bmdVideoOutputHardwareAnamorphic149To1080iUpconversion = 0x75343169, + bmdVideoOutputHardwarePillarbox720pUpconversion = 0x75703770, + bmdVideoOutputHardwarePillarbox1080iUpconversion = 0x75703169 + } BMDVideoOutputConversionMode; + +typedef /* [v1_enum] */ +enum _BMDVideoInputConversionMode + { + bmdNoVideoInputConversion = 0x6e6f6e65, + bmdVideoInputLetterboxDownconversionFromHD1080 = 0x31306c62, + bmdVideoInputAnamorphicDownconversionFromHD1080 = 0x3130616d, + bmdVideoInputLetterboxDownconversionFromHD720 = 0x37326c62, + bmdVideoInputAnamorphicDownconversionFromHD720 = 0x3732616d, + bmdVideoInputLetterboxUpconversion = 0x6c627570, + bmdVideoInputAnamorphicUpconversion = 0x616d7570 + } BMDVideoInputConversionMode; + +typedef /* [v1_enum] */ +enum _BMDVideo3DPackingFormat + { + bmdVideo3DPackingSidebySideHalf = 0x73627368, + bmdVideo3DPackingLinebyLine = 0x6c62796c, + bmdVideo3DPackingTopAndBottom = 0x7461626f, + bmdVideo3DPackingFramePacking = 0x6672706b, + bmdVideo3DPackingLeftOnly = 0x6c656674, + bmdVideo3DPackingRightOnly = 0x72696768 + } BMDVideo3DPackingFormat; + +typedef /* [v1_enum] */ +enum _BMDIdleVideoOutputOperation + { + bmdIdleVideoOutputBlack = 0x626c6163, + bmdIdleVideoOutputLastFrame = 0x6c616661, + bmdIdleVideoOutputDesktop = 0x6465736b + } BMDIdleVideoOutputOperation; + +typedef /* [v1_enum] */ +enum _BMDDeckLinkAttributeID + { + BMDDeckLinkSupportsInternalKeying = 0x6b657969, + BMDDeckLinkSupportsExternalKeying = 0x6b657965, + BMDDeckLinkSupportsHDKeying = 0x6b657968, + BMDDeckLinkSupportsInputFormatDetection = 0x696e6664, + BMDDeckLinkHasReferenceInput = 0x6872696e, + BMDDeckLinkHasSerialPort = 0x68737074, + BMDDeckLinkHasAnalogVideoOutputGain = 0x61766f67, + BMDDeckLinkCanOnlyAdjustOverallVideoOutputGain = 0x6f766f67, + BMDDeckLinkHasVideoInputAntiAliasingFilter = 0x6161666c, + BMDDeckLinkHasBypass = 0x62797073, + BMDDeckLinkSupportsDesktopDisplay = 0x65787464, + BMDDeckLinkSupportsClockTimingAdjustment = 0x63746164, + BMDDeckLinkSupportsFullDuplex = 0x66647570, + BMDDeckLinkSupportsFullFrameReferenceInputTimingOffset = 0x6672696e, + BMDDeckLinkSupportsSMPTELevelAOutput = 0x6c766c61, + BMDDeckLinkSupportsDualLinkSDI = 0x73646c73, + BMDDeckLinkSupportsIdleOutput = 0x69646f75, + BMDDeckLinkMaximumAudioChannels = 0x6d616368, + BMDDeckLinkMaximumAnalogAudioChannels = 0x61616368, + BMDDeckLinkNumberOfSubDevices = 0x6e736264, + BMDDeckLinkSubDeviceIndex = 0x73756269, + BMDDeckLinkPersistentID = 0x70656964, + BMDDeckLinkTopologicalID = 0x746f6964, + BMDDeckLinkVideoOutputConnections = 0x766f636e, + BMDDeckLinkVideoInputConnections = 0x7669636e, + BMDDeckLinkAudioOutputConnections = 0x616f636e, + BMDDeckLinkAudioInputConnections = 0x6169636e, + BMDDeckLinkDeviceBusyState = 0x64627374, + BMDDeckLinkVideoIOSupport = 0x76696f73, + BMDDeckLinkVideoInputGainMinimum = 0x7669676d, + BMDDeckLinkVideoInputGainMaximum = 0x76696778, + BMDDeckLinkVideoOutputGainMinimum = 0x766f676d, + BMDDeckLinkVideoOutputGainMaximum = 0x766f6778, + BMDDeckLinkSerialPortDeviceName = 0x736c706e + } BMDDeckLinkAttributeID; + +typedef /* [v1_enum] */ +enum _BMDDeckLinkAPIInformationID + { + BMDDeckLinkAPIVersion = 0x76657273 + } BMDDeckLinkAPIInformationID; + +/* [v1_enum] */ +enum _BMDDeviceBusyState + { + bmdDeviceCaptureBusy = ( 1 << 0 ) , + bmdDevicePlaybackBusy = ( 1 << 1 ) , + bmdDeviceSerialPortBusy = ( 1 << 2 ) + } ; +typedef /* [v1_enum] */ +enum _BMDVideoIOSupport + { + bmdDeviceSupportsCapture = ( 1 << 0 ) , + bmdDeviceSupportsPlayback = ( 1 << 1 ) + } BMDVideoIOSupport; + +typedef /* [v1_enum] */ +enum _BMD3DPreviewFormat + { + bmd3DPreviewFormatDefault = 0x64656661, + bmd3DPreviewFormatLeftOnly = 0x6c656674, + bmd3DPreviewFormatRightOnly = 0x72696768, + bmd3DPreviewFormatSideBySide = 0x73696465, + bmd3DPreviewFormatTopBottom = 0x746f7062 + } BMD3DPreviewFormat; + +typedef /* [v1_enum] */ +enum _BMDNotifications + { + bmdPreferencesChanged = 0x70726566 + } BMDNotifications; + + + + + + + + + + + + + + + + + + + + + + + + + +typedef /* [v1_enum] */ +enum _BMDDeckLinkConfigurationID_v10_2 + { + bmdDeckLinkConfig3GBpsVideoOutput_v10_2 = 0x33676273 + } BMDDeckLinkConfigurationID_v10_2; + +typedef /* [v1_enum] */ +enum _BMDAudioConnection_v10_2 + { + bmdAudioConnectionEmbedded_v10_2 = 0x656d6264, + bmdAudioConnectionAESEBU_v10_2 = 0x61657320, + bmdAudioConnectionAnalog_v10_2 = 0x616e6c67, + bmdAudioConnectionAnalogXLR_v10_2 = 0x61786c72, + bmdAudioConnectionAnalogRCA_v10_2 = 0x61726361 + } BMDAudioConnection_v10_2; + + +typedef /* [v1_enum] */ +enum _BMDDeckControlVTRControlState_v8_1 + { + bmdDeckControlNotInVTRControlMode_v8_1 = 0x6e76636d, + bmdDeckControlVTRControlPlaying_v8_1 = 0x76747270, + bmdDeckControlVTRControlRecording_v8_1 = 0x76747272, + bmdDeckControlVTRControlStill_v8_1 = 0x76747261, + bmdDeckControlVTRControlSeeking_v8_1 = 0x76747273, + bmdDeckControlVTRControlStopped_v8_1 = 0x7674726f + } BMDDeckControlVTRControlState_v8_1; + + + +typedef /* [v1_enum] */ +enum _BMDVideoConnection_v7_6 + { + bmdVideoConnectionSDI_v7_6 = 0x73646920, + bmdVideoConnectionHDMI_v7_6 = 0x68646d69, + bmdVideoConnectionOpticalSDI_v7_6 = 0x6f707469, + bmdVideoConnectionComponent_v7_6 = 0x63706e74, + bmdVideoConnectionComposite_v7_6 = 0x636d7374, + bmdVideoConnectionSVideo_v7_6 = 0x73766964 + } BMDVideoConnection_v7_6; + + + + + + + + + + + + + + + + + + + + + + + +EXTERN_C const IID LIBID_DeckLinkAPI; + +#ifndef __IDeckLinkTimecode_INTERFACE_DEFINED__ +#define __IDeckLinkTimecode_INTERFACE_DEFINED__ + +/* interface IDeckLinkTimecode */ +/* [helpstring][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkTimecode; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("BC6CFBD3-8317-4325-AC1C-1216391E9340") + IDeckLinkTimecode : public IUnknown + { + public: + virtual BMDTimecodeBCD STDMETHODCALLTYPE GetBCD( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetComponents( + /* [out] */ unsigned char *hours, + /* [out] */ unsigned char *minutes, + /* [out] */ unsigned char *seconds, + /* [out] */ unsigned char *frames) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetString( + /* [out] */ BSTR *timecode) = 0; + + virtual BMDTimecodeFlags STDMETHODCALLTYPE GetFlags( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetTimecodeUserBits( + /* [out] */ BMDTimecodeUserBits *userBits) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkTimecodeVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkTimecode * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkTimecode * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkTimecode * This); + + BMDTimecodeBCD ( STDMETHODCALLTYPE *GetBCD )( + IDeckLinkTimecode * This); + + HRESULT ( STDMETHODCALLTYPE *GetComponents )( + IDeckLinkTimecode * This, + /* [out] */ unsigned char *hours, + /* [out] */ unsigned char *minutes, + /* [out] */ unsigned char *seconds, + /* [out] */ unsigned char *frames); + + HRESULT ( STDMETHODCALLTYPE *GetString )( + IDeckLinkTimecode * This, + /* [out] */ BSTR *timecode); + + BMDTimecodeFlags ( STDMETHODCALLTYPE *GetFlags )( + IDeckLinkTimecode * This); + + HRESULT ( STDMETHODCALLTYPE *GetTimecodeUserBits )( + IDeckLinkTimecode * This, + /* [out] */ BMDTimecodeUserBits *userBits); + + END_INTERFACE + } IDeckLinkTimecodeVtbl; + + interface IDeckLinkTimecode + { + CONST_VTBL struct IDeckLinkTimecodeVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkTimecode_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkTimecode_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkTimecode_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkTimecode_GetBCD(This) \ + ( (This)->lpVtbl -> GetBCD(This) ) + +#define IDeckLinkTimecode_GetComponents(This,hours,minutes,seconds,frames) \ + ( (This)->lpVtbl -> GetComponents(This,hours,minutes,seconds,frames) ) + +#define IDeckLinkTimecode_GetString(This,timecode) \ + ( (This)->lpVtbl -> GetString(This,timecode) ) + +#define IDeckLinkTimecode_GetFlags(This) \ + ( (This)->lpVtbl -> GetFlags(This) ) + +#define IDeckLinkTimecode_GetTimecodeUserBits(This,userBits) \ + ( (This)->lpVtbl -> GetTimecodeUserBits(This,userBits) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkTimecode_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkDisplayModeIterator_INTERFACE_DEFINED__ +#define __IDeckLinkDisplayModeIterator_INTERFACE_DEFINED__ + +/* interface IDeckLinkDisplayModeIterator */ +/* [helpstring][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkDisplayModeIterator; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("9C88499F-F601-4021-B80B-032E4EB41C35") + IDeckLinkDisplayModeIterator : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE Next( + /* [out] */ IDeckLinkDisplayMode **deckLinkDisplayMode) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkDisplayModeIteratorVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkDisplayModeIterator * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkDisplayModeIterator * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkDisplayModeIterator * This); + + HRESULT ( STDMETHODCALLTYPE *Next )( + IDeckLinkDisplayModeIterator * This, + /* [out] */ IDeckLinkDisplayMode **deckLinkDisplayMode); + + END_INTERFACE + } IDeckLinkDisplayModeIteratorVtbl; + + interface IDeckLinkDisplayModeIterator + { + CONST_VTBL struct IDeckLinkDisplayModeIteratorVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkDisplayModeIterator_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkDisplayModeIterator_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkDisplayModeIterator_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkDisplayModeIterator_Next(This,deckLinkDisplayMode) \ + ( (This)->lpVtbl -> Next(This,deckLinkDisplayMode) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkDisplayModeIterator_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkDisplayMode_INTERFACE_DEFINED__ +#define __IDeckLinkDisplayMode_INTERFACE_DEFINED__ + +/* interface IDeckLinkDisplayMode */ +/* [helpstring][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkDisplayMode; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("3EB2C1AB-0A3D-4523-A3AD-F40D7FB14E78") + IDeckLinkDisplayMode : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE GetName( + /* [out] */ BSTR *name) = 0; + + virtual BMDDisplayMode STDMETHODCALLTYPE GetDisplayMode( void) = 0; + + virtual long STDMETHODCALLTYPE GetWidth( void) = 0; + + virtual long STDMETHODCALLTYPE GetHeight( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetFrameRate( + /* [out] */ BMDTimeValue *frameDuration, + /* [out] */ BMDTimeScale *timeScale) = 0; + + virtual BMDFieldDominance STDMETHODCALLTYPE GetFieldDominance( void) = 0; + + virtual BMDDisplayModeFlags STDMETHODCALLTYPE GetFlags( void) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkDisplayModeVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkDisplayMode * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkDisplayMode * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkDisplayMode * This); + + HRESULT ( STDMETHODCALLTYPE *GetName )( + IDeckLinkDisplayMode * This, + /* [out] */ BSTR *name); + + BMDDisplayMode ( STDMETHODCALLTYPE *GetDisplayMode )( + IDeckLinkDisplayMode * This); + + long ( STDMETHODCALLTYPE *GetWidth )( + IDeckLinkDisplayMode * This); + + long ( STDMETHODCALLTYPE *GetHeight )( + IDeckLinkDisplayMode * This); + + HRESULT ( STDMETHODCALLTYPE *GetFrameRate )( + IDeckLinkDisplayMode * This, + /* [out] */ BMDTimeValue *frameDuration, + /* [out] */ BMDTimeScale *timeScale); + + BMDFieldDominance ( STDMETHODCALLTYPE *GetFieldDominance )( + IDeckLinkDisplayMode * This); + + BMDDisplayModeFlags ( STDMETHODCALLTYPE *GetFlags )( + IDeckLinkDisplayMode * This); + + END_INTERFACE + } IDeckLinkDisplayModeVtbl; + + interface IDeckLinkDisplayMode + { + CONST_VTBL struct IDeckLinkDisplayModeVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkDisplayMode_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkDisplayMode_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkDisplayMode_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkDisplayMode_GetName(This,name) \ + ( (This)->lpVtbl -> GetName(This,name) ) + +#define IDeckLinkDisplayMode_GetDisplayMode(This) \ + ( (This)->lpVtbl -> GetDisplayMode(This) ) + +#define IDeckLinkDisplayMode_GetWidth(This) \ + ( (This)->lpVtbl -> GetWidth(This) ) + +#define IDeckLinkDisplayMode_GetHeight(This) \ + ( (This)->lpVtbl -> GetHeight(This) ) + +#define IDeckLinkDisplayMode_GetFrameRate(This,frameDuration,timeScale) \ + ( (This)->lpVtbl -> GetFrameRate(This,frameDuration,timeScale) ) + +#define IDeckLinkDisplayMode_GetFieldDominance(This) \ + ( (This)->lpVtbl -> GetFieldDominance(This) ) + +#define IDeckLinkDisplayMode_GetFlags(This) \ + ( (This)->lpVtbl -> GetFlags(This) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkDisplayMode_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLink_INTERFACE_DEFINED__ +#define __IDeckLink_INTERFACE_DEFINED__ + +/* interface IDeckLink */ +/* [helpstring][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLink; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("C418FBDD-0587-48ED-8FE5-640F0A14AF91") + IDeckLink : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE GetModelName( + /* [out] */ BSTR *modelName) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetDisplayName( + /* [out] */ BSTR *displayName) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLink * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLink * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLink * This); + + HRESULT ( STDMETHODCALLTYPE *GetModelName )( + IDeckLink * This, + /* [out] */ BSTR *modelName); + + HRESULT ( STDMETHODCALLTYPE *GetDisplayName )( + IDeckLink * This, + /* [out] */ BSTR *displayName); + + END_INTERFACE + } IDeckLinkVtbl; + + interface IDeckLink + { + CONST_VTBL struct IDeckLinkVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLink_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLink_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLink_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLink_GetModelName(This,modelName) \ + ( (This)->lpVtbl -> GetModelName(This,modelName) ) + +#define IDeckLink_GetDisplayName(This,displayName) \ + ( (This)->lpVtbl -> GetDisplayName(This,displayName) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLink_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkConfiguration_INTERFACE_DEFINED__ +#define __IDeckLinkConfiguration_INTERFACE_DEFINED__ + +/* interface IDeckLinkConfiguration */ +/* [helpstring][local][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkConfiguration; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("1E69FCF6-4203-4936-8076-2A9F4CFD50CB") + IDeckLinkConfiguration : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE SetFlag( + /* [in] */ BMDDeckLinkConfigurationID cfgID, + /* [in] */ BOOL value) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetFlag( + /* [in] */ BMDDeckLinkConfigurationID cfgID, + /* [out] */ BOOL *value) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetInt( + /* [in] */ BMDDeckLinkConfigurationID cfgID, + /* [in] */ LONGLONG value) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetInt( + /* [in] */ BMDDeckLinkConfigurationID cfgID, + /* [out] */ LONGLONG *value) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetFloat( + /* [in] */ BMDDeckLinkConfigurationID cfgID, + /* [in] */ double value) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetFloat( + /* [in] */ BMDDeckLinkConfigurationID cfgID, + /* [out] */ double *value) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetString( + /* [in] */ BMDDeckLinkConfigurationID cfgID, + /* [in] */ BSTR value) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetString( + /* [in] */ BMDDeckLinkConfigurationID cfgID, + /* [out] */ BSTR *value) = 0; + + virtual HRESULT STDMETHODCALLTYPE WriteConfigurationToPreferences( void) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkConfigurationVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkConfiguration * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkConfiguration * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkConfiguration * This); + + HRESULT ( STDMETHODCALLTYPE *SetFlag )( + IDeckLinkConfiguration * This, + /* [in] */ BMDDeckLinkConfigurationID cfgID, + /* [in] */ BOOL value); + + HRESULT ( STDMETHODCALLTYPE *GetFlag )( + IDeckLinkConfiguration * This, + /* [in] */ BMDDeckLinkConfigurationID cfgID, + /* [out] */ BOOL *value); + + HRESULT ( STDMETHODCALLTYPE *SetInt )( + IDeckLinkConfiguration * This, + /* [in] */ BMDDeckLinkConfigurationID cfgID, + /* [in] */ LONGLONG value); + + HRESULT ( STDMETHODCALLTYPE *GetInt )( + IDeckLinkConfiguration * This, + /* [in] */ BMDDeckLinkConfigurationID cfgID, + /* [out] */ LONGLONG *value); + + HRESULT ( STDMETHODCALLTYPE *SetFloat )( + IDeckLinkConfiguration * This, + /* [in] */ BMDDeckLinkConfigurationID cfgID, + /* [in] */ double value); + + HRESULT ( STDMETHODCALLTYPE *GetFloat )( + IDeckLinkConfiguration * This, + /* [in] */ BMDDeckLinkConfigurationID cfgID, + /* [out] */ double *value); + + HRESULT ( STDMETHODCALLTYPE *SetString )( + IDeckLinkConfiguration * This, + /* [in] */ BMDDeckLinkConfigurationID cfgID, + /* [in] */ BSTR value); + + HRESULT ( STDMETHODCALLTYPE *GetString )( + IDeckLinkConfiguration * This, + /* [in] */ BMDDeckLinkConfigurationID cfgID, + /* [out] */ BSTR *value); + + HRESULT ( STDMETHODCALLTYPE *WriteConfigurationToPreferences )( + IDeckLinkConfiguration * This); + + END_INTERFACE + } IDeckLinkConfigurationVtbl; + + interface IDeckLinkConfiguration + { + CONST_VTBL struct IDeckLinkConfigurationVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkConfiguration_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkConfiguration_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkConfiguration_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkConfiguration_SetFlag(This,cfgID,value) \ + ( (This)->lpVtbl -> SetFlag(This,cfgID,value) ) + +#define IDeckLinkConfiguration_GetFlag(This,cfgID,value) \ + ( (This)->lpVtbl -> GetFlag(This,cfgID,value) ) + +#define IDeckLinkConfiguration_SetInt(This,cfgID,value) \ + ( (This)->lpVtbl -> SetInt(This,cfgID,value) ) + +#define IDeckLinkConfiguration_GetInt(This,cfgID,value) \ + ( (This)->lpVtbl -> GetInt(This,cfgID,value) ) + +#define IDeckLinkConfiguration_SetFloat(This,cfgID,value) \ + ( (This)->lpVtbl -> SetFloat(This,cfgID,value) ) + +#define IDeckLinkConfiguration_GetFloat(This,cfgID,value) \ + ( (This)->lpVtbl -> GetFloat(This,cfgID,value) ) + +#define IDeckLinkConfiguration_SetString(This,cfgID,value) \ + ( (This)->lpVtbl -> SetString(This,cfgID,value) ) + +#define IDeckLinkConfiguration_GetString(This,cfgID,value) \ + ( (This)->lpVtbl -> GetString(This,cfgID,value) ) + +#define IDeckLinkConfiguration_WriteConfigurationToPreferences(This) \ + ( (This)->lpVtbl -> WriteConfigurationToPreferences(This) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkConfiguration_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkDeckControlStatusCallback_INTERFACE_DEFINED__ +#define __IDeckLinkDeckControlStatusCallback_INTERFACE_DEFINED__ + +/* interface IDeckLinkDeckControlStatusCallback */ +/* [helpstring][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkDeckControlStatusCallback; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("53436FFB-B434-4906-BADC-AE3060FFE8EF") + IDeckLinkDeckControlStatusCallback : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE TimecodeUpdate( + /* [in] */ BMDTimecodeBCD currentTimecode) = 0; + + virtual HRESULT STDMETHODCALLTYPE VTRControlStateChanged( + /* [in] */ BMDDeckControlVTRControlState newState, + /* [in] */ BMDDeckControlError error) = 0; + + virtual HRESULT STDMETHODCALLTYPE DeckControlEventReceived( + /* [in] */ BMDDeckControlEvent event, + /* [in] */ BMDDeckControlError error) = 0; + + virtual HRESULT STDMETHODCALLTYPE DeckControlStatusChanged( + /* [in] */ BMDDeckControlStatusFlags flags, + /* [in] */ unsigned int mask) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkDeckControlStatusCallbackVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkDeckControlStatusCallback * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkDeckControlStatusCallback * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkDeckControlStatusCallback * This); + + HRESULT ( STDMETHODCALLTYPE *TimecodeUpdate )( + IDeckLinkDeckControlStatusCallback * This, + /* [in] */ BMDTimecodeBCD currentTimecode); + + HRESULT ( STDMETHODCALLTYPE *VTRControlStateChanged )( + IDeckLinkDeckControlStatusCallback * This, + /* [in] */ BMDDeckControlVTRControlState newState, + /* [in] */ BMDDeckControlError error); + + HRESULT ( STDMETHODCALLTYPE *DeckControlEventReceived )( + IDeckLinkDeckControlStatusCallback * This, + /* [in] */ BMDDeckControlEvent event, + /* [in] */ BMDDeckControlError error); + + HRESULT ( STDMETHODCALLTYPE *DeckControlStatusChanged )( + IDeckLinkDeckControlStatusCallback * This, + /* [in] */ BMDDeckControlStatusFlags flags, + /* [in] */ unsigned int mask); + + END_INTERFACE + } IDeckLinkDeckControlStatusCallbackVtbl; + + interface IDeckLinkDeckControlStatusCallback + { + CONST_VTBL struct IDeckLinkDeckControlStatusCallbackVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkDeckControlStatusCallback_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkDeckControlStatusCallback_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkDeckControlStatusCallback_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkDeckControlStatusCallback_TimecodeUpdate(This,currentTimecode) \ + ( (This)->lpVtbl -> TimecodeUpdate(This,currentTimecode) ) + +#define IDeckLinkDeckControlStatusCallback_VTRControlStateChanged(This,newState,error) \ + ( (This)->lpVtbl -> VTRControlStateChanged(This,newState,error) ) + +#define IDeckLinkDeckControlStatusCallback_DeckControlEventReceived(This,event,error) \ + ( (This)->lpVtbl -> DeckControlEventReceived(This,event,error) ) + +#define IDeckLinkDeckControlStatusCallback_DeckControlStatusChanged(This,flags,mask) \ + ( (This)->lpVtbl -> DeckControlStatusChanged(This,flags,mask) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkDeckControlStatusCallback_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkDeckControl_INTERFACE_DEFINED__ +#define __IDeckLinkDeckControl_INTERFACE_DEFINED__ + +/* interface IDeckLinkDeckControl */ +/* [helpstring][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkDeckControl; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("8E1C3ACE-19C7-4E00-8B92-D80431D958BE") + IDeckLinkDeckControl : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE Open( + /* [in] */ BMDTimeScale timeScale, + /* [in] */ BMDTimeValue timeValue, + /* [in] */ BOOL timecodeIsDropFrame, + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE Close( + /* [in] */ BOOL standbyOn) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetCurrentState( + /* [out] */ BMDDeckControlMode *mode, + /* [out] */ BMDDeckControlVTRControlState *vtrControlState, + /* [out] */ BMDDeckControlStatusFlags *flags) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetStandby( + /* [in] */ BOOL standbyOn) = 0; + + virtual HRESULT STDMETHODCALLTYPE SendCommand( + /* [in] */ unsigned char *inBuffer, + /* [in] */ unsigned int inBufferSize, + /* [out] */ unsigned char *outBuffer, + /* [out] */ unsigned int *outDataSize, + /* [in] */ unsigned int outBufferSize, + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE Play( + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE Stop( + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE TogglePlayStop( + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE Eject( + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE GoToTimecode( + /* [in] */ BMDTimecodeBCD timecode, + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE FastForward( + /* [in] */ BOOL viewTape, + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE Rewind( + /* [in] */ BOOL viewTape, + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE StepForward( + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE StepBack( + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE Jog( + /* [in] */ double rate, + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE Shuttle( + /* [in] */ double rate, + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetTimecodeString( + /* [out] */ BSTR *currentTimeCode, + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetTimecode( + /* [out] */ IDeckLinkTimecode **currentTimecode, + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetTimecodeBCD( + /* [out] */ BMDTimecodeBCD *currentTimecode, + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetPreroll( + /* [in] */ unsigned int prerollSeconds) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetPreroll( + /* [out] */ unsigned int *prerollSeconds) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetExportOffset( + /* [in] */ int exportOffsetFields) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetExportOffset( + /* [out] */ int *exportOffsetFields) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetManualExportOffset( + /* [out] */ int *deckManualExportOffsetFields) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetCaptureOffset( + /* [in] */ int captureOffsetFields) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetCaptureOffset( + /* [out] */ int *captureOffsetFields) = 0; + + virtual HRESULT STDMETHODCALLTYPE StartExport( + /* [in] */ BMDTimecodeBCD inTimecode, + /* [in] */ BMDTimecodeBCD outTimecode, + /* [in] */ BMDDeckControlExportModeOpsFlags exportModeOps, + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE StartCapture( + /* [in] */ BOOL useVITC, + /* [in] */ BMDTimecodeBCD inTimecode, + /* [in] */ BMDTimecodeBCD outTimecode, + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetDeviceID( + /* [out] */ unsigned short *deviceId, + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE Abort( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE CrashRecordStart( + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE CrashRecordStop( + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetCallback( + /* [in] */ IDeckLinkDeckControlStatusCallback *callback) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkDeckControlVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkDeckControl * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkDeckControl * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkDeckControl * This); + + HRESULT ( STDMETHODCALLTYPE *Open )( + IDeckLinkDeckControl * This, + /* [in] */ BMDTimeScale timeScale, + /* [in] */ BMDTimeValue timeValue, + /* [in] */ BOOL timecodeIsDropFrame, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *Close )( + IDeckLinkDeckControl * This, + /* [in] */ BOOL standbyOn); + + HRESULT ( STDMETHODCALLTYPE *GetCurrentState )( + IDeckLinkDeckControl * This, + /* [out] */ BMDDeckControlMode *mode, + /* [out] */ BMDDeckControlVTRControlState *vtrControlState, + /* [out] */ BMDDeckControlStatusFlags *flags); + + HRESULT ( STDMETHODCALLTYPE *SetStandby )( + IDeckLinkDeckControl * This, + /* [in] */ BOOL standbyOn); + + HRESULT ( STDMETHODCALLTYPE *SendCommand )( + IDeckLinkDeckControl * This, + /* [in] */ unsigned char *inBuffer, + /* [in] */ unsigned int inBufferSize, + /* [out] */ unsigned char *outBuffer, + /* [out] */ unsigned int *outDataSize, + /* [in] */ unsigned int outBufferSize, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *Play )( + IDeckLinkDeckControl * This, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *Stop )( + IDeckLinkDeckControl * This, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *TogglePlayStop )( + IDeckLinkDeckControl * This, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *Eject )( + IDeckLinkDeckControl * This, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *GoToTimecode )( + IDeckLinkDeckControl * This, + /* [in] */ BMDTimecodeBCD timecode, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *FastForward )( + IDeckLinkDeckControl * This, + /* [in] */ BOOL viewTape, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *Rewind )( + IDeckLinkDeckControl * This, + /* [in] */ BOOL viewTape, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *StepForward )( + IDeckLinkDeckControl * This, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *StepBack )( + IDeckLinkDeckControl * This, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *Jog )( + IDeckLinkDeckControl * This, + /* [in] */ double rate, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *Shuttle )( + IDeckLinkDeckControl * This, + /* [in] */ double rate, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *GetTimecodeString )( + IDeckLinkDeckControl * This, + /* [out] */ BSTR *currentTimeCode, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *GetTimecode )( + IDeckLinkDeckControl * This, + /* [out] */ IDeckLinkTimecode **currentTimecode, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *GetTimecodeBCD )( + IDeckLinkDeckControl * This, + /* [out] */ BMDTimecodeBCD *currentTimecode, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *SetPreroll )( + IDeckLinkDeckControl * This, + /* [in] */ unsigned int prerollSeconds); + + HRESULT ( STDMETHODCALLTYPE *GetPreroll )( + IDeckLinkDeckControl * This, + /* [out] */ unsigned int *prerollSeconds); + + HRESULT ( STDMETHODCALLTYPE *SetExportOffset )( + IDeckLinkDeckControl * This, + /* [in] */ int exportOffsetFields); + + HRESULT ( STDMETHODCALLTYPE *GetExportOffset )( + IDeckLinkDeckControl * This, + /* [out] */ int *exportOffsetFields); + + HRESULT ( STDMETHODCALLTYPE *GetManualExportOffset )( + IDeckLinkDeckControl * This, + /* [out] */ int *deckManualExportOffsetFields); + + HRESULT ( STDMETHODCALLTYPE *SetCaptureOffset )( + IDeckLinkDeckControl * This, + /* [in] */ int captureOffsetFields); + + HRESULT ( STDMETHODCALLTYPE *GetCaptureOffset )( + IDeckLinkDeckControl * This, + /* [out] */ int *captureOffsetFields); + + HRESULT ( STDMETHODCALLTYPE *StartExport )( + IDeckLinkDeckControl * This, + /* [in] */ BMDTimecodeBCD inTimecode, + /* [in] */ BMDTimecodeBCD outTimecode, + /* [in] */ BMDDeckControlExportModeOpsFlags exportModeOps, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *StartCapture )( + IDeckLinkDeckControl * This, + /* [in] */ BOOL useVITC, + /* [in] */ BMDTimecodeBCD inTimecode, + /* [in] */ BMDTimecodeBCD outTimecode, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *GetDeviceID )( + IDeckLinkDeckControl * This, + /* [out] */ unsigned short *deviceId, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *Abort )( + IDeckLinkDeckControl * This); + + HRESULT ( STDMETHODCALLTYPE *CrashRecordStart )( + IDeckLinkDeckControl * This, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *CrashRecordStop )( + IDeckLinkDeckControl * This, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *SetCallback )( + IDeckLinkDeckControl * This, + /* [in] */ IDeckLinkDeckControlStatusCallback *callback); + + END_INTERFACE + } IDeckLinkDeckControlVtbl; + + interface IDeckLinkDeckControl + { + CONST_VTBL struct IDeckLinkDeckControlVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkDeckControl_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkDeckControl_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkDeckControl_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkDeckControl_Open(This,timeScale,timeValue,timecodeIsDropFrame,error) \ + ( (This)->lpVtbl -> Open(This,timeScale,timeValue,timecodeIsDropFrame,error) ) + +#define IDeckLinkDeckControl_Close(This,standbyOn) \ + ( (This)->lpVtbl -> Close(This,standbyOn) ) + +#define IDeckLinkDeckControl_GetCurrentState(This,mode,vtrControlState,flags) \ + ( (This)->lpVtbl -> GetCurrentState(This,mode,vtrControlState,flags) ) + +#define IDeckLinkDeckControl_SetStandby(This,standbyOn) \ + ( (This)->lpVtbl -> SetStandby(This,standbyOn) ) + +#define IDeckLinkDeckControl_SendCommand(This,inBuffer,inBufferSize,outBuffer,outDataSize,outBufferSize,error) \ + ( (This)->lpVtbl -> SendCommand(This,inBuffer,inBufferSize,outBuffer,outDataSize,outBufferSize,error) ) + +#define IDeckLinkDeckControl_Play(This,error) \ + ( (This)->lpVtbl -> Play(This,error) ) + +#define IDeckLinkDeckControl_Stop(This,error) \ + ( (This)->lpVtbl -> Stop(This,error) ) + +#define IDeckLinkDeckControl_TogglePlayStop(This,error) \ + ( (This)->lpVtbl -> TogglePlayStop(This,error) ) + +#define IDeckLinkDeckControl_Eject(This,error) \ + ( (This)->lpVtbl -> Eject(This,error) ) + +#define IDeckLinkDeckControl_GoToTimecode(This,timecode,error) \ + ( (This)->lpVtbl -> GoToTimecode(This,timecode,error) ) + +#define IDeckLinkDeckControl_FastForward(This,viewTape,error) \ + ( (This)->lpVtbl -> FastForward(This,viewTape,error) ) + +#define IDeckLinkDeckControl_Rewind(This,viewTape,error) \ + ( (This)->lpVtbl -> Rewind(This,viewTape,error) ) + +#define IDeckLinkDeckControl_StepForward(This,error) \ + ( (This)->lpVtbl -> StepForward(This,error) ) + +#define IDeckLinkDeckControl_StepBack(This,error) \ + ( (This)->lpVtbl -> StepBack(This,error) ) + +#define IDeckLinkDeckControl_Jog(This,rate,error) \ + ( (This)->lpVtbl -> Jog(This,rate,error) ) + +#define IDeckLinkDeckControl_Shuttle(This,rate,error) \ + ( (This)->lpVtbl -> Shuttle(This,rate,error) ) + +#define IDeckLinkDeckControl_GetTimecodeString(This,currentTimeCode,error) \ + ( (This)->lpVtbl -> GetTimecodeString(This,currentTimeCode,error) ) + +#define IDeckLinkDeckControl_GetTimecode(This,currentTimecode,error) \ + ( (This)->lpVtbl -> GetTimecode(This,currentTimecode,error) ) + +#define IDeckLinkDeckControl_GetTimecodeBCD(This,currentTimecode,error) \ + ( (This)->lpVtbl -> GetTimecodeBCD(This,currentTimecode,error) ) + +#define IDeckLinkDeckControl_SetPreroll(This,prerollSeconds) \ + ( (This)->lpVtbl -> SetPreroll(This,prerollSeconds) ) + +#define IDeckLinkDeckControl_GetPreroll(This,prerollSeconds) \ + ( (This)->lpVtbl -> GetPreroll(This,prerollSeconds) ) + +#define IDeckLinkDeckControl_SetExportOffset(This,exportOffsetFields) \ + ( (This)->lpVtbl -> SetExportOffset(This,exportOffsetFields) ) + +#define IDeckLinkDeckControl_GetExportOffset(This,exportOffsetFields) \ + ( (This)->lpVtbl -> GetExportOffset(This,exportOffsetFields) ) + +#define IDeckLinkDeckControl_GetManualExportOffset(This,deckManualExportOffsetFields) \ + ( (This)->lpVtbl -> GetManualExportOffset(This,deckManualExportOffsetFields) ) + +#define IDeckLinkDeckControl_SetCaptureOffset(This,captureOffsetFields) \ + ( (This)->lpVtbl -> SetCaptureOffset(This,captureOffsetFields) ) + +#define IDeckLinkDeckControl_GetCaptureOffset(This,captureOffsetFields) \ + ( (This)->lpVtbl -> GetCaptureOffset(This,captureOffsetFields) ) + +#define IDeckLinkDeckControl_StartExport(This,inTimecode,outTimecode,exportModeOps,error) \ + ( (This)->lpVtbl -> StartExport(This,inTimecode,outTimecode,exportModeOps,error) ) + +#define IDeckLinkDeckControl_StartCapture(This,useVITC,inTimecode,outTimecode,error) \ + ( (This)->lpVtbl -> StartCapture(This,useVITC,inTimecode,outTimecode,error) ) + +#define IDeckLinkDeckControl_GetDeviceID(This,deviceId,error) \ + ( (This)->lpVtbl -> GetDeviceID(This,deviceId,error) ) + +#define IDeckLinkDeckControl_Abort(This) \ + ( (This)->lpVtbl -> Abort(This) ) + +#define IDeckLinkDeckControl_CrashRecordStart(This,error) \ + ( (This)->lpVtbl -> CrashRecordStart(This,error) ) + +#define IDeckLinkDeckControl_CrashRecordStop(This,error) \ + ( (This)->lpVtbl -> CrashRecordStop(This,error) ) + +#define IDeckLinkDeckControl_SetCallback(This,callback) \ + ( (This)->lpVtbl -> SetCallback(This,callback) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkDeckControl_INTERFACE_DEFINED__ */ + + +#ifndef __IBMDStreamingDeviceNotificationCallback_INTERFACE_DEFINED__ +#define __IBMDStreamingDeviceNotificationCallback_INTERFACE_DEFINED__ + +/* interface IBMDStreamingDeviceNotificationCallback */ +/* [helpstring][uuid][object] */ + + +EXTERN_C const IID IID_IBMDStreamingDeviceNotificationCallback; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("F9531D64-3305-4B29-A387-7F74BB0D0E84") + IBMDStreamingDeviceNotificationCallback : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE StreamingDeviceArrived( + /* [in] */ IDeckLink *device) = 0; + + virtual HRESULT STDMETHODCALLTYPE StreamingDeviceRemoved( + /* [in] */ IDeckLink *device) = 0; + + virtual HRESULT STDMETHODCALLTYPE StreamingDeviceModeChanged( + /* [in] */ IDeckLink *device, + /* [in] */ BMDStreamingDeviceMode mode) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IBMDStreamingDeviceNotificationCallbackVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IBMDStreamingDeviceNotificationCallback * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IBMDStreamingDeviceNotificationCallback * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IBMDStreamingDeviceNotificationCallback * This); + + HRESULT ( STDMETHODCALLTYPE *StreamingDeviceArrived )( + IBMDStreamingDeviceNotificationCallback * This, + /* [in] */ IDeckLink *device); + + HRESULT ( STDMETHODCALLTYPE *StreamingDeviceRemoved )( + IBMDStreamingDeviceNotificationCallback * This, + /* [in] */ IDeckLink *device); + + HRESULT ( STDMETHODCALLTYPE *StreamingDeviceModeChanged )( + IBMDStreamingDeviceNotificationCallback * This, + /* [in] */ IDeckLink *device, + /* [in] */ BMDStreamingDeviceMode mode); + + END_INTERFACE + } IBMDStreamingDeviceNotificationCallbackVtbl; + + interface IBMDStreamingDeviceNotificationCallback + { + CONST_VTBL struct IBMDStreamingDeviceNotificationCallbackVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IBMDStreamingDeviceNotificationCallback_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IBMDStreamingDeviceNotificationCallback_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IBMDStreamingDeviceNotificationCallback_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IBMDStreamingDeviceNotificationCallback_StreamingDeviceArrived(This,device) \ + ( (This)->lpVtbl -> StreamingDeviceArrived(This,device) ) + +#define IBMDStreamingDeviceNotificationCallback_StreamingDeviceRemoved(This,device) \ + ( (This)->lpVtbl -> StreamingDeviceRemoved(This,device) ) + +#define IBMDStreamingDeviceNotificationCallback_StreamingDeviceModeChanged(This,device,mode) \ + ( (This)->lpVtbl -> StreamingDeviceModeChanged(This,device,mode) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IBMDStreamingDeviceNotificationCallback_INTERFACE_DEFINED__ */ + + +#ifndef __IBMDStreamingH264InputCallback_INTERFACE_DEFINED__ +#define __IBMDStreamingH264InputCallback_INTERFACE_DEFINED__ + +/* interface IBMDStreamingH264InputCallback */ +/* [helpstring][uuid][object] */ + + +EXTERN_C const IID IID_IBMDStreamingH264InputCallback; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("823C475F-55AE-46F9-890C-537CC5CEDCCA") + IBMDStreamingH264InputCallback : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE H264NALPacketArrived( + /* [in] */ IBMDStreamingH264NALPacket *nalPacket) = 0; + + virtual HRESULT STDMETHODCALLTYPE H264AudioPacketArrived( + /* [in] */ IBMDStreamingAudioPacket *audioPacket) = 0; + + virtual HRESULT STDMETHODCALLTYPE MPEG2TSPacketArrived( + /* [in] */ IBMDStreamingMPEG2TSPacket *tsPacket) = 0; + + virtual HRESULT STDMETHODCALLTYPE H264VideoInputConnectorScanningChanged( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE H264VideoInputConnectorChanged( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE H264VideoInputModeChanged( void) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IBMDStreamingH264InputCallbackVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IBMDStreamingH264InputCallback * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IBMDStreamingH264InputCallback * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IBMDStreamingH264InputCallback * This); + + HRESULT ( STDMETHODCALLTYPE *H264NALPacketArrived )( + IBMDStreamingH264InputCallback * This, + /* [in] */ IBMDStreamingH264NALPacket *nalPacket); + + HRESULT ( STDMETHODCALLTYPE *H264AudioPacketArrived )( + IBMDStreamingH264InputCallback * This, + /* [in] */ IBMDStreamingAudioPacket *audioPacket); + + HRESULT ( STDMETHODCALLTYPE *MPEG2TSPacketArrived )( + IBMDStreamingH264InputCallback * This, + /* [in] */ IBMDStreamingMPEG2TSPacket *tsPacket); + + HRESULT ( STDMETHODCALLTYPE *H264VideoInputConnectorScanningChanged )( + IBMDStreamingH264InputCallback * This); + + HRESULT ( STDMETHODCALLTYPE *H264VideoInputConnectorChanged )( + IBMDStreamingH264InputCallback * This); + + HRESULT ( STDMETHODCALLTYPE *H264VideoInputModeChanged )( + IBMDStreamingH264InputCallback * This); + + END_INTERFACE + } IBMDStreamingH264InputCallbackVtbl; + + interface IBMDStreamingH264InputCallback + { + CONST_VTBL struct IBMDStreamingH264InputCallbackVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IBMDStreamingH264InputCallback_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IBMDStreamingH264InputCallback_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IBMDStreamingH264InputCallback_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IBMDStreamingH264InputCallback_H264NALPacketArrived(This,nalPacket) \ + ( (This)->lpVtbl -> H264NALPacketArrived(This,nalPacket) ) + +#define IBMDStreamingH264InputCallback_H264AudioPacketArrived(This,audioPacket) \ + ( (This)->lpVtbl -> H264AudioPacketArrived(This,audioPacket) ) + +#define IBMDStreamingH264InputCallback_MPEG2TSPacketArrived(This,tsPacket) \ + ( (This)->lpVtbl -> MPEG2TSPacketArrived(This,tsPacket) ) + +#define IBMDStreamingH264InputCallback_H264VideoInputConnectorScanningChanged(This) \ + ( (This)->lpVtbl -> H264VideoInputConnectorScanningChanged(This) ) + +#define IBMDStreamingH264InputCallback_H264VideoInputConnectorChanged(This) \ + ( (This)->lpVtbl -> H264VideoInputConnectorChanged(This) ) + +#define IBMDStreamingH264InputCallback_H264VideoInputModeChanged(This) \ + ( (This)->lpVtbl -> H264VideoInputModeChanged(This) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IBMDStreamingH264InputCallback_INTERFACE_DEFINED__ */ + + +#ifndef __IBMDStreamingDiscovery_INTERFACE_DEFINED__ +#define __IBMDStreamingDiscovery_INTERFACE_DEFINED__ + +/* interface IBMDStreamingDiscovery */ +/* [helpstring][uuid][object] */ + + +EXTERN_C const IID IID_IBMDStreamingDiscovery; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("2C837444-F989-4D87-901A-47C8A36D096D") + IBMDStreamingDiscovery : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE InstallDeviceNotifications( + /* [in] */ IBMDStreamingDeviceNotificationCallback *theCallback) = 0; + + virtual HRESULT STDMETHODCALLTYPE UninstallDeviceNotifications( void) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IBMDStreamingDiscoveryVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IBMDStreamingDiscovery * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IBMDStreamingDiscovery * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IBMDStreamingDiscovery * This); + + HRESULT ( STDMETHODCALLTYPE *InstallDeviceNotifications )( + IBMDStreamingDiscovery * This, + /* [in] */ IBMDStreamingDeviceNotificationCallback *theCallback); + + HRESULT ( STDMETHODCALLTYPE *UninstallDeviceNotifications )( + IBMDStreamingDiscovery * This); + + END_INTERFACE + } IBMDStreamingDiscoveryVtbl; + + interface IBMDStreamingDiscovery + { + CONST_VTBL struct IBMDStreamingDiscoveryVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IBMDStreamingDiscovery_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IBMDStreamingDiscovery_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IBMDStreamingDiscovery_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IBMDStreamingDiscovery_InstallDeviceNotifications(This,theCallback) \ + ( (This)->lpVtbl -> InstallDeviceNotifications(This,theCallback) ) + +#define IBMDStreamingDiscovery_UninstallDeviceNotifications(This) \ + ( (This)->lpVtbl -> UninstallDeviceNotifications(This) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IBMDStreamingDiscovery_INTERFACE_DEFINED__ */ + + +#ifndef __IBMDStreamingVideoEncodingMode_INTERFACE_DEFINED__ +#define __IBMDStreamingVideoEncodingMode_INTERFACE_DEFINED__ + +/* interface IBMDStreamingVideoEncodingMode */ +/* [helpstring][uuid][object] */ + + +EXTERN_C const IID IID_IBMDStreamingVideoEncodingMode; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("1AB8035B-CD13-458D-B6DF-5E8F7C2141D9") + IBMDStreamingVideoEncodingMode : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE GetName( + /* [out] */ BSTR *name) = 0; + + virtual unsigned int STDMETHODCALLTYPE GetPresetID( void) = 0; + + virtual unsigned int STDMETHODCALLTYPE GetSourcePositionX( void) = 0; + + virtual unsigned int STDMETHODCALLTYPE GetSourcePositionY( void) = 0; + + virtual unsigned int STDMETHODCALLTYPE GetSourceWidth( void) = 0; + + virtual unsigned int STDMETHODCALLTYPE GetSourceHeight( void) = 0; + + virtual unsigned int STDMETHODCALLTYPE GetDestWidth( void) = 0; + + virtual unsigned int STDMETHODCALLTYPE GetDestHeight( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetFlag( + /* [in] */ BMDStreamingEncodingModePropertyID cfgID, + /* [out] */ BOOL *value) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetInt( + /* [in] */ BMDStreamingEncodingModePropertyID cfgID, + /* [out] */ LONGLONG *value) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetFloat( + /* [in] */ BMDStreamingEncodingModePropertyID cfgID, + /* [out] */ double *value) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetString( + /* [in] */ BMDStreamingEncodingModePropertyID cfgID, + /* [out] */ BSTR *value) = 0; + + virtual HRESULT STDMETHODCALLTYPE CreateMutableVideoEncodingMode( + /* [out] */ IBMDStreamingMutableVideoEncodingMode **newEncodingMode) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IBMDStreamingVideoEncodingModeVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IBMDStreamingVideoEncodingMode * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IBMDStreamingVideoEncodingMode * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IBMDStreamingVideoEncodingMode * This); + + HRESULT ( STDMETHODCALLTYPE *GetName )( + IBMDStreamingVideoEncodingMode * This, + /* [out] */ BSTR *name); + + unsigned int ( STDMETHODCALLTYPE *GetPresetID )( + IBMDStreamingVideoEncodingMode * This); + + unsigned int ( STDMETHODCALLTYPE *GetSourcePositionX )( + IBMDStreamingVideoEncodingMode * This); + + unsigned int ( STDMETHODCALLTYPE *GetSourcePositionY )( + IBMDStreamingVideoEncodingMode * This); + + unsigned int ( STDMETHODCALLTYPE *GetSourceWidth )( + IBMDStreamingVideoEncodingMode * This); + + unsigned int ( STDMETHODCALLTYPE *GetSourceHeight )( + IBMDStreamingVideoEncodingMode * This); + + unsigned int ( STDMETHODCALLTYPE *GetDestWidth )( + IBMDStreamingVideoEncodingMode * This); + + unsigned int ( STDMETHODCALLTYPE *GetDestHeight )( + IBMDStreamingVideoEncodingMode * This); + + HRESULT ( STDMETHODCALLTYPE *GetFlag )( + IBMDStreamingVideoEncodingMode * This, + /* [in] */ BMDStreamingEncodingModePropertyID cfgID, + /* [out] */ BOOL *value); + + HRESULT ( STDMETHODCALLTYPE *GetInt )( + IBMDStreamingVideoEncodingMode * This, + /* [in] */ BMDStreamingEncodingModePropertyID cfgID, + /* [out] */ LONGLONG *value); + + HRESULT ( STDMETHODCALLTYPE *GetFloat )( + IBMDStreamingVideoEncodingMode * This, + /* [in] */ BMDStreamingEncodingModePropertyID cfgID, + /* [out] */ double *value); + + HRESULT ( STDMETHODCALLTYPE *GetString )( + IBMDStreamingVideoEncodingMode * This, + /* [in] */ BMDStreamingEncodingModePropertyID cfgID, + /* [out] */ BSTR *value); + + HRESULT ( STDMETHODCALLTYPE *CreateMutableVideoEncodingMode )( + IBMDStreamingVideoEncodingMode * This, + /* [out] */ IBMDStreamingMutableVideoEncodingMode **newEncodingMode); + + END_INTERFACE + } IBMDStreamingVideoEncodingModeVtbl; + + interface IBMDStreamingVideoEncodingMode + { + CONST_VTBL struct IBMDStreamingVideoEncodingModeVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IBMDStreamingVideoEncodingMode_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IBMDStreamingVideoEncodingMode_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IBMDStreamingVideoEncodingMode_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IBMDStreamingVideoEncodingMode_GetName(This,name) \ + ( (This)->lpVtbl -> GetName(This,name) ) + +#define IBMDStreamingVideoEncodingMode_GetPresetID(This) \ + ( (This)->lpVtbl -> GetPresetID(This) ) + +#define IBMDStreamingVideoEncodingMode_GetSourcePositionX(This) \ + ( (This)->lpVtbl -> GetSourcePositionX(This) ) + +#define IBMDStreamingVideoEncodingMode_GetSourcePositionY(This) \ + ( (This)->lpVtbl -> GetSourcePositionY(This) ) + +#define IBMDStreamingVideoEncodingMode_GetSourceWidth(This) \ + ( (This)->lpVtbl -> GetSourceWidth(This) ) + +#define IBMDStreamingVideoEncodingMode_GetSourceHeight(This) \ + ( (This)->lpVtbl -> GetSourceHeight(This) ) + +#define IBMDStreamingVideoEncodingMode_GetDestWidth(This) \ + ( (This)->lpVtbl -> GetDestWidth(This) ) + +#define IBMDStreamingVideoEncodingMode_GetDestHeight(This) \ + ( (This)->lpVtbl -> GetDestHeight(This) ) + +#define IBMDStreamingVideoEncodingMode_GetFlag(This,cfgID,value) \ + ( (This)->lpVtbl -> GetFlag(This,cfgID,value) ) + +#define IBMDStreamingVideoEncodingMode_GetInt(This,cfgID,value) \ + ( (This)->lpVtbl -> GetInt(This,cfgID,value) ) + +#define IBMDStreamingVideoEncodingMode_GetFloat(This,cfgID,value) \ + ( (This)->lpVtbl -> GetFloat(This,cfgID,value) ) + +#define IBMDStreamingVideoEncodingMode_GetString(This,cfgID,value) \ + ( (This)->lpVtbl -> GetString(This,cfgID,value) ) + +#define IBMDStreamingVideoEncodingMode_CreateMutableVideoEncodingMode(This,newEncodingMode) \ + ( (This)->lpVtbl -> CreateMutableVideoEncodingMode(This,newEncodingMode) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IBMDStreamingVideoEncodingMode_INTERFACE_DEFINED__ */ + + +#ifndef __IBMDStreamingMutableVideoEncodingMode_INTERFACE_DEFINED__ +#define __IBMDStreamingMutableVideoEncodingMode_INTERFACE_DEFINED__ + +/* interface IBMDStreamingMutableVideoEncodingMode */ +/* [helpstring][uuid][object] */ + + +EXTERN_C const IID IID_IBMDStreamingMutableVideoEncodingMode; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("19BF7D90-1E0A-400D-B2C6-FFC4E78AD49D") + IBMDStreamingMutableVideoEncodingMode : public IBMDStreamingVideoEncodingMode + { + public: + virtual HRESULT STDMETHODCALLTYPE SetSourceRect( + /* [in] */ unsigned int posX, + /* [in] */ unsigned int posY, + /* [in] */ unsigned int width, + /* [in] */ unsigned int height) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetDestSize( + /* [in] */ unsigned int width, + /* [in] */ unsigned int height) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetFlag( + /* [in] */ BMDStreamingEncodingModePropertyID cfgID, + /* [in] */ BOOL value) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetInt( + /* [in] */ BMDStreamingEncodingModePropertyID cfgID, + /* [in] */ LONGLONG value) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetFloat( + /* [in] */ BMDStreamingEncodingModePropertyID cfgID, + /* [in] */ double value) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetString( + /* [in] */ BMDStreamingEncodingModePropertyID cfgID, + /* [in] */ BSTR value) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IBMDStreamingMutableVideoEncodingModeVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IBMDStreamingMutableVideoEncodingMode * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IBMDStreamingMutableVideoEncodingMode * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IBMDStreamingMutableVideoEncodingMode * This); + + HRESULT ( STDMETHODCALLTYPE *GetName )( + IBMDStreamingMutableVideoEncodingMode * This, + /* [out] */ BSTR *name); + + unsigned int ( STDMETHODCALLTYPE *GetPresetID )( + IBMDStreamingMutableVideoEncodingMode * This); + + unsigned int ( STDMETHODCALLTYPE *GetSourcePositionX )( + IBMDStreamingMutableVideoEncodingMode * This); + + unsigned int ( STDMETHODCALLTYPE *GetSourcePositionY )( + IBMDStreamingMutableVideoEncodingMode * This); + + unsigned int ( STDMETHODCALLTYPE *GetSourceWidth )( + IBMDStreamingMutableVideoEncodingMode * This); + + unsigned int ( STDMETHODCALLTYPE *GetSourceHeight )( + IBMDStreamingMutableVideoEncodingMode * This); + + unsigned int ( STDMETHODCALLTYPE *GetDestWidth )( + IBMDStreamingMutableVideoEncodingMode * This); + + unsigned int ( STDMETHODCALLTYPE *GetDestHeight )( + IBMDStreamingMutableVideoEncodingMode * This); + + HRESULT ( STDMETHODCALLTYPE *GetFlag )( + IBMDStreamingMutableVideoEncodingMode * This, + /* [in] */ BMDStreamingEncodingModePropertyID cfgID, + /* [out] */ BOOL *value); + + HRESULT ( STDMETHODCALLTYPE *GetInt )( + IBMDStreamingMutableVideoEncodingMode * This, + /* [in] */ BMDStreamingEncodingModePropertyID cfgID, + /* [out] */ LONGLONG *value); + + HRESULT ( STDMETHODCALLTYPE *GetFloat )( + IBMDStreamingMutableVideoEncodingMode * This, + /* [in] */ BMDStreamingEncodingModePropertyID cfgID, + /* [out] */ double *value); + + HRESULT ( STDMETHODCALLTYPE *GetString )( + IBMDStreamingMutableVideoEncodingMode * This, + /* [in] */ BMDStreamingEncodingModePropertyID cfgID, + /* [out] */ BSTR *value); + + HRESULT ( STDMETHODCALLTYPE *CreateMutableVideoEncodingMode )( + IBMDStreamingMutableVideoEncodingMode * This, + /* [out] */ IBMDStreamingMutableVideoEncodingMode **newEncodingMode); + + HRESULT ( STDMETHODCALLTYPE *SetSourceRect )( + IBMDStreamingMutableVideoEncodingMode * This, + /* [in] */ unsigned int posX, + /* [in] */ unsigned int posY, + /* [in] */ unsigned int width, + /* [in] */ unsigned int height); + + HRESULT ( STDMETHODCALLTYPE *SetDestSize )( + IBMDStreamingMutableVideoEncodingMode * This, + /* [in] */ unsigned int width, + /* [in] */ unsigned int height); + + HRESULT ( STDMETHODCALLTYPE *SetFlag )( + IBMDStreamingMutableVideoEncodingMode * This, + /* [in] */ BMDStreamingEncodingModePropertyID cfgID, + /* [in] */ BOOL value); + + HRESULT ( STDMETHODCALLTYPE *SetInt )( + IBMDStreamingMutableVideoEncodingMode * This, + /* [in] */ BMDStreamingEncodingModePropertyID cfgID, + /* [in] */ LONGLONG value); + + HRESULT ( STDMETHODCALLTYPE *SetFloat )( + IBMDStreamingMutableVideoEncodingMode * This, + /* [in] */ BMDStreamingEncodingModePropertyID cfgID, + /* [in] */ double value); + + HRESULT ( STDMETHODCALLTYPE *SetString )( + IBMDStreamingMutableVideoEncodingMode * This, + /* [in] */ BMDStreamingEncodingModePropertyID cfgID, + /* [in] */ BSTR value); + + END_INTERFACE + } IBMDStreamingMutableVideoEncodingModeVtbl; + + interface IBMDStreamingMutableVideoEncodingMode + { + CONST_VTBL struct IBMDStreamingMutableVideoEncodingModeVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IBMDStreamingMutableVideoEncodingMode_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IBMDStreamingMutableVideoEncodingMode_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IBMDStreamingMutableVideoEncodingMode_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IBMDStreamingMutableVideoEncodingMode_GetName(This,name) \ + ( (This)->lpVtbl -> GetName(This,name) ) + +#define IBMDStreamingMutableVideoEncodingMode_GetPresetID(This) \ + ( (This)->lpVtbl -> GetPresetID(This) ) + +#define IBMDStreamingMutableVideoEncodingMode_GetSourcePositionX(This) \ + ( (This)->lpVtbl -> GetSourcePositionX(This) ) + +#define IBMDStreamingMutableVideoEncodingMode_GetSourcePositionY(This) \ + ( (This)->lpVtbl -> GetSourcePositionY(This) ) + +#define IBMDStreamingMutableVideoEncodingMode_GetSourceWidth(This) \ + ( (This)->lpVtbl -> GetSourceWidth(This) ) + +#define IBMDStreamingMutableVideoEncodingMode_GetSourceHeight(This) \ + ( (This)->lpVtbl -> GetSourceHeight(This) ) + +#define IBMDStreamingMutableVideoEncodingMode_GetDestWidth(This) \ + ( (This)->lpVtbl -> GetDestWidth(This) ) + +#define IBMDStreamingMutableVideoEncodingMode_GetDestHeight(This) \ + ( (This)->lpVtbl -> GetDestHeight(This) ) + +#define IBMDStreamingMutableVideoEncodingMode_GetFlag(This,cfgID,value) \ + ( (This)->lpVtbl -> GetFlag(This,cfgID,value) ) + +#define IBMDStreamingMutableVideoEncodingMode_GetInt(This,cfgID,value) \ + ( (This)->lpVtbl -> GetInt(This,cfgID,value) ) + +#define IBMDStreamingMutableVideoEncodingMode_GetFloat(This,cfgID,value) \ + ( (This)->lpVtbl -> GetFloat(This,cfgID,value) ) + +#define IBMDStreamingMutableVideoEncodingMode_GetString(This,cfgID,value) \ + ( (This)->lpVtbl -> GetString(This,cfgID,value) ) + +#define IBMDStreamingMutableVideoEncodingMode_CreateMutableVideoEncodingMode(This,newEncodingMode) \ + ( (This)->lpVtbl -> CreateMutableVideoEncodingMode(This,newEncodingMode) ) + + +#define IBMDStreamingMutableVideoEncodingMode_SetSourceRect(This,posX,posY,width,height) \ + ( (This)->lpVtbl -> SetSourceRect(This,posX,posY,width,height) ) + +#define IBMDStreamingMutableVideoEncodingMode_SetDestSize(This,width,height) \ + ( (This)->lpVtbl -> SetDestSize(This,width,height) ) + +#define IBMDStreamingMutableVideoEncodingMode_SetFlag(This,cfgID,value) \ + ( (This)->lpVtbl -> SetFlag(This,cfgID,value) ) + +#define IBMDStreamingMutableVideoEncodingMode_SetInt(This,cfgID,value) \ + ( (This)->lpVtbl -> SetInt(This,cfgID,value) ) + +#define IBMDStreamingMutableVideoEncodingMode_SetFloat(This,cfgID,value) \ + ( (This)->lpVtbl -> SetFloat(This,cfgID,value) ) + +#define IBMDStreamingMutableVideoEncodingMode_SetString(This,cfgID,value) \ + ( (This)->lpVtbl -> SetString(This,cfgID,value) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IBMDStreamingMutableVideoEncodingMode_INTERFACE_DEFINED__ */ + + +#ifndef __IBMDStreamingVideoEncodingModePresetIterator_INTERFACE_DEFINED__ +#define __IBMDStreamingVideoEncodingModePresetIterator_INTERFACE_DEFINED__ + +/* interface IBMDStreamingVideoEncodingModePresetIterator */ +/* [helpstring][uuid][object] */ + + +EXTERN_C const IID IID_IBMDStreamingVideoEncodingModePresetIterator; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("7AC731A3-C950-4AD0-804A-8377AA51C6C4") + IBMDStreamingVideoEncodingModePresetIterator : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE Next( + /* [out] */ IBMDStreamingVideoEncodingMode **videoEncodingMode) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IBMDStreamingVideoEncodingModePresetIteratorVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IBMDStreamingVideoEncodingModePresetIterator * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IBMDStreamingVideoEncodingModePresetIterator * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IBMDStreamingVideoEncodingModePresetIterator * This); + + HRESULT ( STDMETHODCALLTYPE *Next )( + IBMDStreamingVideoEncodingModePresetIterator * This, + /* [out] */ IBMDStreamingVideoEncodingMode **videoEncodingMode); + + END_INTERFACE + } IBMDStreamingVideoEncodingModePresetIteratorVtbl; + + interface IBMDStreamingVideoEncodingModePresetIterator + { + CONST_VTBL struct IBMDStreamingVideoEncodingModePresetIteratorVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IBMDStreamingVideoEncodingModePresetIterator_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IBMDStreamingVideoEncodingModePresetIterator_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IBMDStreamingVideoEncodingModePresetIterator_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IBMDStreamingVideoEncodingModePresetIterator_Next(This,videoEncodingMode) \ + ( (This)->lpVtbl -> Next(This,videoEncodingMode) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IBMDStreamingVideoEncodingModePresetIterator_INTERFACE_DEFINED__ */ + + +#ifndef __IBMDStreamingDeviceInput_INTERFACE_DEFINED__ +#define __IBMDStreamingDeviceInput_INTERFACE_DEFINED__ + +/* interface IBMDStreamingDeviceInput */ +/* [helpstring][uuid][object] */ + + +EXTERN_C const IID IID_IBMDStreamingDeviceInput; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("24B6B6EC-1727-44BB-9818-34FF086ACF98") + IBMDStreamingDeviceInput : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE DoesSupportVideoInputMode( + /* [in] */ BMDDisplayMode inputMode, + /* [out] */ BOOL *result) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetVideoInputModeIterator( + /* [out] */ IDeckLinkDisplayModeIterator **iterator) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetVideoInputMode( + /* [in] */ BMDDisplayMode inputMode) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetCurrentDetectedVideoInputMode( + /* [out] */ BMDDisplayMode *detectedMode) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetVideoEncodingMode( + /* [out] */ IBMDStreamingVideoEncodingMode **encodingMode) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetVideoEncodingModePresetIterator( + /* [in] */ BMDDisplayMode inputMode, + /* [out] */ IBMDStreamingVideoEncodingModePresetIterator **iterator) = 0; + + virtual HRESULT STDMETHODCALLTYPE DoesSupportVideoEncodingMode( + /* [in] */ BMDDisplayMode inputMode, + /* [in] */ IBMDStreamingVideoEncodingMode *encodingMode, + /* [out] */ BMDStreamingEncodingSupport *result, + /* [out] */ IBMDStreamingVideoEncodingMode **changedEncodingMode) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetVideoEncodingMode( + /* [in] */ IBMDStreamingVideoEncodingMode *encodingMode) = 0; + + virtual HRESULT STDMETHODCALLTYPE StartCapture( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE StopCapture( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetCallback( + /* [in] */ IUnknown *theCallback) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IBMDStreamingDeviceInputVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IBMDStreamingDeviceInput * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IBMDStreamingDeviceInput * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IBMDStreamingDeviceInput * This); + + HRESULT ( STDMETHODCALLTYPE *DoesSupportVideoInputMode )( + IBMDStreamingDeviceInput * This, + /* [in] */ BMDDisplayMode inputMode, + /* [out] */ BOOL *result); + + HRESULT ( STDMETHODCALLTYPE *GetVideoInputModeIterator )( + IBMDStreamingDeviceInput * This, + /* [out] */ IDeckLinkDisplayModeIterator **iterator); + + HRESULT ( STDMETHODCALLTYPE *SetVideoInputMode )( + IBMDStreamingDeviceInput * This, + /* [in] */ BMDDisplayMode inputMode); + + HRESULT ( STDMETHODCALLTYPE *GetCurrentDetectedVideoInputMode )( + IBMDStreamingDeviceInput * This, + /* [out] */ BMDDisplayMode *detectedMode); + + HRESULT ( STDMETHODCALLTYPE *GetVideoEncodingMode )( + IBMDStreamingDeviceInput * This, + /* [out] */ IBMDStreamingVideoEncodingMode **encodingMode); + + HRESULT ( STDMETHODCALLTYPE *GetVideoEncodingModePresetIterator )( + IBMDStreamingDeviceInput * This, + /* [in] */ BMDDisplayMode inputMode, + /* [out] */ IBMDStreamingVideoEncodingModePresetIterator **iterator); + + HRESULT ( STDMETHODCALLTYPE *DoesSupportVideoEncodingMode )( + IBMDStreamingDeviceInput * This, + /* [in] */ BMDDisplayMode inputMode, + /* [in] */ IBMDStreamingVideoEncodingMode *encodingMode, + /* [out] */ BMDStreamingEncodingSupport *result, + /* [out] */ IBMDStreamingVideoEncodingMode **changedEncodingMode); + + HRESULT ( STDMETHODCALLTYPE *SetVideoEncodingMode )( + IBMDStreamingDeviceInput * This, + /* [in] */ IBMDStreamingVideoEncodingMode *encodingMode); + + HRESULT ( STDMETHODCALLTYPE *StartCapture )( + IBMDStreamingDeviceInput * This); + + HRESULT ( STDMETHODCALLTYPE *StopCapture )( + IBMDStreamingDeviceInput * This); + + HRESULT ( STDMETHODCALLTYPE *SetCallback )( + IBMDStreamingDeviceInput * This, + /* [in] */ IUnknown *theCallback); + + END_INTERFACE + } IBMDStreamingDeviceInputVtbl; + + interface IBMDStreamingDeviceInput + { + CONST_VTBL struct IBMDStreamingDeviceInputVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IBMDStreamingDeviceInput_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IBMDStreamingDeviceInput_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IBMDStreamingDeviceInput_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IBMDStreamingDeviceInput_DoesSupportVideoInputMode(This,inputMode,result) \ + ( (This)->lpVtbl -> DoesSupportVideoInputMode(This,inputMode,result) ) + +#define IBMDStreamingDeviceInput_GetVideoInputModeIterator(This,iterator) \ + ( (This)->lpVtbl -> GetVideoInputModeIterator(This,iterator) ) + +#define IBMDStreamingDeviceInput_SetVideoInputMode(This,inputMode) \ + ( (This)->lpVtbl -> SetVideoInputMode(This,inputMode) ) + +#define IBMDStreamingDeviceInput_GetCurrentDetectedVideoInputMode(This,detectedMode) \ + ( (This)->lpVtbl -> GetCurrentDetectedVideoInputMode(This,detectedMode) ) + +#define IBMDStreamingDeviceInput_GetVideoEncodingMode(This,encodingMode) \ + ( (This)->lpVtbl -> GetVideoEncodingMode(This,encodingMode) ) + +#define IBMDStreamingDeviceInput_GetVideoEncodingModePresetIterator(This,inputMode,iterator) \ + ( (This)->lpVtbl -> GetVideoEncodingModePresetIterator(This,inputMode,iterator) ) + +#define IBMDStreamingDeviceInput_DoesSupportVideoEncodingMode(This,inputMode,encodingMode,result,changedEncodingMode) \ + ( (This)->lpVtbl -> DoesSupportVideoEncodingMode(This,inputMode,encodingMode,result,changedEncodingMode) ) + +#define IBMDStreamingDeviceInput_SetVideoEncodingMode(This,encodingMode) \ + ( (This)->lpVtbl -> SetVideoEncodingMode(This,encodingMode) ) + +#define IBMDStreamingDeviceInput_StartCapture(This) \ + ( (This)->lpVtbl -> StartCapture(This) ) + +#define IBMDStreamingDeviceInput_StopCapture(This) \ + ( (This)->lpVtbl -> StopCapture(This) ) + +#define IBMDStreamingDeviceInput_SetCallback(This,theCallback) \ + ( (This)->lpVtbl -> SetCallback(This,theCallback) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IBMDStreamingDeviceInput_INTERFACE_DEFINED__ */ + + +#ifndef __IBMDStreamingH264NALPacket_INTERFACE_DEFINED__ +#define __IBMDStreamingH264NALPacket_INTERFACE_DEFINED__ + +/* interface IBMDStreamingH264NALPacket */ +/* [helpstring][uuid][object] */ + + +EXTERN_C const IID IID_IBMDStreamingH264NALPacket; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("E260E955-14BE-4395-9775-9F02CC0A9D89") + IBMDStreamingH264NALPacket : public IUnknown + { + public: + virtual long STDMETHODCALLTYPE GetPayloadSize( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetBytes( + /* [out] */ void **buffer) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetBytesWithSizePrefix( + /* [out] */ void **buffer) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetDisplayTime( + /* [in] */ ULONGLONG requestedTimeScale, + /* [out] */ ULONGLONG *displayTime) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetPacketIndex( + /* [out] */ unsigned int *packetIndex) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IBMDStreamingH264NALPacketVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IBMDStreamingH264NALPacket * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IBMDStreamingH264NALPacket * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IBMDStreamingH264NALPacket * This); + + long ( STDMETHODCALLTYPE *GetPayloadSize )( + IBMDStreamingH264NALPacket * This); + + HRESULT ( STDMETHODCALLTYPE *GetBytes )( + IBMDStreamingH264NALPacket * This, + /* [out] */ void **buffer); + + HRESULT ( STDMETHODCALLTYPE *GetBytesWithSizePrefix )( + IBMDStreamingH264NALPacket * This, + /* [out] */ void **buffer); + + HRESULT ( STDMETHODCALLTYPE *GetDisplayTime )( + IBMDStreamingH264NALPacket * This, + /* [in] */ ULONGLONG requestedTimeScale, + /* [out] */ ULONGLONG *displayTime); + + HRESULT ( STDMETHODCALLTYPE *GetPacketIndex )( + IBMDStreamingH264NALPacket * This, + /* [out] */ unsigned int *packetIndex); + + END_INTERFACE + } IBMDStreamingH264NALPacketVtbl; + + interface IBMDStreamingH264NALPacket + { + CONST_VTBL struct IBMDStreamingH264NALPacketVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IBMDStreamingH264NALPacket_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IBMDStreamingH264NALPacket_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IBMDStreamingH264NALPacket_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IBMDStreamingH264NALPacket_GetPayloadSize(This) \ + ( (This)->lpVtbl -> GetPayloadSize(This) ) + +#define IBMDStreamingH264NALPacket_GetBytes(This,buffer) \ + ( (This)->lpVtbl -> GetBytes(This,buffer) ) + +#define IBMDStreamingH264NALPacket_GetBytesWithSizePrefix(This,buffer) \ + ( (This)->lpVtbl -> GetBytesWithSizePrefix(This,buffer) ) + +#define IBMDStreamingH264NALPacket_GetDisplayTime(This,requestedTimeScale,displayTime) \ + ( (This)->lpVtbl -> GetDisplayTime(This,requestedTimeScale,displayTime) ) + +#define IBMDStreamingH264NALPacket_GetPacketIndex(This,packetIndex) \ + ( (This)->lpVtbl -> GetPacketIndex(This,packetIndex) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IBMDStreamingH264NALPacket_INTERFACE_DEFINED__ */ + + +#ifndef __IBMDStreamingAudioPacket_INTERFACE_DEFINED__ +#define __IBMDStreamingAudioPacket_INTERFACE_DEFINED__ + +/* interface IBMDStreamingAudioPacket */ +/* [helpstring][uuid][object] */ + + +EXTERN_C const IID IID_IBMDStreamingAudioPacket; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("D9EB5902-1AD2-43F4-9E2C-3CFA50B5EE19") + IBMDStreamingAudioPacket : public IUnknown + { + public: + virtual BMDStreamingAudioCodec STDMETHODCALLTYPE GetCodec( void) = 0; + + virtual long STDMETHODCALLTYPE GetPayloadSize( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetBytes( + /* [out] */ void **buffer) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetPlayTime( + /* [in] */ ULONGLONG requestedTimeScale, + /* [out] */ ULONGLONG *playTime) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetPacketIndex( + /* [out] */ unsigned int *packetIndex) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IBMDStreamingAudioPacketVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IBMDStreamingAudioPacket * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IBMDStreamingAudioPacket * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IBMDStreamingAudioPacket * This); + + BMDStreamingAudioCodec ( STDMETHODCALLTYPE *GetCodec )( + IBMDStreamingAudioPacket * This); + + long ( STDMETHODCALLTYPE *GetPayloadSize )( + IBMDStreamingAudioPacket * This); + + HRESULT ( STDMETHODCALLTYPE *GetBytes )( + IBMDStreamingAudioPacket * This, + /* [out] */ void **buffer); + + HRESULT ( STDMETHODCALLTYPE *GetPlayTime )( + IBMDStreamingAudioPacket * This, + /* [in] */ ULONGLONG requestedTimeScale, + /* [out] */ ULONGLONG *playTime); + + HRESULT ( STDMETHODCALLTYPE *GetPacketIndex )( + IBMDStreamingAudioPacket * This, + /* [out] */ unsigned int *packetIndex); + + END_INTERFACE + } IBMDStreamingAudioPacketVtbl; + + interface IBMDStreamingAudioPacket + { + CONST_VTBL struct IBMDStreamingAudioPacketVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IBMDStreamingAudioPacket_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IBMDStreamingAudioPacket_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IBMDStreamingAudioPacket_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IBMDStreamingAudioPacket_GetCodec(This) \ + ( (This)->lpVtbl -> GetCodec(This) ) + +#define IBMDStreamingAudioPacket_GetPayloadSize(This) \ + ( (This)->lpVtbl -> GetPayloadSize(This) ) + +#define IBMDStreamingAudioPacket_GetBytes(This,buffer) \ + ( (This)->lpVtbl -> GetBytes(This,buffer) ) + +#define IBMDStreamingAudioPacket_GetPlayTime(This,requestedTimeScale,playTime) \ + ( (This)->lpVtbl -> GetPlayTime(This,requestedTimeScale,playTime) ) + +#define IBMDStreamingAudioPacket_GetPacketIndex(This,packetIndex) \ + ( (This)->lpVtbl -> GetPacketIndex(This,packetIndex) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IBMDStreamingAudioPacket_INTERFACE_DEFINED__ */ + + +#ifndef __IBMDStreamingMPEG2TSPacket_INTERFACE_DEFINED__ +#define __IBMDStreamingMPEG2TSPacket_INTERFACE_DEFINED__ + +/* interface IBMDStreamingMPEG2TSPacket */ +/* [helpstring][uuid][object] */ + + +EXTERN_C const IID IID_IBMDStreamingMPEG2TSPacket; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("91810D1C-4FB3-4AAA-AE56-FA301D3DFA4C") + IBMDStreamingMPEG2TSPacket : public IUnknown + { + public: + virtual long STDMETHODCALLTYPE GetPayloadSize( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetBytes( + /* [out] */ void **buffer) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IBMDStreamingMPEG2TSPacketVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IBMDStreamingMPEG2TSPacket * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IBMDStreamingMPEG2TSPacket * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IBMDStreamingMPEG2TSPacket * This); + + long ( STDMETHODCALLTYPE *GetPayloadSize )( + IBMDStreamingMPEG2TSPacket * This); + + HRESULT ( STDMETHODCALLTYPE *GetBytes )( + IBMDStreamingMPEG2TSPacket * This, + /* [out] */ void **buffer); + + END_INTERFACE + } IBMDStreamingMPEG2TSPacketVtbl; + + interface IBMDStreamingMPEG2TSPacket + { + CONST_VTBL struct IBMDStreamingMPEG2TSPacketVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IBMDStreamingMPEG2TSPacket_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IBMDStreamingMPEG2TSPacket_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IBMDStreamingMPEG2TSPacket_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IBMDStreamingMPEG2TSPacket_GetPayloadSize(This) \ + ( (This)->lpVtbl -> GetPayloadSize(This) ) + +#define IBMDStreamingMPEG2TSPacket_GetBytes(This,buffer) \ + ( (This)->lpVtbl -> GetBytes(This,buffer) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IBMDStreamingMPEG2TSPacket_INTERFACE_DEFINED__ */ + + +#ifndef __IBMDStreamingH264NALParser_INTERFACE_DEFINED__ +#define __IBMDStreamingH264NALParser_INTERFACE_DEFINED__ + +/* interface IBMDStreamingH264NALParser */ +/* [helpstring][uuid][object] */ + + +EXTERN_C const IID IID_IBMDStreamingH264NALParser; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("5867F18C-5BFA-4CCC-B2A7-9DFD140417D2") + IBMDStreamingH264NALParser : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE IsNALSequenceParameterSet( + /* [in] */ IBMDStreamingH264NALPacket *nal) = 0; + + virtual HRESULT STDMETHODCALLTYPE IsNALPictureParameterSet( + /* [in] */ IBMDStreamingH264NALPacket *nal) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetProfileAndLevelFromSPS( + /* [in] */ IBMDStreamingH264NALPacket *nal, + /* [out] */ unsigned int *profileIdc, + /* [out] */ unsigned int *profileCompatability, + /* [out] */ unsigned int *levelIdc) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IBMDStreamingH264NALParserVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IBMDStreamingH264NALParser * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IBMDStreamingH264NALParser * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IBMDStreamingH264NALParser * This); + + HRESULT ( STDMETHODCALLTYPE *IsNALSequenceParameterSet )( + IBMDStreamingH264NALParser * This, + /* [in] */ IBMDStreamingH264NALPacket *nal); + + HRESULT ( STDMETHODCALLTYPE *IsNALPictureParameterSet )( + IBMDStreamingH264NALParser * This, + /* [in] */ IBMDStreamingH264NALPacket *nal); + + HRESULT ( STDMETHODCALLTYPE *GetProfileAndLevelFromSPS )( + IBMDStreamingH264NALParser * This, + /* [in] */ IBMDStreamingH264NALPacket *nal, + /* [out] */ unsigned int *profileIdc, + /* [out] */ unsigned int *profileCompatability, + /* [out] */ unsigned int *levelIdc); + + END_INTERFACE + } IBMDStreamingH264NALParserVtbl; + + interface IBMDStreamingH264NALParser + { + CONST_VTBL struct IBMDStreamingH264NALParserVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IBMDStreamingH264NALParser_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IBMDStreamingH264NALParser_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IBMDStreamingH264NALParser_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IBMDStreamingH264NALParser_IsNALSequenceParameterSet(This,nal) \ + ( (This)->lpVtbl -> IsNALSequenceParameterSet(This,nal) ) + +#define IBMDStreamingH264NALParser_IsNALPictureParameterSet(This,nal) \ + ( (This)->lpVtbl -> IsNALPictureParameterSet(This,nal) ) + +#define IBMDStreamingH264NALParser_GetProfileAndLevelFromSPS(This,nal,profileIdc,profileCompatability,levelIdc) \ + ( (This)->lpVtbl -> GetProfileAndLevelFromSPS(This,nal,profileIdc,profileCompatability,levelIdc) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IBMDStreamingH264NALParser_INTERFACE_DEFINED__ */ + + +EXTERN_C const CLSID CLSID_CBMDStreamingDiscovery; + +#ifdef __cplusplus + +class DECLSPEC_UUID("0CAA31F6-8A26-40B0-86A4-BF58DCCA710C") +CBMDStreamingDiscovery; +#endif + +EXTERN_C const CLSID CLSID_CBMDStreamingH264NALParser; + +#ifdef __cplusplus + +class DECLSPEC_UUID("7753EFBD-951C-407C-97A5-23C737B73B52") +CBMDStreamingH264NALParser; +#endif + +#ifndef __IDeckLinkVideoOutputCallback_INTERFACE_DEFINED__ +#define __IDeckLinkVideoOutputCallback_INTERFACE_DEFINED__ + +/* interface IDeckLinkVideoOutputCallback */ +/* [helpstring][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkVideoOutputCallback; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("20AA5225-1958-47CB-820B-80A8D521A6EE") + IDeckLinkVideoOutputCallback : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE ScheduledFrameCompleted( + /* [in] */ IDeckLinkVideoFrame *completedFrame, + /* [in] */ BMDOutputFrameCompletionResult result) = 0; + + virtual HRESULT STDMETHODCALLTYPE ScheduledPlaybackHasStopped( void) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkVideoOutputCallbackVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkVideoOutputCallback * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkVideoOutputCallback * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkVideoOutputCallback * This); + + HRESULT ( STDMETHODCALLTYPE *ScheduledFrameCompleted )( + IDeckLinkVideoOutputCallback * This, + /* [in] */ IDeckLinkVideoFrame *completedFrame, + /* [in] */ BMDOutputFrameCompletionResult result); + + HRESULT ( STDMETHODCALLTYPE *ScheduledPlaybackHasStopped )( + IDeckLinkVideoOutputCallback * This); + + END_INTERFACE + } IDeckLinkVideoOutputCallbackVtbl; + + interface IDeckLinkVideoOutputCallback + { + CONST_VTBL struct IDeckLinkVideoOutputCallbackVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkVideoOutputCallback_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkVideoOutputCallback_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkVideoOutputCallback_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkVideoOutputCallback_ScheduledFrameCompleted(This,completedFrame,result) \ + ( (This)->lpVtbl -> ScheduledFrameCompleted(This,completedFrame,result) ) + +#define IDeckLinkVideoOutputCallback_ScheduledPlaybackHasStopped(This) \ + ( (This)->lpVtbl -> ScheduledPlaybackHasStopped(This) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkVideoOutputCallback_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkInputCallback_INTERFACE_DEFINED__ +#define __IDeckLinkInputCallback_INTERFACE_DEFINED__ + +/* interface IDeckLinkInputCallback */ +/* [helpstring][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkInputCallback; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("DD04E5EC-7415-42AB-AE4A-E80C4DFC044A") + IDeckLinkInputCallback : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE VideoInputFormatChanged( + /* [in] */ BMDVideoInputFormatChangedEvents notificationEvents, + /* [in] */ IDeckLinkDisplayMode *newDisplayMode, + /* [in] */ BMDDetectedVideoInputFormatFlags detectedSignalFlags) = 0; + + virtual HRESULT STDMETHODCALLTYPE VideoInputFrameArrived( + /* [in] */ IDeckLinkVideoInputFrame *videoFrame, + /* [in] */ IDeckLinkAudioInputPacket *audioPacket) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkInputCallbackVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkInputCallback * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkInputCallback * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkInputCallback * This); + + HRESULT ( STDMETHODCALLTYPE *VideoInputFormatChanged )( + IDeckLinkInputCallback * This, + /* [in] */ BMDVideoInputFormatChangedEvents notificationEvents, + /* [in] */ IDeckLinkDisplayMode *newDisplayMode, + /* [in] */ BMDDetectedVideoInputFormatFlags detectedSignalFlags); + + HRESULT ( STDMETHODCALLTYPE *VideoInputFrameArrived )( + IDeckLinkInputCallback * This, + /* [in] */ IDeckLinkVideoInputFrame *videoFrame, + /* [in] */ IDeckLinkAudioInputPacket *audioPacket); + + END_INTERFACE + } IDeckLinkInputCallbackVtbl; + + interface IDeckLinkInputCallback + { + CONST_VTBL struct IDeckLinkInputCallbackVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkInputCallback_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkInputCallback_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkInputCallback_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkInputCallback_VideoInputFormatChanged(This,notificationEvents,newDisplayMode,detectedSignalFlags) \ + ( (This)->lpVtbl -> VideoInputFormatChanged(This,notificationEvents,newDisplayMode,detectedSignalFlags) ) + +#define IDeckLinkInputCallback_VideoInputFrameArrived(This,videoFrame,audioPacket) \ + ( (This)->lpVtbl -> VideoInputFrameArrived(This,videoFrame,audioPacket) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkInputCallback_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkMemoryAllocator_INTERFACE_DEFINED__ +#define __IDeckLinkMemoryAllocator_INTERFACE_DEFINED__ + +/* interface IDeckLinkMemoryAllocator */ +/* [helpstring][local][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkMemoryAllocator; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("B36EB6E7-9D29-4AA8-92EF-843B87A289E8") + IDeckLinkMemoryAllocator : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE AllocateBuffer( + /* [in] */ unsigned int bufferSize, + /* [out] */ void **allocatedBuffer) = 0; + + virtual HRESULT STDMETHODCALLTYPE ReleaseBuffer( + /* [in] */ void *buffer) = 0; + + virtual HRESULT STDMETHODCALLTYPE Commit( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE Decommit( void) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkMemoryAllocatorVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkMemoryAllocator * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkMemoryAllocator * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkMemoryAllocator * This); + + HRESULT ( STDMETHODCALLTYPE *AllocateBuffer )( + IDeckLinkMemoryAllocator * This, + /* [in] */ unsigned int bufferSize, + /* [out] */ void **allocatedBuffer); + + HRESULT ( STDMETHODCALLTYPE *ReleaseBuffer )( + IDeckLinkMemoryAllocator * This, + /* [in] */ void *buffer); + + HRESULT ( STDMETHODCALLTYPE *Commit )( + IDeckLinkMemoryAllocator * This); + + HRESULT ( STDMETHODCALLTYPE *Decommit )( + IDeckLinkMemoryAllocator * This); + + END_INTERFACE + } IDeckLinkMemoryAllocatorVtbl; + + interface IDeckLinkMemoryAllocator + { + CONST_VTBL struct IDeckLinkMemoryAllocatorVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkMemoryAllocator_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkMemoryAllocator_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkMemoryAllocator_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkMemoryAllocator_AllocateBuffer(This,bufferSize,allocatedBuffer) \ + ( (This)->lpVtbl -> AllocateBuffer(This,bufferSize,allocatedBuffer) ) + +#define IDeckLinkMemoryAllocator_ReleaseBuffer(This,buffer) \ + ( (This)->lpVtbl -> ReleaseBuffer(This,buffer) ) + +#define IDeckLinkMemoryAllocator_Commit(This) \ + ( (This)->lpVtbl -> Commit(This) ) + +#define IDeckLinkMemoryAllocator_Decommit(This) \ + ( (This)->lpVtbl -> Decommit(This) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkMemoryAllocator_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkAudioOutputCallback_INTERFACE_DEFINED__ +#define __IDeckLinkAudioOutputCallback_INTERFACE_DEFINED__ + +/* interface IDeckLinkAudioOutputCallback */ +/* [helpstring][local][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkAudioOutputCallback; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("403C681B-7F46-4A12-B993-2BB127084EE6") + IDeckLinkAudioOutputCallback : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE RenderAudioSamples( + /* [in] */ BOOL preroll) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkAudioOutputCallbackVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkAudioOutputCallback * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkAudioOutputCallback * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkAudioOutputCallback * This); + + HRESULT ( STDMETHODCALLTYPE *RenderAudioSamples )( + IDeckLinkAudioOutputCallback * This, + /* [in] */ BOOL preroll); + + END_INTERFACE + } IDeckLinkAudioOutputCallbackVtbl; + + interface IDeckLinkAudioOutputCallback + { + CONST_VTBL struct IDeckLinkAudioOutputCallbackVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkAudioOutputCallback_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkAudioOutputCallback_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkAudioOutputCallback_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkAudioOutputCallback_RenderAudioSamples(This,preroll) \ + ( (This)->lpVtbl -> RenderAudioSamples(This,preroll) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkAudioOutputCallback_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkIterator_INTERFACE_DEFINED__ +#define __IDeckLinkIterator_INTERFACE_DEFINED__ + +/* interface IDeckLinkIterator */ +/* [helpstring][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkIterator; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("50FB36CD-3063-4B73-BDBB-958087F2D8BA") + IDeckLinkIterator : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE Next( + /* [out] */ IDeckLink **deckLinkInstance) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkIteratorVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkIterator * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkIterator * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkIterator * This); + + HRESULT ( STDMETHODCALLTYPE *Next )( + IDeckLinkIterator * This, + /* [out] */ IDeckLink **deckLinkInstance); + + END_INTERFACE + } IDeckLinkIteratorVtbl; + + interface IDeckLinkIterator + { + CONST_VTBL struct IDeckLinkIteratorVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkIterator_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkIterator_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkIterator_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkIterator_Next(This,deckLinkInstance) \ + ( (This)->lpVtbl -> Next(This,deckLinkInstance) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkIterator_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkAPIInformation_INTERFACE_DEFINED__ +#define __IDeckLinkAPIInformation_INTERFACE_DEFINED__ + +/* interface IDeckLinkAPIInformation */ +/* [helpstring][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkAPIInformation; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("7BEA3C68-730D-4322-AF34-8A7152B532A4") + IDeckLinkAPIInformation : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE GetFlag( + /* [in] */ BMDDeckLinkAPIInformationID cfgID, + /* [out] */ BOOL *value) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetInt( + /* [in] */ BMDDeckLinkAPIInformationID cfgID, + /* [out] */ LONGLONG *value) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetFloat( + /* [in] */ BMDDeckLinkAPIInformationID cfgID, + /* [out] */ double *value) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetString( + /* [in] */ BMDDeckLinkAPIInformationID cfgID, + /* [out] */ BSTR *value) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkAPIInformationVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkAPIInformation * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkAPIInformation * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkAPIInformation * This); + + HRESULT ( STDMETHODCALLTYPE *GetFlag )( + IDeckLinkAPIInformation * This, + /* [in] */ BMDDeckLinkAPIInformationID cfgID, + /* [out] */ BOOL *value); + + HRESULT ( STDMETHODCALLTYPE *GetInt )( + IDeckLinkAPIInformation * This, + /* [in] */ BMDDeckLinkAPIInformationID cfgID, + /* [out] */ LONGLONG *value); + + HRESULT ( STDMETHODCALLTYPE *GetFloat )( + IDeckLinkAPIInformation * This, + /* [in] */ BMDDeckLinkAPIInformationID cfgID, + /* [out] */ double *value); + + HRESULT ( STDMETHODCALLTYPE *GetString )( + IDeckLinkAPIInformation * This, + /* [in] */ BMDDeckLinkAPIInformationID cfgID, + /* [out] */ BSTR *value); + + END_INTERFACE + } IDeckLinkAPIInformationVtbl; + + interface IDeckLinkAPIInformation + { + CONST_VTBL struct IDeckLinkAPIInformationVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkAPIInformation_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkAPIInformation_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkAPIInformation_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkAPIInformation_GetFlag(This,cfgID,value) \ + ( (This)->lpVtbl -> GetFlag(This,cfgID,value) ) + +#define IDeckLinkAPIInformation_GetInt(This,cfgID,value) \ + ( (This)->lpVtbl -> GetInt(This,cfgID,value) ) + +#define IDeckLinkAPIInformation_GetFloat(This,cfgID,value) \ + ( (This)->lpVtbl -> GetFloat(This,cfgID,value) ) + +#define IDeckLinkAPIInformation_GetString(This,cfgID,value) \ + ( (This)->lpVtbl -> GetString(This,cfgID,value) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkAPIInformation_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkOutput_INTERFACE_DEFINED__ +#define __IDeckLinkOutput_INTERFACE_DEFINED__ + +/* interface IDeckLinkOutput */ +/* [helpstring][local][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkOutput; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("CC5C8A6E-3F2F-4B3A-87EA-FD78AF300564") + IDeckLinkOutput : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE DoesSupportVideoMode( + /* [in] */ BMDDisplayMode displayMode, + /* [in] */ BMDPixelFormat pixelFormat, + /* [in] */ BMDVideoOutputFlags flags, + /* [out] */ BMDDisplayModeSupport *result, + /* [out] */ IDeckLinkDisplayMode **resultDisplayMode) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetDisplayModeIterator( + /* [out] */ IDeckLinkDisplayModeIterator **iterator) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetScreenPreviewCallback( + /* [in] */ IDeckLinkScreenPreviewCallback *previewCallback) = 0; + + virtual HRESULT STDMETHODCALLTYPE EnableVideoOutput( + /* [in] */ BMDDisplayMode displayMode, + /* [in] */ BMDVideoOutputFlags flags) = 0; + + virtual HRESULT STDMETHODCALLTYPE DisableVideoOutput( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetVideoOutputFrameMemoryAllocator( + /* [in] */ IDeckLinkMemoryAllocator *theAllocator) = 0; + + virtual HRESULT STDMETHODCALLTYPE CreateVideoFrame( + /* [in] */ int width, + /* [in] */ int height, + /* [in] */ int rowBytes, + /* [in] */ BMDPixelFormat pixelFormat, + /* [in] */ BMDFrameFlags flags, + /* [out] */ IDeckLinkMutableVideoFrame **outFrame) = 0; + + virtual HRESULT STDMETHODCALLTYPE CreateAncillaryData( + /* [in] */ BMDPixelFormat pixelFormat, + /* [out] */ IDeckLinkVideoFrameAncillary **outBuffer) = 0; + + virtual HRESULT STDMETHODCALLTYPE DisplayVideoFrameSync( + /* [in] */ IDeckLinkVideoFrame *theFrame) = 0; + + virtual HRESULT STDMETHODCALLTYPE ScheduleVideoFrame( + /* [in] */ IDeckLinkVideoFrame *theFrame, + /* [in] */ BMDTimeValue displayTime, + /* [in] */ BMDTimeValue displayDuration, + /* [in] */ BMDTimeScale timeScale) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetScheduledFrameCompletionCallback( + /* [in] */ IDeckLinkVideoOutputCallback *theCallback) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetBufferedVideoFrameCount( + /* [out] */ unsigned int *bufferedFrameCount) = 0; + + virtual HRESULT STDMETHODCALLTYPE EnableAudioOutput( + /* [in] */ BMDAudioSampleRate sampleRate, + /* [in] */ BMDAudioSampleType sampleType, + /* [in] */ unsigned int channelCount, + /* [in] */ BMDAudioOutputStreamType streamType) = 0; + + virtual HRESULT STDMETHODCALLTYPE DisableAudioOutput( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE WriteAudioSamplesSync( + /* [in] */ void *buffer, + /* [in] */ unsigned int sampleFrameCount, + /* [out] */ unsigned int *sampleFramesWritten) = 0; + + virtual HRESULT STDMETHODCALLTYPE BeginAudioPreroll( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE EndAudioPreroll( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE ScheduleAudioSamples( + /* [in] */ void *buffer, + /* [in] */ unsigned int sampleFrameCount, + /* [in] */ BMDTimeValue streamTime, + /* [in] */ BMDTimeScale timeScale, + /* [out] */ unsigned int *sampleFramesWritten) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetBufferedAudioSampleFrameCount( + /* [out] */ unsigned int *bufferedSampleFrameCount) = 0; + + virtual HRESULT STDMETHODCALLTYPE FlushBufferedAudioSamples( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetAudioCallback( + /* [in] */ IDeckLinkAudioOutputCallback *theCallback) = 0; + + virtual HRESULT STDMETHODCALLTYPE StartScheduledPlayback( + /* [in] */ BMDTimeValue playbackStartTime, + /* [in] */ BMDTimeScale timeScale, + /* [in] */ double playbackSpeed) = 0; + + virtual HRESULT STDMETHODCALLTYPE StopScheduledPlayback( + /* [in] */ BMDTimeValue stopPlaybackAtTime, + /* [out] */ BMDTimeValue *actualStopTime, + /* [in] */ BMDTimeScale timeScale) = 0; + + virtual HRESULT STDMETHODCALLTYPE IsScheduledPlaybackRunning( + /* [out] */ BOOL *active) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetScheduledStreamTime( + /* [in] */ BMDTimeScale desiredTimeScale, + /* [out] */ BMDTimeValue *streamTime, + /* [out] */ double *playbackSpeed) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetReferenceStatus( + /* [out] */ BMDReferenceStatus *referenceStatus) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetHardwareReferenceClock( + /* [in] */ BMDTimeScale desiredTimeScale, + /* [out] */ BMDTimeValue *hardwareTime, + /* [out] */ BMDTimeValue *timeInFrame, + /* [out] */ BMDTimeValue *ticksPerFrame) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetFrameCompletionReferenceTimestamp( + /* [in] */ IDeckLinkVideoFrame *theFrame, + /* [in] */ BMDTimeScale desiredTimeScale, + /* [out] */ BMDTimeValue *frameCompletionTimestamp) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkOutputVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkOutput * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkOutput * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkOutput * This); + + HRESULT ( STDMETHODCALLTYPE *DoesSupportVideoMode )( + IDeckLinkOutput * This, + /* [in] */ BMDDisplayMode displayMode, + /* [in] */ BMDPixelFormat pixelFormat, + /* [in] */ BMDVideoOutputFlags flags, + /* [out] */ BMDDisplayModeSupport *result, + /* [out] */ IDeckLinkDisplayMode **resultDisplayMode); + + HRESULT ( STDMETHODCALLTYPE *GetDisplayModeIterator )( + IDeckLinkOutput * This, + /* [out] */ IDeckLinkDisplayModeIterator **iterator); + + HRESULT ( STDMETHODCALLTYPE *SetScreenPreviewCallback )( + IDeckLinkOutput * This, + /* [in] */ IDeckLinkScreenPreviewCallback *previewCallback); + + HRESULT ( STDMETHODCALLTYPE *EnableVideoOutput )( + IDeckLinkOutput * This, + /* [in] */ BMDDisplayMode displayMode, + /* [in] */ BMDVideoOutputFlags flags); + + HRESULT ( STDMETHODCALLTYPE *DisableVideoOutput )( + IDeckLinkOutput * This); + + HRESULT ( STDMETHODCALLTYPE *SetVideoOutputFrameMemoryAllocator )( + IDeckLinkOutput * This, + /* [in] */ IDeckLinkMemoryAllocator *theAllocator); + + HRESULT ( STDMETHODCALLTYPE *CreateVideoFrame )( + IDeckLinkOutput * This, + /* [in] */ int width, + /* [in] */ int height, + /* [in] */ int rowBytes, + /* [in] */ BMDPixelFormat pixelFormat, + /* [in] */ BMDFrameFlags flags, + /* [out] */ IDeckLinkMutableVideoFrame **outFrame); + + HRESULT ( STDMETHODCALLTYPE *CreateAncillaryData )( + IDeckLinkOutput * This, + /* [in] */ BMDPixelFormat pixelFormat, + /* [out] */ IDeckLinkVideoFrameAncillary **outBuffer); + + HRESULT ( STDMETHODCALLTYPE *DisplayVideoFrameSync )( + IDeckLinkOutput * This, + /* [in] */ IDeckLinkVideoFrame *theFrame); + + HRESULT ( STDMETHODCALLTYPE *ScheduleVideoFrame )( + IDeckLinkOutput * This, + /* [in] */ IDeckLinkVideoFrame *theFrame, + /* [in] */ BMDTimeValue displayTime, + /* [in] */ BMDTimeValue displayDuration, + /* [in] */ BMDTimeScale timeScale); + + HRESULT ( STDMETHODCALLTYPE *SetScheduledFrameCompletionCallback )( + IDeckLinkOutput * This, + /* [in] */ IDeckLinkVideoOutputCallback *theCallback); + + HRESULT ( STDMETHODCALLTYPE *GetBufferedVideoFrameCount )( + IDeckLinkOutput * This, + /* [out] */ unsigned int *bufferedFrameCount); + + HRESULT ( STDMETHODCALLTYPE *EnableAudioOutput )( + IDeckLinkOutput * This, + /* [in] */ BMDAudioSampleRate sampleRate, + /* [in] */ BMDAudioSampleType sampleType, + /* [in] */ unsigned int channelCount, + /* [in] */ BMDAudioOutputStreamType streamType); + + HRESULT ( STDMETHODCALLTYPE *DisableAudioOutput )( + IDeckLinkOutput * This); + + HRESULT ( STDMETHODCALLTYPE *WriteAudioSamplesSync )( + IDeckLinkOutput * This, + /* [in] */ void *buffer, + /* [in] */ unsigned int sampleFrameCount, + /* [out] */ unsigned int *sampleFramesWritten); + + HRESULT ( STDMETHODCALLTYPE *BeginAudioPreroll )( + IDeckLinkOutput * This); + + HRESULT ( STDMETHODCALLTYPE *EndAudioPreroll )( + IDeckLinkOutput * This); + + HRESULT ( STDMETHODCALLTYPE *ScheduleAudioSamples )( + IDeckLinkOutput * This, + /* [in] */ void *buffer, + /* [in] */ unsigned int sampleFrameCount, + /* [in] */ BMDTimeValue streamTime, + /* [in] */ BMDTimeScale timeScale, + /* [out] */ unsigned int *sampleFramesWritten); + + HRESULT ( STDMETHODCALLTYPE *GetBufferedAudioSampleFrameCount )( + IDeckLinkOutput * This, + /* [out] */ unsigned int *bufferedSampleFrameCount); + + HRESULT ( STDMETHODCALLTYPE *FlushBufferedAudioSamples )( + IDeckLinkOutput * This); + + HRESULT ( STDMETHODCALLTYPE *SetAudioCallback )( + IDeckLinkOutput * This, + /* [in] */ IDeckLinkAudioOutputCallback *theCallback); + + HRESULT ( STDMETHODCALLTYPE *StartScheduledPlayback )( + IDeckLinkOutput * This, + /* [in] */ BMDTimeValue playbackStartTime, + /* [in] */ BMDTimeScale timeScale, + /* [in] */ double playbackSpeed); + + HRESULT ( STDMETHODCALLTYPE *StopScheduledPlayback )( + IDeckLinkOutput * This, + /* [in] */ BMDTimeValue stopPlaybackAtTime, + /* [out] */ BMDTimeValue *actualStopTime, + /* [in] */ BMDTimeScale timeScale); + + HRESULT ( STDMETHODCALLTYPE *IsScheduledPlaybackRunning )( + IDeckLinkOutput * This, + /* [out] */ BOOL *active); + + HRESULT ( STDMETHODCALLTYPE *GetScheduledStreamTime )( + IDeckLinkOutput * This, + /* [in] */ BMDTimeScale desiredTimeScale, + /* [out] */ BMDTimeValue *streamTime, + /* [out] */ double *playbackSpeed); + + HRESULT ( STDMETHODCALLTYPE *GetReferenceStatus )( + IDeckLinkOutput * This, + /* [out] */ BMDReferenceStatus *referenceStatus); + + HRESULT ( STDMETHODCALLTYPE *GetHardwareReferenceClock )( + IDeckLinkOutput * This, + /* [in] */ BMDTimeScale desiredTimeScale, + /* [out] */ BMDTimeValue *hardwareTime, + /* [out] */ BMDTimeValue *timeInFrame, + /* [out] */ BMDTimeValue *ticksPerFrame); + + HRESULT ( STDMETHODCALLTYPE *GetFrameCompletionReferenceTimestamp )( + IDeckLinkOutput * This, + /* [in] */ IDeckLinkVideoFrame *theFrame, + /* [in] */ BMDTimeScale desiredTimeScale, + /* [out] */ BMDTimeValue *frameCompletionTimestamp); + + END_INTERFACE + } IDeckLinkOutputVtbl; + + interface IDeckLinkOutput + { + CONST_VTBL struct IDeckLinkOutputVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkOutput_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkOutput_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkOutput_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkOutput_DoesSupportVideoMode(This,displayMode,pixelFormat,flags,result,resultDisplayMode) \ + ( (This)->lpVtbl -> DoesSupportVideoMode(This,displayMode,pixelFormat,flags,result,resultDisplayMode) ) + +#define IDeckLinkOutput_GetDisplayModeIterator(This,iterator) \ + ( (This)->lpVtbl -> GetDisplayModeIterator(This,iterator) ) + +#define IDeckLinkOutput_SetScreenPreviewCallback(This,previewCallback) \ + ( (This)->lpVtbl -> SetScreenPreviewCallback(This,previewCallback) ) + +#define IDeckLinkOutput_EnableVideoOutput(This,displayMode,flags) \ + ( (This)->lpVtbl -> EnableVideoOutput(This,displayMode,flags) ) + +#define IDeckLinkOutput_DisableVideoOutput(This) \ + ( (This)->lpVtbl -> DisableVideoOutput(This) ) + +#define IDeckLinkOutput_SetVideoOutputFrameMemoryAllocator(This,theAllocator) \ + ( (This)->lpVtbl -> SetVideoOutputFrameMemoryAllocator(This,theAllocator) ) + +#define IDeckLinkOutput_CreateVideoFrame(This,width,height,rowBytes,pixelFormat,flags,outFrame) \ + ( (This)->lpVtbl -> CreateVideoFrame(This,width,height,rowBytes,pixelFormat,flags,outFrame) ) + +#define IDeckLinkOutput_CreateAncillaryData(This,pixelFormat,outBuffer) \ + ( (This)->lpVtbl -> CreateAncillaryData(This,pixelFormat,outBuffer) ) + +#define IDeckLinkOutput_DisplayVideoFrameSync(This,theFrame) \ + ( (This)->lpVtbl -> DisplayVideoFrameSync(This,theFrame) ) + +#define IDeckLinkOutput_ScheduleVideoFrame(This,theFrame,displayTime,displayDuration,timeScale) \ + ( (This)->lpVtbl -> ScheduleVideoFrame(This,theFrame,displayTime,displayDuration,timeScale) ) + +#define IDeckLinkOutput_SetScheduledFrameCompletionCallback(This,theCallback) \ + ( (This)->lpVtbl -> SetScheduledFrameCompletionCallback(This,theCallback) ) + +#define IDeckLinkOutput_GetBufferedVideoFrameCount(This,bufferedFrameCount) \ + ( (This)->lpVtbl -> GetBufferedVideoFrameCount(This,bufferedFrameCount) ) + +#define IDeckLinkOutput_EnableAudioOutput(This,sampleRate,sampleType,channelCount,streamType) \ + ( (This)->lpVtbl -> EnableAudioOutput(This,sampleRate,sampleType,channelCount,streamType) ) + +#define IDeckLinkOutput_DisableAudioOutput(This) \ + ( (This)->lpVtbl -> DisableAudioOutput(This) ) + +#define IDeckLinkOutput_WriteAudioSamplesSync(This,buffer,sampleFrameCount,sampleFramesWritten) \ + ( (This)->lpVtbl -> WriteAudioSamplesSync(This,buffer,sampleFrameCount,sampleFramesWritten) ) + +#define IDeckLinkOutput_BeginAudioPreroll(This) \ + ( (This)->lpVtbl -> BeginAudioPreroll(This) ) + +#define IDeckLinkOutput_EndAudioPreroll(This) \ + ( (This)->lpVtbl -> EndAudioPreroll(This) ) + +#define IDeckLinkOutput_ScheduleAudioSamples(This,buffer,sampleFrameCount,streamTime,timeScale,sampleFramesWritten) \ + ( (This)->lpVtbl -> ScheduleAudioSamples(This,buffer,sampleFrameCount,streamTime,timeScale,sampleFramesWritten) ) + +#define IDeckLinkOutput_GetBufferedAudioSampleFrameCount(This,bufferedSampleFrameCount) \ + ( (This)->lpVtbl -> GetBufferedAudioSampleFrameCount(This,bufferedSampleFrameCount) ) + +#define IDeckLinkOutput_FlushBufferedAudioSamples(This) \ + ( (This)->lpVtbl -> FlushBufferedAudioSamples(This) ) + +#define IDeckLinkOutput_SetAudioCallback(This,theCallback) \ + ( (This)->lpVtbl -> SetAudioCallback(This,theCallback) ) + +#define IDeckLinkOutput_StartScheduledPlayback(This,playbackStartTime,timeScale,playbackSpeed) \ + ( (This)->lpVtbl -> StartScheduledPlayback(This,playbackStartTime,timeScale,playbackSpeed) ) + +#define IDeckLinkOutput_StopScheduledPlayback(This,stopPlaybackAtTime,actualStopTime,timeScale) \ + ( (This)->lpVtbl -> StopScheduledPlayback(This,stopPlaybackAtTime,actualStopTime,timeScale) ) + +#define IDeckLinkOutput_IsScheduledPlaybackRunning(This,active) \ + ( (This)->lpVtbl -> IsScheduledPlaybackRunning(This,active) ) + +#define IDeckLinkOutput_GetScheduledStreamTime(This,desiredTimeScale,streamTime,playbackSpeed) \ + ( (This)->lpVtbl -> GetScheduledStreamTime(This,desiredTimeScale,streamTime,playbackSpeed) ) + +#define IDeckLinkOutput_GetReferenceStatus(This,referenceStatus) \ + ( (This)->lpVtbl -> GetReferenceStatus(This,referenceStatus) ) + +#define IDeckLinkOutput_GetHardwareReferenceClock(This,desiredTimeScale,hardwareTime,timeInFrame,ticksPerFrame) \ + ( (This)->lpVtbl -> GetHardwareReferenceClock(This,desiredTimeScale,hardwareTime,timeInFrame,ticksPerFrame) ) + +#define IDeckLinkOutput_GetFrameCompletionReferenceTimestamp(This,theFrame,desiredTimeScale,frameCompletionTimestamp) \ + ( (This)->lpVtbl -> GetFrameCompletionReferenceTimestamp(This,theFrame,desiredTimeScale,frameCompletionTimestamp) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkOutput_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkInput_INTERFACE_DEFINED__ +#define __IDeckLinkInput_INTERFACE_DEFINED__ + +/* interface IDeckLinkInput */ +/* [helpstring][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkInput; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("AF22762B-DFAC-4846-AA79-FA8883560995") + IDeckLinkInput : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE DoesSupportVideoMode( + /* [in] */ BMDDisplayMode displayMode, + /* [in] */ BMDPixelFormat pixelFormat, + /* [in] */ BMDVideoInputFlags flags, + /* [out] */ BMDDisplayModeSupport *result, + /* [out] */ IDeckLinkDisplayMode **resultDisplayMode) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetDisplayModeIterator( + /* [out] */ IDeckLinkDisplayModeIterator **iterator) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetScreenPreviewCallback( + /* [in] */ IDeckLinkScreenPreviewCallback *previewCallback) = 0; + + virtual HRESULT STDMETHODCALLTYPE EnableVideoInput( + /* [in] */ BMDDisplayMode displayMode, + /* [in] */ BMDPixelFormat pixelFormat, + /* [in] */ BMDVideoInputFlags flags) = 0; + + virtual HRESULT STDMETHODCALLTYPE DisableVideoInput( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetAvailableVideoFrameCount( + /* [out] */ unsigned int *availableFrameCount) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetVideoInputFrameMemoryAllocator( + /* [in] */ IDeckLinkMemoryAllocator *theAllocator) = 0; + + virtual HRESULT STDMETHODCALLTYPE EnableAudioInput( + /* [in] */ BMDAudioSampleRate sampleRate, + /* [in] */ BMDAudioSampleType sampleType, + /* [in] */ unsigned int channelCount) = 0; + + virtual HRESULT STDMETHODCALLTYPE DisableAudioInput( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetAvailableAudioSampleFrameCount( + /* [out] */ unsigned int *availableSampleFrameCount) = 0; + + virtual HRESULT STDMETHODCALLTYPE StartStreams( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE StopStreams( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE PauseStreams( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE FlushStreams( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetCallback( + /* [in] */ IDeckLinkInputCallback *theCallback) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetHardwareReferenceClock( + /* [in] */ BMDTimeScale desiredTimeScale, + /* [out] */ BMDTimeValue *hardwareTime, + /* [out] */ BMDTimeValue *timeInFrame, + /* [out] */ BMDTimeValue *ticksPerFrame) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkInputVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkInput * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkInput * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkInput * This); + + HRESULT ( STDMETHODCALLTYPE *DoesSupportVideoMode )( + IDeckLinkInput * This, + /* [in] */ BMDDisplayMode displayMode, + /* [in] */ BMDPixelFormat pixelFormat, + /* [in] */ BMDVideoInputFlags flags, + /* [out] */ BMDDisplayModeSupport *result, + /* [out] */ IDeckLinkDisplayMode **resultDisplayMode); + + HRESULT ( STDMETHODCALLTYPE *GetDisplayModeIterator )( + IDeckLinkInput * This, + /* [out] */ IDeckLinkDisplayModeIterator **iterator); + + HRESULT ( STDMETHODCALLTYPE *SetScreenPreviewCallback )( + IDeckLinkInput * This, + /* [in] */ IDeckLinkScreenPreviewCallback *previewCallback); + + HRESULT ( STDMETHODCALLTYPE *EnableVideoInput )( + IDeckLinkInput * This, + /* [in] */ BMDDisplayMode displayMode, + /* [in] */ BMDPixelFormat pixelFormat, + /* [in] */ BMDVideoInputFlags flags); + + HRESULT ( STDMETHODCALLTYPE *DisableVideoInput )( + IDeckLinkInput * This); + + HRESULT ( STDMETHODCALLTYPE *GetAvailableVideoFrameCount )( + IDeckLinkInput * This, + /* [out] */ unsigned int *availableFrameCount); + + HRESULT ( STDMETHODCALLTYPE *SetVideoInputFrameMemoryAllocator )( + IDeckLinkInput * This, + /* [in] */ IDeckLinkMemoryAllocator *theAllocator); + + HRESULT ( STDMETHODCALLTYPE *EnableAudioInput )( + IDeckLinkInput * This, + /* [in] */ BMDAudioSampleRate sampleRate, + /* [in] */ BMDAudioSampleType sampleType, + /* [in] */ unsigned int channelCount); + + HRESULT ( STDMETHODCALLTYPE *DisableAudioInput )( + IDeckLinkInput * This); + + HRESULT ( STDMETHODCALLTYPE *GetAvailableAudioSampleFrameCount )( + IDeckLinkInput * This, + /* [out] */ unsigned int *availableSampleFrameCount); + + HRESULT ( STDMETHODCALLTYPE *StartStreams )( + IDeckLinkInput * This); + + HRESULT ( STDMETHODCALLTYPE *StopStreams )( + IDeckLinkInput * This); + + HRESULT ( STDMETHODCALLTYPE *PauseStreams )( + IDeckLinkInput * This); + + HRESULT ( STDMETHODCALLTYPE *FlushStreams )( + IDeckLinkInput * This); + + HRESULT ( STDMETHODCALLTYPE *SetCallback )( + IDeckLinkInput * This, + /* [in] */ IDeckLinkInputCallback *theCallback); + + HRESULT ( STDMETHODCALLTYPE *GetHardwareReferenceClock )( + IDeckLinkInput * This, + /* [in] */ BMDTimeScale desiredTimeScale, + /* [out] */ BMDTimeValue *hardwareTime, + /* [out] */ BMDTimeValue *timeInFrame, + /* [out] */ BMDTimeValue *ticksPerFrame); + + END_INTERFACE + } IDeckLinkInputVtbl; + + interface IDeckLinkInput + { + CONST_VTBL struct IDeckLinkInputVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkInput_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkInput_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkInput_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkInput_DoesSupportVideoMode(This,displayMode,pixelFormat,flags,result,resultDisplayMode) \ + ( (This)->lpVtbl -> DoesSupportVideoMode(This,displayMode,pixelFormat,flags,result,resultDisplayMode) ) + +#define IDeckLinkInput_GetDisplayModeIterator(This,iterator) \ + ( (This)->lpVtbl -> GetDisplayModeIterator(This,iterator) ) + +#define IDeckLinkInput_SetScreenPreviewCallback(This,previewCallback) \ + ( (This)->lpVtbl -> SetScreenPreviewCallback(This,previewCallback) ) + +#define IDeckLinkInput_EnableVideoInput(This,displayMode,pixelFormat,flags) \ + ( (This)->lpVtbl -> EnableVideoInput(This,displayMode,pixelFormat,flags) ) + +#define IDeckLinkInput_DisableVideoInput(This) \ + ( (This)->lpVtbl -> DisableVideoInput(This) ) + +#define IDeckLinkInput_GetAvailableVideoFrameCount(This,availableFrameCount) \ + ( (This)->lpVtbl -> GetAvailableVideoFrameCount(This,availableFrameCount) ) + +#define IDeckLinkInput_SetVideoInputFrameMemoryAllocator(This,theAllocator) \ + ( (This)->lpVtbl -> SetVideoInputFrameMemoryAllocator(This,theAllocator) ) + +#define IDeckLinkInput_EnableAudioInput(This,sampleRate,sampleType,channelCount) \ + ( (This)->lpVtbl -> EnableAudioInput(This,sampleRate,sampleType,channelCount) ) + +#define IDeckLinkInput_DisableAudioInput(This) \ + ( (This)->lpVtbl -> DisableAudioInput(This) ) + +#define IDeckLinkInput_GetAvailableAudioSampleFrameCount(This,availableSampleFrameCount) \ + ( (This)->lpVtbl -> GetAvailableAudioSampleFrameCount(This,availableSampleFrameCount) ) + +#define IDeckLinkInput_StartStreams(This) \ + ( (This)->lpVtbl -> StartStreams(This) ) + +#define IDeckLinkInput_StopStreams(This) \ + ( (This)->lpVtbl -> StopStreams(This) ) + +#define IDeckLinkInput_PauseStreams(This) \ + ( (This)->lpVtbl -> PauseStreams(This) ) + +#define IDeckLinkInput_FlushStreams(This) \ + ( (This)->lpVtbl -> FlushStreams(This) ) + +#define IDeckLinkInput_SetCallback(This,theCallback) \ + ( (This)->lpVtbl -> SetCallback(This,theCallback) ) + +#define IDeckLinkInput_GetHardwareReferenceClock(This,desiredTimeScale,hardwareTime,timeInFrame,ticksPerFrame) \ + ( (This)->lpVtbl -> GetHardwareReferenceClock(This,desiredTimeScale,hardwareTime,timeInFrame,ticksPerFrame) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkInput_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkVideoFrame_INTERFACE_DEFINED__ +#define __IDeckLinkVideoFrame_INTERFACE_DEFINED__ + +/* interface IDeckLinkVideoFrame */ +/* [helpstring][local][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkVideoFrame; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("3F716FE0-F023-4111-BE5D-EF4414C05B17") + IDeckLinkVideoFrame : public IUnknown + { + public: + virtual long STDMETHODCALLTYPE GetWidth( void) = 0; + + virtual long STDMETHODCALLTYPE GetHeight( void) = 0; + + virtual long STDMETHODCALLTYPE GetRowBytes( void) = 0; + + virtual BMDPixelFormat STDMETHODCALLTYPE GetPixelFormat( void) = 0; + + virtual BMDFrameFlags STDMETHODCALLTYPE GetFlags( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetBytes( + /* [out] */ void **buffer) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetTimecode( + /* [in] */ BMDTimecodeFormat format, + /* [out] */ IDeckLinkTimecode **timecode) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetAncillaryData( + /* [out] */ IDeckLinkVideoFrameAncillary **ancillary) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkVideoFrameVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkVideoFrame * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkVideoFrame * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkVideoFrame * This); + + long ( STDMETHODCALLTYPE *GetWidth )( + IDeckLinkVideoFrame * This); + + long ( STDMETHODCALLTYPE *GetHeight )( + IDeckLinkVideoFrame * This); + + long ( STDMETHODCALLTYPE *GetRowBytes )( + IDeckLinkVideoFrame * This); + + BMDPixelFormat ( STDMETHODCALLTYPE *GetPixelFormat )( + IDeckLinkVideoFrame * This); + + BMDFrameFlags ( STDMETHODCALLTYPE *GetFlags )( + IDeckLinkVideoFrame * This); + + HRESULT ( STDMETHODCALLTYPE *GetBytes )( + IDeckLinkVideoFrame * This, + /* [out] */ void **buffer); + + HRESULT ( STDMETHODCALLTYPE *GetTimecode )( + IDeckLinkVideoFrame * This, + /* [in] */ BMDTimecodeFormat format, + /* [out] */ IDeckLinkTimecode **timecode); + + HRESULT ( STDMETHODCALLTYPE *GetAncillaryData )( + IDeckLinkVideoFrame * This, + /* [out] */ IDeckLinkVideoFrameAncillary **ancillary); + + END_INTERFACE + } IDeckLinkVideoFrameVtbl; + + interface IDeckLinkVideoFrame + { + CONST_VTBL struct IDeckLinkVideoFrameVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkVideoFrame_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkVideoFrame_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkVideoFrame_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkVideoFrame_GetWidth(This) \ + ( (This)->lpVtbl -> GetWidth(This) ) + +#define IDeckLinkVideoFrame_GetHeight(This) \ + ( (This)->lpVtbl -> GetHeight(This) ) + +#define IDeckLinkVideoFrame_GetRowBytes(This) \ + ( (This)->lpVtbl -> GetRowBytes(This) ) + +#define IDeckLinkVideoFrame_GetPixelFormat(This) \ + ( (This)->lpVtbl -> GetPixelFormat(This) ) + +#define IDeckLinkVideoFrame_GetFlags(This) \ + ( (This)->lpVtbl -> GetFlags(This) ) + +#define IDeckLinkVideoFrame_GetBytes(This,buffer) \ + ( (This)->lpVtbl -> GetBytes(This,buffer) ) + +#define IDeckLinkVideoFrame_GetTimecode(This,format,timecode) \ + ( (This)->lpVtbl -> GetTimecode(This,format,timecode) ) + +#define IDeckLinkVideoFrame_GetAncillaryData(This,ancillary) \ + ( (This)->lpVtbl -> GetAncillaryData(This,ancillary) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkVideoFrame_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkMutableVideoFrame_INTERFACE_DEFINED__ +#define __IDeckLinkMutableVideoFrame_INTERFACE_DEFINED__ + +/* interface IDeckLinkMutableVideoFrame */ +/* [helpstring][local][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkMutableVideoFrame; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("69E2639F-40DA-4E19-B6F2-20ACE815C390") + IDeckLinkMutableVideoFrame : public IDeckLinkVideoFrame + { + public: + virtual HRESULT STDMETHODCALLTYPE SetFlags( + /* [in] */ BMDFrameFlags newFlags) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetTimecode( + /* [in] */ BMDTimecodeFormat format, + /* [in] */ IDeckLinkTimecode *timecode) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetTimecodeFromComponents( + /* [in] */ BMDTimecodeFormat format, + /* [in] */ unsigned char hours, + /* [in] */ unsigned char minutes, + /* [in] */ unsigned char seconds, + /* [in] */ unsigned char frames, + /* [in] */ BMDTimecodeFlags flags) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetAncillaryData( + /* [in] */ IDeckLinkVideoFrameAncillary *ancillary) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetTimecodeUserBits( + /* [in] */ BMDTimecodeFormat format, + /* [in] */ BMDTimecodeUserBits userBits) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkMutableVideoFrameVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkMutableVideoFrame * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkMutableVideoFrame * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkMutableVideoFrame * This); + + long ( STDMETHODCALLTYPE *GetWidth )( + IDeckLinkMutableVideoFrame * This); + + long ( STDMETHODCALLTYPE *GetHeight )( + IDeckLinkMutableVideoFrame * This); + + long ( STDMETHODCALLTYPE *GetRowBytes )( + IDeckLinkMutableVideoFrame * This); + + BMDPixelFormat ( STDMETHODCALLTYPE *GetPixelFormat )( + IDeckLinkMutableVideoFrame * This); + + BMDFrameFlags ( STDMETHODCALLTYPE *GetFlags )( + IDeckLinkMutableVideoFrame * This); + + HRESULT ( STDMETHODCALLTYPE *GetBytes )( + IDeckLinkMutableVideoFrame * This, + /* [out] */ void **buffer); + + HRESULT ( STDMETHODCALLTYPE *GetTimecode )( + IDeckLinkMutableVideoFrame * This, + /* [in] */ BMDTimecodeFormat format, + /* [out] */ IDeckLinkTimecode **timecode); + + HRESULT ( STDMETHODCALLTYPE *GetAncillaryData )( + IDeckLinkMutableVideoFrame * This, + /* [out] */ IDeckLinkVideoFrameAncillary **ancillary); + + HRESULT ( STDMETHODCALLTYPE *SetFlags )( + IDeckLinkMutableVideoFrame * This, + /* [in] */ BMDFrameFlags newFlags); + + HRESULT ( STDMETHODCALLTYPE *SetTimecode )( + IDeckLinkMutableVideoFrame * This, + /* [in] */ BMDTimecodeFormat format, + /* [in] */ IDeckLinkTimecode *timecode); + + HRESULT ( STDMETHODCALLTYPE *SetTimecodeFromComponents )( + IDeckLinkMutableVideoFrame * This, + /* [in] */ BMDTimecodeFormat format, + /* [in] */ unsigned char hours, + /* [in] */ unsigned char minutes, + /* [in] */ unsigned char seconds, + /* [in] */ unsigned char frames, + /* [in] */ BMDTimecodeFlags flags); + + HRESULT ( STDMETHODCALLTYPE *SetAncillaryData )( + IDeckLinkMutableVideoFrame * This, + /* [in] */ IDeckLinkVideoFrameAncillary *ancillary); + + HRESULT ( STDMETHODCALLTYPE *SetTimecodeUserBits )( + IDeckLinkMutableVideoFrame * This, + /* [in] */ BMDTimecodeFormat format, + /* [in] */ BMDTimecodeUserBits userBits); + + END_INTERFACE + } IDeckLinkMutableVideoFrameVtbl; + + interface IDeckLinkMutableVideoFrame + { + CONST_VTBL struct IDeckLinkMutableVideoFrameVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkMutableVideoFrame_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkMutableVideoFrame_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkMutableVideoFrame_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkMutableVideoFrame_GetWidth(This) \ + ( (This)->lpVtbl -> GetWidth(This) ) + +#define IDeckLinkMutableVideoFrame_GetHeight(This) \ + ( (This)->lpVtbl -> GetHeight(This) ) + +#define IDeckLinkMutableVideoFrame_GetRowBytes(This) \ + ( (This)->lpVtbl -> GetRowBytes(This) ) + +#define IDeckLinkMutableVideoFrame_GetPixelFormat(This) \ + ( (This)->lpVtbl -> GetPixelFormat(This) ) + +#define IDeckLinkMutableVideoFrame_GetFlags(This) \ + ( (This)->lpVtbl -> GetFlags(This) ) + +#define IDeckLinkMutableVideoFrame_GetBytes(This,buffer) \ + ( (This)->lpVtbl -> GetBytes(This,buffer) ) + +#define IDeckLinkMutableVideoFrame_GetTimecode(This,format,timecode) \ + ( (This)->lpVtbl -> GetTimecode(This,format,timecode) ) + +#define IDeckLinkMutableVideoFrame_GetAncillaryData(This,ancillary) \ + ( (This)->lpVtbl -> GetAncillaryData(This,ancillary) ) + + +#define IDeckLinkMutableVideoFrame_SetFlags(This,newFlags) \ + ( (This)->lpVtbl -> SetFlags(This,newFlags) ) + +#define IDeckLinkMutableVideoFrame_SetTimecode(This,format,timecode) \ + ( (This)->lpVtbl -> SetTimecode(This,format,timecode) ) + +#define IDeckLinkMutableVideoFrame_SetTimecodeFromComponents(This,format,hours,minutes,seconds,frames,flags) \ + ( (This)->lpVtbl -> SetTimecodeFromComponents(This,format,hours,minutes,seconds,frames,flags) ) + +#define IDeckLinkMutableVideoFrame_SetAncillaryData(This,ancillary) \ + ( (This)->lpVtbl -> SetAncillaryData(This,ancillary) ) + +#define IDeckLinkMutableVideoFrame_SetTimecodeUserBits(This,format,userBits) \ + ( (This)->lpVtbl -> SetTimecodeUserBits(This,format,userBits) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkMutableVideoFrame_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkVideoFrame3DExtensions_INTERFACE_DEFINED__ +#define __IDeckLinkVideoFrame3DExtensions_INTERFACE_DEFINED__ + +/* interface IDeckLinkVideoFrame3DExtensions */ +/* [helpstring][local][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkVideoFrame3DExtensions; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("DA0F7E4A-EDC7-48A8-9CDD-2DB51C729CD7") + IDeckLinkVideoFrame3DExtensions : public IUnknown + { + public: + virtual BMDVideo3DPackingFormat STDMETHODCALLTYPE Get3DPackingFormat( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetFrameForRightEye( + /* [out] */ IDeckLinkVideoFrame **rightEyeFrame) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkVideoFrame3DExtensionsVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkVideoFrame3DExtensions * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkVideoFrame3DExtensions * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkVideoFrame3DExtensions * This); + + BMDVideo3DPackingFormat ( STDMETHODCALLTYPE *Get3DPackingFormat )( + IDeckLinkVideoFrame3DExtensions * This); + + HRESULT ( STDMETHODCALLTYPE *GetFrameForRightEye )( + IDeckLinkVideoFrame3DExtensions * This, + /* [out] */ IDeckLinkVideoFrame **rightEyeFrame); + + END_INTERFACE + } IDeckLinkVideoFrame3DExtensionsVtbl; + + interface IDeckLinkVideoFrame3DExtensions + { + CONST_VTBL struct IDeckLinkVideoFrame3DExtensionsVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkVideoFrame3DExtensions_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkVideoFrame3DExtensions_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkVideoFrame3DExtensions_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkVideoFrame3DExtensions_Get3DPackingFormat(This) \ + ( (This)->lpVtbl -> Get3DPackingFormat(This) ) + +#define IDeckLinkVideoFrame3DExtensions_GetFrameForRightEye(This,rightEyeFrame) \ + ( (This)->lpVtbl -> GetFrameForRightEye(This,rightEyeFrame) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkVideoFrame3DExtensions_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkVideoInputFrame_INTERFACE_DEFINED__ +#define __IDeckLinkVideoInputFrame_INTERFACE_DEFINED__ + +/* interface IDeckLinkVideoInputFrame */ +/* [helpstring][local][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkVideoInputFrame; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("05CFE374-537C-4094-9A57-680525118F44") + IDeckLinkVideoInputFrame : public IDeckLinkVideoFrame + { + public: + virtual HRESULT STDMETHODCALLTYPE GetStreamTime( + /* [out] */ BMDTimeValue *frameTime, + /* [out] */ BMDTimeValue *frameDuration, + /* [in] */ BMDTimeScale timeScale) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetHardwareReferenceTimestamp( + /* [in] */ BMDTimeScale timeScale, + /* [out] */ BMDTimeValue *frameTime, + /* [out] */ BMDTimeValue *frameDuration) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkVideoInputFrameVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkVideoInputFrame * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkVideoInputFrame * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkVideoInputFrame * This); + + long ( STDMETHODCALLTYPE *GetWidth )( + IDeckLinkVideoInputFrame * This); + + long ( STDMETHODCALLTYPE *GetHeight )( + IDeckLinkVideoInputFrame * This); + + long ( STDMETHODCALLTYPE *GetRowBytes )( + IDeckLinkVideoInputFrame * This); + + BMDPixelFormat ( STDMETHODCALLTYPE *GetPixelFormat )( + IDeckLinkVideoInputFrame * This); + + BMDFrameFlags ( STDMETHODCALLTYPE *GetFlags )( + IDeckLinkVideoInputFrame * This); + + HRESULT ( STDMETHODCALLTYPE *GetBytes )( + IDeckLinkVideoInputFrame * This, + /* [out] */ void **buffer); + + HRESULT ( STDMETHODCALLTYPE *GetTimecode )( + IDeckLinkVideoInputFrame * This, + /* [in] */ BMDTimecodeFormat format, + /* [out] */ IDeckLinkTimecode **timecode); + + HRESULT ( STDMETHODCALLTYPE *GetAncillaryData )( + IDeckLinkVideoInputFrame * This, + /* [out] */ IDeckLinkVideoFrameAncillary **ancillary); + + HRESULT ( STDMETHODCALLTYPE *GetStreamTime )( + IDeckLinkVideoInputFrame * This, + /* [out] */ BMDTimeValue *frameTime, + /* [out] */ BMDTimeValue *frameDuration, + /* [in] */ BMDTimeScale timeScale); + + HRESULT ( STDMETHODCALLTYPE *GetHardwareReferenceTimestamp )( + IDeckLinkVideoInputFrame * This, + /* [in] */ BMDTimeScale timeScale, + /* [out] */ BMDTimeValue *frameTime, + /* [out] */ BMDTimeValue *frameDuration); + + END_INTERFACE + } IDeckLinkVideoInputFrameVtbl; + + interface IDeckLinkVideoInputFrame + { + CONST_VTBL struct IDeckLinkVideoInputFrameVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkVideoInputFrame_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkVideoInputFrame_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkVideoInputFrame_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkVideoInputFrame_GetWidth(This) \ + ( (This)->lpVtbl -> GetWidth(This) ) + +#define IDeckLinkVideoInputFrame_GetHeight(This) \ + ( (This)->lpVtbl -> GetHeight(This) ) + +#define IDeckLinkVideoInputFrame_GetRowBytes(This) \ + ( (This)->lpVtbl -> GetRowBytes(This) ) + +#define IDeckLinkVideoInputFrame_GetPixelFormat(This) \ + ( (This)->lpVtbl -> GetPixelFormat(This) ) + +#define IDeckLinkVideoInputFrame_GetFlags(This) \ + ( (This)->lpVtbl -> GetFlags(This) ) + +#define IDeckLinkVideoInputFrame_GetBytes(This,buffer) \ + ( (This)->lpVtbl -> GetBytes(This,buffer) ) + +#define IDeckLinkVideoInputFrame_GetTimecode(This,format,timecode) \ + ( (This)->lpVtbl -> GetTimecode(This,format,timecode) ) + +#define IDeckLinkVideoInputFrame_GetAncillaryData(This,ancillary) \ + ( (This)->lpVtbl -> GetAncillaryData(This,ancillary) ) + + +#define IDeckLinkVideoInputFrame_GetStreamTime(This,frameTime,frameDuration,timeScale) \ + ( (This)->lpVtbl -> GetStreamTime(This,frameTime,frameDuration,timeScale) ) + +#define IDeckLinkVideoInputFrame_GetHardwareReferenceTimestamp(This,timeScale,frameTime,frameDuration) \ + ( (This)->lpVtbl -> GetHardwareReferenceTimestamp(This,timeScale,frameTime,frameDuration) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkVideoInputFrame_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkVideoFrameAncillary_INTERFACE_DEFINED__ +#define __IDeckLinkVideoFrameAncillary_INTERFACE_DEFINED__ + +/* interface IDeckLinkVideoFrameAncillary */ +/* [helpstring][local][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkVideoFrameAncillary; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("732E723C-D1A4-4E29-9E8E-4A88797A0004") + IDeckLinkVideoFrameAncillary : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE GetBufferForVerticalBlankingLine( + /* [in] */ unsigned int lineNumber, + /* [out] */ void **buffer) = 0; + + virtual BMDPixelFormat STDMETHODCALLTYPE GetPixelFormat( void) = 0; + + virtual BMDDisplayMode STDMETHODCALLTYPE GetDisplayMode( void) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkVideoFrameAncillaryVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkVideoFrameAncillary * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkVideoFrameAncillary * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkVideoFrameAncillary * This); + + HRESULT ( STDMETHODCALLTYPE *GetBufferForVerticalBlankingLine )( + IDeckLinkVideoFrameAncillary * This, + /* [in] */ unsigned int lineNumber, + /* [out] */ void **buffer); + + BMDPixelFormat ( STDMETHODCALLTYPE *GetPixelFormat )( + IDeckLinkVideoFrameAncillary * This); + + BMDDisplayMode ( STDMETHODCALLTYPE *GetDisplayMode )( + IDeckLinkVideoFrameAncillary * This); + + END_INTERFACE + } IDeckLinkVideoFrameAncillaryVtbl; + + interface IDeckLinkVideoFrameAncillary + { + CONST_VTBL struct IDeckLinkVideoFrameAncillaryVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkVideoFrameAncillary_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkVideoFrameAncillary_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkVideoFrameAncillary_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkVideoFrameAncillary_GetBufferForVerticalBlankingLine(This,lineNumber,buffer) \ + ( (This)->lpVtbl -> GetBufferForVerticalBlankingLine(This,lineNumber,buffer) ) + +#define IDeckLinkVideoFrameAncillary_GetPixelFormat(This) \ + ( (This)->lpVtbl -> GetPixelFormat(This) ) + +#define IDeckLinkVideoFrameAncillary_GetDisplayMode(This) \ + ( (This)->lpVtbl -> GetDisplayMode(This) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkVideoFrameAncillary_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkAudioInputPacket_INTERFACE_DEFINED__ +#define __IDeckLinkAudioInputPacket_INTERFACE_DEFINED__ + +/* interface IDeckLinkAudioInputPacket */ +/* [helpstring][local][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkAudioInputPacket; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("E43D5870-2894-11DE-8C30-0800200C9A66") + IDeckLinkAudioInputPacket : public IUnknown + { + public: + virtual long STDMETHODCALLTYPE GetSampleFrameCount( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetBytes( + /* [out] */ void **buffer) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetPacketTime( + /* [out] */ BMDTimeValue *packetTime, + /* [in] */ BMDTimeScale timeScale) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkAudioInputPacketVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkAudioInputPacket * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkAudioInputPacket * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkAudioInputPacket * This); + + long ( STDMETHODCALLTYPE *GetSampleFrameCount )( + IDeckLinkAudioInputPacket * This); + + HRESULT ( STDMETHODCALLTYPE *GetBytes )( + IDeckLinkAudioInputPacket * This, + /* [out] */ void **buffer); + + HRESULT ( STDMETHODCALLTYPE *GetPacketTime )( + IDeckLinkAudioInputPacket * This, + /* [out] */ BMDTimeValue *packetTime, + /* [in] */ BMDTimeScale timeScale); + + END_INTERFACE + } IDeckLinkAudioInputPacketVtbl; + + interface IDeckLinkAudioInputPacket + { + CONST_VTBL struct IDeckLinkAudioInputPacketVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkAudioInputPacket_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkAudioInputPacket_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkAudioInputPacket_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkAudioInputPacket_GetSampleFrameCount(This) \ + ( (This)->lpVtbl -> GetSampleFrameCount(This) ) + +#define IDeckLinkAudioInputPacket_GetBytes(This,buffer) \ + ( (This)->lpVtbl -> GetBytes(This,buffer) ) + +#define IDeckLinkAudioInputPacket_GetPacketTime(This,packetTime,timeScale) \ + ( (This)->lpVtbl -> GetPacketTime(This,packetTime,timeScale) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkAudioInputPacket_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkScreenPreviewCallback_INTERFACE_DEFINED__ +#define __IDeckLinkScreenPreviewCallback_INTERFACE_DEFINED__ + +/* interface IDeckLinkScreenPreviewCallback */ +/* [helpstring][local][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkScreenPreviewCallback; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("B1D3F49A-85FE-4C5D-95C8-0B5D5DCCD438") + IDeckLinkScreenPreviewCallback : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE DrawFrame( + /* [in] */ IDeckLinkVideoFrame *theFrame) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkScreenPreviewCallbackVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkScreenPreviewCallback * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkScreenPreviewCallback * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkScreenPreviewCallback * This); + + HRESULT ( STDMETHODCALLTYPE *DrawFrame )( + IDeckLinkScreenPreviewCallback * This, + /* [in] */ IDeckLinkVideoFrame *theFrame); + + END_INTERFACE + } IDeckLinkScreenPreviewCallbackVtbl; + + interface IDeckLinkScreenPreviewCallback + { + CONST_VTBL struct IDeckLinkScreenPreviewCallbackVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkScreenPreviewCallback_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkScreenPreviewCallback_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkScreenPreviewCallback_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkScreenPreviewCallback_DrawFrame(This,theFrame) \ + ( (This)->lpVtbl -> DrawFrame(This,theFrame) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkScreenPreviewCallback_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkGLScreenPreviewHelper_INTERFACE_DEFINED__ +#define __IDeckLinkGLScreenPreviewHelper_INTERFACE_DEFINED__ + +/* interface IDeckLinkGLScreenPreviewHelper */ +/* [helpstring][local][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkGLScreenPreviewHelper; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("504E2209-CAC7-4C1A-9FB4-C5BB6274D22F") + IDeckLinkGLScreenPreviewHelper : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE InitializeGL( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE PaintGL( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetFrame( + /* [in] */ IDeckLinkVideoFrame *theFrame) = 0; + + virtual HRESULT STDMETHODCALLTYPE Set3DPreviewFormat( + /* [in] */ BMD3DPreviewFormat previewFormat) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkGLScreenPreviewHelperVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkGLScreenPreviewHelper * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkGLScreenPreviewHelper * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkGLScreenPreviewHelper * This); + + HRESULT ( STDMETHODCALLTYPE *InitializeGL )( + IDeckLinkGLScreenPreviewHelper * This); + + HRESULT ( STDMETHODCALLTYPE *PaintGL )( + IDeckLinkGLScreenPreviewHelper * This); + + HRESULT ( STDMETHODCALLTYPE *SetFrame )( + IDeckLinkGLScreenPreviewHelper * This, + /* [in] */ IDeckLinkVideoFrame *theFrame); + + HRESULT ( STDMETHODCALLTYPE *Set3DPreviewFormat )( + IDeckLinkGLScreenPreviewHelper * This, + /* [in] */ BMD3DPreviewFormat previewFormat); + + END_INTERFACE + } IDeckLinkGLScreenPreviewHelperVtbl; + + interface IDeckLinkGLScreenPreviewHelper + { + CONST_VTBL struct IDeckLinkGLScreenPreviewHelperVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkGLScreenPreviewHelper_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkGLScreenPreviewHelper_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkGLScreenPreviewHelper_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkGLScreenPreviewHelper_InitializeGL(This) \ + ( (This)->lpVtbl -> InitializeGL(This) ) + +#define IDeckLinkGLScreenPreviewHelper_PaintGL(This) \ + ( (This)->lpVtbl -> PaintGL(This) ) + +#define IDeckLinkGLScreenPreviewHelper_SetFrame(This,theFrame) \ + ( (This)->lpVtbl -> SetFrame(This,theFrame) ) + +#define IDeckLinkGLScreenPreviewHelper_Set3DPreviewFormat(This,previewFormat) \ + ( (This)->lpVtbl -> Set3DPreviewFormat(This,previewFormat) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkGLScreenPreviewHelper_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkDX9ScreenPreviewHelper_INTERFACE_DEFINED__ +#define __IDeckLinkDX9ScreenPreviewHelper_INTERFACE_DEFINED__ + +/* interface IDeckLinkDX9ScreenPreviewHelper */ +/* [helpstring][local][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkDX9ScreenPreviewHelper; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("2094B522-D1A1-40C0-9AC7-1C012218EF02") + IDeckLinkDX9ScreenPreviewHelper : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE Initialize( + /* [in] */ void *device) = 0; + + virtual HRESULT STDMETHODCALLTYPE Render( + /* [in] */ RECT *rc) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetFrame( + /* [in] */ IDeckLinkVideoFrame *theFrame) = 0; + + virtual HRESULT STDMETHODCALLTYPE Set3DPreviewFormat( + /* [in] */ BMD3DPreviewFormat previewFormat) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkDX9ScreenPreviewHelperVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkDX9ScreenPreviewHelper * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkDX9ScreenPreviewHelper * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkDX9ScreenPreviewHelper * This); + + HRESULT ( STDMETHODCALLTYPE *Initialize )( + IDeckLinkDX9ScreenPreviewHelper * This, + /* [in] */ void *device); + + HRESULT ( STDMETHODCALLTYPE *Render )( + IDeckLinkDX9ScreenPreviewHelper * This, + /* [in] */ RECT *rc); + + HRESULT ( STDMETHODCALLTYPE *SetFrame )( + IDeckLinkDX9ScreenPreviewHelper * This, + /* [in] */ IDeckLinkVideoFrame *theFrame); + + HRESULT ( STDMETHODCALLTYPE *Set3DPreviewFormat )( + IDeckLinkDX9ScreenPreviewHelper * This, + /* [in] */ BMD3DPreviewFormat previewFormat); + + END_INTERFACE + } IDeckLinkDX9ScreenPreviewHelperVtbl; + + interface IDeckLinkDX9ScreenPreviewHelper + { + CONST_VTBL struct IDeckLinkDX9ScreenPreviewHelperVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkDX9ScreenPreviewHelper_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkDX9ScreenPreviewHelper_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkDX9ScreenPreviewHelper_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkDX9ScreenPreviewHelper_Initialize(This,device) \ + ( (This)->lpVtbl -> Initialize(This,device) ) + +#define IDeckLinkDX9ScreenPreviewHelper_Render(This,rc) \ + ( (This)->lpVtbl -> Render(This,rc) ) + +#define IDeckLinkDX9ScreenPreviewHelper_SetFrame(This,theFrame) \ + ( (This)->lpVtbl -> SetFrame(This,theFrame) ) + +#define IDeckLinkDX9ScreenPreviewHelper_Set3DPreviewFormat(This,previewFormat) \ + ( (This)->lpVtbl -> Set3DPreviewFormat(This,previewFormat) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkDX9ScreenPreviewHelper_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkNotificationCallback_INTERFACE_DEFINED__ +#define __IDeckLinkNotificationCallback_INTERFACE_DEFINED__ + +/* interface IDeckLinkNotificationCallback */ +/* [helpstring][local][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkNotificationCallback; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("b002a1ec-070d-4288-8289-bd5d36e5ff0d") + IDeckLinkNotificationCallback : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE Notify( + /* [in] */ BMDNotifications topic, + /* [in] */ ULONGLONG param1, + /* [in] */ ULONGLONG param2) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkNotificationCallbackVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkNotificationCallback * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkNotificationCallback * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkNotificationCallback * This); + + HRESULT ( STDMETHODCALLTYPE *Notify )( + IDeckLinkNotificationCallback * This, + /* [in] */ BMDNotifications topic, + /* [in] */ ULONGLONG param1, + /* [in] */ ULONGLONG param2); + + END_INTERFACE + } IDeckLinkNotificationCallbackVtbl; + + interface IDeckLinkNotificationCallback + { + CONST_VTBL struct IDeckLinkNotificationCallbackVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkNotificationCallback_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkNotificationCallback_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkNotificationCallback_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkNotificationCallback_Notify(This,topic,param1,param2) \ + ( (This)->lpVtbl -> Notify(This,topic,param1,param2) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkNotificationCallback_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkNotification_INTERFACE_DEFINED__ +#define __IDeckLinkNotification_INTERFACE_DEFINED__ + +/* interface IDeckLinkNotification */ +/* [helpstring][local][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkNotification; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("0a1fb207-e215-441b-9b19-6fa1575946c5") + IDeckLinkNotification : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE Subscribe( + /* [in] */ BMDNotifications topic, + /* [in] */ IDeckLinkNotificationCallback *theCallback) = 0; + + virtual HRESULT STDMETHODCALLTYPE Unsubscribe( + /* [in] */ BMDNotifications topic, + /* [in] */ IDeckLinkNotificationCallback *theCallback) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkNotificationVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkNotification * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkNotification * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkNotification * This); + + HRESULT ( STDMETHODCALLTYPE *Subscribe )( + IDeckLinkNotification * This, + /* [in] */ BMDNotifications topic, + /* [in] */ IDeckLinkNotificationCallback *theCallback); + + HRESULT ( STDMETHODCALLTYPE *Unsubscribe )( + IDeckLinkNotification * This, + /* [in] */ BMDNotifications topic, + /* [in] */ IDeckLinkNotificationCallback *theCallback); + + END_INTERFACE + } IDeckLinkNotificationVtbl; + + interface IDeckLinkNotification + { + CONST_VTBL struct IDeckLinkNotificationVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkNotification_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkNotification_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkNotification_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkNotification_Subscribe(This,topic,theCallback) \ + ( (This)->lpVtbl -> Subscribe(This,topic,theCallback) ) + +#define IDeckLinkNotification_Unsubscribe(This,topic,theCallback) \ + ( (This)->lpVtbl -> Unsubscribe(This,topic,theCallback) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkNotification_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkAttributes_INTERFACE_DEFINED__ +#define __IDeckLinkAttributes_INTERFACE_DEFINED__ + +/* interface IDeckLinkAttributes */ +/* [helpstring][local][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkAttributes; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("ABC11843-D966-44CB-96E2-A1CB5D3135C4") + IDeckLinkAttributes : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE GetFlag( + /* [in] */ BMDDeckLinkAttributeID cfgID, + /* [out] */ BOOL *value) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetInt( + /* [in] */ BMDDeckLinkAttributeID cfgID, + /* [out] */ LONGLONG *value) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetFloat( + /* [in] */ BMDDeckLinkAttributeID cfgID, + /* [out] */ double *value) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetString( + /* [in] */ BMDDeckLinkAttributeID cfgID, + /* [out] */ BSTR *value) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkAttributesVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkAttributes * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkAttributes * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkAttributes * This); + + HRESULT ( STDMETHODCALLTYPE *GetFlag )( + IDeckLinkAttributes * This, + /* [in] */ BMDDeckLinkAttributeID cfgID, + /* [out] */ BOOL *value); + + HRESULT ( STDMETHODCALLTYPE *GetInt )( + IDeckLinkAttributes * This, + /* [in] */ BMDDeckLinkAttributeID cfgID, + /* [out] */ LONGLONG *value); + + HRESULT ( STDMETHODCALLTYPE *GetFloat )( + IDeckLinkAttributes * This, + /* [in] */ BMDDeckLinkAttributeID cfgID, + /* [out] */ double *value); + + HRESULT ( STDMETHODCALLTYPE *GetString )( + IDeckLinkAttributes * This, + /* [in] */ BMDDeckLinkAttributeID cfgID, + /* [out] */ BSTR *value); + + END_INTERFACE + } IDeckLinkAttributesVtbl; + + interface IDeckLinkAttributes + { + CONST_VTBL struct IDeckLinkAttributesVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkAttributes_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkAttributes_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkAttributes_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkAttributes_GetFlag(This,cfgID,value) \ + ( (This)->lpVtbl -> GetFlag(This,cfgID,value) ) + +#define IDeckLinkAttributes_GetInt(This,cfgID,value) \ + ( (This)->lpVtbl -> GetInt(This,cfgID,value) ) + +#define IDeckLinkAttributes_GetFloat(This,cfgID,value) \ + ( (This)->lpVtbl -> GetFloat(This,cfgID,value) ) + +#define IDeckLinkAttributes_GetString(This,cfgID,value) \ + ( (This)->lpVtbl -> GetString(This,cfgID,value) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkAttributes_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkKeyer_INTERFACE_DEFINED__ +#define __IDeckLinkKeyer_INTERFACE_DEFINED__ + +/* interface IDeckLinkKeyer */ +/* [helpstring][local][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkKeyer; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("89AFCAF5-65F8-421E-98F7-96FE5F5BFBA3") + IDeckLinkKeyer : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE Enable( + /* [in] */ BOOL isExternal) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetLevel( + /* [in] */ unsigned char level) = 0; + + virtual HRESULT STDMETHODCALLTYPE RampUp( + /* [in] */ unsigned int numberOfFrames) = 0; + + virtual HRESULT STDMETHODCALLTYPE RampDown( + /* [in] */ unsigned int numberOfFrames) = 0; + + virtual HRESULT STDMETHODCALLTYPE Disable( void) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkKeyerVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkKeyer * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkKeyer * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkKeyer * This); + + HRESULT ( STDMETHODCALLTYPE *Enable )( + IDeckLinkKeyer * This, + /* [in] */ BOOL isExternal); + + HRESULT ( STDMETHODCALLTYPE *SetLevel )( + IDeckLinkKeyer * This, + /* [in] */ unsigned char level); + + HRESULT ( STDMETHODCALLTYPE *RampUp )( + IDeckLinkKeyer * This, + /* [in] */ unsigned int numberOfFrames); + + HRESULT ( STDMETHODCALLTYPE *RampDown )( + IDeckLinkKeyer * This, + /* [in] */ unsigned int numberOfFrames); + + HRESULT ( STDMETHODCALLTYPE *Disable )( + IDeckLinkKeyer * This); + + END_INTERFACE + } IDeckLinkKeyerVtbl; + + interface IDeckLinkKeyer + { + CONST_VTBL struct IDeckLinkKeyerVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkKeyer_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkKeyer_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkKeyer_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkKeyer_Enable(This,isExternal) \ + ( (This)->lpVtbl -> Enable(This,isExternal) ) + +#define IDeckLinkKeyer_SetLevel(This,level) \ + ( (This)->lpVtbl -> SetLevel(This,level) ) + +#define IDeckLinkKeyer_RampUp(This,numberOfFrames) \ + ( (This)->lpVtbl -> RampUp(This,numberOfFrames) ) + +#define IDeckLinkKeyer_RampDown(This,numberOfFrames) \ + ( (This)->lpVtbl -> RampDown(This,numberOfFrames) ) + +#define IDeckLinkKeyer_Disable(This) \ + ( (This)->lpVtbl -> Disable(This) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkKeyer_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkVideoConversion_INTERFACE_DEFINED__ +#define __IDeckLinkVideoConversion_INTERFACE_DEFINED__ + +/* interface IDeckLinkVideoConversion */ +/* [helpstring][local][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkVideoConversion; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("3BBCB8A2-DA2C-42D9-B5D8-88083644E99A") + IDeckLinkVideoConversion : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE ConvertFrame( + /* [in] */ IDeckLinkVideoFrame *srcFrame, + /* [in] */ IDeckLinkVideoFrame *dstFrame) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkVideoConversionVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkVideoConversion * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkVideoConversion * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkVideoConversion * This); + + HRESULT ( STDMETHODCALLTYPE *ConvertFrame )( + IDeckLinkVideoConversion * This, + /* [in] */ IDeckLinkVideoFrame *srcFrame, + /* [in] */ IDeckLinkVideoFrame *dstFrame); + + END_INTERFACE + } IDeckLinkVideoConversionVtbl; + + interface IDeckLinkVideoConversion + { + CONST_VTBL struct IDeckLinkVideoConversionVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkVideoConversion_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkVideoConversion_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkVideoConversion_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkVideoConversion_ConvertFrame(This,srcFrame,dstFrame) \ + ( (This)->lpVtbl -> ConvertFrame(This,srcFrame,dstFrame) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkVideoConversion_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkDeviceNotificationCallback_INTERFACE_DEFINED__ +#define __IDeckLinkDeviceNotificationCallback_INTERFACE_DEFINED__ + +/* interface IDeckLinkDeviceNotificationCallback */ +/* [helpstring][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkDeviceNotificationCallback; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("4997053B-0ADF-4CC8-AC70-7A50C4BE728F") + IDeckLinkDeviceNotificationCallback : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE DeckLinkDeviceArrived( + /* [in] */ IDeckLink *deckLinkDevice) = 0; + + virtual HRESULT STDMETHODCALLTYPE DeckLinkDeviceRemoved( + /* [in] */ IDeckLink *deckLinkDevice) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkDeviceNotificationCallbackVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkDeviceNotificationCallback * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkDeviceNotificationCallback * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkDeviceNotificationCallback * This); + + HRESULT ( STDMETHODCALLTYPE *DeckLinkDeviceArrived )( + IDeckLinkDeviceNotificationCallback * This, + /* [in] */ IDeckLink *deckLinkDevice); + + HRESULT ( STDMETHODCALLTYPE *DeckLinkDeviceRemoved )( + IDeckLinkDeviceNotificationCallback * This, + /* [in] */ IDeckLink *deckLinkDevice); + + END_INTERFACE + } IDeckLinkDeviceNotificationCallbackVtbl; + + interface IDeckLinkDeviceNotificationCallback + { + CONST_VTBL struct IDeckLinkDeviceNotificationCallbackVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkDeviceNotificationCallback_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkDeviceNotificationCallback_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkDeviceNotificationCallback_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkDeviceNotificationCallback_DeckLinkDeviceArrived(This,deckLinkDevice) \ + ( (This)->lpVtbl -> DeckLinkDeviceArrived(This,deckLinkDevice) ) + +#define IDeckLinkDeviceNotificationCallback_DeckLinkDeviceRemoved(This,deckLinkDevice) \ + ( (This)->lpVtbl -> DeckLinkDeviceRemoved(This,deckLinkDevice) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkDeviceNotificationCallback_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkDiscovery_INTERFACE_DEFINED__ +#define __IDeckLinkDiscovery_INTERFACE_DEFINED__ + +/* interface IDeckLinkDiscovery */ +/* [helpstring][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkDiscovery; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("CDBF631C-BC76-45FA-B44D-C55059BC6101") + IDeckLinkDiscovery : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE InstallDeviceNotifications( + /* [in] */ IDeckLinkDeviceNotificationCallback *deviceNotificationCallback) = 0; + + virtual HRESULT STDMETHODCALLTYPE UninstallDeviceNotifications( void) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkDiscoveryVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkDiscovery * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkDiscovery * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkDiscovery * This); + + HRESULT ( STDMETHODCALLTYPE *InstallDeviceNotifications )( + IDeckLinkDiscovery * This, + /* [in] */ IDeckLinkDeviceNotificationCallback *deviceNotificationCallback); + + HRESULT ( STDMETHODCALLTYPE *UninstallDeviceNotifications )( + IDeckLinkDiscovery * This); + + END_INTERFACE + } IDeckLinkDiscoveryVtbl; + + interface IDeckLinkDiscovery + { + CONST_VTBL struct IDeckLinkDiscoveryVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkDiscovery_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkDiscovery_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkDiscovery_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkDiscovery_InstallDeviceNotifications(This,deviceNotificationCallback) \ + ( (This)->lpVtbl -> InstallDeviceNotifications(This,deviceNotificationCallback) ) + +#define IDeckLinkDiscovery_UninstallDeviceNotifications(This) \ + ( (This)->lpVtbl -> UninstallDeviceNotifications(This) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkDiscovery_INTERFACE_DEFINED__ */ + + +EXTERN_C const CLSID CLSID_CDeckLinkIterator; + +#ifdef __cplusplus + +class DECLSPEC_UUID("1F2E109A-8F4F-49E4-9203-135595CB6FA5") +CDeckLinkIterator; +#endif + +EXTERN_C const CLSID CLSID_CDeckLinkAPIInformation; + +#ifdef __cplusplus + +class DECLSPEC_UUID("263CA19F-ED09-482E-9F9D-84005783A237") +CDeckLinkAPIInformation; +#endif + +EXTERN_C const CLSID CLSID_CDeckLinkGLScreenPreviewHelper; + +#ifdef __cplusplus + +class DECLSPEC_UUID("F63E77C7-B655-4A4A-9AD0-3CA85D394343") +CDeckLinkGLScreenPreviewHelper; +#endif + +EXTERN_C const CLSID CLSID_CDeckLinkDX9ScreenPreviewHelper; + +#ifdef __cplusplus + +class DECLSPEC_UUID("CC010023-E01D-4525-9D59-80C8AB3DC7A0") +CDeckLinkDX9ScreenPreviewHelper; +#endif + +EXTERN_C const CLSID CLSID_CDeckLinkVideoConversion; + +#ifdef __cplusplus + +class DECLSPEC_UUID("7DBBBB11-5B7B-467D-AEA4-CEA468FD368C") +CDeckLinkVideoConversion; +#endif + +EXTERN_C const CLSID CLSID_CDeckLinkDiscovery; + +#ifdef __cplusplus + +class DECLSPEC_UUID("1073A05C-D885-47E9-B3C6-129B3F9F648B") +CDeckLinkDiscovery; +#endif + +#ifndef __IDeckLinkConfiguration_v10_2_INTERFACE_DEFINED__ +#define __IDeckLinkConfiguration_v10_2_INTERFACE_DEFINED__ + +/* interface IDeckLinkConfiguration_v10_2 */ +/* [helpstring][local][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkConfiguration_v10_2; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("C679A35B-610C-4D09-B748-1D0478100FC0") + IDeckLinkConfiguration_v10_2 : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE SetFlag( + /* [in] */ BMDDeckLinkConfigurationID cfgID, + /* [in] */ BOOL value) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetFlag( + /* [in] */ BMDDeckLinkConfigurationID cfgID, + /* [out] */ BOOL *value) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetInt( + /* [in] */ BMDDeckLinkConfigurationID cfgID, + /* [in] */ LONGLONG value) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetInt( + /* [in] */ BMDDeckLinkConfigurationID cfgID, + /* [out] */ LONGLONG *value) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetFloat( + /* [in] */ BMDDeckLinkConfigurationID cfgID, + /* [in] */ double value) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetFloat( + /* [in] */ BMDDeckLinkConfigurationID cfgID, + /* [out] */ double *value) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetString( + /* [in] */ BMDDeckLinkConfigurationID cfgID, + /* [in] */ BSTR value) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetString( + /* [in] */ BMDDeckLinkConfigurationID cfgID, + /* [out] */ BSTR *value) = 0; + + virtual HRESULT STDMETHODCALLTYPE WriteConfigurationToPreferences( void) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkConfiguration_v10_2Vtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkConfiguration_v10_2 * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkConfiguration_v10_2 * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkConfiguration_v10_2 * This); + + HRESULT ( STDMETHODCALLTYPE *SetFlag )( + IDeckLinkConfiguration_v10_2 * This, + /* [in] */ BMDDeckLinkConfigurationID cfgID, + /* [in] */ BOOL value); + + HRESULT ( STDMETHODCALLTYPE *GetFlag )( + IDeckLinkConfiguration_v10_2 * This, + /* [in] */ BMDDeckLinkConfigurationID cfgID, + /* [out] */ BOOL *value); + + HRESULT ( STDMETHODCALLTYPE *SetInt )( + IDeckLinkConfiguration_v10_2 * This, + /* [in] */ BMDDeckLinkConfigurationID cfgID, + /* [in] */ LONGLONG value); + + HRESULT ( STDMETHODCALLTYPE *GetInt )( + IDeckLinkConfiguration_v10_2 * This, + /* [in] */ BMDDeckLinkConfigurationID cfgID, + /* [out] */ LONGLONG *value); + + HRESULT ( STDMETHODCALLTYPE *SetFloat )( + IDeckLinkConfiguration_v10_2 * This, + /* [in] */ BMDDeckLinkConfigurationID cfgID, + /* [in] */ double value); + + HRESULT ( STDMETHODCALLTYPE *GetFloat )( + IDeckLinkConfiguration_v10_2 * This, + /* [in] */ BMDDeckLinkConfigurationID cfgID, + /* [out] */ double *value); + + HRESULT ( STDMETHODCALLTYPE *SetString )( + IDeckLinkConfiguration_v10_2 * This, + /* [in] */ BMDDeckLinkConfigurationID cfgID, + /* [in] */ BSTR value); + + HRESULT ( STDMETHODCALLTYPE *GetString )( + IDeckLinkConfiguration_v10_2 * This, + /* [in] */ BMDDeckLinkConfigurationID cfgID, + /* [out] */ BSTR *value); + + HRESULT ( STDMETHODCALLTYPE *WriteConfigurationToPreferences )( + IDeckLinkConfiguration_v10_2 * This); + + END_INTERFACE + } IDeckLinkConfiguration_v10_2Vtbl; + + interface IDeckLinkConfiguration_v10_2 + { + CONST_VTBL struct IDeckLinkConfiguration_v10_2Vtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkConfiguration_v10_2_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkConfiguration_v10_2_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkConfiguration_v10_2_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkConfiguration_v10_2_SetFlag(This,cfgID,value) \ + ( (This)->lpVtbl -> SetFlag(This,cfgID,value) ) + +#define IDeckLinkConfiguration_v10_2_GetFlag(This,cfgID,value) \ + ( (This)->lpVtbl -> GetFlag(This,cfgID,value) ) + +#define IDeckLinkConfiguration_v10_2_SetInt(This,cfgID,value) \ + ( (This)->lpVtbl -> SetInt(This,cfgID,value) ) + +#define IDeckLinkConfiguration_v10_2_GetInt(This,cfgID,value) \ + ( (This)->lpVtbl -> GetInt(This,cfgID,value) ) + +#define IDeckLinkConfiguration_v10_2_SetFloat(This,cfgID,value) \ + ( (This)->lpVtbl -> SetFloat(This,cfgID,value) ) + +#define IDeckLinkConfiguration_v10_2_GetFloat(This,cfgID,value) \ + ( (This)->lpVtbl -> GetFloat(This,cfgID,value) ) + +#define IDeckLinkConfiguration_v10_2_SetString(This,cfgID,value) \ + ( (This)->lpVtbl -> SetString(This,cfgID,value) ) + +#define IDeckLinkConfiguration_v10_2_GetString(This,cfgID,value) \ + ( (This)->lpVtbl -> GetString(This,cfgID,value) ) + +#define IDeckLinkConfiguration_v10_2_WriteConfigurationToPreferences(This) \ + ( (This)->lpVtbl -> WriteConfigurationToPreferences(This) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkConfiguration_v10_2_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkOutput_v9_9_INTERFACE_DEFINED__ +#define __IDeckLinkOutput_v9_9_INTERFACE_DEFINED__ + +/* interface IDeckLinkOutput_v9_9 */ +/* [helpstring][local][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkOutput_v9_9; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("A3EF0963-0862-44ED-92A9-EE89ABF431C7") + IDeckLinkOutput_v9_9 : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE DoesSupportVideoMode( + /* [in] */ BMDDisplayMode displayMode, + /* [in] */ BMDPixelFormat pixelFormat, + /* [in] */ BMDVideoOutputFlags flags, + /* [out] */ BMDDisplayModeSupport *result, + /* [out] */ IDeckLinkDisplayMode **resultDisplayMode) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetDisplayModeIterator( + /* [out] */ IDeckLinkDisplayModeIterator **iterator) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetScreenPreviewCallback( + /* [in] */ IDeckLinkScreenPreviewCallback *previewCallback) = 0; + + virtual HRESULT STDMETHODCALLTYPE EnableVideoOutput( + /* [in] */ BMDDisplayMode displayMode, + /* [in] */ BMDVideoOutputFlags flags) = 0; + + virtual HRESULT STDMETHODCALLTYPE DisableVideoOutput( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetVideoOutputFrameMemoryAllocator( + /* [in] */ IDeckLinkMemoryAllocator *theAllocator) = 0; + + virtual HRESULT STDMETHODCALLTYPE CreateVideoFrame( + /* [in] */ int width, + /* [in] */ int height, + /* [in] */ int rowBytes, + /* [in] */ BMDPixelFormat pixelFormat, + /* [in] */ BMDFrameFlags flags, + /* [out] */ IDeckLinkMutableVideoFrame **outFrame) = 0; + + virtual HRESULT STDMETHODCALLTYPE CreateAncillaryData( + /* [in] */ BMDPixelFormat pixelFormat, + /* [out] */ IDeckLinkVideoFrameAncillary **outBuffer) = 0; + + virtual HRESULT STDMETHODCALLTYPE DisplayVideoFrameSync( + /* [in] */ IDeckLinkVideoFrame *theFrame) = 0; + + virtual HRESULT STDMETHODCALLTYPE ScheduleVideoFrame( + /* [in] */ IDeckLinkVideoFrame *theFrame, + /* [in] */ BMDTimeValue displayTime, + /* [in] */ BMDTimeValue displayDuration, + /* [in] */ BMDTimeScale timeScale) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetScheduledFrameCompletionCallback( + /* [in] */ IDeckLinkVideoOutputCallback *theCallback) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetBufferedVideoFrameCount( + /* [out] */ unsigned int *bufferedFrameCount) = 0; + + virtual HRESULT STDMETHODCALLTYPE EnableAudioOutput( + /* [in] */ BMDAudioSampleRate sampleRate, + /* [in] */ BMDAudioSampleType sampleType, + /* [in] */ unsigned int channelCount, + /* [in] */ BMDAudioOutputStreamType streamType) = 0; + + virtual HRESULT STDMETHODCALLTYPE DisableAudioOutput( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE WriteAudioSamplesSync( + /* [in] */ void *buffer, + /* [in] */ unsigned int sampleFrameCount, + /* [out] */ unsigned int *sampleFramesWritten) = 0; + + virtual HRESULT STDMETHODCALLTYPE BeginAudioPreroll( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE EndAudioPreroll( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE ScheduleAudioSamples( + /* [in] */ void *buffer, + /* [in] */ unsigned int sampleFrameCount, + /* [in] */ BMDTimeValue streamTime, + /* [in] */ BMDTimeScale timeScale, + /* [out] */ unsigned int *sampleFramesWritten) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetBufferedAudioSampleFrameCount( + /* [out] */ unsigned int *bufferedSampleFrameCount) = 0; + + virtual HRESULT STDMETHODCALLTYPE FlushBufferedAudioSamples( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetAudioCallback( + /* [in] */ IDeckLinkAudioOutputCallback *theCallback) = 0; + + virtual HRESULT STDMETHODCALLTYPE StartScheduledPlayback( + /* [in] */ BMDTimeValue playbackStartTime, + /* [in] */ BMDTimeScale timeScale, + /* [in] */ double playbackSpeed) = 0; + + virtual HRESULT STDMETHODCALLTYPE StopScheduledPlayback( + /* [in] */ BMDTimeValue stopPlaybackAtTime, + /* [out] */ BMDTimeValue *actualStopTime, + /* [in] */ BMDTimeScale timeScale) = 0; + + virtual HRESULT STDMETHODCALLTYPE IsScheduledPlaybackRunning( + /* [out] */ BOOL *active) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetScheduledStreamTime( + /* [in] */ BMDTimeScale desiredTimeScale, + /* [out] */ BMDTimeValue *streamTime, + /* [out] */ double *playbackSpeed) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetReferenceStatus( + /* [out] */ BMDReferenceStatus *referenceStatus) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetHardwareReferenceClock( + /* [in] */ BMDTimeScale desiredTimeScale, + /* [out] */ BMDTimeValue *hardwareTime, + /* [out] */ BMDTimeValue *timeInFrame, + /* [out] */ BMDTimeValue *ticksPerFrame) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkOutput_v9_9Vtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkOutput_v9_9 * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkOutput_v9_9 * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkOutput_v9_9 * This); + + HRESULT ( STDMETHODCALLTYPE *DoesSupportVideoMode )( + IDeckLinkOutput_v9_9 * This, + /* [in] */ BMDDisplayMode displayMode, + /* [in] */ BMDPixelFormat pixelFormat, + /* [in] */ BMDVideoOutputFlags flags, + /* [out] */ BMDDisplayModeSupport *result, + /* [out] */ IDeckLinkDisplayMode **resultDisplayMode); + + HRESULT ( STDMETHODCALLTYPE *GetDisplayModeIterator )( + IDeckLinkOutput_v9_9 * This, + /* [out] */ IDeckLinkDisplayModeIterator **iterator); + + HRESULT ( STDMETHODCALLTYPE *SetScreenPreviewCallback )( + IDeckLinkOutput_v9_9 * This, + /* [in] */ IDeckLinkScreenPreviewCallback *previewCallback); + + HRESULT ( STDMETHODCALLTYPE *EnableVideoOutput )( + IDeckLinkOutput_v9_9 * This, + /* [in] */ BMDDisplayMode displayMode, + /* [in] */ BMDVideoOutputFlags flags); + + HRESULT ( STDMETHODCALLTYPE *DisableVideoOutput )( + IDeckLinkOutput_v9_9 * This); + + HRESULT ( STDMETHODCALLTYPE *SetVideoOutputFrameMemoryAllocator )( + IDeckLinkOutput_v9_9 * This, + /* [in] */ IDeckLinkMemoryAllocator *theAllocator); + + HRESULT ( STDMETHODCALLTYPE *CreateVideoFrame )( + IDeckLinkOutput_v9_9 * This, + /* [in] */ int width, + /* [in] */ int height, + /* [in] */ int rowBytes, + /* [in] */ BMDPixelFormat pixelFormat, + /* [in] */ BMDFrameFlags flags, + /* [out] */ IDeckLinkMutableVideoFrame **outFrame); + + HRESULT ( STDMETHODCALLTYPE *CreateAncillaryData )( + IDeckLinkOutput_v9_9 * This, + /* [in] */ BMDPixelFormat pixelFormat, + /* [out] */ IDeckLinkVideoFrameAncillary **outBuffer); + + HRESULT ( STDMETHODCALLTYPE *DisplayVideoFrameSync )( + IDeckLinkOutput_v9_9 * This, + /* [in] */ IDeckLinkVideoFrame *theFrame); + + HRESULT ( STDMETHODCALLTYPE *ScheduleVideoFrame )( + IDeckLinkOutput_v9_9 * This, + /* [in] */ IDeckLinkVideoFrame *theFrame, + /* [in] */ BMDTimeValue displayTime, + /* [in] */ BMDTimeValue displayDuration, + /* [in] */ BMDTimeScale timeScale); + + HRESULT ( STDMETHODCALLTYPE *SetScheduledFrameCompletionCallback )( + IDeckLinkOutput_v9_9 * This, + /* [in] */ IDeckLinkVideoOutputCallback *theCallback); + + HRESULT ( STDMETHODCALLTYPE *GetBufferedVideoFrameCount )( + IDeckLinkOutput_v9_9 * This, + /* [out] */ unsigned int *bufferedFrameCount); + + HRESULT ( STDMETHODCALLTYPE *EnableAudioOutput )( + IDeckLinkOutput_v9_9 * This, + /* [in] */ BMDAudioSampleRate sampleRate, + /* [in] */ BMDAudioSampleType sampleType, + /* [in] */ unsigned int channelCount, + /* [in] */ BMDAudioOutputStreamType streamType); + + HRESULT ( STDMETHODCALLTYPE *DisableAudioOutput )( + IDeckLinkOutput_v9_9 * This); + + HRESULT ( STDMETHODCALLTYPE *WriteAudioSamplesSync )( + IDeckLinkOutput_v9_9 * This, + /* [in] */ void *buffer, + /* [in] */ unsigned int sampleFrameCount, + /* [out] */ unsigned int *sampleFramesWritten); + + HRESULT ( STDMETHODCALLTYPE *BeginAudioPreroll )( + IDeckLinkOutput_v9_9 * This); + + HRESULT ( STDMETHODCALLTYPE *EndAudioPreroll )( + IDeckLinkOutput_v9_9 * This); + + HRESULT ( STDMETHODCALLTYPE *ScheduleAudioSamples )( + IDeckLinkOutput_v9_9 * This, + /* [in] */ void *buffer, + /* [in] */ unsigned int sampleFrameCount, + /* [in] */ BMDTimeValue streamTime, + /* [in] */ BMDTimeScale timeScale, + /* [out] */ unsigned int *sampleFramesWritten); + + HRESULT ( STDMETHODCALLTYPE *GetBufferedAudioSampleFrameCount )( + IDeckLinkOutput_v9_9 * This, + /* [out] */ unsigned int *bufferedSampleFrameCount); + + HRESULT ( STDMETHODCALLTYPE *FlushBufferedAudioSamples )( + IDeckLinkOutput_v9_9 * This); + + HRESULT ( STDMETHODCALLTYPE *SetAudioCallback )( + IDeckLinkOutput_v9_9 * This, + /* [in] */ IDeckLinkAudioOutputCallback *theCallback); + + HRESULT ( STDMETHODCALLTYPE *StartScheduledPlayback )( + IDeckLinkOutput_v9_9 * This, + /* [in] */ BMDTimeValue playbackStartTime, + /* [in] */ BMDTimeScale timeScale, + /* [in] */ double playbackSpeed); + + HRESULT ( STDMETHODCALLTYPE *StopScheduledPlayback )( + IDeckLinkOutput_v9_9 * This, + /* [in] */ BMDTimeValue stopPlaybackAtTime, + /* [out] */ BMDTimeValue *actualStopTime, + /* [in] */ BMDTimeScale timeScale); + + HRESULT ( STDMETHODCALLTYPE *IsScheduledPlaybackRunning )( + IDeckLinkOutput_v9_9 * This, + /* [out] */ BOOL *active); + + HRESULT ( STDMETHODCALLTYPE *GetScheduledStreamTime )( + IDeckLinkOutput_v9_9 * This, + /* [in] */ BMDTimeScale desiredTimeScale, + /* [out] */ BMDTimeValue *streamTime, + /* [out] */ double *playbackSpeed); + + HRESULT ( STDMETHODCALLTYPE *GetReferenceStatus )( + IDeckLinkOutput_v9_9 * This, + /* [out] */ BMDReferenceStatus *referenceStatus); + + HRESULT ( STDMETHODCALLTYPE *GetHardwareReferenceClock )( + IDeckLinkOutput_v9_9 * This, + /* [in] */ BMDTimeScale desiredTimeScale, + /* [out] */ BMDTimeValue *hardwareTime, + /* [out] */ BMDTimeValue *timeInFrame, + /* [out] */ BMDTimeValue *ticksPerFrame); + + END_INTERFACE + } IDeckLinkOutput_v9_9Vtbl; + + interface IDeckLinkOutput_v9_9 + { + CONST_VTBL struct IDeckLinkOutput_v9_9Vtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkOutput_v9_9_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkOutput_v9_9_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkOutput_v9_9_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkOutput_v9_9_DoesSupportVideoMode(This,displayMode,pixelFormat,flags,result,resultDisplayMode) \ + ( (This)->lpVtbl -> DoesSupportVideoMode(This,displayMode,pixelFormat,flags,result,resultDisplayMode) ) + +#define IDeckLinkOutput_v9_9_GetDisplayModeIterator(This,iterator) \ + ( (This)->lpVtbl -> GetDisplayModeIterator(This,iterator) ) + +#define IDeckLinkOutput_v9_9_SetScreenPreviewCallback(This,previewCallback) \ + ( (This)->lpVtbl -> SetScreenPreviewCallback(This,previewCallback) ) + +#define IDeckLinkOutput_v9_9_EnableVideoOutput(This,displayMode,flags) \ + ( (This)->lpVtbl -> EnableVideoOutput(This,displayMode,flags) ) + +#define IDeckLinkOutput_v9_9_DisableVideoOutput(This) \ + ( (This)->lpVtbl -> DisableVideoOutput(This) ) + +#define IDeckLinkOutput_v9_9_SetVideoOutputFrameMemoryAllocator(This,theAllocator) \ + ( (This)->lpVtbl -> SetVideoOutputFrameMemoryAllocator(This,theAllocator) ) + +#define IDeckLinkOutput_v9_9_CreateVideoFrame(This,width,height,rowBytes,pixelFormat,flags,outFrame) \ + ( (This)->lpVtbl -> CreateVideoFrame(This,width,height,rowBytes,pixelFormat,flags,outFrame) ) + +#define IDeckLinkOutput_v9_9_CreateAncillaryData(This,pixelFormat,outBuffer) \ + ( (This)->lpVtbl -> CreateAncillaryData(This,pixelFormat,outBuffer) ) + +#define IDeckLinkOutput_v9_9_DisplayVideoFrameSync(This,theFrame) \ + ( (This)->lpVtbl -> DisplayVideoFrameSync(This,theFrame) ) + +#define IDeckLinkOutput_v9_9_ScheduleVideoFrame(This,theFrame,displayTime,displayDuration,timeScale) \ + ( (This)->lpVtbl -> ScheduleVideoFrame(This,theFrame,displayTime,displayDuration,timeScale) ) + +#define IDeckLinkOutput_v9_9_SetScheduledFrameCompletionCallback(This,theCallback) \ + ( (This)->lpVtbl -> SetScheduledFrameCompletionCallback(This,theCallback) ) + +#define IDeckLinkOutput_v9_9_GetBufferedVideoFrameCount(This,bufferedFrameCount) \ + ( (This)->lpVtbl -> GetBufferedVideoFrameCount(This,bufferedFrameCount) ) + +#define IDeckLinkOutput_v9_9_EnableAudioOutput(This,sampleRate,sampleType,channelCount,streamType) \ + ( (This)->lpVtbl -> EnableAudioOutput(This,sampleRate,sampleType,channelCount,streamType) ) + +#define IDeckLinkOutput_v9_9_DisableAudioOutput(This) \ + ( (This)->lpVtbl -> DisableAudioOutput(This) ) + +#define IDeckLinkOutput_v9_9_WriteAudioSamplesSync(This,buffer,sampleFrameCount,sampleFramesWritten) \ + ( (This)->lpVtbl -> WriteAudioSamplesSync(This,buffer,sampleFrameCount,sampleFramesWritten) ) + +#define IDeckLinkOutput_v9_9_BeginAudioPreroll(This) \ + ( (This)->lpVtbl -> BeginAudioPreroll(This) ) + +#define IDeckLinkOutput_v9_9_EndAudioPreroll(This) \ + ( (This)->lpVtbl -> EndAudioPreroll(This) ) + +#define IDeckLinkOutput_v9_9_ScheduleAudioSamples(This,buffer,sampleFrameCount,streamTime,timeScale,sampleFramesWritten) \ + ( (This)->lpVtbl -> ScheduleAudioSamples(This,buffer,sampleFrameCount,streamTime,timeScale,sampleFramesWritten) ) + +#define IDeckLinkOutput_v9_9_GetBufferedAudioSampleFrameCount(This,bufferedSampleFrameCount) \ + ( (This)->lpVtbl -> GetBufferedAudioSampleFrameCount(This,bufferedSampleFrameCount) ) + +#define IDeckLinkOutput_v9_9_FlushBufferedAudioSamples(This) \ + ( (This)->lpVtbl -> FlushBufferedAudioSamples(This) ) + +#define IDeckLinkOutput_v9_9_SetAudioCallback(This,theCallback) \ + ( (This)->lpVtbl -> SetAudioCallback(This,theCallback) ) + +#define IDeckLinkOutput_v9_9_StartScheduledPlayback(This,playbackStartTime,timeScale,playbackSpeed) \ + ( (This)->lpVtbl -> StartScheduledPlayback(This,playbackStartTime,timeScale,playbackSpeed) ) + +#define IDeckLinkOutput_v9_9_StopScheduledPlayback(This,stopPlaybackAtTime,actualStopTime,timeScale) \ + ( (This)->lpVtbl -> StopScheduledPlayback(This,stopPlaybackAtTime,actualStopTime,timeScale) ) + +#define IDeckLinkOutput_v9_9_IsScheduledPlaybackRunning(This,active) \ + ( (This)->lpVtbl -> IsScheduledPlaybackRunning(This,active) ) + +#define IDeckLinkOutput_v9_9_GetScheduledStreamTime(This,desiredTimeScale,streamTime,playbackSpeed) \ + ( (This)->lpVtbl -> GetScheduledStreamTime(This,desiredTimeScale,streamTime,playbackSpeed) ) + +#define IDeckLinkOutput_v9_9_GetReferenceStatus(This,referenceStatus) \ + ( (This)->lpVtbl -> GetReferenceStatus(This,referenceStatus) ) + +#define IDeckLinkOutput_v9_9_GetHardwareReferenceClock(This,desiredTimeScale,hardwareTime,timeInFrame,ticksPerFrame) \ + ( (This)->lpVtbl -> GetHardwareReferenceClock(This,desiredTimeScale,hardwareTime,timeInFrame,ticksPerFrame) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkOutput_v9_9_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkInput_v9_2_INTERFACE_DEFINED__ +#define __IDeckLinkInput_v9_2_INTERFACE_DEFINED__ + +/* interface IDeckLinkInput_v9_2 */ +/* [helpstring][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkInput_v9_2; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("6D40EF78-28B9-4E21-990D-95BB7750A04F") + IDeckLinkInput_v9_2 : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE DoesSupportVideoMode( + /* [in] */ BMDDisplayMode displayMode, + /* [in] */ BMDPixelFormat pixelFormat, + /* [in] */ BMDVideoInputFlags flags, + /* [out] */ BMDDisplayModeSupport *result, + /* [out] */ IDeckLinkDisplayMode **resultDisplayMode) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetDisplayModeIterator( + /* [out] */ IDeckLinkDisplayModeIterator **iterator) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetScreenPreviewCallback( + /* [in] */ IDeckLinkScreenPreviewCallback *previewCallback) = 0; + + virtual HRESULT STDMETHODCALLTYPE EnableVideoInput( + /* [in] */ BMDDisplayMode displayMode, + /* [in] */ BMDPixelFormat pixelFormat, + /* [in] */ BMDVideoInputFlags flags) = 0; + + virtual HRESULT STDMETHODCALLTYPE DisableVideoInput( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetAvailableVideoFrameCount( + /* [out] */ unsigned int *availableFrameCount) = 0; + + virtual HRESULT STDMETHODCALLTYPE EnableAudioInput( + /* [in] */ BMDAudioSampleRate sampleRate, + /* [in] */ BMDAudioSampleType sampleType, + /* [in] */ unsigned int channelCount) = 0; + + virtual HRESULT STDMETHODCALLTYPE DisableAudioInput( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetAvailableAudioSampleFrameCount( + /* [out] */ unsigned int *availableSampleFrameCount) = 0; + + virtual HRESULT STDMETHODCALLTYPE StartStreams( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE StopStreams( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE PauseStreams( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE FlushStreams( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetCallback( + /* [in] */ IDeckLinkInputCallback *theCallback) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetHardwareReferenceClock( + /* [in] */ BMDTimeScale desiredTimeScale, + /* [out] */ BMDTimeValue *hardwareTime, + /* [out] */ BMDTimeValue *timeInFrame, + /* [out] */ BMDTimeValue *ticksPerFrame) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkInput_v9_2Vtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkInput_v9_2 * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkInput_v9_2 * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkInput_v9_2 * This); + + HRESULT ( STDMETHODCALLTYPE *DoesSupportVideoMode )( + IDeckLinkInput_v9_2 * This, + /* [in] */ BMDDisplayMode displayMode, + /* [in] */ BMDPixelFormat pixelFormat, + /* [in] */ BMDVideoInputFlags flags, + /* [out] */ BMDDisplayModeSupport *result, + /* [out] */ IDeckLinkDisplayMode **resultDisplayMode); + + HRESULT ( STDMETHODCALLTYPE *GetDisplayModeIterator )( + IDeckLinkInput_v9_2 * This, + /* [out] */ IDeckLinkDisplayModeIterator **iterator); + + HRESULT ( STDMETHODCALLTYPE *SetScreenPreviewCallback )( + IDeckLinkInput_v9_2 * This, + /* [in] */ IDeckLinkScreenPreviewCallback *previewCallback); + + HRESULT ( STDMETHODCALLTYPE *EnableVideoInput )( + IDeckLinkInput_v9_2 * This, + /* [in] */ BMDDisplayMode displayMode, + /* [in] */ BMDPixelFormat pixelFormat, + /* [in] */ BMDVideoInputFlags flags); + + HRESULT ( STDMETHODCALLTYPE *DisableVideoInput )( + IDeckLinkInput_v9_2 * This); + + HRESULT ( STDMETHODCALLTYPE *GetAvailableVideoFrameCount )( + IDeckLinkInput_v9_2 * This, + /* [out] */ unsigned int *availableFrameCount); + + HRESULT ( STDMETHODCALLTYPE *EnableAudioInput )( + IDeckLinkInput_v9_2 * This, + /* [in] */ BMDAudioSampleRate sampleRate, + /* [in] */ BMDAudioSampleType sampleType, + /* [in] */ unsigned int channelCount); + + HRESULT ( STDMETHODCALLTYPE *DisableAudioInput )( + IDeckLinkInput_v9_2 * This); + + HRESULT ( STDMETHODCALLTYPE *GetAvailableAudioSampleFrameCount )( + IDeckLinkInput_v9_2 * This, + /* [out] */ unsigned int *availableSampleFrameCount); + + HRESULT ( STDMETHODCALLTYPE *StartStreams )( + IDeckLinkInput_v9_2 * This); + + HRESULT ( STDMETHODCALLTYPE *StopStreams )( + IDeckLinkInput_v9_2 * This); + + HRESULT ( STDMETHODCALLTYPE *PauseStreams )( + IDeckLinkInput_v9_2 * This); + + HRESULT ( STDMETHODCALLTYPE *FlushStreams )( + IDeckLinkInput_v9_2 * This); + + HRESULT ( STDMETHODCALLTYPE *SetCallback )( + IDeckLinkInput_v9_2 * This, + /* [in] */ IDeckLinkInputCallback *theCallback); + + HRESULT ( STDMETHODCALLTYPE *GetHardwareReferenceClock )( + IDeckLinkInput_v9_2 * This, + /* [in] */ BMDTimeScale desiredTimeScale, + /* [out] */ BMDTimeValue *hardwareTime, + /* [out] */ BMDTimeValue *timeInFrame, + /* [out] */ BMDTimeValue *ticksPerFrame); + + END_INTERFACE + } IDeckLinkInput_v9_2Vtbl; + + interface IDeckLinkInput_v9_2 + { + CONST_VTBL struct IDeckLinkInput_v9_2Vtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkInput_v9_2_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkInput_v9_2_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkInput_v9_2_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkInput_v9_2_DoesSupportVideoMode(This,displayMode,pixelFormat,flags,result,resultDisplayMode) \ + ( (This)->lpVtbl -> DoesSupportVideoMode(This,displayMode,pixelFormat,flags,result,resultDisplayMode) ) + +#define IDeckLinkInput_v9_2_GetDisplayModeIterator(This,iterator) \ + ( (This)->lpVtbl -> GetDisplayModeIterator(This,iterator) ) + +#define IDeckLinkInput_v9_2_SetScreenPreviewCallback(This,previewCallback) \ + ( (This)->lpVtbl -> SetScreenPreviewCallback(This,previewCallback) ) + +#define IDeckLinkInput_v9_2_EnableVideoInput(This,displayMode,pixelFormat,flags) \ + ( (This)->lpVtbl -> EnableVideoInput(This,displayMode,pixelFormat,flags) ) + +#define IDeckLinkInput_v9_2_DisableVideoInput(This) \ + ( (This)->lpVtbl -> DisableVideoInput(This) ) + +#define IDeckLinkInput_v9_2_GetAvailableVideoFrameCount(This,availableFrameCount) \ + ( (This)->lpVtbl -> GetAvailableVideoFrameCount(This,availableFrameCount) ) + +#define IDeckLinkInput_v9_2_EnableAudioInput(This,sampleRate,sampleType,channelCount) \ + ( (This)->lpVtbl -> EnableAudioInput(This,sampleRate,sampleType,channelCount) ) + +#define IDeckLinkInput_v9_2_DisableAudioInput(This) \ + ( (This)->lpVtbl -> DisableAudioInput(This) ) + +#define IDeckLinkInput_v9_2_GetAvailableAudioSampleFrameCount(This,availableSampleFrameCount) \ + ( (This)->lpVtbl -> GetAvailableAudioSampleFrameCount(This,availableSampleFrameCount) ) + +#define IDeckLinkInput_v9_2_StartStreams(This) \ + ( (This)->lpVtbl -> StartStreams(This) ) + +#define IDeckLinkInput_v9_2_StopStreams(This) \ + ( (This)->lpVtbl -> StopStreams(This) ) + +#define IDeckLinkInput_v9_2_PauseStreams(This) \ + ( (This)->lpVtbl -> PauseStreams(This) ) + +#define IDeckLinkInput_v9_2_FlushStreams(This) \ + ( (This)->lpVtbl -> FlushStreams(This) ) + +#define IDeckLinkInput_v9_2_SetCallback(This,theCallback) \ + ( (This)->lpVtbl -> SetCallback(This,theCallback) ) + +#define IDeckLinkInput_v9_2_GetHardwareReferenceClock(This,desiredTimeScale,hardwareTime,timeInFrame,ticksPerFrame) \ + ( (This)->lpVtbl -> GetHardwareReferenceClock(This,desiredTimeScale,hardwareTime,timeInFrame,ticksPerFrame) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkInput_v9_2_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkDeckControlStatusCallback_v8_1_INTERFACE_DEFINED__ +#define __IDeckLinkDeckControlStatusCallback_v8_1_INTERFACE_DEFINED__ + +/* interface IDeckLinkDeckControlStatusCallback_v8_1 */ +/* [helpstring][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkDeckControlStatusCallback_v8_1; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("E5F693C1-4283-4716-B18F-C1431521955B") + IDeckLinkDeckControlStatusCallback_v8_1 : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE TimecodeUpdate( + /* [in] */ BMDTimecodeBCD currentTimecode) = 0; + + virtual HRESULT STDMETHODCALLTYPE VTRControlStateChanged( + /* [in] */ BMDDeckControlVTRControlState_v8_1 newState, + /* [in] */ BMDDeckControlError error) = 0; + + virtual HRESULT STDMETHODCALLTYPE DeckControlEventReceived( + /* [in] */ BMDDeckControlEvent event, + /* [in] */ BMDDeckControlError error) = 0; + + virtual HRESULT STDMETHODCALLTYPE DeckControlStatusChanged( + /* [in] */ BMDDeckControlStatusFlags flags, + /* [in] */ unsigned int mask) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkDeckControlStatusCallback_v8_1Vtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkDeckControlStatusCallback_v8_1 * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkDeckControlStatusCallback_v8_1 * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkDeckControlStatusCallback_v8_1 * This); + + HRESULT ( STDMETHODCALLTYPE *TimecodeUpdate )( + IDeckLinkDeckControlStatusCallback_v8_1 * This, + /* [in] */ BMDTimecodeBCD currentTimecode); + + HRESULT ( STDMETHODCALLTYPE *VTRControlStateChanged )( + IDeckLinkDeckControlStatusCallback_v8_1 * This, + /* [in] */ BMDDeckControlVTRControlState_v8_1 newState, + /* [in] */ BMDDeckControlError error); + + HRESULT ( STDMETHODCALLTYPE *DeckControlEventReceived )( + IDeckLinkDeckControlStatusCallback_v8_1 * This, + /* [in] */ BMDDeckControlEvent event, + /* [in] */ BMDDeckControlError error); + + HRESULT ( STDMETHODCALLTYPE *DeckControlStatusChanged )( + IDeckLinkDeckControlStatusCallback_v8_1 * This, + /* [in] */ BMDDeckControlStatusFlags flags, + /* [in] */ unsigned int mask); + + END_INTERFACE + } IDeckLinkDeckControlStatusCallback_v8_1Vtbl; + + interface IDeckLinkDeckControlStatusCallback_v8_1 + { + CONST_VTBL struct IDeckLinkDeckControlStatusCallback_v8_1Vtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkDeckControlStatusCallback_v8_1_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkDeckControlStatusCallback_v8_1_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkDeckControlStatusCallback_v8_1_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkDeckControlStatusCallback_v8_1_TimecodeUpdate(This,currentTimecode) \ + ( (This)->lpVtbl -> TimecodeUpdate(This,currentTimecode) ) + +#define IDeckLinkDeckControlStatusCallback_v8_1_VTRControlStateChanged(This,newState,error) \ + ( (This)->lpVtbl -> VTRControlStateChanged(This,newState,error) ) + +#define IDeckLinkDeckControlStatusCallback_v8_1_DeckControlEventReceived(This,event,error) \ + ( (This)->lpVtbl -> DeckControlEventReceived(This,event,error) ) + +#define IDeckLinkDeckControlStatusCallback_v8_1_DeckControlStatusChanged(This,flags,mask) \ + ( (This)->lpVtbl -> DeckControlStatusChanged(This,flags,mask) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkDeckControlStatusCallback_v8_1_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkDeckControl_v8_1_INTERFACE_DEFINED__ +#define __IDeckLinkDeckControl_v8_1_INTERFACE_DEFINED__ + +/* interface IDeckLinkDeckControl_v8_1 */ +/* [helpstring][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkDeckControl_v8_1; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("522A9E39-0F3C-4742-94EE-D80DE335DA1D") + IDeckLinkDeckControl_v8_1 : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE Open( + /* [in] */ BMDTimeScale timeScale, + /* [in] */ BMDTimeValue timeValue, + /* [in] */ BOOL timecodeIsDropFrame, + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE Close( + /* [in] */ BOOL standbyOn) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetCurrentState( + /* [out] */ BMDDeckControlMode *mode, + /* [out] */ BMDDeckControlVTRControlState_v8_1 *vtrControlState, + /* [out] */ BMDDeckControlStatusFlags *flags) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetStandby( + /* [in] */ BOOL standbyOn) = 0; + + virtual HRESULT STDMETHODCALLTYPE SendCommand( + /* [in] */ unsigned char *inBuffer, + /* [in] */ unsigned int inBufferSize, + /* [out] */ unsigned char *outBuffer, + /* [out] */ unsigned int *outDataSize, + /* [in] */ unsigned int outBufferSize, + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE Play( + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE Stop( + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE TogglePlayStop( + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE Eject( + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE GoToTimecode( + /* [in] */ BMDTimecodeBCD timecode, + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE FastForward( + /* [in] */ BOOL viewTape, + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE Rewind( + /* [in] */ BOOL viewTape, + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE StepForward( + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE StepBack( + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE Jog( + /* [in] */ double rate, + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE Shuttle( + /* [in] */ double rate, + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetTimecodeString( + /* [out] */ BSTR *currentTimeCode, + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetTimecode( + /* [out] */ IDeckLinkTimecode **currentTimecode, + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetTimecodeBCD( + /* [out] */ BMDTimecodeBCD *currentTimecode, + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetPreroll( + /* [in] */ unsigned int prerollSeconds) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetPreroll( + /* [out] */ unsigned int *prerollSeconds) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetExportOffset( + /* [in] */ int exportOffsetFields) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetExportOffset( + /* [out] */ int *exportOffsetFields) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetManualExportOffset( + /* [out] */ int *deckManualExportOffsetFields) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetCaptureOffset( + /* [in] */ int captureOffsetFields) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetCaptureOffset( + /* [out] */ int *captureOffsetFields) = 0; + + virtual HRESULT STDMETHODCALLTYPE StartExport( + /* [in] */ BMDTimecodeBCD inTimecode, + /* [in] */ BMDTimecodeBCD outTimecode, + /* [in] */ BMDDeckControlExportModeOpsFlags exportModeOps, + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE StartCapture( + /* [in] */ BOOL useVITC, + /* [in] */ BMDTimecodeBCD inTimecode, + /* [in] */ BMDTimecodeBCD outTimecode, + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetDeviceID( + /* [out] */ unsigned short *deviceId, + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE Abort( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE CrashRecordStart( + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE CrashRecordStop( + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetCallback( + /* [in] */ IDeckLinkDeckControlStatusCallback_v8_1 *callback) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkDeckControl_v8_1Vtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkDeckControl_v8_1 * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkDeckControl_v8_1 * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkDeckControl_v8_1 * This); + + HRESULT ( STDMETHODCALLTYPE *Open )( + IDeckLinkDeckControl_v8_1 * This, + /* [in] */ BMDTimeScale timeScale, + /* [in] */ BMDTimeValue timeValue, + /* [in] */ BOOL timecodeIsDropFrame, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *Close )( + IDeckLinkDeckControl_v8_1 * This, + /* [in] */ BOOL standbyOn); + + HRESULT ( STDMETHODCALLTYPE *GetCurrentState )( + IDeckLinkDeckControl_v8_1 * This, + /* [out] */ BMDDeckControlMode *mode, + /* [out] */ BMDDeckControlVTRControlState_v8_1 *vtrControlState, + /* [out] */ BMDDeckControlStatusFlags *flags); + + HRESULT ( STDMETHODCALLTYPE *SetStandby )( + IDeckLinkDeckControl_v8_1 * This, + /* [in] */ BOOL standbyOn); + + HRESULT ( STDMETHODCALLTYPE *SendCommand )( + IDeckLinkDeckControl_v8_1 * This, + /* [in] */ unsigned char *inBuffer, + /* [in] */ unsigned int inBufferSize, + /* [out] */ unsigned char *outBuffer, + /* [out] */ unsigned int *outDataSize, + /* [in] */ unsigned int outBufferSize, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *Play )( + IDeckLinkDeckControl_v8_1 * This, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *Stop )( + IDeckLinkDeckControl_v8_1 * This, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *TogglePlayStop )( + IDeckLinkDeckControl_v8_1 * This, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *Eject )( + IDeckLinkDeckControl_v8_1 * This, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *GoToTimecode )( + IDeckLinkDeckControl_v8_1 * This, + /* [in] */ BMDTimecodeBCD timecode, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *FastForward )( + IDeckLinkDeckControl_v8_1 * This, + /* [in] */ BOOL viewTape, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *Rewind )( + IDeckLinkDeckControl_v8_1 * This, + /* [in] */ BOOL viewTape, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *StepForward )( + IDeckLinkDeckControl_v8_1 * This, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *StepBack )( + IDeckLinkDeckControl_v8_1 * This, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *Jog )( + IDeckLinkDeckControl_v8_1 * This, + /* [in] */ double rate, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *Shuttle )( + IDeckLinkDeckControl_v8_1 * This, + /* [in] */ double rate, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *GetTimecodeString )( + IDeckLinkDeckControl_v8_1 * This, + /* [out] */ BSTR *currentTimeCode, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *GetTimecode )( + IDeckLinkDeckControl_v8_1 * This, + /* [out] */ IDeckLinkTimecode **currentTimecode, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *GetTimecodeBCD )( + IDeckLinkDeckControl_v8_1 * This, + /* [out] */ BMDTimecodeBCD *currentTimecode, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *SetPreroll )( + IDeckLinkDeckControl_v8_1 * This, + /* [in] */ unsigned int prerollSeconds); + + HRESULT ( STDMETHODCALLTYPE *GetPreroll )( + IDeckLinkDeckControl_v8_1 * This, + /* [out] */ unsigned int *prerollSeconds); + + HRESULT ( STDMETHODCALLTYPE *SetExportOffset )( + IDeckLinkDeckControl_v8_1 * This, + /* [in] */ int exportOffsetFields); + + HRESULT ( STDMETHODCALLTYPE *GetExportOffset )( + IDeckLinkDeckControl_v8_1 * This, + /* [out] */ int *exportOffsetFields); + + HRESULT ( STDMETHODCALLTYPE *GetManualExportOffset )( + IDeckLinkDeckControl_v8_1 * This, + /* [out] */ int *deckManualExportOffsetFields); + + HRESULT ( STDMETHODCALLTYPE *SetCaptureOffset )( + IDeckLinkDeckControl_v8_1 * This, + /* [in] */ int captureOffsetFields); + + HRESULT ( STDMETHODCALLTYPE *GetCaptureOffset )( + IDeckLinkDeckControl_v8_1 * This, + /* [out] */ int *captureOffsetFields); + + HRESULT ( STDMETHODCALLTYPE *StartExport )( + IDeckLinkDeckControl_v8_1 * This, + /* [in] */ BMDTimecodeBCD inTimecode, + /* [in] */ BMDTimecodeBCD outTimecode, + /* [in] */ BMDDeckControlExportModeOpsFlags exportModeOps, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *StartCapture )( + IDeckLinkDeckControl_v8_1 * This, + /* [in] */ BOOL useVITC, + /* [in] */ BMDTimecodeBCD inTimecode, + /* [in] */ BMDTimecodeBCD outTimecode, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *GetDeviceID )( + IDeckLinkDeckControl_v8_1 * This, + /* [out] */ unsigned short *deviceId, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *Abort )( + IDeckLinkDeckControl_v8_1 * This); + + HRESULT ( STDMETHODCALLTYPE *CrashRecordStart )( + IDeckLinkDeckControl_v8_1 * This, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *CrashRecordStop )( + IDeckLinkDeckControl_v8_1 * This, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *SetCallback )( + IDeckLinkDeckControl_v8_1 * This, + /* [in] */ IDeckLinkDeckControlStatusCallback_v8_1 *callback); + + END_INTERFACE + } IDeckLinkDeckControl_v8_1Vtbl; + + interface IDeckLinkDeckControl_v8_1 + { + CONST_VTBL struct IDeckLinkDeckControl_v8_1Vtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkDeckControl_v8_1_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkDeckControl_v8_1_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkDeckControl_v8_1_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkDeckControl_v8_1_Open(This,timeScale,timeValue,timecodeIsDropFrame,error) \ + ( (This)->lpVtbl -> Open(This,timeScale,timeValue,timecodeIsDropFrame,error) ) + +#define IDeckLinkDeckControl_v8_1_Close(This,standbyOn) \ + ( (This)->lpVtbl -> Close(This,standbyOn) ) + +#define IDeckLinkDeckControl_v8_1_GetCurrentState(This,mode,vtrControlState,flags) \ + ( (This)->lpVtbl -> GetCurrentState(This,mode,vtrControlState,flags) ) + +#define IDeckLinkDeckControl_v8_1_SetStandby(This,standbyOn) \ + ( (This)->lpVtbl -> SetStandby(This,standbyOn) ) + +#define IDeckLinkDeckControl_v8_1_SendCommand(This,inBuffer,inBufferSize,outBuffer,outDataSize,outBufferSize,error) \ + ( (This)->lpVtbl -> SendCommand(This,inBuffer,inBufferSize,outBuffer,outDataSize,outBufferSize,error) ) + +#define IDeckLinkDeckControl_v8_1_Play(This,error) \ + ( (This)->lpVtbl -> Play(This,error) ) + +#define IDeckLinkDeckControl_v8_1_Stop(This,error) \ + ( (This)->lpVtbl -> Stop(This,error) ) + +#define IDeckLinkDeckControl_v8_1_TogglePlayStop(This,error) \ + ( (This)->lpVtbl -> TogglePlayStop(This,error) ) + +#define IDeckLinkDeckControl_v8_1_Eject(This,error) \ + ( (This)->lpVtbl -> Eject(This,error) ) + +#define IDeckLinkDeckControl_v8_1_GoToTimecode(This,timecode,error) \ + ( (This)->lpVtbl -> GoToTimecode(This,timecode,error) ) + +#define IDeckLinkDeckControl_v8_1_FastForward(This,viewTape,error) \ + ( (This)->lpVtbl -> FastForward(This,viewTape,error) ) + +#define IDeckLinkDeckControl_v8_1_Rewind(This,viewTape,error) \ + ( (This)->lpVtbl -> Rewind(This,viewTape,error) ) + +#define IDeckLinkDeckControl_v8_1_StepForward(This,error) \ + ( (This)->lpVtbl -> StepForward(This,error) ) + +#define IDeckLinkDeckControl_v8_1_StepBack(This,error) \ + ( (This)->lpVtbl -> StepBack(This,error) ) + +#define IDeckLinkDeckControl_v8_1_Jog(This,rate,error) \ + ( (This)->lpVtbl -> Jog(This,rate,error) ) + +#define IDeckLinkDeckControl_v8_1_Shuttle(This,rate,error) \ + ( (This)->lpVtbl -> Shuttle(This,rate,error) ) + +#define IDeckLinkDeckControl_v8_1_GetTimecodeString(This,currentTimeCode,error) \ + ( (This)->lpVtbl -> GetTimecodeString(This,currentTimeCode,error) ) + +#define IDeckLinkDeckControl_v8_1_GetTimecode(This,currentTimecode,error) \ + ( (This)->lpVtbl -> GetTimecode(This,currentTimecode,error) ) + +#define IDeckLinkDeckControl_v8_1_GetTimecodeBCD(This,currentTimecode,error) \ + ( (This)->lpVtbl -> GetTimecodeBCD(This,currentTimecode,error) ) + +#define IDeckLinkDeckControl_v8_1_SetPreroll(This,prerollSeconds) \ + ( (This)->lpVtbl -> SetPreroll(This,prerollSeconds) ) + +#define IDeckLinkDeckControl_v8_1_GetPreroll(This,prerollSeconds) \ + ( (This)->lpVtbl -> GetPreroll(This,prerollSeconds) ) + +#define IDeckLinkDeckControl_v8_1_SetExportOffset(This,exportOffsetFields) \ + ( (This)->lpVtbl -> SetExportOffset(This,exportOffsetFields) ) + +#define IDeckLinkDeckControl_v8_1_GetExportOffset(This,exportOffsetFields) \ + ( (This)->lpVtbl -> GetExportOffset(This,exportOffsetFields) ) + +#define IDeckLinkDeckControl_v8_1_GetManualExportOffset(This,deckManualExportOffsetFields) \ + ( (This)->lpVtbl -> GetManualExportOffset(This,deckManualExportOffsetFields) ) + +#define IDeckLinkDeckControl_v8_1_SetCaptureOffset(This,captureOffsetFields) \ + ( (This)->lpVtbl -> SetCaptureOffset(This,captureOffsetFields) ) + +#define IDeckLinkDeckControl_v8_1_GetCaptureOffset(This,captureOffsetFields) \ + ( (This)->lpVtbl -> GetCaptureOffset(This,captureOffsetFields) ) + +#define IDeckLinkDeckControl_v8_1_StartExport(This,inTimecode,outTimecode,exportModeOps,error) \ + ( (This)->lpVtbl -> StartExport(This,inTimecode,outTimecode,exportModeOps,error) ) + +#define IDeckLinkDeckControl_v8_1_StartCapture(This,useVITC,inTimecode,outTimecode,error) \ + ( (This)->lpVtbl -> StartCapture(This,useVITC,inTimecode,outTimecode,error) ) + +#define IDeckLinkDeckControl_v8_1_GetDeviceID(This,deviceId,error) \ + ( (This)->lpVtbl -> GetDeviceID(This,deviceId,error) ) + +#define IDeckLinkDeckControl_v8_1_Abort(This) \ + ( (This)->lpVtbl -> Abort(This) ) + +#define IDeckLinkDeckControl_v8_1_CrashRecordStart(This,error) \ + ( (This)->lpVtbl -> CrashRecordStart(This,error) ) + +#define IDeckLinkDeckControl_v8_1_CrashRecordStop(This,error) \ + ( (This)->lpVtbl -> CrashRecordStop(This,error) ) + +#define IDeckLinkDeckControl_v8_1_SetCallback(This,callback) \ + ( (This)->lpVtbl -> SetCallback(This,callback) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkDeckControl_v8_1_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLink_v8_0_INTERFACE_DEFINED__ +#define __IDeckLink_v8_0_INTERFACE_DEFINED__ + +/* interface IDeckLink_v8_0 */ +/* [helpstring][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLink_v8_0; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("62BFF75D-6569-4E55-8D4D-66AA03829ABC") + IDeckLink_v8_0 : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE GetModelName( + /* [out] */ BSTR *modelName) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLink_v8_0Vtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLink_v8_0 * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLink_v8_0 * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLink_v8_0 * This); + + HRESULT ( STDMETHODCALLTYPE *GetModelName )( + IDeckLink_v8_0 * This, + /* [out] */ BSTR *modelName); + + END_INTERFACE + } IDeckLink_v8_0Vtbl; + + interface IDeckLink_v8_0 + { + CONST_VTBL struct IDeckLink_v8_0Vtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLink_v8_0_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLink_v8_0_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLink_v8_0_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLink_v8_0_GetModelName(This,modelName) \ + ( (This)->lpVtbl -> GetModelName(This,modelName) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLink_v8_0_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkIterator_v8_0_INTERFACE_DEFINED__ +#define __IDeckLinkIterator_v8_0_INTERFACE_DEFINED__ + +/* interface IDeckLinkIterator_v8_0 */ +/* [helpstring][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkIterator_v8_0; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("74E936FC-CC28-4A67-81A0-1E94E52D4E69") + IDeckLinkIterator_v8_0 : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE Next( + /* [out] */ IDeckLink_v8_0 **deckLinkInstance) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkIterator_v8_0Vtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkIterator_v8_0 * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkIterator_v8_0 * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkIterator_v8_0 * This); + + HRESULT ( STDMETHODCALLTYPE *Next )( + IDeckLinkIterator_v8_0 * This, + /* [out] */ IDeckLink_v8_0 **deckLinkInstance); + + END_INTERFACE + } IDeckLinkIterator_v8_0Vtbl; + + interface IDeckLinkIterator_v8_0 + { + CONST_VTBL struct IDeckLinkIterator_v8_0Vtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkIterator_v8_0_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkIterator_v8_0_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkIterator_v8_0_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkIterator_v8_0_Next(This,deckLinkInstance) \ + ( (This)->lpVtbl -> Next(This,deckLinkInstance) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkIterator_v8_0_INTERFACE_DEFINED__ */ + + +EXTERN_C const CLSID CLSID_CDeckLinkIterator_v8_0; + +#ifdef __cplusplus + +class DECLSPEC_UUID("D9EDA3B3-2887-41FA-B724-017CF1EB1D37") +CDeckLinkIterator_v8_0; +#endif + +#ifndef __IDeckLinkDeckControl_v7_9_INTERFACE_DEFINED__ +#define __IDeckLinkDeckControl_v7_9_INTERFACE_DEFINED__ + +/* interface IDeckLinkDeckControl_v7_9 */ +/* [helpstring][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkDeckControl_v7_9; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("A4D81043-0619-42B7-8ED6-602D29041DF7") + IDeckLinkDeckControl_v7_9 : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE Open( + /* [in] */ BMDTimeScale timeScale, + /* [in] */ BMDTimeValue timeValue, + /* [in] */ BOOL timecodeIsDropFrame, + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE Close( + /* [in] */ BOOL standbyOn) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetCurrentState( + /* [out] */ BMDDeckControlMode *mode, + /* [out] */ BMDDeckControlVTRControlState *vtrControlState, + /* [out] */ BMDDeckControlStatusFlags *flags) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetStandby( + /* [in] */ BOOL standbyOn) = 0; + + virtual HRESULT STDMETHODCALLTYPE Play( + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE Stop( + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE TogglePlayStop( + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE Eject( + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE GoToTimecode( + /* [in] */ BMDTimecodeBCD timecode, + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE FastForward( + /* [in] */ BOOL viewTape, + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE Rewind( + /* [in] */ BOOL viewTape, + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE StepForward( + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE StepBack( + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE Jog( + /* [in] */ double rate, + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE Shuttle( + /* [in] */ double rate, + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetTimecodeString( + /* [out] */ BSTR *currentTimeCode, + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetTimecode( + /* [out] */ IDeckLinkTimecode **currentTimecode, + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetTimecodeBCD( + /* [out] */ BMDTimecodeBCD *currentTimecode, + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetPreroll( + /* [in] */ unsigned int prerollSeconds) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetPreroll( + /* [out] */ unsigned int *prerollSeconds) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetExportOffset( + /* [in] */ int exportOffsetFields) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetExportOffset( + /* [out] */ int *exportOffsetFields) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetManualExportOffset( + /* [out] */ int *deckManualExportOffsetFields) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetCaptureOffset( + /* [in] */ int captureOffsetFields) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetCaptureOffset( + /* [out] */ int *captureOffsetFields) = 0; + + virtual HRESULT STDMETHODCALLTYPE StartExport( + /* [in] */ BMDTimecodeBCD inTimecode, + /* [in] */ BMDTimecodeBCD outTimecode, + /* [in] */ BMDDeckControlExportModeOpsFlags exportModeOps, + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE StartCapture( + /* [in] */ BOOL useVITC, + /* [in] */ BMDTimecodeBCD inTimecode, + /* [in] */ BMDTimecodeBCD outTimecode, + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetDeviceID( + /* [out] */ unsigned short *deviceId, + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE Abort( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE CrashRecordStart( + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE CrashRecordStop( + /* [out] */ BMDDeckControlError *error) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetCallback( + /* [in] */ IDeckLinkDeckControlStatusCallback *callback) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkDeckControl_v7_9Vtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkDeckControl_v7_9 * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkDeckControl_v7_9 * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkDeckControl_v7_9 * This); + + HRESULT ( STDMETHODCALLTYPE *Open )( + IDeckLinkDeckControl_v7_9 * This, + /* [in] */ BMDTimeScale timeScale, + /* [in] */ BMDTimeValue timeValue, + /* [in] */ BOOL timecodeIsDropFrame, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *Close )( + IDeckLinkDeckControl_v7_9 * This, + /* [in] */ BOOL standbyOn); + + HRESULT ( STDMETHODCALLTYPE *GetCurrentState )( + IDeckLinkDeckControl_v7_9 * This, + /* [out] */ BMDDeckControlMode *mode, + /* [out] */ BMDDeckControlVTRControlState *vtrControlState, + /* [out] */ BMDDeckControlStatusFlags *flags); + + HRESULT ( STDMETHODCALLTYPE *SetStandby )( + IDeckLinkDeckControl_v7_9 * This, + /* [in] */ BOOL standbyOn); + + HRESULT ( STDMETHODCALLTYPE *Play )( + IDeckLinkDeckControl_v7_9 * This, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *Stop )( + IDeckLinkDeckControl_v7_9 * This, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *TogglePlayStop )( + IDeckLinkDeckControl_v7_9 * This, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *Eject )( + IDeckLinkDeckControl_v7_9 * This, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *GoToTimecode )( + IDeckLinkDeckControl_v7_9 * This, + /* [in] */ BMDTimecodeBCD timecode, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *FastForward )( + IDeckLinkDeckControl_v7_9 * This, + /* [in] */ BOOL viewTape, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *Rewind )( + IDeckLinkDeckControl_v7_9 * This, + /* [in] */ BOOL viewTape, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *StepForward )( + IDeckLinkDeckControl_v7_9 * This, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *StepBack )( + IDeckLinkDeckControl_v7_9 * This, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *Jog )( + IDeckLinkDeckControl_v7_9 * This, + /* [in] */ double rate, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *Shuttle )( + IDeckLinkDeckControl_v7_9 * This, + /* [in] */ double rate, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *GetTimecodeString )( + IDeckLinkDeckControl_v7_9 * This, + /* [out] */ BSTR *currentTimeCode, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *GetTimecode )( + IDeckLinkDeckControl_v7_9 * This, + /* [out] */ IDeckLinkTimecode **currentTimecode, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *GetTimecodeBCD )( + IDeckLinkDeckControl_v7_9 * This, + /* [out] */ BMDTimecodeBCD *currentTimecode, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *SetPreroll )( + IDeckLinkDeckControl_v7_9 * This, + /* [in] */ unsigned int prerollSeconds); + + HRESULT ( STDMETHODCALLTYPE *GetPreroll )( + IDeckLinkDeckControl_v7_9 * This, + /* [out] */ unsigned int *prerollSeconds); + + HRESULT ( STDMETHODCALLTYPE *SetExportOffset )( + IDeckLinkDeckControl_v7_9 * This, + /* [in] */ int exportOffsetFields); + + HRESULT ( STDMETHODCALLTYPE *GetExportOffset )( + IDeckLinkDeckControl_v7_9 * This, + /* [out] */ int *exportOffsetFields); + + HRESULT ( STDMETHODCALLTYPE *GetManualExportOffset )( + IDeckLinkDeckControl_v7_9 * This, + /* [out] */ int *deckManualExportOffsetFields); + + HRESULT ( STDMETHODCALLTYPE *SetCaptureOffset )( + IDeckLinkDeckControl_v7_9 * This, + /* [in] */ int captureOffsetFields); + + HRESULT ( STDMETHODCALLTYPE *GetCaptureOffset )( + IDeckLinkDeckControl_v7_9 * This, + /* [out] */ int *captureOffsetFields); + + HRESULT ( STDMETHODCALLTYPE *StartExport )( + IDeckLinkDeckControl_v7_9 * This, + /* [in] */ BMDTimecodeBCD inTimecode, + /* [in] */ BMDTimecodeBCD outTimecode, + /* [in] */ BMDDeckControlExportModeOpsFlags exportModeOps, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *StartCapture )( + IDeckLinkDeckControl_v7_9 * This, + /* [in] */ BOOL useVITC, + /* [in] */ BMDTimecodeBCD inTimecode, + /* [in] */ BMDTimecodeBCD outTimecode, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *GetDeviceID )( + IDeckLinkDeckControl_v7_9 * This, + /* [out] */ unsigned short *deviceId, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *Abort )( + IDeckLinkDeckControl_v7_9 * This); + + HRESULT ( STDMETHODCALLTYPE *CrashRecordStart )( + IDeckLinkDeckControl_v7_9 * This, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *CrashRecordStop )( + IDeckLinkDeckControl_v7_9 * This, + /* [out] */ BMDDeckControlError *error); + + HRESULT ( STDMETHODCALLTYPE *SetCallback )( + IDeckLinkDeckControl_v7_9 * This, + /* [in] */ IDeckLinkDeckControlStatusCallback *callback); + + END_INTERFACE + } IDeckLinkDeckControl_v7_9Vtbl; + + interface IDeckLinkDeckControl_v7_9 + { + CONST_VTBL struct IDeckLinkDeckControl_v7_9Vtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkDeckControl_v7_9_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkDeckControl_v7_9_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkDeckControl_v7_9_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkDeckControl_v7_9_Open(This,timeScale,timeValue,timecodeIsDropFrame,error) \ + ( (This)->lpVtbl -> Open(This,timeScale,timeValue,timecodeIsDropFrame,error) ) + +#define IDeckLinkDeckControl_v7_9_Close(This,standbyOn) \ + ( (This)->lpVtbl -> Close(This,standbyOn) ) + +#define IDeckLinkDeckControl_v7_9_GetCurrentState(This,mode,vtrControlState,flags) \ + ( (This)->lpVtbl -> GetCurrentState(This,mode,vtrControlState,flags) ) + +#define IDeckLinkDeckControl_v7_9_SetStandby(This,standbyOn) \ + ( (This)->lpVtbl -> SetStandby(This,standbyOn) ) + +#define IDeckLinkDeckControl_v7_9_Play(This,error) \ + ( (This)->lpVtbl -> Play(This,error) ) + +#define IDeckLinkDeckControl_v7_9_Stop(This,error) \ + ( (This)->lpVtbl -> Stop(This,error) ) + +#define IDeckLinkDeckControl_v7_9_TogglePlayStop(This,error) \ + ( (This)->lpVtbl -> TogglePlayStop(This,error) ) + +#define IDeckLinkDeckControl_v7_9_Eject(This,error) \ + ( (This)->lpVtbl -> Eject(This,error) ) + +#define IDeckLinkDeckControl_v7_9_GoToTimecode(This,timecode,error) \ + ( (This)->lpVtbl -> GoToTimecode(This,timecode,error) ) + +#define IDeckLinkDeckControl_v7_9_FastForward(This,viewTape,error) \ + ( (This)->lpVtbl -> FastForward(This,viewTape,error) ) + +#define IDeckLinkDeckControl_v7_9_Rewind(This,viewTape,error) \ + ( (This)->lpVtbl -> Rewind(This,viewTape,error) ) + +#define IDeckLinkDeckControl_v7_9_StepForward(This,error) \ + ( (This)->lpVtbl -> StepForward(This,error) ) + +#define IDeckLinkDeckControl_v7_9_StepBack(This,error) \ + ( (This)->lpVtbl -> StepBack(This,error) ) + +#define IDeckLinkDeckControl_v7_9_Jog(This,rate,error) \ + ( (This)->lpVtbl -> Jog(This,rate,error) ) + +#define IDeckLinkDeckControl_v7_9_Shuttle(This,rate,error) \ + ( (This)->lpVtbl -> Shuttle(This,rate,error) ) + +#define IDeckLinkDeckControl_v7_9_GetTimecodeString(This,currentTimeCode,error) \ + ( (This)->lpVtbl -> GetTimecodeString(This,currentTimeCode,error) ) + +#define IDeckLinkDeckControl_v7_9_GetTimecode(This,currentTimecode,error) \ + ( (This)->lpVtbl -> GetTimecode(This,currentTimecode,error) ) + +#define IDeckLinkDeckControl_v7_9_GetTimecodeBCD(This,currentTimecode,error) \ + ( (This)->lpVtbl -> GetTimecodeBCD(This,currentTimecode,error) ) + +#define IDeckLinkDeckControl_v7_9_SetPreroll(This,prerollSeconds) \ + ( (This)->lpVtbl -> SetPreroll(This,prerollSeconds) ) + +#define IDeckLinkDeckControl_v7_9_GetPreroll(This,prerollSeconds) \ + ( (This)->lpVtbl -> GetPreroll(This,prerollSeconds) ) + +#define IDeckLinkDeckControl_v7_9_SetExportOffset(This,exportOffsetFields) \ + ( (This)->lpVtbl -> SetExportOffset(This,exportOffsetFields) ) + +#define IDeckLinkDeckControl_v7_9_GetExportOffset(This,exportOffsetFields) \ + ( (This)->lpVtbl -> GetExportOffset(This,exportOffsetFields) ) + +#define IDeckLinkDeckControl_v7_9_GetManualExportOffset(This,deckManualExportOffsetFields) \ + ( (This)->lpVtbl -> GetManualExportOffset(This,deckManualExportOffsetFields) ) + +#define IDeckLinkDeckControl_v7_9_SetCaptureOffset(This,captureOffsetFields) \ + ( (This)->lpVtbl -> SetCaptureOffset(This,captureOffsetFields) ) + +#define IDeckLinkDeckControl_v7_9_GetCaptureOffset(This,captureOffsetFields) \ + ( (This)->lpVtbl -> GetCaptureOffset(This,captureOffsetFields) ) + +#define IDeckLinkDeckControl_v7_9_StartExport(This,inTimecode,outTimecode,exportModeOps,error) \ + ( (This)->lpVtbl -> StartExport(This,inTimecode,outTimecode,exportModeOps,error) ) + +#define IDeckLinkDeckControl_v7_9_StartCapture(This,useVITC,inTimecode,outTimecode,error) \ + ( (This)->lpVtbl -> StartCapture(This,useVITC,inTimecode,outTimecode,error) ) + +#define IDeckLinkDeckControl_v7_9_GetDeviceID(This,deviceId,error) \ + ( (This)->lpVtbl -> GetDeviceID(This,deviceId,error) ) + +#define IDeckLinkDeckControl_v7_9_Abort(This) \ + ( (This)->lpVtbl -> Abort(This) ) + +#define IDeckLinkDeckControl_v7_9_CrashRecordStart(This,error) \ + ( (This)->lpVtbl -> CrashRecordStart(This,error) ) + +#define IDeckLinkDeckControl_v7_9_CrashRecordStop(This,error) \ + ( (This)->lpVtbl -> CrashRecordStop(This,error) ) + +#define IDeckLinkDeckControl_v7_9_SetCallback(This,callback) \ + ( (This)->lpVtbl -> SetCallback(This,callback) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkDeckControl_v7_9_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkDisplayModeIterator_v7_6_INTERFACE_DEFINED__ +#define __IDeckLinkDisplayModeIterator_v7_6_INTERFACE_DEFINED__ + +/* interface IDeckLinkDisplayModeIterator_v7_6 */ +/* [helpstring][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkDisplayModeIterator_v7_6; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("455D741F-1779-4800-86F5-0B5D13D79751") + IDeckLinkDisplayModeIterator_v7_6 : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE Next( + /* [out] */ IDeckLinkDisplayMode_v7_6 **deckLinkDisplayMode) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkDisplayModeIterator_v7_6Vtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkDisplayModeIterator_v7_6 * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkDisplayModeIterator_v7_6 * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkDisplayModeIterator_v7_6 * This); + + HRESULT ( STDMETHODCALLTYPE *Next )( + IDeckLinkDisplayModeIterator_v7_6 * This, + /* [out] */ IDeckLinkDisplayMode_v7_6 **deckLinkDisplayMode); + + END_INTERFACE + } IDeckLinkDisplayModeIterator_v7_6Vtbl; + + interface IDeckLinkDisplayModeIterator_v7_6 + { + CONST_VTBL struct IDeckLinkDisplayModeIterator_v7_6Vtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkDisplayModeIterator_v7_6_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkDisplayModeIterator_v7_6_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkDisplayModeIterator_v7_6_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkDisplayModeIterator_v7_6_Next(This,deckLinkDisplayMode) \ + ( (This)->lpVtbl -> Next(This,deckLinkDisplayMode) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkDisplayModeIterator_v7_6_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkDisplayMode_v7_6_INTERFACE_DEFINED__ +#define __IDeckLinkDisplayMode_v7_6_INTERFACE_DEFINED__ + +/* interface IDeckLinkDisplayMode_v7_6 */ +/* [helpstring][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkDisplayMode_v7_6; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("87451E84-2B7E-439E-A629-4393EA4A8550") + IDeckLinkDisplayMode_v7_6 : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE GetName( + /* [out] */ BSTR *name) = 0; + + virtual BMDDisplayMode STDMETHODCALLTYPE GetDisplayMode( void) = 0; + + virtual long STDMETHODCALLTYPE GetWidth( void) = 0; + + virtual long STDMETHODCALLTYPE GetHeight( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetFrameRate( + /* [out] */ BMDTimeValue *frameDuration, + /* [out] */ BMDTimeScale *timeScale) = 0; + + virtual BMDFieldDominance STDMETHODCALLTYPE GetFieldDominance( void) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkDisplayMode_v7_6Vtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkDisplayMode_v7_6 * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkDisplayMode_v7_6 * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkDisplayMode_v7_6 * This); + + HRESULT ( STDMETHODCALLTYPE *GetName )( + IDeckLinkDisplayMode_v7_6 * This, + /* [out] */ BSTR *name); + + BMDDisplayMode ( STDMETHODCALLTYPE *GetDisplayMode )( + IDeckLinkDisplayMode_v7_6 * This); + + long ( STDMETHODCALLTYPE *GetWidth )( + IDeckLinkDisplayMode_v7_6 * This); + + long ( STDMETHODCALLTYPE *GetHeight )( + IDeckLinkDisplayMode_v7_6 * This); + + HRESULT ( STDMETHODCALLTYPE *GetFrameRate )( + IDeckLinkDisplayMode_v7_6 * This, + /* [out] */ BMDTimeValue *frameDuration, + /* [out] */ BMDTimeScale *timeScale); + + BMDFieldDominance ( STDMETHODCALLTYPE *GetFieldDominance )( + IDeckLinkDisplayMode_v7_6 * This); + + END_INTERFACE + } IDeckLinkDisplayMode_v7_6Vtbl; + + interface IDeckLinkDisplayMode_v7_6 + { + CONST_VTBL struct IDeckLinkDisplayMode_v7_6Vtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkDisplayMode_v7_6_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkDisplayMode_v7_6_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkDisplayMode_v7_6_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkDisplayMode_v7_6_GetName(This,name) \ + ( (This)->lpVtbl -> GetName(This,name) ) + +#define IDeckLinkDisplayMode_v7_6_GetDisplayMode(This) \ + ( (This)->lpVtbl -> GetDisplayMode(This) ) + +#define IDeckLinkDisplayMode_v7_6_GetWidth(This) \ + ( (This)->lpVtbl -> GetWidth(This) ) + +#define IDeckLinkDisplayMode_v7_6_GetHeight(This) \ + ( (This)->lpVtbl -> GetHeight(This) ) + +#define IDeckLinkDisplayMode_v7_6_GetFrameRate(This,frameDuration,timeScale) \ + ( (This)->lpVtbl -> GetFrameRate(This,frameDuration,timeScale) ) + +#define IDeckLinkDisplayMode_v7_6_GetFieldDominance(This) \ + ( (This)->lpVtbl -> GetFieldDominance(This) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkDisplayMode_v7_6_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkOutput_v7_6_INTERFACE_DEFINED__ +#define __IDeckLinkOutput_v7_6_INTERFACE_DEFINED__ + +/* interface IDeckLinkOutput_v7_6 */ +/* [helpstring][local][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkOutput_v7_6; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("29228142-EB8C-4141-A621-F74026450955") + IDeckLinkOutput_v7_6 : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE DoesSupportVideoMode( + BMDDisplayMode displayMode, + BMDPixelFormat pixelFormat, + /* [out] */ BMDDisplayModeSupport *result) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetDisplayModeIterator( + /* [out] */ IDeckLinkDisplayModeIterator_v7_6 **iterator) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetScreenPreviewCallback( + /* [in] */ IDeckLinkScreenPreviewCallback_v7_6 *previewCallback) = 0; + + virtual HRESULT STDMETHODCALLTYPE EnableVideoOutput( + BMDDisplayMode displayMode, + BMDVideoOutputFlags flags) = 0; + + virtual HRESULT STDMETHODCALLTYPE DisableVideoOutput( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetVideoOutputFrameMemoryAllocator( + /* [in] */ IDeckLinkMemoryAllocator *theAllocator) = 0; + + virtual HRESULT STDMETHODCALLTYPE CreateVideoFrame( + int width, + int height, + int rowBytes, + BMDPixelFormat pixelFormat, + BMDFrameFlags flags, + /* [out] */ IDeckLinkMutableVideoFrame_v7_6 **outFrame) = 0; + + virtual HRESULT STDMETHODCALLTYPE CreateAncillaryData( + BMDPixelFormat pixelFormat, + /* [out] */ IDeckLinkVideoFrameAncillary **outBuffer) = 0; + + virtual HRESULT STDMETHODCALLTYPE DisplayVideoFrameSync( + /* [in] */ IDeckLinkVideoFrame_v7_6 *theFrame) = 0; + + virtual HRESULT STDMETHODCALLTYPE ScheduleVideoFrame( + /* [in] */ IDeckLinkVideoFrame_v7_6 *theFrame, + BMDTimeValue displayTime, + BMDTimeValue displayDuration, + BMDTimeScale timeScale) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetScheduledFrameCompletionCallback( + /* [in] */ IDeckLinkVideoOutputCallback_v7_6 *theCallback) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetBufferedVideoFrameCount( + /* [out] */ unsigned int *bufferedFrameCount) = 0; + + virtual HRESULT STDMETHODCALLTYPE EnableAudioOutput( + BMDAudioSampleRate sampleRate, + BMDAudioSampleType sampleType, + unsigned int channelCount, + BMDAudioOutputStreamType streamType) = 0; + + virtual HRESULT STDMETHODCALLTYPE DisableAudioOutput( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE WriteAudioSamplesSync( + /* [in] */ void *buffer, + unsigned int sampleFrameCount, + /* [out] */ unsigned int *sampleFramesWritten) = 0; + + virtual HRESULT STDMETHODCALLTYPE BeginAudioPreroll( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE EndAudioPreroll( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE ScheduleAudioSamples( + /* [in] */ void *buffer, + unsigned int sampleFrameCount, + BMDTimeValue streamTime, + BMDTimeScale timeScale, + /* [out] */ unsigned int *sampleFramesWritten) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetBufferedAudioSampleFrameCount( + /* [out] */ unsigned int *bufferedSampleFrameCount) = 0; + + virtual HRESULT STDMETHODCALLTYPE FlushBufferedAudioSamples( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetAudioCallback( + /* [in] */ IDeckLinkAudioOutputCallback *theCallback) = 0; + + virtual HRESULT STDMETHODCALLTYPE StartScheduledPlayback( + BMDTimeValue playbackStartTime, + BMDTimeScale timeScale, + double playbackSpeed) = 0; + + virtual HRESULT STDMETHODCALLTYPE StopScheduledPlayback( + BMDTimeValue stopPlaybackAtTime, + /* [out] */ BMDTimeValue *actualStopTime, + BMDTimeScale timeScale) = 0; + + virtual HRESULT STDMETHODCALLTYPE IsScheduledPlaybackRunning( + /* [out] */ BOOL *active) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetScheduledStreamTime( + BMDTimeScale desiredTimeScale, + /* [out] */ BMDTimeValue *streamTime, + /* [out] */ double *playbackSpeed) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetHardwareReferenceClock( + BMDTimeScale desiredTimeScale, + /* [out] */ BMDTimeValue *hardwareTime, + /* [out] */ BMDTimeValue *timeInFrame, + /* [out] */ BMDTimeValue *ticksPerFrame) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkOutput_v7_6Vtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkOutput_v7_6 * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkOutput_v7_6 * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkOutput_v7_6 * This); + + HRESULT ( STDMETHODCALLTYPE *DoesSupportVideoMode )( + IDeckLinkOutput_v7_6 * This, + BMDDisplayMode displayMode, + BMDPixelFormat pixelFormat, + /* [out] */ BMDDisplayModeSupport *result); + + HRESULT ( STDMETHODCALLTYPE *GetDisplayModeIterator )( + IDeckLinkOutput_v7_6 * This, + /* [out] */ IDeckLinkDisplayModeIterator_v7_6 **iterator); + + HRESULT ( STDMETHODCALLTYPE *SetScreenPreviewCallback )( + IDeckLinkOutput_v7_6 * This, + /* [in] */ IDeckLinkScreenPreviewCallback_v7_6 *previewCallback); + + HRESULT ( STDMETHODCALLTYPE *EnableVideoOutput )( + IDeckLinkOutput_v7_6 * This, + BMDDisplayMode displayMode, + BMDVideoOutputFlags flags); + + HRESULT ( STDMETHODCALLTYPE *DisableVideoOutput )( + IDeckLinkOutput_v7_6 * This); + + HRESULT ( STDMETHODCALLTYPE *SetVideoOutputFrameMemoryAllocator )( + IDeckLinkOutput_v7_6 * This, + /* [in] */ IDeckLinkMemoryAllocator *theAllocator); + + HRESULT ( STDMETHODCALLTYPE *CreateVideoFrame )( + IDeckLinkOutput_v7_6 * This, + int width, + int height, + int rowBytes, + BMDPixelFormat pixelFormat, + BMDFrameFlags flags, + /* [out] */ IDeckLinkMutableVideoFrame_v7_6 **outFrame); + + HRESULT ( STDMETHODCALLTYPE *CreateAncillaryData )( + IDeckLinkOutput_v7_6 * This, + BMDPixelFormat pixelFormat, + /* [out] */ IDeckLinkVideoFrameAncillary **outBuffer); + + HRESULT ( STDMETHODCALLTYPE *DisplayVideoFrameSync )( + IDeckLinkOutput_v7_6 * This, + /* [in] */ IDeckLinkVideoFrame_v7_6 *theFrame); + + HRESULT ( STDMETHODCALLTYPE *ScheduleVideoFrame )( + IDeckLinkOutput_v7_6 * This, + /* [in] */ IDeckLinkVideoFrame_v7_6 *theFrame, + BMDTimeValue displayTime, + BMDTimeValue displayDuration, + BMDTimeScale timeScale); + + HRESULT ( STDMETHODCALLTYPE *SetScheduledFrameCompletionCallback )( + IDeckLinkOutput_v7_6 * This, + /* [in] */ IDeckLinkVideoOutputCallback_v7_6 *theCallback); + + HRESULT ( STDMETHODCALLTYPE *GetBufferedVideoFrameCount )( + IDeckLinkOutput_v7_6 * This, + /* [out] */ unsigned int *bufferedFrameCount); + + HRESULT ( STDMETHODCALLTYPE *EnableAudioOutput )( + IDeckLinkOutput_v7_6 * This, + BMDAudioSampleRate sampleRate, + BMDAudioSampleType sampleType, + unsigned int channelCount, + BMDAudioOutputStreamType streamType); + + HRESULT ( STDMETHODCALLTYPE *DisableAudioOutput )( + IDeckLinkOutput_v7_6 * This); + + HRESULT ( STDMETHODCALLTYPE *WriteAudioSamplesSync )( + IDeckLinkOutput_v7_6 * This, + /* [in] */ void *buffer, + unsigned int sampleFrameCount, + /* [out] */ unsigned int *sampleFramesWritten); + + HRESULT ( STDMETHODCALLTYPE *BeginAudioPreroll )( + IDeckLinkOutput_v7_6 * This); + + HRESULT ( STDMETHODCALLTYPE *EndAudioPreroll )( + IDeckLinkOutput_v7_6 * This); + + HRESULT ( STDMETHODCALLTYPE *ScheduleAudioSamples )( + IDeckLinkOutput_v7_6 * This, + /* [in] */ void *buffer, + unsigned int sampleFrameCount, + BMDTimeValue streamTime, + BMDTimeScale timeScale, + /* [out] */ unsigned int *sampleFramesWritten); + + HRESULT ( STDMETHODCALLTYPE *GetBufferedAudioSampleFrameCount )( + IDeckLinkOutput_v7_6 * This, + /* [out] */ unsigned int *bufferedSampleFrameCount); + + HRESULT ( STDMETHODCALLTYPE *FlushBufferedAudioSamples )( + IDeckLinkOutput_v7_6 * This); + + HRESULT ( STDMETHODCALLTYPE *SetAudioCallback )( + IDeckLinkOutput_v7_6 * This, + /* [in] */ IDeckLinkAudioOutputCallback *theCallback); + + HRESULT ( STDMETHODCALLTYPE *StartScheduledPlayback )( + IDeckLinkOutput_v7_6 * This, + BMDTimeValue playbackStartTime, + BMDTimeScale timeScale, + double playbackSpeed); + + HRESULT ( STDMETHODCALLTYPE *StopScheduledPlayback )( + IDeckLinkOutput_v7_6 * This, + BMDTimeValue stopPlaybackAtTime, + /* [out] */ BMDTimeValue *actualStopTime, + BMDTimeScale timeScale); + + HRESULT ( STDMETHODCALLTYPE *IsScheduledPlaybackRunning )( + IDeckLinkOutput_v7_6 * This, + /* [out] */ BOOL *active); + + HRESULT ( STDMETHODCALLTYPE *GetScheduledStreamTime )( + IDeckLinkOutput_v7_6 * This, + BMDTimeScale desiredTimeScale, + /* [out] */ BMDTimeValue *streamTime, + /* [out] */ double *playbackSpeed); + + HRESULT ( STDMETHODCALLTYPE *GetHardwareReferenceClock )( + IDeckLinkOutput_v7_6 * This, + BMDTimeScale desiredTimeScale, + /* [out] */ BMDTimeValue *hardwareTime, + /* [out] */ BMDTimeValue *timeInFrame, + /* [out] */ BMDTimeValue *ticksPerFrame); + + END_INTERFACE + } IDeckLinkOutput_v7_6Vtbl; + + interface IDeckLinkOutput_v7_6 + { + CONST_VTBL struct IDeckLinkOutput_v7_6Vtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkOutput_v7_6_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkOutput_v7_6_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkOutput_v7_6_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkOutput_v7_6_DoesSupportVideoMode(This,displayMode,pixelFormat,result) \ + ( (This)->lpVtbl -> DoesSupportVideoMode(This,displayMode,pixelFormat,result) ) + +#define IDeckLinkOutput_v7_6_GetDisplayModeIterator(This,iterator) \ + ( (This)->lpVtbl -> GetDisplayModeIterator(This,iterator) ) + +#define IDeckLinkOutput_v7_6_SetScreenPreviewCallback(This,previewCallback) \ + ( (This)->lpVtbl -> SetScreenPreviewCallback(This,previewCallback) ) + +#define IDeckLinkOutput_v7_6_EnableVideoOutput(This,displayMode,flags) \ + ( (This)->lpVtbl -> EnableVideoOutput(This,displayMode,flags) ) + +#define IDeckLinkOutput_v7_6_DisableVideoOutput(This) \ + ( (This)->lpVtbl -> DisableVideoOutput(This) ) + +#define IDeckLinkOutput_v7_6_SetVideoOutputFrameMemoryAllocator(This,theAllocator) \ + ( (This)->lpVtbl -> SetVideoOutputFrameMemoryAllocator(This,theAllocator) ) + +#define IDeckLinkOutput_v7_6_CreateVideoFrame(This,width,height,rowBytes,pixelFormat,flags,outFrame) \ + ( (This)->lpVtbl -> CreateVideoFrame(This,width,height,rowBytes,pixelFormat,flags,outFrame) ) + +#define IDeckLinkOutput_v7_6_CreateAncillaryData(This,pixelFormat,outBuffer) \ + ( (This)->lpVtbl -> CreateAncillaryData(This,pixelFormat,outBuffer) ) + +#define IDeckLinkOutput_v7_6_DisplayVideoFrameSync(This,theFrame) \ + ( (This)->lpVtbl -> DisplayVideoFrameSync(This,theFrame) ) + +#define IDeckLinkOutput_v7_6_ScheduleVideoFrame(This,theFrame,displayTime,displayDuration,timeScale) \ + ( (This)->lpVtbl -> ScheduleVideoFrame(This,theFrame,displayTime,displayDuration,timeScale) ) + +#define IDeckLinkOutput_v7_6_SetScheduledFrameCompletionCallback(This,theCallback) \ + ( (This)->lpVtbl -> SetScheduledFrameCompletionCallback(This,theCallback) ) + +#define IDeckLinkOutput_v7_6_GetBufferedVideoFrameCount(This,bufferedFrameCount) \ + ( (This)->lpVtbl -> GetBufferedVideoFrameCount(This,bufferedFrameCount) ) + +#define IDeckLinkOutput_v7_6_EnableAudioOutput(This,sampleRate,sampleType,channelCount,streamType) \ + ( (This)->lpVtbl -> EnableAudioOutput(This,sampleRate,sampleType,channelCount,streamType) ) + +#define IDeckLinkOutput_v7_6_DisableAudioOutput(This) \ + ( (This)->lpVtbl -> DisableAudioOutput(This) ) + +#define IDeckLinkOutput_v7_6_WriteAudioSamplesSync(This,buffer,sampleFrameCount,sampleFramesWritten) \ + ( (This)->lpVtbl -> WriteAudioSamplesSync(This,buffer,sampleFrameCount,sampleFramesWritten) ) + +#define IDeckLinkOutput_v7_6_BeginAudioPreroll(This) \ + ( (This)->lpVtbl -> BeginAudioPreroll(This) ) + +#define IDeckLinkOutput_v7_6_EndAudioPreroll(This) \ + ( (This)->lpVtbl -> EndAudioPreroll(This) ) + +#define IDeckLinkOutput_v7_6_ScheduleAudioSamples(This,buffer,sampleFrameCount,streamTime,timeScale,sampleFramesWritten) \ + ( (This)->lpVtbl -> ScheduleAudioSamples(This,buffer,sampleFrameCount,streamTime,timeScale,sampleFramesWritten) ) + +#define IDeckLinkOutput_v7_6_GetBufferedAudioSampleFrameCount(This,bufferedSampleFrameCount) \ + ( (This)->lpVtbl -> GetBufferedAudioSampleFrameCount(This,bufferedSampleFrameCount) ) + +#define IDeckLinkOutput_v7_6_FlushBufferedAudioSamples(This) \ + ( (This)->lpVtbl -> FlushBufferedAudioSamples(This) ) + +#define IDeckLinkOutput_v7_6_SetAudioCallback(This,theCallback) \ + ( (This)->lpVtbl -> SetAudioCallback(This,theCallback) ) + +#define IDeckLinkOutput_v7_6_StartScheduledPlayback(This,playbackStartTime,timeScale,playbackSpeed) \ + ( (This)->lpVtbl -> StartScheduledPlayback(This,playbackStartTime,timeScale,playbackSpeed) ) + +#define IDeckLinkOutput_v7_6_StopScheduledPlayback(This,stopPlaybackAtTime,actualStopTime,timeScale) \ + ( (This)->lpVtbl -> StopScheduledPlayback(This,stopPlaybackAtTime,actualStopTime,timeScale) ) + +#define IDeckLinkOutput_v7_6_IsScheduledPlaybackRunning(This,active) \ + ( (This)->lpVtbl -> IsScheduledPlaybackRunning(This,active) ) + +#define IDeckLinkOutput_v7_6_GetScheduledStreamTime(This,desiredTimeScale,streamTime,playbackSpeed) \ + ( (This)->lpVtbl -> GetScheduledStreamTime(This,desiredTimeScale,streamTime,playbackSpeed) ) + +#define IDeckLinkOutput_v7_6_GetHardwareReferenceClock(This,desiredTimeScale,hardwareTime,timeInFrame,ticksPerFrame) \ + ( (This)->lpVtbl -> GetHardwareReferenceClock(This,desiredTimeScale,hardwareTime,timeInFrame,ticksPerFrame) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkOutput_v7_6_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkInput_v7_6_INTERFACE_DEFINED__ +#define __IDeckLinkInput_v7_6_INTERFACE_DEFINED__ + +/* interface IDeckLinkInput_v7_6 */ +/* [helpstring][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkInput_v7_6; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("300C135A-9F43-48E2-9906-6D7911D93CF1") + IDeckLinkInput_v7_6 : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE DoesSupportVideoMode( + BMDDisplayMode displayMode, + BMDPixelFormat pixelFormat, + /* [out] */ BMDDisplayModeSupport *result) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetDisplayModeIterator( + /* [out] */ IDeckLinkDisplayModeIterator_v7_6 **iterator) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetScreenPreviewCallback( + /* [in] */ IDeckLinkScreenPreviewCallback_v7_6 *previewCallback) = 0; + + virtual HRESULT STDMETHODCALLTYPE EnableVideoInput( + BMDDisplayMode displayMode, + BMDPixelFormat pixelFormat, + BMDVideoInputFlags flags) = 0; + + virtual HRESULT STDMETHODCALLTYPE DisableVideoInput( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetAvailableVideoFrameCount( + /* [out] */ unsigned int *availableFrameCount) = 0; + + virtual HRESULT STDMETHODCALLTYPE EnableAudioInput( + BMDAudioSampleRate sampleRate, + BMDAudioSampleType sampleType, + unsigned int channelCount) = 0; + + virtual HRESULT STDMETHODCALLTYPE DisableAudioInput( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetAvailableAudioSampleFrameCount( + /* [out] */ unsigned int *availableSampleFrameCount) = 0; + + virtual HRESULT STDMETHODCALLTYPE StartStreams( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE StopStreams( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE PauseStreams( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE FlushStreams( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetCallback( + /* [in] */ IDeckLinkInputCallback_v7_6 *theCallback) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetHardwareReferenceClock( + BMDTimeScale desiredTimeScale, + /* [out] */ BMDTimeValue *hardwareTime, + /* [out] */ BMDTimeValue *timeInFrame, + /* [out] */ BMDTimeValue *ticksPerFrame) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkInput_v7_6Vtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkInput_v7_6 * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkInput_v7_6 * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkInput_v7_6 * This); + + HRESULT ( STDMETHODCALLTYPE *DoesSupportVideoMode )( + IDeckLinkInput_v7_6 * This, + BMDDisplayMode displayMode, + BMDPixelFormat pixelFormat, + /* [out] */ BMDDisplayModeSupport *result); + + HRESULT ( STDMETHODCALLTYPE *GetDisplayModeIterator )( + IDeckLinkInput_v7_6 * This, + /* [out] */ IDeckLinkDisplayModeIterator_v7_6 **iterator); + + HRESULT ( STDMETHODCALLTYPE *SetScreenPreviewCallback )( + IDeckLinkInput_v7_6 * This, + /* [in] */ IDeckLinkScreenPreviewCallback_v7_6 *previewCallback); + + HRESULT ( STDMETHODCALLTYPE *EnableVideoInput )( + IDeckLinkInput_v7_6 * This, + BMDDisplayMode displayMode, + BMDPixelFormat pixelFormat, + BMDVideoInputFlags flags); + + HRESULT ( STDMETHODCALLTYPE *DisableVideoInput )( + IDeckLinkInput_v7_6 * This); + + HRESULT ( STDMETHODCALLTYPE *GetAvailableVideoFrameCount )( + IDeckLinkInput_v7_6 * This, + /* [out] */ unsigned int *availableFrameCount); + + HRESULT ( STDMETHODCALLTYPE *EnableAudioInput )( + IDeckLinkInput_v7_6 * This, + BMDAudioSampleRate sampleRate, + BMDAudioSampleType sampleType, + unsigned int channelCount); + + HRESULT ( STDMETHODCALLTYPE *DisableAudioInput )( + IDeckLinkInput_v7_6 * This); + + HRESULT ( STDMETHODCALLTYPE *GetAvailableAudioSampleFrameCount )( + IDeckLinkInput_v7_6 * This, + /* [out] */ unsigned int *availableSampleFrameCount); + + HRESULT ( STDMETHODCALLTYPE *StartStreams )( + IDeckLinkInput_v7_6 * This); + + HRESULT ( STDMETHODCALLTYPE *StopStreams )( + IDeckLinkInput_v7_6 * This); + + HRESULT ( STDMETHODCALLTYPE *PauseStreams )( + IDeckLinkInput_v7_6 * This); + + HRESULT ( STDMETHODCALLTYPE *FlushStreams )( + IDeckLinkInput_v7_6 * This); + + HRESULT ( STDMETHODCALLTYPE *SetCallback )( + IDeckLinkInput_v7_6 * This, + /* [in] */ IDeckLinkInputCallback_v7_6 *theCallback); + + HRESULT ( STDMETHODCALLTYPE *GetHardwareReferenceClock )( + IDeckLinkInput_v7_6 * This, + BMDTimeScale desiredTimeScale, + /* [out] */ BMDTimeValue *hardwareTime, + /* [out] */ BMDTimeValue *timeInFrame, + /* [out] */ BMDTimeValue *ticksPerFrame); + + END_INTERFACE + } IDeckLinkInput_v7_6Vtbl; + + interface IDeckLinkInput_v7_6 + { + CONST_VTBL struct IDeckLinkInput_v7_6Vtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkInput_v7_6_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkInput_v7_6_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkInput_v7_6_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkInput_v7_6_DoesSupportVideoMode(This,displayMode,pixelFormat,result) \ + ( (This)->lpVtbl -> DoesSupportVideoMode(This,displayMode,pixelFormat,result) ) + +#define IDeckLinkInput_v7_6_GetDisplayModeIterator(This,iterator) \ + ( (This)->lpVtbl -> GetDisplayModeIterator(This,iterator) ) + +#define IDeckLinkInput_v7_6_SetScreenPreviewCallback(This,previewCallback) \ + ( (This)->lpVtbl -> SetScreenPreviewCallback(This,previewCallback) ) + +#define IDeckLinkInput_v7_6_EnableVideoInput(This,displayMode,pixelFormat,flags) \ + ( (This)->lpVtbl -> EnableVideoInput(This,displayMode,pixelFormat,flags) ) + +#define IDeckLinkInput_v7_6_DisableVideoInput(This) \ + ( (This)->lpVtbl -> DisableVideoInput(This) ) + +#define IDeckLinkInput_v7_6_GetAvailableVideoFrameCount(This,availableFrameCount) \ + ( (This)->lpVtbl -> GetAvailableVideoFrameCount(This,availableFrameCount) ) + +#define IDeckLinkInput_v7_6_EnableAudioInput(This,sampleRate,sampleType,channelCount) \ + ( (This)->lpVtbl -> EnableAudioInput(This,sampleRate,sampleType,channelCount) ) + +#define IDeckLinkInput_v7_6_DisableAudioInput(This) \ + ( (This)->lpVtbl -> DisableAudioInput(This) ) + +#define IDeckLinkInput_v7_6_GetAvailableAudioSampleFrameCount(This,availableSampleFrameCount) \ + ( (This)->lpVtbl -> GetAvailableAudioSampleFrameCount(This,availableSampleFrameCount) ) + +#define IDeckLinkInput_v7_6_StartStreams(This) \ + ( (This)->lpVtbl -> StartStreams(This) ) + +#define IDeckLinkInput_v7_6_StopStreams(This) \ + ( (This)->lpVtbl -> StopStreams(This) ) + +#define IDeckLinkInput_v7_6_PauseStreams(This) \ + ( (This)->lpVtbl -> PauseStreams(This) ) + +#define IDeckLinkInput_v7_6_FlushStreams(This) \ + ( (This)->lpVtbl -> FlushStreams(This) ) + +#define IDeckLinkInput_v7_6_SetCallback(This,theCallback) \ + ( (This)->lpVtbl -> SetCallback(This,theCallback) ) + +#define IDeckLinkInput_v7_6_GetHardwareReferenceClock(This,desiredTimeScale,hardwareTime,timeInFrame,ticksPerFrame) \ + ( (This)->lpVtbl -> GetHardwareReferenceClock(This,desiredTimeScale,hardwareTime,timeInFrame,ticksPerFrame) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkInput_v7_6_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkTimecode_v7_6_INTERFACE_DEFINED__ +#define __IDeckLinkTimecode_v7_6_INTERFACE_DEFINED__ + +/* interface IDeckLinkTimecode_v7_6 */ +/* [helpstring][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkTimecode_v7_6; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("EFB9BCA6-A521-44F7-BD69-2332F24D9EE6") + IDeckLinkTimecode_v7_6 : public IUnknown + { + public: + virtual BMDTimecodeBCD STDMETHODCALLTYPE GetBCD( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetComponents( + /* [out] */ unsigned char *hours, + /* [out] */ unsigned char *minutes, + /* [out] */ unsigned char *seconds, + /* [out] */ unsigned char *frames) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetString( + /* [out] */ BSTR *timecode) = 0; + + virtual BMDTimecodeFlags STDMETHODCALLTYPE GetFlags( void) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkTimecode_v7_6Vtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkTimecode_v7_6 * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkTimecode_v7_6 * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkTimecode_v7_6 * This); + + BMDTimecodeBCD ( STDMETHODCALLTYPE *GetBCD )( + IDeckLinkTimecode_v7_6 * This); + + HRESULT ( STDMETHODCALLTYPE *GetComponents )( + IDeckLinkTimecode_v7_6 * This, + /* [out] */ unsigned char *hours, + /* [out] */ unsigned char *minutes, + /* [out] */ unsigned char *seconds, + /* [out] */ unsigned char *frames); + + HRESULT ( STDMETHODCALLTYPE *GetString )( + IDeckLinkTimecode_v7_6 * This, + /* [out] */ BSTR *timecode); + + BMDTimecodeFlags ( STDMETHODCALLTYPE *GetFlags )( + IDeckLinkTimecode_v7_6 * This); + + END_INTERFACE + } IDeckLinkTimecode_v7_6Vtbl; + + interface IDeckLinkTimecode_v7_6 + { + CONST_VTBL struct IDeckLinkTimecode_v7_6Vtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkTimecode_v7_6_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkTimecode_v7_6_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkTimecode_v7_6_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkTimecode_v7_6_GetBCD(This) \ + ( (This)->lpVtbl -> GetBCD(This) ) + +#define IDeckLinkTimecode_v7_6_GetComponents(This,hours,minutes,seconds,frames) \ + ( (This)->lpVtbl -> GetComponents(This,hours,minutes,seconds,frames) ) + +#define IDeckLinkTimecode_v7_6_GetString(This,timecode) \ + ( (This)->lpVtbl -> GetString(This,timecode) ) + +#define IDeckLinkTimecode_v7_6_GetFlags(This) \ + ( (This)->lpVtbl -> GetFlags(This) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkTimecode_v7_6_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkVideoFrame_v7_6_INTERFACE_DEFINED__ +#define __IDeckLinkVideoFrame_v7_6_INTERFACE_DEFINED__ + +/* interface IDeckLinkVideoFrame_v7_6 */ +/* [helpstring][local][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkVideoFrame_v7_6; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("A8D8238E-6B18-4196-99E1-5AF717B83D32") + IDeckLinkVideoFrame_v7_6 : public IUnknown + { + public: + virtual long STDMETHODCALLTYPE GetWidth( void) = 0; + + virtual long STDMETHODCALLTYPE GetHeight( void) = 0; + + virtual long STDMETHODCALLTYPE GetRowBytes( void) = 0; + + virtual BMDPixelFormat STDMETHODCALLTYPE GetPixelFormat( void) = 0; + + virtual BMDFrameFlags STDMETHODCALLTYPE GetFlags( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetBytes( + /* [out] */ void **buffer) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetTimecode( + BMDTimecodeFormat format, + /* [out] */ IDeckLinkTimecode_v7_6 **timecode) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetAncillaryData( + /* [out] */ IDeckLinkVideoFrameAncillary **ancillary) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkVideoFrame_v7_6Vtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkVideoFrame_v7_6 * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkVideoFrame_v7_6 * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkVideoFrame_v7_6 * This); + + long ( STDMETHODCALLTYPE *GetWidth )( + IDeckLinkVideoFrame_v7_6 * This); + + long ( STDMETHODCALLTYPE *GetHeight )( + IDeckLinkVideoFrame_v7_6 * This); + + long ( STDMETHODCALLTYPE *GetRowBytes )( + IDeckLinkVideoFrame_v7_6 * This); + + BMDPixelFormat ( STDMETHODCALLTYPE *GetPixelFormat )( + IDeckLinkVideoFrame_v7_6 * This); + + BMDFrameFlags ( STDMETHODCALLTYPE *GetFlags )( + IDeckLinkVideoFrame_v7_6 * This); + + HRESULT ( STDMETHODCALLTYPE *GetBytes )( + IDeckLinkVideoFrame_v7_6 * This, + /* [out] */ void **buffer); + + HRESULT ( STDMETHODCALLTYPE *GetTimecode )( + IDeckLinkVideoFrame_v7_6 * This, + BMDTimecodeFormat format, + /* [out] */ IDeckLinkTimecode_v7_6 **timecode); + + HRESULT ( STDMETHODCALLTYPE *GetAncillaryData )( + IDeckLinkVideoFrame_v7_6 * This, + /* [out] */ IDeckLinkVideoFrameAncillary **ancillary); + + END_INTERFACE + } IDeckLinkVideoFrame_v7_6Vtbl; + + interface IDeckLinkVideoFrame_v7_6 + { + CONST_VTBL struct IDeckLinkVideoFrame_v7_6Vtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkVideoFrame_v7_6_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkVideoFrame_v7_6_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkVideoFrame_v7_6_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkVideoFrame_v7_6_GetWidth(This) \ + ( (This)->lpVtbl -> GetWidth(This) ) + +#define IDeckLinkVideoFrame_v7_6_GetHeight(This) \ + ( (This)->lpVtbl -> GetHeight(This) ) + +#define IDeckLinkVideoFrame_v7_6_GetRowBytes(This) \ + ( (This)->lpVtbl -> GetRowBytes(This) ) + +#define IDeckLinkVideoFrame_v7_6_GetPixelFormat(This) \ + ( (This)->lpVtbl -> GetPixelFormat(This) ) + +#define IDeckLinkVideoFrame_v7_6_GetFlags(This) \ + ( (This)->lpVtbl -> GetFlags(This) ) + +#define IDeckLinkVideoFrame_v7_6_GetBytes(This,buffer) \ + ( (This)->lpVtbl -> GetBytes(This,buffer) ) + +#define IDeckLinkVideoFrame_v7_6_GetTimecode(This,format,timecode) \ + ( (This)->lpVtbl -> GetTimecode(This,format,timecode) ) + +#define IDeckLinkVideoFrame_v7_6_GetAncillaryData(This,ancillary) \ + ( (This)->lpVtbl -> GetAncillaryData(This,ancillary) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkVideoFrame_v7_6_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkMutableVideoFrame_v7_6_INTERFACE_DEFINED__ +#define __IDeckLinkMutableVideoFrame_v7_6_INTERFACE_DEFINED__ + +/* interface IDeckLinkMutableVideoFrame_v7_6 */ +/* [helpstring][local][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkMutableVideoFrame_v7_6; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("46FCEE00-B4E6-43D0-91C0-023A7FCEB34F") + IDeckLinkMutableVideoFrame_v7_6 : public IDeckLinkVideoFrame_v7_6 + { + public: + virtual HRESULT STDMETHODCALLTYPE SetFlags( + BMDFrameFlags newFlags) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetTimecode( + BMDTimecodeFormat format, + /* [in] */ IDeckLinkTimecode_v7_6 *timecode) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetTimecodeFromComponents( + BMDTimecodeFormat format, + unsigned char hours, + unsigned char minutes, + unsigned char seconds, + unsigned char frames, + BMDTimecodeFlags flags) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetAncillaryData( + /* [in] */ IDeckLinkVideoFrameAncillary *ancillary) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkMutableVideoFrame_v7_6Vtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkMutableVideoFrame_v7_6 * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkMutableVideoFrame_v7_6 * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkMutableVideoFrame_v7_6 * This); + + long ( STDMETHODCALLTYPE *GetWidth )( + IDeckLinkMutableVideoFrame_v7_6 * This); + + long ( STDMETHODCALLTYPE *GetHeight )( + IDeckLinkMutableVideoFrame_v7_6 * This); + + long ( STDMETHODCALLTYPE *GetRowBytes )( + IDeckLinkMutableVideoFrame_v7_6 * This); + + BMDPixelFormat ( STDMETHODCALLTYPE *GetPixelFormat )( + IDeckLinkMutableVideoFrame_v7_6 * This); + + BMDFrameFlags ( STDMETHODCALLTYPE *GetFlags )( + IDeckLinkMutableVideoFrame_v7_6 * This); + + HRESULT ( STDMETHODCALLTYPE *GetBytes )( + IDeckLinkMutableVideoFrame_v7_6 * This, + /* [out] */ void **buffer); + + HRESULT ( STDMETHODCALLTYPE *GetTimecode )( + IDeckLinkMutableVideoFrame_v7_6 * This, + BMDTimecodeFormat format, + /* [out] */ IDeckLinkTimecode_v7_6 **timecode); + + HRESULT ( STDMETHODCALLTYPE *GetAncillaryData )( + IDeckLinkMutableVideoFrame_v7_6 * This, + /* [out] */ IDeckLinkVideoFrameAncillary **ancillary); + + HRESULT ( STDMETHODCALLTYPE *SetFlags )( + IDeckLinkMutableVideoFrame_v7_6 * This, + BMDFrameFlags newFlags); + + HRESULT ( STDMETHODCALLTYPE *SetTimecode )( + IDeckLinkMutableVideoFrame_v7_6 * This, + BMDTimecodeFormat format, + /* [in] */ IDeckLinkTimecode_v7_6 *timecode); + + HRESULT ( STDMETHODCALLTYPE *SetTimecodeFromComponents )( + IDeckLinkMutableVideoFrame_v7_6 * This, + BMDTimecodeFormat format, + unsigned char hours, + unsigned char minutes, + unsigned char seconds, + unsigned char frames, + BMDTimecodeFlags flags); + + HRESULT ( STDMETHODCALLTYPE *SetAncillaryData )( + IDeckLinkMutableVideoFrame_v7_6 * This, + /* [in] */ IDeckLinkVideoFrameAncillary *ancillary); + + END_INTERFACE + } IDeckLinkMutableVideoFrame_v7_6Vtbl; + + interface IDeckLinkMutableVideoFrame_v7_6 + { + CONST_VTBL struct IDeckLinkMutableVideoFrame_v7_6Vtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkMutableVideoFrame_v7_6_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkMutableVideoFrame_v7_6_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkMutableVideoFrame_v7_6_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkMutableVideoFrame_v7_6_GetWidth(This) \ + ( (This)->lpVtbl -> GetWidth(This) ) + +#define IDeckLinkMutableVideoFrame_v7_6_GetHeight(This) \ + ( (This)->lpVtbl -> GetHeight(This) ) + +#define IDeckLinkMutableVideoFrame_v7_6_GetRowBytes(This) \ + ( (This)->lpVtbl -> GetRowBytes(This) ) + +#define IDeckLinkMutableVideoFrame_v7_6_GetPixelFormat(This) \ + ( (This)->lpVtbl -> GetPixelFormat(This) ) + +#define IDeckLinkMutableVideoFrame_v7_6_GetFlags(This) \ + ( (This)->lpVtbl -> GetFlags(This) ) + +#define IDeckLinkMutableVideoFrame_v7_6_GetBytes(This,buffer) \ + ( (This)->lpVtbl -> GetBytes(This,buffer) ) + +#define IDeckLinkMutableVideoFrame_v7_6_GetTimecode(This,format,timecode) \ + ( (This)->lpVtbl -> GetTimecode(This,format,timecode) ) + +#define IDeckLinkMutableVideoFrame_v7_6_GetAncillaryData(This,ancillary) \ + ( (This)->lpVtbl -> GetAncillaryData(This,ancillary) ) + + +#define IDeckLinkMutableVideoFrame_v7_6_SetFlags(This,newFlags) \ + ( (This)->lpVtbl -> SetFlags(This,newFlags) ) + +#define IDeckLinkMutableVideoFrame_v7_6_SetTimecode(This,format,timecode) \ + ( (This)->lpVtbl -> SetTimecode(This,format,timecode) ) + +#define IDeckLinkMutableVideoFrame_v7_6_SetTimecodeFromComponents(This,format,hours,minutes,seconds,frames,flags) \ + ( (This)->lpVtbl -> SetTimecodeFromComponents(This,format,hours,minutes,seconds,frames,flags) ) + +#define IDeckLinkMutableVideoFrame_v7_6_SetAncillaryData(This,ancillary) \ + ( (This)->lpVtbl -> SetAncillaryData(This,ancillary) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkMutableVideoFrame_v7_6_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkVideoInputFrame_v7_6_INTERFACE_DEFINED__ +#define __IDeckLinkVideoInputFrame_v7_6_INTERFACE_DEFINED__ + +/* interface IDeckLinkVideoInputFrame_v7_6 */ +/* [helpstring][local][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkVideoInputFrame_v7_6; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("9A74FA41-AE9F-47AC-8CF4-01F42DD59965") + IDeckLinkVideoInputFrame_v7_6 : public IDeckLinkVideoFrame_v7_6 + { + public: + virtual HRESULT STDMETHODCALLTYPE GetStreamTime( + /* [out] */ BMDTimeValue *frameTime, + /* [out] */ BMDTimeValue *frameDuration, + BMDTimeScale timeScale) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetHardwareReferenceTimestamp( + BMDTimeScale timeScale, + /* [out] */ BMDTimeValue *frameTime, + /* [out] */ BMDTimeValue *frameDuration) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkVideoInputFrame_v7_6Vtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkVideoInputFrame_v7_6 * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkVideoInputFrame_v7_6 * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkVideoInputFrame_v7_6 * This); + + long ( STDMETHODCALLTYPE *GetWidth )( + IDeckLinkVideoInputFrame_v7_6 * This); + + long ( STDMETHODCALLTYPE *GetHeight )( + IDeckLinkVideoInputFrame_v7_6 * This); + + long ( STDMETHODCALLTYPE *GetRowBytes )( + IDeckLinkVideoInputFrame_v7_6 * This); + + BMDPixelFormat ( STDMETHODCALLTYPE *GetPixelFormat )( + IDeckLinkVideoInputFrame_v7_6 * This); + + BMDFrameFlags ( STDMETHODCALLTYPE *GetFlags )( + IDeckLinkVideoInputFrame_v7_6 * This); + + HRESULT ( STDMETHODCALLTYPE *GetBytes )( + IDeckLinkVideoInputFrame_v7_6 * This, + /* [out] */ void **buffer); + + HRESULT ( STDMETHODCALLTYPE *GetTimecode )( + IDeckLinkVideoInputFrame_v7_6 * This, + BMDTimecodeFormat format, + /* [out] */ IDeckLinkTimecode_v7_6 **timecode); + + HRESULT ( STDMETHODCALLTYPE *GetAncillaryData )( + IDeckLinkVideoInputFrame_v7_6 * This, + /* [out] */ IDeckLinkVideoFrameAncillary **ancillary); + + HRESULT ( STDMETHODCALLTYPE *GetStreamTime )( + IDeckLinkVideoInputFrame_v7_6 * This, + /* [out] */ BMDTimeValue *frameTime, + /* [out] */ BMDTimeValue *frameDuration, + BMDTimeScale timeScale); + + HRESULT ( STDMETHODCALLTYPE *GetHardwareReferenceTimestamp )( + IDeckLinkVideoInputFrame_v7_6 * This, + BMDTimeScale timeScale, + /* [out] */ BMDTimeValue *frameTime, + /* [out] */ BMDTimeValue *frameDuration); + + END_INTERFACE + } IDeckLinkVideoInputFrame_v7_6Vtbl; + + interface IDeckLinkVideoInputFrame_v7_6 + { + CONST_VTBL struct IDeckLinkVideoInputFrame_v7_6Vtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkVideoInputFrame_v7_6_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkVideoInputFrame_v7_6_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkVideoInputFrame_v7_6_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkVideoInputFrame_v7_6_GetWidth(This) \ + ( (This)->lpVtbl -> GetWidth(This) ) + +#define IDeckLinkVideoInputFrame_v7_6_GetHeight(This) \ + ( (This)->lpVtbl -> GetHeight(This) ) + +#define IDeckLinkVideoInputFrame_v7_6_GetRowBytes(This) \ + ( (This)->lpVtbl -> GetRowBytes(This) ) + +#define IDeckLinkVideoInputFrame_v7_6_GetPixelFormat(This) \ + ( (This)->lpVtbl -> GetPixelFormat(This) ) + +#define IDeckLinkVideoInputFrame_v7_6_GetFlags(This) \ + ( (This)->lpVtbl -> GetFlags(This) ) + +#define IDeckLinkVideoInputFrame_v7_6_GetBytes(This,buffer) \ + ( (This)->lpVtbl -> GetBytes(This,buffer) ) + +#define IDeckLinkVideoInputFrame_v7_6_GetTimecode(This,format,timecode) \ + ( (This)->lpVtbl -> GetTimecode(This,format,timecode) ) + +#define IDeckLinkVideoInputFrame_v7_6_GetAncillaryData(This,ancillary) \ + ( (This)->lpVtbl -> GetAncillaryData(This,ancillary) ) + + +#define IDeckLinkVideoInputFrame_v7_6_GetStreamTime(This,frameTime,frameDuration,timeScale) \ + ( (This)->lpVtbl -> GetStreamTime(This,frameTime,frameDuration,timeScale) ) + +#define IDeckLinkVideoInputFrame_v7_6_GetHardwareReferenceTimestamp(This,timeScale,frameTime,frameDuration) \ + ( (This)->lpVtbl -> GetHardwareReferenceTimestamp(This,timeScale,frameTime,frameDuration) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkVideoInputFrame_v7_6_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkScreenPreviewCallback_v7_6_INTERFACE_DEFINED__ +#define __IDeckLinkScreenPreviewCallback_v7_6_INTERFACE_DEFINED__ + +/* interface IDeckLinkScreenPreviewCallback_v7_6 */ +/* [helpstring][local][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkScreenPreviewCallback_v7_6; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("373F499D-4B4D-4518-AD22-6354E5A5825E") + IDeckLinkScreenPreviewCallback_v7_6 : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE DrawFrame( + /* [in] */ IDeckLinkVideoFrame_v7_6 *theFrame) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkScreenPreviewCallback_v7_6Vtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkScreenPreviewCallback_v7_6 * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkScreenPreviewCallback_v7_6 * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkScreenPreviewCallback_v7_6 * This); + + HRESULT ( STDMETHODCALLTYPE *DrawFrame )( + IDeckLinkScreenPreviewCallback_v7_6 * This, + /* [in] */ IDeckLinkVideoFrame_v7_6 *theFrame); + + END_INTERFACE + } IDeckLinkScreenPreviewCallback_v7_6Vtbl; + + interface IDeckLinkScreenPreviewCallback_v7_6 + { + CONST_VTBL struct IDeckLinkScreenPreviewCallback_v7_6Vtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkScreenPreviewCallback_v7_6_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkScreenPreviewCallback_v7_6_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkScreenPreviewCallback_v7_6_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkScreenPreviewCallback_v7_6_DrawFrame(This,theFrame) \ + ( (This)->lpVtbl -> DrawFrame(This,theFrame) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkScreenPreviewCallback_v7_6_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkGLScreenPreviewHelper_v7_6_INTERFACE_DEFINED__ +#define __IDeckLinkGLScreenPreviewHelper_v7_6_INTERFACE_DEFINED__ + +/* interface IDeckLinkGLScreenPreviewHelper_v7_6 */ +/* [helpstring][local][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkGLScreenPreviewHelper_v7_6; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("BA575CD9-A15E-497B-B2C2-F9AFE7BE4EBA") + IDeckLinkGLScreenPreviewHelper_v7_6 : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE InitializeGL( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE PaintGL( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetFrame( + /* [in] */ IDeckLinkVideoFrame_v7_6 *theFrame) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkGLScreenPreviewHelper_v7_6Vtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkGLScreenPreviewHelper_v7_6 * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkGLScreenPreviewHelper_v7_6 * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkGLScreenPreviewHelper_v7_6 * This); + + HRESULT ( STDMETHODCALLTYPE *InitializeGL )( + IDeckLinkGLScreenPreviewHelper_v7_6 * This); + + HRESULT ( STDMETHODCALLTYPE *PaintGL )( + IDeckLinkGLScreenPreviewHelper_v7_6 * This); + + HRESULT ( STDMETHODCALLTYPE *SetFrame )( + IDeckLinkGLScreenPreviewHelper_v7_6 * This, + /* [in] */ IDeckLinkVideoFrame_v7_6 *theFrame); + + END_INTERFACE + } IDeckLinkGLScreenPreviewHelper_v7_6Vtbl; + + interface IDeckLinkGLScreenPreviewHelper_v7_6 + { + CONST_VTBL struct IDeckLinkGLScreenPreviewHelper_v7_6Vtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkGLScreenPreviewHelper_v7_6_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkGLScreenPreviewHelper_v7_6_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkGLScreenPreviewHelper_v7_6_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkGLScreenPreviewHelper_v7_6_InitializeGL(This) \ + ( (This)->lpVtbl -> InitializeGL(This) ) + +#define IDeckLinkGLScreenPreviewHelper_v7_6_PaintGL(This) \ + ( (This)->lpVtbl -> PaintGL(This) ) + +#define IDeckLinkGLScreenPreviewHelper_v7_6_SetFrame(This,theFrame) \ + ( (This)->lpVtbl -> SetFrame(This,theFrame) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkGLScreenPreviewHelper_v7_6_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkVideoConversion_v7_6_INTERFACE_DEFINED__ +#define __IDeckLinkVideoConversion_v7_6_INTERFACE_DEFINED__ + +/* interface IDeckLinkVideoConversion_v7_6 */ +/* [helpstring][local][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkVideoConversion_v7_6; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("3EB504C9-F97D-40FE-A158-D407D48CB53B") + IDeckLinkVideoConversion_v7_6 : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE ConvertFrame( + /* [in] */ IDeckLinkVideoFrame_v7_6 *srcFrame, + /* [in] */ IDeckLinkVideoFrame_v7_6 *dstFrame) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkVideoConversion_v7_6Vtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkVideoConversion_v7_6 * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkVideoConversion_v7_6 * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkVideoConversion_v7_6 * This); + + HRESULT ( STDMETHODCALLTYPE *ConvertFrame )( + IDeckLinkVideoConversion_v7_6 * This, + /* [in] */ IDeckLinkVideoFrame_v7_6 *srcFrame, + /* [in] */ IDeckLinkVideoFrame_v7_6 *dstFrame); + + END_INTERFACE + } IDeckLinkVideoConversion_v7_6Vtbl; + + interface IDeckLinkVideoConversion_v7_6 + { + CONST_VTBL struct IDeckLinkVideoConversion_v7_6Vtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkVideoConversion_v7_6_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkVideoConversion_v7_6_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkVideoConversion_v7_6_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkVideoConversion_v7_6_ConvertFrame(This,srcFrame,dstFrame) \ + ( (This)->lpVtbl -> ConvertFrame(This,srcFrame,dstFrame) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkVideoConversion_v7_6_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkConfiguration_v7_6_INTERFACE_DEFINED__ +#define __IDeckLinkConfiguration_v7_6_INTERFACE_DEFINED__ + +/* interface IDeckLinkConfiguration_v7_6 */ +/* [helpstring][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkConfiguration_v7_6; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("B8EAD569-B764-47F0-A73F-AE40DF6CBF10") + IDeckLinkConfiguration_v7_6 : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE GetConfigurationValidator( + /* [out] */ IDeckLinkConfiguration_v7_6 **configObject) = 0; + + virtual HRESULT STDMETHODCALLTYPE WriteConfigurationToPreferences( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetVideoOutputFormat( + /* [in] */ BMDVideoConnection_v7_6 videoOutputConnection) = 0; + + virtual HRESULT STDMETHODCALLTYPE IsVideoOutputActive( + /* [in] */ BMDVideoConnection_v7_6 videoOutputConnection, + /* [out] */ BOOL *active) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetAnalogVideoOutputFlags( + /* [in] */ BMDAnalogVideoFlags analogVideoFlags) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetAnalogVideoOutputFlags( + /* [out] */ BMDAnalogVideoFlags *analogVideoFlags) = 0; + + virtual HRESULT STDMETHODCALLTYPE EnableFieldFlickerRemovalWhenPaused( + /* [in] */ BOOL enable) = 0; + + virtual HRESULT STDMETHODCALLTYPE IsEnabledFieldFlickerRemovalWhenPaused( + /* [out] */ BOOL *enabled) = 0; + + virtual HRESULT STDMETHODCALLTYPE Set444And3GBpsVideoOutput( + /* [in] */ BOOL enable444VideoOutput, + /* [in] */ BOOL enable3GbsOutput) = 0; + + virtual HRESULT STDMETHODCALLTYPE Get444And3GBpsVideoOutput( + /* [out] */ BOOL *is444VideoOutputEnabled, + /* [out] */ BOOL *threeGbsOutputEnabled) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetVideoOutputConversionMode( + /* [in] */ BMDVideoOutputConversionMode conversionMode) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetVideoOutputConversionMode( + /* [out] */ BMDVideoOutputConversionMode *conversionMode) = 0; + + virtual HRESULT STDMETHODCALLTYPE Set_HD1080p24_to_HD1080i5994_Conversion( + /* [in] */ BOOL enable) = 0; + + virtual HRESULT STDMETHODCALLTYPE Get_HD1080p24_to_HD1080i5994_Conversion( + /* [out] */ BOOL *enabled) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetVideoInputFormat( + /* [in] */ BMDVideoConnection_v7_6 videoInputFormat) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetVideoInputFormat( + /* [out] */ BMDVideoConnection_v7_6 *videoInputFormat) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetAnalogVideoInputFlags( + /* [in] */ BMDAnalogVideoFlags analogVideoFlags) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetAnalogVideoInputFlags( + /* [out] */ BMDAnalogVideoFlags *analogVideoFlags) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetVideoInputConversionMode( + /* [in] */ BMDVideoInputConversionMode conversionMode) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetVideoInputConversionMode( + /* [out] */ BMDVideoInputConversionMode *conversionMode) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetBlackVideoOutputDuringCapture( + /* [in] */ BOOL blackOutInCapture) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetBlackVideoOutputDuringCapture( + /* [out] */ BOOL *blackOutInCapture) = 0; + + virtual HRESULT STDMETHODCALLTYPE Set32PulldownSequenceInitialTimecodeFrame( + /* [in] */ unsigned int aFrameTimecode) = 0; + + virtual HRESULT STDMETHODCALLTYPE Get32PulldownSequenceInitialTimecodeFrame( + /* [out] */ unsigned int *aFrameTimecode) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetVancSourceLineMapping( + /* [in] */ unsigned int activeLine1VANCsource, + /* [in] */ unsigned int activeLine2VANCsource, + /* [in] */ unsigned int activeLine3VANCsource) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetVancSourceLineMapping( + /* [out] */ unsigned int *activeLine1VANCsource, + /* [out] */ unsigned int *activeLine2VANCsource, + /* [out] */ unsigned int *activeLine3VANCsource) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetAudioInputFormat( + /* [in] */ BMDAudioConnection_v10_2 audioInputFormat) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetAudioInputFormat( + /* [out] */ BMDAudioConnection_v10_2 *audioInputFormat) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkConfiguration_v7_6Vtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkConfiguration_v7_6 * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkConfiguration_v7_6 * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkConfiguration_v7_6 * This); + + HRESULT ( STDMETHODCALLTYPE *GetConfigurationValidator )( + IDeckLinkConfiguration_v7_6 * This, + /* [out] */ IDeckLinkConfiguration_v7_6 **configObject); + + HRESULT ( STDMETHODCALLTYPE *WriteConfigurationToPreferences )( + IDeckLinkConfiguration_v7_6 * This); + + HRESULT ( STDMETHODCALLTYPE *SetVideoOutputFormat )( + IDeckLinkConfiguration_v7_6 * This, + /* [in] */ BMDVideoConnection_v7_6 videoOutputConnection); + + HRESULT ( STDMETHODCALLTYPE *IsVideoOutputActive )( + IDeckLinkConfiguration_v7_6 * This, + /* [in] */ BMDVideoConnection_v7_6 videoOutputConnection, + /* [out] */ BOOL *active); + + HRESULT ( STDMETHODCALLTYPE *SetAnalogVideoOutputFlags )( + IDeckLinkConfiguration_v7_6 * This, + /* [in] */ BMDAnalogVideoFlags analogVideoFlags); + + HRESULT ( STDMETHODCALLTYPE *GetAnalogVideoOutputFlags )( + IDeckLinkConfiguration_v7_6 * This, + /* [out] */ BMDAnalogVideoFlags *analogVideoFlags); + + HRESULT ( STDMETHODCALLTYPE *EnableFieldFlickerRemovalWhenPaused )( + IDeckLinkConfiguration_v7_6 * This, + /* [in] */ BOOL enable); + + HRESULT ( STDMETHODCALLTYPE *IsEnabledFieldFlickerRemovalWhenPaused )( + IDeckLinkConfiguration_v7_6 * This, + /* [out] */ BOOL *enabled); + + HRESULT ( STDMETHODCALLTYPE *Set444And3GBpsVideoOutput )( + IDeckLinkConfiguration_v7_6 * This, + /* [in] */ BOOL enable444VideoOutput, + /* [in] */ BOOL enable3GbsOutput); + + HRESULT ( STDMETHODCALLTYPE *Get444And3GBpsVideoOutput )( + IDeckLinkConfiguration_v7_6 * This, + /* [out] */ BOOL *is444VideoOutputEnabled, + /* [out] */ BOOL *threeGbsOutputEnabled); + + HRESULT ( STDMETHODCALLTYPE *SetVideoOutputConversionMode )( + IDeckLinkConfiguration_v7_6 * This, + /* [in] */ BMDVideoOutputConversionMode conversionMode); + + HRESULT ( STDMETHODCALLTYPE *GetVideoOutputConversionMode )( + IDeckLinkConfiguration_v7_6 * This, + /* [out] */ BMDVideoOutputConversionMode *conversionMode); + + HRESULT ( STDMETHODCALLTYPE *Set_HD1080p24_to_HD1080i5994_Conversion )( + IDeckLinkConfiguration_v7_6 * This, + /* [in] */ BOOL enable); + + HRESULT ( STDMETHODCALLTYPE *Get_HD1080p24_to_HD1080i5994_Conversion )( + IDeckLinkConfiguration_v7_6 * This, + /* [out] */ BOOL *enabled); + + HRESULT ( STDMETHODCALLTYPE *SetVideoInputFormat )( + IDeckLinkConfiguration_v7_6 * This, + /* [in] */ BMDVideoConnection_v7_6 videoInputFormat); + + HRESULT ( STDMETHODCALLTYPE *GetVideoInputFormat )( + IDeckLinkConfiguration_v7_6 * This, + /* [out] */ BMDVideoConnection_v7_6 *videoInputFormat); + + HRESULT ( STDMETHODCALLTYPE *SetAnalogVideoInputFlags )( + IDeckLinkConfiguration_v7_6 * This, + /* [in] */ BMDAnalogVideoFlags analogVideoFlags); + + HRESULT ( STDMETHODCALLTYPE *GetAnalogVideoInputFlags )( + IDeckLinkConfiguration_v7_6 * This, + /* [out] */ BMDAnalogVideoFlags *analogVideoFlags); + + HRESULT ( STDMETHODCALLTYPE *SetVideoInputConversionMode )( + IDeckLinkConfiguration_v7_6 * This, + /* [in] */ BMDVideoInputConversionMode conversionMode); + + HRESULT ( STDMETHODCALLTYPE *GetVideoInputConversionMode )( + IDeckLinkConfiguration_v7_6 * This, + /* [out] */ BMDVideoInputConversionMode *conversionMode); + + HRESULT ( STDMETHODCALLTYPE *SetBlackVideoOutputDuringCapture )( + IDeckLinkConfiguration_v7_6 * This, + /* [in] */ BOOL blackOutInCapture); + + HRESULT ( STDMETHODCALLTYPE *GetBlackVideoOutputDuringCapture )( + IDeckLinkConfiguration_v7_6 * This, + /* [out] */ BOOL *blackOutInCapture); + + HRESULT ( STDMETHODCALLTYPE *Set32PulldownSequenceInitialTimecodeFrame )( + IDeckLinkConfiguration_v7_6 * This, + /* [in] */ unsigned int aFrameTimecode); + + HRESULT ( STDMETHODCALLTYPE *Get32PulldownSequenceInitialTimecodeFrame )( + IDeckLinkConfiguration_v7_6 * This, + /* [out] */ unsigned int *aFrameTimecode); + + HRESULT ( STDMETHODCALLTYPE *SetVancSourceLineMapping )( + IDeckLinkConfiguration_v7_6 * This, + /* [in] */ unsigned int activeLine1VANCsource, + /* [in] */ unsigned int activeLine2VANCsource, + /* [in] */ unsigned int activeLine3VANCsource); + + HRESULT ( STDMETHODCALLTYPE *GetVancSourceLineMapping )( + IDeckLinkConfiguration_v7_6 * This, + /* [out] */ unsigned int *activeLine1VANCsource, + /* [out] */ unsigned int *activeLine2VANCsource, + /* [out] */ unsigned int *activeLine3VANCsource); + + HRESULT ( STDMETHODCALLTYPE *SetAudioInputFormat )( + IDeckLinkConfiguration_v7_6 * This, + /* [in] */ BMDAudioConnection_v10_2 audioInputFormat); + + HRESULT ( STDMETHODCALLTYPE *GetAudioInputFormat )( + IDeckLinkConfiguration_v7_6 * This, + /* [out] */ BMDAudioConnection_v10_2 *audioInputFormat); + + END_INTERFACE + } IDeckLinkConfiguration_v7_6Vtbl; + + interface IDeckLinkConfiguration_v7_6 + { + CONST_VTBL struct IDeckLinkConfiguration_v7_6Vtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkConfiguration_v7_6_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkConfiguration_v7_6_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkConfiguration_v7_6_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkConfiguration_v7_6_GetConfigurationValidator(This,configObject) \ + ( (This)->lpVtbl -> GetConfigurationValidator(This,configObject) ) + +#define IDeckLinkConfiguration_v7_6_WriteConfigurationToPreferences(This) \ + ( (This)->lpVtbl -> WriteConfigurationToPreferences(This) ) + +#define IDeckLinkConfiguration_v7_6_SetVideoOutputFormat(This,videoOutputConnection) \ + ( (This)->lpVtbl -> SetVideoOutputFormat(This,videoOutputConnection) ) + +#define IDeckLinkConfiguration_v7_6_IsVideoOutputActive(This,videoOutputConnection,active) \ + ( (This)->lpVtbl -> IsVideoOutputActive(This,videoOutputConnection,active) ) + +#define IDeckLinkConfiguration_v7_6_SetAnalogVideoOutputFlags(This,analogVideoFlags) \ + ( (This)->lpVtbl -> SetAnalogVideoOutputFlags(This,analogVideoFlags) ) + +#define IDeckLinkConfiguration_v7_6_GetAnalogVideoOutputFlags(This,analogVideoFlags) \ + ( (This)->lpVtbl -> GetAnalogVideoOutputFlags(This,analogVideoFlags) ) + +#define IDeckLinkConfiguration_v7_6_EnableFieldFlickerRemovalWhenPaused(This,enable) \ + ( (This)->lpVtbl -> EnableFieldFlickerRemovalWhenPaused(This,enable) ) + +#define IDeckLinkConfiguration_v7_6_IsEnabledFieldFlickerRemovalWhenPaused(This,enabled) \ + ( (This)->lpVtbl -> IsEnabledFieldFlickerRemovalWhenPaused(This,enabled) ) + +#define IDeckLinkConfiguration_v7_6_Set444And3GBpsVideoOutput(This,enable444VideoOutput,enable3GbsOutput) \ + ( (This)->lpVtbl -> Set444And3GBpsVideoOutput(This,enable444VideoOutput,enable3GbsOutput) ) + +#define IDeckLinkConfiguration_v7_6_Get444And3GBpsVideoOutput(This,is444VideoOutputEnabled,threeGbsOutputEnabled) \ + ( (This)->lpVtbl -> Get444And3GBpsVideoOutput(This,is444VideoOutputEnabled,threeGbsOutputEnabled) ) + +#define IDeckLinkConfiguration_v7_6_SetVideoOutputConversionMode(This,conversionMode) \ + ( (This)->lpVtbl -> SetVideoOutputConversionMode(This,conversionMode) ) + +#define IDeckLinkConfiguration_v7_6_GetVideoOutputConversionMode(This,conversionMode) \ + ( (This)->lpVtbl -> GetVideoOutputConversionMode(This,conversionMode) ) + +#define IDeckLinkConfiguration_v7_6_Set_HD1080p24_to_HD1080i5994_Conversion(This,enable) \ + ( (This)->lpVtbl -> Set_HD1080p24_to_HD1080i5994_Conversion(This,enable) ) + +#define IDeckLinkConfiguration_v7_6_Get_HD1080p24_to_HD1080i5994_Conversion(This,enabled) \ + ( (This)->lpVtbl -> Get_HD1080p24_to_HD1080i5994_Conversion(This,enabled) ) + +#define IDeckLinkConfiguration_v7_6_SetVideoInputFormat(This,videoInputFormat) \ + ( (This)->lpVtbl -> SetVideoInputFormat(This,videoInputFormat) ) + +#define IDeckLinkConfiguration_v7_6_GetVideoInputFormat(This,videoInputFormat) \ + ( (This)->lpVtbl -> GetVideoInputFormat(This,videoInputFormat) ) + +#define IDeckLinkConfiguration_v7_6_SetAnalogVideoInputFlags(This,analogVideoFlags) \ + ( (This)->lpVtbl -> SetAnalogVideoInputFlags(This,analogVideoFlags) ) + +#define IDeckLinkConfiguration_v7_6_GetAnalogVideoInputFlags(This,analogVideoFlags) \ + ( (This)->lpVtbl -> GetAnalogVideoInputFlags(This,analogVideoFlags) ) + +#define IDeckLinkConfiguration_v7_6_SetVideoInputConversionMode(This,conversionMode) \ + ( (This)->lpVtbl -> SetVideoInputConversionMode(This,conversionMode) ) + +#define IDeckLinkConfiguration_v7_6_GetVideoInputConversionMode(This,conversionMode) \ + ( (This)->lpVtbl -> GetVideoInputConversionMode(This,conversionMode) ) + +#define IDeckLinkConfiguration_v7_6_SetBlackVideoOutputDuringCapture(This,blackOutInCapture) \ + ( (This)->lpVtbl -> SetBlackVideoOutputDuringCapture(This,blackOutInCapture) ) + +#define IDeckLinkConfiguration_v7_6_GetBlackVideoOutputDuringCapture(This,blackOutInCapture) \ + ( (This)->lpVtbl -> GetBlackVideoOutputDuringCapture(This,blackOutInCapture) ) + +#define IDeckLinkConfiguration_v7_6_Set32PulldownSequenceInitialTimecodeFrame(This,aFrameTimecode) \ + ( (This)->lpVtbl -> Set32PulldownSequenceInitialTimecodeFrame(This,aFrameTimecode) ) + +#define IDeckLinkConfiguration_v7_6_Get32PulldownSequenceInitialTimecodeFrame(This,aFrameTimecode) \ + ( (This)->lpVtbl -> Get32PulldownSequenceInitialTimecodeFrame(This,aFrameTimecode) ) + +#define IDeckLinkConfiguration_v7_6_SetVancSourceLineMapping(This,activeLine1VANCsource,activeLine2VANCsource,activeLine3VANCsource) \ + ( (This)->lpVtbl -> SetVancSourceLineMapping(This,activeLine1VANCsource,activeLine2VANCsource,activeLine3VANCsource) ) + +#define IDeckLinkConfiguration_v7_6_GetVancSourceLineMapping(This,activeLine1VANCsource,activeLine2VANCsource,activeLine3VANCsource) \ + ( (This)->lpVtbl -> GetVancSourceLineMapping(This,activeLine1VANCsource,activeLine2VANCsource,activeLine3VANCsource) ) + +#define IDeckLinkConfiguration_v7_6_SetAudioInputFormat(This,audioInputFormat) \ + ( (This)->lpVtbl -> SetAudioInputFormat(This,audioInputFormat) ) + +#define IDeckLinkConfiguration_v7_6_GetAudioInputFormat(This,audioInputFormat) \ + ( (This)->lpVtbl -> GetAudioInputFormat(This,audioInputFormat) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkConfiguration_v7_6_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkVideoOutputCallback_v7_6_INTERFACE_DEFINED__ +#define __IDeckLinkVideoOutputCallback_v7_6_INTERFACE_DEFINED__ + +/* interface IDeckLinkVideoOutputCallback_v7_6 */ +/* [helpstring][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkVideoOutputCallback_v7_6; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("E763A626-4A3C-49D1-BF13-E7AD3692AE52") + IDeckLinkVideoOutputCallback_v7_6 : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE ScheduledFrameCompleted( + /* [in] */ IDeckLinkVideoFrame_v7_6 *completedFrame, + /* [in] */ BMDOutputFrameCompletionResult result) = 0; + + virtual HRESULT STDMETHODCALLTYPE ScheduledPlaybackHasStopped( void) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkVideoOutputCallback_v7_6Vtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkVideoOutputCallback_v7_6 * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkVideoOutputCallback_v7_6 * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkVideoOutputCallback_v7_6 * This); + + HRESULT ( STDMETHODCALLTYPE *ScheduledFrameCompleted )( + IDeckLinkVideoOutputCallback_v7_6 * This, + /* [in] */ IDeckLinkVideoFrame_v7_6 *completedFrame, + /* [in] */ BMDOutputFrameCompletionResult result); + + HRESULT ( STDMETHODCALLTYPE *ScheduledPlaybackHasStopped )( + IDeckLinkVideoOutputCallback_v7_6 * This); + + END_INTERFACE + } IDeckLinkVideoOutputCallback_v7_6Vtbl; + + interface IDeckLinkVideoOutputCallback_v7_6 + { + CONST_VTBL struct IDeckLinkVideoOutputCallback_v7_6Vtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkVideoOutputCallback_v7_6_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkVideoOutputCallback_v7_6_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkVideoOutputCallback_v7_6_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkVideoOutputCallback_v7_6_ScheduledFrameCompleted(This,completedFrame,result) \ + ( (This)->lpVtbl -> ScheduledFrameCompleted(This,completedFrame,result) ) + +#define IDeckLinkVideoOutputCallback_v7_6_ScheduledPlaybackHasStopped(This) \ + ( (This)->lpVtbl -> ScheduledPlaybackHasStopped(This) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkVideoOutputCallback_v7_6_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkInputCallback_v7_6_INTERFACE_DEFINED__ +#define __IDeckLinkInputCallback_v7_6_INTERFACE_DEFINED__ + +/* interface IDeckLinkInputCallback_v7_6 */ +/* [helpstring][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkInputCallback_v7_6; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("31D28EE7-88B6-4CB1-897A-CDBF79A26414") + IDeckLinkInputCallback_v7_6 : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE VideoInputFormatChanged( + /* [in] */ BMDVideoInputFormatChangedEvents notificationEvents, + /* [in] */ IDeckLinkDisplayMode_v7_6 *newDisplayMode, + /* [in] */ BMDDetectedVideoInputFormatFlags detectedSignalFlags) = 0; + + virtual HRESULT STDMETHODCALLTYPE VideoInputFrameArrived( + /* [in] */ IDeckLinkVideoInputFrame_v7_6 *videoFrame, + /* [in] */ IDeckLinkAudioInputPacket *audioPacket) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkInputCallback_v7_6Vtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkInputCallback_v7_6 * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkInputCallback_v7_6 * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkInputCallback_v7_6 * This); + + HRESULT ( STDMETHODCALLTYPE *VideoInputFormatChanged )( + IDeckLinkInputCallback_v7_6 * This, + /* [in] */ BMDVideoInputFormatChangedEvents notificationEvents, + /* [in] */ IDeckLinkDisplayMode_v7_6 *newDisplayMode, + /* [in] */ BMDDetectedVideoInputFormatFlags detectedSignalFlags); + + HRESULT ( STDMETHODCALLTYPE *VideoInputFrameArrived )( + IDeckLinkInputCallback_v7_6 * This, + /* [in] */ IDeckLinkVideoInputFrame_v7_6 *videoFrame, + /* [in] */ IDeckLinkAudioInputPacket *audioPacket); + + END_INTERFACE + } IDeckLinkInputCallback_v7_6Vtbl; + + interface IDeckLinkInputCallback_v7_6 + { + CONST_VTBL struct IDeckLinkInputCallback_v7_6Vtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkInputCallback_v7_6_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkInputCallback_v7_6_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkInputCallback_v7_6_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkInputCallback_v7_6_VideoInputFormatChanged(This,notificationEvents,newDisplayMode,detectedSignalFlags) \ + ( (This)->lpVtbl -> VideoInputFormatChanged(This,notificationEvents,newDisplayMode,detectedSignalFlags) ) + +#define IDeckLinkInputCallback_v7_6_VideoInputFrameArrived(This,videoFrame,audioPacket) \ + ( (This)->lpVtbl -> VideoInputFrameArrived(This,videoFrame,audioPacket) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkInputCallback_v7_6_INTERFACE_DEFINED__ */ + + +EXTERN_C const CLSID CLSID_CDeckLinkGLScreenPreviewHelper_v7_6; + +#ifdef __cplusplus + +class DECLSPEC_UUID("D398CEE7-4434-4CA3-9BA6-5AE34556B905") +CDeckLinkGLScreenPreviewHelper_v7_6; +#endif + +EXTERN_C const CLSID CLSID_CDeckLinkVideoConversion_v7_6; + +#ifdef __cplusplus + +class DECLSPEC_UUID("FFA84F77-73BE-4FB7-B03E-B5E44B9F759B") +CDeckLinkVideoConversion_v7_6; +#endif + +#ifndef __IDeckLinkInputCallback_v7_3_INTERFACE_DEFINED__ +#define __IDeckLinkInputCallback_v7_3_INTERFACE_DEFINED__ + +/* interface IDeckLinkInputCallback_v7_3 */ +/* [helpstring][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkInputCallback_v7_3; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("FD6F311D-4D00-444B-9ED4-1F25B5730AD0") + IDeckLinkInputCallback_v7_3 : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE VideoInputFormatChanged( + /* [in] */ BMDVideoInputFormatChangedEvents notificationEvents, + /* [in] */ IDeckLinkDisplayMode_v7_6 *newDisplayMode, + /* [in] */ BMDDetectedVideoInputFormatFlags detectedSignalFlags) = 0; + + virtual HRESULT STDMETHODCALLTYPE VideoInputFrameArrived( + /* [in] */ IDeckLinkVideoInputFrame_v7_3 *videoFrame, + /* [in] */ IDeckLinkAudioInputPacket *audioPacket) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkInputCallback_v7_3Vtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkInputCallback_v7_3 * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkInputCallback_v7_3 * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkInputCallback_v7_3 * This); + + HRESULT ( STDMETHODCALLTYPE *VideoInputFormatChanged )( + IDeckLinkInputCallback_v7_3 * This, + /* [in] */ BMDVideoInputFormatChangedEvents notificationEvents, + /* [in] */ IDeckLinkDisplayMode_v7_6 *newDisplayMode, + /* [in] */ BMDDetectedVideoInputFormatFlags detectedSignalFlags); + + HRESULT ( STDMETHODCALLTYPE *VideoInputFrameArrived )( + IDeckLinkInputCallback_v7_3 * This, + /* [in] */ IDeckLinkVideoInputFrame_v7_3 *videoFrame, + /* [in] */ IDeckLinkAudioInputPacket *audioPacket); + + END_INTERFACE + } IDeckLinkInputCallback_v7_3Vtbl; + + interface IDeckLinkInputCallback_v7_3 + { + CONST_VTBL struct IDeckLinkInputCallback_v7_3Vtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkInputCallback_v7_3_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkInputCallback_v7_3_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkInputCallback_v7_3_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkInputCallback_v7_3_VideoInputFormatChanged(This,notificationEvents,newDisplayMode,detectedSignalFlags) \ + ( (This)->lpVtbl -> VideoInputFormatChanged(This,notificationEvents,newDisplayMode,detectedSignalFlags) ) + +#define IDeckLinkInputCallback_v7_3_VideoInputFrameArrived(This,videoFrame,audioPacket) \ + ( (This)->lpVtbl -> VideoInputFrameArrived(This,videoFrame,audioPacket) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkInputCallback_v7_3_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkOutput_v7_3_INTERFACE_DEFINED__ +#define __IDeckLinkOutput_v7_3_INTERFACE_DEFINED__ + +/* interface IDeckLinkOutput_v7_3 */ +/* [helpstring][local][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkOutput_v7_3; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("271C65E3-C323-4344-A30F-D908BCB20AA3") + IDeckLinkOutput_v7_3 : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE DoesSupportVideoMode( + BMDDisplayMode displayMode, + BMDPixelFormat pixelFormat, + /* [out] */ BMDDisplayModeSupport *result) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetDisplayModeIterator( + /* [out] */ IDeckLinkDisplayModeIterator_v7_6 **iterator) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetScreenPreviewCallback( + /* [in] */ IDeckLinkScreenPreviewCallback *previewCallback) = 0; + + virtual HRESULT STDMETHODCALLTYPE EnableVideoOutput( + BMDDisplayMode displayMode, + BMDVideoOutputFlags flags) = 0; + + virtual HRESULT STDMETHODCALLTYPE DisableVideoOutput( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetVideoOutputFrameMemoryAllocator( + /* [in] */ IDeckLinkMemoryAllocator *theAllocator) = 0; + + virtual HRESULT STDMETHODCALLTYPE CreateVideoFrame( + int width, + int height, + int rowBytes, + BMDPixelFormat pixelFormat, + BMDFrameFlags flags, + /* [out] */ IDeckLinkMutableVideoFrame_v7_6 **outFrame) = 0; + + virtual HRESULT STDMETHODCALLTYPE CreateAncillaryData( + BMDPixelFormat pixelFormat, + /* [out] */ IDeckLinkVideoFrameAncillary **outBuffer) = 0; + + virtual HRESULT STDMETHODCALLTYPE DisplayVideoFrameSync( + /* [in] */ IDeckLinkVideoFrame_v7_6 *theFrame) = 0; + + virtual HRESULT STDMETHODCALLTYPE ScheduleVideoFrame( + /* [in] */ IDeckLinkVideoFrame_v7_6 *theFrame, + BMDTimeValue displayTime, + BMDTimeValue displayDuration, + BMDTimeScale timeScale) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetScheduledFrameCompletionCallback( + /* [in] */ IDeckLinkVideoOutputCallback *theCallback) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetBufferedVideoFrameCount( + /* [out] */ unsigned int *bufferedFrameCount) = 0; + + virtual HRESULT STDMETHODCALLTYPE EnableAudioOutput( + BMDAudioSampleRate sampleRate, + BMDAudioSampleType sampleType, + unsigned int channelCount, + BMDAudioOutputStreamType streamType) = 0; + + virtual HRESULT STDMETHODCALLTYPE DisableAudioOutput( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE WriteAudioSamplesSync( + /* [in] */ void *buffer, + unsigned int sampleFrameCount, + /* [out] */ unsigned int *sampleFramesWritten) = 0; + + virtual HRESULT STDMETHODCALLTYPE BeginAudioPreroll( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE EndAudioPreroll( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE ScheduleAudioSamples( + /* [in] */ void *buffer, + unsigned int sampleFrameCount, + BMDTimeValue streamTime, + BMDTimeScale timeScale, + /* [out] */ unsigned int *sampleFramesWritten) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetBufferedAudioSampleFrameCount( + /* [out] */ unsigned int *bufferedSampleFrameCount) = 0; + + virtual HRESULT STDMETHODCALLTYPE FlushBufferedAudioSamples( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetAudioCallback( + /* [in] */ IDeckLinkAudioOutputCallback *theCallback) = 0; + + virtual HRESULT STDMETHODCALLTYPE StartScheduledPlayback( + BMDTimeValue playbackStartTime, + BMDTimeScale timeScale, + double playbackSpeed) = 0; + + virtual HRESULT STDMETHODCALLTYPE StopScheduledPlayback( + BMDTimeValue stopPlaybackAtTime, + /* [out] */ BMDTimeValue *actualStopTime, + BMDTimeScale timeScale) = 0; + + virtual HRESULT STDMETHODCALLTYPE IsScheduledPlaybackRunning( + /* [out] */ BOOL *active) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetHardwareReferenceClock( + BMDTimeScale desiredTimeScale, + /* [out] */ BMDTimeValue *elapsedTimeSinceSchedulerBegan) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkOutput_v7_3Vtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkOutput_v7_3 * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkOutput_v7_3 * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkOutput_v7_3 * This); + + HRESULT ( STDMETHODCALLTYPE *DoesSupportVideoMode )( + IDeckLinkOutput_v7_3 * This, + BMDDisplayMode displayMode, + BMDPixelFormat pixelFormat, + /* [out] */ BMDDisplayModeSupport *result); + + HRESULT ( STDMETHODCALLTYPE *GetDisplayModeIterator )( + IDeckLinkOutput_v7_3 * This, + /* [out] */ IDeckLinkDisplayModeIterator_v7_6 **iterator); + + HRESULT ( STDMETHODCALLTYPE *SetScreenPreviewCallback )( + IDeckLinkOutput_v7_3 * This, + /* [in] */ IDeckLinkScreenPreviewCallback *previewCallback); + + HRESULT ( STDMETHODCALLTYPE *EnableVideoOutput )( + IDeckLinkOutput_v7_3 * This, + BMDDisplayMode displayMode, + BMDVideoOutputFlags flags); + + HRESULT ( STDMETHODCALLTYPE *DisableVideoOutput )( + IDeckLinkOutput_v7_3 * This); + + HRESULT ( STDMETHODCALLTYPE *SetVideoOutputFrameMemoryAllocator )( + IDeckLinkOutput_v7_3 * This, + /* [in] */ IDeckLinkMemoryAllocator *theAllocator); + + HRESULT ( STDMETHODCALLTYPE *CreateVideoFrame )( + IDeckLinkOutput_v7_3 * This, + int width, + int height, + int rowBytes, + BMDPixelFormat pixelFormat, + BMDFrameFlags flags, + /* [out] */ IDeckLinkMutableVideoFrame_v7_6 **outFrame); + + HRESULT ( STDMETHODCALLTYPE *CreateAncillaryData )( + IDeckLinkOutput_v7_3 * This, + BMDPixelFormat pixelFormat, + /* [out] */ IDeckLinkVideoFrameAncillary **outBuffer); + + HRESULT ( STDMETHODCALLTYPE *DisplayVideoFrameSync )( + IDeckLinkOutput_v7_3 * This, + /* [in] */ IDeckLinkVideoFrame_v7_6 *theFrame); + + HRESULT ( STDMETHODCALLTYPE *ScheduleVideoFrame )( + IDeckLinkOutput_v7_3 * This, + /* [in] */ IDeckLinkVideoFrame_v7_6 *theFrame, + BMDTimeValue displayTime, + BMDTimeValue displayDuration, + BMDTimeScale timeScale); + + HRESULT ( STDMETHODCALLTYPE *SetScheduledFrameCompletionCallback )( + IDeckLinkOutput_v7_3 * This, + /* [in] */ IDeckLinkVideoOutputCallback *theCallback); + + HRESULT ( STDMETHODCALLTYPE *GetBufferedVideoFrameCount )( + IDeckLinkOutput_v7_3 * This, + /* [out] */ unsigned int *bufferedFrameCount); + + HRESULT ( STDMETHODCALLTYPE *EnableAudioOutput )( + IDeckLinkOutput_v7_3 * This, + BMDAudioSampleRate sampleRate, + BMDAudioSampleType sampleType, + unsigned int channelCount, + BMDAudioOutputStreamType streamType); + + HRESULT ( STDMETHODCALLTYPE *DisableAudioOutput )( + IDeckLinkOutput_v7_3 * This); + + HRESULT ( STDMETHODCALLTYPE *WriteAudioSamplesSync )( + IDeckLinkOutput_v7_3 * This, + /* [in] */ void *buffer, + unsigned int sampleFrameCount, + /* [out] */ unsigned int *sampleFramesWritten); + + HRESULT ( STDMETHODCALLTYPE *BeginAudioPreroll )( + IDeckLinkOutput_v7_3 * This); + + HRESULT ( STDMETHODCALLTYPE *EndAudioPreroll )( + IDeckLinkOutput_v7_3 * This); + + HRESULT ( STDMETHODCALLTYPE *ScheduleAudioSamples )( + IDeckLinkOutput_v7_3 * This, + /* [in] */ void *buffer, + unsigned int sampleFrameCount, + BMDTimeValue streamTime, + BMDTimeScale timeScale, + /* [out] */ unsigned int *sampleFramesWritten); + + HRESULT ( STDMETHODCALLTYPE *GetBufferedAudioSampleFrameCount )( + IDeckLinkOutput_v7_3 * This, + /* [out] */ unsigned int *bufferedSampleFrameCount); + + HRESULT ( STDMETHODCALLTYPE *FlushBufferedAudioSamples )( + IDeckLinkOutput_v7_3 * This); + + HRESULT ( STDMETHODCALLTYPE *SetAudioCallback )( + IDeckLinkOutput_v7_3 * This, + /* [in] */ IDeckLinkAudioOutputCallback *theCallback); + + HRESULT ( STDMETHODCALLTYPE *StartScheduledPlayback )( + IDeckLinkOutput_v7_3 * This, + BMDTimeValue playbackStartTime, + BMDTimeScale timeScale, + double playbackSpeed); + + HRESULT ( STDMETHODCALLTYPE *StopScheduledPlayback )( + IDeckLinkOutput_v7_3 * This, + BMDTimeValue stopPlaybackAtTime, + /* [out] */ BMDTimeValue *actualStopTime, + BMDTimeScale timeScale); + + HRESULT ( STDMETHODCALLTYPE *IsScheduledPlaybackRunning )( + IDeckLinkOutput_v7_3 * This, + /* [out] */ BOOL *active); + + HRESULT ( STDMETHODCALLTYPE *GetHardwareReferenceClock )( + IDeckLinkOutput_v7_3 * This, + BMDTimeScale desiredTimeScale, + /* [out] */ BMDTimeValue *elapsedTimeSinceSchedulerBegan); + + END_INTERFACE + } IDeckLinkOutput_v7_3Vtbl; + + interface IDeckLinkOutput_v7_3 + { + CONST_VTBL struct IDeckLinkOutput_v7_3Vtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkOutput_v7_3_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkOutput_v7_3_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkOutput_v7_3_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkOutput_v7_3_DoesSupportVideoMode(This,displayMode,pixelFormat,result) \ + ( (This)->lpVtbl -> DoesSupportVideoMode(This,displayMode,pixelFormat,result) ) + +#define IDeckLinkOutput_v7_3_GetDisplayModeIterator(This,iterator) \ + ( (This)->lpVtbl -> GetDisplayModeIterator(This,iterator) ) + +#define IDeckLinkOutput_v7_3_SetScreenPreviewCallback(This,previewCallback) \ + ( (This)->lpVtbl -> SetScreenPreviewCallback(This,previewCallback) ) + +#define IDeckLinkOutput_v7_3_EnableVideoOutput(This,displayMode,flags) \ + ( (This)->lpVtbl -> EnableVideoOutput(This,displayMode,flags) ) + +#define IDeckLinkOutput_v7_3_DisableVideoOutput(This) \ + ( (This)->lpVtbl -> DisableVideoOutput(This) ) + +#define IDeckLinkOutput_v7_3_SetVideoOutputFrameMemoryAllocator(This,theAllocator) \ + ( (This)->lpVtbl -> SetVideoOutputFrameMemoryAllocator(This,theAllocator) ) + +#define IDeckLinkOutput_v7_3_CreateVideoFrame(This,width,height,rowBytes,pixelFormat,flags,outFrame) \ + ( (This)->lpVtbl -> CreateVideoFrame(This,width,height,rowBytes,pixelFormat,flags,outFrame) ) + +#define IDeckLinkOutput_v7_3_CreateAncillaryData(This,pixelFormat,outBuffer) \ + ( (This)->lpVtbl -> CreateAncillaryData(This,pixelFormat,outBuffer) ) + +#define IDeckLinkOutput_v7_3_DisplayVideoFrameSync(This,theFrame) \ + ( (This)->lpVtbl -> DisplayVideoFrameSync(This,theFrame) ) + +#define IDeckLinkOutput_v7_3_ScheduleVideoFrame(This,theFrame,displayTime,displayDuration,timeScale) \ + ( (This)->lpVtbl -> ScheduleVideoFrame(This,theFrame,displayTime,displayDuration,timeScale) ) + +#define IDeckLinkOutput_v7_3_SetScheduledFrameCompletionCallback(This,theCallback) \ + ( (This)->lpVtbl -> SetScheduledFrameCompletionCallback(This,theCallback) ) + +#define IDeckLinkOutput_v7_3_GetBufferedVideoFrameCount(This,bufferedFrameCount) \ + ( (This)->lpVtbl -> GetBufferedVideoFrameCount(This,bufferedFrameCount) ) + +#define IDeckLinkOutput_v7_3_EnableAudioOutput(This,sampleRate,sampleType,channelCount,streamType) \ + ( (This)->lpVtbl -> EnableAudioOutput(This,sampleRate,sampleType,channelCount,streamType) ) + +#define IDeckLinkOutput_v7_3_DisableAudioOutput(This) \ + ( (This)->lpVtbl -> DisableAudioOutput(This) ) + +#define IDeckLinkOutput_v7_3_WriteAudioSamplesSync(This,buffer,sampleFrameCount,sampleFramesWritten) \ + ( (This)->lpVtbl -> WriteAudioSamplesSync(This,buffer,sampleFrameCount,sampleFramesWritten) ) + +#define IDeckLinkOutput_v7_3_BeginAudioPreroll(This) \ + ( (This)->lpVtbl -> BeginAudioPreroll(This) ) + +#define IDeckLinkOutput_v7_3_EndAudioPreroll(This) \ + ( (This)->lpVtbl -> EndAudioPreroll(This) ) + +#define IDeckLinkOutput_v7_3_ScheduleAudioSamples(This,buffer,sampleFrameCount,streamTime,timeScale,sampleFramesWritten) \ + ( (This)->lpVtbl -> ScheduleAudioSamples(This,buffer,sampleFrameCount,streamTime,timeScale,sampleFramesWritten) ) + +#define IDeckLinkOutput_v7_3_GetBufferedAudioSampleFrameCount(This,bufferedSampleFrameCount) \ + ( (This)->lpVtbl -> GetBufferedAudioSampleFrameCount(This,bufferedSampleFrameCount) ) + +#define IDeckLinkOutput_v7_3_FlushBufferedAudioSamples(This) \ + ( (This)->lpVtbl -> FlushBufferedAudioSamples(This) ) + +#define IDeckLinkOutput_v7_3_SetAudioCallback(This,theCallback) \ + ( (This)->lpVtbl -> SetAudioCallback(This,theCallback) ) + +#define IDeckLinkOutput_v7_3_StartScheduledPlayback(This,playbackStartTime,timeScale,playbackSpeed) \ + ( (This)->lpVtbl -> StartScheduledPlayback(This,playbackStartTime,timeScale,playbackSpeed) ) + +#define IDeckLinkOutput_v7_3_StopScheduledPlayback(This,stopPlaybackAtTime,actualStopTime,timeScale) \ + ( (This)->lpVtbl -> StopScheduledPlayback(This,stopPlaybackAtTime,actualStopTime,timeScale) ) + +#define IDeckLinkOutput_v7_3_IsScheduledPlaybackRunning(This,active) \ + ( (This)->lpVtbl -> IsScheduledPlaybackRunning(This,active) ) + +#define IDeckLinkOutput_v7_3_GetHardwareReferenceClock(This,desiredTimeScale,elapsedTimeSinceSchedulerBegan) \ + ( (This)->lpVtbl -> GetHardwareReferenceClock(This,desiredTimeScale,elapsedTimeSinceSchedulerBegan) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkOutput_v7_3_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkInput_v7_3_INTERFACE_DEFINED__ +#define __IDeckLinkInput_v7_3_INTERFACE_DEFINED__ + +/* interface IDeckLinkInput_v7_3 */ +/* [helpstring][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkInput_v7_3; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("4973F012-9925-458C-871C-18774CDBBECB") + IDeckLinkInput_v7_3 : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE DoesSupportVideoMode( + BMDDisplayMode displayMode, + BMDPixelFormat pixelFormat, + /* [out] */ BMDDisplayModeSupport *result) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetDisplayModeIterator( + /* [out] */ IDeckLinkDisplayModeIterator_v7_6 **iterator) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetScreenPreviewCallback( + /* [in] */ IDeckLinkScreenPreviewCallback *previewCallback) = 0; + + virtual HRESULT STDMETHODCALLTYPE EnableVideoInput( + BMDDisplayMode displayMode, + BMDPixelFormat pixelFormat, + BMDVideoInputFlags flags) = 0; + + virtual HRESULT STDMETHODCALLTYPE DisableVideoInput( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetAvailableVideoFrameCount( + /* [out] */ unsigned int *availableFrameCount) = 0; + + virtual HRESULT STDMETHODCALLTYPE EnableAudioInput( + BMDAudioSampleRate sampleRate, + BMDAudioSampleType sampleType, + unsigned int channelCount) = 0; + + virtual HRESULT STDMETHODCALLTYPE DisableAudioInput( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetAvailableAudioSampleFrameCount( + /* [out] */ unsigned int *availableSampleFrameCount) = 0; + + virtual HRESULT STDMETHODCALLTYPE StartStreams( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE StopStreams( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE PauseStreams( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE FlushStreams( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetCallback( + /* [in] */ IDeckLinkInputCallback_v7_3 *theCallback) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkInput_v7_3Vtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkInput_v7_3 * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkInput_v7_3 * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkInput_v7_3 * This); + + HRESULT ( STDMETHODCALLTYPE *DoesSupportVideoMode )( + IDeckLinkInput_v7_3 * This, + BMDDisplayMode displayMode, + BMDPixelFormat pixelFormat, + /* [out] */ BMDDisplayModeSupport *result); + + HRESULT ( STDMETHODCALLTYPE *GetDisplayModeIterator )( + IDeckLinkInput_v7_3 * This, + /* [out] */ IDeckLinkDisplayModeIterator_v7_6 **iterator); + + HRESULT ( STDMETHODCALLTYPE *SetScreenPreviewCallback )( + IDeckLinkInput_v7_3 * This, + /* [in] */ IDeckLinkScreenPreviewCallback *previewCallback); + + HRESULT ( STDMETHODCALLTYPE *EnableVideoInput )( + IDeckLinkInput_v7_3 * This, + BMDDisplayMode displayMode, + BMDPixelFormat pixelFormat, + BMDVideoInputFlags flags); + + HRESULT ( STDMETHODCALLTYPE *DisableVideoInput )( + IDeckLinkInput_v7_3 * This); + + HRESULT ( STDMETHODCALLTYPE *GetAvailableVideoFrameCount )( + IDeckLinkInput_v7_3 * This, + /* [out] */ unsigned int *availableFrameCount); + + HRESULT ( STDMETHODCALLTYPE *EnableAudioInput )( + IDeckLinkInput_v7_3 * This, + BMDAudioSampleRate sampleRate, + BMDAudioSampleType sampleType, + unsigned int channelCount); + + HRESULT ( STDMETHODCALLTYPE *DisableAudioInput )( + IDeckLinkInput_v7_3 * This); + + HRESULT ( STDMETHODCALLTYPE *GetAvailableAudioSampleFrameCount )( + IDeckLinkInput_v7_3 * This, + /* [out] */ unsigned int *availableSampleFrameCount); + + HRESULT ( STDMETHODCALLTYPE *StartStreams )( + IDeckLinkInput_v7_3 * This); + + HRESULT ( STDMETHODCALLTYPE *StopStreams )( + IDeckLinkInput_v7_3 * This); + + HRESULT ( STDMETHODCALLTYPE *PauseStreams )( + IDeckLinkInput_v7_3 * This); + + HRESULT ( STDMETHODCALLTYPE *FlushStreams )( + IDeckLinkInput_v7_3 * This); + + HRESULT ( STDMETHODCALLTYPE *SetCallback )( + IDeckLinkInput_v7_3 * This, + /* [in] */ IDeckLinkInputCallback_v7_3 *theCallback); + + END_INTERFACE + } IDeckLinkInput_v7_3Vtbl; + + interface IDeckLinkInput_v7_3 + { + CONST_VTBL struct IDeckLinkInput_v7_3Vtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkInput_v7_3_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkInput_v7_3_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkInput_v7_3_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkInput_v7_3_DoesSupportVideoMode(This,displayMode,pixelFormat,result) \ + ( (This)->lpVtbl -> DoesSupportVideoMode(This,displayMode,pixelFormat,result) ) + +#define IDeckLinkInput_v7_3_GetDisplayModeIterator(This,iterator) \ + ( (This)->lpVtbl -> GetDisplayModeIterator(This,iterator) ) + +#define IDeckLinkInput_v7_3_SetScreenPreviewCallback(This,previewCallback) \ + ( (This)->lpVtbl -> SetScreenPreviewCallback(This,previewCallback) ) + +#define IDeckLinkInput_v7_3_EnableVideoInput(This,displayMode,pixelFormat,flags) \ + ( (This)->lpVtbl -> EnableVideoInput(This,displayMode,pixelFormat,flags) ) + +#define IDeckLinkInput_v7_3_DisableVideoInput(This) \ + ( (This)->lpVtbl -> DisableVideoInput(This) ) + +#define IDeckLinkInput_v7_3_GetAvailableVideoFrameCount(This,availableFrameCount) \ + ( (This)->lpVtbl -> GetAvailableVideoFrameCount(This,availableFrameCount) ) + +#define IDeckLinkInput_v7_3_EnableAudioInput(This,sampleRate,sampleType,channelCount) \ + ( (This)->lpVtbl -> EnableAudioInput(This,sampleRate,sampleType,channelCount) ) + +#define IDeckLinkInput_v7_3_DisableAudioInput(This) \ + ( (This)->lpVtbl -> DisableAudioInput(This) ) + +#define IDeckLinkInput_v7_3_GetAvailableAudioSampleFrameCount(This,availableSampleFrameCount) \ + ( (This)->lpVtbl -> GetAvailableAudioSampleFrameCount(This,availableSampleFrameCount) ) + +#define IDeckLinkInput_v7_3_StartStreams(This) \ + ( (This)->lpVtbl -> StartStreams(This) ) + +#define IDeckLinkInput_v7_3_StopStreams(This) \ + ( (This)->lpVtbl -> StopStreams(This) ) + +#define IDeckLinkInput_v7_3_PauseStreams(This) \ + ( (This)->lpVtbl -> PauseStreams(This) ) + +#define IDeckLinkInput_v7_3_FlushStreams(This) \ + ( (This)->lpVtbl -> FlushStreams(This) ) + +#define IDeckLinkInput_v7_3_SetCallback(This,theCallback) \ + ( (This)->lpVtbl -> SetCallback(This,theCallback) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkInput_v7_3_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkVideoInputFrame_v7_3_INTERFACE_DEFINED__ +#define __IDeckLinkVideoInputFrame_v7_3_INTERFACE_DEFINED__ + +/* interface IDeckLinkVideoInputFrame_v7_3 */ +/* [helpstring][local][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkVideoInputFrame_v7_3; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("CF317790-2894-11DE-8C30-0800200C9A66") + IDeckLinkVideoInputFrame_v7_3 : public IDeckLinkVideoFrame_v7_6 + { + public: + virtual HRESULT STDMETHODCALLTYPE GetStreamTime( + /* [out] */ BMDTimeValue *frameTime, + /* [out] */ BMDTimeValue *frameDuration, + BMDTimeScale timeScale) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkVideoInputFrame_v7_3Vtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkVideoInputFrame_v7_3 * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkVideoInputFrame_v7_3 * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkVideoInputFrame_v7_3 * This); + + long ( STDMETHODCALLTYPE *GetWidth )( + IDeckLinkVideoInputFrame_v7_3 * This); + + long ( STDMETHODCALLTYPE *GetHeight )( + IDeckLinkVideoInputFrame_v7_3 * This); + + long ( STDMETHODCALLTYPE *GetRowBytes )( + IDeckLinkVideoInputFrame_v7_3 * This); + + BMDPixelFormat ( STDMETHODCALLTYPE *GetPixelFormat )( + IDeckLinkVideoInputFrame_v7_3 * This); + + BMDFrameFlags ( STDMETHODCALLTYPE *GetFlags )( + IDeckLinkVideoInputFrame_v7_3 * This); + + HRESULT ( STDMETHODCALLTYPE *GetBytes )( + IDeckLinkVideoInputFrame_v7_3 * This, + /* [out] */ void **buffer); + + HRESULT ( STDMETHODCALLTYPE *GetTimecode )( + IDeckLinkVideoInputFrame_v7_3 * This, + BMDTimecodeFormat format, + /* [out] */ IDeckLinkTimecode_v7_6 **timecode); + + HRESULT ( STDMETHODCALLTYPE *GetAncillaryData )( + IDeckLinkVideoInputFrame_v7_3 * This, + /* [out] */ IDeckLinkVideoFrameAncillary **ancillary); + + HRESULT ( STDMETHODCALLTYPE *GetStreamTime )( + IDeckLinkVideoInputFrame_v7_3 * This, + /* [out] */ BMDTimeValue *frameTime, + /* [out] */ BMDTimeValue *frameDuration, + BMDTimeScale timeScale); + + END_INTERFACE + } IDeckLinkVideoInputFrame_v7_3Vtbl; + + interface IDeckLinkVideoInputFrame_v7_3 + { + CONST_VTBL struct IDeckLinkVideoInputFrame_v7_3Vtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkVideoInputFrame_v7_3_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkVideoInputFrame_v7_3_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkVideoInputFrame_v7_3_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkVideoInputFrame_v7_3_GetWidth(This) \ + ( (This)->lpVtbl -> GetWidth(This) ) + +#define IDeckLinkVideoInputFrame_v7_3_GetHeight(This) \ + ( (This)->lpVtbl -> GetHeight(This) ) + +#define IDeckLinkVideoInputFrame_v7_3_GetRowBytes(This) \ + ( (This)->lpVtbl -> GetRowBytes(This) ) + +#define IDeckLinkVideoInputFrame_v7_3_GetPixelFormat(This) \ + ( (This)->lpVtbl -> GetPixelFormat(This) ) + +#define IDeckLinkVideoInputFrame_v7_3_GetFlags(This) \ + ( (This)->lpVtbl -> GetFlags(This) ) + +#define IDeckLinkVideoInputFrame_v7_3_GetBytes(This,buffer) \ + ( (This)->lpVtbl -> GetBytes(This,buffer) ) + +#define IDeckLinkVideoInputFrame_v7_3_GetTimecode(This,format,timecode) \ + ( (This)->lpVtbl -> GetTimecode(This,format,timecode) ) + +#define IDeckLinkVideoInputFrame_v7_3_GetAncillaryData(This,ancillary) \ + ( (This)->lpVtbl -> GetAncillaryData(This,ancillary) ) + + +#define IDeckLinkVideoInputFrame_v7_3_GetStreamTime(This,frameTime,frameDuration,timeScale) \ + ( (This)->lpVtbl -> GetStreamTime(This,frameTime,frameDuration,timeScale) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkVideoInputFrame_v7_3_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkDisplayModeIterator_v7_1_INTERFACE_DEFINED__ +#define __IDeckLinkDisplayModeIterator_v7_1_INTERFACE_DEFINED__ + +/* interface IDeckLinkDisplayModeIterator_v7_1 */ +/* [helpstring][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkDisplayModeIterator_v7_1; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("B28131B6-59AC-4857-B5AC-CD75D5883E2F") + IDeckLinkDisplayModeIterator_v7_1 : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE Next( + /* [out] */ IDeckLinkDisplayMode_v7_1 **deckLinkDisplayMode) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkDisplayModeIterator_v7_1Vtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkDisplayModeIterator_v7_1 * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkDisplayModeIterator_v7_1 * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkDisplayModeIterator_v7_1 * This); + + HRESULT ( STDMETHODCALLTYPE *Next )( + IDeckLinkDisplayModeIterator_v7_1 * This, + /* [out] */ IDeckLinkDisplayMode_v7_1 **deckLinkDisplayMode); + + END_INTERFACE + } IDeckLinkDisplayModeIterator_v7_1Vtbl; + + interface IDeckLinkDisplayModeIterator_v7_1 + { + CONST_VTBL struct IDeckLinkDisplayModeIterator_v7_1Vtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkDisplayModeIterator_v7_1_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkDisplayModeIterator_v7_1_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkDisplayModeIterator_v7_1_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkDisplayModeIterator_v7_1_Next(This,deckLinkDisplayMode) \ + ( (This)->lpVtbl -> Next(This,deckLinkDisplayMode) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkDisplayModeIterator_v7_1_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkDisplayMode_v7_1_INTERFACE_DEFINED__ +#define __IDeckLinkDisplayMode_v7_1_INTERFACE_DEFINED__ + +/* interface IDeckLinkDisplayMode_v7_1 */ +/* [helpstring][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkDisplayMode_v7_1; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("AF0CD6D5-8376-435E-8433-54F9DD530AC3") + IDeckLinkDisplayMode_v7_1 : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE GetName( + /* [out] */ BSTR *name) = 0; + + virtual BMDDisplayMode STDMETHODCALLTYPE GetDisplayMode( void) = 0; + + virtual long STDMETHODCALLTYPE GetWidth( void) = 0; + + virtual long STDMETHODCALLTYPE GetHeight( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetFrameRate( + /* [out] */ BMDTimeValue *frameDuration, + /* [out] */ BMDTimeScale *timeScale) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkDisplayMode_v7_1Vtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkDisplayMode_v7_1 * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkDisplayMode_v7_1 * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkDisplayMode_v7_1 * This); + + HRESULT ( STDMETHODCALLTYPE *GetName )( + IDeckLinkDisplayMode_v7_1 * This, + /* [out] */ BSTR *name); + + BMDDisplayMode ( STDMETHODCALLTYPE *GetDisplayMode )( + IDeckLinkDisplayMode_v7_1 * This); + + long ( STDMETHODCALLTYPE *GetWidth )( + IDeckLinkDisplayMode_v7_1 * This); + + long ( STDMETHODCALLTYPE *GetHeight )( + IDeckLinkDisplayMode_v7_1 * This); + + HRESULT ( STDMETHODCALLTYPE *GetFrameRate )( + IDeckLinkDisplayMode_v7_1 * This, + /* [out] */ BMDTimeValue *frameDuration, + /* [out] */ BMDTimeScale *timeScale); + + END_INTERFACE + } IDeckLinkDisplayMode_v7_1Vtbl; + + interface IDeckLinkDisplayMode_v7_1 + { + CONST_VTBL struct IDeckLinkDisplayMode_v7_1Vtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkDisplayMode_v7_1_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkDisplayMode_v7_1_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkDisplayMode_v7_1_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkDisplayMode_v7_1_GetName(This,name) \ + ( (This)->lpVtbl -> GetName(This,name) ) + +#define IDeckLinkDisplayMode_v7_1_GetDisplayMode(This) \ + ( (This)->lpVtbl -> GetDisplayMode(This) ) + +#define IDeckLinkDisplayMode_v7_1_GetWidth(This) \ + ( (This)->lpVtbl -> GetWidth(This) ) + +#define IDeckLinkDisplayMode_v7_1_GetHeight(This) \ + ( (This)->lpVtbl -> GetHeight(This) ) + +#define IDeckLinkDisplayMode_v7_1_GetFrameRate(This,frameDuration,timeScale) \ + ( (This)->lpVtbl -> GetFrameRate(This,frameDuration,timeScale) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkDisplayMode_v7_1_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkVideoFrame_v7_1_INTERFACE_DEFINED__ +#define __IDeckLinkVideoFrame_v7_1_INTERFACE_DEFINED__ + +/* interface IDeckLinkVideoFrame_v7_1 */ +/* [helpstring][local][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkVideoFrame_v7_1; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("333F3A10-8C2D-43CF-B79D-46560FEEA1CE") + IDeckLinkVideoFrame_v7_1 : public IUnknown + { + public: + virtual long STDMETHODCALLTYPE GetWidth( void) = 0; + + virtual long STDMETHODCALLTYPE GetHeight( void) = 0; + + virtual long STDMETHODCALLTYPE GetRowBytes( void) = 0; + + virtual BMDPixelFormat STDMETHODCALLTYPE GetPixelFormat( void) = 0; + + virtual BMDFrameFlags STDMETHODCALLTYPE GetFlags( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetBytes( + void **buffer) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkVideoFrame_v7_1Vtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkVideoFrame_v7_1 * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkVideoFrame_v7_1 * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkVideoFrame_v7_1 * This); + + long ( STDMETHODCALLTYPE *GetWidth )( + IDeckLinkVideoFrame_v7_1 * This); + + long ( STDMETHODCALLTYPE *GetHeight )( + IDeckLinkVideoFrame_v7_1 * This); + + long ( STDMETHODCALLTYPE *GetRowBytes )( + IDeckLinkVideoFrame_v7_1 * This); + + BMDPixelFormat ( STDMETHODCALLTYPE *GetPixelFormat )( + IDeckLinkVideoFrame_v7_1 * This); + + BMDFrameFlags ( STDMETHODCALLTYPE *GetFlags )( + IDeckLinkVideoFrame_v7_1 * This); + + HRESULT ( STDMETHODCALLTYPE *GetBytes )( + IDeckLinkVideoFrame_v7_1 * This, + void **buffer); + + END_INTERFACE + } IDeckLinkVideoFrame_v7_1Vtbl; + + interface IDeckLinkVideoFrame_v7_1 + { + CONST_VTBL struct IDeckLinkVideoFrame_v7_1Vtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkVideoFrame_v7_1_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkVideoFrame_v7_1_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkVideoFrame_v7_1_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkVideoFrame_v7_1_GetWidth(This) \ + ( (This)->lpVtbl -> GetWidth(This) ) + +#define IDeckLinkVideoFrame_v7_1_GetHeight(This) \ + ( (This)->lpVtbl -> GetHeight(This) ) + +#define IDeckLinkVideoFrame_v7_1_GetRowBytes(This) \ + ( (This)->lpVtbl -> GetRowBytes(This) ) + +#define IDeckLinkVideoFrame_v7_1_GetPixelFormat(This) \ + ( (This)->lpVtbl -> GetPixelFormat(This) ) + +#define IDeckLinkVideoFrame_v7_1_GetFlags(This) \ + ( (This)->lpVtbl -> GetFlags(This) ) + +#define IDeckLinkVideoFrame_v7_1_GetBytes(This,buffer) \ + ( (This)->lpVtbl -> GetBytes(This,buffer) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkVideoFrame_v7_1_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkVideoInputFrame_v7_1_INTERFACE_DEFINED__ +#define __IDeckLinkVideoInputFrame_v7_1_INTERFACE_DEFINED__ + +/* interface IDeckLinkVideoInputFrame_v7_1 */ +/* [helpstring][local][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkVideoInputFrame_v7_1; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("C8B41D95-8848-40EE-9B37-6E3417FB114B") + IDeckLinkVideoInputFrame_v7_1 : public IDeckLinkVideoFrame_v7_1 + { + public: + virtual HRESULT STDMETHODCALLTYPE GetFrameTime( + BMDTimeValue *frameTime, + BMDTimeValue *frameDuration, + BMDTimeScale timeScale) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkVideoInputFrame_v7_1Vtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkVideoInputFrame_v7_1 * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkVideoInputFrame_v7_1 * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkVideoInputFrame_v7_1 * This); + + long ( STDMETHODCALLTYPE *GetWidth )( + IDeckLinkVideoInputFrame_v7_1 * This); + + long ( STDMETHODCALLTYPE *GetHeight )( + IDeckLinkVideoInputFrame_v7_1 * This); + + long ( STDMETHODCALLTYPE *GetRowBytes )( + IDeckLinkVideoInputFrame_v7_1 * This); + + BMDPixelFormat ( STDMETHODCALLTYPE *GetPixelFormat )( + IDeckLinkVideoInputFrame_v7_1 * This); + + BMDFrameFlags ( STDMETHODCALLTYPE *GetFlags )( + IDeckLinkVideoInputFrame_v7_1 * This); + + HRESULT ( STDMETHODCALLTYPE *GetBytes )( + IDeckLinkVideoInputFrame_v7_1 * This, + void **buffer); + + HRESULT ( STDMETHODCALLTYPE *GetFrameTime )( + IDeckLinkVideoInputFrame_v7_1 * This, + BMDTimeValue *frameTime, + BMDTimeValue *frameDuration, + BMDTimeScale timeScale); + + END_INTERFACE + } IDeckLinkVideoInputFrame_v7_1Vtbl; + + interface IDeckLinkVideoInputFrame_v7_1 + { + CONST_VTBL struct IDeckLinkVideoInputFrame_v7_1Vtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkVideoInputFrame_v7_1_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkVideoInputFrame_v7_1_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkVideoInputFrame_v7_1_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkVideoInputFrame_v7_1_GetWidth(This) \ + ( (This)->lpVtbl -> GetWidth(This) ) + +#define IDeckLinkVideoInputFrame_v7_1_GetHeight(This) \ + ( (This)->lpVtbl -> GetHeight(This) ) + +#define IDeckLinkVideoInputFrame_v7_1_GetRowBytes(This) \ + ( (This)->lpVtbl -> GetRowBytes(This) ) + +#define IDeckLinkVideoInputFrame_v7_1_GetPixelFormat(This) \ + ( (This)->lpVtbl -> GetPixelFormat(This) ) + +#define IDeckLinkVideoInputFrame_v7_1_GetFlags(This) \ + ( (This)->lpVtbl -> GetFlags(This) ) + +#define IDeckLinkVideoInputFrame_v7_1_GetBytes(This,buffer) \ + ( (This)->lpVtbl -> GetBytes(This,buffer) ) + + +#define IDeckLinkVideoInputFrame_v7_1_GetFrameTime(This,frameTime,frameDuration,timeScale) \ + ( (This)->lpVtbl -> GetFrameTime(This,frameTime,frameDuration,timeScale) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkVideoInputFrame_v7_1_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkAudioInputPacket_v7_1_INTERFACE_DEFINED__ +#define __IDeckLinkAudioInputPacket_v7_1_INTERFACE_DEFINED__ + +/* interface IDeckLinkAudioInputPacket_v7_1 */ +/* [helpstring][local][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkAudioInputPacket_v7_1; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("C86DE4F6-A29F-42E3-AB3A-1363E29F0788") + IDeckLinkAudioInputPacket_v7_1 : public IUnknown + { + public: + virtual long STDMETHODCALLTYPE GetSampleCount( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetBytes( + void **buffer) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetAudioPacketTime( + BMDTimeValue *packetTime, + BMDTimeScale timeScale) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkAudioInputPacket_v7_1Vtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkAudioInputPacket_v7_1 * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkAudioInputPacket_v7_1 * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkAudioInputPacket_v7_1 * This); + + long ( STDMETHODCALLTYPE *GetSampleCount )( + IDeckLinkAudioInputPacket_v7_1 * This); + + HRESULT ( STDMETHODCALLTYPE *GetBytes )( + IDeckLinkAudioInputPacket_v7_1 * This, + void **buffer); + + HRESULT ( STDMETHODCALLTYPE *GetAudioPacketTime )( + IDeckLinkAudioInputPacket_v7_1 * This, + BMDTimeValue *packetTime, + BMDTimeScale timeScale); + + END_INTERFACE + } IDeckLinkAudioInputPacket_v7_1Vtbl; + + interface IDeckLinkAudioInputPacket_v7_1 + { + CONST_VTBL struct IDeckLinkAudioInputPacket_v7_1Vtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkAudioInputPacket_v7_1_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkAudioInputPacket_v7_1_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkAudioInputPacket_v7_1_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkAudioInputPacket_v7_1_GetSampleCount(This) \ + ( (This)->lpVtbl -> GetSampleCount(This) ) + +#define IDeckLinkAudioInputPacket_v7_1_GetBytes(This,buffer) \ + ( (This)->lpVtbl -> GetBytes(This,buffer) ) + +#define IDeckLinkAudioInputPacket_v7_1_GetAudioPacketTime(This,packetTime,timeScale) \ + ( (This)->lpVtbl -> GetAudioPacketTime(This,packetTime,timeScale) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkAudioInputPacket_v7_1_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkVideoOutputCallback_v7_1_INTERFACE_DEFINED__ +#define __IDeckLinkVideoOutputCallback_v7_1_INTERFACE_DEFINED__ + +/* interface IDeckLinkVideoOutputCallback_v7_1 */ +/* [helpstring][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkVideoOutputCallback_v7_1; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("EBD01AFA-E4B0-49C6-A01D-EDB9D1B55FD9") + IDeckLinkVideoOutputCallback_v7_1 : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE ScheduledFrameCompleted( + /* [in] */ IDeckLinkVideoFrame_v7_1 *completedFrame, + /* [in] */ BMDOutputFrameCompletionResult result) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkVideoOutputCallback_v7_1Vtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkVideoOutputCallback_v7_1 * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkVideoOutputCallback_v7_1 * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkVideoOutputCallback_v7_1 * This); + + HRESULT ( STDMETHODCALLTYPE *ScheduledFrameCompleted )( + IDeckLinkVideoOutputCallback_v7_1 * This, + /* [in] */ IDeckLinkVideoFrame_v7_1 *completedFrame, + /* [in] */ BMDOutputFrameCompletionResult result); + + END_INTERFACE + } IDeckLinkVideoOutputCallback_v7_1Vtbl; + + interface IDeckLinkVideoOutputCallback_v7_1 + { + CONST_VTBL struct IDeckLinkVideoOutputCallback_v7_1Vtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkVideoOutputCallback_v7_1_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkVideoOutputCallback_v7_1_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkVideoOutputCallback_v7_1_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkVideoOutputCallback_v7_1_ScheduledFrameCompleted(This,completedFrame,result) \ + ( (This)->lpVtbl -> ScheduledFrameCompleted(This,completedFrame,result) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkVideoOutputCallback_v7_1_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkInputCallback_v7_1_INTERFACE_DEFINED__ +#define __IDeckLinkInputCallback_v7_1_INTERFACE_DEFINED__ + +/* interface IDeckLinkInputCallback_v7_1 */ +/* [helpstring][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkInputCallback_v7_1; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("7F94F328-5ED4-4E9F-9729-76A86BDC99CC") + IDeckLinkInputCallback_v7_1 : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE VideoInputFrameArrived( + /* [in] */ IDeckLinkVideoInputFrame_v7_1 *videoFrame, + /* [in] */ IDeckLinkAudioInputPacket_v7_1 *audioPacket) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkInputCallback_v7_1Vtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkInputCallback_v7_1 * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkInputCallback_v7_1 * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkInputCallback_v7_1 * This); + + HRESULT ( STDMETHODCALLTYPE *VideoInputFrameArrived )( + IDeckLinkInputCallback_v7_1 * This, + /* [in] */ IDeckLinkVideoInputFrame_v7_1 *videoFrame, + /* [in] */ IDeckLinkAudioInputPacket_v7_1 *audioPacket); + + END_INTERFACE + } IDeckLinkInputCallback_v7_1Vtbl; + + interface IDeckLinkInputCallback_v7_1 + { + CONST_VTBL struct IDeckLinkInputCallback_v7_1Vtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkInputCallback_v7_1_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkInputCallback_v7_1_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkInputCallback_v7_1_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkInputCallback_v7_1_VideoInputFrameArrived(This,videoFrame,audioPacket) \ + ( (This)->lpVtbl -> VideoInputFrameArrived(This,videoFrame,audioPacket) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkInputCallback_v7_1_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkOutput_v7_1_INTERFACE_DEFINED__ +#define __IDeckLinkOutput_v7_1_INTERFACE_DEFINED__ + +/* interface IDeckLinkOutput_v7_1 */ +/* [helpstring][local][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkOutput_v7_1; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("AE5B3E9B-4E1E-4535-B6E8-480FF52F6CE5") + IDeckLinkOutput_v7_1 : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE DoesSupportVideoMode( + BMDDisplayMode displayMode, + BMDPixelFormat pixelFormat, + /* [out] */ BMDDisplayModeSupport *result) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetDisplayModeIterator( + /* [out] */ IDeckLinkDisplayModeIterator_v7_1 **iterator) = 0; + + virtual HRESULT STDMETHODCALLTYPE EnableVideoOutput( + BMDDisplayMode displayMode) = 0; + + virtual HRESULT STDMETHODCALLTYPE DisableVideoOutput( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetVideoOutputFrameMemoryAllocator( + /* [in] */ IDeckLinkMemoryAllocator *theAllocator) = 0; + + virtual HRESULT STDMETHODCALLTYPE CreateVideoFrame( + int width, + int height, + int rowBytes, + BMDPixelFormat pixelFormat, + BMDFrameFlags flags, + IDeckLinkVideoFrame_v7_1 **outFrame) = 0; + + virtual HRESULT STDMETHODCALLTYPE CreateVideoFrameFromBuffer( + void *buffer, + int width, + int height, + int rowBytes, + BMDPixelFormat pixelFormat, + BMDFrameFlags flags, + IDeckLinkVideoFrame_v7_1 **outFrame) = 0; + + virtual HRESULT STDMETHODCALLTYPE DisplayVideoFrameSync( + IDeckLinkVideoFrame_v7_1 *theFrame) = 0; + + virtual HRESULT STDMETHODCALLTYPE ScheduleVideoFrame( + IDeckLinkVideoFrame_v7_1 *theFrame, + BMDTimeValue displayTime, + BMDTimeValue displayDuration, + BMDTimeScale timeScale) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetScheduledFrameCompletionCallback( + /* [in] */ IDeckLinkVideoOutputCallback_v7_1 *theCallback) = 0; + + virtual HRESULT STDMETHODCALLTYPE EnableAudioOutput( + BMDAudioSampleRate sampleRate, + BMDAudioSampleType sampleType, + unsigned int channelCount) = 0; + + virtual HRESULT STDMETHODCALLTYPE DisableAudioOutput( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE WriteAudioSamplesSync( + void *buffer, + unsigned int sampleFrameCount, + /* [out] */ unsigned int *sampleFramesWritten) = 0; + + virtual HRESULT STDMETHODCALLTYPE BeginAudioPreroll( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE EndAudioPreroll( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE ScheduleAudioSamples( + void *buffer, + unsigned int sampleFrameCount, + BMDTimeValue streamTime, + BMDTimeScale timeScale, + /* [out] */ unsigned int *sampleFramesWritten) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetBufferedAudioSampleFrameCount( + /* [out] */ unsigned int *bufferedSampleCount) = 0; + + virtual HRESULT STDMETHODCALLTYPE FlushBufferedAudioSamples( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetAudioCallback( + /* [in] */ IDeckLinkAudioOutputCallback *theCallback) = 0; + + virtual HRESULT STDMETHODCALLTYPE StartScheduledPlayback( + BMDTimeValue playbackStartTime, + BMDTimeScale timeScale, + double playbackSpeed) = 0; + + virtual HRESULT STDMETHODCALLTYPE StopScheduledPlayback( + BMDTimeValue stopPlaybackAtTime, + BMDTimeValue *actualStopTime, + BMDTimeScale timeScale) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetHardwareReferenceClock( + BMDTimeScale desiredTimeScale, + BMDTimeValue *elapsedTimeSinceSchedulerBegan) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkOutput_v7_1Vtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkOutput_v7_1 * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkOutput_v7_1 * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkOutput_v7_1 * This); + + HRESULT ( STDMETHODCALLTYPE *DoesSupportVideoMode )( + IDeckLinkOutput_v7_1 * This, + BMDDisplayMode displayMode, + BMDPixelFormat pixelFormat, + /* [out] */ BMDDisplayModeSupport *result); + + HRESULT ( STDMETHODCALLTYPE *GetDisplayModeIterator )( + IDeckLinkOutput_v7_1 * This, + /* [out] */ IDeckLinkDisplayModeIterator_v7_1 **iterator); + + HRESULT ( STDMETHODCALLTYPE *EnableVideoOutput )( + IDeckLinkOutput_v7_1 * This, + BMDDisplayMode displayMode); + + HRESULT ( STDMETHODCALLTYPE *DisableVideoOutput )( + IDeckLinkOutput_v7_1 * This); + + HRESULT ( STDMETHODCALLTYPE *SetVideoOutputFrameMemoryAllocator )( + IDeckLinkOutput_v7_1 * This, + /* [in] */ IDeckLinkMemoryAllocator *theAllocator); + + HRESULT ( STDMETHODCALLTYPE *CreateVideoFrame )( + IDeckLinkOutput_v7_1 * This, + int width, + int height, + int rowBytes, + BMDPixelFormat pixelFormat, + BMDFrameFlags flags, + IDeckLinkVideoFrame_v7_1 **outFrame); + + HRESULT ( STDMETHODCALLTYPE *CreateVideoFrameFromBuffer )( + IDeckLinkOutput_v7_1 * This, + void *buffer, + int width, + int height, + int rowBytes, + BMDPixelFormat pixelFormat, + BMDFrameFlags flags, + IDeckLinkVideoFrame_v7_1 **outFrame); + + HRESULT ( STDMETHODCALLTYPE *DisplayVideoFrameSync )( + IDeckLinkOutput_v7_1 * This, + IDeckLinkVideoFrame_v7_1 *theFrame); + + HRESULT ( STDMETHODCALLTYPE *ScheduleVideoFrame )( + IDeckLinkOutput_v7_1 * This, + IDeckLinkVideoFrame_v7_1 *theFrame, + BMDTimeValue displayTime, + BMDTimeValue displayDuration, + BMDTimeScale timeScale); + + HRESULT ( STDMETHODCALLTYPE *SetScheduledFrameCompletionCallback )( + IDeckLinkOutput_v7_1 * This, + /* [in] */ IDeckLinkVideoOutputCallback_v7_1 *theCallback); + + HRESULT ( STDMETHODCALLTYPE *EnableAudioOutput )( + IDeckLinkOutput_v7_1 * This, + BMDAudioSampleRate sampleRate, + BMDAudioSampleType sampleType, + unsigned int channelCount); + + HRESULT ( STDMETHODCALLTYPE *DisableAudioOutput )( + IDeckLinkOutput_v7_1 * This); + + HRESULT ( STDMETHODCALLTYPE *WriteAudioSamplesSync )( + IDeckLinkOutput_v7_1 * This, + void *buffer, + unsigned int sampleFrameCount, + /* [out] */ unsigned int *sampleFramesWritten); + + HRESULT ( STDMETHODCALLTYPE *BeginAudioPreroll )( + IDeckLinkOutput_v7_1 * This); + + HRESULT ( STDMETHODCALLTYPE *EndAudioPreroll )( + IDeckLinkOutput_v7_1 * This); + + HRESULT ( STDMETHODCALLTYPE *ScheduleAudioSamples )( + IDeckLinkOutput_v7_1 * This, + void *buffer, + unsigned int sampleFrameCount, + BMDTimeValue streamTime, + BMDTimeScale timeScale, + /* [out] */ unsigned int *sampleFramesWritten); + + HRESULT ( STDMETHODCALLTYPE *GetBufferedAudioSampleFrameCount )( + IDeckLinkOutput_v7_1 * This, + /* [out] */ unsigned int *bufferedSampleCount); + + HRESULT ( STDMETHODCALLTYPE *FlushBufferedAudioSamples )( + IDeckLinkOutput_v7_1 * This); + + HRESULT ( STDMETHODCALLTYPE *SetAudioCallback )( + IDeckLinkOutput_v7_1 * This, + /* [in] */ IDeckLinkAudioOutputCallback *theCallback); + + HRESULT ( STDMETHODCALLTYPE *StartScheduledPlayback )( + IDeckLinkOutput_v7_1 * This, + BMDTimeValue playbackStartTime, + BMDTimeScale timeScale, + double playbackSpeed); + + HRESULT ( STDMETHODCALLTYPE *StopScheduledPlayback )( + IDeckLinkOutput_v7_1 * This, + BMDTimeValue stopPlaybackAtTime, + BMDTimeValue *actualStopTime, + BMDTimeScale timeScale); + + HRESULT ( STDMETHODCALLTYPE *GetHardwareReferenceClock )( + IDeckLinkOutput_v7_1 * This, + BMDTimeScale desiredTimeScale, + BMDTimeValue *elapsedTimeSinceSchedulerBegan); + + END_INTERFACE + } IDeckLinkOutput_v7_1Vtbl; + + interface IDeckLinkOutput_v7_1 + { + CONST_VTBL struct IDeckLinkOutput_v7_1Vtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkOutput_v7_1_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkOutput_v7_1_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkOutput_v7_1_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkOutput_v7_1_DoesSupportVideoMode(This,displayMode,pixelFormat,result) \ + ( (This)->lpVtbl -> DoesSupportVideoMode(This,displayMode,pixelFormat,result) ) + +#define IDeckLinkOutput_v7_1_GetDisplayModeIterator(This,iterator) \ + ( (This)->lpVtbl -> GetDisplayModeIterator(This,iterator) ) + +#define IDeckLinkOutput_v7_1_EnableVideoOutput(This,displayMode) \ + ( (This)->lpVtbl -> EnableVideoOutput(This,displayMode) ) + +#define IDeckLinkOutput_v7_1_DisableVideoOutput(This) \ + ( (This)->lpVtbl -> DisableVideoOutput(This) ) + +#define IDeckLinkOutput_v7_1_SetVideoOutputFrameMemoryAllocator(This,theAllocator) \ + ( (This)->lpVtbl -> SetVideoOutputFrameMemoryAllocator(This,theAllocator) ) + +#define IDeckLinkOutput_v7_1_CreateVideoFrame(This,width,height,rowBytes,pixelFormat,flags,outFrame) \ + ( (This)->lpVtbl -> CreateVideoFrame(This,width,height,rowBytes,pixelFormat,flags,outFrame) ) + +#define IDeckLinkOutput_v7_1_CreateVideoFrameFromBuffer(This,buffer,width,height,rowBytes,pixelFormat,flags,outFrame) \ + ( (This)->lpVtbl -> CreateVideoFrameFromBuffer(This,buffer,width,height,rowBytes,pixelFormat,flags,outFrame) ) + +#define IDeckLinkOutput_v7_1_DisplayVideoFrameSync(This,theFrame) \ + ( (This)->lpVtbl -> DisplayVideoFrameSync(This,theFrame) ) + +#define IDeckLinkOutput_v7_1_ScheduleVideoFrame(This,theFrame,displayTime,displayDuration,timeScale) \ + ( (This)->lpVtbl -> ScheduleVideoFrame(This,theFrame,displayTime,displayDuration,timeScale) ) + +#define IDeckLinkOutput_v7_1_SetScheduledFrameCompletionCallback(This,theCallback) \ + ( (This)->lpVtbl -> SetScheduledFrameCompletionCallback(This,theCallback) ) + +#define IDeckLinkOutput_v7_1_EnableAudioOutput(This,sampleRate,sampleType,channelCount) \ + ( (This)->lpVtbl -> EnableAudioOutput(This,sampleRate,sampleType,channelCount) ) + +#define IDeckLinkOutput_v7_1_DisableAudioOutput(This) \ + ( (This)->lpVtbl -> DisableAudioOutput(This) ) + +#define IDeckLinkOutput_v7_1_WriteAudioSamplesSync(This,buffer,sampleFrameCount,sampleFramesWritten) \ + ( (This)->lpVtbl -> WriteAudioSamplesSync(This,buffer,sampleFrameCount,sampleFramesWritten) ) + +#define IDeckLinkOutput_v7_1_BeginAudioPreroll(This) \ + ( (This)->lpVtbl -> BeginAudioPreroll(This) ) + +#define IDeckLinkOutput_v7_1_EndAudioPreroll(This) \ + ( (This)->lpVtbl -> EndAudioPreroll(This) ) + +#define IDeckLinkOutput_v7_1_ScheduleAudioSamples(This,buffer,sampleFrameCount,streamTime,timeScale,sampleFramesWritten) \ + ( (This)->lpVtbl -> ScheduleAudioSamples(This,buffer,sampleFrameCount,streamTime,timeScale,sampleFramesWritten) ) + +#define IDeckLinkOutput_v7_1_GetBufferedAudioSampleFrameCount(This,bufferedSampleCount) \ + ( (This)->lpVtbl -> GetBufferedAudioSampleFrameCount(This,bufferedSampleCount) ) + +#define IDeckLinkOutput_v7_1_FlushBufferedAudioSamples(This) \ + ( (This)->lpVtbl -> FlushBufferedAudioSamples(This) ) + +#define IDeckLinkOutput_v7_1_SetAudioCallback(This,theCallback) \ + ( (This)->lpVtbl -> SetAudioCallback(This,theCallback) ) + +#define IDeckLinkOutput_v7_1_StartScheduledPlayback(This,playbackStartTime,timeScale,playbackSpeed) \ + ( (This)->lpVtbl -> StartScheduledPlayback(This,playbackStartTime,timeScale,playbackSpeed) ) + +#define IDeckLinkOutput_v7_1_StopScheduledPlayback(This,stopPlaybackAtTime,actualStopTime,timeScale) \ + ( (This)->lpVtbl -> StopScheduledPlayback(This,stopPlaybackAtTime,actualStopTime,timeScale) ) + +#define IDeckLinkOutput_v7_1_GetHardwareReferenceClock(This,desiredTimeScale,elapsedTimeSinceSchedulerBegan) \ + ( (This)->lpVtbl -> GetHardwareReferenceClock(This,desiredTimeScale,elapsedTimeSinceSchedulerBegan) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkOutput_v7_1_INTERFACE_DEFINED__ */ + + +#ifndef __IDeckLinkInput_v7_1_INTERFACE_DEFINED__ +#define __IDeckLinkInput_v7_1_INTERFACE_DEFINED__ + +/* interface IDeckLinkInput_v7_1 */ +/* [helpstring][uuid][object] */ + + +EXTERN_C const IID IID_IDeckLinkInput_v7_1; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("2B54EDEF-5B32-429F-BA11-BB990596EACD") + IDeckLinkInput_v7_1 : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE DoesSupportVideoMode( + BMDDisplayMode displayMode, + BMDPixelFormat pixelFormat, + /* [out] */ BMDDisplayModeSupport *result) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetDisplayModeIterator( + /* [out] */ IDeckLinkDisplayModeIterator_v7_1 **iterator) = 0; + + virtual HRESULT STDMETHODCALLTYPE EnableVideoInput( + BMDDisplayMode displayMode, + BMDPixelFormat pixelFormat, + BMDVideoInputFlags flags) = 0; + + virtual HRESULT STDMETHODCALLTYPE DisableVideoInput( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE EnableAudioInput( + BMDAudioSampleRate sampleRate, + BMDAudioSampleType sampleType, + unsigned int channelCount) = 0; + + virtual HRESULT STDMETHODCALLTYPE DisableAudioInput( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE ReadAudioSamples( + void *buffer, + unsigned int sampleFrameCount, + /* [out] */ unsigned int *sampleFramesRead, + /* [out] */ BMDTimeValue *audioPacketTime, + BMDTimeScale timeScale) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetBufferedAudioSampleFrameCount( + /* [out] */ unsigned int *bufferedSampleCount) = 0; + + virtual HRESULT STDMETHODCALLTYPE StartStreams( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE StopStreams( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE PauseStreams( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetCallback( + /* [in] */ IDeckLinkInputCallback_v7_1 *theCallback) = 0; + + }; + + +#else /* C style interface */ + + typedef struct IDeckLinkInput_v7_1Vtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeckLinkInput_v7_1 * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeckLinkInput_v7_1 * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeckLinkInput_v7_1 * This); + + HRESULT ( STDMETHODCALLTYPE *DoesSupportVideoMode )( + IDeckLinkInput_v7_1 * This, + BMDDisplayMode displayMode, + BMDPixelFormat pixelFormat, + /* [out] */ BMDDisplayModeSupport *result); + + HRESULT ( STDMETHODCALLTYPE *GetDisplayModeIterator )( + IDeckLinkInput_v7_1 * This, + /* [out] */ IDeckLinkDisplayModeIterator_v7_1 **iterator); + + HRESULT ( STDMETHODCALLTYPE *EnableVideoInput )( + IDeckLinkInput_v7_1 * This, + BMDDisplayMode displayMode, + BMDPixelFormat pixelFormat, + BMDVideoInputFlags flags); + + HRESULT ( STDMETHODCALLTYPE *DisableVideoInput )( + IDeckLinkInput_v7_1 * This); + + HRESULT ( STDMETHODCALLTYPE *EnableAudioInput )( + IDeckLinkInput_v7_1 * This, + BMDAudioSampleRate sampleRate, + BMDAudioSampleType sampleType, + unsigned int channelCount); + + HRESULT ( STDMETHODCALLTYPE *DisableAudioInput )( + IDeckLinkInput_v7_1 * This); + + HRESULT ( STDMETHODCALLTYPE *ReadAudioSamples )( + IDeckLinkInput_v7_1 * This, + void *buffer, + unsigned int sampleFrameCount, + /* [out] */ unsigned int *sampleFramesRead, + /* [out] */ BMDTimeValue *audioPacketTime, + BMDTimeScale timeScale); + + HRESULT ( STDMETHODCALLTYPE *GetBufferedAudioSampleFrameCount )( + IDeckLinkInput_v7_1 * This, + /* [out] */ unsigned int *bufferedSampleCount); + + HRESULT ( STDMETHODCALLTYPE *StartStreams )( + IDeckLinkInput_v7_1 * This); + + HRESULT ( STDMETHODCALLTYPE *StopStreams )( + IDeckLinkInput_v7_1 * This); + + HRESULT ( STDMETHODCALLTYPE *PauseStreams )( + IDeckLinkInput_v7_1 * This); + + HRESULT ( STDMETHODCALLTYPE *SetCallback )( + IDeckLinkInput_v7_1 * This, + /* [in] */ IDeckLinkInputCallback_v7_1 *theCallback); + + END_INTERFACE + } IDeckLinkInput_v7_1Vtbl; + + interface IDeckLinkInput_v7_1 + { + CONST_VTBL struct IDeckLinkInput_v7_1Vtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeckLinkInput_v7_1_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeckLinkInput_v7_1_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeckLinkInput_v7_1_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeckLinkInput_v7_1_DoesSupportVideoMode(This,displayMode,pixelFormat,result) \ + ( (This)->lpVtbl -> DoesSupportVideoMode(This,displayMode,pixelFormat,result) ) + +#define IDeckLinkInput_v7_1_GetDisplayModeIterator(This,iterator) \ + ( (This)->lpVtbl -> GetDisplayModeIterator(This,iterator) ) + +#define IDeckLinkInput_v7_1_EnableVideoInput(This,displayMode,pixelFormat,flags) \ + ( (This)->lpVtbl -> EnableVideoInput(This,displayMode,pixelFormat,flags) ) + +#define IDeckLinkInput_v7_1_DisableVideoInput(This) \ + ( (This)->lpVtbl -> DisableVideoInput(This) ) + +#define IDeckLinkInput_v7_1_EnableAudioInput(This,sampleRate,sampleType,channelCount) \ + ( (This)->lpVtbl -> EnableAudioInput(This,sampleRate,sampleType,channelCount) ) + +#define IDeckLinkInput_v7_1_DisableAudioInput(This) \ + ( (This)->lpVtbl -> DisableAudioInput(This) ) + +#define IDeckLinkInput_v7_1_ReadAudioSamples(This,buffer,sampleFrameCount,sampleFramesRead,audioPacketTime,timeScale) \ + ( (This)->lpVtbl -> ReadAudioSamples(This,buffer,sampleFrameCount,sampleFramesRead,audioPacketTime,timeScale) ) + +#define IDeckLinkInput_v7_1_GetBufferedAudioSampleFrameCount(This,bufferedSampleCount) \ + ( (This)->lpVtbl -> GetBufferedAudioSampleFrameCount(This,bufferedSampleCount) ) + +#define IDeckLinkInput_v7_1_StartStreams(This) \ + ( (This)->lpVtbl -> StartStreams(This) ) + +#define IDeckLinkInput_v7_1_StopStreams(This) \ + ( (This)->lpVtbl -> StopStreams(This) ) + +#define IDeckLinkInput_v7_1_PauseStreams(This) \ + ( (This)->lpVtbl -> PauseStreams(This) ) + +#define IDeckLinkInput_v7_1_SetCallback(This,theCallback) \ + ( (This)->lpVtbl -> SetCallback(This,theCallback) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeckLinkInput_v7_1_INTERFACE_DEFINED__ */ + +#endif /* __DeckLinkAPI_LIBRARY_DEFINED__ */ + +/* Additional Prototypes for ALL interfaces */ + +/* end of Additional Prototypes */ + +#ifdef __cplusplus +} +#endif + +#endif + + diff --git a/intern/decklink/win/DeckLinkAPI_i.c b/intern/decklink/win/DeckLinkAPI_i.c new file mode 100644 index 00000000000..a13d486aae8 --- /dev/null +++ b/intern/decklink/win/DeckLinkAPI_i.c @@ -0,0 +1,343 @@ + + +/* this ALWAYS GENERATED file contains the IIDs and CLSIDs */ + +/* link this file in with the server and any clients */ + + + /* File created by MIDL compiler version 8.00.0603 */ +/* at Mon Apr 13 20:57:05 2015 + */ +/* Compiler settings for ..\..\include\DeckLinkAPI.idl: + Oicf, W1, Zp8, env=Win64 (32b run), target_arch=AMD64 8.00.0603 + protocol : dce , ms_ext, c_ext, robust + error checks: allocation ref bounds_check enum stub_data + VC __declspec() decoration level: + __declspec(uuid()), __declspec(selectany), __declspec(novtable) + DECLSPEC_UUID(), MIDL_INTERFACE() +*/ +/* @@MIDL_FILE_HEADING( ) */ + +#pragma warning( disable: 4049 ) /* more than 64k source lines */ + + +#ifdef __cplusplus +extern "C"{ +#endif + + +#include <rpc.h> +#include <rpcndr.h> + +#ifdef _MIDL_USE_GUIDDEF_ + +#ifndef INITGUID +#define INITGUID +#include <guiddef.h> +#undef INITGUID +#else +#include <guiddef.h> +#endif + +#define MIDL_DEFINE_GUID(type,name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \ + DEFINE_GUID(name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) + +#else // !_MIDL_USE_GUIDDEF_ + +#ifndef __IID_DEFINED__ +#define __IID_DEFINED__ + +typedef struct _IID +{ + unsigned long x; + unsigned short s1; + unsigned short s2; + unsigned char c[8]; +} IID; + +#endif // __IID_DEFINED__ + +#ifndef CLSID_DEFINED +#define CLSID_DEFINED +typedef IID CLSID; +#endif // CLSID_DEFINED + +#define MIDL_DEFINE_GUID(type,name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \ + const type name = {l,w1,w2,{b1,b2,b3,b4,b5,b6,b7,b8}} + +#endif !_MIDL_USE_GUIDDEF_ + +MIDL_DEFINE_GUID(IID, LIBID_DeckLinkAPI,0xD864517A,0xEDD5,0x466D,0x86,0x7D,0xC8,0x19,0xF1,0xC0,0x52,0xBB); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkTimecode,0xBC6CFBD3,0x8317,0x4325,0xAC,0x1C,0x12,0x16,0x39,0x1E,0x93,0x40); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkDisplayModeIterator,0x9C88499F,0xF601,0x4021,0xB8,0x0B,0x03,0x2E,0x4E,0xB4,0x1C,0x35); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkDisplayMode,0x3EB2C1AB,0x0A3D,0x4523,0xA3,0xAD,0xF4,0x0D,0x7F,0xB1,0x4E,0x78); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLink,0xC418FBDD,0x0587,0x48ED,0x8F,0xE5,0x64,0x0F,0x0A,0x14,0xAF,0x91); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkConfiguration,0x1E69FCF6,0x4203,0x4936,0x80,0x76,0x2A,0x9F,0x4C,0xFD,0x50,0xCB); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkDeckControlStatusCallback,0x53436FFB,0xB434,0x4906,0xBA,0xDC,0xAE,0x30,0x60,0xFF,0xE8,0xEF); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkDeckControl,0x8E1C3ACE,0x19C7,0x4E00,0x8B,0x92,0xD8,0x04,0x31,0xD9,0x58,0xBE); + + +MIDL_DEFINE_GUID(IID, IID_IBMDStreamingDeviceNotificationCallback,0xF9531D64,0x3305,0x4B29,0xA3,0x87,0x7F,0x74,0xBB,0x0D,0x0E,0x84); + + +MIDL_DEFINE_GUID(IID, IID_IBMDStreamingH264InputCallback,0x823C475F,0x55AE,0x46F9,0x89,0x0C,0x53,0x7C,0xC5,0xCE,0xDC,0xCA); + + +MIDL_DEFINE_GUID(IID, IID_IBMDStreamingDiscovery,0x2C837444,0xF989,0x4D87,0x90,0x1A,0x47,0xC8,0xA3,0x6D,0x09,0x6D); + + +MIDL_DEFINE_GUID(IID, IID_IBMDStreamingVideoEncodingMode,0x1AB8035B,0xCD13,0x458D,0xB6,0xDF,0x5E,0x8F,0x7C,0x21,0x41,0xD9); + + +MIDL_DEFINE_GUID(IID, IID_IBMDStreamingMutableVideoEncodingMode,0x19BF7D90,0x1E0A,0x400D,0xB2,0xC6,0xFF,0xC4,0xE7,0x8A,0xD4,0x9D); + + +MIDL_DEFINE_GUID(IID, IID_IBMDStreamingVideoEncodingModePresetIterator,0x7AC731A3,0xC950,0x4AD0,0x80,0x4A,0x83,0x77,0xAA,0x51,0xC6,0xC4); + + +MIDL_DEFINE_GUID(IID, IID_IBMDStreamingDeviceInput,0x24B6B6EC,0x1727,0x44BB,0x98,0x18,0x34,0xFF,0x08,0x6A,0xCF,0x98); + + +MIDL_DEFINE_GUID(IID, IID_IBMDStreamingH264NALPacket,0xE260E955,0x14BE,0x4395,0x97,0x75,0x9F,0x02,0xCC,0x0A,0x9D,0x89); + + +MIDL_DEFINE_GUID(IID, IID_IBMDStreamingAudioPacket,0xD9EB5902,0x1AD2,0x43F4,0x9E,0x2C,0x3C,0xFA,0x50,0xB5,0xEE,0x19); + + +MIDL_DEFINE_GUID(IID, IID_IBMDStreamingMPEG2TSPacket,0x91810D1C,0x4FB3,0x4AAA,0xAE,0x56,0xFA,0x30,0x1D,0x3D,0xFA,0x4C); + + +MIDL_DEFINE_GUID(IID, IID_IBMDStreamingH264NALParser,0x5867F18C,0x5BFA,0x4CCC,0xB2,0xA7,0x9D,0xFD,0x14,0x04,0x17,0xD2); + + +MIDL_DEFINE_GUID(CLSID, CLSID_CBMDStreamingDiscovery,0x0CAA31F6,0x8A26,0x40B0,0x86,0xA4,0xBF,0x58,0xDC,0xCA,0x71,0x0C); + + +MIDL_DEFINE_GUID(CLSID, CLSID_CBMDStreamingH264NALParser,0x7753EFBD,0x951C,0x407C,0x97,0xA5,0x23,0xC7,0x37,0xB7,0x3B,0x52); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkVideoOutputCallback,0x20AA5225,0x1958,0x47CB,0x82,0x0B,0x80,0xA8,0xD5,0x21,0xA6,0xEE); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkInputCallback,0xDD04E5EC,0x7415,0x42AB,0xAE,0x4A,0xE8,0x0C,0x4D,0xFC,0x04,0x4A); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkMemoryAllocator,0xB36EB6E7,0x9D29,0x4AA8,0x92,0xEF,0x84,0x3B,0x87,0xA2,0x89,0xE8); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkAudioOutputCallback,0x403C681B,0x7F46,0x4A12,0xB9,0x93,0x2B,0xB1,0x27,0x08,0x4E,0xE6); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkIterator,0x50FB36CD,0x3063,0x4B73,0xBD,0xBB,0x95,0x80,0x87,0xF2,0xD8,0xBA); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkAPIInformation,0x7BEA3C68,0x730D,0x4322,0xAF,0x34,0x8A,0x71,0x52,0xB5,0x32,0xA4); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkOutput,0xCC5C8A6E,0x3F2F,0x4B3A,0x87,0xEA,0xFD,0x78,0xAF,0x30,0x05,0x64); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkInput,0xAF22762B,0xDFAC,0x4846,0xAA,0x79,0xFA,0x88,0x83,0x56,0x09,0x95); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkVideoFrame,0x3F716FE0,0xF023,0x4111,0xBE,0x5D,0xEF,0x44,0x14,0xC0,0x5B,0x17); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkMutableVideoFrame,0x69E2639F,0x40DA,0x4E19,0xB6,0xF2,0x20,0xAC,0xE8,0x15,0xC3,0x90); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkVideoFrame3DExtensions,0xDA0F7E4A,0xEDC7,0x48A8,0x9C,0xDD,0x2D,0xB5,0x1C,0x72,0x9C,0xD7); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkVideoInputFrame,0x05CFE374,0x537C,0x4094,0x9A,0x57,0x68,0x05,0x25,0x11,0x8F,0x44); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkVideoFrameAncillary,0x732E723C,0xD1A4,0x4E29,0x9E,0x8E,0x4A,0x88,0x79,0x7A,0x00,0x04); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkAudioInputPacket,0xE43D5870,0x2894,0x11DE,0x8C,0x30,0x08,0x00,0x20,0x0C,0x9A,0x66); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkScreenPreviewCallback,0xB1D3F49A,0x85FE,0x4C5D,0x95,0xC8,0x0B,0x5D,0x5D,0xCC,0xD4,0x38); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkGLScreenPreviewHelper,0x504E2209,0xCAC7,0x4C1A,0x9F,0xB4,0xC5,0xBB,0x62,0x74,0xD2,0x2F); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkDX9ScreenPreviewHelper,0x2094B522,0xD1A1,0x40C0,0x9A,0xC7,0x1C,0x01,0x22,0x18,0xEF,0x02); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkNotificationCallback,0xb002a1ec,0x070d,0x4288,0x82,0x89,0xbd,0x5d,0x36,0xe5,0xff,0x0d); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkNotification,0x0a1fb207,0xe215,0x441b,0x9b,0x19,0x6f,0xa1,0x57,0x59,0x46,0xc5); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkAttributes,0xABC11843,0xD966,0x44CB,0x96,0xE2,0xA1,0xCB,0x5D,0x31,0x35,0xC4); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkKeyer,0x89AFCAF5,0x65F8,0x421E,0x98,0xF7,0x96,0xFE,0x5F,0x5B,0xFB,0xA3); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkVideoConversion,0x3BBCB8A2,0xDA2C,0x42D9,0xB5,0xD8,0x88,0x08,0x36,0x44,0xE9,0x9A); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkDeviceNotificationCallback,0x4997053B,0x0ADF,0x4CC8,0xAC,0x70,0x7A,0x50,0xC4,0xBE,0x72,0x8F); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkDiscovery,0xCDBF631C,0xBC76,0x45FA,0xB4,0x4D,0xC5,0x50,0x59,0xBC,0x61,0x01); + + +MIDL_DEFINE_GUID(CLSID, CLSID_CDeckLinkIterator,0x1F2E109A,0x8F4F,0x49E4,0x92,0x03,0x13,0x55,0x95,0xCB,0x6F,0xA5); + + +MIDL_DEFINE_GUID(CLSID, CLSID_CDeckLinkAPIInformation,0x263CA19F,0xED09,0x482E,0x9F,0x9D,0x84,0x00,0x57,0x83,0xA2,0x37); + + +MIDL_DEFINE_GUID(CLSID, CLSID_CDeckLinkGLScreenPreviewHelper,0xF63E77C7,0xB655,0x4A4A,0x9A,0xD0,0x3C,0xA8,0x5D,0x39,0x43,0x43); + + +MIDL_DEFINE_GUID(CLSID, CLSID_CDeckLinkDX9ScreenPreviewHelper,0xCC010023,0xE01D,0x4525,0x9D,0x59,0x80,0xC8,0xAB,0x3D,0xC7,0xA0); + + +MIDL_DEFINE_GUID(CLSID, CLSID_CDeckLinkVideoConversion,0x7DBBBB11,0x5B7B,0x467D,0xAE,0xA4,0xCE,0xA4,0x68,0xFD,0x36,0x8C); + + +MIDL_DEFINE_GUID(CLSID, CLSID_CDeckLinkDiscovery,0x1073A05C,0xD885,0x47E9,0xB3,0xC6,0x12,0x9B,0x3F,0x9F,0x64,0x8B); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkConfiguration_v10_2,0xC679A35B,0x610C,0x4D09,0xB7,0x48,0x1D,0x04,0x78,0x10,0x0F,0xC0); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkOutput_v9_9,0xA3EF0963,0x0862,0x44ED,0x92,0xA9,0xEE,0x89,0xAB,0xF4,0x31,0xC7); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkInput_v9_2,0x6D40EF78,0x28B9,0x4E21,0x99,0x0D,0x95,0xBB,0x77,0x50,0xA0,0x4F); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkDeckControlStatusCallback_v8_1,0xE5F693C1,0x4283,0x4716,0xB1,0x8F,0xC1,0x43,0x15,0x21,0x95,0x5B); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkDeckControl_v8_1,0x522A9E39,0x0F3C,0x4742,0x94,0xEE,0xD8,0x0D,0xE3,0x35,0xDA,0x1D); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLink_v8_0,0x62BFF75D,0x6569,0x4E55,0x8D,0x4D,0x66,0xAA,0x03,0x82,0x9A,0xBC); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkIterator_v8_0,0x74E936FC,0xCC28,0x4A67,0x81,0xA0,0x1E,0x94,0xE5,0x2D,0x4E,0x69); + + +MIDL_DEFINE_GUID(CLSID, CLSID_CDeckLinkIterator_v8_0,0xD9EDA3B3,0x2887,0x41FA,0xB7,0x24,0x01,0x7C,0xF1,0xEB,0x1D,0x37); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkDeckControl_v7_9,0xA4D81043,0x0619,0x42B7,0x8E,0xD6,0x60,0x2D,0x29,0x04,0x1D,0xF7); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkDisplayModeIterator_v7_6,0x455D741F,0x1779,0x4800,0x86,0xF5,0x0B,0x5D,0x13,0xD7,0x97,0x51); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkDisplayMode_v7_6,0x87451E84,0x2B7E,0x439E,0xA6,0x29,0x43,0x93,0xEA,0x4A,0x85,0x50); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkOutput_v7_6,0x29228142,0xEB8C,0x4141,0xA6,0x21,0xF7,0x40,0x26,0x45,0x09,0x55); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkInput_v7_6,0x300C135A,0x9F43,0x48E2,0x99,0x06,0x6D,0x79,0x11,0xD9,0x3C,0xF1); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkTimecode_v7_6,0xEFB9BCA6,0xA521,0x44F7,0xBD,0x69,0x23,0x32,0xF2,0x4D,0x9E,0xE6); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkVideoFrame_v7_6,0xA8D8238E,0x6B18,0x4196,0x99,0xE1,0x5A,0xF7,0x17,0xB8,0x3D,0x32); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkMutableVideoFrame_v7_6,0x46FCEE00,0xB4E6,0x43D0,0x91,0xC0,0x02,0x3A,0x7F,0xCE,0xB3,0x4F); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkVideoInputFrame_v7_6,0x9A74FA41,0xAE9F,0x47AC,0x8C,0xF4,0x01,0xF4,0x2D,0xD5,0x99,0x65); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkScreenPreviewCallback_v7_6,0x373F499D,0x4B4D,0x4518,0xAD,0x22,0x63,0x54,0xE5,0xA5,0x82,0x5E); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkGLScreenPreviewHelper_v7_6,0xBA575CD9,0xA15E,0x497B,0xB2,0xC2,0xF9,0xAF,0xE7,0xBE,0x4E,0xBA); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkVideoConversion_v7_6,0x3EB504C9,0xF97D,0x40FE,0xA1,0x58,0xD4,0x07,0xD4,0x8C,0xB5,0x3B); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkConfiguration_v7_6,0xB8EAD569,0xB764,0x47F0,0xA7,0x3F,0xAE,0x40,0xDF,0x6C,0xBF,0x10); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkVideoOutputCallback_v7_6,0xE763A626,0x4A3C,0x49D1,0xBF,0x13,0xE7,0xAD,0x36,0x92,0xAE,0x52); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkInputCallback_v7_6,0x31D28EE7,0x88B6,0x4CB1,0x89,0x7A,0xCD,0xBF,0x79,0xA2,0x64,0x14); + + +MIDL_DEFINE_GUID(CLSID, CLSID_CDeckLinkGLScreenPreviewHelper_v7_6,0xD398CEE7,0x4434,0x4CA3,0x9B,0xA6,0x5A,0xE3,0x45,0x56,0xB9,0x05); + + +MIDL_DEFINE_GUID(CLSID, CLSID_CDeckLinkVideoConversion_v7_6,0xFFA84F77,0x73BE,0x4FB7,0xB0,0x3E,0xB5,0xE4,0x4B,0x9F,0x75,0x9B); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkInputCallback_v7_3,0xFD6F311D,0x4D00,0x444B,0x9E,0xD4,0x1F,0x25,0xB5,0x73,0x0A,0xD0); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkOutput_v7_3,0x271C65E3,0xC323,0x4344,0xA3,0x0F,0xD9,0x08,0xBC,0xB2,0x0A,0xA3); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkInput_v7_3,0x4973F012,0x9925,0x458C,0x87,0x1C,0x18,0x77,0x4C,0xDB,0xBE,0xCB); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkVideoInputFrame_v7_3,0xCF317790,0x2894,0x11DE,0x8C,0x30,0x08,0x00,0x20,0x0C,0x9A,0x66); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkDisplayModeIterator_v7_1,0xB28131B6,0x59AC,0x4857,0xB5,0xAC,0xCD,0x75,0xD5,0x88,0x3E,0x2F); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkDisplayMode_v7_1,0xAF0CD6D5,0x8376,0x435E,0x84,0x33,0x54,0xF9,0xDD,0x53,0x0A,0xC3); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkVideoFrame_v7_1,0x333F3A10,0x8C2D,0x43CF,0xB7,0x9D,0x46,0x56,0x0F,0xEE,0xA1,0xCE); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkVideoInputFrame_v7_1,0xC8B41D95,0x8848,0x40EE,0x9B,0x37,0x6E,0x34,0x17,0xFB,0x11,0x4B); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkAudioInputPacket_v7_1,0xC86DE4F6,0xA29F,0x42E3,0xAB,0x3A,0x13,0x63,0xE2,0x9F,0x07,0x88); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkVideoOutputCallback_v7_1,0xEBD01AFA,0xE4B0,0x49C6,0xA0,0x1D,0xED,0xB9,0xD1,0xB5,0x5F,0xD9); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkInputCallback_v7_1,0x7F94F328,0x5ED4,0x4E9F,0x97,0x29,0x76,0xA8,0x6B,0xDC,0x99,0xCC); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkOutput_v7_1,0xAE5B3E9B,0x4E1E,0x4535,0xB6,0xE8,0x48,0x0F,0xF5,0x2F,0x6C,0xE5); + + +MIDL_DEFINE_GUID(IID, IID_IDeckLinkInput_v7_1,0x2B54EDEF,0x5B32,0x429F,0xBA,0x11,0xBB,0x99,0x05,0x96,0xEA,0xCD); + +#undef MIDL_DEFINE_GUID + +#ifdef __cplusplus +} +#endif + + + diff --git a/intern/ghost/CMakeLists.txt b/intern/ghost/CMakeLists.txt index d31e9472168..e549a48d4b9 100644 --- a/intern/ghost/CMakeLists.txt +++ b/intern/ghost/CMakeLists.txt @@ -223,6 +223,10 @@ elseif(WITH_X11) ) endif() + if(WITH_X11_ALPHA) + add_definitions(-DWITH_X11_ALPHA) + endif() + if(WITH_INPUT_NDOF) list(APPEND SRC intern/GHOST_NDOFManagerUnix.cpp diff --git a/intern/ghost/GHOST_ISystem.h b/intern/ghost/GHOST_ISystem.h index 4c48473c7b8..08045b93db9 100644 --- a/intern/ghost/GHOST_ISystem.h +++ b/intern/ghost/GHOST_ISystem.h @@ -277,7 +277,7 @@ public: */ virtual GHOST_TSuccess beginFullScreen( const GHOST_DisplaySetting& setting, GHOST_IWindow **window, - const bool stereoVisual, const GHOST_TUns16 numOfAASamples = 0) = 0; + const bool stereoVisual, const bool alphaBackground = 0, const GHOST_TUns16 numOfAASamples = 0) = 0; /** * Updates the resolution while in fullscreen mode. diff --git a/intern/ghost/GHOST_Types.h b/intern/ghost/GHOST_Types.h index b3e560ab4b4..7e77ba3a41f 100644 --- a/intern/ghost/GHOST_Types.h +++ b/intern/ghost/GHOST_Types.h @@ -57,7 +57,8 @@ typedef struct { typedef enum { GHOST_glStereoVisual = (1 << 0), - GHOST_glDebugContext = (1 << 1) + GHOST_glDebugContext = (1 << 1), + GHOST_glAlphaBackground = (1 << 2), } GHOST_GLFlags; diff --git a/intern/ghost/intern/GHOST_ContextGLX.cpp b/intern/ghost/intern/GHOST_ContextGLX.cpp index 90d810b7986..9ac61db4041 100644 --- a/intern/ghost/intern/GHOST_ContextGLX.cpp +++ b/intern/ghost/intern/GHOST_ContextGLX.cpp @@ -62,6 +62,7 @@ GHOST_ContextGLX::GHOST_ContextGLX( Window window, Display *display, XVisualInfo *visualInfo, + GLXFBConfig fbconfig, int contextProfileMask, int contextMajorVersion, int contextMinorVersion, @@ -70,6 +71,7 @@ GHOST_ContextGLX::GHOST_ContextGLX( : GHOST_Context(stereoVisual, numOfAASamples), m_display(display), m_visualInfo(visualInfo), + m_fbconfig(fbconfig), m_window(window), m_contextProfileMask(contextProfileMask), m_contextMajorVersion(contextMajorVersion), @@ -153,15 +155,7 @@ void GHOST_ContextGLX::initContextGLXEW() GHOST_TSuccess GHOST_ContextGLX::initializeDrawingContext() { -#ifdef WITH_X11_XINPUT - /* use our own event handlers to avoid exiting blender, - * this would happen for eg: - * if you open blender, unplug a tablet, then open a new window. */ - XErrorHandler old_handler = XSetErrorHandler (GHOST_X11_ApplicationErrorHandler ); - XIOErrorHandler old_handler_io = XSetIOErrorHandler(GHOST_X11_ApplicationIOErrorHandler); -#endif - - + GHOST_X11_ERROR_HANDLERS_OVERRIDE(handler_store); /* -------------------------------------------------------------------- */ /* Begin Inline Glew */ @@ -285,19 +279,24 @@ const bool GLXEW_ARB_create_context_robustness = attribs[i++] = 0; /* Create a GL 3.x context */ - GLXFBConfig *framebuffer_config = NULL; - { - int glx_attribs[64]; - int fbcount = 0; + if (m_fbconfig) { + m_context = glXCreateContextAttribsARB(m_display, m_fbconfig, s_sharedContext, true, attribs); + } + else { + GLXFBConfig *framebuffer_config = NULL; + { + int glx_attribs[64]; + int fbcount = 0; - GHOST_X11_GL_GetAttributes(glx_attribs, 64, m_numOfAASamples, m_stereoVisual, true); + GHOST_X11_GL_GetAttributes(glx_attribs, 64, m_numOfAASamples, m_stereoVisual, false, true); - framebuffer_config = glXChooseFBConfig(m_display, DefaultScreen(m_display), glx_attribs, &fbcount); - } + framebuffer_config = glXChooseFBConfig(m_display, DefaultScreen(m_display), glx_attribs, &fbcount); + } - if (framebuffer_config) { - m_context = glXCreateContextAttribsARB(m_display, framebuffer_config[0], s_sharedContext, True, attribs); - XFree(framebuffer_config); + if (framebuffer_config) { + m_context = glXCreateContextAttribsARB(m_display, framebuffer_config[0], s_sharedContext, True, attribs); + XFree(framebuffer_config); + } } } else { @@ -343,11 +342,8 @@ const bool GLXEW_ARB_create_context_robustness = success = GHOST_kFailure; } -#ifdef WITH_X11_XINPUT - /* Restore handler */ - XSetErrorHandler (old_handler); - XSetIOErrorHandler(old_handler_io); -#endif + + GHOST_X11_ERROR_HANDLERS_RESTORE(handler_store); return success; } @@ -401,16 +397,11 @@ GHOST_TSuccess GHOST_ContextGLX::getSwapInterval(int &intervalOut) int GHOST_X11_GL_GetAttributes( int *attribs, int attribs_max, int samples, bool is_stereo_visual, + bool need_alpha, bool for_fb_config) { int i = 0; -#ifdef GHOST_OPENGL_ALPHA - const bool need_alpha = true; -#else - const bool need_alpha = false; -#endif - #ifdef GHOST_OPENGL_STENCIL const bool need_stencil = true; #else diff --git a/intern/ghost/intern/GHOST_ContextGLX.h b/intern/ghost/intern/GHOST_ContextGLX.h index 8c2231a0b01..f0f010d1942 100644 --- a/intern/ghost/intern/GHOST_ContextGLX.h +++ b/intern/ghost/intern/GHOST_ContextGLX.h @@ -66,6 +66,7 @@ public: Window window, Display *display, XVisualInfo *visualInfo, + GLXFBConfig fbconfig, int contextProfileMask, int contextMajorVersion, int contextMinorVersion, @@ -128,6 +129,7 @@ private: Display *m_display; XVisualInfo *m_visualInfo; + GLXFBConfig m_fbconfig; Window m_window; const int m_contextProfileMask; @@ -151,6 +153,7 @@ private: int GHOST_X11_GL_GetAttributes( int *attribs, int attribs_max, int samples, bool is_stereo_visual, + bool need_alpha, bool for_fb_config); #endif // __GHOST_CONTEXTGLX_H__ diff --git a/intern/ghost/intern/GHOST_ContextWGL.cpp b/intern/ghost/intern/GHOST_ContextWGL.cpp index cb580f60bd7..eeb6a2469ee 100644 --- a/intern/ghost/intern/GHOST_ContextWGL.cpp +++ b/intern/ghost/intern/GHOST_ContextWGL.cpp @@ -63,6 +63,7 @@ static bool is_crappy_intel_card() GHOST_ContextWGL::GHOST_ContextWGL( bool stereoVisual, + bool alphaBackground, GHOST_TUns16 numOfAASamples, HWND hWnd, HDC hDC, @@ -78,6 +79,7 @@ GHOST_ContextWGL::GHOST_ContextWGL( m_contextMajorVersion(contextMajorVersion), m_contextMinorVersion(contextMinorVersion), m_contextFlags(contextFlags), + m_alphaBackground(alphaBackground), m_contextResetNotificationStrategy(contextResetNotificationStrategy), m_hGLRC(NULL) #ifdef WITH_GLEW_MX @@ -168,7 +170,7 @@ GHOST_TSuccess GHOST_ContextWGL::activateDrawingContext() /* Ron Fosner's code for weighting pixel formats and forcing software. * See http://www.opengl.org/resources/faq/technical/weight.cpp */ -static int weight_pixel_format(PIXELFORMATDESCRIPTOR &pfd) +static int weight_pixel_format(PIXELFORMATDESCRIPTOR &pfd, PIXELFORMATDESCRIPTOR &preferredPFD) { int weight = 0; @@ -194,11 +196,12 @@ static int weight_pixel_format(PIXELFORMATDESCRIPTOR &pfd) weight += pfd.cColorBits - 8; -#ifdef GHOST_OPENGL_ALPHA - if (pfd.cAlphaBits > 0) + if (preferredPFD.cAlphaBits > 0 && pfd.cAlphaBits > 0) + weight++; +#ifdef WIN32_COMPOSITING + if ((preferredPFD.dwFlags & PFD_SUPPORT_COMPOSITION) && (pfd.dwFlags & PFD_SUPPORT_COMPOSITION)) weight++; #endif - #ifdef GHOST_OPENGL_STENCIL if (pfd.cStencilBits >= 8) weight++; @@ -239,7 +242,7 @@ static int choose_pixel_format_legacy(HDC hDC, PIXELFORMATDESCRIPTOR &preferredP WIN32_CHK(check == lastPFD); - int w = weight_pixel_format(pfd); + int w = weight_pixel_format(pfd, preferredPFD); if (w > weight) { weight = w; @@ -496,7 +499,10 @@ int GHOST_ContextWGL::_choose_pixel_format_arb_2( { std::vector<int> iAttributes; +#define _MAX_PIXEL_FORMATS 32 + int iPixelFormat = 0; + int iPixelFormats[_MAX_PIXEL_FORMATS]; int samples; @@ -521,8 +527,31 @@ int GHOST_ContextWGL::_choose_pixel_format_arb_2( sRGB); UINT nNumFormats; - WIN32_CHK(wglChoosePixelFormatARB(m_hDC, &(iAttributes[0]), NULL, 1, &iPixelFormat, &nNumFormats)); - + WIN32_CHK(wglChoosePixelFormatARB(m_hDC, &(iAttributes[0]), NULL, _MAX_PIXEL_FORMATS, iPixelFormats, &nNumFormats)); + +#ifdef WIN32_COMPOSITING + if (needAlpha && nNumFormats) { + // scan through all pixel format to make sure one supports compositing + PIXELFORMATDESCRIPTOR pfd; + int i; + + for (i = 0; i < nNumFormats; i++) { + if (DescribePixelFormat(m_hDC, iPixelFormats[i], sizeof(PIXELFORMATDESCRIPTOR), &pfd)) { + if (pfd.dwFlags & PFD_SUPPORT_COMPOSITION) { + iPixelFormat = iPixelFormats[i]; + break; + } + } + } + if (i == nNumFormats) { + fprintf(stderr, + "Warning! Unable to find a pixel format with compositing capability.\n"); + iPixelFormat = iPixelFormats[0]; + } + } + else +#endif + iPixelFormat = iPixelFormats[0]; /* total number of formats that match (regardless of size of iPixelFormat array) * see: WGL_ARB_pixel_format extension spec */ if (nNumFormats > 0) @@ -538,7 +567,7 @@ int GHOST_ContextWGL::_choose_pixel_format_arb_2( // check how many samples were actually gotten if (iPixelFormat != 0) { int iQuery[] = { WGL_SAMPLES_ARB }; - int actualSamples; + int actualSamples, alphaBits; wglGetPixelFormatAttribivARB(m_hDC, iPixelFormat, 0, 1, iQuery, &actualSamples); if (actualSamples != *numOfAASamples) { @@ -549,6 +578,14 @@ int GHOST_ContextWGL::_choose_pixel_format_arb_2( *numOfAASamples = actualSamples; // set context property to actual value } + if (needAlpha) { + iQuery[0] = WGL_ALPHA_BITS_ARB; + wglGetPixelFormatAttribivARB(m_hDC, iPixelFormat, 0, 1, iQuery, &alphaBits); + if (alphaBits == 0) { + fprintf(stderr, + "Warning! Unable to find a frame buffer with alpha channel.\n"); + } + } } else { *numOfAASamples = 0; @@ -674,9 +711,15 @@ int GHOST_ContextWGL::choose_pixel_format( PFD_DRAW_TO_WINDOW | PFD_SWAP_COPY | /* support swap copy */ PFD_DOUBLEBUFFER | /* support double-buffering */ - (stereoVisual ? PFD_STEREO : 0), /* support stereo */ + (stereoVisual ? PFD_STEREO : 0) |/* support stereo */ + ( +#ifdef WIN32_COMPOSITING + needAlpha ? PFD_SUPPORT_COMPOSITION : /* support composition for transparent background */ +#endif + 0 + ), PFD_TYPE_RGBA, /* color type */ - 24, /* preferred color depth */ + (needAlpha ? 32 : 24), /* preferred color depth */ 0, 0, 0, 0, 0, 0, /* color bits (ignored) */ needAlpha ? 8 : 0, /* alpha buffer */ 0, /* alpha shift (ignored) */ @@ -727,11 +770,7 @@ static void reportContextString(const char *name, const char *dummy, const char GHOST_TSuccess GHOST_ContextWGL::initializeDrawingContext() { -#ifdef GHOST_OPENGL_ALPHA - const bool needAlpha = true; -#else - const bool needAlpha = false; -#endif + const bool needAlpha = m_alphaBackground; #ifdef GHOST_OPENGL_STENCIL const bool needStencil = true; diff --git a/intern/ghost/intern/GHOST_ContextWGL.h b/intern/ghost/intern/GHOST_ContextWGL.h index 3b04a33b662..580b4dcb82f 100644 --- a/intern/ghost/intern/GHOST_ContextWGL.h +++ b/intern/ghost/intern/GHOST_ContextWGL.h @@ -32,6 +32,8 @@ #ifndef __GHOST_CONTEXTWGL_H__ #define __GHOST_CONTEXTWGL_H__ +//#define WIN32_COMPOSITING + #include "GHOST_Context.h" #ifdef WITH_GLEW_MX @@ -65,6 +67,7 @@ public: */ GHOST_ContextWGL( bool stereoVisual, + bool alphaBackground, GHOST_TUns16 numOfAASamples, HWND hWnd, HDC hDC, @@ -164,6 +167,7 @@ private: const int m_contextMajorVersion; const int m_contextMinorVersion; const int m_contextFlags; + const bool m_alphaBackground; const int m_contextResetNotificationStrategy; HGLRC m_hGLRC; diff --git a/intern/ghost/intern/GHOST_DropTargetWin32.cpp b/intern/ghost/intern/GHOST_DropTargetWin32.cpp index 96ff79aa65a..cbf37bf1b16 100644 --- a/intern/ghost/intern/GHOST_DropTargetWin32.cpp +++ b/intern/ghost/intern/GHOST_DropTargetWin32.cpp @@ -125,8 +125,7 @@ HRESULT __stdcall GHOST_DropTargetWin32::DragEnter(IDataObject *pDataObject, DWO */ HRESULT __stdcall GHOST_DropTargetWin32::DragOver(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect) { - if (m_window->canAcceptDragOperation()) - { + if (m_window->canAcceptDragOperation()) { *pdwEffect = allowedDropEffect(*pdwEffect); } else { @@ -154,8 +153,7 @@ HRESULT __stdcall GHOST_DropTargetWin32::DragLeave(void) HRESULT __stdcall GHOST_DropTargetWin32::Drop(IDataObject *pDataObject, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect) { void *data = getGhostData(pDataObject); - if (m_window->canAcceptDragOperation()) - { + if (m_window->canAcceptDragOperation()) { *pdwEffect = allowedDropEffect(*pdwEffect); } @@ -189,15 +187,13 @@ GHOST_TDragnDropTypes GHOST_DropTargetWin32::getGhostType(IDataObject *pDataObje * conversion, but we do the conversion ourself with WC_NO_BEST_FIT_CHARS. */ FORMATETC fmtetc = { CF_TEXT, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; - if (pDataObject->QueryGetData(&fmtetc) == S_OK) - { + if (pDataObject->QueryGetData(&fmtetc) == S_OK) { return GHOST_kDragnDropTypeString; } // Filesnames fmtetc.cfFormat = CF_HDROP; - if (pDataObject->QueryGetData(&fmtetc) == S_OK) - { + if (pDataObject->QueryGetData(&fmtetc) == S_OK) { return GHOST_kDragnDropTypeFilenames; } diff --git a/intern/ghost/intern/GHOST_EventManager.cpp b/intern/ghost/intern/GHOST_EventManager.cpp index bc531bd515b..0675ac734ed 100644 --- a/intern/ghost/intern/GHOST_EventManager.cpp +++ b/intern/ghost/intern/GHOST_EventManager.cpp @@ -167,11 +167,9 @@ void GHOST_EventManager::removeWindowEvents(GHOST_IWindow *window) { TEventStack::iterator iter; iter = m_events.begin(); - while (iter != m_events.end()) - { + while (iter != m_events.end()) { GHOST_IEvent *event = *iter; - if (event->getWindow() == window) - { + if (event->getWindow() == window) { GHOST_PRINT("GHOST_EventManager::removeWindowEvents(): removing event\n"); /* * Found an event for this window, remove it. @@ -191,11 +189,9 @@ void GHOST_EventManager::removeTypeEvents(GHOST_TEventType type, GHOST_IWindow * { TEventStack::iterator iter; iter = m_events.begin(); - while (iter != m_events.end()) - { + while (iter != m_events.end()) { GHOST_IEvent *event = *iter; - if ((event->getType() == type) && (!window || (event->getWindow() == window))) - { + if ((event->getType() == type) && (!window || (event->getWindow() == window))) { GHOST_PRINT("GHOST_EventManager::removeTypeEvents(): removing event\n"); /* * Found an event of this type for the window, remove it. diff --git a/intern/ghost/intern/GHOST_NDOFManager.cpp b/intern/ghost/intern/GHOST_NDOFManager.cpp index f18b7911f45..c8e14ad357f 100644 --- a/intern/ghost/intern/GHOST_NDOFManager.cpp +++ b/intern/ghost/intern/GHOST_NDOFManager.cpp @@ -378,8 +378,7 @@ void GHOST_NDOFManager::updateButton(int button_number, bool press, GHOST_TUns64 NDOF_ButtonT button = (button_number < m_buttonCount) ? m_hidMap[button_number] : NDOF_BUTTON_NONE; - switch (button) - { + switch (button) { case NDOF_BUTTON_NONE: #ifdef DEBUG_NDOF_BUTTONS printf("discarded\n"); diff --git a/intern/ghost/intern/GHOST_System.cpp b/intern/ghost/intern/GHOST_System.cpp index 639ce451d23..c53580818e6 100644 --- a/intern/ghost/intern/GHOST_System.cpp +++ b/intern/ghost/intern/GHOST_System.cpp @@ -140,7 +140,7 @@ bool GHOST_System::validWindow(GHOST_IWindow *window) GHOST_TSuccess GHOST_System::beginFullScreen(const GHOST_DisplaySetting& setting, GHOST_IWindow **window, - const bool stereoVisual, const GHOST_TUns16 numOfAASamples) + const bool stereoVisual, const bool alphaBackground, const GHOST_TUns16 numOfAASamples) { GHOST_TSuccess success = GHOST_kFailure; GHOST_ASSERT(m_windowManager, "GHOST_System::beginFullScreen(): invalid window manager"); @@ -152,7 +152,7 @@ GHOST_TSuccess GHOST_System::beginFullScreen(const GHOST_DisplaySetting& setting success = m_displayManager->setCurrentDisplaySetting(GHOST_DisplayManager::kMainDisplay, setting); if (success == GHOST_kSuccess) { //GHOST_PRINT("GHOST_System::beginFullScreen(): creating full-screen window\n"); - success = createFullScreenWindow((GHOST_Window **)window, setting, stereoVisual, numOfAASamples); + success = createFullScreenWindow((GHOST_Window **)window, setting, stereoVisual, alphaBackground, numOfAASamples); if (success == GHOST_kSuccess) { m_windowManager->beginFullScreen(*window, stereoVisual); } @@ -349,12 +349,14 @@ GHOST_TSuccess GHOST_System::exit() } GHOST_TSuccess GHOST_System::createFullScreenWindow(GHOST_Window **window, const GHOST_DisplaySetting &settings, - const bool stereoVisual, const GHOST_TUns16 numOfAASamples) + const bool stereoVisual, const bool alphaBackground, const GHOST_TUns16 numOfAASamples) { GHOST_GLSettings glSettings = {0}; if (stereoVisual) glSettings.flags |= GHOST_glStereoVisual; + if (alphaBackground) + glSettings.flags |= GHOST_glAlphaBackground; glSettings.numOfAASamples = numOfAASamples; /* note: don't use getCurrentDisplaySetting() because on X11 we may diff --git a/intern/ghost/intern/GHOST_System.h b/intern/ghost/intern/GHOST_System.h index c4951adb4fd..a10259bc9e9 100644 --- a/intern/ghost/intern/GHOST_System.h +++ b/intern/ghost/intern/GHOST_System.h @@ -144,8 +144,8 @@ public: * \return Indication of success. */ GHOST_TSuccess beginFullScreen(const GHOST_DisplaySetting& setting, GHOST_IWindow **window, - const bool stereoVisual, const GHOST_TUns16 numOfAASamples = 0); - + const bool stereoVisual, const bool alphaBackground, const GHOST_TUns16 numOfAASamples = 0); + /** * Updates the resolution while in fullscreen mode. * \param setting The new setting of the display. @@ -336,7 +336,7 @@ protected: * \return Indication of success. */ GHOST_TSuccess createFullScreenWindow(GHOST_Window **window, const GHOST_DisplaySetting &settings, - const bool stereoVisual, const GHOST_TUns16 numOfAASamples = 0); + const bool stereoVisual, const bool alphaBackground = 0, const GHOST_TUns16 numOfAASamples = 0); /** The display manager (platform dependent). */ GHOST_DisplayManager *m_displayManager; diff --git a/intern/ghost/intern/GHOST_SystemCocoa.mm b/intern/ghost/intern/GHOST_SystemCocoa.mm index c9855cfdf7e..bce390732fe 100644 --- a/intern/ghost/intern/GHOST_SystemCocoa.mm +++ b/intern/ghost/intern/GHOST_SystemCocoa.mm @@ -830,7 +830,7 @@ GHOST_TSuccess GHOST_SystemCocoa::handleWindowEvent(GHOST_TEventType eventType, window->updateDrawingContext(); pushEvent( new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowSize, window) ); //Mouse up event is trapped by the resizing event loop, so send it anyway to the window manager - pushEvent(new GHOST_EventButton(getMilliSeconds(), GHOST_kEventButtonUp, window, convertButton(0))); + pushEvent(new GHOST_EventButton(getMilliSeconds(), GHOST_kEventButtonUp, window, GHOST_kButtonMaskLeft)); //m_ignoreWindowSizedMessages = true; } break; @@ -1278,19 +1278,29 @@ GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr) switch ([event type]) { case NSLeftMouseDown: + pushEvent(new GHOST_EventButton([event timestamp] * 1000, GHOST_kEventButtonDown, window, GHOST_kButtonMaskLeft)); + handleTabletEvent(event); //Handle tablet events combined with mouse events + break; case NSRightMouseDown: + pushEvent(new GHOST_EventButton([event timestamp] * 1000, GHOST_kEventButtonDown, window, GHOST_kButtonMaskRight)); + handleTabletEvent(event); //Handle tablet events combined with mouse events + break; case NSOtherMouseDown: pushEvent(new GHOST_EventButton([event timestamp] * 1000, GHOST_kEventButtonDown, window, convertButton([event buttonNumber]))); - //Handle tablet events combined with mouse events - handleTabletEvent(event); + handleTabletEvent(event); //Handle tablet events combined with mouse events break; case NSLeftMouseUp: + pushEvent(new GHOST_EventButton([event timestamp] * 1000, GHOST_kEventButtonUp, window, GHOST_kButtonMaskLeft)); + handleTabletEvent(event); //Handle tablet events combined with mouse events + break; case NSRightMouseUp: + pushEvent(new GHOST_EventButton([event timestamp] * 1000, GHOST_kEventButtonUp, window, GHOST_kButtonMaskRight)); + handleTabletEvent(event); //Handle tablet events combined with mouse events + break; case NSOtherMouseUp: pushEvent(new GHOST_EventButton([event timestamp] * 1000, GHOST_kEventButtonUp, window, convertButton([event buttonNumber]))); - //Handle tablet events combined with mouse events - handleTabletEvent(event); + handleTabletEvent(event); //Handle tablet events combined with mouse events break; case NSLeftMouseDragged: diff --git a/intern/ghost/intern/GHOST_SystemPathsWin32.cpp b/intern/ghost/intern/GHOST_SystemPathsWin32.cpp index 2bd380050f1..7d0ce5158fe 100644 --- a/intern/ghost/intern/GHOST_SystemPathsWin32.cpp +++ b/intern/ghost/intern/GHOST_SystemPathsWin32.cpp @@ -76,8 +76,7 @@ const GHOST_TUns8 *GHOST_SystemPathsWin32::getSystemDir(int, const char *version HRESULT hResult = SHGetFolderPathW(NULL, CSIDL_COMMON_APPDATA, NULL, SHGFP_TYPE_CURRENT, knownpath_16); - if (hResult == S_OK) - { + if (hResult == S_OK) { conv_utf_16_to_8(knownpath_16, knownpath, MAX_PATH * 3); strcat(knownpath, "\\Blender Foundation\\Blender\\"); strcat(knownpath, versionstr); @@ -94,8 +93,7 @@ const GHOST_TUns8 *GHOST_SystemPathsWin32::getUserDir(int, const char *versionst HRESULT hResult = SHGetFolderPathW(NULL, CSIDL_APPDATA, NULL, SHGFP_TYPE_CURRENT, knownpath_16); - if (hResult == S_OK) - { + if (hResult == S_OK) { conv_utf_16_to_8(knownpath_16, knownpath, MAX_PATH * 3); strcat(knownpath, "\\Blender Foundation\\Blender\\"); strcat(knownpath, versionstr); diff --git a/intern/ghost/intern/GHOST_SystemWin32.cpp b/intern/ghost/intern/GHOST_SystemWin32.cpp index 43fb5dc4205..1ce8002520f 100644 --- a/intern/ghost/intern/GHOST_SystemWin32.cpp +++ b/intern/ghost/intern/GHOST_SystemWin32.cpp @@ -241,6 +241,7 @@ GHOST_IWindow *GHOST_SystemWin32::createWindow( state, type, ((glSettings.flags & GHOST_glStereoVisual) != 0), + ((glSettings.flags & GHOST_glAlphaBackground) != 0), glSettings.numOfAASamples, parentWindow, ((glSettings.flags & GHOST_glDebugContext) != 0)); @@ -408,7 +409,11 @@ GHOST_TSuccess GHOST_SystemWin32::init() ::LoadIcon(NULL, IDI_APPLICATION); } wc.hCursor = ::LoadCursor(0, IDC_ARROW); - wc.hbrBackground = 0; + wc.hbrBackground = +#ifdef INW32_COMPISITING + (HBRUSH)CreateSolidBrush +#endif + (0x00000000); wc.lpszMenuName = 0; wc.lpszClassName = L"GHOST_WindowClass"; @@ -1540,8 +1545,7 @@ static bool isStartedFromCommandPrompt() int GHOST_SystemWin32::toggleConsole(int action) { - switch (action) - { + switch (action) { case 3: // startup: hide if not started from command prompt { if (isStartedFromCommandPrompt()) { diff --git a/intern/ghost/intern/GHOST_SystemX11.cpp b/intern/ghost/intern/GHOST_SystemX11.cpp index c9946c13122..55d013f6e5f 100644 --- a/intern/ghost/intern/GHOST_SystemX11.cpp +++ b/intern/ghost/intern/GHOST_SystemX11.cpp @@ -73,6 +73,10 @@ /* for debugging - so we can breakpoint X11 errors */ // #define USE_X11_ERROR_HANDLERS +#ifdef WITH_X11_XINPUT +# define USE_XINPUT_HOTPLUG +#endif + /* see [#34039] Fix Alt key glitch on Unity desktop */ #define USE_UNITY_WORKAROUND @@ -169,11 +173,36 @@ GHOST_SystemX11( } #ifdef WITH_X11_XINPUT + /* detect if we have xinput (for reuse) */ + { + memset(&m_xinput_version, 0, sizeof(m_xinput_version)); + XExtensionVersion *version = XGetExtensionVersion(m_display, INAME); + if (version && (version != (XExtensionVersion *)NoSuchExtension)) { + if (version->present) { + m_xinput_version = *version; + } + XFree(version); + } + } + +#ifdef USE_XINPUT_HOTPLUG + if (m_xinput_version.present) { + XEventClass class_presence; + int xi_presence; + DevicePresence(m_display, xi_presence, class_presence); + XSelectExtensionEvent( + m_display, + RootWindow(m_display, DefaultScreen(m_display)), + &class_presence, 1); + (void)xi_presence; + } +#endif /* USE_XINPUT_HOTPLUG */ + /* initialize incase X11 fails to load */ memset(&m_xtablet, 0, sizeof(m_xtablet)); - initXInputDevices(); -#endif + refreshXInputDevices(); +#endif /* WITH_X11_XINPUT */ } GHOST_SystemX11:: @@ -310,6 +339,7 @@ createWindow(const STR_String& title, left, top, width, height, state, parentWindow, type, ((glSettings.flags & GHOST_glStereoVisual) != 0), exclusive, + ((glSettings.flags & GHOST_glAlphaBackground) != 0), glSettings.numOfAASamples, (glSettings.flags & GHOST_glDebugContext) != 0); if (window) { @@ -419,8 +449,7 @@ static Bool init_timestamp_scanner(Display *, XEvent *event, XPointer arg) { init_timestamp_data *data = reinterpret_cast<init_timestamp_data *>(arg); - switch (event->type) - { + switch (event->type) { case ButtonPress: case ButtonRelease: data->timestamp = event->xbutton.time; @@ -627,8 +656,13 @@ static bool checkTabletProximity(Display *display, XDevice *device) return false; } + /* needed since unplugging will abort() without this */ + GHOST_X11_ERROR_HANDLERS_OVERRIDE(handler_store); + state = XQueryDeviceState(display, device); + GHOST_X11_ERROR_HANDLERS_RESTORE(handler_store); + if (state) { XInputClass *cls = state->data; // printf("%d class%s :\n", state->num_classes, @@ -661,6 +695,41 @@ GHOST_SystemX11::processEvent(XEvent *xe) GHOST_WindowX11 *window = findGhostWindow(xe->xany.window); GHOST_Event *g_event = NULL; +#ifdef USE_XINPUT_HOTPLUG + /* Hot-Plug support */ + if (m_xinput_version.present) { + XEventClass class_presence; + int xi_presence; + + DevicePresence(m_display, xi_presence, class_presence); + (void)class_presence; + + if (xe->type == xi_presence) { + XDevicePresenceNotifyEvent *notify_event = (XDevicePresenceNotifyEvent *)xe; + if ((notify_event->devchange == DeviceEnabled) || + (notify_event->devchange == DeviceDisabled) || + (notify_event->devchange == DeviceAdded) || + (notify_event->devchange == DeviceRemoved)) + { + refreshXInputDevices(); + + /* update all window events */ + { + vector<GHOST_IWindow *> & win_vec = m_windowManager->getWindows(); + vector<GHOST_IWindow *>::iterator win_it = win_vec.begin(); + vector<GHOST_IWindow *>::const_iterator win_end = win_vec.end(); + + for (; win_it != win_end; ++win_it) { + GHOST_WindowX11 *window = static_cast<GHOST_WindowX11 *>(*win_it); + window->refreshXInputDevices(); + } + } + } + } + } +#endif /* USE_XINPUT_HOTPLUG */ + + if (!window) { return; } @@ -680,7 +749,6 @@ GHOST_SystemX11::processEvent(XEvent *xe) } } #endif /* WITH_X11_XINPUT */ - switch (xe->type) { case Expose: { @@ -1917,8 +1985,6 @@ GHOST_TSuccess GHOST_SystemX11::pushDragDropEvent(GHOST_TEventType eventType, ); } #endif - -#if defined(USE_X11_ERROR_HANDLERS) || defined(WITH_X11_XINPUT) /* * These callbacks can be used for debugging, so we can breakpoint on an X11 error. @@ -1952,7 +2018,6 @@ int GHOST_X11_ApplicationIOErrorHandler(Display * /*display*/) /* No exit! - but keep lint happy */ return 0; } -#endif #ifdef WITH_X11_XINPUT /* These C functions are copied from Wine 1.1.13's wintab.c */ @@ -1963,8 +2028,7 @@ int GHOST_X11_ApplicationIOErrorHandler(Display * /*display*/) static bool match_token(const char *haystack, const char *needle) { const char *p, *q; - for (p = haystack; *p; ) - { + for (p = haystack; *p; ) { while (*p && isspace(*p)) p++; if (!*p) @@ -2050,23 +2114,27 @@ static BOOL is_eraser(const char *name, const char *type) #undef FALSE /* end code copied from wine */ -void GHOST_SystemX11::initXInputDevices() +void GHOST_SystemX11::refreshXInputDevices() { - static XErrorHandler old_handler = (XErrorHandler) 0; - static XIOErrorHandler old_handler_io = (XIOErrorHandler) 0; + if (m_xinput_version.present) { + + if (m_xtablet.StylusDevice) { + XCloseDevice(m_display, m_xtablet.StylusDevice); + m_xtablet.StylusDevice = NULL; + } + + if (m_xtablet.EraserDevice) { + XCloseDevice(m_display, m_xtablet.EraserDevice); + m_xtablet.EraserDevice = NULL; + } - XExtensionVersion *version = XGetExtensionVersion(m_display, INAME); + /* Install our error handler to override Xlib's termination behavior */ + GHOST_X11_ERROR_HANDLERS_OVERRIDE(handler_store); - if (version && (version != (XExtensionVersion *)NoSuchExtension)) { - if (version->present) { + { int device_count; XDeviceInfo *device_info = XListInputDevices(m_display, &device_count); - m_xtablet.StylusDevice = NULL; - m_xtablet.EraserDevice = NULL; - /* Install our error handler to override Xlib's termination behavior */ - old_handler = XSetErrorHandler(GHOST_X11_ApplicationErrorHandler); - old_handler_io = XSetIOErrorHandler(GHOST_X11_ApplicationIOErrorHandler); for (int i = 0; i < device_count; ++i) { char *device_type = device_info[i].type ? XGetAtomName(m_display, device_info[i].type) : NULL; @@ -2125,13 +2193,10 @@ void GHOST_SystemX11::initXInputDevices() } } - /* Restore handler */ - (void) XSetErrorHandler(old_handler); - (void) XSetIOErrorHandler(old_handler_io); - XFreeDeviceList(device_info); } - XFree(version); + + GHOST_X11_ERROR_HANDLERS_RESTORE(handler_store); } } diff --git a/intern/ghost/intern/GHOST_SystemX11.h b/intern/ghost/intern/GHOST_SystemX11.h index a0088dbe8f0..e60cab6a194 100644 --- a/intern/ghost/intern/GHOST_SystemX11.h +++ b/intern/ghost/intern/GHOST_SystemX11.h @@ -52,6 +52,20 @@ int GHOST_X11_ApplicationErrorHandler(Display *display, XErrorEvent *theEvent); int GHOST_X11_ApplicationIOErrorHandler(Display *display); +#define GHOST_X11_ERROR_HANDLERS_OVERRIDE(var) \ + struct { \ + XErrorHandler handler; \ + XIOErrorHandler handler_io; \ + } var = { \ + XSetErrorHandler(GHOST_X11_ApplicationErrorHandler), \ + XSetIOErrorHandler(GHOST_X11_ApplicationIOErrorHandler), \ + } + +#define GHOST_X11_ERROR_HANDLERS_RESTORE(var) \ + { \ + (void)XSetErrorHandler(var.handler); \ + (void)XSetIOErrorHandler(var.handler_io); \ + } ((void)0) class GHOST_WindowX11; @@ -328,6 +342,10 @@ public: #endif } m_atom; +#ifdef WITH_X11_XINPUT + XExtensionVersion m_xinput_version; +#endif + private: Display *m_display; @@ -367,7 +385,7 @@ private: #endif #ifdef WITH_X11_XINPUT - void initXInputDevices(); + void refreshXInputDevices(); #endif GHOST_WindowX11 * diff --git a/intern/ghost/intern/GHOST_WindowWin32.cpp b/intern/ghost/intern/GHOST_WindowWin32.cpp index 81c08f4fc06..c9bcb38ab68 100644 --- a/intern/ghost/intern/GHOST_WindowWin32.cpp +++ b/intern/ghost/intern/GHOST_WindowWin32.cpp @@ -43,7 +43,9 @@ #else # include "GHOST_ContextWGL.h" #endif - +#ifdef WIN32_COMPOSITING +#include <Dwmapi.h> +#endif #include <math.h> #include <string.h> @@ -70,7 +72,8 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system, GHOST_TUns32 height, GHOST_TWindowState state, GHOST_TDrawingContextType type, - bool wantStereoVisual, + bool wantStereoVisual, + bool alphaBackground, GHOST_TUns16 wantNumOfAASamples, GHOST_TEmbedderWindowID parentwindowhwnd, bool is_debug) @@ -83,6 +86,7 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system, m_hasGrabMouse(false), m_nPressedButtons(0), m_customCursor(0), + m_wantAlphaBackground(alphaBackground), m_wintab(NULL), m_tabletData(NULL), m_tablet(0), @@ -181,17 +185,17 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system, wchar_t *title_16 = alloc_utf16_from_8((char *)(const char *)title, 0); m_hWnd = ::CreateWindowW( - s_windowClassName, // pointer to registered class name - title_16, // pointer to window name - wintype, // window style - left, // horizontal position of window - top, // vertical position of window - width, // window width - height, // window height - (HWND) m_parentWindowHwnd, // handle to parent or owner window - 0, // handle to menu or child-window identifier - ::GetModuleHandle(0), // handle to application instance - 0); // pointer to window-creation data + s_windowClassName, // pointer to registered class name + title_16, // pointer to window name + wintype, // window style + left, // horizontal position of window + top, // vertical position of window + width, // window width + height, // window height + (HWND)m_parentWindowHwnd, // handle to parent or owner window + 0, // handle to menu or child-window identifier + ::GetModuleHandle(0), // handle to application instance + 0); // pointer to window-creation data free(title_16); } else { @@ -243,6 +247,24 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system, } ::ShowWindow(m_hWnd, nCmdShow); +#ifdef WIN32_COMPOSITING + if (alphaBackground && parentwindowhwnd == 0) { + + HRESULT hr = S_OK; + + // Create and populate the Blur Behind structure + DWM_BLURBEHIND bb = { 0 }; + + // Enable Blur Behind and apply to the entire client area + bb.dwFlags = DWM_BB_ENABLE | DWM_BB_BLURREGION; + bb.fEnable = true; + bb.hRgnBlur = CreateRectRgn(0, 0, -1, -1); + + // Apply Blur Behind + hr = DwmEnableBlurBehindWindow(m_hWnd, &bb); + DeleteObject(bb.hRgnBlur); + } +#endif // Force an initial paint of the window ::UpdateWindow(m_hWnd); } @@ -622,6 +644,7 @@ GHOST_Context *GHOST_WindowWin32::newDrawingContext(GHOST_TDrawingContextType ty #if defined(WITH_GL_PROFILE_CORE) GHOST_Context *context = new GHOST_ContextWGL( m_wantStereoVisual, + m_wantAlphaBackground, m_wantNumOfAASamples, m_hWnd, m_hDC, @@ -632,6 +655,7 @@ GHOST_Context *GHOST_WindowWin32::newDrawingContext(GHOST_TDrawingContextType ty #elif defined(WITH_GL_PROFILE_ES20) GHOST_Context *context = new GHOST_ContextWGL( m_wantStereoVisual, + m_wantAlphaBackground, m_wantNumOfAASamples, m_hWnd, m_hDC, @@ -642,6 +666,7 @@ GHOST_Context *GHOST_WindowWin32::newDrawingContext(GHOST_TDrawingContextType ty #elif defined(WITH_GL_PROFILE_COMPAT) GHOST_Context *context = new GHOST_ContextWGL( m_wantStereoVisual, + m_wantAlphaBackground, m_wantNumOfAASamples, m_hWnd, m_hDC, diff --git a/intern/ghost/intern/GHOST_WindowWin32.h b/intern/ghost/intern/GHOST_WindowWin32.h index b508c2f37df..a1cf58c9ceb 100644 --- a/intern/ghost/intern/GHOST_WindowWin32.h +++ b/intern/ghost/intern/GHOST_WindowWin32.h @@ -89,6 +89,7 @@ public: GHOST_TWindowState state, GHOST_TDrawingContextType type = GHOST_kDrawingContextTypeNone, bool wantStereoVisual = false, + bool alphaBackground = false, GHOST_TUns16 wantNumOfAASamples = 0, GHOST_TEmbedderWindowID parentWindowHwnd = 0, bool is_debug = false); @@ -328,6 +329,8 @@ private: int m_nPressedButtons; /** HCURSOR structure of the custom cursor */ HCURSOR m_customCursor; + /** request GL context aith alpha channel */ + bool m_wantAlphaBackground; /** ITaskbarList3 structure for progress bar*/ ITaskbarList3 *m_Bar; diff --git a/intern/ghost/intern/GHOST_WindowX11.cpp b/intern/ghost/intern/GHOST_WindowX11.cpp index e68e0901dab..fd002cec80c 100644 --- a/intern/ghost/intern/GHOST_WindowX11.cpp +++ b/intern/ghost/intern/GHOST_WindowX11.cpp @@ -33,7 +33,9 @@ #include <X11/cursorfont.h> #include <X11/Xatom.h> #include <X11/Xutil.h> - +#ifdef WITH_X11_ALPHA +#include <X11/extensions/Xrender.h> +#endif #include "GHOST_WindowX11.h" #include "GHOST_SystemX11.h" #include "STR_String.h" @@ -164,15 +166,21 @@ static const unsigned long BLENDER_ICON_48x48x32[] = { static XVisualInfo *x11_visualinfo_from_glx( Display *display, - bool stereoVisual, GHOST_TUns16 *r_numOfAASamples) + bool stereoVisual, + GHOST_TUns16 *r_numOfAASamples, + bool needAlpha, + GLXFBConfig *fbconfig) { - XVisualInfo *visualInfo = NULL; + XVisualInfo *visual = NULL; GHOST_TUns16 numOfAASamples = *r_numOfAASamples; + int glx_major, glx_minor, glx_version; /* GLX version: major.minor */ GHOST_TUns16 actualSamples; + int glx_attribs[64]; + + *fbconfig = NULL; /* Set up the minimum attributes that we require and see if * X can find us a visual matching those requirements. */ - int glx_major, glx_minor; /* GLX version: major.minor */ if (!glXQueryVersion(display, &glx_major, &glx_minor)) { fprintf(stderr, @@ -182,53 +190,118 @@ static XVisualInfo *x11_visualinfo_from_glx( return NULL; } + glx_version = glx_major*100 + glx_minor; - /* GLX >= 1.4 required for multi-sample */ - if ((glx_major > 1) || (glx_major == 1 && glx_minor >= 4)) { + if (glx_version >= 104) { actualSamples = numOfAASamples; } else { numOfAASamples = 0; actualSamples = 0; } + +#ifdef WITH_X11_ALPHA + if ( needAlpha + && glx_version >= 103 + && (glXChooseFBConfig || + (glXChooseFBConfig = (PFNGLXCHOOSEFBCONFIGPROC)glXGetProcAddressARB((const GLubyte *)"glXChooseFBConfig")) != NULL) + && (glXGetVisualFromFBConfig || + (glXGetVisualFromFBConfig = (PFNGLXGETVISUALFROMFBCONFIGPROC)glXGetProcAddressARB((const GLubyte *)"glXGetVisualFromFBConfig")) != NULL) + ) { + GLXFBConfig *fbconfigs; + int nbfbconfig; + int i; + + for (;;) { + + GHOST_X11_GL_GetAttributes(glx_attribs, 64, actualSamples, stereoVisual, needAlpha, true); + + fbconfigs = glXChooseFBConfig(display, DefaultScreen(display), glx_attribs, &nbfbconfig); + + /* Any sample level or even zero, which means oversampling disabled, is good + * but we need a valid visual to continue */ + if (nbfbconfig > 0) { + /* take a frame buffer config that has alpha cap */ + for (i=0 ;i<nbfbconfig; i++) { + visual = (XVisualInfo*)glXGetVisualFromFBConfig(display, fbconfigs[i]); + if (!visual) + continue; + /* if we don't need a alpha background, the first config will do, otherwise + * test the alphaMask as it won't necessarily be present */ + if (needAlpha) { + XRenderPictFormat *pict_format = XRenderFindVisualFormat(display, visual->visual); + if (!pict_format) + continue; + if (pict_format->direct.alphaMask <= 0) + continue; + } + *fbconfig = fbconfigs[i]; + break; + } + XFree(fbconfigs); + if (i<nbfbconfig) { + if (actualSamples < numOfAASamples) { + fprintf(stderr, + "Warning! Unable to find a multisample pixel format that supports exactly %d samples. " + "Substituting one that uses %d samples.\n", + numOfAASamples, actualSamples); + } + break; + } + visual = NULL; + } - /* Find the display with highest samples, starting at level requested */ - for (;;) { - int glx_attribs[64]; - - GHOST_X11_GL_GetAttributes(glx_attribs, 64, actualSamples, stereoVisual, false); - - visualInfo = glXChooseVisual(display, DefaultScreen(display), glx_attribs); - - /* Any sample level or even zero, which means oversampling disabled, is good - * but we need a valid visual to continue */ - if (visualInfo != NULL) { - if (actualSamples < numOfAASamples) { + if (actualSamples == 0) { + /* All options exhausted, cannot continue */ fprintf(stderr, - "Warning! Unable to find a multisample pixel format that supports exactly %d samples. " - "Substituting one that uses %d samples.\n", - numOfAASamples, actualSamples); + "%s:%d: X11 glXChooseVisual() failed, " + "verify working openGL system!\n", + __FILE__, __LINE__); + + return NULL; + } + else { + --actualSamples; } - break; } + } + else +#endif + { + /* legacy, don't use extension */ + for (;;) { + GHOST_X11_GL_GetAttributes(glx_attribs, 64, actualSamples, stereoVisual, needAlpha, false); + + visual = glXChooseVisual(display, DefaultScreen(display), glx_attribs); + + /* Any sample level or even zero, which means oversampling disabled, is good + * but we need a valid visual to continue */ + if (visual != NULL) { + if (actualSamples < numOfAASamples) { + fprintf(stderr, + "Warning! Unable to find a multisample pixel format that supports exactly %d samples. " + "Substituting one that uses %d samples.\n", + numOfAASamples, actualSamples); + } + break; + } - if (actualSamples == 0) { - /* All options exhausted, cannot continue */ - fprintf(stderr, - "%s:%d: X11 glXChooseVisual() failed, " - "verify working openGL system!\n", - __FILE__, __LINE__); + if (actualSamples == 0) { + /* All options exhausted, cannot continue */ + fprintf(stderr, + "%s:%d: X11 glXChooseVisual() failed, " + "verify working openGL system!\n", + __FILE__, __LINE__); - return NULL; - } - else { - --actualSamples; + return NULL; + } + else { + --actualSamples; + } } } - *r_numOfAASamples = actualSamples; - - return visualInfo; + return visual; } GHOST_WindowX11:: @@ -244,10 +317,12 @@ GHOST_WindowX11(GHOST_SystemX11 *system, GHOST_TDrawingContextType type, const bool stereoVisual, const bool exclusive, + const bool alphaBackground, const GHOST_TUns16 numOfAASamples, const bool is_debug) : GHOST_Window(width, height, state, stereoVisual, exclusive, numOfAASamples), m_display(display), m_visualInfo(NULL), + m_fbconfig(NULL), m_normal_state(GHOST_kWindowStateNormal), m_system(system), m_invalid_window(false), @@ -264,7 +339,7 @@ GHOST_WindowX11(GHOST_SystemX11 *system, m_is_debug_context(is_debug) { if (type == GHOST_kDrawingContextTypeOpenGL) { - m_visualInfo = x11_visualinfo_from_glx(m_display, stereoVisual, &m_wantNumOfAASamples); + m_visualInfo = x11_visualinfo_from_glx(m_display, stereoVisual, &m_wantNumOfAASamples, alphaBackground, (GLXFBConfig*)&m_fbconfig); } else { XVisualInfo tmp = {0}; @@ -491,7 +566,7 @@ GHOST_WindowX11(GHOST_SystemX11 *system, } #ifdef WITH_X11_XINPUT - initXInputDevices(); + refreshXInputDevices(); m_tabletData.Active = GHOST_kTabletModeNone; #endif @@ -558,45 +633,40 @@ bool GHOST_WindowX11::createX11_XIC() #endif #ifdef WITH_X11_XINPUT -void GHOST_WindowX11::initXInputDevices() +void GHOST_WindowX11::refreshXInputDevices() { - XExtensionVersion *version = XGetExtensionVersion(m_display, INAME); - - if (version && (version != (XExtensionVersion *)NoSuchExtension)) { - if (version->present) { - GHOST_SystemX11::GHOST_TabletX11 &xtablet = m_system->GetXTablet(); - XEventClass xevents[8], ev; - int dcount = 0; - - /* With modern XInput (xlib 1.6.2 at least and/or evdev 2.9.0) and some 'no-name' tablets - * like 'UC-LOGIC Tablet WP5540U', we also need to 'select' ButtonPress for motion event, - * otherwise we do not get any tablet motion event once pen is pressed... See T43367. - */ - - if (xtablet.StylusDevice) { - DeviceMotionNotify(xtablet.StylusDevice, xtablet.MotionEvent, ev); - if (ev) xevents[dcount++] = ev; - DeviceButtonPress(xtablet.StylusDevice, xtablet.PressEvent, ev); - if (ev) xevents[dcount++] = ev; - ProximityIn(xtablet.StylusDevice, xtablet.ProxInEvent, ev); - if (ev) xevents[dcount++] = ev; - ProximityOut(xtablet.StylusDevice, xtablet.ProxOutEvent, ev); - if (ev) xevents[dcount++] = ev; - } - if (xtablet.EraserDevice) { - DeviceMotionNotify(xtablet.EraserDevice, xtablet.MotionEventEraser, ev); - if (ev) xevents[dcount++] = ev; - DeviceButtonPress(xtablet.EraserDevice, xtablet.PressEventEraser, ev); - if (ev) xevents[dcount++] = ev; - ProximityIn(xtablet.EraserDevice, xtablet.ProxInEventEraser, ev); - if (ev) xevents[dcount++] = ev; - ProximityOut(xtablet.EraserDevice, xtablet.ProxOutEventEraser, ev); - if (ev) xevents[dcount++] = ev; - } + if (m_system->m_xinput_version.present) { + GHOST_SystemX11::GHOST_TabletX11 &xtablet = m_system->GetXTablet(); + XEventClass xevents[8], ev; + int dcount = 0; + + /* With modern XInput (xlib 1.6.2 at least and/or evdev 2.9.0) and some 'no-name' tablets + * like 'UC-LOGIC Tablet WP5540U', we also need to 'select' ButtonPress for motion event, + * otherwise we do not get any tablet motion event once pen is pressed... See T43367. + */ - XSelectExtensionEvent(m_display, m_window, xevents, dcount); + if (xtablet.StylusDevice) { + DeviceMotionNotify(xtablet.StylusDevice, xtablet.MotionEvent, ev); + if (ev) xevents[dcount++] = ev; + DeviceButtonPress(xtablet.StylusDevice, xtablet.PressEvent, ev); + if (ev) xevents[dcount++] = ev; + ProximityIn(xtablet.StylusDevice, xtablet.ProxInEvent, ev); + if (ev) xevents[dcount++] = ev; + ProximityOut(xtablet.StylusDevice, xtablet.ProxOutEvent, ev); + if (ev) xevents[dcount++] = ev; + } + if (xtablet.EraserDevice) { + DeviceMotionNotify(xtablet.EraserDevice, xtablet.MotionEventEraser, ev); + if (ev) xevents[dcount++] = ev; + DeviceButtonPress(xtablet.EraserDevice, xtablet.PressEventEraser, ev); + if (ev) xevents[dcount++] = ev; + ProximityIn(xtablet.EraserDevice, xtablet.ProxInEventEraser, ev); + if (ev) xevents[dcount++] = ev; + ProximityOut(xtablet.EraserDevice, xtablet.ProxOutEventEraser, ev); + if (ev) xevents[dcount++] = ev; } - XFree(version); + + XSelectExtensionEvent(m_display, m_window, xevents, dcount); } } @@ -1240,6 +1310,7 @@ GHOST_Context *GHOST_WindowX11::newDrawingContext(GHOST_TDrawingContextType type m_window, m_display, m_visualInfo, + (GLXFBConfig)m_fbconfig, GLX_CONTEXT_CORE_PROFILE_BIT_ARB, 3, 2, GHOST_OPENGL_GLX_CONTEXT_FLAGS | (m_is_debug_context ? GLX_CONTEXT_DEBUG_BIT_ARB : 0), @@ -1251,6 +1322,7 @@ GHOST_Context *GHOST_WindowX11::newDrawingContext(GHOST_TDrawingContextType type m_window, m_display, m_visualInfo, + (GLXFBConfig)m_fbconfig, GLX_CONTEXT_ES2_PROFILE_BIT_EXT, 2, 0, GHOST_OPENGL_GLX_CONTEXT_FLAGS | (m_is_debug_context ? GLX_CONTEXT_DEBUG_BIT_ARB : 0), @@ -1262,6 +1334,7 @@ GHOST_Context *GHOST_WindowX11::newDrawingContext(GHOST_TDrawingContextType type m_window, m_display, m_visualInfo, + (GLXFBConfig)m_fbconfig, 0, // profile bit 0, 0, GHOST_OPENGL_GLX_CONTEXT_FLAGS | (m_is_debug_context ? GLX_CONTEXT_DEBUG_BIT_ARB : 0), diff --git a/intern/ghost/intern/GHOST_WindowX11.h b/intern/ghost/intern/GHOST_WindowX11.h index 5beb7b43032..9380aa9d631 100644 --- a/intern/ghost/intern/GHOST_WindowX11.h +++ b/intern/ghost/intern/GHOST_WindowX11.h @@ -73,6 +73,7 @@ public: * \param parentWindow Parent (embedder) window * \param type The type of drawing context installed in this window. * \param stereoVisual Stereo visual for quad buffered stereo. + * \param alphaBackground Enable alpha blending of window with display background * \param numOfAASamples Number of samples used for AA (zero if no AA) */ GHOST_WindowX11( @@ -88,6 +89,7 @@ public: GHOST_TDrawingContextType type = GHOST_kDrawingContextTypeNone, const bool stereoVisual = false, const bool exclusive = false, + const bool alphaBackground = false, const GHOST_TUns16 numOfAASamples = 0, const bool is_debug = false ); @@ -210,6 +212,10 @@ public: bool createX11_XIC(); #endif +#ifdef WITH_X11_XINPUT + void refreshXInputDevices(); +#endif + #ifdef WITH_XDND GHOST_DropTargetX11 *getDropTarget() { @@ -313,14 +319,11 @@ private: Cursor getEmptyCursor( ); - -#ifdef WITH_X11_XINPUT - void initXInputDevices(); -#endif Window m_window; Display *m_display; XVisualInfo *m_visualInfo; + void *m_fbconfig; GHOST_TWindowState m_normal_state; diff --git a/intern/gpudirect/CMakeLists.txt b/intern/gpudirect/CMakeLists.txt new file mode 100644 index 00000000000..88c09a663b8 --- /dev/null +++ b/intern/gpudirect/CMakeLists.txt @@ -0,0 +1,41 @@ +# ***** 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. +# +# The Original Code is Copyright (C) 2015, Blender Foundation +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): Blender Foundation. +# +# ***** END GPL LICENSE BLOCK ***** + +set(INC + . + # XXX, bad level include! + ../../source/blender/blenlib +) + +set(INC_SYS + ${GLEW_INCLUDE_PATH} +) + +set(SRC + dvpapi.cpp + dvpapi.h +) + +blender_add_lib(bf_intern_gpudirect "${SRC}" "${INC}" "${INC_SYS}") diff --git a/intern/gpudirect/dvpapi.cpp b/intern/gpudirect/dvpapi.cpp new file mode 100644 index 00000000000..56b58e0a348 --- /dev/null +++ b/intern/gpudirect/dvpapi.cpp @@ -0,0 +1,147 @@ +/* + * ***** 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. + * + * The Original Code is Copyright (C) 2015, Blender Foundation + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Blender Foundation. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file gpudirect/dvpapi.c + * \ingroup gpudirect + */ + +#ifdef WIN32 + +#include <stdlib.h> +#include "dvpapi.h" + +extern "C" { +#include "BLI_dynlib.h" +} + +#define KDVPAPI_Name "dvp.dll" + +typedef DVPStatus (DVPAPIENTRY * PFNDVPINITGLCONTEXT) (uint32_t flags); +typedef DVPStatus (DVPAPIENTRY * PFNDVPCLOSEGLCONTEXT) (void); +typedef DVPStatus (DVPAPIENTRY * PFNDVPGETLIBRARYVERSION)(uint32_t *major, uint32_t *minor); + +static uint32_t __dvpMajorVersion = 0; +static uint32_t __dvpMinorVersion = 0; +static PFNDVPGETLIBRARYVERSION __dvpGetLibrayVersion = NULL; +static PFNDVPINITGLCONTEXT __dvpInitGLContext = NULL; +static PFNDVPCLOSEGLCONTEXT __dvpCloseGLContext = NULL; +PFNDVPBEGIN __dvpBegin = NULL; +PFNDVPEND __dvpEnd = NULL; +PFNDVPCREATEBUFFER __dvpCreateBuffer = NULL; +PFNDVPDESTROYBUFFER __dvpDestroyBuffer = NULL; +PFNDVPFREEBUFFER __dvpFreeBuffer = NULL; +PFNDVPMEMCPYLINED __dvpMemcpyLined = NULL; +PFNDVPMEMCPY __dvpMemcpy = NULL; +PFNDVPIMPORTSYNCOBJECT __dvpImportSyncObject = NULL; +PFNDVPFREESYNCOBJECT __dvpFreeSyncObject = NULL; +PFNDVPMAPBUFFERENDAPI __dvpMapBufferEndAPI = NULL; +PFNDVPMAPBUFFERWAITDVP __dvpMapBufferWaitDVP = NULL; +PFNDVPMAPBUFFERENDDVP __dvpMapBufferEndDVP = NULL; +PFNDVPMAPBUFFERWAITAPI __dvpMapBufferWaitAPI = NULL; +PFNDVPBINDTOGLCTX __dvpBindToGLCtx = NULL; +PFNDVPGETREQUIREDCONSTANTSGLCTX __dvpGetRequiredConstantsGLCtx = NULL; +PFNDVPCREATEGPUTEXTUREGL __dvpCreateGPUTextureGL = NULL; +PFNDVPUNBINDFROMGLCTX __dvpUnbindFromGLCtx = NULL; + +static DynamicLibrary *__dvpLibrary = NULL; + +DVPStatus dvpGetLibrayVersion(uint32_t *major, uint32_t *minor) +{ + if (!__dvpLibrary) + return DVP_STATUS_ERROR; + *major = __dvpMajorVersion; + *minor = __dvpMinorVersion; + return DVP_STATUS_OK; +} + +DVPStatus dvpInitGLContext(uint32_t flags) +{ + DVPStatus status; + if (!__dvpLibrary) { + __dvpLibrary = BLI_dynlib_open(KDVPAPI_Name); + if (!__dvpLibrary) { + return DVP_STATUS_ERROR; + } +// "?dvpInitGLContext@@YA?AW4DVPStatus@@I@Z"; + __dvpInitGLContext = (PFNDVPINITGLCONTEXT)BLI_dynlib_find_symbol(__dvpLibrary, "?dvpInitGLContext@@YA?AW4DVPStatus@@I@Z"); + __dvpCloseGLContext = (PFNDVPCLOSEGLCONTEXT)BLI_dynlib_find_symbol(__dvpLibrary, "?dvpCloseGLContext@@YA?AW4DVPStatus@@XZ"); + __dvpGetLibrayVersion = (PFNDVPGETLIBRARYVERSION)BLI_dynlib_find_symbol(__dvpLibrary, "?dvpGetLibrayVersion@@YA?AW4DVPStatus@@PEAI0@Z"); + __dvpBegin = (PFNDVPBEGIN)BLI_dynlib_find_symbol(__dvpLibrary, "?dvpBegin@@YA?AW4DVPStatus@@XZ"); + __dvpEnd = (PFNDVPEND)BLI_dynlib_find_symbol(__dvpLibrary, "?dvpEnd@@YA?AW4DVPStatus@@XZ"); + __dvpCreateBuffer = (PFNDVPCREATEBUFFER)BLI_dynlib_find_symbol(__dvpLibrary, "?dvpCreateBuffer@@YA?AW4DVPStatus@@PEAUDVPSysmemBufferDescRec@@PEA_K@Z"); + __dvpDestroyBuffer = (PFNDVPDESTROYBUFFER)BLI_dynlib_find_symbol(__dvpLibrary, "?dvpDestroyBuffer@@YA?AW4DVPStatus@@_K@Z"); + __dvpFreeBuffer = (PFNDVPFREEBUFFER)BLI_dynlib_find_symbol(__dvpLibrary, "?dvpFreeBuffer@@YA?AW4DVPStatus@@_K@Z"); + __dvpMemcpyLined = (PFNDVPMEMCPYLINED)BLI_dynlib_find_symbol(__dvpLibrary, "?dvpMemcpyLined@@YA?AW4DVPStatus@@_K0I000III@Z"); + __dvpMemcpy = (PFNDVPMEMCPY)BLI_dynlib_find_symbol(__dvpLibrary, "?dvpMemcpy2D@@YA?AW4DVPStatus@@_K0I000IIIII@Z"); + __dvpImportSyncObject = (PFNDVPIMPORTSYNCOBJECT)BLI_dynlib_find_symbol(__dvpLibrary, "?dvpImportSyncObject@@YA?AW4DVPStatus@@PEAUDVPSyncObjectDescRec@@PEA_K@Z"); + __dvpFreeSyncObject = (PFNDVPFREESYNCOBJECT)BLI_dynlib_find_symbol(__dvpLibrary, "?dvpFreeSyncObject@@YA?AW4DVPStatus@@_K@Z"); + __dvpMapBufferEndAPI = (PFNDVPMAPBUFFERENDAPI)BLI_dynlib_find_symbol(__dvpLibrary, "?dvpMapBufferEndAPI@@YA?AW4DVPStatus@@_K@Z"); + __dvpMapBufferWaitDVP = (PFNDVPMAPBUFFERWAITDVP)BLI_dynlib_find_symbol(__dvpLibrary, "?dvpMapBufferWaitDVP@@YA?AW4DVPStatus@@_K@Z"); + __dvpMapBufferEndDVP = (PFNDVPMAPBUFFERENDDVP)BLI_dynlib_find_symbol(__dvpLibrary, "?dvpMapBufferEndDVP@@YA?AW4DVPStatus@@_K@Z"); + __dvpMapBufferWaitAPI = (PFNDVPMAPBUFFERWAITAPI)BLI_dynlib_find_symbol(__dvpLibrary, "?dvpMapBufferWaitAPI@@YA?AW4DVPStatus@@_K@Z"); + __dvpBindToGLCtx = (PFNDVPBINDTOGLCTX)BLI_dynlib_find_symbol(__dvpLibrary, "?dvpBindToGLCtx@@YA?AW4DVPStatus@@_K@Z"); + __dvpGetRequiredConstantsGLCtx = (PFNDVPGETREQUIREDCONSTANTSGLCTX)BLI_dynlib_find_symbol(__dvpLibrary, "?dvpGetRequiredConstantsGLCtx@@YA?AW4DVPStatus@@PEAI00000@Z"); + __dvpCreateGPUTextureGL = (PFNDVPCREATEGPUTEXTUREGL)BLI_dynlib_find_symbol(__dvpLibrary, "?dvpCreateGPUTextureGL@@YA?AW4DVPStatus@@IPEA_K@Z"); + __dvpUnbindFromGLCtx = (PFNDVPUNBINDFROMGLCTX)BLI_dynlib_find_symbol(__dvpLibrary, "?dvpUnbindFromGLCtx@@YA?AW4DVPStatus@@_K@Z"); + if (!__dvpInitGLContext || + !__dvpCloseGLContext || + !__dvpGetLibrayVersion || + !__dvpBegin || + !__dvpEnd || + !__dvpCreateBuffer || + !__dvpDestroyBuffer || + !__dvpFreeBuffer || + !__dvpMemcpyLined || + !__dvpMemcpy || + !__dvpImportSyncObject || + !__dvpFreeSyncObject || + !__dvpMapBufferEndAPI || + !__dvpMapBufferWaitDVP || + !__dvpMapBufferEndDVP || + !__dvpMapBufferWaitAPI || + !__dvpBindToGLCtx || + !__dvpGetRequiredConstantsGLCtx || + !__dvpCreateGPUTextureGL || + !__dvpUnbindFromGLCtx) + { + return DVP_STATUS_ERROR; + } + // check that the library version is what we want + if ((status = __dvpGetLibrayVersion(&__dvpMajorVersion, &__dvpMinorVersion)) != DVP_STATUS_OK) + return status; + if (__dvpMajorVersion != DVP_MAJOR_VERSION || __dvpMinorVersion < DVP_MINOR_VERSION) + return DVP_STATUS_ERROR; + } + return (!__dvpInitGLContext) ? DVP_STATUS_ERROR : __dvpInitGLContext(flags); +} + +DVPStatus dvpCloseGLContext(void) +{ + return (!__dvpCloseGLContext) ? DVP_STATUS_ERROR : __dvpCloseGLContext(); +} + +#endif // WIN32 diff --git a/intern/gpudirect/dvpapi.h b/intern/gpudirect/dvpapi.h new file mode 100644 index 00000000000..cafc4e862ae --- /dev/null +++ b/intern/gpudirect/dvpapi.h @@ -0,0 +1,667 @@ +/* + * ***** 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. + * + * The Original Code is Copyright (C) 2015, Blender Foundation + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Blender Foundation. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file gpudirect/dvpapi.h + * \ingroup gpudirect + */ + +#ifndef __DVPAPI_H__ +#define __DVPAPI_H__ + +#ifdef WIN32 + +#include <stdlib.h> +#include <stdint.h> + +#include "GL/glew.h" + +#if defined(__GNUC__) && __GNUC__>=4 +# define DVPAPI extern __attribute__ ((visibility("default"))) +#elif defined(__SUNPRO_C) || defined(__SUNPRO_CC) +# define DVPAPI extern __global +#else +# define DVPAPI extern +#endif + +#define DVPAPIENTRY +#define DVP_MAJOR_VERSION 1 +#define DVP_MINOR_VERSION 63 + +typedef uint64_t DVPBufferHandle; +typedef uint64_t DVPSyncObjectHandle; + +typedef enum { + DVP_STATUS_OK = 0, + DVP_STATUS_INVALID_PARAMETER = 1, + DVP_STATUS_UNSUPPORTED = 2, + DVP_STATUS_END_ENUMERATION = 3, + DVP_STATUS_INVALID_DEVICE = 4, + DVP_STATUS_OUT_OF_MEMORY = 5, + DVP_STATUS_INVALID_OPERATION = 6, + DVP_STATUS_TIMEOUT = 7, + DVP_STATUS_INVALID_CONTEXT = 8, + DVP_STATUS_INVALID_RESOURCE_TYPE = 9, + DVP_STATUS_INVALID_FORMAT_OR_TYPE = 10, + DVP_STATUS_DEVICE_UNINITIALIZED = 11, + DVP_STATUS_UNSIGNALED = 12, + DVP_STATUS_SYNC_ERROR = 13, + DVP_STATUS_SYNC_STILL_BOUND = 14, + DVP_STATUS_ERROR = -1, +} DVPStatus; + +// Pixel component formats stored in the system memory buffer +// analogous to those defined in the OpenGL API, except for +// DVP_BUFFER and the DVP_CUDA_* types. DVP_BUFFER provides +// an unspecified format type to allow for general interpretation +// of the bytes at a later stage (in GPU shader). Note that not +// all paths will achieve optimal speeds due to lack of HW support +// for the transformation. The CUDA types are to be used when +// copying to/from a system memory buffer from-to a CUDA array, as the +// CUDA array implies a memory layout that matches the array. +typedef enum { + DVP_BUFFER, // Buffer treated as a raw buffer + // and copied directly into GPU buffer + // without any interpretation of the + // stored bytes. + DVP_DEPTH_COMPONENT, + DVP_RGBA, + DVP_BGRA, + DVP_RED, + DVP_GREEN, + DVP_BLUE, + DVP_ALPHA, + DVP_RGB, + DVP_BGR, + DVP_LUMINANCE, + DVP_LUMINANCE_ALPHA, + DVP_CUDA_1_CHANNEL, + DVP_CUDA_2_CHANNELS, + DVP_CUDA_4_CHANNELS, + DVP_RGBA_INTEGER, + DVP_BGRA_INTEGER, + DVP_RED_INTEGER, + DVP_GREEN_INTEGER, + DVP_BLUE_INTEGER, + DVP_ALPHA_INTEGER, + DVP_RGB_INTEGER, + DVP_BGR_INTEGER, + DVP_LUMINANCE_INTEGER, + DVP_LUMINANCE_ALPHA_INTEGER, +} DVPBufferFormats; + +// Possible pixel component storage types for system memory buffers +typedef enum { + DVP_UNSIGNED_BYTE, + DVP_BYTE, + DVP_UNSIGNED_SHORT, + DVP_SHORT, + DVP_UNSIGNED_INT, + DVP_INT, + DVP_FLOAT, + DVP_HALF_FLOAT, + DVP_UNSIGNED_BYTE_3_3_2, + DVP_UNSIGNED_BYTE_2_3_3_REV, + DVP_UNSIGNED_SHORT_5_6_5, + DVP_UNSIGNED_SHORT_5_6_5_REV, + DVP_UNSIGNED_SHORT_4_4_4_4, + DVP_UNSIGNED_SHORT_4_4_4_4_REV, + DVP_UNSIGNED_SHORT_5_5_5_1, + DVP_UNSIGNED_SHORT_1_5_5_5_REV, + DVP_UNSIGNED_INT_8_8_8_8, + DVP_UNSIGNED_INT_8_8_8_8_REV, + DVP_UNSIGNED_INT_10_10_10_2, + DVP_UNSIGNED_INT_2_10_10_10_REV, +} DVPBufferTypes; + +// System memory descriptor describing the size and storage formats +// of the buffer +typedef struct DVPSysmemBufferDescRec { + uint32_t width; // Buffer Width + uint32_t height; // Buffer Height + uint32_t stride; // Stride + uint32_t size; // Specifies the surface size if + // format == DVP_BUFFER + DVPBufferFormats format; // see enum above + DVPBufferTypes type; // see enum above + void *bufAddr; // Buffer memory address +} DVPSysmemBufferDesc; + +// Flags specified at sync object creation: +// ---------------------------------------- +// Tells the implementation to use events wherever +// possible instead of software spin loops. Note if HW +// wait operations are supported by the implementation +// then events will not be used in the dvpMemcpy* +// functions. In such a case, events may still be used +// in dvpSyncObjClientWait* functions. +#define DVP_SYNC_OBJECT_FLAGS_USE_EVENTS 0x00000001 + +typedef struct DVPSyncObjectDescRec { + uint32_t *sem; // Location to write semaphore value + uint32_t flags; // See above DVP_SYNC_OBJECT_FLAGS_* bits + DVPStatus (*externalClientWaitFunc) (DVPSyncObjectHandle sync, + uint32_t value, + bool GEQ, // If true then the function should wait for the sync value to be + // greater than or equal to the value parameter. Otherwise just a + // straight forward equality comparison should be performed. + uint64_t timeout); + // If non-null, externalClientWaitFunc allows the DVP library + // to call the application to wait for a sync object to be + // released. This allows the application to create events, + // which can be triggered on device interrupts instead of + // using spin loops inside the DVP library. Upon succeeding + // the function must return DVP_STATUS_OK, non-zero for failure + // and DVP_STATUS_TIMEOUT on timeout. The externalClientWaitFunc should + // not alter the current GL or CUDA context state +} DVPSyncObjectDesc; + +// Time used when event timeouts should be ignored +#define DVP_TIMEOUT_IGNORED 0xFFFFFFFFFFFFFFFFull + +typedef DVPStatus (DVPAPIENTRY * PFNDVPBEGIN) (void); +typedef DVPStatus (DVPAPIENTRY * PFNDVPEND) (void); +typedef DVPStatus (DVPAPIENTRY * PFNDVPCREATEBUFFER)(DVPSysmemBufferDesc *desc, DVPBufferHandle *hBuf); +typedef DVPStatus (DVPAPIENTRY * PFNDVPDESTROYBUFFER)(DVPBufferHandle hBuf); +typedef DVPStatus (DVPAPIENTRY * PFNDVPFREEBUFFER)(DVPBufferHandle gpuBufferHandle); +typedef DVPStatus (DVPAPIENTRY * PFNDVPMEMCPYLINED)(DVPBufferHandle srcBuffer, + DVPSyncObjectHandle srcSync, + uint32_t srcAcquireValue, + uint64_t timeout, + DVPBufferHandle dstBuffer, + DVPSyncObjectHandle dstSync, + uint32_t dstReleaseValue, + uint32_t startingLine, + uint32_t numberOfLines); +typedef DVPStatus (DVPAPIENTRY * PFNDVPMEMCPY)(DVPBufferHandle srcBuffer, + DVPSyncObjectHandle srcSync, + uint32_t srcAcquireValue, + uint64_t timeout, + DVPBufferHandle dstBuffer, + DVPSyncObjectHandle dstSync, + uint32_t dstReleaseValue, + uint32_t srcOffset, + uint32_t dstOffset, + uint32_t count); +typedef DVPStatus (DVPAPIENTRY * PFNDVPIMPORTSYNCOBJECT)(DVPSyncObjectDesc *desc, + DVPSyncObjectHandle *syncObject); +typedef DVPStatus (DVPAPIENTRY * PFNDVPFREESYNCOBJECT)(DVPSyncObjectHandle syncObject); +typedef DVPStatus (DVPAPIENTRY * PFNDVPGETREQUIREDCONSTANTSGLCTX)(uint32_t *bufferAddrAlignment, + uint32_t *bufferGPUStrideAlignment, + uint32_t *semaphoreAddrAlignment, + uint32_t *semaphoreAllocSize, + uint32_t *semaphorePayloadOffset, + uint32_t *semaphorePayloadSize); +typedef DVPStatus (DVPAPIENTRY * PFNDVPBINDTOGLCTX)(DVPBufferHandle hBuf); +typedef DVPStatus (DVPAPIENTRY * PFNDVPUNBINDFROMGLCTX)(DVPBufferHandle hBuf); +typedef DVPStatus (DVPAPIENTRY * PFNDVPMAPBUFFERENDAPI)(DVPBufferHandle gpuBufferHandle); +typedef DVPStatus (DVPAPIENTRY * PFNDVPMAPBUFFERWAITDVP)(DVPBufferHandle gpuBufferHandle); +typedef DVPStatus (DVPAPIENTRY * PFNDVPMAPBUFFERENDDVP)(DVPBufferHandle gpuBufferHandle); +typedef DVPStatus (DVPAPIENTRY * PFNDVPMAPBUFFERWAITAPI)(DVPBufferHandle gpuBufferHandle); +typedef DVPStatus (DVPAPIENTRY * PFNDVPCREATEGPUTEXTUREGL)(GLuint texID, + DVPBufferHandle *bufferHandle); + +// Flags supplied to the dvpInit* functions: +// +// DVP_DEVICE_FLAGS_SHARE_APP_CONTEXT is only supported for OpenGL +// contexts and is the only supported flag for CUDA. It allows for +// certain cases to be optimized by sharing the context +// of the application for the DVP operations. This removes the +// need to do certain synchronizations. See issue 5 for parallel +// issues. When used, the app's GL context must be current for all calls +// to the DVP library. +// the DVP library. +#define DVP_DEVICE_FLAGS_SHARE_APP_CONTEXT 0x000000001 + +//------------------------------------------------------------------------ +// Function: dvpInitGLContext +// +// To be called before any DVP resources are allocated. +// This call allows for specification of flags that may +// change the way DVP operations are performed. See above +// for the list of flags. +// +// The OpenGL context must be current at time of call. +// +// Parameters: flags[IN] - Buffer description structure +// +// Returns: DVP_STATUS_OK +// DVP_STATUS_INVALID_PARAMETER +// DVP_STATUS_ERROR +//------------------------------------------------------------------------ +extern DVPStatus dvpInitGLContext(uint32_t flags); + +//------------------------------------------------------------------------ +// Function: dvpCloseGLContext +// +// Function to be called when app closes to allow freeing +// of any DVP library allocated resources. +// +// The OpenGL context must be current at time of call. +// +// Parameters: none +// +// Returns: DVP_STATUS_OK +// DVP_STATUS_INVALID_PARAMETER +// DVP_STATUS_ERROR +//------------------------------------------------------------------------ +extern DVPStatus dvpCloseGLContext(); + +//------------------------------------------------------------------------ +// Function: dvpGetLibrayVersion +// +// Description: Returns the current version of the library +// +// Parameters: major[OUT] - returned major version +// minor[OUT] - returned minor version +// +// Returns: DVP_STATUS_OK +//------------------------------------------------------------------------ +extern DVPStatus dvpGetLibrayVersion(uint32_t *major, uint32_t *minor); + +//------------------------------------------------------------------------ +// Function: dvpBegin +// +// Description: dvpBegin must be called before any combination of DVP +// function calls dvpMemCpy*, dvpMapBufferWaitDVP, +// dvpSyncObjClientWait*, and dvpMapBufferEndDVP. After +// the last of these functions has been called is dvpEnd +// must be called. This allows for more efficient batched +// DVP operations. +// +// Parameters: none +// +// Returns: DVP_STATUS_OK +// DVP_STATUS_ERROR +//------------------------------------------------------------------------ +#define dvpBegin DVPAPI_GET_FUN(__dvpBegin) + +//------------------------------------------------------------------------ +// Function: dvpEnd +// +// Description: dvpEnd signals the end of a batch of DVP function calls +// that began with dvpBegin +// +// Parameters: none +// +// Returns: DVP_STATUS_OK +// DVP_STATUS_ERROR +//------------------------------------------------------------------------ +#define dvpEnd DVPAPI_GET_FUN(__dvpEnd) + + +//------------------------------------------------------------------------ +// Function: dvpCreateBuffer +// +// Description: Create a DVP buffer using system memory, wrapping a user +// passed pointer. The pointer must be aligned +// to values returned by dvpGetRequiredAlignments* +// +// Parameters: desc[IN] - Buffer description structure +// hBuf[OUT] - DVP Buffer handle +// +// Returns: DVP_STATUS_OK +// DVP_STATUS_INVALID_PARAMETER +// DVP_STATUS_ERROR +//------------------------------------------------------------------------ +#define dvpCreateBuffer DVPAPI_GET_FUN(__dvpCreateBuffer) + + +//------------------------------------------------------------------------ +// Function: dvpDestroyBuffer +// +// Description: Destroy a previously created DVP buffer. +// +// Parameters: hBuf[IN] - DVP Buffer handle +// +// Returns: DVP_STATUS_OK +// DVP_STATUS_INVALID_PARAMETER +// DVP_STATUS_ERROR +//------------------------------------------------------------------------ +#define dvpDestroyBuffer DVPAPI_GET_FUN(__dvpDestroyBuffer) + +//------------------------------------------------------------------------ +// Function: dvpFreeBuffer +// +// Description: dvpFreeBuffer frees the DVP buffer reference +// +// Parameters: gpuBufferHandle[IN] - DVP Buffer handle +// +// Returns: DVP_STATUS_OK +// DVP_STATUS_INVALID_PARAMETER +// DVP_STATUS_ERROR +//------------------------------------------------------------------------ +#define dvpFreeBuffer DVPAPI_GET_FUN(__dvpFreeBuffer) + +//------------------------------------------------------------------------ +// Function: dvpMemcpyLined +// +// Description: dvpMemcpyLined provides buffer copies between a +// DVP sysmem buffer and a graphics API texture (as opposed to +// a buffer type). Other buffer types (such +// as graphics API buffers) return DVP_STATUS_INVALID_PARAMETER. +// +// In addition, see "dvpMemcpy* general comments" above. +// +// Parameters: srcBuffer[IN] - src buffer handle +// srcSync[IN] - sync to acquire on before transfer +// srcAcquireValue[IN] - value to acquire on before transfer +// timeout[IN] - time out value in nanoseconds. +// dstBuffer[IN] - src buffer handle +// dstSync[IN] - sync to release on transfer completion +// dstReleaseValue[IN] - value to release on completion +// startingLine[IN] - starting line of buffer +// numberOfLines[IN] - number of lines to copy +// +// Returns: DVP_STATUS_OK +// DVP_STATUS_INVALID_PARAMETER +// DVP_STATUS_ERROR +// +// GL state effected: The following GL state may be altered by this +// function (not relevant if no GL source or destination +// is used): +// -GL_PACK_SKIP_ROWS, GL_PACK_SKIP_PIXELS, +// GL_PACK_ROW_LENGTH +// -The buffer bound to GL_PIXEL_PACK_BUFFER +// -The current bound framebuffer (GL_FRAMEBUFFER_EXT) +// -GL_UNPACK_SKIP_ROWS, GL_UNPACK_SKIP_PIXELS, +// GL_UNPACK_ROW_LENGTH +// -The buffer bound to GL_PIXEL_UNPACK_BUFFER +// -The texture bound to GL_TEXTURE_2D +//------------------------------------------------------------------------ +#define dvpMemcpyLined DVPAPI_GET_FUN(__dvpMemcpyLined) + + +//------------------------------------------------------------------------ +// Function: dvpMemcpy +// +// Description: dvpMemcpy provides buffer copies between a +// DVP sysmem buffer and a graphics API pure buffer (as +// opposed to a texture type). Other buffer types (such +// as graphics API textures) return +// DVP_STATUS_INVALID_PARAMETER. +// +// The start address of the srcBuffer is given by srcOffset +// and the dstBuffer start address is given by dstOffset. +// +// In addition, see "dvpMemcpy* general comments" above. +// +// Parameters: srcBuffer[IN] - src buffer handle +// srcSync[IN] - sync to acquire on before transfer +// srcAcquireValue[IN] - value to acquire on before transfer +// timeout[IN] - time out value in nanoseconds. +// dstBuffer[IN] - src buffer handle +// dstSync[IN] - sync to release on completion +// dstReleaseValue[IN] - value to release on completion +// uint32_t srcOffset[IN] - byte offset of srcBuffer +// uint32_t dstOffset[IN] - byte offset of dstBuffer +// uint32_t count[IN] - number of bytes to copy +// +// Returns: DVP_STATUS_OK +// DVP_STATUS_INVALID_PARAMETER +// DVP_STATUS_ERROR +// +// GL state effected: The following GL state may be altered by this +// function (not relevant if no GL source or destination +// is used): +// - The buffer bound to GL_COPY_WRITE_BUFFER +// - The buffer bound to GL_COPY_READ_BUFFER +// +//------------------------------------------------------------------------ +#define dvpMemcpy DVPAPI_GET_FUN(__dvpMemcpy) + +//------------------------------------------------------------------------ +// Function: dvpImportSyncObject +// +// Description: dvpImportSyncObject creates a DVPSyncObject from the +// DVPSyncObjectDesc. Note that a sync object is not +// supported for copy operations targeting different APIs. +// This means, for example, it is illegal to call dvpMemCpy* +// for source or target GL texture with sync object A and +// then later use that same sync object in dvpMemCpy* +// operation for a source or target CUDA buffer. The same +// semaphore memory can still be used for two different sync +// objects. +// +// Parameters: desc[IN] - data describing the sync object +// syncObject[OUT] - handle to sync object +// +// Returns: DVP_STATUS_OK +// DVP_STATUS_INVALID_PARAMETER +// DVP_STATUS_ERROR +//------------------------------------------------------------------------ +#define dvpImportSyncObject DVPAPI_GET_FUN(__dvpImportSyncObject) + +//------------------------------------------------------------------------ +// Function: dvpFreeSyncObject +// +// Description: dvpFreeSyncObject waits for any outstanding releases on +// this sync object before freeing the resources allocated for +// the specified sync object. The application must make sure +// any outstanding acquire operations have already been +// completed. +// +// If OpenGL is being used and the app's GL context is being +// shared (via the DVP_DEVICE_FLAGS_SHARE_APP_CONTEXT flag), +// then dvpFreeSyncObject needs to be called while each context, +// on which the sync object was used, is current. If +// DVP_DEVICE_FLAGS_SHARE_APP_CONTEXT is used and there are out +// standing contexts from which this sync object must be free'd +// then dvpFreeSyncObject will return DVP_STATUS_SYNC_STILL_BOUND. +// +// Parameters: syncObject[IN] - handle to sync object to be free'd +// +// Returns: DVP_STATUS_OK +// DVP_STATUS_INVALID_PARAMETER +// DVP_STATUS_ERROR +// DVP_STATUS_SYNC_STILL_BOUND +//------------------------------------------------------------------------ +#define dvpFreeSyncObject DVPAPI_GET_FUN(__dvpFreeSyncObject) + + +//------------------------------------------------------------------------ +// Function: dvpMapBufferEndAPI +// +// Description: Tells DVP to setup a signal for this buffer in the +// callers API context or device. The signal follows all +// previous API operations up to this point and, thus, +// allows subsequent DVP calls to know when then this buffer +// is ready for use within the DVP library. This function +// would be followed by a call to dvpMapBufferWaitDVP to +// synchronize rendering in the API stream and the DVP +// stream. +// +// If OpenGL or CUDA is used, the OpenGL/CUDA context +// must be current at time of call. +// +// The use of dvpMapBufferEndAPI is NOT recommended for +// CUDA synchronisation, as it is more optimal to use a +// applcation CUDA stream in conjunction with +// dvpMapBufferEndCUDAStream. This allows the driver to +// do optimisations, such as parllelise the copy operations +// and compute. +// +// This must be called outside the dvpBegin/dvpEnd pair. In +// addition, this call is not thread safe and must be called +// from or fenced against the rendering thread associated with +// the context or device. +// +// Parameters: gpuBufferHandle[IN] - buffer to track +// +// Returns: DVP_STATUS_OK +// DVP_STATUS_INVALID_PARAMETER +// DVP_STATUS_ERROR +// DVP_STATUS_UNSIGNALED - returned if the API is +// unable to place a signal in the API context queue +//------------------------------------------------------------------------ +#define dvpMapBufferEndAPI DVPAPI_GET_FUN(__dvpMapBufferEndAPI) + +//------------------------------------------------------------------------ +// Function: dvpMapBufferEndAPI +// +// Description: Tells DVP to setup a signal for this buffer in the +// callers API context or device. The signal follows all +// previous API operations up to this point and, thus, +// allows subsequent DVP calls to know when then this buffer +// is ready for use within the DVP library. This function +// would be followed by a call to dvpMapBufferWaitDVP to +// synchronize rendering in the API stream and the DVP +// stream. +// +// If OpenGL or CUDA is used, the OpenGL/CUDA context +// must be current at time of call. +// +// The use of dvpMapBufferEndAPI is NOT recommended for +// CUDA synchronisation, as it is more optimal to use a +// applcation CUDA stream in conjunction with +// dvpMapBufferEndCUDAStream. This allows the driver to +// do optimisations, such as parllelise the copy operations +// and compute. +// +// This must be called outside the dvpBegin/dvpEnd pair. In +// addition, this call is not thread safe and must be called +// from or fenced against the rendering thread associated with +// the context or device. +// +// Parameters: gpuBufferHandle[IN] - buffer to track +// +// Returns: DVP_STATUS_OK +// DVP_STATUS_INVALID_PARAMETER +// DVP_STATUS_ERROR +// DVP_STATUS_UNSIGNALED - returned if the API is +// unable to place a signal in the API context queue +//------------------------------------------------------------------------ +#define dvpMapBufferEndAPI DVPAPI_GET_FUN(__dvpMapBufferEndAPI) + +//------------------------------------------------------------------------ +// Function: dvpMapBufferWaitDVP +// +// Description: Tells DVP to make the DVP stream wait for a previous +// signal triggered by a dvpMapBufferEndAPI call. +// +// This must be called inside the dvpBegin/dvpEnd pair. +// +// Parameters: gpuBufferHandle[IN] - buffer to track +// +// Returns: DVP_STATUS_OK +// DVP_STATUS_INVALID_PARAMETER +// DVP_STATUS_ERROR +//------------------------------------------------------------------------ +#define dvpMapBufferWaitDVP DVPAPI_GET_FUN(__dvpMapBufferWaitDVP) + +//------------------------------------------------------------------------ +// Function: dvpMapBufferEndDVP +// +// Description: Tells DVP to setup a signal for this buffer after +// DVP operations are complete. The signal allows +// the API to know when then this buffer is +// ready for use within a API stream. This function would +// be followed by a call to dvpMapBufferWaitAPI to +// synchronize copies in the DVP stream and the API +// rendering stream. +// +// This must be called inside the dvpBegin/dvpEnd pair. +// +// Parameters: gpuBufferHandle[IN] - buffer to track +// +// Returns: DVP_STATUS_OK +// DVP_STATUS_INVALID_PARAMETER +// DVP_STATUS_ERROR +//------------------------------------------------------------------------ +#define dvpMapBufferEndDVP DVPAPI_GET_FUN(__dvpMapBufferEndDVP) + +//------------------------------------------------------------------------ +// Function: dvpMapBufferWaitAPI +// +// Description: Tells DVP to make the current API context or device to +// wait for a previous signal triggered by a +// dvpMapBufferEndDVP call. +// +// The use of dvpMapBufferWaitCUDAStream is NOT recommended for +// CUDA synchronisation, as it is more optimal to use a +// applcation CUDA stream in conjunction with +// dvpMapBufferEndCUDAStream. This allows the driver to +// do optimisations, such as parllelise the copy operations +// and compute. +// +// If OpenGL or CUDA is used, the OpenGL/CUDA context +// must be current at time of call. +// +// This must be called outside the dvpBegin/dvpEnd pair. In +// addition, this call is not thread safe and must be called +// from or fenced against the rendering thread associated with +// the context or device. +// +// Parameters: gpuBufferHandle[IN] - buffer to track +// +// Returns: DVP_STATUS_OK +// DVP_STATUS_INVALID_PARAMETER +// DVP_STATUS_ERROR +//------------------------------------------------------------------------ +#define dvpMapBufferWaitAPI DVPAPI_GET_FUN(__dvpMapBufferWaitAPI) + +//------------------------------------------------------------------------ +// If the multiple GL contexts used in the application access the same +// sysmem buffers, then application must create those GL contexts with +// display list shared. +//------------------------------------------------------------------------ +#define dvpBindToGLCtx DVPAPI_GET_FUN(__dvpBindToGLCtx) +#define dvpGetRequiredConstantsGLCtx DVPAPI_GET_FUN(__dvpGetRequiredConstantsGLCtx) +#define dvpCreateGPUTextureGL DVPAPI_GET_FUN(__dvpCreateGPUTextureGL) +#define dvpUnbindFromGLCtx DVPAPI_GET_FUN(__dvpUnbindFromGLCtx) + + +DVPAPI PFNDVPBEGIN __dvpBegin; +DVPAPI PFNDVPEND __dvpEnd; +DVPAPI PFNDVPCREATEBUFFER __dvpCreateBuffer; +DVPAPI PFNDVPDESTROYBUFFER __dvpDestroyBuffer; +DVPAPI PFNDVPFREEBUFFER __dvpFreeBuffer; +DVPAPI PFNDVPMEMCPYLINED __dvpMemcpyLined; +DVPAPI PFNDVPMEMCPY __dvpMemcpy; +DVPAPI PFNDVPIMPORTSYNCOBJECT __dvpImportSyncObject; +DVPAPI PFNDVPFREESYNCOBJECT __dvpFreeSyncObject; +DVPAPI PFNDVPMAPBUFFERENDAPI __dvpMapBufferEndAPI; +DVPAPI PFNDVPMAPBUFFERWAITDVP __dvpMapBufferWaitDVP; +DVPAPI PFNDVPMAPBUFFERENDDVP __dvpMapBufferEndDVP; +DVPAPI PFNDVPMAPBUFFERWAITAPI __dvpMapBufferWaitAPI; + + +//------------------------------------------------------------------------ +// If the multiple GL contexts used in the application access the same +// sysmem buffers, then application must create those GL contexts with +// display list shared. +//------------------------------------------------------------------------ +DVPAPI PFNDVPBINDTOGLCTX __dvpBindToGLCtx; +DVPAPI PFNDVPGETREQUIREDCONSTANTSGLCTX __dvpGetRequiredConstantsGLCtx; +DVPAPI PFNDVPCREATEGPUTEXTUREGL __dvpCreateGPUTextureGL; +DVPAPI PFNDVPUNBINDFROMGLCTX __dvpUnbindFromGLCtx; + +#define DVPAPI_GET_FUN(x) x + +#endif // WIN32 + +#endif // __DVPAPI_H__ + diff --git a/intern/moto/include/MT_Matrix4x4.h b/intern/moto/include/MT_Matrix4x4.h index 045cc3b8361..2ecac81ea6f 100644 --- a/intern/moto/include/MT_Matrix4x4.h +++ b/intern/moto/include/MT_Matrix4x4.h @@ -144,6 +144,16 @@ public: } /** + * Scale the rows of this matrix with x, y, z, w respectively. + */ + void tscale(MT_Scalar x, MT_Scalar y, MT_Scalar z, MT_Scalar w) { + m_el[0][0] *= x; m_el[1][0] *= y; m_el[2][0] *= z; m_el[3][0] *= w; + m_el[0][1] *= x; m_el[1][1] *= y; m_el[2][1] *= z; m_el[3][1] *= w; + m_el[0][2] *= x; m_el[1][2] *= y; m_el[2][2] *= z; m_el[3][2] *= w; + m_el[0][3] *= x; m_el[1][3] *= y; m_el[2][3] *= z; m_el[3][3] *= w; + } + + /** * Return a column-scaled version of this matrix. */ MT_Matrix4x4 scaled(MT_Scalar x, MT_Scalar y, MT_Scalar z, MT_Scalar w) const { diff --git a/release/datafiles/LICENSE-droidsans.ttf.txt b/release/datafiles/LICENSE-droidsans.ttf.txt index cf6f53e8644..6711ad37338 100644 --- a/release/datafiles/LICENSE-droidsans.ttf.txt +++ b/release/datafiles/LICENSE-droidsans.ttf.txt @@ -52,6 +52,8 @@ License: GPL-2.1+ (8) tlwg Loma (Thaï) Copyright: 2003 National Electronics and Computer Technology Center +Modified to fix and/or adapt kerning to Blender basic layout engine by Hồ Châu in 2016. + License: GPL-2+ with Font exception See Appendices C. diff --git a/release/datafiles/fonts/droidsans.ttf.gz b/release/datafiles/fonts/droidsans.ttf.gz Binary files differindex 5b942162141..7940852f637 100644 --- a/release/datafiles/fonts/droidsans.ttf.gz +++ b/release/datafiles/fonts/droidsans.ttf.gz diff --git a/release/scripts/modules/bl_i18n_utils/utils_spell_check.py b/release/scripts/modules/bl_i18n_utils/utils_spell_check.py index 636b6b0f46b..98a117e95a6 100644 --- a/release/scripts/modules/bl_i18n_utils/utils_spell_check.py +++ b/release/scripts/modules/bl_i18n_utils/utils_spell_check.py @@ -58,7 +58,6 @@ class SpellChecker: "vertices", # Merged words - #~ "addon", "addons", "antialiasing", "arcsine", "arccosine", "arctangent", "autoclip", @@ -127,6 +126,7 @@ class SpellChecker: "multipaint", "multires", "multiresolution", "multisampling", + "multiscatter", "multitexture", "multithreaded", "multiuser", @@ -530,6 +530,7 @@ class SpellChecker: "futura", "fx", "gfx", + "ggx", "gl", "glsl", "gpl", diff --git a/release/scripts/modules/bpy/utils/__init__.py b/release/scripts/modules/bpy/utils/__init__.py index 5e2769c12d3..66974dedc24 100644 --- a/release/scripts/modules/bpy/utils/__init__.py +++ b/release/scripts/modules/bpy/utils/__init__.py @@ -52,15 +52,15 @@ __all__ = ( ) from _bpy import ( + _utils_units as units, + blend_paths, escape_identifier, register_class, - unregister_class, - blend_paths, resource_path, + script_paths as _bpy_script_paths, + unregister_class, + user_resource as _user_resource, ) -from _bpy import script_paths as _bpy_script_paths -from _bpy import user_resource as _user_resource -from _bpy import _utils_units as units import bpy as _bpy import os as _os @@ -641,11 +641,10 @@ def unregister_module(module, verbose=False): # we start with the built-in default mapping def _blender_default_map(): - import sys import rna_manual_reference as ref_mod ret = (ref_mod.url_manual_prefix, ref_mod.url_manual_mapping) # avoid storing in memory - del sys.modules["rna_manual_reference"] + del _sys.modules["rna_manual_reference"] return ret # hooks for doc lookups diff --git a/release/scripts/modules/bpy/utils/previews.py b/release/scripts/modules/bpy/utils/previews.py index c67c523ea72..568116b027c 100644 --- a/release/scripts/modules/bpy/utils/previews.py +++ b/release/scripts/modules/bpy/utils/previews.py @@ -30,7 +30,7 @@ This allows scripts to generate their own previews, and use them as icons in UI Custom Icon Example ------------------- -.. literalinclude:: ../../../release/scripts/templates_py/ui_previews_custom_icon.py +.. literalinclude:: __/__/__/release/scripts/templates_py/ui_previews_custom_icon.py """ __all__ = ( diff --git a/release/scripts/modules/bpy_extras/keyconfig_utils.py b/release/scripts/modules/bpy_extras/keyconfig_utils.py index 6246e4489e1..534dabf3d43 100644 --- a/release/scripts/modules/bpy_extras/keyconfig_utils.py +++ b/release/scripts/modules/bpy_extras/keyconfig_utils.py @@ -76,7 +76,9 @@ KM_HIERARCHY = [ ('Graph Editor', 'GRAPH_EDITOR', 'WINDOW', [ ('Graph Editor Generic', 'GRAPH_EDITOR', 'WINDOW', []), ]), - ('Dopesheet', 'DOPESHEET_EDITOR', 'WINDOW', []), + ('Dopesheet', 'DOPESHEET_EDITOR', 'WINDOW', [ + ('Dopesheet Generic', 'DOPESHEET_EDITOR', 'WINDOW', []), + ]), ('NLA Editor', 'NLA_EDITOR', 'WINDOW', [ ('NLA Channels', 'NLA_EDITOR', 'WINDOW', []), ('NLA Generic', 'NLA_EDITOR', 'WINDOW', []), diff --git a/release/scripts/modules/bpy_extras/view3d_utils.py b/release/scripts/modules/bpy_extras/view3d_utils.py index 4aa06262970..5f83cdcfa0d 100644 --- a/release/scripts/modules/bpy_extras/view3d_utils.py +++ b/release/scripts/modules/bpy_extras/view3d_utils.py @@ -101,7 +101,7 @@ def region_2d_to_origin_3d(region, rv3d, coord, clamp=None): persinv = persmat.inverted() origin_start = ((persinv.col[0].xyz * dx) + (persinv.col[1].xyz * dy) + - viewinv.translation) + persinv.translation) if clamp != 0.0: if rv3d.view_perspective != 'CAMERA': diff --git a/release/scripts/startup/bl_operators/file.py b/release/scripts/startup/bl_operators/file.py index 64cc0aeddb3..51e079164b6 100644 --- a/release/scripts/startup/bl_operators/file.py +++ b/release/scripts/startup/bl_operators/file.py @@ -97,13 +97,9 @@ class WM_OT_previews_batch_generate(Operator): return {'RUNNING_MODAL'} def execute(self, context): - if "subprocess" in locals(): - import imp - imp.reload(preview_render) - else: - import os - import subprocess - from bl_previews_utils import bl_previews_render as preview_render + import os + import subprocess + from bl_previews_utils import bl_previews_render as preview_render context.window_manager.progress_begin(0, len(self.files)) context.window_manager.progress_update(0) @@ -210,13 +206,9 @@ class WM_OT_previews_batch_clear(Operator): return {'RUNNING_MODAL'} def execute(self, context): - if "subprocess" in locals(): - import imp - imp.reload(preview_render) - else: - import os - import subprocess - from bl_previews_utils import bl_previews_render as preview_render + import os + import subprocess + from bl_previews_utils import bl_previews_render as preview_render context.window_manager.progress_begin(0, len(self.files)) context.window_manager.progress_update(0) diff --git a/release/scripts/startup/bl_operators/wm.py b/release/scripts/startup/bl_operators/wm.py index 76d41d91b78..cc8921f1a8e 100644 --- a/release/scripts/startup/bl_operators/wm.py +++ b/release/scripts/startup/bl_operators/wm.py @@ -1357,7 +1357,10 @@ class WM_OT_properties_add(Operator): return prop_new - prop = unique_name(item.keys()) + prop = unique_name( + {*item.keys(), + *type(item).bl_rna.properties.keys(), + }) item[prop] = 1.0 rna_idprop_ui_prop_update(item, prop) diff --git a/release/scripts/startup/bl_ui/properties_constraint.py b/release/scripts/startup/bl_ui/properties_constraint.py index 4ca2f773dcc..2a98303d00e 100644 --- a/release/scripts/startup/bl_ui/properties_constraint.py +++ b/release/scripts/startup/bl_ui/properties_constraint.py @@ -96,25 +96,25 @@ class ConstraintButtonsPanel: def CHILD_OF(self, context, layout, con): self.target_template(layout, con) - split = layout.split() - - col = split.column() - col.label(text="Location:") - col.prop(con, "use_location_x", text="X") - col.prop(con, "use_location_y", text="Y") - col.prop(con, "use_location_z", text="Z") - - col = split.column() - col.label(text="Rotation:") - col.prop(con, "use_rotation_x", text="X") - col.prop(con, "use_rotation_y", text="Y") - col.prop(con, "use_rotation_z", text="Z") - - col = split.column() - col.label(text="Scale:") - col.prop(con, "use_scale_x", text="X") - col.prop(con, "use_scale_y", text="Y") - col.prop(con, "use_scale_z", text="Z") + #split = layout.split() + + #col = split.column() + #col.label(text="Location:") + #col.prop(con, "use_location_x", text="X") + #col.prop(con, "use_location_y", text="Y") + #col.prop(con, "use_location_z", text="Z") + + #col = split.column() + #col.label(text="Rotation:") + #col.prop(con, "use_rotation_x", text="X") + #col.prop(con, "use_rotation_y", text="Y") + #col.prop(con, "use_rotation_z", text="Z") + + #col = split.column() + #col.label(text="Scale:") + #col.prop(con, "use_scale_x", text="X") + #col.prop(con, "use_scale_y", text="Y") + #col.prop(con, "use_scale_z", text="Z") row = layout.row() row.operator("constraint.childof_set_inverse") diff --git a/release/scripts/startup/bl_ui/properties_data_curve.py b/release/scripts/startup/bl_ui/properties_data_curve.py index 81ecd2e8db5..af8431ba1dc 100644 --- a/release/scripts/startup/bl_ui/properties_data_curve.py +++ b/release/scripts/startup/bl_ui/properties_data_curve.py @@ -370,8 +370,11 @@ class DATA_PT_paragraph(CurveButtonsPanelText, Panel): text = context.curve - layout.label(text="Align:") - layout.prop(text, "align", expand=True) + layout.label(text="Horizontal Alignment:") + layout.prop(text, "align_x", expand=True) + + layout.label(text="Vertical Alignment:") + layout.prop(text, "align_y", expand=True) split = layout.split() diff --git a/release/scripts/startup/bl_ui/properties_data_modifier.py b/release/scripts/startup/bl_ui/properties_data_modifier.py index aa03863a198..7863c075344 100644 --- a/release/scripts/startup/bl_ui/properties_data_modifier.py +++ b/release/scripts/startup/bl_ui/properties_data_modifier.py @@ -1418,6 +1418,7 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel): sub = row.row(align=True) sub.active = has_vgroup sub.prop(md, "invert_vertex_group", text="", icon='ARROW_LEFTRIGHT') + subcol.prop(md, "mix_limit") def CORRECTIVE_SMOOTH(self, layout, ob, md): is_bind = md.is_bind diff --git a/release/scripts/startup/bl_ui/properties_grease_pencil_common.py b/release/scripts/startup/bl_ui/properties_grease_pencil_common.py index a823789f2c3..ac412688fa1 100644 --- a/release/scripts/startup/bl_ui/properties_grease_pencil_common.py +++ b/release/scripts/startup/bl_ui/properties_grease_pencil_common.py @@ -63,6 +63,9 @@ class GreasePencilDrawingToolsPanel: def draw(self, context): layout = self.layout + is_3d_view = context.space_data.type == 'VIEW_3D' + is_clip_editor = context.space_data.type == 'CLIP_EDITOR' + col = layout.column(align=True) col.label(text="Draw:") @@ -85,9 +88,9 @@ class GreasePencilDrawingToolsPanel: col.separator() col.label("Data Source:") row = col.row(align=True) - if context.space_data.type == 'VIEW_3D': + if is_3d_view: row.prop(context.tool_settings, "grease_pencil_source", expand=True) - elif context.space_data.type == 'CLIP_EDITOR': + elif is_clip_editor: row.prop(context.space_data, "grease_pencil_source", expand=True) col.separator() @@ -97,19 +100,19 @@ class GreasePencilDrawingToolsPanel: gpd = context.gpencil_data - if gpd: + if gpd and not is_3d_view: layout.separator() layout.separator() col = layout.column(align=True) col.prop(gpd, "use_stroke_edit_mode", text="Enable Editing", icon='EDIT', toggle=True) - if context.space_data.type == 'VIEW_3D': + if is_3d_view: col.separator() col.separator() col.label(text="Tools:") - col.operator("gpencil.convert", text="Convert...") + col.operator_menu_enum("gpencil.convert", text="Convert to Geometry...", property="type") col.operator("view3d.ruler") @@ -133,20 +136,23 @@ class GreasePencilStrokeEditPanel: def draw(self, context): layout = self.layout - layout.label(text="Select:") - col = layout.column(align=True) - col.operator("gpencil.select_all", text="Select All") - col.operator("gpencil.select_border") - col.operator("gpencil.select_circle") + is_3d_view = context.space_data.type == 'VIEW_3D' - layout.separator() + if not is_3d_view: + layout.label(text="Select:") + col = layout.column(align=True) + col.operator("gpencil.select_all", text="Select All") + col.operator("gpencil.select_border") + col.operator("gpencil.select_circle") - col = layout.column(align=True) - col.operator("gpencil.select_linked") - col.operator("gpencil.select_more") - col.operator("gpencil.select_less") + layout.separator() - layout.separator() + col = layout.column(align=True) + col.operator("gpencil.select_linked") + col.operator("gpencil.select_more") + col.operator("gpencil.select_less") + + layout.separator() layout.label(text="Edit:") row = layout.row(align=True) @@ -160,12 +166,13 @@ class GreasePencilStrokeEditPanel: layout.separator() - col = layout.column(align=True) - col.operator("transform.translate") # icon='MAN_TRANS' - col.operator("transform.rotate") # icon='MAN_ROT' - col.operator("transform.resize", text="Scale") # icon='MAN_SCALE' + if not is_3d_view: + col = layout.column(align=True) + col.operator("transform.translate") # icon='MAN_TRANS' + col.operator("transform.rotate") # icon='MAN_ROT' + col.operator("transform.resize", text="Scale") # icon='MAN_SCALE' - layout.separator() + layout.separator() col = layout.column(align=True) col.operator("transform.bend", text="Bend") diff --git a/release/scripts/startup/bl_ui/properties_render.py b/release/scripts/startup/bl_ui/properties_render.py index 13e7265319b..4ea1c3a5cc7 100644 --- a/release/scripts/startup/bl_ui/properties_render.py +++ b/release/scripts/startup/bl_ui/properties_render.py @@ -248,6 +248,7 @@ class RENDER_PT_shading(RenderButtonsPanel, Panel): col = split.column() col.prop(rd, "use_raytrace", text="Ray Tracing") col.prop(rd, "alpha_mode", text="Alpha") + col.prop(rd, "use_world_space_shading", text="World Space Shading") class RENDER_PT_performance(RenderButtonsPanel, Panel): diff --git a/release/scripts/startup/bl_ui/space_clip.py b/release/scripts/startup/bl_ui/space_clip.py index e809ef9ffde..8bb3cf2814c 100644 --- a/release/scripts/startup/bl_ui/space_clip.py +++ b/release/scripts/startup/bl_ui/space_clip.py @@ -1186,8 +1186,8 @@ class CLIP_MT_view(Menu): layout.separator() layout.operator("screen.area_dupli") - layout.operator("screen.screen_full_area", text="Toggle Maximize Area") - layout.operator("screen.screen_full_area").use_hide_panels = True + layout.operator("screen.screen_full_area") + layout.operator("screen.screen_full_area", text="Toggle Fullscreen Area").use_hide_panels = True class CLIP_MT_clip(Menu): diff --git a/release/scripts/startup/bl_ui/space_console.py b/release/scripts/startup/bl_ui/space_console.py index 327fb94cb95..4266abc5ad7 100644 --- a/release/scripts/startup/bl_ui/space_console.py +++ b/release/scripts/startup/bl_ui/space_console.py @@ -70,8 +70,8 @@ class CONSOLE_MT_console(Menu): layout.separator() layout.operator("screen.area_dupli") - layout.operator("screen.screen_full_area", text="Toggle Maximize Area") - layout.operator("screen.screen_full_area").use_hide_panels = True + layout.operator("screen.screen_full_area") + layout.operator("screen.screen_full_area", text="Toggle Fullscreen Area").use_hide_panels = True class CONSOLE_MT_language(Menu): diff --git a/release/scripts/startup/bl_ui/space_dopesheet.py b/release/scripts/startup/bl_ui/space_dopesheet.py index 0eeba5be369..546c9c2808d 100644 --- a/release/scripts/startup/bl_ui/space_dopesheet.py +++ b/release/scripts/startup/bl_ui/space_dopesheet.py @@ -232,8 +232,8 @@ class DOPESHEET_MT_view(Menu): layout.separator() layout.operator("screen.area_dupli") - layout.operator("screen.screen_full_area", text="Toggle Maximize Area") - layout.operator("screen.screen_full_area").use_hide_panels = True + layout.operator("screen.screen_full_area") + layout.operator("screen.screen_full_area", text="Toggle Fullscreen Area").use_hide_panels = True class DOPESHEET_MT_select(Menu): @@ -250,6 +250,8 @@ class DOPESHEET_MT_select(Menu): layout.operator("action.select_border").axis_range = False layout.operator("action.select_border", text="Border Axis Range").axis_range = True + layout.operator("action.select_circle") + layout.separator() layout.operator("action.select_column", text="Columns on Selected Keys").mode = 'KEYS' layout.operator("action.select_column", text="Column on Current Frame").mode = 'CFRA' diff --git a/release/scripts/startup/bl_ui/space_graph.py b/release/scripts/startup/bl_ui/space_graph.py index 82497f11bb1..446df9e6e79 100644 --- a/release/scripts/startup/bl_ui/space_graph.py +++ b/release/scripts/startup/bl_ui/space_graph.py @@ -129,8 +129,8 @@ class GRAPH_MT_view(Menu): layout.separator() layout.operator("screen.area_dupli") - layout.operator("screen.screen_full_area", text="Toggle Maximize Area") - layout.operator("screen.screen_full_area").use_hide_panels = True + layout.operator("screen.screen_full_area") + layout.operator("screen.screen_full_area", text="Toggle Fullscreen Area").use_hide_panels = True class GRAPH_MT_select(Menu): @@ -154,6 +154,8 @@ class GRAPH_MT_select(Menu): props.axis_range = False props.include_handles = True + layout.operator("graph.select_circle") + layout.separator() layout.operator("graph.select_column", text="Columns on Selected Keys").mode = 'KEYS' layout.operator("graph.select_column", text="Column on Current Frame").mode = 'CFRA' diff --git a/release/scripts/startup/bl_ui/space_image.py b/release/scripts/startup/bl_ui/space_image.py index fbea07a317e..c191a4b5bdc 100644 --- a/release/scripts/startup/bl_ui/space_image.py +++ b/release/scripts/startup/bl_ui/space_image.py @@ -123,8 +123,8 @@ class IMAGE_MT_view(Menu): layout.separator() layout.operator("screen.area_dupli") - layout.operator("screen.screen_full_area", text="Toggle Maximize Area") - layout.operator("screen.screen_full_area").use_hide_panels = True + layout.operator("screen.screen_full_area") + layout.operator("screen.screen_full_area", text="Toggle Fullscreen Area").use_hide_panels = True class IMAGE_MT_select(Menu): diff --git a/release/scripts/startup/bl_ui/space_logic.py b/release/scripts/startup/bl_ui/space_logic.py index 48b54feba17..1b316a3eede 100644 --- a/release/scripts/startup/bl_ui/space_logic.py +++ b/release/scripts/startup/bl_ui/space_logic.py @@ -127,8 +127,8 @@ class LOGIC_MT_view(Menu): layout.separator() layout.operator("screen.area_dupli") - layout.operator("screen.screen_full_area", text="Toggle Maximize Area") - layout.operator("screen.screen_full_area").use_hide_panels = True + layout.operator("screen.screen_full_area") + layout.operator("screen.screen_full_area", text="Toggle Fullscreen Area").use_hide_panels = True if __name__ == "__main__": # only for live edit. bpy.utils.register_module(__name__) diff --git a/release/scripts/startup/bl_ui/space_nla.py b/release/scripts/startup/bl_ui/space_nla.py index 64d3b427260..f6f010e3760 100644 --- a/release/scripts/startup/bl_ui/space_nla.py +++ b/release/scripts/startup/bl_ui/space_nla.py @@ -90,8 +90,8 @@ class NLA_MT_view(Menu): layout.separator() layout.operator("screen.area_dupli") - layout.operator("screen.screen_full_area", text="Toggle Maximize Area") - layout.operator("screen.screen_full_area").use_hide_panels = True + layout.operator("screen.screen_full_area") + layout.operator("screen.screen_full_area", text="Toggle Fullscreen Area").use_hide_panels = True class NLA_MT_select(Menu): diff --git a/release/scripts/startup/bl_ui/space_node.py b/release/scripts/startup/bl_ui/space_node.py index 986edc7405b..ee342265f3d 100644 --- a/release/scripts/startup/bl_ui/space_node.py +++ b/release/scripts/startup/bl_ui/space_node.py @@ -192,8 +192,8 @@ class NODE_MT_view(Menu): layout.separator() layout.operator("screen.area_dupli") - layout.operator("screen.screen_full_area", text="Toggle Maximize Area") - layout.operator("screen.screen_full_area").use_hide_panels = True + layout.operator("screen.screen_full_area") + layout.operator("screen.screen_full_area", text="Toggle Fullscreen Area").use_hide_panels = True class NODE_MT_select(Menu): diff --git a/release/scripts/startup/bl_ui/space_outliner.py b/release/scripts/startup/bl_ui/space_outliner.py index 7b1dfb9579a..708db2eec8d 100644 --- a/release/scripts/startup/bl_ui/space_outliner.py +++ b/release/scripts/startup/bl_ui/space_outliner.py @@ -99,8 +99,8 @@ class OUTLINER_MT_view(Menu): layout.separator() layout.operator("screen.area_dupli") - layout.operator("screen.screen_full_area", text="Toggle Maximize Area") - layout.operator("screen.screen_full_area").use_hide_panels = True + layout.operator("screen.screen_full_area") + layout.operator("screen.screen_full_area", text="Toggle Fullscreen Area").use_hide_panels = True class OUTLINER_MT_search(Menu): diff --git a/release/scripts/startup/bl_ui/space_sequencer.py b/release/scripts/startup/bl_ui/space_sequencer.py index 65fd0a43619..539ee7a6af4 100644 --- a/release/scripts/startup/bl_ui/space_sequencer.py +++ b/release/scripts/startup/bl_ui/space_sequencer.py @@ -221,8 +221,8 @@ class SEQUENCER_MT_view(Menu): layout.separator() layout.operator("screen.area_dupli") - layout.operator("screen.screen_full_area", text="Toggle Maximize Area") - layout.operator("screen.screen_full_area").use_hide_panels = True + layout.operator("screen.screen_full_area") + layout.operator("screen.screen_full_area", text="Toggle Fullscreen Area").use_hide_panels = True class SEQUENCER_MT_select(Menu): diff --git a/release/scripts/startup/bl_ui/space_text.py b/release/scripts/startup/bl_ui/space_text.py index 5eb4e333130..1fd10575e07 100644 --- a/release/scripts/startup/bl_ui/space_text.py +++ b/release/scripts/startup/bl_ui/space_text.py @@ -181,8 +181,8 @@ class TEXT_MT_view(Menu): layout.separator() layout.operator("screen.area_dupli") - layout.operator("screen.screen_full_area", text="Toggle Maximize Area") - layout.operator("screen.screen_full_area").use_hide_panels = True + layout.operator("screen.screen_full_area") + layout.operator("screen.screen_full_area", text="Toggle Fullscreen Area").use_hide_panels = True class TEXT_MT_text(Menu): diff --git a/release/scripts/startup/bl_ui/space_time.py b/release/scripts/startup/bl_ui/space_time.py index 5b0075b4147..508e62e4f56 100644 --- a/release/scripts/startup/bl_ui/space_time.py +++ b/release/scripts/startup/bl_ui/space_time.py @@ -152,8 +152,8 @@ class TIME_MT_view(Menu): layout.separator() layout.operator("screen.area_dupli") - layout.operator("screen.screen_full_area", text="Toggle Maximize Area") - layout.operator("screen.screen_full_area").use_hide_panels = True + layout.operator("screen.screen_full_area") + layout.operator("screen.screen_full_area", text="Toggle Fullscreen Area").use_hide_panels = True class TIME_MT_cache(Menu): diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py index 6f9ae98cc71..bfa69c94601 100644 --- a/release/scripts/startup/bl_ui/space_view3d.py +++ b/release/scripts/startup/bl_ui/space_view3d.py @@ -81,7 +81,20 @@ class VIEW3D_HT_header(Header): row.prop(toolsettings, "proportional_edit_falloff", icon_only=True) # Snap - if not obj or mode not in {'SCULPT', 'VERTEX_PAINT', 'WEIGHT_PAINT', 'TEXTURE_PAINT'}: + show_snap = False + if obj is None: + show_snap = True + else: + if mode not in {'SCULPT', 'VERTEX_PAINT', 'WEIGHT_PAINT', 'TEXTURE_PAINT'}: + show_snap = True + else: + paint_settings = UnifiedPaintPanel.paint_settings(context) + if paint_settings: + brush = paint_settings.brush + if brush and brush.stroke_method == 'CURVE': + show_snap = True + + if show_snap: snap_element = toolsettings.snap_element row = layout.row(align=True) row.prop(toolsettings, "use_snap", text="") @@ -458,8 +471,8 @@ class VIEW3D_MT_view(Menu): layout.operator("screen.area_dupli") layout.operator("screen.region_quadview") - layout.operator("screen.screen_full_area", text="Toggle Maximize Area") - layout.operator("screen.screen_full_area").use_hide_panels = True + layout.operator("screen.screen_full_area") + layout.operator("screen.screen_full_area", text="Toggle Fullscreen Area").use_hide_panels = True class VIEW3D_MT_view_navigation(Menu): @@ -1726,6 +1739,13 @@ class VIEW3D_MT_paint_vertex(Menu): layout.operator("paint.vertex_color_smooth") layout.operator("paint.vertex_color_dirt") + layout.separator() + + layout.operator("paint.vertex_color_invert", text="Invert") + layout.operator("paint.vertex_color_levels", text="Levels") + layout.operator("paint.vertex_color_hsv", text="Hue Saturation Value") + layout.operator("paint.vertex_color_brightness_contrast", text="Bright/Contrast") + class VIEW3D_MT_hook(Menu): bl_label = "Hooks" @@ -2617,7 +2637,7 @@ class VIEW3D_MT_edit_gpencil_delete(Menu): layout.separator() - layout.operator("gpencil.active_frame_delete") + layout.operator("gpencil.active_frames_delete_all") # Edit Curve diff --git a/release/scripts/startup/bl_ui/space_view3d_toolbar.py b/release/scripts/startup/bl_ui/space_view3d_toolbar.py index 49c7600c055..ca1ab4c37dd 100644 --- a/release/scripts/startup/bl_ui/space_view3d_toolbar.py +++ b/release/scripts/startup/bl_ui/space_view3d_toolbar.py @@ -1532,6 +1532,15 @@ class VIEW3D_PT_sculpt_dyntopo(Panel, View3DPaintPanel): def poll(cls, context): return (context.sculpt_object and context.tool_settings.sculpt) + def draw_header(self, context): + layout = self.layout + layout.operator( + "sculpt.dynamic_topology_toggle", + icon='CHECKBOX_HLT' if context.sculpt_object.use_dynamic_topology_sculpting else 'CHECKBOX_DEHLT', + text="", + emboss=False, + ) + def draw(self, context): layout = self.layout @@ -1540,11 +1549,6 @@ class VIEW3D_PT_sculpt_dyntopo(Panel, View3DPaintPanel): settings = self.paint_settings(context) brush = settings.brush - if context.sculpt_object.use_dynamic_topology_sculpting: - layout.operator("sculpt.dynamic_topology_toggle", icon='X', text="Disable Dyntopo") - else: - layout.operator("sculpt.dynamic_topology_toggle", icon='SCULPT_DYNTOPO', text="Enable Dyntopo") - col = layout.column() col.active = context.sculpt_object.use_dynamic_topology_sculpting sub = col.column(align=True) diff --git a/release/scripts/templates_py/script_stub.py b/release/scripts/templates_py/external_script_stub.py index 5505ca64078..5505ca64078 100644 --- a/release/scripts/templates_py/script_stub.py +++ b/release/scripts/templates_py/external_script_stub.py diff --git a/source/blender/blenfont/intern/blf_glyph.c b/source/blender/blenfont/intern/blf_glyph.c index 41726e41176..aa7d539538b 100644 --- a/source/blender/blenfont/intern/blf_glyph.c +++ b/source/blender/blenfont/intern/blf_glyph.c @@ -55,6 +55,10 @@ #include "BIF_gl.h" #include "BLF_api.h" +#ifndef BLF_STANDALONE +#include "GPU_basic_shader.h" +#endif + #include "blf_internal_types.h" #include "blf_internal.h" @@ -179,6 +183,16 @@ static void blf_glyph_cache_texture(FontBLF *font, GlyphCacheBLF *gc) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); +#ifndef BLF_STANDALONE + /* needed since basic shader doesn't support alpha-only textures, + * while we could add support this is only used in a few places + * (an alternative could be to have a simple shader for BLF). */ + if (GLEW_ARB_texture_swizzle && GPU_basic_shader_use_glsl_get()) { + GLint swizzle_mask[] = {GL_ONE, GL_ONE, GL_ONE, GL_ALPHA}; + glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzle_mask); + } +#endif + glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA8, gc->p2_width, gc->p2_height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, NULL); } diff --git a/source/blender/blenkernel/BKE_DerivedMesh.h b/source/blender/blenkernel/BKE_DerivedMesh.h index 8ccc4a6eb0e..606488f85cc 100644 --- a/source/blender/blenkernel/BKE_DerivedMesh.h +++ b/source/blender/blenkernel/BKE_DerivedMesh.h @@ -694,7 +694,7 @@ DerivedMesh *mesh_create_derived_render( CustomDataMask dataMask); DerivedMesh *getEditDerivedBMesh( - struct BMEditMesh *em, struct Object *ob, + struct BMEditMesh *em, struct Object *ob, CustomDataMask data_mask, float (*vertexCos)[3]); DerivedMesh *mesh_create_derived_index_render( @@ -723,7 +723,7 @@ DerivedMesh *mesh_create_derived_physics( CustomDataMask dataMask); DerivedMesh *editbmesh_get_derived_base( - struct Object *, struct BMEditMesh *em); + struct Object *ob, struct BMEditMesh *em, CustomDataMask data_mask); DerivedMesh *editbmesh_get_derived_cage( struct Scene *scene, struct Object *, struct BMEditMesh *em, CustomDataMask dataMask); diff --git a/source/blender/blenkernel/BKE_animsys.h b/source/blender/blenkernel/BKE_animsys.h index 6524afff051..772e08589c1 100644 --- a/source/blender/blenkernel/BKE_animsys.h +++ b/source/blender/blenkernel/BKE_animsys.h @@ -62,7 +62,7 @@ struct AnimData *BKE_animdata_add_id(struct ID *id); bool BKE_animdata_set_action(struct ReportList *reports, struct ID *id, struct bAction *act); /* Free AnimData */ -void BKE_animdata_free(struct ID *id); +void BKE_animdata_free(struct ID *id, const bool do_id_user); /* Copy AnimData */ struct AnimData *BKE_animdata_copy(struct AnimData *adt, const bool do_action); diff --git a/source/blender/blenkernel/BKE_blender.h b/source/blender/blenkernel/BKE_blender.h index 8ce85c8e615..d2d9c763031 100644 --- a/source/blender/blenkernel/BKE_blender.h +++ b/source/blender/blenkernel/BKE_blender.h @@ -50,6 +50,11 @@ void BKE_blender_userdef_refresh(void); void BKE_blender_callback_test_break_set(void (*func)(void)); int BKE_blender_test_break(void); +/* Blenders' own atexit (avoids leaking) */ +void BKE_blender_atexit_register(void (*func)(void *user_data), void *user_data); +void BKE_blender_atexit_unregister(void (*func)(void *user_data), const void *user_data); +void BKE_blender_atexit(void); + #ifdef __cplusplus } #endif diff --git a/source/blender/blenkernel/BKE_blender_undo.h b/source/blender/blenkernel/BKE_blender_undo.h index cd18bd8db40..9547eeb9838 100644 --- a/source/blender/blenkernel/BKE_blender_undo.h +++ b/source/blender/blenkernel/BKE_blender_undo.h @@ -45,6 +45,8 @@ extern const char *BKE_undo_get_name(int nr, bool *r_active); extern bool BKE_undo_save_file(const char *filename); extern struct Main *BKE_undo_get_main(struct Scene **r_scene); +extern void BKE_undo_callback_wm_kill_jobs_set(void (*callback)(struct bContext *C)); + #ifdef __cplusplus } #endif diff --git a/source/blender/blenkernel/BKE_bvhutils.h b/source/blender/blenkernel/BKE_bvhutils.h index 7bd3ca88076..07db2217bac 100644 --- a/source/blender/blenkernel/BKE_bvhutils.h +++ b/source/blender/blenkernel/BKE_bvhutils.h @@ -43,9 +43,11 @@ struct BMEditMesh; struct MVert; struct MFace; +typedef struct LinkNode BVHCache; + /** -* struct that kepts basic information about a BVHTree build from a editmesh -*/ + * struct that kepts basic information about a BVHTree build from a editmesh + */ typedef struct BVHTreeFromEditMesh { struct BVHTree *tree; @@ -54,11 +56,13 @@ typedef struct BVHTreeFromEditMesh { BVHTree_RayCastCallback raycast_callback; BVHTree_NearestToRayCallback nearest_to_ray_callback; + struct BMEditMesh *em; + /* radius for raycast */ float sphere_radius; /* Private data */ - struct BMEditMesh *em; + bool cached; } BVHTreeFromEditMesh; @@ -118,6 +122,14 @@ BVHTree *bvhtree_from_mesh_verts_ex( const bool vert_allocated, const BLI_bitmap *mask, int verts_num_active, float epsilon, int tree_type, int axis); +BVHTree *bvhtree_from_editmesh_edges( + BVHTreeFromEditMesh *data, struct BMEditMesh *em, + float epsilon, int tree_type, int axis); +BVHTree *bvhtree_from_editmesh_edges_ex( + BVHTreeFromEditMesh *data, struct BMEditMesh *em, + const BLI_bitmap *edges_mask, int edges_num_active, + float epsilon, int tree_type, int axis); + BVHTree *bvhtree_from_mesh_edges( struct BVHTreeFromMesh *data, struct DerivedMesh *mesh, float epsilon, int tree_type, int axis); @@ -133,12 +145,12 @@ BVHTree *bvhtree_from_mesh_faces_ex( float epsilon, int tree_type, int axis); BVHTree *bvhtree_from_editmesh_looptri( - BVHTreeFromEditMesh *data, struct BMEditMesh *em, float epsilon, - int tree_type, int axis); + BVHTreeFromEditMesh *data, struct BMEditMesh *em, + float epsilon, int tree_type, int axis, BVHCache **bvhCache); BVHTree *bvhtree_from_editmesh_looptri_ex( BVHTreeFromEditMesh *data, struct BMEditMesh *em, const BLI_bitmap *mask, int looptri_num_active, - float epsilon, int tree_type, int axis); + float epsilon, int tree_type, int axis, BVHCache **bvhCache); BVHTree *bvhtree_from_mesh_looptri( struct BVHTreeFromMesh *data, struct DerivedMesh *mesh, float epsilon, int tree_type, int axis); @@ -165,9 +177,7 @@ float bvhtree_ray_tri_intersection( float bvhtree_sphereray_tri_intersection( const BVHTreeRay *ray, float radius, const float m_dist, const float v0[3], const float v1[3], const float v2[3]); -float nearest_point_in_tri_surface_squared( - const float v0[3], const float v1[3], const float v2[3], - const float p[3], int *v, int *e, float nearest[3]); + /** * BVHCache @@ -179,9 +189,10 @@ enum { BVHTREE_FROM_EDGES = 1, BVHTREE_FROM_FACES = 2, BVHTREE_FROM_LOOPTRI = 3, + + BVHTREE_FROM_EM_LOOPTRI = 4, }; -typedef struct LinkNode BVHCache; BVHTree *bvhcache_find(BVHCache *cache, int type); bool bvhcache_has_tree(const BVHCache *cache, const BVHTree *tree); @@ -189,4 +200,5 @@ void bvhcache_insert(BVHCache **cache_p, BVHTree *tree, int type); void bvhcache_init(BVHCache **cache_p); void bvhcache_free(BVHCache **cache_p); + #endif diff --git a/source/blender/blenkernel/BKE_curve.h b/source/blender/blenkernel/BKE_curve.h index 061270b8b41..659884d96a4 100644 --- a/source/blender/blenkernel/BKE_curve.h +++ b/source/blender/blenkernel/BKE_curve.h @@ -66,7 +66,6 @@ typedef struct CurveCache { #define CU_DO_2DFILL(cu) ((((cu)->flag & CU_3D) == 0) && (((cu)->flag & (CU_FRONT | CU_BACK)) != 0)) /* ** Curve ** */ -void BKE_curve_unlink(struct Curve *cu); void BKE_curve_free(struct Curve *cu); void BKE_curve_editfont_free(struct Curve *cu); void BKE_curve_init(struct Curve *cu); @@ -151,6 +150,16 @@ void BKE_nurb_minmax(struct Nurb *nu, bool use_radius, float min[3], float max[3 void BKE_nurb_makeFaces(struct Nurb *nu, float *coord_array, int rowstride, int resolu, int resolv); void BKE_nurb_makeCurve(struct Nurb *nu, float *coord_array, float *tilt_array, float *radius_array, float *weight_array, int resolu, int stride); +unsigned int BKE_curve_calc_coords_axis_len( + const unsigned int bezt_array_len, const unsigned int resolu, + const bool is_cyclic, const bool use_cyclic_duplicate_endpoint); +void BKE_curve_calc_coords_axis( + const struct BezTriple *bezt_array, const unsigned int bezt_array_len, const unsigned int resolu, + const bool is_cyclic, const bool use_cyclic_duplicate_endpoint, + /* array params */ + const unsigned int axis, const unsigned int stride, + float *r_points); + void BKE_nurb_knot_calc_u(struct Nurb *nu); void BKE_nurb_knot_calc_v(struct Nurb *nu); diff --git a/source/blender/blenkernel/BKE_displist.h b/source/blender/blenkernel/BKE_displist.h index 3b096773d96..9625f05192a 100644 --- a/source/blender/blenkernel/BKE_displist.h +++ b/source/blender/blenkernel/BKE_displist.h @@ -45,10 +45,14 @@ #define DL_VERTS 7 /* dl->flag */ -#define DL_CYCL_U 1 -#define DL_CYCL_V 2 -#define DL_FRONT_CURVE 4 -#define DL_BACK_CURVE 8 +enum { + /** U/V swapped here compared with #Nurb.flagu, #Nurb.flagv and #CU_NURB_CYCLIC */ + DL_CYCL_U = (1 << 0), + DL_CYCL_V = (1 << 1), + + DL_FRONT_CURVE = (1 << 2), + DL_BACK_CURVE = (1 << 3), +}; /* prototypes */ @@ -70,7 +74,7 @@ typedef struct DispList { int charidx; int totindex; /* indexed array drawing surfaces */ - unsigned int *bevelSplitFlag; + unsigned int *bevel_split; /* BLI_bitmap */ } DispList; void BKE_displist_copy(struct ListBase *lbn, struct ListBase *lb); diff --git a/source/blender/blenkernel/BKE_group.h b/source/blender/blenkernel/BKE_group.h index 9056e48cf50..ae6e52b613b 100644 --- a/source/blender/blenkernel/BKE_group.h +++ b/source/blender/blenkernel/BKE_group.h @@ -41,7 +41,6 @@ struct Object; struct Scene; void BKE_group_free(struct Group *group); -void BKE_group_unlink(struct Main *bmain, struct Group *group); struct Group *BKE_group_add(struct Main *bmain, const char *name); struct Group *BKE_group_copy(struct Group *group); bool BKE_group_object_add(struct Group *group, struct Object *ob, struct Scene *scene, struct Base *base); diff --git a/source/blender/blenkernel/BKE_library.h b/source/blender/blenkernel/BKE_library.h index 2215fbfbd7d..56f040ab260 100644 --- a/source/blender/blenkernel/BKE_library.h +++ b/source/blender/blenkernel/BKE_library.h @@ -60,13 +60,15 @@ void BKE_libblock_relink(struct ID *id); void BKE_libblock_rename(struct Main *bmain, struct ID *id, const char *name) ATTR_NONNULL(); void BLI_libblock_ensure_unique_name(struct Main *bmain, const char *name) ATTR_NONNULL(); +struct ID *BKE_libblock_find_name_ex(struct Main *bmain, const short type, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +struct ID *BKE_libblock_find_name(const short type, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); + +/* library_remap.c (keep here since they're general functions) */ void BKE_libblock_free(struct Main *bmain, void *idv) ATTR_NONNULL(); void BKE_libblock_free_ex(struct Main *bmain, void *idv, bool do_id_user) ATTR_NONNULL(); void BKE_libblock_free_us(struct Main *bmain, void *idv) ATTR_NONNULL(); void BKE_libblock_free_data(struct Main *bmain, struct ID *id) ATTR_NONNULL(); - -struct ID *BKE_libblock_find_name_ex(struct Main *bmain, const short type, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); -struct ID *BKE_libblock_find_name(const short type, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +void BKE_libblock_delete(struct Main *bmain, void *idv) ATTR_NONNULL(); void BKE_id_lib_local_paths(struct Main *bmain, struct Library *lib, struct ID *id); void id_lib_extern(struct ID *id); @@ -82,7 +84,6 @@ void id_fake_user_clear(struct ID *id); bool id_make_local(struct ID *id, bool test); bool id_single_user(struct bContext *C, struct ID *id, struct PointerRNA *ptr, struct PropertyRNA *prop); bool id_copy(struct ID *id, struct ID **newid, bool test); -bool id_unlink(struct ID *id, int test); void id_sort_by_name(struct ListBase *lb, struct ID *id); bool new_id(struct ListBase *lb, struct ID *id, const char *name); @@ -119,16 +120,11 @@ void BKE_main_lib_objects_recalc_all(struct Main *bmain); /* (MAX_ID_NAME - 2) + 3 */ void BKE_id_ui_prefix(char name[66 + 1], const struct ID *id); +void BKE_library_free(struct Library *lib); + void BKE_library_make_local( struct Main *bmain, const struct Library *lib, const bool untagged_only, const bool set_fake); -typedef void (*BKE_library_free_window_manager_cb)(struct bContext *, struct wmWindowManager *); -typedef void (*BKE_library_free_notifier_reference_cb)(const void *); -typedef void (*BKE_library_free_editor_id_reference_cb)(const struct ID *); - -void BKE_library_callback_free_window_manager_set(BKE_library_free_window_manager_cb func); -void BKE_library_callback_free_notifier_reference_set(BKE_library_free_notifier_reference_cb func); -void BKE_library_callback_free_editor_id_reference_set(BKE_library_free_editor_id_reference_cb func); /* use when "" is given to new_id() */ #define ID_FALLBACK_NAME N_("Untitled") diff --git a/source/blender/blenkernel/BKE_library_idmap.h b/source/blender/blenkernel/BKE_library_idmap.h new file mode 100644 index 00000000000..971586ea8b7 --- /dev/null +++ b/source/blender/blenkernel/BKE_library_idmap.h @@ -0,0 +1,50 @@ +/* + * ***** 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. + * + * ***** END GPL LICENSE BLOCK ***** + */ +#ifndef __BKE_LIBRARY_IDMAP_H__ +#define __BKE_LIBRARY_IDMAP_H__ + +/** \file BKE_library_idmap.h + * \ingroup bke + */ + +#include "BLI_compiler_attrs.h" + +struct ID; +struct Main; +struct IDNameLib_Map; + +struct IDNameLib_Map *BKE_main_idmap_create( + struct Main *bmain) + ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +void BKE_main_idmap_destroy( + struct IDNameLib_Map *id_typemap) + ATTR_NONNULL(); +struct Main *BKE_main_idmap_main_get( + struct IDNameLib_Map *id_typemap) + ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +struct ID *BKE_main_idmap_lookup( + struct IDNameLib_Map *id_typemap, + short id_type, const char *name, const struct Library *lib) + ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 3); +struct ID *BKE_main_idmap_lookup_id( + struct IDNameLib_Map *id_typemap, const struct ID *id) + ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2); + +#endif /* __BKE_LIBRARY_IDMAP_H__ */ diff --git a/source/blender/blenkernel/BKE_library_query.h b/source/blender/blenkernel/BKE_library_query.h index 2e73be576f9..3a2b49f911c 100644 --- a/source/blender/blenkernel/BKE_library_query.h +++ b/source/blender/blenkernel/BKE_library_query.h @@ -32,6 +32,7 @@ */ struct ID; +struct Main; /* Tips for the callback for cases it's gonna to modify the pointer. */ enum { @@ -52,7 +53,7 @@ enum { enum { IDWALK_RET_NOP = 0, - IDWALK_RET_STOP_ITER = 1 << 0, /* Completly top iteration. */ + IDWALK_RET_STOP_ITER = 1 << 0, /* Completly stop iteration. */ IDWALK_RET_STOP_RECURSION = 1 << 1, /* Stop recursion, that is, do not loop over ID used by current one. */ }; @@ -75,4 +76,6 @@ void BKE_library_update_ID_link_user(struct ID *id_dst, struct ID *id_src, const int BKE_library_ID_use_ID(struct ID *id_user, struct ID *id_used); +bool BKE_library_ID_is_indirectly_used(struct Main *bmain, void *idv); + #endif /* __BKE_LIBRARY_QUERY_H__ */ diff --git a/source/blender/blenkernel/BKE_library_remap.h b/source/blender/blenkernel/BKE_library_remap.h new file mode 100644 index 00000000000..754005276f0 --- /dev/null +++ b/source/blender/blenkernel/BKE_library_remap.h @@ -0,0 +1,78 @@ +/* + * ***** 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. + * + * ***** END GPL LICENSE BLOCK ***** + */ +#ifndef __BKE_LIBRARY_REMAP_H__ +#define __BKE_LIBRARY_REMAP_H__ + +/** \file BKE_library_remap.h + * \ingroup bke + */ +#ifdef __cplusplus +extern "C" { +#endif + +#include "BLI_compiler_attrs.h" + +/* BKE_libblock_free, delete are declared in BKE_library.h for convenience. */ + +/* Also IDRemap->flag. */ +enum { + /* Do not remap indirect usages of IDs (that is, when user is some linked data). */ + ID_REMAP_SKIP_INDIRECT_USAGE = 1 << 0, + /* This flag should always be set, *except for 'unlink' scenarios* (only relevant when new_id == NULL). + * Basically, when unset, NEVER_NULL ID usages will keep pointing to old_id, but (if needed) old_id user count + * will still be decremented. This is mandatory for 'delete ID' case, but in all other situation this would lead + * to invalid user counts! */ + ID_REMAP_SKIP_NEVER_NULL_USAGE = 1 << 1, + /* This tells the callback func to flag with LIB_DOIT all IDs using target one with a 'never NULL' pointer + * (like e.g. Object->data). */ + ID_REMAP_FLAG_NEVER_NULL_USAGE = 1 << 2, + /* This tells the callback func to force setting IDs using target one with a 'never NULL' pointer to NULL. + * WARNING! Use with extreme care, this will leave database in broken state! */ + ID_REMAP_FORCE_NEVER_NULL_USAGE = 1 << 3, +}; + +/* Note: Requiring new_id to be non-null, this *may* not be the case ultimately, but makes things simpler for now. */ +void BKE_libblock_remap_locked( + struct Main *bmain, void *old_idv, void *new_idv, + const short remap_flags) ATTR_NONNULL(1, 2); +void BKE_libblock_remap( + struct Main *bmain, void *old_idv, void *new_idv, + const short remap_flags) ATTR_NONNULL(1, 2); + +void BKE_libblock_unlink( + struct Main *bmain, void *idv, + const bool do_flag_never_null, const bool do_skip_indirect) ATTR_NONNULL(); + +void BKE_libblock_relink_ex(void *idv, void *old_idv, void *new_idv, const bool us_min_never_null) ATTR_NONNULL(1); + + +typedef void (*BKE_library_free_window_manager_cb)(struct bContext *, struct wmWindowManager *); +typedef void (*BKE_library_free_notifier_reference_cb)(const void *); +typedef void (*BKE_library_remap_editor_id_reference_cb)(struct ID *, struct ID *); + +void BKE_library_callback_free_window_manager_set(BKE_library_free_window_manager_cb func); +void BKE_library_callback_free_notifier_reference_set(BKE_library_free_notifier_reference_cb func); +void BKE_library_callback_remap_editor_id_reference_set(BKE_library_remap_editor_id_reference_cb func); + +#ifdef __cplusplus +} +#endif + +#endif /* __BKE_LIBRARY_REMAP_H__ */ diff --git a/source/blender/blenkernel/BKE_linestyle.h b/source/blender/blenkernel/BKE_linestyle.h index e3eead4102c..e343cd29622 100644 --- a/source/blender/blenkernel/BKE_linestyle.h +++ b/source/blender/blenkernel/BKE_linestyle.h @@ -79,8 +79,6 @@ void BKE_linestyle_geometry_modifier_move(FreestyleLineStyle *linestyle, LineSty void BKE_linestyle_modifier_list_color_ramps(FreestyleLineStyle *linestyle, ListBase *listbase); char *BKE_linestyle_path_to_color_ramp(FreestyleLineStyle *linestyle, struct ColorBand *color_ramp); -void BKE_linestyle_target_object_unlink(FreestyleLineStyle *linestyle, struct Object *ob); - bool BKE_linestyle_use_textures(FreestyleLineStyle *linestyle, const bool use_shading_nodes); void BKE_linestyle_default_shader(const struct bContext *C, FreestyleLineStyle *linestyle); diff --git a/source/blender/blenkernel/BKE_mask.h b/source/blender/blenkernel/BKE_mask.h index 25893d54dca..f3d12b5a8cc 100644 --- a/source/blender/blenkernel/BKE_mask.h +++ b/source/blender/blenkernel/BKE_mask.h @@ -125,8 +125,7 @@ struct Mask *BKE_mask_new(struct Main *bmain, const char *name); struct Mask *BKE_mask_copy_nolib(struct Mask *mask); struct Mask *BKE_mask_copy(struct Mask *mask); -void BKE_mask_free_nolib(struct Mask *mask); -void BKE_mask_free(struct Main *bmain, struct Mask *mask); +void BKE_mask_free(struct Mask *mask); void BKE_mask_coord_from_frame(float r_co[2], const float co[2], const float frame_size[2]); void BKE_mask_coord_from_movieclip(struct MovieClip *clip, struct MovieClipUser *user, float r_co[2], const float co[2]); diff --git a/source/blender/blenkernel/BKE_mball.h b/source/blender/blenkernel/BKE_mball.h index 0574b88bef3..b8258455c65 100644 --- a/source/blender/blenkernel/BKE_mball.h +++ b/source/blender/blenkernel/BKE_mball.h @@ -38,7 +38,6 @@ struct Object; struct Scene; struct MetaElem; -void BKE_mball_unlink(struct MetaBall *mb); void BKE_mball_free(struct MetaBall *mb); void BKE_mball_init(struct MetaBall *mb); struct MetaBall *BKE_mball_add(struct Main *bmain, const char *name); diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h index c7d5857b873..2cc28ca837f 100644 --- a/source/blender/blenkernel/BKE_mesh.h +++ b/source/blender/blenkernel/BKE_mesh.h @@ -32,6 +32,7 @@ */ struct ID; +struct BMeshCreateParams; struct BoundBox; struct EdgeHash; struct ListBase; @@ -69,7 +70,9 @@ extern "C" { /* *** mesh.c *** */ -struct BMesh *BKE_mesh_to_bmesh(struct Mesh *me, struct Object *ob, const bool add_key_index); +struct BMesh *BKE_mesh_to_bmesh( + struct Mesh *me, struct Object *ob, + const bool add_key_index, const struct BMeshCreateParams *params); int poly_find_loop_from_vert( const struct MPoly *poly, @@ -81,8 +84,7 @@ int poly_get_adj_loops_from_vert( int BKE_mesh_edge_other_vert(const struct MEdge *e, int v); -void BKE_mesh_unlink(struct Mesh *me); -void BKE_mesh_free(struct Mesh *me, int unlink); +void BKE_mesh_free(struct Mesh *me); void BKE_mesh_init(struct Mesh *me); struct Mesh *BKE_mesh_add(struct Main *bmain, const char *name); struct Mesh *BKE_mesh_copy_ex(struct Main *bmain, struct Mesh *me); @@ -323,7 +325,7 @@ void BKE_mesh_mdisp_flip(struct MDisps *md, const bool use_loop_mdisp_flip); void BKE_mesh_polygon_flip_ex( struct MPoly *mpoly, struct MLoop *mloop, struct CustomData *ldata, - struct MDisps *mdisp, const bool use_loop_mdisp_flip); + float (*lnors)[3], struct MDisps *mdisp, const bool use_loop_mdisp_flip); void BKE_mesh_polygon_flip(struct MPoly *mpoly, struct MLoop *mloop, struct CustomData *ldata); void BKE_mesh_polygons_flip(struct MPoly *mpoly, struct MLoop *mloop, struct CustomData *ldata, int totpoly); diff --git a/source/blender/blenkernel/BKE_movieclip.h b/source/blender/blenkernel/BKE_movieclip.h index afca326c727..3d963ac109c 100644 --- a/source/blender/blenkernel/BKE_movieclip.h +++ b/source/blender/blenkernel/BKE_movieclip.h @@ -40,7 +40,6 @@ struct MovieClipUser; struct MovieDistortion; void BKE_movieclip_free(struct MovieClip *clip); -void BKE_movieclip_unlink(struct Main *bmain, struct MovieClip *clip); struct MovieClip *BKE_movieclip_file_add(struct Main *bmain, const char *name); struct MovieClip *BKE_movieclip_file_add_exists_ex(struct Main *bmain, const char *name, bool *r_exists); diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index 76e49566d19..bf198c9b86b 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -334,7 +334,6 @@ void ntreeInitDefault(struct bNodeTree *ntree); struct bNodeTree *ntreeAddTree(struct Main *bmain, const char *name, const char *idname); /* copy/free funcs, need to manage ID users */ -void ntreeFreeTree_ex(struct bNodeTree *ntree, const bool do_id_user); void ntreeFreeTree(struct bNodeTree *ntree); struct bNodeTree *ntreeCopyTree_ex(struct bNodeTree *ntree, struct Main *bmain, const bool do_id_user); struct bNodeTree *ntreeCopyTree(struct bNodeTree *ntree); @@ -348,6 +347,7 @@ void ntreeUserDecrefID(struct bNodeTree *ntree); struct bNodeTree *ntreeFromID(struct ID *id); void ntreeMakeLocal(struct bNodeTree *ntree, bool id_in_mainlist); +struct bNode *ntreeFindType(const struct bNodeTree *ntree, int type); bool ntreeHasType(const struct bNodeTree *ntree, int type); bool ntreeHasTree(const struct bNodeTree *ntree, const struct bNodeTree *lookup); void ntreeUpdateTree(struct Main *main, struct bNodeTree *ntree); diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h index 7d6096407ff..f46fb73f4c9 100644 --- a/source/blender/blenkernel/BKE_object.h +++ b/source/blender/blenkernel/BKE_object.h @@ -65,7 +65,6 @@ void BKE_object_free_curve_cache(struct Object *ob); void BKE_object_update_base_layer(struct Scene *scene, struct Object *ob); void BKE_object_free(struct Object *ob); -void BKE_object_free_ex(struct Object *ob, bool do_id_user); void BKE_object_free_derived_caches(struct Object *ob); void BKE_object_free_caches(struct Object *object); @@ -79,7 +78,6 @@ void BKE_object_free_modifiers(struct Object *ob); void BKE_object_make_proxy(struct Object *ob, struct Object *target, struct Object *gob); void BKE_object_copy_proxy_drivers(struct Object *ob, struct Object *target); -void BKE_object_unlink(struct Main *bmain, struct Object *ob); bool BKE_object_exists_check(struct Object *obtest); bool BKE_object_is_in_editmode(struct Object *ob); bool BKE_object_is_in_editmode_vgroup(struct Object *ob); @@ -208,6 +206,8 @@ void BKE_object_eval_uber_data(struct EvaluationContext *eval_ctx, struct Scene *scene, struct Object *ob); +void BKE_object_eval_proxy_backlink(struct EvaluationContext *eval_ctx, struct Object *ob); + void BKE_object_handle_data_update(struct EvaluationContext *eval_ctx, struct Scene *scene, struct Object *ob); diff --git a/source/blender/blenkernel/BKE_particle.h b/source/blender/blenkernel/BKE_particle.h index e17fb9f7a02..5daa94c4302 100644 --- a/source/blender/blenkernel/BKE_particle.h +++ b/source/blender/blenkernel/BKE_particle.h @@ -148,7 +148,8 @@ typedef struct ParticleThreadContext { struct ParticleData *tpars; /* path caching */ - int editupdate, between, segments, extra_segments; + bool editupdate; + int between, segments, extra_segments; int totchild, totparent, parent_pass; float cfra; @@ -293,7 +294,7 @@ void psys_set_current_num(Object *ob, int index); struct LatticeDeformData *psys_create_lattice_deform_data(struct ParticleSimulationData *sim); bool psys_in_edit_mode(struct Scene *scene, struct ParticleSystem *psys); -bool psys_check_enabled(struct Object *ob, struct ParticleSystem *psys); +bool psys_check_enabled(struct Object *ob, struct ParticleSystem *psys, const bool use_render_params); bool psys_check_edited(struct ParticleSystem *psys); void psys_check_group_weights(struct ParticleSettings *part); @@ -327,11 +328,11 @@ void BKE_particlesettings_make_local(struct ParticleSettings *part); void psys_reset(struct ParticleSystem *psys, int mode); -void psys_find_parents(struct ParticleSimulationData *sim); +void psys_find_parents(struct ParticleSimulationData *sim, const bool use_render_params); -void psys_cache_paths(struct ParticleSimulationData *sim, float cfra); -void psys_cache_edit_paths(struct Scene *scene, struct Object *ob, struct PTCacheEdit *edit, float cfra); -void psys_cache_child_paths(struct ParticleSimulationData *sim, float cfra, int editupdate); +void psys_cache_paths(struct ParticleSimulationData *sim, float cfra, const bool use_render_params); +void psys_cache_edit_paths(struct Scene *scene, struct Object *ob, struct PTCacheEdit *edit, float cfra, const bool use_render_params); +void psys_cache_child_paths(struct ParticleSimulationData *sim, float cfra, const bool editupdate, const bool use_render_params); int do_guides(struct ParticleSettings *part, struct ListBase *effectors, ParticleKey *state, int pa_num, float time); void precalc_guides(struct ParticleSimulationData *sim, struct ListBase *effectors); float psys_get_timestep(struct ParticleSimulationData *sim); @@ -379,7 +380,7 @@ void psys_check_boid_data(struct ParticleSystem *psys); void psys_get_birth_coords(struct ParticleSimulationData *sim, struct ParticleData *pa, struct ParticleKey *state, float dtime, float cfra); -void particle_system_update(struct Scene *scene, struct Object *ob, struct ParticleSystem *psys); +void particle_system_update(struct Scene *scene, struct Object *ob, struct ParticleSystem *psys, const bool use_render_params); /* Callback format for performing operations on ID-pointers for particle systems */ typedef void (*ParticleSystemIDFunc)(struct ParticleSystem *psys, struct ID **idpoin, void *userdata, int cd_flag); diff --git a/source/blender/blenkernel/BKE_sca.h b/source/blender/blenkernel/BKE_sca.h index fa448aa97b8..1743a4431fd 100644 --- a/source/blender/blenkernel/BKE_sca.h +++ b/source/blender/blenkernel/BKE_sca.h @@ -67,7 +67,6 @@ void clear_sca_new_poins_ob(struct Object *ob); void clear_sca_new_poins(void); void set_sca_new_poins_ob(struct Object *ob); void set_sca_new_poins(void); -void sca_remove_ob_poin(struct Object *obt, struct Object *ob); void sca_move_sensor(struct bSensor *sens_to_move, struct Object *ob, int move_up); void sca_move_controller(struct bController *cont_to_move, struct Object *ob, int move_up); diff --git a/source/blender/blenkernel/BKE_scene.h b/source/blender/blenkernel/BKE_scene.h index a4c44b9934e..ccb7dc8e015 100644 --- a/source/blender/blenkernel/BKE_scene.h +++ b/source/blender/blenkernel/BKE_scene.h @@ -100,10 +100,11 @@ struct Scene *BKE_scene_set_name(struct Main *bmain, const char *name); struct Scene *BKE_scene_copy(struct Scene *sce, int type); void BKE_scene_groups_relink(struct Scene *sce); -void BKE_scene_unlink(struct Main *bmain, struct Scene *sce, struct Scene *newsce); struct Object *BKE_scene_camera_find(struct Scene *sc); +#ifdef DURIAN_CAMERA_SWITCH struct Object *BKE_scene_camera_switch_find(struct Scene *scene); // DURIAN_CAMERA_SWITCH +#endif int BKE_scene_camera_switch_update(struct Scene *scene); char *BKE_scene_find_marker_name(struct Scene *scene, int frame); @@ -135,6 +136,7 @@ float get_render_aosss_error(const struct RenderData *r, float error); bool BKE_scene_use_new_shading_nodes(const struct Scene *scene); bool BKE_scene_use_shading_nodes_custom(struct Scene *scene); +bool BKE_scene_use_world_space_shading(struct Scene *scene); bool BKE_scene_use_spherical_stereo(struct Scene *scene); bool BKE_scene_uses_blender_internal(const struct Scene *scene); diff --git a/source/blender/blenkernel/BKE_screen.h b/source/blender/blenkernel/BKE_screen.h index d05df3470b5..14e978b23f2 100644 --- a/source/blender/blenkernel/BKE_screen.h +++ b/source/blender/blenkernel/BKE_screen.h @@ -99,6 +99,9 @@ typedef struct SpaceType { /* return context data */ int (*context)(const struct bContext *, const char *, struct bContextDataResult *); + /* Used when we want to replace an ID by another (or NULL). */ + void (*id_remap)(struct ScrArea *, struct SpaceLink *, struct ID *, struct ID *); + /* region type definitions */ ListBase regiontypes; @@ -274,8 +277,8 @@ void BKE_spacedata_freelist(ListBase *lb); void BKE_spacedata_copylist(ListBase *lb1, ListBase *lb2); void BKE_spacedata_draw_locks(int set); -void BKE_spacedata_callback_id_unref_set(void (*func)(struct SpaceLink *sl, const struct ID *)); -void BKE_spacedata_id_unref(struct SpaceLink *sl, const struct ID *id); +void BKE_spacedata_callback_id_remap_set(void (*func)(struct ScrArea *, struct SpaceLink *, struct ID *, struct ID *)); +void BKE_spacedata_id_unref(struct ScrArea *sa, struct SpaceLink *sl, struct ID *id); /* area/regions */ struct ARegion *BKE_area_region_copy(struct SpaceType *st, struct ARegion *ar); diff --git a/source/blender/blenkernel/BKE_sound.h b/source/blender/blenkernel/BKE_sound.h index 67db2537c8f..18d9fe061a8 100644 --- a/source/blender/blenkernel/BKE_sound.h +++ b/source/blender/blenkernel/BKE_sound.h @@ -72,8 +72,6 @@ struct bSound *BKE_sound_new_buffer(struct Main *bmain, struct bSound *source); struct bSound *BKE_sound_new_limiter(struct Main *bmain, struct bSound *source, float start, float end); #endif -void BKE_sound_delete(struct Main *bmain, struct bSound *sound); - void BKE_sound_cache(struct bSound *sound); void BKE_sound_delete_cache(struct bSound *sound); diff --git a/source/blender/blenkernel/BKE_text.h b/source/blender/blenkernel/BKE_text.h index b14593f5a56..858feeeab10 100644 --- a/source/blender/blenkernel/BKE_text.h +++ b/source/blender/blenkernel/BKE_text.h @@ -53,7 +53,6 @@ struct Text *BKE_text_load_ex(struct Main *bmain, const char *file, const cha const bool is_internal); struct Text *BKE_text_load (struct Main *bmain, const char *file, const char *relpath); struct Text *BKE_text_copy (struct Main *bmain, struct Text *ta); -void BKE_text_unlink (struct Main *bmain, struct Text *text); void BKE_text_clear (struct Text *text); void BKE_text_write (struct Text *text, const char *str); int BKE_text_file_modified_check(struct Text *text); diff --git a/source/blender/blenkernel/BKE_world.h b/source/blender/blenkernel/BKE_world.h index 8d7ab230919..0be61fe0229 100644 --- a/source/blender/blenkernel/BKE_world.h +++ b/source/blender/blenkernel/BKE_world.h @@ -37,7 +37,6 @@ struct Main; struct World; void BKE_world_free(struct World *sc); -void BKE_world_free_ex(struct World *sc, bool do_id_user); void BKE_world_init(struct World *wrld); struct World *add_world(struct Main *bmian, const char *name); struct World *BKE_world_copy(struct World *wrld); diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt index afab0ccc5a5..b7ff81d603b 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -49,9 +49,6 @@ set(INC ../../../intern/smoke/extern ../../../intern/atomic ../../../intern/libmv - - # XXX - BAD LEVEL CALL WM_api.h - ../windowmanager ) set(INC_SYS @@ -121,7 +118,9 @@ set(SRC intern/lamp.c intern/lattice.c intern/library.c + intern/library_idmap.c intern/library_query.c + intern/library_remap.c intern/linestyle.c intern/mask.c intern/mask_evaluate.c @@ -244,7 +243,9 @@ set(SRC BKE_lamp.h BKE_lattice.h BKE_library.h + BKE_library_idmap.h BKE_library_query.h + BKE_library_remap.h BKE_linestyle.h BKE_main.h BKE_mask.h diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c index 0de0e4d7797..79e500f8ceb 100644 --- a/source/blender/blenkernel/intern/DerivedMesh.c +++ b/source/blender/blenkernel/intern/DerivedMesh.c @@ -1433,10 +1433,12 @@ static void calc_weightpaint_vert_array( Object *ob, DerivedMesh *dm, int const draw_flag, DMWeightColorInfo *dm_wcinfo, unsigned char (*r_wtcol_v)[4]) { - MDeformVert *dv = DM_get_vert_data_layer(dm, CD_MDEFORMVERT); - int numVerts = dm->getNumVerts(dm); + BMEditMesh *em = (dm->type == DM_TYPE_EDITBMESH) ? BKE_editmesh_from_object(ob) : NULL; + const int numVerts = dm->getNumVerts(dm); - if (dv && (ob->actdef != 0)) { + if ((ob->actdef != 0) && + (CustomData_has_layer(em ? &em->bm->vdata : &dm->vertData, CD_MDEFORMVERT))) + { unsigned char (*wc)[4] = r_wtcol_v; unsigned int i; @@ -1455,8 +1457,30 @@ static void calc_weightpaint_vert_array( } } - for (i = numVerts; i != 0; i--, wc++, dv++) { - calc_weightpaint_vert_color((unsigned char *)wc, dv, dm_wcinfo, defbase_tot, defbase_act, defbase_sel, defbase_sel_tot, draw_flag); + /* editmesh won't have deform verts unless modifiers require it, + * avoid having to create an array of deform-verts only for drawing + * by reading from the bmesh directly. */ + if (em) { + BMIter iter; + BMVert *eve; + const int cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT); + BLI_assert(cd_dvert_offset != -1); + + BM_ITER_MESH_INDEX (eve, &iter, em->bm, BM_VERTS_OF_MESH, i) { + const MDeformVert *dv = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset); + calc_weightpaint_vert_color( + (unsigned char *)wc, dv, dm_wcinfo, + defbase_tot, defbase_act, defbase_sel, defbase_sel_tot, draw_flag); + wc++; + } + } + else { + const MDeformVert *dv = DM_get_vert_data_layer(dm, CD_MDEFORMVERT); + for (i = numVerts; i != 0; i--, wc++, dv++) { + calc_weightpaint_vert_color( + (unsigned char *)wc, dv, dm_wcinfo, + defbase_tot, defbase_act, defbase_sel, defbase_sel_tot, draw_flag); + } } if (defbase_sel) { @@ -2282,7 +2306,7 @@ static void editbmesh_calc_modifiers( modifiers_clearErrors(ob); if (r_cage && cageIndex == -1) { - *r_cage = getEditDerivedBMesh(em, ob, NULL); + *r_cage = getEditDerivedBMesh(em, ob, dataMask, NULL); } md = modifiers_getVirtualModifierList(ob, &virtualModifierData); @@ -2448,7 +2472,7 @@ static void editbmesh_calc_modifiers( } else { *r_cage = getEditDerivedBMesh( - em, ob, + em, ob, mask, deformedVerts ? MEM_dupallocN(deformedVerts) : NULL); } } @@ -2484,7 +2508,7 @@ static void editbmesh_calc_modifiers( } else { /* this is just a copy of the editmesh, no need to calc normals */ - *r_final = getEditDerivedBMesh(em, ob, deformedVerts); + *r_final = getEditDerivedBMesh(em, ob, dataMask, deformedVerts); deformedVerts = NULL; /* In this case, we should never have weight-modifying modifiers in stack... */ @@ -2847,9 +2871,9 @@ DerivedMesh *editbmesh_get_derived_cage(Scene *scene, Object *obedit, BMEditMesh return em->derivedCage; } -DerivedMesh *editbmesh_get_derived_base(Object *obedit, BMEditMesh *em) +DerivedMesh *editbmesh_get_derived_base(Object *obedit, BMEditMesh *em, CustomDataMask data_mask) { - return getEditDerivedBMesh(em, obedit, NULL); + return getEditDerivedBMesh(em, obedit, data_mask, NULL); } /***/ @@ -3881,7 +3905,6 @@ static void navmesh_drawColored(DerivedMesh *dm) /* if (GPU_buffer_legacy(dm) ) */ /* TODO - VBO draw code, not high priority - campbell */ { DEBUG_VBO("Using legacy code. drawNavMeshColored\n"); - //glShadeModel(GL_SMOOTH); glBegin(glmode = GL_QUADS); for (a = 0; a < dm->numTessFaceData; a++, mface++) { int new_glmode = mface->v4 ? GL_QUADS : GL_TRIANGLES; diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c index df9b9683687..46ee8a4d888 100644 --- a/source/blender/blenkernel/intern/action.c +++ b/source/blender/blenkernel/intern/action.c @@ -159,22 +159,19 @@ void BKE_action_make_local(bAction *act) /* .................................. */ +/** Free (or release) any data used by this action (does not free the action itself). */ void BKE_action_free(bAction *act) -{ - /* sanity check */ - if (act == NULL) - return; - +{ + /* No animdata here. */ + /* Free F-Curves */ free_fcurves(&act->curves); /* Free groups */ - if (act->groups.first) - BLI_freelistN(&act->groups); + BLI_freelistN(&act->groups); /* Free pose-references (aka local markers) */ - if (act->markers.first) - BLI_freelistN(&act->markers); + BLI_freelistN(&act->markers); } /* .................................. */ diff --git a/source/blender/blenkernel/intern/anim.c b/source/blender/blenkernel/intern/anim.c index dff696863e9..7d3d12ac112 100644 --- a/source/blender/blenkernel/intern/anim.c +++ b/source/blender/blenkernel/intern/anim.c @@ -340,11 +340,11 @@ static void motionpaths_calc_update_scene(Scene *scene) } } #else // original, 'always correct' version - /* do all updates - * - if this is too slow, resort to using a more efficient way - * that doesn't force complete update, but for now, this is the - * most accurate way! - */ + /* do all updates + * - if this is too slow, resort to using a more efficient way + * that doesn't force complete update, but for now, this is the + * most accurate way! + */ BKE_scene_update_for_newframe(G.main->eval_ctx, G.main, scene, scene->lay); /* XXX this is the best way we can get anything moving */ #endif } diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c index 99aae6239e8..91b33f3efd3 100644 --- a/source/blender/blenkernel/intern/anim_sys.c +++ b/source/blender/blenkernel/intern/anim_sys.c @@ -216,7 +216,7 @@ bool BKE_animdata_set_action(ReportList *reports, ID *id, bAction *act) /* Freeing -------------------------------------------- */ /* Free AnimData used by the nominated ID-block, and clear ID-block's AnimData pointer */ -void BKE_animdata_free(ID *id) +void BKE_animdata_free(ID *id, const bool do_id_user) { /* Only some ID-blocks have this info for now, so we cast the * types that do to be of type IdAdtTemplate @@ -227,12 +227,14 @@ void BKE_animdata_free(ID *id) /* check if there's any AnimData to start with */ if (adt) { - /* unlink action (don't free, as it's in its own list) */ - if (adt->action) - id_us_min(&adt->action->id); - /* same goes for the temporarily displaced action */ - if (adt->tmpact) - id_us_min(&adt->tmpact->id); + if (do_id_user) { + /* unlink action (don't free, as it's in its own list) */ + if (adt->action) + id_us_min(&adt->action->id); + /* same goes for the temporarily displaced action */ + if (adt->tmpact) + id_us_min(&adt->tmpact->id); + } /* free nla data */ free_nladata(&adt->nla_tracks); @@ -292,7 +294,7 @@ bool BKE_animdata_copy_id(ID *id_to, ID *id_from, const bool do_action) if ((id_to && id_from) && (GS(id_to->name) != GS(id_from->name))) return false; - BKE_animdata_free(id_to); + BKE_animdata_free(id_to, true); adt = BKE_animdata_from_id(id_from); if (adt) { diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c index 04b4733fd44..b59618f46b2 100644 --- a/source/blender/blenkernel/intern/armature.c +++ b/source/blender/blenkernel/intern/armature.c @@ -120,30 +120,25 @@ void BKE_armature_bonelist_free(ListBase *lb) BLI_freelistN(lb); } +/** Free (or release) any data used by this armature (does not free the armature itself). */ void BKE_armature_free(bArmature *arm) { - if (arm) { - BKE_armature_bonelist_free(&arm->bonebase); + BKE_animdata_free(&arm->id, false); - /* free editmode data */ - if (arm->edbo) { - BLI_freelistN(arm->edbo); + BKE_armature_bonelist_free(&arm->bonebase); - MEM_freeN(arm->edbo); - arm->edbo = NULL; - } + /* free editmode data */ + if (arm->edbo) { + BLI_freelistN(arm->edbo); - /* free sketch */ - if (arm->sketch) { - freeSketch(arm->sketch); - arm->sketch = NULL; - } + MEM_freeN(arm->edbo); + arm->edbo = NULL; + } - /* free animation data */ - if (arm->adt) { - BKE_animdata_free(&arm->id); - arm->adt = NULL; - } + /* free sketch */ + if (arm->sketch) { + freeSketch(arm->sketch); + arm->sketch = NULL; } } @@ -640,6 +635,7 @@ void b_bone_spline_setup(bPoseChannel *pchan, int rest, Mat4 result_array[MAX_BB { const float circle_factor = length * (cubic_tangent_factor_circle_v3(h1, h2) / 0.75f); + const float hlength1 = bone->ease1 * circle_factor; const float hlength2 = bone->ease2 * circle_factor; diff --git a/source/blender/blenkernel/intern/blender.c b/source/blender/blenkernel/intern/blender.c index 15492fbd20d..0805335da66 100644 --- a/source/blender/blenkernel/intern/blender.c +++ b/source/blender/blenkernel/intern/blender.c @@ -226,3 +226,56 @@ int BKE_blender_test_break(void) return (G.is_break == true); } + +/** \name Blender's AtExit + * + * \note Don't use MEM_mallocN so functions can be registered at any time. + * \{ */ + +struct AtExitData { + struct AtExitData *next; + + void (*func)(void *user_data); + void *user_data; +} *g_atexit = NULL; + +void BKE_blender_atexit_register(void (*func)(void *user_data), void *user_data) +{ + struct AtExitData *ae = malloc(sizeof(*ae)); + ae->next = g_atexit; + ae->func = func; + ae->user_data = user_data; + g_atexit = ae; +} + +void BKE_blender_atexit_unregister(void (*func)(void *user_data), const void *user_data) +{ + struct AtExitData *ae = g_atexit; + struct AtExitData **ae_p = &g_atexit; + + while (ae) { + if ((ae->func == func) && (ae->user_data == user_data)) { + *ae_p = ae->next; + free(ae); + return; + } + ae_p = &ae; + ae = ae->next; + } +} + +void BKE_blender_atexit(void) +{ + struct AtExitData *ae = g_atexit, *ae_next; + while (ae) { + ae_next = ae->next; + + ae->func(ae->user_data); + + free(ae); + ae = ae_next; + } + g_atexit = NULL; +} + +/** \} */ diff --git a/source/blender/blenkernel/intern/blender_undo.c b/source/blender/blenkernel/intern/blender_undo.c index ca0a1b91cea..d64bf7ecf43 100644 --- a/source/blender/blenkernel/intern/blender_undo.c +++ b/source/blender/blenkernel/intern/blender_undo.c @@ -66,9 +66,6 @@ #include "BLO_readfile.h" #include "BLO_writefile.h" -#include "WM_api.h" // XXXXX BAD, very BAD dependency (bad level call) - remove asap, elubie - - /* -------------------------------------------------------------------- */ /** \name Global Undo @@ -87,6 +84,15 @@ typedef struct UndoElem { static ListBase undobase = {NULL, NULL}; static UndoElem *curundo = NULL; +/** + * Avoid bad-level call to #WM_jobs_kill_all_except() + */ +static void (*undo_wm_job_kill_callback)(struct bContext *C) = NULL; + +void BKE_undo_callback_wm_kill_jobs_set(void (*callback)(struct bContext *C)) +{ + undo_wm_job_kill_callback = callback; +} static int read_undosave(bContext *C, UndoElem *uel) { @@ -94,7 +100,7 @@ static int read_undosave(bContext *C, UndoElem *uel) int success = 0, fileflags; /* This is needed so undoing/redoing doesn't crash with threaded previews going */ - WM_jobs_kill_all_except(CTX_wm_manager(C), CTX_wm_screen(C)); + undo_wm_job_kill_callback(C); BLI_strncpy(mainstr, G.main->name, sizeof(mainstr)); /* temporal store */ diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c index da7863096e3..44cacffb71f 100644 --- a/source/blender/blenkernel/intern/brush.c +++ b/source/blender/blenkernel/intern/brush.c @@ -202,37 +202,18 @@ Brush *BKE_brush_copy(Brush *brush) return brushn; } -/* not brush itself */ +/** Free (or release) any data used by this brush (does not free the brush itself). */ void BKE_brush_free(Brush *brush) { - id_us_min((ID *)brush->mtex.tex); - id_us_min((ID *)brush->mask_mtex.tex); - id_us_min((ID *)brush->paint_curve); - - if (brush->icon_imbuf) + if (brush->icon_imbuf) { IMB_freeImBuf(brush->icon_imbuf); - - BKE_previewimg_free(&(brush->preview)); + } curvemapping_free(brush->curve); - if (brush->gradient) - MEM_freeN(brush->gradient); -} + MEM_SAFE_FREE(brush->gradient); -/** - * \note Currently users don't remove brushes from the UI (as is done for scene, text... etc) - * This is only used by RNA, which can remove brushes. - */ -void BKE_brush_unlink(Main *bmain, Brush *brush) -{ - Brush *brush_iter; - - for (brush_iter = bmain->brush.first; brush_iter; brush_iter = brush_iter->id.next) { - if (brush_iter->toggle_brush == brush) { - brush_iter->toggle_brush = NULL; - } - } + BKE_previewimg_free(&(brush->preview)); } static void extern_local_brush(Brush *brush) diff --git a/source/blender/blenkernel/intern/bvhutils.c b/source/blender/blenkernel/intern/bvhutils.c index 7821946eb6e..264d87b86f3 100644 --- a/source/blender/blenkernel/intern/bvhutils.c +++ b/source/blender/blenkernel/intern/bvhutils.c @@ -565,7 +565,7 @@ BVHTree *bvhtree_from_mesh_verts( /** * Builds a bvh tree where nodes are the given vertices (note: does not copy given mverts!). * \param vert_allocated if true, vert freeing will be done when freeing data. - * \param mask if not null, true elements give which vert to add to BVH tree. + * \param verts_mask if not null, true elements give which vert to add to BVH tree. * \param verts_num_active if >= 0, number of active verts to add to BVH tree (else will be computed from mask). */ BVHTree *bvhtree_from_mesh_verts_ex( @@ -590,6 +590,77 @@ BVHTree *bvhtree_from_mesh_verts_ex( /** \name Edge Builder * \{ */ +static BVHTree *bvhtree_from_editmesh_edges_create_tree( + float epsilon, int tree_type, int axis, + BMEditMesh *em, const int edges_num, + const BLI_bitmap *edges_mask, int edges_num_active) +{ + BVHTree *tree = NULL; + int i; + BM_mesh_elem_table_ensure(em->bm, BM_EDGE); + if (edges_mask) { + BLI_assert(IN_RANGE_INCL(edges_num_active, 0, edges_num)); + } + else { + edges_num_active = edges_num; + } + + tree = BLI_bvhtree_new(edges_num_active, epsilon, tree_type, axis); + + if (tree) { + BMIter iter; + BMEdge *eed; + BM_ITER_MESH_INDEX (eed, &iter, em->bm, BM_EDGES_OF_MESH, i) { + if (edges_mask && !BLI_BITMAP_TEST_BOOL(edges_mask, i)) { + continue; + } + float co[2][3]; + copy_v3_v3(co[0], eed->v1->co); + copy_v3_v3(co[1], eed->v2->co); + + BLI_bvhtree_insert(tree, i, co[0], 2); + } + BLI_assert(BLI_bvhtree_get_size(tree) == edges_num_active); + BLI_bvhtree_balance(tree); + } + + return tree; +} + +/* Builds a bvh tree where nodes are the edges of the given em */ +BVHTree *bvhtree_from_editmesh_edges_ex( + BVHTreeFromEditMesh *data, BMEditMesh *em, + const BLI_bitmap *edges_mask, int edges_num_active, + float epsilon, int tree_type, int axis) +{ + int edge_num = em->bm->totedge; + + BVHTree *tree = bvhtree_from_editmesh_edges_create_tree( + epsilon, tree_type, axis, + em, edge_num, edges_mask, edges_num_active); + + if (tree) { + memset(data, 0, sizeof(*data)); + data->tree = tree; + data->em = em; + data->nearest_callback = NULL; /* TODO */ + data->raycast_callback = NULL; /* TODO */ + /* TODO: not urgent however since users currently define own callbacks */ + data->nearest_to_ray_callback = NULL; + } + + return tree; +} +BVHTree *bvhtree_from_editmesh_edges( + BVHTreeFromEditMesh *data, BMEditMesh *em, + float epsilon, int tree_type, int axis) +{ + return bvhtree_from_editmesh_edges_ex( + data, em, + NULL, -1, + epsilon, tree_type, axis); +} + /* Builds a bvh tree where nodes are the edges of the given dm */ BVHTree *bvhtree_from_mesh_edges( BVHTreeFromMesh *data, DerivedMesh *dm, @@ -804,7 +875,7 @@ BVHTree *bvhtree_from_mesh_faces( * Builds a bvh tree where nodes are the given tessellated faces (note: does not copy given mfaces!). * \param vert_allocated if true, vert freeing will be done when freeing data. * \param face_allocated if true, face freeing will be done when freeing data. - * \param mask if not null, true elements give which faces to add to BVH tree. + * \param faces_mask: if not null, true elements give which faces to add to BVH tree. * \param numFaces_active if >= 0, number of active faces to add to BVH tree (else will be computed from mask). */ BVHTree *bvhtree_from_mesh_faces_ex( @@ -968,17 +1039,37 @@ static void bvhtree_from_mesh_looptri_setup_data( BVHTree *bvhtree_from_editmesh_looptri_ex( BVHTreeFromEditMesh *data, BMEditMesh *em, const BLI_bitmap *looptri_mask, int looptri_num_active, - float epsilon, int tree_type, int axis) + float epsilon, int tree_type, int axis, BVHCache **bvhCache) { /* BMESH specific check that we have tessfaces, - * we _could_ tessellate here but rather not - campbell - * - * this assert checks we have tessfaces, - * if not caller should use DM_ensure_tessface() */ + * we _could_ tessellate here but rather not - campbell */ - BVHTree *tree = bvhtree_from_editmesh_looptri_create_tree( - epsilon, tree_type, axis, - em, em->tottri, looptri_mask, looptri_num_active); + BVHTree *tree; + if (bvhCache) { + BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_READ); + tree = bvhcache_find(*bvhCache, BVHTREE_FROM_EM_LOOPTRI); + BLI_rw_mutex_unlock(&cache_rwlock); + if (tree == NULL) { + BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE); + tree = bvhcache_find(*bvhCache, BVHTREE_FROM_EM_LOOPTRI); + if (tree == NULL) { + tree = bvhtree_from_editmesh_looptri_create_tree( + epsilon, tree_type, axis, + em, em->tottri, looptri_mask, looptri_num_active); + if (tree) { + /* Save on cache for later use */ + /* printf("BVHTree built and saved on cache\n"); */ + bvhcache_insert(bvhCache, tree, BVHTREE_FROM_EM_LOOPTRI); + } + } + BLI_rw_mutex_unlock(&cache_rwlock); + } + } + else { + tree = bvhtree_from_editmesh_looptri_create_tree( + epsilon, tree_type, axis, + em, em->tottri, looptri_mask, looptri_num_active); + } if (tree) { data->tree = tree; @@ -987,17 +1078,18 @@ BVHTree *bvhtree_from_editmesh_looptri_ex( data->nearest_to_ray_callback = NULL; data->sphere_radius = 0.0f; data->em = em; + data->cached = bvhCache != NULL; } return tree; } BVHTree *bvhtree_from_editmesh_looptri( BVHTreeFromEditMesh *data, BMEditMesh *em, - float epsilon, int tree_type, int axis) + float epsilon, int tree_type, int axis, BVHCache **bvhCache) { return bvhtree_from_editmesh_looptri_ex( data, em, NULL, -1, - epsilon, tree_type, axis); + epsilon, tree_type, axis, bvhCache); } /** @@ -1045,6 +1137,9 @@ BVHTree *bvhtree_from_mesh_looptri( tree = bvhcache_find(dm->bvhCache, BVHTREE_FROM_LOOPTRI); if (tree == NULL) { int looptri_num = dm->getNumLoopTri(dm); + + /* this assert checks we have looptris, + * if not caller should use DM_ensure_looptri() */ BLI_assert(!(looptri_num == 0 && dm->getNumPolys(dm) != 0)); tree = bvhtree_from_mesh_looptri_create_tree( @@ -1102,7 +1197,9 @@ BVHTree *bvhtree_from_mesh_looptri_ex( void free_bvhtree_from_editmesh(struct BVHTreeFromEditMesh *data) { if (data->tree) { - BLI_bvhtree_free(data->tree); + if (!data->cached) { + BLI_bvhtree_free(data->tree); + } memset(data, 0, sizeof(*data)); } } diff --git a/source/blender/blenkernel/intern/camera.c b/source/blender/blenkernel/intern/camera.c index 96bac2c2f41..eabee742327 100644 --- a/source/blender/blenkernel/intern/camera.c +++ b/source/blender/blenkernel/intern/camera.c @@ -153,9 +153,10 @@ void BKE_camera_make_local(Camera *cam) } } +/** Free (or release) any data used by this camera (does not free the camera itself). */ void BKE_camera_free(Camera *ca) { - BKE_animdata_free((ID *)ca); + BKE_animdata_free((ID *)ca, false); } /******************************** Camera Usage *******************************/ diff --git a/source/blender/blenkernel/intern/cdderivedmesh.c b/source/blender/blenkernel/intern/cdderivedmesh.c index e7e6118813e..159d5b82a6c 100644 --- a/source/blender/blenkernel/intern/cdderivedmesh.c +++ b/source/blender/blenkernel/intern/cdderivedmesh.c @@ -61,8 +61,6 @@ #include "GPU_shader.h" #include "GPU_basic_shader.h" -#include "WM_api.h" - #include <string.h> #include <limits.h> #include <math.h> @@ -464,7 +462,6 @@ static void cdDM_drawFacesSolid( BKE_pbvh_draw(cddm->pbvh, partial_redraw_planes, face_nors, setMaterial, false, false); - glShadeModel(GL_FLAT); return; } } @@ -472,7 +469,6 @@ static void cdDM_drawFacesSolid( GPU_vertex_setup(dm); GPU_normal_setup(dm); GPU_triangle_setup(dm); - glShadeModel(GL_SMOOTH); for (a = 0; a < dm->drawObject->totmaterial; a++) { if (!setMaterial || setMaterial(dm->drawObject->materials[a].mat_nr + 1, NULL)) { GPU_buffer_draw_elements( @@ -481,8 +477,6 @@ static void cdDM_drawFacesSolid( } } GPU_buffers_unbind(); - - glShadeModel(GL_FLAT); } static void cdDM_drawFacesTex_common( @@ -553,8 +547,7 @@ static void cdDM_drawFacesTex_common( if (mloopcol) { GPU_color_setup(dm, colType); } - - glShadeModel(GL_SMOOTH); + /* lastFlag = 0; */ /* UNUSED */ for (mat_index = 0; mat_index < dm->drawObject->totmaterial; mat_index++) { GPUBufferMaterial *bufmat = dm->drawObject->materials + mat_index; @@ -633,7 +626,6 @@ static void cdDM_drawFacesTex_common( } GPU_buffers_unbind(); - glShadeModel(GL_FLAT); } @@ -705,10 +697,10 @@ static void cdDM_drawMappedFaces( } if ((orig != ORIGINDEX_NONE) && !is_hidden) - WM_framebuffer_index_get(orig + 1, &selcol); + GPU_select_index_get(orig + 1, &selcol); } else if (orig != ORIGINDEX_NONE) - WM_framebuffer_index_get(orig + 1, &selcol); + GPU_select_index_get(orig + 1, &selcol); for (j = 0; j < mpoly->totloop; j++) fi_map[start_element++] = selcol; @@ -742,9 +734,6 @@ static void cdDM_drawMappedFaces( } } } - - - glShadeModel(GL_SMOOTH); tot_tri_elem = dm->drawObject->tot_triangle_point; @@ -841,7 +830,6 @@ static void cdDM_drawMappedFaces( } GPU_basic_shader_bind(GPU_SHADER_USE_COLOR); - glShadeModel(GL_FLAT); GPU_buffers_unbind(); @@ -929,8 +917,6 @@ static void cdDM_drawMappedFacesGLSL( matnr = -1; do_draw = false; - glShadeModel(GL_SMOOTH); - if (setDrawOptions != NULL) { DMVertexAttribs attribs; DEBUG_VBO("Using legacy code. cdDM_drawMappedFacesGLSL\n"); @@ -1153,8 +1139,6 @@ static void cdDM_drawMappedFacesGLSL( MEM_freeN(mat_orig_to_new); MEM_freeN(matconv); } - - glShadeModel(GL_FLAT); } static void cdDM_drawFacesGLSL(DerivedMesh *dm, DMSetMaterial setMaterial) @@ -1203,8 +1187,6 @@ static void cdDM_drawMappedFacesMat( matnr = -1; - glShadeModel(GL_SMOOTH); - memset(&attribs, 0, sizeof(attribs)); glBegin(GL_TRIANGLES); @@ -1260,8 +1242,6 @@ static void cdDM_drawMappedFacesMat( cddm_draw_attrib_vertex(&attribs, mvert, a, vtri[2], ltri[2], 2, ln3, smoothnormal); } glEnd(); - - glShadeModel(GL_FLAT); } static void cdDM_drawMappedEdges(DerivedMesh *dm, DMSetDrawOptions setDrawOptions, void *userData) @@ -2660,6 +2640,9 @@ void CDDM_calc_loop_normals(DerivedMesh *dm, const bool use_split_normals, const } /* #define DEBUG_CLNORS */ +#ifdef DEBUG_CLNORS +# include "BLI_linklist.h" +#endif void CDDM_calc_loop_normals_spacearr( DerivedMesh *dm, const bool use_split_normals, const float split_angle, MLoopNorSpaceArray *r_lnors_spacearr) diff --git a/source/blender/blenkernel/intern/crazyspace.c b/source/blender/blenkernel/intern/crazyspace.c index c8de0786697..56df8e51eba 100644 --- a/source/blender/blenkernel/intern/crazyspace.c +++ b/source/blender/blenkernel/intern/crazyspace.c @@ -39,6 +39,7 @@ #include "DNA_meshdata_types.h" #include "BLI_utildefines.h" +#include "BLI_linklist.h" #include "BLI_math.h" #include "BKE_crazyspace.h" @@ -275,7 +276,13 @@ int BKE_crazyspace_get_first_deform_matrices_editbmesh(Scene *scene, Object *ob, if (mti->type == eModifierTypeType_OnlyDeform && mti->deformMatricesEM) { if (!defmats) { - dm = getEditDerivedBMesh(em, ob, NULL); + const int required_mode = eModifierMode_Realtime | eModifierMode_Editmode; + CustomDataMask data_mask = CD_MASK_BAREMESH; + CDMaskLink *datamasks = modifiers_calcDataMasks(scene, ob, md, data_mask, required_mode, NULL, 0); + data_mask = datamasks->mask; + BLI_linklist_free((LinkNode *)datamasks, NULL); + + dm = getEditDerivedBMesh(em, ob, data_mask, NULL); deformedVerts = editbmesh_get_vertex_cos(em, &numVerts); defmats = MEM_mallocN(sizeof(*defmats) * numVerts, "defmats"); diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c index 8afb451f768..c52b0f6a884 100644 --- a/source/blender/blenkernel/intern/curve.c +++ b/source/blender/blenkernel/intern/curve.c @@ -69,36 +69,6 @@ static int cu_isectLL(const float v1[3], const float v2[3], const float v3[3], c short cox, short coy, float *lambda, float *mu, float vec[3]); -void BKE_curve_unlink(Curve *cu) -{ - int a; - - for (a = 0; a < cu->totcol; a++) { - if (cu->mat[a]) - id_us_min(&cu->mat[a]->id); - cu->mat[a] = NULL; - } - if (cu->vfont) - id_us_min(&cu->vfont->id); - cu->vfont = NULL; - - if (cu->vfontb) - id_us_min(&cu->vfontb->id); - cu->vfontb = NULL; - - if (cu->vfonti) - id_us_min(&cu->vfonti->id); - cu->vfonti = NULL; - - if (cu->vfontbi) - id_us_min(&cu->vfontbi->id); - cu->vfontbi = NULL; - - if (cu->key) - id_us_min(&cu->key->id); - cu->key = NULL; -} - /* frees editcurve entirely */ void BKE_curve_editfont_free(Curve *cu) { @@ -136,26 +106,21 @@ void BKE_curve_editNurb_free(Curve *cu) } } -/* don't free curve itself */ +/** Free (or release) any data used by this curve (does not free the curve itself). */ void BKE_curve_free(Curve *cu) { + BKE_animdata_free((ID *)cu, false); + BKE_nurbList_free(&cu->nurb); BKE_curve_editfont_free(cu); BKE_curve_editNurb_free(cu); - BKE_curve_unlink(cu); - BKE_animdata_free((ID *)cu); - - if (cu->mat) - MEM_freeN(cu->mat); - if (cu->str) - MEM_freeN(cu->str); - if (cu->strinfo) - MEM_freeN(cu->strinfo); - if (cu->bb) - MEM_freeN(cu->bb); - if (cu->tb) - MEM_freeN(cu->tb); + + MEM_SAFE_FREE(cu->mat); + MEM_SAFE_FREE(cu->str); + MEM_SAFE_FREE(cu->strinfo); + MEM_SAFE_FREE(cu->bb); + MEM_SAFE_FREE(cu->tb); } void BKE_curve_init(Curve *cu) @@ -1419,6 +1384,71 @@ void BKE_nurb_makeCurve(Nurb *nu, float *coord_array, float *tilt_array, float * MEM_freeN(basisu); } +/** + * Calculate the length for arrays filled in by #BKE_curve_calc_coords_axis. + */ +unsigned int BKE_curve_calc_coords_axis_len( + const unsigned int bezt_array_len, const unsigned int resolu, + const bool is_cyclic, const bool use_cyclic_duplicate_endpoint) +{ + const unsigned int segments = bezt_array_len - (is_cyclic ? 0 : 1); + const unsigned int points_len = (segments * resolu) + (is_cyclic ? (use_cyclic_duplicate_endpoint) : 1); + return points_len; +} + +/** + * Calcualte an array for the entire curve (cyclic or non-cyclic). + * \note Call for each axis. + * + * \param use_cyclic_duplicate_endpoint: Duplicate values at the beginning & end of the array. + */ +void BKE_curve_calc_coords_axis( + const BezTriple *bezt_array, const unsigned int bezt_array_len, const unsigned int resolu, + const bool is_cyclic, const bool use_cyclic_duplicate_endpoint, + /* array params */ + const unsigned int axis, const unsigned int stride, + float *r_points) +{ + const unsigned int points_len = BKE_curve_calc_coords_axis_len( + bezt_array_len, resolu, is_cyclic, use_cyclic_duplicate_endpoint); + float *r_points_offset = r_points; + + const unsigned int resolu_stride = resolu * stride; + const unsigned int bezt_array_last = bezt_array_len - 1; + + for (unsigned int i = 0; i < bezt_array_last; i++) { + const BezTriple *bezt_curr = &bezt_array[i]; + const BezTriple *bezt_next = &bezt_array[i + 1]; + BKE_curve_forward_diff_bezier( + bezt_curr->vec[1][axis], bezt_curr->vec[2][axis], + bezt_next->vec[0][axis], bezt_next->vec[1][axis], + r_points_offset, (int)resolu, stride); + r_points_offset = POINTER_OFFSET(r_points_offset, resolu_stride); + } + + if (is_cyclic) { + const BezTriple *bezt_curr = &bezt_array[bezt_array_last]; + const BezTriple *bezt_next = &bezt_array[0]; + BKE_curve_forward_diff_bezier( + bezt_curr->vec[1][axis], bezt_curr->vec[2][axis], + bezt_next->vec[0][axis], bezt_next->vec[1][axis], + r_points_offset, (int)resolu, stride); + r_points_offset = POINTER_OFFSET(r_points_offset, resolu_stride); + if (use_cyclic_duplicate_endpoint) { + *r_points_offset = *r_points; + r_points_offset = POINTER_OFFSET(r_points_offset, stride); + } + } + else { + float *r_points_last = POINTER_OFFSET(r_points, bezt_array_last * resolu_stride); + *r_points_last = bezt_array[bezt_array_last].vec[1][axis]; + r_points_offset = POINTER_OFFSET(r_points_offset, stride); + } + + BLI_assert(POINTER_OFFSET(r_points, points_len * stride) == r_points_offset); + UNUSED_VARS_NDEBUG(points_len); +} + /* forward differencing method for bezier curve */ void BKE_curve_forward_diff_bezier(float q0, float q1, float q2, float q3, float *p, int it, int stride) { diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c index de79a30bd60..612f1f477e1 100644 --- a/source/blender/blenkernel/intern/customdata.c +++ b/source/blender/blenkernel/intern/customdata.c @@ -1853,8 +1853,6 @@ static CustomDataLayer *customData_add_layer__internal(CustomData *data, int typ (alloctype == CD_DUPLICATE) || (alloctype == CD_REFERENCE)); - BLI_assert(size >= 0); - if (!typeInfo->defaultname && CustomData_has_layer(data, type)) return &data->layers[CustomData_get_layer_index(data, type)]; diff --git a/source/blender/blenkernel/intern/depsgraph.c b/source/blender/blenkernel/intern/depsgraph.c index 14c230e4a45..8ea65bf92c1 100644 --- a/source/blender/blenkernel/intern/depsgraph.c +++ b/source/blender/blenkernel/intern/depsgraph.c @@ -770,7 +770,7 @@ static void build_dag_object(DagForest *dag, DagNode *scenenode, Main *bmain, Sc dag_add_relation(dag, node, node, DAG_RL_OB_DATA, "Particle-Object Relation"); - if (!psys_check_enabled(ob, psys)) + if (!psys_check_enabled(ob, psys, G.is_rendering)) continue; if (ELEM(part->phystype, PART_PHYS_KEYED, PART_PHYS_BOIDS)) { @@ -2285,7 +2285,7 @@ static void dag_object_time_update_flags(Main *bmain, Scene *scene, Object *ob) ParticleSystem *psys = ob->particlesystem.first; for (; psys; psys = psys->next) { - if (psys_check_enabled(ob, psys)) { + if (psys_check_enabled(ob, psys, G.is_rendering)) { ob->recalc |= OB_RECALC_DATA; break; } diff --git a/source/blender/blenkernel/intern/displist.c b/source/blender/blenkernel/intern/displist.c index 98cbe47c7f9..49db75a0474 100644 --- a/source/blender/blenkernel/intern/displist.c +++ b/source/blender/blenkernel/intern/displist.c @@ -71,7 +71,7 @@ void BKE_displist_elem_free(DispList *dl) if (dl->verts) MEM_freeN(dl->verts); if (dl->nors) MEM_freeN(dl->nors); if (dl->index) MEM_freeN(dl->index); - if (dl->bevelSplitFlag) MEM_freeN(dl->bevelSplitFlag); + if (dl->bevel_split) MEM_freeN(dl->bevel_split); MEM_freeN(dl); } } @@ -144,8 +144,9 @@ void BKE_displist_copy(ListBase *lbn, ListBase *lb) dln->nors = MEM_dupallocN(dl->nors); dln->index = MEM_dupallocN(dl->index); - if (dl->bevelSplitFlag) - dln->bevelSplitFlag = MEM_dupallocN(dl->bevelSplitFlag); + if (dl->bevel_split) { + dln->bevel_split = MEM_dupallocN(dl->bevel_split); + } dl = dl->next; } @@ -1629,7 +1630,7 @@ static void do_makeDispListCurveTypes(Scene *scene, Object *ob, ListBase *dispba if (dlb->type == DL_POLY) { dl->flag |= DL_CYCL_U; } - if ((bl->poly >= 0) && (steps != 2)) { + if ((bl->poly >= 0) && (steps > 2)) { dl->flag |= DL_CYCL_V; } @@ -1642,8 +1643,7 @@ static void do_makeDispListCurveTypes(Scene *scene, Object *ob, ListBase *dispba /* CU_2D conflicts with R_NOPUNOFLIP */ dl->rt = nu->flag & ~CU_2D; - dl->bevelSplitFlag = MEM_callocN(sizeof(*dl->bevelSplitFlag) * ((steps + 0x1F) >> 5), - "bevelSplitFlag"); + dl->bevel_split = BLI_BITMAP_NEW(steps, "bevel_split"); /* for each point of poly make a bevel piece */ bevp_first = bl->bevpoints; @@ -1683,7 +1683,7 @@ static void do_makeDispListCurveTypes(Scene *scene, Object *ob, ListBase *dispba } if (bevp->split_tag) { - dl->bevelSplitFlag[a >> 5] |= 1 << (a & 0x1F); + BLI_BITMAP_ENABLE(dl->bevel_split, a); } /* rotate bevel piece and write in data */ diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c index 2d531e32f69..6207217f2c7 100644 --- a/source/blender/blenkernel/intern/dynamicpaint.c +++ b/source/blender/blenkernel/intern/dynamicpaint.c @@ -1826,14 +1826,14 @@ static DerivedMesh *dynamicPaint_Modifier_apply( DynamicPaintModifierApplyData data = {.surface = surface, .fcolor = fcolor}; BLI_task_parallel_range(0, sData->total_points, &data, dynamic_paint_apply_surface_vpaint_blend_cb, - sData->total_points > 1000); + sData->total_points > 1000); /* paint layer */ MLoopCol *mloopcol = CustomData_get_layer_named(&result->loopData, CD_MLOOPCOL, surface->output_name); /* if output layer is lost from a constructive modifier, re-add it */ if (!mloopcol && dynamicPaint_outputLayerExists(surface, ob, 0)) { mloopcol = CustomData_add_layer_named( - &result->loopData, CD_MLOOPCOL, CD_CALLOC, NULL, totloop, surface->output_name); + &result->loopData, CD_MLOOPCOL, CD_CALLOC, NULL, totloop, surface->output_name); } /* wet layer */ @@ -1841,7 +1841,7 @@ static DerivedMesh *dynamicPaint_Modifier_apply( /* if output layer is lost from a constructive modifier, re-add it */ if (!mloopcol_wet && dynamicPaint_outputLayerExists(surface, ob, 1)) { mloopcol_wet = CustomData_add_layer_named( - &result->loopData, CD_MLOOPCOL, CD_CALLOC, NULL, totloop, surface->output_name2); + &result->loopData, CD_MLOOPCOL, CD_CALLOC, NULL, totloop, surface->output_name2); } /* Save preview results to weight layer to be able to share same drawing methods */ @@ -1850,7 +1850,7 @@ static DerivedMesh *dynamicPaint_Modifier_apply( mloopcol_preview = CustomData_get_layer(&result->loopData, CD_PREVIEW_MLOOPCOL); if (!mloopcol_preview) { mloopcol_preview = CustomData_add_layer( - &result->loopData, CD_PREVIEW_MLOOPCOL, CD_CALLOC, NULL, totloop); + &result->loopData, CD_PREVIEW_MLOOPCOL, CD_CALLOC, NULL, totloop); } } @@ -2367,15 +2367,15 @@ static int dynamic_paint_find_neighbour_pixel( edge1_index = 0; edge2_index = 1; dist_squared = dist_squared_to_line_segment_v2( - pixel, - mloopuv[mlooptri[cPoint->tri_index].tri[0]].uv, - mloopuv[mlooptri[cPoint->tri_index].tri[1]].uv); + pixel, + mloopuv[mlooptri[cPoint->tri_index].tri[0]].uv, + mloopuv[mlooptri[cPoint->tri_index].tri[1]].uv); /* Dist to second edge */ t_dist_squared = dist_squared_to_line_segment_v2( - pixel, - mloopuv[mlooptri[cPoint->tri_index].tri[1]].uv, - mloopuv[mlooptri[cPoint->tri_index].tri[2]].uv); + pixel, + mloopuv[mlooptri[cPoint->tri_index].tri[1]].uv, + mloopuv[mlooptri[cPoint->tri_index].tri[2]].uv); if (t_dist_squared < dist_squared) { e1_index = cPoint->v2; e2_index = cPoint->v3; @@ -2386,9 +2386,9 @@ static int dynamic_paint_find_neighbour_pixel( /* Dist to third edge */ t_dist_squared = dist_squared_to_line_segment_v2( - pixel, - mloopuv[mlooptri[cPoint->tri_index].tri[2]].uv, - mloopuv[mlooptri[cPoint->tri_index].tri[0]].uv); + pixel, + mloopuv[mlooptri[cPoint->tri_index].tri[2]].uv, + mloopuv[mlooptri[cPoint->tri_index].tri[0]].uv); if (t_dist_squared < dist_squared) { e1_index = cPoint->v3; e2_index = cPoint->v1; @@ -2439,9 +2439,9 @@ static int dynamic_paint_find_neighbour_pixel( //printf("connected UV : %f,%f & %f,%f - %f,%f & %f,%f\n", s_uv1[0], s_uv1[1], s_uv2[0], s_uv2[1], t_uv1[0], t_uv1[1], t_uv2[0], t_uv2[1]); if (((s_uv1[0] == t_uv1[0] && s_uv1[1] == t_uv1[1]) && - (s_uv2[0] == t_uv2[0] && s_uv2[1] == t_uv2[1])) || - ((s_uv2[0] == t_uv1[0] && s_uv2[1] == t_uv1[1]) && - (s_uv1[0] == t_uv2[0] && s_uv1[1] == t_uv2[1]))) + (s_uv2[0] == t_uv2[0] && s_uv2[1] == t_uv2[1])) || + ((s_uv2[0] == t_uv1[0] && s_uv2[1] == t_uv1[1]) && + (s_uv1[0] == t_uv2[0] && s_uv1[1] == t_uv2[1]))) { return ((px + neighX[n_index]) + w * (py + neighY[n_index])); } @@ -2451,15 +2451,15 @@ static int dynamic_paint_find_neighbour_pixel( * on this other face UV */ lambda = closest_to_line_v2( - closest_point, pixel, - mloopuv[mlooptri[cPoint->tri_index].tri[edge1_index]].uv, - mloopuv[mlooptri[cPoint->tri_index].tri[edge2_index]].uv); + closest_point, pixel, + mloopuv[mlooptri[cPoint->tri_index].tri[edge1_index]].uv, + mloopuv[mlooptri[cPoint->tri_index].tri[edge2_index]].uv); CLAMP(lambda, 0.0f, 1.0f); sub_v2_v2v2( - dir_vec, - mloopuv[mlooptri[target_tri].tri[target_uv2]].uv, - mloopuv[mlooptri[target_tri].tri[target_uv1]].uv); + dir_vec, + mloopuv[mlooptri[target_tri].tri[target_uv2]].uv, + mloopuv[mlooptri[target_tri].tri[target_uv1]].uv); mul_v2_fl(dir_vec, lambda); @@ -2678,8 +2678,8 @@ int dynamicPaint_createUVSurface(Scene *scene, DynamicPaintSurface *surface, flo ImgSeqFormatData *f_data = MEM_callocN(sizeof(*f_data), "ImgSeqFormatData"); if (f_data) { f_data->uv_p = MEM_callocN(active_points * sizeof(*f_data->uv_p), "PaintUVPoint"); - f_data->barycentricWeights = MEM_callocN(active_points * aa_samples * sizeof(*f_data->barycentricWeights), - "PaintUVPoint"); + f_data->barycentricWeights = + MEM_callocN(active_points * aa_samples * sizeof(*f_data->barycentricWeights), "PaintUVPoint"); if (!f_data->uv_p || !f_data->barycentricWeights) error = 1; @@ -2881,7 +2881,7 @@ void dynamicPaint_outputSurfaceImage(DynamicPaintSurface *surface, char *filenam } DynamicPaintOutputSurfaceImageData data = {.surface = surface, .ibuf = ibuf}; - switch(surface->type) { + switch (surface->type) { case MOD_DPAINT_SURFACE_T_PAINT: switch (output_layer) { case 0: @@ -3883,12 +3883,12 @@ static int dynamicPaint_paintMesh(DynamicPaintSurface *surface, /* loop through cell points and process brush */ DynamicPaintPaintData data = { - .surface = surface, + .surface = surface, .brush = brush, .brushOb = brushOb, .bMats = bMats, .scene = scene, .timescale = timescale, .c_index = c_index, - .dm = dm, .mvert = mvert, .mloop = mloop, .mlooptri = mlooptri, - .brush_radius = brush_radius, .avg_brushNor = avg_brushNor, .brushVelocity = brushVelocity, - .treeData = &treeData + .dm = dm, .mvert = mvert, .mloop = mloop, .mlooptri = mlooptri, + .brush_radius = brush_radius, .avg_brushNor = avg_brushNor, .brushVelocity = brushVelocity, + .treeData = &treeData }; BLI_task_parallel_range_ex(0, grid->s_num[c_index], &data, NULL, 0, dynamic_paint_paint_mesh_cell_point_cb_ex, @@ -4170,10 +4170,10 @@ static int dynamicPaint_paintParticles(DynamicPaintSurface *surface, /* loop through cell points */ DynamicPaintPaintData data = { - .surface = surface, + .surface = surface, .brush = brush, .psys = psys, .solidradius = solidradius, .timescale = timescale, .c_index = c_index, - .treeData = tree, + .treeData = tree, }; BLI_task_parallel_range_ex(0, grid->s_num[c_index], &data, NULL, 0, dynamic_paint_paint_particle_cell_point_cb_ex, @@ -4313,16 +4313,16 @@ static int dynamicPaint_paintSinglePoint( * Loop through every surface point */ DynamicPaintPaintData data = { - .surface = surface, - .brush = brush, .brushOb = brushOb, .bMats = bMats, - .scene = scene, .timescale = timescale, - .mvert = mvert, - .brush_radius = brush_radius, .brushVelocity = &brushVel, + .surface = surface, + .brush = brush, .brushOb = brushOb, .bMats = bMats, + .scene = scene, .timescale = timescale, + .mvert = mvert, + .brush_radius = brush_radius, .brushVelocity = &brushVel, .pointCoord = pointCoord, }; BLI_task_parallel_range_ex(0, sData->total_points, &data, NULL, 0, - dynamic_paint_paint_single_point_cb_ex, - sData->total_points > 1000, true); + dynamic_paint_paint_single_point_cb_ex, + sData->total_points > 1000, true); return 1; } @@ -4755,83 +4755,83 @@ static void dynamic_paint_effect_drip_cb(void *userdata, const int index) { const DynamicPaintEffectData *data = userdata; - const DynamicPaintSurface *surface = data->surface; - const PaintSurfaceData *sData = surface->data; - BakeAdjPoint *bNeighs = sData->bData->bNeighs; - PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index]; - const PaintPoint *prevPoint = data->prevPoint; - const PaintPoint *pPoint_prev = &prevPoint[index]; - const float *force = data->force; - const float eff_scale = data->eff_scale; + const DynamicPaintSurface *surface = data->surface; + const PaintSurfaceData *sData = surface->data; + BakeAdjPoint *bNeighs = sData->bData->bNeighs; + PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index]; + const PaintPoint *prevPoint = data->prevPoint; + const PaintPoint *pPoint_prev = &prevPoint[index]; + const float *force = data->force; + const float eff_scale = data->eff_scale; - const int *n_target = sData->adj_data->n_target; + const int *n_target = sData->adj_data->n_target; - uint8_t *point_locks = data->point_locks; + uint8_t *point_locks = data->point_locks; - int closest_id[2]; - float closest_d[2]; + int closest_id[2]; + float closest_d[2]; - /* adjust drip speed depending on wetness */ - float w_factor = pPoint_prev->wetness - 0.025f; - if (w_factor <= 0) - return; - CLAMP(w_factor, 0.0f, 1.0f); + /* adjust drip speed depending on wetness */ + float w_factor = pPoint_prev->wetness - 0.025f; + if (w_factor <= 0) + return; + CLAMP(w_factor, 0.0f, 1.0f); - /* get force affect points */ - surface_determineForceTargetPoints(sData, index, &force[index * 4], closest_d, closest_id); + /* get force affect points */ + surface_determineForceTargetPoints(sData, index, &force[index * 4], closest_d, closest_id); - /* Apply movement towards those two points */ - for (int i = 0; i < 2; i++) { - const int n_idx = closest_id[i]; - if (n_idx != -1 && closest_d[i] > 0.0f) { - const float dir_dot = closest_d[i]; + /* Apply movement towards those two points */ + for (int i = 0; i < 2; i++) { + const int n_idx = closest_id[i]; + if (n_idx != -1 && closest_d[i] > 0.0f) { + const float dir_dot = closest_d[i]; - /* just skip if angle is too extreme */ - if (dir_dot <= 0.0f) - continue; + /* just skip if angle is too extreme */ + if (dir_dot <= 0.0f) + continue; - float dir_factor, a_factor; - const float speed_scale = eff_scale * force[index * 4 + 3] / bNeighs[n_idx].dist; + float dir_factor, a_factor; + const float speed_scale = eff_scale * force[index * 4 + 3] / bNeighs[n_idx].dist; - const unsigned int n_trgt = (unsigned int)n_target[n_idx]; + const unsigned int n_trgt = (unsigned int)n_target[n_idx]; - /* Sort of spinlock, but only for given ePoint. - * Since the odds a same ePoint is modified at the same time by several threads is very low, this is - * much more eficient than a global spin lock. */ - const unsigned int pointlock_idx = n_trgt / 8; - const uint8_t pointlock_bitmask = 1 << (n_trgt & 7); /* 7 == 0b111 */ - while (atomic_fetch_and_or_uint8(&point_locks[pointlock_idx], pointlock_bitmask) & pointlock_bitmask); + /* Sort of spinlock, but only for given ePoint. + * Since the odds a same ePoint is modified at the same time by several threads is very low, this is + * much more eficient than a global spin lock. */ + const unsigned int pointlock_idx = n_trgt / 8; + const uint8_t pointlock_bitmask = 1 << (n_trgt & 7); /* 7 == 0b111 */ + while (atomic_fetch_and_or_uint8(&point_locks[pointlock_idx], pointlock_bitmask) & pointlock_bitmask); - PaintPoint *ePoint = &((PaintPoint *)sData->type_data)[n_trgt]; - const float e_wet = ePoint->wetness; + PaintPoint *ePoint = &((PaintPoint *)sData->type_data)[n_trgt]; + const float e_wet = ePoint->wetness; - dir_factor = min_ff(0.5f, dir_dot * min_ff(speed_scale, 1.0f) * w_factor); + dir_factor = min_ff(0.5f, dir_dot * min_ff(speed_scale, 1.0f) * w_factor); - /* mix new wetness */ - ePoint->wetness += dir_factor; - CLAMP(ePoint->wetness, 0.0f, MAX_WETNESS); + /* mix new wetness */ + ePoint->wetness += dir_factor; + CLAMP(ePoint->wetness, 0.0f, MAX_WETNESS); - /* mix new color */ - a_factor = dir_factor / pPoint_prev->wetness; - CLAMP(a_factor, 0.0f, 1.0f); - mixColors(ePoint->e_color, ePoint->e_color[3], pPoint_prev->e_color, pPoint_prev->e_color[3], a_factor); - /* dripping is supposed to preserve alpha level */ - if (pPoint_prev->e_color[3] > ePoint->e_color[3]) { - ePoint->e_color[3] += a_factor * pPoint_prev->e_color[3]; - CLAMP_MAX(ePoint->e_color[3], pPoint_prev->e_color[3]); - } + /* mix new color */ + a_factor = dir_factor / pPoint_prev->wetness; + CLAMP(a_factor, 0.0f, 1.0f); + mixColors(ePoint->e_color, ePoint->e_color[3], pPoint_prev->e_color, pPoint_prev->e_color[3], a_factor); + /* dripping is supposed to preserve alpha level */ + if (pPoint_prev->e_color[3] > ePoint->e_color[3]) { + ePoint->e_color[3] += a_factor * pPoint_prev->e_color[3]; + CLAMP_MAX(ePoint->e_color[3], pPoint_prev->e_color[3]); + } - /* decrease paint wetness on current point */ - pPoint->wetness -= (ePoint->wetness - e_wet); - CLAMP(pPoint->wetness, 0.0f, MAX_WETNESS); + /* decrease paint wetness on current point */ + pPoint->wetness -= (ePoint->wetness - e_wet); + CLAMP(pPoint->wetness, 0.0f, MAX_WETNESS); #ifndef NDEBUG uint8_t ret = atomic_fetch_and_and_uint8(&point_locks[pointlock_idx], ~pointlock_bitmask); - BLI_assert(ret & pointlock_bitmask); + BLI_assert(ret & pointlock_bitmask); #else atomic_fetch_and_and_uint8(&point_locks[pointlock_idx], ~pointlock_bitmask); #endif - } + } } } @@ -4892,7 +4892,7 @@ static void dynamicPaint_doEffectStep( memcpy(prevPoint, sData->type_data, sData->total_points * sizeof(struct PaintPoint)); DynamicPaintEffectData data = { - .surface = surface, .prevPoint = prevPoint, + .surface = surface, .prevPoint = prevPoint, .eff_scale = eff_scale, .force = force, .point_locks = point_locks, }; @@ -5108,7 +5108,7 @@ static void dynamic_paint_surface_pre_step_cb(void *userdata, const int index) if (pPoint->color[3]) { for (i = 0; i < 3; i++) { pPoint->color[i] = (f_color[i] * f_color[3] - pPoint->e_color[i] * pPoint->e_color[3]) / - (pPoint->color[3] * (1.0f - pPoint->e_color[3])); + (pPoint->color[3] * (1.0f - pPoint->e_color[3])); } } } @@ -5129,17 +5129,17 @@ static void dynamic_paint_surface_pre_step_cb(void *userdata, const int index) if (surface->flags & MOD_DPAINT_DISSOLVE) { value_dissolve(&pPoint->color[3], surface->diss_speed, timescale, - (surface->flags & MOD_DPAINT_DISSOLVE_LOG) != 0); + (surface->flags & MOD_DPAINT_DISSOLVE_LOG) != 0); CLAMP_MIN(pPoint->color[3], 0.0f); value_dissolve(&pPoint->e_color[3], surface->diss_speed, timescale, - (surface->flags & MOD_DPAINT_DISSOLVE_LOG) != 0); + (surface->flags & MOD_DPAINT_DISSOLVE_LOG) != 0); CLAMP_MIN(pPoint->e_color[3], 0.0f); } } /* dissolve for float types */ else if (surface->flags & MOD_DPAINT_DISSOLVE && - (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE || surface->type == MOD_DPAINT_SURFACE_T_WEIGHT)) + (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE || surface->type == MOD_DPAINT_SURFACE_T_WEIGHT)) { float *point = &((float *)sData->type_data)[index]; /* log or linear */ @@ -5388,7 +5388,7 @@ static int dynamicPaint_generateBakeData(DynamicPaintSurface *surface, const Sce */ DynamicPaintGenerateBakeData data = { .surface = surface, .ob = ob, - .mvert = mvert, .canvas_verts = canvas_verts, + .mvert = mvert, .canvas_verts = canvas_verts, .do_velocity_data = do_velocity_data, .new_bdata = new_bdata, }; BLI_task_parallel_range( @@ -5503,7 +5503,7 @@ static int dynamicPaint_doStep(Scene *scene, Object *ob, DynamicPaintSurface *su if (brush->collision == MOD_DPAINT_COL_PSYS) { if (brush->psys && brush->psys->part && ELEM(brush->psys->part->type, PART_EMITTER, PART_FLUID) && - psys_check_enabled(brushObj, brush->psys)) + psys_check_enabled(brushObj, brush->psys, G.is_rendering)) { /* Paint a particle system */ BKE_animsys_evaluate_animdata(scene, &brush->psys->part->id, brush->psys->part->adt, diff --git a/source/blender/blenkernel/intern/editderivedmesh.c b/source/blender/blenkernel/intern/editderivedmesh.c index ffd000eed88..1aba76baa2c 100644 --- a/source/blender/blenkernel/intern/editderivedmesh.c +++ b/source/blender/blenkernel/intern/editderivedmesh.c @@ -1181,6 +1181,14 @@ static void emDM_drawMappedFaces( /* if non zero we know a face was rendered */ if (poly_prev != GL_ZERO) glEnd(); + + if (draw_option_prev == DM_DRAW_OPTION_STIPPLE) { + GPU_basic_shader_bind(GPU_SHADER_USE_COLOR); + } + + if (shade_prev == GL_FLAT) { + glShadeModel(GL_SMOOTH); + } } static void bmdm_get_tri_uv(BMLoop *ltri[3], MLoopUV *luv[3], const int cd_loop_uv_offset) @@ -1236,8 +1244,6 @@ static void emDM_drawFacesTex_common( // dummylcol.r = dummylcol.g = dummylcol.b = dummylcol.a = 255; /* UNUSED */ /* always use smooth shading even for flat faces, else vertex colors wont interpolate */ - glShadeModel(GL_SMOOTH); - BM_mesh_elem_index_ensure(bm, BM_FACE); /* call again below is ok */ @@ -1384,8 +1390,6 @@ static void emDM_drawFacesTex_common( } } } - - glShadeModel(GL_FLAT); } static void emDM_drawFacesTex( @@ -1524,8 +1528,6 @@ static void emDM_drawMappedFacesGLSL( vertexNos = bmdm->vertexNos; polyNos = bmdm->polyNos; - /* always use smooth shading even for flat faces, else vertex colors wont interpolate */ - glShadeModel(GL_SMOOTH); BM_mesh_elem_index_ensure(bm, (BM_VERT | BM_FACE) | (lnors ? BM_LOOP : 0)); for (i = 0; i < em->tottri; i++) { @@ -1636,8 +1638,6 @@ static void emDM_drawMappedFacesMat( vertexNos = bmdm->vertexNos; polyNos = bmdm->polyNos; - /* always use smooth shading even for flat faces, else vertex colors wont interpolate */ - glShadeModel(GL_SMOOTH); BM_mesh_elem_index_ensure(bm, (BM_VERT | BM_FACE) | (lnors ? BM_LOOP : 0)); for (i = 0; i < em->tottri; i++) { @@ -2226,16 +2226,17 @@ static CustomData *bmDm_getPolyDataLayout(DerivedMesh *dm) return &bmdm->em->bm->pdata; } - +/** + * \note This may be called per-draw, + * avoid allocating large arrays where possible and keep this a thin wrapper for #BMesh. + */ DerivedMesh *getEditDerivedBMesh( - BMEditMesh *em, - Object *UNUSED(ob), + BMEditMesh *em, struct Object *UNUSED(ob), + CustomDataMask data_mask, float (*vertexCos)[3]) { EditDerivedBMesh *bmdm = MEM_callocN(sizeof(*bmdm), __func__); BMesh *bm = em->bm; - const int cd_dvert_offset = CustomData_get_offset(&bm->vdata, CD_MDEFORMVERT); - const int cd_skin_offset = CustomData_get_offset(&bm->vdata, CD_MVERT_SKIN); bmdm->em = em; @@ -2304,6 +2305,9 @@ DerivedMesh *getEditDerivedBMesh( bmdm->vertexCos = (const float (*)[3])vertexCos; bmdm->dm.deformedOnly = (vertexCos != NULL); + const int cd_dvert_offset = (data_mask & CD_MASK_MDEFORMVERT) ? + CustomData_get_offset(&bm->vdata, CD_MDEFORMVERT) : -1; + if (cd_dvert_offset != -1) { BMIter iter; BMVert *eve; @@ -2317,6 +2321,9 @@ DerivedMesh *getEditDerivedBMesh( } } + const int cd_skin_offset = (data_mask & CD_MASK_MVERT_SKIN) ? + CustomData_get_offset(&bm->vdata, CD_MVERT_SKIN) : -1; + if (cd_skin_offset != -1) { BMIter iter; BMVert *eve; diff --git a/source/blender/blenkernel/intern/effect.c b/source/blender/blenkernel/intern/effect.c index f06dd6f9de4..5090e46f1fc 100644 --- a/source/blender/blenkernel/intern/effect.c +++ b/source/blender/blenkernel/intern/effect.c @@ -139,9 +139,6 @@ void free_partdeflect(PartDeflect *pd) if (!pd) return; - if (pd->tex) - id_us_min(&pd->tex->id); - if (pd->rng) BLI_rng_free(pd->rng); @@ -182,7 +179,7 @@ static void add_particles_to_effectors(ListBase **effectors, Scene *scene, Effec { ParticleSettings *part= psys->part; - if ( !psys_check_enabled(ob, psys) ) + if ( !psys_check_enabled(ob, psys, G.is_rendering) ) return; if ( psys == psys_src && (part->flag & PART_SELF_EFFECT) == 0) diff --git a/source/blender/blenkernel/intern/font.c b/source/blender/blenkernel/intern/font.c index aed33d2c64d..5e1f8814ed6 100644 --- a/source/blender/blenkernel/intern/font.c +++ b/source/blender/blenkernel/intern/font.c @@ -95,10 +95,9 @@ void BKE_vfont_free_data(struct VFont *vfont) } } +/** Free (or release) any data used by this font (does not free the font itself). */ void BKE_vfont_free(struct VFont *vf) { - if (vf == NULL) return; - BKE_vfont_free_data(vf); if (vf->packedfile) { @@ -541,7 +540,7 @@ int BKE_vfont_select_get(Object *ob, int *r_start, int *r_end) BLI_assert(ef->len >= 0); BLI_assert(ef->selstart >= 0 && ef->selstart <= ef->len + 1); - BLI_assert(ef->selend >= 0 && ef->selend <= ef->len); + BLI_assert(ef->selend >= 0 && ef->selend <= ef->len + 1); BLI_assert(ef->pos >= 0 && ef->pos <= ef->len); if (ef->selstart == 0) { @@ -628,6 +627,8 @@ bool BKE_vfont_to_curve_ex(Main *bmain, Object *ob, int mode, ListBase *r_nubase bool use_textbox; VChar *che; struct CharTrans *chartransdata = NULL, *ct; + /* Text at the beginning of the last used text-box (use for y-axis alignment). */ + int i_textbox = 0; struct TempLineInfo *lineinfo; float *f, xof, yof, xtrax, linedist; float twidth, maxlen = 0; @@ -830,6 +831,7 @@ makebreak: (cu->totbox > (curbox + 1)) && ((-(yof - tb_scale.y)) > (tb_scale.h - linedist) - yof_scale)) { + i_textbox = i + 1; maxlen = 0; curbox++; @@ -908,10 +910,10 @@ makebreak: /* linedata is now: width of line */ - if (cu->spacemode != CU_LEFT) { + if (cu->spacemode != CU_ALIGN_X_LEFT) { ct = chartransdata; - if (cu->spacemode == CU_RIGHT) { + if (cu->spacemode == CU_ALIGN_X_RIGHT) { struct TempLineInfo *li; for (i = 0, li = lineinfo; i < lnr; i++, li++) { @@ -923,7 +925,7 @@ makebreak: ct++; } } - else if (cu->spacemode == CU_MIDDLE) { + else if (cu->spacemode == CU_ALIGN_X_MIDDLE) { struct TempLineInfo *li; for (i = 0, li = lineinfo; i < lnr; i++, li++) { @@ -935,7 +937,7 @@ makebreak: ct++; } } - else if ((cu->spacemode == CU_FLUSH) && use_textbox) { + else if ((cu->spacemode == CU_ALIGN_X_FLUSH) && use_textbox) { struct TempLineInfo *li; for (i = 0, li = lineinfo; i < lnr; i++, li++) { @@ -956,7 +958,7 @@ makebreak: ct++; } } - else if ((cu->spacemode == CU_JUSTIFY) && use_textbox) { + else if ((cu->spacemode == CU_ALIGN_X_JUSTIFY) && use_textbox) { float curofs = 0.0f; for (i = 0; i <= slen; i++) { for (j = i; @@ -983,6 +985,60 @@ makebreak: } } + /* top-baseline is default, in this case, do nothing */ + if (cu->align_y != CU_ALIGN_Y_TOP_BASELINE) { + if (tb_scale.h != 0.0f) { + /* top and top-baseline are the same when text-boxes are used */ + if (cu->align_y != CU_ALIGN_Y_TOP && i_textbox < slen) { + /* all previous textboxes are 'full', only align the last used text-box */ + float yoff; + int lines; + struct CharTrans *ct_last, *ct_textbox; + + ct_last = chartransdata + slen - 1; + ct_textbox = chartransdata + i_textbox; + + lines = ct_last->linenr - ct_textbox->linenr + 1; + if (mem[slen - 1] == '\n') { + lines++; + } + + if (cu->align_y == CU_ALIGN_Y_BOTTOM) { + yoff = (lines * linedist) - tb_scale.h; + } + else if (cu->align_y == CU_ALIGN_Y_CENTER) { + yoff = 0.5f * ((lines * linedist) - tb_scale.h); + } + + ct = ct_textbox; + for (i = i_textbox - 1; i < slen; i++) { + ct->yof += yoff; + ct++; + } + } + } + else { + /* non text-box case handled separately */ + ct = chartransdata; + float yoff; + + if (cu->align_y == CU_ALIGN_Y_TOP) { + yoff = -linedist; + } + else if (cu->align_y == CU_ALIGN_Y_BOTTOM) { + yoff = (lnr - 1.0f) * linedist; + } + else if (cu->align_y == CU_ALIGN_Y_CENTER) { + yoff = (lnr - 2.0f) * linedist * 0.5f; + } + + for (i = 0; i <= slen; i++) { + ct->yof += yoff; + ct++; + } + } + } + MEM_freeN(lineinfo); /* TEXT ON CURVE */ @@ -1021,13 +1077,13 @@ makebreak: /* path longer than text: spacemode involves */ distfac = 1.0f / distfac; - if (cu->spacemode == CU_RIGHT) { + if (cu->spacemode == CU_ALIGN_X_RIGHT) { timeofs = 1.0f - distfac; } - else if (cu->spacemode == CU_MIDDLE) { + else if (cu->spacemode == CU_ALIGN_X_MIDDLE) { timeofs = (1.0f - distfac) / 2.0f; } - else if (cu->spacemode == CU_FLUSH) { + else if (cu->spacemode == CU_ALIGN_X_FLUSH) { distfac = 1.0f; } } diff --git a/source/blender/blenkernel/intern/gpencil.c b/source/blender/blenkernel/intern/gpencil.c index f3eb5430bce..af1bcd0c545 100644 --- a/source/blender/blenkernel/intern/gpencil.c +++ b/source/blender/blenkernel/intern/gpencil.c @@ -113,16 +113,13 @@ void free_gpencil_layers(ListBase *list) } /* Free all of GPencil datablock's related data, but not the block itself */ +/** Free (or release) any data used by this grease pencil (does not free the gpencil itself). */ void BKE_gpencil_free(bGPdata *gpd) { + BKE_animdata_free(&gpd->id, false); + /* free layers */ free_gpencil_layers(&gpd->layers); - - /* free animation data */ - if (gpd->adt) { - BKE_animdata_free(&gpd->id); - gpd->adt = NULL; - } } /* -------- Container Creation ---------- */ diff --git a/source/blender/blenkernel/intern/group.c b/source/blender/blenkernel/intern/group.c index a44eb1df9fe..4fdee7e3633 100644 --- a/source/blender/blenkernel/intern/group.c +++ b/source/blender/blenkernel/intern/group.c @@ -60,79 +60,19 @@ static void free_group_object(GroupObject *go) MEM_freeN(go); } - +/** Free (or release) any data used by this group (does not free the group itself). */ void BKE_group_free(Group *group) { /* don't free group itself */ GroupObject *go; - BKE_previewimg_free(&group->preview); + /* No animdata here. */ while ((go = BLI_pophead(&group->gobject))) { free_group_object(go); } -} -void BKE_group_unlink(Main *bmain, Group *group) -{ - Material *ma; - Object *ob; - Scene *sce; - SceneRenderLayer *srl; - ParticleSystem *psys; - - for (ma = bmain->mat.first; ma; ma = ma->id.next) { - if (ma->group == group) - ma->group = NULL; - } - for (ma = bmain->mat.first; ma; ma = ma->id.next) { - if (ma->group == group) - ma->group = NULL; - } - for (sce = bmain->scene.first; sce; sce = sce->id.next) { - Base *base = sce->base.first; - - /* ensure objects are not in this group */ - for (; base; base = base->next) { - if (BKE_group_object_unlink(group, base->object, sce, base) && - BKE_group_object_find(NULL, base->object) == NULL) - { - base->object->flag &= ~OB_FROMGROUP; - base->flag &= ~OB_FROMGROUP; - } - } - - for (srl = sce->r.layers.first; srl; srl = srl->next) { - FreestyleLineSet *lineset; - - if (srl->light_override == group) - srl->light_override = NULL; - for (lineset = srl->freestyleConfig.linesets.first; lineset; lineset = lineset->next) { - if (lineset->group == group) - lineset->group = NULL; - } - } - } - - for (ob = bmain->object.first; ob; ob = ob->id.next) { - - if (ob->dup_group == group) { - ob->dup_group = NULL; - } - - for (psys = ob->particlesystem.first; psys; psys = psys->next) { - if (psys->part->dup_group == group) - psys->part->dup_group = NULL; -#if 0 /* not used anymore, only keps for readfile.c, no need to account for this */ - if (psys->part->eff_group == group) - psys->part->eff_group = NULL; -#endif - } - } - - /* group stays in library, but no members */ - BKE_group_free(group); - group->id.us = 0; + BKE_previewimg_free(&group->preview); } Group *BKE_group_add(Main *bmain, const char *name) diff --git a/source/blender/blenkernel/intern/idcode.c b/source/blender/blenkernel/intern/idcode.c index 68a741bc3fc..90b3713e47c 100644 --- a/source/blender/blenkernel/intern/idcode.c +++ b/source/blender/blenkernel/intern/idcode.c @@ -39,6 +39,7 @@ #include "BLT_translation.h" +#include "BKE_library.h" #include "BKE_idcode.h" typedef struct { @@ -54,6 +55,7 @@ typedef struct { /* plural need to match rna_main.c's MainCollectionDef */ /* WARNING! Keep it in sync with i18n contexts in BLT_translation.h */ static IDType idtypes[] = { + /** ID's directly below must all be in #Main, and be kept in sync with #MAX_LIBARRAY (membership, not order) */ { ID_AC, "Action", "actions", BLT_I18NCONTEXT_ID_ACTION, IDTYPE_FLAGS_ISLINKABLE }, { ID_AR, "Armature", "armatures", BLT_I18NCONTEXT_ID_ARMATURE, IDTYPE_FLAGS_ISLINKABLE }, { ID_BR, "Brush", "brushes", BLT_I18NCONTEXT_ID_BRUSH, IDTYPE_FLAGS_ISLINKABLE }, @@ -61,7 +63,6 @@ static IDType idtypes[] = { { ID_CU, "Curve", "curves", BLT_I18NCONTEXT_ID_CURVE, IDTYPE_FLAGS_ISLINKABLE }, { ID_GD, "GPencil", "grease_pencil", BLT_I18NCONTEXT_ID_GPENCIL, IDTYPE_FLAGS_ISLINKABLE }, /* rename gpencil */ { ID_GR, "Group", "groups", BLT_I18NCONTEXT_ID_GROUP, IDTYPE_FLAGS_ISLINKABLE }, - { ID_ID, "ID", "ids", BLT_I18NCONTEXT_ID_ID, 0 }, /* plural is fake */ { ID_IM, "Image", "images", BLT_I18NCONTEXT_ID_IMAGE, IDTYPE_FLAGS_ISLINKABLE }, { ID_IP, "Ipo", "ipos", "", IDTYPE_FLAGS_ISLINKABLE }, /* deprecated */ { ID_KE, "Key", "shape_keys", BLT_I18NCONTEXT_ID_SHAPEKEY, 0 }, @@ -89,8 +90,14 @@ static IDType idtypes[] = { { ID_VF, "VFont", "fonts", BLT_I18NCONTEXT_ID_VFONT, IDTYPE_FLAGS_ISLINKABLE }, { ID_WO, "World", "worlds", BLT_I18NCONTEXT_ID_WORLD, IDTYPE_FLAGS_ISLINKABLE }, { ID_WM, "WindowManager", "window_managers", BLT_I18NCONTEXT_ID_WINDOWMANAGER, 0 }, + + /** Keep last, not an ID exactly, only include for completeness */ + { ID_ID, "ID", "ids", BLT_I18NCONTEXT_ID_ID, 0 }, /* plural is fake */ }; +/* -1 for ID_ID */ +BLI_STATIC_ASSERT((ARRAY_SIZE(idtypes) - 1 == MAX_LIBARRAY), "Missing IDType"); + static IDType *idtype_from_name(const char *str) { int i = ARRAY_SIZE(idtypes); @@ -117,7 +124,7 @@ static IDType *idtype_from_code(short idcode) /** * Return if the ID code is a valid ID code. * - * \param code The code to check. + * \param idcode: The code to check. * \return Boolean, 0 when invalid. */ bool BKE_idcode_is_valid(short idcode) @@ -128,7 +135,7 @@ bool BKE_idcode_is_valid(short idcode) /** * Return non-zero when an ID type is linkable. * - * \param code The code to check. + * \param idcode: The code to check. * \return Boolean, 0 when non linkable. */ bool BKE_idcode_is_linkable(short idcode) @@ -141,7 +148,7 @@ bool BKE_idcode_is_linkable(short idcode) /** * Convert an idcode into a name. * - * \param code The code to convert. + * \param idcode: The code to convert. * \return A static string representing the name of * the code. */ @@ -254,7 +261,7 @@ short BKE_idcode_from_idfilter(const int idfilter) /** * Convert an idcode into a name (plural). * - * \param code The code to convert. + * \param idcode: The code to convert. * \return A static string representing the name of * the code. */ @@ -268,7 +275,7 @@ const char *BKE_idcode_to_name_plural(short idcode) /** * Convert an idcode into its translations' context. * - * \param code The code to convert. + * \param idcode: The code to convert. * \return A static string representing the i18n context of the code. */ const char *BKE_idcode_to_translation_context(short idcode) diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c index 0b2c844cb2c..69384a70969 100644 --- a/source/blender/blenkernel/intern/image.c +++ b/source/blender/blenkernel/intern/image.c @@ -95,8 +95,6 @@ #include "DNA_screen_types.h" #include "DNA_view3d_types.h" -#include "WM_api.h" - static SpinLock image_spin; /* prototypes */ @@ -324,20 +322,16 @@ void BKE_image_free_buffers(Image *ima) ima->ok = IMA_OK; } -/* called by library too, do not free ima itself */ +/** Free (or release) any data used by this image (does not free the image itself). */ void BKE_image_free(Image *ima) { int a; + /* Also frees animdata. */ BKE_image_free_buffers(ima); image_free_packedfiles(ima); - BKE_icon_id_delete(&ima->id); - ima->id.icon_id = 0; - - BKE_previewimg_free(&ima->preview); - for (a = 0; a < IMA_MAX_RENDER_SLOT; a++) { if (ima->renders[a]) { RE_FreeRenderResult(ima->renders[a]); @@ -346,7 +340,10 @@ void BKE_image_free(Image *ima) } BKE_image_free_views(ima); - MEM_freeN(ima->stereo3d_format); + MEM_SAFE_FREE(ima->stereo3d_format); + + BKE_icon_id_delete(&ima->id); + BKE_previewimg_free(&ima->preview); } /* only image block itself */ diff --git a/source/blender/blenkernel/intern/key.c b/source/blender/blenkernel/intern/key.c index 362f41335d2..2517e2cc197 100644 --- a/source/blender/blenkernel/intern/key.c +++ b/source/blender/blenkernel/intern/key.c @@ -74,11 +74,13 @@ #define IPO_BEZTRIPLE 100 #define IPO_BPOINT 101 + +/** Free (or release) any data used by this shapekey (does not free the key itself). */ void BKE_key_free(Key *key) { KeyBlock *kb; - - BKE_animdata_free((ID *)key); + + BKE_animdata_free((ID *)key, false); while ((kb = BLI_pophead(&key->block))) { if (kb->data) diff --git a/source/blender/blenkernel/intern/lamp.c b/source/blender/blenkernel/intern/lamp.c index 49a573489ef..692b703f721 100644 --- a/source/blender/blenkernel/intern/lamp.c +++ b/source/blender/blenkernel/intern/lamp.c @@ -234,7 +234,7 @@ void BKE_lamp_free(Lamp *la) MEM_freeN(mtex); } - BKE_animdata_free((ID *)la); + BKE_animdata_free((ID *)la, false); curvemapping_free(la->curfalloff); diff --git a/source/blender/blenkernel/intern/lattice.c b/source/blender/blenkernel/intern/lattice.c index b350e932281..58c0a567116 100644 --- a/source/blender/blenkernel/intern/lattice.c +++ b/source/blender/blenkernel/intern/lattice.c @@ -300,24 +300,27 @@ Lattice *BKE_lattice_copy(Lattice *lt) return ltn; } +/** Free (or release) any data used by this lattice (does not free the lattice itself). */ void BKE_lattice_free(Lattice *lt) { - if (lt->def) MEM_freeN(lt->def); - if (lt->dvert) BKE_defvert_array_free(lt->dvert, lt->pntsu * lt->pntsv * lt->pntsw); + BKE_animdata_free(<->id, false); + + MEM_SAFE_FREE(lt->def); + if (lt->dvert) { + BKE_defvert_array_free(lt->dvert, lt->pntsu * lt->pntsv * lt->pntsw); + lt->dvert = NULL; + } if (lt->editlatt) { Lattice *editlt = lt->editlatt->latt; - if (editlt->def) MEM_freeN(editlt->def); - if (editlt->dvert) BKE_defvert_array_free(editlt->dvert, lt->pntsu * lt->pntsv * lt->pntsw); + if (editlt->def) + MEM_freeN(editlt->def); + if (editlt->dvert) + BKE_defvert_array_free(editlt->dvert, lt->pntsu * lt->pntsv * lt->pntsw); MEM_freeN(editlt); MEM_freeN(lt->editlatt); - } - - /* free animation data */ - if (lt->adt) { - BKE_animdata_free(<->id); - lt->adt = NULL; + lt->editlatt = NULL; } } diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c index 961b45df4e6..fe16df18813 100644 --- a/source/blender/blenkernel/intern/library.c +++ b/source/blender/blenkernel/intern/library.c @@ -84,7 +84,6 @@ #include "BKE_context.h" #include "BKE_curve.h" #include "BKE_depsgraph.h" -#include "BKE_fcurve.h" #include "BKE_font.h" #include "BKE_global.h" #include "BKE_group.h" @@ -92,7 +91,6 @@ #include "BKE_idcode.h" #include "BKE_idprop.h" #include "BKE_image.h" -#include "BKE_ipo.h" #include "BKE_key.h" #include "BKE_lamp.h" #include "BKE_lattice.h" @@ -103,16 +101,12 @@ #include "BKE_material.h" #include "BKE_main.h" #include "BKE_mball.h" -#include "BKE_movieclip.h" #include "BKE_mask.h" #include "BKE_node.h" #include "BKE_object.h" -#include "BKE_paint.h" #include "BKE_particle.h" #include "BKE_packedFile.h" #include "BKE_speaker.h" -#include "BKE_sound.h" -#include "BKE_screen.h" #include "BKE_scene.h" #include "BKE_text.h" #include "BKE_texture.h" @@ -125,10 +119,6 @@ #include "IMB_imbuf.h" #include "IMB_imbuf_types.h" -#ifdef WITH_PYTHON -#include "BPY_extern.h" -#endif - /* GS reads the memory pointed at in a specific ordering. * only use this definition, makes little and big endian systems * work fine, in conjunction with MAKE_ID */ @@ -182,7 +172,6 @@ void id_us_ensure_real(ID *id) } } -/* Unused currently... */ void id_us_clear_real(ID *id) { if (id && (id->tag & LIB_TAG_EXTRAUSER)) { @@ -232,9 +221,7 @@ void id_us_min(ID *id) if (id->us <= limit) { printf("ID user decrement error: %s (from '%s'): %d <= %d\n", id->name, id->lib ? id->lib->filepath : "[Main]", id->us, limit); - /* We cannot assert here, because of how we 'delete' datablocks currently (setting their usercount to zero), - * this is weak but it's how it works for now. */ - /* BLI_assert(0); */ + BLI_assert(0); id->us = limit; } else { @@ -462,37 +449,6 @@ bool id_copy(ID *id, ID **newid, bool test) return false; } -bool id_unlink(ID *id, int test) -{ - Main *mainlib = G.main; - short type = GS(id->name); - - switch (type) { - case ID_TXT: - if (test) return true; - BKE_text_unlink(mainlib, (Text *)id); - break; - case ID_GR: - if (test) return true; - BKE_group_unlink(mainlib, (Group *)id); - break; - case ID_OB: - if (test) return true; - BKE_object_unlink(mainlib, (Object *)id); - break; - } - - if (id->us == 0) { - if (test) return true; - - BKE_libblock_free(mainlib, id); - - return true; - } - - return false; -} - bool id_single_user(bContext *C, ID *id, PointerRNA *ptr, PropertyRNA *prop) { ID *newid = NULL; @@ -1111,234 +1067,12 @@ void BKE_libblock_relink(ID *id) BKE_library_foreach_ID_link(id, id_relink_looper, NULL, 0); } -static void BKE_library_free(Library *lib) +void BKE_library_free(Library *lib) { if (lib->packedfile) freePackedFile(lib->packedfile); } -static BKE_library_free_window_manager_cb free_windowmanager_cb = NULL; - -void BKE_library_callback_free_window_manager_set(BKE_library_free_window_manager_cb func) -{ - free_windowmanager_cb = func; -} - -static BKE_library_free_notifier_reference_cb free_notifier_reference_cb = NULL; - -void BKE_library_callback_free_notifier_reference_set(BKE_library_free_notifier_reference_cb func) -{ - free_notifier_reference_cb = func; -} - -static BKE_library_free_editor_id_reference_cb free_editor_id_reference_cb = NULL; - -void BKE_library_callback_free_editor_id_reference_set(BKE_library_free_editor_id_reference_cb func) -{ - free_editor_id_reference_cb = func; -} - -static void animdata_dtar_clear_cb(ID *UNUSED(id), AnimData *adt, void *userdata) -{ - ChannelDriver *driver; - FCurve *fcu; - - /* find the driver this belongs to and update it */ - for (fcu = adt->drivers.first; fcu; fcu = fcu->next) { - driver = fcu->driver; - - if (driver) { - DriverVar *dvar; - for (dvar = driver->variables.first; dvar; dvar = dvar->next) { - DRIVER_TARGETS_USED_LOOPER(dvar) - { - if (dtar->id == userdata) - dtar->id = NULL; - } - DRIVER_TARGETS_LOOPER_END - } - } - } -} - -void BKE_libblock_free_data(Main *bmain, ID *id) -{ - if (id->properties) { - IDP_FreeProperty(id->properties); - MEM_freeN(id->properties); - } - - /* this ID may be a driver target! */ - BKE_animdata_main_cb(bmain, animdata_dtar_clear_cb, (void *)id); -} - -/* used in headerbuttons.c image.c mesh.c screen.c sound.c and library.c */ -void BKE_libblock_free_ex(Main *bmain, void *idv, bool do_id_user) -{ - ID *id = idv; - short type = GS(id->name); - ListBase *lb = which_libbase(bmain, type); - - DAG_id_type_tag(bmain, type); - -#ifdef WITH_PYTHON - BPY_id_release(id); -#endif - - switch (type) { /* GetShort from util.h */ - case ID_SCE: - BKE_scene_free((Scene *)id); - break; - case ID_LI: - BKE_library_free((Library *)id); - break; - case ID_OB: - BKE_object_free_ex((Object *)id, do_id_user); - break; - case ID_ME: - BKE_mesh_free((Mesh *)id, 1); - break; - case ID_CU: - BKE_curve_free((Curve *)id); - break; - case ID_MB: - BKE_mball_free((MetaBall *)id); - break; - case ID_MA: - BKE_material_free((Material *)id); - break; - case ID_TE: - BKE_texture_free((Tex *)id); - break; - case ID_IM: - BKE_image_free((Image *)id); - break; - case ID_LT: - BKE_lattice_free((Lattice *)id); - break; - case ID_LA: - BKE_lamp_free((Lamp *)id); - break; - case ID_CA: - BKE_camera_free((Camera *) id); - break; - case ID_IP: - BKE_ipo_free((Ipo *)id); - break; - case ID_KE: - BKE_key_free((Key *)id); - break; - case ID_WO: - BKE_world_free((World *)id); - break; - case ID_SCR: - BKE_screen_free((bScreen *)id); - break; - case ID_VF: - BKE_vfont_free((VFont *)id); - break; - case ID_TXT: - BKE_text_free((Text *)id); - break; - case ID_SPK: - BKE_speaker_free((Speaker *)id); - break; - case ID_SO: - BKE_sound_free((bSound *)id); - break; - case ID_GR: - BKE_group_free((Group *)id); - break; - case ID_AR: - BKE_armature_free((bArmature *)id); - break; - case ID_AC: - BKE_action_free((bAction *)id); - break; - case ID_NT: - ntreeFreeTree_ex((bNodeTree *)id, do_id_user); - break; - case ID_BR: - BKE_brush_free((Brush *)id); - break; - case ID_PA: - BKE_particlesettings_free((ParticleSettings *)id); - break; - case ID_WM: - if (free_windowmanager_cb) - free_windowmanager_cb(NULL, (wmWindowManager *)id); - break; - case ID_GD: - BKE_gpencil_free((bGPdata *)id); - break; - case ID_MC: - BKE_movieclip_free((MovieClip *)id); - break; - case ID_MSK: - BKE_mask_free(bmain, (Mask *)id); - break; - case ID_LS: - BKE_linestyle_free((FreestyleLineStyle *)id); - break; - case ID_PAL: - BKE_palette_free((Palette *)id); - break; - case ID_PC: - BKE_paint_curve_free((PaintCurve *)id); - break; - } - - /* avoid notifying on removed data */ - BKE_main_lock(bmain); - - if (free_notifier_reference_cb) { - free_notifier_reference_cb(id); - } - - if (free_editor_id_reference_cb) { - free_editor_id_reference_cb(id); - } - - BLI_remlink(lb, id); - - BKE_libblock_free_data(bmain, id); - BKE_main_unlock(bmain); - - MEM_freeN(id); -} - -void BKE_libblock_free(Main *bmain, void *idv) -{ - BKE_libblock_free_ex(bmain, idv, true); -} - -void BKE_libblock_free_us(Main *bmain, void *idv) /* test users */ -{ - ID *id = idv; - - id_us_min(id); - - /* XXX This is a temp (2.77) hack so that we keep same behavior as in 2.76 regarding groups when deleting an object. - * Since only 'user_one' usage of objects is groups, and only 'real user' usage of objects is scenes, - * removing that 'user_one' tag when there is no more real (scene) users of an object ensures it gets - * fully unlinked. - * Otherwise, there is no real way to get rid of an object anymore - better handling of this is TODO. - */ - if ((GS(id->name) == ID_OB) && (id->us == 1)) { - id_us_clear_real(id); - } - - if (id->us == 0) { - switch (GS(id->name)) { - case ID_OB: - BKE_object_unlink(bmain, (Object *)id); - break; - } - - BKE_libblock_free(bmain, id); - } -} - Main *BKE_main_new(void) { Main *bmain = MEM_callocN(sizeof(Main), "new main"); diff --git a/source/blender/blenkernel/intern/library_idmap.c b/source/blender/blenkernel/intern/library_idmap.c new file mode 100644 index 00000000000..daf097b9f0b --- /dev/null +++ b/source/blender/blenkernel/intern/library_idmap.c @@ -0,0 +1,176 @@ +/* + * ***** 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. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include <string.h> +#include <stdlib.h> + +#include "MEM_guardedalloc.h" + +#include "BLI_utildefines.h" +#include "BLI_ghash.h" +#include "BLI_listbase.h" + +#include "DNA_ID.h" + +#include "BKE_idcode.h" +#include "BKE_library.h" +#include "BKE_library_idmap.h" /* own include */ + +/** \file blender/blenkernel/intern/library_idmap.c + * \ingroup bke + * + * Utility functions for faster ID lookups. + */ + +/** \name BKE_main_idmap API + * + * Cache ID (name, library lookups). + * This doesn't account for adding/removing data-blocks, + * and should only be used when performing many lookups. + * + * \note GHash's are initialized on demand, + * since its likely some types will never have lookups run on them, + * so its a waste to create and never use. + * \{ */ + +struct IDNameLib_Key { + /** ``ID.name + 2``: without the ID type prefix, since each id type gets it's own 'map' */ + const char *name; + /** ``ID.lib``: */ + const Library *lib; +}; + +struct IDNameLib_TypeMap { + GHash *map; + short id_type; + /* only for storage of keys in the ghash, avoid many single allocs */ + struct IDNameLib_Key *keys; +}; + +/** + * Opaque structure, external API users only see this. + */ +struct IDNameLib_Map { + struct IDNameLib_TypeMap type_maps[MAX_LIBARRAY]; + struct Main *bmain; +}; + +static struct IDNameLib_TypeMap *main_idmap_from_idcode(struct IDNameLib_Map *id_map, short id_type) +{ + for (int i = 0; i < MAX_LIBARRAY; i++) { + if (id_map->type_maps[i].id_type == id_type) { + return &id_map->type_maps[i]; + } + } + return NULL; +} + +struct IDNameLib_Map *BKE_main_idmap_create(struct Main *bmain) +{ + struct IDNameLib_Map *id_map = MEM_mallocN(sizeof(*id_map), __func__); + + int index = 0; + while (index < MAX_LIBARRAY) { + struct IDNameLib_TypeMap *type_map = &id_map->type_maps[index]; + type_map->map = NULL; + type_map->id_type = BKE_idcode_iter_step(&index); + BLI_assert(type_map->id_type != 0); + } + BLI_assert(index == MAX_LIBARRAY); + + id_map->bmain = bmain; + + return id_map; +} + +struct Main *BKE_main_idmap_main_get(struct IDNameLib_Map *id_map) +{ + return id_map->bmain; +} + +static unsigned int idkey_hash(const void *ptr) +{ + const struct IDNameLib_Key *idkey = ptr; + unsigned int key = BLI_ghashutil_strhash(idkey->name); + if (idkey->lib) { + key ^= BLI_ghashutil_ptrhash(idkey->lib); + } + return key; +} + +static bool idkey_cmp(const void *a, const void *b) +{ + const struct IDNameLib_Key *idkey_a = a; + const struct IDNameLib_Key *idkey_b = b; + return strcmp(idkey_a->name, idkey_b->name) || (idkey_a->lib != idkey_b->lib); +} + +ID *BKE_main_idmap_lookup(struct IDNameLib_Map *id_map, short id_type, const char *name, const Library *lib) +{ + struct IDNameLib_TypeMap *type_map = main_idmap_from_idcode(id_map, id_type); + + if (UNLIKELY(type_map == NULL)) { + return NULL; + } + + /* lazy init */ + if (type_map->map == NULL) { + ListBase *lb = which_libbase(id_map->bmain, id_type); + const int lb_len = BLI_listbase_count(lb); + if (lb_len == 0) { + return NULL; + } + type_map->map = BLI_ghash_new_ex(idkey_hash, idkey_cmp, __func__, lb_len); + type_map->keys = MEM_mallocN(sizeof(struct IDNameLib_Key) * lb_len, __func__); + + GHash *map = type_map->map; + struct IDNameLib_Key *key = type_map->keys; + + for (ID *id = lb->first; id; id = id->next, key++) { + key->name = id->name + 2; + key->lib = id->lib; + BLI_ghash_insert(map, key, id); + } + } + + const struct IDNameLib_Key key_lookup = {name, lib}; + return BLI_ghash_lookup(type_map->map, &key_lookup); +} + +ID *BKE_main_idmap_lookup_id(struct IDNameLib_Map *id_map, const ID *id) +{ + return BKE_main_idmap_lookup(id_map, GS(id->name), id->name + 2, id->lib); +} + +void BKE_main_idmap_destroy(struct IDNameLib_Map *id_map) +{ + struct IDNameLib_TypeMap *type_map = id_map->type_maps; + for (int i = 0; i < MAX_LIBARRAY; i++, type_map++) { + if (type_map->map) { + BLI_ghash_free(type_map->map, NULL, NULL); + type_map->map = NULL; + MEM_freeN(type_map->keys); + } + } + + MEM_freeN(id_map); +} + +/** \} */ diff --git a/source/blender/blenkernel/intern/library_query.c b/source/blender/blenkernel/intern/library_query.c index d29d2191602..ebbbf1eb974 100644 --- a/source/blender/blenkernel/intern/library_query.c +++ b/source/blender/blenkernel/intern/library_query.c @@ -29,6 +29,7 @@ #include <stdlib.h> +#include "MEM_guardedalloc.h" #include "DNA_actuator_types.h" #include "DNA_anim_types.h" @@ -61,6 +62,7 @@ #include "DNA_world_types.h" #include "BLI_utildefines.h" +#include "BLI_listbase.h" #include "BLI_ghash.h" #include "BLI_linklist_stack.h" @@ -69,6 +71,7 @@ #include "BKE_fcurve.h" #include "BKE_library.h" #include "BKE_library_query.h" +#include "BKE_main.h" #include "BKE_modifier.h" #include "BKE_particle.h" #include "BKE_rigidbody.h" @@ -198,9 +201,24 @@ static void library_foreach_actuatorsObjectLooper( FOREACH_FINALIZE_VOID; } +static void library_foreach_nla_strip(LibraryForeachIDData *data, NlaStrip *strip) +{ + NlaStrip *substrip; + + FOREACH_CALLBACK_INVOKE(data, strip->act, IDWALK_USER); + + for (substrip = strip->strips.first; substrip; substrip = substrip->next) { + library_foreach_nla_strip(data, substrip); + } + + FOREACH_FINALIZE_VOID; +} + static void library_foreach_animationData(LibraryForeachIDData *data, AnimData *adt) { FCurve *fcu; + NlaTrack *nla_track; + NlaStrip *nla_strip; for (fcu = adt->drivers.first; fcu; fcu = fcu->next) { ChannelDriver *driver = fcu->driver; @@ -216,6 +234,15 @@ static void library_foreach_animationData(LibraryForeachIDData *data, AnimData * } } + FOREACH_CALLBACK_INVOKE(data, adt->action, IDWALK_USER); + FOREACH_CALLBACK_INVOKE(data, adt->tmpact, IDWALK_USER); + + for (nla_track = adt->nla_tracks.first; nla_track; nla_track = nla_track->next) { + for (nla_strip = nla_track->strips.first; nla_strip; nla_strip = nla_strip->next) { + library_foreach_nla_strip(data, nla_strip); + } + } + FOREACH_FINALIZE_VOID; } @@ -227,6 +254,14 @@ static void library_foreach_mtex(LibraryForeachIDData *data, MTex *mtex) FOREACH_FINALIZE_VOID; } +static void library_foreach_paint(LibraryForeachIDData *data, Paint *paint) +{ + FOREACH_CALLBACK_INVOKE(data, paint->brush, IDWALK_USER); + FOREACH_CALLBACK_INVOKE(data, paint->palette, IDWALK_USER); + + FOREACH_FINALIZE_VOID; +} + /** * Loop over all of the ID's this datablock links to. @@ -268,6 +303,12 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u } switch (GS(id->name)) { + case ID_LI: + { + Library *lib = (Library *) id; + CALLBACK_INVOKE(lib->parent, IDWALK_NOP); + break; + } case ID_SCE: { Scene *scene = (Scene *) id; @@ -278,8 +319,11 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u CALLBACK_INVOKE(scene->camera, IDWALK_NOP); CALLBACK_INVOKE(scene->world, IDWALK_USER); CALLBACK_INVOKE(scene->set, IDWALK_NOP); - CALLBACK_INVOKE(scene->clip, IDWALK_NOP); - CALLBACK_INVOKE(scene->nodetree, IDWALK_NOP); + CALLBACK_INVOKE(scene->clip, IDWALK_USER); + if (scene->nodetree) { + /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */ + BKE_library_foreach_ID_link((ID *)scene->nodetree, callback, user_data, flag); + } /* DO NOT handle scene->basact here, it's doubling with the loop over whole scene->base later, * since basact is just a pointer to one of those items. */ CALLBACK_INVOKE(scene->obedit, IDWALK_NOP); @@ -318,6 +362,9 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u CALLBACK_INVOKE(seq->clip, IDWALK_USER); CALLBACK_INVOKE(seq->mask, IDWALK_USER); CALLBACK_INVOKE(seq->sound, IDWALK_USER); + for (SequenceModifierData *smd = seq->modifiers.first; smd; smd = smd->next) { + CALLBACK_INVOKE(smd->mask_id, IDWALK_USER); + } } SEQ_END } @@ -330,28 +377,28 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u if (toolsett) { CALLBACK_INVOKE(toolsett->skgen_template, IDWALK_NOP); + CALLBACK_INVOKE(toolsett->particle.scene, IDWALK_NOP); CALLBACK_INVOKE(toolsett->particle.object, IDWALK_NOP); CALLBACK_INVOKE(toolsett->particle.shape_object, IDWALK_NOP); - CALLBACK_INVOKE(toolsett->imapaint.stencil, IDWALK_NOP); - CALLBACK_INVOKE(toolsett->imapaint.clone, IDWALK_NOP); - CALLBACK_INVOKE(toolsett->imapaint.canvas, IDWALK_NOP); + + library_foreach_paint(&data, &toolsett->imapaint.paint); + CALLBACK_INVOKE(toolsett->imapaint.stencil, IDWALK_USER); + CALLBACK_INVOKE(toolsett->imapaint.clone, IDWALK_USER); + CALLBACK_INVOKE(toolsett->imapaint.canvas, IDWALK_USER); + if (toolsett->vpaint) { - CALLBACK_INVOKE(toolsett->vpaint->paint.brush, IDWALK_NOP); - CALLBACK_INVOKE(toolsett->vpaint->paint.palette, IDWALK_NOP); + library_foreach_paint(&data, &toolsett->vpaint->paint); } if (toolsett->wpaint) { - CALLBACK_INVOKE(toolsett->wpaint->paint.brush, IDWALK_NOP); - CALLBACK_INVOKE(toolsett->wpaint->paint.palette, IDWALK_NOP); + library_foreach_paint(&data, &toolsett->wpaint->paint); } if (toolsett->sculpt) { - CALLBACK_INVOKE(toolsett->sculpt->paint.brush, IDWALK_NOP); - CALLBACK_INVOKE(toolsett->sculpt->paint.palette, IDWALK_NOP); + library_foreach_paint(&data, &toolsett->sculpt->paint); CALLBACK_INVOKE(toolsett->sculpt->gravity_object, IDWALK_NOP); } if (toolsett->uvsculpt) { - CALLBACK_INVOKE(toolsett->uvsculpt->paint.brush, IDWALK_NOP); - CALLBACK_INVOKE(toolsett->uvsculpt->paint.palette, IDWALK_NOP); + library_foreach_paint(&data, &toolsett->uvsculpt->paint); } } @@ -398,6 +445,7 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u CALLBACK_INVOKE(object->pd->tex, IDWALK_USER); CALLBACK_INVOKE(object->pd->f_source, IDWALK_NOP); } + /* Note that ob->effect is deprecated, so no need to handle it here. */ if (object->pose) { bPoseChannel *pchan; @@ -419,6 +467,10 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u } } + CALLBACK_INVOKE(object->probe, IDWALK_NOP); + CALLBACK_INVOKE(object->parallaxcorrect, IDWALK_NOP); + CALLBACK_INVOKE(object->reflectionplane, IDWALK_NOP); + modifiers_foreachIDLink(object, library_foreach_modifiersForeachIDLink, &data); BKE_constraints_id_loop(&object->constraints, library_foreach_constraintObjectLooper, &data); @@ -426,6 +478,10 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u BKE_particlesystem_id_loop(psys, library_foreach_particlesystemsObjectLooper, &data); } + if (object->soft && object->soft->effector_weights) { + CALLBACK_INVOKE(object->soft->effector_weights->group, IDWALK_NOP); + } + BKE_sca_sensors_id_loop(&object->sensors, library_foreach_sensorsObjectLooper, &data); BKE_sca_controllers_id_loop(&object->controllers, library_foreach_controllersObjectLooper, &data); BKE_sca_actuators_id_loop(&object->actuators, library_foreach_actuatorsObjectLooper, &data); @@ -477,7 +533,10 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u library_foreach_mtex(&data, material->mtex[i]); } } - CALLBACK_INVOKE(material->nodetree, IDWALK_NOP); + if (material->nodetree) { + /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */ + BKE_library_foreach_ID_link((ID *)material->nodetree, callback, user_data, flag); + } CALLBACK_INVOKE(material->group, IDWALK_USER); break; } @@ -485,7 +544,10 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u case ID_TE: { Tex *texture = (Tex *) id; - CALLBACK_INVOKE(texture->nodetree, IDWALK_NOP); + if (texture->nodetree) { + /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */ + BKE_library_foreach_ID_link((ID *)texture->nodetree, callback, user_data, flag); + } CALLBACK_INVOKE(texture->ima, IDWALK_USER); if (texture->env) { CALLBACK_INVOKE(texture->env->object, IDWALK_NOP); @@ -515,7 +577,10 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u library_foreach_mtex(&data, lamp->mtex[i]); } } - CALLBACK_INVOKE(lamp->nodetree, IDWALK_NOP); + if (lamp->nodetree) { + /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */ + BKE_library_foreach_ID_link((ID *)lamp->nodetree, callback, user_data, flag); + } break; } @@ -548,7 +613,10 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u library_foreach_mtex(&data, world->mtex[i]); } } - CALLBACK_INVOKE(world->nodetree, IDWALK_NOP); + if (world->nodetree) { + /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */ + BKE_library_foreach_ID_link((ID *)world->nodetree, callback, user_data, flag); + } break; } @@ -608,6 +676,15 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u CALLBACK_INVOKE(psett->effector_weights->group, IDWALK_NOP); } + if (psett->pd) { + CALLBACK_INVOKE(psett->pd->tex, IDWALK_USER); + CALLBACK_INVOKE(psett->pd->f_source, IDWALK_NOP); + } + if (psett->pd2) { + CALLBACK_INVOKE(psett->pd2->tex, IDWALK_USER); + CALLBACK_INVOKE(psett->pd2->f_source, IDWALK_NOP); + } + if (psett->boids) { BoidState *state; BoidRule *rule; @@ -625,7 +702,6 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u } } } - break; } @@ -634,16 +710,23 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u MovieClip *clip = (MovieClip *) id; MovieTracking *tracking = &clip->tracking; MovieTrackingObject *object; + MovieTrackingTrack *track; + MovieTrackingPlaneTrack *plane_track; CALLBACK_INVOKE(clip->gpd, IDWALK_USER); - for (object = tracking->objects.first; object; object = object->next) { - ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, object); - MovieTrackingTrack *track; - for (track = tracksbase->first; track; track = track->next) { + for (track = tracking->tracks.first; track; track = track->next) { + CALLBACK_INVOKE(track->gpd, IDWALK_USER); + } + for (object = tracking->objects.first; object; object = object->next) { + for (track = object->tracks.first; track; track = track->next) { CALLBACK_INVOKE(track->gpd, IDWALK_USER); } } + + for (plane_track = tracking->plane_tracks.first; plane_track; plane_track = plane_track->next) { + CALLBACK_INVOKE(plane_track->image, IDWALK_USER); + } break; } @@ -673,7 +756,10 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u library_foreach_mtex(&data, linestyle->mtex[i]); } } - CALLBACK_INVOKE(linestyle->nodetree, IDWALK_NOP); + if (linestyle->nodetree) { + /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */ + BKE_library_foreach_ID_link((ID *)linestyle->nodetree, callback, user_data, flag); + } for (lsm = linestyle->color_modifiers.first; lsm; lsm = lsm->next) { if (lsm->type == LS_MODIFIER_DISTANCE_FROM_OBJECT) { @@ -742,11 +828,18 @@ typedef struct IDUsersIter { int count; /* Set by callback. */ } IDUsersIter; -static int foreach_libblock_id_users_callback(void *user_data, ID *UNUSED(self_id), ID **id_p, int UNUSED(cb_flag)) +static int foreach_libblock_id_users_callback(void *user_data, ID *UNUSED(self_id), ID **id_p, int cb_flag) { IDUsersIter *iter = user_data; if (*id_p && (*id_p == iter->id)) { +#if 0 + printf("%s uses %s (refcounted: %d, userone: %d, used_one: %d, used_one_active: %d)\n", + iter->curr_id->name, iter->id->name, (cb_flag & IDWALK_USER) ? 1 : 0, (cb_flag & IDWALK_USER_ONE) ? 1 : 0, + (iter->id->tag & LIB_TAG_EXTRAUSER) ? 1 : 0, (iter->id->tag & LIB_TAG_EXTRAUSER_SET) ? 1 : 0); +#else + UNUSED_VARS(cb_flag); +#endif iter->count++; } @@ -776,3 +869,53 @@ int BKE_library_ID_use_ID(ID *id_user, ID *id_used) return iter.count; } + + +static int foreach_libblock_check_indirect_usage_callback( + void *user_data, ID *UNUSED(id_self), ID **id_p, int UNUSED(cb_flag)) +{ + IDUsersIter *iter = user_data; + + if (*id_p && (*id_p == iter->id)) { + iter->count++; + return IDWALK_RET_STOP_ITER; + } + + return IDWALK_RET_NOP; +} + +/** + * Check wether given ID is used indirectly (i.e. by another linked ID). + */ +bool BKE_library_ID_is_indirectly_used(Main *bmain, void *idv) +{ + IDUsersIter iter; + ListBase *lb_array[MAX_LIBARRAY]; + int i = set_listbasepointers(bmain, lb_array); + + iter.id = idv; + iter.count = 0; + while (i--) { + ID *id_curr = lb_array[i]->first; + + for (; id_curr; id_curr = id_curr->next) { + if (!id_curr->lib) { + continue; + } + + iter.curr_id = id_curr; + BKE_library_foreach_ID_link( + id_curr, foreach_libblock_check_indirect_usage_callback, &iter, IDWALK_NOP); + + if (iter.count) { + break; + } + } + if (iter.count) { + break; + } + } + + return (iter.count != 0); +} + diff --git a/source/blender/blenkernel/intern/library_remap.c b/source/blender/blenkernel/intern/library_remap.c new file mode 100644 index 00000000000..81543fad0fe --- /dev/null +++ b/source/blender/blenkernel/intern/library_remap.c @@ -0,0 +1,776 @@ +/* + * ***** 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. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/blenkernel/intern/library_remap.c + * \ingroup bke + * + * Contains management of ID's and libraries remap, unlink and free logic. + */ + +#include <stdio.h> +#include <ctype.h> +#include <string.h> +#include <stdlib.h> +#include <stddef.h> +#include <assert.h> + +#include "MEM_guardedalloc.h" + +/* all types are needed here, in order to do memory operations */ +#include "DNA_anim_types.h" +#include "DNA_armature_types.h" +#include "DNA_brush_types.h" +#include "DNA_camera_types.h" +#include "DNA_group_types.h" +#include "DNA_gpencil_types.h" +#include "DNA_ipo_types.h" +#include "DNA_key_types.h" +#include "DNA_lamp_types.h" +#include "DNA_lattice_types.h" +#include "DNA_linestyle_types.h" +#include "DNA_material_types.h" +#include "DNA_mesh_types.h" +#include "DNA_meta_types.h" +#include "DNA_movieclip_types.h" +#include "DNA_mask_types.h" +#include "DNA_node_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" +#include "DNA_screen_types.h" +#include "DNA_speaker_types.h" +#include "DNA_sound_types.h" +#include "DNA_text_types.h" +#include "DNA_vfont_types.h" +#include "DNA_windowmanager_types.h" +#include "DNA_world_types.h" + +#include "BLI_blenlib.h" +#include "BLI_utildefines.h" + +#include "BKE_action.h" +#include "BKE_animsys.h" +#include "BKE_armature.h" +#include "BKE_brush.h" +#include "BKE_camera.h" +#include "BKE_curve.h" +#include "BKE_depsgraph.h" +#include "BKE_fcurve.h" +#include "BKE_font.h" +#include "BKE_group.h" +#include "BKE_gpencil.h" +#include "BKE_idprop.h" +#include "BKE_image.h" +#include "BKE_ipo.h" +#include "BKE_key.h" +#include "BKE_lamp.h" +#include "BKE_lattice.h" +#include "BKE_library.h" +#include "BKE_library_query.h" +#include "BKE_library_remap.h" +#include "BKE_linestyle.h" +#include "BKE_mesh.h" +#include "BKE_material.h" +#include "BKE_main.h" +#include "BKE_mball.h" +#include "BKE_movieclip.h" +#include "BKE_mask.h" +#include "BKE_node.h" +#include "BKE_object.h" +#include "BKE_paint.h" +#include "BKE_particle.h" +#include "BKE_speaker.h" +#include "BKE_sound.h" +#include "BKE_screen.h" +#include "BKE_scene.h" +#include "BKE_text.h" +#include "BKE_texture.h" +#include "BKE_world.h" + +#ifdef WITH_PYTHON +#include "BPY_extern.h" +#endif + +static BKE_library_free_window_manager_cb free_windowmanager_cb = NULL; + +void BKE_library_callback_free_window_manager_set(BKE_library_free_window_manager_cb func) +{ + free_windowmanager_cb = func; +} + +static BKE_library_free_notifier_reference_cb free_notifier_reference_cb = NULL; + +void BKE_library_callback_free_notifier_reference_set(BKE_library_free_notifier_reference_cb func) +{ + free_notifier_reference_cb = func; +} + +static BKE_library_remap_editor_id_reference_cb remap_editor_id_reference_cb = NULL; + +void BKE_library_callback_remap_editor_id_reference_set(BKE_library_remap_editor_id_reference_cb func) +{ + remap_editor_id_reference_cb = func; +} + +typedef struct IDRemap { + ID *old_id; + ID *new_id; + ID *id; /* The ID in which we are replacing old_id by new_id usages. */ + short flag; + + /* 'Output' data. */ + short status; + int skipped_direct; /* Number of direct usecases that could not be remapped (e.g.: obdata when in edit mode). */ + int skipped_indirect; /* Number of indirect usecases that could not be remapped. */ + int skipped_refcounted; /* Number of skipped usecases that refcount the datablock. */ +} IDRemap; + +/* IDRemap->flag enums defined in BKE_library.h */ + +/* IDRemap->status */ +enum { + /* *** Set by callback. *** */ + ID_REMAP_IS_LINKED_DIRECT = 1 << 0, /* new_id is directly linked in current .blend. */ + ID_REMAP_IS_USER_ONE_SKIPPED = 1 << 1, /* There was some skipped 'user_one' usages of old_id. */ +}; + +static int foreach_libblock_remap_callback(void *user_data, ID *UNUSED(id_self), ID **id_p, int cb_flag) +{ + IDRemap *id_remap_data = user_data; + ID *old_id = id_remap_data->old_id; + ID *new_id = id_remap_data->new_id; + ID *id = id_remap_data->id; + + if (!old_id) { /* Used to cleanup all IDs used by a specific one. */ + BLI_assert(!new_id); + old_id = *id_p; + } + + if (*id_p && (*id_p == old_id)) { + const bool is_indirect = (id->lib != NULL); + const bool skip_indirect = (id_remap_data->flag & ID_REMAP_SKIP_INDIRECT_USAGE) != 0; + /* Note: proxy usage implies LIB_TAG_EXTERN, so on this aspect it is direct, + * on the other hand since they get reset to lib data on file open/reload it is indirect too... + * Edit Mode is also a 'skip direct' case. */ + const bool is_obj = (GS(id->name) == ID_OB); + const bool is_proxy = (is_obj && (((Object *)id)->proxy || ((Object *)id)->proxy_group)); + const bool is_obj_editmode = (is_obj && BKE_object_is_in_editmode((Object *)id)); + const bool is_never_null = ((cb_flag & IDWALK_NEVER_NULL) && (new_id == NULL) && + (id_remap_data->flag & ID_REMAP_FORCE_NEVER_NULL_USAGE) == 0); + const bool skip_never_null = (id_remap_data->flag & ID_REMAP_SKIP_NEVER_NULL_USAGE) != 0; + +#ifdef DEBUG_PRINT + printf("In %s: Remapping %s (%p) to %s (%p) (skip_indirect: %d)\n", + id->name, old_id->name, old_id, new_id ? new_id->name : "<NONE>", new_id, skip_indirect); +#endif + + if ((id_remap_data->flag & ID_REMAP_FLAG_NEVER_NULL_USAGE) && (cb_flag & IDWALK_NEVER_NULL)) { + id->tag |= LIB_TAG_DOIT; + } + + /* Special hack in case it's Object->data and we are in edit mode (skipped_direct too). */ + if ((is_never_null && skip_never_null) || + (is_obj_editmode && (((Object *)id)->data == *id_p)) || + (skip_indirect && (is_proxy || is_indirect))) + { + if (is_indirect) { + id_remap_data->skipped_indirect++; + } + else if (is_never_null || is_proxy || is_obj_editmode) { + id_remap_data->skipped_direct++; + } + else { + BLI_assert(0); + } + if (cb_flag & IDWALK_USER) { + id_remap_data->skipped_refcounted++; + } + else if (cb_flag & IDWALK_USER_ONE) { + /* No need to count number of times this happens, just a flag is enough. */ + id_remap_data->status |= ID_REMAP_IS_USER_ONE_SKIPPED; + } + } + else { + if (!is_never_null) { + *id_p = new_id; + } + if (cb_flag & IDWALK_USER) { + id_us_min(old_id); + /* We do not want to handle LIB_TAG_INDIRECT/LIB_TAG_EXTERN here. */ + if (new_id) + new_id->us++; + } + else if (cb_flag & IDWALK_USER_ONE) { + id_us_ensure_real(new_id); + /* We cannot affect old_id->us directly, LIB_TAG_EXTRAUSER(_SET) are assumed to be set as needed, + * that extra user is processed in final handling... */ + } + if (!is_indirect) { + id_remap_data->status |= ID_REMAP_IS_LINKED_DIRECT; + } + } + } + + return IDWALK_RET_NOP; +} + +/** + * Execute the 'data' part of the remapping (that is, all ID pointers from other ID datablocks). + * + * Behavior differs depending on whether given \a id is NULL or not: + * - \a id NULL: \a old_id must be non-NULL, \a new_id may be NULL (unlinking \a old_id) or not + * (remapping \a old_id to \a new_id). The whole \a bmain database is checked, and all pointers to \a old_id + * are remapped to \a new_id. + * - \a id is non-NULL: + * + If \a old_id is NULL, \a new_id must also be NULL, and all ID pointers from \a id are cleared (i.e. \a id + * does not references any other datablock anymore). + * + If \a old_id is non-NULL, behavior is as with a NULL \a id, but only for given \a id. + * + * \param bmain: the Main data storage to operate on (can be NULL if \a id is non-NULL). + * \param id: the datablock to operate on (can be NULL if \a bmain is non-NULL). + * \param old_id: the datablock to dereference (may be NULL if \a id is non-NULL). + * \param new_id: the new datablock to replace \a old_id references with (may be NULL). + * \param r_id_remap_data: if non-NULL, the IDRemap struct to use (uselful to retrieve info about remapping process). + */ +static void libblock_remap_data( + Main *bmain, ID *id, ID *old_id, ID *new_id, const short remap_flags, IDRemap *r_id_remap_data) +{ + IDRemap id_remap_data; + ListBase *lb_array[MAX_LIBARRAY]; + int i; + + if (r_id_remap_data == NULL) { + r_id_remap_data = &id_remap_data; + } + r_id_remap_data->old_id = old_id; + r_id_remap_data->new_id = new_id; + r_id_remap_data->id = NULL; + r_id_remap_data->flag = remap_flags; + r_id_remap_data->status = 0; + r_id_remap_data->skipped_direct = 0; + r_id_remap_data->skipped_indirect = 0; + r_id_remap_data->skipped_refcounted = 0; + + if (id) { +#ifdef DEBUG_PRINT + printf("\tchecking id %s (%p, %p)\n", id->name, id, id->lib); +#endif + r_id_remap_data->id = id; + BKE_library_foreach_ID_link(id, foreach_libblock_remap_callback, (void *)r_id_remap_data, IDWALK_NOP); + } + else { + i = set_listbasepointers(bmain, lb_array); + + /* Note that this is a very 'bruteforce' approach, maybe we could use some depsgraph to only process + * objects actually using given old_id... sounds rather unlikely currently, though, so this will do for now. */ + + while (i--) { + ID *id_curr = lb_array[i]->first; + + for (; id_curr; id_curr = id_curr->next) { + /* Note that we cannot skip indirect usages of old_id here (if requested), we still need to check it for + * the user count handling... + * XXX No more true (except for debug usage of those skipping counters). */ + r_id_remap_data->id = id_curr; + BKE_library_foreach_ID_link( + id_curr, foreach_libblock_remap_callback, (void *)r_id_remap_data, IDWALK_NOP); + } + } + } + + /* XXX We may not want to always 'transfer' fakeuser from old to new id... Think for now it's desired behavior + * though, we can always add an option (flag) to control this later if needed. */ + if (old_id && (old_id->flag & LIB_FAKEUSER)) { + id_fake_user_clear(old_id); + id_fake_user_set(new_id); + } + + id_us_clear_real(old_id); + + if (new_id && (new_id->tag & LIB_TAG_INDIRECT) && (r_id_remap_data->status & ID_REMAP_IS_LINKED_DIRECT)) { + new_id->tag &= ~LIB_TAG_INDIRECT; + new_id->tag |= LIB_TAG_EXTERN; + } + +#ifdef DEBUG_PRINT + printf("%s: %d occurences skipped (%d direct and %d indirect ones)\n", __func__, + r_id_remap_data->skipped_direct + r_id_remap_data->skipped_indirect, + r_id_remap_data->skipped_direct, r_id_remap_data->skipped_indirect); +#endif +} + +/** + * Replace all references in given Main to \a old_id by \a new_id + * (if \a new_id is NULL, it unlinks \a old_id). + */ +void BKE_libblock_remap_locked( + Main *bmain, void *old_idv, void *new_idv, + const short remap_flags) +{ + IDRemap id_remap_data; + ID *old_id = old_idv; + ID *new_id = new_idv; + int skipped_direct, skipped_refcounted; + + BLI_assert(old_id != NULL); + BLI_assert((new_id == NULL) || GS(old_id->name) == GS(new_id->name)); + BLI_assert(old_id != new_id); + + /* Some pre-process updates. + * This is a bit ugly, but cannot see a way to avoid it. Maybe we should do a per-ID callback for this instead? + */ + if (GS(old_id->name) == ID_OB) { + Object *old_ob = (Object *)old_id; + Object *new_ob = (Object *)new_id; + + if (new_ob == NULL) { + Scene *sce; + Base *base; + + for (sce = bmain->scene.first; sce; sce = sce->id.next) { + base = BKE_scene_base_find(sce, old_ob); + + if (base) { + id_us_min((ID *)base->object); + BKE_scene_base_unlink(sce, base); + MEM_freeN(base); + } + } + } + } + + libblock_remap_data(bmain, NULL, old_id, new_id, remap_flags, &id_remap_data); + + if (free_notifier_reference_cb) { + free_notifier_reference_cb(old_id); + } + + /* We assume editors do not hold references to their IDs... This is false in some cases + * (Image is especially tricky here), editors' code is to handle refcount (id->us) itself then. */ + if (remap_editor_id_reference_cb) { + remap_editor_id_reference_cb(old_id, new_id); + } + + skipped_direct = id_remap_data.skipped_direct; + skipped_refcounted = id_remap_data.skipped_refcounted; + + /* If old_id was used by some ugly 'user_one' stuff (like Image or Clip editors...), and user count has actually + * been incremented for that, we have to decrease once more its user count... unless we had to skip + * some 'user_one' cases. */ + if ((old_id->tag & LIB_TAG_EXTRAUSER_SET) && !(id_remap_data.status & ID_REMAP_IS_USER_ONE_SKIPPED)) { + id_us_min(old_id); + old_id->tag &= ~LIB_TAG_EXTRAUSER_SET; + } + + BLI_assert(old_id->us - skipped_refcounted >= 0); + UNUSED_VARS_NDEBUG(skipped_refcounted); + + if (skipped_direct == 0) { + /* old_id is assumed to not be used directly anymore... */ + if (old_id->lib && (old_id->tag & LIB_TAG_EXTERN)) { + old_id->tag &= ~LIB_TAG_EXTERN; + old_id->tag |= LIB_TAG_INDIRECT; + } + } + + /* Some after-process updates. + * This is a bit ugly, but cannot see a way to avoid it. Maybe we should do a per-ID callback for this instead? + */ + switch (GS(old_id->name)) { + case ID_OB: + { + Object *old_ob = (Object *)old_id; + Object *new_ob = (Object *)new_id; + + if (old_ob->flag & OB_FROMGROUP) { + /* Note that for Scene's BaseObject->flag, either we: + * - unlinked old_ob (i.e. new_ob is NULL), in which case scenes' bases have been removed already. + * - remapped old_ob by new_ob, in which case scenes' bases are still valid as is. + * So in any case, no need to update them here. */ + if (BKE_group_object_find(NULL, old_ob) == NULL) { + old_ob->flag &= ~OB_FROMGROUP; + } + if (new_ob == NULL) { /* We need to remove NULL-ified groupobjects... */ + Group *group; + for (group = bmain->group.first; group; group = group->id.next) { + BKE_group_object_unlink(group, NULL, NULL, NULL); + } + } + else { + new_ob->flag |= OB_FROMGROUP; + } + } + break; + } + case ID_GR: + if (new_id == NULL) { /* Only affects us in case group was unlinked. */ + for (Scene *sce = bmain->scene.first; sce; sce = sce->id.next) { + /* Note that here we assume no object has no base (i.e. all objects are assumed instanced + * in one scene...). */ + for (Base *base = sce->base.first; base; base = base->next) { + if (base->flag & OB_FROMGROUP) { + Object *ob = base->object; + + if (ob->flag & OB_FROMGROUP) { + Group *grp = BKE_group_object_find(NULL, ob); + + /* Unlinked group (old_id) is still in bmain... */ + if (grp && (&grp->id == old_id)) { + grp = BKE_group_object_find(grp, ob); + } + if (!grp) { + ob->flag &= ~OB_FROMGROUP; + } + } + if (!(ob->flag & OB_FROMGROUP)) { + base->flag &= ~OB_FROMGROUP; + } + } + } + } + } + break; + default: + break; + } + + /* Full rebuild of DAG! */ + DAG_relations_tag_update(bmain); +} + +void BKE_libblock_remap(Main *bmain, void *old_idv, void *new_idv, const short remap_flags) +{ + BKE_main_lock(bmain); + + BKE_libblock_remap_locked(bmain, old_idv, new_idv, remap_flags); + + BKE_main_unlock(bmain); +} + +/** + * Unlink given \a id from given \a bmain (does not touch to indirect, i.e. library, usages of the ID). + * + * \param do_flag_never_null: If true, all IDs using \a idv in a 'non-NULL' way are flagged by \a LIB_TAG_DOIT flag + * (quite obviously, 'non-NULL' usages can never be unlinked by this function...). + */ +void BKE_libblock_unlink(Main *bmain, void *idv, const bool do_flag_never_null, const bool do_skip_indirect) +{ + const short remap_flags = (do_skip_indirect ? ID_REMAP_SKIP_INDIRECT_USAGE : 0) | + (do_flag_never_null ? ID_REMAP_FLAG_NEVER_NULL_USAGE : 0); + + BKE_main_lock(bmain); + + BKE_libblock_remap_locked(bmain, idv, NULL, remap_flags); + + BKE_main_unlock(bmain); +} + +/** Similar to libblock_remap, but only affects IDs used by given \a idv ID. + * + * \param old_idv: Unlike BKE_libblock_remap, can be NULL, + * in which case all ID usages by given \a idv will be cleared. + * \param us_min_never_null: If \a true and new_id is NULL, + * 'NEVER_NULL' ID usages keep their old id, but this one still gets its user count decremented + * (needed when given \a idv is going to be deleted right after being unlinked). + */ +/* Should be able to replace all _relink() funcs (constraints, rigidbody, etc.) ? */ +/* XXX Arg! Naming... :( + * _relink? avoids confusion with _remap, but is confusing with _unlink + * _remap_used_ids? + * _remap_datablocks? + * BKE_id_remap maybe? + * ... sigh + */ +void BKE_libblock_relink_ex( + void *idv, void *old_idv, void *new_idv, const bool us_min_never_null) +{ + ID *id = idv; + ID *old_id = old_idv; + ID *new_id = new_idv; + int remap_flags = us_min_never_null ? 0 : ID_REMAP_SKIP_NEVER_NULL_USAGE; + + /* No need to lock here, we are only affecting given ID. */ + + BLI_assert(id); + if (old_id) { + BLI_assert((new_id == NULL) || GS(old_id->name) == GS(new_id->name)); + BLI_assert(old_id != new_id); + } + else { + BLI_assert(new_id == NULL); + } + + libblock_remap_data(NULL, id, old_id, new_id, remap_flags, NULL); +} + +static void animdata_dtar_clear_cb(ID *UNUSED(id), AnimData *adt, void *userdata) +{ + ChannelDriver *driver; + FCurve *fcu; + + /* find the driver this belongs to and update it */ + for (fcu = adt->drivers.first; fcu; fcu = fcu->next) { + driver = fcu->driver; + + if (driver) { + DriverVar *dvar; + for (dvar = driver->variables.first; dvar; dvar = dvar->next) { + DRIVER_TARGETS_USED_LOOPER(dvar) + { + if (dtar->id == userdata) + dtar->id = NULL; + } + DRIVER_TARGETS_LOOPER_END + } + } + } +} + +void BKE_libblock_free_data(Main *bmain, ID *id) +{ + if (id->properties) { + IDP_FreeProperty(id->properties); + MEM_freeN(id->properties); + } + + /* this ID may be a driver target! */ + BKE_animdata_main_cb(bmain, animdata_dtar_clear_cb, (void *)id); +} + +/** + * used in headerbuttons.c image.c mesh.c screen.c sound.c and library.c + * + * \param do_id_user: if \a true, try to release other ID's 'references' hold by \a idv. + */ +void BKE_libblock_free_ex(Main *bmain, void *idv, const bool do_id_user) +{ + ID *id = idv; + short type = GS(id->name); + ListBase *lb = which_libbase(bmain, type); + + DAG_id_type_tag(bmain, type); + +#ifdef WITH_PYTHON + BPY_id_release(id); +#endif + + if (do_id_user) { + BKE_libblock_relink_ex(id, NULL, NULL, true); + } + + switch (type) { + case ID_SCE: + BKE_scene_free((Scene *)id); + break; + case ID_LI: + BKE_library_free((Library *)id); + break; + case ID_OB: + BKE_object_free((Object *)id); + break; + case ID_ME: + BKE_mesh_free((Mesh *)id); + break; + case ID_CU: + BKE_curve_free((Curve *)id); + break; + case ID_MB: + BKE_mball_free((MetaBall *)id); + break; + case ID_MA: + BKE_material_free((Material *)id); + break; + case ID_TE: + BKE_texture_free((Tex *)id); + break; + case ID_IM: + BKE_image_free((Image *)id); + break; + case ID_LT: + BKE_lattice_free((Lattice *)id); + break; + case ID_LA: + BKE_lamp_free((Lamp *)id); + break; + case ID_CA: + BKE_camera_free((Camera *) id); + break; + case ID_IP: /* Deprecated. */ + BKE_ipo_free((Ipo *)id); + break; + case ID_KE: + BKE_key_free((Key *)id); + break; + case ID_WO: + BKE_world_free((World *)id); + break; + case ID_SCR: + BKE_screen_free((bScreen *)id); + break; + case ID_VF: + BKE_vfont_free((VFont *)id); + break; + case ID_TXT: + BKE_text_free((Text *)id); + break; + case ID_SPK: + BKE_speaker_free((Speaker *)id); + break; + case ID_SO: + BKE_sound_free((bSound *)id); + break; + case ID_GR: + BKE_group_free((Group *)id); + break; + case ID_AR: + BKE_armature_free((bArmature *)id); + break; + case ID_AC: + BKE_action_free((bAction *)id); + break; + case ID_NT: + ntreeFreeTree((bNodeTree *)id); + break; + case ID_BR: + BKE_brush_free((Brush *)id); + break; + case ID_PA: + BKE_particlesettings_free((ParticleSettings *)id); + break; + case ID_WM: + if (free_windowmanager_cb) + free_windowmanager_cb(NULL, (wmWindowManager *)id); + break; + case ID_GD: + BKE_gpencil_free((bGPdata *)id); + break; + case ID_MC: + BKE_movieclip_free((MovieClip *)id); + break; + case ID_MSK: + BKE_mask_free((Mask *)id); + break; + case ID_LS: + BKE_linestyle_free((FreestyleLineStyle *)id); + break; + case ID_PAL: + BKE_palette_free((Palette *)id); + break; + case ID_PC: + BKE_paint_curve_free((PaintCurve *)id); + break; + } + + /* avoid notifying on removed data */ + BKE_main_lock(bmain); + + if (free_notifier_reference_cb) { + free_notifier_reference_cb(id); + } + + if (remap_editor_id_reference_cb) { + remap_editor_id_reference_cb(id, NULL); + } + + BLI_remlink(lb, id); + + BKE_libblock_free_data(bmain, id); + BKE_main_unlock(bmain); + + MEM_freeN(id); +} + +void BKE_libblock_free(Main *bmain, void *idv) +{ + BKE_libblock_free_ex(bmain, idv, true); +} + +void BKE_libblock_free_us(Main *bmain, void *idv) /* test users */ +{ + ID *id = idv; + + id_us_min(id); + + /* XXX This is a temp (2.77) hack so that we keep same behavior as in 2.76 regarding groups when deleting an object. + * Since only 'user_one' usage of objects is groups, and only 'real user' usage of objects is scenes, + * removing that 'user_one' tag when there is no more real (scene) users of an object ensures it gets + * fully unlinked. + * Otherwise, there is no real way to get rid of an object anymore - better handling of this is TODO. + */ + if ((GS(id->name) == ID_OB) && (id->us == 1)) { + id_us_clear_real(id); + } + + if (id->us == 0) { + BKE_libblock_unlink(bmain, id, false, false); + + BKE_libblock_free(bmain, id); + } +} + +void BKE_libblock_delete(Main *bmain, void *idv) +{ + ListBase *lbarray[MAX_LIBARRAY]; + int base_count, i; + + base_count = set_listbasepointers(bmain, lbarray); + BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false); + + /* First tag all datablocks directly from target lib. + * Note that we go forward here, since we want to check dependencies before users (e.g. meshes before objects). + * Avoids to have to loop twice. */ + for (i = 0; i < base_count; i++) { + ListBase *lb = lbarray[i]; + ID *id; + + for (id = lb->first; id; id = id->next) { + /* Note: in case we delete a library, we also delete all its datablocks! */ + if ((id == (ID *)idv) || (id->lib == (Library *)idv) || (id->tag & LIB_TAG_DOIT)) { + id->tag |= LIB_TAG_DOIT; + /* Will tag 'never NULL' users of this ID too. + * Note that we cannot use BKE_libblock_unlink() here, since it would ignore indirect (and proxy!) + * links, this can lead to nasty crashing here in second, actual deleting loop. + * Also, this will also flag users of deleted data that cannot be unlinked + * (object using deleted obdata, etc.), so that they also get deleted. */ + BKE_libblock_remap(bmain, id, NULL, ID_REMAP_FLAG_NEVER_NULL_USAGE | ID_REMAP_FORCE_NEVER_NULL_USAGE); + } + } + } + + /* In usual reversed order, such that all usage of a given ID, even 'never NULL' ones, have been already cleared + * when we reach it (e.g. Objects being processed before meshes, they'll have already released their 'reference' + * over meshes when we come to freeing obdata). */ + for (i = base_count; i--; ) { + ListBase *lb = lbarray[i]; + ID *id, *id_next; + + for (id = lb->first; id; id = id_next) { + id_next = id->next; + if (id->tag & LIB_TAG_DOIT) { + if (id->us != 0) { +#ifdef DEBUG_PRINT + printf("%s: deleting %s (%d)\n", __func__, id->name, id->us); +#endif + BLI_assert(id->us == 0); + } + BKE_libblock_free(bmain, id); + } + } + } +} diff --git a/source/blender/blenkernel/intern/linestyle.c b/source/blender/blenkernel/intern/linestyle.c index 5a1dfc04045..30dc48819e9 100644 --- a/source/blender/blenkernel/intern/linestyle.c +++ b/source/blender/blenkernel/intern/linestyle.c @@ -125,26 +125,25 @@ FreestyleLineStyle *BKE_linestyle_new(struct Main *bmain, const char *name) return linestyle; } +/** Free (or release) any data used by this linestyle (does not free the linestyle itself). */ void BKE_linestyle_free(FreestyleLineStyle *linestyle) { LineStyleModifier *m; - - MTex *mtex; int a; + BKE_animdata_free(&linestyle->id, false); + for (a = 0; a < MAX_MTEX; a++) { - mtex = linestyle->mtex[a]; - if (mtex && mtex->tex) - id_us_min(&mtex->tex->id); - if (mtex) - MEM_freeN(mtex); + MEM_SAFE_FREE(linestyle->mtex[a]); } + + /* is no lib link block, but linestyle extension */ if (linestyle->nodetree) { ntreeFreeTree(linestyle->nodetree); MEM_freeN(linestyle->nodetree); + linestyle->nodetree = NULL; } - BKE_animdata_free(&linestyle->id); while ((m = (LineStyleModifier *)linestyle->color_modifiers.first)) BKE_linestyle_color_modifier_remove(linestyle, m); while ((m = (LineStyleModifier *)linestyle->alpha_modifiers.first)) @@ -1452,33 +1451,6 @@ char *BKE_linestyle_path_to_color_ramp(FreestyleLineStyle *linestyle, ColorBand return NULL; } -void BKE_linestyle_target_object_unlink(FreestyleLineStyle *linestyle, struct Object *ob) -{ - LineStyleModifier *m; - - for (m = (LineStyleModifier *)linestyle->color_modifiers.first; m; m = m->next) { - if (m->type == LS_MODIFIER_DISTANCE_FROM_OBJECT) { - if (((LineStyleColorModifier_DistanceFromObject *)m)->target == ob) { - ((LineStyleColorModifier_DistanceFromObject *)m)->target = NULL; - } - } - } - for (m = (LineStyleModifier *)linestyle->alpha_modifiers.first; m; m = m->next) { - if (m->type == LS_MODIFIER_DISTANCE_FROM_OBJECT) { - if (((LineStyleAlphaModifier_DistanceFromObject *)m)->target == ob) { - ((LineStyleAlphaModifier_DistanceFromObject *)m)->target = NULL; - } - } - } - for (m = (LineStyleModifier *)linestyle->thickness_modifiers.first; m; m = m->next) { - if (m->type == LS_MODIFIER_DISTANCE_FROM_OBJECT) { - if (((LineStyleThicknessModifier_DistanceFromObject *)m)->target == ob) { - ((LineStyleThicknessModifier_DistanceFromObject *)m)->target = NULL; - } - } - } -} - bool BKE_linestyle_use_textures(FreestyleLineStyle *linestyle, const bool use_shading_nodes) { if (use_shading_nodes) { diff --git a/source/blender/blenkernel/intern/mask.c b/source/blender/blenkernel/intern/mask.c index 930a3c487ec..94e53755ac4 100644 --- a/source/blender/blenkernel/intern/mask.c +++ b/source/blender/blenkernel/intern/mask.c @@ -1010,63 +1010,10 @@ void BKE_mask_layer_free_list(ListBase *masklayers) } } -/** free for temp copy, but don't manage unlinking from other pointers */ -void BKE_mask_free_nolib(Mask *mask) +/** Free (or release) any data used by this mask (does not free the mask itself). */ +void BKE_mask_free(Mask *mask) { - BKE_mask_layer_free_list(&mask->masklayers); -} - -void BKE_mask_free(Main *bmain, Mask *mask) -{ - bScreen *scr; - ScrArea *area; - SpaceLink *sl; - Scene *scene; - - for (scr = bmain->screen.first; scr; scr = scr->id.next) { - for (area = scr->areabase.first; area; area = area->next) { - for (sl = area->spacedata.first; sl; sl = sl->next) { - switch (sl->spacetype) { - case SPACE_CLIP: - { - SpaceClip *sc = (SpaceClip *)sl; - - if (sc->mask_info.mask == mask) { - sc->mask_info.mask = NULL; - } - break; - } - case SPACE_IMAGE: - { - SpaceImage *sima = (SpaceImage *)sl; - - if (sima->mask_info.mask == mask) { - sima->mask_info.mask = NULL; - } - break; - } - } - } - } - } - - for (scene = bmain->scene.first; scene; scene = scene->id.next) { - if (scene->ed) { - Sequence *seq; - - SEQ_BEGIN (scene->ed, seq) - { - if (seq->mask == mask) { - seq->mask = NULL; - } - } - SEQ_END - } - } - - FOREACH_NODETREE(bmain, ntree, id) { - BKE_node_tree_unlink_id((ID *)mask, ntree); - } FOREACH_NODETREE_END + BKE_animdata_free((ID *)mask, false); /* free mask data */ BKE_mask_layer_free_list(&mask->masklayers); diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c index 30f82a50ed9..db5ac54ada9 100644 --- a/source/blender/blenkernel/intern/material.c +++ b/source/blender/blenkernel/intern/material.c @@ -81,47 +81,33 @@ void init_def_material(void) BKE_material_init(&defmaterial); } -/* not material itself */ +/** Free (or release) any data used by this material (does not free the material itself). */ void BKE_material_free(Material *ma) { - BKE_material_free_ex(ma, true); -} - -/* not material itself */ -void BKE_material_free_ex(Material *ma, bool do_id_user) -{ - MTex *mtex; int a; + + BKE_animdata_free((ID *)ma, false); for (a = 0; a < MAX_MTEX; a++) { - mtex = ma->mtex[a]; - if (do_id_user && mtex && mtex->tex) - id_us_min(&mtex->tex->id); - if (mtex) - MEM_freeN(mtex); + MEM_SAFE_FREE(ma->mtex[a]); } - if (ma->ramp_col) MEM_freeN(ma->ramp_col); - if (ma->ramp_spec) MEM_freeN(ma->ramp_spec); - - BKE_animdata_free((ID *)ma); - - if (ma->preview) - BKE_previewimg_free(&ma->preview); - BKE_icon_id_delete((struct ID *)ma); - ma->id.icon_id = 0; + MEM_SAFE_FREE(ma->ramp_col); + MEM_SAFE_FREE(ma->ramp_spec); /* is no lib link block, but material extension */ if (ma->nodetree) { - ntreeFreeTree_ex(ma->nodetree, do_id_user); + ntreeFreeTree(ma->nodetree); MEM_freeN(ma->nodetree); + ma->nodetree = NULL; } - if (ma->texpaintslot) - MEM_freeN(ma->texpaintslot); + MEM_SAFE_FREE(ma->texpaintslot); + + GPU_material_free(&ma->gpumaterial); - if (ma->gpumaterial.first) - GPU_material_free(&ma->gpumaterial); + BKE_icon_id_delete((ID *)ma); + BKE_previewimg_free(&ma->preview); } void BKE_material_init(Material *ma) @@ -1840,7 +1826,7 @@ void free_matcopybuf(void) matcopybuf.ramp_spec = NULL; if (matcopybuf.nodetree) { - ntreeFreeTree_ex(matcopybuf.nodetree, false); + ntreeFreeTree(matcopybuf.nodetree); MEM_freeN(matcopybuf.nodetree); matcopybuf.nodetree = NULL; } diff --git a/source/blender/blenkernel/intern/mball.c b/source/blender/blenkernel/intern/mball.c index d7019aa8458..685cd35fc20 100644 --- a/source/blender/blenkernel/intern/mball.c +++ b/source/blender/blenkernel/intern/mball.c @@ -66,28 +66,13 @@ /* Functions */ -void BKE_mball_unlink(MetaBall *mb) +/** Free (or release) any data used by this mball (does not free the mball itself). */ +void BKE_mball_free(MetaBall *mb) { - int a; - - for (a = 0; a < mb->totcol; a++) { - if (mb->mat[a]) - id_us_min(&mb->mat[a]->id); - mb->mat[a] = NULL; - } -} + BKE_animdata_free((ID *)mb, false); + MEM_SAFE_FREE(mb->mat); -/* do not free mball itself */ -void BKE_mball_free(MetaBall *mb) -{ - BKE_mball_unlink(mb); - - if (mb->adt) { - BKE_animdata_free((ID *)mb); - mb->adt = NULL; - } - if (mb->mat) MEM_freeN(mb->mat); BLI_freelistN(&mb->elems); if (mb->disp.first) BKE_displist_free(&mb->disp); } diff --git a/source/blender/blenkernel/intern/mball_tessellate.c b/source/blender/blenkernel/intern/mball_tessellate.c index e8418e876bb..2068854421f 100644 --- a/source/blender/blenkernel/intern/mball_tessellate.c +++ b/source/blender/blenkernel/intern/mball_tessellate.c @@ -1159,7 +1159,7 @@ static void init_meta(EvaluationContext *eval_ctx, PROCESS *process, Scene *scen new_ml->imat = BLI_memarena_alloc(process->pgn_elements, 4 * 4 * sizeof(float)); /* too big stiffness seems only ugly due to linear interpolation - * no need to have possibility for too big stiffness */ + * no need to have possibility for too big stiffness */ if (ml->s > 10.0f) new_ml->s = 10.0f; else new_ml->s = ml->s; @@ -1294,7 +1294,7 @@ void BKE_mball_polygonize(EvaluationContext *eval_ctx, Scene *scene, Object *ob, build_bvh_spatial(&process, &process.metaball_bvh, 0, process.totelem, &process.allbb); /* don't polygonize metaballs with too high resolution (base mball to small) - * note: Eps was 0.0001f but this was giving problems for blood animation for durian, using 0.00001f */ + * note: Eps was 0.0001f but this was giving problems for blood animation for durian, using 0.00001f */ if (ob->size[0] > 0.00001f * (process.allbb.max[0] - process.allbb.min[0]) || ob->size[1] > 0.00001f * (process.allbb.max[1] - process.allbb.min[1]) || ob->size[2] > 0.00001f * (process.allbb.max[2] - process.allbb.min[2])) diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c index 2af78cca79f..706902ef3cf 100644 --- a/source/blender/blenkernel/intern/mesh.c +++ b/source/blender/blenkernel/intern/mesh.c @@ -427,38 +427,10 @@ bool BKE_mesh_has_custom_loop_normals(Mesh *me) } } -/* Note: unlinking is called when me->id.us is 0, question remains how - * much unlinking of Library data in Mesh should be done... probably - * we need a more generic method, like the expand() functions in - * readfile.c */ - -void BKE_mesh_unlink(Mesh *me) -{ - int a; - - if (me == NULL) return; - - if (me->mat) { - for (a = 0; a < me->totcol; a++) { - if (me->mat[a]) - id_us_min(&me->mat[a]->id); - me->mat[a] = NULL; - } - } - - if (me->key) { - id_us_min(&me->key->id); - } - me->key = NULL; - - if (me->texcomesh) me->texcomesh = NULL; -} - -/* do not free mesh itself */ -void BKE_mesh_free(Mesh *me, int unlink) +/** Free (or release) any data used by this mesh (does not free the mesh itself). */ +void BKE_mesh_free(Mesh *me) { - if (unlink) - BKE_mesh_unlink(me); + BKE_animdata_free(&me->id, false); CustomData_free(&me->vdata, me->totvert); CustomData_free(&me->edata, me->totedge); @@ -466,16 +438,10 @@ void BKE_mesh_free(Mesh *me, int unlink) CustomData_free(&me->ldata, me->totloop); CustomData_free(&me->pdata, me->totpoly); - if (me->adt) { - BKE_animdata_free(&me->id); - me->adt = NULL; - } - - if (me->mat) MEM_freeN(me->mat); - - if (me->bb) MEM_freeN(me->bb); - if (me->mselect) MEM_freeN(me->mselect); - if (me->edit_btmesh) MEM_freeN(me->edit_btmesh); + MEM_SAFE_FREE(me->mat); + MEM_SAFE_FREE(me->bb); + MEM_SAFE_FREE(me->mselect); + MEM_SAFE_FREE(me->edit_btmesh); } static void mesh_tessface_clear_intern(Mesh *mesh, int free_customdata) @@ -595,12 +561,14 @@ Mesh *BKE_mesh_copy(Mesh *me) return BKE_mesh_copy_ex(G.main, me); } -BMesh *BKE_mesh_to_bmesh(Mesh *me, Object *ob, const bool add_key_index) +BMesh *BKE_mesh_to_bmesh( + Mesh *me, Object *ob, + const bool add_key_index, const struct BMeshCreateParams *params) { BMesh *bm; const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(me); - bm = BM_mesh_create(&allocsize); + bm = BM_mesh_create(&allocsize, params); BM_mesh_bm_from_me( bm, me, (&(struct BMeshFromMeshParams){ diff --git a/source/blender/blenkernel/intern/mesh_evaluate.c b/source/blender/blenkernel/intern/mesh_evaluate.c index 577a21285f8..1c86fbcfe8e 100644 --- a/source/blender/blenkernel/intern/mesh_evaluate.c +++ b/source/blender/blenkernel/intern/mesh_evaluate.c @@ -677,7 +677,7 @@ static void split_loop_nor_single_do(LoopSplitTaskDataCommon *common_data, LoopS */ copy_v3_v3(*lnor, polynors[mp_index]); - /* printf("BASIC: handling loop %d / edge %d / vert %d\n", ml_curr_index, ml_curr->e, ml_curr->v); */ + /* printf("BASIC: handling loop %d / edge %d / vert %d / poly %d\n", ml_curr_index, ml_curr->e, ml_curr->v, mp_index); */ /* If needed, generate this (simple!) lnor space. */ if (lnors_spacearr) { @@ -3262,14 +3262,14 @@ void BKE_mesh_mdisp_flip(MDisps *md, const bool use_loop_mdisp_flip) */ void BKE_mesh_polygon_flip_ex( MPoly *mpoly, MLoop *mloop, CustomData *ldata, - MDisps *mdisp, const bool use_loop_mdisp_flip) + float (*lnors)[3], MDisps *mdisp, const bool use_loop_mdisp_flip) { int loopstart = mpoly->loopstart; int loopend = loopstart + mpoly->totloop - 1; const bool loops_in_ldata = (CustomData_get_layer(ldata, CD_MLOOP) == mloop); if (mdisp) { - for (int i = mpoly->loopstart; i <= loopend; i++) { + for (int i = loopstart; i <= loopend; i++) { BKE_mesh_mdisp_flip(&mdisp[i], use_loop_mdisp_flip); } } @@ -3288,6 +3288,9 @@ void BKE_mesh_polygon_flip_ex( if (!loops_in_ldata) { SWAP(MLoop, mloop[loopstart], mloop[loopend]); } + if (lnors) { + swap_v3_v3(lnors[loopstart], lnors[loopend]); + } CustomData_swap(ldata, loopstart, loopend); } /* Even if we did not swap the other 'pivot' loop, we need to set its swapped edge. */ @@ -3299,7 +3302,7 @@ void BKE_mesh_polygon_flip_ex( void BKE_mesh_polygon_flip(MPoly *mpoly, MLoop *mloop, CustomData *ldata) { MDisps *mdisp = CustomData_get_layer(ldata, CD_MDISPS); - BKE_mesh_polygon_flip_ex(mpoly, mloop, ldata, mdisp, true); + BKE_mesh_polygon_flip_ex(mpoly, mloop, ldata, NULL, mdisp, true); } /** @@ -3315,7 +3318,7 @@ void BKE_mesh_polygons_flip( int i; for (mp = mpoly, i = 0; i < totpoly; mp++, i++) { - BKE_mesh_polygon_flip_ex(mp, mloop, ldata, mdisp, true); + BKE_mesh_polygon_flip_ex(mp, mloop, ldata, NULL, mdisp, true); } } diff --git a/source/blender/blenkernel/intern/modifiers_bmesh.c b/source/blender/blenkernel/intern/modifiers_bmesh.c index 18f3db6bd15..0838630a6cb 100644 --- a/source/blender/blenkernel/intern/modifiers_bmesh.c +++ b/source/blender/blenkernel/intern/modifiers_bmesh.c @@ -211,7 +211,9 @@ BMEditMesh *DM_to_editbmesh(DerivedMesh *dm, BMEditMesh *existing, const bool do bm = em->bm; } else { - bm = BM_mesh_create(&bm_mesh_allocsize_default); + bm = BM_mesh_create( + &bm_mesh_allocsize_default, + &((struct BMeshCreateParams){.use_toolflags = false,})); } DM_to_bmesh_ex(dm, bm, do_tessellate); @@ -233,7 +235,9 @@ BMesh *DM_to_bmesh(DerivedMesh *dm, const bool calc_face_normal) BMesh *bm; const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_DM(dm); - bm = BM_mesh_create(&allocsize); + bm = BM_mesh_create( + &allocsize, + &((struct BMeshCreateParams){.use_toolflags = false,})); DM_to_bmesh_ex(dm, bm, calc_face_normal); diff --git a/source/blender/blenkernel/intern/movieclip.c b/source/blender/blenkernel/intern/movieclip.c index a8d3c600817..f99457a4c26 100644 --- a/source/blender/blenkernel/intern/movieclip.c +++ b/source/blender/blenkernel/intern/movieclip.c @@ -608,7 +608,7 @@ static MovieClip *movieclip_alloc(Main *bmain, const char *name) return clip; } -static void movieclip_load_get_szie(MovieClip *clip) +static void movieclip_load_get_size(MovieClip *clip) { int width, height; MovieClipUser user = {0}; @@ -670,7 +670,7 @@ MovieClip *BKE_movieclip_file_add(Main *bmain, const char *name) detect_clip_source(clip); - movieclip_load_get_szie(clip); + movieclip_load_get_size(clip); if (clip->lastsize[0]) { int width = clip->lastsize[0]; @@ -1248,7 +1248,7 @@ static void free_buffers(MovieClip *clip) clip->anim = NULL; } - BKE_animdata_free((ID *) clip); + BKE_animdata_free((ID *) clip, false); } void BKE_movieclip_clear_cache(MovieClip *clip) @@ -1276,7 +1276,7 @@ void BKE_movieclip_reload(MovieClip *clip) detect_clip_source(clip); clip->lastsize[0] = clip->lastsize[1] = 0; - movieclip_load_get_szie(clip); + movieclip_load_get_size(clip); movieclip_calc_length(clip); @@ -1482,80 +1482,15 @@ void BKE_movieclip_build_proxy_frame_for_ibuf(MovieClip *clip, ImBuf *ibuf, stru } } +/** Free (or release) any data used by this movie clip (does not free the clip itself). */ void BKE_movieclip_free(MovieClip *clip) { + /* Also frees animdata. */ free_buffers(clip); BKE_tracking_free(&clip->tracking); } -void BKE_movieclip_unlink(Main *bmain, MovieClip *clip) -{ - bScreen *scr; - ScrArea *area; - SpaceLink *sl; - Scene *sce; - Object *ob; - - for (scr = bmain->screen.first; scr; scr = scr->id.next) { - for (area = scr->areabase.first; area; area = area->next) { - for (sl = area->spacedata.first; sl; sl = sl->next) { - if (sl->spacetype == SPACE_CLIP) { - SpaceClip *sc = (SpaceClip *) sl; - - if (sc->clip == clip) - sc->clip = NULL; - } - else if (sl->spacetype == SPACE_VIEW3D) { - View3D *v3d = (View3D *) sl; - BGpic *bgpic; - - for (bgpic = v3d->bgpicbase.first; bgpic; bgpic = bgpic->next) { - if (bgpic->clip == clip) - bgpic->clip = NULL; - } - } - } - } - } - - for (sce = bmain->scene.first; sce; sce = sce->id.next) { - if (sce->clip == clip) - sce->clip = NULL; - } - - for (ob = bmain->object.first; ob; ob = ob->id.next) { - bConstraint *con; - - for (con = ob->constraints.first; con; con = con->next) { - if (con->type == CONSTRAINT_TYPE_FOLLOWTRACK) { - bFollowTrackConstraint *data = (bFollowTrackConstraint *) con->data; - - if (data->clip == clip) - data->clip = NULL; - } - else if (con->type == CONSTRAINT_TYPE_CAMERASOLVER) { - bCameraSolverConstraint *data = (bCameraSolverConstraint *) con->data; - - if (data->clip == clip) - data->clip = NULL; - } - else if (con->type == CONSTRAINT_TYPE_OBJECTSOLVER) { - bObjectSolverConstraint *data = (bObjectSolverConstraint *) con->data; - - if (data->clip == clip) - data->clip = NULL; - } - } - } - - FOREACH_NODETREE(bmain, ntree, id) { - BKE_node_tree_unlink_id((ID *)clip, ntree); - } FOREACH_NODETREE_END - - clip->id.us = 0; -} - float BKE_movieclip_remap_scene_to_clip_frame(MovieClip *clip, float framenr) { return framenr - (float) clip->start_frame + 1.0f; diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c index 75f899dd597..d78ddc41e97 100644 --- a/source/blender/blenkernel/intern/node.c +++ b/source/blender/blenkernel/intern/node.c @@ -1782,21 +1782,21 @@ static void free_localized_node_groups(bNodeTree *ntree) for (node = ntree->nodes.first; node; node = node->next) { if (node->type == NODE_GROUP && node->id) { bNodeTree *ngroup = (bNodeTree *)node->id; - ntreeFreeTree_ex(ngroup, false); + ntreeFreeTree(ngroup); MEM_freeN(ngroup); } } } -/* do not free ntree itself here, BKE_libblock_free calls this function too */ -void ntreeFreeTree_ex(bNodeTree *ntree, const bool do_id_user) +/** Free (or release) any data used by this nodetree (does not free the nodetree itself). */ +void ntreeFreeTree(bNodeTree *ntree) { bNodeTree *tntree; bNode *node, *next; bNodeSocket *sock, *nextsock; - - if (ntree == NULL) return; - + + BKE_animdata_free((ID *)ntree, false); + /* XXX hack! node trees should not store execution graphs at all. * This should be removed when old tree types no longer require it. * Currently the execution data for texture nodes remains in the tree @@ -1820,29 +1820,10 @@ void ntreeFreeTree_ex(bNodeTree *ntree, const bool do_id_user) /* unregister associated RNA types */ ntreeInterfaceTypeFree(ntree); - BKE_animdata_free((ID *)ntree); - - id_us_min((ID *)ntree->gpd); - BLI_freelistN(&ntree->links); /* do first, then unlink_node goes fast */ for (node = ntree->nodes.first; node; node = next) { next = node->next; - - /* ntreeUserIncrefID inline */ - - /* XXX, this is correct, however when freeing the entire database - * this ends up accessing freed data which isn't properly unlinking - * its self from scene nodes, SO - for now prefer invalid usercounts - * on free rather then bad memory access - Campbell */ -#if 0 - if (do_id_user) { - id_us_min(node->id); - } -#else - (void)do_id_user; -#endif - node_free_node_ex(ntree, node, false, false); } @@ -1874,11 +1855,6 @@ void ntreeFreeTree_ex(bNodeTree *ntree, const bool do_id_user) BKE_libblock_free_data(G.main, &ntree->id); } } -/* same as ntreeFreeTree_ex but always manage users */ -void ntreeFreeTree(bNodeTree *ntree) -{ - ntreeFreeTree_ex(ntree, true); -} void ntreeFreeCache(bNodeTree *ntree) { @@ -2165,7 +2141,7 @@ void ntreeLocalMerge(bNodeTree *localtree, bNodeTree *ntree) if (ntree->typeinfo->local_merge) ntree->typeinfo->local_merge(localtree, ntree); - ntreeFreeTree_ex(localtree, false); + ntreeFreeTree(localtree); MEM_freeN(localtree); } } @@ -2418,15 +2394,21 @@ void ntreeInterfaceTypeUpdate(bNodeTree *ntree) /* ************ find stuff *************** */ +bNode *ntreeFindType(const bNodeTree *ntree, int type) +{ + if (ntree) { + for (bNode * node = ntree->nodes.first; node; node = node->next) { + if (node->type == type) { + return node; + } + } + } + return NULL; +} + bool ntreeHasType(const bNodeTree *ntree, int type) { - bNode *node; - - if (ntree) - for (node = ntree->nodes.first; node; node = node->next) - if (node->type == type) - return true; - return false; + return ntreeFindType(ntree, type) != NULL; } bool ntreeHasTree(const bNodeTree *ntree, const bNodeTree *lookup) diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index e44318c6633..c2d45c6d447 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -213,7 +213,6 @@ void BKE_object_free_modifiers(Object *ob) /* same for softbody */ BKE_object_free_softbody(ob); - /* modifiers may have stored data in the DM cache */ BKE_object_free_derived_caches(ob); } @@ -318,14 +317,14 @@ void BKE_object_free_derived_caches(Object *ob) if (ob->type == OB_MESH) { Mesh *me = ob->data; - if (me->bb) { + if (me && me->bb) { me->bb->flag |= BOUNDBOX_DIRTY; } } else if (ELEM(ob->type, OB_SURF, OB_CURVE, OB_FONT)) { Curve *cu = ob->data; - if (cu->bb) { + if (cu && cu->bb) { cu->bb->flag |= BOUNDBOX_DIRTY; } } @@ -394,78 +393,54 @@ void BKE_object_free_caches(Object *object) } } -/* do not free object itself */ -void BKE_object_free_ex(Object *ob, bool do_id_user) +/** Free (or release) any data used by this object (does not free the object itself). */ +void BKE_object_free(Object *ob) { - int a; - + BKE_animdata_free((ID *)ob, false); + BKE_object_free_modifiers(ob); - - /* disconnect specific data, but not for lib data (might be indirect data, can get relinked) */ - if (ob->data) { - ID *id = ob->data; - id_us_min(id); - if (id->us == 0 && id->lib == NULL) { - switch (ob->type) { - case OB_MESH: - BKE_mesh_unlink((Mesh *)id); - break; - case OB_CURVE: - BKE_curve_unlink((Curve *)id); - break; - case OB_MBALL: - BKE_mball_unlink((MetaBall *)id); - break; - } - } - ob->data = NULL; - } - if (ob->mat) { - for (a = 0; a < ob->totcol; a++) { - if (ob->mat[a]) - id_us_min(&ob->mat[a]->id); - } - MEM_freeN(ob->mat); + MEM_SAFE_FREE(ob->mat); + MEM_SAFE_FREE(ob->matbits); + MEM_SAFE_FREE(ob->iuser); + MEM_SAFE_FREE(ob->bb); + + BLI_freelistN(&ob->defbase); + if (ob->pose) { + BKE_pose_free_ex(ob->pose, false); + ob->pose = NULL; } - if (ob->matbits) MEM_freeN(ob->matbits); - ob->mat = NULL; - ob->matbits = NULL; - if (ob->iuser) MEM_freeN(ob->iuser); - ob->iuser = NULL; - if (ob->bb) MEM_freeN(ob->bb); - ob->bb = NULL; - if (ob->adt) BKE_animdata_free((ID *)ob); - if (ob->poselib) - id_us_min(&ob->poselib->id); - if (ob->gpd) - id_us_min(&ob->gpd->id); - if (ob->defbase.first) - BLI_freelistN(&ob->defbase); - if (ob->pose) - BKE_pose_free_ex(ob->pose, do_id_user); - if (ob->mpath) + if (ob->mpath) { animviz_free_motionpath(ob->mpath); + ob->mpath = NULL; + } BKE_bproperty_free_list(&ob->prop); - + free_sensors(&ob->sensors); free_controllers(&ob->controllers); free_actuators(&ob->actuators); - BKE_constraints_free_ex(&ob->constraints, do_id_user); + BKE_constraints_free_ex(&ob->constraints, false); free_partdeflect(ob->pd); BKE_rigidbody_free_object(ob); BKE_rigidbody_free_constraint(ob); - if (ob->soft) sbFree(ob->soft); - if (ob->bsoft) bsbFree(ob->bsoft); - if (ob->gpulamp.first) GPU_lamp_free(ob); - if (ob->gpuprobe.first) GPU_probe_free(&ob->gpuprobe); + if (ob->soft) { + sbFree(ob->soft); + ob->soft = NULL; + } + if (ob->bsoft) { + bsbFree(ob->bsoft); + ob->bsoft = NULL; + } + GPU_lamp_free(ob); + + GPU_probe_free(&ob->gpuprobe); BKE_sculptsession_free(ob); - if (ob->pc_ids.first) BLI_freelistN(&ob->pc_ids); + BLI_freelistN(&ob->pc_ids); BLI_freelistN(&ob->lodlevels); @@ -475,409 +450,12 @@ void BKE_object_free_ex(Object *ob, bool do_id_user) if (ob->curve_cache->path) free_path(ob->curve_cache->path); MEM_freeN(ob->curve_cache); + ob->curve_cache = NULL; } BKE_previewimg_free(&ob->preview); } -void BKE_object_free(Object *ob) -{ - BKE_object_free_ex(ob, true); -} - -static void unlink_object__unlinkModifierLinks(void *userData, Object *ob, Object **obpoin, int UNUSED(cd_flag)) -{ - Object *unlinkOb = userData; - - if (*obpoin == unlinkOb) { - *obpoin = NULL; - // XXX: should this just be OB_RECALC_DATA? - DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); - } -} - -void BKE_object_unlink(Main *bmain, Object *ob) -{ - Object *obt; - Material *mat; - World *wrld; - bScreen *sc; - Scene *sce; - SceneRenderLayer *srl; - FreestyleLineSet *lineset; - bNodeTree *ntree; - Curve *cu; - Tex *tex; - Group *group; - Camera *camera; - bConstraint *con; - //bActionStrip *strip; // XXX animsys - ModifierData *md; - ARegion *ar; - RegionView3D *rv3d; - LodLevel *lod; - int a, found; - - unlink_controllers(&ob->controllers); - unlink_actuators(&ob->actuators); - - /* check all objects: parents en bevels and fields, also from libraries */ - /* FIXME: need to check all animation blocks (drivers) */ - obt = bmain->object.first; - while (obt) { - if (obt->proxy == ob) - obt->proxy = NULL; - if (obt->proxy_from == ob) { - obt->proxy_from = NULL; - DAG_id_tag_update(&obt->id, OB_RECALC_OB); - } - if (obt->proxy_group == ob) - obt->proxy_group = NULL; - - if (obt->parent == ob) { - obt->parent = NULL; - DAG_id_tag_update(&obt->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); - } - - modifiers_foreachObjectLink(obt, unlink_object__unlinkModifierLinks, ob); - - if (ELEM(obt->type, OB_CURVE, OB_FONT)) { - cu = obt->data; - - if (cu->bevobj == ob) { - cu->bevobj = NULL; - DAG_id_tag_update(&obt->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); - } - if (cu->taperobj == ob) { - cu->taperobj = NULL; - DAG_id_tag_update(&obt->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); - } - if (cu->textoncurve == ob) { - cu->textoncurve = NULL; - DAG_id_tag_update(&obt->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); - } - } - else if (obt->type == OB_ARMATURE && obt->pose) { - bPoseChannel *pchan; - for (pchan = obt->pose->chanbase.first; pchan; pchan = pchan->next) { - for (con = pchan->constraints.first; con; con = con->next) { - const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); - ListBase targets = {NULL, NULL}; - bConstraintTarget *ct; - - if (cti && cti->get_constraint_targets) { - cti->get_constraint_targets(con, &targets); - - for (ct = targets.first; ct; ct = ct->next) { - if (ct->tar == ob) { - ct->tar = NULL; - ct->subtarget[0] = '\0'; - DAG_id_tag_update(&obt->id, OB_RECALC_DATA); - } - } - - if (cti->flush_constraint_targets) - cti->flush_constraint_targets(con, &targets, 0); - } - } - if (pchan->custom == ob) - pchan->custom = NULL; - } - } - else if (ELEM(OB_MBALL, ob->type, obt->type)) { - if (BKE_mball_is_basis_for(obt, ob)) - DAG_id_tag_update(&obt->id, OB_RECALC_DATA); - } - - sca_remove_ob_poin(obt, ob); - - for (con = obt->constraints.first; con; con = con->next) { - const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); - ListBase targets = {NULL, NULL}; - bConstraintTarget *ct; - - if (cti && cti->get_constraint_targets) { - cti->get_constraint_targets(con, &targets); - - for (ct = targets.first; ct; ct = ct->next) { - if (ct->tar == ob) { - ct->tar = NULL; - ct->subtarget[0] = '\0'; - DAG_id_tag_update(&obt->id, OB_RECALC_DATA); - } - } - - if (cti->flush_constraint_targets) - cti->flush_constraint_targets(con, &targets, 0); - } - } - - /* object is deflector or field */ - if (ob->pd) { - if (obt->soft) - DAG_id_tag_update(&obt->id, OB_RECALC_DATA); - - /* cloth */ - for (md = obt->modifiers.first; md; md = md->next) - if (md->type == eModifierType_Cloth) - DAG_id_tag_update(&obt->id, OB_RECALC_DATA); - } - - /* strips */ -#if 0 // XXX old animation system - for (strip = obt->nlastrips.first; strip; strip = strip->next) { - if (strip->object == ob) - strip->object = NULL; - - if (strip->modifiers.first) { - bActionModifier *amod; - for (amod = strip->modifiers.first; amod; amod = amod->next) - if (amod->ob == ob) - amod->ob = NULL; - } - } -#endif // XXX old animation system - - /* particle systems */ - if (obt->particlesystem.first) { - ParticleSystem *tpsys = obt->particlesystem.first; - for (; tpsys; tpsys = tpsys->next) { - BoidState *state = NULL; - BoidRule *rule = NULL; - - ParticleTarget *pt = tpsys->targets.first; - for (; pt; pt = pt->next) { - if (pt->ob == ob) { - pt->ob = NULL; - DAG_id_tag_update(&obt->id, OB_RECALC_DATA); - break; - } - } - - if (tpsys->target_ob == ob) { - tpsys->target_ob = NULL; - DAG_id_tag_update(&obt->id, OB_RECALC_DATA); - } - - if (tpsys->part->dup_ob == ob) - tpsys->part->dup_ob = NULL; - - if (tpsys->part->phystype == PART_PHYS_BOIDS) { - ParticleData *pa; - BoidParticle *bpa; - int p; - - for (p = 0, pa = tpsys->particles; p < tpsys->totpart; p++, pa++) { - bpa = pa->boid; - if (bpa->ground == ob) - bpa->ground = NULL; - } - } - if (tpsys->part->boids) { - for (state = tpsys->part->boids->states.first; state; state = state->next) { - for (rule = state->rules.first; rule; rule = rule->next) { - if (rule->type == eBoidRuleType_Avoid) { - BoidRuleGoalAvoid *gabr = (BoidRuleGoalAvoid *)rule; - if (gabr->ob == ob) - gabr->ob = NULL; - } - else if (rule->type == eBoidRuleType_FollowLeader) { - BoidRuleFollowLeader *flbr = (BoidRuleFollowLeader *)rule; - if (flbr->ob == ob) - flbr->ob = NULL; - } - } - } - } - - if (tpsys->parent == ob) - tpsys->parent = NULL; - } - if (ob->pd) - DAG_id_tag_update(&obt->id, OB_RECALC_DATA); - } - - /* levels of detail */ - for (lod = obt->lodlevels.first; lod; lod = lod->next) { - if (lod->source == ob) - lod->source = NULL; - } - - /* probe */ - if (obt->probe == ob) - ob->probe = NULL; - - if (obt->parallaxcorrect == ob) - ob->parallaxcorrect = NULL; - - if (obt->reflectionplane == ob) - ob->reflectionplane = NULL; - - obt = obt->id.next; - - } - - /* materials */ - for (mat = bmain->mat.first; mat; mat = mat->id.next) { - if (mat->nodetree) { - ntreeSwitchID(mat->nodetree, &ob->id, NULL); - } - for (a = 0; a < MAX_MTEX; a++) { - if (mat->mtex[a] && ob == mat->mtex[a]->object) { - /* actually, test for lib here... to do */ - mat->mtex[a]->object = NULL; - } - } - } - - /* node trees */ - for (ntree = bmain->nodetree.first; ntree; ntree = ntree->id.next) { - if (ntree->type == NTREE_SHADER) - ntreeSwitchID(ntree, &ob->id, NULL); - } - - /* textures */ - for (tex = bmain->tex.first; tex; tex = tex->id.next) { - if (tex->env && (ob == tex->env->object)) tex->env->object = NULL; - if (tex->pd && (ob == tex->pd->object)) tex->pd->object = NULL; - if (tex->vd && (ob == tex->vd->object)) tex->vd->object = NULL; - } - - /* worlds */ - wrld = bmain->world.first; - while (wrld) { - if (wrld->id.lib == NULL) { - for (a = 0; a < MAX_MTEX; a++) { - if (wrld->mtex[a] && ob == wrld->mtex[a]->object) - wrld->mtex[a]->object = NULL; - } - } - - wrld = wrld->id.next; - } - - /* scenes */ - sce = bmain->scene.first; - while (sce) { - if (sce->id.lib == NULL) { - if (sce->camera == ob) sce->camera = NULL; - if (sce->toolsettings->skgen_template == ob) sce->toolsettings->skgen_template = NULL; - if (sce->toolsettings->particle.object == ob) sce->toolsettings->particle.object = NULL; - if (sce->toolsettings->particle.shape_object == ob) sce->toolsettings->particle.shape_object = NULL; - -#ifdef DURIAN_CAMERA_SWITCH - { - TimeMarker *m; - - for (m = sce->markers.first; m; m = m->next) { - if (m->camera == ob) - m->camera = NULL; - } - } -#endif - if (sce->ed) { - Sequence *seq; - SEQ_BEGIN(sce->ed, seq) - { - if (seq->scene_camera == ob) { - seq->scene_camera = NULL; - } - } - SEQ_END - } - - for (srl = sce->r.layers.first; srl; srl = srl->next) { - for (lineset = (FreestyleLineSet *)srl->freestyleConfig.linesets.first; - lineset; lineset = lineset->next) - { - if (lineset->linestyle) { - BKE_linestyle_target_object_unlink(lineset->linestyle, ob); - } - } - } - } - - sce = sce->id.next; - } - - /* screens */ - sc = bmain->screen.first; - while (sc) { - ScrArea *sa = sc->areabase.first; - while (sa) { - SpaceLink *sl; - - for (sl = sa->spacedata.first; sl; sl = sl->next) { - if (sl->spacetype == SPACE_VIEW3D) { - View3D *v3d = (View3D *) sl; - - /* found doesn't need to be set here */ - if (v3d->ob_centre == ob) { - v3d->ob_centre = NULL; - v3d->ob_centre_bone[0] = '\0'; - } - if (v3d->localvd && v3d->localvd->ob_centre == ob) { - v3d->localvd->ob_centre = NULL; - v3d->localvd->ob_centre_bone[0] = '\0'; - } - - found = 0; - if (v3d->camera == ob) { - v3d->camera = NULL; - found = 1; - } - if (v3d->localvd && v3d->localvd->camera == ob) { - v3d->localvd->camera = NULL; - found += 2; - } - - if (found) { - if (sa->spacetype == SPACE_VIEW3D) { - for (ar = sa->regionbase.first; ar; ar = ar->next) { - if (ar->regiontype == RGN_TYPE_WINDOW) { - rv3d = (RegionView3D *)ar->regiondata; - if (found == 1 || found == 3) { - if (rv3d->persp == RV3D_CAMOB) - rv3d->persp = RV3D_PERSP; - } - if (found == 2 || found == 3) { - if (rv3d->localvd && rv3d->localvd->persp == RV3D_CAMOB) - rv3d->localvd->persp = RV3D_PERSP; - } - } - } - } - } - } -#if 0 - else if (ELEM(sl->spacetype, SPACE_OUTLINER, SPACE_BUTS, SPACE_NODE)) { - /* now handled by WM_main_remove_editor_id_reference */ - } -#endif - } - - sa = sa->next; - } - sc = sc->id.next; - } - - /* groups */ - group = bmain->group.first; - while (group) { - BKE_group_object_unlink(group, ob, NULL, NULL); - group = group->id.next; - } - - /* cameras */ - camera = bmain->camera.first; - while (camera) { - if (camera->dof_ob == ob) { - camera->dof_ob = NULL; - } - camera = camera->id.next; - } -} - /* actual check for internal data, not context or flags */ bool BKE_object_is_in_editmode(Object *ob) { diff --git a/source/blender/blenkernel/intern/object_dupli.c b/source/blender/blenkernel/intern/object_dupli.c index 63c37fddc60..c03f7c2c0ae 100644 --- a/source/blender/blenkernel/intern/object_dupli.c +++ b/source/blender/blenkernel/intern/object_dupli.c @@ -851,7 +851,7 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem if (part == NULL) return; - if (!psys_check_enabled(par, psys)) + if (!psys_check_enabled(par, psys, (ctx->eval_ctx->mode == DAG_EVAL_RENDER))) return; if (!for_render) diff --git a/source/blender/blenkernel/intern/object_update.c b/source/blender/blenkernel/intern/object_update.c index 03348adeabc..6d41c5c2975 100644 --- a/source/blender/blenkernel/intern/object_update.c +++ b/source/blender/blenkernel/intern/object_update.c @@ -269,7 +269,7 @@ void BKE_object_handle_data_update(EvaluationContext *eval_ctx, psys_changed_type(ob, psys); } - if (psys_check_enabled(ob, psys)) { + if (psys_check_enabled(ob, psys, eval_ctx->mode == DAG_EVAL_RENDER)) { /* check use of dupli objects here */ if (psys->part && (psys->part->draw_as == PART_DRAW_REND || eval_ctx->mode == DAG_EVAL_RENDER) && ((psys->part->ren_as == PART_DRAW_OB && psys->part->dup_ob) || @@ -278,7 +278,7 @@ void BKE_object_handle_data_update(EvaluationContext *eval_ctx, ob->transflag |= OB_DUPLIPARTS; } - particle_system_update(scene, ob, psys); + particle_system_update(scene, ob, psys, (eval_ctx->mode == DAG_EVAL_RENDER)); psys = psys->next; } else if (psys->flag & PSYS_DELETE) { @@ -347,3 +347,10 @@ void BKE_object_eval_uber_data(EvaluationContext *eval_ctx, ob->recalc &= ~(OB_RECALC_DATA | OB_RECALC_TIME); } + +void BKE_object_eval_proxy_backlink(EvaluationContext *UNUSED(eval_ctx), Object *ob) +{ + if (ob->proxy) { + ob->proxy->proxy_from = ob; + } +} diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c index 3a2663c5d48..8c1502643c5 100644 --- a/source/blender/blenkernel/intern/paint.c +++ b/source/blender/blenkernel/intern/paint.c @@ -298,13 +298,11 @@ void BKE_paint_brush_set(Paint *p, Brush *br) } } +/** Free (or release) any data used by this paint curve (does not free the pcurve itself). */ void BKE_paint_curve_free(PaintCurve *pc) { - if (pc->points) { - MEM_freeN(pc->points); - pc->points = NULL; - pc->tot_points = 0; - } + MEM_SAFE_FREE(pc->points); + pc->tot_points = 0; } PaintCurve *BKE_paint_curve_add(Main *bmain, const char *name) @@ -378,6 +376,7 @@ Palette *BKE_palette_add(Main *bmain, const char *name) return palette; } +/** Free (or release) any data used by this palette (does not free the palette itself). */ void BKE_palette_free(Palette *palette) { BLI_freelistN(&palette->colors); @@ -493,8 +492,6 @@ void BKE_paint_init(Scene *sce, PaintMode mode, const char col[3]) void BKE_paint_free(Paint *paint) { - id_us_min((ID *)paint->brush); - id_us_min((ID *)paint->palette); curvemapping_free(paint->cavity_curve); } diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c index 25dd7fff380..d1f5afa26a6 100644 --- a/source/blender/blenkernel/intern/particle.c +++ b/source/blender/blenkernel/intern/particle.c @@ -283,7 +283,7 @@ bool psys_in_edit_mode(Scene *scene, ParticleSystem *psys) { return (scene->basact && (scene->basact->object->mode & OB_MODE_PARTICLE_EDIT) && psys == psys_get_current((scene->basact)->object) && (psys->edit || psys->pointcache->edit) && !psys->renderdata); } -bool psys_check_enabled(Object *ob, ParticleSystem *psys) +bool psys_check_enabled(Object *ob, ParticleSystem *psys, const bool use_render_params) { ParticleSystemModifierData *psmd; @@ -291,7 +291,7 @@ bool psys_check_enabled(Object *ob, ParticleSystem *psys) return 0; psmd = psys_get_modifier(ob, psys); - if (psys->renderdata || G.is_rendering) { + if (psys->renderdata || use_render_params) { if (!(psmd->modifier.mode & eModifierMode_Render)) return 0; } @@ -376,12 +376,17 @@ static void fluid_free_settings(SPHFluidSettings *fluid) MEM_freeN(fluid); } +/** Free (or release) any data used by this particle settings (does not free the partsett itself). */ void BKE_particlesettings_free(ParticleSettings *part) { - MTex *mtex; int a; - BKE_animdata_free(&part->id); + + BKE_animdata_free((ID *)part, false); + for (a = 0; a < MAX_MTEX; a++) { + MEM_SAFE_FREE(part->mtex[a]); + } + if (part->clumpcurve) curvemapping_free(part->clumpcurve); if (part->roughcurve) @@ -390,21 +395,12 @@ void BKE_particlesettings_free(ParticleSettings *part) free_partdeflect(part->pd); free_partdeflect(part->pd2); - if (part->effector_weights) - MEM_freeN(part->effector_weights); + MEM_SAFE_FREE(part->effector_weights); BLI_freelistN(&part->dupliweights); boid_free_settings(part->boids); fluid_free_settings(part->fluid); - - for (a = 0; a < MAX_MTEX; a++) { - mtex = part->mtex[a]; - if (mtex && mtex->tex) - id_us_min(&mtex->tex->id); - if (mtex) - MEM_freeN(mtex); - } } void free_hair(Object *UNUSED(ob), ParticleSystem *psys, int dynamics) @@ -573,10 +569,7 @@ void psys_free(Object *ob, ParticleSystem *psys) if (!nr) ob->transflag &= ~OB_DUPLIPARTS; - if (psys->part) { - id_us_min(&psys->part->id); - psys->part = NULL; - } + psys->part = NULL; BKE_ptcache_free_list(&psys->ptcaches); psys->pointcache = NULL; @@ -2014,7 +2007,7 @@ float *psys_cache_vgroup(DerivedMesh *dm, ParticleSystem *psys, int vgroup) } return vg; } -void psys_find_parents(ParticleSimulationData *sim) +void psys_find_parents(ParticleSimulationData *sim, const bool use_render_params) { ParticleSystem *psys = sim->psys; ParticleSettings *part = sim->psys->part; @@ -2026,7 +2019,7 @@ void psys_find_parents(ParticleSimulationData *sim) int from = PART_FROM_FACE; totparent = (int)(totchild * part->parents * 0.3f); - if ((sim->psys->renderdata || G.is_rendering) && part->child_nbr && part->ren_child_nbr) + if ((sim->psys->renderdata || use_render_params) && part->child_nbr && part->ren_child_nbr) totparent *= (float)part->child_nbr / (float)part->ren_child_nbr; /* hard limit, workaround for it being ignored above */ @@ -2057,7 +2050,9 @@ void psys_find_parents(ParticleSimulationData *sim) BLI_kdtree_free(tree); } -static bool psys_thread_context_init_path(ParticleThreadContext *ctx, ParticleSimulationData *sim, Scene *scene, float cfra, int editupdate) +static bool psys_thread_context_init_path( + ParticleThreadContext *ctx, ParticleSimulationData *sim, Scene *scene, + float cfra, const bool editupdate, const bool use_render_params) { ParticleSystem *psys = sim->psys; ParticleSettings *part = psys->part; @@ -2071,7 +2066,7 @@ static bool psys_thread_context_init_path(ParticleThreadContext *ctx, ParticleSi if (psys_in_edit_mode(scene, psys)) { ParticleEditSettings *pset = &scene->toolsettings->particle; - if ((psys->renderdata == 0 && G.is_rendering == 0) && (psys->edit == NULL || pset->flag & PE_DRAW_PART) == 0) + if ((psys->renderdata == 0 && use_render_params == 0) && (psys->edit == NULL || pset->flag & PE_DRAW_PART) == 0) totchild = 0; segments = 1 << pset->draw_step; @@ -2080,14 +2075,14 @@ static bool psys_thread_context_init_path(ParticleThreadContext *ctx, ParticleSi if (totchild && part->childtype == PART_CHILD_FACES) { totparent = (int)(totchild * part->parents * 0.3f); - if ((psys->renderdata || G.is_rendering) && part->child_nbr && part->ren_child_nbr) + if ((psys->renderdata || use_render_params) && part->child_nbr && part->ren_child_nbr) totparent *= (float)part->child_nbr / (float)part->ren_child_nbr; /* part->parents could still be 0 so we can't test with totparent */ between = 1; } - if (psys->renderdata || G.is_rendering) + if (psys->renderdata || use_render_params) segments = 1 << part->ren_step; else { totchild = (int)((float)totchild * (float)part->disp / 100.0f); @@ -2424,7 +2419,9 @@ static void exec_child_path_cache(TaskPool * __restrict UNUSED(pool), void *task } } -void psys_cache_child_paths(ParticleSimulationData *sim, float cfra, int editupdate) +void psys_cache_child_paths( + ParticleSimulationData *sim, float cfra, + const bool editupdate, const bool use_render_params) { TaskScheduler *task_scheduler; TaskPool *task_pool; @@ -2437,7 +2434,7 @@ void psys_cache_child_paths(ParticleSimulationData *sim, float cfra, int editupd return; /* create a task pool for child path tasks */ - if (!psys_thread_context_init_path(&ctx, sim, sim->scene, cfra, editupdate)) + if (!psys_thread_context_init_path(&ctx, sim, sim->scene, cfra, editupdate, use_render_params)) return; task_scheduler = BLI_task_scheduler_get(); @@ -2529,7 +2526,7 @@ static void cache_key_incremental_rotation(ParticleCacheKey *key0, ParticleCache * - Useful for making use of opengl vertex arrays for super fast strand drawing. * - Makes child strands possible and creates them too into the cache. * - Cached path data is also used to determine cut position for the editmode tool. */ -void psys_cache_paths(ParticleSimulationData *sim, float cfra) +void psys_cache_paths(ParticleSimulationData *sim, float cfra, const bool use_render_params) { PARTICLE_PSMD; ParticleEditSettings *pset = &sim->scene->toolsettings->particle; @@ -2553,7 +2550,7 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra) float prev_tangent[3] = {0.0f, 0.0f, 0.0f}, hairmat[4][4]; float rotmat[3][3]; int k; - int segments = (int)pow(2.0, (double)((psys->renderdata || G.is_rendering) ? part->ren_step : part->draw_step)); + int segments = (int)pow(2.0, (double)((psys->renderdata || use_render_params) ? part->ren_step : part->draw_step)); int totpart = psys->totpart; float length, vec[3]; float *vg_effector = NULL; @@ -2732,7 +2729,7 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra) if (vg_length) MEM_freeN(vg_length); } -void psys_cache_edit_paths(Scene *scene, Object *ob, PTCacheEdit *edit, float cfra) +void psys_cache_edit_paths(Scene *scene, Object *ob, PTCacheEdit *edit, float cfra, const bool use_render_params) { ParticleCacheKey *ca, **cache = edit->pathcache; ParticleEditSettings *pset = &scene->toolsettings->particle; @@ -2928,7 +2925,7 @@ void psys_cache_edit_paths(Scene *scene, Object *ob, PTCacheEdit *edit, float cf sim.psys = psys; sim.psmd = psys_get_modifier(ob, psys); - psys_cache_child_paths(&sim, cfra, 1); + psys_cache_child_paths(&sim, cfra, true, use_render_params); } /* clear recalc flag if set here */ diff --git a/source/blender/blenkernel/intern/particle_distribute.c b/source/blender/blenkernel/intern/particle_distribute.c index f6bddfa6f99..c814713f3f4 100644 --- a/source/blender/blenkernel/intern/particle_distribute.c +++ b/source/blender/blenkernel/intern/particle_distribute.c @@ -392,22 +392,25 @@ static int distribute_binary_search(float *sum, int n, float value) { int mid, low = 0, high = n - 1; + if (high == low) + return low; + if (sum[low] >= value) return low; - if (sum[high] < value) + if (sum[high - 1] < value) return high; while (low < high) { mid = (low + high) / 2; - if ((sum[mid] < value) && (sum[mid + 1] >= value)) + if ((sum[mid] >= value) && (sum[mid - 1] < value)) return mid; - if (sum[mid] >= value) { + if (sum[mid] > value) { high = mid - 1; } - else if (sum[mid] < value) { + else { low = mid + 1; } } @@ -1004,56 +1007,62 @@ static int psys_thread_context_init_distribute(ParticleThreadContext *ctx, Parti MEM_freeN(vweight); } +#define MIN_WEIGHT 1e-7f /* Weights too small cause issues e.g. with binary search... */ + /* Calculate total weight of all elements */ int totmapped = 0; totweight = 0.0f; for (i = 0; i < totelem; i++) { - if (element_weight[i] != 0.0f) { + if (element_weight[i] > MIN_WEIGHT) { totmapped++; + totweight += element_weight[i]; } - totweight += element_weight[i]; } - if (totweight == 0.0f) { + if (totmapped == 0) { /* We are not allowed to distribute particles anywhere... */ return 0; } - inv_totweight = (totweight > 0.f ? 1.f/totweight : 0.f); + inv_totweight = 1.0f / totweight; /* Calculate cumulative weights. * We remove all null-weighted elements from element_sum, and create a new mapping * 'activ'_elem_index -> orig_elem_index. - * This simplifies greatly the filtering of zero-weighted items - and can be much mor efficient + * This simplifies greatly the filtering of zero-weighted items - and can be much more efficient * especially in random case (reducing a lot the size of binary-searched array)... */ float *element_sum = MEM_mallocN(sizeof(*element_sum) * totmapped, __func__); int *element_map = MEM_mallocN(sizeof(*element_map) * totmapped, __func__); int i_mapped = 0; - for (i = 0; i < totelem && element_weight[i] == 0.0f; i++); + for (i = 0; i < totelem && element_weight[i] <= MIN_WEIGHT; i++); element_sum[i_mapped] = element_weight[i] * inv_totweight; element_map[i_mapped] = i; i_mapped++; for (i++; i < totelem; i++) { - if (element_weight[i] != 0.0f) { + if (element_weight[i] > MIN_WEIGHT) { element_sum[i_mapped] = element_sum[i_mapped - 1] + element_weight[i] * inv_totweight; + BLI_assert(element_sum[i_mapped] > element_sum[i_mapped - 1]); element_map[i_mapped] = i; i_mapped++; } } BLI_assert(i_mapped == totmapped); - + +#undef MIN_WEIGHT + /* Finally assign elements to particles */ if ((part->flag & PART_TRAND) || (part->simplify_flag & PART_SIMPLIFY_ENABLE)) { - float pos; - for (p = 0; p < totpart; p++) { - /* In theory element_sum[totelem - 1] should be 1.0, + /* In theory element_sum[totmapped - 1] should be 1.0, * but due to float errors this is not necessarily always true, so scale pos accordingly. */ - pos = BLI_frand() * element_sum[totmapped - 1]; - particle_element[p] = element_map[distribute_binary_search(element_sum, totmapped, pos)]; + const float pos = BLI_frand() * element_sum[totmapped - 1]; + const int eidx = distribute_binary_search(element_sum, totmapped, pos); + particle_element[p] = element_map[eidx]; + BLI_assert(pos <= element_sum[eidx]); + BLI_assert(eidx ? (pos > element_sum[eidx - 1]) : (pos >= 0.0f)); jitter_offset[particle_element[p]] = pos; } } diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c index 1ca68f714c8..c3f47fac852 100644 --- a/source/blender/blenkernel/intern/particle_system.c +++ b/source/blender/blenkernel/intern/particle_system.c @@ -230,7 +230,7 @@ static void realloc_particles(ParticleSimulationData *sim, int new_totpart) newboids= MEM_callocN(totpart*sizeof(BoidParticle), "boid particles"); if (newboids == NULL) { - /* allocation error! */ + /* allocation error! */ if (newpars) MEM_freeN(newpars); return; @@ -2885,7 +2885,7 @@ static void collision_check(ParticleSimulationData *sim, int p, float dfra, floa /* Hair */ /************************************************/ /* check if path cache or children need updating and do it if needed */ -static void psys_update_path_cache(ParticleSimulationData *sim, float cfra) +static void psys_update_path_cache(ParticleSimulationData *sim, float cfra, const bool use_render_params) { ParticleSystem *psys = sim->psys; ParticleSettings *part = psys->part; @@ -2909,7 +2909,7 @@ static void psys_update_path_cache(ParticleSimulationData *sim, float cfra) distribute_particles(sim, PART_FROM_CHILD); if (part->childtype==PART_CHILD_FACES && part->parents != 0.0f) - psys_find_parents(sim); + psys_find_parents(sim, use_render_params); } } else @@ -2947,7 +2947,7 @@ static void psys_update_path_cache(ParticleSimulationData *sim, float cfra) } if (!skip) { - psys_cache_paths(sim, cfra); + psys_cache_paths(sim, cfra, use_render_params); /* for render, child particle paths are computed on the fly */ if (part->childtype) { @@ -2957,7 +2957,7 @@ static void psys_update_path_cache(ParticleSimulationData *sim, float cfra) skip = 1; if (!skip) - psys_cache_child_paths(sim, cfra, 0); + psys_cache_child_paths(sim, cfra, 0, use_render_params); } } else if (psys->pathcache) @@ -3193,7 +3193,7 @@ static void do_hair_dynamics(ParticleSimulationData *sim) /* restore cloth effector weights */ psys->clmd->sim_parms->effector_weights = clmd_effweights; } -static void hair_step(ParticleSimulationData *sim, float cfra) +static void hair_step(ParticleSimulationData *sim, float cfra, const bool use_render_params) { ParticleSystem *psys = sim->psys; ParticleSettings *part = psys->part; @@ -3225,7 +3225,7 @@ static void hair_step(ParticleSimulationData *sim, float cfra) /* following lines were removed r29079 but cause bug [#22811], see report for details */ psys_update_effectors(sim); - psys_update_path_cache(sim, cfra); + psys_update_path_cache(sim, cfra, use_render_params); psys->flag |= PSYS_HAIR_UPDATED; } @@ -3732,7 +3732,7 @@ static void cached_step(ParticleSimulationData *sim, float cfra) } } -static void particles_fluid_step(ParticleSimulationData *sim, int UNUSED(cfra)) +static void particles_fluid_step(ParticleSimulationData *sim, int UNUSED(cfra), const bool use_render_params) { ParticleSystem *psys = sim->psys; if (psys->particles) { @@ -3775,7 +3775,7 @@ static void particles_fluid_step(ParticleSimulationData *sim, int UNUSED(cfra)) } gzread(gzf, &totpart, sizeof(totpart)); - totpart = (G.is_rendering)?totpart:(part->disp*totpart) / 100; + totpart = (use_render_params) ? totpart:(part->disp*totpart) / 100; part->totpart= totpart; part->sta=part->end = 1.0f; @@ -3836,6 +3836,8 @@ static void particles_fluid_step(ParticleSimulationData *sim, int UNUSED(cfra)) } // fluid sim particles done } +#else + UNUSED_VARS(use_render_params); #endif // WITH_MOD_FLUID } @@ -3857,7 +3859,7 @@ static int emit_particles(ParticleSimulationData *sim, PTCacheID *pid, float UNU * 2. Check cache (if used) and return if frame is cached * 3. Do dynamics * 4. Save to cache */ -static void system_step(ParticleSimulationData *sim, float cfra) +static void system_step(ParticleSimulationData *sim, float cfra, const bool use_render_params) { ParticleSystem *psys = sim->psys; ParticleSettings *part = psys->part; @@ -3919,7 +3921,7 @@ static void system_step(ParticleSimulationData *sim, float cfra) if (ELEM(cache_result, PTCACHE_READ_EXACT, PTCACHE_READ_INTERPOLATED)) { cached_step(sim, cfra); update_children(sim); - psys_update_path_cache(sim, cfra); + psys_update_path_cache(sim, cfra, use_render_params); BKE_ptcache_validate(cache, (int)cache_cfra); @@ -4137,7 +4139,7 @@ static int hair_needs_recalc(ParticleSystem *psys) /* main particle update call, checks that things are ok on the large scale and * then advances in to actual particle calculations depending on particle type */ -void particle_system_update(Scene *scene, Object *ob, ParticleSystem *psys) +void particle_system_update(Scene *scene, Object *ob, ParticleSystem *psys, const bool use_render_params) { ParticleSimulationData sim= {0}; ParticleSettings *part = psys->part; @@ -4146,7 +4148,7 @@ void particle_system_update(Scene *scene, Object *ob, ParticleSystem *psys) /* drawdata is outdated after ANY change */ if (psys->pdd) psys->pdd->flag &= ~PARTICLE_DRAW_DATA_UPDATED; - if (!psys_check_enabled(ob, psys)) + if (!psys_check_enabled(ob, psys, use_render_params)) return; cfra= BKE_scene_frame_get(scene); @@ -4215,7 +4217,7 @@ void particle_system_update(Scene *scene, Object *ob, ParticleSystem *psys) hcfra=100.0f*(float)i/(float)psys->part->hair_step; if ((part->flag & PART_HAIR_REGROW)==0) BKE_animsys_evaluate_animdata(scene, &part->id, part->adt, hcfra, ADT_RECALC_ANIM); - system_step(&sim, hcfra); + system_step(&sim, hcfra, use_render_params); psys->cfra = hcfra; psys->recalc = 0; save_hair(&sim, hcfra); @@ -4228,12 +4230,12 @@ void particle_system_update(Scene *scene, Object *ob, ParticleSystem *psys) psys->flag |= PSYS_HAIR_DONE; if (psys->flag & PSYS_HAIR_DONE) - hair_step(&sim, cfra); + hair_step(&sim, cfra, use_render_params); break; } case PART_FLUID: { - particles_fluid_step(&sim, (int)cfra); + particles_fluid_step(&sim, (int)cfra, use_render_params); break; } default: @@ -4280,14 +4282,14 @@ void particle_system_update(Scene *scene, Object *ob, ParticleSystem *psys) if (part->phystype == PART_PHYS_KEYED) { psys_count_keyed_targets(&sim); set_keyed_keys(&sim); - psys_update_path_cache(&sim,(int)cfra); + psys_update_path_cache(&sim, (int)cfra, use_render_params); } break; } default: { /* the main dynamic particle system step */ - system_step(&sim, cfra); + system_step(&sim, cfra, use_render_params); break; } } diff --git a/source/blender/blenkernel/intern/pbvh_bmesh.c b/source/blender/blenkernel/intern/pbvh_bmesh.c index 88dc63d6cb2..87d22d01275 100644 --- a/source/blender/blenkernel/intern/pbvh_bmesh.c +++ b/source/blender/blenkernel/intern/pbvh_bmesh.c @@ -1909,17 +1909,22 @@ static void pbvh_bmesh_verify(PBVH *bvh) { /* build list of faces & verts to lookup */ GSet *faces_all = BLI_gset_ptr_new_ex(__func__, bvh->bm->totface); - BMFace *f; BMIter iter; - BM_ITER_MESH(f, &iter, bvh->bm, BM_FACES_OF_MESH) { - BLI_gset_insert(faces_all, f); + + { + BMFace *f; + BM_ITER_MESH(f, &iter, bvh->bm, BM_FACES_OF_MESH) { + BLI_gset_insert(faces_all, f); + } } GSet *verts_all = BLI_gset_ptr_new_ex(__func__, bvh->bm->totvert); - BMVert *v; - BM_ITER_MESH(v, &iter, bvh->bm, BM_VERTS_OF_MESH) { - if (BM_ELEM_CD_GET_INT(v, bvh->cd_vert_node_offset) != DYNTOPO_NODE_NONE) { - BLI_gset_insert(verts_all, v); + { + BMVert *v; + BM_ITER_MESH(v, &iter, bvh->bm, BM_VERTS_OF_MESH) { + if (BM_ELEM_CD_GET_INT(v, bvh->cd_vert_node_offset) != DYNTOPO_NODE_NONE) { + BLI_gset_insert(verts_all, v); + } } } @@ -1936,76 +1941,83 @@ static void pbvh_bmesh_verify(PBVH *bvh) BLI_assert(totvert == BLI_gset_size(verts_all)); } - BM_ITER_MESH(f, &iter, bvh->bm, BM_FACES_OF_MESH) { - BMIter bm_iter; - BMVert *v; - PBVHNode *n = pbvh_bmesh_node_lookup(bvh, f); + { + BMFace *f; + BM_ITER_MESH(f, &iter, bvh->bm, BM_FACES_OF_MESH) { + BMIter bm_iter; + BMVert *v; + PBVHNode *n = pbvh_bmesh_node_lookup(bvh, f); - /* Check that the face's node is a leaf */ - BLI_assert(n->flag & PBVH_Leaf); + /* Check that the face's node is a leaf */ + BLI_assert(n->flag & PBVH_Leaf); - /* Check that the face's node knows it owns the face */ - BLI_assert(BLI_gset_haskey(n->bm_faces, f)); + /* Check that the face's node knows it owns the face */ + BLI_assert(BLI_gset_haskey(n->bm_faces, f)); - /* Check the face's vertices... */ - BM_ITER_ELEM (v, &bm_iter, f, BM_VERTS_OF_FACE) { - PBVHNode *nv; + /* Check the face's vertices... */ + BM_ITER_ELEM (v, &bm_iter, f, BM_VERTS_OF_FACE) { + PBVHNode *nv; - /* Check that the vertex is in the node */ - BLI_assert(BLI_gset_haskey(n->bm_unique_verts, v) ^ - BLI_gset_haskey(n->bm_other_verts, v)); + /* Check that the vertex is in the node */ + BLI_assert(BLI_gset_haskey(n->bm_unique_verts, v) ^ + BLI_gset_haskey(n->bm_other_verts, v)); - /* Check that the vertex has a node owner */ - nv = pbvh_bmesh_node_lookup(bvh, v); + /* Check that the vertex has a node owner */ + nv = pbvh_bmesh_node_lookup(bvh, v); - /* Check that the vertex's node knows it owns the vert */ - BLI_assert(BLI_gset_haskey(nv->bm_unique_verts, v)); + /* Check that the vertex's node knows it owns the vert */ + BLI_assert(BLI_gset_haskey(nv->bm_unique_verts, v)); - /* Check that the vertex isn't duplicated as an 'other' vert */ - BLI_assert(!BLI_gset_haskey(nv->bm_other_verts, v)); + /* Check that the vertex isn't duplicated as an 'other' vert */ + BLI_assert(!BLI_gset_haskey(nv->bm_other_verts, v)); + } } } /* Check verts */ - BM_ITER_MESH(v, &iter, bvh->bm, BM_VERTS_OF_MESH) { - /* vertex isn't tracked */ - if (BM_ELEM_CD_GET_INT(v, bvh->cd_vert_node_offset) == DYNTOPO_NODE_NONE) { - continue; - } + { + BMVert *v; + BM_ITER_MESH(v, &iter, bvh->bm, BM_VERTS_OF_MESH) { + /* vertex isn't tracked */ + if (BM_ELEM_CD_GET_INT(v, bvh->cd_vert_node_offset) == DYNTOPO_NODE_NONE) { + continue; + } - PBVHNode *n = pbvh_bmesh_node_lookup(bvh, v); + PBVHNode *n = pbvh_bmesh_node_lookup(bvh, v); - /* Check that the vert's node is a leaf */ - BLI_assert(n->flag & PBVH_Leaf); + /* Check that the vert's node is a leaf */ + BLI_assert(n->flag & PBVH_Leaf); - /* Check that the vert's node knows it owns the vert */ - BLI_assert(BLI_gset_haskey(n->bm_unique_verts, v)); + /* Check that the vert's node knows it owns the vert */ + BLI_assert(BLI_gset_haskey(n->bm_unique_verts, v)); - /* Check that the vertex isn't duplicated as an 'other' vert */ - BLI_assert(!BLI_gset_haskey(n->bm_other_verts, v)); + /* Check that the vertex isn't duplicated as an 'other' vert */ + BLI_assert(!BLI_gset_haskey(n->bm_other_verts, v)); - /* Check that the vert's node also contains one of the vert's - * adjacent faces */ - bool found = false; - BMIter bm_iter; - BM_ITER_ELEM (f, &bm_iter, v, BM_FACES_OF_VERT) { - if (pbvh_bmesh_node_lookup(bvh, f) == n) { - found = true; - break; + /* Check that the vert's node also contains one of the vert's + * adjacent faces */ + bool found = false; + BMIter bm_iter; + BMFace *f; + BM_ITER_ELEM (f, &bm_iter, v, BM_FACES_OF_VERT) { + if (pbvh_bmesh_node_lookup(bvh, f) == n) { + found = true; + break; + } } - } - BLI_assert(found); + BLI_assert(found); #if 1 - /* total freak stuff, check if node exists somewhere else */ - /* Slow */ - for (int i = 0; i < bvh->totnode; i++) { - PBVHNode *n_other = &bvh->nodes[i]; - if ((n != n_other) && (n_other->bm_unique_verts)) { - BLI_assert(!BLI_gset_haskey(n_other->bm_unique_verts, v)); + /* total freak stuff, check if node exists somewhere else */ + /* Slow */ + for (int i = 0; i < bvh->totnode; i++) { + PBVHNode *n_other = &bvh->nodes[i]; + if ((n != n_other) && (n_other->bm_unique_verts)) { + BLI_assert(!BLI_gset_haskey(n_other->bm_unique_verts, v)); + } } - } #endif + } } #if 0 diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c index f0ba63e35b4..e0a3e9743db 100644 --- a/source/blender/blenkernel/intern/pointcache.c +++ b/source/blender/blenkernel/intern/pointcache.c @@ -55,8 +55,6 @@ #include "PIL_time.h" -#include "WM_api.h" - #include "BKE_appdir.h" #include "BKE_anim.h" #include "BKE_cloth.h" @@ -2501,7 +2499,7 @@ static int ptcache_read_openvdb_stream(PTCacheID *pid, int cfra) #ifdef WITH_OPENVDB char filename[FILE_MAX * 2]; - /* save blend file before using disk pointcache */ + /* save blend file before using disk pointcache */ if (!G.relbase_valid && (pid->cache->flag & PTCACHE_EXTERNAL) == 0) return 0; diff --git a/source/blender/blenkernel/intern/sca.c b/source/blender/blenkernel/intern/sca.c index e90a39e8c0e..a468420f87d 100644 --- a/source/blender/blenkernel/intern/sca.c +++ b/source/blender/blenkernel/intern/sca.c @@ -653,77 +653,6 @@ void set_sca_new_poins(void) } } -void sca_remove_ob_poin(Object *obt, Object *ob) -{ - bSensor *sens; - bMessageSensor *ms; - bActuator *act; - bCameraActuator *ca; - bObjectActuator *oa; - bSceneActuator *sa; - bEditObjectActuator *eoa; - bPropertyActuator *pa; - bMessageActuator *ma; - bParentActuator *para; - bArmatureActuator *aa; - bSteeringActuator *sta; - - - sens= obt->sensors.first; - while (sens) { - switch (sens->type) { - case SENS_MESSAGE: - ms= sens->data; - if (ms->fromObject==ob) ms->fromObject= NULL; - } - sens= sens->next; - } - - act= obt->actuators.first; - while (act) { - switch (act->type) { - case ACT_CAMERA: - ca= act->data; - if (ca->ob==ob) ca->ob= NULL; - break; - case ACT_OBJECT: - oa= act->data; - if (oa->reference==ob) oa->reference= NULL; - break; - case ACT_PROPERTY: - pa= act->data; - if (pa->ob==ob) pa->ob= NULL; - break; - case ACT_SCENE: - sa= act->data; - if (sa->camera==ob) sa->camera= NULL; - break; - case ACT_EDIT_OBJECT: - eoa= act->data; - if (eoa->ob==ob) eoa->ob= NULL; - break; - case ACT_MESSAGE: - ma= act->data; - if (ma->toObject==ob) ma->toObject= NULL; - break; - case ACT_PARENT: - para = act->data; - if (para->ob==ob) para->ob = NULL; - break; - case ACT_ARMATURE: - aa = act->data; - if (aa->target == ob) aa->target = NULL; - if (aa->subtarget == ob) aa->subtarget = NULL; - break; - case ACT_STEERING: - sta = act->data; - if (sta->navmesh == ob) sta->navmesh = NULL; - if (sta->target == ob) sta->target = NULL; - } - act= act->next; - } -} - /* ******************** INTERFACE ******************* */ void sca_move_sensor(bSensor *sens_to_move, Object *ob, int move_up) { diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c index d307ba1811b..0e8efca04d0 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -357,41 +357,34 @@ void BKE_scene_groups_relink(Scene *sce) BKE_rigidbody_world_groups_relink(sce->rigidbody_world); } -/* do not free scene itself */ +/** Free (or release) any data used by this scene (does not free the scene itself). */ void BKE_scene_free(Scene *sce) { - Base *base; SceneRenderLayer *srl; + BKE_animdata_free((ID *)sce, false); + /* check all sequences */ BKE_sequencer_clear_scene_in_allseqs(G.main, sce); - base = sce->base.first; - while (base) { - id_us_min(&base->object->id); - base = base->next; - } - /* do not free objects! */ - - if (sce->gpd) { -#if 0 /* removed since this can be invalid memory when freeing everything */ - /* since the grease pencil data is freed before the scene. - * since grease pencil data is not (yet?), shared between objects - * its probably safe not to do this, some save and reload will free this. */ - id_us_min(&sce->gpd->id); -#endif - sce->gpd = NULL; - } - + sce->basact = NULL; BLI_freelistN(&sce->base); BKE_sequencer_editing_free(sce); - BKE_animdata_free((ID *)sce); BKE_keyingsets_free(&sce->keyingsets); - - if (sce->rigidbody_world) + + /* is no lib link block, but scene extension */ + if (sce->nodetree) { + ntreeFreeTree(sce->nodetree); + MEM_freeN(sce->nodetree); + sce->nodetree = NULL; + } + + if (sce->rigidbody_world) { BKE_rigidbody_free_world(sce->rigidbody_world); - + sce->rigidbody_world = NULL; + } + if (sce->r.avicodecdata) { free_avicodecdata(sce->r.avicodecdata); MEM_freeN(sce->r.avicodecdata); @@ -444,15 +437,8 @@ void BKE_scene_free(Scene *sce) if (sce->depsgraph) DEG_graph_free(sce->depsgraph); - if (sce->nodetree) { - ntreeFreeTree(sce->nodetree); - MEM_freeN(sce->nodetree); - } - - if (sce->stats) - MEM_freeN(sce->stats); - if (sce->fps_info) - MEM_freeN(sce->fps_info); + MEM_SAFE_FREE(sce->stats); + MEM_SAFE_FREE(sce->fps_info); BKE_sound_destroy_scene(sce); @@ -904,40 +890,6 @@ Scene *BKE_scene_set_name(Main *bmain, const char *name) return NULL; } -void BKE_scene_unlink(Main *bmain, Scene *sce, Scene *newsce) -{ - Scene *sce1; - bScreen *screen; - - /* check all sets */ - for (sce1 = bmain->scene.first; sce1; sce1 = sce1->id.next) - if (sce1->set == sce) - sce1->set = NULL; - - for (sce1 = bmain->scene.first; sce1; sce1 = sce1->id.next) { - bNode *node; - - if (sce1 == sce || !sce1->nodetree) - continue; - - for (node = sce1->nodetree->nodes.first; node; node = node->next) { - if (node->id == &sce->id) - node->id = NULL; - } - } - - /* all screens */ - for (screen = bmain->screen.first; screen; screen = screen->id.next) { - if (screen->scene == sce) { - screen->scene = newsce; - } - - /* editors are handled by WM_main_remove_editor_id_reference */ - } - - BKE_libblock_free(bmain, sce); -} - /* Used by metaballs, return *all* objects (including duplis) existing in the scene (including scene's sets) */ int BKE_scene_base_iter_next(EvaluationContext *eval_ctx, SceneBaseIter *iter, Scene **scene, int val, Base **base, Object **ob) @@ -1193,6 +1145,8 @@ void BKE_scene_base_unlink(Scene *sce, Base *base) BKE_rigidbody_remove_object(sce, base->object); BLI_remlink(&sce->base, base); + if (sce->basact == base) + sce->basact = NULL; } void BKE_scene_base_deselect_all(Scene *sce) @@ -2193,6 +2147,13 @@ bool BKE_scene_use_shading_nodes_custom(Scene *scene) return (type && type->flag & RE_USE_SHADING_NODES_CUSTOM); } +bool BKE_scene_use_world_space_shading(Scene *scene) +{ + const RenderEngineType *type = RE_engines_find(scene->r.engine); + return ((scene->r.mode & R_USE_WS_SHADING) || + (type && (type->flag & RE_USE_SHADING_NODES))); +} + bool BKE_scene_use_spherical_stereo(Scene *scene) { RenderEngineType *type = RE_engines_find(scene->r.engine); diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c index 139c6670f74..857bd5447c8 100644 --- a/source/blender/blenkernel/intern/screen.c +++ b/source/blender/blenkernel/intern/screen.c @@ -273,17 +273,18 @@ void BKE_spacedata_draw_locks(int set) } } -static void (*spacedata_id_unref_cb)(struct SpaceLink *sl, const struct ID *id) = NULL; +static void (*spacedata_id_remap_cb)(struct ScrArea *sa, struct SpaceLink *sl, ID *old_id, ID *new_id) = NULL; -void BKE_spacedata_callback_id_unref_set(void (*func)(struct SpaceLink *sl, const struct ID *)) +void BKE_spacedata_callback_id_remap_set(void (*func)(ScrArea *sa, SpaceLink *sl, ID *, ID *)) { - spacedata_id_unref_cb = func; + spacedata_id_remap_cb = func; } -void BKE_spacedata_id_unref(struct SpaceLink *sl, const struct ID *id) +/* UNUSED!!! */ +void BKE_spacedata_id_unref(struct ScrArea *sa, struct SpaceLink *sl, struct ID *id) { - if (spacedata_id_unref_cb) { - spacedata_id_unref_cb(sl, id); + if (spacedata_id_remap_cb) { + spacedata_id_remap_cb(sa, sl, id, NULL); } } @@ -358,11 +359,13 @@ void BKE_screen_area_free(ScrArea *sa) BLI_freelistN(&sa->actionzones); } -/* don't free screen itself */ +/** Free (or release) any data used by this screen (does not free the screen itself). */ void BKE_screen_free(bScreen *sc) { ScrArea *sa, *san; ARegion *ar; + + /* No animdata here. */ for (ar = sc->regionbase.first; ar; ar = ar->next) BKE_area_region_free(NULL, ar); diff --git a/source/blender/blenkernel/intern/sequencer.c b/source/blender/blenkernel/intern/sequencer.c index c82f3a3af23..5ef502e0182 100644 --- a/source/blender/blenkernel/intern/sequencer.c +++ b/source/blender/blenkernel/intern/sequencer.c @@ -3092,7 +3092,7 @@ static ImBuf *seq_render_mask(const SeqRenderData *context, Mask *mask, float nr BKE_maskrasterize_handle_init(mr_handle, mask_temp, context->rectx, context->recty, true, true, true); - BKE_mask_free_nolib(mask_temp); + BKE_mask_free(mask_temp); MEM_freeN(mask_temp); BKE_maskrasterize_buffer(mr_handle, context->rectx, context->recty, maskbuf); @@ -5154,7 +5154,7 @@ Sequence *BKE_sequencer_add_sound_strip(bContext *C, ListBase *seqbasep, SeqLoad info = AUD_getInfo(sound->playback_handle); if (info.specs.channels == AUD_CHANNELS_INVALID) { - BKE_sound_delete(bmain, sound); + BKE_libblock_free(bmain, sound); #if 0 if (op) BKE_report(op->reports, RPT_ERROR, "Unsupported audio format"); diff --git a/source/blender/blenkernel/intern/shrinkwrap.c b/source/blender/blenkernel/intern/shrinkwrap.c index 518d8d68919..7094d5a3547 100644 --- a/source/blender/blenkernel/intern/shrinkwrap.c +++ b/source/blender/blenkernel/intern/shrinkwrap.c @@ -405,21 +405,28 @@ static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc, bool for /* use editmesh to avoid array allocation */ BMEditMesh *emtarget = NULL, *emaux = NULL; - BVHTreeFromEditMesh emtreedata_stack, emauxdata_stack; - BVHTreeFromMesh dmtreedata_stack, dmauxdata_stack; + union { + BVHTreeFromEditMesh emtreedata; + BVHTreeFromMesh dmtreedata; + } treedata_stack, auxdata_stack; + BVHTree *targ_tree; void *targ_callback; if (calc->smd->target && calc->target->type == DM_TYPE_EDITBMESH) { emtarget = BKE_editmesh_from_object(calc->smd->target); - if ((targ_tree = bvhtree_from_editmesh_looptri(&emtreedata_stack, emtarget, 0.0, 4, 6))) { - targ_callback = emtreedata_stack.raycast_callback; - treeData = &emtreedata_stack; + if ((targ_tree = bvhtree_from_editmesh_looptri( + &treedata_stack.emtreedata, emtarget, 0.0, 4, 6, &calc->target->bvhCache))) + { + targ_callback = treedata_stack.emtreedata.raycast_callback; + treeData = &treedata_stack.emtreedata; } } else { - if ((targ_tree = bvhtree_from_mesh_looptri(&dmtreedata_stack, calc->target, 0.0, 4, 6))) { - targ_callback = dmtreedata_stack.raycast_callback; - treeData = &dmtreedata_stack; + if ((targ_tree = bvhtree_from_mesh_looptri( + &treedata_stack.dmtreedata, calc->target, 0.0, 4, 6))) + { + targ_callback = treedata_stack.dmtreedata.raycast_callback; + treeData = &treedata_stack.dmtreedata; } } if (targ_tree) { @@ -429,15 +436,17 @@ static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc, bool for /* use editmesh to avoid array allocation */ if (calc->smd->auxTarget && auxMesh->type == DM_TYPE_EDITBMESH) { emaux = BKE_editmesh_from_object(calc->smd->auxTarget); - if ((aux_tree = bvhtree_from_editmesh_looptri(&emauxdata_stack, emaux, 0.0, 4, 6)) != NULL) { - aux_callback = emauxdata_stack.raycast_callback; - auxData = &emauxdata_stack; + if ((aux_tree = bvhtree_from_editmesh_looptri( + &auxdata_stack.emtreedata, emaux, 0.0, 4, 6, &auxMesh->bvhCache))) + { + aux_callback = auxdata_stack.emtreedata.raycast_callback; + auxData = &auxdata_stack.emtreedata; } } else { - if ((aux_tree = bvhtree_from_mesh_looptri(&dmauxdata_stack, auxMesh, 0.0, 4, 6)) != NULL) { - aux_callback = dmauxdata_stack.raycast_callback; - auxData = &dmauxdata_stack; + if ((aux_tree = bvhtree_from_mesh_looptri(&auxdata_stack.dmtreedata, auxMesh, 0.0, 4, 6)) != NULL) { + aux_callback = auxdata_stack.dmtreedata.raycast_callback; + auxData = &auxdata_stack.dmtreedata; } } } @@ -455,12 +464,21 @@ static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc, bool for /* free data structures */ if (treeData) { - if (emtarget) free_bvhtree_from_editmesh(treeData); - else free_bvhtree_from_mesh(treeData); + if (emtarget) { + free_bvhtree_from_editmesh(treeData); + } + else { + free_bvhtree_from_mesh(treeData); + } } + if (auxData) { - if (emaux) free_bvhtree_from_editmesh(auxData); - else free_bvhtree_from_mesh(auxData); + if (emaux) { + free_bvhtree_from_editmesh(auxData); + } + else { + free_bvhtree_from_mesh(auxData); + } } } diff --git a/source/blender/blenkernel/intern/softbody.c b/source/blender/blenkernel/intern/softbody.c index 25a4fdc0cc7..8fec817d694 100644 --- a/source/blender/blenkernel/intern/softbody.c +++ b/source/blender/blenkernel/intern/softbody.c @@ -2243,7 +2243,7 @@ static void softbody_calc_forces(Scene *scene, Object *ob, float forcetime, floa .. keeping G.debug_value==17 0x11 option for old files 'needing' the bug*/ /* rule we never alter free variables :bp->vec bp->pos in here ! - * this will ruin adaptive stepsize AKA heun! (BM) + * this will ruin adaptive stepsize AKA heun! (BM) */ SoftBody *sb= ob->soft; /* is supposed to be there */ BodyPoint *bp; diff --git a/source/blender/blenkernel/intern/sound.c b/source/blender/blenkernel/intern/sound.c index b016f8a49ed..414be73e234 100644 --- a/source/blender/blenkernel/intern/sound.c +++ b/source/blender/blenkernel/intern/sound.c @@ -123,8 +123,11 @@ bSound *BKE_sound_new_file_exists(struct Main *bmain, const char *filepath) return BKE_sound_new_file_exists_ex(bmain, filepath, NULL); } +/** Free (or release) any data used by this sound (does not free the sound itself). */ void BKE_sound_free(bSound *sound) { + /* No animdata here. */ + if (sound->packedfile) { freePackedFile(sound->packedfile); sound->packedfile = NULL; @@ -148,8 +151,7 @@ void BKE_sound_free(bSound *sound) BLI_spin_end(sound->spinlock); MEM_freeN(sound->spinlock); sound->spinlock = NULL; - } - + } #endif /* WITH_AUDASPACE */ } @@ -315,15 +317,6 @@ bSound *BKE_sound_new_limiter(struct Main *bmain, bSound *source, float start, f } #endif -void BKE_sound_delete(struct Main *bmain, bSound *sound) -{ - if (sound) { - BKE_sound_free(sound); - - BKE_libblock_free(bmain, sound); - } -} - void BKE_sound_cache(bSound *sound) { sound->flags |= SOUND_FLAGS_CACHING; diff --git a/source/blender/blenkernel/intern/speaker.c b/source/blender/blenkernel/intern/speaker.c index c452065fbad..e5075a2d382 100644 --- a/source/blender/blenkernel/intern/speaker.c +++ b/source/blender/blenkernel/intern/speaker.c @@ -141,8 +141,5 @@ void BKE_speaker_make_local(Speaker *spk) void BKE_speaker_free(Speaker *spk) { - if (spk->sound) - id_us_min(&spk->sound->id); - - BKE_animdata_free((ID *)spk); + BKE_animdata_free((ID *)spk, false); } diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c index 88bc3fb9854..b0d19320230 100644 --- a/source/blender/blenkernel/intern/subsurf_ccg.c +++ b/source/blender/blenkernel/intern/subsurf_ccg.c @@ -2619,7 +2619,6 @@ static void ccgDM_drawFacesSolid(DerivedMesh *dm, float (*partial_redraw_planes) if (BKE_pbvh_has_faces(ccgdm->pbvh)) { BKE_pbvh_draw(ccgdm->pbvh, partial_redraw_planes, NULL, setMaterial, false, fast); - glShadeModel(GL_FLAT); } return; @@ -3164,7 +3163,7 @@ static void ccgDM_drawMappedFacesGLSL(DerivedMesh *dm, MEM_freeN(matconv); } - glShadeModel(GL_FLAT); + glShadeModel(GL_SMOOTH); } static void ccgDM_drawFacesGLSL(DerivedMesh *dm, DMSetMaterial setMaterial) diff --git a/source/blender/blenkernel/intern/text.c b/source/blender/blenkernel/intern/text.c index 6def9e3e503..fdc2edba57f 100644 --- a/source/blender/blenkernel/intern/text.c +++ b/source/blender/blenkernel/intern/text.c @@ -171,14 +171,17 @@ void BKE_text_free_lines(Text *text) text->curl = text->sell = NULL; } +/** Free (or release) any data used by this text (does not free the text itself). */ void BKE_text_free(Text *text) { + /* No animdata here. */ + BKE_text_free_lines(text); - if (text->name) MEM_freeN(text->name); - MEM_freeN(text->undo_buf); + MEM_SAFE_FREE(text->name); + MEM_SAFE_FREE(text->undo_buf); #ifdef WITH_PYTHON - if (text->compiled) BPY_text_free_code(text); + BPY_text_free_code(text); #endif } @@ -495,191 +498,6 @@ Text *BKE_text_copy(Main *bmain, Text *ta) return tan; } -void BKE_text_unlink(Main *bmain, Text *text) -{ - bScreen *scr; - ScrArea *area; - SpaceLink *sl; - Object *ob; - bController *cont; - bActuator *act; - bConstraint *con; - bNodeTree *ntree; - bNode *node; - Material *mat; - Lamp *la; - Tex *te; - World *wo; - FreestyleLineStyle *linestyle; - Scene *sce; - SceneRenderLayer *srl; - FreestyleModuleConfig *module; - bool update; - - for (ob = bmain->object.first; ob; ob = ob->id.next) { - /* game controllers */ - for (cont = ob->controllers.first; cont; cont = cont->next) { - if (cont->type == CONT_PYTHON) { - bPythonCont *pc; - - pc = cont->data; - if (pc->text == text) pc->text = NULL; - } - } - /* game actuators */ - for (act = ob->actuators.first; act; act = act->next) { - if (act->type == ACT_2DFILTER) { - bTwoDFilterActuator *tfa; - - tfa = act->data; - if (tfa->text == text) tfa->text = NULL; - } - } - - /* pyconstraints */ - update = 0; - - if (ob->type == OB_ARMATURE && ob->pose) { - bPoseChannel *pchan; - for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { - for (con = pchan->constraints.first; con; con = con->next) { - if (con->type == CONSTRAINT_TYPE_PYTHON) { - bPythonConstraint *data = con->data; - if (data->text == text) data->text = NULL; - update = 1; - - } - } - } - } - - for (con = ob->constraints.first; con; con = con->next) { - if (con->type == CONSTRAINT_TYPE_PYTHON) { - bPythonConstraint *data = con->data; - if (data->text == text) data->text = NULL; - update = 1; - } - } - - if (update) - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); - } - - /* nodes */ - for (la = bmain->lamp.first; la; la = la->id.next) { - ntree = la->nodetree; - if (!ntree) - continue; - for (node = ntree->nodes.first; node; node = node->next) { - if (node->type == NODE_FRAME) { - if ((Text *)node->id == text) { - node->id = NULL; - } - } - } - } - - for (linestyle = bmain->linestyle.first; linestyle; linestyle = linestyle->id.next) { - ntree = linestyle->nodetree; - if (!ntree) - continue; - for (node = ntree->nodes.first; node; node = node->next) { - if (node->type == NODE_FRAME) { - if ((Text *)node->id == text) { - node->id = NULL; - } - } - } - } - - for (mat = bmain->mat.first; mat; mat = mat->id.next) { - ntree = mat->nodetree; - if (!ntree) - continue; - for (node = ntree->nodes.first; node; node = node->next) { - if (ELEM(node->type, SH_NODE_SCRIPT, NODE_FRAME)) { - if ((Text *)node->id == text) { - node->id = NULL; - } - } - } - } - - for (te = bmain->tex.first; te; te = te->id.next) { - ntree = te->nodetree; - if (!ntree) - continue; - for (node = ntree->nodes.first; node; node = node->next) { - if (node->type == NODE_FRAME) { - if ((Text *)node->id == text) { - node->id = NULL; - } - } - } - } - - for (wo = bmain->world.first; wo; wo = wo->id.next) { - ntree = wo->nodetree; - if (!ntree) - continue; - for (node = ntree->nodes.first; node; node = node->next) { - if (node->type == NODE_FRAME) { - if ((Text *)node->id == text) { - node->id = NULL; - } - } - } - } - - for (sce = bmain->scene.first; sce; sce = sce->id.next) { - ntree = sce->nodetree; - if (!ntree) - continue; - for (node = ntree->nodes.first; node; node = node->next) { - if (node->type == NODE_FRAME) { - Text *ntext = (Text *)node->id; - if (ntext == text) node->id = NULL; - } - } - - /* Freestyle (while looping over the scene) */ - for (srl = sce->r.layers.first; srl; srl = srl->next) { - for (module = srl->freestyleConfig.modules.first; module; module = module->next) { - if (module->script == text) - module->script = NULL; - } - } - } - - for (ntree = bmain->nodetree.first; ntree; ntree = ntree->id.next) { - for (node = ntree->nodes.first; node; node = node->next) { - if (ELEM(node->type, SH_NODE_SCRIPT, NODE_FRAME)) { - if ((Text *)node->id == text) { - node->id = NULL; - } - } - } - } - - /* text space */ - for (scr = bmain->screen.first; scr; scr = scr->id.next) { - for (area = scr->areabase.first; area; area = area->next) { - for (sl = area->spacedata.first; sl; sl = sl->next) { - if (sl->spacetype == SPACE_TEXT) { - SpaceText *st = (SpaceText *) sl; - - if (st->text == text) { - st->text = NULL; - st->top = 0; - } - } - } - } - } - - text->id.us = 0; -} - void BKE_text_clear(Text *text) /* called directly from rna */ { int oldstate; diff --git a/source/blender/blenkernel/intern/texture.c b/source/blender/blenkernel/intern/texture.c index d353042b711..9326ece7a4b 100644 --- a/source/blender/blenkernel/intern/texture.c +++ b/source/blender/blenkernel/intern/texture.c @@ -557,23 +557,38 @@ int colorband_element_remove(struct ColorBand *coba, int index) /* ******************* TEX ************************ */ +/** Free (or release) any data used by this texture (does not free the texure itself). */ void BKE_texture_free(Tex *tex) { - if (tex->coba) MEM_freeN(tex->coba); - if (tex->env) BKE_texture_envmap_free(tex->env); - if (tex->pd) BKE_texture_pointdensity_free(tex->pd); - if (tex->vd) BKE_texture_voxeldata_free(tex->vd); - if (tex->ot) BKE_texture_ocean_free(tex->ot); - BKE_animdata_free((struct ID *)tex); - - BKE_previewimg_free(&tex->preview); - BKE_icon_id_delete((struct ID *)tex); - tex->id.icon_id = 0; - + BKE_animdata_free((ID *)tex, false); + + /* is no lib link block, but texture extension */ if (tex->nodetree) { ntreeFreeTree(tex->nodetree); MEM_freeN(tex->nodetree); + tex->nodetree = NULL; } + + MEM_SAFE_FREE(tex->coba); + if (tex->env) { + BKE_texture_envmap_free(tex->env); + tex->env = NULL; + } + if (tex->pd) { + BKE_texture_pointdensity_free(tex->pd); + tex->pd = NULL; + } + if (tex->vd) { + BKE_texture_voxeldata_free(tex->vd); + tex->vd = NULL; + } + if (tex->ot) { + BKE_texture_ocean_free(tex->ot); + tex->ot = NULL; + } + + BKE_icon_id_delete((ID *)tex); + BKE_previewimg_free(&tex->preview); } /* ------------------------------------------------------------------------- */ diff --git a/source/blender/blenkernel/intern/tracking_util.c b/source/blender/blenkernel/intern/tracking_util.c index 3c2444b0ef1..a40e4f72636 100644 --- a/source/blender/blenkernel/intern/tracking_util.c +++ b/source/blender/blenkernel/intern/tracking_util.c @@ -529,7 +529,7 @@ typedef struct AccessCacheKey { static unsigned int accesscache_hashhash(const void *key_v) { const AccessCacheKey *key = (const AccessCacheKey *) key_v; - /* TODP(sergey): Need better hasing here for faster frame access. */ + /* TODP(sergey): Need better hashing here for faster frame access. */ return key->clip_index << 16 | key->frame; } diff --git a/source/blender/blenkernel/intern/world.c b/source/blender/blenkernel/intern/world.c index 66fe0491373..1217992741a 100644 --- a/source/blender/blenkernel/intern/world.c +++ b/source/blender/blenkernel/intern/world.c @@ -53,41 +53,30 @@ #include "GPU_material.h" #include "GPU_probe.h" -void BKE_world_free_ex(World *wrld, bool do_id_user) +/** Free (or release) any data used by this world (does not free the world itself). */ +void BKE_world_free(World *wrld) { - MTex *mtex; int a; - + + BKE_animdata_free((ID *)wrld, false); + for (a = 0; a < MAX_MTEX; a++) { - mtex = wrld->mtex[a]; - if (do_id_user && mtex && mtex->tex) - id_us_min(&mtex->tex->id); - if (mtex) - MEM_freeN(mtex); + MEM_SAFE_FREE(wrld->mtex[a]); } - BKE_previewimg_free(&wrld->preview); - - BKE_animdata_free((ID *)wrld); /* is no lib link block, but world extension */ if (wrld->nodetree) { - ntreeFreeTree_ex(wrld->nodetree, do_id_user); + ntreeFreeTree(wrld->nodetree); MEM_freeN(wrld->nodetree); + wrld->nodetree = NULL; } - if (wrld->gpumaterial.first) - GPU_material_free(&wrld->gpumaterial); + GPU_material_free(&wrld->gpumaterial); - if (wrld->gpuprobe.first) - GPU_probe_free(&wrld->gpuprobe); + GPU_probe_free(&wrld->gpuprobe); BKE_icon_id_delete((struct ID *)wrld); - wrld->id.icon_id = 0; -} - -void BKE_world_free(World *wrld) -{ - BKE_world_free_ex(wrld, true); + BKE_previewimg_free(&wrld->preview); } void BKE_world_init(World *wrld) diff --git a/source/blender/blenlib/BLI_array_store_utils.h b/source/blender/blenlib/BLI_array_store_utils.h new file mode 100644 index 00000000000..6b2a28846f4 --- /dev/null +++ b/source/blender/blenlib/BLI_array_store_utils.h @@ -0,0 +1,50 @@ +/* + * ***** 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. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef __BLI_ARRAY_STORE_UTILS_H__ +#define __BLI_ARRAY_STORE_UTILS_H__ + +/** \file BLI_array_store_utils.h + * \ingroup bli + */ + +struct BArrayStore; + +struct BArrayStore_AtSize { + struct BArrayStore **stride_table; + int stride_table_len; +}; + +BArrayStore *BLI_array_store_at_size_ensure( + struct BArrayStore_AtSize *bs_stride, + const int stride, const int chunk_size); + +BArrayStore *BLI_array_store_at_size_get( + struct BArrayStore_AtSize *bs_stride, + const int stride); + +void BLI_array_store_at_size_clear( + struct BArrayStore_AtSize *bs_stride); + +void BLI_array_store_at_size_calc_memory_usage( + struct BArrayStore_AtSize *bs_stride, + size_t *r_size_expanded, size_t *r_size_compacted); + +#endif /* __BLI_ARRAY_STORE_UTILS_H__ */ diff --git a/source/blender/blenlib/BLI_array_utils.h b/source/blender/blenlib/BLI_array_utils.h index 5ef8421c003..a46c87cec40 100644 --- a/source/blender/blenlib/BLI_array_utils.h +++ b/source/blender/blenlib/BLI_array_utils.h @@ -48,6 +48,10 @@ int _bli_array_findindex(const void *arr, unsigned int arr_len, size_t arr_strid #define BLI_array_findindex(arr, arr_len, p) \ _bli_array_findindex(arr, arr_len, sizeof(*(arr)), p) +int _bli_array_rfindindex(const void *arr, unsigned int arr_len, size_t arr_stride, const void *p); +#define BLI_array_rfindindex(arr, arr_len, p) \ + _bli_array_rfindindex(arr, arr_len, sizeof(*(arr)), p) + void _bli_array_binary_and( void *arr, const void *arr_a, const void *arr_b, unsigned int arr_len, size_t arr_stride); diff --git a/source/blender/blenlib/BLI_kdopbvh.h b/source/blender/blenlib/BLI_kdopbvh.h index fb8c2520e67..91d39801645 100644 --- a/source/blender/blenlib/BLI_kdopbvh.h +++ b/source/blender/blenlib/BLI_kdopbvh.h @@ -96,7 +96,8 @@ typedef void (*BVHTree_NearestPointCallback)(void *userdata, int index, const fl typedef void (*BVHTree_RayCastCallback)(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit); /* callback must update nearest in case it finds a nearest result */ -typedef void (*BVHTree_NearestToRayCallback)(void *userdata, int index, const BVHTreeRay *ray, BVHTreeNearest *nearest); +typedef void (*BVHTree_NearestToRayCallback)(void *userdata, const float ray_co[3], const float ray_dir[3], + const float scale[3], int index, BVHTreeNearest *nearest); /* callback to check if 2 nodes overlap (use thread if intersection results need to be stored) */ typedef bool (*BVHTree_OverlapCallback)(void *userdata, int index_a, int index_b, int thread); @@ -142,8 +143,16 @@ int BLI_bvhtree_find_nearest( BVHTree *tree, const float co[3], BVHTreeNearest *nearest, BVHTree_NearestPointCallback callback, void *userdata); +int BLI_bvhtree_find_nearest_to_ray_angle( + BVHTree *tree, const float co[3], const float dir[3], + const bool ray_is_normalized, const float scale[3], + BVHTreeNearest *nearest, + BVHTree_NearestToRayCallback callback, void *userdata); + int BLI_bvhtree_find_nearest_to_ray( - BVHTree *tree, const float co[3], const float dir[3], BVHTreeNearest *nearest, + BVHTree *tree, const float co[3], const float dir[3], + const bool ray_is_normalized, const float scale[3], + BVHTreeNearest *nearest, BVHTree_NearestToRayCallback callback, void *userdata); int BLI_bvhtree_ray_cast_ex( diff --git a/source/blender/blenlib/BLI_math_geom.h b/source/blender/blenlib/BLI_math_geom.h index 54b824c91ac..84a25f533bf 100644 --- a/source/blender/blenlib/BLI_math_geom.h +++ b/source/blender/blenlib/BLI_math_geom.h @@ -115,6 +115,13 @@ float dist_signed_squared_to_corner_v3v3v3( const float p[3], const float v1[3], const float v2[3], const float v3[3], const float axis_ref[3]); +float dist_squared_to_ray_v3( + const float ray_origin[3], const float ray_direction[3], + const float co[3], float *r_depth); +float dist_squared_ray_to_seg_v3( + const float ray_origin[3], const float ray_direction[3], + const float v0[3], const float v1[3], + float r_point[3], float *r_depth); float closest_to_line_v2(float r_close[2], const float p[2], const float l1[2], const float l2[2]); float closest_to_line_v3(float r_close[3], const float p[3], const float l1[3], const float l2[3]); void closest_to_line_segment_v2(float r_close[2], const float p[2], const float l1[2], const float l2[2]); diff --git a/source/blender/blenlib/BLI_math_matrix.h b/source/blender/blenlib/BLI_math_matrix.h index 6d6fbe4e7af..8124e07dd47 100644 --- a/source/blender/blenlib/BLI_math_matrix.h +++ b/source/blender/blenlib/BLI_math_matrix.h @@ -138,10 +138,14 @@ bool invert_m3_m3(float R[3][3], float A[3][3]); bool invert_m4(float R[4][4]); bool invert_m4_m4(float R[4][4], float A[4][4]); -/* double ariphmetics */ +/* double arithmetic (mixed float/double) */ void mul_m4_v4d(float M[4][4], double r[4]); void mul_v4d_m4v4d(double r[4], float M[4][4], double v[4]); +/* double matrix functions (no mixing types) */ +void mul_v3_m3v3_db(double r[3], double M[3][3], const double a[3]); +void mul_m3_v3_db(double M[3][3], double r[3]); + /****************************** Linear Algebra *******************************/ @@ -269,7 +273,7 @@ void BLI_space_transform_invert_normal(const struct SpaceTransform *data, float /*********************************** Other ***********************************/ void print_m3(const char *str, float M[3][3]); -void print_m4(const char *str, float M[3][4]); +void print_m4(const char *str, float M[4][4]); #define print_m3_id(M) print_m3(STRINGIFY(M), M) #define print_m4_id(M) print_m4(STRINGIFY(M), M) diff --git a/source/blender/blenlib/BLI_math_vector.h b/source/blender/blenlib/BLI_math_vector.h index 5f76b79b298..8a36b047bad 100644 --- a/source/blender/blenlib/BLI_math_vector.h +++ b/source/blender/blenlib/BLI_math_vector.h @@ -148,6 +148,7 @@ MINLINE void negate_v4(float r[4]); MINLINE void negate_v4_v4(float r[4], const float a[3]); MINLINE void negate_v3_short(short r[3]); +MINLINE void negate_v3_db(double r[3]); MINLINE void invert_v2(float r[2]); @@ -231,6 +232,7 @@ void flip_v4_v4v4(float v[4], const float v1[4], const float v2[4]); void flip_v3_v3v3(float v[3], const float v1[3], const float v2[3]); void flip_v2_v2v2(float v[2], const float v1[2], const float v2[2]); + /********************************* Comparison ********************************/ MINLINE bool is_zero_v2(const float a[3]) ATTR_WARN_UNUSED_RESULT; @@ -282,18 +284,18 @@ void angle_poly_v3(float *angles, const float *verts[3], int len); /********************************* Geometry **********************************/ -void project_v2_v2v2(float c[2], const float v1[2], const float v2[2]); -void project_v3_v3v3(float r[3], const float p[3], const float n[3]); -void project_plane_v3_v3v3(float c[3], const float v[3], const float v_plane[3]); -void project_plane_v2_v2v2(float c[2], const float v[2], const float v_plane[2]); -void project_v3_plane(float v[3], const float n[3], const float p[3]); -void reflect_v3_v3v3(float r[3], const float v[3], const float n[3]); +void project_v2_v2v2(float out[2], const float p[2], const float v_proj[2]); +void project_v3_v3v3(float out[3], const float p[3], const float v_proj[3]); +void project_plane_v3_v3v3(float out[3], const float p[3], const float v_plane[3]); +void project_plane_v2_v2v2(float out[2], const float p[2], const float v_plane[2]); +void project_v3_plane(float out[3], const float plane_no[3], const float plane_co[3]); +void reflect_v3_v3v3(float out[3], const float vec[3], const float normal[3]); void ortho_basis_v3v3_v3(float r_n1[3], float r_n2[3], const float n[3]); -void ortho_v3_v3(float p[3], const float v[3]); -void ortho_v2_v2(float p[2], const float v[2]); +void ortho_v3_v3(float out[3], const float v[3]); +void ortho_v2_v2(float out[2], const float v[2]); void bisect_v3_v3v3v3(float r[3], const float a[3], const float b[3], const float c[3]); void rotate_v3_v3v3fl(float v[3], const float p[3], const float axis[3], const float angle); -void rotate_normalized_v3_v3v3fl(float v[3], const float p[3], const float axis[3], const float angle); +void rotate_normalized_v3_v3v3fl(float out[3], const float p[3], const float axis[3], const float angle); /*********************************** Other ***********************************/ diff --git a/source/blender/blenlib/BLI_quadric.h b/source/blender/blenlib/BLI_quadric.h index eaf9c7a0738..d46a221d108 100644 --- a/source/blender/blenlib/BLI_quadric.h +++ b/source/blender/blenlib/BLI_quadric.h @@ -39,8 +39,7 @@ typedef struct Quadric { /* conversion */ void BLI_quadric_from_plane(Quadric *q, const double v[4]); -void BLI_quadric_to_tensor_m3(const Quadric *q, float m[3][3]); -void BLI_quadric_to_vector_v3(const Quadric *q, float v[3]); +void BLI_quadric_to_vector_v3(const Quadric *q, double v[3]); void BLI_quadric_clear(Quadric *q); @@ -50,7 +49,7 @@ void BLI_quadric_add_qu_ququ(Quadric *r, const Quadric *a, const Quadric *b); void BLI_quadric_mul(Quadric *a, const double scalar); /* solve */ -double BLI_quadric_evaluate(const Quadric *q, const float v_fl[3]); -bool BLI_quadric_optimize(const Quadric *q, float v[3], const float epsilon); +double BLI_quadric_evaluate(const Quadric *q, const double v[3]); +bool BLI_quadric_optimize(const Quadric *q, double v[3], const double epsilon); #endif /* __BLI_QUADRIC_H__ */ diff --git a/source/blender/blenlib/BLI_rand.h b/source/blender/blenlib/BLI_rand.h index 7b84dddcb68..f36d2faa1b8 100644 --- a/source/blender/blenlib/BLI_rand.h +++ b/source/blender/blenlib/BLI_rand.h @@ -49,6 +49,7 @@ void BLI_rng_free(struct RNG *rng) ATTR_NONNULL(1); void BLI_rng_seed(struct RNG *rng, unsigned int seed) ATTR_NONNULL(1); void BLI_rng_srandom(struct RNG *rng, unsigned int seed) ATTR_NONNULL(1); +void BLI_rng_get_char_n(RNG *rng, char *bytes, size_t bytes_len) ATTR_NONNULL(1, 2); int BLI_rng_get_int(struct RNG *rng) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1); unsigned int BLI_rng_get_uint(struct RNG *rng) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1); double BLI_rng_get_double(struct RNG *rng) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1); diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt index 42d958774d8..9978d1d19af 100644 --- a/source/blender/blenlib/CMakeLists.txt +++ b/source/blender/blenlib/CMakeLists.txt @@ -53,6 +53,7 @@ set(SRC intern/BLI_mempool.c intern/DLRB_tree.c intern/array_store.c + intern/array_store_utils.c intern/array_utils.c intern/astar.c intern/boxpack2d.c @@ -122,6 +123,7 @@ set(SRC BLI_args.h BLI_array.h BLI_array_store.h + BLI_array_store_utils.h BLI_array_utils.h BLI_astar.h BLI_bitmap.h diff --git a/source/blender/blenlib/intern/BLI_filelist.c b/source/blender/blenlib/intern/BLI_filelist.c index 527d9934797..76de52bda66 100644 --- a/source/blender/blenlib/intern/BLI_filelist.c +++ b/source/blender/blenlib/intern/BLI_filelist.c @@ -352,8 +352,6 @@ void BLI_filelist_entry_datetime_to_string( /** * Deep-duplicate of a single direntry. - * - * \param dup_poin If given, called for each non-NULL direntry->poin. Otherwise, pointer is always simply copied over. */ void BLI_filelist_entry_duplicate(struct direntry *dst, const struct direntry *src) { @@ -368,8 +366,6 @@ void BLI_filelist_entry_duplicate(struct direntry *dst, const struct direntry *s /** * Deep-duplicate of an array of direntries, including the array itself. - * - * \param dup_poin If given, called for each non-NULL direntry->poin. Otherwise, pointer is always simply copied over. */ void BLI_filelist_duplicate( struct direntry **dest_filelist, struct direntry * const src_filelist, const unsigned int nrentries) diff --git a/source/blender/blenlib/intern/BLI_ghash.c b/source/blender/blenlib/intern/BLI_ghash.c index 06946e520a8..f943a8119c4 100644 --- a/source/blender/blenlib/intern/BLI_ghash.c +++ b/source/blender/blenlib/intern/BLI_ghash.c @@ -69,7 +69,7 @@ const unsigned int hashsizes[] = { /** * \note Max load #GHASH_LIMIT_GROW used to be 3. (pre 2.74). - * Python uses 0.6666, tommyhaslib even goes down to 0.5. + * Python uses 0.6666, tommyhashlib even goes down to 0.5. * Reducing our from 3 to 0.75 gives huge speedup (about twice quicker pure GHash insertions/lookup, * about 25% - 30% quicker 'dynamic-topology' stroke drawing e.g.). * Min load #GHASH_LIMIT_SHRINK is a quarter of max load, to avoid resizing to quickly. diff --git a/source/blender/blenlib/intern/BLI_kdopbvh.c b/source/blender/blenlib/intern/BLI_kdopbvh.c index 6cef1924e33..92f4e998206 100644 --- a/source/blender/blenlib/intern/BLI_kdopbvh.c +++ b/source/blender/blenlib/intern/BLI_kdopbvh.c @@ -163,12 +163,23 @@ typedef struct BVHNearestRayData { BVHTree *tree; BVHTree_NearestToRayCallback callback; void *userdata; - BVHTreeRay ray; - struct NearestRayToAABB_Precalc nearest_precalc; + struct { + bool sign[3]; + float origin[3]; + float direction[3]; + + float direction_scaled_square[3]; + float inv_dir[3]; + + float cdot_axis[3]; + } ray; bool pick_smallest[3]; + BVHTreeNearest nearest; + + float scale[3]; } BVHNearestRayData; /** \} */ @@ -1889,58 +1900,374 @@ void BLI_bvhtree_ray_cast_all( /* -------------------------------------------------------------------- */ -/** \name BLI_bvhtree_find_nearest_to_ray +/** \name BLI_bvhtree_find_nearest_to_ray functions * * \{ */ +static void dist_squared_ray_to_aabb_scaled_v3_precalc( + BVHNearestRayData *data, + const float ray_origin[3], const float ray_direction[3], + const bool ray_is_normalized, const float scale[3]) +{ + if (scale) { + copy_v3_v3(data->scale, scale); + } + else { + copy_v3_fl(data->scale, 1.0f); + } + /* un-normalize ray */ + if (ray_is_normalized && scale && + (data->scale[0] != 1.0f || data->scale[1] != 1.0f || data->scale[2] != 1.0f)) + { + data->ray.direction[0] = ray_direction[0] * data->scale[0]; + data->ray.direction[1] = ray_direction[1] * data->scale[1]; + data->ray.direction[2] = ray_direction[2] * data->scale[2]; + + mul_v3_v3fl(data->ray.direction, ray_direction, 1 / len_v3(data->ray.direction)); + } + else { + copy_v3_v3(data->ray.direction, ray_direction); + } + + float dir_sq[3]; + + for (int i = 0; i < 3; i++) { + data->ray.origin[i] = ray_origin[i]; + data->ray.inv_dir[i] = (data->ray.direction[i] != 0.0f) ? + (1.0f / data->ray.direction[i]) : FLT_MAX; + /* It has to be in function of `ray.inv_dir`, + * since the division of 1 by 0.0f, can be -inf or +inf */ + data->ray.sign[i] = (data->ray.inv_dir[i] < 0.0f); + + data->ray.direction_scaled_square[i] = data->ray.direction[i] * data->scale[i]; + + dir_sq[i] = SQUARE(data->ray.direction_scaled_square[i]); + + data->ray.direction_scaled_square[i] *= data->scale[i]; + } + + /* `diag_sq` Length square of each face diagonal */ + float diag_sq[3] = { + dir_sq[1] + dir_sq[2], + dir_sq[0] + dir_sq[2], + dir_sq[0] + dir_sq[1], + }; + + data->ray.cdot_axis[0] = (diag_sq[0] != 0.0f) ? data->ray.direction[0] / diag_sq[0] : FLT_MAX; + data->ray.cdot_axis[1] = (diag_sq[1] != 0.0f) ? data->ray.direction[1] / diag_sq[1] : FLT_MAX; + data->ray.cdot_axis[2] = (diag_sq[2] != 0.0f) ? data->ray.direction[2] / diag_sq[2] : FLT_MAX; +} + +/** + * Returns the squared distance from a ray to a bound-box `AABB`. + * It is based on `fast_ray_nearest_hit` solution to obtain + * the coordinates of the nearest edge of Bound Box to the ray + */ +MINLINE float dist_squared_ray_to_aabb_scaled_v3__impl( + const BVHNearestRayData *data, + const float bv[6], float *r_depth_sq, bool r_axis_closest[3]) +{ + + /* `tmin` is a vector that has the smaller distances to each of the + * infinite planes of the `AABB` faces (hit in nearest face X plane, + * nearest face Y plane and nearest face Z plane) */ + float local_bvmin[3], local_bvmax[3]; + + if (data->ray.sign[0]) { + local_bvmin[0] = bv[1]; + local_bvmax[0] = bv[0]; + } + else { + local_bvmin[0] = bv[0]; + local_bvmax[0] = bv[1]; + } + + if (data->ray.sign[1]) { + local_bvmin[1] = bv[3]; + local_bvmax[1] = bv[2]; + } + else { + local_bvmin[1] = bv[2]; + local_bvmax[1] = bv[3]; + } + + if (data->ray.sign[2]) { + local_bvmin[2] = bv[5]; + local_bvmax[2] = bv[4]; + } + else { + local_bvmin[2] = bv[4]; + local_bvmax[2] = bv[5]; + } + + sub_v3_v3(local_bvmin, data->ray.origin); + sub_v3_v3(local_bvmax, data->ray.origin); + + const float tmin[3] = { + local_bvmin[0] * data->ray.inv_dir[0], + local_bvmin[1] * data->ray.inv_dir[1], + local_bvmin[2] * data->ray.inv_dir[2], + }; + + /* `tmax` is a vector that has the longer distances to each of the + * infinite planes of the `AABB` faces (hit in farthest face X plane, + * farthest face Y plane and farthest face Z plane) */ + const float tmax[3] = { + local_bvmax[0] * data->ray.inv_dir[0], + local_bvmax[1] * data->ray.inv_dir[1], + local_bvmax[2] * data->ray.inv_dir[2], + }; + /* `v1` and `v3` is be the coordinates of the nearest `AABB` edge to the ray*/ + float v1[3], v2[3]; + /* `rtmin` is the highest value of the smaller distances. == max_axis_v3(tmin) + * `rtmax` is the lowest value of longer distances. == min_axis_v3(tmax)*/ + float rtmin, rtmax, mul; + /* `main_axis` is the axis equivalent to edge close to the ray */ + int main_axis; + + r_axis_closest[0] = false; + r_axis_closest[1] = false; + r_axis_closest[2] = false; + + /* *** min_axis_v3(tmax) *** */ + if ((tmax[0] <= tmax[1]) && (tmax[0] <= tmax[2])) { + // printf("# Hit in X %s\n", data->sign[0] ? "min", "max"); + rtmax = tmax[0]; + v1[0] = v2[0] = local_bvmax[0]; + mul = local_bvmax[0] * data->ray.direction_scaled_square[0]; + main_axis = 3; + r_axis_closest[0] = data->ray.sign[0]; + } + else if ((tmax[1] <= tmax[0]) && (tmax[1] <= tmax[2])) { + // printf("# Hit in Y %s\n", data->sign[1] ? "min", "max"); + rtmax = tmax[1]; + v1[1] = v2[1] = local_bvmax[1]; + mul = local_bvmax[1] * data->ray.direction_scaled_square[1]; + main_axis = 2; + r_axis_closest[1] = data->ray.sign[1]; + } + else { + // printf("# Hit in Z %s\n", data->sign[2] ? "min", "max"); + rtmax = tmax[2]; + v1[2] = v2[2] = local_bvmax[2]; + mul = local_bvmax[2] * data->ray.direction_scaled_square[2]; + main_axis = 1; + r_axis_closest[2] = data->ray.sign[2]; + } + + /* *** max_axis_v3(tmin) *** */ + if ((tmin[0] >= tmin[1]) && (tmin[0] >= tmin[2])) { + // printf("# To X %s\n", data->sign[0] ? "max", "min"); + rtmin = tmin[0]; + v1[0] = v2[0] = local_bvmin[0]; + mul += local_bvmin[0] * data->ray.direction_scaled_square[0]; + main_axis -= 3; + r_axis_closest[0] = !data->ray.sign[0]; + } + else if ((tmin[1] >= tmin[0]) && (tmin[1] >= tmin[2])) { + // printf("# To Y %s\n", data->sign[1] ? "max", "min"); + rtmin = tmin[1]; + v1[1] = v2[1] = local_bvmin[1]; + mul += local_bvmin[1] * data->ray.direction_scaled_square[1]; + main_axis -= 1; + r_axis_closest[1] = !data->ray.sign[1]; + } + else { + // printf("# To Z %s\n", data->sign[2] ? "max", "min"); + rtmin = tmin[2]; + v1[2] = v2[2] = local_bvmin[2]; + mul += local_bvmin[2] * data->ray.direction_scaled_square[2]; + main_axis -= 2; + r_axis_closest[2] = !data->ray.sign[2]; + } + /* *** end min/max axis *** */ + + if (main_axis < 0) + main_axis += 3; + + /* if rtmin < rtmax, ray intersect `AABB` */ + if (rtmin <= rtmax) { +#ifdef IGNORE_BEHIND_RAY + /* `if rtmax < depth_min`, the whole `AABB` is behind us */ + if (rtmax < min_depth) { + return fallback; + } +#endif + const float proj = rtmin * data->ray.direction[main_axis]; + + if (data->ray.sign[main_axis]) + r_axis_closest[main_axis] = (proj - local_bvmax[main_axis]) < (local_bvmin[main_axis] - proj); + else + r_axis_closest[main_axis] = (proj - local_bvmin[main_axis]) < (local_bvmax[main_axis] - proj); + + //if (r_depth_sq) + // *r_depth_sq = SQUARE(rtmin); + + return 0.0f; + } +#ifdef IGNORE_BEHIND_RAY + /* `if rtmin < depth_min`, the whole `AABB` is behing us */ + else if (rtmin < min_depth) { + return fallback; + } +#endif + + if (data->ray.sign[main_axis]) { + v1[main_axis] = local_bvmax[main_axis]; + v2[main_axis] = local_bvmin[main_axis]; + } + else { + v1[main_axis] = local_bvmin[main_axis]; + v2[main_axis] = local_bvmax[main_axis]; + } + { + /* `proj` equals to nearest point on the ray closest to the edge `v1 v2` of the `AABB`. */ + const float proj = mul * data->ray.cdot_axis[main_axis]; + float depth_sq, r_point[3]; + if (v1[main_axis] > proj) { /* the nearest point to the ray is the point v1 */ + r_axis_closest[main_axis] = true; + /* `depth` is equivalent the distance of the the projection of v1 on the ray */ + depth_sq = mul + data->ray.direction_scaled_square[main_axis] * v1[main_axis]; + + copy_v3_v3(r_point, v1); + } + else if (v2[main_axis] < proj) { /* the nearest point of the ray is the point v2 */ + r_axis_closest[main_axis] = false; + + depth_sq = mul + data->ray.direction_scaled_square[main_axis] * v2[main_axis]; + + copy_v3_v3(r_point, v2); + } + else { /* the nearest point of the ray is on the edge of the `AABB`. */ + r_axis_closest[main_axis] = (proj - v1[main_axis]) < (v2[main_axis] - proj); + + depth_sq = mul + data->ray.direction_scaled_square[main_axis] * proj; +#if 0 + r_point[0] = main_axis == 0 ? proj : v2[0]; + r_point[1] = main_axis == 1 ? proj : v2[1]; + r_point[2] = main_axis == 2 ? proj : v2[2]; +#else + v2[main_axis] = proj; + copy_v3_v3(r_point, v2); +#endif + } + depth_sq *= depth_sq; + + if (r_depth_sq) + *r_depth_sq = depth_sq; + + /* TODO: scale can be optional */ + r_point[0] *= data->scale[0]; + r_point[1] *= data->scale[1]; + r_point[2] *= data->scale[2]; + + return len_squared_v3(r_point) - depth_sq; + } +} + +/** + * <pre> + * + r_point + * | + * | dist + * | + * +----depth----+orig <-- dir + * + * tangent = dist/depth + * </pre> + */ +static float calc_tangent_sq(BVHNearestRayData *data, BVHNode *node) +{ + float depth_sq; + const float dist_sq = dist_squared_ray_to_aabb_scaled_v3__impl( + data, node->bv, &depth_sq, data->pick_smallest); + + return (dist_sq != 0.0f) ? (dist_sq / depth_sq) : 0.0f; +} + static float calc_dist_sq_to_ray(BVHNearestRayData *data, BVHNode *node) { - const float *bv = node->bv; - const float bb_min[3] = {bv[0], bv[2], bv[4]}; - const float bb_max[3] = {bv[1], bv[3], bv[5]}; - return dist_squared_ray_to_aabb_v3(&data->nearest_precalc, bb_min, bb_max, data->pick_smallest); + return dist_squared_ray_to_aabb_scaled_v3__impl( + data, node->bv, NULL, + data->pick_smallest); } -static void dfs_find_nearest_to_ray_dfs(BVHNearestRayData *data, BVHNode *node) +static void dfs_find_lowest_tangent_dfs(BVHNearestRayData *data, BVHNode *node) { if (node->totnode == 0) { if (data->callback) { - data->callback(data->userdata, node->index, &data->ray, &data->nearest); + data->callback(data->userdata, data->ray.origin, data->ray.direction, + data->scale, node->index, &data->nearest); + } + else { + data->nearest.index = node->index; + data->nearest.dist_sq = calc_tangent_sq(data, node); + /* TODO: return a value to the data->nearest.co + * not urgent however since users currently define own callbacks */ + } + } + else { + int i; + /* First pick the closest node to dive on */ + if (data->pick_smallest[node->main_axis]) { + for (i = 0; i != node->totnode; i++) { + if (calc_tangent_sq(data, node->children[i]) < data->nearest.dist_sq) { + dfs_find_lowest_tangent_dfs(data, node->children[i]); + } + } } else { - const float dist_sq = calc_dist_sq_to_ray(data, node); - if (dist_sq != FLT_MAX) { /* not an invalid ray */ - data->nearest.index = node->index; - data->nearest.dist_sq = dist_sq; - /* TODO: return a value to the data->nearest.co - * not urgent however since users currently define own callbacks */ + for (i = node->totnode - 1; i >= 0; i--) { + if (calc_tangent_sq(data, node->children[i]) < data->nearest.dist_sq) { + dfs_find_lowest_tangent_dfs(data, node->children[i]); + } } } } +} + +static void dfs_find_nearest_to_ray_dfs(BVHNearestRayData *data, BVHNode *node) +{ + if (node->totnode == 0) { + if (data->callback) { + data->callback(data->userdata, data->ray.origin, data->ray.direction, + data->scale, node->index, &data->nearest); + } + else { + data->nearest.index = node->index; + data->nearest.dist_sq = calc_dist_sq_to_ray(data, node); + /* TODO: return a value to the data->nearest.co + * not urgent however since users currently define own callbacks */ + } + } else { int i; /* First pick the closest node to dive on */ if (data->pick_smallest[node->main_axis]) { for (i = 0; i != node->totnode; i++) { - if (calc_dist_sq_to_ray(data, node->children[i]) >= data->nearest.dist_sq) { - continue; + if (calc_dist_sq_to_ray(data, node->children[i]) < data->nearest.dist_sq) { + dfs_find_nearest_to_ray_dfs(data, node->children[i]); } - dfs_find_nearest_to_ray_dfs(data, node->children[i]); } } else { for (i = node->totnode - 1; i >= 0; i--) { - if (calc_dist_sq_to_ray(data, node->children[i]) >= data->nearest.dist_sq) { - continue; + if (calc_dist_sq_to_ray(data, node->children[i]) < data->nearest.dist_sq) { + dfs_find_nearest_to_ray_dfs(data, node->children[i]); } - dfs_find_nearest_to_ray_dfs(data, node->children[i]); } } } } -int BLI_bvhtree_find_nearest_to_ray( - BVHTree *tree, const float co[3], const float dir[3], BVHTreeNearest *nearest, +/** + * Returns the point whose tangent defined by the angle between the point and ray is the lowest + * nearest.dist_sq returns the angle's tangent + */ +int BLI_bvhtree_find_nearest_to_ray_angle( + BVHTree *tree, const float co[3], const float dir[3], + const bool ray_is_normalized, const float scale[3], + BVHTreeNearest *nearest, BVHTree_NearestToRayCallback callback, void *userdata) { BVHNearestRayData data; @@ -1951,11 +2278,46 @@ int BLI_bvhtree_find_nearest_to_ray( data.callback = callback; data.userdata = userdata; - copy_v3_v3(data.ray.origin, co); - copy_v3_v3(data.ray.direction, dir); - data.ray.radius = 0.0f; /* unused here */ + dist_squared_ray_to_aabb_scaled_v3_precalc(&data, co, dir, ray_is_normalized, scale); + + if (nearest) { + memcpy(&data.nearest, nearest, sizeof(*nearest)); + } + else { + data.nearest.index = -1; + data.nearest.dist_sq = FLT_MAX; + } + + /* dfs search */ + if (root) { + if (calc_tangent_sq(&data, root) < data.nearest.dist_sq) + dfs_find_lowest_tangent_dfs(&data, root); + } + + /* copy back results */ + if (nearest) { + memcpy(nearest, &data.nearest, sizeof(*nearest)); + } + + return data.nearest.index; +} + +/* return the nearest point to ray */ +int BLI_bvhtree_find_nearest_to_ray( + BVHTree *tree, const float co[3], const float dir[3], + const bool ray_is_normalized, const float scale[3], + BVHTreeNearest *nearest, + BVHTree_NearestToRayCallback callback, void *userdata) +{ + BVHNearestRayData data; + BVHNode *root = tree->nodes[tree->totleaf]; + + data.tree = tree; + + data.callback = callback; + data.userdata = userdata; - dist_squared_ray_to_aabb_v3_precalc(&data.nearest_precalc, co, dir); + dist_squared_ray_to_aabb_scaled_v3_precalc(&data, co, dir, ray_is_normalized, scale); if (nearest) { memcpy(&data.nearest, nearest, sizeof(*nearest)); diff --git a/source/blender/blenlib/intern/BLI_mempool.c b/source/blender/blenlib/intern/BLI_mempool.c index b7a51f2c48e..783dba5510c 100644 --- a/source/blender/blenlib/intern/BLI_mempool.c +++ b/source/blender/blenlib/intern/BLI_mempool.c @@ -622,7 +622,7 @@ void *BLI_mempool_iterstep(BLI_mempool_iter *iter) iter->curindex = 0; iter->curchunk = iter->curchunk->next; if (iter->curchunk == NULL) { - return NULL; + return (ret->freeword == FREEWORD) ? NULL : ret; } curnode = CHUNK_DATA(iter->curchunk); } diff --git a/source/blender/blenlib/intern/array_store.c b/source/blender/blenlib/intern/array_store.c index 9baccf38fa3..33565596c1f 100644 --- a/source/blender/blenlib/intern/array_store.c +++ b/source/blender/blenlib/intern/array_store.c @@ -36,7 +36,7 @@ * * This diagram is an overview of the structure of a single array-store. * - * \note The only 2 structues here which are referenced externally are the. + * \note The only 2 structures here which are referenced externally are the. * * - BArrayStore: The whole array store. * - BArrayState: Represents a single state (array) of data. @@ -92,7 +92,7 @@ * First matches at either end of the array are detected. * For identical arrays this is all thats needed. * - * De-duplication is performed on any remaining chunks, by hasing the first few bytes of the chunk + * De-duplication is performed on any remaining chunks, by hashing the first few bytes of the chunk * (see: BCHUNK_HASH_TABLE_ACCUMULATE_STEPS). * * \note This is cached for reuse since the referenced data never changes. @@ -650,7 +650,7 @@ static void bchunk_list_append_data( * Use for adding arrays of arbitrary sized memory at once. * * \note This function takes care not to perform redundant chunk-merging checks, - * so we can write succesive fixed size chunks quickly. + * so we can write successive fixed size chunks quickly. */ static void bchunk_list_append_data_n( const BArrayInfo *info, BArrayMemory *bs_mem, @@ -1680,7 +1680,7 @@ void *BLI_array_store_state_data_get_alloc( /** \} */ -/** \name Debigging API (for testing). +/** \name Debugging API (for testing). * \{ */ /* only for test validation */ diff --git a/source/blender/blenlib/intern/array_store_utils.c b/source/blender/blenlib/intern/array_store_utils.c new file mode 100644 index 00000000000..83cd28ddf11 --- /dev/null +++ b/source/blender/blenlib/intern/array_store_utils.c @@ -0,0 +1,103 @@ +/* + * ***** 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. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/blenlib/intern/array_store_utils.c + * \ingroup bli + * \brief Helper functions for BLI_array_store API. + */ + +#include "MEM_guardedalloc.h" + +#include "BLI_utildefines.h" + +#include "BLI_array_store.h" +#include "BLI_array_store_utils.h" /* own include */ + +#include "BLI_math_base.h" + +BArrayStore *BLI_array_store_at_size_ensure( + struct BArrayStore_AtSize *bs_stride, + const int stride, const int chunk_size) +{ + if (bs_stride->stride_table_len < stride) { + bs_stride->stride_table_len = stride; + bs_stride->stride_table = MEM_recallocN(bs_stride->stride_table, sizeof(*bs_stride->stride_table) * stride); + } + BArrayStore **bs_p = &bs_stride->stride_table[stride - 1]; + + if ((*bs_p) == NULL) { +#if 0 + unsigned int chunk_count = chunk_size; +#else + /* calculate best chunk-count to fit a power of two */ + unsigned int chunk_count = chunk_size; + { + unsigned int size = chunk_count * stride; + size = power_of_2_max_u(size); + size = MEM_SIZE_OPTIMAL(size); + chunk_count = size / stride; + } +#endif + + (*bs_p) = BLI_array_store_create(stride, chunk_count); + } + return *bs_p; +} + +BArrayStore *BLI_array_store_at_size_get( + struct BArrayStore_AtSize *bs_stride, + const int stride) +{ + BLI_assert(stride > 0 && stride <= bs_stride->stride_table_len); + return bs_stride->stride_table[stride - 1]; +} + +void BLI_array_store_at_size_clear( + struct BArrayStore_AtSize *bs_stride) +{ + for (int i = 0; i < bs_stride->stride_table_len; i += 1) { + if (bs_stride->stride_table[i]) { + BLI_array_store_destroy(bs_stride->stride_table[i]); + } + } + + MEM_freeN(bs_stride->stride_table); + bs_stride->stride_table = NULL; + bs_stride->stride_table_len = 0; +} + + +void BLI_array_store_at_size_calc_memory_usage( + struct BArrayStore_AtSize *bs_stride, + size_t *r_size_expanded, size_t *r_size_compacted) +{ + size_t size_compacted = 0; + size_t size_expanded = 0; + for (int i = 0; i < bs_stride->stride_table_len; i++) { + BArrayStore *bs = bs_stride->stride_table[i]; + if (bs) { + size_compacted += BLI_array_store_calc_size_compacted_get(bs); + size_expanded += BLI_array_store_calc_size_expanded_get(bs); + } + } + + *r_size_expanded = size_expanded; + *r_size_compacted = size_compacted; +} diff --git a/source/blender/blenlib/intern/array_utils.c b/source/blender/blenlib/intern/array_utils.c index 5d485e2033d..32f0111babd 100644 --- a/source/blender/blenlib/intern/array_utils.c +++ b/source/blender/blenlib/intern/array_utils.c @@ -134,8 +134,22 @@ void _bli_array_permute( int _bli_array_findindex(const void *arr, unsigned int arr_len, size_t arr_stride, const void *p) { const char *arr_step = (const char *)arr; - unsigned int i; - for (i = 0; i < arr_len; i++, arr_step += arr_stride) { + for (unsigned int i = 0; i < arr_len; i++, arr_step += arr_stride) { + if (memcmp(arr_step, p, arr_stride) == 0) { + return (int)i; + } + } + return -1; +} + +/** + * A version of #BLI_array_findindex that searches from the end of the list. + */ +int _bli_array_rfindindex(const void *arr, unsigned int arr_len, size_t arr_stride, const void *p) +{ + const char *arr_step = (const char *)arr + (arr_stride * arr_len); + for (unsigned int i = arr_len; i-- != 0; ) { + arr_step -= arr_stride; if (memcmp(arr_step, p, arr_stride) == 0) { return (int)i; } @@ -183,7 +197,7 @@ void _bli_array_binary_or( * \param user_data: User data for \a test_fn. * \param span_step: Indices to iterate over, * initialize both values to the array length to initialize iteration. - * \param: r_span_len: The length of the span, useful when \a use_wrap is enabled, + * \param r_span_len: The length of the span, useful when \a use_wrap is enabled, * where calculating the length isnt a simple subtraction. */ bool _bli_array_iter_span( diff --git a/source/blender/blenlib/intern/hash_md5.c b/source/blender/blenlib/intern/hash_md5.c index d98b915983c..c73fe7a3ff1 100644 --- a/source/blender/blenlib/intern/hash_md5.c +++ b/source/blender/blenlib/intern/hash_md5.c @@ -112,7 +112,7 @@ static void md5_init_ctx(struct md5_ctx *ctx) * the 'ctx' context for the next 'len' bytes starting at 'buffer'. * It is necessary that 'len' is a multiple of 64!!! */ -static void md5_process_block (const void *buffer, size_t len, struct md5_ctx *ctx) +static void md5_process_block(const void *buffer, size_t len, struct md5_ctx *ctx) { /* These are the four functions used in the four steps of the MD5 algorithm and defined in the RFC 1321. * The first function is a little bit optimized (as found in Colin Plumbs public domain implementation). diff --git a/source/blender/blenlib/intern/math_color_inline.c b/source/blender/blenlib/intern/math_color_inline.c index 180d62105c4..abb8ff35a45 100644 --- a/source/blender/blenlib/intern/math_color_inline.c +++ b/source/blender/blenlib/intern/math_color_inline.c @@ -65,7 +65,7 @@ MALWAYS_INLINE __m128 linearrgb_to_srgb_v4_simd(const __m128 c) MINLINE void srgb_to_linearrgb_v3_v3(float linear[3], const float srgb[3]) { - float r[4] = {srgb[0], srgb[1], srgb[2], 0.0f}; + float r[4] = {srgb[0], srgb[1], srgb[2], 1.0f}; __m128 *rv = (__m128 *)&r; *rv = srgb_to_linearrgb_v4_simd(*rv); linear[0] = r[0]; @@ -75,7 +75,7 @@ MINLINE void srgb_to_linearrgb_v3_v3(float linear[3], const float srgb[3]) MINLINE void linearrgb_to_srgb_v3_v3(float srgb[3], const float linear[3]) { - float r[4] = {linear[0], linear[1], linear[2], 0.0f}; + float r[4] = {linear[0], linear[1], linear[2], 1.0f}; __m128 *rv = (__m128 *)&r; *rv = linearrgb_to_srgb_v4_simd(*rv); srgb[0] = r[0]; diff --git a/source/blender/blenlib/intern/math_geom.c b/source/blender/blenlib/intern/math_geom.c index 370e8bb0035..40454a93ec8 100644 --- a/source/blender/blenlib/intern/math_geom.c +++ b/source/blender/blenlib/intern/math_geom.c @@ -572,6 +572,67 @@ float dist_signed_squared_to_corner_v3v3v3( } } +/** + * return the distance squared of a point to a ray. + */ +float dist_squared_to_ray_v3( + const float ray_origin[3], const float ray_direction[3], + const float co[3], float *r_depth) +{ + float dvec[3]; + sub_v3_v3v3(dvec, co, ray_origin); + *r_depth = dot_v3v3(dvec, ray_direction); + return len_squared_v3(dvec) - SQUARE(*r_depth); +} +/** + * Find the closest point in a seg to a ray and return the distance squared. + * \param r_point : Is the point on segment closest to ray (or to ray_origin if the ray and the segment are parallel). + * \param depth: the distance of r_point projection on ray to the ray_origin. + */ +float dist_squared_ray_to_seg_v3( + const float ray_origin[3], const float ray_direction[3], + const float v0[3], const float v1[3], + float r_point[3], float *r_depth) +{ + float a[3], t[3], n[3], lambda; + sub_v3_v3v3(a, v1, v0); + sub_v3_v3v3(t, v0, ray_origin); + cross_v3_v3v3(n, a, ray_direction); + const float nlen = len_squared_v3(n); + + /* if (nlen == 0.0f) the lines are parallel, + * has no nearest point, only distance squared.*/ + if (nlen == 0.0f) { + /* Calculate the distance to the point v0 then */ + copy_v3_v3(r_point, v0); + *r_depth = dot_v3v3(t, ray_direction); + } + else { + float c[3], cray[3]; + sub_v3_v3v3(c, n, t); + cross_v3_v3v3(cray, c, ray_direction); + lambda = dot_v3v3(cray, n) / nlen; + if (lambda <= 0) { + copy_v3_v3(r_point, v0); + + *r_depth = dot_v3v3(t, ray_direction); + } + else if (lambda >= 1) { + copy_v3_v3(r_point, v1); + + sub_v3_v3v3(t, v1, ray_origin); + *r_depth = dot_v3v3(t, ray_direction); + } + else { + madd_v3_v3v3fl(r_point, v0, a, lambda); + + sub_v3_v3v3(t, r_point, ray_origin); + *r_depth = dot_v3v3(t, ray_direction); + } + } + return len_squared_v3(t) - SQUARE(*r_depth); +} + /* Adapted from "Real-Time Collision Detection" by Christer Ericson, * published by Morgan Kaufmann Publishers, copyright 2005 Elsevier Inc. * @@ -2692,7 +2753,7 @@ bool isect_point_tri_prism_v3(const float p[3], const float v1[3], const float v } /** - * \param r_vi The point \a p projected onto the triangle. + * \param r_isect_co: The point \a p projected onto the triangle. * \return True when \a p is inside the triangle. * \note Its up to the caller to check the distance between \a p and \a r_vi against an error margin. */ @@ -5002,7 +5063,9 @@ float cubic_tangent_factor_circle_v3(const float tan_l[3], const float tan_r[3]) BLI_ASSERT_UNIT_V3(tan_l); BLI_ASSERT_UNIT_V3(tan_r); - const float eps = 1e-7f; + /* -7f causes instability/glitches with Bendy Bones + Custom Refs */ + const float eps = 1e-5f; + const float tan_dot = dot_v3v3(tan_l, tan_r); if (tan_dot > 1.0f - eps) { /* no angle difference (use fallback, length wont make any difference) */ diff --git a/source/blender/blenlib/intern/math_matrix.c b/source/blender/blenlib/intern/math_matrix.c index 0e3f905ef16..c9c61d5c878 100644 --- a/source/blender/blenlib/intern/math_matrix.c +++ b/source/blender/blenlib/intern/math_matrix.c @@ -587,6 +587,15 @@ void mul_v3_m3v3(float r[3], float M[3][3], const float a[3]) r[2] = M[0][2] * a[0] + M[1][2] * a[1] + M[2][2] * a[2]; } +void mul_v3_m3v3_db(double r[3], double M[3][3], const double a[3]) +{ + BLI_assert(r != a); + + r[0] = M[0][0] * a[0] + M[1][0] * a[1] + M[2][0] * a[2]; + r[1] = M[0][1] * a[0] + M[1][1] * a[1] + M[2][1] * a[2]; + r[2] = M[0][2] * a[0] + M[1][2] * a[1] + M[2][2] * a[2]; +} + void mul_v2_m3v3(float r[2], float M[3][3], const float a[3]) { BLI_assert(r != a); @@ -597,10 +606,12 @@ void mul_v2_m3v3(float r[2], float M[3][3], const float a[3]) void mul_m3_v3(float M[3][3], float r[3]) { - float tmp[3]; + mul_v3_m3v3(r, M, (const float[3]){UNPACK3(r)}); +} - mul_v3_m3v3(tmp, M, r); - copy_v3_v3(r, tmp); +void mul_m3_v3_db(double M[3][3], double r[3]) +{ + mul_v3_m3v3_db(r, M, (const double[3]){UNPACK3(r)}); } void mul_transposed_m3_v3(float mat[3][3], float vec[3]) diff --git a/source/blender/blenlib/intern/math_vector.c b/source/blender/blenlib/intern/math_vector.c index 7f2db3743df..988034349e0 100644 --- a/source/blender/blenlib/intern/math_vector.c +++ b/source/blender/blenlib/intern/math_vector.c @@ -585,23 +585,27 @@ void angle_poly_v3(float *angles, const float *verts[3], int len) /********************************* Geometry **********************************/ -/* Project v1 on v2 */ -void project_v2_v2v2(float c[2], const float v1[2], const float v2[2]) +/** + * Project \a p onto \a v_proj + */ +void project_v2_v2v2(float out[2], const float p[2], const float v_proj[2]) { - const float mul = dot_v2v2(v1, v2) / dot_v2v2(v2, v2); + const float mul = dot_v2v2(p, v_proj) / dot_v2v2(v_proj, v_proj); - c[0] = mul * v2[0]; - c[1] = mul * v2[1]; + out[0] = mul * v_proj[0]; + out[1] = mul * v_proj[1]; } -/* Project v1 on v2 */ -void project_v3_v3v3(float c[3], const float v1[3], const float v2[3]) +/** + * Project \a p onto \a v_proj + */ +void project_v3_v3v3(float out[3], const float p[3], const float v_proj[3]) { - const float mul = dot_v3v3(v1, v2) / dot_v3v3(v2, v2); + const float mul = dot_v3v3(p, v_proj) / dot_v3v3(v_proj, v_proj); - c[0] = mul * v2[0]; - c[1] = mul * v2[1]; - c[2] = mul * v2[2]; + out[0] = mul * v_proj[0]; + out[1] = mul * v_proj[1]; + out[2] = mul * v_proj[2]; } /** @@ -617,35 +621,35 @@ void project_v3_v3v3(float c[3], const float v1[3], const float v2[3]) * sub_v3_v3v3(c, v, c); * \endcode */ -void project_plane_v3_v3v3(float c[3], const float v[3], const float v_plane[3]) +void project_plane_v3_v3v3(float out[3], const float p[3], const float v_plane[3]) { - const float mul = dot_v3v3(v, v_plane) / dot_v3v3(v_plane, v_plane); + const float mul = dot_v3v3(p, v_plane) / dot_v3v3(v_plane, v_plane); - c[0] = v[0] - (mul * v_plane[0]); - c[1] = v[1] - (mul * v_plane[1]); - c[2] = v[2] - (mul * v_plane[2]); + out[0] = p[0] - (mul * v_plane[0]); + out[1] = p[1] - (mul * v_plane[1]); + out[2] = p[2] - (mul * v_plane[2]); } -void project_plane_v2_v2v2(float c[2], const float v[2], const float v_plane[2]) +void project_plane_v2_v2v2(float out[2], const float p[2], const float v_plane[2]) { - const float mul = dot_v2v2(v, v_plane) / dot_v2v2(v_plane, v_plane); + const float mul = dot_v2v2(p, v_plane) / dot_v2v2(v_plane, v_plane); - c[0] = v[0] - (mul * v_plane[0]); - c[1] = v[1] - (mul * v_plane[1]); + out[0] = p[0] - (mul * v_plane[0]); + out[1] = p[1] - (mul * v_plane[1]); } /* project a vector on a plane defined by normal and a plane point p */ -void project_v3_plane(float v[3], const float n[3], const float p[3]) +void project_v3_plane(float out[3], const float plane_no[3], const float plane_co[3]) { float vector[3]; float mul; - sub_v3_v3v3(vector, v, p); - mul = dot_v3v3(vector, n) / len_squared_v3(n); + sub_v3_v3v3(vector, out, plane_co); + mul = dot_v3v3(vector, plane_no) / len_squared_v3(plane_no); - mul_v3_v3fl(vector, n, mul); + mul_v3_v3fl(vector, plane_no, mul); - sub_v3_v3(v, vector); + sub_v3_v3(out, vector); } /* Returns a vector bisecting the angle at v2 formed by v1, v2 and v3 */ @@ -664,15 +668,15 @@ void bisect_v3_v3v3v3(float out[3], const float v1[3], const float v2[3], const * Returns a reflection vector from a vector and a normal vector * reflect = vec - ((2 * DotVecs(vec, mirror)) * mirror) */ -void reflect_v3_v3v3(float out[3], const float vec[3], const float normal[3]) +void reflect_v3_v3v3(float out[3], const float v[3], const float normal[3]) { - const float dot2 = 2.0f * dot_v3v3(vec, normal); + const float dot2 = 2.0f * dot_v3v3(v, normal); BLI_ASSERT_UNIT_V3(normal); - out[0] = vec[0] - (dot2 * normal[0]); - out[1] = vec[1] - (dot2 * normal[1]); - out[2] = vec[2] - (dot2 * normal[2]); + out[0] = v[0] - (dot2 * normal[0]); + out[1] = v[1] - (dot2 * normal[1]); + out[2] = v[2] - (dot2 * normal[2]); } /** @@ -710,27 +714,27 @@ void ortho_basis_v3v3_v3(float r_n1[3], float r_n2[3], const float n[3]) * * \note return vector won't maintain same length. */ -void ortho_v3_v3(float p[3], const float v[3]) +void ortho_v3_v3(float out[3], const float v[3]) { const int axis = axis_dominant_v3_single(v); - BLI_assert(p != v); + BLI_assert(out != v); switch (axis) { case 0: - p[0] = -v[1] - v[2]; - p[1] = v[0]; - p[2] = v[0]; + out[0] = -v[1] - v[2]; + out[1] = v[0]; + out[2] = v[0]; break; case 1: - p[0] = v[1]; - p[1] = -v[0] - v[2]; - p[2] = v[1]; + out[0] = v[1]; + out[1] = -v[0] - v[2]; + out[2] = v[1]; break; case 2: - p[0] = v[2]; - p[1] = v[2]; - p[2] = -v[0] - v[1]; + out[0] = v[2]; + out[1] = v[2]; + out[2] = -v[0] - v[1]; break; } } @@ -738,18 +742,19 @@ void ortho_v3_v3(float p[3], const float v[3]) /** * no brainer compared to v3, just have for consistency. */ -void ortho_v2_v2(float p[2], const float v[2]) +void ortho_v2_v2(float out[2], const float v[2]) { - BLI_assert(p != v); + BLI_assert(out != v); - p[0] = -v[1]; - p[1] = v[0]; + out[0] = -v[1]; + out[1] = v[0]; } -/* Rotate a point p by angle theta around an arbitrary axis r +/** + * Rotate a point \a p by \a angle around an arbitrary unit length \a axis. * http://local.wasp.uwa.edu.au/~pbourke/geometry/ */ -void rotate_normalized_v3_v3v3fl(float r[3], const float p[3], const float axis[3], const float angle) +void rotate_normalized_v3_v3v3fl(float out[3], const float p[3], const float axis[3], const float angle) { const float costheta = cosf(angle); const float sintheta = sinf(angle); @@ -757,17 +762,17 @@ void rotate_normalized_v3_v3v3fl(float r[3], const float p[3], const float axis[ /* double check they are normalized */ BLI_ASSERT_UNIT_V3(axis); - r[0] = ((costheta + (1 - costheta) * axis[0] * axis[0]) * p[0]) + - (((1 - costheta) * axis[0] * axis[1] - axis[2] * sintheta) * p[1]) + - (((1 - costheta) * axis[0] * axis[2] + axis[1] * sintheta) * p[2]); + out[0] = ((costheta + (1 - costheta) * axis[0] * axis[0]) * p[0]) + + (((1 - costheta) * axis[0] * axis[1] - axis[2] * sintheta) * p[1]) + + (((1 - costheta) * axis[0] * axis[2] + axis[1] * sintheta) * p[2]); - r[1] = (((1 - costheta) * axis[0] * axis[1] + axis[2] * sintheta) * p[0]) + - ((costheta + (1 - costheta) * axis[1] * axis[1]) * p[1]) + - (((1 - costheta) * axis[1] * axis[2] - axis[0] * sintheta) * p[2]); + out[1] = (((1 - costheta) * axis[0] * axis[1] + axis[2] * sintheta) * p[0]) + + ((costheta + (1 - costheta) * axis[1] * axis[1]) * p[1]) + + (((1 - costheta) * axis[1] * axis[2] - axis[0] * sintheta) * p[2]); - r[2] = (((1 - costheta) * axis[0] * axis[2] - axis[1] * sintheta) * p[0]) + - (((1 - costheta) * axis[1] * axis[2] + axis[0] * sintheta) * p[1]) + - ((costheta + (1 - costheta) * axis[2] * axis[2]) * p[2]); + out[2] = (((1 - costheta) * axis[0] * axis[2] - axis[1] * sintheta) * p[0]) + + (((1 - costheta) * axis[1] * axis[2] + axis[0] * sintheta) * p[1]) + + ((costheta + (1 - costheta) * axis[2] * axis[2]) * p[2]); } void rotate_v3_v3v3fl(float r[3], const float p[3], const float axis[3], const float angle) diff --git a/source/blender/blenlib/intern/math_vector_inline.c b/source/blender/blenlib/intern/math_vector_inline.c index b43fb6e986c..fd9f3d5ff99 100644 --- a/source/blender/blenlib/intern/math_vector_inline.c +++ b/source/blender/blenlib/intern/math_vector_inline.c @@ -633,6 +633,13 @@ MINLINE void negate_v3_short(short r[3]) r[2] = (short)-r[2]; } +MINLINE void negate_v3_db(double r[3]) +{ + r[0] = -r[0]; + r[1] = -r[1]; + r[2] = -r[2]; +} + MINLINE void invert_v2(float r[2]) { BLI_assert(!ELEM(0.0f, r[0], r[1])); diff --git a/source/blender/blenlib/intern/path_util.c b/source/blender/blenlib/intern/path_util.c index 2b793841c38..ded10ad7713 100644 --- a/source/blender/blenlib/intern/path_util.c +++ b/source/blender/blenlib/intern/path_util.c @@ -310,7 +310,7 @@ static int BLI_path_unc_prefix_len(const char *path); /* defined below in same f /** * Remove redundant characters from \a path and optionally make absolute. * - * \param relbase: The path this is relative to, or ignored when NULL. + * \param relabase: The path this is relative to, or ignored when NULL. * \param path: Can be any input, and this function converts it to a regular full path. * Also removes garbage from directory paths, like `/../` or double slashes etc. * diff --git a/source/blender/blenlib/intern/quadric.c b/source/blender/blenlib/intern/quadric.c index 588cd9c2cb5..c9d27494455 100644 --- a/source/blender/blenlib/intern/quadric.c +++ b/source/blender/blenlib/intern/quadric.c @@ -63,26 +63,68 @@ void BLI_quadric_from_plane(Quadric *q, const double v[4]) q->d2 = v[3] * v[3]; } -void BLI_quadric_to_tensor_m3(const Quadric *q, float m[3][3]) +#if 0 /* UNUSED */ + +static void quadric_to_tensor_m3(const Quadric *q, double m[3][3]) { - m[0][0] = (float)q->a2; - m[0][1] = (float)q->ab; - m[0][2] = (float)q->ac; + m[0][0] = q->a2; + m[0][1] = q->ab; + m[0][2] = q->ac; - m[1][0] = (float)q->ab; - m[1][1] = (float)q->b2; - m[1][2] = (float)q->bc; + m[1][0] = q->ab; + m[1][1] = q->b2; + m[1][2] = q->bc; - m[2][0] = (float)q->ac; - m[2][1] = (float)q->bc; - m[2][2] = (float)q->c2; + m[2][0] = q->ac; + m[2][1] = q->bc; + m[2][2] = q->c2; } -void BLI_quadric_to_vector_v3(const Quadric *q, float v[3]) +#endif + +/** + * Inline inverse matrix creation. + * Equivalent of: + * + * \code{.c} + * quadric_to_tensor_m3(q, m); + * invert_m3_db(m, eps); + * \endcode + */ +static bool quadric_to_tensor_m3_inverse(const Quadric *q, double m[3][3], double epsilon) { - v[0] = (float)q->ad; - v[1] = (float)q->bd; - v[2] = (float)q->cd; + const double det = + (q->a2 * (q->b2 * q->c2 - q->bc * q->bc) - + q->ab * (q->ab * q->c2 - q->ac * q->bc) + + q->ac * (q->ab * q->bc - q->ac * q->b2)); + + if (fabs(det) > epsilon) { + const double invdet = 1.0 / det; + + m[0][0] = (q->b2 * q->c2 - q->bc * q->bc) * invdet; + m[1][0] = (q->bc * q->ac - q->ab * q->c2) * invdet; + m[2][0] = (q->ab * q->bc - q->b2 * q->ac) * invdet; + + m[0][1] = (q->ac * q->bc - q->ab * q->c2) * invdet; + m[1][1] = (q->a2 * q->c2 - q->ac * q->ac) * invdet; + m[2][1] = (q->ab * q->ac - q->a2 * q->bc) * invdet; + + m[0][2] = (q->ab * q->bc - q->ac * q->b2) * invdet; + m[1][2] = (q->ac * q->ab - q->a2 * q->bc) * invdet; + m[2][2] = (q->a2 * q->b2 - q->ab * q->ab) * invdet; + + return true; + } + else { + return false; + } +} + +void BLI_quadric_to_vector_v3(const Quadric *q, double v[3]) +{ + v[0] = q->ad; + v[1] = q->bd; + v[2] = q->cd; } void BLI_quadric_clear(Quadric *q) @@ -105,26 +147,22 @@ void BLI_quadric_mul(Quadric *a, const double scalar) mul_vn_db((double *)a, QUADRIC_FLT_TOT, scalar); } -double BLI_quadric_evaluate(const Quadric *q, const float v_fl[3]) +double BLI_quadric_evaluate(const Quadric *q, const double v[3]) { - const double v[3] = {UNPACK3(v_fl)}; return ((q->a2 * v[0] * v[0]) + (q->ab * 2 * v[0] * v[1]) + (q->ac * 2 * v[0] * v[2]) + (q->ad * 2 * v[0]) + (q->b2 * v[1] * v[1]) + (q->bc * 2 * v[1] * v[2]) + (q->bd * 2 * v[1]) + (q->c2 * v[2] * v[2]) + (q->cd * 2 * v[2]) + (q->d2)); } -bool BLI_quadric_optimize(const Quadric *q, float v[3], const float epsilon) +bool BLI_quadric_optimize(const Quadric *q, double v[3], const double epsilon) { - float m[3][3]; + double m[3][3]; - BLI_quadric_to_tensor_m3(q, m); - - if (invert_m3_ex(m, epsilon)) { + if (quadric_to_tensor_m3_inverse(q, m, epsilon)) { BLI_quadric_to_vector_v3(q, v); - mul_m3_v3(m, v); - negate_v3(v); - + mul_m3_v3_db(m, v); + negate_v3_db(v); return true; } else { diff --git a/source/blender/blenlib/intern/rand.c b/source/blender/blenlib/intern/rand.c index 66c568a7ff3..40d9a3da3d9 100644 --- a/source/blender/blenlib/intern/rand.c +++ b/source/blender/blenlib/intern/rand.c @@ -46,6 +46,7 @@ #define MULTIPLIER 0x5DEECE66Dll #define MASK 0x0000FFFFFFFFFFFFll +#define MASK_BYTES 2 #define ADDEND 0xB #define LOWSEED 0x330E @@ -107,6 +108,45 @@ BLI_INLINE void rng_step(RNG *rng) rng->X = (MULTIPLIER * rng->X + ADDEND) & MASK; } +void BLI_rng_get_char_n(RNG *rng, char *bytes, size_t bytes_len) +{ + size_t last_len = 0; + size_t trim_len = bytes_len; + +#define RAND_STRIDE (sizeof(rng->X) - MASK_BYTES) + + if (trim_len > RAND_STRIDE) { + last_len = trim_len % RAND_STRIDE; + trim_len = trim_len - last_len; + } + else { + trim_len = 0; + last_len = bytes_len; + } + + const char *data_src = (void *)&(rng->X); + size_t i = 0; + while (i != trim_len) { + BLI_assert(i < trim_len); +#ifdef __BIG_ENDIAN__ + for (size_t j = (RAND_STRIDE + MASK_BYTES) - 1; j != MASK_BYTES - 1; j--) +#else + for (size_t j = 0; j != RAND_STRIDE; j++) +#endif + { + bytes[i++] = data_src[j]; + } + rng_step(rng); + } + if (last_len) { + for (size_t j = 0; j != last_len; j++) { + bytes[i++] = data_src[j]; + } + } + +#undef RAND_STRIDE +} + int BLI_rng_get_int(RNG *rng) { rng_step(rng); diff --git a/source/blender/blenlib/intern/storage.c b/source/blender/blenlib/intern/storage.c index aba7c9d5ee2..3edc00a8c1a 100644 --- a/source/blender/blenlib/intern/storage.c +++ b/source/blender/blenlib/intern/storage.c @@ -389,7 +389,7 @@ LinkNode *BLI_file_read_as_lines(const char *name) /* * size = because on win32 reading * all the bytes in the file will return - * less bytes because of crnl changes. + * less bytes because of `CRNL` changes. */ size = fread(buf, 1, size, fp); for (i = 0; i <= size; i++) { diff --git a/source/blender/blenlib/intern/task.c b/source/blender/blenlib/intern/task.c index 58475b7f835..bd7b7f9cdbd 100644 --- a/source/blender/blenlib/intern/task.c +++ b/source/blender/blenlib/intern/task.c @@ -928,7 +928,7 @@ static void task_parallel_range_ex( func_finalize(userdata, userdata_chunk_local); } } - MALLOCA_FREE(userdata_chunk_array, userdata_chunk_size * num_tasks); + MALLOCA_FREE(userdata_chunk_array, userdata_chunk_size * num_tasks); } } @@ -992,7 +992,8 @@ void BLI_task_parallel_range( * (similar to OpenMP's firstprivate). * \param userdata_chunk_size Memory size of \a userdata_chunk. * \param func_ex Callback function (advanced version). - * \param func_finalize Callback function, called after all workers have finisehd, useful to finalize accumulative tasks. + * \param func_finalize Callback function, called after all workers have finished, + * useful to finalize accumulative tasks. * \param use_threading If \a true, actually split-execute loop in threads, else just do a sequential forloop * (allows caller to use any kind of test to switch on parallelization or not). * \param use_dynamic_scheduling If \a true, the whole range is divided in a lot of small chunks (of size 32 currently), diff --git a/source/blender/blenloader/BLO_readfile.h b/source/blender/blenloader/BLO_readfile.h index bf47682297d..c85cf128643 100644 --- a/source/blender/blenloader/BLO_readfile.h +++ b/source/blender/blenloader/BLO_readfile.h @@ -100,7 +100,8 @@ struct ID *BLO_library_link_named_part(struct Main *mainl, BlendHandle **bh, con struct ID *BLO_library_link_named_part_ex( struct Main *mainl, BlendHandle **bh, const short idcode, const char *name, const short flag, - struct Scene *scene, struct View3D *v3d); + struct Scene *scene, struct View3D *v3d, + const bool use_placeholders, const bool force_indirect); void BLO_library_link_end(struct Main *mainl, BlendHandle **bh, short flag, struct Scene *scene, struct View3D *v3d); void BLO_library_link_copypaste(struct Main *mainl, BlendHandle *bh); diff --git a/source/blender/blenloader/CMakeLists.txt b/source/blender/blenloader/CMakeLists.txt index 8364df38208..479d3a15e6c 100644 --- a/source/blender/blenloader/CMakeLists.txt +++ b/source/blender/blenloader/CMakeLists.txt @@ -35,6 +35,10 @@ set(INC ../nodes ../render/extern/include ../../../intern/guardedalloc + + # for writefile.c: dna_type_offsets.h + ${CMAKE_BINARY_DIR}/source/blender/makesdna/intern + ) set(INC_SYS @@ -74,3 +78,6 @@ if(WITH_CODEC_FFMPEG) endif() blender_add_lib(bf_blenloader "${SRC}" "${INC}" "${INC_SYS}") + +# needed so writefile.c can use dna_type_offsets.h +add_dependencies(bf_blenloader bf_dna) diff --git a/source/blender/blenloader/intern/readblenentry.c b/source/blender/blenloader/intern/readblenentry.c index 3cae95d418e..be893177b3b 100644 --- a/source/blender/blenloader/intern/readblenentry.c +++ b/source/blender/blenloader/intern/readblenentry.c @@ -411,22 +411,23 @@ BlendFileData *BLO_read_from_memfile(Main *oldmain, const char *filename, MemFil /* Even though directly used libs have been already moved to new main, indirect ones have not. * This is a bit annoying, but we have no choice but to keep them all for now - means some now unused * data may remain in memory, but think we'll have to live with it. */ - Main *libmain; + Main *libmain, *libmain_next; Main *newmain = bfd->main; ListBase new_mainlist = {newmain, newmain}; - for (libmain = oldmain->next; libmain; libmain = libmain->next) { + for (libmain = oldmain->next; libmain; libmain = libmain_next) { + libmain_next = libmain->next; /* Note that LIB_INDIRECT does not work with libraries themselves, so we use non-NULL parent * to detect indirect-linked ones... */ if (libmain->curlib && (libmain->curlib->parent != NULL)) { BLI_remlink(&old_mainlist, libmain); BLI_addtail(&new_mainlist, libmain); } -#if 0 else { +#ifdef PRINT_DEBUG printf("Dropped Main for lib: %s\n", libmain->curlib->id.name); - } #endif + } } /* In any case, we need to move all lib datablocks themselves - those are 'first level data', * getting rid of them would imply updating spaces & co to prevent invalid pointers access. */ diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 10f603c9f6b..67597661470 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -113,6 +113,7 @@ #include "BKE_action.h" #include "BKE_armature.h" +#include "BKE_blender_version.h" #include "BKE_brush.h" #include "BKE_cloth.h" #include "BKE_constraint.h" @@ -124,6 +125,7 @@ #include "BKE_global.h" // for G #include "BKE_group.h" #include "BKE_library.h" // for which_libbase +#include "BKE_library_idmap.h" #include "BKE_library_query.h" #include "BKE_idcode.h" #include "BKE_material.h" @@ -159,69 +161,74 @@ #include <errno.h> -/* - * Remark: still a weak point is the newaddress() function, that doesnt solve reading from - * multiple files at the same time - * - * (added remark: oh, i thought that was solved? will look at that... (ton) - * +/** * READ - * - Existing Library (Main) push or free - * - allocate new Main + * ==== + * + * - Existing Library (#Main) push or free + * - allocate new #Main * - load file - * - read SDNA + * - read #SDNA * - for each LibBlock - * - read LibBlock - * - if a Library - * - make a new Main - * - attach ID's to it - * - else - * - read associated 'direct data' - * - link direct data (internal and to LibBlock) - * - read FileGlobal - * - read USER data, only when indicated (file is ~/X.XX/startup.blend) + * - read LibBlock + * - if a Library + * - make a new #Main + * - attach ID's to it + * - else + * - read associated 'direct data' + * - link direct data (internal and to LibBlock) + * - read #FileGlobal + * - read #USER data, only when indicated (file is ``~/X.XX/startup.blend``) * - free file - * - per Library (per Main) - * - read file - * - read SDNA - * - find LibBlocks and attach IDs to Main - * - if external LibBlock - * - search all Main's - * - or it's already read, - * - or not read yet - * - or make new Main - * - per LibBlock - * - read recursive - * - read associated direct data - * - link direct data (internal and to LibBlock) - * - free file + * - per Library (per #Main) + * - read file + * - read #SDNA + * - find LibBlocks and attach #ID's to #Main + * - if external LibBlock + * - search all #Main's + * - or it's already read, + * - or not read yet + * - or make new #Main + * - per LibBlock + * - read recursive + * - read associated direct data + * - link direct data (internal and to LibBlock) + * - free file * - per Library with unread LibBlocks - * - read file - * - read SDNA - * - per LibBlock - * - read recursive - * - read associated direct data - * - link direct data (internal and to LibBlock) - * - free file - * - join all Mains + * - read file + * - read #SDNA + * - per LibBlock + * - read recursive + * - read associated direct data + * - link direct data (internal and to LibBlock) + * - free file + * - join all #Main's * - link all LibBlocks and indirect pointers to libblocks - * - initialize FileGlobal and copy pointers to Global + * - initialize #FileGlobal and copy pointers to #Global + * + * \note Still a weak point is the new-address function, that doesnt solve reading from + * multiple files at the same time. + * (added remark: oh, i thought that was solved? will look at that... (ton). */ /* use GHash for BHead name-based lookups (speeds up linking) */ #define USE_GHASH_BHEAD +/* Use GHash for restoring pointers by name */ +#define USE_GHASH_RESTORE_POINTER + /***/ typedef struct OldNew { - void *old, *newp; + const void *old; + void *newp; int nr; } OldNew; typedef struct OldNewMap { OldNew *entries; int nentries, entriessize; - int sorted; + bool sorted; int lasthit; } OldNewMap; @@ -287,12 +294,13 @@ static int verg_oldnewmap(const void *v1, const void *v2) static void oldnewmap_sort(FileData *fd) { + BLI_assert(fd->libmap->sorted == false); qsort(fd->libmap->entries, fd->libmap->nentries, sizeof(OldNew), verg_oldnewmap); fd->libmap->sorted = 1; } /* nr is zero for data, and ID code for libdata */ -static void oldnewmap_insert(OldNewMap *onm, void *oldaddr, void *newaddr, int nr) +static void oldnewmap_insert(OldNewMap *onm, const void *oldaddr, void *newaddr, int nr) { OldNew *entry; @@ -309,7 +317,7 @@ static void oldnewmap_insert(OldNewMap *onm, void *oldaddr, void *newaddr, int n entry->nr = nr; } -void blo_do_versions_oldnewmap_insert(OldNewMap *onm, void *oldaddr, void *newaddr, int nr) +void blo_do_versions_oldnewmap_insert(OldNewMap *onm, const void *oldaddr, void *newaddr, int nr) { oldnewmap_insert(onm, oldaddr, newaddr, nr); } @@ -364,7 +372,7 @@ static int oldnewmap_lookup_entry_full(const OldNewMap *onm, const void *addr, i return -1; } -static void *oldnewmap_lookup_and_inc(OldNewMap *onm, void *addr, bool increase_users) +static void *oldnewmap_lookup_and_inc(OldNewMap *onm, const void *addr, bool increase_users) { int i; @@ -394,7 +402,7 @@ static void *oldnewmap_lookup_and_inc(OldNewMap *onm, void *addr, bool increase_ } /* for libdata, nr has ID code, no increment */ -static void *oldnewmap_liblookup(OldNewMap *onm, void *addr, void *lib) +static void *oldnewmap_liblookup(OldNewMap *onm, const void *addr, const void *lib) { if (addr == NULL) { return NULL; @@ -402,11 +410,8 @@ static void *oldnewmap_liblookup(OldNewMap *onm, void *addr, void *lib) /* lasthit works fine for non-libdata, linking there is done in same sequence as writing */ if (onm->sorted) { - OldNew entry_s, *entry; - - entry_s.old = addr; - - entry = bsearch(&entry_s, onm->entries, onm->nentries, sizeof(OldNew), verg_oldnewmap); + const OldNew entry_s = {.old = addr}; + OldNew *entry = bsearch(&entry_s, onm->entries, onm->nentries, sizeof(OldNew), verg_oldnewmap); if (entry) { ID *id = entry->newp; @@ -486,53 +491,57 @@ void blo_join_main(ListBase *mainlist) } } -static void split_libdata(ListBase *lb, Main *first) +static void split_libdata(ListBase *lb_src, Main **lib_main_array, const unsigned int lib_main_array_len) { - ListBase *lbn; - ID *id, *idnext; - Main *mainvar; - - id = lb->first; - while (id) { + for (ID *id = lb_src->first, *idnext; id; id = idnext) { idnext = id->next; + if (id->lib) { - mainvar = first; - while (mainvar) { - if (mainvar->curlib == id->lib) { - lbn= which_libbase(mainvar, GS(id->name)); - BLI_remlink(lb, id); - BLI_addtail(lbn, id); - break; - } - mainvar = mainvar->next; + if (((unsigned int)id->lib->temp_index < lib_main_array_len) && + /* this check should never fail, just incase 'id->lib' is a dangling pointer. */ + (lib_main_array[id->lib->temp_index]->curlib == id->lib)) + { + Main *mainvar = lib_main_array[id->lib->temp_index]; + ListBase *lb_dst = which_libbase(mainvar, GS(id->name)); + BLI_remlink(lb_src, id); + BLI_addtail(lb_dst, id); + } + else { + printf("%s: invalid library for '%s'\n", __func__, id->name); + BLI_assert(0); } - if (mainvar == NULL) printf("error split_libdata\n"); } - id = idnext; } } void blo_split_main(ListBase *mainlist, Main *main) { - ListBase *lbarray[MAX_LIBARRAY]; - Library *lib; - int i; - mainlist->first = mainlist->last = main; main->next = NULL; if (BLI_listbase_is_empty(&main->library)) return; - for (lib = main->library.first; lib; lib = lib->id.next) { + /* (Library.temp_index -> Main), lookup table */ + const unsigned int lib_main_array_len = BLI_listbase_count(&main->library); + Main **lib_main_array = MEM_mallocN(lib_main_array_len * sizeof(*lib_main_array), __func__); + + int i = 0; + for (Library *lib = main->library.first; lib; lib = lib->id.next, i++) { Main *libmain = BKE_main_new(); libmain->curlib = lib; BLI_addtail(mainlist, libmain); + lib->temp_index = i; + lib_main_array[i] = libmain; } + ListBase *lbarray[MAX_LIBARRAY]; i = set_listbasepointers(main, lbarray); - while (i--) - split_libdata(lbarray[i], main->next); + while (i--) { + split_libdata(lbarray[i], lib_main_array, lib_main_array_len); + } + + MEM_freeN(lib_main_array); } static void read_file_version(FileData *fd, Main *main) @@ -871,8 +880,6 @@ static void decode_blender_header(FileData *fd) if (readsize == sizeof(header)) { if (STREQLEN(header, "BLENDER", 7)) { - int remove_this_endian_test = 1; - fd->flags |= FD_FLAGS_FILE_OK; /* what size are pointers in the file ? */ @@ -891,7 +898,7 @@ static void decode_blender_header(FileData *fd) /* is the file saved in a different endian * than we need ? */ - if (((((char *)&remove_this_endian_test)[0] == 1) ? L_ENDIAN : B_ENDIAN) != ((header[8] == 'v') ? L_ENDIAN : B_ENDIAN)) { + if (((header[8] == 'v') ? L_ENDIAN : B_ENDIAN) != ENDIAN_ORDER) { fd->flags |= FD_FLAGS_SWITCH_ENDIAN; } @@ -1251,7 +1258,7 @@ void blo_freefiledata(FileData *fd) } if (fd->strm.next_in) { - if (inflateEnd (&fd->strm) != Z_OK) { + if (inflateEnd(&fd->strm) != Z_OK) { printf("close gzip stream error\n"); } } @@ -1317,6 +1324,7 @@ bool BLO_has_bfile_extension(const char *str) * * \param path the full path to explode. * \param r_dir the string that'll contain path up to blend file itself ('library' path). + * WARNING! Must be FILE_MAX_LIBEXTRA long (it also stores group and name strings)! * \param r_group the string that'll contain 'group' part of the path, if any. May be NULL. * \param r_name the string that'll contain data's name part of the path, if any. May be NULL. * \return true if path contains a blend file. @@ -1413,7 +1421,7 @@ BlendThumbnail *BLO_thumbnail_from_file(const char *filepath) /* ************** OLD POINTERS ******************* */ -static void *newdataadr(FileData *fd, void *adr) /* only direct databocks */ +static void *newdataadr(FileData *fd, const void *adr) /* only direct databocks */ { return oldnewmap_lookup_and_inc(fd->datamap, adr, true); } @@ -1430,7 +1438,7 @@ static void *newdataadr(FileData *fd, void *adr) /* only direct databocks */ * fcurve group pointer and keeps lasthit optimal for linking all further * fcurves. */ -static void *newdataadr_ex(FileData *fd, void *adr, bool increase_lasthit) /* only direct databocks */ +static void *newdataadr_ex(FileData *fd, const void *adr, bool increase_lasthit) /* only direct databocks */ { if (increase_lasthit) { return newdataadr(fd, adr); @@ -1443,38 +1451,38 @@ static void *newdataadr_ex(FileData *fd, void *adr, bool increase_lasthit) /* o } } -static void *newdataadr_no_us(FileData *fd, void *adr) /* only direct databocks */ +static void *newdataadr_no_us(FileData *fd, const void *adr) /* only direct databocks */ { return oldnewmap_lookup_and_inc(fd->datamap, adr, false); } -static void *newglobadr(FileData *fd, void *adr) /* direct datablocks with global linking */ +static void *newglobadr(FileData *fd, const void *adr) /* direct datablocks with global linking */ { return oldnewmap_lookup_and_inc(fd->globmap, adr, true); } -static void *newimaadr(FileData *fd, void *adr) /* used to restore image data after undo */ +static void *newimaadr(FileData *fd, const void *adr) /* used to restore image data after undo */ { if (fd->imamap && adr) return oldnewmap_lookup_and_inc(fd->imamap, adr, true); return NULL; } -static void *newmclipadr(FileData *fd, void *adr) /* used to restore movie clip data after undo */ +static void *newmclipadr(FileData *fd, const void *adr) /* used to restore movie clip data after undo */ { if (fd->movieclipmap && adr) return oldnewmap_lookup_and_inc(fd->movieclipmap, adr, true); return NULL; } -static void *newsoundadr(FileData *fd, void *adr) /* used to restore sound data after undo */ +static void *newsoundadr(FileData *fd, const void *adr) /* used to restore sound data after undo */ { if (fd->soundmap && adr) return oldnewmap_lookup_and_inc(fd->soundmap, adr, true); return NULL; } -static void *newpackedadr(FileData *fd, void *adr) /* used to restore packed data after undo */ +static void *newpackedadr(FileData *fd, const void *adr) /* used to restore packed data after undo */ { if (fd->packedmap && adr) return oldnewmap_lookup_and_inc(fd->packedmap, adr, true); @@ -1483,17 +1491,17 @@ static void *newpackedadr(FileData *fd, void *adr) /* used to restore packe } -static void *newlibadr(FileData *fd, void *lib, void *adr) /* only lib data */ +static void *newlibadr(FileData *fd, const void *lib, const void *adr) /* only lib data */ { return oldnewmap_liblookup(fd->libmap, adr, lib); } -void *blo_do_versions_newlibadr(FileData *fd, void *lib, void *adr) /* only lib data */ +void *blo_do_versions_newlibadr(FileData *fd, const void *lib, const void *adr) /* only lib data */ { return newlibadr(fd, lib, adr); } -static void *newlibadr_us(FileData *fd, void *lib, void *adr) /* increases user number */ +static void *newlibadr_us(FileData *fd, const void *lib, const void *adr) /* increases user number */ { ID *id = newlibadr(fd, lib, adr); @@ -1502,15 +1510,27 @@ static void *newlibadr_us(FileData *fd, void *lib, void *adr) /* increases user return id; } -void *blo_do_versions_newlibadr_us(FileData *fd, void *lib, void *adr) /* increases user number */ +void *blo_do_versions_newlibadr_us(FileData *fd, const void *lib, const void *adr) /* increases user number */ { return newlibadr_us(fd, lib, adr); } -static void change_idid_adr_fd(FileData *fd, void *old, void *new) +static void *newlibadr_real_us(FileData *fd, const void *lib, const void *adr) /* ensures real user */ +{ + ID *id = newlibadr(fd, lib, adr); + + id_us_ensure_real(id); + + return id; +} + +static void change_idid_adr_fd(FileData *fd, const void *old, void *new) { int i; + /* use a binary search if we have a sorted libmap, for now it's not needed. */ + BLI_assert(fd->libmap->sorted == false); + for (i = 0; i < fd->libmap->nentries; i++) { OldNew *entry = &fd->libmap->entries[i]; @@ -2165,9 +2185,10 @@ static void lib_link_brush(FileData *fd, Main *main) if (brush->id.tag & LIB_TAG_NEED_LINK) { brush->id.tag &= ~LIB_TAG_NEED_LINK; + /* brush->(mask_)mtex.obj is ignored on purpose? */ brush->mtex.tex = newlibadr_us(fd, brush->id.lib, brush->mtex.tex); brush->mask_mtex.tex = newlibadr_us(fd, brush->id.lib, brush->mask_mtex.tex); - brush->clone.image = newlibadr_us(fd, brush->id.lib, brush->clone.image); + brush->clone.image = newlibadr(fd, brush->id.lib, brush->clone.image); brush->toggle_brush = newlibadr(fd, brush->id.lib, brush->toggle_brush); brush->paint_curve = newlibadr_us(fd, brush->id.lib, brush->paint_curve); } @@ -3798,7 +3819,7 @@ static void lib_link_texture(FileData *fd, Main *main) lib_link_animdata(fd, &tex->id, tex->adt); tex->ima = newlibadr_us(fd, tex->id.lib, tex->ima); - tex->ipo = newlibadr_us(fd, tex->id.lib, tex->ipo); + tex->ipo = newlibadr_us(fd, tex->id.lib, tex->ipo); // XXX deprecated - old animation system if (tex->env) tex->env->object = newlibadr(fd, tex->id.lib, tex->env->object); if (tex->pd) @@ -3882,7 +3903,7 @@ static void lib_link_material(FileData *fd, Main *main) * of library blocks that implement this.*/ IDP_LibLinkProperty(ma->id.properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd); - ma->ipo = newlibadr_us(fd, ma->id.lib, ma->ipo); + ma->ipo = newlibadr_us(fd, ma->id.lib, ma->ipo); // XXX deprecated - old animation system ma->group = newlibadr_us(fd, ma->id.lib, ma->group); for (a = 0; a < MAX_MTEX; a++) { @@ -3951,7 +3972,7 @@ static void direct_link_pointcache_cb(FileData *fd, void *data) /* the cache saves non-struct data without DNA */ if (pm->data[i] && ptcache_data_struct[i][0]=='\0' && (fd->flags & FD_FLAGS_SWITCH_ENDIAN)) { - int tot = (BKE_ptcache_data_size (i) * pm->totpoint) / sizeof(int); /* data_size returns bytes */ + int tot = (BKE_ptcache_data_size(i) * pm->totpoint) / sizeof(int); /* data_size returns bytes */ int *poin = pm->data[i]; BLI_endian_switch_int32_array(poin, tot); @@ -4035,9 +4056,13 @@ static void lib_link_particlesettings(FileData *fd, Main *main) lib_link_partdeflect(fd, &part->id, part->pd); lib_link_partdeflect(fd, &part->id, part->pd2); - if (part->effector_weights) + if (part->effector_weights) { part->effector_weights->group = newlibadr(fd, part->id.lib, part->effector_weights->group); - + } + else { + part->effector_weights = BKE_add_effector_weights(part->eff_group); + } + if (part->dupliweights.first && part->dup_group) { int index_ok = 0; /* check for old files without indices (all indexes 0) */ @@ -4285,8 +4310,7 @@ static void lib_link_mtface(FileData *fd, Mesh *me, MTFace *mtface, int totface) * little bogus; it would be better if each mesh consistently added one ref * to each image it used. - z0r */ for (i = 0; i < totface; i++, tf++) { - tf->tpage= newlibadr(fd, me->id.lib, tf->tpage); - id_us_ensure_real(&tf->tpage->id); + tf->tpage = newlibadr_real_us(fd, me->id.lib, tf->tpage); } } @@ -4314,8 +4338,7 @@ static void lib_link_customdata_mtpoly(FileData *fd, Mesh *me, CustomData *pdata int j; for (j = 0; j < totface; j++, tf++) { - tf->tpage = newlibadr(fd, me->id.lib, tf->tpage); - id_us_ensure_real((ID *)tf->tpage); + tf->tpage = newlibadr_real_us(fd, me->id.lib, tf->tpage); } } } @@ -4865,7 +4888,7 @@ static void lib_link_object(FileData *fd, Main *main) FluidsimModifierData *fluidmd = (FluidsimModifierData *)modifiers_findByType(ob, eModifierType_Fluidsim); if (fluidmd && fluidmd->fss) - fluidmd->fss->ipo = newlibadr_us(fd, ob->id.lib, fluidmd->fss->ipo); + fluidmd->fss->ipo = newlibadr_us(fd, ob->id.lib, fluidmd->fss->ipo); // XXX deprecated - old animation system } { @@ -4904,6 +4927,7 @@ static void lib_link_object(FileData *fd, Main *main) { ob->probe = newlibadr(fd, ob->id.lib, ob->probe); ob->parallaxcorrect = newlibadr(fd, ob->id.lib, ob->parallaxcorrect); + ob->reflectionplane = newlibadr(fd, ob->id.lib, ob->reflectionplane); BLI_listbase_clear(&ob->gpuprobe); } } @@ -5610,7 +5634,6 @@ static void lib_link_scene(FileData *fd, Main *main) for (base = sce->base.first; base; base = next) { next = base->next; - /* base->object= newlibadr_us(fd, sce->id.lib, base->object); */ base->object = newlibadr_us(fd, sce->id.lib, base->object); if (base->object == NULL) { @@ -5624,7 +5647,7 @@ static void lib_link_scene(FileData *fd, Main *main) SEQ_BEGIN (sce->ed, seq) { - if (seq->ipo) seq->ipo = newlibadr_us(fd, sce->id.lib, seq->ipo); + if (seq->ipo) seq->ipo = newlibadr_us(fd, sce->id.lib, seq->ipo); // XXX deprecated - old animation system seq->scene_sound = NULL; if (seq->scene) { seq->scene = newlibadr(fd, sce->id.lib, seq->scene); @@ -6264,8 +6287,8 @@ static void lib_link_screen(FileData *fd, Main *main) else if (sl->spacetype == SPACE_IMAGE) { SpaceImage *sima = (SpaceImage *)sl; - sima->image = newlibadr_us(fd, sc->id.lib, sima->image); - sima->mask_info.mask = newlibadr_us(fd, sc->id.lib, sima->mask_info.mask); + sima->image = newlibadr_real_us(fd, sc->id.lib, sima->image); + sima->mask_info.mask = newlibadr_real_us(fd, sc->id.lib, sima->mask_info.mask); /* NOTE: pre-2.5, this was local data not lib data, but now we need this as lib data * so fingers crossed this works fine! @@ -6371,8 +6394,8 @@ static void lib_link_screen(FileData *fd, Main *main) else if (sl->spacetype == SPACE_CLIP) { SpaceClip *sclip = (SpaceClip *)sl; - sclip->clip = newlibadr_us(fd, sc->id.lib, sclip->clip); - sclip->mask_info.mask = newlibadr_us(fd, sc->id.lib, sclip->mask_info.mask); + sclip->clip = newlibadr_real_us(fd, sc->id.lib, sclip->clip); + sclip->mask_info.mask = newlibadr_real_us(fd, sc->id.lib, sclip->mask_info.mask); } else if (sl->spacetype == SPACE_LOGIC) { SpaceLogic *slogic = (SpaceLogic *)sl; @@ -6392,68 +6415,96 @@ typedef enum ePointerUserMode { USER_REAL = 1, /* ensure at least one real user (fake user ignored) */ } ePointerUserMode; -static bool restore_pointer(ID *id, ID *newid, ePointerUserMode user) +static void restore_pointer_user(ID *id, ID *newid, ePointerUserMode user) { - if (STREQ(newid->name + 2, id->name + 2)) { - if (newid->lib == id->lib) { - if (user == USER_REAL) { - id_us_ensure_real(newid); + BLI_assert(STREQ(newid->name + 2, id->name + 2)); + BLI_assert(newid->lib == id->lib); + UNUSED_VARS_NDEBUG(id); + + if (user == USER_REAL) { + id_us_ensure_real(newid); + } +} + +#ifndef USE_GHASH_RESTORE_POINTER +/** + * A version of #restore_pointer_by_name that performs a full search (slow!). + * Use only for limited lookups, when the overhead of + * creating a #IDNameLib_Map for a single lookup isn't worthwhile. + */ +static void *restore_pointer_by_name_main(Main *mainp, ID *id, ePointerUserMode user) +{ + if (id) { + ListBase *lb = which_libbase(mainp, GS(id->name)); + if (lb) { /* there's still risk of checking corrupt mem (freed Ids in oops) */ + ID *idn = lb->first; + for (; idn; idn = idn->next) { + if (STREQ(idn->name + 2, id->name + 2)) { + if (idn->lib == id->lib) { + restore_pointer_user(id, idn, user); + break; + } + } } - return true; + return idn; } } - return false; + return NULL; } +#endif /** * Only for undo files, or to restore a screen after reading without UI... * - * user + * \param user: * - USER_IGNORE: no usercount change * - USER_REAL: ensure a real user (even if a fake one is set) + * \param id_map: lookup table, use when performing many lookups. + * this could be made an optional argument (falling back to a full lookup), + * however at the moment it's always available. */ -static void *restore_pointer_by_name(Main *mainp, ID *id, ePointerUserMode user) +static void *restore_pointer_by_name(struct IDNameLib_Map *id_map, ID *id, ePointerUserMode user) { +#ifdef USE_GHASH_RESTORE_POINTER if (id) { - ListBase *lb = which_libbase(mainp, GS(id->name)); - if (lb) { // there's still risk of checking corrupt mem (freed Ids in oops) - ID *idn = lb->first; - - for (; idn; idn = idn->next) { - if (restore_pointer(id, idn, user)) - break; - } - - return idn; + /* use fast lookup when available */ + ID *idn = BKE_main_idmap_lookup_id(id_map, id); + if (idn) { + restore_pointer_user(id, idn, user); } + return idn; } return NULL; +#else + Main *mainp = BKE_main_idmap_main_get(id_map); + return restore_pointer_by_name_main(mainp, id, user); +#endif } -static void lib_link_seq_clipboard_pt_restore(ID *id, Main *newmain) +static void lib_link_seq_clipboard_pt_restore(ID *id, struct IDNameLib_Map *id_map) { if (id) { /* clipboard must ensure this */ BLI_assert(id->newid != NULL); - id->newid = restore_pointer_by_name(newmain, (ID *)id->newid, USER_REAL); + id->newid = restore_pointer_by_name(id_map, id->newid, USER_REAL); } } static int lib_link_seq_clipboard_cb(Sequence *seq, void *arg_pt) { - Main *newmain = (Main *)arg_pt; + struct IDNameLib_Map *id_map = arg_pt; - lib_link_seq_clipboard_pt_restore((ID *)seq->scene, newmain); - lib_link_seq_clipboard_pt_restore((ID *)seq->scene_camera, newmain); - lib_link_seq_clipboard_pt_restore((ID *)seq->clip, newmain); - lib_link_seq_clipboard_pt_restore((ID *)seq->mask, newmain); - lib_link_seq_clipboard_pt_restore((ID *)seq->sound, newmain); + lib_link_seq_clipboard_pt_restore((ID *)seq->scene, id_map); + lib_link_seq_clipboard_pt_restore((ID *)seq->scene_camera, id_map); + lib_link_seq_clipboard_pt_restore((ID *)seq->clip, id_map); + lib_link_seq_clipboard_pt_restore((ID *)seq->mask, id_map); + lib_link_seq_clipboard_pt_restore((ID *)seq->sound, id_map); return 1; } -static void lib_link_clipboard_restore(Main *newmain) +static void lib_link_clipboard_restore(struct IDNameLib_Map *id_map) { /* update IDs stored in sequencer clipboard */ - BKE_sequencer_base_recursive_apply(&seqbase_clipboard, lib_link_seq_clipboard_cb, newmain); + BKE_sequencer_base_recursive_apply(&seqbase_clipboard, lib_link_seq_clipboard_cb, id_map); } /* called from kernel/blender.c */ @@ -6465,11 +6516,13 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc wmWindowManager *wm; bScreen *sc; ScrArea *sa; - + + struct IDNameLib_Map *id_map = BKE_main_idmap_create(newmain); + /* first windowmanager */ for (wm = newmain->wm.first; wm; wm = wm->id.next) { for (win= wm->windows.first; win; win= win->next) { - win->screen = restore_pointer_by_name(newmain, (ID *)win->screen, USER_REAL); + win->screen = restore_pointer_by_name(id_map, (ID *)win->screen, USER_REAL); if (win->screen == NULL) win->screen = curscreen; @@ -6482,7 +6535,7 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc for (sc = newmain->screen.first; sc; sc = sc->id.next) { Scene *oldscene = sc->scene; - sc->scene= restore_pointer_by_name(newmain, (ID *)sc->scene, USER_REAL); + sc->scene= restore_pointer_by_name(id_map, (ID *)sc->scene, USER_REAL); if (sc->scene == NULL) sc->scene = curscene; @@ -6501,16 +6554,16 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc if (v3d->scenelock) v3d->camera = NULL; /* always get from scene */ else - v3d->camera = restore_pointer_by_name(newmain, (ID *)v3d->camera, USER_REAL); + v3d->camera = restore_pointer_by_name(id_map, (ID *)v3d->camera, USER_REAL); if (v3d->camera == NULL) v3d->camera = sc->scene->camera; - v3d->ob_centre = restore_pointer_by_name(newmain, (ID *)v3d->ob_centre, USER_REAL); + v3d->ob_centre = restore_pointer_by_name(id_map, (ID *)v3d->ob_centre, USER_REAL); for (bgpic= v3d->bgpicbase.first; bgpic; bgpic= bgpic->next) { - if ((bgpic->ima = restore_pointer_by_name(newmain, (ID *)bgpic->ima, USER_IGNORE))) { + if ((bgpic->ima = restore_pointer_by_name(id_map, (ID *)bgpic->ima, USER_IGNORE))) { id_us_plus((ID *)bgpic->ima); } - if ((bgpic->clip = restore_pointer_by_name(newmain, (ID *)bgpic->clip, USER_IGNORE))) { + if ((bgpic->clip = restore_pointer_by_name(id_map, (ID *)bgpic->clip, USER_IGNORE))) { id_us_plus((ID *)bgpic->clip); } } @@ -6554,10 +6607,10 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc bDopeSheet *ads = sipo->ads; if (ads) { - ads->source = restore_pointer_by_name(newmain, (ID *)ads->source, USER_REAL); + ads->source = restore_pointer_by_name(id_map, (ID *)ads->source, USER_REAL); if (ads->filter_grp) - ads->filter_grp = restore_pointer_by_name(newmain, (ID *)ads->filter_grp, USER_IGNORE); + ads->filter_grp = restore_pointer_by_name(id_map, (ID *)ads->filter_grp, USER_IGNORE); } /* force recalc of list of channels (i.e. includes calculating F-Curve colors) @@ -6567,7 +6620,7 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc } else if (sl->spacetype == SPACE_BUTS) { SpaceButs *sbuts = (SpaceButs *)sl; - sbuts->pinid = restore_pointer_by_name(newmain, sbuts->pinid, USER_IGNORE); + sbuts->pinid = restore_pointer_by_name(id_map, sbuts->pinid, USER_IGNORE); if (sbuts->pinid == NULL) { sbuts->flag &= ~SB_PIN_CONTEXT; } @@ -6584,11 +6637,11 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc else if (sl->spacetype == SPACE_ACTION) { SpaceAction *saction = (SpaceAction *)sl; - saction->action = restore_pointer_by_name(newmain, (ID *)saction->action, USER_REAL); - saction->ads.source = restore_pointer_by_name(newmain, (ID *)saction->ads.source, USER_REAL); + saction->action = restore_pointer_by_name(id_map, (ID *)saction->action, USER_REAL); + saction->ads.source = restore_pointer_by_name(id_map, (ID *)saction->ads.source, USER_REAL); if (saction->ads.filter_grp) - saction->ads.filter_grp = restore_pointer_by_name(newmain, (ID *)saction->ads.filter_grp, USER_IGNORE); + saction->ads.filter_grp = restore_pointer_by_name(id_map, (ID *)saction->ads.filter_grp, USER_IGNORE); /* force recalc of list of channels, potentially updating the active action @@ -6599,7 +6652,7 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc else if (sl->spacetype == SPACE_IMAGE) { SpaceImage *sima = (SpaceImage *)sl; - sima->image = restore_pointer_by_name(newmain, (ID *)sima->image, USER_REAL); + sima->image = restore_pointer_by_name(id_map, (ID *)sima->image, USER_REAL); /* this will be freed, not worth attempting to find same scene, * since it gets initialized later */ @@ -6614,8 +6667,8 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc /* NOTE: pre-2.5, this was local data not lib data, but now we need this as lib data * so assume that here we're doing for undo only... */ - sima->gpd = restore_pointer_by_name(newmain, (ID *)sima->gpd, USER_REAL); - sima->mask_info.mask = restore_pointer_by_name(newmain, (ID *)sima->mask_info.mask, USER_REAL); + sima->gpd = restore_pointer_by_name(id_map, (ID *)sima->gpd, USER_REAL); + sima->mask_info.mask = restore_pointer_by_name(id_map, (ID *)sima->mask_info.mask, USER_REAL); } else if (sl->spacetype == SPACE_SEQ) { SpaceSeq *sseq = (SpaceSeq *)sl; @@ -6623,29 +6676,29 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc /* NOTE: pre-2.5, this was local data not lib data, but now we need this as lib data * so assume that here we're doing for undo only... */ - sseq->gpd = restore_pointer_by_name(newmain, (ID *)sseq->gpd, USER_REAL); + sseq->gpd = restore_pointer_by_name(id_map, (ID *)sseq->gpd, USER_REAL); } else if (sl->spacetype == SPACE_NLA) { SpaceNla *snla = (SpaceNla *)sl; bDopeSheet *ads = snla->ads; if (ads) { - ads->source = restore_pointer_by_name(newmain, (ID *)ads->source, USER_REAL); + ads->source = restore_pointer_by_name(id_map, (ID *)ads->source, USER_REAL); if (ads->filter_grp) - ads->filter_grp = restore_pointer_by_name(newmain, (ID *)ads->filter_grp, USER_IGNORE); + ads->filter_grp = restore_pointer_by_name(id_map, (ID *)ads->filter_grp, USER_IGNORE); } } else if (sl->spacetype == SPACE_TEXT) { SpaceText *st = (SpaceText *)sl; - st->text = restore_pointer_by_name(newmain, (ID *)st->text, USER_REAL); + st->text = restore_pointer_by_name(id_map, (ID *)st->text, USER_REAL); if (st->text == NULL) st->text = newmain->text.first; } else if (sl->spacetype == SPACE_SCRIPT) { SpaceScript *scpt = (SpaceScript *)sl; - scpt->script = restore_pointer_by_name(newmain, (ID *)scpt->script, USER_REAL); + scpt->script = restore_pointer_by_name(id_map, (ID *)scpt->script, USER_REAL); /*sc->script = NULL; - 2.45 set to null, better re-run the script */ if (scpt->script) { @@ -6655,7 +6708,7 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc else if (sl->spacetype == SPACE_OUTLINER) { SpaceOops *so= (SpaceOops *)sl; - so->search_tse.id = restore_pointer_by_name(newmain, so->search_tse.id, USER_IGNORE); + so->search_tse.id = restore_pointer_by_name(id_map, so->search_tse.id, USER_IGNORE); if (so->treestore) { TreeStoreElem *tselem; @@ -6665,7 +6718,7 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc while ((tselem = BLI_mempool_iterstep(&iter))) { /* Do not try to restore pointers to drivers/sequence/etc., can crash in undo case! */ if (TSE_IS_REAL_ID(tselem)) { - tselem->id = restore_pointer_by_name(newmain, tselem->id, USER_IGNORE); + tselem->id = restore_pointer_by_name(id_map, tselem->id, USER_IGNORE); } else { tselem->id = NULL; @@ -6683,14 +6736,14 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc bNodeTree *ntree; /* node tree can be stored locally in id too, link this first */ - snode->id = restore_pointer_by_name(newmain, snode->id, USER_REAL); - snode->from = restore_pointer_by_name(newmain, snode->from, USER_IGNORE); + snode->id = restore_pointer_by_name(id_map, snode->id, USER_REAL); + snode->from = restore_pointer_by_name(id_map, snode->from, USER_IGNORE); ntree = nodetree_from_id(snode->id); if (ntree) snode->nodetree = ntree; else - snode->nodetree = restore_pointer_by_name(newmain, (ID*)snode->nodetree, USER_REAL); + snode->nodetree = restore_pointer_by_name(id_map, (ID*)snode->nodetree, USER_REAL); for (path = snode->treepath.first; path; path = path->next) { if (path == snode->treepath.first) { @@ -6698,7 +6751,7 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc path->nodetree = snode->nodetree; } else - path->nodetree= restore_pointer_by_name(newmain, (ID*)path->nodetree, USER_REAL); + path->nodetree= restore_pointer_by_name(id_map, (ID*)path->nodetree, USER_REAL); if (!path->nodetree) break; @@ -6724,22 +6777,24 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc else if (sl->spacetype == SPACE_CLIP) { SpaceClip *sclip = (SpaceClip *)sl; - sclip->clip = restore_pointer_by_name(newmain, (ID *)sclip->clip, USER_REAL); - sclip->mask_info.mask = restore_pointer_by_name(newmain, (ID *)sclip->mask_info.mask, USER_REAL); + sclip->clip = restore_pointer_by_name(id_map, (ID *)sclip->clip, USER_REAL); + sclip->mask_info.mask = restore_pointer_by_name(id_map, (ID *)sclip->mask_info.mask, USER_REAL); sclip->scopes.ok = 0; } else if (sl->spacetype == SPACE_LOGIC) { SpaceLogic *slogic = (SpaceLogic *)sl; - slogic->gpd = restore_pointer_by_name(newmain, (ID *)slogic->gpd, USER_REAL); + slogic->gpd = restore_pointer_by_name(id_map, (ID *)slogic->gpd, USER_REAL); } } } } /* update IDs stored in all possible clipboards */ - lib_link_clipboard_restore(newmain); + lib_link_clipboard_restore(id_map); + + BKE_main_idmap_destroy(id_map); } static void direct_link_region(FileData *fd, ARegion *ar, int spacetype) @@ -7001,11 +7056,7 @@ static bool direct_link_screen(FileData *fd, bScreen *sc) } else if (sl->spacetype == SPACE_IMAGE) { SpaceImage *sima = (SpaceImage *)sl; - - sima->cumap = newdataadr(fd, sima->cumap); - if (sima->cumap) - direct_link_curvemapping(fd, sima->cumap); - + sima->iuser.scene = NULL; sima->iuser.ok = 1; sima->scopes.waveform_1 = NULL; @@ -7320,12 +7371,11 @@ static void lib_link_group(FileData *fd, Main *main) add_us = false; for (go = group->gobject.first; go; go = go->next) { - go->ob= newlibadr(fd, group->id.lib, go->ob); + go->ob = newlibadr_real_us(fd, group->id.lib, go->ob); if (go->ob) { go->ob->flag |= OB_FROMGROUP; /* if group has an object, it increments user... */ add_us = true; - id_us_ensure_real(&go->ob->id); } } if (add_us) { @@ -7897,7 +7947,7 @@ static BHead *read_data_into_oldnewmap(FileData *fd, BHead *bhead, const char *a return bhead; } -static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, int flag, ID **r_id) +static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, const short tag, ID **r_id) { /* this routine reads a libblock and its direct data. Use link functions to connect it all */ @@ -7909,21 +7959,27 @@ static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, int flag, ID /* In undo case, most libs and linked data should be kept as is from previous state (see BLO_read_from_memfile). * However, some needed by the snapshot being read may have been removed in previous one, and would go missing. * This leads e.g. to desappearing objects in some undo/redo case, see T34446. - * That means we have to carefully check whether current lib or libdata already exits in old main, if it does - * we merely copy it over into new main area, otherwise we have to do a full read of that bhead... */ + * That means we have to carefully check whether current lib or libdata already exits in old main, if it does + * we merely copy it over into new main area, otherwise we have to do a full read of that bhead... */ if (fd->memfile && ELEM(bhead->code, ID_LI, ID_ID)) { const char *idname = bhead_id_name(fd, bhead); - /* printf("Checking %s...\n", idname); */ +#ifdef PRINT_DEBUG + printf("Checking %s...\n", idname); +#endif if (bhead->code == ID_LI) { Main *libmain = fd->old_mainlist->first; /* Skip oldmain itself... */ for (libmain = libmain->next; libmain; libmain = libmain->next) { - /* printf("... against %s: ", libmain->curlib ? libmain->curlib->id.name : "<NULL>"); */ +#ifdef PRINT_DEBUG + printf("... against %s: ", libmain->curlib ? libmain->curlib->id.name : "<NULL>"); +#endif if (libmain->curlib && STREQ(idname, libmain->curlib->id.name)) { Main *oldmain = fd->old_mainlist->first; - /* printf("FOUND!\n"); */ +#ifdef PRINT_DEBUG + printf("FOUND!\n"); +#endif /* In case of a library, we need to re-add its main to fd->mainlist, because if we have later * a missing ID_ID, we need to get the correct lib it is linked to! * Order is crucial, we cannot bulk-add it in BLO_read_from_memfile() like it used to be... */ @@ -7937,13 +7993,19 @@ static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, int flag, ID } return blo_nextbhead(fd, bhead); } - /* printf("nothing...\n"); */ +#ifdef PRINT_DEBUG + printf("nothing...\n"); +#endif } } else { - /* printf("... in %s (%s): ", main->curlib ? main->curlib->id.name : "<NULL>", main->curlib ? main->curlib->name : "<NULL>"); */ +#ifdef PRINT_DEBUG + printf("... in %s (%s): ", main->curlib ? main->curlib->id.name : "<NULL>", main->curlib ? main->curlib->name : "<NULL>"); +#endif if ((id = BKE_libblock_find_name_ex(main, GS(idname), idname + 2))) { - /* printf("FOUND!\n"); */ +#ifdef PRINT_DEBUG + printf("FOUND!\n"); +#endif /* Even though we found our linked ID, there is no guarantee its address is still the same... */ if (id != bhead->old) { oldnewmap_insert(fd->libmap, bhead->old, id, GS(id->name)); @@ -7955,7 +8017,9 @@ static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, int flag, ID } return blo_nextbhead(fd, bhead); } - /* printf("nothing...\n"); */ +#ifdef PRINT_DEBUG + printf("nothing...\n"); +#endif } } @@ -7983,7 +8047,7 @@ static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, int flag, ID if (!id) return blo_nextbhead(fd, bhead); - id->tag = flag | LIB_TAG_NEED_LINK; + id->tag = tag | LIB_TAG_NEED_LINK; id->lib = main->curlib; id->us = ID_FAKE_USERS(id); id->icon_id = 0; @@ -8241,6 +8305,9 @@ static void do_versions(FileData *fd, Library *lib, Main *main) blo_do_versions_260(fd, lib, main); blo_do_versions_270(fd, lib, main); + main->versionfile = BLENDER_VERSION; + main->subversionfile = BLENDER_SUBVERSION; + /* WATCH IT!!!: pointers from libdata have not been converted yet here! */ /* WATCH IT 2!: Userdef struct init see do_versions_userdef() above! */ @@ -8469,7 +8536,7 @@ BlendFileData *blo_read_file_internal(FileData *fd, const char *filepath) struct BHeadSort { BHead *bhead; - void *old; + const void *old; }; static int verg_bheadsort(const void *v1, const void *v2) @@ -9275,6 +9342,7 @@ static void expand_object(FileData *fd, Main *mainvar, Object *ob) expand_doit(fd, mainvar, ob->probe); expand_doit(fd, mainvar, ob->parallaxcorrect); + expand_doit(fd, mainvar, ob->reflectionplane); } static void expand_scene(FileData *fd, Main *mainvar, Scene *sce) @@ -9664,16 +9732,16 @@ static void give_base_to_groups( } } -static ID *create_placeholder(Main *mainvar, const char *idname, const short flag) +static ID *create_placeholder(Main *mainvar, const short idcode, const char *idname, const short tag) { - const short idcode = GS(idname); ListBase *lb = which_libbase(mainvar, idcode); ID *ph_id = BKE_libblock_alloc_notest(idcode); - memcpy(ph_id->name, idname, sizeof(ph_id->name)); + *((short *)ph_id->name) = idcode; + BLI_strncpy(ph_id->name + 2, idname, sizeof(ph_id->name) - 2); BKE_libblock_init_empty(ph_id); ph_id->lib = mainvar->curlib; - ph_id->tag = flag | LIB_TAG_MISSING; + ph_id->tag = tag | LIB_TAG_MISSING; ph_id->us = ID_FAKE_USERS(ph_id); ph_id->icon_id = 0; @@ -9685,7 +9753,9 @@ static ID *create_placeholder(Main *mainvar, const char *idname, const short fla /* returns true if the item was found * but it may already have already been appended/linked */ -static ID *link_named_part(Main *mainl, FileData *fd, const short idcode, const char *name) +static ID *link_named_part( + Main *mainl, FileData *fd, const short idcode, const char *name, + const bool use_placeholders, const bool force_indirect) { BHead *bhead = find_bhead_from_code_name(fd, idcode, name); ID *id; @@ -9696,7 +9766,7 @@ static ID *link_named_part(Main *mainl, FileData *fd, const short idcode, const id = is_yet_read(fd, mainl, bhead); if (id == NULL) { /* not read yet */ - read_libblock(fd, mainl, bhead, LIB_TAG_TESTEXT, &id); + read_libblock(fd, mainl, bhead, force_indirect ? LIB_TAG_TESTIND : LIB_TAG_TESTEXT, &id); if (id) { /* sort by name in list */ @@ -9709,18 +9779,22 @@ static ID *link_named_part(Main *mainl, FileData *fd, const short idcode, const if (G.debug) printf("append: already linked\n"); oldnewmap_insert(fd->libmap, bhead->old, id, bhead->code); - if (id->tag & LIB_TAG_INDIRECT) { + if (!force_indirect && (id->tag & LIB_TAG_INDIRECT)) { id->tag &= ~LIB_TAG_INDIRECT; id->tag |= LIB_TAG_EXTERN; } } } + else if (use_placeholders) { + /* XXX flag part is weak! */ + id = create_placeholder(mainl, idcode, name, force_indirect ? LIB_TAG_INDIRECT : LIB_TAG_EXTERN); + } else { id = NULL; } /* if we found the id but the id is NULL, this is really bad */ - BLI_assert((bhead != NULL) == (id != NULL)); + BLI_assert(!((bhead != NULL) && (id == NULL))); return id; } @@ -9792,9 +9866,9 @@ void BLO_library_link_copypaste(Main *mainl, BlendHandle *bh) static ID *link_named_part_ex( Main *mainl, FileData *fd, const short idcode, const char *name, const short flag, - Scene *scene, View3D *v3d) + Scene *scene, View3D *v3d, const bool use_placeholders, const bool force_indirect) { - ID *id = link_named_part(mainl, fd, idcode, name); + ID *id = link_named_part(mainl, fd, idcode, name, use_placeholders, force_indirect); if (id && (GS(id->name) == ID_OB)) { /* loose object: give a base */ link_object_postprocess(id, scene, v3d, flag); @@ -9820,7 +9894,7 @@ static ID *link_named_part_ex( ID *BLO_library_link_named_part(Main *mainl, BlendHandle **bh, const short idcode, const char *name) { FileData *fd = (FileData*)(*bh); - return link_named_part(mainl, fd, idcode, name); + return link_named_part(mainl, fd, idcode, name, false, false); } /** @@ -9834,15 +9908,18 @@ ID *BLO_library_link_named_part(Main *mainl, BlendHandle **bh, const short idcod * \param flag Options for linking, used for instantiating. * \param scene The scene in which to instantiate objects/groups (if NULL, no instantiation is done). * \param v3d The active View3D (only to define active layers for instantiated objects & groups, can be NULL). + * \param use_placeholders If true, generate a placeholder (empty ID) if not found in current lib file. + * \param force_indirect If true, force loaded ID to be tagged as LIB_TAG_INDIRECT (used in reload context only). * \return the linked ID when found. */ ID *BLO_library_link_named_part_ex( Main *mainl, BlendHandle **bh, const short idcode, const char *name, const short flag, - Scene *scene, View3D *v3d) + Scene *scene, View3D *v3d, + const bool use_placeholders, const bool force_indirect) { FileData *fd = (FileData*)(*bh); - return link_named_part_ex(mainl, fd, idcode, name, flag, scene, v3d); + return link_named_part_ex(mainl, fd, idcode, name, flag, scene, v3d, use_placeholders, force_indirect); } static void link_id_part(ReportList *reports, FileData *fd, Main *mainvar, ID *id, ID **r_id) @@ -9882,7 +9959,7 @@ static void link_id_part(ReportList *reports, FileData *fd, Main *mainvar, ID *i /* Generate a placeholder for this ID (simplified version of read_libblock actually...). */ if (r_id) { - *r_id = is_valid ? create_placeholder(mainvar, id->name, id->tag) : NULL; + *r_id = is_valid ? create_placeholder(mainvar, GS(id->name), id->name + 2, id->tag) : NULL; } } } @@ -10012,21 +10089,22 @@ void *BLO_library_read_struct(FileData *fd, BHead *bh, const char *blockname) /* ************* READ LIBRARY ************** */ -static int mainvar_count_libread_blocks(Main *mainvar) +static int mainvar_id_tag_any_check(Main *mainvar, const short tag) { ListBase *lbarray[MAX_LIBARRAY]; - int a, tot = 0; + int a; a = set_listbasepointers(mainvar, lbarray); while (a--) { ID *id; for (id = lbarray[a]->first; id; id = id->next) { - if (id->tag & LIB_TAG_READ) - tot++; + if (id->tag & tag) { + return true; + } } } - return tot; + return false; } static void read_libraries(FileData *basefd, ListBase *mainlist) @@ -10046,10 +10124,9 @@ static void read_libraries(FileData *basefd, ListBase *mainlist) /* test 1: read libdata */ mainptr= mainl->next; while (mainptr) { - int tot = mainvar_count_libread_blocks(mainptr); - - // printf("found LIB_TAG_READ %s\n", mainptr->curlib->name); - if (tot) { + if (mainvar_id_tag_any_check(mainptr, LIB_TAG_READ)) { + // printf("found LIB_TAG_READ %s\n", mainptr->curlib->name); + FileData *fd = mainptr->curlib->filedata; if (fd == NULL) { diff --git a/source/blender/blenloader/intern/readfile.h b/source/blender/blenloader/intern/readfile.h index f5c19f5ee22..42728fd406f 100644 --- a/source/blender/blenloader/intern/readfile.h +++ b/source/blender/blenloader/intern/readfile.h @@ -156,9 +156,9 @@ const char *bhead_id_name(const FileData *fd, const BHead *bhead); void blo_reportf_wrap(struct ReportList *reports, ReportType type, const char *format, ...) ATTR_PRINTF_FORMAT(3, 4); -void blo_do_versions_oldnewmap_insert(struct OldNewMap *onm, void *oldaddr, void *newaddr, int nr); -void *blo_do_versions_newlibadr(struct FileData *fd, void *lib, void *adr); -void *blo_do_versions_newlibadr_us(struct FileData *fd, void *lib, void *adr); +void blo_do_versions_oldnewmap_insert(struct OldNewMap *onm, const void *oldaddr, void *newaddr, int nr); +void *blo_do_versions_newlibadr(struct FileData *fd, const void *lib, const void *adr); +void *blo_do_versions_newlibadr_us(struct FileData *fd, const void *lib, const void *adr); struct PartEff *blo_do_version_give_parteff_245(struct Object *ob); void blo_do_version_old_trackto_to_constraints(struct Object *ob); diff --git a/source/blender/blenloader/intern/versioning_270.c b/source/blender/blenloader/intern/versioning_270.c index d81cd6a6c60..2a6c88f4922 100644 --- a/source/blender/blenloader/intern/versioning_270.c +++ b/source/blender/blenloader/intern/versioning_270.c @@ -1212,9 +1212,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) } } } - } - { for (Camera *camera = main->camera.first; camera != NULL; camera = camera->id.next) { if (camera->stereo.pole_merge_angle_from == 0.0f && camera->stereo.pole_merge_angle_to == 0.0f) @@ -1223,5 +1221,19 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) camera->stereo.pole_merge_angle_to = DEG2RAD(75.0f); } } + + if (!DNA_struct_elem_find(fd->filesdna, "NormalEditModifierData", "float", "mix_limit")) { + Object *ob; + + for (ob = main->object.first; ob; ob = ob->id.next) { + ModifierData *md; + for (md = ob->modifiers.first; md; md = md->next) { + if (md->type == eModifierType_NormalEdit) { + NormalEditModifierData *nemd = (NormalEditModifierData *)md; + nemd->mix_limit = DEG2RADF(180.0f); + } + } + } + } } } diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index d3c418dd72c..bc91ea8779a 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -29,15 +29,22 @@ */ -/* - * FILEFORMAT: IFF-style structure (but not IFF compatible!) +/** + * + * FILE FORMAT + * =========== + * + * IFF-style structure (but not IFF compatible!) * * start file: + * <pre> * BLENDER_V100 12 bytes (versie 1.00) * V = big endian, v = little endian * _ = 4 byte pointer, - = 8 byte pointer + * </pre> * - * datablocks: also see struct BHead + * datablocks: (also see struct #BHead). + * <pre> * <bh.code> 4 chars * <bh.len> int, len data after BHead * <bh.old> void, old pointer @@ -46,29 +53,32 @@ * data * ... * ... + * </pre> * * Almost all data in Blender are structures. Each struct saved * gets a BHead header. With BHead the struct can be linked again * and compared with StructDNA . * + * * WRITE + * ===== * * Preferred writing order: (not really a must, but why would you do it random?) * Any case: direct data is ALWAYS after the lib block * * (Local file data) * - for each LibBlock - * - write LibBlock - * - write associated direct data + * - write LibBlock + * - write associated direct data * (External file data) * - per library - * - write library block - * - per LibBlock - * - write the ID of LibBlock - * - write TEST (128x128, blend file preview, optional) - * - write FileGlobal (some global vars) - * - write SDNA - * - write USER if filename is ~/X.XX/config/startup.blend + * - write library block + * - per LibBlock + * - write the ID of LibBlock + * - write #TEST (#RenderInfo struct. 128x128 blend file preview is optional). + * - write #GLOB (#FileGlobal struct) (some global vars). + * - write #DNA1 (#SDNA struct) + * - write #USER (#UserDef struct) if filename is ``~/X.XX/config/startup.blend``. */ @@ -163,7 +173,7 @@ #include "BKE_mesh.h" #ifdef USE_NODE_COMPAT_CUSTOMNODES -#include "NOD_socket.h" /* for sock->default_value data */ +#include "NOD_socket.h" /* for sock->default_value data */ #endif @@ -174,6 +184,9 @@ #include "readfile.h" +/* for SDNA_TYPE_FROM_STRUCT() macro */ +#include "dna_type_offsets.h" + #include <errno.h> /* ********* my write, buffered writing with minimum size chunks ************ */ @@ -294,8 +307,9 @@ typedef struct { unsigned char *buf; MemFile *compare, *current; - - int tot, count, error; + + int tot, count; + bool error; /* Wrap writing, so we can use zlib or * other compression types later, see: G_FILE_COMPRESS @@ -303,33 +317,32 @@ typedef struct { WriteWrap *ww; #ifdef USE_BMESH_SAVE_AS_COMPAT - char use_mesh_compat; /* option to save with older mesh format */ + bool use_mesh_compat; /* option to save with older mesh format */ #endif } WriteData; static WriteData *writedata_new(WriteWrap *ww) { - WriteData *wd= MEM_callocN(sizeof(*wd), "writedata"); - - /* XXX, see note about this in readfile.c, remove - * once we have an xp lock - zr - */ - - if (wd == NULL) return NULL; + WriteData *wd = MEM_callocN(sizeof(*wd), "writedata"); wd->sdna = DNA_sdna_from_data(DNAstr, DNAlen, false); wd->ww = ww; - wd->buf= MEM_mallocN(MYWRITE_BUFFER_SIZE, "wd->buf"); + wd->buf = MEM_mallocN(MYWRITE_BUFFER_SIZE, "wd->buf"); return wd; } static void writedata_do_write(WriteData *wd, const void *mem, int memlen) { - if ((wd == NULL) || wd->error || (mem == NULL) || memlen < 1) return; - if (wd->error) return; + if ((wd == NULL) || wd->error || (mem == NULL) || memlen < 1) { + return; + } + + if (UNLIKELY(wd->error)) { + return; + } /* memory based save */ if (wd->current) { @@ -337,7 +350,7 @@ static void writedata_do_write(WriteData *wd, const void *mem, int memlen) } else { if (wd->ww->write(wd->ww, mem, memlen) != memlen) { - wd->error = 1; + wd->error = true; } } } @@ -358,34 +371,36 @@ static void writedata_free(WriteData *wd) * \param len Length of new chunk of data * \warning Talks to other functions with global parameters */ - + #define MYWRITE_FLUSH NULL static void mywrite(WriteData *wd, const void *adr, int len) { - if (wd->error) return; + if (UNLIKELY(wd->error)) { + return; + } /* flush helps compression for undo-save */ - if (adr==MYWRITE_FLUSH) { + if (adr == MYWRITE_FLUSH) { if (wd->count) { writedata_do_write(wd, wd->buf, wd->count); - wd->count= 0; + wd->count = 0; } return; } - wd->tot+= len; - + wd->tot += len; + /* if we have a single big chunk, write existing data in * buffer and write out big chunk in smaller pieces */ - if (len>MYWRITE_MAX_CHUNK) { + if (len > MYWRITE_MAX_CHUNK) { if (wd->count) { writedata_do_write(wd, wd->buf, wd->count); - wd->count= 0; + wd->count = 0; } do { - int writelen= MIN2(len, MYWRITE_MAX_CHUNK); + int writelen = MIN2(len, MYWRITE_MAX_CHUNK); writedata_do_write(wd, adr, writelen); adr = (const char *)adr + writelen; len -= writelen; @@ -395,14 +410,14 @@ static void mywrite(WriteData *wd, const void *adr, int len) } /* if data would overflow buffer, write out the buffer */ - if (len+wd->count>MYWRITE_BUFFER_SIZE-1) { + if (len + wd->count > MYWRITE_BUFFER_SIZE - 1) { writedata_do_write(wd, wd->buf, wd->count); - wd->count= 0; + wd->count = 0; } /* append data at end of buffer */ memcpy(&wd->buf[wd->count], adr, len); - wd->count+= len; + wd->count += len; } /** @@ -414,15 +429,17 @@ static void mywrite(WriteData *wd, const void *adr, int len) */ static WriteData *bgnwrite(WriteWrap *ww, MemFile *compare, MemFile *current) { - WriteData *wd= writedata_new(ww); + WriteData *wd = writedata_new(ww); - if (wd == NULL) return NULL; + if (wd == NULL) { + return NULL; + } - wd->compare= compare; - wd->current= current; + wd->compare = compare; + wd->current = current; /* this inits comparing */ memfile_chunk_add(compare, NULL, NULL, 0); - + return wd; } @@ -432,16 +449,14 @@ static WriteData *bgnwrite(WriteWrap *ww, MemFile *compare, MemFile *current) * \return unknown global variable otherwise * \warning Talks to other functions with global parameters */ -static int endwrite(WriteData *wd) +static bool endwrite(WriteData *wd) { - int err; - if (wd->count) { writedata_do_write(wd, wd->buf, wd->count); - wd->count= 0; + wd->count = 0; } - - err= wd->error; + + const bool err = wd->error; writedata_free(wd); return err; @@ -449,51 +464,82 @@ static int endwrite(WriteData *wd) /* ********** WRITE FILE ****************** */ -static void writestruct_at_address(WriteData *wd, int filecode, const char *structname, int nr, void *adr, void *data) +static void writestruct_at_address_nr( + WriteData *wd, int filecode, const int struct_nr, int nr, + const void *adr, const void *data) { BHead bh; const short *sp; - if (adr==NULL || data==NULL || nr==0) return; + BLI_assert(struct_nr > 0 && struct_nr < SDNA_TYPE_MAX); - /* init BHead */ - bh.code= filecode; - bh.old= adr; - bh.nr= nr; - - bh.SDNAnr= DNA_struct_find_nr(wd->sdna, structname); - if (bh.SDNAnr== -1) { - printf("error: can't find SDNA code <%s>\n", structname); + if (adr == NULL || data == NULL || nr == 0) { return; } - sp= wd->sdna->structs[bh.SDNAnr]; - bh.len= nr*wd->sdna->typelens[sp[0]]; + /* init BHead */ + bh.code = filecode; + bh.old = adr; + bh.nr = nr; + + bh.SDNAnr = struct_nr; + sp = wd->sdna->structs[bh.SDNAnr]; - if (bh.len==0) return; + bh.len = nr * wd->sdna->typelens[sp[0]]; + + if (bh.len == 0) { + return; + } mywrite(wd, &bh, sizeof(BHead)); mywrite(wd, data, bh.len); } -static void writestruct(WriteData *wd, int filecode, const char *structname, int nr, void *adr) +static void writestruct_at_address_id( + WriteData *wd, int filecode, const char *structname, int nr, + const void *adr, const void *data) +{ + if (adr == NULL || data == NULL || nr == 0) { + return; + } + + const int SDNAnr = DNA_struct_find_nr(wd->sdna, structname); + if (UNLIKELY(SDNAnr == -1)) { + printf("error: can't find SDNA code <%s>\n", structname); + return; + } + + writestruct_at_address_nr(wd, filecode, SDNAnr, nr, adr, data); +} + +static void writestruct_nr( + WriteData *wd, int filecode, const int struct_nr, int nr, + const void *adr) { - writestruct_at_address(wd, filecode, structname, nr, adr, adr); + writestruct_at_address_nr(wd, filecode, struct_nr, nr, adr, adr); +} + +static void writestruct_id( + WriteData *wd, int filecode, const char *structname, int nr, + const void *adr) +{ + writestruct_at_address_id(wd, filecode, structname, nr, adr, adr); } static void writedata(WriteData *wd, int filecode, int len, const void *adr) /* do not use for structs */ { BHead bh; - if (adr==NULL) return; - if (len==0) return; + if (adr == NULL || len == 0) { + return; + } /* align to 4 (writes uninitialized bytes in some cases) */ len = (len + 3) & ~3; /* init BHead */ bh.code = filecode; - bh.old = (void *)adr; /* this is safe to cast from const */ + bh.old = adr; bh.nr = 1; bh.SDNAnr = 0; bh.len = len; @@ -503,68 +549,99 @@ static void writedata(WriteData *wd, int filecode, int len, const void *adr) /* } /* use this to force writing of lists in same order as reading (using link_list) */ -static void writelist(WriteData *wd, int filecode, const char *structname, ListBase *lb) +static void writelist_nr(WriteData *wd, int filecode, const int struct_nr, const ListBase *lb) { - Link *link = lb->first; - + const Link *link = lb->first; + while (link) { - writestruct(wd, filecode, structname, 1, link); + writestruct_nr(wd, filecode, struct_nr, 1, link); link = link->next; } } +#if 0 +static void writelist_id(WriteData *wd, int filecode, const char *structname, const ListBase *lb) +{ + const Link *link = lb->first; + if (link) { + + const int struct_nr = DNA_struct_find_nr(wd->sdna, structname); + if (struct_nr == -1) { + printf("error: can't find SDNA code <%s>\n", structname); + return; + } + + while (link) { + writestruct_nr(wd, filecode, struct_nr, 1, link); + link = link->next; + } + } +} +#endif + +#define writestruct_at_address(wd, filecode, struct_id, nr, adr, data) \ + writestruct_at_address_nr(wd, filecode, SDNA_TYPE_FROM_STRUCT(struct_id), nr, adr, data) + +#define writestruct(wd, filecode, struct_id, nr, adr) \ + writestruct_nr(wd, filecode, SDNA_TYPE_FROM_STRUCT(struct_id), nr, adr) + +#define writelist(wd, filecode, struct_id, lb) \ + writelist_nr(wd, filecode, SDNA_TYPE_FROM_STRUCT(struct_id), lb) + /* *************** writing some direct data structs used in more code parts **************** */ /*These functions are used by blender's .blend system for file saving/loading.*/ -void IDP_WriteProperty_OnlyData(IDProperty *prop, void *wd); -void IDP_WriteProperty(IDProperty *prop, void *wd); +void IDP_WriteProperty_OnlyData(const IDProperty *prop, void *wd); +void IDP_WriteProperty(const IDProperty *prop, void *wd); -static void IDP_WriteArray(IDProperty *prop, void *wd) +static void IDP_WriteArray(const IDProperty *prop, void *wd) { /*REMEMBER to set totalen to len in the linking code!!*/ if (prop->data.pointer) { writedata(wd, DATA, MEM_allocN_len(prop->data.pointer), prop->data.pointer); if (prop->subtype == IDP_GROUP) { - IDProperty **array= prop->data.pointer; + IDProperty **array = prop->data.pointer; int a; - for (a=0; a<prop->len; a++) + for (a = 0; a < prop->len; a++) { IDP_WriteProperty(array[a], wd); + } } } } -static void IDP_WriteIDPArray(IDProperty *prop, void *wd) +static void IDP_WriteIDPArray(const IDProperty *prop, void *wd) { /*REMEMBER to set totalen to len in the linking code!!*/ if (prop->data.pointer) { - IDProperty *array = prop->data.pointer; + const IDProperty *array = prop->data.pointer; int a; - writestruct(wd, DATA, "IDProperty", prop->len, array); + writestruct(wd, DATA, IDProperty, prop->len, array); - for (a=0; a<prop->len; a++) + for (a = 0; a < prop->len; a++) { IDP_WriteProperty_OnlyData(&array[a], wd); + } } } -static void IDP_WriteString(IDProperty *prop, void *wd) +static void IDP_WriteString(const IDProperty *prop, void *wd) { /*REMEMBER to set totalen to len in the linking code!!*/ writedata(wd, DATA, prop->len, prop->data.pointer); } -static void IDP_WriteGroup(IDProperty *prop, void *wd) +static void IDP_WriteGroup(const IDProperty *prop, void *wd) { IDProperty *loop; - for (loop=prop->data.group.first; loop; loop=loop->next) { + for (loop = prop->data.group.first; loop; loop = loop->next) { IDP_WriteProperty(loop, wd); } } /* Functions to read/write ID Properties */ -void IDP_WriteProperty_OnlyData(IDProperty *prop, void *wd) +void IDP_WriteProperty_OnlyData(const IDProperty *prop, void *wd) { switch (prop->type) { case IDP_GROUP: @@ -582,35 +659,38 @@ void IDP_WriteProperty_OnlyData(IDProperty *prop, void *wd) } } -void IDP_WriteProperty(IDProperty *prop, void *wd) +void IDP_WriteProperty(const IDProperty *prop, void *wd) { - writestruct(wd, DATA, "IDProperty", 1, prop); + writestruct(wd, DATA, IDProperty, 1, prop); IDP_WriteProperty_OnlyData(prop, wd); } -static void write_previews(WriteData *wd, PreviewImage *prv) +static void write_iddata(void *wd, const ID *id) +{ + /* ID_WM's id->properties are considered runtime only, and never written in .blend file. */ + if (id->properties && !ELEM(GS(id->name), ID_WM)) { + IDP_WriteProperty(id->properties, wd); + } +} + +static void write_previews(WriteData *wd, const PreviewImage *prv_orig) { /* Never write previews when doing memsave (i.e. undo/redo)! */ - if (prv && !wd->current) { - short w = prv->w[1]; - short h = prv->h[1]; - unsigned int *rect = prv->rect[1]; + if (prv_orig && !wd->current) { + PreviewImage prv = *prv_orig; /* don't write out large previews if not requested */ if (!(U.flag & USER_SAVE_PREVIEWS)) { - prv->w[1] = 0; - prv->h[1] = 0; - prv->rect[1] = NULL; + prv.w[1] = 0; + prv.h[1] = 0; + prv.rect[1] = NULL; } - writestruct(wd, DATA, "PreviewImage", 1, prv); - if (prv->rect[0]) writedata(wd, DATA, prv->w[0] * prv->h[0] * sizeof(unsigned int), prv->rect[0]); - if (prv->rect[1]) writedata(wd, DATA, prv->w[1] * prv->h[1] * sizeof(unsigned int), prv->rect[1]); - - /* restore preview, we still want to keep it in memory even if not saved to file */ - if (!(U.flag & USER_SAVE_PREVIEWS) ) { - prv->w[1] = w; - prv->h[1] = h; - prv->rect[1] = rect; + writestruct_at_address(wd, DATA, PreviewImage, 1, prv_orig, &prv); + if (prv.rect[0]) { + writedata(wd, DATA, prv.w[0] * prv.h[0] * sizeof(unsigned int), prv.rect[0]); + } + if (prv.rect[1]) { + writedata(wd, DATA, prv.w[1] * prv.h[1] * sizeof(unsigned int), prv.rect[1]); } } } @@ -618,45 +698,47 @@ static void write_previews(WriteData *wd, PreviewImage *prv) static void write_fmodifiers(WriteData *wd, ListBase *fmodifiers) { FModifier *fcm; - + /* Write all modifiers first (for faster reloading) */ - writelist(wd, DATA, "FModifier", fmodifiers); - + writelist(wd, DATA, FModifier, fmodifiers); + /* Modifiers */ - for (fcm= fmodifiers->first; fcm; fcm= fcm->next) { - const FModifierTypeInfo *fmi= fmodifier_get_typeinfo(fcm); - + for (fcm = fmodifiers->first; fcm; fcm = fcm->next) { + const FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm); + /* Write the specific data */ if (fmi && fcm->data) { /* firstly, just write the plain fmi->data struct */ - writestruct(wd, DATA, fmi->structName, 1, fcm->data); - + writestruct_id(wd, DATA, fmi->structName, 1, fcm->data); + /* do any modifier specific stuff */ switch (fcm->type) { case FMODIFIER_TYPE_GENERATOR: { - FMod_Generator *data= (FMod_Generator *)fcm->data; - + FMod_Generator *data = fcm->data; + /* write coefficients array */ - if (data->coefficients) - writedata(wd, DATA, sizeof(float)*(data->arraysize), data->coefficients); + if (data->coefficients) { + writedata(wd, DATA, sizeof(float) * (data->arraysize), data->coefficients); + } break; } case FMODIFIER_TYPE_ENVELOPE: { - FMod_Envelope *data= (FMod_Envelope *)fcm->data; - + FMod_Envelope *data = fcm->data; + /* write envelope data */ - if (data->data) - writestruct(wd, DATA, "FCM_EnvelopeData", data->totvert, data->data); + if (data->data) { + writestruct(wd, DATA, FCM_EnvelopeData, data->totvert, data->data); + } break; } case FMODIFIER_TYPE_PYTHON: { - FMod_Python *data = (FMod_Python *)fcm->data; - + FMod_Python *data = fcm->data; + /* Write ID Properties -- and copy this comment EXACTLY for easy finding * of library blocks that implement this.*/ IDP_WriteProperty(data->prop, wd); @@ -671,37 +753,41 @@ static void write_fmodifiers(WriteData *wd, ListBase *fmodifiers) static void write_fcurves(WriteData *wd, ListBase *fcurves) { FCurve *fcu; - - writelist(wd, DATA, "FCurve", fcurves); - for (fcu=fcurves->first; fcu; fcu=fcu->next) { + + writelist(wd, DATA, FCurve, fcurves); + for (fcu = fcurves->first; fcu; fcu = fcu->next) { /* curve data */ - if (fcu->bezt) - writestruct(wd, DATA, "BezTriple", fcu->totvert, fcu->bezt); - if (fcu->fpt) - writestruct(wd, DATA, "FPoint", fcu->totvert, fcu->fpt); - - if (fcu->rna_path) - writedata(wd, DATA, strlen(fcu->rna_path)+1, fcu->rna_path); - + if (fcu->bezt) { + writestruct(wd, DATA, BezTriple, fcu->totvert, fcu->bezt); + } + if (fcu->fpt) { + writestruct(wd, DATA, FPoint, fcu->totvert, fcu->fpt); + } + + if (fcu->rna_path) { + writedata(wd, DATA, strlen(fcu->rna_path) + 1, fcu->rna_path); + } + /* driver data */ if (fcu->driver) { - ChannelDriver *driver= fcu->driver; + ChannelDriver *driver = fcu->driver; DriverVar *dvar; - - writestruct(wd, DATA, "ChannelDriver", 1, driver); - + + writestruct(wd, DATA, ChannelDriver, 1, driver); + /* variables */ - writelist(wd, DATA, "DriverVar", &driver->variables); - for (dvar= driver->variables.first; dvar; dvar= dvar->next) { + writelist(wd, DATA, DriverVar, &driver->variables); + for (dvar = driver->variables.first; dvar; dvar = dvar->next) { DRIVER_TARGETS_USED_LOOPER(dvar) { - if (dtar->rna_path) - writedata(wd, DATA, strlen(dtar->rna_path)+1, dtar->rna_path); + if (dtar->rna_path) { + writedata(wd, DATA, strlen(dtar->rna_path) + 1, dtar->rna_path); + } } DRIVER_TARGETS_LOOPER_END } } - + /* write F-Modifiers */ write_fmodifiers(wd, &fcu->modifiers); } @@ -709,27 +795,27 @@ static void write_fcurves(WriteData *wd, ListBase *fcurves) static void write_actions(WriteData *wd, ListBase *idbase) { - bAction *act; + bAction *act; bActionGroup *grp; TimeMarker *marker; - - for (act=idbase->first; act; act= act->id.next) { - if (act->id.us>0 || wd->current) { - writestruct(wd, ID_AC, "bAction", 1, act); - if (act->id.properties) IDP_WriteProperty(act->id.properties, wd); - + + for (act = idbase->first; act; act = act->id.next) { + if (act->id.us > 0 || wd->current) { + writestruct(wd, ID_AC, bAction, 1, act); + write_iddata(wd, &act->id); + write_fcurves(wd, &act->curves); - - for (grp=act->groups.first; grp; grp=grp->next) { - writestruct(wd, DATA, "bActionGroup", 1, grp); + + for (grp = act->groups.first; grp; grp = grp->next) { + writestruct(wd, DATA, bActionGroup, 1, grp); } - - for (marker=act->markers.first; marker; marker=marker->next) { - writestruct(wd, DATA, "TimeMarker", 1, marker); + + for (marker = act->markers.first; marker; marker = marker->next) { + writestruct(wd, DATA, TimeMarker, 1, marker); } } } - + /* flush helps the compression for undo-save */ mywrite(wd, MYWRITE_FLUSH, 0); } @@ -738,18 +824,19 @@ static void write_keyingsets(WriteData *wd, ListBase *list) { KeyingSet *ks; KS_Path *ksp; - - for (ks= list->first; ks; ks= ks->next) { + + for (ks = list->first; ks; ks = ks->next) { /* KeyingSet */ - writestruct(wd, DATA, "KeyingSet", 1, ks); - + writestruct(wd, DATA, KeyingSet, 1, ks); + /* Paths */ - for (ksp= ks->paths.first; ksp; ksp= ksp->next) { + for (ksp = ks->paths.first; ksp; ksp = ksp->next) { /* Path */ - writestruct(wd, DATA, "KS_Path", 1, ksp); - - if (ksp->rna_path) - writedata(wd, DATA, strlen(ksp->rna_path)+1, ksp->rna_path); + writestruct(wd, DATA, KS_Path, 1, ksp); + + if (ksp->rna_path) { + writedata(wd, DATA, strlen(ksp->rna_path) + 1, ksp->rna_path); + } } } } @@ -757,13 +844,13 @@ static void write_keyingsets(WriteData *wd, ListBase *list) static void write_nlastrips(WriteData *wd, ListBase *strips) { NlaStrip *strip; - - writelist(wd, DATA, "NlaStrip", strips); - for (strip= strips->first; strip; strip= strip->next) { + + writelist(wd, DATA, NlaStrip, strips); + for (strip = strips->first; strip; strip = strip->next) { /* write the strip's F-Curves and modifiers */ write_fcurves(wd, &strip->fcurves); write_fmodifiers(wd, &strip->modifiers); - + /* write the strip's children */ write_nlastrips(wd, &strip->strips); } @@ -772,12 +859,12 @@ static void write_nlastrips(WriteData *wd, ListBase *strips) static void write_nladata(WriteData *wd, ListBase *nlabase) { NlaTrack *nlt; - + /* write all the tracks */ - for (nlt= nlabase->first; nlt; nlt= nlt->next) { + for (nlt = nlabase->first; nlt; nlt = nlt->next) { /* write the track first */ - writestruct(wd, DATA, "NlaTrack", 1, nlt); - + writestruct(wd, DATA, NlaTrack, 1, nlt); + /* write the track's strips */ write_nlastrips(wd, &nlt->strips); } @@ -786,38 +873,37 @@ static void write_nladata(WriteData *wd, ListBase *nlabase) static void write_animdata(WriteData *wd, AnimData *adt) { AnimOverride *aor; - + /* firstly, just write the AnimData block */ - writestruct(wd, DATA, "AnimData", 1, adt); - + writestruct(wd, DATA, AnimData, 1, adt); + /* write drivers */ write_fcurves(wd, &adt->drivers); - + /* write overrides */ // FIXME: are these needed? - for (aor= adt->overrides.first; aor; aor= aor->next) { + for (aor = adt->overrides.first; aor; aor = aor->next) { /* overrides consist of base data + rna_path */ - writestruct(wd, DATA, "AnimOverride", 1, aor); - writedata(wd, DATA, strlen(aor->rna_path)+1, aor->rna_path); + writestruct(wd, DATA, AnimOverride, 1, aor); + writedata(wd, DATA, strlen(aor->rna_path) + 1, aor->rna_path); } - + // TODO write the remaps (if they are needed) - + /* write NLA data */ write_nladata(wd, &adt->nla_tracks); } static void write_curvemapping_curves(WriteData *wd, CurveMapping *cumap) { - int a; - - for (a = 0; a < CM_TOT; a++) - writestruct(wd, DATA, "CurveMapPoint", cumap->cm[a].totpoint, cumap->cm[a].curve); + for (int a = 0; a < CM_TOT; a++) { + writestruct(wd, DATA, CurveMapPoint, cumap->cm[a].totpoint, cumap->cm[a].curve); + } } static void write_curvemapping(WriteData *wd, CurveMapping *cumap) { - writestruct(wd, DATA, "CurveMapping", 1, cumap); + writestruct(wd, DATA, CurveMapping, 1, cumap); write_curvemapping_curves(wd, cumap); } @@ -827,14 +913,14 @@ static void write_node_socket(WriteData *wd, bNodeTree *UNUSED(ntree), bNode *no #ifdef USE_NODE_COMPAT_CUSTOMNODES /* forward compatibility code, so older blenders still open */ sock->stack_type = 1; - + if (node->type == NODE_GROUP) { bNodeTree *ngroup = (bNodeTree *)node->id; if (ngroup) { /* for node groups: look up the deprecated groupsock pointer */ sock->groupsock = ntreeFindSocketInterface(ngroup, sock->in_out, sock->identifier); BLI_assert(sock->groupsock != NULL); - + /* node group sockets now use the generic identifier string to verify group nodes, * old blender uses the own_index. */ @@ -844,20 +930,22 @@ static void write_node_socket(WriteData *wd, bNodeTree *UNUSED(ntree), bNode *no #endif /* actual socket writing */ - writestruct(wd, DATA, "bNodeSocket", 1, sock); + writestruct(wd, DATA, bNodeSocket, 1, sock); - if (sock->prop) + if (sock->prop) { IDP_WriteProperty(sock->prop, wd); - - if (sock->default_value) + } + + if (sock->default_value) { writedata(wd, DATA, MEM_allocN_len(sock->default_value), sock->default_value); + } } static void write_node_socket_interface(WriteData *wd, bNodeTree *UNUSED(ntree), bNodeSocket *sock) { #ifdef USE_NODE_COMPAT_CUSTOMNODES /* forward compatibility code, so older blenders still open */ sock->stack_type = 1; - + /* Reconstruct the deprecated default_value structs in socket interface DNA. */ if (sock->default_value == NULL && sock->typeinfo) { node_socket_init_default_value(sock); @@ -865,13 +953,15 @@ static void write_node_socket_interface(WriteData *wd, bNodeTree *UNUSED(ntree), #endif /* actual socket writing */ - writestruct(wd, DATA, "bNodeSocket", 1, sock); + writestruct(wd, DATA, bNodeSocket, 1, sock); - if (sock->prop) + if (sock->prop) { IDP_WriteProperty(sock->prop, wd); - - if (sock->default_value) + } + + if (sock->default_value) { writedata(wd, DATA, MEM_allocN_len(sock->default_value), sock->default_value); + } } /* this is only direct data, tree itself should have been written */ static void write_nodetree(WriteData *wd, bNodeTree *ntree) @@ -879,64 +969,91 @@ static void write_nodetree(WriteData *wd, bNodeTree *ntree) bNode *node; bNodeSocket *sock; bNodeLink *link; - + /* for link_list() speed, we write per list */ - - if (ntree->adt) write_animdata(wd, ntree->adt); - + + if (ntree->adt) { + write_animdata(wd, ntree->adt); + } + for (node = ntree->nodes.first; node; node = node->next) { - writestruct(wd, DATA, "bNode", 1, node); + writestruct(wd, DATA, bNode, 1, node); - if (node->prop) + if (node->prop) { IDP_WriteProperty(node->prop, wd); + } - for (sock= node->inputs.first; sock; sock= sock->next) + for (sock = node->inputs.first; sock; sock = sock->next) { write_node_socket(wd, ntree, node, sock); - for (sock= node->outputs.first; sock; sock= sock->next) + } + for (sock = node->outputs.first; sock; sock = sock->next) { write_node_socket(wd, ntree, node, sock); - - for (link = node->internal_links.first; link; link = link->next) - writestruct(wd, DATA, "bNodeLink", 1, link); + } + + for (link = node->internal_links.first; link; link = link->next) { + writestruct(wd, DATA, bNodeLink, 1, link); + } + if (node->storage) { /* could be handlerized at some point, now only 1 exception still */ - if (ntree->type==NTREE_SHADER && (node->type==SH_NODE_CURVE_VEC || node->type==SH_NODE_CURVE_RGB)) + if ((ntree->type == NTREE_SHADER) && + ELEM(node->type, SH_NODE_CURVE_VEC, SH_NODE_CURVE_RGB)) + { write_curvemapping(wd, node->storage); - else if (ntree->type==NTREE_SHADER && node->type==SH_NODE_SCRIPT) { + } + else if (ntree->type == NTREE_SHADER && + (node->type == SH_NODE_SCRIPT)) + { NodeShaderScript *nss = (NodeShaderScript *)node->storage; - if (nss->bytecode) - writedata(wd, DATA, strlen(nss->bytecode)+1, nss->bytecode); - writestruct(wd, DATA, node->typeinfo->storagename, 1, node->storage); + if (nss->bytecode) { + writedata(wd, DATA, strlen(nss->bytecode) + 1, nss->bytecode); + } + writestruct_id(wd, DATA, node->typeinfo->storagename, 1, node->storage); } - else if (ntree->type==NTREE_COMPOSIT && ELEM(node->type, CMP_NODE_TIME, CMP_NODE_CURVE_VEC, CMP_NODE_CURVE_RGB, CMP_NODE_HUECORRECT)) + else if ((ntree->type == NTREE_COMPOSIT) && + ELEM(node->type, CMP_NODE_TIME, CMP_NODE_CURVE_VEC, CMP_NODE_CURVE_RGB, CMP_NODE_HUECORRECT)) + { write_curvemapping(wd, node->storage); - else if (ntree->type==NTREE_TEXTURE && (node->type==TEX_NODE_CURVE_RGB || node->type==TEX_NODE_CURVE_TIME) ) + } + else if ((ntree->type == NTREE_TEXTURE) && + (node->type == TEX_NODE_CURVE_RGB || node->type == TEX_NODE_CURVE_TIME)) + { write_curvemapping(wd, node->storage); - else if (ntree->type==NTREE_COMPOSIT && node->type==CMP_NODE_MOVIEDISTORTION) { + } + else if ((ntree->type == NTREE_COMPOSIT) && + (node->type == CMP_NODE_MOVIEDISTORTION)) + { /* pass */ } - else - writestruct(wd, DATA, node->typeinfo->storagename, 1, node->storage); + else { + writestruct_id(wd, DATA, node->typeinfo->storagename, 1, node->storage); + } } - - if (node->type==CMP_NODE_OUTPUT_FILE) { + + if (node->type == CMP_NODE_OUTPUT_FILE) { /* inputs have own storage data */ - for (sock = node->inputs.first; sock; sock = sock->next) - writestruct(wd, DATA, "NodeImageMultiFileSocket", 1, sock->storage); + for (sock = node->inputs.first; sock; sock = sock->next) { + writestruct(wd, DATA, NodeImageMultiFileSocket, 1, sock->storage); + } } - if (node->type==CMP_NODE_IMAGE) { + if (node->type == CMP_NODE_IMAGE) { /* write extra socket info */ - for (sock = node->outputs.first; sock; sock = sock->next) - writestruct(wd, DATA, "NodeImageLayer", 1, sock->storage); + for (sock = node->outputs.first; sock; sock = sock->next) { + writestruct(wd, DATA, NodeImageLayer, 1, sock->storage); + } } } - - for (link= ntree->links.first; link; link= link->next) - writestruct(wd, DATA, "bNodeLink", 1, link); - - for (sock = ntree->inputs.first; sock; sock = sock->next) + + for (link = ntree->links.first; link; link = link->next) { + writestruct(wd, DATA, bNodeLink, 1, link); + } + + for (sock = ntree->inputs.first; sock; sock = sock->next) { write_node_socket_interface(wd, ntree, sock); - for (sock = ntree->outputs.first; sock; sock = sock->next) + } + for (sock = ntree->outputs.first; sock; sock = sock->next) { write_node_socket_interface(wd, ntree, sock); + } } /** @@ -991,9 +1108,11 @@ static void write_renderinfo(WriteData *wd, Main *mainvar) /* XXX in future, handle multiple windows with multiple screens? */ current_screen_compat(mainvar, &curscreen, false); - if (curscreen) curscene = curscreen->scene; - - for (sce= mainvar->scene.first; sce; sce= sce->id.next) { + if (curscreen) { + curscene = curscreen->scene; + } + + for (sce = mainvar->scene.first; sce; sce = sce->id.next) { if (sce->id.lib == NULL && (sce == curscene || (sce->r.scemode & R_BG_RENDER))) { data.sfra = sce->r.sfra; data.efra = sce->r.efra; @@ -1008,9 +1127,10 @@ static void write_renderinfo(WriteData *wd, Main *mainvar) static void write_keymapitem(WriteData *wd, wmKeyMapItem *kmi) { - writestruct(wd, DATA, "wmKeyMapItem", 1, kmi); - if (kmi->properties) + writestruct(wd, DATA, wmKeyMapItem, 1, kmi); + if (kmi->properties) { IDP_WriteProperty(kmi->properties, wd); + } } static void write_userdef(WriteData *wd) @@ -1022,75 +1142,82 @@ static void write_userdef(WriteData *wd) bAddon *bext; bPathCompare *path_cmp; uiStyle *style; - - writestruct(wd, USER, "UserDef", 1, &U); - for (btheme= U.themes.first; btheme; btheme=btheme->next) - writestruct(wd, DATA, "bTheme", 1, btheme); + writestruct(wd, USER, UserDef, 1, &U); + + for (btheme = U.themes.first; btheme; btheme = btheme->next) { + writestruct(wd, DATA, bTheme, 1, btheme); + } - for (keymap= U.user_keymaps.first; keymap; keymap=keymap->next) { - writestruct(wd, DATA, "wmKeyMap", 1, keymap); + for (keymap = U.user_keymaps.first; keymap; keymap = keymap->next) { + writestruct(wd, DATA, wmKeyMap, 1, keymap); - for (kmdi=keymap->diff_items.first; kmdi; kmdi=kmdi->next) { - writestruct(wd, DATA, "wmKeyMapDiffItem", 1, kmdi); - if (kmdi->remove_item) + for (kmdi = keymap->diff_items.first; kmdi; kmdi = kmdi->next) { + writestruct(wd, DATA, wmKeyMapDiffItem, 1, kmdi); + if (kmdi->remove_item) { write_keymapitem(wd, kmdi->remove_item); - if (kmdi->add_item) + } + if (kmdi->add_item) { write_keymapitem(wd, kmdi->add_item); + } } - for (kmi=keymap->items.first; kmi; kmi=kmi->next) + for (kmi = keymap->items.first; kmi; kmi = kmi->next) { write_keymapitem(wd, kmi); + } } - for (bext= U.addons.first; bext; bext=bext->next) { - writestruct(wd, DATA, "bAddon", 1, bext); + for (bext = U.addons.first; bext; bext = bext->next) { + writestruct(wd, DATA, bAddon, 1, bext); if (bext->prop) { IDP_WriteProperty(bext->prop, wd); } } for (path_cmp = U.autoexec_paths.first; path_cmp; path_cmp = path_cmp->next) { - writestruct(wd, DATA, "bPathCompare", 1, path_cmp); + writestruct(wd, DATA, bPathCompare, 1, path_cmp); } - - for (style= U.uistyles.first; style; style= style->next) { - writestruct(wd, DATA, "uiStyle", 1, style); + + for (style = U.uistyles.first; style; style = style->next) { + writestruct(wd, DATA, uiStyle, 1, style); } } static void write_boid_state(WriteData *wd, BoidState *state) { BoidRule *rule = state->rules.first; - //BoidCondition *cond = state->conditions.first; - writestruct(wd, DATA, "BoidState", 1, state); + writestruct(wd, DATA, BoidState, 1, state); - for (; rule; rule=rule->next) { + for (; rule; rule = rule->next) { switch (rule->type) { case eBoidRuleType_Goal: case eBoidRuleType_Avoid: - writestruct(wd, DATA, "BoidRuleGoalAvoid", 1, rule); + writestruct(wd, DATA, BoidRuleGoalAvoid, 1, rule); break; case eBoidRuleType_AvoidCollision: - writestruct(wd, DATA, "BoidRuleAvoidCollision", 1, rule); + writestruct(wd, DATA, BoidRuleAvoidCollision, 1, rule); break; case eBoidRuleType_FollowLeader: - writestruct(wd, DATA, "BoidRuleFollowLeader", 1, rule); + writestruct(wd, DATA, BoidRuleFollowLeader, 1, rule); break; case eBoidRuleType_AverageSpeed: - writestruct(wd, DATA, "BoidRuleAverageSpeed", 1, rule); + writestruct(wd, DATA, BoidRuleAverageSpeed, 1, rule); break; case eBoidRuleType_Fight: - writestruct(wd, DATA, "BoidRuleFight", 1, rule); + writestruct(wd, DATA, BoidRuleFight, 1, rule); break; default: - writestruct(wd, DATA, "BoidRule", 1, rule); + writestruct(wd, DATA, BoidRule, 1, rule); break; } } - //for (; cond; cond=cond->next) - // writestruct(wd, DATA, "BoidCondition", 1, cond); +#if 0 + BoidCondition *cond = state->conditions.first; + for (; cond; cond = cond->next) { + writestruct(wd, DATA, BoidCondition, 1, cond); + } +#endif } /* update this also to readfile.c */ @@ -1113,31 +1240,34 @@ static void write_pointcaches(WriteData *wd, ListBase *ptcaches) PointCache *cache = ptcaches->first; int i; - for (; cache; cache=cache->next) { - writestruct(wd, DATA, "PointCache", 1, cache); + for (; cache; cache = cache->next) { + writestruct(wd, DATA, PointCache, 1, cache); - if ((cache->flag & PTCACHE_DISK_CACHE)==0) { + if ((cache->flag & PTCACHE_DISK_CACHE) == 0) { PTCacheMem *pm = cache->mem_cache.first; - for (; pm; pm=pm->next) { + for (; pm; pm = pm->next) { PTCacheExtra *extra = pm->extradata.first; - writestruct(wd, DATA, "PTCacheMem", 1, pm); - - for (i=0; i<BPHYS_TOT_DATA; i++) { - if (pm->data[i] && pm->data_types & (1<<i)) { - if (ptcache_data_struct[i][0] == '\0') + writestruct(wd, DATA, PTCacheMem, 1, pm); + + for (i = 0; i < BPHYS_TOT_DATA; i++) { + if (pm->data[i] && pm->data_types & (1 << i)) { + if (ptcache_data_struct[i][0] == '\0') { writedata(wd, DATA, MEM_allocN_len(pm->data[i]), pm->data[i]); - else - writestruct(wd, DATA, ptcache_data_struct[i], pm->totpoint, pm->data[i]); + } + else { + writestruct_id(wd, DATA, ptcache_data_struct[i], pm->totpoint, pm->data[i]); + } } } - for (; extra; extra=extra->next) { - if (ptcache_extra_struct[extra->type][0] == '\0') + for (; extra; extra = extra->next) { + if (ptcache_extra_struct[extra->type][0] == '\0') { continue; - writestruct(wd, DATA, "PTCacheExtra", 1, extra); - writestruct(wd, DATA, ptcache_extra_struct[extra->type], extra->totdata, extra->data); + } + writestruct(wd, DATA, PTCacheExtra, 1, extra); + writestruct_id(wd, DATA, ptcache_extra_struct[extra->type], extra->totdata, extra->data); } } } @@ -1150,90 +1280,109 @@ static void write_particlesettings(WriteData *wd, ListBase *idbase) GroupObject *go; int a; - part= idbase->first; + part = idbase->first; while (part) { - if (part->id.us>0 || wd->current) { + if (part->id.us > 0 || wd->current) { /* write LibData */ - writestruct(wd, ID_PA, "ParticleSettings", 1, part); - if (part->id.properties) IDP_WriteProperty(part->id.properties, wd); - if (part->adt) write_animdata(wd, part->adt); - writestruct(wd, DATA, "PartDeflect", 1, part->pd); - writestruct(wd, DATA, "PartDeflect", 1, part->pd2); - writestruct(wd, DATA, "EffectorWeights", 1, part->effector_weights); - - if (part->clumpcurve) + writestruct(wd, ID_PA, ParticleSettings, 1, part); + write_iddata(wd, &part->id); + + if (part->adt) { + write_animdata(wd, part->adt); + } + writestruct(wd, DATA, PartDeflect, 1, part->pd); + writestruct(wd, DATA, PartDeflect, 1, part->pd2); + writestruct(wd, DATA, EffectorWeights, 1, part->effector_weights); + + if (part->clumpcurve) { write_curvemapping(wd, part->clumpcurve); - if (part->roughcurve) + } + if (part->roughcurve) { write_curvemapping(wd, part->roughcurve); - + } + dw = part->dupliweights.first; - for (; dw; dw=dw->next) { + for (; dw; dw = dw->next) { /* update indices */ dw->index = 0; if (part->dup_group) { /* can be NULL if lining fails or set to None */ go = part->dup_group->gobject.first; while (go && go->ob != dw->ob) { - go=go->next; + go = go->next; dw->index++; } } - writestruct(wd, DATA, "ParticleDupliWeight", 1, dw); + writestruct(wd, DATA, ParticleDupliWeight, 1, dw); } if (part->boids && part->phystype == PART_PHYS_BOIDS) { BoidState *state = part->boids->states.first; - writestruct(wd, DATA, "BoidSettings", 1, part->boids); + writestruct(wd, DATA, BoidSettings, 1, part->boids); - for (; state; state=state->next) + for (; state; state = state->next) { write_boid_state(wd, state); + } } if (part->fluid && part->phystype == PART_PHYS_FLUID) { - writestruct(wd, DATA, "SPHFluidSettings", 1, part->fluid); + writestruct(wd, DATA, SPHFluidSettings, 1, part->fluid); } - for (a=0; a<MAX_MTEX; a++) { - if (part->mtex[a]) writestruct(wd, DATA, "MTex", 1, part->mtex[a]); + for (a = 0; a < MAX_MTEX; a++) { + if (part->mtex[a]) { + writestruct(wd, DATA, MTex, 1, part->mtex[a]); + } } } - part= part->id.next; + part = part->id.next; } } static void write_particlesystems(WriteData *wd, ListBase *particles) { - ParticleSystem *psys= particles->first; + ParticleSystem *psys = particles->first; ParticleTarget *pt; int a; - for (; psys; psys=psys->next) { - writestruct(wd, DATA, "ParticleSystem", 1, psys); + for (; psys; psys = psys->next) { + writestruct(wd, DATA, ParticleSystem, 1, psys); if (psys->particles) { - writestruct(wd, DATA, "ParticleData", psys->totpart, psys->particles); + writestruct(wd, DATA, ParticleData, psys->totpart, psys->particles); if (psys->particles->hair) { ParticleData *pa = psys->particles; - for (a=0; a<psys->totpart; a++, pa++) - writestruct(wd, DATA, "HairKey", pa->totkey, pa->hair); + for (a = 0; a < psys->totpart; a++, pa++) { + writestruct(wd, DATA, HairKey, pa->totkey, pa->hair); + } } - if (psys->particles->boid && psys->part->phystype == PART_PHYS_BOIDS) - writestruct(wd, DATA, "BoidParticle", psys->totpart, psys->particles->boid); + if (psys->particles->boid && + (psys->part->phystype == PART_PHYS_BOIDS)) + { + writestruct(wd, DATA, BoidParticle, psys->totpart, psys->particles->boid); + } - if (psys->part->fluid && psys->part->phystype == PART_PHYS_FLUID && (psys->part->fluid->flag & SPH_VISCOELASTIC_SPRINGS)) - writestruct(wd, DATA, "ParticleSpring", psys->tot_fluidsprings, psys->fluid_springs); + if (psys->part->fluid && + (psys->part->phystype == PART_PHYS_FLUID) && + (psys->part->fluid->flag & SPH_VISCOELASTIC_SPRINGS)) + { + writestruct(wd, DATA, ParticleSpring, psys->tot_fluidsprings, psys->fluid_springs); + } } pt = psys->targets.first; - for (; pt; pt=pt->next) - writestruct(wd, DATA, "ParticleTarget", 1, pt); + for (; pt; pt = pt->next) { + writestruct(wd, DATA, ParticleTarget, 1, pt); + } - if (psys->child) writestruct(wd, DATA, "ChildParticle", psys->totchild, psys->child); + if (psys->child) { + writestruct(wd, DATA, ChildParticle, psys->totchild, psys->child); + } if (psys->clmd) { - writestruct(wd, DATA, "ClothModifierData", 1, psys->clmd); - writestruct(wd, DATA, "ClothSimSettings", 1, psys->clmd->sim_parms); - writestruct(wd, DATA, "ClothCollSettings", 1, psys->clmd->coll_parms); + writestruct(wd, DATA, ClothModifierData, 1, psys->clmd); + writestruct(wd, DATA, ClothSimSettings, 1, psys->clmd->sim_parms); + writestruct(wd, DATA, ClothCollSettings, 1, psys->clmd->coll_parms); } write_pointcaches(wd, &psys->ptcaches); @@ -1244,14 +1393,15 @@ static void write_properties(WriteData *wd, ListBase *lb) { bProperty *prop; - prop= lb->first; + prop = lb->first; while (prop) { - writestruct(wd, DATA, "bProperty", 1, prop); + writestruct(wd, DATA, bProperty, 1, prop); - if (prop->poin && prop->poin != &prop->data) + if (prop->poin && prop->poin != &prop->data) { writedata(wd, DATA, MEM_allocN_len(prop->poin), prop->poin); + } - prop= prop->next; + prop = prop->next; } } @@ -1259,57 +1409,57 @@ static void write_sensors(WriteData *wd, ListBase *lb) { bSensor *sens; - sens= lb->first; + sens = lb->first; while (sens) { - writestruct(wd, DATA, "bSensor", 1, sens); + writestruct(wd, DATA, bSensor, 1, sens); - writedata(wd, DATA, sizeof(void *)*sens->totlinks, sens->links); + writedata(wd, DATA, sizeof(void *) * sens->totlinks, sens->links); switch (sens->type) { - case SENS_NEAR: - writestruct(wd, DATA, "bNearSensor", 1, sens->data); - break; - case SENS_MOUSE: - writestruct(wd, DATA, "bMouseSensor", 1, sens->data); - break; - case SENS_KEYBOARD: - writestruct(wd, DATA, "bKeyboardSensor", 1, sens->data); - break; - case SENS_PROPERTY: - writestruct(wd, DATA, "bPropertySensor", 1, sens->data); - break; - case SENS_ARMATURE: - writestruct(wd, DATA, "bArmatureSensor", 1, sens->data); - break; - case SENS_ACTUATOR: - writestruct(wd, DATA, "bActuatorSensor", 1, sens->data); - break; - case SENS_DELAY: - writestruct(wd, DATA, "bDelaySensor", 1, sens->data); - break; - case SENS_COLLISION: - writestruct(wd, DATA, "bCollisionSensor", 1, sens->data); - break; - case SENS_RADAR: - writestruct(wd, DATA, "bRadarSensor", 1, sens->data); - break; - case SENS_RANDOM: - writestruct(wd, DATA, "bRandomSensor", 1, sens->data); - break; - case SENS_RAY: - writestruct(wd, DATA, "bRaySensor", 1, sens->data); - break; - case SENS_MESSAGE: - writestruct(wd, DATA, "bMessageSensor", 1, sens->data); - break; - case SENS_JOYSTICK: - writestruct(wd, DATA, "bJoystickSensor", 1, sens->data); - break; - default: - ; /* error: don't know how to write this file */ + case SENS_NEAR: + writestruct(wd, DATA, bNearSensor, 1, sens->data); + break; + case SENS_MOUSE: + writestruct(wd, DATA, bMouseSensor, 1, sens->data); + break; + case SENS_KEYBOARD: + writestruct(wd, DATA, bKeyboardSensor, 1, sens->data); + break; + case SENS_PROPERTY: + writestruct(wd, DATA, bPropertySensor, 1, sens->data); + break; + case SENS_ARMATURE: + writestruct(wd, DATA, bArmatureSensor, 1, sens->data); + break; + case SENS_ACTUATOR: + writestruct(wd, DATA, bActuatorSensor, 1, sens->data); + break; + case SENS_DELAY: + writestruct(wd, DATA, bDelaySensor, 1, sens->data); + break; + case SENS_COLLISION: + writestruct(wd, DATA, bCollisionSensor, 1, sens->data); + break; + case SENS_RADAR: + writestruct(wd, DATA, bRadarSensor, 1, sens->data); + break; + case SENS_RANDOM: + writestruct(wd, DATA, bRandomSensor, 1, sens->data); + break; + case SENS_RAY: + writestruct(wd, DATA, bRaySensor, 1, sens->data); + break; + case SENS_MESSAGE: + writestruct(wd, DATA, bMessageSensor, 1, sens->data); + break; + case SENS_JOYSTICK: + writestruct(wd, DATA, bJoystickSensor, 1, sens->data); + break; + default: + ; /* error: don't know how to write this file */ } - sens= sens->next; + sens = sens->next; } } @@ -1317,24 +1467,24 @@ static void write_controllers(WriteData *wd, ListBase *lb) { bController *cont; - cont= lb->first; + cont = lb->first; while (cont) { - writestruct(wd, DATA, "bController", 1, cont); + writestruct(wd, DATA, bController, 1, cont); - writedata(wd, DATA, sizeof(void *)*cont->totlinks, cont->links); + writedata(wd, DATA, sizeof(void *) * cont->totlinks, cont->links); switch (cont->type) { - case CONT_EXPRESSION: - writestruct(wd, DATA, "bExpressionCont", 1, cont->data); - break; - case CONT_PYTHON: - writestruct(wd, DATA, "bPythonCont", 1, cont->data); - break; - default: - ; /* error: don't know how to write this file */ + case CONT_EXPRESSION: + writestruct(wd, DATA, bExpressionCont, 1, cont->data); + break; + case CONT_PYTHON: + writestruct(wd, DATA, bPythonCont, 1, cont->data); + break; + default: + ; /* error: don't know how to write this file */ } - cont= cont->next; + cont = cont->next; } } @@ -1342,133 +1492,135 @@ static void write_actuators(WriteData *wd, ListBase *lb) { bActuator *act; - act= lb->first; + act = lb->first; while (act) { - writestruct(wd, DATA, "bActuator", 1, act); + writestruct(wd, DATA, bActuator, 1, act); switch (act->type) { - case ACT_ACTION: - case ACT_SHAPEACTION: - writestruct(wd, DATA, "bActionActuator", 1, act->data); - break; - case ACT_SOUND: - writestruct(wd, DATA, "bSoundActuator", 1, act->data); - break; - case ACT_OBJECT: - writestruct(wd, DATA, "bObjectActuator", 1, act->data); - break; - case ACT_PROPERTY: - writestruct(wd, DATA, "bPropertyActuator", 1, act->data); - break; - case ACT_CAMERA: - writestruct(wd, DATA, "bCameraActuator", 1, act->data); - break; - case ACT_CONSTRAINT: - writestruct(wd, DATA, "bConstraintActuator", 1, act->data); - break; - case ACT_EDIT_OBJECT: - writestruct(wd, DATA, "bEditObjectActuator", 1, act->data); - break; - case ACT_SCENE: - writestruct(wd, DATA, "bSceneActuator", 1, act->data); - break; - case ACT_GROUP: - writestruct(wd, DATA, "bGroupActuator", 1, act->data); - break; - case ACT_RANDOM: - writestruct(wd, DATA, "bRandomActuator", 1, act->data); - break; - case ACT_MESSAGE: - writestruct(wd, DATA, "bMessageActuator", 1, act->data); - break; - case ACT_GAME: - writestruct(wd, DATA, "bGameActuator", 1, act->data); - break; - case ACT_VISIBILITY: - writestruct(wd, DATA, "bVisibilityActuator", 1, act->data); - break; - case ACT_2DFILTER: - writestruct(wd, DATA, "bTwoDFilterActuator", 1, act->data); - break; - case ACT_PARENT: - writestruct(wd, DATA, "bParentActuator", 1, act->data); - break; - case ACT_STATE: - writestruct(wd, DATA, "bStateActuator", 1, act->data); - break; - case ACT_ARMATURE: - writestruct(wd, DATA, "bArmatureActuator", 1, act->data); - break; - case ACT_STEERING: - writestruct(wd, DATA, "bSteeringActuator", 1, act->data); - break; - case ACT_MOUSE: - writestruct(wd, DATA, "bMouseActuator", 1, act->data); - break; - default: - ; /* error: don't know how to write this file */ + case ACT_ACTION: + case ACT_SHAPEACTION: + writestruct(wd, DATA, bActionActuator, 1, act->data); + break; + case ACT_SOUND: + writestruct(wd, DATA, bSoundActuator, 1, act->data); + break; + case ACT_OBJECT: + writestruct(wd, DATA, bObjectActuator, 1, act->data); + break; + case ACT_PROPERTY: + writestruct(wd, DATA, bPropertyActuator, 1, act->data); + break; + case ACT_CAMERA: + writestruct(wd, DATA, bCameraActuator, 1, act->data); + break; + case ACT_CONSTRAINT: + writestruct(wd, DATA, bConstraintActuator, 1, act->data); + break; + case ACT_EDIT_OBJECT: + writestruct(wd, DATA, bEditObjectActuator, 1, act->data); + break; + case ACT_SCENE: + writestruct(wd, DATA, bSceneActuator, 1, act->data); + break; + case ACT_GROUP: + writestruct(wd, DATA, bGroupActuator, 1, act->data); + break; + case ACT_RANDOM: + writestruct(wd, DATA, bRandomActuator, 1, act->data); + break; + case ACT_MESSAGE: + writestruct(wd, DATA, bMessageActuator, 1, act->data); + break; + case ACT_GAME: + writestruct(wd, DATA, bGameActuator, 1, act->data); + break; + case ACT_VISIBILITY: + writestruct(wd, DATA, bVisibilityActuator, 1, act->data); + break; + case ACT_2DFILTER: + writestruct(wd, DATA, bTwoDFilterActuator, 1, act->data); + break; + case ACT_PARENT: + writestruct(wd, DATA, bParentActuator, 1, act->data); + break; + case ACT_STATE: + writestruct(wd, DATA, bStateActuator, 1, act->data); + break; + case ACT_ARMATURE: + writestruct(wd, DATA, bArmatureActuator, 1, act->data); + break; + case ACT_STEERING: + writestruct(wd, DATA, bSteeringActuator, 1, act->data); + break; + case ACT_MOUSE: + writestruct(wd, DATA, bMouseActuator, 1, act->data); + break; + default: + ; /* error: don't know how to write this file */ } - act= act->next; + act = act->next; } } static void write_motionpath(WriteData *wd, bMotionPath *mpath) { /* sanity checks */ - if (mpath == NULL) + if (mpath == NULL) { return; - + } + /* firstly, just write the motionpath struct */ - writestruct(wd, DATA, "bMotionPath", 1, mpath); - + writestruct(wd, DATA, bMotionPath, 1, mpath); + /* now write the array of data */ - writestruct(wd, DATA, "bMotionPathVert", mpath->length, mpath->points); + writestruct(wd, DATA, bMotionPathVert, mpath->length, mpath->points); } static void write_constraints(WriteData *wd, ListBase *conlist) { bConstraint *con; - for (con=conlist->first; con; con=con->next) { - const bConstraintTypeInfo *cti= BKE_constraint_typeinfo_get(con); - + for (con = conlist->first; con; con = con->next) { + const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); + /* Write the specific data */ if (cti && con->data) { /* firstly, just write the plain con->data struct */ - writestruct(wd, DATA, cti->structName, 1, con->data); - + writestruct_id(wd, DATA, cti->structName, 1, con->data); + /* do any constraint specific stuff */ switch (con->type) { case CONSTRAINT_TYPE_PYTHON: { - bPythonConstraint *data = (bPythonConstraint *)con->data; + bPythonConstraint *data = con->data; bConstraintTarget *ct; - + /* write targets */ - for (ct= data->targets.first; ct; ct= ct->next) - writestruct(wd, DATA, "bConstraintTarget", 1, ct); - + for (ct = data->targets.first; ct; ct = ct->next) { + writestruct(wd, DATA, bConstraintTarget, 1, ct); + } + /* Write ID Properties -- and copy this comment EXACTLY for easy finding * of library blocks that implement this.*/ IDP_WriteProperty(data->prop, wd); break; } - case CONSTRAINT_TYPE_SPLINEIK: + case CONSTRAINT_TYPE_SPLINEIK: { - bSplineIKConstraint *data = (bSplineIKConstraint *)con->data; - + bSplineIKConstraint *data = con->data; + /* write points array */ - writedata(wd, DATA, sizeof(float)*(data->numpoints), data->points); + writedata(wd, DATA, sizeof(float) * (data->numpoints), data->points); break; } } } - + /* Write the constraint */ - writestruct(wd, DATA, "bConstraint", 1, con); + writestruct(wd, DATA, bConstraint, 1, con); } } @@ -1478,176 +1630,191 @@ static void write_pose(WriteData *wd, bPose *pose) bActionGroup *grp; /* Write each channel */ - if (!pose) + if (pose == NULL) { return; + } /* Write channels */ - for (chan=pose->chanbase.first; chan; chan=chan->next) { + for (chan = pose->chanbase.first; chan; chan = chan->next) { /* Write ID Properties -- and copy this comment EXACTLY for easy finding * of library blocks that implement this.*/ - if (chan->prop) + if (chan->prop) { IDP_WriteProperty(chan->prop, wd); - + } + write_constraints(wd, &chan->constraints); - + write_motionpath(wd, chan->mpath); - - /* prevent crashes with autosave, when a bone duplicated in editmode has not yet been assigned to its posechannel */ - if (chan->bone) - chan->selectflag= chan->bone->flag & BONE_SELECTED; /* gets restored on read, for library armatures */ - - writestruct(wd, DATA, "bPoseChannel", 1, chan); - } - + + /* prevent crashes with autosave, + * when a bone duplicated in editmode has not yet been assigned to its posechannel */ + if (chan->bone) { + /* gets restored on read, for library armatures */ + chan->selectflag = chan->bone->flag & BONE_SELECTED; + } + + writestruct(wd, DATA, bPoseChannel, 1, chan); + } + /* Write groups */ - for (grp=pose->agroups.first; grp; grp=grp->next) - writestruct(wd, DATA, "bActionGroup", 1, grp); + for (grp = pose->agroups.first; grp; grp = grp->next) { + writestruct(wd, DATA, bActionGroup, 1, grp); + } /* write IK param */ if (pose->ikparam) { const char *structname = BKE_pose_ikparam_get_name(pose); - if (structname) - writestruct(wd, DATA, structname, 1, pose->ikparam); + if (structname) { + writestruct_id(wd, DATA, structname, 1, pose->ikparam); + } } /* Write this pose */ - writestruct(wd, DATA, "bPose", 1, pose); + writestruct(wd, DATA, bPose, 1, pose); } static void write_defgroups(WriteData *wd, ListBase *defbase) { - bDeformGroup *defgroup; - - for (defgroup=defbase->first; defgroup; defgroup=defgroup->next) - writestruct(wd, DATA, "bDeformGroup", 1, defgroup); + for (bDeformGroup *defgroup = defbase->first; defgroup; defgroup = defgroup->next) { + writestruct(wd, DATA, bDeformGroup, 1, defgroup); + } } static void write_modifiers(WriteData *wd, ListBase *modbase) { ModifierData *md; - if (modbase == NULL) return; - for (md=modbase->first; md; md= md->next) { + if (modbase == NULL) { + return; + } + + for (md = modbase->first; md; md = md->next) { const ModifierTypeInfo *mti = modifierType_getInfo(md->type); - if (mti == NULL) return; - - writestruct(wd, DATA, mti->structName, 1, md); - - if (md->type==eModifierType_Hook) { - HookModifierData *hmd = (HookModifierData*) md; - + if (mti == NULL) { + return; + } + + writestruct_id(wd, DATA, mti->structName, 1, md); + + if (md->type == eModifierType_Hook) { + HookModifierData *hmd = (HookModifierData *)md; + if (hmd->curfalloff) { write_curvemapping(wd, hmd->curfalloff); } - writedata(wd, DATA, sizeof(int)*hmd->totindex, hmd->indexar); + writedata(wd, DATA, sizeof(int) * hmd->totindex, hmd->indexar); } - else if (md->type==eModifierType_Cloth) { - ClothModifierData *clmd = (ClothModifierData*) md; - - writestruct(wd, DATA, "ClothSimSettings", 1, clmd->sim_parms); - writestruct(wd, DATA, "ClothCollSettings", 1, clmd->coll_parms); - writestruct(wd, DATA, "EffectorWeights", 1, clmd->sim_parms->effector_weights); + else if (md->type == eModifierType_Cloth) { + ClothModifierData *clmd = (ClothModifierData *)md; + + writestruct(wd, DATA, ClothSimSettings, 1, clmd->sim_parms); + writestruct(wd, DATA, ClothCollSettings, 1, clmd->coll_parms); + writestruct(wd, DATA, EffectorWeights, 1, clmd->sim_parms->effector_weights); write_pointcaches(wd, &clmd->ptcaches); } - else if (md->type==eModifierType_Smoke) { - SmokeModifierData *smd = (SmokeModifierData*) md; - + else if (md->type == eModifierType_Smoke) { + SmokeModifierData *smd = (SmokeModifierData *)md; + if (smd->type & MOD_SMOKE_TYPE_DOMAIN) { if (smd->domain) { write_pointcaches(wd, &(smd->domain->ptcaches[0])); /* create fake pointcache so that old blender versions can read it */ smd->domain->point_cache[1] = BKE_ptcache_add(&smd->domain->ptcaches[1]); - smd->domain->point_cache[1]->flag |= PTCACHE_DISK_CACHE|PTCACHE_FAKE_SMOKE; + smd->domain->point_cache[1]->flag |= PTCACHE_DISK_CACHE | PTCACHE_FAKE_SMOKE; smd->domain->point_cache[1]->step = 1; write_pointcaches(wd, &(smd->domain->ptcaches[1])); } - - writestruct(wd, DATA, "SmokeDomainSettings", 1, smd->domain); + + writestruct(wd, DATA, SmokeDomainSettings, 1, smd->domain); if (smd->domain) { /* cleanup the fake pointcache */ BKE_ptcache_free_list(&smd->domain->ptcaches[1]); smd->domain->point_cache[1] = NULL; - - writestruct(wd, DATA, "EffectorWeights", 1, smd->domain->effector_weights); + + writestruct(wd, DATA, EffectorWeights, 1, smd->domain->effector_weights); } } - else if (smd->type & MOD_SMOKE_TYPE_FLOW) - writestruct(wd, DATA, "SmokeFlowSettings", 1, smd->flow); - else if (smd->type & MOD_SMOKE_TYPE_COLL) - writestruct(wd, DATA, "SmokeCollSettings", 1, smd->coll); + else if (smd->type & MOD_SMOKE_TYPE_FLOW) { + writestruct(wd, DATA, SmokeFlowSettings, 1, smd->flow); + } + else if (smd->type & MOD_SMOKE_TYPE_COLL) { + writestruct(wd, DATA, SmokeCollSettings, 1, smd->coll); + } } - else if (md->type==eModifierType_Fluidsim) { - FluidsimModifierData *fluidmd = (FluidsimModifierData*) md; - - writestruct(wd, DATA, "FluidsimSettings", 1, fluidmd->fss); + else if (md->type == eModifierType_Fluidsim) { + FluidsimModifierData *fluidmd = (FluidsimModifierData *)md; + + writestruct(wd, DATA, FluidsimSettings, 1, fluidmd->fss); } - else if (md->type==eModifierType_DynamicPaint) { - DynamicPaintModifierData *pmd = (DynamicPaintModifierData*) md; - + else if (md->type == eModifierType_DynamicPaint) { + DynamicPaintModifierData *pmd = (DynamicPaintModifierData *)md; + if (pmd->canvas) { DynamicPaintSurface *surface; - writestruct(wd, DATA, "DynamicPaintCanvasSettings", 1, pmd->canvas); - + writestruct(wd, DATA, DynamicPaintCanvasSettings, 1, pmd->canvas); + /* write surfaces */ - for (surface=pmd->canvas->surfaces.first; surface; surface=surface->next) - writestruct(wd, DATA, "DynamicPaintSurface", 1, surface); + for (surface = pmd->canvas->surfaces.first; surface; surface = surface->next) { + writestruct(wd, DATA, DynamicPaintSurface, 1, surface); + } /* write caches and effector weights */ - for (surface=pmd->canvas->surfaces.first; surface; surface=surface->next) { + for (surface = pmd->canvas->surfaces.first; surface; surface = surface->next) { write_pointcaches(wd, &(surface->ptcaches)); - writestruct(wd, DATA, "EffectorWeights", 1, surface->effector_weights); + writestruct(wd, DATA, EffectorWeights, 1, surface->effector_weights); } } if (pmd->brush) { - writestruct(wd, DATA, "DynamicPaintBrushSettings", 1, pmd->brush); - writestruct(wd, DATA, "ColorBand", 1, pmd->brush->paint_ramp); - writestruct(wd, DATA, "ColorBand", 1, pmd->brush->vel_ramp); + writestruct(wd, DATA, DynamicPaintBrushSettings, 1, pmd->brush); + writestruct(wd, DATA, ColorBand, 1, pmd->brush->paint_ramp); + writestruct(wd, DATA, ColorBand, 1, pmd->brush->vel_ramp); } } - else if (md->type==eModifierType_Collision) { - + else if (md->type == eModifierType_Collision) { + #if 0 - CollisionModifierData *collmd = (CollisionModifierData*) md; - // TODO: CollisionModifier should use pointcache + CollisionModifierData *collmd = (CollisionModifierData *)md; + // TODO: CollisionModifier should use pointcache // + have proper reset events before enabling this - writestruct(wd, DATA, "MVert", collmd->numverts, collmd->x); - writestruct(wd, DATA, "MVert", collmd->numverts, collmd->xnew); - writestruct(wd, DATA, "MFace", collmd->numfaces, collmd->mfaces); + writestruct(wd, DATA, MVert, collmd->numverts, collmd->x); + writestruct(wd, DATA, MVert, collmd->numverts, collmd->xnew); + writestruct(wd, DATA, MFace, collmd->numfaces, collmd->mfaces); #endif } - else if (md->type==eModifierType_MeshDeform) { - MeshDeformModifierData *mmd = (MeshDeformModifierData*) md; + else if (md->type == eModifierType_MeshDeform) { + MeshDeformModifierData *mmd = (MeshDeformModifierData *)md; int size = mmd->dyngridsize; - writestruct(wd, DATA, "MDefInfluence", mmd->totinfluence, mmd->bindinfluences); + writestruct(wd, DATA, MDefInfluence, mmd->totinfluence, mmd->bindinfluences); writedata(wd, DATA, sizeof(int) * (mmd->totvert + 1), mmd->bindoffsets); writedata(wd, DATA, sizeof(float) * 3 * mmd->totcagevert, - mmd->bindcagecos); - writestruct(wd, DATA, "MDefCell", size*size*size, mmd->dyngrid); - writestruct(wd, DATA, "MDefInfluence", mmd->totinfluence, mmd->dyninfluences); - writedata(wd, DATA, sizeof(int)*mmd->totvert, mmd->dynverts); + mmd->bindcagecos); + writestruct(wd, DATA, MDefCell, size * size * size, mmd->dyngrid); + writestruct(wd, DATA, MDefInfluence, mmd->totinfluence, mmd->dyninfluences); + writedata(wd, DATA, sizeof(int) * mmd->totvert, mmd->dynverts); } - else if (md->type==eModifierType_Warp) { - WarpModifierData *tmd = (WarpModifierData*) md; + else if (md->type == eModifierType_Warp) { + WarpModifierData *tmd = (WarpModifierData *)md; if (tmd->curfalloff) { write_curvemapping(wd, tmd->curfalloff); } } - else if (md->type==eModifierType_WeightVGEdit) { - WeightVGEditModifierData *wmd = (WeightVGEditModifierData*) md; + else if (md->type == eModifierType_WeightVGEdit) { + WeightVGEditModifierData *wmd = (WeightVGEditModifierData *)md; - if (wmd->cmap_curve) + if (wmd->cmap_curve) { write_curvemapping(wd, wmd->cmap_curve); + } } - else if (md->type==eModifierType_LaplacianDeform) { - LaplacianDeformModifierData *lmd = (LaplacianDeformModifierData*) md; + else if (md->type == eModifierType_LaplacianDeform) { + LaplacianDeformModifierData *lmd = (LaplacianDeformModifierData *)md; - writedata(wd, DATA, sizeof(float)*lmd->total_verts * 3, lmd->vertexco); + writedata(wd, DATA, sizeof(float) * lmd->total_verts * 3, lmd->vertexco); } else if (md->type == eModifierType_CorrectiveSmooth) { CorrectiveSmoothModifierData *csmd = (CorrectiveSmoothModifierData *)md; @@ -1662,22 +1829,21 @@ static void write_modifiers(WriteData *wd, ListBase *modbase) static void write_objects(WriteData *wd, ListBase *idbase) { Object *ob; - - ob= idbase->first; + + ob = idbase->first; while (ob) { - if (ob->id.us>0 || wd->current) { + if (ob->id.us > 0 || wd->current) { /* write LibData */ - writestruct(wd, ID_OB, "Object", 1, ob); - - /* Write ID Properties -- and copy this comment EXACTLY for easy finding - * of library blocks that implement this.*/ - if (ob->id.properties) IDP_WriteProperty(ob->id.properties, wd); - - if (ob->adt) write_animdata(wd, ob->adt); - + writestruct(wd, ID_OB, Object, 1, ob); + write_iddata(wd, &ob->id); + + if (ob->adt) { + write_animdata(wd, ob->adt); + } + /* direct data */ - writedata(wd, DATA, sizeof(void *)*ob->totcol, ob->mat); - writedata(wd, DATA, sizeof(char)*ob->totcol, ob->matbits); + writedata(wd, DATA, sizeof(void *) * ob->totcol, ob->mat); + writedata(wd, DATA, sizeof(char) * ob->totcol, ob->matbits); /* write_effects(wd, &ob->effect); */ /* not used anymore */ write_properties(wd, &ob->prop); write_sensors(wd, &ob->sensors); @@ -1695,37 +1861,37 @@ static void write_objects(WriteData *wd, ListBase *idbase) write_defgroups(wd, &ob->defbase); write_constraints(wd, &ob->constraints); write_motionpath(wd, ob->mpath); - - writestruct(wd, DATA, "PartDeflect", 1, ob->pd); - writestruct(wd, DATA, "SoftBody", 1, ob->soft); + + writestruct(wd, DATA, PartDeflect, 1, ob->pd); + writestruct(wd, DATA, SoftBody, 1, ob->soft); if (ob->soft) { write_pointcaches(wd, &ob->soft->ptcaches); - writestruct(wd, DATA, "EffectorWeights", 1, ob->soft->effector_weights); + writestruct(wd, DATA, EffectorWeights, 1, ob->soft->effector_weights); } - writestruct(wd, DATA, "BulletSoftBody", 1, ob->bsoft); - + writestruct(wd, DATA, BulletSoftBody, 1, ob->bsoft); + if (ob->rigidbody_object) { - // TODO: if any extra data is added to handle duplis, will need separate function then - writestruct(wd, DATA, "RigidBodyOb", 1, ob->rigidbody_object); + /* TODO: if any extra data is added to handle duplis, will need separate function then */ + writestruct(wd, DATA, RigidBodyOb, 1, ob->rigidbody_object); } if (ob->rigidbody_constraint) { - writestruct(wd, DATA, "RigidBodyCon", 1, ob->rigidbody_constraint); + writestruct(wd, DATA, RigidBodyCon, 1, ob->rigidbody_constraint); } if (ob->type == OB_EMPTY && ob->empty_drawtype == OB_EMPTY_IMAGE) { - writestruct(wd, DATA, "ImageUser", 1, ob->iuser); + writestruct(wd, DATA, ImageUser, 1, ob->iuser); } write_particlesystems(wd, &ob->particlesystem); write_modifiers(wd, &ob->modifiers); - writelist(wd, DATA, "LinkData", &ob->pc_ids); - writelist(wd, DATA, "LodLevel", &ob->lodlevels); + writelist(wd, DATA, LinkData, &ob->pc_ids); + writelist(wd, DATA, LodLevel, &ob->lodlevels); } write_previews(wd, ob->preview); - ob= ob->id.next; + ob = ob->id.next; } /* flush helps the compression for undo-save */ @@ -1736,25 +1902,25 @@ static void write_objects(WriteData *wd, ListBase *idbase) static void write_vfonts(WriteData *wd, ListBase *idbase) { VFont *vf; - PackedFile * pf; + PackedFile *pf; - vf= idbase->first; + vf = idbase->first; while (vf) { - if (vf->id.us>0 || wd->current) { + if (vf->id.us > 0 || wd->current) { /* write LibData */ - writestruct(wd, ID_VF, "VFont", 1, vf); - if (vf->id.properties) IDP_WriteProperty(vf->id.properties, wd); + writestruct(wd, ID_VF, VFont, 1, vf); + write_iddata(wd, &vf->id); /* direct data */ if (vf->packedfile) { pf = vf->packedfile; - writestruct(wd, DATA, "PackedFile", 1, pf); + writestruct(wd, DATA, PackedFile, 1, pf); writedata(wd, DATA, pf->size, pf->data); } } - vf= vf->id.next; + vf = vf->id.next; } } @@ -1764,25 +1930,29 @@ static void write_keys(WriteData *wd, ListBase *idbase) Key *key; KeyBlock *kb; - key= idbase->first; + key = idbase->first; while (key) { - if (key->id.us>0 || wd->current) { + if (key->id.us > 0 || wd->current) { /* write LibData */ - writestruct(wd, ID_KE, "Key", 1, key); - if (key->id.properties) IDP_WriteProperty(key->id.properties, wd); - - if (key->adt) write_animdata(wd, key->adt); - + writestruct(wd, ID_KE, Key, 1, key); + write_iddata(wd, &key->id); + + if (key->adt) { + write_animdata(wd, key->adt); + } + /* direct data */ - kb= key->block.first; + kb = key->block.first; while (kb) { - writestruct(wd, DATA, "KeyBlock", 1, kb); - if (kb->data) writedata(wd, DATA, kb->totelem*key->elemsize, kb->data); - kb= kb->next; + writestruct(wd, DATA, KeyBlock, 1, kb); + if (kb->data) { + writedata(wd, DATA, kb->totelem * key->elemsize, kb->data); + } + kb = kb->next; } } - key= key->id.next; + key = key->id.next; } /* flush helps the compression for undo-save */ mywrite(wd, MYWRITE_FLUSH, 0); @@ -1792,17 +1962,19 @@ static void write_cameras(WriteData *wd, ListBase *idbase) { Camera *cam; - cam= idbase->first; + cam = idbase->first; while (cam) { - if (cam->id.us>0 || wd->current) { + if (cam->id.us > 0 || wd->current) { /* write LibData */ - writestruct(wd, ID_CA, "Camera", 1, cam); - if (cam->id.properties) IDP_WriteProperty(cam->id.properties, wd); - - if (cam->adt) write_animdata(wd, cam->adt); + writestruct(wd, ID_CA, Camera, 1, cam); + write_iddata(wd, &cam->id); + + if (cam->adt) { + write_animdata(wd, cam->adt); + } } - cam= cam->id.next; + cam = cam->id.next; } } @@ -1811,24 +1983,26 @@ static void write_mballs(WriteData *wd, ListBase *idbase) MetaBall *mb; MetaElem *ml; - mb= idbase->first; + mb = idbase->first; while (mb) { - if (mb->id.us>0 || wd->current) { + if (mb->id.us > 0 || wd->current) { /* write LibData */ - writestruct(wd, ID_MB, "MetaBall", 1, mb); - if (mb->id.properties) IDP_WriteProperty(mb->id.properties, wd); + writestruct(wd, ID_MB, MetaBall, 1, mb); + write_iddata(wd, &mb->id); /* direct data */ - writedata(wd, DATA, sizeof(void *)*mb->totcol, mb->mat); - if (mb->adt) write_animdata(wd, mb->adt); + writedata(wd, DATA, sizeof(void *) * mb->totcol, mb->mat); + if (mb->adt) { + write_animdata(wd, mb->adt); + } - ml= mb->elems.first; + ml = mb->elems.first; while (ml) { - writestruct(wd, DATA, "MetaElem", 1, ml); - ml= ml->next; + writestruct(wd, DATA, MetaElem, 1, ml); + ml = ml->next; } } - mb= mb->id.next; + mb = mb->id.next; } } @@ -1837,43 +2011,50 @@ static void write_curves(WriteData *wd, ListBase *idbase) Curve *cu; Nurb *nu; - cu= idbase->first; + cu = idbase->first; while (cu) { - if (cu->id.us>0 || wd->current) { + if (cu->id.us > 0 || wd->current) { /* write LibData */ - writestruct(wd, ID_CU, "Curve", 1, cu); - + writestruct(wd, ID_CU, Curve, 1, cu); + write_iddata(wd, &cu->id); + /* direct data */ - writedata(wd, DATA, sizeof(void *)*cu->totcol, cu->mat); - if (cu->id.properties) IDP_WriteProperty(cu->id.properties, wd); - if (cu->adt) write_animdata(wd, cu->adt); - + writedata(wd, DATA, sizeof(void *) * cu->totcol, cu->mat); + if (cu->adt) { + write_animdata(wd, cu->adt); + } + if (cu->vfont) { writedata(wd, DATA, cu->len + 1, cu->str); - writestruct(wd, DATA, "CharInfo", cu->len_wchar + 1, cu->strinfo); - writestruct(wd, DATA, "TextBox", cu->totbox, cu->tb); + writestruct(wd, DATA, CharInfo, cu->len_wchar + 1, cu->strinfo); + writestruct(wd, DATA, TextBox, cu->totbox, cu->tb); } else { /* is also the order of reading */ - nu= cu->nurb.first; + nu = cu->nurb.first; while (nu) { - writestruct(wd, DATA, "Nurb", 1, nu); - nu= nu->next; + writestruct(wd, DATA, Nurb, 1, nu); + nu = nu->next; } - nu= cu->nurb.first; + nu = cu->nurb.first; while (nu) { - if (nu->type == CU_BEZIER) - writestruct(wd, DATA, "BezTriple", nu->pntsu, nu->bezt); + if (nu->type == CU_BEZIER) { + writestruct(wd, DATA, BezTriple, nu->pntsu, nu->bezt); + } else { - writestruct(wd, DATA, "BPoint", nu->pntsu*nu->pntsv, nu->bp); - if (nu->knotsu) writedata(wd, DATA, KNOTSU(nu)*sizeof(float), nu->knotsu); - if (nu->knotsv) writedata(wd, DATA, KNOTSV(nu)*sizeof(float), nu->knotsv); + writestruct(wd, DATA, BPoint, nu->pntsu * nu->pntsv, nu->bp); + if (nu->knotsu) { + writedata(wd, DATA, KNOTSU(nu) * sizeof(float), nu->knotsu); + } + if (nu->knotsv) { + writedata(wd, DATA, KNOTSV(nu) * sizeof(float), nu->knotsv); + } } - nu= nu->next; + nu = nu->next; } } } - cu= cu->id.next; + cu = cu->id.next; } /* flush helps the compression for undo-save */ @@ -1883,15 +2064,15 @@ static void write_curves(WriteData *wd, ListBase *idbase) static void write_dverts(WriteData *wd, int count, MDeformVert *dvlist) { if (dvlist) { - int i; - + /* Write the dvert list */ - writestruct(wd, DATA, "MDeformVert", count, dvlist); - + writestruct(wd, DATA, MDeformVert, count, dvlist); + /* Write deformation data for each dvert */ - for (i=0; i<count; i++) { - if (dvlist[i].dw) - writestruct(wd, DATA, "MDeformWeight", dvlist[i].totweight, dvlist[i].dw); + for (int i = 0; i < count; i++) { + if (dvlist[i].dw) { + writestruct(wd, DATA, MDeformWeight, dvlist[i].totweight, dvlist[i].dw); + } } } } @@ -1900,17 +2081,19 @@ static void write_mdisps(WriteData *wd, int count, MDisps *mdlist, int external) { if (mdlist) { int i; - - writestruct(wd, DATA, "MDisps", count, mdlist); + + writestruct(wd, DATA, MDisps, count, mdlist); for (i = 0; i < count; ++i) { MDisps *md = &mdlist[i]; if (md->disps) { - if (!external) + if (!external) { writedata(wd, DATA, sizeof(float) * 3 * md->totdisp, md->disps); + } } - - if (md->hidden) + + if (md->hidden) { writedata(wd, DATA, BLI_BITMAP_SIZE(md->totdisp), md->hidden); + } } } } @@ -1919,8 +2102,8 @@ static void write_grid_paint_mask(WriteData *wd, int count, GridPaintMask *grid_ { if (grid_paint_mask) { int i; - - writestruct(wd, DATA, "GridPaintMask", count, grid_paint_mask); + + writestruct(wd, DATA, GridPaintMask, count, grid_paint_mask); for (i = 0; i < count; ++i) { GridPaintMask *gpm = &grid_paint_mask[i]; if (gpm->data) { @@ -1940,11 +2123,12 @@ static void write_customdata( int i; /* write external customdata (not for undo) */ - if (data->external && !wd->current) + if (data->external && !wd->current) { CustomData_external_write(data, id, CD_MASK_MESH, count, 0); + } + + writestruct_at_address(wd, DATA, CustomDataLayer, data->totlayer, data->layers, layers); - writestruct_at_address(wd, DATA, "CustomDataLayer", data->totlayer, data->layers, layers); - for (i = 0; i < data->totlayer; i++) { CustomDataLayer *layer = &layers[i]; const char *structname; @@ -1970,10 +2154,14 @@ static void write_customdata( /* when using partial visibility, the MEdge and MFace layers * are smaller than the original, so their type and count is * passed to make this work */ - if (layer->type != partial_type) datasize= structnum*count; - else datasize= structnum*partial_count; + if (layer->type != partial_type) { + datasize = structnum * count; + } + else { + datasize = structnum * partial_count; + } - writestruct(wd, DATA, structname, datasize, layer->data); + writestruct_id(wd, DATA, structname, datasize, layer->data); } else { printf("%s error: layer '%s':%d - can't be written to file\n", @@ -1982,20 +2170,21 @@ static void write_customdata( } } - if (data->external) - writestruct(wd, DATA, "CustomDataExternal", 1, data->external); + if (data->external) { + writestruct(wd, DATA, CustomDataExternal, 1, data->external); + } } static void write_meshes(WriteData *wd, ListBase *idbase) { Mesh *mesh; - int save_for_old_blender= 0; + bool save_for_old_blender = false; #ifdef USE_BMESH_SAVE_AS_COMPAT save_for_old_blender = wd->use_mesh_compat; /* option to save with older mesh format */ #endif - mesh= idbase->first; + mesh = idbase->first; while (mesh) { CustomDataLayer *vlayers = NULL, vlayers_buff[CD_TEMP_CHUNK_SIZE]; CustomDataLayer *elayers = NULL, elayers_buff[CD_TEMP_CHUNK_SIZE]; @@ -2003,7 +2192,7 @@ static void write_meshes(WriteData *wd, ListBase *idbase) CustomDataLayer *llayers = NULL, llayers_buff[CD_TEMP_CHUNK_SIZE]; CustomDataLayer *players = NULL, players_buff[CD_TEMP_CHUNK_SIZE]; - if (mesh->id.us>0 || wd->current) { + if (mesh->id.us > 0 || wd->current) { /* write LibData */ if (!save_for_old_blender) { /* write a copy of the mesh, don't modify in place because it is @@ -2036,13 +2225,15 @@ static void write_meshes(WriteData *wd, ListBase *idbase) CustomData_file_write_prepare(&mesh->ldata, &llayers, llayers_buff, ARRAY_SIZE(llayers_buff)); CustomData_file_write_prepare(&mesh->pdata, &players, players_buff, ARRAY_SIZE(players_buff)); - writestruct_at_address(wd, ID_ME, "Mesh", 1, old_mesh, mesh); + writestruct_at_address(wd, ID_ME, Mesh, 1, old_mesh, mesh); + write_iddata(wd, &mesh->id); /* direct data */ - if (mesh->id.properties) IDP_WriteProperty(mesh->id.properties, wd); - if (mesh->adt) write_animdata(wd, mesh->adt); + if (mesh->adt) { + write_animdata(wd, mesh->adt); + } - writedata(wd, DATA, sizeof(void *)*mesh->totcol, mesh->mat); + writedata(wd, DATA, sizeof(void *) * mesh->totcol, mesh->mat); writedata(wd, DATA, sizeof(MSelect) * mesh->totselect, mesh->mselect); write_customdata(wd, &mesh->id, mesh->totvert, &mesh->vdata, vlayers, -1, 0); @@ -2094,13 +2285,15 @@ static void write_meshes(WriteData *wd, ListBase *idbase) CustomData_file_write_prepare(&mesh->pdata, &players, players_buff, ARRAY_SIZE(players_buff)); #endif - writestruct_at_address(wd, ID_ME, "Mesh", 1, old_mesh, mesh); + writestruct_at_address(wd, ID_ME, Mesh, 1, old_mesh, mesh); + write_iddata(wd, &mesh->id); /* direct data */ - if (mesh->id.properties) IDP_WriteProperty(mesh->id.properties, wd); - if (mesh->adt) write_animdata(wd, mesh->adt); + if (mesh->adt) { + write_animdata(wd, mesh->adt); + } - writedata(wd, DATA, sizeof(void *)*mesh->totcol, mesh->mat); + writedata(wd, DATA, sizeof(void *) * mesh->totcol, mesh->mat); /* writedata(wd, DATA, sizeof(MSelect) * mesh->totselect, mesh->mselect); */ /* pre-bmesh NULL's */ write_customdata(wd, &mesh->id, mesh->totvert, &mesh->vdata, vlayers, -1, 0); @@ -2137,44 +2330,46 @@ static void write_meshes(WriteData *wd, ListBase *idbase) MEM_freeN(players); } - mesh= mesh->id.next; + mesh = mesh->id.next; } } static void write_lattices(WriteData *wd, ListBase *idbase) { Lattice *lt; - - lt= idbase->first; + + lt = idbase->first; while (lt) { - if (lt->id.us>0 || wd->current) { + if (lt->id.us > 0 || wd->current) { /* write LibData */ - writestruct(wd, ID_LT, "Lattice", 1, lt); - if (lt->id.properties) IDP_WriteProperty(lt->id.properties, wd); - + writestruct(wd, ID_LT, Lattice, 1, lt); + write_iddata(wd, <->id); + /* write animdata */ - if (lt->adt) write_animdata(wd, lt->adt); - + if (lt->adt) { + write_animdata(wd, lt->adt); + } + /* direct data */ - writestruct(wd, DATA, "BPoint", lt->pntsu*lt->pntsv*lt->pntsw, lt->def); - - write_dverts(wd, lt->pntsu*lt->pntsv*lt->pntsw, lt->dvert); - + writestruct(wd, DATA, BPoint, lt->pntsu * lt->pntsv * lt->pntsw, lt->def); + + write_dverts(wd, lt->pntsu * lt->pntsv * lt->pntsw, lt->dvert); + } - lt= lt->id.next; + lt = lt->id.next; } } static void write_images(WriteData *wd, ListBase *idbase) { Image *ima; - PackedFile * pf; + PackedFile *pf; ImageView *iv; ImagePackedFile *imapf; - ima= idbase->first; + ima = idbase->first; while (ima) { - if (ima->id.us>0 || wd->current) { + if (ima->id.us > 0 || wd->current) { /* Some trickery to keep forward compatibility of packed images. */ BLI_assert(ima->packedfile == NULL); if (ima->packedfiles.first != NULL) { @@ -2183,27 +2378,28 @@ static void write_images(WriteData *wd, ListBase *idbase) } /* write LibData */ - writestruct(wd, ID_IM, "Image", 1, ima); - if (ima->id.properties) IDP_WriteProperty(ima->id.properties, wd); + writestruct(wd, ID_IM, Image, 1, ima); + write_iddata(wd, &ima->id); for (imapf = ima->packedfiles.first; imapf; imapf = imapf->next) { - writestruct(wd, DATA, "ImagePackedFile", 1, imapf); + writestruct(wd, DATA, ImagePackedFile, 1, imapf); if (imapf->packedfile) { pf = imapf->packedfile; - writestruct(wd, DATA, "PackedFile", 1, pf); + writestruct(wd, DATA, PackedFile, 1, pf); writedata(wd, DATA, pf->size, pf->data); } } write_previews(wd, ima->preview); - for (iv = ima->views.first; iv; iv = iv->next) - writestruct(wd, DATA, "ImageView", 1, iv); - writestruct(wd, DATA, "Stereo3dFormat", 1, ima->stereo3d_format); + for (iv = ima->views.first; iv; iv = iv->next) { + writestruct(wd, DATA, ImageView, 1, iv); + } + writestruct(wd, DATA, Stereo3dFormat, 1, ima->stereo3d_format); ima->packedfile = NULL; } - ima= ima->id.next; + ima = ima->id.next; } /* flush helps the compression for undo-save */ mywrite(wd, MYWRITE_FLUSH, 0); @@ -2213,35 +2409,49 @@ static void write_textures(WriteData *wd, ListBase *idbase) { Tex *tex; - tex= idbase->first; + tex = idbase->first; while (tex) { - if (tex->id.us>0 || wd->current) { + if (tex->id.us > 0 || wd->current) { /* write LibData */ - writestruct(wd, ID_TE, "Tex", 1, tex); - if (tex->id.properties) IDP_WriteProperty(tex->id.properties, wd); + writestruct(wd, ID_TE, Tex, 1, tex); + write_iddata(wd, &tex->id); - if (tex->adt) write_animdata(wd, tex->adt); + if (tex->adt) { + write_animdata(wd, tex->adt); + } /* direct data */ - if (tex->coba) writestruct(wd, DATA, "ColorBand", 1, tex->coba); - if (tex->type == TEX_ENVMAP && tex->env) writestruct(wd, DATA, "EnvMap", 1, tex->env); + if (tex->coba) { + writestruct(wd, DATA, ColorBand, 1, tex->coba); + } + if (tex->type == TEX_ENVMAP && tex->env) { + writestruct(wd, DATA, EnvMap, 1, tex->env); + } if (tex->type == TEX_POINTDENSITY && tex->pd) { - writestruct(wd, DATA, "PointDensity", 1, tex->pd); - if (tex->pd->coba) writestruct(wd, DATA, "ColorBand", 1, tex->pd->coba); - if (tex->pd->falloff_curve) write_curvemapping(wd, tex->pd->falloff_curve); + writestruct(wd, DATA, PointDensity, 1, tex->pd); + if (tex->pd->coba) { + writestruct(wd, DATA, ColorBand, 1, tex->pd->coba); + } + if (tex->pd->falloff_curve) { + write_curvemapping(wd, tex->pd->falloff_curve); + } } - if (tex->type == TEX_VOXELDATA) writestruct(wd, DATA, "VoxelData", 1, tex->vd); - if (tex->type == TEX_OCEAN && tex->ot) writestruct(wd, DATA, "OceanTex", 1, tex->ot); - + if (tex->type == TEX_VOXELDATA) { + writestruct(wd, DATA, VoxelData, 1, tex->vd); + } + if (tex->type == TEX_OCEAN && tex->ot) { + writestruct(wd, DATA, OceanTex, 1, tex->ot); + } + /* nodetree is integral part of texture, no libdata */ if (tex->nodetree) { - writestruct(wd, DATA, "bNodeTree", 1, tex->nodetree); + writestruct(wd, DATA, bNodeTree, 1, tex->nodetree); write_nodetree(wd, tex->nodetree); } - + write_previews(wd, tex->preview); } - tex= tex->id.next; + tex = tex->id.next; } /* flush helps the compression for undo-save */ @@ -2253,36 +2463,39 @@ static void write_materials(WriteData *wd, ListBase *idbase) Material *ma; int a; - ma= idbase->first; + ma = idbase->first; while (ma) { - if (ma->id.us>0 || wd->current) { + if (ma->id.us > 0 || wd->current) { /* write LibData */ - writestruct(wd, ID_MA, "Material", 1, ma); - - /* Write ID Properties -- and copy this comment EXACTLY for easy finding - * of library blocks that implement this.*/ - /* manually set head group property to IDP_GROUP, just in case it hadn't been - * set yet :) */ - if (ma->id.properties) IDP_WriteProperty(ma->id.properties, wd); - - if (ma->adt) write_animdata(wd, ma->adt); - - for (a=0; a<MAX_MTEX; a++) { - if (ma->mtex[a]) writestruct(wd, DATA, "MTex", 1, ma->mtex[a]); - } - - if (ma->ramp_col) writestruct(wd, DATA, "ColorBand", 1, ma->ramp_col); - if (ma->ramp_spec) writestruct(wd, DATA, "ColorBand", 1, ma->ramp_spec); - + writestruct(wd, ID_MA, Material, 1, ma); + write_iddata(wd, &ma->id); + + if (ma->adt) { + write_animdata(wd, ma->adt); + } + + for (a = 0; a < MAX_MTEX; a++) { + if (ma->mtex[a]) { + writestruct(wd, DATA, MTex, 1, ma->mtex[a]); + } + } + + if (ma->ramp_col) { + writestruct(wd, DATA, ColorBand, 1, ma->ramp_col); + } + if (ma->ramp_spec) { + writestruct(wd, DATA, ColorBand, 1, ma->ramp_spec); + } + /* nodetree is integral part of material, no libdata */ if (ma->nodetree) { - writestruct(wd, DATA, "bNodeTree", 1, ma->nodetree); + writestruct(wd, DATA, bNodeTree, 1, ma->nodetree); write_nodetree(wd, ma->nodetree); } write_previews(wd, ma->preview); } - ma= ma->id.next; + ma = ma->id.next; } } @@ -2291,28 +2504,32 @@ static void write_worlds(WriteData *wd, ListBase *idbase) World *wrld; int a; - wrld= idbase->first; + wrld = idbase->first; while (wrld) { - if (wrld->id.us>0 || wd->current) { + if (wrld->id.us > 0 || wd->current) { /* write LibData */ - writestruct(wd, ID_WO, "World", 1, wrld); - if (wrld->id.properties) IDP_WriteProperty(wrld->id.properties, wd); - - if (wrld->adt) write_animdata(wd, wrld->adt); - - for (a=0; a<MAX_MTEX; a++) { - if (wrld->mtex[a]) writestruct(wd, DATA, "MTex", 1, wrld->mtex[a]); + writestruct(wd, ID_WO, World, 1, wrld); + write_iddata(wd, &wrld->id); + + if (wrld->adt) { + write_animdata(wd, wrld->adt); + } + + for (a = 0; a < MAX_MTEX; a++) { + if (wrld->mtex[a]) { + writestruct(wd, DATA, MTex, 1, wrld->mtex[a]); + } } /* nodetree is integral part of world, no libdata */ if (wrld->nodetree) { - writestruct(wd, DATA, "bNodeTree", 1, wrld->nodetree); + writestruct(wd, DATA, bNodeTree, 1, wrld->nodetree); write_nodetree(wd, wrld->nodetree); } - + write_previews(wd, wrld->preview); } - wrld= wrld->id.next; + wrld = wrld->id.next; } } @@ -2321,33 +2538,38 @@ static void write_lamps(WriteData *wd, ListBase *idbase) Lamp *la; int a; - la= idbase->first; + la = idbase->first; while (la) { - if (la->id.us>0 || wd->current) { + if (la->id.us > 0 || wd->current) { /* write LibData */ - writestruct(wd, ID_LA, "Lamp", 1, la); - if (la->id.properties) IDP_WriteProperty(la->id.properties, wd); - - if (la->adt) write_animdata(wd, la->adt); - + writestruct(wd, ID_LA, Lamp, 1, la); + write_iddata(wd, &la->id); + + if (la->adt) { + write_animdata(wd, la->adt); + } + /* direct data */ - for (a=0; a<MAX_MTEX; a++) { - if (la->mtex[a]) writestruct(wd, DATA, "MTex", 1, la->mtex[a]); + for (a = 0; a < MAX_MTEX; a++) { + if (la->mtex[a]) { + writestruct(wd, DATA, MTex, 1, la->mtex[a]); + } } - - if (la->curfalloff) + + if (la->curfalloff) { write_curvemapping(wd, la->curfalloff); - + } + /* nodetree is integral part of lamps, no libdata */ if (la->nodetree) { - writestruct(wd, DATA, "bNodeTree", 1, la->nodetree); + writestruct(wd, DATA, bNodeTree, 1, la->nodetree); write_nodetree(wd, la->nodetree); } write_previews(wd, la->preview); - + } - la= la->id.next; + la = la->id.next; } } @@ -2359,21 +2581,21 @@ static void write_sequence_modifiers(WriteData *wd, ListBase *modbase) const SequenceModifierTypeInfo *smti = BKE_sequence_modifier_type_info_get(smd->type); if (smti) { - writestruct(wd, DATA, smti->struct_name, 1, smd); + writestruct_id(wd, DATA, smti->struct_name, 1, smd); if (smd->type == seqModifierType_Curves) { - CurvesModifierData *cmd = (CurvesModifierData *) smd; + CurvesModifierData *cmd = (CurvesModifierData *)smd; write_curvemapping(wd, &cmd->curve_mapping); } else if (smd->type == seqModifierType_HueCorrect) { - HueCorrectModifierData *hcmd = (HueCorrectModifierData *) smd; + HueCorrectModifierData *hcmd = (HueCorrectModifierData *)smd; write_curvemapping(wd, &hcmd->curve_mapping); } } else { - writestruct(wd, DATA, "SequenceModifierData", 1, smd); + writestruct(wd, DATA, SequenceModifierData, 1, smd); } } } @@ -2387,8 +2609,9 @@ static void write_view_settings(WriteData *wd, ColorManagedViewSettings *view_se static void write_paint(WriteData *wd, Paint *p) { - if (p->cavity_curve) + if (p->cavity_curve) { write_curvemapping(wd, p->cavity_curve); + } } static void write_scenes(WriteData *wd, ListBase *scebase) @@ -2406,106 +2629,114 @@ static void write_scenes(WriteData *wd, ListBase *scebase) ToolSettings *tos; FreestyleModuleConfig *fmc; FreestyleLineSet *fls; - - sce= scebase->first; + + sce = scebase->first; while (sce) { /* write LibData */ - writestruct(wd, ID_SCE, "Scene", 1, sce); - if (sce->id.properties) IDP_WriteProperty(sce->id.properties, wd); - - if (sce->adt) write_animdata(wd, sce->adt); + writestruct(wd, ID_SCE, Scene, 1, sce); + write_iddata(wd, &sce->id); + + if (sce->adt) { + write_animdata(wd, sce->adt); + } write_keyingsets(wd, &sce->keyingsets); - + /* direct data */ - base= sce->base.first; + base = sce->base.first; while (base) { - writestruct(wd, DATA, "Base", 1, base); - base= base->next; + writestruct(wd, DATA, Base, 1, base); + base = base->next; } - + tos = sce->toolsettings; - writestruct(wd, DATA, "ToolSettings", 1, tos); + writestruct(wd, DATA, ToolSettings, 1, tos); if (tos->vpaint) { - writestruct(wd, DATA, "VPaint", 1, tos->vpaint); - write_paint (wd, &tos->vpaint->paint); + writestruct(wd, DATA, VPaint, 1, tos->vpaint); + write_paint(wd, &tos->vpaint->paint); } if (tos->wpaint) { - writestruct(wd, DATA, "VPaint", 1, tos->wpaint); - write_paint (wd, &tos->wpaint->paint); + writestruct(wd, DATA, VPaint, 1, tos->wpaint); + write_paint(wd, &tos->wpaint->paint); } if (tos->sculpt) { - writestruct(wd, DATA, "Sculpt", 1, tos->sculpt); - write_paint (wd, &tos->sculpt->paint); + writestruct(wd, DATA, Sculpt, 1, tos->sculpt); + write_paint(wd, &tos->sculpt->paint); } if (tos->uvsculpt) { - writestruct(wd, DATA, "UvSculpt", 1, tos->uvsculpt); - write_paint (wd, &tos->uvsculpt->paint); + writestruct(wd, DATA, UvSculpt, 1, tos->uvsculpt); + write_paint(wd, &tos->uvsculpt->paint); } write_paint(wd, &tos->imapaint.paint); - ed= sce->ed; + ed = sce->ed; if (ed) { - writestruct(wd, DATA, "Editing", 1, ed); - + writestruct(wd, DATA, Editing, 1, ed); + /* reset write flags too */ - - SEQ_BEGIN (ed, seq) + + SEQ_BEGIN(ed, seq) { - if (seq->strip) seq->strip->done = false; - writestruct(wd, DATA, "Sequence", 1, seq); + if (seq->strip) { + seq->strip->done = false; + } + writestruct(wd, DATA, Sequence, 1, seq); } SEQ_END - - SEQ_BEGIN (ed, seq) + + SEQ_BEGIN(ed, seq) { - if (seq->strip && seq->strip->done==0) { + if (seq->strip && seq->strip->done == 0) { /* write strip with 'done' at 0 because readfile */ - + if (seq->effectdata) { switch (seq->type) { - case SEQ_TYPE_COLOR: - writestruct(wd, DATA, "SolidColorVars", 1, seq->effectdata); - break; - case SEQ_TYPE_SPEED: - writestruct(wd, DATA, "SpeedControlVars", 1, seq->effectdata); - break; - case SEQ_TYPE_WIPE: - writestruct(wd, DATA, "WipeVars", 1, seq->effectdata); - break; - case SEQ_TYPE_GLOW: - writestruct(wd, DATA, "GlowVars", 1, seq->effectdata); - break; - case SEQ_TYPE_TRANSFORM: - writestruct(wd, DATA, "TransformVars", 1, seq->effectdata); - break; - case SEQ_TYPE_GAUSSIAN_BLUR: - writestruct(wd, DATA, "GaussianBlurVars", 1, seq->effectdata); - break; - case SEQ_TYPE_TEXT: - writestruct(wd, DATA, "TextVars", 1, seq->effectdata); - break; + case SEQ_TYPE_COLOR: + writestruct(wd, DATA, SolidColorVars, 1, seq->effectdata); + break; + case SEQ_TYPE_SPEED: + writestruct(wd, DATA, SpeedControlVars, 1, seq->effectdata); + break; + case SEQ_TYPE_WIPE: + writestruct(wd, DATA, WipeVars, 1, seq->effectdata); + break; + case SEQ_TYPE_GLOW: + writestruct(wd, DATA, GlowVars, 1, seq->effectdata); + break; + case SEQ_TYPE_TRANSFORM: + writestruct(wd, DATA, TransformVars, 1, seq->effectdata); + break; + case SEQ_TYPE_GAUSSIAN_BLUR: + writestruct(wd, DATA, GaussianBlurVars, 1, seq->effectdata); + break; + case SEQ_TYPE_TEXT: + writestruct(wd, DATA, TextVars, 1, seq->effectdata); + break; } } - writestruct(wd, DATA, "Stereo3dFormat", 1, seq->stereo3d_format); + writestruct(wd, DATA, Stereo3dFormat, 1, seq->stereo3d_format); - strip= seq->strip; - writestruct(wd, DATA, "Strip", 1, strip); + strip = seq->strip; + writestruct(wd, DATA, Strip, 1, strip); if (seq->flag & SEQ_USE_CROP && strip->crop) { - writestruct(wd, DATA, "StripCrop", 1, strip->crop); + writestruct(wd, DATA, StripCrop, 1, strip->crop); } if (seq->flag & SEQ_USE_TRANSFORM && strip->transform) { - writestruct(wd, DATA, "StripTransform", 1, strip->transform); + writestruct(wd, DATA, StripTransform, 1, strip->transform); } if (seq->flag & SEQ_USE_PROXY && strip->proxy) { - writestruct(wd, DATA, "StripProxy", 1, strip->proxy); + writestruct(wd, DATA, StripProxy, 1, strip->proxy); } - if (seq->type==SEQ_TYPE_IMAGE) - writestruct(wd, DATA, "StripElem", MEM_allocN_len(strip->stripdata) / sizeof(struct StripElem), strip->stripdata); - else if (seq->type==SEQ_TYPE_MOVIE || seq->type==SEQ_TYPE_SOUND_RAM || seq->type == SEQ_TYPE_SOUND_HD) - writestruct(wd, DATA, "StripElem", 1, strip->stripdata); - + if (seq->type == SEQ_TYPE_IMAGE) { + writestruct(wd, DATA, StripElem, + MEM_allocN_len(strip->stripdata) / sizeof(struct StripElem), + strip->stripdata); + } + else if (ELEM(seq->type, SEQ_TYPE_MOVIE, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SOUND_HD)) { + writestruct(wd, DATA, StripElem, 1, strip->stripdata); + } + strip->done = true; } @@ -2516,67 +2747,76 @@ static void write_scenes(WriteData *wd, ListBase *scebase) write_sequence_modifiers(wd, &seq->modifiers); } SEQ_END - + /* new; meta stack too, even when its nasty restore code */ - for (ms= ed->metastack.first; ms; ms= ms->next) { - writestruct(wd, DATA, "MetaStack", 1, ms); + for (ms = ed->metastack.first; ms; ms = ms->next) { + writestruct(wd, DATA, MetaStack, 1, ms); } } - + if (sce->r.avicodecdata) { - writestruct(wd, DATA, "AviCodecData", 1, sce->r.avicodecdata); - if (sce->r.avicodecdata->lpFormat) writedata(wd, DATA, sce->r.avicodecdata->cbFormat, sce->r.avicodecdata->lpFormat); - if (sce->r.avicodecdata->lpParms) writedata(wd, DATA, sce->r.avicodecdata->cbParms, sce->r.avicodecdata->lpParms); + writestruct(wd, DATA, AviCodecData, 1, sce->r.avicodecdata); + if (sce->r.avicodecdata->lpFormat) { + writedata(wd, DATA, sce->r.avicodecdata->cbFormat, sce->r.avicodecdata->lpFormat); + } + if (sce->r.avicodecdata->lpParms) { + writedata(wd, DATA, sce->r.avicodecdata->cbParms, sce->r.avicodecdata->lpParms); + } } if (sce->r.qtcodecdata) { - writestruct(wd, DATA, "QuicktimeCodecData", 1, sce->r.qtcodecdata); - if (sce->r.qtcodecdata->cdParms) writedata(wd, DATA, sce->r.qtcodecdata->cdSize, sce->r.qtcodecdata->cdParms); + writestruct(wd, DATA, QuicktimeCodecData, 1, sce->r.qtcodecdata); + if (sce->r.qtcodecdata->cdParms) { + writedata(wd, DATA, sce->r.qtcodecdata->cdSize, sce->r.qtcodecdata->cdParms); + } } if (sce->r.ffcodecdata.properties) { IDP_WriteProperty(sce->r.ffcodecdata.properties, wd); } /* writing dynamic list of TimeMarkers to the blend file */ - for (marker= sce->markers.first; marker; marker= marker->next) - writestruct(wd, DATA, "TimeMarker", 1, marker); - + for (marker = sce->markers.first; marker; marker = marker->next) { + writestruct(wd, DATA, TimeMarker, 1, marker); + } + /* writing dynamic list of TransformOrientations to the blend file */ - for (ts = sce->transform_spaces.first; ts; ts = ts->next) - writestruct(wd, DATA, "TransformOrientation", 1, ts); - + for (ts = sce->transform_spaces.first; ts; ts = ts->next) { + writestruct(wd, DATA, TransformOrientation, 1, ts); + } + for (srl = sce->r.layers.first; srl; srl = srl->next) { - writestruct(wd, DATA, "SceneRenderLayer", 1, srl); + writestruct(wd, DATA, SceneRenderLayer, 1, srl); for (fmc = srl->freestyleConfig.modules.first; fmc; fmc = fmc->next) { - writestruct(wd, DATA, "FreestyleModuleConfig", 1, fmc); + writestruct(wd, DATA, FreestyleModuleConfig, 1, fmc); } for (fls = srl->freestyleConfig.linesets.first; fls; fls = fls->next) { - writestruct(wd, DATA, "FreestyleLineSet", 1, fls); + writestruct(wd, DATA, FreestyleLineSet, 1, fls); } } /* writing MultiView to the blend file */ - for (srv = sce->r.views.first; srv; srv = srv->next) - writestruct(wd, DATA, "SceneRenderView", 1, srv); - + for (srv = sce->r.views.first; srv; srv = srv->next) { + writestruct(wd, DATA, SceneRenderView, 1, srv); + } + if (sce->nodetree) { - writestruct(wd, DATA, "bNodeTree", 1, sce->nodetree); + writestruct(wd, DATA, bNodeTree, 1, sce->nodetree); write_nodetree(wd, sce->nodetree); } write_view_settings(wd, &sce->view_settings); - + /* writing RigidBodyWorld data to the blend file */ if (sce->rigidbody_world) { - writestruct(wd, DATA, "RigidBodyWorld", 1, sce->rigidbody_world); - writestruct(wd, DATA, "EffectorWeights", 1, sce->rigidbody_world->effector_weights); + writestruct(wd, DATA, RigidBodyWorld, 1, sce->rigidbody_world); + writestruct(wd, DATA, EffectorWeights, 1, sce->rigidbody_world->effector_weights); write_pointcaches(wd, &(sce->rigidbody_world->ptcaches)); } - + write_previews(wd, sce->preview); write_curvemapping_curves(wd, &sce->r.mblur_shutter_curve); - sce= sce->id.next; + sce = sce->id.next; } /* flush helps the compression for undo-save */ mywrite(wd, MYWRITE_FLUSH, 0); @@ -2588,26 +2828,29 @@ static void write_gpencils(WriteData *wd, ListBase *lb) bGPDlayer *gpl; bGPDframe *gpf; bGPDstroke *gps; - - for (gpd= lb->first; gpd; gpd= gpd->id.next) { - if (gpd->id.us>0 || wd->current) { + + for (gpd = lb->first; gpd; gpd = gpd->id.next) { + if (gpd->id.us > 0 || wd->current) { /* write gpd data block to file */ - writestruct(wd, ID_GD, "bGPdata", 1, gpd); - - if (gpd->adt) write_animdata(wd, gpd->adt); - + writestruct(wd, ID_GD, bGPdata, 1, gpd); + write_iddata(wd, &gpd->id); + + if (gpd->adt) { + write_animdata(wd, gpd->adt); + } + /* write grease-pencil layers to file */ - writelist(wd, DATA, "bGPDlayer", &gpd->layers); - for (gpl= gpd->layers.first; gpl; gpl= gpl->next) { - + writelist(wd, DATA, bGPDlayer, &gpd->layers); + for (gpl = gpd->layers.first; gpl; gpl = gpl->next) { + /* write this layer's frames to file */ - writelist(wd, DATA, "bGPDframe", &gpl->frames); - for (gpf= gpl->frames.first; gpf; gpf= gpf->next) { - + writelist(wd, DATA, bGPDframe, &gpl->frames); + for (gpf = gpl->frames.first; gpf; gpf = gpf->next) { + /* write strokes */ - writelist(wd, DATA, "bGPDstroke", &gpf->strokes); - for (gps= gpf->strokes.first; gps; gps= gps->next) { - writestruct(wd, DATA, "bGPDspoint", gps->totpoints, gps->points); + writelist(wd, DATA, bGPDstroke, &gpf->strokes); + for (gps = gpf->strokes.first; gps; gps = gps->next) { + writestruct(wd, DATA, bGPDspoint, gps->totpoints, gps->points); } } } @@ -2619,32 +2862,35 @@ static void write_windowmanagers(WriteData *wd, ListBase *lb) { wmWindowManager *wm; wmWindow *win; - - for (wm= lb->first; wm; wm= wm->id.next) { - writestruct(wd, ID_WM, "wmWindowManager", 1, wm); - - for (win= wm->windows.first; win; win= win->next) { - writestruct(wd, DATA, "wmWindow", 1, win); - writestruct(wd, DATA, "Stereo3dFormat", 1, win->stereo3d_format); + + for (wm = lb->first; wm; wm = wm->id.next) { + writestruct(wd, ID_WM, wmWindowManager, 1, wm); + write_iddata(wd, &wm->id); + + for (win = wm->windows.first; win; win = win->next) { + writestruct(wd, DATA, wmWindow, 1, win); + writestruct(wd, DATA, Stereo3dFormat, 1, win->stereo3d_format); } } } static void write_region(WriteData *wd, ARegion *ar, int spacetype) -{ - writestruct(wd, DATA, "ARegion", 1, ar); - +{ + writestruct(wd, DATA, ARegion, 1, ar); + if (ar->regiondata) { switch (spacetype) { case SPACE_VIEW3D: - if (ar->regiontype==RGN_TYPE_WINDOW) { - RegionView3D *rv3d= ar->regiondata; - writestruct(wd, DATA, "RegionView3D", 1, rv3d); - - if (rv3d->localvd) - writestruct(wd, DATA, "RegionView3D", 1, rv3d->localvd); - if (rv3d->clipbb) - writestruct(wd, DATA, "BoundBox", 1, rv3d->clipbb); + if (ar->regiontype == RGN_TYPE_WINDOW) { + RegionView3D *rv3d = ar->regiondata; + writestruct(wd, DATA, RegionView3D, 1, rv3d); + + if (rv3d->localvd) { + writestruct(wd, DATA, RegionView3D, 1, rv3d->localvd); + } + if (rv3d->clipbb) { + writestruct(wd, DATA, BoundBox, 1, rv3d->clipbb); + } } else @@ -2658,7 +2904,7 @@ static void write_region(WriteData *wd, ARegion *ar, int spacetype) static void write_uilist(WriteData *wd, uiList *ui_list) { - writestruct(wd, DATA, "uiList", 1, ui_list); + writestruct(wd, DATA, uiList, 1, ui_list); if (ui_list->properties) { IDP_WriteProperty(ui_list->properties, wd); @@ -2668,7 +2914,7 @@ static void write_uilist(WriteData *wd, uiList *ui_list) static void write_soops(WriteData *wd, SpaceOops *so, LinkNode **tmp_mem_list) { BLI_mempool *ts = so->treestore; - + if (ts) { int elems = BLI_mempool_count(ts); /* linearize mempool to array */ @@ -2680,13 +2926,13 @@ static void write_soops(WriteData *wd, SpaceOops *so, LinkNode **tmp_mem_list) ts_flat->usedelem = elems; ts_flat->totelem = elems; ts_flat->data = data; - + /* temporarily replace mempool-treestore by flat-treestore */ so->treestore = (BLI_mempool *)ts_flat; - writestruct(wd, DATA, "SpaceOops", 1, so); + writestruct(wd, DATA, SpaceOops, 1, so); - writestruct(wd, DATA, "TreeStore", 1, ts_flat); - writestruct(wd, DATA, "TreeStoreElem", elems, data); + writestruct(wd, DATA, TreeStore, 1, ts_flat); + writestruct(wd, DATA, TreeStoreElem, elems, data); /* we do not free the pointers immediately, because if we have multiple * outliners in a screen we might get the same address on the next @@ -2697,14 +2943,14 @@ static void write_soops(WriteData *wd, SpaceOops *so, LinkNode **tmp_mem_list) } else { so->treestore = NULL; - writestruct(wd, DATA, "SpaceOops", 1, so); + writestruct(wd, DATA, SpaceOops, 1, so); } /* restore old treestore */ so->treestore = ts; } else { - writestruct(wd, DATA, "SpaceOops", 1, so); + writestruct(wd, DATA, SpaceOops, 1, so); } } @@ -2716,277 +2962,236 @@ static void write_screens(WriteData *wd, ListBase *scrbase) ScrEdge *se; LinkNode *tmp_mem_list = NULL; - sc= scrbase->first; + sc = scrbase->first; while (sc) { - + /* write LibData */ /* in 2.50+ files, the file identifier for screens is patched, forward compatibility */ - writestruct(wd, ID_SCRN, "Screen", 1, sc); - if (sc->id.properties) - IDP_WriteProperty(sc->id.properties, wd); - + writestruct(wd, ID_SCRN, bScreen, 1, sc); + write_iddata(wd, &sc->id); + /* direct data */ - for (sv= sc->vertbase.first; sv; sv= sv->next) - writestruct(wd, DATA, "ScrVert", 1, sv); - - for (se= sc->edgebase.first; se; se= se->next) - writestruct(wd, DATA, "ScrEdge", 1, se); - - for (sa= sc->areabase.first; sa; sa= sa->next) { + for (sv = sc->vertbase.first; sv; sv = sv->next) { + writestruct(wd, DATA, ScrVert, 1, sv); + } + + for (se = sc->edgebase.first; se; se = se->next) { + writestruct(wd, DATA, ScrEdge, 1, se); + } + + for (sa = sc->areabase.first; sa; sa = sa->next) { SpaceLink *sl; Panel *pa; uiList *ui_list; uiPreview *ui_preview; PanelCategoryStack *pc_act; ARegion *ar; - - writestruct(wd, DATA, "ScrArea", 1, sa); - - for (ar= sa->regionbase.first; ar; ar= ar->next) { + + writestruct(wd, DATA, ScrArea, 1, sa); + + for (ar = sa->regionbase.first; ar; ar = ar->next) { write_region(wd, ar, sa->spacetype); - - for (pa= ar->panels.first; pa; pa= pa->next) - writestruct(wd, DATA, "Panel", 1, pa); - - for (pc_act = ar->panels_category_active.first; pc_act; pc_act = pc_act->next) - writestruct(wd, DATA, "PanelCategoryStack", 1, pc_act); - - for (ui_list = ar->ui_lists.first; ui_list; ui_list = ui_list->next) + + for (pa = ar->panels.first; pa; pa = pa->next) { + writestruct(wd, DATA, Panel, 1, pa); + } + + for (pc_act = ar->panels_category_active.first; pc_act; pc_act = pc_act->next) { + writestruct(wd, DATA, PanelCategoryStack, 1, pc_act); + } + + for (ui_list = ar->ui_lists.first; ui_list; ui_list = ui_list->next) { write_uilist(wd, ui_list); + } - for (ui_preview = ar->ui_previews.first; ui_preview; ui_preview = ui_preview->next) - writestruct(wd, DATA, "uiPreview", 1, ui_preview); + for (ui_preview = ar->ui_previews.first; ui_preview; ui_preview = ui_preview->next) { + writestruct(wd, DATA, uiPreview, 1, ui_preview); + } } - - sl= sa->spacedata.first; + + sl = sa->spacedata.first; while (sl) { - for (ar= sl->regionbase.first; ar; ar= ar->next) + for (ar = sl->regionbase.first; ar; ar = ar->next) { write_region(wd, ar, sl->spacetype); - - if (sl->spacetype==SPACE_VIEW3D) { - View3D *v3d= (View3D *) sl; + } + + if (sl->spacetype == SPACE_VIEW3D) { + View3D *v3d = (View3D *)sl; BGpic *bgpic; - writestruct(wd, DATA, "View3D", 1, v3d); - for (bgpic= v3d->bgpicbase.first; bgpic; bgpic= bgpic->next) - writestruct(wd, DATA, "BGpic", 1, bgpic); - if (v3d->localvd) writestruct(wd, DATA, "View3D", 1, v3d->localvd); - - if (v3d->fx_settings.ssao) - writestruct(wd, DATA, "GPUSSAOSettings", 1, v3d->fx_settings.ssao); - if (v3d->fx_settings.dof) - writestruct(wd, DATA, "GPUDOFSettings", 1, v3d->fx_settings.dof); - - if (v3d->pbr_settings.brdf) - writestruct(wd, DATA, "GPUBRDFSettings", 1, v3d->pbr_settings.brdf); + writestruct(wd, DATA, View3D, 1, v3d); + for (bgpic = v3d->bgpicbase.first; bgpic; bgpic = bgpic->next) { + writestruct(wd, DATA, BGpic, 1, bgpic); + } + if (v3d->localvd) { + writestruct(wd, DATA, View3D, 1, v3d->localvd); + } + + if (v3d->fx_settings.ssao) { + writestruct(wd, DATA, GPUSSAOSettings, 1, v3d->fx_settings.ssao); + } + if (v3d->fx_settings.dof) { + writestruct(wd, DATA, GPUDOFSettings, 1, v3d->fx_settings.dof); + } + + if (v3d->pbr_settings.brdf) { + writestruct(wd, DATA, GPUBRDFSettings, 1, v3d->pbr_settings.brdf); + } if (v3d->pbr_settings.ssr) - writestruct(wd, DATA, "GPUSSRSettings", 1, v3d->pbr_settings.ssr); - if (v3d->pbr_settings.ssao) - writestruct(wd, DATA, "GPUSSAOSettings", 1, v3d->pbr_settings.ssao); + { + writestruct(wd, DATA, GPUSSRSettings, 1, v3d->pbr_settings.ssr); + } + if (v3d->pbr_settings.ssao) { + writestruct(wd, DATA, GPUSSAOSettings, 1, v3d->pbr_settings.ssao); + } } - else if (sl->spacetype==SPACE_IPO) { - SpaceIpo *sipo= (SpaceIpo *)sl; + else if (sl->spacetype == SPACE_IPO) { + SpaceIpo *sipo = (SpaceIpo *)sl; ListBase tmpGhosts = sipo->ghostCurves; - + /* temporarily disable ghost curves when saving */ - sipo->ghostCurves.first= sipo->ghostCurves.last= NULL; - - writestruct(wd, DATA, "SpaceIpo", 1, sl); - if (sipo->ads) writestruct(wd, DATA, "bDopeSheet", 1, sipo->ads); - + sipo->ghostCurves.first = sipo->ghostCurves.last = NULL; + + writestruct(wd, DATA, SpaceIpo, 1, sl); + if (sipo->ads) { + writestruct(wd, DATA, bDopeSheet, 1, sipo->ads); + } + /* reenable ghost curves */ - sipo->ghostCurves= tmpGhosts; + sipo->ghostCurves = tmpGhosts; } - else if (sl->spacetype==SPACE_BUTS) { - writestruct(wd, DATA, "SpaceButs", 1, sl); + else if (sl->spacetype == SPACE_BUTS) { + writestruct(wd, DATA, SpaceButs, 1, sl); } - else if (sl->spacetype==SPACE_FILE) { - SpaceFile *sfile= (SpaceFile *)sl; + else if (sl->spacetype == SPACE_FILE) { + SpaceFile *sfile = (SpaceFile *)sl; - writestruct(wd, DATA, "SpaceFile", 1, sl); - if (sfile->params) - writestruct(wd, DATA, "FileSelectParams", 1, sfile->params); + writestruct(wd, DATA, SpaceFile, 1, sl); + if (sfile->params) { + writestruct(wd, DATA, FileSelectParams, 1, sfile->params); + } } - else if (sl->spacetype==SPACE_SEQ) { - writestruct(wd, DATA, "SpaceSeq", 1, sl); + else if (sl->spacetype == SPACE_SEQ) { + writestruct(wd, DATA, SpaceSeq, 1, sl); } - else if (sl->spacetype==SPACE_OUTLINER) { - SpaceOops *so= (SpaceOops *)sl; + else if (sl->spacetype == SPACE_OUTLINER) { + SpaceOops *so = (SpaceOops *)sl; write_soops(wd, so, &tmp_mem_list); } - else if (sl->spacetype==SPACE_IMAGE) { - SpaceImage *sima= (SpaceImage *)sl; - - writestruct(wd, DATA, "SpaceImage", 1, sl); - if (sima->cumap) - write_curvemapping(wd, sima->cumap); + else if (sl->spacetype == SPACE_IMAGE) { + writestruct(wd, DATA, SpaceImage, 1, sl); } - else if (sl->spacetype==SPACE_TEXT) { - writestruct(wd, DATA, "SpaceText", 1, sl); + else if (sl->spacetype == SPACE_TEXT) { + writestruct(wd, DATA, SpaceText, 1, sl); } - else if (sl->spacetype==SPACE_SCRIPT) { - SpaceScript *scr = (SpaceScript*)sl; + else if (sl->spacetype == SPACE_SCRIPT) { + SpaceScript *scr = (SpaceScript *)sl; scr->but_refs = NULL; - writestruct(wd, DATA, "SpaceScript", 1, sl); + writestruct(wd, DATA, SpaceScript, 1, sl); } - else if (sl->spacetype==SPACE_ACTION) { - writestruct(wd, DATA, "SpaceAction", 1, sl); + else if (sl->spacetype == SPACE_ACTION) { + writestruct(wd, DATA, SpaceAction, 1, sl); } - else if (sl->spacetype==SPACE_NLA) { - SpaceNla *snla= (SpaceNla *)sl; - - writestruct(wd, DATA, "SpaceNla", 1, snla); - if (snla->ads) writestruct(wd, DATA, "bDopeSheet", 1, snla->ads); + else if (sl->spacetype == SPACE_NLA) { + SpaceNla *snla = (SpaceNla *)sl; + + writestruct(wd, DATA, SpaceNla, 1, snla); + if (snla->ads) { + writestruct(wd, DATA, bDopeSheet, 1, snla->ads); + } } - else if (sl->spacetype==SPACE_TIME) { - writestruct(wd, DATA, "SpaceTime", 1, sl); + else if (sl->spacetype == SPACE_TIME) { + writestruct(wd, DATA, SpaceTime, 1, sl); } - else if (sl->spacetype==SPACE_NODE) { + else if (sl->spacetype == SPACE_NODE) { SpaceNode *snode = (SpaceNode *)sl; bNodeTreePath *path; - writestruct(wd, DATA, "SpaceNode", 1, snode); - - for (path=snode->treepath.first; path; path=path->next) - writestruct(wd, DATA, "bNodeTreePath", 1, path); + writestruct(wd, DATA, SpaceNode, 1, snode); + + for (path = snode->treepath.first; path; path = path->next) { + writestruct(wd, DATA, bNodeTreePath, 1, path); + } } - else if (sl->spacetype==SPACE_LOGIC) { - writestruct(wd, DATA, "SpaceLogic", 1, sl); + else if (sl->spacetype == SPACE_LOGIC) { + writestruct(wd, DATA, SpaceLogic, 1, sl); } - else if (sl->spacetype==SPACE_CONSOLE) { - SpaceConsole *con = (SpaceConsole*)sl; + else if (sl->spacetype == SPACE_CONSOLE) { + SpaceConsole *con = (SpaceConsole *)sl; ConsoleLine *cl; - for (cl=con->history.first; cl; cl=cl->next) { + for (cl = con->history.first; cl; cl = cl->next) { /* 'len_alloc' is invalid on write, set from 'len' on read */ - writestruct(wd, DATA, "ConsoleLine", 1, cl); - writedata(wd, DATA, cl->len+1, cl->line); + writestruct(wd, DATA, ConsoleLine, 1, cl); + writedata(wd, DATA, cl->len + 1, cl->line); } - writestruct(wd, DATA, "SpaceConsole", 1, sl); + writestruct(wd, DATA, SpaceConsole, 1, sl); } - else if (sl->spacetype==SPACE_USERPREF) { - writestruct(wd, DATA, "SpaceUserPref", 1, sl); + else if (sl->spacetype == SPACE_USERPREF) { + writestruct(wd, DATA, SpaceUserPref, 1, sl); } - else if (sl->spacetype==SPACE_CLIP) { - writestruct(wd, DATA, "SpaceClip", 1, sl); + else if (sl->spacetype == SPACE_CLIP) { + writestruct(wd, DATA, SpaceClip, 1, sl); } else if (sl->spacetype == SPACE_INFO) { - writestruct(wd, DATA, "SpaceInfo", 1, sl); + writestruct(wd, DATA, SpaceInfo, 1, sl); } - sl= sl->next; + sl = sl->next; } } - sc= sc->id.next; + sc = sc->id.next; } BLI_linklist_freeN(tmp_mem_list); - + /* flush helps the compression for undo-save */ mywrite(wd, MYWRITE_FLUSH, 0); } -static void write_libraries(WriteData *wd, Main *main) -{ - ListBase *lbarray[MAX_LIBARRAY]; - ID *id; - int a, tot; - bool found_one; - - for (; main; main= main->next) { - - a=tot= set_listbasepointers(main, lbarray); - - /* test: is lib being used */ - if (main->curlib && main->curlib->packedfile) - found_one = true; - else { - found_one = false; - while (tot--) { - for (id= lbarray[tot]->first; id; id= id->next) { - if (id->us > 0 && (id->tag & LIB_TAG_EXTERN)) { - found_one = true; - break; - } - } - if (found_one) break; - } - } - - /* to be able to restore quit.blend and temp saves, the packed blend has to be in undo buffers... */ - /* XXX needs rethink, just like save UI in undo files now - would be nice to append things only for the] - * quit.blend and temp saves */ - if (found_one) { - writestruct(wd, ID_LI, "Library", 1, main->curlib); - - if (main->curlib->packedfile) { - PackedFile *pf = main->curlib->packedfile; - writestruct(wd, DATA, "PackedFile", 1, pf); - writedata(wd, DATA, pf->size, pf->data); - if (wd->current == NULL) - printf("write packed .blend: %s\n", main->curlib->name); - } - - while (a--) { - for (id= lbarray[a]->first; id; id= id->next) { - if (id->us > 0 && (id->tag & LIB_TAG_EXTERN)) { - if (!BKE_idcode_is_linkable(GS(id->name))) { - printf("ERROR: write file: datablock '%s' from lib '%s' is not linkable " - "but is flagged as directly linked", id->name, main->curlib->filepath); - BLI_assert(0); - } - writestruct(wd, ID_ID, "ID", 1, id); - } - } - } - } - } -} - static void write_bone(WriteData *wd, Bone *bone) { - Bone* cbone; - - // PATCH for upward compatibility after 2.37+ armature recode + /* PATCH for upward compatibility after 2.37+ armature recode */ bone->size[0] = bone->size[1] = bone->size[2] = 1.0f; - - // Write this bone - writestruct(wd, DATA, "Bone", 1, bone); + + /* Write this bone */ + writestruct(wd, DATA, Bone, 1, bone); /* Write ID Properties -- and copy this comment EXACTLY for easy finding * of library blocks that implement this.*/ - if (bone->prop) + if (bone->prop) { IDP_WriteProperty(bone->prop, wd); - - // Write Children - cbone= bone->childbase.first; - while (cbone) { + } + + /* Write Children */ + for (Bone *cbone = bone->childbase.first; cbone; cbone = cbone->next) { write_bone(wd, cbone); - cbone= cbone->next; } } static void write_armatures(WriteData *wd, ListBase *idbase) { - bArmature *arm; - Bone *bone; + bArmature *arm; + Bone *bone; - arm=idbase->first; + arm = idbase->first; while (arm) { - if (arm->id.us>0 || wd->current) { - writestruct(wd, ID_AR, "bArmature", 1, arm); - if (arm->id.properties) IDP_WriteProperty(arm->id.properties, wd); + if (arm->id.us > 0 || wd->current) { + writestruct(wd, ID_AR, bArmature, 1, arm); + write_iddata(wd, &arm->id); - if (arm->adt) write_animdata(wd, arm->adt); + if (arm->adt) { + write_animdata(wd, arm->adt); + } /* Direct data */ - bone= arm->bonebase.first; + bone = arm->bonebase.first; while (bone) { write_bone(wd, bone); - bone=bone->next; + bone = bone->next; } } - arm=arm->id.next; + arm = arm->id.next; } /* flush helps the compression for undo-save */ @@ -2998,32 +3203,37 @@ static void write_texts(WriteData *wd, ListBase *idbase) Text *text; TextLine *tmp; - text= idbase->first; + text = idbase->first; while (text) { - if ( (text->flags & TXT_ISMEM) && (text->flags & TXT_ISEXT)) text->flags &= ~TXT_ISEXT; + if ( (text->flags & TXT_ISMEM) && (text->flags & TXT_ISEXT)) { + text->flags &= ~TXT_ISEXT; + } /* write LibData */ - writestruct(wd, ID_TXT, "Text", 1, text); - if (text->name) writedata(wd, DATA, strlen(text->name)+1, text->name); - if (text->id.properties) IDP_WriteProperty(text->id.properties, wd); + writestruct(wd, ID_TXT, Text, 1, text); + write_iddata(wd, &text->id); + + if (text->name) { + writedata(wd, DATA, strlen(text->name) + 1, text->name); + } if (!(text->flags & TXT_ISEXT)) { /* now write the text data, in two steps for optimization in the readfunction */ - tmp= text->lines.first; + tmp = text->lines.first; while (tmp) { - writestruct(wd, DATA, "TextLine", 1, tmp); - tmp= tmp->next; + writestruct(wd, DATA, TextLine, 1, tmp); + tmp = tmp->next; } - tmp= text->lines.first; + tmp = text->lines.first; while (tmp) { - writedata(wd, DATA, tmp->len+1, tmp->line); - tmp= tmp->next; + writedata(wd, DATA, tmp->len + 1, tmp->line); + tmp = tmp->next; } } - text= text->id.next; + text = text->id.next; } /* flush helps the compression for undo-save */ @@ -3034,16 +3244,18 @@ static void write_speakers(WriteData *wd, ListBase *idbase) { Speaker *spk; - spk= idbase->first; + spk = idbase->first; while (spk) { - if (spk->id.us>0 || wd->current) { + if (spk->id.us > 0 || wd->current) { /* write LibData */ - writestruct(wd, ID_SPK, "Speaker", 1, spk); - if (spk->id.properties) IDP_WriteProperty(spk->id.properties, wd); + writestruct(wd, ID_SPK, Speaker, 1, spk); + write_iddata(wd, &spk->id); - if (spk->adt) write_animdata(wd, spk->adt); + if (spk->adt) { + write_animdata(wd, spk->adt); + } } - spk= spk->id.next; + spk = spk->id.next; } } @@ -3051,22 +3263,22 @@ static void write_sounds(WriteData *wd, ListBase *idbase) { bSound *sound; - PackedFile * pf; + PackedFile *pf; - sound= idbase->first; + sound = idbase->first; while (sound) { - if (sound->id.us>0 || wd->current) { + if (sound->id.us > 0 || wd->current) { /* write LibData */ - writestruct(wd, ID_SO, "bSound", 1, sound); - if (sound->id.properties) IDP_WriteProperty(sound->id.properties, wd); + writestruct(wd, ID_SO, bSound, 1, sound); + write_iddata(wd, &sound->id); if (sound->packedfile) { pf = sound->packedfile; - writestruct(wd, DATA, "PackedFile", 1, pf); + writestruct(wd, DATA, PackedFile, 1, pf); writedata(wd, DATA, pf->size, pf->data); } } - sound= sound->id.next; + sound = sound->id.next; } /* flush helps the compression for undo-save */ @@ -3078,18 +3290,18 @@ static void write_groups(WriteData *wd, ListBase *idbase) Group *group; GroupObject *go; - for (group= idbase->first; group; group= group->id.next) { - if (group->id.us>0 || wd->current) { + for (group = idbase->first; group; group = group->id.next) { + if (group->id.us > 0 || wd->current) { /* write LibData */ - writestruct(wd, ID_GR, "Group", 1, group); - if (group->id.properties) IDP_WriteProperty(group->id.properties, wd); + writestruct(wd, ID_GR, Group, 1, group); + write_iddata(wd, &group->id); write_previews(wd, group->preview); - go= group->gobject.first; + go = group->gobject.first; while (go) { - writestruct(wd, DATA, "GroupObject", 1, go); - go= go->next; + writestruct(wd, DATA, GroupObject, 1, go); + go = go->next; } } } @@ -3098,15 +3310,15 @@ static void write_groups(WriteData *wd, ListBase *idbase) static void write_nodetrees(WriteData *wd, ListBase *idbase) { bNodeTree *ntree; - - for (ntree=idbase->first; ntree; ntree= ntree->id.next) { - if (ntree->id.us>0 || wd->current) { - writestruct(wd, ID_NT, "bNodeTree", 1, ntree); + + for (ntree = idbase->first; ntree; ntree = ntree->id.next) { + if (ntree->id.us > 0 || wd->current) { + writestruct(wd, ID_NT, bNodeTree, 1, ntree); + /* Note that trees directly used by other IDs (materials etc.) are not 'real' ID, they cannot + * be linked, etc., so we write actual id data here only, for 'real' ID trees. */ + write_iddata(wd, &ntree->id); + write_nodetree(wd, ntree); - - if (ntree->id.properties) IDP_WriteProperty(ntree->id.properties, wd); - - if (ntree->adt) write_animdata(wd, ntree->adt); } } } @@ -3116,11 +3328,12 @@ static void customnodes_add_deprecated_data(Main *mainvar) { FOREACH_NODETREE(mainvar, ntree, id) { bNodeLink *link, *last_link = ntree->links.last; - + /* only do this for node groups */ - if (id != &ntree->id) + if (id != &ntree->id) { continue; - + } + /* Forward compatibility for group nodes: add links to node tree interface sockets. * These links are invalid by new rules (missing node pointer)! * They will be removed again in customnodes_free_deprecated_data, @@ -3131,7 +3344,7 @@ static void customnodes_add_deprecated_data(Main *mainvar) for (link = ntree->links.first; link; link = link->next) { bNode *fromnode = link->fromnode, *tonode = link->tonode; bNodeSocket *fromsock = link->fromsock, *tosock = link->tosock; - + /* check both sides of the link, to handle direct input-to-output links */ if (fromnode->type == NODE_GROUP_INPUT) { fromnode = NULL; @@ -3142,22 +3355,23 @@ static void customnodes_add_deprecated_data(Main *mainvar) tonode = NULL; tosock = ntreeFindSocketInterface(ntree, SOCK_OUT, tosock->identifier); } - + if (!fromnode || !tonode) { /* Note: not using nodeAddLink here, it asserts existing node pointers */ bNodeLink *tlink = MEM_callocN(sizeof(bNodeLink), "group node link"); tlink->fromnode = fromnode; tlink->fromsock = fromsock; tlink->tonode = tonode; - tlink->tosock= tosock; + tlink->tosock = tosock; tosock->link = tlink; tlink->flag |= NODE_LINK_VALID; BLI_addtail(&ntree->links, tlink); } - + /* don't check newly created compatibility links */ - if (link == last_link) + if (link == last_link) { break; + } } } FOREACH_NODETREE_END @@ -3167,11 +3381,12 @@ static void customnodes_free_deprecated_data(Main *mainvar) { FOREACH_NODETREE(mainvar, ntree, id) { bNodeLink *link, *next_link; - + for (link = ntree->links.first; link; link = next_link) { next_link = link->next; - if (link->fromnode == NULL || link->tonode == NULL) + if (link->fromnode == NULL || link->tonode == NULL) { nodeRemLink(ntree, link); + } } } FOREACH_NODETREE_END @@ -3181,16 +3396,18 @@ static void customnodes_free_deprecated_data(Main *mainvar) static void write_brushes(WriteData *wd, ListBase *idbase) { Brush *brush; - - for (brush=idbase->first; brush; brush= brush->id.next) { - if (brush->id.us>0 || wd->current) { - writestruct(wd, ID_BR, "Brush", 1, brush); - if (brush->id.properties) IDP_WriteProperty(brush->id.properties, wd); - - if (brush->curve) + + for (brush = idbase->first; brush; brush = brush->id.next) { + if (brush->id.us > 0 || wd->current) { + writestruct(wd, ID_BR, Brush, 1, brush); + write_iddata(wd, &brush->id); + + if (brush->curve) { write_curvemapping(wd, brush->curve); - if (brush->gradient) - writestruct(wd, DATA, "ColorBand", 1, brush->gradient); + } + if (brush->gradient) { + writestruct(wd, DATA, ColorBand, 1, brush->gradient); + } } } } @@ -3202,11 +3419,12 @@ static void write_palettes(WriteData *wd, ListBase *idbase) for (palette = idbase->first; palette; palette = palette->id.next) { if (palette->id.us > 0 || wd->current) { PaletteColor *color; - writestruct(wd, ID_PAL, "Palette", 1, palette); - if (palette->id.properties) IDP_WriteProperty(palette->id.properties, wd); + writestruct(wd, ID_PAL, Palette, 1, palette); + write_iddata(wd, &palette->id); - for (color = palette->colors.first; color; color= color->next) - writestruct(wd, DATA, "PaletteColor", 1, color); + for (color = palette->colors.first; color; color = color->next) { + writestruct(wd, DATA, PaletteColor, 1, color); + } } } } @@ -3217,10 +3435,10 @@ static void write_paintcurves(WriteData *wd, ListBase *idbase) for (pc = idbase->first; pc; pc = pc->id.next) { if (pc->id.us > 0 || wd->current) { - writestruct(wd, ID_PC, "PaintCurve", 1, pc); + writestruct(wd, ID_PC, PaintCurve, 1, pc); + write_iddata(wd, &pc->id); - writestruct(wd, DATA, "PaintCurvePoint", pc->tot_points, pc->points); - if (pc->id.properties) IDP_WriteProperty(pc->id.properties, wd); + writestruct(wd, DATA, PaintCurvePoint, pc->tot_points, pc->points); } } } @@ -3229,14 +3447,15 @@ static void write_movieTracks(WriteData *wd, ListBase *tracks) { MovieTrackingTrack *track; - track= tracks->first; + track = tracks->first; while (track) { - writestruct(wd, DATA, "MovieTrackingTrack", 1, track); + writestruct(wd, DATA, MovieTrackingTrack, 1, track); - if (track->markers) - writestruct(wd, DATA, "MovieTrackingMarker", track->markersnr, track->markers); + if (track->markers) { + writestruct(wd, DATA, MovieTrackingMarker, track->markersnr, track->markers); + } - track= track->next; + track = track->next; } } @@ -3248,53 +3467,54 @@ static void write_moviePlaneTracks(WriteData *wd, ListBase *plane_tracks_base) plane_track; plane_track = plane_track->next) { - writestruct(wd, DATA, "MovieTrackingPlaneTrack", 1, plane_track); + writestruct(wd, DATA, MovieTrackingPlaneTrack, 1, plane_track); writedata(wd, DATA, sizeof(MovieTrackingTrack *) * plane_track->point_tracksnr, plane_track->point_tracks); - writestruct(wd, DATA, "MovieTrackingPlaneMarker", plane_track->markersnr, plane_track->markers); + writestruct(wd, DATA, MovieTrackingPlaneMarker, plane_track->markersnr, plane_track->markers); } } static void write_movieReconstruction(WriteData *wd, MovieTrackingReconstruction *reconstruction) { - if (reconstruction->camnr) - writestruct(wd, DATA, "MovieReconstructedCamera", reconstruction->camnr, reconstruction->cameras); + if (reconstruction->camnr) { + writestruct(wd, DATA, MovieReconstructedCamera, reconstruction->camnr, reconstruction->cameras); + } } static void write_movieclips(WriteData *wd, ListBase *idbase) { MovieClip *clip; - clip= idbase->first; + clip = idbase->first; while (clip) { - if (clip->id.us>0 || wd->current) { - MovieTracking *tracking= &clip->tracking; + if (clip->id.us > 0 || wd->current) { + MovieTracking *tracking = &clip->tracking; MovieTrackingObject *object; - writestruct(wd, ID_MC, "MovieClip", 1, clip); - if (clip->id.properties) - IDP_WriteProperty(clip->id.properties, wd); + writestruct(wd, ID_MC, MovieClip, 1, clip); + write_iddata(wd, &clip->id); - if (clip->adt) + if (clip->adt) { write_animdata(wd, clip->adt); + } write_movieTracks(wd, &tracking->tracks); write_moviePlaneTracks(wd, &tracking->plane_tracks); write_movieReconstruction(wd, &tracking->reconstruction); - object= tracking->objects.first; + object = tracking->objects.first; while (object) { - writestruct(wd, DATA, "MovieTrackingObject", 1, object); + writestruct(wd, DATA, MovieTrackingObject, 1, object); write_movieTracks(wd, &object->tracks); write_moviePlaneTracks(wd, &object->plane_tracks); write_movieReconstruction(wd, &object->reconstruction); - object= object->next; + object = object->next; } } - clip= clip->id.next; + clip = clip->id.next; } /* flush helps the compression for undo-save */ @@ -3310,16 +3530,18 @@ static void write_masks(WriteData *wd, ListBase *idbase) if (mask->id.us > 0 || wd->current) { MaskLayer *masklay; - writestruct(wd, ID_MSK, "Mask", 1, mask); + writestruct(wd, ID_MSK, Mask, 1, mask); + write_iddata(wd, &mask->id); - if (mask->adt) + if (mask->adt) { write_animdata(wd, mask->adt); + } for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) { MaskSpline *spline; MaskLayerShape *masklay_shape; - writestruct(wd, DATA, "MaskLayer", 1, masklay); + writestruct(wd, DATA, MaskLayer, 1, masklay); for (spline = masklay->splines.first; spline; spline = spline->next) { int i; @@ -3327,22 +3549,28 @@ static void write_masks(WriteData *wd, ListBase *idbase) void *points_deform = spline->points_deform; spline->points_deform = NULL; - writestruct(wd, DATA, "MaskSpline", 1, spline); - writestruct(wd, DATA, "MaskSplinePoint", spline->tot_point, spline->points); + writestruct(wd, DATA, MaskSpline, 1, spline); + writestruct(wd, DATA, MaskSplinePoint, spline->tot_point, spline->points); spline->points_deform = points_deform; for (i = 0; i < spline->tot_point; i++) { MaskSplinePoint *point = &spline->points[i]; - if (point->tot_uw) - writestruct(wd, DATA, "MaskSplinePointUW", point->tot_uw, point->uw); + if (point->tot_uw) { + writestruct(wd, DATA, MaskSplinePointUW, point->tot_uw, point->uw); + } } } - for (masklay_shape = masklay->splines_shapes.first; masklay_shape; masklay_shape = masklay_shape->next) { - writestruct(wd, DATA, "MaskLayerShape", 1, masklay_shape); - writedata(wd, DATA, masklay_shape->tot_vert * sizeof(float) * MASK_OBJECT_SHAPE_ELEM_SIZE, masklay_shape->data); + for (masklay_shape = masklay->splines_shapes.first; + masklay_shape; + masklay_shape = masklay_shape->next) + { + writestruct(wd, DATA, MaskLayerShape, 1, masklay_shape); + writedata(wd, DATA, + masklay_shape->tot_vert * sizeof(float) * MASK_OBJECT_SHAPE_ELEM_SIZE, + masklay_shape->data); } } } @@ -3357,65 +3585,65 @@ static void write_masks(WriteData *wd, ListBase *idbase) static void write_linestyle_color_modifiers(WriteData *wd, ListBase *modifiers) { LineStyleModifier *m; - const char *struct_name; for (m = modifiers->first; m; m = m->next) { + int struct_nr; switch (m->type) { - case LS_MODIFIER_ALONG_STROKE: - struct_name = "LineStyleColorModifier_AlongStroke"; - break; - case LS_MODIFIER_DISTANCE_FROM_CAMERA: - struct_name = "LineStyleColorModifier_DistanceFromCamera"; - break; - case LS_MODIFIER_DISTANCE_FROM_OBJECT: - struct_name = "LineStyleColorModifier_DistanceFromObject"; - break; - case LS_MODIFIER_MATERIAL: - struct_name = "LineStyleColorModifier_Material"; - break; - case LS_MODIFIER_TANGENT: - struct_name = "LineStyleColorModifier_Tangent"; - break; - case LS_MODIFIER_NOISE: - struct_name = "LineStyleColorModifier_Noise"; - break; - case LS_MODIFIER_CREASE_ANGLE: - struct_name = "LineStyleColorModifier_CreaseAngle"; - break; - case LS_MODIFIER_CURVATURE_3D: - struct_name = "LineStyleColorModifier_Curvature_3D"; - break; - default: - struct_name = "LineStyleColorModifier"; /* this should not happen */ + case LS_MODIFIER_ALONG_STROKE: + struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleColorModifier_AlongStroke); + break; + case LS_MODIFIER_DISTANCE_FROM_CAMERA: + struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleColorModifier_DistanceFromCamera); + break; + case LS_MODIFIER_DISTANCE_FROM_OBJECT: + struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleColorModifier_DistanceFromObject); + break; + case LS_MODIFIER_MATERIAL: + struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleColorModifier_Material); + break; + case LS_MODIFIER_TANGENT: + struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleColorModifier_Tangent); + break; + case LS_MODIFIER_NOISE: + struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleColorModifier_Noise); + break; + case LS_MODIFIER_CREASE_ANGLE: + struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleColorModifier_CreaseAngle); + break; + case LS_MODIFIER_CURVATURE_3D: + struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleColorModifier_Curvature_3D); + break; + default: + struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleModifier); /* this should not happen */ } - writestruct(wd, DATA, struct_name, 1, m); + writestruct_nr(wd, DATA, struct_nr, 1, m); } for (m = modifiers->first; m; m = m->next) { switch (m->type) { - case LS_MODIFIER_ALONG_STROKE: - writestruct(wd, DATA, "ColorBand", 1, ((LineStyleColorModifier_AlongStroke *)m)->color_ramp); - break; - case LS_MODIFIER_DISTANCE_FROM_CAMERA: - writestruct(wd, DATA, "ColorBand", 1, ((LineStyleColorModifier_DistanceFromCamera *)m)->color_ramp); - break; - case LS_MODIFIER_DISTANCE_FROM_OBJECT: - writestruct(wd, DATA, "ColorBand", 1, ((LineStyleColorModifier_DistanceFromObject *)m)->color_ramp); - break; - case LS_MODIFIER_MATERIAL: - writestruct(wd, DATA, "ColorBand", 1, ((LineStyleColorModifier_Material *)m)->color_ramp); - break; - case LS_MODIFIER_TANGENT: - writestruct(wd, DATA, "ColorBand", 1, ((LineStyleColorModifier_Tangent *)m)->color_ramp); - break; - case LS_MODIFIER_NOISE: - writestruct(wd, DATA, "ColorBand", 1, ((LineStyleColorModifier_Noise *)m)->color_ramp); - break; - case LS_MODIFIER_CREASE_ANGLE: - writestruct(wd, DATA, "ColorBand", 1, ((LineStyleColorModifier_CreaseAngle *)m)->color_ramp); - break; - case LS_MODIFIER_CURVATURE_3D: - writestruct(wd, DATA, "ColorBand", 1, ((LineStyleColorModifier_Curvature_3D *)m)->color_ramp); - break; + case LS_MODIFIER_ALONG_STROKE: + writestruct(wd, DATA, ColorBand, 1, ((LineStyleColorModifier_AlongStroke *)m)->color_ramp); + break; + case LS_MODIFIER_DISTANCE_FROM_CAMERA: + writestruct(wd, DATA, ColorBand, 1, ((LineStyleColorModifier_DistanceFromCamera *)m)->color_ramp); + break; + case LS_MODIFIER_DISTANCE_FROM_OBJECT: + writestruct(wd, DATA, ColorBand, 1, ((LineStyleColorModifier_DistanceFromObject *)m)->color_ramp); + break; + case LS_MODIFIER_MATERIAL: + writestruct(wd, DATA, ColorBand, 1, ((LineStyleColorModifier_Material *)m)->color_ramp); + break; + case LS_MODIFIER_TANGENT: + writestruct(wd, DATA, ColorBand, 1, ((LineStyleColorModifier_Tangent *)m)->color_ramp); + break; + case LS_MODIFIER_NOISE: + writestruct(wd, DATA, ColorBand, 1, ((LineStyleColorModifier_Noise *)m)->color_ramp); + break; + case LS_MODIFIER_CREASE_ANGLE: + writestruct(wd, DATA, ColorBand, 1, ((LineStyleColorModifier_CreaseAngle *)m)->color_ramp); + break; + case LS_MODIFIER_CURVATURE_3D: + writestruct(wd, DATA, ColorBand, 1, ((LineStyleColorModifier_Curvature_3D *)m)->color_ramp); + break; } } } @@ -3423,65 +3651,65 @@ static void write_linestyle_color_modifiers(WriteData *wd, ListBase *modifiers) static void write_linestyle_alpha_modifiers(WriteData *wd, ListBase *modifiers) { LineStyleModifier *m; - const char *struct_name; for (m = modifiers->first; m; m = m->next) { + int struct_nr; switch (m->type) { - case LS_MODIFIER_ALONG_STROKE: - struct_name = "LineStyleAlphaModifier_AlongStroke"; - break; - case LS_MODIFIER_DISTANCE_FROM_CAMERA: - struct_name = "LineStyleAlphaModifier_DistanceFromCamera"; - break; - case LS_MODIFIER_DISTANCE_FROM_OBJECT: - struct_name = "LineStyleAlphaModifier_DistanceFromObject"; - break; - case LS_MODIFIER_MATERIAL: - struct_name = "LineStyleAlphaModifier_Material"; - break; - case LS_MODIFIER_TANGENT: - struct_name = "LineStyleAlphaModifier_Tangent"; - break; - case LS_MODIFIER_NOISE: - struct_name = "LineStyleAlphaModifier_Noise"; - break; - case LS_MODIFIER_CREASE_ANGLE: - struct_name = "LineStyleAlphaModifier_CreaseAngle"; - break; - case LS_MODIFIER_CURVATURE_3D: - struct_name = "LineStyleAlphaModifier_Curvature_3D"; - break; - default: - struct_name = "LineStyleAlphaModifier"; /* this should not happen */ + case LS_MODIFIER_ALONG_STROKE: + struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleAlphaModifier_AlongStroke); + break; + case LS_MODIFIER_DISTANCE_FROM_CAMERA: + struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleAlphaModifier_DistanceFromCamera); + break; + case LS_MODIFIER_DISTANCE_FROM_OBJECT: + struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleAlphaModifier_DistanceFromObject); + break; + case LS_MODIFIER_MATERIAL: + struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleAlphaModifier_Material); + break; + case LS_MODIFIER_TANGENT: + struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleAlphaModifier_Tangent); + break; + case LS_MODIFIER_NOISE: + struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleAlphaModifier_Noise); + break; + case LS_MODIFIER_CREASE_ANGLE: + struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleAlphaModifier_CreaseAngle); + break; + case LS_MODIFIER_CURVATURE_3D: + struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleAlphaModifier_Curvature_3D); + break; + default: + struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleModifier); /* this should not happen */ } - writestruct(wd, DATA, struct_name, 1, m); + writestruct_nr(wd, DATA, struct_nr, 1, m); } for (m = modifiers->first; m; m = m->next) { switch (m->type) { - case LS_MODIFIER_ALONG_STROKE: - write_curvemapping(wd, ((LineStyleAlphaModifier_AlongStroke *)m)->curve); - break; - case LS_MODIFIER_DISTANCE_FROM_CAMERA: - write_curvemapping(wd, ((LineStyleAlphaModifier_DistanceFromCamera *)m)->curve); - break; - case LS_MODIFIER_DISTANCE_FROM_OBJECT: - write_curvemapping(wd, ((LineStyleAlphaModifier_DistanceFromObject *)m)->curve); - break; - case LS_MODIFIER_MATERIAL: - write_curvemapping(wd, ((LineStyleAlphaModifier_Material *)m)->curve); - break; - case LS_MODIFIER_TANGENT: - write_curvemapping(wd, ((LineStyleAlphaModifier_Tangent *)m)->curve); - break; - case LS_MODIFIER_NOISE: - write_curvemapping(wd, ((LineStyleAlphaModifier_Noise *)m)->curve); - break; - case LS_MODIFIER_CREASE_ANGLE: - write_curvemapping(wd, ((LineStyleAlphaModifier_CreaseAngle *)m)->curve); - break; - case LS_MODIFIER_CURVATURE_3D: - write_curvemapping(wd, ((LineStyleAlphaModifier_Curvature_3D *)m)->curve); - break; + case LS_MODIFIER_ALONG_STROKE: + write_curvemapping(wd, ((LineStyleAlphaModifier_AlongStroke *)m)->curve); + break; + case LS_MODIFIER_DISTANCE_FROM_CAMERA: + write_curvemapping(wd, ((LineStyleAlphaModifier_DistanceFromCamera *)m)->curve); + break; + case LS_MODIFIER_DISTANCE_FROM_OBJECT: + write_curvemapping(wd, ((LineStyleAlphaModifier_DistanceFromObject *)m)->curve); + break; + case LS_MODIFIER_MATERIAL: + write_curvemapping(wd, ((LineStyleAlphaModifier_Material *)m)->curve); + break; + case LS_MODIFIER_TANGENT: + write_curvemapping(wd, ((LineStyleAlphaModifier_Tangent *)m)->curve); + break; + case LS_MODIFIER_NOISE: + write_curvemapping(wd, ((LineStyleAlphaModifier_Noise *)m)->curve); + break; + case LS_MODIFIER_CREASE_ANGLE: + write_curvemapping(wd, ((LineStyleAlphaModifier_CreaseAngle *)m)->curve); + break; + case LS_MODIFIER_CURVATURE_3D: + write_curvemapping(wd, ((LineStyleAlphaModifier_Curvature_3D *)m)->curve); + break; } } } @@ -3489,65 +3717,65 @@ static void write_linestyle_alpha_modifiers(WriteData *wd, ListBase *modifiers) static void write_linestyle_thickness_modifiers(WriteData *wd, ListBase *modifiers) { LineStyleModifier *m; - const char *struct_name; for (m = modifiers->first; m; m = m->next) { + int struct_nr; switch (m->type) { - case LS_MODIFIER_ALONG_STROKE: - struct_name = "LineStyleThicknessModifier_AlongStroke"; - break; - case LS_MODIFIER_DISTANCE_FROM_CAMERA: - struct_name = "LineStyleThicknessModifier_DistanceFromCamera"; - break; - case LS_MODIFIER_DISTANCE_FROM_OBJECT: - struct_name = "LineStyleThicknessModifier_DistanceFromObject"; - break; - case LS_MODIFIER_MATERIAL: - struct_name = "LineStyleThicknessModifier_Material"; - break; - case LS_MODIFIER_CALLIGRAPHY: - struct_name = "LineStyleThicknessModifier_Calligraphy"; - break; - case LS_MODIFIER_TANGENT: - struct_name = "LineStyleThicknessModifier_Tangent"; - break; - case LS_MODIFIER_NOISE: - struct_name = "LineStyleThicknessModifier_Noise"; - break; - case LS_MODIFIER_CREASE_ANGLE: - struct_name = "LineStyleThicknessModifier_CreaseAngle"; - break; - case LS_MODIFIER_CURVATURE_3D: - struct_name = "LineStyleThicknessModifier_Curvature_3D"; - break; - default: - struct_name = "LineStyleThicknessModifier"; /* this should not happen */ + case LS_MODIFIER_ALONG_STROKE: + struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleThicknessModifier_AlongStroke); + break; + case LS_MODIFIER_DISTANCE_FROM_CAMERA: + struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleThicknessModifier_DistanceFromCamera); + break; + case LS_MODIFIER_DISTANCE_FROM_OBJECT: + struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleThicknessModifier_DistanceFromObject); + break; + case LS_MODIFIER_MATERIAL: + struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleThicknessModifier_Material); + break; + case LS_MODIFIER_CALLIGRAPHY: + struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleThicknessModifier_Calligraphy); + break; + case LS_MODIFIER_TANGENT: + struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleThicknessModifier_Tangent); + break; + case LS_MODIFIER_NOISE: + struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleThicknessModifier_Noise); + break; + case LS_MODIFIER_CREASE_ANGLE: + struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleThicknessModifier_CreaseAngle); + break; + case LS_MODIFIER_CURVATURE_3D: + struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleThicknessModifier_Curvature_3D); + break; + default: + struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleModifier); /* this should not happen */ } - writestruct(wd, DATA, struct_name, 1, m); + writestruct_nr(wd, DATA, struct_nr, 1, m); } for (m = modifiers->first; m; m = m->next) { switch (m->type) { - case LS_MODIFIER_ALONG_STROKE: - write_curvemapping(wd, ((LineStyleThicknessModifier_AlongStroke *)m)->curve); - break; - case LS_MODIFIER_DISTANCE_FROM_CAMERA: - write_curvemapping(wd, ((LineStyleThicknessModifier_DistanceFromCamera *)m)->curve); - break; - case LS_MODIFIER_DISTANCE_FROM_OBJECT: - write_curvemapping(wd, ((LineStyleThicknessModifier_DistanceFromObject *)m)->curve); - break; - case LS_MODIFIER_MATERIAL: - write_curvemapping(wd, ((LineStyleThicknessModifier_Material *)m)->curve); - break; - case LS_MODIFIER_TANGENT: - write_curvemapping(wd, ((LineStyleThicknessModifier_Tangent *)m)->curve); - break; - case LS_MODIFIER_CREASE_ANGLE: - write_curvemapping(wd, ((LineStyleThicknessModifier_CreaseAngle *)m)->curve); - break; - case LS_MODIFIER_CURVATURE_3D: - write_curvemapping(wd, ((LineStyleThicknessModifier_Curvature_3D *)m)->curve); - break; + case LS_MODIFIER_ALONG_STROKE: + write_curvemapping(wd, ((LineStyleThicknessModifier_AlongStroke *)m)->curve); + break; + case LS_MODIFIER_DISTANCE_FROM_CAMERA: + write_curvemapping(wd, ((LineStyleThicknessModifier_DistanceFromCamera *)m)->curve); + break; + case LS_MODIFIER_DISTANCE_FROM_OBJECT: + write_curvemapping(wd, ((LineStyleThicknessModifier_DistanceFromObject *)m)->curve); + break; + case LS_MODIFIER_MATERIAL: + write_curvemapping(wd, ((LineStyleThicknessModifier_Material *)m)->curve); + break; + case LS_MODIFIER_TANGENT: + write_curvemapping(wd, ((LineStyleThicknessModifier_Tangent *)m)->curve); + break; + case LS_MODIFIER_CREASE_ANGLE: + write_curvemapping(wd, ((LineStyleThicknessModifier_CreaseAngle *)m)->curve); + break; + case LS_MODIFIER_CURVATURE_3D: + write_curvemapping(wd, ((LineStyleThicknessModifier_Curvature_3D *)m)->curve); + break; } } } @@ -3555,56 +3783,56 @@ static void write_linestyle_thickness_modifiers(WriteData *wd, ListBase *modifie static void write_linestyle_geometry_modifiers(WriteData *wd, ListBase *modifiers) { LineStyleModifier *m; - const char *struct_name; for (m = modifiers->first; m; m = m->next) { + int struct_nr; switch (m->type) { - case LS_MODIFIER_SAMPLING: - struct_name = "LineStyleGeometryModifier_Sampling"; - break; - case LS_MODIFIER_BEZIER_CURVE: - struct_name = "LineStyleGeometryModifier_BezierCurve"; - break; - case LS_MODIFIER_SINUS_DISPLACEMENT: - struct_name = "LineStyleGeometryModifier_SinusDisplacement"; - break; - case LS_MODIFIER_SPATIAL_NOISE: - struct_name = "LineStyleGeometryModifier_SpatialNoise"; - break; - case LS_MODIFIER_PERLIN_NOISE_1D: - struct_name = "LineStyleGeometryModifier_PerlinNoise1D"; - break; - case LS_MODIFIER_PERLIN_NOISE_2D: - struct_name = "LineStyleGeometryModifier_PerlinNoise2D"; - break; - case LS_MODIFIER_BACKBONE_STRETCHER: - struct_name = "LineStyleGeometryModifier_BackboneStretcher"; - break; - case LS_MODIFIER_TIP_REMOVER: - struct_name = "LineStyleGeometryModifier_TipRemover"; - break; - case LS_MODIFIER_POLYGONIZATION: - struct_name = "LineStyleGeometryModifier_Polygonalization"; - break; - case LS_MODIFIER_GUIDING_LINES: - struct_name = "LineStyleGeometryModifier_GuidingLines"; - break; - case LS_MODIFIER_BLUEPRINT: - struct_name = "LineStyleGeometryModifier_Blueprint"; - break; - case LS_MODIFIER_2D_OFFSET: - struct_name = "LineStyleGeometryModifier_2DOffset"; - break; - case LS_MODIFIER_2D_TRANSFORM: - struct_name = "LineStyleGeometryModifier_2DTransform"; - break; - case LS_MODIFIER_SIMPLIFICATION: - struct_name = "LineStyleGeometryModifier_Simplification"; - break; - default: - struct_name = "LineStyleGeometryModifier"; /* this should not happen */ + case LS_MODIFIER_SAMPLING: + struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleGeometryModifier_Sampling); + break; + case LS_MODIFIER_BEZIER_CURVE: + struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleGeometryModifier_BezierCurve); + break; + case LS_MODIFIER_SINUS_DISPLACEMENT: + struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleGeometryModifier_SinusDisplacement); + break; + case LS_MODIFIER_SPATIAL_NOISE: + struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleGeometryModifier_SpatialNoise); + break; + case LS_MODIFIER_PERLIN_NOISE_1D: + struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleGeometryModifier_PerlinNoise1D); + break; + case LS_MODIFIER_PERLIN_NOISE_2D: + struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleGeometryModifier_PerlinNoise2D); + break; + case LS_MODIFIER_BACKBONE_STRETCHER: + struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleGeometryModifier_BackboneStretcher); + break; + case LS_MODIFIER_TIP_REMOVER: + struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleGeometryModifier_TipRemover); + break; + case LS_MODIFIER_POLYGONIZATION: + struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleGeometryModifier_Polygonalization); + break; + case LS_MODIFIER_GUIDING_LINES: + struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleGeometryModifier_GuidingLines); + break; + case LS_MODIFIER_BLUEPRINT: + struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleGeometryModifier_Blueprint); + break; + case LS_MODIFIER_2D_OFFSET: + struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleGeometryModifier_2DOffset); + break; + case LS_MODIFIER_2D_TRANSFORM: + struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleGeometryModifier_2DTransform); + break; + case LS_MODIFIER_SIMPLIFICATION: + struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleGeometryModifier_Simplification); + break; + default: + struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleModifier); /* this should not happen */ } - writestruct(wd, DATA, struct_name, 1, m); + writestruct_nr(wd, DATA, struct_nr, 1, m); } } @@ -3614,27 +3842,94 @@ static void write_linestyles(WriteData *wd, ListBase *idbase) int a; for (linestyle = idbase->first; linestyle; linestyle = linestyle->id.next) { - if (linestyle->id.us>0 || wd->current) { - writestruct(wd, ID_LS, "FreestyleLineStyle", 1, linestyle); - if (linestyle->id.properties) - IDP_WriteProperty(linestyle->id.properties, wd); - if (linestyle->adt) + if (linestyle->id.us > 0 || wd->current) { + writestruct(wd, ID_LS, FreestyleLineStyle, 1, linestyle); + write_iddata(wd, &linestyle->id); + + if (linestyle->adt) { write_animdata(wd, linestyle->adt); + } + write_linestyle_color_modifiers(wd, &linestyle->color_modifiers); write_linestyle_alpha_modifiers(wd, &linestyle->alpha_modifiers); write_linestyle_thickness_modifiers(wd, &linestyle->thickness_modifiers); write_linestyle_geometry_modifiers(wd, &linestyle->geometry_modifiers); - for (a=0; a<MAX_MTEX; a++) { - if (linestyle->mtex[a]) writestruct(wd, DATA, "MTex", 1, linestyle->mtex[a]); + for (a = 0; a < MAX_MTEX; a++) { + if (linestyle->mtex[a]) { + writestruct(wd, DATA, MTex, 1, linestyle->mtex[a]); + } } if (linestyle->nodetree) { - writestruct(wd, DATA, "bNodeTree", 1, linestyle->nodetree); + writestruct(wd, DATA, bNodeTree, 1, linestyle->nodetree); write_nodetree(wd, linestyle->nodetree); } } } } +/* Keep it last of write_foodata functions. */ +static void write_libraries(WriteData *wd, Main *main) +{ + ListBase *lbarray[MAX_LIBARRAY]; + ID *id; + int a, tot; + bool found_one; + + for (; main; main = main->next) { + + a = tot = set_listbasepointers(main, lbarray); + + /* test: is lib being used */ + if (main->curlib && main->curlib->packedfile) { + found_one = true; + } + else { + found_one = false; + while (tot--) { + for (id = lbarray[tot]->first; id; id = id->next) { + if (id->us > 0 && (id->tag & LIB_TAG_EXTERN)) { + found_one = true; + break; + } + } + if (found_one) { + break; + } + } + } + + /* to be able to restore quit.blend and temp saves, the packed blend has to be in undo buffers... */ + /* XXX needs rethink, just like save UI in undo files now - would be nice to append things only for the] + * quit.blend and temp saves */ + if (found_one) { + writestruct(wd, ID_LI, Library, 1, main->curlib); + write_iddata(wd, &main->curlib->id); + + if (main->curlib->packedfile) { + PackedFile *pf = main->curlib->packedfile; + writestruct(wd, DATA, PackedFile, 1, pf); + writedata(wd, DATA, pf->size, pf->data); + if (wd->current == NULL) { + printf("write packed .blend: %s\n", main->curlib->name); + } + } + + while (a--) { + for (id = lbarray[a]->first; id; id = id->next) { + if (id->us > 0 && (id->tag & LIB_TAG_EXTERN)) { + if (!BKE_idcode_is_linkable(GS(id->name))) { + printf("ERROR: write file: datablock '%s' from lib '%s' is not linkable " + "but is flagged as directly linked", id->name, main->curlib->filepath); + BLI_assert(0); + } + writestruct(wd, ID_ID, ID, 1, id); + } + } + } + } + } +} + /* context is usually defined by WM, two cases where no WM is available: * - for forward compatibility, curscreen has to be saved * - for undofile, curscene needs to be saved */ @@ -3644,7 +3939,7 @@ static void write_global(WriteData *wd, int fileflags, Main *mainvar) FileGlobal fg; bScreen *screen; char subvstr[8]; - + /* prevent mem checkers from complaining */ memset(fg.pad, 0, sizeof(fg.pad)); memset(fg.filename, 0, sizeof(fg.filename)); @@ -3653,20 +3948,20 @@ static void write_global(WriteData *wd, int fileflags, Main *mainvar) current_screen_compat(mainvar, &screen, is_undo); /* XXX still remap G */ - fg.curscreen= screen; - fg.curscene= screen ? screen->scene : NULL; + fg.curscreen = screen; + fg.curscene = screen ? screen->scene : NULL; /* prevent to save this, is not good convention, and feature with concerns... */ - fg.fileflags= (fileflags & ~G_FILE_FLAGS_RUNTIME); + fg.fileflags = (fileflags & ~G_FILE_FLAGS_RUNTIME); - fg.globalf= G.f; + fg.globalf = G.f; BLI_strncpy(fg.filename, mainvar->name, sizeof(fg.filename)); sprintf(subvstr, "%4d", BLENDER_SUBVERSION); memcpy(fg.subvstr, subvstr, 4); - - fg.subversion= BLENDER_SUBVERSION; - fg.minversion= BLENDER_MINVERSION; - fg.minsubversion= BLENDER_MINSUBVERSION; + + fg.subversion = BLENDER_SUBVERSION; + fg.minversion = BLENDER_MINVERSION; + fg.minsubversion = BLENDER_MINSUBVERSION; #ifdef WITH_BUILDINFO { extern unsigned long build_commit_timestamp; @@ -3679,7 +3974,7 @@ static void write_global(WriteData *wd, int fileflags, Main *mainvar) fg.build_commit_timestamp = 0; BLI_strncpy(fg.build_hash, "unknown", sizeof(fg.build_hash)); #endif - writestruct(wd, GLOB, "FileGlobal", 1, &fg); + writestruct(wd, GLOB, FileGlobal, 1, &fg); } /* preview image, first 2 values are width and height @@ -3694,11 +3989,11 @@ static void write_thumb(WriteData *wd, const BlendThumbnail *thumb) } /* if MemFile * there's filesave to memory */ -static int write_file_handle( +static bool write_file_handle( Main *mainvar, WriteWrap *ww, MemFile *compare, MemFile *current, - int write_user_block, int write_flags, const BlendThumbnail *thumb) + int write_flags, const BlendThumbnail *thumb) { BHead bhead; ListBase mainlist; @@ -3733,42 +4028,42 @@ static int write_file_handle( write_global(wd, write_flags, mainvar); write_windowmanagers(wd, &mainvar->wm); - write_screens (wd, &mainvar->screen); - write_movieclips (wd, &mainvar->movieclip); - write_masks (wd, &mainvar->mask); - write_scenes (wd, &mainvar->scene); - write_curves (wd, &mainvar->curve); - write_mballs (wd, &mainvar->mball); - write_images (wd, &mainvar->image); - write_cameras (wd, &mainvar->camera); - write_lamps (wd, &mainvar->lamp); - write_lattices (wd, &mainvar->latt); - write_vfonts (wd, &mainvar->vfont); - write_keys (wd, &mainvar->key); - write_worlds (wd, &mainvar->world); - write_texts (wd, &mainvar->text); - write_speakers (wd, &mainvar->speaker); - write_sounds (wd, &mainvar->sound); - write_groups (wd, &mainvar->group); + write_screens(wd, &mainvar->screen); + write_movieclips(wd, &mainvar->movieclip); + write_masks(wd, &mainvar->mask); + write_scenes(wd, &mainvar->scene); + write_curves(wd, &mainvar->curve); + write_mballs(wd, &mainvar->mball); + write_images(wd, &mainvar->image); + write_cameras(wd, &mainvar->camera); + write_lamps(wd, &mainvar->lamp); + write_lattices(wd, &mainvar->latt); + write_vfonts(wd, &mainvar->vfont); + write_keys(wd, &mainvar->key); + write_worlds(wd, &mainvar->world); + write_texts(wd, &mainvar->text); + write_speakers(wd, &mainvar->speaker); + write_sounds(wd, &mainvar->sound); + write_groups(wd, &mainvar->group); write_armatures(wd, &mainvar->armature); - write_actions (wd, &mainvar->action); - write_objects (wd, &mainvar->object); + write_actions(wd, &mainvar->action); + write_objects(wd, &mainvar->object); write_materials(wd, &mainvar->mat); - write_textures (wd, &mainvar->tex); - write_meshes (wd, &mainvar->mesh); + write_textures(wd, &mainvar->tex); + write_meshes(wd, &mainvar->mesh); write_particlesettings(wd, &mainvar->particle); write_nodetrees(wd, &mainvar->nodetree); - write_brushes (wd, &mainvar->brush); - write_palettes (wd, &mainvar->palettes); - write_paintcurves (wd, &mainvar->paintcurves); - write_gpencils (wd, &mainvar->gpencil); + write_brushes(wd, &mainvar->brush); + write_palettes(wd, &mainvar->palettes); + write_paintcurves(wd, &mainvar->paintcurves); + write_gpencils(wd, &mainvar->gpencil); write_linestyles(wd, &mainvar->linestyle); write_libraries(wd, mainvar->next); - if (write_user_block) { + if (write_flags & G_FILE_USERPREFS) { write_userdef(wd); } - + /* dna as last, because (to be implemented) test for which structs are written */ writedata(wd, DNA1, wd->sdna->datalen, wd->sdna->data); @@ -3785,7 +4080,7 @@ static int write_file_handle( /* end of file */ memset(&bhead, 0, sizeof(BHead)); - bhead.code= ENDB; + bhead.code = ENDB; mywrite(wd, &bhead, sizeof(BHead)); blo_join_main(&mainlist); @@ -3798,16 +4093,19 @@ static int write_file_handle( static bool do_history(const char *name, ReportList *reports) { char tempname1[FILE_MAX], tempname2[FILE_MAX]; - int hisnr= U.versions; - - if (U.versions==0) return 0; - if (strlen(name)<2) { + int hisnr = U.versions; + + if (U.versions == 0) { + return 0; + } + + if (strlen(name) < 2) { BKE_report(reports, RPT_ERROR, "Unable to make version backup: filename too short"); return 1; } while (hisnr > 1) { - BLI_snprintf(tempname1, sizeof(tempname1), "%s%d", name, hisnr-1); + BLI_snprintf(tempname1, sizeof(tempname1), "%s%d", name, hisnr - 1); if (BLI_exists(tempname1)) { BLI_snprintf(tempname2, sizeof(tempname2), "%s%d", name, hisnr); @@ -3839,8 +4137,7 @@ bool BLO_write_file( Main *mainvar, const char *filepath, int write_flags, ReportList *reports, const BlendThumbnail *thumb) { - char tempname[FILE_MAX+1]; - int err, write_user_block; + char tempname[FILE_MAX + 1]; eWriteWrapType ww_type; WriteWrap ww; @@ -3895,13 +4192,13 @@ bool BLO_write_file( } } - write_user_block= write_flags & G_FILE_USERPREFS; - - if (write_flags & G_FILE_RELATIVE_REMAP) - BKE_bpath_relative_convert(mainvar, filepath, NULL); /* note, making relative to something OTHER then G.main->name */ + if (write_flags & G_FILE_RELATIVE_REMAP) { + /* note, making relative to something OTHER then G.main->name */ + BKE_bpath_relative_convert(mainvar, filepath, NULL); + } /* actual file writing */ - err = write_file_handle(mainvar, &ww, NULL, NULL, write_user_block, write_flags, thumb); + const bool err = write_file_handle(mainvar, &ww, NULL, NULL, write_flags, thumb); ww.close(&ww); @@ -3940,9 +4237,9 @@ bool BLO_write_file( */ bool BLO_write_file_mem(Main *mainvar, MemFile *compare, MemFile *current, int write_flags) { - int err; + write_flags &= ~G_FILE_USERPREFS; - err = write_file_handle(mainvar, NULL, compare, current, 0, write_flags, NULL); + const bool err = write_file_handle(mainvar, NULL, compare, current, write_flags, NULL); return (err == 0); } diff --git a/source/blender/bmesh/bmesh_class.h b/source/blender/bmesh/bmesh_class.h index e3caeedd2c9..72ea7bd7f5d 100644 --- a/source/blender/bmesh/bmesh_class.h +++ b/source/blender/bmesh/bmesh_class.h @@ -89,7 +89,6 @@ BLI_STATIC_ASSERT((sizeof(BMHeader) <= 16), "BMHeader size has grown!"); typedef struct BMVert { BMHeader head; - struct BMFlagLayer *oflags; /* keep after header, an array of flags, mostly used by the operator stack */ float co[3]; /* vertex coordinates */ float no[3]; /* vertex normal */ @@ -102,6 +101,11 @@ typedef struct BMVert { struct BMEdge *e; } BMVert; +typedef struct BMVert_OFlag { + BMVert base; + struct BMFlagLayer *oflags; +} BMVert_OFlag; + /* disk link structure, only used by edges */ typedef struct BMDiskLink { struct BMEdge *next, *prev; @@ -109,7 +113,6 @@ typedef struct BMDiskLink { typedef struct BMEdge { BMHeader head; - struct BMFlagLayer *oflags; /* keep after header, an array of flags, mostly used by the operator stack */ struct BMVert *v1, *v2; /* vertices (unordered) */ @@ -122,6 +125,11 @@ typedef struct BMEdge { BMDiskLink v1_disk_link, v2_disk_link; } BMEdge; +typedef struct BMEdge_OFlag { + BMEdge base; + struct BMFlagLayer *oflags; +} BMEdge_OFlag; + typedef struct BMLoop { BMHeader head; /* notice no flags layer */ @@ -142,10 +150,6 @@ typedef struct BMLoop { /* can cast BMFace/BMEdge/BMVert, but NOT BMLoop, since these don't have a flag layer */ typedef struct BMElemF { BMHeader head; - - /* keep directly after header, - * optional array of flags, only used by the operator stack */ - struct BMFlagLayer *oflags; } BMElemF; /* can cast anything to this, including BMLoop */ @@ -163,7 +167,6 @@ typedef struct BMLoopList { typedef struct BMFace { BMHeader head; - struct BMFlagLayer *oflags; /* an array of flags, mostly used by the operator stack */ #ifdef USE_BMESH_HOLES int totbounds; /*total boundaries, is one plus the number of holes in the face*/ @@ -177,6 +180,11 @@ typedef struct BMFace { // short _pad[3]; } BMFace; +typedef struct BMFace_OFlag { + BMFace base; + struct BMFlagLayer *oflags; +} BMFace_OFlag; + typedef struct BMFlagLayer { short f; /* flags */ } BMFlagLayer; @@ -217,6 +225,8 @@ typedef struct BMesh { /* operator api stuff (must be all NULL or all alloc'd) */ struct BLI_mempool *vtoolflagpool, *etoolflagpool, *ftoolflagpool; + unsigned int use_toolflags : 1; + int toolflag_index; struct BMOperator *currentop; @@ -259,10 +269,12 @@ enum { /* args for _Generic */ #define _BM_GENERIC_TYPE_ELEM_NONCONST \ void *, BMVert *, BMEdge *, BMLoop *, BMFace *, \ + BMVert_OFlag *, BMEdge_OFlag *, BMFace_OFlag *, \ BMElem *, BMElemF *, BMHeader * #define _BM_GENERIC_TYPE_ELEM_CONST \ const void *, const BMVert *, const BMEdge *, const BMLoop *, const BMFace *, \ + const BMVert_OFlag *, const BMEdge_OFlag *, const BMFace_OFlag *, \ const BMElem *, const BMElemF *, const BMHeader *, \ void * const, BMVert * const, BMEdge * const, BMLoop * const, BMFace * const, \ BMElem * const, BMElemF * const, BMHeader * const @@ -276,6 +288,27 @@ enum { #define BM_CHECK_TYPE_ELEM(ele) \ CHECK_TYPE_ANY(ele, _BM_GENERIC_TYPE_ELEM_NONCONST, _BM_GENERIC_TYPE_ELEM_CONST) +/* vert */ +#define _BM_GENERIC_TYPE_VERT_NONCONST BMVert *, BMVert_OFlag * +#define _BM_GENERIC_TYPE_VERT_CONST const BMVert *, const BMVert_OFlag * +#define BM_CHECK_TYPE_VERT_CONST(ele) CHECK_TYPE_ANY(ele, _BM_GENERIC_TYPE_VERT_CONST) +#define BM_CHECK_TYPE_VERT_NONCONST(ele) CHECK_TYPE_ANY(ele, _BM_GENERIC_TYPE_ELEM_NONCONST) +#define BM_CHECK_TYPE_VERT(ele) CHECK_TYPE_ANY(ele, _BM_GENERIC_TYPE_VERT_NONCONST, _BM_GENERIC_TYPE_VERT_CONST) +/* edge */ +#define _BM_GENERIC_TYPE_EDGE_NONCONST BMEdge *, BMEdge_OFlag * +#define _BM_GENERIC_TYPE_EDGE_CONST const BMEdge *, const BMEdge_OFlag * +#define BM_CHECK_TYPE_EDGE_CONST(ele) CHECK_TYPE_ANY(ele, _BM_GENERIC_TYPE_EDGE_CONST) +#define BM_CHECK_TYPE_EDGE_NONCONST(ele) CHECK_TYPE_ANY(ele, _BM_GENERIC_TYPE_ELEM_NONCONST) +#define BM_CHECK_TYPE_EDGE(ele) CHECK_TYPE_ANY(ele, _BM_GENERIC_TYPE_EDGE_NONCONST, _BM_GENERIC_TYPE_EDGE_CONST) +/* face */ +#define _BM_GENERIC_TYPE_FACE_NONCONST BMFace *, BMFace_OFlag * +#define _BM_GENERIC_TYPE_FACE_CONST const BMFace *, const BMFace_OFlag * +#define BM_CHECK_TYPE_FACE_CONST(ele) CHECK_TYPE_ANY(ele, _BM_GENERIC_TYPE_FACE_CONST) +#define BM_CHECK_TYPE_FACE_NONCONST(ele) CHECK_TYPE_ANY(ele, _BM_GENERIC_TYPE_ELEM_NONCONST) +#define BM_CHECK_TYPE_FACE(ele) CHECK_TYPE_ANY(ele, _BM_GENERIC_TYPE_FACE_NONCONST, _BM_GENERIC_TYPE_FACE_CONST) + + + /* Assignment from a void* to a typed pointer is not allowed in C++, * casting the LHS to void works fine though. */ diff --git a/source/blender/bmesh/intern/bmesh_construct.c b/source/blender/bmesh/intern/bmesh_construct.c index fdad93ee90d..4d92baab6eb 100644 --- a/source/blender/bmesh/intern/bmesh_construct.c +++ b/source/blender/bmesh/intern/bmesh_construct.c @@ -714,7 +714,9 @@ BMesh *BM_mesh_copy(BMesh *bm_old) const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_BM(bm_old); /* allocate a bmesh */ - bm_new = BM_mesh_create(&allocsize); + bm_new = BM_mesh_create( + &allocsize, + &((struct BMeshCreateParams){.use_toolflags = bm_old->use_toolflags,})); BM_mesh_copy_init_customdata(bm_new, bm_old, &allocsize); diff --git a/source/blender/bmesh/intern/bmesh_core.c b/source/blender/bmesh/intern/bmesh_core.c index 1d68cdcf28a..e83b752947c 100644 --- a/source/blender/bmesh/intern/bmesh_core.c +++ b/source/blender/bmesh/intern/bmesh_core.c @@ -81,7 +81,9 @@ BMVert *BM_vert_create( v->head.api_flag = 0; /* allocate flags */ - v->oflags = bm->vtoolflagpool ? BLI_mempool_calloc(bm->vtoolflagpool) : NULL; + if (bm->use_toolflags) { + ((BMVert_OFlag *)v)->oflags = bm->vtoolflagpool ? BLI_mempool_calloc(bm->vtoolflagpool) : NULL; + } /* 'v->no' is handled by BM_elem_attrs_copy */ if (co) { @@ -174,7 +176,9 @@ BMEdge *BM_edge_create( e->head.api_flag = 0; /* allocate flags */ - e->oflags = bm->etoolflagpool ? BLI_mempool_calloc(bm->etoolflagpool) : NULL; + if (bm->use_toolflags) { + ((BMEdge_OFlag *)e)->oflags = bm->etoolflagpool ? BLI_mempool_calloc(bm->etoolflagpool) : NULL; + } e->v1 = v1; e->v2 = v2; @@ -386,7 +390,9 @@ BLI_INLINE BMFace *bm_face_create__internal(BMesh *bm) f->head.api_flag = 0; /* allocate flags */ - f->oflags = bm->ftoolflagpool ? BLI_mempool_calloc(bm->ftoolflagpool) : NULL; + if (bm->use_toolflags) { + ((BMFace_OFlag *)f)->oflags = bm->ftoolflagpool ? BLI_mempool_calloc(bm->ftoolflagpool) : NULL; + } #ifdef USE_BMESH_HOLES BLI_listbase_clear(&f->loops); @@ -758,7 +764,7 @@ static void bm_kill_only_vert(BMesh *bm, BMVert *v) CustomData_bmesh_free_block(&bm->vdata, &v->head.data); if (bm->vtoolflagpool) { - BLI_mempool_free(bm->vtoolflagpool, v->oflags); + BLI_mempool_free(bm->vtoolflagpool, ((BMVert_OFlag *)v)->oflags); } BLI_mempool_free(bm->vpool, v); } @@ -779,7 +785,7 @@ static void bm_kill_only_edge(BMesh *bm, BMEdge *e) CustomData_bmesh_free_block(&bm->edata, &e->head.data); if (bm->etoolflagpool) { - BLI_mempool_free(bm->etoolflagpool, e->oflags); + BLI_mempool_free(bm->etoolflagpool, ((BMEdge_OFlag *)e)->oflags); } BLI_mempool_free(bm->epool, e); } @@ -803,7 +809,7 @@ static void bm_kill_only_face(BMesh *bm, BMFace *f) CustomData_bmesh_free_block(&bm->pdata, &f->head.data); if (bm->ftoolflagpool) { - BLI_mempool_free(bm->ftoolflagpool, f->oflags); + BLI_mempool_free(bm->ftoolflagpool, ((BMFace_OFlag *)f)->oflags); } BLI_mempool_free(bm->fpool, f); } @@ -2196,7 +2202,7 @@ BMFace *bmesh_jfke(BMesh *bm, BMFace *f1, BMFace *f2, BMEdge *e) /* deallocate edge and its two loops as well as f2 */ if (bm->etoolflagpool) { - BLI_mempool_free(bm->etoolflagpool, l_f1->e->oflags); + BLI_mempool_free(bm->etoolflagpool, ((BMEdge_OFlag *)l_f1->e)->oflags); } BLI_mempool_free(bm->epool, l_f1->e); bm->totedge--; @@ -2205,7 +2211,7 @@ BMFace *bmesh_jfke(BMesh *bm, BMFace *f1, BMFace *f2, BMEdge *e) BLI_mempool_free(bm->lpool, l_f2); bm->totloop--; if (bm->ftoolflagpool) { - BLI_mempool_free(bm->ftoolflagpool, f2->oflags); + BLI_mempool_free(bm->ftoolflagpool, ((BMFace_OFlag *)f2)->oflags); } BLI_mempool_free(bm->fpool, f2); bm->totface--; diff --git a/source/blender/bmesh/intern/bmesh_delete.c b/source/blender/bmesh/intern/bmesh_delete.c index 882d78ce6b3..1449a6ef9d7 100644 --- a/source/blender/bmesh/intern/bmesh_delete.c +++ b/source/blender/bmesh/intern/bmesh_delete.c @@ -54,7 +54,7 @@ static void bmo_remove_tagged_faces(BMesh *bm, const short oflag) BMIter iter; BM_ITER_MESH_MUTABLE (f, f_next, &iter, bm, BM_FACES_OF_MESH) { - if (BMO_elem_flag_test(bm, f, oflag)) { + if (BMO_face_flag_test(bm, f, oflag)) { BM_face_kill(bm, f); } } @@ -66,7 +66,7 @@ static void bmo_remove_tagged_edges(BMesh *bm, const short oflag) BMIter iter; BM_ITER_MESH_MUTABLE (e, e_next, &iter, bm, BM_EDGES_OF_MESH) { - if (BMO_elem_flag_test(bm, e, oflag)) { + if (BMO_edge_flag_test(bm, e, oflag)) { BM_edge_kill(bm, e); } } @@ -78,7 +78,7 @@ static void bmo_remove_tagged_verts(BMesh *bm, const short oflag) BMIter iter; BM_ITER_MESH_MUTABLE (v, v_next, &iter, bm, BM_VERTS_OF_MESH) { - if (BMO_elem_flag_test(bm, v, oflag)) { + if (BMO_vert_flag_test(bm, v, oflag)) { BM_vert_kill(bm, v); } } @@ -90,7 +90,7 @@ static void bmo_remove_tagged_verts_loose(BMesh *bm, const short oflag) BMIter iter; BM_ITER_MESH_MUTABLE (v, v_next, &iter, bm, BM_VERTS_OF_MESH) { - if (BMO_elem_flag_test(bm, v, oflag) && (v->e == NULL)) { + if (BMO_vert_flag_test(bm, v, oflag) && (v->e == NULL)) { BM_vert_kill(bm, v); } } @@ -132,9 +132,9 @@ void BMO_mesh_delete_oflag_context(BMesh *bm, const short oflag, const int type) { /* flush down to vert */ BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) { - if (BMO_elem_flag_test(bm, e, oflag)) { - BMO_elem_flag_enable(bm, e->v1, oflag); - BMO_elem_flag_enable(bm, e->v2, oflag); + if (BMO_edge_flag_test(bm, e, oflag)) { + BMO_vert_flag_enable(bm, e->v1, oflag); + BMO_vert_flag_enable(bm, e->v2, oflag); } } bmo_remove_tagged_edges(bm, oflag); @@ -165,27 +165,27 @@ void BMO_mesh_delete_oflag_context(BMesh *bm, const short oflag, const int type) { /* go through and mark all edges and all verts of all faces for delete */ BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) { - if (BMO_elem_flag_test(bm, f, oflag)) { + if (BMO_face_flag_test(bm, f, oflag)) { BMLoop *l_first = BM_FACE_FIRST_LOOP(f); BMLoop *l_iter; l_iter = l_first; do { - BMO_elem_flag_enable(bm, l_iter->v, oflag); - BMO_elem_flag_enable(bm, l_iter->e, oflag); + BMO_vert_flag_enable(bm, l_iter->v, oflag); + BMO_edge_flag_enable(bm, l_iter->e, oflag); } while ((l_iter = l_iter->next) != l_first); } } /* now go through and mark all remaining faces all edges for keeping */ BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) { - if (!BMO_elem_flag_test(bm, f, oflag)) { + if (!BMO_face_flag_test(bm, f, oflag)) { BMLoop *l_first = BM_FACE_FIRST_LOOP(f); BMLoop *l_iter; l_iter = l_first; do { - BMO_elem_flag_disable(bm, l_iter->v, oflag); - BMO_elem_flag_disable(bm, l_iter->e, oflag); + BMO_vert_flag_disable(bm, l_iter->v, oflag); + BMO_edge_flag_disable(bm, l_iter->e, oflag); } while ((l_iter = l_iter->next) != l_first); } } @@ -195,13 +195,13 @@ void BMO_mesh_delete_oflag_context(BMesh *bm, const short oflag, const int type) /* Only exception to normal 'DEL_FACES' logic. */ if (type == DEL_FACES_KEEP_BOUNDARY) { if (BM_edge_is_boundary(e)) { - BMO_elem_flag_disable(bm, e, oflag); + BMO_edge_flag_disable(bm, e, oflag); } } - if (!BMO_elem_flag_test(bm, e, oflag)) { - BMO_elem_flag_disable(bm, e->v1, oflag); - BMO_elem_flag_disable(bm, e->v2, oflag); + if (!BMO_edge_flag_test(bm, e, oflag)) { + BMO_vert_flag_disable(bm, e->v1, oflag); + BMO_vert_flag_disable(bm, e->v2, oflag); } } diff --git a/source/blender/bmesh/intern/bmesh_iterators.c b/source/blender/bmesh/intern/bmesh_iterators.c index cc79e28a361..961b10d848a 100644 --- a/source/blender/bmesh/intern/bmesh_iterators.c +++ b/source/blender/bmesh/intern/bmesh_iterators.c @@ -339,16 +339,43 @@ int BMO_iter_elem_count_flag( const short oflag, const bool value) { BMIter iter; - BMElemF *ele; int count = 0; /* loops have no header flags */ BLI_assert(bm_iter_itype_htype_map[itype] != BM_LOOP); - BM_ITER_ELEM (ele, &iter, data, itype) { - if (BMO_elem_flag_test_bool(bm, ele, oflag) == value) { - count++; + switch (bm_iter_itype_htype_map[itype]) { + case BM_VERT: + { + BMVert *ele; + BM_ITER_ELEM (ele, &iter, data, itype) { + if (BMO_vert_flag_test_bool(bm, ele, oflag) == value) { + count++; + } + } + break; } + case BM_EDGE: + { + BMEdge *ele; + BM_ITER_ELEM (ele, &iter, data, itype) { + if (BMO_edge_flag_test_bool(bm, ele, oflag) == value) { + count++; + } + } + break; + } + case BM_FACE: + { + BMFace *ele; + BM_ITER_ELEM (ele, &iter, data, itype) { + if (BMO_face_flag_test_bool(bm, ele, oflag) == value) { + count++; + } + } + break; + } + } return count; } diff --git a/source/blender/bmesh/intern/bmesh_marking.c b/source/blender/bmesh/intern/bmesh_marking.c index 3fe888736f0..d6ca7239e39 100644 --- a/source/blender/bmesh/intern/bmesh_marking.c +++ b/source/blender/bmesh/intern/bmesh_marking.c @@ -904,7 +904,7 @@ void BM_editselection_plane(BMEditSelection *ese, float r_plane[3]) } else if (ese->htype == BM_FACE) { BMFace *efa = (BMFace *)ese->ele; - BM_face_calc_plane(efa, r_plane); + BM_face_calc_tangent_auto(efa, r_plane); } } diff --git a/source/blender/bmesh/intern/bmesh_mesh.c b/source/blender/bmesh/intern/bmesh_mesh.c index ed1bd16b2e4..32aa80a4e73 100644 --- a/source/blender/bmesh/intern/bmesh_mesh.c +++ b/source/blender/bmesh/intern/bmesh_mesh.c @@ -48,16 +48,52 @@ const BMAllocTemplate bm_mesh_allocsize_default = {512, 1024, 2048, 512}; const BMAllocTemplate bm_mesh_chunksize_default = {512, 1024, 2048, 512}; -static void bm_mempool_init(BMesh *bm, const BMAllocTemplate *allocsize) +static void bm_mempool_init_ex( + const BMAllocTemplate *allocsize, const bool use_toolflags, + BLI_mempool **r_vpool, BLI_mempool **r_epool, BLI_mempool **r_lpool, BLI_mempool **r_fpool) { - bm->vpool = BLI_mempool_create(sizeof(BMVert), allocsize->totvert, - bm_mesh_chunksize_default.totvert, BLI_MEMPOOL_ALLOW_ITER); - bm->epool = BLI_mempool_create(sizeof(BMEdge), allocsize->totedge, - bm_mesh_chunksize_default.totedge, BLI_MEMPOOL_ALLOW_ITER); - bm->lpool = BLI_mempool_create(sizeof(BMLoop), allocsize->totloop, - bm_mesh_chunksize_default.totloop, BLI_MEMPOOL_NOP); - bm->fpool = BLI_mempool_create(sizeof(BMFace), allocsize->totface, - bm_mesh_chunksize_default.totface, BLI_MEMPOOL_ALLOW_ITER); + size_t vert_size, edge_size, loop_size, face_size; + + if (use_toolflags == true) { + vert_size = sizeof(BMVert_OFlag); + edge_size = sizeof(BMEdge_OFlag); + loop_size = sizeof(BMLoop); + face_size = sizeof(BMFace_OFlag); + } + else { + vert_size = sizeof(BMVert); + edge_size = sizeof(BMEdge); + loop_size = sizeof(BMLoop); + face_size = sizeof(BMFace); + } + + if (r_vpool) { + *r_vpool = BLI_mempool_create( + vert_size, allocsize->totvert, + bm_mesh_chunksize_default.totvert, BLI_MEMPOOL_ALLOW_ITER); + } + if (r_epool) { + *r_epool = BLI_mempool_create( + edge_size, allocsize->totedge, + bm_mesh_chunksize_default.totedge, BLI_MEMPOOL_ALLOW_ITER); + } + if (r_lpool) { + *r_lpool = BLI_mempool_create( + loop_size, allocsize->totloop, + bm_mesh_chunksize_default.totloop, BLI_MEMPOOL_NOP); + } + if (r_fpool) { + *r_fpool = BLI_mempool_create( + face_size, allocsize->totface, + bm_mesh_chunksize_default.totface, BLI_MEMPOOL_ALLOW_ITER); + } +} + +static void bm_mempool_init(BMesh *bm, const BMAllocTemplate *allocsize, const bool use_toolflags) +{ + bm_mempool_init_ex( + allocsize, use_toolflags, + &bm->vpool, &bm->epool, &bm->lpool, &bm->fpool); #ifdef USE_BMESH_HOLES bm->looplistpool = BLI_mempool_create(sizeof(BMLoopList), 512, 512, BLI_MEMPOOL_NOP); @@ -66,6 +102,8 @@ static void bm_mempool_init(BMesh *bm, const BMAllocTemplate *allocsize) void BM_mesh_elem_toolflags_ensure(BMesh *bm) { + BLI_assert(bm->use_toolflags); + if (bm->vtoolflagpool && bm->etoolflagpool && bm->ftoolflagpool) { return; } @@ -80,7 +118,7 @@ void BM_mesh_elem_toolflags_ensure(BMesh *bm) { BLI_mempool *toolflagpool = bm->vtoolflagpool; BMIter iter; - BMElemF *ele; + BMVert_OFlag *ele; BM_ITER_MESH (ele, &iter, bm, BM_VERTS_OF_MESH) { ele->oflags = BLI_mempool_calloc(toolflagpool); } @@ -89,7 +127,7 @@ void BM_mesh_elem_toolflags_ensure(BMesh *bm) { BLI_mempool *toolflagpool = bm->etoolflagpool; BMIter iter; - BMElemF *ele; + BMEdge_OFlag *ele; BM_ITER_MESH (ele, &iter, bm, BM_EDGES_OF_MESH) { ele->oflags = BLI_mempool_calloc(toolflagpool); } @@ -98,7 +136,7 @@ void BM_mesh_elem_toolflags_ensure(BMesh *bm) { BLI_mempool *toolflagpool = bm->ftoolflagpool; BMIter iter; - BMElemF *ele; + BMFace_OFlag *ele; BM_ITER_MESH (ele, &iter, bm, BM_FACES_OF_MESH) { ele->oflags = BLI_mempool_calloc(toolflagpool); } @@ -134,15 +172,18 @@ void BM_mesh_elem_toolflags_clear(BMesh *bm) * * \note ob is needed by multires */ -BMesh *BM_mesh_create(const BMAllocTemplate *allocsize) +BMesh *BM_mesh_create( + const BMAllocTemplate *allocsize, + const struct BMeshCreateParams *params) { /* allocate the structure */ BMesh *bm = MEM_callocN(sizeof(BMesh), __func__); /* allocate the memory pools for the mesh elements */ - bm_mempool_init(bm, allocsize); + bm_mempool_init(bm, allocsize, params->use_toolflags); /* allocate one flag pool that we don't get rid of. */ + bm->use_toolflags = params->use_toolflags; bm->toolflag_index = 0; bm->totflags = 0; @@ -239,13 +280,16 @@ void BM_mesh_data_free(BMesh *bm) */ void BM_mesh_clear(BMesh *bm) { + const bool use_toolflags = bm->use_toolflags; + /* free old mesh */ BM_mesh_data_free(bm); memset(bm, 0, sizeof(BMesh)); /* allocate the memory pools for the mesh elements */ - bm_mempool_init(bm, &bm_mesh_allocsize_default); + bm_mempool_init(bm, &bm_mesh_allocsize_default, use_toolflags); + bm->use_toolflags = use_toolflags; bm->toolflag_index = 0; bm->totflags = 0; @@ -1706,3 +1750,262 @@ void BM_mesh_remap( if (fptr_map) BLI_ghash_free(fptr_map, NULL, NULL); } + +/** + * Use new memory pools for this mesh. + * + * \note needed for re-sizing elements (adding/removing tool flags) + * but could also be used for packing fragmented bmeshes. + */ +void BM_mesh_rebuild( + BMesh *bm, const struct BMeshCreateParams *params, + BLI_mempool *vpool_dst, BLI_mempool *epool_dst, BLI_mempool *lpool_dst, BLI_mempool *fpool_dst) +{ + const char remap = + (vpool_dst ? BM_VERT : 0) | + (epool_dst ? BM_EDGE : 0) | + (lpool_dst ? BM_LOOP : 0) | + (fpool_dst ? BM_FACE : 0); + + BMVert **vtable_dst = (remap & BM_VERT) ? MEM_mallocN(bm->totvert * sizeof(BMVert *), __func__) : NULL; + BMEdge **etable_dst = (remap & BM_EDGE) ? MEM_mallocN(bm->totedge * sizeof(BMEdge *), __func__) : NULL; + BMLoop **ltable_dst = (remap & BM_LOOP) ? MEM_mallocN(bm->totloop * sizeof(BMLoop *), __func__) : NULL; + BMFace **ftable_dst = (remap & BM_FACE) ? MEM_mallocN(bm->totface * sizeof(BMFace *), __func__) : NULL; + + const bool use_toolflags = params->use_toolflags; + + if (remap & BM_VERT) { + BMIter iter; + int index; + BMVert *v_src; + BM_ITER_MESH_INDEX (v_src, &iter, bm, BM_VERTS_OF_MESH, index) { + BMVert *v_dst = BLI_mempool_alloc(vpool_dst); + memcpy(v_dst, v_src, sizeof(BMVert)); + if (use_toolflags) { + ((BMVert_OFlag *)v_dst)->oflags = bm->vtoolflagpool ? BLI_mempool_calloc(bm->vtoolflagpool) : NULL; + } + + vtable_dst[index] = v_dst; + BM_elem_index_set(v_src, index); /* set_ok */ + } + } + + if (remap & BM_EDGE) { + BMIter iter; + int index; + BMEdge *e_src; + BM_ITER_MESH_INDEX (e_src, &iter, bm, BM_EDGES_OF_MESH, index) { + BMEdge *e_dst = BLI_mempool_alloc(epool_dst); + memcpy(e_dst, e_src, sizeof(BMEdge)); + if (use_toolflags) { + ((BMEdge_OFlag *)e_dst)->oflags = bm->etoolflagpool ? BLI_mempool_calloc(bm->etoolflagpool) : NULL; + } + + etable_dst[index] = e_dst; + BM_elem_index_set(e_src, index); /* set_ok */ + } + } + + if (remap & (BM_LOOP | BM_FACE)) { + BMIter iter; + int index, index_loop = 0; + BMFace *f_src; + BM_ITER_MESH_INDEX (f_src, &iter, bm, BM_FACES_OF_MESH, index) { + + if (remap & BM_FACE) { + BMFace *f_dst = BLI_mempool_alloc(fpool_dst); + memcpy(f_dst, f_src, sizeof(BMFace)); + if (use_toolflags) { + ((BMFace_OFlag *)f_dst)->oflags = bm->ftoolflagpool ? BLI_mempool_calloc(bm->ftoolflagpool) : NULL; + } + + ftable_dst[index] = f_dst; + BM_elem_index_set(f_src, index); /* set_ok */ + } + + /* handle loops */ + if (remap & BM_LOOP) { + BMLoop *l_iter_src, *l_first_src; + l_iter_src = l_first_src = BM_FACE_FIRST_LOOP((BMFace *)f_src); + do { + BMLoop *l_dst = BLI_mempool_alloc(lpool_dst); + memcpy(l_dst, l_iter_src, sizeof(BMLoop)); + ltable_dst[index_loop] = l_dst; + BM_elem_index_set(l_iter_src, index_loop++); /* set_ok */ + } while ((l_iter_src = l_iter_src->next) != l_first_src); + } + } + } + +#define MAP_VERT(ele) vtable_dst[BM_elem_index_get(ele)] +#define MAP_EDGE(ele) etable_dst[BM_elem_index_get(ele)] +#define MAP_LOOP(ele) ltable_dst[BM_elem_index_get(ele)] +#define MAP_FACE(ele) ftable_dst[BM_elem_index_get(ele)] + +#define REMAP_VERT(ele) { if (remap & BM_VERT) { ele = MAP_VERT(ele); }} ((void)0) +#define REMAP_EDGE(ele) { if (remap & BM_EDGE) { ele = MAP_EDGE(ele); }} ((void)0) +#define REMAP_LOOP(ele) { if (remap & BM_LOOP) { ele = MAP_LOOP(ele); }} ((void)0) +#define REMAP_FACE(ele) { if (remap & BM_FACE) { ele = MAP_FACE(ele); }} ((void)0) + + /* verts */ + { + for (int i = 0; i < bm->totvert; i++) { + BMVert *v = vtable_dst[i]; + if (v->e) { + REMAP_EDGE(v->e); + } + } + } + + /* edges */ + { + for (int i = 0; i < bm->totedge; i++) { + BMEdge *e = etable_dst[i]; + REMAP_VERT(e->v1); + REMAP_VERT(e->v2); + REMAP_EDGE(e->v1_disk_link.next); + REMAP_EDGE(e->v1_disk_link.prev); + REMAP_EDGE(e->v2_disk_link.next); + REMAP_EDGE(e->v2_disk_link.prev); + if (e->l) { + REMAP_LOOP(e->l); + } + } + } + + /* faces */ + { + for (int i = 0; i < bm->totface; i++) { + BMFace *f = ftable_dst[i]; + REMAP_LOOP(f->l_first); + + { + BMLoop *l_iter, *l_first; + l_iter = l_first = BM_FACE_FIRST_LOOP((BMFace *)f); + do { + REMAP_VERT(l_iter->v); + REMAP_EDGE(l_iter->e); + REMAP_FACE(l_iter->f); + + REMAP_LOOP(l_iter->radial_next); + REMAP_LOOP(l_iter->radial_prev); + REMAP_LOOP(l_iter->next); + REMAP_LOOP(l_iter->prev); + } while ((l_iter = l_iter->next) != l_first); + } + } + } + + for (BMEditSelection *ese = bm->selected.first; ese; ese = ese->next) { + switch (ese->htype) { + case BM_VERT: + if (remap & BM_VERT) { + ese->ele = (BMElem *)MAP_VERT(ese->ele); + } + break; + case BM_EDGE: + if (remap & BM_EDGE) { + ese->ele = (BMElem *)MAP_EDGE(ese->ele); + } + break; + case BM_FACE: + if (remap & BM_FACE) { + ese->ele = (BMElem *)MAP_FACE(ese->ele); + } + break; + } + } + + if (bm->act_face) { + REMAP_FACE(bm->act_face); + } + +#undef MAP_VERT +#undef MAP_EDGE +#undef MAP_LOOP +#undef MAP_EDGE + +#undef REMAP_VERT +#undef REMAP_EDGE +#undef REMAP_LOOP +#undef REMAP_EDGE + + /* Cleanup, re-use local tables if the current mesh had tables allocated. + * could use irrespective but it may use more memory then the caller wants (and not be needed). */ + if (remap & BM_VERT) { + if (bm->vtable) { + SWAP(BMVert **, vtable_dst, bm->vtable); + bm->vtable_tot = bm->totvert; + bm->elem_table_dirty &= ~BM_VERT; + } + MEM_freeN(vtable_dst); + BLI_mempool_destroy(bm->vpool); + bm->vpool = vpool_dst; + } + + if (remap & BM_EDGE) { + if (bm->etable) { + SWAP(BMEdge **, etable_dst, bm->etable); + bm->etable_tot = bm->totedge; + bm->elem_table_dirty &= ~BM_EDGE; + } + MEM_freeN(etable_dst); + BLI_mempool_destroy(bm->epool); + bm->epool = epool_dst; + } + + if (remap & BM_LOOP) { + /* no loop table */ + MEM_freeN(ltable_dst); + BLI_mempool_destroy(bm->lpool); + bm->lpool = lpool_dst; + } + + if (remap & BM_FACE) { + if (bm->ftable) { + SWAP(BMFace **, ftable_dst, bm->ftable); + bm->ftable_tot = bm->totface; + bm->elem_table_dirty &= ~BM_FACE; + } + MEM_freeN(ftable_dst); + BLI_mempool_destroy(bm->fpool); + bm->fpool = fpool_dst; + } +} + +/** + * Re-allocatges mesh data with/without toolflags. + */ +void BM_mesh_toolflags_set(BMesh *bm, bool use_toolflags) +{ + if (bm->use_toolflags == use_toolflags) { + return; + } + + const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_BM(bm); + + BLI_mempool *vpool_dst = NULL; + BLI_mempool *epool_dst = NULL; + BLI_mempool *fpool_dst = NULL; + + bm_mempool_init_ex( + &allocsize, use_toolflags, + &vpool_dst, &epool_dst, NULL, &fpool_dst); + + if (use_toolflags == false) { + BLI_mempool_destroy(bm->vtoolflagpool); + BLI_mempool_destroy(bm->etoolflagpool); + BLI_mempool_destroy(bm->ftoolflagpool); + + bm->vtoolflagpool = NULL; + bm->etoolflagpool = NULL; + bm->ftoolflagpool = NULL; + } + + BM_mesh_rebuild( + bm, + &((struct BMeshCreateParams){.use_toolflags = use_toolflags,}), + vpool_dst, epool_dst, NULL, fpool_dst); + + bm->use_toolflags = use_toolflags; +}
\ No newline at end of file diff --git a/source/blender/bmesh/intern/bmesh_mesh.h b/source/blender/bmesh/intern/bmesh_mesh.h index b9cdc4ccf66..6a9540c3b60 100644 --- a/source/blender/bmesh/intern/bmesh_mesh.h +++ b/source/blender/bmesh/intern/bmesh_mesh.h @@ -32,7 +32,14 @@ struct MLoopNorSpaceArray; void BM_mesh_elem_toolflags_ensure(BMesh *bm); void BM_mesh_elem_toolflags_clear(BMesh *bm); -BMesh *BM_mesh_create(const struct BMAllocTemplate *allocsize); + +struct BMeshCreateParams { + unsigned int use_toolflags : 1; +}; + +BMesh *BM_mesh_create( + const struct BMAllocTemplate *allocsize, + const struct BMeshCreateParams *params); void BM_mesh_free(BMesh *bm); void BM_mesh_data_free(BMesh *bm); @@ -53,6 +60,8 @@ void BM_mesh_elem_index_validate( BMesh *bm, const char *location, const char *func, const char *msg_a, const char *msg_b); +void BM_mesh_toolflags_set(BMesh *bm, bool use_toolflags); + #ifndef NDEBUG bool BM_mesh_elem_table_check(BMesh *bm); #endif @@ -83,6 +92,10 @@ void BM_mesh_remap( const unsigned int *edge_idx, const unsigned int *face_idx); +void BM_mesh_rebuild( + BMesh *bm, const struct BMeshCreateParams *params, + struct BLI_mempool *vpool, struct BLI_mempool *epool, struct BLI_mempool *lpool, struct BLI_mempool *fpool); + typedef struct BMAllocTemplate { int totvert, totedge, totloop, totface; } BMAllocTemplate; @@ -113,10 +126,4 @@ extern const BMAllocTemplate bm_mesh_chunksize_default; #define BMALLOC_TEMPLATE_FROM_DM(...) VA_NARGS_CALL_OVERLOAD(_VA_BMALLOC_TEMPLATE_FROM_DM_, __VA_ARGS__) - - -enum { - BM_MESH_CREATE_USE_TOOLFLAGS = (1 << 0) -}; - #endif /* __BMESH_MESH_H__ */ diff --git a/source/blender/bmesh/intern/bmesh_operator_api.h b/source/blender/bmesh/intern/bmesh_operator_api.h index cf93fe0935e..30cd1df9c4e 100644 --- a/source/blender/bmesh/intern/bmesh_operator_api.h +++ b/source/blender/bmesh/intern/bmesh_operator_api.h @@ -75,15 +75,74 @@ extern "C" { struct GHashIterator; -#define BMO_elem_flag_test( bm, ele, oflag) _bmo_elem_flag_test (bm, (ele)->oflags, oflag) -#define BMO_elem_flag_test_bool(bm, ele, oflag) _bmo_elem_flag_test_bool(bm, (ele)->oflags, oflag) -#define BMO_elem_flag_enable( bm, ele, oflag) _bmo_elem_flag_enable (bm, (ele)->oflags, oflag) -#define BMO_elem_flag_disable( bm, ele, oflag) _bmo_elem_flag_disable (bm, (ele)->oflags, oflag) -#define BMO_elem_flag_set( bm, ele, oflag, val) _bmo_elem_flag_set (bm, (ele)->oflags, oflag, val) -#define BMO_elem_flag_toggle( bm, ele, oflag) _bmo_elem_flag_toggle (bm, (ele)->oflags, oflag) - -BLI_INLINE short _bmo_elem_flag_test( BMesh *bm, BMFlagLayer *oflags, const short oflag); -BLI_INLINE bool _bmo_elem_flag_test_bool(BMesh *bm, BMFlagLayer *oflags, const short oflag); +BLI_INLINE BMFlagLayer *BMO_elem_flag_from_header(BMHeader *ele_head) +{ + switch (ele_head->htype) { + case BM_VERT: return ((BMVert_OFlag *)ele_head)->oflags; + case BM_EDGE: return ((BMEdge_OFlag *)ele_head)->oflags; + default: return ((BMFace_OFlag *)ele_head)->oflags; + } +} + +#define BMO_elem_flag_test(bm, ele, oflag) \ + _bmo_elem_flag_test(bm, BMO_elem_flag_from_header(&(ele)->head), oflag) +#define BMO_elem_flag_test_bool(bm, ele, oflag) \ + _bmo_elem_flag_test_bool(bm, BMO_elem_flag_from_header(&(ele)->head), oflag) +#define BMO_elem_flag_enable(bm, ele, oflag) \ + _bmo_elem_flag_enable(bm, (BM_CHECK_TYPE_ELEM_NONCONST(ele), BMO_elem_flag_from_header(&(ele)->head)), oflag) +#define BMO_elem_flag_disable(bm, ele, oflag) \ + _bmo_elem_flag_disable(bm, (BM_CHECK_TYPE_ELEM_NONCONST(ele), BMO_elem_flag_from_header(&(ele)->head)), oflag) +#define BMO_elem_flag_set(bm, ele, oflag, val) \ + _bmo_elem_flag_set(bm, (BM_CHECK_TYPE_ELEM_NONCONST(ele), BMO_elem_flag_from_header(&(ele)->head)), oflag, val) +#define BMO_elem_flag_toggle(bm, ele, oflag) \ + _bmo_elem_flag_toggle(bm, (BM_CHECK_TYPE_ELEM_NONCONST(ele), BMO_elem_flag_from_header(&(ele)->head)), oflag) + +/* take care not to instansiate args multiple times */ +#ifdef __GNUC___ +#define _BMO_CAST_V_CONST(e) ({ typeof(e) _e = e; \ + (BM_CHECK_TYPE_VERT(_e), BLI_assert(((const BMHeader *)_e)->htype == BM_VERT), (const BMVert_OFlag *)_e); }) +#define _BMO_CAST_E_CONST(e) ({ typeof(e) _e = e; \ + (BM_CHECK_TYPE_EDGE(_e), BLI_assert(((const BMHeader *)_e)->htype == BM_EDGE), (const BMEdge_OFlag *)_e); }) +#define _BMO_CAST_F_CONST(e) ({ typeof(e) _e = e; \ + (BM_CHECK_TYPE_FACE(_e), BLI_assert(((const BMHeader *)_e)->htype == BM_FACE), (const BMFace_OFlag *)_e); }) +#define _BMO_CAST_V(e) ({ typeof(e) _e = e; \ + (BM_CHECK_TYPE_VERT_NONCONST(_e), BLI_assert(((BMHeader *)_e)->htype == BM_VERT), (BMVert_OFlag *)_e); }) +#define _BMO_CAST_E(e) ({ typeof(e) _e = e; \ + (BM_CHECK_TYPE_EDGE_NONCONST(_e), BLI_assert(((BMHeader *)_e)->htype == BM_EDGE), (BMEdge_OFlag *)_e); }) +#define _BMO_CAST_F(e) ({ typeof(e) _e = e; \ + (BM_CHECK_TYPE_FACE_NONCONST(_e), BLI_assert(((BMHeader *)_e)->htype == BM_FACE), (BMFace_OFlag *)_e); }) +#else +#define _BMO_CAST_V_CONST(e) (BM_CHECK_TYPE_VERT(e), (const BMVert_OFlag *)e) +#define _BMO_CAST_E_CONST(e) (BM_CHECK_TYPE_EDGE(e), (const BMEdge_OFlag *)e) +#define _BMO_CAST_F_CONST(e) (BM_CHECK_TYPE_FACE(e), (const BMFace_OFlag *)e) +#define _BMO_CAST_V(e) (BM_CHECK_TYPE_VERT_NONCONST(e), (BMVert_OFlag *)e) +#define _BMO_CAST_E(e) (BM_CHECK_TYPE_EDGE_NONCONST(e), (BMEdge_OFlag *)e) +#define _BMO_CAST_F(e) (BM_CHECK_TYPE_FACE_NONCONST(e), (BMFace_OFlag *)e) +#endif + +#define BMO_vert_flag_test( bm, e, oflag) _bmo_elem_flag_test (bm, _BMO_CAST_V_CONST(e)->oflags, oflag) +#define BMO_vert_flag_test_bool(bm, e, oflag) _bmo_elem_flag_test_bool(bm, _BMO_CAST_V_CONST(e)->oflags, oflag) +#define BMO_vert_flag_enable( bm, e, oflag) _bmo_elem_flag_enable (bm, _BMO_CAST_V(e)->oflags, oflag) +#define BMO_vert_flag_disable( bm, e, oflag) _bmo_elem_flag_disable (bm, _BMO_CAST_V(e)->oflags, oflag) +#define BMO_vert_flag_set( bm, e, oflag, val) _bmo_elem_flag_set (bm, _BMO_CAST_V(e)->oflags, oflag, val) +#define BMO_vert_flag_toggle( bm, e, oflag) _bmo_elem_flag_toggle (bm, _BMO_CAST_V(e)->oflags, oflag) + +#define BMO_edge_flag_test( bm, e, oflag) _bmo_elem_flag_test (bm, _BMO_CAST_E_CONST(e)->oflags, oflag) +#define BMO_edge_flag_test_bool(bm, e, oflag) _bmo_elem_flag_test_bool(bm, _BMO_CAST_E_CONST(e)->oflags, oflag) +#define BMO_edge_flag_enable( bm, e, oflag) _bmo_elem_flag_enable (bm, _BMO_CAST_E(e)->oflags, oflag) +#define BMO_edge_flag_disable( bm, e, oflag) _bmo_elem_flag_disable (bm, _BMO_CAST_E(e)->oflags, oflag) +#define BMO_edge_flag_set( bm, e, oflag, val) _bmo_elem_flag_set (bm, _BMO_CAST_E(e)->oflags, oflag, val) +#define BMO_edge_flag_toggle( bm, e, oflag) _bmo_elem_flag_toggle (bm, _BMO_CAST_E(e)->oflags, oflag) + +#define BMO_face_flag_test( bm, e, oflag) _bmo_elem_flag_test (bm, _BMO_CAST_F_CONST(e)->oflags, oflag) +#define BMO_face_flag_test_bool(bm, e, oflag) _bmo_elem_flag_test_bool(bm, _BMO_CAST_F_CONST(e)->oflags, oflag) +#define BMO_face_flag_enable( bm, e, oflag) _bmo_elem_flag_enable (bm, _BMO_CAST_F(e)->oflags, oflag) +#define BMO_face_flag_disable( bm, e, oflag) _bmo_elem_flag_disable (bm, _BMO_CAST_F(e)->oflags, oflag) +#define BMO_face_flag_set( bm, e, oflag, val) _bmo_elem_flag_set (bm, _BMO_CAST_F(e)->oflags, oflag, val) +#define BMO_face_flag_toggle( bm, e, oflag) _bmo_elem_flag_toggle (bm, _BMO_CAST_F(e)->oflags, oflag) + +BLI_INLINE short _bmo_elem_flag_test( BMesh *bm, const BMFlagLayer *oflags, const short oflag); +BLI_INLINE bool _bmo_elem_flag_test_bool(BMesh *bm, const BMFlagLayer *oflags, const short oflag); BLI_INLINE void _bmo_elem_flag_enable( BMesh *bm, BMFlagLayer *oflags, const short oflag); BLI_INLINE void _bmo_elem_flag_disable( BMesh *bm, BMFlagLayer *oflags, const short oflag); BLI_INLINE void _bmo_elem_flag_set( BMesh *bm, BMFlagLayer *oflags, const short oflag, int val); diff --git a/source/blender/bmesh/intern/bmesh_operator_api_inline.h b/source/blender/bmesh/intern/bmesh_operator_api_inline.h index 00fcd9e7a9b..eb1c161f19d 100644 --- a/source/blender/bmesh/intern/bmesh_operator_api_inline.h +++ b/source/blender/bmesh/intern/bmesh_operator_api_inline.h @@ -39,32 +39,37 @@ /* flags 15 and 16 (1 << 14 and 1 << 15) are reserved for bmesh api use */ ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2) -BLI_INLINE short _bmo_elem_flag_test(BMesh *bm, BMFlagLayer *oflags, const short oflag) +BLI_INLINE short _bmo_elem_flag_test(BMesh *bm, const BMFlagLayer *oflags, const short oflag) { + BLI_assert(bm->use_toolflags); return oflags[bm->toolflag_index].f & oflag; } ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2) -BLI_INLINE bool _bmo_elem_flag_test_bool(BMesh *bm, BMFlagLayer *oflags, const short oflag) +BLI_INLINE bool _bmo_elem_flag_test_bool(BMesh *bm, const BMFlagLayer *oflags, const short oflag) { + BLI_assert(bm->use_toolflags); return (oflags[bm->toolflag_index].f & oflag) != 0; } ATTR_NONNULL(1, 2) BLI_INLINE void _bmo_elem_flag_enable(BMesh *bm, BMFlagLayer *oflags, const short oflag) { + BLI_assert(bm->use_toolflags); oflags[bm->toolflag_index].f |= oflag; } ATTR_NONNULL(1, 2) BLI_INLINE void _bmo_elem_flag_disable(BMesh *bm, BMFlagLayer *oflags, const short oflag) { + BLI_assert(bm->use_toolflags); oflags[bm->toolflag_index].f &= (short)~oflag; } ATTR_NONNULL(1, 2) BLI_INLINE void _bmo_elem_flag_set(BMesh *bm, BMFlagLayer *oflags, const short oflag, int val) { + BLI_assert(bm->use_toolflags); if (val) oflags[bm->toolflag_index].f |= oflag; else oflags[bm->toolflag_index].f &= (short)~oflag; } @@ -72,6 +77,7 @@ BLI_INLINE void _bmo_elem_flag_set(BMesh *bm, BMFlagLayer *oflags, const short o ATTR_NONNULL(1, 2) BLI_INLINE void _bmo_elem_flag_toggle(BMesh *bm, BMFlagLayer *oflags, const short oflag) { + BLI_assert(bm->use_toolflags); oflags[bm->toolflag_index].f ^= oflag; } diff --git a/source/blender/bmesh/intern/bmesh_operators.c b/source/blender/bmesh/intern/bmesh_operators.c index 960ff568e93..706a7f74ed2 100644 --- a/source/blender/bmesh/intern/bmesh_operators.c +++ b/source/blender/bmesh/intern/bmesh_operators.c @@ -548,27 +548,44 @@ static int bmo_mesh_flag_count( BMesh *bm, const char htype, const short oflag, const bool test_for_enabled) { - const char iter_types[3] = {BM_VERTS_OF_MESH, - BM_EDGES_OF_MESH, - BM_FACES_OF_MESH}; + int count_vert = 0, count_edge = 0, count_face = 0; - const char flag_types[3] = {BM_VERT, BM_EDGE, BM_FACE}; - - BMIter iter; - int count = 0; - BMElemF *ele_f; - int i; - - for (i = 0; i < 3; i++) { - if (htype & flag_types[i]) { - BM_ITER_MESH (ele_f, &iter, bm, iter_types[i]) { - if (BMO_elem_flag_test_bool(bm, ele_f, oflag) == test_for_enabled) - count++; +#pragma omp parallel sections if ((bm->totvert + bm->totedge + bm->totface >= BM_OMP_LIMIT) && \ + (ELEM(htype, BM_VERT, BM_EDGE, BM_FACE) == 0)) + { +#pragma omp section + if (htype & BM_VERT) { + BMIter iter; + BMVert *ele; + BM_ITER_MESH (ele, &iter, bm, BM_VERTS_OF_MESH) { + if (BMO_vert_flag_test_bool(bm, ele, oflag) == test_for_enabled) { + count_vert++; + } + } + } +#pragma omp section + if (htype & BM_EDGE) { + BMIter iter; + BMEdge *ele; + BM_ITER_MESH (ele, &iter, bm, BM_EDGES_OF_MESH) { + if (BMO_edge_flag_test_bool(bm, ele, oflag) == test_for_enabled) { + count_edge++; + } + } + } +#pragma omp section + if (htype & BM_FACE) { + BMIter iter; + BMFace *ele; + BM_ITER_MESH (ele, &iter, bm, BM_FACES_OF_MESH) { + if (BMO_face_flag_test_bool(bm, ele, oflag) == test_for_enabled) { + count_face++; + } } } } - return count; + return (count_vert + count_edge + count_face); } @@ -584,21 +601,32 @@ int BMO_mesh_disabled_flag_count(BMesh *bm, const char htype, const short oflag) void BMO_mesh_flag_disable_all(BMesh *bm, BMOperator *UNUSED(op), const char htype, const short oflag) { - const char iter_types[3] = {BM_VERTS_OF_MESH, - BM_EDGES_OF_MESH, - BM_FACES_OF_MESH}; - - const char flag_types[3] = {BM_VERT, BM_EDGE, BM_FACE}; - BMElemF *ele; - int i; - -#pragma omp parallel for schedule(static) if (bm->totvert + bm->totedge + bm->totface >= BM_OMP_LIMIT) - for (i = 0; i < 3; i++) { - if (htype & flag_types[i]) { +#pragma omp parallel sections if ((bm->totvert + bm->totedge + bm->totface >= BM_OMP_LIMIT) && \ + (ELEM(htype, BM_VERT, BM_EDGE, BM_FACE) == 0)) + { +#pragma omp section + if (htype & BM_VERT) { BMIter iter; - BM_ITER_MESH (ele, &iter, bm, iter_types[i]) { - BMO_elem_flag_disable(bm, ele, oflag); + BMVert *ele; + BM_ITER_MESH (ele, &iter, bm, BM_VERTS_OF_MESH) { + BMO_vert_flag_disable(bm, ele, oflag); + } + } +#pragma omp section + if (htype & BM_EDGE) { + BMIter iter; + BMEdge *ele; + BM_ITER_MESH (ele, &iter, bm, BM_EDGES_OF_MESH) { + BMO_edge_flag_disable(bm, ele, oflag); + } + } +#pragma omp section + if (htype & BM_FACE) { + BMIter iter; + BMFace *ele; + BM_ITER_MESH (ele, &iter, bm, BM_FACES_OF_MESH) { + BMO_face_flag_disable(bm, ele, oflag); } } } @@ -1007,7 +1035,7 @@ static void bmo_slot_buffer_from_flag( if (htype & BM_VERT) { BM_ITER_MESH (ele, &iter, bm, BM_VERTS_OF_MESH) { - if (BMO_elem_flag_test_bool(bm, (BMElemF *)ele, oflag) == test_for_enabled) { + if (BMO_vert_flag_test_bool(bm, (BMVert *)ele, oflag) == test_for_enabled) { ele_array[i] = ele; i++; } @@ -1016,7 +1044,7 @@ static void bmo_slot_buffer_from_flag( if (htype & BM_EDGE) { BM_ITER_MESH (ele, &iter, bm, BM_EDGES_OF_MESH) { - if (BMO_elem_flag_test_bool(bm, (BMElemF *)ele, oflag) == test_for_enabled) { + if (BMO_edge_flag_test_bool(bm, (BMEdge *)ele, oflag) == test_for_enabled) { ele_array[i] = ele; i++; } @@ -1025,7 +1053,7 @@ static void bmo_slot_buffer_from_flag( if (htype & BM_FACE) { BM_ITER_MESH (ele, &iter, bm, BM_FACES_OF_MESH) { - if (BMO_elem_flag_test_bool(bm, (BMElemF *)ele, oflag) == test_for_enabled) { + if (BMO_face_flag_test_bool(bm, (BMFace *)ele, oflag) == test_for_enabled) { ele_array[i] = ele; i++; } @@ -1213,7 +1241,7 @@ static void bmo_flag_layer_alloc(BMesh *bm) #pragma omp section { BMIter iter; - BMElemF *ele; + BMVert_OFlag *ele; int i; BLI_mempool *newpool = bm->vtoolflagpool; @@ -1223,14 +1251,14 @@ static void bmo_flag_layer_alloc(BMesh *bm) void *oldflags = ele->oflags; ele->oflags = BLI_mempool_calloc(newpool); memcpy(ele->oflags, oldflags, old_totflags_size); - BM_elem_index_set(ele, i); /* set_inline */ + BM_elem_index_set(&ele->base, i); /* set_inline */ BM_ELEM_API_FLAG_CLEAR((BMElemF *)ele); } } #pragma omp section { BMIter iter; - BMElemF *ele; + BMEdge_OFlag *ele; int i; BLI_mempool *newpool = bm->etoolflagpool; @@ -1239,14 +1267,14 @@ static void bmo_flag_layer_alloc(BMesh *bm) void *oldflags = ele->oflags; ele->oflags = BLI_mempool_calloc(newpool); memcpy(ele->oflags, oldflags, old_totflags_size); - BM_elem_index_set(ele, i); /* set_inline */ + BM_elem_index_set(&ele->base, i); /* set_inline */ BM_ELEM_API_FLAG_CLEAR((BMElemF *)ele); } } #pragma omp section { BMIter iter; - BMElemF *ele; + BMFace_OFlag *ele; int i; BLI_mempool *newpool = bm->ftoolflagpool; @@ -1255,7 +1283,7 @@ static void bmo_flag_layer_alloc(BMesh *bm) void *oldflags = ele->oflags; ele->oflags = BLI_mempool_calloc(newpool); memcpy(ele->oflags, oldflags, old_totflags_size); - BM_elem_index_set(ele, i); /* set_inline */ + BM_elem_index_set(&ele->base, i); /* set_inline */ BM_ELEM_API_FLAG_CLEAR((BMElemF *)ele); } } @@ -1292,7 +1320,7 @@ static void bmo_flag_layer_free(BMesh *bm) #pragma omp section { BMIter iter; - BMElemF *ele; + BMVert_OFlag *ele; int i; BLI_mempool *newpool = bm->vtoolflagpool; @@ -1302,14 +1330,14 @@ static void bmo_flag_layer_free(BMesh *bm) void *oldflags = ele->oflags; ele->oflags = BLI_mempool_alloc(newpool); memcpy(ele->oflags, oldflags, new_totflags_size); - BM_elem_index_set(ele, i); /* set_inline */ + BM_elem_index_set(&ele->base, i); /* set_inline */ BM_ELEM_API_FLAG_CLEAR((BMElemF *)ele); } } #pragma omp section { BMIter iter; - BMElemF *ele; + BMEdge_OFlag *ele; int i; BLI_mempool *newpool = bm->etoolflagpool; @@ -1318,14 +1346,14 @@ static void bmo_flag_layer_free(BMesh *bm) void *oldflags = ele->oflags; ele->oflags = BLI_mempool_alloc(newpool); memcpy(ele->oflags, oldflags, new_totflags_size); - BM_elem_index_set(ele, i); /* set_inline */ + BM_elem_index_set(&ele->base, i); /* set_inline */ BM_ELEM_API_FLAG_CLEAR((BMElemF *)ele); } } #pragma omp section { BMIter iter; - BMElemF *ele; + BMFace_OFlag *ele; int i; BLI_mempool *newpool = bm->ftoolflagpool; @@ -1334,7 +1362,7 @@ static void bmo_flag_layer_free(BMesh *bm) void *oldflags = ele->oflags; ele->oflags = BLI_mempool_alloc(newpool); memcpy(ele->oflags, oldflags, new_totflags_size); - BM_elem_index_set(ele, i); /* set_inline */ + BM_elem_index_set(&ele->base, i); /* set_inline */ BM_ELEM_API_FLAG_CLEAR((BMElemF *)ele); } } @@ -1361,31 +1389,31 @@ static void bmo_flag_layer_clear(BMesh *bm) #pragma omp section { BMIter iter; - BMElemF *ele; + BMVert_OFlag *ele; int i; BM_ITER_MESH_INDEX (ele, &iter, bm, BM_VERTS_OF_MESH, i) { ele->oflags[totflags_offset] = zero_flag; - BM_elem_index_set(ele, i); /* set_inline */ + BM_elem_index_set(&ele->base, i); /* set_inline */ } } #pragma omp section { BMIter iter; - BMElemF *ele; + BMEdge_OFlag *ele; int i; BM_ITER_MESH_INDEX (ele, &iter, bm, BM_EDGES_OF_MESH, i) { ele->oflags[totflags_offset] = zero_flag; - BM_elem_index_set(ele, i); /* set_inline */ + BM_elem_index_set(&ele->base, i); /* set_inline */ } } #pragma omp section { BMIter iter; - BMElemF *ele; + BMFace_OFlag *ele; int i; BM_ITER_MESH_INDEX (ele, &iter, bm, BM_FACES_OF_MESH, i) { ele->oflags[totflags_offset] = zero_flag; - BM_elem_index_set(ele, i); /* set_inline */ + BM_elem_index_set(&ele->base, i); /* set_inline */ } } } diff --git a/source/blender/bmesh/intern/bmesh_polygon.c b/source/blender/bmesh/intern/bmesh_polygon.c index 62b29e61d08..fff6bea044c 100644 --- a/source/blender/bmesh/intern/bmesh_polygon.c +++ b/source/blender/bmesh/intern/bmesh_polygon.c @@ -286,64 +286,258 @@ float BM_face_calc_perimeter(const BMFace *f) return perimeter; } -void BM_vert_tri_calc_plane(BMVert *verts[3], float r_plane[3]) +/** + * Utility function to calculate the edge which is most different from the other two. + * + * \return The first edge index, where the second vertex is ``(index + 1) % 3``. + */ +static int bm_vert_tri_find_unique_edge(BMVert *verts[3]) { - float lens[3]; + /* find the most 'unique' loop, (greatest difference to others) */ +#if 1 + /* optimized version that avoids sqrt */ float difs[3]; - int order[3] = {0, 1, 2}; + for (int i_prev = 1, i_curr = 2, i_next = 0; + i_next < 3; + i_prev = i_curr, i_curr = i_next++) + { + const float *co = verts[i_curr]->co; + const float *co_other[2] = {verts[i_prev]->co, verts[i_next]->co}; + float proj_dir[3]; + mid_v3_v3v3(proj_dir, co_other[0], co_other[1]); + sub_v3_v3(proj_dir, co); + + float proj_pair[2][3]; + project_v3_v3v3(proj_pair[0], co_other[0], proj_dir); + project_v3_v3v3(proj_pair[1], co_other[1], proj_dir); + difs[i_next] = len_squared_v3v3(proj_pair[0], proj_pair[1]); + } +#else + const float lens[3] = { + len_v3v3(verts[0]->co, verts[1]->co), + len_v3v3(verts[1]->co, verts[2]->co), + len_v3v3(verts[2]->co, verts[0]->co), + }; + const float difs[3] = { + fabsf(lens[1] - lens[2]), + fabsf(lens[2] - lens[0]), + fabsf(lens[0] - lens[1]), + }; +#endif - lens[0] = len_v3v3(verts[0]->co, verts[1]->co); - lens[1] = len_v3v3(verts[1]->co, verts[2]->co); - lens[2] = len_v3v3(verts[2]->co, verts[0]->co); + int order[3] = {0, 1, 2}; + axis_sort_v3(difs, order); - /* find the shortest or the longest loop */ - difs[0] = fabsf(lens[1] - lens[2]); - difs[1] = fabsf(lens[2] - lens[0]); - difs[2] = fabsf(lens[0] - lens[1]); + return order[0]; +} - axis_sort_v3(difs, order); - sub_v3_v3v3(r_plane, verts[order[0]]->co, verts[(order[0] + 1) % 3]->co); +/** + * Calculate a tangent from any 3 vertices. + * + * The tangent aligns to the most *unique* edge + * (the edge most unlike the other two). + * + * \param r_tangent: Calculated unit length tangent (return value). + */ +void BM_vert_tri_calc_tangent_edge(BMVert *verts[3], float r_tangent[3]) +{ + const int index = bm_vert_tri_find_unique_edge(verts); + + sub_v3_v3v3(r_tangent, verts[index]->co, verts[(index + 1) % 3]->co); + + normalize_v3(r_tangent); } /** - * Compute a meaningful direction along the face (use for manipulator axis). - * \note result isnt normalized. + * Calculate a tangent from any 3 vertices, + * + * The tangent follows the center-line formed by the most unique edges center + * and the opposite vertex. + * + * \param r_tangent: Calculated unit length tangent (return value). */ -void BM_face_calc_plane(const BMFace *f, float r_plane[3]) +void BM_vert_tri_calc_tangent_edge_pair(BMVert *verts[3], float r_tangent[3]) +{ + const int index = bm_vert_tri_find_unique_edge(verts); + + const float *v_a = verts[index]->co; + const float *v_b = verts[(index + 1) % 3]->co; + const float *v_other = verts[(index + 2) % 3]->co; + + mid_v3_v3v3(r_tangent, v_a, v_b); + sub_v3_v3v3(r_tangent, v_other, r_tangent); + + normalize_v3(r_tangent); +} + +/** + * Compute the tanget of the face, using the longest edge. + */ +void BM_face_calc_tangent_edge(const BMFace *f, float r_tangent[3]) +{ + const BMLoop *l_long = BM_face_find_longest_loop((BMFace *)f); + + sub_v3_v3v3(r_tangent, l_long->v->co, l_long->next->v->co); + + normalize_v3(r_tangent); + +} + +/** + * Compute the tanget of the face, using the two longest disconected edges. + * + * \param r_tangent: Calculated unit length tangent (return value). + */ +void BM_face_calc_tangent_edge_pair(const BMFace *f, float r_tangent[3]) { if (f->len == 3) { BMVert *verts[3]; BM_face_as_array_vert_tri((BMFace *)f, verts); - BM_vert_tri_calc_plane(verts, r_plane); + BM_vert_tri_calc_tangent_edge_pair(verts, r_tangent); } else if (f->len == 4) { + /* Use longest edge pair */ BMVert *verts[4]; float vec[3], vec_a[3], vec_b[3]; - // BM_iter_as_array(NULL, BM_VERTS_OF_FACE, efa, (void **)verts, 4); BM_face_as_array_vert_quad((BMFace *)f, verts); sub_v3_v3v3(vec_a, verts[3]->co, verts[2]->co); sub_v3_v3v3(vec_b, verts[0]->co, verts[1]->co); - add_v3_v3v3(r_plane, vec_a, vec_b); + add_v3_v3v3(r_tangent, vec_a, vec_b); sub_v3_v3v3(vec_a, verts[0]->co, verts[3]->co); sub_v3_v3v3(vec_b, verts[1]->co, verts[2]->co); add_v3_v3v3(vec, vec_a, vec_b); - /* use the biggest edge length */ - if (len_squared_v3(r_plane) < len_squared_v3(vec)) { - copy_v3_v3(r_plane, vec); + /* use the longest edge length */ + if (len_squared_v3(r_tangent) < len_squared_v3(vec)) { + copy_v3_v3(r_tangent, vec); } } else { - const BMLoop *l_long = BM_face_find_longest_loop((BMFace *)f); + /* For ngons use two longest disconnected edges */ + BMLoop *l_long = BM_face_find_longest_loop((BMFace *)f); + BMLoop *l_long_other = NULL; - sub_v3_v3v3(r_plane, l_long->v->co, l_long->next->v->co); + float len_max_sq = 0.0f; + float vec_a[3], vec_b[3]; + + BMLoop *l_iter = l_long->prev->prev; + BMLoop *l_last = l_long->next; + + do { + const float len_sq = len_squared_v3v3(l_iter->v->co, l_iter->next->v->co); + if (len_sq >= len_max_sq) { + l_long_other = l_iter; + len_max_sq = len_sq; + } + } while ((l_iter = l_iter->prev) != l_last); + + sub_v3_v3v3(vec_a, l_long->next->v->co, l_long->v->co); + sub_v3_v3v3(vec_b, l_long_other->v->co, l_long_other->next->v->co); + add_v3_v3v3(r_tangent, vec_a, vec_b); + + /* Edges may not be opposite side of the ngon, + * this could cause problems for ngons with multiple-aligned edges of the same length. + * Fallback to longest edge. */ + if (UNLIKELY(normalize_v3(r_tangent) == 0.0f)) { + normalize_v3_v3(r_tangent, vec_a); + } } +} - normalize_v3(r_plane); +/** + * Compute the tanget of the face, using the edge farthest away from any vertex in the face. + * + * \param r_tangent: Calculated unit length tangent (return value). + */ +void BM_face_calc_tangent_edge_diagonal(const BMFace *f, float r_tangent[3]) +{ + BMLoop *l_iter, *l_first; + + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + + /* incase of degenerate faces */ + zero_v3(r_tangent); + + /* warning: O(n^2) loop here, take care! */ + float dist_max_sq = 0.0f; + do { + BMLoop *l_iter_other = l_iter->next; + BMLoop *l_iter_last = l_iter->prev; + do { + BLI_assert(!ELEM(l_iter->v->co, l_iter_other->v->co, l_iter_other->next->v->co)); + float co_other[3], vec[3]; + closest_to_line_segment_v3(co_other, l_iter->v->co, l_iter_other->v->co, l_iter_other->next->v->co); + sub_v3_v3v3(vec, l_iter->v->co, co_other); + + const float dist_sq = len_squared_v3(vec); + if (dist_sq > dist_max_sq) { + dist_max_sq = dist_sq; + copy_v3_v3(r_tangent, vec); + } + } while ((l_iter_other = l_iter_other->next) != l_iter_last); + } while ((l_iter = l_iter->next) != l_first); + + normalize_v3(r_tangent); +} + +/** + * Compute the tanget of the face, using longest distance between vertices on the face. + * + * \note The logic is almost identical to #BM_face_calc_tangent_edge_diagonal + */ +void BM_face_calc_tangent_vert_diagonal(const BMFace *f, float r_tangent[3]) +{ + BMLoop *l_iter, *l_first; + + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + + /* incase of degenerate faces */ + zero_v3(r_tangent); + + /* warning: O(n^2) loop here, take care! */ + float dist_max_sq = 0.0f; + do { + BMLoop *l_iter_other = l_iter->next; + do { + float vec[3]; + sub_v3_v3v3(vec, l_iter->v->co, l_iter_other->v->co); + + const float dist_sq = len_squared_v3(vec); + if (dist_sq > dist_max_sq) { + dist_max_sq = dist_sq; + copy_v3_v3(r_tangent, vec); + } + } while ((l_iter_other = l_iter_other->next) != l_iter); + } while ((l_iter = l_iter->next) != l_first); + + normalize_v3(r_tangent); +} + +/** + * Compute a meaningful direction along the face (use for manipulator axis). + * + * \note Callers shouldn't depend on the *exact* method used here. + */ +void BM_face_calc_tangent_auto(const BMFace *f, float r_tangent[3]) +{ + if (f->len == 3) { + /* most 'unique' edge of a triangle */ + BMVert *verts[3]; + BM_face_as_array_vert_tri((BMFace *)f, verts); + BM_vert_tri_calc_tangent_edge(verts, r_tangent); + } + else if (f->len == 4) { + /* longest edge pair of a quad */ + BM_face_calc_tangent_edge_pair((BMFace *)f, r_tangent); + } + else { + /* longest edge of an ngon */ + BM_face_calc_tangent_edge((BMFace *)f, r_tangent); + } } /** @@ -842,6 +1036,7 @@ void BM_face_triangulate( const int quad_method, const int ngon_method, const bool use_tag, + /* use for ngons only! */ MemArena *pf_arena, /* use for MOD_TRIANGULATE_NGON_BEAUTY only! */ diff --git a/source/blender/bmesh/intern/bmesh_polygon.h b/source/blender/bmesh/intern/bmesh_polygon.h index 8f0df81af73..1e50a504875 100644 --- a/source/blender/bmesh/intern/bmesh_polygon.h +++ b/source/blender/bmesh/intern/bmesh_polygon.h @@ -45,7 +45,11 @@ float BM_face_calc_normal_vcos( float BM_face_calc_normal_subset(const BMLoop *l_first, const BMLoop *l_last, float r_no[3]) ATTR_NONNULL(); float BM_face_calc_area(const BMFace *f) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); float BM_face_calc_perimeter(const BMFace *f) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); -void BM_face_calc_plane(const BMFace *f, float r_plane[3]) ATTR_NONNULL(); +void BM_face_calc_tangent_edge(const BMFace *f, float r_plane[3]) ATTR_NONNULL(); +void BM_face_calc_tangent_edge_pair(const BMFace *f, float r_plane[3]) ATTR_NONNULL(); +void BM_face_calc_tangent_edge_diagonal(const BMFace *f, float r_plane[3]) ATTR_NONNULL(); +void BM_face_calc_tangent_vert_diagonal(const BMFace *f, float r_plane[3]) ATTR_NONNULL(); +void BM_face_calc_tangent_auto(const BMFace *f, float r_plane[3]) ATTR_NONNULL(); void BM_face_calc_center_bounds(const BMFace *f, float center[3]) ATTR_NONNULL(); void BM_face_calc_center_mean(const BMFace *f, float center[3]) ATTR_NONNULL(); void BM_face_calc_center_mean_vcos( @@ -90,6 +94,7 @@ void BM_face_as_array_vert_quad(BMFace *f, BMVert *r_verts[4]) ATTR_NONNULL(); void BM_face_as_array_loop_tri(BMFace *f, BMLoop *r_loops[3]) ATTR_NONNULL(); void BM_face_as_array_loop_quad(BMFace *f, BMLoop *r_loops[4]) ATTR_NONNULL(); -void BM_vert_tri_calc_plane(BMVert *verts[3], float r_plane[3]); +void BM_vert_tri_calc_tangent_edge(BMVert *verts[3], float r_tangent[3]); +void BM_vert_tri_calc_tangent_edge_pair(BMVert *verts[3], float r_tangent[3]); #endif /* __BMESH_POLYGON_H__ */ diff --git a/source/blender/bmesh/intern/bmesh_polygon_edgenet.c b/source/blender/bmesh/intern/bmesh_polygon_edgenet.c index c224a1ad587..5ee0e904a33 100644 --- a/source/blender/bmesh/intern/bmesh_polygon_edgenet.c +++ b/source/blender/bmesh/intern/bmesh_polygon_edgenet.c @@ -97,15 +97,27 @@ static BMLoop *bm_edge_flagged_radial_first(BMEdge *e) return NULL; } +static void normalize_v2_m3_v3v3(float out[2], float axis_mat[3][3], const float v1[3], const float v2[3]) +{ + float dir[3]; + sub_v3_v3v3(dir, v1, v2); + mul_v2_m3v3(out, axis_mat, dir); + normalize_v2(out); +} + + +/** + * \note Be sure to update #bm_face_split_edgenet_find_loop_pair_exists + * when making changed to edge picking logic. + */ static bool bm_face_split_edgenet_find_loop_pair( - BMVert *v_init, const float face_normal[3], + BMVert *v_init, + const float face_normal[3], float face_normal_matrix[3][3], BMEdge *e_pair[2]) { /* Always find one boundary edge (to determine winding) * and one wire (if available), otherwise another boundary. */ - BMIter iter; - BMEdge *e; /* detect winding */ BMLoop *l_walk; @@ -116,18 +128,22 @@ static bool bm_face_split_edgenet_find_loop_pair( int edges_boundary_len = 0; int edges_wire_len = 0; - BM_ITER_ELEM (e, &iter, v_init, BM_EDGES_OF_VERT) { - if (BM_ELEM_API_FLAG_TEST(e, EDGE_NET)) { - const unsigned int count = bm_edge_flagged_radial_count(e); - if (count == 1) { - BLI_SMALLSTACK_PUSH(edges_boundary, e); - edges_boundary_len++; - } - else if (count == 0) { - BLI_SMALLSTACK_PUSH(edges_wire, e); - edges_wire_len++; + { + BMEdge *e, *e_first; + e = e_first = v_init->e; + do { + if (BM_ELEM_API_FLAG_TEST(e, EDGE_NET)) { + const unsigned int count = bm_edge_flagged_radial_count(e); + if (count == 1) { + BLI_SMALLSTACK_PUSH(edges_boundary, e); + edges_boundary_len++; + } + else if (count == 0) { + BLI_SMALLSTACK_PUSH(edges_wire, e); + edges_wire_len++; + } } - } + } while ((e = BM_DISK_EDGE_NEXT(e, v_init)) != e_first); } /* first edge should always be boundary */ @@ -136,10 +152,17 @@ static bool bm_face_split_edgenet_find_loop_pair( } e_pair[0] = BLI_SMALLSTACK_POP(edges_boundary); + /* use to hold boundary OR wire edges */ + BLI_SMALLSTACK_DECLARE(edges_search, BMEdge *); + /* attempt one boundary and one wire, or 2 boundary */ if (edges_wire_len == 0) { - if (edges_boundary_len >= 2) { + if (edges_boundary_len > 1) { e_pair[1] = BLI_SMALLSTACK_POP(edges_boundary); + + if (edges_boundary_len > 2) { + BLI_SMALLSTACK_SWAP(edges_search, edges_wire); + } } else { /* one boundary and no wire */ @@ -148,27 +171,37 @@ static bool bm_face_split_edgenet_find_loop_pair( } else { e_pair[1] = BLI_SMALLSTACK_POP(edges_wire); - if (edges_wire_len > 1) { - BMVert *v_prev = BM_edge_other_vert(e_pair[0], v_init); - BMVert *v_next; - float angle_best; - - v_next = BM_edge_other_vert(e_pair[1], v_init); - angle_best = angle_on_axis_v3v3v3_v3(v_prev->co, v_init->co, v_next->co, face_normal); - - while ((e = BLI_SMALLSTACK_POP(edges_wire))) { - float angle_test; - v_next = BM_edge_other_vert(e, v_init); - angle_test = angle_on_axis_v3v3v3_v3(v_prev->co, v_init->co, v_next->co, face_normal); - if (angle_test < angle_best) { - angle_best = angle_test; - e_pair[1] = e; - } - } + BLI_SMALLSTACK_SWAP(edges_search, edges_wire); } } + /* if we swapped above, search this list for the best edge */ + if (!BLI_SMALLSTACK_IS_EMPTY(edges_search)) { + /* find the best edge in 'edge_list' to use for 'e_pair[1]' */ + const BMVert *v_prev = BM_edge_other_vert(e_pair[0], v_init); + const BMVert *v_next = BM_edge_other_vert(e_pair[1], v_init); + + float dir_prev[2], dir_next[2]; + + normalize_v2_m3_v3v3(dir_prev, face_normal_matrix, v_prev->co, v_init->co); + normalize_v2_m3_v3v3(dir_next, face_normal_matrix, v_next->co, v_init->co); + float angle_best_cos = dot_v2v2(dir_next, dir_prev); + + BMEdge *e; + while ((e = BLI_SMALLSTACK_POP(edges_search))) { + v_next = BM_edge_other_vert(e, v_init); + float dir_test[2]; + + normalize_v2_m3_v3v3(dir_test, face_normal_matrix, v_next->co, v_init->co); + const float angle_test_cos = dot_v2v2(dir_prev, dir_test); + + if (angle_test_cos > angle_best_cos) { + angle_best_cos = angle_test_cos; + e_pair[1] = e; + } + } + } /* flip based on winding */ l_walk = bm_edge_flagged_radial_first(e_pair[0]); @@ -186,6 +219,58 @@ static bool bm_face_split_edgenet_find_loop_pair( return true; } +/** + * A reduced version of #bm_face_split_edgenet_find_loop_pair + * that only checks if it would return true. + * + * \note There is no use in caching resulting edges here, + * since between this check and running #bm_face_split_edgenet_find_loop, + * the selected edges may have had faces attached. + */ +static bool bm_face_split_edgenet_find_loop_pair_exists( + BMVert *v_init) +{ + int edges_boundary_len = 0; + int edges_wire_len = 0; + + { + BMEdge *e, *e_first; + e = e_first = v_init->e; + do { + if (BM_ELEM_API_FLAG_TEST(e, EDGE_NET)) { + const unsigned int count = bm_edge_flagged_radial_count(e); + if (count == 1) { + edges_boundary_len++; + } + else if (count == 0) { + edges_wire_len++; + } + } + } while ((e = BM_DISK_EDGE_NEXT(e, v_init)) != e_first); + } + + /* first edge should always be boundary */ + if (edges_boundary_len == 0) { + return false; + } + + /* attempt one boundary and one wire, or 2 boundary */ + if (edges_wire_len == 0) { + if (edges_boundary_len >= 2) { + /* pass */ + } + else { + /* one boundary and no wire */ + return false; + } + } + else { + /* pass */ + } + + return true; +} + static bool bm_face_split_edgenet_find_loop_walk( BMVert *v_init, const float face_normal[3], /* cache to avoid realloc every time */ @@ -232,9 +317,6 @@ static bool bm_face_split_edgenet_find_loop_walk( * alternatives are stored in the 'vert_stack'. */ while ((v = BLI_SMALLSTACK_POP_EX(vert_stack, vert_stack_next))) { - BMIter eiter; - BMEdge *e_next; - #ifdef USE_FASTPATH_NOFORK walk_nofork: #else @@ -250,35 +332,42 @@ walk_nofork: goto finally; } - BM_ITER_ELEM (e_next, &eiter, v, BM_EDGES_OF_VERT) { - if ((v->e != e_next) && - (BM_ELEM_API_FLAG_TEST(e_next, EDGE_NET)) && - (bm_edge_flagged_radial_count(e_next) < 2)) - { - BMVert *v_next; + BMEdge *e_next, *e_first; + e_first = v->e; + e_next = BM_DISK_EDGE_NEXT(e_first, v); /* always skip this verts edge */ + + /* in rare cases there may be edges with a single connecting vertex */ + if (e_next != e_first) { + do { + if ((BM_ELEM_API_FLAG_TEST(e_next, EDGE_NET)) && + (bm_edge_flagged_radial_count(e_next) < 2)) + { + BMVert *v_next; - v_next = BM_edge_other_vert(e_next, v); + v_next = BM_edge_other_vert(e_next, v); + BLI_assert(v->e != e_next); #ifdef DEBUG_PRINT - /* indent and print */ - { - BMVert *_v = v; - do { - printf(" "); - } while ((_v = BM_edge_other_vert(_v->e, _v)) != v_init); - printf("vert %d -> %d (add=%d)\n", - BM_elem_index_get(v), BM_elem_index_get(v_next), - BM_ELEM_API_FLAG_TEST(v_next, VERT_VISIT) == 0); - } + /* indent and print */ + { + BMVert *_v = v; + do { + printf(" "); + } while ((_v = BM_edge_other_vert(_v->e, _v)) != v_init); + printf("vert %d -> %d (add=%d)\n", + BM_elem_index_get(v), BM_elem_index_get(v_next), + BM_ELEM_API_FLAG_TEST(v_next, VERT_VISIT) == 0); + } #endif - if (!BM_ELEM_API_FLAG_TEST(v_next, VERT_VISIT)) { - eo = STACK_PUSH_RET_PTR(edge_order); - eo->v = v_next; + if (!BM_ELEM_API_FLAG_TEST(v_next, VERT_VISIT)) { + eo = STACK_PUSH_RET_PTR(edge_order); + eo->v = v_next; - v_next->e = e_next; + v_next->e = e_next; + } } - } + } while ((e_next = BM_DISK_EDGE_NEXT(e_next, v)) != e_first); } #ifdef USE_FASTPATH_NOFORK @@ -329,7 +418,7 @@ finally: } static bool bm_face_split_edgenet_find_loop( - BMVert *v_init, const float face_normal[3], + BMVert *v_init, const float face_normal[3], float face_normal_matrix[3][3], /* cache to avoid realloc every time */ struct VertOrder *edge_order, const unsigned int edge_order_len, BMVert **r_face_verts, int *r_face_verts_len) @@ -337,7 +426,7 @@ static bool bm_face_split_edgenet_find_loop( BMEdge *e_pair[2]; BMVert *v; - if (!bm_face_split_edgenet_find_loop_pair(v_init, face_normal, e_pair)) { + if (!bm_face_split_edgenet_find_loop_pair(v_init, face_normal, face_normal_matrix, e_pair)) { return false; } @@ -432,12 +521,18 @@ bool BM_face_split_edgenet( BM_ELEM_API_FLAG_ENABLE(l_iter->e, EDGE_NET); } while ((l_iter = l_iter->next) != l_first); + float face_normal_matrix[3][3]; + axis_dominant_v3_to_m3(face_normal_matrix, f->no); + /* any vert can be used to begin with */ STACK_PUSH(vert_queue, l_first->v); while ((v = STACK_POP(vert_queue))) { - if (bm_face_split_edgenet_find_loop(v, f->no, edge_order, edge_order_len, face_verts, &face_verts_len)) { + if (bm_face_split_edgenet_find_loop( + v, f->no, face_normal_matrix, + edge_order, edge_order_len, face_verts, &face_verts_len)) + { BMFace *f_new; f_new = BM_face_create_verts(bm, face_verts, face_verts_len, f, BM_CREATE_NOP, false); @@ -447,7 +542,6 @@ bool BM_face_split_edgenet( } if (f_new) { - bool l_prev_is_boundary; BLI_array_append(face_arr, f_new); copy_v3_v3(f_new->no, f->no); @@ -463,13 +557,10 @@ bool BM_face_split_edgenet( /* add new verts to keep finding loops for * (verts between boundary and manifold edges) */ l_iter = l_first = BM_FACE_FIRST_LOOP(f_new); - l_prev_is_boundary = (bm_edge_flagged_radial_count(l_iter->prev->e) == 1); do { - bool l_iter_is_boundary = (bm_edge_flagged_radial_count(l_iter->e) == 1); - if (l_prev_is_boundary != l_iter_is_boundary) { + if (bm_face_split_edgenet_find_loop_pair_exists(l_iter->v)) { STACK_PUSH(vert_queue, l_iter->v); } - l_prev_is_boundary = l_iter_is_boundary; } while ((l_iter = l_iter->next) != l_first); } } diff --git a/source/blender/bmesh/intern/bmesh_private.h b/source/blender/bmesh/intern/bmesh_private.h index 9b3a147301d..d8d297c9298 100644 --- a/source/blender/bmesh/intern/bmesh_private.h +++ b/source/blender/bmesh/intern/bmesh_private.h @@ -67,12 +67,13 @@ enum { _FLAG_MV = (1 << 1), /* make face, vertex */ _FLAG_OVERLAP = (1 << 2), /* general overlap flag */ _FLAG_WALK = (1 << 3), /* general walk flag (keep clean) */ + _FLAG_WALK_ALT = (1 << 4), /* same as _FLAG_WALK, for when a second tag is needed */ _FLAG_ELEM_CHECK = (1 << 7), /* reserved for bmesh_elem_check */ }; #define BM_ELEM_API_FLAG_ENABLE(element, f) { ((element)->head.api_flag |= (f)); } (void)0 -#define BM_ELEM_API_FLAG_DISABLE(element, f) { ((element)->head.api_flag &= ~(f)); } (void)0 +#define BM_ELEM_API_FLAG_DISABLE(element, f) { ((element)->head.api_flag &= (unsigned char)~(f)); } (void)0 #define BM_ELEM_API_FLAG_TEST(element, f) ((element)->head.api_flag & (f)) #define BM_ELEM_API_FLAG_CLEAR(element) { ((element)->head.api_flag = 0); } (void)0 diff --git a/source/blender/bmesh/intern/bmesh_walkers_impl.c b/source/blender/bmesh/intern/bmesh_walkers_impl.c index 018700c0efa..279440984bb 100644 --- a/source/blender/bmesh/intern/bmesh_walkers_impl.c +++ b/source/blender/bmesh/intern/bmesh_walkers_impl.c @@ -49,7 +49,7 @@ static bool bmw_mask_check_vert(BMWalker *walker, BMVert *v) if ((walker->flag & BMW_FLAG_TEST_HIDDEN) && BM_elem_flag_test(v, BM_ELEM_HIDDEN)) { return false; } - else if (walker->mask_vert && !BMO_elem_flag_test(walker->bm, v, walker->mask_vert)) { + else if (walker->mask_vert && !BMO_vert_flag_test(walker->bm, v, walker->mask_vert)) { return false; } else { @@ -62,7 +62,7 @@ static bool bmw_mask_check_edge(BMWalker *walker, BMEdge *e) if ((walker->flag & BMW_FLAG_TEST_HIDDEN) && BM_elem_flag_test(e, BM_ELEM_HIDDEN)) { return false; } - else if (walker->mask_edge && !BMO_elem_flag_test(walker->bm, e, walker->mask_edge)) { + else if (walker->mask_edge && !BMO_edge_flag_test(walker->bm, e, walker->mask_edge)) { return false; } else { @@ -75,7 +75,7 @@ static bool bmw_mask_check_face(BMWalker *walker, BMFace *f) if ((walker->flag & BMW_FLAG_TEST_HIDDEN) && BM_elem_flag_test(f, BM_ELEM_HIDDEN)) { return false; } - else if (walker->mask_face && !BMO_elem_flag_test(walker->bm, f, walker->mask_face)) { + else if (walker->mask_face && !BMO_face_flag_test(walker->bm, f, walker->mask_face)) { return false; } else { @@ -223,7 +223,7 @@ static void *bmw_VertShellWalker_step(BMWalker *walker) do { if (!BLI_gset_haskey(walker->visit_set, curedge)) { if (!walker->restrictflag || - (walker->restrictflag && BMO_elem_flag_test(walker->bm, curedge, walker->restrictflag))) + (walker->restrictflag && BMO_edge_flag_test(walker->bm, curedge, walker->restrictflag))) { BMwShellWalker *newstate; @@ -748,7 +748,7 @@ static void *bmw_IslandboundWalker_step(BMWalker *walker) iwalk = BMW_state_add(walker); iwalk->base = owalk.base; - //if (!BMO_elem_flag_test(walker->bm, l->f, walker->restrictflag)) + //if (!BMO_face_flag_test(walker->bm, l->f, walker->restrictflag)) // iwalk->curloop = l->radial_next; iwalk->curloop = l; //else iwalk->curloop = l; iwalk->lastv = v; diff --git a/source/blender/bmesh/operators/bmo_beautify.c b/source/blender/bmesh/operators/bmo_beautify.c index 4a292c33472..c68d92ea5e0 100644 --- a/source/blender/bmesh/operators/bmo_beautify.c +++ b/source/blender/bmesh/operators/bmo_beautify.c @@ -52,7 +52,7 @@ void bmo_beautify_fill_exec(BMesh *bm, BMOperator *op) int edge_array_len = 0; BMO_ITER (f, &siter, op->slots_in, "faces", BM_FACE) { if (f->len == 3) { - BMO_elem_flag_enable(bm, f, FACE_MARK); + BMO_face_flag_enable(bm, f, FACE_MARK); } } @@ -68,8 +68,8 @@ void bmo_beautify_fill_exec(BMesh *bm, BMOperator *op) /* edge is manifold and can be rotated */ if (BM_edge_rotate_check(e) && /* faces are tagged */ - BMO_elem_flag_test(bm, e->l->f, FACE_MARK) && - BMO_elem_flag_test(bm, e->l->radial_next->f, FACE_MARK)) + BMO_face_flag_test(bm, e->l->f, FACE_MARK) && + BMO_face_flag_test(bm, e->l->radial_next->f, FACE_MARK)) { edge_array[edge_array_len] = e; edge_array_len++; diff --git a/source/blender/bmesh/operators/bmo_bridge.c b/source/blender/bmesh/operators/bmo_bridge.c index a0149a41921..6ef0fd6b084 100644 --- a/source/blender/bmesh/operators/bmo_bridge.c +++ b/source/blender/bmesh/operators/bmo_bridge.c @@ -131,13 +131,13 @@ static void bm_face_edges_tag_out(BMesh *bm, BMFace *f) BMLoop *l_iter, *l_first; l_iter = l_first = BM_FACE_FIRST_LOOP(f); do { - BMO_elem_flag_enable(bm, l_iter->e, EDGE_OUT); + BMO_edge_flag_enable(bm, l_iter->e, EDGE_OUT); } while ((l_iter = l_iter->next) != l_first); } static bool bm_edge_test_cb(BMEdge *e, void *bm_v) { - return BMO_elem_flag_test((BMesh *)bm_v, e, EDGE_MARK); + return BMO_edge_flag_test((BMesh *)bm_v, e, EDGE_MARK); } static void bridge_loop_pair( @@ -425,7 +425,7 @@ static void bridge_loop_pair( if (f_example && (f_example != f)) { BM_elem_attrs_copy(bm, bm, f_example, f); } - BMO_elem_flag_enable(bm, f, FACE_OUT); + BMO_face_flag_enable(bm, f, FACE_OUT); BM_elem_flag_enable(f, BM_ELEM_TAG); /* tag all edges of the face, untag the loop edges after */ @@ -486,7 +486,7 @@ static void bridge_loop_pair( BMOIter siter; BMFace *f; BMO_ITER (f, &siter, op_sub.slots_in, "faces", BM_FACE) { - BMO_elem_flag_enable(bm, f, FACE_OUT); + BMO_face_flag_enable(bm, f, FACE_OUT); bm_face_edges_tag_out(bm, f); } } @@ -498,7 +498,7 @@ static void bridge_loop_pair( BMOIter siter; BMFace *f; BMO_ITER (f, &siter, op_sub.slots_out, "geom.out", BM_FACE) { - BMO_elem_flag_enable(bm, f, FACE_OUT); + BMO_face_flag_enable(bm, f, FACE_OUT); bm_face_edges_tag_out(bm, f); } } @@ -520,7 +520,7 @@ static void bridge_loop_pair( if (el_next) { if (el->data != el_next->data) { BMEdge *e = BM_edge_exists(el->data, el_next->data); - BMO_elem_flag_disable(bm, e, EDGE_OUT); + BMO_edge_flag_disable(bm, e, EDGE_OUT); } } } diff --git a/source/blender/bmesh/operators/bmo_connect.c b/source/blender/bmesh/operators/bmo_connect.c index 0213329118c..5c9cd8dc3fa 100644 --- a/source/blender/bmesh/operators/bmo_connect.c +++ b/source/blender/bmesh/operators/bmo_connect.c @@ -62,10 +62,10 @@ static int bm_face_connect_verts(BMesh *bm, BMFace *f, const bool check_degenera l_iter = l_first = BM_FACE_FIRST_LOOP(f); do { - if (BMO_elem_flag_test(bm, l_iter->v, VERT_INPUT) && + if (BMO_vert_flag_test(bm, l_iter->v, VERT_INPUT) && /* ensure this vertex isnt part of a contiguous group */ - ((BMO_elem_flag_test(bm, l_iter->prev->v, VERT_INPUT) == 0) || - (BMO_elem_flag_test(bm, l_iter->next->v, VERT_INPUT) == 0))) + ((BMO_vert_flag_test(bm, l_iter->prev->v, VERT_INPUT) == 0) || + (BMO_vert_flag_test(bm, l_iter->next->v, VERT_INPUT) == 0))) { if (!l_tag_prev) { l_tag_prev = l_tag_first = l_iter; @@ -75,7 +75,7 @@ static int bm_face_connect_verts(BMesh *bm, BMFace *f, const bool check_degenera if (!BM_loop_is_adjacent(l_tag_prev, l_iter)) { BMEdge *e; e = BM_edge_exists(l_tag_prev->v, l_iter->v); - if (e == NULL || !BMO_elem_flag_test(bm, e, EDGE_OUT)) { + if (e == NULL || !BMO_edge_flag_test(bm, e, EDGE_OUT)) { BMLoop **l_pair = STACK_PUSH_RET(loops_split); l_pair[0] = l_tag_prev; l_pair[1] = l_iter; @@ -138,8 +138,8 @@ static int bm_face_connect_verts(BMesh *bm, BMFace *f, const bool check_degenera if (!l_new || !f_new) { return -1; } - // BMO_elem_flag_enable(bm, f_new, FACE_NEW); - BMO_elem_flag_enable(bm, l_new->e, EDGE_OUT); + // BMO_face_flag_enable(bm, f_new, FACE_NEW); + BMO_edge_flag_enable(bm, l_new->e, EDGE_OUT); } return 1; @@ -164,12 +164,12 @@ void bmo_connect_verts_exec(BMesh *bm, BMOperator *op) BMIter iter; BMLoop *l_iter; - BMO_elem_flag_enable(bm, v, VERT_INPUT); + BMO_vert_flag_enable(bm, v, VERT_INPUT); BM_ITER_ELEM (l_iter, &iter, v, BM_LOOPS_OF_VERT) { f = l_iter->f; - if (!BMO_elem_flag_test(bm, f, FACE_EXCLUDE)) { - if (!BMO_elem_flag_test(bm, f, FACE_TAG)) { - BMO_elem_flag_enable(bm, f, FACE_TAG); + if (!BMO_face_flag_test(bm, f, FACE_EXCLUDE)) { + if (!BMO_face_flag_test(bm, f, FACE_TAG)) { + BMO_face_flag_enable(bm, f, FACE_TAG); if (f->len > 3) { BLI_LINKSTACK_PUSH(faces, f); } @@ -179,11 +179,11 @@ void bmo_connect_verts_exec(BMesh *bm, BMOperator *op) /* flag edges even if these are not newly created * this way cut-pairs that include co-linear edges will get * predictable output. */ - if (BMO_elem_flag_test(bm, l_iter->prev->v, VERT_INPUT)) { - BMO_elem_flag_enable(bm, l_iter->prev->e, EDGE_OUT_ADJ); + if (BMO_vert_flag_test(bm, l_iter->prev->v, VERT_INPUT)) { + BMO_edge_flag_enable(bm, l_iter->prev->e, EDGE_OUT_ADJ); } - if (BMO_elem_flag_test(bm, l_iter->next->v, VERT_INPUT)) { - BMO_elem_flag_enable(bm, l_iter->e, EDGE_OUT_ADJ); + if (BMO_vert_flag_test(bm, l_iter->next->v, VERT_INPUT)) { + BMO_edge_flag_enable(bm, l_iter->e, EDGE_OUT_ADJ); } } } diff --git a/source/blender/bmesh/operators/bmo_connect_concave.c b/source/blender/bmesh/operators/bmo_connect_concave.c index 34f59aad4f1..9bb67ed9341 100644 --- a/source/blender/bmesh/operators/bmo_connect_concave.c +++ b/source/blender/bmesh/operators/bmo_connect_concave.c @@ -85,7 +85,7 @@ static bool bm_face_split_by_concave( BMFace **faces_array = BLI_array_alloca(faces_array, faces_array_tot); BMEdge **edges_array = BLI_array_alloca(edges_array, edges_array_tot); const int quad_method = 0, ngon_method = 0; /* beauty */ - LinkNode *r_faces_double = NULL; + LinkNode *faces_double = NULL; float normal[3]; BLI_assert(f_base->len > 3); @@ -96,7 +96,7 @@ static bool bm_face_split_by_concave( bm, f_base, faces_array, &faces_array_tot, edges_array, &edges_array_tot, - &r_faces_double, + &faces_double, quad_method, ngon_method, false, pf_arena, pf_heap, pf_ehash); @@ -107,10 +107,10 @@ static bool bm_face_split_by_concave( int i; for (i = 0; i < faces_array_tot; i++) { BMFace *f = faces_array[i]; - BMO_elem_flag_enable(bm, f, FACE_OUT); + BMO_face_flag_enable(bm, f, FACE_OUT); } } - BMO_elem_flag_enable(bm, f_base, FACE_OUT); + BMO_face_flag_enable(bm, f_base, FACE_OUT); if (edges_array_tot) { int i; @@ -120,7 +120,7 @@ static bool bm_face_split_by_concave( for (i = 0; i < edges_array_tot; i++) { BMLoop *l_pair[2]; BMEdge *e = edges_array[i]; - BMO_elem_flag_enable(bm, e, EDGE_OUT); + BMO_edge_flag_enable(bm, e, EDGE_OUT); if (BM_edge_is_contiguous(e) && BM_edge_loop_pair(e, &l_pair[0], &l_pair[1])) @@ -153,7 +153,7 @@ static bool bm_face_split_by_concave( BMFace *f_new, *f_pair[2] = {l_pair[0]->f, l_pair[1]->f}; f_new = BM_faces_join(bm, f_pair, 2, true); if (f_new) { - BMO_elem_flag_enable(bm, f_new, FACE_OUT); + BMO_face_flag_enable(bm, f_new, FACE_OUT); } } } @@ -163,6 +163,13 @@ static bool bm_face_split_by_concave( BLI_heap_clear(pf_heap, NULL); BLI_edgehash_clear_ex(pf_ehash, NULL, BLI_POLYFILL_ALLOC_NGON_RESERVE); + while (faces_double) { + LinkNode *next = faces_double->next; + BM_face_kill(bm, faces_double->link); + MEM_freeN(faces_double); + faces_double = next; + } + return true; } diff --git a/source/blender/bmesh/operators/bmo_connect_nonplanar.c b/source/blender/bmesh/operators/bmo_connect_nonplanar.c index c80fb95c44a..9b3e1d38feb 100644 --- a/source/blender/bmesh/operators/bmo_connect_nonplanar.c +++ b/source/blender/bmesh/operators/bmo_connect_nonplanar.c @@ -136,9 +136,9 @@ static bool bm_face_split_by_angle(BMesh *bm, BMFace *f, BMFace *r_f_pair[2], co r_f_pair[0] = f; r_f_pair[1] = f_new; - BMO_elem_flag_enable(bm, f, FACE_OUT); - BMO_elem_flag_enable(bm, f_new, FACE_OUT); - BMO_elem_flag_enable(bm, l_new->e, EDGE_OUT); + BMO_face_flag_enable(bm, f, FACE_OUT); + BMO_face_flag_enable(bm, f_new, FACE_OUT); + BMO_edge_flag_enable(bm, l_new->e, EDGE_OUT); return true; } } diff --git a/source/blender/bmesh/operators/bmo_connect_pair.c b/source/blender/bmesh/operators/bmo_connect_pair.c index 3b860778e1c..3eb6fe0cb97 100644 --- a/source/blender/bmesh/operators/bmo_connect_pair.c +++ b/source/blender/bmesh/operators/bmo_connect_pair.c @@ -67,18 +67,29 @@ #define ELE_TOUCHED 4 #define FACE_WALK_TEST(f) (CHECK_TYPE_INLINE(f, BMFace *), \ - BMO_elem_flag_test(pc->bm_bmoflag, f, FACE_EXCLUDE) == 0) + BMO_face_flag_test(pc->bm_bmoflag, f, FACE_EXCLUDE) == 0) #define VERT_WALK_TEST(v) (CHECK_TYPE_INLINE(v, BMVert *), \ - BMO_elem_flag_test(pc->bm_bmoflag, v, VERT_EXCLUDE) == 0) + BMO_vert_flag_test(pc->bm_bmoflag, v, VERT_EXCLUDE) == 0) +#if 0 #define ELE_TOUCH_TEST(e) \ (CHECK_TYPE_ANY(e, BMVert *, BMEdge *, BMElem *, BMElemF *), \ BMO_elem_flag_test(pc->bm_bmoflag, (BMElemF *)e, ELE_TOUCHED)) +#endif #define ELE_TOUCH_MARK(e) \ { CHECK_TYPE_ANY(e, BMVert *, BMEdge *, BMElem *, BMElemF *); \ BMO_elem_flag_enable(pc->bm_bmoflag, (BMElemF *)e, ELE_TOUCHED); } ((void)0) +#define ELE_TOUCH_TEST_VERT(v) BMO_vert_flag_test(pc->bm_bmoflag, v, ELE_TOUCHED) +// #define ELE_TOUCH_MARK_VERT(v) BMO_vert_flag_enable(pc->bm_bmoflag, (BMElemF *)e, ELE_TOUCHED) + +// #define ELE_TOUCH_TEST_EDGE(v) BMO_edge_flag_test(pc->bm_bmoflag, v, ELE_TOUCHED) +// #define ELE_TOUCH_MARK_EDGE(v) BMO_edge_flag_enable(pc->bm_bmoflag, (BMElemF *)e, ELE_TOUCHED) + +// #define ELE_TOUCH_TEST_FACE(v) BMO_face_flag_test(pc->bm_bmoflag, v, ELE_TOUCHED) +// #define ELE_TOUCH_MARK_FACE(v) BMO_face_flag_enable(pc->bm_bmoflag, (BMElemF *)e, ELE_TOUCHED) + // #define DEBUG_PRINT typedef struct PathContext { @@ -352,7 +363,7 @@ static PathLinkState *state_step__face_edges( BMElem *ele_next_from = (BMElem *)l_iter->f; if (FACE_WALK_TEST((BMFace *)ele_next_from) && - (ELE_TOUCH_TEST(ele_next) == false)) + (ELE_TOUCH_TEST_VERT((BMVert *)ele_next) == false)) { min_dist_dir_update(mddir, dist_dir); mddir->dist_min[index] = dist_test; @@ -397,7 +408,7 @@ static PathLinkState *state_step__face_verts( BMElem *ele_next_from = (BMElem *)l_iter->f; if (FACE_WALK_TEST((BMFace *)ele_next_from) && - (ELE_TOUCH_TEST(ele_next) == false)) + (ELE_TOUCH_TEST_VERT((BMVert *)ele_next) == false)) { min_dist_dir_update(mddir, dist_dir); mddir->dist_min[index] = dist_test; @@ -480,7 +491,7 @@ static bool state_step(PathContext *pc, PathLinkState *state) if (state_isect_co_exact(pc, v_other->co)) { BMElem *ele_next = (BMElem *)v_other; BMElem *ele_next_from = (BMElem *)e; - if (ELE_TOUCH_TEST(ele_next) == false) { + if (ELE_TOUCH_TEST_VERT((BMVert *)ele_next) == false) { state = state_link_add_test(pc, state, &state_orig, ele_next, ele_next_from); } } @@ -703,11 +714,11 @@ void bmo_connect_vert_pair_exec(BMesh *bm, BMOperator *op) BMVert *v_new; float e_fac = state_calc_co_pair_fac(&pc, e->v1->co, e->v2->co); v_new = BM_edge_split(bm, e, e->v1, NULL, e_fac); - BMO_elem_flag_enable(bm, v_new, VERT_OUT); + BMO_vert_flag_enable(bm, v_new, VERT_OUT); } else if (link->ele->head.htype == BM_VERT) { BMVert *v = (BMVert *)link->ele; - BMO_elem_flag_enable(bm, v, VERT_OUT); + BMO_vert_flag_enable(bm, v, VERT_OUT); } else { BLI_assert(0); @@ -715,8 +726,8 @@ void bmo_connect_vert_pair_exec(BMesh *bm, BMOperator *op) } while ((link = link->next)); } - BMO_elem_flag_enable(bm, pc.v_a, VERT_OUT); - BMO_elem_flag_enable(bm, pc.v_b, VERT_OUT); + BMO_vert_flag_enable(bm, pc.v_a, VERT_OUT); + BMO_vert_flag_enable(bm, pc.v_b, VERT_OUT); BLI_mempool_destroy(pc.link_pool); diff --git a/source/blender/bmesh/operators/bmo_create.c b/source/blender/bmesh/operators/bmo_create.c index a1e20dab63e..7b8cb36ab59 100644 --- a/source/blender/bmesh/operators/bmo_create.c +++ b/source/blender/bmesh/operators/bmo_create.c @@ -52,12 +52,19 @@ void bmo_contextual_create_exec(BMesh *bm, BMOperator *op) /* count number of each element type we were passe */ BMO_ITER (h, &oiter, op->slots_in, "geom", BM_VERT | BM_EDGE | BM_FACE) { switch (h->htype) { - case BM_VERT: totv++; break; - case BM_EDGE: tote++; break; - case BM_FACE: totf++; break; + case BM_VERT: + BMO_vert_flag_enable(bm, (BMVert *)h, ELE_NEW); + totv++; + break; + case BM_EDGE: + BMO_edge_flag_enable(bm, (BMEdge *)h, ELE_NEW); + tote++; + break; + case BM_FACE: + BMO_face_flag_enable(bm, (BMFace *)h, ELE_NEW); + totf++; + break; } - - BMO_elem_flag_enable(bm, (BMElemF *)h, ELE_NEW); } /* --- Support Edge Creation --- @@ -71,7 +78,7 @@ void bmo_contextual_create_exec(BMesh *bm, BMOperator *op) /* create edge */ e = BM_edge_create(bm, verts[0], verts[1], NULL, BM_CREATE_NO_DOUBLE); - BMO_elem_flag_enable(bm, e, ELE_OUT); + BMO_edge_flag_enable(bm, e, ELE_OUT); tote += 1; BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "edges.out", BM_EDGE, ELE_OUT); return; @@ -131,10 +138,10 @@ void bmo_contextual_create_exec(BMesh *bm, BMOperator *op) BMEdge *e; e = BM_edge_create(bm, v_free, v_a, NULL, BM_CREATE_NO_DOUBLE); - BMO_elem_flag_enable(bm, e, ELE_NEW); + BMO_edge_flag_enable(bm, e, ELE_NEW); e = BM_edge_create(bm, v_free, v_b, NULL, BM_CREATE_NO_DOUBLE); - BMO_elem_flag_enable(bm, e, ELE_NEW); + BMO_edge_flag_enable(bm, e, ELE_NEW); tote += 2; } } @@ -236,7 +243,7 @@ void bmo_contextual_create_exec(BMesh *bm, BMOperator *op) for (ese = bm->selected.first; ese; ese = ese->next) { if (ese->htype == BM_VERT) { - if (BMO_elem_flag_test(bm, (BMElemF *)ese->ele, ELE_NEW)) { + if (BMO_vert_flag_test(bm, (BMVert *)ese->ele, ELE_NEW)) { tot_ese_v++; } else { @@ -256,7 +263,7 @@ void bmo_contextual_create_exec(BMesh *bm, BMOperator *op) BMVert *v = (BMVert *)ese->ele; if (v_prev) { BMEdge *e = BM_edge_create(bm, v, v_prev, NULL, BM_CREATE_NO_DOUBLE); - BMO_elem_flag_enable(bm, e, ELE_OUT); + BMO_edge_flag_enable(bm, e, ELE_OUT); } v_prev = v; } @@ -286,7 +293,7 @@ void bmo_contextual_create_exec(BMesh *bm, BMOperator *op) f = BM_face_create_ngon_vcloud(bm, vert_arr, totv, NULL, BM_CREATE_NO_DOUBLE); if (f) { - BMO_elem_flag_enable(bm, f, ELE_OUT); + BMO_face_flag_enable(bm, f, ELE_OUT); f->mat_nr = mat_nr; if (use_smooth) { BM_elem_flag_enable(f, BM_ELEM_SMOOTH); diff --git a/source/blender/bmesh/operators/bmo_dissolve.c b/source/blender/bmesh/operators/bmo_dissolve.c index 86062ff0b66..05efb14a699 100644 --- a/source/blender/bmesh/operators/bmo_dissolve.c +++ b/source/blender/bmesh/operators/bmo_dissolve.c @@ -74,10 +74,10 @@ static bool UNUSED_FUNCTION(check_hole_in_region) (BMesh *bm, BMFace *f) for (f2 = BMW_begin(®walker, f); f2; f2 = BMW_step(®walker)) { BM_ITER_ELEM (l2, &liter2, f2, BM_LOOPS_OF_FACE) { l3 = l2->radial_next; - if (BMO_elem_flag_test(bm, l3->f, FACE_MARK) != - BMO_elem_flag_test(bm, l2->f, FACE_MARK)) + if (BMO_face_flag_test(bm, l3->f, FACE_MARK) != + BMO_face_flag_test(bm, l2->f, FACE_MARK)) { - if (!BMO_elem_flag_test(bm, l2->e, EDGE_MARK)) { + if (!BMO_edge_flag_test(bm, l2->e, EDGE_MARK)) { return false; } } @@ -99,14 +99,14 @@ static void bm_face_split(BMesh *bm, const short oflag, bool use_edge_delete) } BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { - if (BMO_elem_flag_test(bm, v, oflag)) { + if (BMO_vert_flag_test(bm, v, oflag)) { if (BM_vert_is_edge_pair(v) == false) { BMIter liter; BMLoop *l; BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) { if (l->f->len > 3) { - if (BMO_elem_flag_test(bm, l->next->v, oflag) == 0 && - BMO_elem_flag_test(bm, l->prev->v, oflag) == 0) + if (BMO_vert_flag_test(bm, l->next->v, oflag) == 0 && + BMO_vert_flag_test(bm, l->prev->v, oflag) == 0) { BM_face_split(bm, l->f, l->next, l->prev, NULL, NULL, true); } @@ -153,7 +153,7 @@ void bmo_dissolve_faces_exec(BMesh *bm, BMOperator *op) BMVert *v; BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) { - BMO_elem_flag_set(bm, v, VERT_MARK, !BM_vert_is_edge_pair(v)); + BMO_vert_flag_set(bm, v, VERT_MARK, !BM_vert_is_edge_pair(v)); } } @@ -162,7 +162,7 @@ void bmo_dissolve_faces_exec(BMesh *bm, BMOperator *op) /* collect region */ BMO_ITER (f, &oiter, op->slots_in, "faces", BM_FACE) { BMFace *f_iter; - if (!BMO_elem_flag_test(bm, f, FACE_TAG)) { + if (!BMO_face_flag_test(bm, f, FACE_TAG)) { continue; } @@ -181,8 +181,8 @@ void bmo_dissolve_faces_exec(BMesh *bm, BMOperator *op) for (i = 0; i < BLI_array_count(faces); i++) { f_iter = faces[i]; - BMO_elem_flag_disable(bm, f_iter, FACE_TAG); - BMO_elem_flag_enable(bm, f_iter, FACE_ORIG); + BMO_face_flag_disable(bm, f_iter, FACE_TAG); + BMO_face_flag_enable(bm, f_iter, FACE_ORIG); } if (BMO_error_occurred(bm)) { @@ -229,8 +229,8 @@ void bmo_dissolve_faces_exec(BMesh *bm, BMOperator *op) /* if making the new face failed (e.g. overlapping test) * unmark the original faces for deletion */ - BMO_elem_flag_disable(bm, f_new, FACE_ORIG); - BMO_elem_flag_enable(bm, f_new, FACE_NEW); + BMO_face_flag_disable(bm, f_new, FACE_ORIG); + BMO_face_flag_enable(bm, f_new, FACE_NEW); } /* Typically no faces need to be deleted */ @@ -243,7 +243,7 @@ void bmo_dissolve_faces_exec(BMesh *bm, BMOperator *op) BMVert *v, *v_next; BM_ITER_MESH_MUTABLE (v, v_next, &viter, bm, BM_VERTS_OF_MESH) { - if (BMO_elem_flag_test(bm, v, VERT_MARK)) { + if (BMO_vert_flag_test(bm, v, VERT_MARK)) { if (BM_vert_is_edge_pair(v)) { BM_vert_collapse_edge(bm, v->e, v, true, true); } @@ -285,14 +285,14 @@ void bmo_dissolve_edges_exec(BMesh *bm, BMOperator *op) BMIter itersub; int untag_count = 0; BM_ITER_ELEM (e, &itersub, v, BM_EDGES_OF_VERT) { - if (!BMO_elem_flag_test(bm, e, EDGE_TAG)) { + if (!BMO_edge_flag_test(bm, e, EDGE_TAG)) { untag_count++; } } /* check that we have 2 edges remaining after dissolve */ if (untag_count <= 2) { - BMO_elem_flag_enable(bm, v, VERT_TAG); + BMO_vert_flag_enable(bm, v, VERT_TAG); } } @@ -301,7 +301,7 @@ void bmo_dissolve_edges_exec(BMesh *bm, BMOperator *op) if (use_verts) { BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { - BMO_elem_flag_set(bm, v, VERT_MARK, !BM_vert_is_edge_pair(v)); + BMO_vert_flag_set(bm, v, VERT_MARK, !BM_vert_is_edge_pair(v)); } } @@ -314,8 +314,8 @@ void bmo_dissolve_edges_exec(BMesh *bm, BMOperator *op) BMLoop *l_first, *l_iter; l_iter = l_first = BM_FACE_FIRST_LOOP(f_pair[j]); do { - BMO_elem_flag_enable(bm, l_iter->v, VERT_ISGC); - BMO_elem_flag_enable(bm, l_iter->e, EDGE_ISGC); + BMO_vert_flag_enable(bm, l_iter->v, VERT_ISGC); + BMO_edge_flag_enable(bm, l_iter->e, EDGE_ISGC); } while ((l_iter = l_iter->next) != l_first); } } @@ -341,12 +341,12 @@ void bmo_dissolve_edges_exec(BMesh *bm, BMOperator *op) /* Cleanup geometry (#BM_faces_join_pair, but it removes geometry we're looping on) * so do this in a separate pass instead. */ BM_ITER_MESH_MUTABLE (e, e_next, &iter, bm, BM_EDGES_OF_MESH) { - if ((e->l == NULL) && BMO_elem_flag_test(bm, e, EDGE_ISGC)) { + if ((e->l == NULL) && BMO_edge_flag_test(bm, e, EDGE_ISGC)) { BM_edge_kill(bm, e); } } BM_ITER_MESH_MUTABLE (v, v_next, &iter, bm, BM_VERTS_OF_MESH) { - if ((v->e == NULL) && BMO_elem_flag_test(bm, v, VERT_ISGC)) { + if ((v->e == NULL) && BMO_vert_flag_test(bm, v, VERT_ISGC)) { BM_vert_kill(bm, v); } } @@ -355,7 +355,7 @@ void bmo_dissolve_edges_exec(BMesh *bm, BMOperator *op) if (use_verts) { BM_ITER_MESH_MUTABLE (v, v_next, &iter, bm, BM_VERTS_OF_MESH) { - if (BMO_elem_flag_test(bm, v, VERT_MARK)) { + if (BMO_vert_flag_test(bm, v, VERT_MARK)) { if (BM_vert_is_edge_pair(v)) { BM_vert_collapse_edge(bm, v->e, v, true, true); } @@ -376,7 +376,7 @@ void bmo_dissolve_verts_exec(BMesh *bm, BMOperator *op) const bool use_boundary_tear = BMO_slot_bool_get(op->slots_in, "use_boundary_tear"); BMO_ITER (v, &oiter, op->slots_in, "verts", BM_VERT) { - BMO_elem_flag_enable(bm, v, VERT_MARK | VERT_ISGC); + BMO_vert_flag_enable(bm, v, VERT_MARK | VERT_ISGC); } if (use_face_split) { @@ -388,7 +388,7 @@ void bmo_dissolve_verts_exec(BMesh *bm, BMOperator *op) if (!BM_vert_is_edge_pair(v)) { BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) { if (BM_edge_is_boundary(e)) { - BMO_elem_flag_enable(bm, v, VERT_MARK_TEAR); + BMO_vert_flag_enable(bm, v, VERT_MARK_TEAR); break; } } @@ -406,8 +406,8 @@ void bmo_dissolve_verts_exec(BMesh *bm, BMOperator *op) BMLoop *l_iter; l_iter = l_first; do { - BMO_elem_flag_enable(bm, l_iter->v, VERT_ISGC); - BMO_elem_flag_enable(bm, l_iter->e, EDGE_ISGC); + BMO_vert_flag_enable(bm, l_iter->v, VERT_ISGC); + BMO_edge_flag_enable(bm, l_iter->e, EDGE_ISGC); } while ((l_iter = l_iter->next) != l_first); e_first = l_first->e; @@ -428,14 +428,14 @@ void bmo_dissolve_verts_exec(BMesh *bm, BMOperator *op) BMO_ITER (v, &oiter, op->slots_in, "verts", BM_VERT) { /* tag here so we avoid feedback loop (checking topology as we edit) */ if (BM_vert_is_edge_pair(v)) { - BMO_elem_flag_enable(bm, v, VERT_MARK_PAIR); + BMO_vert_flag_enable(bm, v, VERT_MARK_PAIR); } } BMO_ITER (v, &oiter, op->slots_in, "verts", BM_VERT) { BMIter itersub; - if (!BMO_elem_flag_test(bm, v, VERT_MARK_PAIR)) { + if (!BMO_vert_flag_test(bm, v, VERT_MARK_PAIR)) { BM_ITER_ELEM (e, &itersub, v, BM_EDGES_OF_VERT) { BMFace *fa, *fb; if (BM_edge_face_pair(e, &fa, &fb)) { @@ -456,7 +456,7 @@ void bmo_dissolve_verts_exec(BMesh *bm, BMOperator *op) /* Cleanup geometry (#BM_faces_join_pair, but it removes geometry we're looping on) * so do this in a separate pass instead. */ BM_ITER_MESH_MUTABLE (e, e_next, &iter, bm, BM_EDGES_OF_MESH) { - if ((e->l == NULL) && BMO_elem_flag_test(bm, e, EDGE_ISGC)) { + if ((e->l == NULL) && BMO_edge_flag_test(bm, e, EDGE_ISGC)) { BM_edge_kill(bm, e); } } @@ -469,7 +469,7 @@ void bmo_dissolve_verts_exec(BMesh *bm, BMOperator *op) } BM_ITER_MESH_MUTABLE (v, v_next, &iter, bm, BM_VERTS_OF_MESH) { - if ((v->e == NULL) && BMO_elem_flag_test(bm, v, VERT_ISGC)) { + if ((v->e == NULL) && BMO_vert_flag_test(bm, v, VERT_ISGC)) { BM_vert_kill(bm, v); } } @@ -518,9 +518,9 @@ void bmo_dissolve_degenerate_exec(BMesh *bm, BMOperator *op) /* collapse zero length edges, this accounts for zero area faces too */ found = false; BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) { - if (BMO_elem_flag_test(bm, e, EDGE_MARK)) { + if (BMO_edge_flag_test(bm, e, EDGE_MARK)) { if (BM_edge_calc_length_squared(e) < dist_sq) { - BMO_elem_flag_enable(bm, e, EDGE_COLLAPSE); + BMO_edge_flag_enable(bm, e, EDGE_COLLAPSE); found = true; } } @@ -543,7 +543,7 @@ void bmo_dissolve_degenerate_exec(BMesh *bm, BMOperator *op) /* clip degenerate ears from the face */ found = false; BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) { - if (e->l && BMO_elem_flag_test(bm, e, EDGE_MARK)) { + if (e->l && BMO_edge_flag_test(bm, e, EDGE_MARK)) { BMLoop *l_iter, *l_first; l_iter = l_first = e->l; do { @@ -553,11 +553,11 @@ void bmo_dissolve_degenerate_exec(BMesh *bm, BMOperator *op) ((void)BM_elem_flag_enable(l_iter, BM_ELEM_TAG), /* check we're marked to tested (radial edge already tested) */ - BMO_elem_flag_test(bm, l_iter->prev->e, EDGE_MARK) && + BMO_edge_flag_test(bm, l_iter->prev->e, EDGE_MARK) && /* check edges are not already going to be collapsed */ - !BMO_elem_flag_test(bm, l_iter->e, EDGE_COLLAPSE) && - !BMO_elem_flag_test(bm, l_iter->prev->e, EDGE_COLLAPSE))) + !BMO_edge_flag_test(bm, l_iter->e, EDGE_COLLAPSE) && + !BMO_edge_flag_test(bm, l_iter->prev->e, EDGE_COLLAPSE))) { /* test if the faces loop (ear) is degenerate */ float dir_prev[3], len_prev; @@ -577,14 +577,14 @@ void bmo_dissolve_degenerate_exec(BMesh *bm, BMOperator *op) /* both edges the same length */ if (l_iter->f->len == 3) { /* ideally this would have been discovered with short edge test above */ - BMO_elem_flag_enable(bm, l_iter->next->e, EDGE_COLLAPSE); + BMO_edge_flag_enable(bm, l_iter->next->e, EDGE_COLLAPSE); found = true; } else { /* add a joining edge and tag for removal */ BMLoop *l_split; if (BM_face_split(bm, l_iter->f, l_iter->prev, l_iter->next, &l_split, NULL, true)) { - BMO_elem_flag_enable(bm, l_split->e, EDGE_COLLAPSE); + BMO_edge_flag_enable(bm, l_split->e, EDGE_COLLAPSE); found = true; reset = true; } @@ -599,7 +599,7 @@ void bmo_dissolve_degenerate_exec(BMesh *bm, BMOperator *op) BLI_assert(v_new == l_iter->next->v); (void)v_new; if (BM_face_split(bm, l_iter->f, l_iter->prev, l_iter->next, &l_split, NULL, true)) { - BMO_elem_flag_enable(bm, l_split->e, EDGE_COLLAPSE); + BMO_edge_flag_enable(bm, l_split->e, EDGE_COLLAPSE); found = true; } reset = true; @@ -613,7 +613,7 @@ void bmo_dissolve_degenerate_exec(BMesh *bm, BMOperator *op) BLI_assert(v_new == l_iter->prev->v); (void)v_new; if (BM_face_split(bm, l_iter->f, l_iter->prev, l_iter->next, &l_split, NULL, true)) { - BMO_elem_flag_enable(bm, l_split->e, EDGE_COLLAPSE); + BMO_edge_flag_enable(bm, l_split->e, EDGE_COLLAPSE); found = true; } reset = true; diff --git a/source/blender/bmesh/operators/bmo_dupe.c b/source/blender/bmesh/operators/bmo_dupe.c index fd430de80f9..56639a097b6 100644 --- a/source/blender/bmesh/operators/bmo_dupe.c +++ b/source/blender/bmesh/operators/bmo_dupe.c @@ -63,7 +63,7 @@ static BMVert *bmo_vert_copy( BM_elem_attrs_copy(bm_src, bm_dst, v_src, v_dst); /* Mark the vert for output */ - BMO_elem_flag_enable(bm_dst, v_dst, DUPE_NEW); + BMO_vert_flag_enable(bm_dst, v_dst, DUPE_NEW); return v_dst; } @@ -94,7 +94,7 @@ static BMEdge *bmo_edge_copy( BMLoop *l_iter_src, *l_first_src; l_iter_src = l_first_src = e_src->l; do { - if (BMO_elem_flag_test(bm_src, l_iter_src->f, DUPE_INPUT)) { + if (BMO_face_flag_test(bm_src, l_iter_src->f, DUPE_INPUT)) { rlen++; } } while ((l_iter_src = l_iter_src->radial_next) != l_first_src); @@ -123,7 +123,7 @@ static BMEdge *bmo_edge_copy( BM_elem_attrs_copy(bm_src, bm_dst, e_src, e_dst); /* Mark the edge for output */ - BMO_elem_flag_enable(bm_dst, e_dst, DUPE_NEW); + BMO_edge_flag_enable(bm_dst, e_dst, DUPE_NEW); return e_dst; } @@ -175,7 +175,7 @@ static BMFace *bmo_face_copy( (l_iter_src = l_iter_src->next) != l_first_src); /* Mark the face for output */ - BMO_elem_flag_enable(bm_dst, f_dst, DUPE_NEW); + BMO_face_flag_enable(bm_dst, f_dst, DUPE_NEW); return f_dst; } @@ -209,8 +209,8 @@ static void bmo_mesh_copy(BMOperator *op, BMesh *bm_dst, BMesh *bm_src) /* duplicate flagged vertices */ BM_ITER_MESH (v, &viter, bm_src, BM_VERTS_OF_MESH) { - if (BMO_elem_flag_test(bm_src, v, DUPE_INPUT) && - !BMO_elem_flag_test(bm_src, v, DUPE_DONE)) + if (BMO_vert_flag_test(bm_src, v, DUPE_INPUT) && + BMO_vert_flag_test(bm_src, v, DUPE_DONE) == false) { BMIter iter; bool isolated = true; @@ -218,7 +218,7 @@ static void bmo_mesh_copy(BMOperator *op, BMesh *bm_dst, BMesh *bm_src) v2 = bmo_vert_copy(op, slot_vert_map_out, bm_dst, bm_src, v, vhash); BM_ITER_ELEM (f, &iter, v, BM_FACES_OF_VERT) { - if (BMO_elem_flag_test(bm_src, f, DUPE_INPUT)) { + if (BMO_face_flag_test(bm_src, f, DUPE_INPUT)) { isolated = false; break; } @@ -226,7 +226,7 @@ static void bmo_mesh_copy(BMOperator *op, BMesh *bm_dst, BMesh *bm_src) if (isolated) { BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) { - if (BMO_elem_flag_test(bm_src, e, DUPE_INPUT)) { + if (BMO_edge_flag_test(bm_src, e, DUPE_INPUT)) { isolated = false; break; } @@ -237,53 +237,53 @@ static void bmo_mesh_copy(BMOperator *op, BMesh *bm_dst, BMesh *bm_src) BMO_slot_map_elem_insert(op, slot_isovert_map_out, v, v2); } - BMO_elem_flag_enable(bm_src, v, DUPE_DONE); + BMO_vert_flag_enable(bm_src, v, DUPE_DONE); } } /* now we dupe all the edges */ BM_ITER_MESH (e, &eiter, bm_src, BM_EDGES_OF_MESH) { - if (BMO_elem_flag_test(bm_src, e, DUPE_INPUT) && - !BMO_elem_flag_test(bm_src, e, DUPE_DONE)) + if (BMO_edge_flag_test(bm_src, e, DUPE_INPUT) && + BMO_edge_flag_test(bm_src, e, DUPE_DONE) == false) { /* make sure that verts are copied */ - if (!BMO_elem_flag_test(bm_src, e->v1, DUPE_DONE)) { + if (!BMO_vert_flag_test(bm_src, e->v1, DUPE_DONE)) { bmo_vert_copy(op, slot_vert_map_out, bm_dst, bm_src, e->v1, vhash); - BMO_elem_flag_enable(bm_src, e->v1, DUPE_DONE); + BMO_vert_flag_enable(bm_src, e->v1, DUPE_DONE); } - if (!BMO_elem_flag_test(bm_src, e->v2, DUPE_DONE)) { + if (!BMO_vert_flag_test(bm_src, e->v2, DUPE_DONE)) { bmo_vert_copy(op, slot_vert_map_out, bm_dst, bm_src, e->v2, vhash); - BMO_elem_flag_enable(bm_src, e->v2, DUPE_DONE); + BMO_vert_flag_enable(bm_src, e->v2, DUPE_DONE); } /* now copy the actual edge */ bmo_edge_copy(op, slot_edge_map_out, slot_boundary_map_out, bm_dst, bm_src, e, vhash, ehash); - BMO_elem_flag_enable(bm_src, e, DUPE_DONE); + BMO_edge_flag_enable(bm_src, e, DUPE_DONE); } } /* first we dupe all flagged faces and their elements from source */ BM_ITER_MESH (f, &fiter, bm_src, BM_FACES_OF_MESH) { - if (BMO_elem_flag_test(bm_src, f, DUPE_INPUT)) { + if (BMO_face_flag_test(bm_src, f, DUPE_INPUT)) { /* vertex pass */ BM_ITER_ELEM (v, &viter, f, BM_VERTS_OF_FACE) { - if (!BMO_elem_flag_test(bm_src, v, DUPE_DONE)) { + if (!BMO_vert_flag_test(bm_src, v, DUPE_DONE)) { bmo_vert_copy(op, slot_vert_map_out, bm_dst, bm_src, v, vhash); - BMO_elem_flag_enable(bm_src, v, DUPE_DONE); + BMO_vert_flag_enable(bm_src, v, DUPE_DONE); } } /* edge pass */ BM_ITER_ELEM (e, &eiter, f, BM_EDGES_OF_FACE) { - if (!BMO_elem_flag_test(bm_src, e, DUPE_DONE)) { + if (!BMO_edge_flag_test(bm_src, e, DUPE_DONE)) { bmo_edge_copy(op, slot_edge_map_out, slot_boundary_map_out, bm_dst, bm_src, e, vhash, ehash); - BMO_elem_flag_enable(bm_src, e, DUPE_DONE); + BMO_edge_flag_enable(bm_src, e, DUPE_DONE); } } bmo_face_copy(op, slot_face_map_out, bm_dst, bm_src, f, vhash, ehash); - BMO_elem_flag_enable(bm_src, f, DUPE_DONE); + BMO_face_flag_enable(bm_src, f, DUPE_DONE); } } @@ -408,26 +408,26 @@ void bmo_split_exec(BMesh *bm, BMOperator *op) BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { bool found = false; BM_ITER_ELEM (f, &iter2, e, BM_FACES_OF_EDGE) { - if (!BMO_elem_flag_test(bm, f, SPLIT_INPUT)) { + if (!BMO_face_flag_test(bm, f, SPLIT_INPUT)) { found = true; break; } } if (found == false) { - BMO_elem_flag_enable(bm, e, SPLIT_INPUT); + BMO_edge_flag_enable(bm, e, SPLIT_INPUT); } } BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { bool found = false; BM_ITER_ELEM (e, &iter2, v, BM_EDGES_OF_VERT) { - if (!BMO_elem_flag_test(bm, e, SPLIT_INPUT)) { + if (!BMO_edge_flag_test(bm, e, SPLIT_INPUT)) { found = true; break; } } if (found == false) { - BMO_elem_flag_enable(bm, v, SPLIT_INPUT); + BMO_vert_flag_enable(bm, v, SPLIT_INPUT); } } } diff --git a/source/blender/bmesh/operators/bmo_edgenet.c b/source/blender/bmesh/operators/bmo_edgenet.c index f348014cead..64b092da5c8 100644 --- a/source/blender/bmesh/operators/bmo_edgenet.c +++ b/source/blender/bmesh/operators/bmo_edgenet.c @@ -94,8 +94,8 @@ static BMEdge *edge_next(BMesh *bm, BMEdge *e) for (i = 0; i < 2; i++) { BM_ITER_ELEM (e2, &iter, i ? e->v2 : e->v1, BM_EDGES_OF_VERT) { - if ((BMO_elem_flag_test(bm, e2, EDGE_MARK)) && - (!BMO_elem_flag_test(bm, e2, EDGE_VIS)) && + if ((BMO_edge_flag_test(bm, e2, EDGE_MARK)) && + (BMO_edge_flag_test(bm, e2, EDGE_VIS) == false) && (e2 != e)) { return e2; @@ -144,7 +144,7 @@ void bmo_edgenet_prepare_exec(BMesh *bm, BMOperator *op) count = 0; while (1) { BMO_ITER (e, &siter, op->slots_in, "edges", BM_EDGE) { - if (!BMO_elem_flag_test(bm, e, EDGE_VIS)) { + if (!BMO_edge_flag_test(bm, e, EDGE_VIS)) { if (BMO_iter_elem_count_flag(bm, BM_EDGES_OF_VERT, e->v1, EDGE_MARK, true) == 1 || BMO_iter_elem_count_flag(bm, BM_EDGES_OF_VERT, e->v2, EDGE_MARK, true) == 1) { @@ -169,7 +169,7 @@ void bmo_edgenet_prepare_exec(BMesh *bm, BMOperator *op) i = 0; while (e) { - BMO_elem_flag_enable(bm, e, EDGE_VIS); + BMO_edge_flag_enable(bm, e, EDGE_VIS); BLI_array_grow_one(edges); edges[i] = e; @@ -258,9 +258,9 @@ void bmo_edgenet_prepare_exec(BMesh *bm, BMOperator *op) } e = BM_edge_create(bm, v1, v3, NULL, BM_CREATE_NO_DOUBLE); - BMO_elem_flag_enable(bm, e, ELE_NEW); + BMO_edge_flag_enable(bm, e, ELE_NEW); e = BM_edge_create(bm, v2, v4, NULL, BM_CREATE_NO_DOUBLE); - BMO_elem_flag_enable(bm, e, ELE_NEW); + BMO_edge_flag_enable(bm, e, ELE_NEW); } else if (edges1) { BMVert *v1, *v2; @@ -270,7 +270,7 @@ void bmo_edgenet_prepare_exec(BMesh *bm, BMOperator *op) i = BLI_array_count(edges1) - 1; v2 = BM_vert_in_edge(edges1[i - 1], edges1[i]->v1) ? edges1[i]->v2 : edges1[i]->v1; e = BM_edge_create(bm, v1, v2, NULL, BM_CREATE_NO_DOUBLE); - BMO_elem_flag_enable(bm, e, ELE_NEW); + BMO_edge_flag_enable(bm, e, ELE_NEW); } } diff --git a/source/blender/bmesh/operators/bmo_extrude.c b/source/blender/bmesh/operators/bmo_extrude.c index 5a3bef6ba81..f2a8e05d763 100644 --- a/source/blender/bmesh/operators/bmo_extrude.c +++ b/source/blender/bmesh/operators/bmo_extrude.c @@ -70,10 +70,10 @@ void bmo_extrude_discrete_faces_exec(BMesh *bm, BMOperator *op) BMLoop *l_org, *l_org_first; BMLoop *l_new; - BMO_elem_flag_enable(bm, f_org, EXT_DEL); + BMO_face_flag_enable(bm, f_org, EXT_DEL); f_new = BM_face_copy(bm, bm, f_org, true, true); - BMO_elem_flag_enable(bm, f_new, EXT_KEEP); + BMO_face_flag_enable(bm, f_new, EXT_KEEP); if (select_history_map) { BMEditSelection *ese; @@ -188,9 +188,9 @@ void bmo_extrude_edge_only_exec(BMesh *bm, BMOperator *op) BMEdge *e, *e_new; BMO_ITER (e, &siter, op->slots_in, "edges", BM_EDGE) { - BMO_elem_flag_enable(bm, e, EXT_INPUT); - BMO_elem_flag_enable(bm, e->v1, EXT_INPUT); - BMO_elem_flag_enable(bm, e->v2, EXT_INPUT); + BMO_edge_flag_enable(bm, e, EXT_INPUT); + BMO_vert_flag_enable(bm, e->v1, EXT_INPUT); + BMO_vert_flag_enable(bm, e->v2, EXT_INPUT); } BMO_op_initf( @@ -228,13 +228,14 @@ void bmo_extrude_edge_only_exec(BMesh *bm, BMOperator *op) f = BM_face_create_verts(bm, f_verts, 4, NULL, BM_CREATE_NOP, true); bm_extrude_copy_face_loop_attributes(bm, f); - if (BMO_elem_flag_test(bm, e, EXT_INPUT)) + if (BMO_edge_flag_test(bm, e, EXT_INPUT)) { e = e_new; + } - BMO_elem_flag_enable(bm, f, EXT_KEEP); - BMO_elem_flag_enable(bm, e, EXT_KEEP); - BMO_elem_flag_enable(bm, e->v1, EXT_KEEP); - BMO_elem_flag_enable(bm, e->v2, EXT_KEEP); + BMO_face_flag_enable(bm, f, EXT_KEEP); + BMO_edge_flag_enable(bm, e, EXT_KEEP); + BMO_vert_flag_enable(bm, e->v1, EXT_KEEP); + BMO_vert_flag_enable(bm, e->v2, EXT_KEEP); } @@ -258,7 +259,7 @@ void bmo_extrude_vert_indiv_exec(BMesh *bm, BMOperator *op) for (v = BMO_iter_new(&siter, op->slots_in, "verts", BM_VERT); v; v = BMO_iter_step(&siter)) { dupev = BM_vert_create(bm, v->co, v, BM_CREATE_NOP); - BMO_elem_flag_enable(bm, dupev, EXT_KEEP); + BMO_vert_flag_enable(bm, dupev, EXT_KEEP); if (has_vskin) bm_extrude_disable_skin_root(bm, v); @@ -279,7 +280,7 @@ void bmo_extrude_vert_indiv_exec(BMesh *bm, BMOperator *op) } e = BM_edge_create(bm, v, dupev, NULL, BM_CREATE_NOP); - BMO_elem_flag_enable(bm, e, EXT_KEEP); + BMO_edge_flag_enable(bm, e, EXT_KEEP); } if (select_history_map) { @@ -350,7 +351,7 @@ void bmo_extrude_face_region_exec(BMesh *bm, BMOperator *op) int edge_face_tot; - if (!BMO_elem_flag_test(bm, e, EXT_INPUT)) { + if (!BMO_edge_flag_test(bm, e, EXT_INPUT)) { continue; } @@ -358,7 +359,7 @@ void bmo_extrude_face_region_exec(BMesh *bm, BMOperator *op) edge_face_tot = 0; /* edge/face count */ BM_ITER_ELEM (f, &fiter, e, BM_FACES_OF_EDGE) { - if (!BMO_elem_flag_test(bm, f, EXT_INPUT)) { + if (!BMO_face_flag_test(bm, f, EXT_INPUT)) { found = true; delorig = true; break; @@ -369,7 +370,7 @@ void bmo_extrude_face_region_exec(BMesh *bm, BMOperator *op) if ((edge_face_tot > 1) && (found == false)) { /* edge has a face user, that face isn't extrude input */ - BMO_elem_flag_enable(bm, e, EXT_DEL); + BMO_edge_flag_enable(bm, e, EXT_DEL); } } } @@ -380,7 +381,9 @@ void bmo_extrude_face_region_exec(BMesh *bm, BMOperator *op) found = false; BM_ITER_ELEM (e, &viter, v, BM_EDGES_OF_VERT) { - if (!BMO_elem_flag_test(bm, e, EXT_INPUT) || !BMO_elem_flag_test(bm, e, EXT_DEL)) { + if (!BMO_edge_flag_test(bm, e, EXT_INPUT) || + !BMO_edge_flag_test(bm, e, EXT_DEL)) + { found = true; break; } @@ -389,7 +392,7 @@ void bmo_extrude_face_region_exec(BMesh *bm, BMOperator *op) /* avoid an extra loop */ if (found == true) { BM_ITER_ELEM (f, &viter, v, BM_FACES_OF_VERT) { - if (!BMO_elem_flag_test(bm, f, EXT_INPUT)) { + if (!BMO_face_flag_test(bm, f, EXT_INPUT)) { found = true; break; } @@ -397,14 +400,14 @@ void bmo_extrude_face_region_exec(BMesh *bm, BMOperator *op) } if (found == false) { - BMO_elem_flag_enable(bm, v, EXT_DEL); + BMO_vert_flag_enable(bm, v, EXT_DEL); } } } BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { - if (BMO_elem_flag_test(bm, f, EXT_INPUT)) { - BMO_elem_flag_enable(bm, f, EXT_DEL); + if (BMO_face_flag_test(bm, f, EXT_INPUT)) { + BMO_face_flag_enable(bm, f, EXT_DEL); } } @@ -426,7 +429,7 @@ void bmo_extrude_face_region_exec(BMesh *bm, BMOperator *op) } slot_facemap_out = BMO_slot_get(dupeop.slots_out, "face_map.out"); - if (bm->act_face && BMO_elem_flag_test(bm, bm->act_face, EXT_INPUT)) { + if (bm->act_face && BMO_face_flag_test(bm, bm->act_face, EXT_INPUT)) { bm->act_face = BMO_slot_map_elem_get(slot_facemap_out, bm->act_face); } @@ -437,7 +440,7 @@ void bmo_extrude_face_region_exec(BMesh *bm, BMOperator *op) /* if not delorig, reverse loops of original face */ if (!delorig) { BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { - if (BMO_elem_flag_test(bm, f, EXT_INPUT)) { + if (BMO_face_flag_test(bm, f, EXT_INPUT)) { BM_face_normal_flip(bm, f); } } @@ -583,7 +586,7 @@ static void calc_solidify_normals(BMesh *bm) BM_mesh_elem_index_ensure(bm, BM_EDGE); BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) { - if (!BMO_elem_flag_test(bm, f, FACE_MARK)) { + if (!BMO_face_flag_test(bm, f, FACE_MARK)) { continue; } @@ -591,15 +594,15 @@ static void calc_solidify_normals(BMesh *bm) /* And mark all edges and vertices on the * marked faces */ - BMO_elem_flag_enable(bm, e, EDGE_MARK); - BMO_elem_flag_enable(bm, e->v1, VERT_MARK); - BMO_elem_flag_enable(bm, e->v2, VERT_MARK); + BMO_edge_flag_enable(bm, e, EDGE_MARK); + BMO_vert_flag_enable(bm, e->v1, VERT_MARK); + BMO_vert_flag_enable(bm, e->v2, VERT_MARK); edge_face_count[BM_elem_index_get(e)]++; } } BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) { - if (!BMO_elem_flag_test(bm, e, EDGE_MARK)) { + if (!BMO_edge_flag_test(bm, e, EDGE_MARK)) { continue; } @@ -608,9 +611,9 @@ static void calc_solidify_normals(BMesh *bm) if (i == 0 || i > 2) { /* Edge & vertices are non-manifold even when considering * only marked faces */ - BMO_elem_flag_enable(bm, e, EDGE_NONMAN); - BMO_elem_flag_enable(bm, e->v1, VERT_NONMAN); - BMO_elem_flag_enable(bm, e->v2, VERT_NONMAN); + BMO_edge_flag_enable(bm, e, EDGE_NONMAN); + BMO_vert_flag_enable(bm, e->v1, VERT_NONMAN); + BMO_vert_flag_enable(bm, e->v2, VERT_NONMAN); } } MEM_freeN(edge_face_count); @@ -618,11 +621,11 @@ static void calc_solidify_normals(BMesh *bm) BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) { if (!BM_vert_is_manifold(v)) { - BMO_elem_flag_enable(bm, v, VERT_NONMAN); + BMO_vert_flag_enable(bm, v, VERT_NONMAN); continue; } - if (BMO_elem_flag_test(bm, v, VERT_MARK)) { + if (BMO_vert_flag_test(bm, v, VERT_MARK)) { zero_v3(v->no); } } @@ -631,20 +634,20 @@ static void calc_solidify_normals(BMesh *bm) /* If the edge is not part of a the solidify region * its normal should not be considered */ - if (!BMO_elem_flag_test(bm, e, EDGE_MARK)) { + if (!BMO_edge_flag_test(bm, e, EDGE_MARK)) { continue; } /* If the edge joins more than two marked faces high * quality normal computation won't work */ - if (BMO_elem_flag_test(bm, e, EDGE_NONMAN)) { + if (BMO_edge_flag_test(bm, e, EDGE_NONMAN)) { continue; } f1 = f2 = NULL; BM_ITER_ELEM (f, &fiter, e, BM_FACES_OF_EDGE) { - if (BMO_elem_flag_test(bm, f, FACE_MARK)) { + if (BMO_face_flag_test(bm, f, FACE_MARK)) { if (f1 == NULL) { f1 = f; } @@ -689,11 +692,11 @@ static void calc_solidify_normals(BMesh *bm) /* normalize accumulated vertex normal */ BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) { - if (!BMO_elem_flag_test(bm, v, VERT_MARK)) { + if (!BMO_vert_flag_test(bm, v, VERT_MARK)) { continue; } - if (BMO_elem_flag_test(bm, v, VERT_NONMAN)) { + if (BMO_vert_flag_test(bm, v, VERT_NONMAN)) { /* use standard normals for vertices connected to non-manifold edges */ BM_vert_normal_update(v); } @@ -701,7 +704,7 @@ static void calc_solidify_normals(BMesh *bm) /* exceptional case, totally flat. use the normal * of any marked face around the vertex */ BM_ITER_ELEM (f, &fiter, v, BM_FACES_OF_VERT) { - if (BMO_elem_flag_test(bm, f, FACE_MARK)) { + if (BMO_face_flag_test(bm, f, FACE_MARK)) { break; } } @@ -726,7 +729,7 @@ static void solidify_add_thickness(BMesh *bm, const float dist) BM_mesh_elem_index_ensure(bm, BM_VERT); BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { - if (BMO_elem_flag_test(bm, f, FACE_MARK)) { + if (BMO_face_flag_test(bm, f, FACE_MARK)) { /* array for passing verts to angle_poly_v3 */ float *face_angles = BLI_buffer_reinit_data(&face_angles_buf, float, f->len); diff --git a/source/blender/bmesh/operators/bmo_fill_edgeloop.c b/source/blender/bmesh/operators/bmo_fill_edgeloop.c index 0fbaf5ff11a..c68130bc11d 100644 --- a/source/blender/bmesh/operators/bmo_fill_edgeloop.c +++ b/source/blender/bmesh/operators/bmo_fill_edgeloop.c @@ -59,14 +59,14 @@ void bmo_edgeloop_fill_exec(BMesh *bm, BMOperator *op) i = 0; BMO_ITER (e, &oiter, op->slots_in, "edges", BM_EDGE) { BMIter viter; - BMO_elem_flag_enable(bm, e, EDGE_MARK); + BMO_edge_flag_enable(bm, e, EDGE_MARK); BM_ITER_ELEM (v, &viter, e, BM_VERTS_OF_EDGE) { - if (BMO_elem_flag_test(bm, v, VERT_USED) == false) { + if (BMO_vert_flag_test(bm, v, VERT_USED) == false) { if (i == tote) { goto cleanup; } - BMO_elem_flag_enable(bm, v, VERT_USED); + BMO_vert_flag_enable(bm, v, VERT_USED); verts[i++] = v; } } @@ -103,21 +103,21 @@ void bmo_edgeloop_fill_exec(BMesh *bm, BMOperator *op) while (totv_used < totv) { for (i = 0; i < totv; i++) { v = verts[i]; - if (BMO_elem_flag_test(bm, v, VERT_USED)) { + if (BMO_vert_flag_test(bm, v, VERT_USED)) { break; } } /* this should never fail, as long as (totv_used < totv) * we should have marked verts available */ - BLI_assert(BMO_elem_flag_test(bm, v, VERT_USED)); + BLI_assert(BMO_vert_flag_test(bm, v, VERT_USED)); /* watch it, 'i' is used for final face length */ i = 0; do { /* we know that there are 2 edges per vertex so no need to check */ BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) { - if (BMO_elem_flag_test(bm, e, EDGE_MARK)) { + if (BMO_edge_flag_test(bm, e, EDGE_MARK)) { if (e != e_prev) { e_next = e; break; @@ -127,7 +127,7 @@ void bmo_edgeloop_fill_exec(BMesh *bm, BMOperator *op) /* fill in the array */ f_verts[i] = v; - BMO_elem_flag_disable(bm, v, VERT_USED); + BMO_vert_flag_disable(bm, v, VERT_USED); totv_used++; /* step over the edges */ @@ -141,7 +141,7 @@ void bmo_edgeloop_fill_exec(BMesh *bm, BMOperator *op) /* don't use calc_edges option because we already have the edges */ f = BM_face_create_ngon_verts(bm, f_verts, i, NULL, BM_CREATE_NOP, true, false); - BMO_elem_flag_enable(bm, f, ELE_OUT); + BMO_face_flag_enable(bm, f, ELE_OUT); f->mat_nr = mat_nr; if (use_smooth) { BM_elem_flag_enable(f, BM_ELEM_SMOOTH); diff --git a/source/blender/bmesh/operators/bmo_fill_grid.c b/source/blender/bmesh/operators/bmo_fill_grid.c index 77556591728..04ae915b707 100644 --- a/source/blender/bmesh/operators/bmo_fill_grid.c +++ b/source/blender/bmesh/operators/bmo_fill_grid.c @@ -466,7 +466,7 @@ static void bm_grid_fill_array( /* end interp */ - BMO_elem_flag_enable(bm, f, FACE_OUT); + BMO_face_flag_enable(bm, f, FACE_OUT); f->mat_nr = mat_nr; if (use_smooth) { BM_elem_flag_enable(f, BM_ELEM_SMOOTH); @@ -585,7 +585,7 @@ static void bm_edgeloop_flag_set(struct BMEdgeLoopStore *estore, char hflag, boo static bool bm_edge_test_cb(BMEdge *e, void *bm_v) { - return BMO_elem_flag_test_bool((BMesh *)bm_v, e, EDGE_MARK); + return BMO_edge_flag_test_bool((BMesh *)bm_v, e, EDGE_MARK); } static bool bm_edge_test_rail_cb(BMEdge *e, void *UNUSED(bm_v)) diff --git a/source/blender/bmesh/operators/bmo_hull.c b/source/blender/bmesh/operators/bmo_hull.c index 2dfad5a1f47..9c41e4f2115 100644 --- a/source/blender/bmesh/operators/bmo_hull.c +++ b/source/blender/bmesh/operators/bmo_hull.c @@ -81,7 +81,7 @@ static void hull_add_triangle( /* Mark triangles vertices as not interior */ for (i = 0; i < 3; i++) - BMO_elem_flag_disable(bm, t->v[i], HULL_FLAG_INTERIOR_ELE); + BMO_vert_flag_disable(bm, t->v[i], HULL_FLAG_INTERIOR_ELE); BLI_gset_insert(hull_triangles, t); normal_tri_v3(t->no, v1->co, v2->co, v3->co); @@ -93,8 +93,8 @@ static BMFace *hull_find_example_face(BMesh *bm, BMEdge *e) BMFace *f; BM_ITER_ELEM (f, &iter, e, BM_FACES_OF_EDGE) { - if (BMO_elem_flag_test(bm, f, HULL_FLAG_INPUT) || - !BMO_elem_flag_test(bm, f, HULL_FLAG_OUTPUT_GEOM)) + if (BMO_face_flag_test(bm, f, HULL_FLAG_INPUT) || + BMO_face_flag_test(bm, f, HULL_FLAG_OUTPUT_GEOM) == false) { return f; } @@ -124,9 +124,9 @@ static void hull_output_triangles(BMesh *bm, GSet *hull_triangles) * disabled, but an output face in the hull is the * same as a face in the existing mesh, it should not * be marked as unused or interior. */ - BMO_elem_flag_enable(bm, f, HULL_FLAG_OUTPUT_GEOM); - BMO_elem_flag_disable(bm, f, HULL_FLAG_HOLE); - BMO_elem_flag_disable(bm, f, HULL_FLAG_INTERIOR_ELE); + BMO_face_flag_enable(bm, f, HULL_FLAG_OUTPUT_GEOM); + BMO_face_flag_disable(bm, f, HULL_FLAG_HOLE); + BMO_face_flag_disable(bm, f, HULL_FLAG_INTERIOR_ELE); } else { /* Look for an adjacent face that existed before the hull */ @@ -140,12 +140,12 @@ static void hull_output_triangles(BMesh *bm, GSet *hull_triangles) BM_face_copy_shared(bm, f, NULL, NULL); } /* Mark face for 'geom.out' slot and select */ - BMO_elem_flag_enable(bm, f, HULL_FLAG_OUTPUT_GEOM); + BMO_face_flag_enable(bm, f, HULL_FLAG_OUTPUT_GEOM); BM_face_select_set(bm, f, true); /* Mark edges for 'geom.out' slot */ for (i = 0; i < 3; i++) { - BMO_elem_flag_enable(bm, edges[i], HULL_FLAG_OUTPUT_GEOM); + BMO_edge_flag_enable(bm, edges[i], HULL_FLAG_OUTPUT_GEOM); } } else { @@ -154,17 +154,17 @@ static void hull_output_triangles(BMesh *bm, GSet *hull_triangles) const int next = (i == 2 ? 0 : i + 1); BMEdge *e = BM_edge_exists(t->v[i], t->v[next]); if (e && - BMO_elem_flag_test(bm, e, HULL_FLAG_INPUT) && - !BMO_elem_flag_test(bm, e, HULL_FLAG_HOLE)) + BMO_edge_flag_test(bm, e, HULL_FLAG_INPUT) && + !BMO_edge_flag_test(bm, e, HULL_FLAG_HOLE)) { - BMO_elem_flag_enable(bm, e, HULL_FLAG_OUTPUT_GEOM); + BMO_edge_flag_enable(bm, e, HULL_FLAG_OUTPUT_GEOM); } } } /* Mark verts for 'geom.out' slot */ for (i = 0; i < 3; i++) { - BMO_elem_flag_enable(bm, t->v[i], HULL_FLAG_OUTPUT_GEOM); + BMO_vert_flag_enable(bm, t->v[i], HULL_FLAG_OUTPUT_GEOM); } } } @@ -292,8 +292,8 @@ static void hull_remove_overlapping( BM_vert_in_face(t->v[2], f) && f_on_hull) { t->skip = true; - BMO_elem_flag_disable(bm, f, HULL_FLAG_INTERIOR_ELE); - BMO_elem_flag_enable(bm, f, HULL_FLAG_HOLE); + BMO_face_flag_disable(bm, f, HULL_FLAG_INTERIOR_ELE); + BMO_face_flag_enable(bm, f, HULL_FLAG_HOLE); } } } @@ -310,13 +310,13 @@ static void hull_mark_interior_elements( /* Check for interior edges too */ BMO_ITER (e, &oiter, op->slots_in, "input", BM_EDGE) { if (!hull_final_edges_lookup(final_edges, e->v1, e->v2)) - BMO_elem_flag_enable(bm, e, HULL_FLAG_INTERIOR_ELE); + BMO_edge_flag_enable(bm, e, HULL_FLAG_INTERIOR_ELE); } /* Mark all input faces as interior, some may be unmarked in * hull_remove_overlapping() */ BMO_ITER (f, &oiter, op->slots_in, "input", BM_FACE) { - BMO_elem_flag_enable(bm, f, HULL_FLAG_INTERIOR_ELE); + BMO_face_flag_enable(bm, f, HULL_FLAG_INTERIOR_ELE); } } @@ -333,47 +333,50 @@ static void hull_tag_unused(BMesh *bm, BMOperator *op) * the hull), but that aren't also used by elements outside the * input set */ BMO_ITER (v, &oiter, op->slots_in, "input", BM_VERT) { - if (BMO_elem_flag_test(bm, v, HULL_FLAG_INTERIOR_ELE)) { + if (BMO_vert_flag_test(bm, v, HULL_FLAG_INTERIOR_ELE)) { bool del = true; BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) { - if (!BMO_elem_flag_test(bm, e, HULL_FLAG_INPUT)) { + if (!BMO_edge_flag_test(bm, e, HULL_FLAG_INPUT)) { del = false; break; } } BM_ITER_ELEM (f, &iter, v, BM_FACES_OF_VERT) { - if (!BMO_elem_flag_test(bm, f, HULL_FLAG_INPUT)) { + if (!BMO_face_flag_test(bm, f, HULL_FLAG_INPUT)) { del = false; break; } } - if (del) - BMO_elem_flag_enable(bm, v, HULL_FLAG_DEL); + if (del) { + BMO_vert_flag_enable(bm, v, HULL_FLAG_DEL); + } } } BMO_ITER (e, &oiter, op->slots_in, "input", BM_EDGE) { - if (BMO_elem_flag_test(bm, e, HULL_FLAG_INTERIOR_ELE)) { + if (BMO_edge_flag_test(bm, e, HULL_FLAG_INTERIOR_ELE)) { bool del = true; BM_ITER_ELEM (f, &iter, e, BM_FACES_OF_EDGE) { - if (!BMO_elem_flag_test(bm, f, HULL_FLAG_INPUT)) { + if (!BMO_face_flag_test(bm, f, HULL_FLAG_INPUT)) { del = false; break; } } - if (del) - BMO_elem_flag_enable(bm, e, HULL_FLAG_DEL); + if (del) { + BMO_edge_flag_enable(bm, e, HULL_FLAG_DEL); + } } } BMO_ITER (f, &oiter, op->slots_in, "input", BM_FACE) { - if (BMO_elem_flag_test(bm, f, HULL_FLAG_INTERIOR_ELE)) - BMO_elem_flag_enable(bm, f, HULL_FLAG_DEL); + if (BMO_face_flag_test(bm, f, HULL_FLAG_INTERIOR_ELE)) { + BMO_face_flag_enable(bm, f, HULL_FLAG_DEL); + } } } @@ -387,10 +390,10 @@ static void hull_tag_holes(BMesh *bm, BMOperator *op) /* Unmark any hole faces if they are isolated or part of a * border */ BMO_ITER (f, &oiter, op->slots_in, "input", BM_FACE) { - if (BMO_elem_flag_test(bm, f, HULL_FLAG_HOLE)) { + if (BMO_face_flag_test(bm, f, HULL_FLAG_HOLE)) { BM_ITER_ELEM (e, &iter, f, BM_EDGES_OF_FACE) { if (BM_edge_is_boundary(e)) { - BMO_elem_flag_disable(bm, f, HULL_FLAG_HOLE); + BMO_face_flag_disable(bm, f, HULL_FLAG_HOLE); break; } } @@ -405,14 +408,14 @@ static void hull_tag_holes(BMesh *bm, BMOperator *op) BM_ITER_ELEM (f, &iter, e, BM_FACES_OF_EDGE) { any_faces = true; - if (!BMO_elem_flag_test(bm, f, HULL_FLAG_HOLE)) { + if (!BMO_face_flag_test(bm, f, HULL_FLAG_HOLE)) { hole = false; break; } } if (hole && any_faces) - BMO_elem_flag_enable(bm, e, HULL_FLAG_HOLE); + BMO_edge_flag_enable(bm, e, HULL_FLAG_HOLE); } } @@ -578,11 +581,17 @@ void bmo_convex_hull_exec(BMesh *bm, BMOperator *op) /* Tag input elements */ BMO_ITER (ele, &oiter, op->slots_in, "input", BM_ALL) { - BMO_elem_flag_enable(bm, ele, HULL_FLAG_INPUT); - + /* Mark all vertices as interior to begin with */ - if (ele->head.htype == BM_VERT) - BMO_elem_flag_enable(bm, ele, HULL_FLAG_INTERIOR_ELE); + if (ele->head.htype == BM_VERT) { + BMO_vert_flag_enable(bm, (BMVert *)ele, HULL_FLAG_INPUT | HULL_FLAG_INTERIOR_ELE); + } + else if (ele->head.htype == BM_EDGE) { + BMO_edge_flag_enable(bm, (BMEdge *)ele, HULL_FLAG_INPUT); + } + else { + BMO_face_flag_enable(bm, (BMFace *)ele, HULL_FLAG_INPUT); + } } hull_pool = BLI_mempool_create(sizeof(HullTriangle), 0, 128, BLI_MEMPOOL_NOP); diff --git a/source/blender/bmesh/operators/bmo_inset.c b/source/blender/bmesh/operators/bmo_inset.c index ef5d90e6acb..c52c608e671 100644 --- a/source/blender/bmesh/operators/bmo_inset.c +++ b/source/blender/bmesh/operators/bmo_inset.c @@ -313,7 +313,7 @@ static void bmo_face_inset_individual( l_iter->next->v, l_iter->v, f, BM_CREATE_NOP); - BMO_elem_flag_enable(bm, f_new_outer, ELE_NEW); + BMO_face_flag_enable(bm, f_new_outer, ELE_NEW); /* copy loop data */ l_other = l_iter->radial_next; @@ -1037,7 +1037,7 @@ void bmo_inset_region_exec(BMesh *bm, BMOperator *op) /* no need to check doubles, we KNOW there won't be any */ /* yes - reverse face is correct in this case */ f = BM_face_create_verts(bm, varr, j, es->l->f, BM_CREATE_NOP, true); - BMO_elem_flag_enable(bm, f, ELE_NEW); + BMO_face_flag_enable(bm, f, ELE_NEW); /* copy for loop data, otherwise UV's and vcols are no good. * tiny speedup here we could be more clever and copy from known adjacent data diff --git a/source/blender/bmesh/operators/bmo_join_triangles.c b/source/blender/bmesh/operators/bmo_join_triangles.c index 3718f14276c..bc620e4a020 100644 --- a/source/blender/bmesh/operators/bmo_join_triangles.c +++ b/source/blender/bmesh/operators/bmo_join_triangles.c @@ -315,7 +315,7 @@ void bmo_join_triangles_exec(BMesh *bm, BMOperator *op) /* flag all edges of all input face */ BMO_ITER (f, &siter, op->slots_in, "faces", BM_FACE) { if (f->len == 3) { - BMO_elem_flag_enable(bm, f, FACE_INPUT); + BMO_face_flag_enable(bm, f, FACE_INPUT); } } @@ -323,11 +323,11 @@ void bmo_join_triangles_exec(BMesh *bm, BMOperator *op) BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { BMFace *f_a, *f_b; if (BM_edge_face_pair(e, &f_a, &f_b) && - (BMO_elem_flag_test(bm, f_a, FACE_INPUT) && - BMO_elem_flag_test(bm, f_b, FACE_INPUT))) + (BMO_face_flag_test(bm, f_a, FACE_INPUT) && + BMO_face_flag_test(bm, f_b, FACE_INPUT))) { if (!bm_edge_is_delimit(e, &delimit_data)) { - BMO_elem_flag_enable(bm, e, EDGE_MARK); + BMO_edge_flag_enable(bm, e, EDGE_MARK); totedge_tag++; } } @@ -345,7 +345,7 @@ void bmo_join_triangles_exec(BMesh *bm, BMOperator *op) const BMVert *verts[4]; float error; - if (!BMO_elem_flag_test(bm, e, EDGE_MARK)) + if (!BMO_edge_flag_test(bm, e, EDGE_MARK)) continue; bm_edge_to_quad_verts(e, verts); @@ -372,7 +372,7 @@ void bmo_join_triangles_exec(BMesh *bm, BMOperator *op) BMFace *f_new; f_new = BM_faces_join_pair(bm, f_a, f_b, e, true); if (f_new) { - BMO_elem_flag_enable(bm, f_new, FACE_OUT); + BMO_face_flag_enable(bm, f_new, FACE_OUT); } } } diff --git a/source/blender/bmesh/operators/bmo_normals.c b/source/blender/bmesh/operators/bmo_normals.c index 6044960265b..f0738303d5c 100644 --- a/source/blender/bmesh/operators/bmo_normals.c +++ b/source/blender/bmesh/operators/bmo_normals.c @@ -111,7 +111,7 @@ static int recalc_face_normals_find_index(BMesh *bm, BMFace **faces, const int f madd_v3_v3fl(cent, f_cent, cent_fac * f_area); cent_area_accum += f_area; - BLI_assert(BMO_elem_flag_test(bm, faces[i], FACE_TEMP) == 0); + BLI_assert(BMO_face_flag_test(bm, faces[i], FACE_TEMP) == 0); BLI_assert(BM_face_is_normal_valid(faces[i])); } @@ -209,7 +209,7 @@ static void bmo_recalc_face_normals_array(BMesh *bm, BMFace **faces, const int f f_start_index = recalc_face_normals_find_index(bm, faces, faces_len, &is_flip); if (is_flip) { - BMO_elem_flag_enable(bm, faces[f_start_index], FACE_FLIP); + BMO_face_flag_enable(bm, faces[f_start_index], FACE_FLIP); } /* now that we've found our starting face, make all connected faces @@ -219,10 +219,10 @@ static void bmo_recalc_face_normals_array(BMesh *bm, BMFace **faces, const int f BLI_LINKSTACK_INIT(fstack); BLI_LINKSTACK_PUSH(fstack, faces[f_start_index]); - BMO_elem_flag_enable(bm, faces[f_start_index], FACE_TEMP); + BMO_face_flag_enable(bm, faces[f_start_index], FACE_TEMP); while ((f = BLI_LINKSTACK_POP(fstack))) { - const bool flip_state = BMO_elem_flag_test_bool(bm, f, FACE_FLIP); + const bool flip_state = BMO_face_flag_test_bool(bm, f, FACE_FLIP); BMLoop *l_iter, *l_first; l_iter = l_first = BM_FACE_FIRST_LOOP(f); @@ -230,9 +230,9 @@ static void bmo_recalc_face_normals_array(BMesh *bm, BMFace **faces, const int f BMLoop *l_other = l_iter->radial_next; if ((l_other != l_iter) && bmo_recalc_normal_loop_filter_cb(l_iter, NULL)) { - if (!BMO_elem_flag_test(bm, l_other->f, FACE_TEMP)) { - BMO_elem_flag_enable(bm, l_other->f, FACE_TEMP); - BMO_elem_flag_set(bm, l_other->f, FACE_FLIP, (l_other->v == l_iter->v) != flip_state); + if (!BMO_face_flag_test(bm, l_other->f, FACE_TEMP)) { + BMO_face_flag_enable(bm, l_other->f, FACE_TEMP); + BMO_face_flag_set(bm, l_other->f, FACE_FLIP, (l_other->v == l_iter->v) != flip_state); BLI_LINKSTACK_PUSH(fstack, l_other->f); } } @@ -243,10 +243,10 @@ static void bmo_recalc_face_normals_array(BMesh *bm, BMFace **faces, const int f /* apply flipping to oflag'd faces */ for (i = 0; i < faces_len; i++) { - if (BMO_elem_flag_test(bm, faces[i], oflag_flip) == oflag_flip) { + if (BMO_face_flag_test(bm, faces[i], oflag_flip) == oflag_flip) { BM_face_normal_flip(bm, faces[i]); } - BMO_elem_flag_disable(bm, faces[i], FACE_TEMP); + BMO_face_flag_disable(bm, faces[i], FACE_TEMP); } } @@ -284,7 +284,7 @@ void bmo_recalc_face_normals_exec(BMesh *bm, BMOperator *op) faces_grp[j] = BM_face_at_index(bm, groups_array[fg_sta + j]); if (is_calc == false) { - is_calc = BMO_elem_flag_test_bool(bm, faces_grp[j], FACE_FLAG); + is_calc = BMO_face_flag_test_bool(bm, faces_grp[j], FACE_FLAG); } } diff --git a/source/blender/bmesh/operators/bmo_offset_edgeloops.c b/source/blender/bmesh/operators/bmo_offset_edgeloops.c index 8f4bc5ef3ad..7a6f779b34f 100644 --- a/source/blender/bmesh/operators/bmo_offset_edgeloops.c +++ b/source/blender/bmesh/operators/bmo_offset_edgeloops.c @@ -178,7 +178,7 @@ void bmo_offset_edgeloops_exec(BMesh *bm, BMOperator *op) #ifdef USE_CAP_OPTION if (v_edges_num_untag == 1) { - BMO_elem_flag_enable(bm, v, ELE_VERT_ENDPOINT); + BMO_vert_flag_enable(bm, v, ELE_VERT_ENDPOINT); } CLAMP_MIN(v_edges_max, v_edges_num); @@ -201,7 +201,7 @@ void bmo_offset_edgeloops_exec(BMesh *bm, BMOperator *op) (BM_elem_index_get(l->prev->v) == -1)) { #ifdef USE_CAP_OPTION - if (use_cap_endpoint || (BMO_elem_flag_test(bm, v, ELE_VERT_ENDPOINT) == 0)) + if (use_cap_endpoint || (BMO_vert_flag_test(bm, v, ELE_VERT_ENDPOINT) == 0)) #endif { BMLoop *l_new; @@ -209,7 +209,7 @@ void bmo_offset_edgeloops_exec(BMesh *bm, BMOperator *op) BLI_assert(f_cmp == l->f); BLI_assert(f_cmp != l_new->f); UNUSED_VARS_NDEBUG(f_cmp); - BMO_elem_flag_enable(bm, l_new->e, ELE_NEW); + BMO_edge_flag_enable(bm, l_new->e, ELE_NEW); } } else if (l->f->len > 4) { @@ -222,7 +222,7 @@ void bmo_offset_edgeloops_exec(BMesh *bm, BMOperator *op) BM_face_split(bm, l->f, l->prev->prev, l->next, &l_new, NULL, true); BLI_assert(f_cmp == l->f); BLI_assert(f_cmp != l_new->f); - BMO_elem_flag_enable(bm, l_new->e, ELE_NEW); + BMO_edge_flag_enable(bm, l_new->e, ELE_NEW); BM_elem_flag_disable(l->f, BM_ELEM_TAG); } else { @@ -230,7 +230,7 @@ void bmo_offset_edgeloops_exec(BMesh *bm, BMOperator *op) BMLoop *l_new; bm_face_split_walk_back(bm, l, &l_new); do { - BMO_elem_flag_enable(bm, l_new->e, ELE_NEW); + BMO_edge_flag_enable(bm, l_new->e, ELE_NEW); l_new = l_new->next; } while (BM_vert_is_edge_pair(l_new->v)); BM_elem_flag_disable(l->f, BM_ELEM_TAG); diff --git a/source/blender/bmesh/operators/bmo_planar_faces.c b/source/blender/bmesh/operators/bmo_planar_faces.c index 2856d3d18a6..a0951455fb4 100644 --- a/source/blender/bmesh/operators/bmo_planar_faces.c +++ b/source/blender/bmesh/operators/bmo_planar_faces.c @@ -71,13 +71,13 @@ void bmo_planar_faces_exec(BMesh *bm, BMOperator *op) l_iter = l_first = BM_FACE_FIRST_LOOP(f); do { - if (!BMO_elem_flag_test(bm, l_iter->v, ELE_VERT_ADJUST)) { - BMO_elem_flag_enable(bm, l_iter->v, ELE_VERT_ADJUST); + if (!BMO_vert_flag_test(bm, l_iter->v, ELE_VERT_ADJUST)) { + BMO_vert_flag_enable(bm, l_iter->v, ELE_VERT_ADJUST); shared_vert_num += 1; } } while ((l_iter = l_iter->next) != l_first); - BMO_elem_flag_enable(bm, f, ELE_FACE_ADJUST); + BMO_face_flag_enable(bm, f, ELE_FACE_ADJUST); } vert_accum_pool = BLI_mempool_create(sizeof(struct VertAccum), 0, 512, BLI_MEMPOOL_NOP); @@ -91,10 +91,10 @@ void bmo_planar_faces_exec(BMesh *bm, BMOperator *op) BMLoop *l_iter, *l_first; float plane[4]; - if (!BMO_elem_flag_test(bm, f, ELE_FACE_ADJUST)) { + if (!BMO_face_flag_test(bm, f, ELE_FACE_ADJUST)) { continue; } - BMO_elem_flag_disable(bm, f, ELE_FACE_ADJUST); + BMO_face_flag_disable(bm, f, ELE_FACE_ADJUST); BLI_assert(f->len != 3); @@ -130,7 +130,7 @@ void bmo_planar_faces_exec(BMesh *bm, BMOperator *op) BMIter iter; if (len_squared_v3v3(v->co, va->co) > eps_sq) { - BMO_elem_flag_enable(bm, v, ELE_VERT_ADJUST); + BMO_vert_flag_enable(bm, v, ELE_VERT_ADJUST); interp_v3_v3v3(v->co, v->co, va->co, fac); changed = true; } @@ -138,7 +138,7 @@ void bmo_planar_faces_exec(BMesh *bm, BMOperator *op) /* tag for re-calculation */ BM_ITER_ELEM (f, &iter, v, BM_FACES_OF_VERT) { if (f->len != 3) { - BMO_elem_flag_enable(bm, f, ELE_FACE_ADJUST); + BMO_face_flag_enable(bm, f, ELE_FACE_ADJUST); } } } diff --git a/source/blender/bmesh/operators/bmo_poke.c b/source/blender/bmesh/operators/bmo_poke.c index 4d86d6e8e5b..32ad25b7b82 100644 --- a/source/blender/bmesh/operators/bmo_poke.c +++ b/source/blender/bmesh/operators/bmo_poke.c @@ -87,7 +87,7 @@ void bmo_poke_exec(BMesh *bm, BMOperator *op) bm_face_calc_center_fn(f, f_center); v_center = BM_vert_create(bm, f_center, NULL, BM_CREATE_NOP); - BMO_elem_flag_enable(bm, v_center, ELE_NEW); + BMO_vert_flag_enable(bm, v_center, ELE_NEW); if (cd_loop_mdisp_offset != -1) { if (center_mode == BMOP_POKE_MEAN) { @@ -128,7 +128,7 @@ void bmo_poke_exec(BMesh *bm, BMOperator *op) BM_elem_attrs_copy(bm, bm, l_iter, l_new); BM_elem_attrs_copy(bm, bm, l_iter->next, l_new->next); - BMO_elem_flag_enable(bm, f_new, ELE_NEW); + BMO_face_flag_enable(bm, f_new, ELE_NEW); if (cd_loop_mdisp_offset != -1) { float f_new_center[3]; diff --git a/source/blender/bmesh/operators/bmo_primitive.c b/source/blender/bmesh/operators/bmo_primitive.c index b120b48447f..d2b9fa9efa3 100644 --- a/source/blender/bmesh/operators/bmo_primitive.c +++ b/source/blender/bmesh/operators/bmo_primitive.c @@ -259,7 +259,7 @@ void bmo_create_grid_exec(BMesh *bm, BMOperator *op) vec[0] = ((x * xtot_inv2) - 1.0f) * dia; mul_v3_m4v3(tvec, mat, vec); varr[i] = BM_vert_create(bm, tvec, NULL, BM_CREATE_NOP); - BMO_elem_flag_enable(bm, varr[i], VERT_MARK); + BMO_vert_flag_enable(bm, varr[i], VERT_MARK); i++; } } @@ -277,7 +277,7 @@ void bmo_create_grid_exec(BMesh *bm, BMOperator *op) f = BM_face_create_verts(bm, vquad, 4, NULL, BM_CREATE_NOP, true); if (calc_uvs) { - BMO_elem_flag_enable(bm, f, FACE_MARK); + BMO_face_flag_enable(bm, f, FACE_MARK); } } } @@ -315,7 +315,7 @@ void BM_mesh_calc_uvs_grid(BMesh *bm, const unsigned int x_segments, const unsig BLI_assert(cd_loop_uv_offset != -1); BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { - if (!BMO_elem_flag_test(bm, f, oflag)) + if (!BMO_face_flag_test(bm, f, oflag)) continue; BM_ITER_ELEM_INDEX (l, &liter, f, BM_LOOPS_OF_FACE, loop_index) { @@ -380,11 +380,11 @@ void bmo_create_uvsphere_exec(BMesh *bm, BMOperator *op) vec[1] = dia * sinf(phi); vec[2] = dia * cosf(phi); eve = BM_vert_create(bm, vec, NULL, BM_CREATE_NOP); - BMO_elem_flag_enable(bm, eve, VERT_MARK); + BMO_vert_flag_enable(bm, eve, VERT_MARK); if (a != 0) { e = BM_edge_create(bm, preveve, eve, NULL, BM_CREATE_NOP); - BMO_elem_flag_enable(bm, e, EDGE_ORIG); + BMO_edge_flag_enable(bm, e, EDGE_ORIG); } phi += phid; @@ -442,14 +442,14 @@ void bmo_create_uvsphere_exec(BMesh *bm, BMOperator *op) bool valid = true; BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { - if (!BMO_elem_flag_test(bm, l->v, VERT_MARK)) { + if (!BMO_vert_flag_test(bm, l->v, VERT_MARK)) { valid = false; break; } } if (valid) { - BMO_elem_flag_enable(bm, f, FACE_MARK); + BMO_face_flag_enable(bm, f, FACE_MARK); } } @@ -458,7 +458,7 @@ void bmo_create_uvsphere_exec(BMesh *bm, BMOperator *op) /* and now do imat */ BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) { - if (BMO_elem_flag_test(bm, eve, VERT_MARK)) { + if (BMO_vert_flag_test(bm, eve, VERT_MARK)) { mul_m4_v3(mat, eve->co); } } @@ -493,7 +493,7 @@ void bmo_create_icosphere_exec(BMesh *bm, BMOperator *op) vec[2] = dia_div * icovert[a][2]; eva[a] = BM_vert_create(bm, vec, NULL, BM_CREATE_NOP); - BMO_elem_flag_enable(bm, eva[a], VERT_MARK); + BMO_vert_flag_enable(bm, eva[a], VERT_MARK); } for (a = 0; a < 20; a++) { @@ -507,10 +507,10 @@ void bmo_create_icosphere_exec(BMesh *bm, BMOperator *op) eftemp = BM_face_create_quad_tri(bm, v1, v2, v3, NULL, NULL, BM_CREATE_NOP); BM_ITER_ELEM (l, &liter, eftemp, BM_LOOPS_OF_FACE) { - BMO_elem_flag_enable(bm, l->e, EDGE_MARK); + BMO_edge_flag_enable(bm, l->e, EDGE_MARK); } - BMO_elem_flag_enable(bm, eftemp, FACE_MARK); + BMO_face_flag_enable(bm, eftemp, FACE_MARK); } if (subdiv > 1) { @@ -540,14 +540,14 @@ void bmo_create_icosphere_exec(BMesh *bm, BMOperator *op) bool valid = true; BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { - if (!BMO_elem_flag_test(bm, l->v, VERT_MARK)) { + if (!BMO_vert_flag_test(bm, l->v, VERT_MARK)) { valid = false; break; } } if (valid) { - BMO_elem_flag_enable(bm, f, FACE_MARK); + BMO_face_flag_enable(bm, f, FACE_MARK); } } @@ -556,7 +556,7 @@ void bmo_create_icosphere_exec(BMesh *bm, BMOperator *op) /* must transform after because of sphere subdivision */ BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) { - if (BMO_elem_flag_test(bm, v, VERT_MARK)) { + if (BMO_vert_flag_test(bm, v, VERT_MARK)) { mul_m4_v3(mat, v->co); } } @@ -626,7 +626,7 @@ void BM_mesh_calc_uvs_sphere(BMesh *bm, const short oflag) BLI_assert(cd_loop_uv_offset != -1); /* caller is responsible for giving us UVs */ BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { - if (!BMO_elem_flag_test(bm, f, oflag)) + if (!BMO_face_flag_test(bm, f, oflag)) continue; bm_mesh_calc_uvs_sphere_face(f, mat_rot, cd_loop_uv_offset); @@ -650,7 +650,7 @@ void bmo_create_monkey_exec(BMesh *bm, BMOperator *op) v[1] = monkeyv[i][2] / -128.0; tv[i] = BM_vert_create(bm, v, NULL, BM_CREATE_NOP); - BMO_elem_flag_enable(bm, tv[i], VERT_MARK); + BMO_vert_flag_enable(bm, tv[i], VERT_MARK); if (fabsf(v[0] = -v[0]) < 0.001f) { tv[monkeynv + i] = tv[i]; @@ -661,7 +661,7 @@ void bmo_create_monkey_exec(BMesh *bm, BMOperator *op) tv[monkeynv + i] = eve; } - BMO_elem_flag_enable(bm, tv[monkeynv + i], VERT_MARK); + BMO_vert_flag_enable(bm, tv[monkeynv + i], VERT_MARK); mul_m4_v3(mat, tv[i]->co); } @@ -713,7 +713,7 @@ void bmo_create_circle_exec(BMesh *bm, BMOperator *op) mul_m4_v3(mat, vec); cent1 = BM_vert_create(bm, vec, NULL, BM_CREATE_NOP); - BMO_elem_flag_enable(bm, cent1, VERT_MARK); + BMO_vert_flag_enable(bm, cent1, VERT_MARK); } for (a = 0; a < segs; a++, phi += phid) { @@ -724,7 +724,7 @@ void bmo_create_circle_exec(BMesh *bm, BMOperator *op) mul_m4_v3(mat, vec); v1 = BM_vert_create(bm, vec, NULL, BM_CREATE_NOP); - BMO_elem_flag_enable(bm, v1, VERT_MARK); + BMO_vert_flag_enable(bm, v1, VERT_MARK); if (lastv1) BM_edge_create(bm, v1, lastv1, NULL, BM_CREATE_NOP); @@ -733,7 +733,7 @@ void bmo_create_circle_exec(BMesh *bm, BMOperator *op) BMFace *f; f = BM_face_create_quad_tri(bm, cent1, lastv1, v1, NULL, NULL, BM_CREATE_NOP); - BMO_elem_flag_enable(bm, f, FACE_NEW); + BMO_face_flag_enable(bm, f, FACE_NEW); } if (!firstv1) @@ -751,7 +751,7 @@ void bmo_create_circle_exec(BMesh *bm, BMOperator *op) BMFace *f; f = BM_face_create_quad_tri(bm, cent1, v1, firstv1, NULL, NULL, BM_CREATE_NOP); - BMO_elem_flag_enable(bm, f, FACE_NEW); + BMO_face_flag_enable(bm, f, FACE_NEW); if (calc_uvs) { BM_mesh_calc_uvs_circle(bm, mat, dia, FACE_NEW); @@ -791,7 +791,7 @@ void BM_mesh_calc_uvs_circle(BMesh *bm, float mat[4][4], const float radius, con invert_m4_m4(inv_mat, mat); BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) { - if (!BMO_elem_flag_test(bm, f, oflag)) + if (!BMO_face_flag_test(bm, f, oflag)) continue; BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { @@ -845,8 +845,8 @@ void bmo_create_cone_exec(BMesh *bm, BMOperator *op) cent2 = BM_vert_create(bm, vec, NULL, BM_CREATE_NOP); - BMO_elem_flag_enable(bm, cent1, VERT_MARK); - BMO_elem_flag_enable(bm, cent2, VERT_MARK); + BMO_vert_flag_enable(bm, cent1, VERT_MARK); + BMO_vert_flag_enable(bm, cent2, VERT_MARK); } for (a = 0; a < segs; a++, phi += phid) { @@ -862,27 +862,27 @@ void bmo_create_cone_exec(BMesh *bm, BMOperator *op) mul_m4_v3(mat, vec); v2 = BM_vert_create(bm, vec, NULL, BM_CREATE_NOP); - BMO_elem_flag_enable(bm, v1, VERT_MARK); - BMO_elem_flag_enable(bm, v2, VERT_MARK); + BMO_vert_flag_enable(bm, v1, VERT_MARK); + BMO_vert_flag_enable(bm, v2, VERT_MARK); if (a) { if (cap_ends) { f = BM_face_create_quad_tri(bm, cent1, lastv1, v1, NULL, NULL, BM_CREATE_NOP); if (calc_uvs) { - BMO_elem_flag_enable(bm, f, FACE_MARK); + BMO_face_flag_enable(bm, f, FACE_MARK); } - BMO_elem_flag_enable(bm, f, FACE_NEW); + BMO_face_flag_enable(bm, f, FACE_NEW); f = BM_face_create_quad_tri(bm, cent2, v2, lastv2, NULL, NULL, BM_CREATE_NOP); if (calc_uvs) { - BMO_elem_flag_enable(bm, f, FACE_MARK); + BMO_face_flag_enable(bm, f, FACE_MARK); } - BMO_elem_flag_enable(bm, f, FACE_NEW); + BMO_face_flag_enable(bm, f, FACE_NEW); } f = BM_face_create_quad_tri(bm, lastv1, lastv2, v2, v1, NULL, BM_CREATE_NOP); if (calc_uvs) { - BMO_elem_flag_enable(bm, f, FACE_MARK); + BMO_face_flag_enable(bm, f, FACE_MARK); } } else { @@ -900,20 +900,20 @@ void bmo_create_cone_exec(BMesh *bm, BMOperator *op) if (cap_ends) { f = BM_face_create_quad_tri(bm, cent1, v1, firstv1, NULL, NULL, BM_CREATE_NOP); if (calc_uvs) { - BMO_elem_flag_enable(bm, f, FACE_MARK); + BMO_face_flag_enable(bm, f, FACE_MARK); } - BMO_elem_flag_enable(bm, f, FACE_NEW); + BMO_face_flag_enable(bm, f, FACE_NEW); f = BM_face_create_quad_tri(bm, cent2, firstv2, v2, NULL, NULL, BM_CREATE_NOP); if (calc_uvs) { - BMO_elem_flag_enable(bm, f, FACE_MARK); + BMO_face_flag_enable(bm, f, FACE_MARK); } - BMO_elem_flag_enable(bm, f, FACE_NEW); + BMO_face_flag_enable(bm, f, FACE_NEW); } f = BM_face_create_quad_tri(bm, v1, v2, firstv2, firstv1, NULL, BM_CREATE_NOP); if (calc_uvs) { - BMO_elem_flag_enable(bm, f, FACE_MARK); + BMO_face_flag_enable(bm, f, FACE_MARK); } if (calc_uvs) { @@ -981,7 +981,7 @@ void BM_mesh_calc_uvs_cone( y = 1.0f - uv_height; BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) { - if (!BMO_elem_flag_test(bm, f, oflag)) + if (!BMO_face_flag_test(bm, f, oflag)) continue; if (f->len == 4 && radius_top && radius_bottom) { @@ -1063,7 +1063,7 @@ void bmo_create_cube_exec(BMesh *bm, BMOperator *op) float vec[3] = {(float)x * off, (float)y * off, (float)z * off}; mul_m4_v3(mat, vec); verts[i] = BM_vert_create(bm, vec, NULL, BM_CREATE_NOP); - BMO_elem_flag_enable(bm, verts[i], VERT_MARK); + BMO_vert_flag_enable(bm, verts[i], VERT_MARK); i++; } } @@ -1080,7 +1080,7 @@ void bmo_create_cube_exec(BMesh *bm, BMOperator *op) f = BM_face_create_verts(bm, quad, 4, NULL, BM_CREATE_NOP, true); if (calc_uvs) { - BMO_elem_flag_enable(bm, f, FACE_MARK); + BMO_face_flag_enable(bm, f, FACE_MARK); } } @@ -1117,7 +1117,7 @@ void BM_mesh_calc_uvs_cube(BMesh *bm, const short oflag) BLI_assert(cd_loop_uv_offset != -1); /* the caller can ensure that we have UVs */ BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) { - if (!BMO_elem_flag_test(bm, f, oflag)) { + if (!BMO_face_flag_test(bm, f, oflag)) { continue; } diff --git a/source/blender/bmesh/operators/bmo_removedoubles.c b/source/blender/bmesh/operators/bmo_removedoubles.c index a1f40b31fc7..6da591b23a0 100644 --- a/source/blender/bmesh/operators/bmo_removedoubles.c +++ b/source/blender/bmesh/operators/bmo_removedoubles.c @@ -98,7 +98,7 @@ static BMFace *remdoubles_createface(BMesh *bm, BMFace *f, BMOpSlot *slot_target { #define LOOP_MAP_VERT_INIT(l_init, v_map, is_del) \ v_map = l_init->v; \ - is_del = BMO_elem_flag_test_bool(bm, v_map, ELE_DEL); \ + is_del = BMO_vert_flag_test_bool(bm, v_map, ELE_DEL); \ if (is_del) { \ v_map = BMO_slot_map_elem_get(slot_targetmap, v_map); \ } ((void)0) @@ -131,12 +131,12 @@ static BMFace *remdoubles_createface(BMesh *bm, BMFace *f, BMOpSlot *slot_target } if (e_new) { - if (UNLIKELY(BMO_elem_flag_test(bm, v_curr, VERT_IN_FACE))) { + if (UNLIKELY(BMO_vert_flag_test(bm, v_curr, VERT_IN_FACE))) { /* we can't make the face, bail out */ STACK_CLEAR(edges); goto finally; } - BMO_elem_flag_enable(bm, v_curr, VERT_IN_FACE); + BMO_vert_flag_enable(bm, v_curr, VERT_IN_FACE); STACK_PUSH(edges, e_new); STACK_PUSH(loops, l_curr); @@ -155,7 +155,7 @@ finally: { unsigned int i; for (i = 0; i < STACK_SIZE(verts); i++) { - BMO_elem_flag_disable(bm, verts[i], VERT_IN_FACE); + BMO_vert_flag_disable(bm, verts[i], VERT_IN_FACE); } } @@ -198,7 +198,7 @@ void bmo_weld_verts_exec(BMesh *bm, BMOperator *op) /* mark merge verts for deletion */ BM_ITER_MESH (v1, &iter, bm, BM_VERTS_OF_MESH) { if ((v2 = BMO_slot_map_elem_get(slot_targetmap, v1))) { - BMO_elem_flag_enable(bm, v1, ELE_DEL); + BMO_vert_flag_enable(bm, v1, ELE_DEL); /* merge the vertex flags, else we get randomly selected/unselected verts */ BM_elem_flag_merge(v1, v2); @@ -212,8 +212,8 @@ void bmo_weld_verts_exec(BMesh *bm, BMOperator *op) } BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { - const bool is_del_v1 = BMO_elem_flag_test_bool(bm, (v1 = e->v1), ELE_DEL); - const bool is_del_v2 = BMO_elem_flag_test_bool(bm, (v2 = e->v2), ELE_DEL); + const bool is_del_v1 = BMO_vert_flag_test_bool(bm, (v1 = e->v1), ELE_DEL); + const bool is_del_v2 = BMO_vert_flag_test_bool(bm, (v2 = e->v2), ELE_DEL); if (is_del_v1 || is_del_v2) { if (is_del_v1) @@ -222,27 +222,18 @@ void bmo_weld_verts_exec(BMesh *bm, BMOperator *op) v2 = BMO_slot_map_elem_get(slot_targetmap, v2); if (v1 == v2) { - BMO_elem_flag_enable(bm, e, EDGE_COL); + BMO_edge_flag_enable(bm, e, EDGE_COL); } - else if (!BM_edge_exists(v1, v2)) { - BMEdge *e_new = BM_edge_create(bm, v1, v2, e, BM_CREATE_NOP); - - /* low level selection, not essential but means we can keep - * edge selection valid on auto-merge for example. */ - if ((BM_elem_flag_test(e, BM_ELEM_SELECT) == true) && - (BM_elem_flag_test(e_new, BM_ELEM_SELECT) == false)) - { - BM_elem_flag_disable(e, BM_ELEM_SELECT); - BM_elem_flag_merge_into(e_new, e_new, e); - BM_elem_flag_enable(e_new, BM_ELEM_SELECT); - /* bm->totedgesel remains valid */ - } - else { - BM_elem_flag_merge_into(e_new, e_new, e); + else { + /* always merge flags, even for edges we already created */ + BMEdge *e_new = BM_edge_exists(v1, v2); + if (e_new == NULL) { + e_new = BM_edge_create(bm, v1, v2, e, BM_CREATE_NOP); } + BM_elem_flag_merge(e_new, e); } - BMO_elem_flag_enable(bm, e, ELE_DEL); + BMO_edge_flag_enable(bm, e, ELE_DEL); } } @@ -253,16 +244,16 @@ void bmo_weld_verts_exec(BMesh *bm, BMOperator *op) int edge_collapse = 0; BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { - if (BMO_elem_flag_test(bm, l->v, ELE_DEL)) { + if (BMO_vert_flag_test(bm, l->v, ELE_DEL)) { vert_delete = true; } - if (BMO_elem_flag_test(bm, l->e, EDGE_COL)) { + if (BMO_edge_flag_test(bm, l->e, EDGE_COL)) { edge_collapse++; } } if (vert_delete) { - BMO_elem_flag_enable(bm, f, ELE_DEL); + BMO_face_flag_enable(bm, f, ELE_DEL); if (f->len - edge_collapse >= 3) { BMFace *f_new = remdoubles_createface(bm, f, slot_targetmap); @@ -270,8 +261,12 @@ void bmo_weld_verts_exec(BMesh *bm, BMOperator *op) /* do this so we don't need to return a list of created faces */ if (f_new) { bmesh_face_swap_data(f_new, f); - SWAP(BMFlagLayer *, f->oflags, f_new->oflags); - BMO_elem_flag_disable(bm, f, ELE_DEL); + + if (bm->use_toolflags) { + SWAP(BMFlagLayer *, ((BMFace_OFlag *)f)->oflags, ((BMFace_OFlag *)f_new)->oflags); + } + + BMO_face_flag_disable(bm, f, ELE_DEL); BM_face_kill(bm, f_new); } @@ -448,7 +443,7 @@ void bmo_collapse_exec(BMesh *bm, BMOperator *op) float min[3], max[3], center[3]; BMVert *v_tar; - if (!BMO_elem_flag_test(bm, e, EDGE_MARK)) + if (!BMO_edge_flag_test(bm, e, EDGE_MARK)) continue; BLI_assert(BLI_stack_is_empty(edge_stack)); @@ -519,7 +514,7 @@ static void bmo_collapsecon_do_layer(BMesh *bm, const int layer, const short ofl BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { - if (BMO_elem_flag_test(bm, l->e, oflag)) { + if (BMO_edge_flag_test(bm, l->e, oflag)) { /* walk */ BLI_assert(BLI_stack_is_empty(block_stack)); @@ -615,7 +610,7 @@ static void bmesh_find_doubles_common( for (i = 0; i < verts_len; i++) { BMVert *v_check = verts[i]; - if (BMO_elem_flag_test(bm, v_check, VERT_DOUBLE | VERT_TARGET)) { + if (BMO_vert_flag_test(bm, v_check, VERT_DOUBLE | VERT_TARGET)) { continue; } @@ -623,7 +618,7 @@ static void bmesh_find_doubles_common( BMVert *v_other = verts[j]; /* a match has already been found, (we could check which is best, for now don't) */ - if (BMO_elem_flag_test(bm, v_other, VERT_DOUBLE | VERT_TARGET)) { + if (BMO_vert_flag_test(bm, v_other, VERT_DOUBLE | VERT_TARGET)) { continue; } @@ -637,19 +632,19 @@ static void bmesh_find_doubles_common( } if (keepvert) { - if (BMO_elem_flag_test(bm, v_other, VERT_KEEP) == BMO_elem_flag_test(bm, v_check, VERT_KEEP)) + if (BMO_vert_flag_test(bm, v_other, VERT_KEEP) == BMO_vert_flag_test(bm, v_check, VERT_KEEP)) continue; } if (compare_len_squared_v3v3(v_check->co, v_other->co, dist_sq)) { /* If one vert is marked as keep, make sure it will be the target */ - if (BMO_elem_flag_test(bm, v_other, VERT_KEEP)) { + if (BMO_vert_flag_test(bm, v_other, VERT_KEEP)) { SWAP(BMVert *, v_check, v_other); } - BMO_elem_flag_enable(bm, v_other, VERT_DOUBLE); - BMO_elem_flag_enable(bm, v_check, VERT_TARGET); + BMO_vert_flag_enable(bm, v_other, VERT_DOUBLE); + BMO_vert_flag_enable(bm, v_check, VERT_TARGET); BMO_slot_map_elem_insert(optarget, optarget_slot, v_other, v_check); } @@ -692,8 +687,8 @@ void bmo_automerge_exec(BMesh *bm, BMOperator *op) * as VERT_KEEP. */ BMO_slot_buffer_flag_enable(bm, op->slots_in, "verts", BM_VERT, VERT_IN); BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) { - if (!BMO_elem_flag_test(bm, v, VERT_IN)) { - BMO_elem_flag_enable(bm, v, VERT_KEEP); + if (!BMO_vert_flag_test(bm, v, VERT_IN)) { + BMO_vert_flag_enable(bm, v, VERT_KEEP); } } diff --git a/source/blender/bmesh/operators/bmo_similar.c b/source/blender/bmesh/operators/bmo_similar.c index 708d57a7a08..454d6d8c6c8 100644 --- a/source/blender/bmesh/operators/bmo_similar.c +++ b/source/blender/bmesh/operators/bmo_similar.c @@ -121,8 +121,8 @@ void bmo_similar_faces_exec(BMesh *bm, BMOperator *op) * and n is the total number of faces */ BMO_ITER (fs, &fs_iter, op->slots_in, "faces", BM_FACE) { - if (!BMO_elem_flag_test(bm, fs, FACE_MARK)) { /* is this really needed ? */ - BMO_elem_flag_enable(bm, fs, FACE_MARK); + if (!BMO_face_flag_test(bm, fs, FACE_MARK)) { /* is this really needed ? */ + BMO_face_flag_enable(bm, fs, FACE_MARK); num_sels++; } } @@ -134,7 +134,7 @@ void bmo_similar_faces_exec(BMesh *bm, BMOperator *op) /* loop through all the faces and fill the faces/indices structure */ BM_ITER_MESH (fm, &fm_iter, bm, BM_FACES_OF_MESH) { f_ext[i].f = fm; - if (BMO_elem_flag_test(bm, fm, FACE_MARK)) { + if (BMO_face_flag_test(bm, fm, FACE_MARK)) { indices[idx] = i; idx++; } @@ -179,21 +179,21 @@ void bmo_similar_faces_exec(BMesh *bm, BMOperator *op) /* now select the rest (if any) */ for (i = 0; i < num_total; i++) { fm = f_ext[i].f; - if (!BMO_elem_flag_test(bm, fm, FACE_MARK) && !BM_elem_flag_test(fm, BM_ELEM_HIDDEN)) { + if (!BMO_face_flag_test(bm, fm, FACE_MARK) && !BM_elem_flag_test(fm, BM_ELEM_HIDDEN)) { bool cont = true; for (idx = 0; idx < num_sels && cont == true; idx++) { fs = f_ext[indices[idx]].f; switch (type) { case SIMFACE_MATERIAL: if (fm->mat_nr == fs->mat_nr) { - BMO_elem_flag_enable(bm, fm, FACE_MARK); + BMO_face_flag_enable(bm, fm, FACE_MARK); cont = false; } break; case SIMFACE_IMAGE: if (f_ext[i].t == f_ext[indices[idx]].t) { - BMO_elem_flag_enable(bm, fm, FACE_MARK); + BMO_face_flag_enable(bm, fm, FACE_MARK); cont = false; } break; @@ -201,7 +201,7 @@ void bmo_similar_faces_exec(BMesh *bm, BMOperator *op) case SIMFACE_NORMAL: angle = angle_normalized_v3v3(fs->no, fm->no); /* if the angle between the normals -> 0 */ if (angle <= thresh_radians) { - BMO_elem_flag_enable(bm, fm, FACE_MARK); + BMO_face_flag_enable(bm, fm, FACE_MARK); cont = false; } break; @@ -218,7 +218,7 @@ void bmo_similar_faces_exec(BMesh *bm, BMOperator *op) if (angle <= thresh_radians) { /* and dot product difference -> 0 */ delta_fl = f_ext[i].d - (f_ext[indices[idx]].d * sign); if (bm_sel_similar_cmp_fl(delta_fl, thresh, compare)) { - BMO_elem_flag_enable(bm, fm, FACE_MARK); + BMO_face_flag_enable(bm, fm, FACE_MARK); cont = false; } } @@ -227,7 +227,7 @@ void bmo_similar_faces_exec(BMesh *bm, BMOperator *op) case SIMFACE_AREA: delta_fl = f_ext[i].area - f_ext[indices[idx]].area; if (bm_sel_similar_cmp_fl(delta_fl, thresh, compare)) { - BMO_elem_flag_enable(bm, fm, FACE_MARK); + BMO_face_flag_enable(bm, fm, FACE_MARK); cont = false; } break; @@ -235,7 +235,7 @@ void bmo_similar_faces_exec(BMesh *bm, BMOperator *op) case SIMFACE_SIDES: delta_i = fm->len - fs->len; if (bm_sel_similar_cmp_i(delta_i, compare)) { - BMO_elem_flag_enable(bm, fm, FACE_MARK); + BMO_face_flag_enable(bm, fm, FACE_MARK); cont = false; } break; @@ -243,14 +243,14 @@ void bmo_similar_faces_exec(BMesh *bm, BMOperator *op) case SIMFACE_PERIMETER: delta_fl = f_ext[i].perim - f_ext[indices[idx]].perim; if (bm_sel_similar_cmp_fl(delta_fl, thresh, compare)) { - BMO_elem_flag_enable(bm, fm, FACE_MARK); + BMO_face_flag_enable(bm, fm, FACE_MARK); cont = false; } break; case SIMFACE_SMOOTH: if (BM_elem_flag_test(fm, BM_ELEM_SMOOTH) == BM_elem_flag_test(fs, BM_ELEM_SMOOTH)) { - BMO_elem_flag_enable(bm, fm, FACE_MARK); + BMO_face_flag_enable(bm, fm, FACE_MARK); cont = false; } break; @@ -263,7 +263,7 @@ void bmo_similar_faces_exec(BMesh *bm, BMOperator *op) ffa2 = CustomData_bmesh_get(&bm->pdata, fm->head.data, CD_FREESTYLE_FACE); if (ffa1 && ffa2 && (ffa1->flag & FREESTYLE_FACE_MARK) == (ffa2->flag & FREESTYLE_FACE_MARK)) { - BMO_elem_flag_enable(bm, fm, FACE_MARK); + BMO_face_flag_enable(bm, fm, FACE_MARK); cont = false; } } @@ -350,7 +350,7 @@ void bmo_similar_edges_exec(BMesh *bm, BMOperator *op) /* iterate through all selected edges and mark them */ BMO_ITER (es, &es_iter, op->slots_in, "edges", BM_EDGE) { - BMO_elem_flag_enable(bm, es, EDGE_MARK); + BMO_edge_flag_enable(bm, es, EDGE_MARK); num_sels++; } @@ -361,7 +361,7 @@ void bmo_similar_edges_exec(BMesh *bm, BMOperator *op) /* loop through all the edges and fill the edges/indices structure */ BM_ITER_MESH (e, &e_iter, bm, BM_EDGES_OF_MESH) { e_ext[i].e = e; - if (BMO_elem_flag_test(bm, e, EDGE_MARK)) { + if (BMO_edge_flag_test(bm, e, EDGE_MARK)) { indices[idx] = i; idx++; } @@ -397,7 +397,9 @@ void bmo_similar_edges_exec(BMesh *bm, BMOperator *op) /* select the edges if any */ for (i = 0; i < num_total; i++) { e = e_ext[i].e; - if (!BMO_elem_flag_test(bm, e, EDGE_MARK) && !BM_elem_flag_test(e, BM_ELEM_HIDDEN)) { + if (!BMO_edge_flag_test(bm, e, EDGE_MARK) && + !BM_elem_flag_test(e, BM_ELEM_HIDDEN)) + { bool cont = true; for (idx = 0; idx < num_sels && cont == true; idx++) { es = e_ext[indices[idx]].e; @@ -405,7 +407,7 @@ void bmo_similar_edges_exec(BMesh *bm, BMOperator *op) case SIMEDGE_LENGTH: delta_fl = e_ext[i].length - e_ext[indices[idx]].length; if (bm_sel_similar_cmp_fl(delta_fl, thresh, compare)) { - BMO_elem_flag_enable(bm, e, EDGE_MARK); + BMO_edge_flag_enable(bm, e, EDGE_MARK); cont = false; } break; @@ -418,7 +420,7 @@ void bmo_similar_edges_exec(BMesh *bm, BMOperator *op) angle = fabsf(angle - (float)M_PI); if (angle / (float)M_PI_2 <= thresh) { - BMO_elem_flag_enable(bm, e, EDGE_MARK); + BMO_edge_flag_enable(bm, e, EDGE_MARK); cont = false; } break; @@ -426,7 +428,7 @@ void bmo_similar_edges_exec(BMesh *bm, BMOperator *op) case SIMEDGE_FACE: delta_i = e_ext[i].faces - e_ext[indices[idx]].faces; if (bm_sel_similar_cmp_i(delta_i, compare)) { - BMO_elem_flag_enable(bm, e, EDGE_MARK); + BMO_edge_flag_enable(bm, e, EDGE_MARK); cont = false; } break; @@ -435,7 +437,7 @@ void bmo_similar_edges_exec(BMesh *bm, BMOperator *op) if (e_ext[i].faces == 2) { if (e_ext[indices[idx]].faces == 2) { if (fabsf(e_ext[i].angle - e_ext[indices[idx]].angle) <= thresh) { - BMO_elem_flag_enable(bm, e, EDGE_MARK); + BMO_edge_flag_enable(bm, e, EDGE_MARK); cont = false; } } @@ -454,7 +456,7 @@ void bmo_similar_edges_exec(BMesh *bm, BMOperator *op) delta_fl = *c1 - *c2; if (bm_sel_similar_cmp_fl(delta_fl, thresh, compare)) { - BMO_elem_flag_enable(bm, e, EDGE_MARK); + BMO_edge_flag_enable(bm, e, EDGE_MARK); cont = false; } } @@ -469,7 +471,7 @@ void bmo_similar_edges_exec(BMesh *bm, BMOperator *op) delta_fl = *c1 - *c2; if (bm_sel_similar_cmp_fl(delta_fl, thresh, compare)) { - BMO_elem_flag_enable(bm, e, EDGE_MARK); + BMO_edge_flag_enable(bm, e, EDGE_MARK); cont = false; } } @@ -477,14 +479,14 @@ void bmo_similar_edges_exec(BMesh *bm, BMOperator *op) case SIMEDGE_SEAM: if (BM_elem_flag_test(e, BM_ELEM_SEAM) == BM_elem_flag_test(es, BM_ELEM_SEAM)) { - BMO_elem_flag_enable(bm, e, EDGE_MARK); + BMO_edge_flag_enable(bm, e, EDGE_MARK); cont = false; } break; case SIMEDGE_SHARP: if (BM_elem_flag_test(e, BM_ELEM_SMOOTH) == BM_elem_flag_test(es, BM_ELEM_SMOOTH)) { - BMO_elem_flag_enable(bm, e, EDGE_MARK); + BMO_edge_flag_enable(bm, e, EDGE_MARK); cont = false; } break; @@ -497,7 +499,7 @@ void bmo_similar_edges_exec(BMesh *bm, BMOperator *op) fed2 = CustomData_bmesh_get(&bm->edata, es->head.data, CD_FREESTYLE_EDGE); if (fed1 && fed2 && (fed1->flag & FREESTYLE_EDGE_MARK) == (fed2->flag & FREESTYLE_EDGE_MARK)) { - BMO_elem_flag_enable(bm, e, EDGE_MARK); + BMO_edge_flag_enable(bm, e, EDGE_MARK); cont = false; } } @@ -562,7 +564,7 @@ void bmo_similar_verts_exec(BMesh *bm, BMOperator *op) /* iterate through all selected edges and mark them */ BMO_ITER (vs, &vs_iter, op->slots_in, "verts", BM_VERT) { - BMO_elem_flag_enable(bm, vs, VERT_MARK); + BMO_vert_flag_enable(bm, vs, VERT_MARK); num_sels++; } @@ -573,7 +575,7 @@ void bmo_similar_verts_exec(BMesh *bm, BMOperator *op) /* loop through all the vertices and fill the vertices/indices structure */ BM_ITER_MESH (v, &v_iter, bm, BM_VERTS_OF_MESH) { v_ext[i].v = v; - if (BMO_elem_flag_test(bm, v, VERT_MARK)) { + if (BMO_vert_flag_test(bm, v, VERT_MARK)) { indices[idx] = i; idx++; } @@ -599,7 +601,9 @@ void bmo_similar_verts_exec(BMesh *bm, BMOperator *op) /* select the vertices if any */ for (i = 0; i < num_total; i++) { v = v_ext[i].v; - if (!BMO_elem_flag_test(bm, v, VERT_MARK) && !BM_elem_flag_test(v, BM_ELEM_HIDDEN)) { + if (!BMO_vert_flag_test(bm, v, VERT_MARK) && + !BM_elem_flag_test(v, BM_ELEM_HIDDEN)) + { bool cont = true; for (idx = 0; idx < num_sels && cont == true; idx++) { vs = v_ext[indices[idx]].v; @@ -607,7 +611,7 @@ void bmo_similar_verts_exec(BMesh *bm, BMOperator *op) case SIMVERT_NORMAL: /* compare the angle between the normals */ if (angle_normalized_v3v3(v->no, vs->no) <= thresh_radians) { - BMO_elem_flag_enable(bm, v, VERT_MARK); + BMO_vert_flag_enable(bm, v, VERT_MARK); cont = false; } break; @@ -615,7 +619,7 @@ void bmo_similar_verts_exec(BMesh *bm, BMOperator *op) /* number of adjacent faces */ delta_i = v_ext[i].num_faces - v_ext[indices[idx]].num_faces; if (bm_sel_similar_cmp_i(delta_i, compare)) { - BMO_elem_flag_enable(bm, v, VERT_MARK); + BMO_vert_flag_enable(bm, v, VERT_MARK); cont = false; } break; @@ -623,7 +627,7 @@ void bmo_similar_verts_exec(BMesh *bm, BMOperator *op) case SIMVERT_VGROUP: if (v_ext[i].dvert != NULL && v_ext[indices[idx]].dvert != NULL) { if (defvert_find_shared(v_ext[i].dvert, v_ext[indices[idx]].dvert) != -1) { - BMO_elem_flag_enable(bm, v, VERT_MARK); + BMO_vert_flag_enable(bm, v, VERT_MARK); cont = false; } } @@ -632,7 +636,7 @@ void bmo_similar_verts_exec(BMesh *bm, BMOperator *op) /* number of adjacent edges */ delta_i = v_ext[i].num_edges - v_ext[indices[idx]].num_edges; if (bm_sel_similar_cmp_i(delta_i, compare)) { - BMO_elem_flag_enable(bm, v, VERT_MARK); + BMO_vert_flag_enable(bm, v, VERT_MARK); cont = false; } break; diff --git a/source/blender/bmesh/operators/bmo_subdivide.c b/source/blender/bmesh/operators/bmo_subdivide.c index 38fa2cfdcc8..8d672b32caa 100644 --- a/source/blender/bmesh/operators/bmo_subdivide.c +++ b/source/blender/bmesh/operators/bmo_subdivide.c @@ -384,7 +384,7 @@ static BMVert *bm_subdivide_edge_addvert( v_new = BM_edge_split(bm, edge, edge->v1, r_edge, factor_edge_split); - BMO_elem_flag_enable(bm, v_new, ELE_INNER); + BMO_vert_flag_enable(bm, v_new, ELE_INNER); /* offset for smooth or sphere or fractal */ alter_co(v_new, e_orig, params, factor_subd, v_a, v_b); @@ -419,7 +419,7 @@ static BMVert *subdivide_edge_num( BMVert *v_new; float factor_edge_split, factor_subd; - if (BMO_elem_flag_test(bm, edge, EDGE_PERCENT) && totpoint == 1) { + if (BMO_edge_flag_test(bm, edge, EDGE_PERCENT) && totpoint == 1) { factor_edge_split = BMO_slot_map_float_get(params->slot_edge_percents, edge); factor_subd = 0.0f; } @@ -449,9 +449,9 @@ static void bm_subdivide_multicut( for (i = 0; i < numcuts; i++) { v = subdivide_edge_num(bm, eed, &e_tmp, i, params->numcuts, params, v_a, v_b, &e_new); - BMO_elem_flag_enable(bm, v, SUBD_SPLIT | ELE_SPLIT); - BMO_elem_flag_enable(bm, eed, SUBD_SPLIT | ELE_SPLIT); - BMO_elem_flag_enable(bm, e_new, SUBD_SPLIT | ELE_SPLIT); + BMO_vert_flag_enable(bm, v, SUBD_SPLIT | ELE_SPLIT); + BMO_edge_flag_enable(bm, eed, SUBD_SPLIT | ELE_SPLIT); + BMO_edge_flag_enable(bm, e_new, SUBD_SPLIT | ELE_SPLIT); BM_CHECK_ELEMENT(v); if (v->e) BM_CHECK_ELEMENT(v->e); @@ -698,8 +698,8 @@ static void quad_4edge_subdivide(BMesh *bm, BMFace *UNUSED(face), BMVert **verts if (!e) continue; - BMO_elem_flag_enable(bm, e, ELE_INNER); - BMO_elem_flag_enable(bm, f_new, ELE_INNER); + BMO_edge_flag_enable(bm, e, ELE_INNER); + BMO_face_flag_enable(bm, f_new, ELE_INNER); v1 = lines[(i + 1) * s] = verts[a]; @@ -711,7 +711,7 @@ static void quad_4edge_subdivide(BMesh *bm, BMFace *UNUSED(face), BMVert **verts BMESH_ASSERT(v != NULL); - BMO_elem_flag_enable(bm, e_new, ELE_INNER); + BMO_edge_flag_enable(bm, e_new, ELE_INNER); lines[(i + 1) * s + a + 1] = v; } } @@ -724,8 +724,8 @@ static void quad_4edge_subdivide(BMesh *bm, BMFace *UNUSED(face), BMVert **verts if (!e) continue; - BMO_elem_flag_enable(bm, e, ELE_INNER); - BMO_elem_flag_enable(bm, f_new, ELE_INNER); + BMO_edge_flag_enable(bm, e, ELE_INNER); + BMO_face_flag_enable(bm, f_new, ELE_INNER); } } @@ -802,8 +802,8 @@ static void tri_3edge_subdivide(BMesh *bm, BMFace *UNUSED(face), BMVert **verts, e = connect_smallest_face(bm, verts[a], verts[b], &f_new); if (!e) goto cleanup; - BMO_elem_flag_enable(bm, e, ELE_INNER); - BMO_elem_flag_enable(bm, f_new, ELE_INNER); + BMO_edge_flag_enable(bm, e, ELE_INNER); + BMO_face_flag_enable(bm, f_new, ELE_INNER); lines[i + 1][0] = verts[a]; lines[i + 1][i + 1] = verts[b]; @@ -817,7 +817,7 @@ static void tri_3edge_subdivide(BMesh *bm, BMFace *UNUSED(face), BMVert **verts, v = subdivide_edge_num(bm, e, &e_tmp, j, i, params, verts[a], verts[b], &e_new); lines[i + 1][j + 1] = v; - BMO_elem_flag_enable(bm, e_new, ELE_INNER); + BMO_edge_flag_enable(bm, e_new, ELE_INNER); } } @@ -837,13 +837,13 @@ static void tri_3edge_subdivide(BMesh *bm, BMFace *UNUSED(face), BMVert **verts, for (j = 0; j < i; j++) { e = connect_smallest_face(bm, lines[i][j], lines[i + 1][j + 1], &f_new); - BMO_elem_flag_enable(bm, e, ELE_INNER); - BMO_elem_flag_enable(bm, f_new, ELE_INNER); + BMO_edge_flag_enable(bm, e, ELE_INNER); + BMO_face_flag_enable(bm, f_new, ELE_INNER); e = connect_smallest_face(bm, lines[i][j + 1], lines[i + 1][j + 1], &f_new); - BMO_elem_flag_enable(bm, e, ELE_INNER); - BMO_elem_flag_enable(bm, f_new, ELE_INNER); + BMO_edge_flag_enable(bm, e, ELE_INNER); + BMO_face_flag_enable(bm, f_new, ELE_INNER); } } @@ -1023,7 +1023,7 @@ void bmo_subdivide_edges_exec(BMesh *bm, BMOperator *op) edges[i] = l_new->e; verts[i] = l_new->v; - if (BMO_elem_flag_test(bm, edges[i], SUBD_SPLIT)) { + if (BMO_edge_flag_test(bm, edges[i], SUBD_SPLIT)) { if (!e1) e1 = edges[i]; else e2 = edges[i]; @@ -1043,13 +1043,13 @@ void bmo_subdivide_edges_exec(BMesh *bm, BMOperator *op) } } - if (BMO_elem_flag_test(bm, face, FACE_CUSTOMFILL)) { + if (BMO_face_flag_test(bm, face, FACE_CUSTOMFILL)) { pat = *BMO_slot_map_data_get(params.slot_custom_patterns, face); for (i = 0; i < pat->len; i++) { matched = 1; for (j = 0; j < pat->len; j++) { a = (j + i) % pat->len; - if ((!!BMO_elem_flag_test(bm, edges[a], SUBD_SPLIT)) != (!!pat->seledges[j])) { + if ((!!BMO_edge_flag_test(bm, edges[a], SUBD_SPLIT)) != (!!pat->seledges[j])) { matched = 0; break; } @@ -1062,7 +1062,7 @@ void bmo_subdivide_edges_exec(BMesh *bm, BMOperator *op) fd->start = verts[i]; fd->face = face; fd->totedgesel = totesel; - BMO_elem_flag_enable(bm, face, SUBD_SPLIT); + BMO_face_flag_enable(bm, face, SUBD_SPLIT); break; } } @@ -1082,7 +1082,7 @@ void bmo_subdivide_edges_exec(BMesh *bm, BMOperator *op) matched = 1; for (b = 0; b < pat->len; b++) { j = (b + a) % pat->len; - if ((!!BMO_elem_flag_test(bm, edges[j], SUBD_SPLIT)) != (!!pat->seledges[b])) { + if ((!!BMO_edge_flag_test(bm, edges[j], SUBD_SPLIT)) != (!!pat->seledges[b])) { matched = 0; break; } @@ -1094,7 +1094,7 @@ void bmo_subdivide_edges_exec(BMesh *bm, BMOperator *op) if (matched) { SubDFaceData *fd; - BMO_elem_flag_enable(bm, face, SUBD_SPLIT); + BMO_face_flag_enable(bm, face, SUBD_SPLIT); fd = BLI_stack_push_r(facedata); fd->pat = pat; @@ -1110,7 +1110,7 @@ void bmo_subdivide_edges_exec(BMesh *bm, BMOperator *op) if (!matched && totesel) { SubDFaceData *fd; - BMO_elem_flag_enable(bm, face, SUBD_SPLIT); + BMO_face_flag_enable(bm, face, SUBD_SPLIT); /* must initialize all members here */ fd = BLI_stack_push_r(facedata); @@ -1162,22 +1162,22 @@ void bmo_subdivide_edges_exec(BMesh *bm, BMOperator *op) /* find the boundary of one of the split edges */ for (a = 1; a < vlen; a++) { - if (!BMO_elem_flag_test(bm, loops[a - 1]->v, ELE_INNER) && - BMO_elem_flag_test(bm, loops[a]->v, ELE_INNER)) + if (!BMO_vert_flag_test(bm, loops[a - 1]->v, ELE_INNER) && + BMO_vert_flag_test(bm, loops[a]->v, ELE_INNER)) { break; } } - if (BMO_elem_flag_test(bm, loops[(a + numcuts + 1) % vlen]->v, ELE_INNER)) { + if (BMO_vert_flag_test(bm, loops[(a + numcuts + 1) % vlen]->v, ELE_INNER)) { b = (a + numcuts + 1) % vlen; } else { /* find the boundary of the other edge. */ for (j = 0; j < vlen; j++) { b = (j + a + numcuts + 1) % vlen; - if (!BMO_elem_flag_test(bm, loops[b == 0 ? vlen - 1 : b - 1]->v, ELE_INNER) && - BMO_elem_flag_test(bm, loops[b]->v, ELE_INNER)) + if (!BMO_vert_flag_test(bm, loops[b == 0 ? vlen - 1 : b - 1]->v, ELE_INNER) && + BMO_vert_flag_test(bm, loops[b]->v, ELE_INNER)) { break; } @@ -1245,7 +1245,7 @@ void bmo_subdivide_edges_exec(BMesh *bm, BMOperator *op) BLI_assert(BM_edge_exists(loops_split[j][0]->v, loops_split[j][1]->v) == NULL); f_new = BM_face_split(bm, face, loops_split[j][0], loops_split[j][1], &l_new, NULL, false); if (f_new) { - BMO_elem_flag_enable(bm, l_new->e, ELE_INNER); + BMO_edge_flag_enable(bm, l_new->e, ELE_INNER); } } } diff --git a/source/blender/bmesh/operators/bmo_subdivide_edgering.c b/source/blender/bmesh/operators/bmo_subdivide_edgering.c index b5a95ad6283..b4a77bf1a38 100644 --- a/source/blender/bmesh/operators/bmo_subdivide_edgering.c +++ b/source/blender/bmesh/operators/bmo_subdivide_edgering.c @@ -128,7 +128,7 @@ static void bmo_edgeloop_vert_tag(BMesh *bm, struct BMEdgeLoopStore *el_store, c { LinkData *node = BM_edgeloop_verts_get(el_store)->first; do { - BMO_elem_flag_set(bm, (BMVert *)node->data, oflag, tag); + BMO_vert_flag_set(bm, (BMVert *)node->data, oflag, tag); } while ((node = node->next)); } @@ -137,7 +137,7 @@ static bool bmo_face_is_vert_tag_all(BMesh *bm, BMFace *f, short oflag) BMLoop *l_iter, *l_first; l_iter = l_first = BM_FACE_FIRST_LOOP(f); do { - if (!BMO_elem_flag_test(bm, l_iter->v, oflag)) { + if (!BMO_vert_flag_test(bm, l_iter->v, oflag)) { return false; } } while ((l_iter = l_iter->next) != l_first); @@ -150,7 +150,7 @@ static bool bm_vert_is_tag_edge_connect(BMesh *bm, BMVert *v) BMEdge *e; BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) { - if (BMO_elem_flag_test(bm, e, EDGE_RING)) { + if (BMO_edge_flag_test(bm, e, EDGE_RING)) { BMVert *v_other = BM_edge_other_vert(e, v); if (BM_elem_flag_test(v_other, BM_ELEM_TAG)) { return true; @@ -243,7 +243,7 @@ static GSet *bm_edgering_pair_calc(BMesh *bm, ListBase *eloops_rim) BMVert *v = ((LinkData *)BM_edgeloop_verts_get(el_store)->first)->data; BM_ITER_ELEM (e, &eiter, (BMVert *)v, BM_EDGES_OF_VERT) { - if (BMO_elem_flag_test(bm, e, EDGE_RING)) { + if (BMO_edge_flag_test(bm, e, EDGE_RING)) { struct BMEdgeLoopStore *el_store_other; BMVert *v_other = BM_edge_other_vert(e, v); GHashPair pair_test; @@ -339,7 +339,7 @@ static void bm_vert_calc_surface_tangent(BMesh *bm, BMVert *v, float r_no[3]) if (UNLIKELY(BM_edge_is_wire(e))) { /* pass - this may confuse things */ } - else if (BMO_elem_flag_test(bm, e, EDGE_RIM)) { + else if (BMO_edge_flag_test(bm, e, EDGE_RIM)) { BMIter liter; BMLoop *l; BM_ITER_ELEM (l, &liter, e, BM_LOOPS_OF_EDGE) { @@ -347,7 +347,7 @@ static void bm_vert_calc_surface_tangent(BMesh *bm, BMVert *v, float r_no[3]) float no[3]; // BM_face_normal_update(l->f); BM_edge_calc_face_tangent(e, l, no); - if (BMO_elem_flag_test(bm, l->f, FACE_SHARED)) { + if (BMO_face_flag_test(bm, l->f, FACE_SHARED)) { add_v3_v3(no_inner, no); found_inner = true; } @@ -356,7 +356,7 @@ static void bm_vert_calc_surface_tangent(BMesh *bm, BMVert *v, float r_no[3]) found_outer = true; /* other side is used too, blend midway */ - if (BMO_elem_flag_test(bm, l->f, FACE_OUT)) { + if (BMO_face_flag_test(bm, l->f, FACE_OUT)) { found_outer_tag = true; } } @@ -400,9 +400,9 @@ static void bm_faces_share_tag_flush(BMesh *bm, BMEdge **e_arr, const unsigned i l_iter = l_first = e->l; do { - if (!BMO_elem_flag_test(bm, l_iter->f, FACE_SHARED)) { + if (!BMO_face_flag_test(bm, l_iter->f, FACE_SHARED)) { if (bmo_face_is_vert_tag_all(bm, l_iter->f, VERT_SHARED)) { - BMO_elem_flag_enable(bm, l_iter->f, FACE_SHARED); + BMO_face_flag_enable(bm, l_iter->f, FACE_SHARED); } } } while ((l_iter = l_iter->radial_next) != l_first); @@ -422,7 +422,7 @@ static void bm_faces_share_tag_clear(BMesh *bm, BMEdge **e_arr_iter, const unsig l_iter = l_first = e->l; do { - BMO_elem_flag_disable(bm, l_iter->f, FACE_SHARED); + BMO_face_flag_disable(bm, l_iter->f, FACE_SHARED); } while ((l_iter = l_iter->radial_next) != l_first); } } @@ -834,8 +834,8 @@ static void bm_face_slice(BMesh *bm, BMLoop *l, const int cuts) if (l_new->f->len < l_new->radial_next->f->len) { l_new = l_new->radial_next; } - BMO_elem_flag_enable(bm, l_new->f, FACE_OUT); - BMO_elem_flag_enable(bm, l_new->radial_next->f, FACE_OUT); + BMO_face_flag_enable(bm, l_new->f, FACE_OUT); + BMO_face_flag_enable(bm, l_new->radial_next->f, FACE_OUT); } } @@ -903,7 +903,7 @@ static void bm_edgering_pair_order( node = lb_a->first; BM_ITER_ELEM (e, &eiter, (BMVert *)node->data, BM_EDGES_OF_VERT) { - if (BMO_elem_flag_test(bm, e, EDGE_RING)) { + if (BMO_edge_flag_test(bm, e, EDGE_RING)) { v_other = BM_edge_other_vert(e, (BMVert *)node->data); if (BM_elem_flag_test(v_other, BM_ELEM_TAG)) { break; @@ -938,7 +938,7 @@ static void bm_edgering_pair_order( /* if we dont share and edge - flip */ BMEdge *e = BM_edge_exists(((LinkData *)lb_a->first)->data, ((LinkData *)lb_b->first)->data); - if (e == NULL || !BMO_elem_flag_test(bm, e, EDGE_RING)) { + if (e == NULL || !BMO_edge_flag_test(bm, e, EDGE_RING)) { BM_edgeloop_flip(bm, el_store_b); } } @@ -983,19 +983,19 @@ static void bm_edgering_pair_subdiv( BMIter eiter; BM_ITER_ELEM (e, &eiter, (BMVert *)node->data, BM_EDGES_OF_VERT) { - if (!BMO_elem_flag_test(bm, e, EDGE_IN_STACK)) { + if (!BMO_edge_flag_test(bm, e, EDGE_IN_STACK)) { BMVert *v_other = BM_edge_other_vert(e, (BMVert *)node->data); if (BM_elem_flag_test(v_other, BM_ELEM_TAG)) { BMIter fiter; - BMO_elem_flag_enable(bm, e, EDGE_IN_STACK); + BMO_edge_flag_enable(bm, e, EDGE_IN_STACK); STACK_PUSH(edges_ring_arr, e); /* add faces to the stack */ BM_ITER_ELEM (f, &fiter, e, BM_FACES_OF_EDGE) { - if (BMO_elem_flag_test(bm, f, FACE_OUT)) { - if (!BMO_elem_flag_test(bm, f, FACE_IN_STACK)) { - BMO_elem_flag_enable(bm, f, FACE_IN_STACK); + if (BMO_face_flag_test(bm, f, FACE_OUT)) { + if (!BMO_face_flag_test(bm, f, FACE_IN_STACK)) { + BMO_face_flag_enable(bm, f, FACE_IN_STACK); STACK_PUSH(faces_ring_arr, f); } } @@ -1009,10 +1009,10 @@ static void bm_edgering_pair_subdiv( /* found opposite edge */ BMVert *v_other; - BMO_elem_flag_disable(bm, e, EDGE_IN_STACK); + BMO_edge_flag_disable(bm, e, EDGE_IN_STACK); /* unrelated to subdiv, but if we _don't_ clear flag, multiple rings fail */ - BMO_elem_flag_disable(bm, e, EDGE_RING); + BMO_edge_flag_disable(bm, e, EDGE_RING); v_other = BM_elem_flag_test(e->v1, BM_ELEM_TAG) ? e->v1 : e->v2; bm_edge_subdiv_as_loop(bm, eloops_ring, e, v_other, cuts); @@ -1021,12 +1021,12 @@ static void bm_edgering_pair_subdiv( while ((f = STACK_POP(faces_ring_arr))) { BMLoop *l_iter, *l_first; - BMO_elem_flag_disable(bm, f, FACE_IN_STACK); + BMO_face_flag_disable(bm, f, FACE_IN_STACK); /* Check each edge of the face */ l_iter = l_first = BM_FACE_FIRST_LOOP(f); do { - if (BMO_elem_flag_test(bm, l_iter->e, EDGE_RIM)) { + if (BMO_edge_flag_test(bm, l_iter->e, EDGE_RIM)) { bm_face_slice(bm, l_iter, cuts); break; } @@ -1064,7 +1064,7 @@ static void bm_edgering_pair_ringsubd( static bool bm_edge_rim_test_cb(BMEdge *e, void *bm_v) { BMesh *bm = bm_v; - return BMO_elem_flag_test_bool(bm, e, EDGE_RIM); + return BMO_edge_flag_test_bool(bm, e, EDGE_RIM); } @@ -1099,25 +1099,25 @@ void bmo_subdivide_edgering_exec(BMesh *bm, BMOperator *op) BMFace *f; BM_ITER_ELEM (f, &fiter, e, BM_FACES_OF_EDGE) { - if (!BMO_elem_flag_test(bm, f, FACE_OUT)) { + if (!BMO_face_flag_test(bm, f, FACE_OUT)) { BMIter liter; BMLoop *l; bool ok = false; /* check at least 2 edges in the face are rings */ BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { - if (BMO_elem_flag_test(bm, l->e, EDGE_RING) && e != l->e) { + if (BMO_edge_flag_test(bm, l->e, EDGE_RING) && e != l->e) { ok = true; break; } } if (ok) { - BMO_elem_flag_enable(bm, f, FACE_OUT); + BMO_face_flag_enable(bm, f, FACE_OUT); BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { - if (!BMO_elem_flag_test(bm, l->e, EDGE_RING)) { - BMO_elem_flag_enable(bm, l->e, EDGE_RIM); + if (!BMO_edge_flag_test(bm, l->e, EDGE_RING)) { + BMO_edge_flag_enable(bm, l->e, EDGE_RIM); } } } diff --git a/source/blender/bmesh/operators/bmo_triangulate.c b/source/blender/bmesh/operators/bmo_triangulate.c index 6fb09c76ea4..8938d086c1a 100644 --- a/source/blender/bmesh/operators/bmo_triangulate.c +++ b/source/blender/bmesh/operators/bmo_triangulate.c @@ -91,7 +91,7 @@ void bmo_triangle_fill_exec(BMesh *bm, BMOperator *op) BMVert **e_verts = &e->v1; unsigned int i; - BMO_elem_flag_enable(bm, e, EDGE_MARK); + BMO_edge_flag_enable(bm, e, EDGE_MARK); calc_winding = (calc_winding || BM_edge_is_boundary(e)); @@ -132,7 +132,7 @@ void bmo_triangle_fill_exec(BMesh *bm, BMOperator *op) add_v3_v3(normal, v->no); BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) { - if (BMO_elem_flag_test(bm, e, EDGE_MARK)) { + if (BMO_edge_flag_test(bm, e, EDGE_MARK)) { if (e_index == 2) { e_index = 0; break; @@ -203,7 +203,7 @@ void bmo_triangle_fill_exec(BMesh *bm, BMOperator *op) for (i = 0, i_prev = 2; i < 3; i_prev = i++) { e = BM_edge_exists(v_tri[i], v_tri[i_prev]); - if (e && BM_edge_is_boundary(e) && BMO_elem_flag_test(bm, e, EDGE_MARK)) { + if (e && BM_edge_is_boundary(e) && BMO_edge_flag_test(bm, e, EDGE_MARK)) { winding_votes += (e->l->v == v_tri[i]) ? 1 : -1; } } @@ -226,10 +226,10 @@ void bmo_triangle_fill_exec(BMesh *bm, BMOperator *op) sf_tri->v1->tmp.p, sf_tri->v2->tmp.p, sf_tri->v3->tmp.p, NULL, NULL, BM_CREATE_NO_DOUBLE); - BMO_elem_flag_enable(bm, f, ELE_NEW); + BMO_face_flag_enable(bm, f, ELE_NEW); BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { - if (!BMO_elem_flag_test(bm, l->e, EDGE_MARK)) { - BMO_elem_flag_enable(bm, l->e, ELE_NEW); + if (!BMO_edge_flag_test(bm, l->e, EDGE_MARK)) { + BMO_edge_flag_enable(bm, l->e, ELE_NEW); } } } @@ -244,29 +244,33 @@ void bmo_triangle_fill_exec(BMesh *bm, BMOperator *op) BMO_slot_buffer_flag_enable(bm, bmop.slots_out, "geom.out", BM_FACE | BM_EDGE, ELE_NEW); BMO_op_finish(bm, &bmop); } - - BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "geom.out", BM_EDGE | BM_FACE, ELE_NEW); if (use_dissolve) { - BMO_ITER (e, &siter, op->slots_out, "geom.out", BM_EDGE) { - if (LIKELY(e->l)) { /* in rare cases the edges face will have already been removed from the edge */ - BMFace *f_new; - f_new = BM_faces_join_pair(bm, e->l->f, - e->l->radial_next->f, e, - false); /* join faces */ - if (f_new) { - BMO_elem_flag_enable(bm, f_new, ELE_NEW); - BM_edge_kill(bm, e); + BMEdge *e_next; + BMIter iter; + + BM_ITER_MESH_MUTABLE (e, e_next, &iter, bm, BM_EDGES_OF_MESH) { + if (BMO_edge_flag_test(bm, e, ELE_NEW)) { + /* in rare cases the edges face will have already been removed from the edge */ + if (LIKELY(e->l)) { + BMFace *f_new = BM_faces_join_pair( + bm, e->l->f, + e->l->radial_next->f, e, + false); /* join faces */ + if (f_new) { + BMO_face_flag_enable(bm, f_new, ELE_NEW); + BM_edge_kill(bm, e); + } + else { + BMO_error_clear(bm); + } } else { - BMO_error_clear(bm); + BM_edge_kill(bm, e); } } - else { - BM_edge_kill(bm, e); - } } - - BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "geom.out", BM_EDGE | BM_FACE, ELE_NEW); } + + BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "geom.out", BM_EDGE | BM_FACE, ELE_NEW); } diff --git a/source/blender/bmesh/operators/bmo_utils.c b/source/blender/bmesh/operators/bmo_utils.c index e596032663e..aa1e4bc7523 100644 --- a/source/blender/bmesh/operators/bmo_utils.c +++ b/source/blender/bmesh/operators/bmo_utils.c @@ -48,7 +48,7 @@ void bmo_create_vert_exec(BMesh *bm, BMOperator *op) BMO_slot_vec_get(op->slots_in, "co", vec); - BMO_elem_flag_enable(bm, BM_vert_create(bm, vec, NULL, BM_CREATE_NOP), ELE_NEW); + BMO_vert_flag_enable(bm, BM_vert_create(bm, vec, NULL, BM_CREATE_NOP), ELE_NEW); BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "vert.out", BM_VERT, ELE_NEW); } @@ -74,7 +74,7 @@ void bmo_transform_exec(BMesh *UNUSED(bm), BMOperator *op) void bmo_translate_exec(BMesh *bm, BMOperator *op) { float mat[4][4], vec[3]; - + BMO_slot_vec_get(op->slots_in, "vec", vec); unit_m4(mat); @@ -86,7 +86,7 @@ void bmo_translate_exec(BMesh *bm, BMOperator *op) void bmo_scale_exec(BMesh *bm, BMOperator *op) { float mat[3][3], vec[3]; - + BMO_slot_vec_get(op->slots_in, "vec", vec); unit_m3(mat); @@ -143,18 +143,18 @@ void bmo_rotate_edges_exec(BMesh *bm, BMOperator *op) if (BM_edge_face_pair(e, &fa, &fb)) { /* check we're untouched */ - if (BMO_elem_flag_test(bm, fa, FACE_TAINT) == false && - BMO_elem_flag_test(bm, fb, FACE_TAINT) == false) + if (BMO_face_flag_test(bm, fa, FACE_TAINT) == false && + BMO_face_flag_test(bm, fb, FACE_TAINT) == false) { /* don't touch again (faces will be freed so run before rotating the edge) */ - BMO_elem_flag_enable(bm, fa, FACE_TAINT); - BMO_elem_flag_enable(bm, fb, FACE_TAINT); + BMO_face_flag_enable(bm, fa, FACE_TAINT); + BMO_face_flag_enable(bm, fb, FACE_TAINT); if (!(e2 = BM_edge_rotate(bm, e, use_ccw, check_flag))) { - BMO_elem_flag_disable(bm, fa, FACE_TAINT); - BMO_elem_flag_disable(bm, fb, FACE_TAINT); + BMO_face_flag_disable(bm, fa, FACE_TAINT); + BMO_face_flag_disable(bm, fb, FACE_TAINT); #if 0 BMO_error_raise(bm, op, BMERR_INVALID_SELECTION, "Could not rotate edge"); return; @@ -163,7 +163,7 @@ void bmo_rotate_edges_exec(BMesh *bm, BMOperator *op) continue; } - BMO_elem_flag_enable(bm, e2, EDGE_OUT); + BMO_edge_flag_enable(bm, e2, EDGE_OUT); } } } @@ -184,11 +184,11 @@ static void bmo_face_flag_set_flush(BMesh *bm, BMFace *f, const short oflag, con BMLoop *l_iter; BMLoop *l_first; - BMO_elem_flag_set(bm, f, oflag, value); + BMO_face_flag_set(bm, f, oflag, value); l_iter = l_first = BM_FACE_FIRST_LOOP(f); do { - BMO_elem_flag_set(bm, l_iter->e, oflag, value); - BMO_elem_flag_set(bm, l_iter->v, oflag, value); + BMO_edge_flag_set(bm, l_iter->e, oflag, value); + BMO_vert_flag_set(bm, l_iter->v, oflag, value); } while ((l_iter = l_iter->next) != l_first); } @@ -210,7 +210,9 @@ static void bmo_region_extend_expand( BMEdge *e; BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) { - if (!BMO_elem_flag_test(bm, e, SEL_ORIG) && !BM_elem_flag_test(e, BM_ELEM_HIDDEN)) { + if (!BMO_edge_flag_test(bm, e, SEL_ORIG) && + !BM_elem_flag_test(e, BM_ELEM_HIDDEN)) + { found = true; break; } @@ -223,9 +225,11 @@ static void bmo_region_extend_expand( BMEdge *e; BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) { - if (!BMO_elem_flag_test(bm, e, SEL_FLAG) && !BM_elem_flag_test(e, BM_ELEM_HIDDEN)) { - BMO_elem_flag_enable(bm, e, SEL_FLAG); - BMO_elem_flag_enable(bm, BM_edge_other_vert(e, v), SEL_FLAG); + if (!BMO_edge_flag_test(bm, e, SEL_FLAG) && + !BM_elem_flag_test(e, BM_ELEM_HIDDEN)) + { + BMO_edge_flag_enable(bm, e, SEL_FLAG); + BMO_vert_flag_enable(bm, BM_edge_other_vert(e, v), SEL_FLAG); } } } @@ -234,7 +238,9 @@ static void bmo_region_extend_expand( BMFace *f; BM_ITER_ELEM (f, &fiter, v, BM_FACES_OF_VERT) { - if (!BMO_elem_flag_test(bm, f, SEL_FLAG) && !BM_elem_flag_test(f, BM_ELEM_HIDDEN)) { + if (!BMO_face_flag_test(bm, f, SEL_FLAG) && + !BM_elem_flag_test(f, BM_ELEM_HIDDEN)) + { bmo_face_flag_set_flush(bm, f, SEL_FLAG, true); } } @@ -245,9 +251,11 @@ static void bmo_region_extend_expand( BMEdge *e; BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) { if (BM_edge_is_wire(e)) { - if (!BMO_elem_flag_test(bm, e, SEL_FLAG) && !BM_elem_flag_test(e, BM_ELEM_HIDDEN)) { - BMO_elem_flag_enable(bm, e, SEL_FLAG); - BMO_elem_flag_enable(bm, BM_edge_other_vert(e, v), SEL_FLAG); + if (!BMO_edge_flag_test(bm, e, SEL_FLAG) && + !BM_elem_flag_test(e, BM_ELEM_HIDDEN)) + { + BMO_edge_flag_enable(bm, e, SEL_FLAG); + BMO_vert_flag_enable(bm, BM_edge_other_vert(e, v), SEL_FLAG); } } } @@ -269,10 +277,10 @@ static void bmo_region_extend_expand( BMFace *f_other; BM_ITER_ELEM (f_other, &fiter, l->e, BM_FACES_OF_EDGE) { - if (!BMO_elem_flag_test(bm, f_other, SEL_ORIG | SEL_FLAG) && + if (!BMO_face_flag_test(bm, f_other, SEL_ORIG | SEL_FLAG) && !BM_elem_flag_test(f_other, BM_ELEM_HIDDEN)) { - BMO_elem_flag_enable(bm, f_other, SEL_FLAG); + BMO_face_flag_enable(bm, f_other, SEL_FLAG); } } } @@ -281,10 +289,10 @@ static void bmo_region_extend_expand( BMFace *f_other; BM_ITER_ELEM (f_other, &fiter, l->v, BM_FACES_OF_VERT) { - if (!BMO_elem_flag_test(bm, f_other, SEL_ORIG | SEL_FLAG) && + if (!BMO_face_flag_test(bm, f_other, SEL_ORIG | SEL_FLAG) && !BM_elem_flag_test(f_other, BM_ELEM_HIDDEN)) { - BMO_elem_flag_enable(bm, f_other, SEL_FLAG); + BMO_face_flag_enable(bm, f_other, SEL_FLAG); } } } @@ -310,7 +318,7 @@ static void bmo_region_extend_contract( BMEdge *e; BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) { - if (!BMO_elem_flag_test(bm, e, SEL_ORIG)) { + if (!BMO_edge_flag_test(bm, e, SEL_ORIG)) { found = true; break; } @@ -321,7 +329,7 @@ static void bmo_region_extend_contract( BMFace *f; BM_ITER_ELEM (f, &fiter, v, BM_FACES_OF_VERT) { - if (!BMO_elem_flag_test(bm, f, SEL_ORIG)) { + if (!BMO_face_flag_test(bm, f, SEL_ORIG)) { found = true; break; } @@ -334,7 +342,7 @@ static void bmo_region_extend_contract( BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) { if (BM_edge_is_wire(e)) { - if (!BMO_elem_flag_test(bm, e, SEL_ORIG)) { + if (!BMO_edge_flag_test(bm, e, SEL_ORIG)) { found = true; break; } @@ -347,10 +355,10 @@ static void bmo_region_extend_contract( BMIter eiter; BMEdge *e; - BMO_elem_flag_enable(bm, v, SEL_FLAG); + BMO_vert_flag_enable(bm, v, SEL_FLAG); BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) { - BMO_elem_flag_enable(bm, e, SEL_FLAG); + BMO_edge_flag_enable(bm, e, SEL_FLAG); } } } @@ -369,8 +377,8 @@ static void bmo_region_extend_contract( BMFace *f_other; BM_ITER_ELEM (f_other, &fiter, l->e, BM_FACES_OF_EDGE) { - if (!BMO_elem_flag_test(bm, f_other, SEL_ORIG)) { - BMO_elem_flag_enable(bm, f, SEL_FLAG); + if (!BMO_face_flag_test(bm, f_other, SEL_ORIG)) { + BMO_face_flag_enable(bm, f, SEL_FLAG); break; } } @@ -380,8 +388,8 @@ static void bmo_region_extend_contract( BMFace *f_other; BM_ITER_ELEM (f_other, &fiter, l->v, BM_FACES_OF_VERT) { - if (!BMO_elem_flag_test(bm, f_other, SEL_ORIG)) { - BMO_elem_flag_enable(bm, f, SEL_FLAG); + if (!BMO_face_flag_test(bm, f_other, SEL_ORIG)) { + BMO_face_flag_enable(bm, f, SEL_FLAG); break; } } @@ -420,7 +428,7 @@ void bmo_smooth_vert_exec(BMesh *UNUSED(bm), BMOperator *op) const float fac = BMO_slot_float_get(op->slots_in, "factor"); int i, j, clipx, clipy, clipz; int xaxis, yaxis, zaxis; - + clipx = BMO_slot_bool_get(op->slots_in, "mirror_clip_x"); clipy = BMO_slot_bool_get(op->slots_in, "mirror_clip_y"); clipz = BMO_slot_bool_get(op->slots_in, "mirror_clip_z"); @@ -441,7 +449,7 @@ void bmo_smooth_vert_exec(BMesh *UNUSED(bm), BMOperator *op) add_v3_v3v3(co, co, co2); j += 1; } - + if (!j) { copy_v3_v3(co, v->co); i++; diff --git a/source/blender/bmesh/tools/bmesh_beautify.c b/source/blender/bmesh/tools/bmesh_beautify.c index 19fe492c670..3e3a6547b75 100644 --- a/source/blender/bmesh/tools/bmesh_beautify.c +++ b/source/blender/bmesh/tools/bmesh_beautify.c @@ -424,11 +424,13 @@ void BM_mesh_beautify_fill( flag, method); /* update flags */ - if (oflag_edge) - BMO_elem_flag_enable(bm, e, oflag_edge); + if (oflag_edge) { + BMO_edge_flag_enable(bm, e, oflag_edge); + } + if (oflag_face) { - BMO_elem_flag_enable(bm, e->l->f, oflag_face); - BMO_elem_flag_enable(bm, e->l->radial_next->f, oflag_face); + BMO_face_flag_enable(bm, e->l->f, oflag_face); + BMO_face_flag_enable(bm, e->l->radial_next->f, oflag_face); } } } diff --git a/source/blender/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c index 0ed1dffcafb..4dc1c8a9f00 100644 --- a/source/blender/bmesh/tools/bmesh_bevel.c +++ b/source/blender/bmesh/tools/bmesh_bevel.c @@ -1849,11 +1849,11 @@ static void build_boundary(BevelParams *bp, BevVert *bv, bool construct) do { BLI_assert(e->is_bev); /* Make the BoundVert for the right side of e; other side will be made - * when the beveled edge to the left of e is handled. - * Analyze edges until next beveled edge. - * They are either "in plane" (preceding and subsequent faces are coplanar) - * or not. The "non-in-plane" edges effect silhouette and we prefer to slide - * along one of those if possible. */ + * when the beveled edge to the left of e is handled. + * Analyze edges until next beveled edge. + * They are either "in plane" (preceding and subsequent faces are coplanar) + * or not. The "non-in-plane" edges effect silhouette and we prefer to slide + * along one of those if possible. */ nip = nnip = 0; /* counts of in-plane / not-in-plane */ enip = eip = NULL; /* representatives of each */ for (e2 = e->next; !e2->is_bev; e2 = e2->next) { diff --git a/source/blender/bmesh/tools/bmesh_bisect_plane.c b/source/blender/bmesh/tools/bmesh_bisect_plane.c index 9fb6d39a008..51b92a3c45e 100644 --- a/source/blender/bmesh/tools/bmesh_bisect_plane.c +++ b/source/blender/bmesh/tools/bmesh_bisect_plane.c @@ -155,9 +155,9 @@ static void bm_face_bisect_verts(BMesh *bm, BMFace *f, const float plane[4], con BM_face_split(bm, f, l_a, l_b, &l_new, NULL, true); if (l_new) { if (oflag_center) { - BMO_elem_flag_enable(bm, l_new->e, oflag_center); - BMO_elem_flag_enable(bm, l_new->f, oflag_center); - BMO_elem_flag_enable(bm, f, oflag_center); + BMO_edge_flag_enable(bm, l_new->e, oflag_center); + BMO_face_flag_enable(bm, l_new->f, oflag_center); + BMO_face_flag_enable(bm, f, oflag_center); } } } @@ -270,9 +270,9 @@ static void bm_face_bisect_verts(BMesh *bm, BMFace *f, const float plane[4], con if (l_new) { if (oflag_center) { - BMO_elem_flag_enable(bm, l_new->e, oflag_center); - BMO_elem_flag_enable(bm, l_new->f, oflag_center); - BMO_elem_flag_enable(bm, face_split_arr[j], oflag_center); + BMO_edge_flag_enable(bm, l_new->e, oflag_center); + BMO_face_flag_enable(bm, l_new->f, oflag_center); + BMO_face_flag_enable(bm, face_split_arr[j], oflag_center); } } @@ -372,7 +372,7 @@ void BM_mesh_bisect_plane( if (BM_VERT_DIR(v) == 0) { if (oflag_center) { - BMO_elem_flag_enable(bm, v, oflag_center); + BMO_vert_flag_enable(bm, v, oflag_center); } if (use_snap_center) { closest_to_plane_v3(v->co, plane, v->co); @@ -407,7 +407,7 @@ void BM_mesh_bisect_plane( v_new = BM_edge_split(bm, e, e->v1, NULL, e_fac); vert_is_center_enable(v_new); if (oflag_center) { - BMO_elem_flag_enable(bm, v_new, oflag_center); + BMO_vert_flag_enable(bm, v_new, oflag_center); } BM_VERT_DIR(v_new) = 0; @@ -439,7 +439,7 @@ void BM_mesh_bisect_plane( /* if both verts are on the center - tag it */ if (oflag_center) { if (side[0] == 0 && side[1] == 0) { - BMO_elem_flag_enable(bm, e, oflag_center); + BMO_edge_flag_enable(bm, e, oflag_center); } } } diff --git a/source/blender/bmesh/tools/bmesh_decimate_collapse.c b/source/blender/bmesh/tools/bmesh_decimate_collapse.c index 0a5e5aba86b..52a0df5b9d1 100644 --- a/source/blender/bmesh/tools/bmesh_decimate_collapse.c +++ b/source/blender/bmesh/tools/bmesh_decimate_collapse.c @@ -34,6 +34,14 @@ #include "BLI_math.h" #include "BLI_quadric.h" #include "BLI_heap.h" +#include "BLI_linklist.h" +#include "BLI_alloca.h" +#include "BLI_memarena.h" +#include "BLI_edgehash.h" +#include "BLI_polyfill2d.h" +#include "BLI_polyfill2d_beautify.h" +#include "BLI_stackdefines.h" + #include "BKE_customdata.h" @@ -55,14 +63,14 @@ /* if the cost from #BLI_quadric_evaluate is 'noise', fallback to topology */ #define USE_TOPOLOGY_FALLBACK #ifdef USE_TOPOLOGY_FALLBACK -# define TOPOLOGY_FALLBACK_EPS FLT_EPSILON +/* cost is calculated with double precision, it's ok to use a very small epsilon, see T48154. */ +# define TOPOLOGY_FALLBACK_EPS 1e-12f #endif -/* these checks are for rare cases that we can't avoid since they are valid meshes still */ -#define USE_SAFETY_CHECKS - #define BOUNDARY_PRESERVE_WEIGHT 100.0f -#define OPTIMIZE_EPS 0.01f /* FLT_EPSILON is too small, see [#33106] */ +/* Uses double precision, impacts behavior on near-flat surfaces, + * cane give issues with very small faces. 1e-2 is too big, see: T48154. */ +#define OPTIMIZE_EPS 1e-8 #define COST_INVALID FLT_MAX typedef enum CD_UseFlag { @@ -134,8 +142,8 @@ static void bm_decim_build_quadrics(BMesh *bm, Quadric *vquadrics) } -static void bm_decim_calc_target_co( - BMEdge *e, float optimize_co[3], +static void bm_decim_calc_target_co_db( + BMEdge *e, double optimize_co[3], const Quadric *vquadrics) { /* compute an edge contraction target for edge 'e' @@ -152,10 +160,22 @@ static void bm_decim_calc_target_co( return; /* all is good */ } else { - mid_v3_v3v3(optimize_co, e->v1->co, e->v2->co); + optimize_co[0] = 0.5 * ((double)e->v1->co[0] + (double)e->v2->co[0]); + optimize_co[1] = 0.5 * ((double)e->v1->co[1] + (double)e->v2->co[1]); + optimize_co[2] = 0.5 * ((double)e->v1->co[2] + (double)e->v2->co[2]); } } +static void bm_decim_calc_target_co_fl( + BMEdge *e, float optimize_co[3], + const Quadric *vquadrics) +{ + double optimize_co_db[3]; + bm_decim_calc_target_co_db(e, optimize_co_db, vquadrics); + copy_v3fl_v3db(optimize_co, optimize_co_db); +} + + static bool bm_edge_collapse_is_degenerate_flip(BMEdge *e, const float optimize_co[3]) { BMIter liter; @@ -234,8 +254,6 @@ static void bm_decim_build_edge_cost_single( const float *vweights, const float vweight_factor, Heap *eheap, HeapNode **eheap_table) { - const Quadric *q1, *q2; - float optimize_co[3]; float cost; if (eheap_table[BM_elem_index_get(e)]) { @@ -273,15 +291,17 @@ static void bm_decim_build_edge_cost_single( } /* end sanity check */ + { + double optimize_co[3]; + bm_decim_calc_target_co_db(e, optimize_co, vquadrics); - bm_decim_calc_target_co(e, optimize_co, vquadrics); - - q1 = &vquadrics[BM_elem_index_get(e->v1)]; - q2 = &vquadrics[BM_elem_index_get(e->v2)]; - - cost = (BLI_quadric_evaluate(q1, optimize_co) + - BLI_quadric_evaluate(q2, optimize_co)); + const Quadric *q1, *q2; + q1 = &vquadrics[BM_elem_index_get(e->v1)]; + q2 = &vquadrics[BM_elem_index_get(e->v2)]; + cost = (BLI_quadric_evaluate(q1, optimize_co) + + BLI_quadric_evaluate(q2, optimize_co)); + } /* note, 'cost' shouldn't be negative but happens sometimes with small values. * this can cause faces that make up a flat surface to over-collapse, see [#37121] */ @@ -472,12 +492,58 @@ static int *bm_edge_symmetry_map(BMesh *bm, unsigned int symmetry_axis, float li * * \return true if any faces were triangulated. */ +static bool bm_face_triangulate( + BMesh *bm, BMFace *f_base, LinkNode **r_faces_double, int *r_edges_tri_tot, -static bool bm_decim_triangulate_begin(BMesh *bm) + MemArena *pf_arena, + /* use for MOD_TRIANGULATE_NGON_BEAUTY only! */ + struct Heap *pf_heap, struct EdgeHash *pf_ehash) +{ + const int f_base_len = f_base->len; + int faces_array_tot = f_base_len - 3; + int edges_array_tot = f_base_len - 3; + BMFace **faces_array = BLI_array_alloca(faces_array, faces_array_tot); + BMEdge **edges_array = BLI_array_alloca(edges_array, edges_array_tot); + const int quad_method = 0, ngon_method = 0; /* beauty */ + + bool has_cut = false; + + const int f_index = BM_elem_index_get(f_base); + + BM_face_triangulate( + bm, f_base, + faces_array, &faces_array_tot, + edges_array, &edges_array_tot, + r_faces_double, + quad_method, ngon_method, false, + pf_arena, + pf_heap, pf_ehash); + + for (int i = 0; i < edges_array_tot; i++) { + BMLoop *l_iter, *l_first; + l_iter = l_first = edges_array[i]->l; + do { + BM_elem_index_set(l_iter, f_index); /* set_dirty */ + has_cut = true; + } while ((l_iter = l_iter->radial_next) != l_first); + } + + for (int i = 0; i < faces_array_tot; i++) { + BM_face_normal_update(faces_array[i]); + } + + *r_edges_tri_tot += edges_array_tot; + + return has_cut; +} + + +static bool bm_decim_triangulate_begin(BMesh *bm, int *r_edges_tri_tot) { BMIter iter; BMFace *f; - // bool has_quad; // could optimize this a little + bool has_quad = false; + bool has_ngon = false; bool has_cut = false; BLI_assert((bm->elem_index_dirty & BM_VERT) == 0); @@ -492,98 +558,104 @@ static bool bm_decim_triangulate_begin(BMesh *bm) BM_elem_index_set(l_iter, -1); /* set_dirty */ } while ((l_iter = l_iter->next) != l_first); - // has_quad |= (f->len == 4) + has_quad |= (f->len > 3); + has_ngon |= (f->len > 4); } bm->elem_index_dirty |= BM_LOOP; - /* adding new faces as we loop over faces - * is normally best avoided, however in this case its not so bad because any face touched twice - * will already be triangulated*/ - BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { - if (f->len == 4) { - BMLoop *f_l[4]; - BMLoop *l_a, *l_b; + { + MemArena *pf_arena; + Heap *pf_heap; + EdgeHash *pf_ehash; - { - BMLoop *l_iter = BM_FACE_FIRST_LOOP(f); + LinkNode *faces_double = NULL; - f_l[0] = l_iter; l_iter = l_iter->next; - f_l[1] = l_iter; l_iter = l_iter->next; - f_l[2] = l_iter; l_iter = l_iter->next; - f_l[3] = l_iter; - } + if (has_ngon) { + pf_arena = BLI_memarena_new(BLI_POLYFILL_ARENA_SIZE, __func__); + pf_heap = BLI_heap_new_ex(BLI_POLYFILL_ALLOC_NGON_RESERVE); + pf_ehash = BLI_edgehash_new_ex(__func__, BLI_POLYFILL_ALLOC_NGON_RESERVE); + } + else { + pf_arena = NULL; + pf_heap = NULL; + pf_ehash = NULL; + } - if (len_squared_v3v3(f_l[0]->v->co, f_l[2]->v->co) < - len_squared_v3v3(f_l[1]->v->co, f_l[3]->v->co)) - { - l_a = f_l[0]; - l_b = f_l[2]; + /* adding new faces as we loop over faces + * is normally best avoided, however in this case its not so bad because any face touched twice + * will already be triangulated*/ + BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { + if (f->len > 3) { + has_cut |= bm_face_triangulate( + bm, f, &faces_double, + r_edges_tri_tot, + + pf_arena, + pf_heap, pf_ehash); } - else { - l_a = f_l[1]; - l_b = f_l[3]; - } - -#ifdef USE_SAFETY_CHECKS - if (BM_edge_exists(l_a->v, l_b->v) == NULL) -#endif - { - BMFace *f_new; - BMLoop *l_new; - - /* warning, NO_DOUBLE option here isn't handled as nice as it could be - * - if there is a quad that has a free standing edge joining it along - * where we want to split the face, there isnt a good way we can handle this. - * currently that edge will get removed when joining the tris back into a quad. */ - f_new = BM_face_split(bm, f, l_a, l_b, &l_new, NULL, false); - - if (f_new) { - /* the value of this doesn't matter, only that the 2 loops match and have unique values */ - const int f_index = BM_elem_index_get(f); - - /* since we just split theres only ever 2 loops */ - BLI_assert(BM_edge_is_manifold(l_new->e)); - - BM_elem_index_set(l_new, f_index); /* set_dirty */ - BM_elem_index_set(l_new->radial_next, f_index); /* set_dirty */ + } - BM_face_normal_update(f); - BM_face_normal_update(f_new); + while (faces_double) { + LinkNode *next = faces_double->next; + BM_face_kill(bm, faces_double->link); + MEM_freeN(faces_double); + faces_double = next; + } - has_cut = true; - } - } + if (has_ngon) { + BLI_memarena_free(pf_arena); + BLI_heap_free(pf_heap, NULL); + BLI_edgehash_free(pf_ehash, NULL); } - } - BLI_assert((bm->elem_index_dirty & BM_VERT) == 0); + BLI_assert((bm->elem_index_dirty & BM_VERT) == 0); - if (has_cut) { - /* now triangulation is done we need to correct index values */ - BM_mesh_elem_index_ensure(bm, BM_EDGE | BM_FACE); + if (has_cut) { + /* now triangulation is done we need to correct index values */ + BM_mesh_elem_index_ensure(bm, BM_EDGE | BM_FACE); + } } return has_cut; } -static void bm_decim_triangulate_end(BMesh *bm) + +static void bm_decim_triangulate_end(BMesh *bm, const int edges_tri_tot) { /* decimation finished, now re-join */ BMIter iter; - BMEdge *e, *e_next; + BMEdge *e; + + /* we need to collect before merging for ngons since the loops indices will be lost */ + BMEdge **edges_tri = MEM_mallocN(MIN2(edges_tri_tot, bm->totedge) * sizeof(*edges_tri), __func__); + STACK_DECLARE(edges_tri); + + STACK_INIT(edges_tri, MIN2(edges_tri_tot, bm->totedge)); /* boundary edges */ - BM_ITER_MESH_MUTABLE (e, e_next, &iter, bm, BM_EDGES_OF_MESH) { + BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { BMLoop *l_a, *l_b; if (BM_edge_loop_pair(e, &l_a, &l_b)) { const int l_a_index = BM_elem_index_get(l_a); if (l_a_index != -1) { const int l_b_index = BM_elem_index_get(l_b); if (l_a_index == l_b_index) { - if (LIKELY(l_a->f->len == 3 && l_b->f->len == 3)) { - if (l_a->v != l_b->v) { /* if this is the case, faces have become flipped */ - /* check we are not making a degenerate quad */ + if (l_a->v != l_b->v) { /* if this is the case, faces have become flipped */ + /* check we are not making a degenerate quad */ + +#define CAN_LOOP_MERGE(l) \ + (BM_loop_is_manifold(l) && \ + ((l)->v != (l)->radial_next->v) && \ + (l_a_index == BM_elem_index_get(l)) && \ + (l_a_index == BM_elem_index_get((l)->radial_next))) + + if ((l_a->f->len == 3 && l_b->f->len == 3) && + (!CAN_LOOP_MERGE(l_a->next)) && + (!CAN_LOOP_MERGE(l_a->prev)) && + (!CAN_LOOP_MERGE(l_b->next)) && + (!CAN_LOOP_MERGE(l_b->prev))) + { BMVert *vquad[4] = { e->v1, BM_vert_in_edge(e, l_a->next->v) ? l_a->prev->v : l_a->next->v, @@ -596,17 +668,32 @@ static void bm_decim_triangulate_end(BMesh *bm) BLI_assert(ELEM(vquad[2], vquad[1], vquad[0], vquad[3]) == false); BLI_assert(ELEM(vquad[3], vquad[1], vquad[2], vquad[0]) == false); - if (is_quad_convex_v3(vquad[0]->co, vquad[1]->co, vquad[2]->co, vquad[3]->co)) { - /* highly unlikely to fail, but prevents possible double-ups */ - BMFace *f[2] = {l_a->f, l_b->f}; - BM_faces_join(bm, f, 2, true); + if (!is_quad_convex_v3(vquad[0]->co, vquad[1]->co, vquad[2]->co, vquad[3]->co)) { + continue; } } +#undef CAN_LOOP_MERGE + + /* highly unlikely to fail, but prevents possible double-ups */ + STACK_PUSH(edges_tri, e); } } } } } + + for (int i = 0; i < STACK_SIZE(edges_tri); i++) { + BMLoop *l_a, *l_b; + e = edges_tri[i]; + if (BM_edge_loop_pair(e, &l_a, &l_b)) { + BMFace *f_array[2] = {l_a->f, l_b->f}; + BM_faces_join(bm, f_array, 2, false); + if (e->l == NULL) { + BM_edge_kill(bm, e); + } + } + } + MEM_freeN(edges_tri); } #endif /* USE_TRIANGULATE */ @@ -1083,7 +1170,7 @@ static bool bm_decim_edge_collapse( return false; } - bm_decim_calc_target_co(e, optimize_co, vquadrics); + bm_decim_calc_target_co_fl(e, optimize_co, vquadrics); /* check if this would result in an overlapping face */ if (UNLIKELY(bm_edge_collapse_is_degenerate_flip(e, optimize_co))) { @@ -1205,7 +1292,8 @@ static bool bm_decim_edge_collapse( * \param factor face count multiplier [0 - 1] * \param vweights Optional array of vertex aligned weights [0 - 1], * a vertex group is the usual source for this. - * \param axis: Axis of symmetry, -1 to disable mirror decimate. + * \param symmetry_axis: Axis of symmetry, -1 to disable mirror decimate. + * \param symmetry_eps: Threshold when matching mirror verts. */ void BM_mesh_decimate_collapse( BMesh *bm, @@ -1219,7 +1307,6 @@ void BM_mesh_decimate_collapse( Quadric *vquadrics; /* vert index aligned quadrics */ int tot_edge_orig; int face_tot_target; - bool use_triangulate; CD_UseFlag customdata_flag = 0; @@ -1229,8 +1316,11 @@ void BM_mesh_decimate_collapse( #endif #ifdef USE_TRIANGULATE + int edges_tri_tot = 0; /* temp convert quads to triangles */ - use_triangulate = bm_decim_triangulate_begin(bm); + bool use_triangulate = bm_decim_triangulate_begin(bm, &edges_tri_tot); +#else + UNUSED_VARS(do_triangulate); #endif @@ -1352,7 +1442,7 @@ void BM_mesh_decimate_collapse( goto invalidate; } - bm_decim_calc_target_co(e, optimize_co, vquadrics); + bm_decim_calc_target_co_fl(e, optimize_co, vquadrics); if (e_index_mirr == e_index) { optimize_co[symmetry_axis] = 0.0f; @@ -1415,7 +1505,7 @@ invalidate: /* its possible we only had triangles, skip this step in that case */ if (LIKELY(use_triangulate)) { /* temp convert quads to triangles */ - bm_decim_triangulate_end(bm); + bm_decim_triangulate_end(bm, edges_tri_tot); } } #endif diff --git a/source/blender/bmesh/tools/bmesh_decimate_dissolve.c b/source/blender/bmesh/tools/bmesh_decimate_dissolve.c index ad35d57f35b..978cceee37c 100644 --- a/source/blender/bmesh/tools/bmesh_decimate_dissolve.c +++ b/source/blender/bmesh/tools/bmesh_decimate_dissolve.c @@ -335,7 +335,7 @@ void BM_mesh_decimate_dissolve_ex( /* update normal */ BM_face_normal_update(f_new); if (oflag_out) { - BMO_elem_flag_enable(bm, f_new, oflag_out); + BMO_face_flag_enable(bm, f_new, oflag_out); } /* re-calculate costs */ diff --git a/source/blender/bmesh/tools/bmesh_decimate_unsubdivide.c b/source/blender/bmesh/tools/bmesh_decimate_unsubdivide.c index db60b3e15e1..0fc571bc0a8 100644 --- a/source/blender/bmesh/tools/bmesh_decimate_unsubdivide.c +++ b/source/blender/bmesh/tools/bmesh_decimate_unsubdivide.c @@ -213,7 +213,7 @@ void BM_mesh_decimate_unsubdivide_ex(BMesh *bm, const int iterations, const bool BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { if (BM_elem_flag_test(v, BM_ELEM_TAG) && bm_vert_dissolve_fan_test(v)) { #ifdef USE_WALKER - BMO_elem_flag_enable(bm, v, ELE_VERT_TAG); + BMO_vert_flag_enable(bm, v, ELE_VERT_TAG); #endif BM_elem_index_set(v, VERT_INDEX_INIT); /* set_dirty! */ } @@ -238,7 +238,7 @@ void BM_mesh_decimate_unsubdivide_ex(BMesh *bm, const int iterations, const bool BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { if (v->e && (BM_elem_index_get(v) == VERT_INDEX_INIT)) { #ifdef USE_WALKER - if (BMO_elem_flag_test(bm, v, ELE_VERT_TAG)) + if (BMO_vert_flag_test(bm, v, ELE_VERT_TAG)) #endif { /* check again incase the topology changed */ diff --git a/source/blender/bmesh/tools/bmesh_intersect.c b/source/blender/bmesh/tools/bmesh_intersect.c index 9d1f7fa45d2..58234ddf3bd 100644 --- a/source/blender/bmesh/tools/bmesh_intersect.c +++ b/source/blender/bmesh/tools/bmesh_intersect.c @@ -53,6 +53,8 @@ #include "BLI_buffer.h" #include "bmesh.h" +#include "intern/bmesh_private.h" + #include "bmesh_intersect.h" /* own include */ #include "tools/bmesh_edgesplit.h" @@ -535,8 +537,6 @@ static void bm_isect_tri_tri( const float *f_b_cos[3] = {UNPACK3_EX(, fv_b, ->co)}; float f_a_nor[3]; float f_b_nor[3]; - int a_mask = 0; - int b_mask = 0; unsigned int i; @@ -556,6 +556,22 @@ static void bm_isect_tri_tri( STACK_INIT(iv_ls_a, ARRAY_SIZE(iv_ls_a)); STACK_INIT(iv_ls_b, ARRAY_SIZE(iv_ls_b)); +#define VERT_VISIT_A _FLAG_WALK +#define VERT_VISIT_B _FLAG_WALK_ALT + +#define STACK_PUSH_TEST_A(ele) \ + if (BM_ELEM_API_FLAG_TEST(ele, VERT_VISIT_A) == 0) { \ + BM_ELEM_API_FLAG_ENABLE(ele, VERT_VISIT_A); \ + STACK_PUSH(iv_ls_a, ele); \ + } ((void)0) + +#define STACK_PUSH_TEST_B(ele) \ + if (BM_ELEM_API_FLAG_TEST(ele, VERT_VISIT_B) == 0) { \ + BM_ELEM_API_FLAG_ENABLE(ele, VERT_VISIT_B); \ + STACK_PUSH(iv_ls_b, ele); \ + } ((void)0) + + /* vert-vert * --------- */ { @@ -567,22 +583,18 @@ static void bm_isect_tri_tri( unsigned int i_b; for (i_b = 0; i_b < 3; i_b++) { if (len_squared_v3v3(fv_a[i_a]->co, fv_b[i_b]->co) <= s->epsilon.eps2x_sq) { - if (!((1 << i_a) & a_mask)) { - STACK_PUSH(iv_ls_a, fv_a[i_a]); - a_mask |= (1 << i_a); #ifdef USE_DUMP + if (BM_ELEM_API_FLAG_TEST(fv_a[i_a], VERT_VISIT) == 0) { printf(" ('VERT-VERT-A') %d, %d),\n", i_a, BM_elem_index_get(fv_a[i_a])); -#endif } - if (!((1 << i_b) & b_mask)) { - STACK_PUSH(iv_ls_b, fv_b[i_b]); - b_mask |= (1 << i_b); -#ifdef USE_DUMP + if (BM_ELEM_API_FLAG_TEST(fv_b[i_b], VERT_VISIT) == 0) { printf(" ('VERT-VERT-B') %d, %d),\n", i_b, BM_elem_index_get(fv_b[i_b])); -#endif } +#endif + STACK_PUSH_TEST_A(fv_a[i_a]); + STACK_PUSH_TEST_B(fv_b[i_b]); } } } @@ -593,22 +605,25 @@ static void bm_isect_tri_tri( { unsigned int i_a; for (i_a = 0; i_a < 3; i_a++) { - if (!((1 << i_a) & a_mask)) { + if (BM_ELEM_API_FLAG_TEST(fv_a[i_a], VERT_VISIT_A) == 0) { unsigned int i_b_e0; for (i_b_e0 = 0; i_b_e0 < 3; i_b_e0++) { unsigned int i_b_e1 = (i_b_e0 + 1) % 3; - float fac; - if (((1 << i_b_e0) | (1 << i_b_e1)) & b_mask) + + if (BM_ELEM_API_FLAG_TEST(fv_b[i_b_e0], VERT_VISIT_B) || + BM_ELEM_API_FLAG_TEST(fv_b[i_b_e1], VERT_VISIT_B)) + { continue; - fac = line_point_factor_v3(fv_a[i_a]->co, fv_b[i_b_e0]->co, fv_b[i_b_e1]->co); + } + + const float fac = line_point_factor_v3(fv_a[i_a]->co, fv_b[i_b_e0]->co, fv_b[i_b_e1]->co); if ((fac > 0.0f - s->epsilon.eps) && (fac < 1.0f + s->epsilon.eps)) { float ix[3]; interp_v3_v3v3(ix, fv_b[i_b_e0]->co, fv_b[i_b_e1]->co, fac); if (len_squared_v3v3(ix, fv_a[i_a]->co) <= s->epsilon.eps2x_sq) { BMEdge *e; - STACK_PUSH(iv_ls_b, fv_a[i_a]); - // STACK_PUSH(iv_ls_a, fv_a[i_a]); - a_mask |= (1 << i_a); + STACK_PUSH_TEST_B(fv_a[i_a]); + // STACK_PUSH_TEST_A(fv_a[i_a]); e = BM_edge_exists(fv_b[i_b_e0], fv_b[i_b_e1]); #ifdef USE_DUMP printf(" ('VERT-EDGE-A', %d, %d),\n", @@ -631,22 +646,25 @@ static void bm_isect_tri_tri( { unsigned int i_b; for (i_b = 0; i_b < 3; i_b++) { - if (!((1 << i_b) & b_mask)) { + if (BM_ELEM_API_FLAG_TEST(fv_b[i_b], VERT_VISIT_B) == 0) { unsigned int i_a_e0; for (i_a_e0 = 0; i_a_e0 < 3; i_a_e0++) { unsigned int i_a_e1 = (i_a_e0 + 1) % 3; - float fac; - if (((1 << i_a_e0) | (1 << i_a_e1)) & a_mask) + + if (BM_ELEM_API_FLAG_TEST(fv_a[i_a_e0], VERT_VISIT_A) || + BM_ELEM_API_FLAG_TEST(fv_a[i_a_e1], VERT_VISIT_A)) + { continue; - fac = line_point_factor_v3(fv_b[i_b]->co, fv_a[i_a_e0]->co, fv_a[i_a_e1]->co); + } + + const float fac = line_point_factor_v3(fv_b[i_b]->co, fv_a[i_a_e0]->co, fv_a[i_a_e1]->co); if ((fac > 0.0f - s->epsilon.eps) && (fac < 1.0f + s->epsilon.eps)) { float ix[3]; interp_v3_v3v3(ix, fv_a[i_a_e0]->co, fv_a[i_a_e1]->co, fac); if (len_squared_v3v3(ix, fv_b[i_b]->co) <= s->epsilon.eps2x_sq) { BMEdge *e; - STACK_PUSH(iv_ls_a, fv_b[i_b]); - // STACK_PUSH(iv_ls_b, fv_b[i_b]); - b_mask |= (1 << i_b); + STACK_PUSH_TEST_A(fv_b[i_b]); + // STACK_PUSH_NOTEST(iv_ls_b, fv_b[i_b]); e = BM_edge_exists(fv_a[i_a_e0], fv_a[i_a_e1]); #ifdef USE_DUMP printf(" ('VERT-EDGE-B', %d, %d),\n", @@ -680,17 +698,15 @@ static void bm_isect_tri_tri( // second check for verts intersecting the triangle for (i_a = 0; i_a < 3; i_a++) { - float ix[3]; - if ((1 << i_a) & a_mask) + if (BM_ELEM_API_FLAG_TEST(fv_a[i_a], VERT_VISIT_A)) { continue; + } + + float ix[3]; if (isect_point_tri_v3(fv_a[i_a]->co, UNPACK3(t_scale), ix)) { if (len_squared_v3v3(ix, fv_a[i_a]->co) <= s->epsilon.eps2x_sq) { - BLI_assert(BLI_array_findindex(iv_ls_a, STACK_SIZE(iv_ls_a), fv_a[i_a]) == -1); - BLI_assert(BLI_array_findindex(iv_ls_b, STACK_SIZE(iv_ls_b), fv_a[i_a]) == -1); - - STACK_PUSH(iv_ls_a, fv_a[i_a]); - STACK_PUSH(iv_ls_b, fv_a[i_a]); - a_mask |= (1 << i_a); + STACK_PUSH_TEST_A(fv_a[i_a]); + STACK_PUSH_TEST_B(fv_a[i_a]); #ifdef USE_DUMP printf(" 'VERT TRI-A',\n"); #endif @@ -709,18 +725,15 @@ static void bm_isect_tri_tri( tri_v3_scale(UNPACK3(t_scale), 1.0f - s->epsilon.eps2x); for (i_b = 0; i_b < 3; i_b++) { - float ix[3]; - if ((1 << i_b) & b_mask) + if (BM_ELEM_API_FLAG_TEST(fv_b[i_b], VERT_VISIT_B)) { continue; + } + float ix[3]; if (isect_point_tri_v3(fv_b[i_b]->co, UNPACK3(t_scale), ix)) { if (len_squared_v3v3(ix, fv_b[i_b]->co) <= s->epsilon.eps2x_sq) { - BLI_assert(BLI_array_findindex((void **)iv_ls_a, STACK_SIZE(iv_ls_a), fv_b[i_b]) == -1); - BLI_assert(BLI_array_findindex((void **)iv_ls_b, STACK_SIZE(iv_ls_b), fv_b[i_b]) == -1); - - STACK_PUSH(iv_ls_a, fv_b[i_b]); - STACK_PUSH(iv_ls_b, fv_b[i_b]); - b_mask |= (1 << i_b); + STACK_PUSH_TEST_A(fv_b[i_b]); + STACK_PUSH_TEST_B(fv_b[i_b]); #ifdef USE_DUMP printf(" 'VERT TRI-B',\n"); #endif @@ -735,7 +748,7 @@ static void bm_isect_tri_tri( #ifdef USE_DUMP printf("# OVERLAP\n"); #endif - return; + goto finally; } normal_tri_v3(f_a_nor, UNPACK3(f_a_cos)); @@ -744,37 +757,42 @@ static void bm_isect_tri_tri( /* edge-tri & edge-edge * -------------------- */ { - unsigned int i_e0; - for (i_e0 = 0; i_e0 < 3; i_e0++) { - unsigned int i_e1 = (i_e0 + 1) % 3; + for (unsigned int i_a_e0 = 0; i_a_e0 < 3; i_a_e0++) { + unsigned int i_a_e1 = (i_a_e0 + 1) % 3; enum ISectType side; BMVert *iv; - if (((1 << i_e0) | (1 << i_e1)) & a_mask) + + if (BM_ELEM_API_FLAG_TEST(fv_a[i_a_e0], VERT_VISIT_A) || + BM_ELEM_API_FLAG_TEST(fv_a[i_a_e1], VERT_VISIT_A)) + { continue; - iv = bm_isect_edge_tri(s, fv_a[i_e0], fv_a[i_e1], fv_b, b_index, f_b_cos, f_b_nor, &side); + } + + iv = bm_isect_edge_tri(s, fv_a[i_a_e0], fv_a[i_a_e1], fv_b, b_index, f_b_cos, f_b_nor, &side); if (iv) { - BLI_assert(BLI_array_findindex((void **)iv_ls_a, STACK_SIZE(iv_ls_a), iv) == -1); - BLI_assert(BLI_array_findindex((void **)iv_ls_b, STACK_SIZE(iv_ls_b), iv) == -1); - STACK_PUSH(iv_ls_a, iv); - STACK_PUSH(iv_ls_b, iv); + STACK_PUSH_TEST_A(iv); + STACK_PUSH_TEST_B(iv); #ifdef USE_DUMP printf(" ('EDGE-TRI-A', %d),\n", side); #endif } } - for (i_e0 = 0; i_e0 < 3; i_e0++) { - unsigned int i_e1 = (i_e0 + 1) % 3; + for (unsigned int i_b_e0 = 0; i_b_e0 < 3; i_b_e0++) { + unsigned int i_b_e1 = (i_b_e0 + 1) % 3; enum ISectType side; BMVert *iv; - if (((1 << i_e0) | (1 << i_e1)) & b_mask) + + if (BM_ELEM_API_FLAG_TEST(fv_b[i_b_e0], VERT_VISIT_B) || + BM_ELEM_API_FLAG_TEST(fv_b[i_b_e1], VERT_VISIT_B)) + { continue; - iv = bm_isect_edge_tri(s, fv_b[i_e0], fv_b[i_e1], fv_a, a_index, f_a_cos, f_a_nor, &side); + } + + iv = bm_isect_edge_tri(s, fv_b[i_b_e0], fv_b[i_b_e1], fv_a, a_index, f_a_cos, f_a_nor, &side); if (iv) { - BLI_assert(BLI_array_findindex((void **)iv_ls_a, STACK_SIZE(iv_ls_a), iv) == -1); - BLI_assert(BLI_array_findindex((void **)iv_ls_b, STACK_SIZE(iv_ls_b), iv) == -1); - STACK_PUSH(iv_ls_a, iv); - STACK_PUSH(iv_ls_b, iv); + STACK_PUSH_TEST_A(iv); + STACK_PUSH_TEST_B(iv); #ifdef USE_DUMP printf(" ('EDGE-TRI-B', %d),\n", side); #endif @@ -827,6 +845,15 @@ static void bm_isect_tri_tri( // BLI_assert(len(ie_vs) <= 2) } } + +finally: + for (i = 0; i < STACK_SIZE(iv_ls_a); i++) { + BM_ELEM_API_FLAG_DISABLE(iv_ls_a[i], VERT_VISIT_A); \ + } + for (i = 0; i < STACK_SIZE(iv_ls_b); i++) { + BM_ELEM_API_FLAG_DISABLE(iv_ls_b[i], VERT_VISIT_B); \ + } + } #ifdef USE_BVH diff --git a/source/blender/collada/MeshImporter.cpp b/source/blender/collada/MeshImporter.cpp index 3adddddb8e7..6ff6de33d56 100644 --- a/source/blender/collada/MeshImporter.cpp +++ b/source/blender/collada/MeshImporter.cpp @@ -172,8 +172,7 @@ void UVDataWrapper::getUV(int uv_index, float *uv) } } -VCOLDataWrapper::VCOLDataWrapper(COLLADAFW::MeshVertexData& vdata) : mVData(&vdata){ -} +VCOLDataWrapper::VCOLDataWrapper(COLLADAFW::MeshVertexData& vdata) : mVData(&vdata) {} void VCOLDataWrapper::get_vcol(int v_index, MLoopCol *mloopcol) { @@ -271,38 +270,41 @@ bool MeshImporter::is_nice_mesh(COLLADAFW::Mesh *mesh) // checks if mesh has su COLLADAFW::MeshPrimitiveArray& prim_arr = mesh->getMeshPrimitives(); const std::string &name = bc_get_dae_name(mesh); - int hole_count = 0; 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(); - + + int hole_count = 0; + int nonface_count = 0; + for (unsigned int j = 0; j < vca.getCount(); j++) { int count = vca[j]; if (abs(count) < 3) { - fprintf(stderr, "ERROR: Primitive %s in %s has at least one face with vertex count < 3\n", - type_str, name.c_str()); - return false; + nonface_count++; } - if (count < 0) - { + + if (count < 0) { hole_count ++; } } - if (hole_count > 0) - { + if (hole_count > 0) { fprintf(stderr, "WARNING: Primitive %s in %s: %d holes not imported (unsupported)\n", type_str, name.c_str(), hole_count); } + + if (nonface_count > 0) { + fprintf(stderr, "WARNING: Primitive %s in %s: %d faces with vertex count < 3 (rejected)\n", type_str, name.c_str(), nonface_count); + } } else if (type == COLLADAFW::MeshPrimitive::LINES) { diff --git a/source/blender/collada/collada_utils.cpp b/source/blender/collada/collada_utils.cpp index f0984fbc127..649c86edd25 100644 --- a/source/blender/collada/collada_utils.cpp +++ b/source/blender/collada/collada_utils.cpp @@ -357,8 +357,11 @@ void bc_triangulate_mesh(Mesh *me) bool use_beauty = false; bool tag_only = false; int quad_method = MOD_TRIANGULATE_QUAD_SHORTEDGE; /* XXX: The triangulation method selection could be offered in the UI */ - - BMesh *bm = BM_mesh_create(&bm_mesh_allocsize_default); + + const struct BMeshCreateParams bm_create_params = {0}; + BMesh *bm = BM_mesh_create( + &bm_mesh_allocsize_default, + &bm_create_params); BMeshFromMeshParams bm_from_me_params = {0}; bm_from_me_params.calc_face_normal = true; BM_mesh_bm_from_me(bm, me, &bm_from_me_params); @@ -370,8 +373,8 @@ void bc_triangulate_mesh(Mesh *me) } /* -* A bone is a leaf when it has no children or all children are not connected. -*/ + * A bone is a leaf when it has no children or all children are not connected. + */ bool bc_is_leaf_bone(Bone *bone) { for (Bone *child = (Bone *)bone->childbase.first; child; child = child->next) { @@ -410,10 +413,10 @@ int bc_set_layer(int bitfield, int layer, bool enable) } /** -* BoneExtended is a helper class needed for the Bone chain finder -* See ArmatureImporter::fix_leaf_bones() -* and ArmatureImporter::connect_bone_chains() -**/ + * BoneExtended is a helper class needed for the Bone chain finder + * See ArmatureImporter::fix_leaf_bones() + * and ArmatureImporter::connect_bone_chains() + */ BoneExtended::BoneExtended(EditBone *aBone) { diff --git a/source/blender/compositor/intern/COM_OpenCLDevice.h b/source/blender/compositor/intern/COM_OpenCLDevice.h index a513954ee0d..ad40b4851fb 100644 --- a/source/blender/compositor/intern/COM_OpenCLDevice.h +++ b/source/blender/compositor/intern/COM_OpenCLDevice.h @@ -95,9 +95,9 @@ public: void execute(WorkPackage *work); /** - * @brief determine an image format - * @param memorybuffer - */ + * @brief determine an image format + * @param memorybuffer + */ static const cl_image_format *determineImageFormat(MemoryBuffer *memoryBuffer); cl_context getContext() { return this->m_context; } diff --git a/source/blender/compositor/operations/COM_ImageOperation.cpp b/source/blender/compositor/operations/COM_ImageOperation.cpp index 624378f2ae9..7d59358831c 100644 --- a/source/blender/compositor/operations/COM_ImageOperation.cpp +++ b/source/blender/compositor/operations/COM_ImageOperation.cpp @@ -160,10 +160,10 @@ static void sampleImageAtLocation(ImBuf *ibuf, float x, float y, PixelSampler sa void ImageOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler) { int ix = x, iy = y; - if (ix < 0 || iy < 0 || ix >= this->m_buffer->x || iy >= this->m_buffer->y) { + if (this->m_imageFloatBuffer == NULL && this->m_imageByteBuffer == NULL) { zero_v4(output); } - else if (this->m_imageFloatBuffer == NULL && this->m_imageByteBuffer == NULL) { + else if (ix < 0 || iy < 0 || ix >= this->m_buffer->x || iy >= this->m_buffer->y) { zero_v4(output); } else { diff --git a/source/blender/compositor/operations/COM_MaskOperation.cpp b/source/blender/compositor/operations/COM_MaskOperation.cpp index 220b4e908a6..d6e5fdf86bb 100644 --- a/source/blender/compositor/operations/COM_MaskOperation.cpp +++ b/source/blender/compositor/operations/COM_MaskOperation.cpp @@ -94,7 +94,7 @@ void MaskOperation::initExecution() frame_iter += frame_step; } - BKE_mask_free_nolib(mask_temp); + BKE_mask_free(mask_temp); MEM_freeN(mask_temp); } } diff --git a/source/blender/depsgraph/intern/builder/deg_builder.cc b/source/blender/depsgraph/intern/builder/deg_builder.cc index 9f80c21a6a4..6169100d574 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder.cc @@ -24,7 +24,7 @@ * ***** END GPL LICENSE BLOCK ***** */ -/** \file blender/depsgraph/intern/build/deg_builder.cc +/** \file blender/depsgraph/intern/builder/deg_builder.cc * \ingroup depsgraph */ diff --git a/source/blender/depsgraph/intern/builder/deg_builder.h b/source/blender/depsgraph/intern/builder/deg_builder.h index 7ecb4b20684..bdc030e3810 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder.h +++ b/source/blender/depsgraph/intern/builder/deg_builder.h @@ -24,7 +24,7 @@ * ***** END GPL LICENSE BLOCK ***** */ -/** \file blender/depsgraph/intern/build/deg_builder.h +/** \file blender/depsgraph/intern/builder/deg_builder.h * \ingroup depsgraph */ diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc index 5359cc8754a..74a5be997f1 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc @@ -24,7 +24,7 @@ * ***** END GPL LICENSE BLOCK ***** */ -/** \file blender/depsgraph/intern/builder/deg_build_nodes.cc +/** \file blender/depsgraph/intern/builder/deg_builder_nodes.cc * \ingroup depsgraph * * Methods for constructing depsgraph's nodes @@ -296,16 +296,15 @@ void DepsgraphNodeBuilder::build_scene(Main *bmain, Scene *scene) for (Base *base = (Base *)scene->base.first; base; base = base->next) { Object *ob = base->object; - /* object itself */ - build_object(scene, base, ob); - /* object that this is a proxy for */ // XXX: the way that proxies work needs to be completely reviewed! if (ob->proxy) { ob->proxy->proxy_from = ob; - build_object(scene, base, ob->proxy); } + /* object itself */ + build_object(scene, base, ob); + /* Object dupligroup. */ if (ob->dup_group) { build_group(scene, base, ob->dup_group); @@ -486,6 +485,12 @@ void DepsgraphNodeBuilder::build_object(Scene *scene, Base *base, Object *ob) if (ob->gpd) { build_gpencil(ob->gpd); } + + if (ob->proxy != NULL) { + add_operation_node(&ob->id, DEPSNODE_TYPE_PROXY, DEPSOP_TYPE_POST, + function_bind(BKE_object_eval_proxy_backlink, _1, ob), + DEG_OPCODE_PLACEHOLDER, "Parameters Eval"); + } } void DepsgraphNodeBuilder::build_object_transform(Scene *scene, Object *ob) diff --git a/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.cc b/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.cc index 0e78df52ff8..f870a33fb68 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.cc @@ -24,7 +24,7 @@ * ***** END GPL LICENSE BLOCK ***** */ -/** \file blender/depsgraph/intern/builder/deg_builder_pchanmap.h +/** \file blender/depsgraph/intern/builder/deg_builder_pchanmap.cc * \ingroup depsgraph */ diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc index 10aebb75fbf..34c661b21f3 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc @@ -266,6 +266,13 @@ void DepsgraphRelationBuilder::build_scene(Main *bmain, Scene *scene) for (Base *base = (Base *)scene->base.first; base; base = base->next) { Object *ob = base->object; + /* Object that this is a proxy for. + * Just makes sure backlink is correct. + */ + if (ob->proxy) { + ob->proxy->proxy_from = ob; + } + /* object itself */ build_object(bmain, scene, ob); @@ -433,7 +440,6 @@ void DepsgraphRelationBuilder::build_object(Main *bmain, Scene *scene, Object *o break; } - case OB_ARMATURE: /* Pose */ if (ob->id.lib != NULL && ob->proxy_from != NULL) { build_proxy_rig(ob); @@ -1069,7 +1075,7 @@ void DepsgraphRelationBuilder::build_particles(Scene *scene, Object *ob) OperationKey psys_key(&ob->id, DEPSNODE_TYPE_EVAL_PARTICLES, DEG_OPCODE_PSYS_EVAL, psys->name); /* XXX: if particle system is later re-enabled, we must do full rebuild? */ - if (!psys_check_enabled(ob, psys)) + if (!psys_check_enabled(ob, psys, G.is_rendering)) continue; /* TODO(sergey): Are all particle systems depends on time? @@ -1311,10 +1317,12 @@ void DepsgraphRelationBuilder::build_ik_pose(Object *ob, OperationKey done_key(&ob->id, DEPSNODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_DONE); add_relation(solver_key, done_key, DEPSREL_TYPE_TRANSFORM, "IK Chain Result"); } + else { + OperationKey final_transforms_key(&ob->id, DEPSNODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_DONE); + add_relation(solver_key, final_transforms_key, DEPSREL_TYPE_TRANSFORM, "IK Solver Result"); + } parchan->flag |= POSE_DONE; - OperationKey final_transforms_key(&ob->id, DEPSNODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_DONE); - add_relation(solver_key, final_transforms_key, DEPSREL_TYPE_TRANSFORM, "IK Solver Result"); root_map->add_bone(parchan->name, rootchan->name); @@ -1426,20 +1434,20 @@ void DepsgraphRelationBuilder::build_rig(Scene *scene, Object *ob) } /* IK Solvers... - * - These require separate processing steps are pose-level - * to be executed between chains of bones (i.e. once the - * base transforms of a bunch of bones is done) - * - * - We build relations for these before the dependencies - * between ops in the same component as it is necessary - * to check whether such bones are in the same IK chain - * (or else we get weird issues with either in-chain - * references, or with bones being parented to IK'd bones) - * - * Unsolved Issues: - * - Care is needed to ensure that multi-headed trees work out the same as in ik-tree building - * - Animated chain-lengths are a problem... - */ + * - These require separate processing steps are pose-level + * to be executed between chains of bones (i.e. once the + * base transforms of a bunch of bones is done) + * + * - We build relations for these before the dependencies + * between ops in the same component as it is necessary + * to check whether such bones are in the same IK chain + * (or else we get weird issues with either in-chain + * references, or with bones being parented to IK'd bones) + * + * Unsolved Issues: + * - Care is needed to ensure that multi-headed trees work out the same as in ik-tree building + * - Animated chain-lengths are a problem... + */ RootPChanMap root_map; bool pose_depends_on_local_transform = false; for (bPoseChannel *pchan = (bPoseChannel *)ob->pose->chanbase.first; pchan; pchan = pchan->next) { diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.h b/source/blender/depsgraph/intern/builder/deg_builder_relations.h index c0bf82becda..ce6d2c961fd 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.h +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.h @@ -42,7 +42,6 @@ #include "BLI_utildefines.h" #include "BLI_string.h" -#include "intern/depsgraph_types.h" #include "intern/nodes/deg_node.h" #include "intern/nodes/deg_node_operation.h" @@ -292,7 +291,8 @@ struct DepsNodeHandle /* Utilities for Builders ----------------------------------------------------- */ template <typename KeyType> -OperationDepsNode *DepsgraphRelationBuilder::find_operation_node(const KeyType& key) { +OperationDepsNode *DepsgraphRelationBuilder::find_operation_node(const KeyType& key) +{ DepsNode *node = find_node(key); return node != NULL ? node->get_exit_operation() : NULL; } diff --git a/source/blender/depsgraph/intern/builder/deg_builder_transitive.cc b/source/blender/depsgraph/intern/builder/deg_builder_transitive.cc index 0322ef7fa1d..76cd81f1b8f 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_transitive.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_transitive.cc @@ -99,7 +99,7 @@ void deg_graph_transitive_reduction(Depsgraph *graph) /* Remove redundant paths to the target. */ for (DepsNode::Relations::const_iterator it_rel = target->inlinks.begin(); it_rel != target->inlinks.end(); - ) + ) { DepsRelation *rel = *it_rel; /* Increment in advance, so we can safely remove the relation. */ diff --git a/source/blender/depsgraph/intern/depsgraph_type_defines.cc b/source/blender/depsgraph/intern/depsgraph_type_defines.cc index 97208939e57..4ce91516c84 100644 --- a/source/blender/depsgraph/intern/depsgraph_type_defines.cc +++ b/source/blender/depsgraph/intern/depsgraph_type_defines.cc @@ -136,13 +136,15 @@ static const char *stringify_opcode(eDepsOperation_Code opcode) return "UNKNOWN"; } -DepsOperationStringifier::DepsOperationStringifier() { +DepsOperationStringifier::DepsOperationStringifier() +{ for (int i = 0; i < DEG_NUM_OPCODES; ++i) { names_[i] = stringify_opcode((eDepsOperation_Code)i); } } -const char *DepsOperationStringifier::operator[](eDepsOperation_Code opcode) { +const char *DepsOperationStringifier::operator[](eDepsOperation_Code opcode) +{ BLI_assert((opcode > 0) && (opcode < DEG_NUM_OPCODES)); if (opcode >= 0 && opcode < DEG_NUM_OPCODES) { return names_[opcode]; diff --git a/source/blender/depsgraph/intern/eval/deg_eval.cc b/source/blender/depsgraph/intern/eval/deg_eval.cc index 198cd349002..3024d625846 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval.cc @@ -24,7 +24,7 @@ * ***** END GPL LICENSE BLOCK ***** */ -/** \file blender/depsgraph/intern/depsgraph_eval.cc +/** \file blender/depsgraph/intern/eval/deg_eval.cc * \ingroup depsgraph * * Evaluation engine entrypoints for Depsgraph Engine. diff --git a/source/blender/depsgraph/intern/eval/deg_eval.h b/source/blender/depsgraph/intern/eval/deg_eval.h index 0d42f63433f..92f87b03803 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval.h +++ b/source/blender/depsgraph/intern/eval/deg_eval.h @@ -24,7 +24,7 @@ * ***** END GPL LICENSE BLOCK ***** */ -/** \file blender/depsgraph/intern/eval/deg_eval.cc +/** \file blender/depsgraph/intern/eval/deg_eval.h * \ingroup depsgraph * * Evaluation engine entrypoints for Depsgraph Engine. diff --git a/source/blender/depsgraph/intern/eval/deg_eval_flush.cc b/source/blender/depsgraph/intern/eval/deg_eval_flush.cc index af68f5c55c4..9ba0b61a4f1 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_flush.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval_flush.cc @@ -24,7 +24,7 @@ * ***** END GPL LICENSE BLOCK ***** */ -/** \file blender/depsgraph/intern/depsgraph_tag.cc +/** \file blender/depsgraph/intern/eval/deg_eval_flush.cc * \ingroup depsgraph * * Core routines for how the Depsgraph works. @@ -80,10 +80,14 @@ static void flush_init_func(void *data_v, int i) */ Depsgraph *graph = (Depsgraph *)data_v; OperationDepsNode *node = graph->operations[i]; - IDDepsNode *id_node = node->owner->owner; + ComponentDepsNode *comp_node = node->owner; + IDDepsNode *id_node = comp_node->owner; id_node->done = 0; + comp_node->done = 0; node->scheduled = false; - node->owner->flags &= ~DEPSCOMP_FULLY_SCHEDULED; + if (comp_node->type == DEPSNODE_TYPE_PROXY) { + node->flag |= DEPSOP_FLAG_NEEDS_UPDATE; + } } /* Flush updates from tagged nodes outwards until all affected nodes @@ -133,49 +137,10 @@ void deg_graph_flush_updates(Main *bmain, Depsgraph *graph) for (;;) { node->flag |= DEPSOP_FLAG_NEEDS_UPDATE; - IDDepsNode *id_node = node->owner->owner; - - if (id_node->done == 0) { - deg_editors_id_update(bmain, id_node->id); - id_node->done = 1; - } - - lib_id_recalc_tag(bmain, id_node->id); - /* TODO(sergey): For until we've got proper data nodes in the graph. */ - lib_id_recalc_data_tag(bmain, id_node->id); - - ID *id = id_node->id; - /* This code is used to preserve those areas which does direct - * object update, - * - * Plus it ensures visibility changes and relations and layers - * visibility update has proper flags to work with. - */ - if (GS(id->name) == ID_OB) { - Object *object = (Object *)id; - ComponentDepsNode *comp_node = node->owner; - if (comp_node->type == DEPSNODE_TYPE_ANIMATION) { - object->recalc |= OB_RECALC_TIME; - } - else if (comp_node->type == DEPSNODE_TYPE_TRANSFORM) { - object->recalc |= OB_RECALC_OB; - } - else { - object->recalc |= OB_RECALC_DATA; - } - } - - /* TODO(sergey): For until incremental updates are possible - * witin a component at least we tag the whole component - * for update. - */ - ComponentDepsNode *component = node->owner; - if ((component->flags & DEPSCOMP_FULLY_SCHEDULED) == 0) { - foreach (OperationDepsNode *op, component->operations) { - op->flag |= DEPSOP_FLAG_NEEDS_UPDATE; - } - component->flags |= DEPSCOMP_FULLY_SCHEDULED; - } + ComponentDepsNode *comp_node = node->owner; + IDDepsNode *id_node = comp_node->owner; + id_node->done = 1; + comp_node->done = 1; /* Flush to nodes along links... */ if (node->outlinks.size() == 1) { @@ -200,6 +165,52 @@ void deg_graph_flush_updates(Main *bmain, Depsgraph *graph) } } } + + GHASH_FOREACH_BEGIN(DEG::IDDepsNode *, id_node, graph->id_hash) + { + if (id_node->done == 1) { + ID *id = id_node->id; + Object *object = NULL; + + if (GS(id->name) == ID_OB) { + object = (Object *)id; + } + + deg_editors_id_update(bmain, id_node->id); + + lib_id_recalc_tag(bmain, id_node->id); + /* TODO(sergey): For until we've got proper data nodes in the graph. */ + lib_id_recalc_data_tag(bmain, id_node->id); + + GHASH_FOREACH_BEGIN(const ComponentDepsNode *, comp_node, id_node->components) + { + if (comp_node->done) { + foreach (OperationDepsNode *op, comp_node->operations) { + op->flag |= DEPSOP_FLAG_NEEDS_UPDATE; + } + if (object != NULL) { + /* This code is used to preserve those areas which does + * direct object update, + * + * Plus it ensures visibility changes and relations and + * layers visibility update has proper flags to work with. + */ + if (comp_node->type == DEPSNODE_TYPE_ANIMATION) { + object->recalc |= OB_RECALC_TIME; + } + else if (comp_node->type == DEPSNODE_TYPE_TRANSFORM) { + object->recalc |= OB_RECALC_OB; + } + else { + object->recalc |= OB_RECALC_DATA; + } + } + } + } + GHASH_FOREACH_END(); + } + } + GHASH_FOREACH_END(); } static void graph_clear_func(void *data_v, int i) diff --git a/source/blender/depsgraph/intern/eval/deg_eval_flush.h b/source/blender/depsgraph/intern/eval/deg_eval_flush.h index 8912aebee7d..ecd3a5ec660 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_flush.h +++ b/source/blender/depsgraph/intern/eval/deg_eval_flush.h @@ -24,7 +24,7 @@ * ***** END GPL LICENSE BLOCK ***** */ -/** \file blender/depsgraph/intern/eval/deg_eval_flush.cc +/** \file blender/depsgraph/intern/eval/deg_eval_flush.h * \ingroup depsgraph * * Core routines for how the Depsgraph works. diff --git a/source/blender/depsgraph/intern/nodes/deg_node.cc b/source/blender/depsgraph/intern/nodes/deg_node.cc index 78293f7f483..12d5ee00a63 100644 --- a/source/blender/depsgraph/intern/nodes/deg_node.cc +++ b/source/blender/depsgraph/intern/nodes/deg_node.cc @@ -24,7 +24,7 @@ * ***** END GPL LICENSE BLOCK ***** */ -/** \file blender/depsgraph/intern/depsnode.cc +/** \file blender/depsgraph/intern/nodes/deg_node.cc * \ingroup depsgraph */ diff --git a/source/blender/depsgraph/intern/nodes/deg_node.h b/source/blender/depsgraph/intern/nodes/deg_node.h index d79d3d2348d..416996052c9 100644 --- a/source/blender/depsgraph/intern/nodes/deg_node.h +++ b/source/blender/depsgraph/intern/nodes/deg_node.h @@ -24,7 +24,7 @@ * ***** END GPL LICENSE BLOCK ***** */ -/** \file blender/depsgraph/intern/depsnode.h +/** \file depsgraph/intern/nodes/deg_node.h * \ingroup depsgraph */ diff --git a/source/blender/depsgraph/intern/nodes/deg_node_component.cc b/source/blender/depsgraph/intern/nodes/deg_node_component.cc index 7e49fec051f..6ac45c99798 100644 --- a/source/blender/depsgraph/intern/nodes/deg_node_component.cc +++ b/source/blender/depsgraph/intern/nodes/deg_node_component.cc @@ -24,7 +24,7 @@ * ***** END GPL LICENSE BLOCK ***** */ -/** \file blender/depsgraph/intern/depsnode_component.cc +/** \file blender/depsgraph/intern/nodes/deg_node_component.cc * \ingroup depsgraph */ @@ -86,7 +86,6 @@ static void comp_node_hash_value_free(void *value_v) ComponentDepsNode::ComponentDepsNode() : entry_operation(NULL), exit_operation(NULL), - flags(0), layers(0) { operations_map = BLI_ghash_new(comp_node_hash_key, @@ -117,10 +116,10 @@ string ComponentDepsNode::identifier() const { string &idname = this->owner->name; - char typebuf[7]; + char typebuf[16]; sprintf(typebuf, "(%d)", type); - char layers[7]; + char layers[16]; sprintf(layers, "%d", this->layers); return string(typebuf) + name + " : " + idname + " (Layers: " + layers + ")"; @@ -257,7 +256,7 @@ OperationDepsNode *ComponentDepsNode::get_entry_operation() entry_operation = op_node; return op_node; } - else if(operations.size() == 1) { + else if (operations.size() == 1) { return operations[0]; } return NULL; @@ -280,7 +279,7 @@ OperationDepsNode *ComponentDepsNode::get_exit_operation() exit_operation = op_node; return op_node; } - else if(operations.size() == 1) { + else if (operations.size() == 1) { return operations[0]; } return NULL; diff --git a/source/blender/depsgraph/intern/nodes/deg_node_component.h b/source/blender/depsgraph/intern/nodes/deg_node_component.h index df321ea9299..6f62d91cd79 100644 --- a/source/blender/depsgraph/intern/nodes/deg_node_component.h +++ b/source/blender/depsgraph/intern/nodes/deg_node_component.h @@ -24,7 +24,7 @@ * ***** END GPL LICENSE BLOCK ***** */ -/** \file blender/depsgraph/intern/depsnode_component.h +/** \file blender/depsgraph/intern/nodes/deg_node_component.h * \ingroup depsgraph */ @@ -47,13 +47,6 @@ struct Depsgraph; struct OperationDepsNode; struct BoneComponentDepsNode; -typedef enum eDepsComponent_Flag { - /* Temporary flags, meaning all the component's operations has been - * scheduled for update. - */ - DEPSCOMP_FULLY_SCHEDULED = 1, -} eDepsComponent_Flag; - /* ID Component - Base type for all components */ struct ComponentDepsNode : public DepsNode { /* Key used to look up operations within a component */ @@ -165,8 +158,6 @@ struct ComponentDepsNode : public DepsNode { // XXX: a poll() callback to check if component's first node can be started? - int flags; - /* Temporary bitmask, used during graph construction. */ int layers; }; diff --git a/source/blender/depsgraph/intern/nodes/deg_node_operation.cc b/source/blender/depsgraph/intern/nodes/deg_node_operation.cc index a9f9703bb3b..5847af29ac2 100644 --- a/source/blender/depsgraph/intern/nodes/deg_node_operation.cc +++ b/source/blender/depsgraph/intern/nodes/deg_node_operation.cc @@ -24,7 +24,7 @@ * ***** END GPL LICENSE BLOCK ***** */ -/** \file blender/depsgraph/intern/depsnode_operation.cc +/** \file blender/depsgraph/intern/nodes/deg_node_operation.cc * \ingroup depsgraph */ diff --git a/source/blender/depsgraph/intern/nodes/deg_node_operation.h b/source/blender/depsgraph/intern/nodes/deg_node_operation.h index f03078fc3db..598393054db 100644 --- a/source/blender/depsgraph/intern/nodes/deg_node_operation.h +++ b/source/blender/depsgraph/intern/nodes/deg_node_operation.h @@ -24,7 +24,7 @@ * ***** END GPL LICENSE BLOCK ***** */ -/** \file blender/depsgraph/intern/depsnode_operation.h +/** \file blender/depsgraph/intern/nodes/deg_node_operation.h * \ingroup depsgraph */ diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c index 8822c8511de..c98470fb194 100644 --- a/source/blender/editors/animation/anim_channels_edit.c +++ b/source/blender/editors/animation/anim_channels_edit.c @@ -2119,7 +2119,7 @@ static int animchannels_clean_empty_exec(bContext *C, wmOperator *UNUSED(op)) /* remove AnimData? */ if (action_empty && nla_empty && drivers_empty) { - BKE_animdata_free(id); + BKE_animdata_free(id, true); } } diff --git a/source/blender/editors/animation/anim_ipo_utils.c b/source/blender/editors/animation/anim_ipo_utils.c index ae6894ac546..fc6f4036d02 100644 --- a/source/blender/editors/animation/anim_ipo_utils.c +++ b/source/blender/editors/animation/anim_ipo_utils.c @@ -192,7 +192,7 @@ int getname_anim_fcurve(char *name, ID *id, FCurve *fcu) #define HSV_BANDWIDTH 0.3f /* used to determine the color of F-Curves with FCURVE_COLOR_AUTO_RAINBOW set */ -//void fcurve_rainbow (unsigned int cur, unsigned int tot, float *out) +// void fcurve_rainbow(unsigned int cur, unsigned int tot, float *out) void getcolor_fcurve_rainbow(int cur, int tot, float out[3]) { float hsv[3], fac; diff --git a/source/blender/editors/animation/drivers.c b/source/blender/editors/animation/drivers.c index a82cca9e52a..21c25f829b1 100644 --- a/source/blender/editors/animation/drivers.c +++ b/source/blender/editors/animation/drivers.c @@ -158,7 +158,7 @@ static int add_driver_with_target( ReportList *UNUSED(reports), ID *dst_id, const char dst_path[], int dst_index, ID *src_id, const char src_path[], int src_index, - PointerRNA *UNUSED(dst_ptr), PropertyRNA *dst_prop, + PointerRNA *dst_ptr, PropertyRNA *dst_prop, PointerRNA *src_ptr, PropertyRNA *src_prop, short flag, int driver_type) { @@ -207,11 +207,15 @@ static int add_driver_with_target( /* Create a driver variable for the target * - For transform properties, we want to automatically use "transform channel" instead * (The only issue is with quat rotations vs euler channels...) + * - To avoid problems with transform properties depending on the final transform that they + * control (thus creating pseudo-cycles - see T48734), we don't use transform channels + * when both the source and destinations are in same places. */ dvar = driver_add_new_variable(driver); if (ELEM(src_ptr->type, &RNA_Object, &RNA_PoseBone) && - (STREQ(prop_name, "location") || STREQ(prop_name, "scale") || STRPREFIX(prop_name, "rotation_"))) + (STREQ(prop_name, "location") || STREQ(prop_name, "scale") || STRPREFIX(prop_name, "rotation_")) && + (src_ptr->data != dst_ptr->data)) { /* Transform Channel */ DriverTarget *dtar; diff --git a/source/blender/editors/animation/keyframes_edit.c b/source/blender/editors/animation/keyframes_edit.c index 08a7355694b..7b35a154fc8 100644 --- a/source/blender/editors/animation/keyframes_edit.c +++ b/source/blender/editors/animation/keyframes_edit.c @@ -539,10 +539,10 @@ static short ok_bezier_region(KeyframeEditData *ked, BezTriple *bezt) } /** - * only called from #ok_bezier_region_lasso + * Called from #ok_bezier_region_lasso and #ok_bezier_channel_lasso */ -static bool bezier_region_lasso_test( - const struct KeyframeEdit_LassoData *data_lasso, +bool keyframe_region_lasso_test( + const KeyframeEdit_LassoData *data_lasso, const float xy[2]) { if (BLI_rctf_isect_pt_v(data_lasso->rectf_scaled, xy)) { @@ -564,7 +564,7 @@ static short ok_bezier_region_lasso(KeyframeEditData *ked, BezTriple *bezt) if (ked->data) { short ok = 0; -#define KEY_CHECK_OK(_index) bezier_region_lasso_test(ked->data, bezt->vec[_index]) +#define KEY_CHECK_OK(_index) keyframe_region_lasso_test(ked->data, bezt->vec[_index]) KEYFRAME_OK_CHECKS(KEY_CHECK_OK); #undef KEY_CHECK_OK @@ -575,11 +575,38 @@ static short ok_bezier_region_lasso(KeyframeEditData *ked, BezTriple *bezt) return 0; } +static short ok_bezier_channel_lasso(KeyframeEditData *ked, BezTriple *bezt) +{ + /* check for lasso customdata (KeyframeEdit_LassoData) */ + if (ked->data) { + KeyframeEdit_LassoData *data = ked->data; + float pt[2]; + + /* late-binding remap of the x values (for summary channels) */ + /* XXX: Ideally we reset, but it should be fine just leaving it as-is + * as the next channel will reset it properly, while the next summary-channel + * curve will also reset by itself... + */ + if (ked->iterflags & (KED_F1_NLA_UNMAP | KED_F2_NLA_UNMAP)) { + data->rectf_scaled->xmin = ked->f1; + data->rectf_scaled->xmax = ked->f2; + } + + /* only use the x-coordinate of the point; the y is the channel range... */ + pt[0] = bezt->vec[1][0]; + pt[1] = ked->channel_y; + + if (keyframe_region_lasso_test(data, pt)) + return KEYFRAME_OK_KEY; + } + return 0; +} + /** - * only called from #ok_bezier_region_circle + * Called from #ok_bezier_region_circle and #ok_bezier_channel_circle */ -static bool bezier_region_circle_test( - const struct KeyframeEdit_CircleData *data_circle, +bool keyframe_region_circle_test( + const KeyframeEdit_CircleData *data_circle, const float xy[2]) { if (BLI_rctf_isect_pt_v(data_circle->rectf_scaled, xy)) { @@ -602,7 +629,7 @@ static short ok_bezier_region_circle(KeyframeEditData *ked, BezTriple *bezt) if (ked->data) { short ok = 0; -#define KEY_CHECK_OK(_index) bezier_region_circle_test(ked->data, bezt->vec[_index]) +#define KEY_CHECK_OK(_index) keyframe_region_circle_test(ked->data, bezt->vec[_index]) KEYFRAME_OK_CHECKS(KEY_CHECK_OK); #undef KEY_CHECK_OK @@ -613,6 +640,33 @@ static short ok_bezier_region_circle(KeyframeEditData *ked, BezTriple *bezt) return 0; } +static short ok_bezier_channel_circle(KeyframeEditData *ked, BezTriple *bezt) +{ + /* check for circle select customdata (KeyframeEdit_CircleData) */ + if (ked->data) { + KeyframeEdit_CircleData *data = ked->data; + float pt[2]; + + /* late-binding remap of the x values (for summary channels) */ + /* XXX: Ideally we reset, but it should be fine just leaving it as-is + * as the next channel will reset it properly, while the next summary-channel + * curve will also reset by itself... + */ + if (ked->iterflags & (KED_F1_NLA_UNMAP | KED_F2_NLA_UNMAP)) { + data->rectf_scaled->xmin = ked->f1; + data->rectf_scaled->xmax = ked->f2; + } + + /* only use the x-coordinate of the point; the y is the channel range... */ + pt[0] = bezt->vec[1][0]; + pt[1] = ked->channel_y; + + if (keyframe_region_circle_test(data, pt)) + return KEYFRAME_OK_KEY; + } + return 0; +} + KeyframeEditFunc ANIM_editkeyframes_ok(short mode) { @@ -634,6 +688,10 @@ KeyframeEditFunc ANIM_editkeyframes_ok(short mode) return ok_bezier_region_lasso; case BEZT_OK_REGION_CIRCLE: /* only if the point falls within KeyframeEdit_CircleData defined data */ return ok_bezier_region_circle; + case BEZT_OK_CHANNEL_LASSO: /* same as BEZT_OK_REGION_LASSO, but we're only using the x-value of the points */ + return ok_bezier_channel_lasso; + case BEZT_OK_CHANNEL_CIRCLE: /* same as BEZT_OK_REGION_CIRCLE, but we're only using the x-value of the points */ + return ok_bezier_channel_circle; default: /* nothing was ok */ return NULL; } diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c index 172f2b9069e..0c0f54f0179 100644 --- a/source/blender/editors/animation/keyframing.c +++ b/source/blender/editors/animation/keyframing.c @@ -1069,6 +1069,9 @@ short insert_keyframe(ReportList *reports, ID *id, bAction *act, const char grou if (ELEM(RNA_property_subtype(prop), PROP_TRANSLATION, PROP_XYZ, PROP_EULER, PROP_COLOR, PROP_COORDS)) { fcu->color_mode = FCURVE_COLOR_AUTO_RGB; } + else if (RNA_property_subtype(prop), PROP_QUATERNION) { + fcu->color_mode = FCURVE_COLOR_AUTO_YRGB; + } } /* insert keyframe */ @@ -2035,7 +2038,7 @@ bool autokeyframe_cfra_can_key(Scene *scene, ID *id) else { /* Normal Mode (or treat as being normal mode): * - * Just in case the flags are't set properly (i.e. only on/off is set, without a mode) + * Just in case the flags aren't set properly (i.e. only on/off is set, without a mode) * let's set the "normal" flag too, so that it will all be sane everywhere... */ scene->toolsettings->autokey_mode = AUTOKEY_MODE_NORMAL; diff --git a/source/blender/editors/curve/CMakeLists.txt b/source/blender/editors/curve/CMakeLists.txt index ebdf6bb43ff..2f5b2ab6e87 100644 --- a/source/blender/editors/curve/CMakeLists.txt +++ b/source/blender/editors/curve/CMakeLists.txt @@ -43,6 +43,7 @@ set(SRC editcurve_paint.c editcurve_select.c editfont.c + editfont_undo.c curve_intern.h ) diff --git a/source/blender/editors/curve/editcurve_paint.c b/source/blender/editors/curve/editcurve_paint.c index bb7cc61f580..38018541929 100644 --- a/source/blender/editors/curve/editcurve_paint.c +++ b/source/blender/editors/curve/editcurve_paint.c @@ -911,7 +911,7 @@ static int curve_draw_exec(bContext *C, wmOperator *op) unsigned int corners_index_len = 0; const int result = curve_fit_cubic_to_points_fl( - coords, stroke_len, dims, error_threshold, + coords, stroke_len, dims, error_threshold, CURVE_FIT_CALC_HIGH_QUALIY, corners, corners_len, &cubic_spline, &cubic_spline_len, NULL, diff --git a/source/blender/editors/curve/editfont.c b/source/blender/editors/curve/editfont.c index 7c1fe0cadf0..053a7ee5023 100644 --- a/source/blender/editors/curve/editfont.c +++ b/source/blender/editors/curve/editfont.c @@ -1794,64 +1794,6 @@ void FONT_OT_unlink(wmOperatorType *ot) ot->exec = font_unlink_exec; } - -/* **************** undo for font object ************** */ - -static void undoFont_to_editFont(void *strv, void *ecu, void *UNUSED(obdata)) -{ - Curve *cu = (Curve *)ecu; - EditFont *ef = cu->editfont; - const char *str = strv; - - ef->pos = *((const short *)str); - ef->len = *((const short *)(str + 2)); - - memcpy(ef->textbuf, str + 4, (ef->len + 1) * sizeof(wchar_t)); - memcpy(ef->textbufinfo, str + 4 + (ef->len + 1) * sizeof(wchar_t), ef->len * sizeof(CharInfo)); - - ef->selstart = ef->selend = 0; - -} - -static void *editFont_to_undoFont(void *ecu, void *UNUSED(obdata)) -{ - Curve *cu = (Curve *)ecu; - EditFont *ef = cu->editfont; - char *str; - - /* The undo buffer includes [MAXTEXT+6]=actual string and [MAXTEXT+4]*sizeof(CharInfo)=charinfo */ - str = MEM_callocN((MAXTEXT + 6) * sizeof(wchar_t) + (MAXTEXT + 4) * sizeof(CharInfo), "string undo"); - - /* Copy the string and string information */ - memcpy(str + 4, ef->textbuf, (ef->len + 1) * sizeof(wchar_t)); - memcpy(str + 4 + (ef->len + 1) * sizeof(wchar_t), ef->textbufinfo, ef->len * sizeof(CharInfo)); - - *((short *)(str + 0)) = ef->pos; - *((short *)(str + 2)) = ef->len; - - return str; -} - -static void free_undoFont(void *strv) -{ - MEM_freeN(strv); -} - -static void *get_undoFont(bContext *C) -{ - Object *obedit = CTX_data_edit_object(C); - if (obedit && obedit->type == OB_FONT) { - return obedit->data; - } - return NULL; -} - -/* and this is all the undo system needs to know */ -void undo_push_font(bContext *C, const char *name) -{ - undo_editmode_push(C, name, get_undoFont, free_undoFont, undoFont_to_editFont, editFont_to_undoFont, NULL); -} - /** * TextBox selection */ diff --git a/source/blender/editors/curve/editfont_undo.c b/source/blender/editors/curve/editfont_undo.c new file mode 100644 index 00000000000..a0453f9694d --- /dev/null +++ b/source/blender/editors/curve/editfont_undo.c @@ -0,0 +1,311 @@ +/* + * ***** 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. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/curve/editfont_undo.c + * \ingroup edcurve + */ + +#include <stdlib.h> +#include <string.h> +#include <wchar.h> + +#include "MEM_guardedalloc.h" + +#include "BLI_utildefines.h" + +#include "DNA_curve_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" + +#include "BKE_context.h" +#include "BKE_font.h" + +#include "ED_curve.h" +#include "ED_util.h" + +#define USE_ARRAY_STORE + +#ifdef USE_ARRAY_STORE +// # define DEBUG_PRINT +# include "BLI_array_store.h" +# include "BLI_array_store_utils.h" +# include "BLI_listbase.h" +# define ARRAY_CHUNK_SIZE 32 +#endif + +typedef struct UndoFont { + wchar_t *textbuf; + struct CharInfo *textbufinfo; + + int len, pos; + +#ifdef USE_ARRAY_STORE + struct { + BArrayState *textbuf; + BArrayState *textbufinfo; + } store; +#endif +} UndoFont; + + +#ifdef USE_ARRAY_STORE + +/** \name Array Store + * \{ */ + +static struct { + struct BArrayStore_AtSize bs_stride; + int users; + + /* We could have the undo API pass in the previous state, for now store a local list */ + ListBase local_links; + +} uf_arraystore = {NULL}; + +/** + * \param create: When false, only free the arrays. + * This is done since when reading from an undo state, they must be temporarily expanded. + * then discarded afterwards, having this argument avoids having 2x code paths. + */ +static void uf_arraystore_compact_ex( + UndoFont *uf, const UndoFont *uf_ref, + bool create) +{ +#define STATE_COMPACT(uf, id, len) \ + if ((uf)->id) { \ + BLI_assert(create == ((uf)->store.id == NULL)); \ + if (create) { \ + BArrayState *state_reference = uf_ref ? uf_ref->store.id : NULL; \ + const size_t stride = sizeof(*(uf)->id); \ + BArrayStore *bs = BLI_array_store_at_size_ensure(&uf_arraystore.bs_stride, stride, ARRAY_CHUNK_SIZE); \ + (uf)->store.id = BLI_array_store_state_add( \ + bs, (uf)->id, (size_t)(len) * stride, state_reference); \ + } \ + /* keep uf->len for validation */ \ + MEM_freeN((uf)->id); \ + (uf)->id = NULL; \ + } ((void)0) + + STATE_COMPACT(uf, textbuf, uf->len + 1); + STATE_COMPACT(uf, textbufinfo, uf->len + 1); + +#undef STATE_COMPACT + + if (create) { + uf_arraystore.users += 1; + } +} + +/** + * Move data from allocated arrays to de-duplicated states and clear arrays. + */ +static void uf_arraystore_compact(UndoFont *um, const UndoFont *uf_ref) +{ + uf_arraystore_compact_ex(um, uf_ref, true); +} + +static void uf_arraystore_compact_with_info(UndoFont *um, const UndoFont *uf_ref) +{ +#ifdef DEBUG_PRINT + size_t size_expanded_prev, size_compacted_prev; + BLI_array_store_at_size_calc_memory_usage(&uf_arraystore.bs_stride, &size_expanded_prev, &size_compacted_prev); +#endif + + uf_arraystore_compact(um, uf_ref); + +#ifdef DEBUG_PRINT + { + size_t size_expanded, size_compacted; + BLI_array_store_at_size_calc_memory_usage(&uf_arraystore.bs_stride, &size_expanded, &size_compacted); + + const double percent_total = size_expanded ? + (((double)size_compacted / (double)size_expanded) * 100.0) : -1.0; + + size_t size_expanded_step = size_expanded - size_expanded_prev; + size_t size_compacted_step = size_compacted - size_compacted_prev; + const double percent_step = size_expanded_step ? + (((double)size_compacted_step / (double)size_expanded_step) * 100.0) : -1.0; + + printf("overall memory use: %.8f%% of expanded size\n", percent_total); + printf("step memory use: %.8f%% of expanded size\n", percent_step); + } +#endif +} + +/** + * Remove data we only expanded for temporary use. + */ +static void uf_arraystore_expand_clear(UndoFont *um) +{ + uf_arraystore_compact_ex(um, NULL, false); +} + +static void uf_arraystore_expand(UndoFont *uf) +{ +#define STATE_EXPAND(uf, id, len) \ + if ((uf)->store.id) { \ + const size_t stride = sizeof(*(uf)->id); \ + BArrayState *state = (uf)->store.id; \ + size_t state_len; \ + (uf)->id = BLI_array_store_state_data_get_alloc(state, &state_len); \ + BLI_assert((len) == (state_len / stride)); \ + UNUSED_VARS_NDEBUG(stride); \ + } ((void)0) + + STATE_EXPAND(uf, textbuf, uf->len + 1); + STATE_EXPAND(uf, textbufinfo, uf->len + 1); + +#undef STATE_EXPAND +} + +static void uf_arraystore_free(UndoFont *uf) +{ +#define STATE_FREE(uf, id) \ + if ((uf)->store.id) { \ + const size_t stride = sizeof(*(uf)->id); \ + BArrayStore *bs = BLI_array_store_at_size_get(&uf_arraystore.bs_stride, stride); \ + BArrayState *state = (uf)->store.id; \ + BLI_array_store_state_remove(bs, state); \ + (uf)->store.id = NULL; \ + } ((void)0) + + STATE_FREE(uf, textbuf); + STATE_FREE(uf, textbufinfo); + +#undef STATE_FREE + + uf_arraystore.users -= 1; + + BLI_assert(uf_arraystore.users >= 0); + + if (uf_arraystore.users == 0) { +#ifdef DEBUG_PRINT + printf("editfont undo store: freeing all data!\n"); +#endif + + BLI_array_store_at_size_clear(&uf_arraystore.bs_stride); + } + +} + +/** \} */ + +#endif /* USE_ARRAY_STORE */ + +static void undoFont_to_editFont(void *uf_v, void *ecu, void *UNUSED(obdata)) +{ + Curve *cu = (Curve *)ecu; + EditFont *ef = cu->editfont; + const UndoFont *uf = uf_v; + + size_t final_size; + +#ifdef USE_ARRAY_STORE + uf_arraystore_expand(uf_v); +#endif + + final_size = sizeof(wchar_t) * (uf->len + 1); + memcpy(ef->textbuf, uf->textbuf, final_size); + + final_size = sizeof(CharInfo) * (uf->len + 1); + memcpy(ef->textbufinfo, uf->textbufinfo, final_size); + + ef->pos = uf->pos; + ef->len = uf->len; + + ef->selstart = ef->selend = 0; + +#ifdef USE_ARRAY_STORE + uf_arraystore_expand_clear(uf_v); +#endif +} + +static void *editFont_to_undoFont(void *ecu, void *UNUSED(obdata)) +{ + Curve *cu = (Curve *)ecu; + EditFont *ef = cu->editfont; + + UndoFont *uf = MEM_callocN(sizeof(*uf), __func__); + + size_t final_size; + + final_size = sizeof(wchar_t) * (ef->len + 1); + uf->textbuf = MEM_mallocN(final_size, __func__); + memcpy(uf->textbuf, ef->textbuf, final_size); + + final_size = sizeof(CharInfo) * (ef->len + 1); + uf->textbufinfo = MEM_mallocN(final_size, __func__); + memcpy(uf->textbufinfo, ef->textbufinfo, final_size); + + uf->pos = ef->pos; + uf->len = ef->len; + +#ifdef USE_ARRAY_STORE + { + const UndoFont *uf_ref = uf_arraystore.local_links.last ? + ((LinkData *)uf_arraystore.local_links.last)->data : NULL; + + /* add oursrlves */ + BLI_addtail(&uf_arraystore.local_links, BLI_genericNodeN(uf)); + + uf_arraystore_compact_with_info(uf, uf_ref); + } +#endif + + return uf; +} + +static void free_undoFont(void *uf_v) +{ + UndoFont *uf = uf_v; + +#ifdef USE_ARRAY_STORE + { + LinkData *link = BLI_findptr(&uf_arraystore.local_links, uf, offsetof(LinkData, data)); + BLI_remlink(&uf_arraystore.local_links, link); + MEM_freeN(link); + } + uf_arraystore_free(uf); +#endif + + if (uf->textbuf) { + MEM_freeN(uf->textbuf); + } + if (uf->textbufinfo) { + MEM_freeN(uf->textbufinfo); + } + + MEM_freeN(uf); +} + +static void *get_undoFont(bContext *C) +{ + Object *obedit = CTX_data_edit_object(C); + if (obedit && obedit->type == OB_FONT) { + return obedit->data; + } + return NULL; +} + +/* and this is all the undo system needs to know */ +void undo_push_font(bContext *C, const char *name) +{ + undo_editmode_push(C, name, get_undoFont, free_undoFont, undoFont_to_editFont, editFont_to_undoFont, NULL); +} diff --git a/source/blender/editors/gpencil/drawgpencil.c b/source/blender/editors/gpencil/drawgpencil.c index 0329598d711..79a2c494239 100644 --- a/source/blender/editors/gpencil/drawgpencil.c +++ b/source/blender/editors/gpencil/drawgpencil.c @@ -763,6 +763,7 @@ static void gp_draw_stroke_2d(bGPDspoint *points, int totpoints, short thickness } glEnd(); + glShadeModel(GL_SMOOTH); } /* draw debug points of curve on top? (original stroke points) */ diff --git a/source/blender/editors/gpencil/editaction_gpencil.c b/source/blender/editors/gpencil/editaction_gpencil.c index a49b3362155..738496a67c6 100644 --- a/source/blender/editors/gpencil/editaction_gpencil.c +++ b/source/blender/editors/gpencil/editaction_gpencil.c @@ -205,6 +205,36 @@ void ED_gplayer_frames_select_border(bGPDlayer *gpl, float min, float max, short } } +/* select the frames in this layer that occur within the lasso/circle region specified */ +void ED_gplayer_frames_select_region(KeyframeEditData *ked, bGPDlayer *gpl, short tool, short select_mode) +{ + bGPDframe *gpf; + + if (gpl == NULL) + return; + + /* only select frames which are within the region */ + for (gpf = gpl->frames.first; gpf; gpf = gpf->next) { + /* construct a dummy point coordinate to do this testing with */ + float pt[2] = {0}; + + pt[0] = gpf->framenum; + pt[1] = ked->channel_y; + + /* check the necessary regions */ + if (tool == BEZT_OK_CHANNEL_LASSO) { + /* Lasso */ + if (keyframe_region_lasso_test(ked->data, pt)) + gpframe_select(gpf, select_mode); + } + else if (tool == BEZT_OK_CHANNEL_CIRCLE) { + /* Circle */ + if (keyframe_region_circle_test(ked->data, pt)) + gpframe_select(gpf, select_mode); + } + } +} + /* ***************************************** */ /* Frame Editing Tools */ diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c index bd1697b9a54..ac49a51c716 100644 --- a/source/blender/editors/gpencil/gpencil_edit.c +++ b/source/blender/editors/gpencil/gpencil_edit.c @@ -652,7 +652,7 @@ void GPENCIL_OT_active_frame_delete(wmOperatorType *ot) /* identifiers */ ot->name = "Delete Active Frame"; ot->idname = "GPENCIL_OT_active_frame_delete"; - ot->description = "Delete the active frame for the active Grease Pencil datablock"; + ot->description = "Delete the active frame for the active Grease Pencil Layer"; ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -661,6 +661,64 @@ void GPENCIL_OT_active_frame_delete(wmOperatorType *ot) ot->poll = gp_actframe_delete_poll; } +/* **************** Delete All Active Frames ****************** */ + +static int gp_actframe_delete_all_poll(bContext *C) +{ + bGPdata *gpd = ED_gpencil_data_get_active(C); + + /* 1) There must be grease pencil data + * 2) Hopefully some of the layers have stuff we can use + */ + return (gpd && gpd->layers.first); +} + +static int gp_actframe_delete_all_exec(bContext *C, wmOperator *op) +{ + Scene *scene = CTX_data_scene(C); + bool success = false; + + CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers) + { + /* try to get the "active" frame - but only if it actually occurs on this frame */ + bGPDframe *gpf = gpencil_layer_getframe(gpl, CFRA, 0); + + if (gpf == NULL) + continue; + + /* delete it... */ + gpencil_layer_delframe(gpl, gpf); + + /* we successfully modified something */ + success = true; + } + CTX_DATA_END; + + /* updates */ + if (success) { + WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); + return OPERATOR_FINISHED; + } + else { + BKE_report(op->reports, RPT_ERROR, "No active frame(s) to delete"); + return OPERATOR_CANCELLED; + } +} + +void GPENCIL_OT_active_frames_delete_all(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Delete All Active Frames"; + ot->idname = "GPENCIL_OT_active_frames_delete_all"; + ot->description = "Delete the active frame(s) of all editable Grease Pencil layers"; + + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* callbacks */ + ot->exec = gp_actframe_delete_all_exec; + ot->poll = gp_actframe_delete_all_poll; +} + /* ******************* Delete Operator ************************ */ typedef enum eGP_DeleteMode { diff --git a/source/blender/editors/gpencil/gpencil_intern.h b/source/blender/editors/gpencil/gpencil_intern.h index dd28f6ac531..53fb33eeb9b 100644 --- a/source/blender/editors/gpencil/gpencil_intern.h +++ b/source/blender/editors/gpencil/gpencil_intern.h @@ -218,6 +218,7 @@ void GPENCIL_OT_unlock_all(struct wmOperatorType *ot); void GPENCIL_OT_layer_isolate(struct wmOperatorType *ot); void GPENCIL_OT_active_frame_delete(struct wmOperatorType *ot); +void GPENCIL_OT_active_frames_delete_all(struct wmOperatorType *ot); void GPENCIL_OT_convert(struct wmOperatorType *ot); diff --git a/source/blender/editors/gpencil/gpencil_ops.c b/source/blender/editors/gpencil/gpencil_ops.c index 405b673c42b..65ee1122b56 100644 --- a/source/blender/editors/gpencil/gpencil_ops.c +++ b/source/blender/editors/gpencil/gpencil_ops.c @@ -105,7 +105,7 @@ static void ed_keymap_gpencil_general(wmKeyConfig *keyconf) /* Delete Active Frame - For easier video tutorials/review sessions */ /* NOTE: This works even when not in EditMode */ - WM_keymap_add_item(keymap, "GPENCIL_OT_active_frame_delete", XKEY, KM_PRESS, 0, DKEY); + WM_keymap_add_item(keymap, "GPENCIL_OT_active_frames_delete_all", XKEY, KM_PRESS, 0, DKEY); } /* ==================== */ @@ -238,7 +238,7 @@ static void ed_keymap_gpencil_editing(wmKeyConfig *keyconf) WM_keymap_add_item(keymap, "GPENCIL_OT_dissolve", XKEY, KM_PRESS, KM_CTRL, 0); WM_keymap_add_item(keymap, "GPENCIL_OT_dissolve", DELKEY, KM_PRESS, KM_CTRL, 0); - WM_keymap_add_item(keymap, "GPENCIL_OT_active_frame_delete", XKEY, KM_PRESS, KM_SHIFT, 0); + WM_keymap_add_item(keymap, "GPENCIL_OT_active_frames_delete_all", XKEY, KM_PRESS, KM_SHIFT, 0); /* copy + paste */ WM_keymap_add_item(keymap, "GPENCIL_OT_copy", CKEY, KM_PRESS, KM_CTRL, 0); @@ -364,6 +364,7 @@ void ED_operatortypes_gpencil(void) WM_operatortype_append(GPENCIL_OT_layer_isolate); WM_operatortype_append(GPENCIL_OT_active_frame_delete); + WM_operatortype_append(GPENCIL_OT_active_frames_delete_all); WM_operatortype_append(GPENCIL_OT_convert); diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c index fba2f30e715..a570d586f50 100644 --- a/source/blender/editors/gpencil/gpencil_paint.c +++ b/source/blender/editors/gpencil/gpencil_paint.c @@ -97,7 +97,8 @@ typedef enum eGP_StrokeAdd_Result { typedef enum eGPencil_PaintFlags { GP_PAINTFLAG_FIRSTRUN = (1 << 0), /* operator just started */ GP_PAINTFLAG_STROKEADDED = (1 << 1), - GP_PAINTFLAG_V3D_ERASER_DEPTH = (1 << 2) + GP_PAINTFLAG_V3D_ERASER_DEPTH = (1 << 2), + GP_PAINTFLAG_SELECTMASK = (1 << 3), } eGPencil_PaintFlags; @@ -813,18 +814,21 @@ static void gp_stroke_eraser_dostroke(tGPsdata *p, BLI_freelinkN(&gpf->strokes, gps); } else if (gps->totpoints == 1) { - gp_point_to_xy(&p->gsc, gps, gps->points, &pc1[0], &pc1[1]); - - /* do boundbox check first */ - if ((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) { - /* only check if point is inside */ - if (len_v2v2_int(mval, pc1) <= radius) { - /* free stroke */ - // XXX: pressure sensitive eraser should apply here too? - MEM_freeN(gps->points); - if (gps->triangles) - MEM_freeN(gps->triangles); - BLI_freelinkN(&gpf->strokes, gps); + /* only process if it hasn't been masked out... */ + if (!(p->flags & GP_PAINTFLAG_SELECTMASK) || (gps->points->flag & GP_SPOINT_SELECT)) { + gp_point_to_xy(&p->gsc, gps, gps->points, &pc1[0], &pc1[1]); + + /* do boundbox check first */ + if ((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) { + /* only check if point is inside */ + if (len_v2v2_int(mval, pc1) <= radius) { + /* free stroke */ + // XXX: pressure sensitive eraser should apply here too? + MEM_freeN(gps->points); + if (gps->triangles) + MEM_freeN(gps->triangles); + BLI_freelinkN(&gpf->strokes, gps); + } } } } @@ -862,6 +866,11 @@ static void gp_stroke_eraser_dostroke(tGPsdata *p, pt1 = gps->points + i; pt2 = gps->points + i + 1; + /* only process if it hasn't been masked out... */ + if ((p->flags & GP_PAINTFLAG_SELECTMASK) && !(gps->points->flag & GP_SPOINT_SELECT)) + continue; + + /* get coordinates of point in screenspace */ gp_point_to_xy(&p->gsc, gps, pt1, &pc1[0], &pc1[1]); gp_point_to_xy(&p->gsc, gps, pt2, &pc2[0], &pc2[1]); @@ -1199,6 +1208,7 @@ static void gp_session_cleanup(tGPsdata *p) static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode) { Scene *scene = p->scene; + ToolSettings *ts = scene->toolsettings; /* get active layer (or add a new one if non-existent) */ p->gpl = gpencil_layer_getactive(p->gpd); @@ -1242,6 +1252,15 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode) /* Ensure this gets set... */ p->gpf = p->gpl->actframe; + /* Restrict eraser to only affecting selected strokes, if the "selection mask" is on + * (though this is only available in editmode) + */ + if (p->gpd->flag & GP_DATA_STROKE_EDITMODE) { + if (ts->gp_sculpt.flag & GP_BRUSHEDIT_FLAG_SELECT_MASK) { + p->flags |= GP_PAINTFLAG_SELECTMASK; + } + } + if (p->gpf == NULL) { p->status = GP_STATUS_ERROR; //if (G.debug & G_DEBUG) @@ -1251,7 +1270,6 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode) } else { /* Drawing Modes - Add a new frame if needed on the active layer */ - ToolSettings *ts = p->scene->toolsettings; short add_frame_mode; if (ts->gpencil_flags & GP_TOOL_FLAG_RETAIN_LAST) diff --git a/source/blender/editors/gpencil/gpencil_utils.c b/source/blender/editors/gpencil/gpencil_utils.c index b2c6107ab61..d62625baaa4 100644 --- a/source/blender/editors/gpencil/gpencil_utils.c +++ b/source/blender/editors/gpencil/gpencil_utils.c @@ -552,8 +552,8 @@ bool gp_smooth_stroke(bGPDstroke *gps, int i, float inf, bool affect_pressure) } /* Only affect endpoints by a fraction of the normal strength, - * to prevent the stroke from shrinking too much - */ + * to prevent the stroke from shrinking too much + */ if ((i == 0) || (i == gps->totpoints - 1)) { inf *= 0.1f; } diff --git a/source/blender/editors/include/BIF_glutil.h b/source/blender/editors/include/BIF_glutil.h index 0ac5c17a552..d3d2c465d46 100644 --- a/source/blender/editors/include/BIF_glutil.h +++ b/source/blender/editors/include/BIF_glutil.h @@ -94,6 +94,7 @@ void glutil_draw_filled_arc(float start, float angle, float radius, int nsegment * The param must cause only one value to be gotten from GL. */ float glaGetOneFloat(int param); +int glaGetOneInt(int param); /** * Functions like glRasterPos2i, except ensures that the resulting diff --git a/source/blender/editors/include/ED_anim_api.h b/source/blender/editors/include/ED_anim_api.h index fb4897c6532..27e1051a336 100644 --- a/source/blender/editors/include/ED_anim_api.h +++ b/source/blender/editors/include/ED_anim_api.h @@ -608,7 +608,7 @@ typedef enum eAnimUnitConv_Flags { ANIM_UNITCONV_SKIPKNOTS = (1 << 4), /* Scale FCurve i a way it fits to -1..1 space */ ANIM_UNITCONV_NORMALIZE = (1 << 5), - /* Only whennormalization is used: use scale factor from previous run, + /* Only when normalization is used: use scale factor from previous run, * prevents curves from jumping all over the place when tweaking them. */ ANIM_UNITCONV_NORMALIZE_FREEZE = (1 << 6), diff --git a/source/blender/editors/include/ED_buttons.h b/source/blender/editors/include/ED_buttons.h index 9a987d7618c..64c16605dec 100644 --- a/source/blender/editors/include/ED_buttons.h +++ b/source/blender/editors/include/ED_buttons.h @@ -37,6 +37,4 @@ bool ED_texture_context_check_particles(const struct bContext *C); bool ED_texture_context_check_linestyle(const struct bContext *C); bool ED_texture_context_check_others(const struct bContext *C); -void ED_buttons_id_unref(struct SpaceButs *sbuts, const struct ID *id); - #endif /* __ED_BUTTONS_H__ */ diff --git a/source/blender/editors/include/ED_curve.h b/source/blender/editors/include/ED_curve.h index 278e3f97ba7..859d45e9c86 100644 --- a/source/blender/editors/include/ED_curve.h +++ b/source/blender/editors/include/ED_curve.h @@ -72,8 +72,7 @@ void ED_curve_deselect_all(struct EditNurb *editnurb); void ED_curve_select_all(struct EditNurb *editnurb); void ED_curve_select_swap(struct EditNurb *editnurb, bool hide_handles); -/* editfont.h */ -void undo_push_font(struct bContext *C, const char *name); +/* editfont.c */ void ED_curve_editfont_load(struct Object *obedit); void ED_curve_editfont_make(struct Object *obedit); void ED_curve_editfont_free(struct Object *obedit); @@ -89,6 +88,9 @@ bool ED_curve_active_center(struct Curve *cu, float center[3]); bool ED_curve_editfont_select_pick(struct bContext *C, const int mval[2], bool extend, bool deselect, bool toggle); +/* editfont_undo.c */ +void undo_push_font(struct bContext *C, const char *name); + #if 0 /* debug only */ void printknots(struct Object *obedit); diff --git a/source/blender/editors/include/ED_fileselect.h b/source/blender/editors/include/ED_fileselect.h index 186a2a26825..92acfa6c1d2 100644 --- a/source/blender/editors/include/ED_fileselect.h +++ b/source/blender/editors/include/ED_fileselect.h @@ -104,11 +104,12 @@ void ED_fileselect_clear(struct wmWindowManager *wm, struct ScrArea *sa, struct void ED_fileselect_exit(struct wmWindowManager *wm, struct ScrArea *sa, struct SpaceFile *sfile); -int ED_file_extension_icon(const char *relname); +int ED_path_extension_type(const char *path); +int ED_file_extension_icon(const char *path); void ED_file_read_bookmarks(void); -void ED_file_change_dir(struct bContext *C, const bool checkdir); +void ED_file_change_dir(struct bContext *C); /* File menu stuff */ diff --git a/source/blender/editors/include/ED_gpencil.h b/source/blender/editors/include/ED_gpencil.h index 255827db373..de5ab80a88f 100644 --- a/source/blender/editors/include/ED_gpencil.h +++ b/source/blender/editors/include/ED_gpencil.h @@ -42,6 +42,7 @@ struct bGPDlayer; struct bGPDframe; struct bGPDstroke; struct bAnimContext; +struct KeyframeEditData; struct PointerRNA; struct wmWindowManager; struct wmKeyConfig; @@ -120,6 +121,7 @@ void ED_gplayer_make_cfra_list(struct bGPDlayer *gpl, ListBase *elems, bool only bool ED_gplayer_frame_select_check(struct bGPDlayer *gpl); void ED_gplayer_frame_select_set(struct bGPDlayer *gpl, short mode); void ED_gplayer_frames_select_border(struct bGPDlayer *gpl, float min, float max, short select_mode); +void ED_gplayer_frames_select_region(struct KeyframeEditData *ked, struct bGPDlayer *gpl, short tool, short select_mode); void ED_gpencil_select_frames(struct bGPDlayer *gpl, short select_mode); void ED_gpencil_select_frame(struct bGPDlayer *gpl, int selx, short select_mode); diff --git a/source/blender/editors/include/ED_keyframes_edit.h b/source/blender/editors/include/ED_keyframes_edit.h index fae3e3677a0..c0eb88cd982 100644 --- a/source/blender/editors/include/ED_keyframes_edit.h +++ b/source/blender/editors/include/ED_keyframes_edit.h @@ -45,14 +45,21 @@ struct Scene; /* bezt validation */ typedef enum eEditKeyframes_Validate { + /* Frame range */ BEZT_OK_FRAME = 1, BEZT_OK_FRAMERANGE, + /* Selection status */ BEZT_OK_SELECTED, + /* Values (y-val) only */ BEZT_OK_VALUE, BEZT_OK_VALUERANGE, + /* For graph editor keyframes (2D tests) */ BEZT_OK_REGION, BEZT_OK_REGION_LASSO, BEZT_OK_REGION_CIRCLE, + /* Only for keyframes a certain Dopesheet channel */ + BEZT_OK_CHANNEL_LASSO, + BEZT_OK_CHANNEL_CIRCLE, } eEditKeyframes_Validate; /* ------------ */ @@ -97,20 +104,20 @@ typedef enum eEditKeyframes_Mirror { } eEditKeyframes_Mirror; /* use with BEZT_OK_REGION_LASSO */ -struct KeyframeEdit_LassoData { - const rctf *rectf_scaled; +typedef struct KeyframeEdit_LassoData { + rctf *rectf_scaled; const rctf *rectf_view; const int (*mcords)[2]; int mcords_tot; -}; +} KeyframeEdit_LassoData; /* use with BEZT_OK_REGION_CIRCLE */ -struct KeyframeEdit_CircleData { - const rctf *rectf_scaled; +typedef struct KeyframeEdit_CircleData { + rctf *rectf_scaled; const rctf *rectf_view; float mval[2]; float radius_squared; -}; +} KeyframeEdit_CircleData; /* ************************************************ */ @@ -157,7 +164,8 @@ typedef struct KeyframeEditData { /* current iteration data */ struct FCurve *fcu; /* F-Curve that is being iterated over */ int curIndex; /* index of current keyframe being iterated over */ - + float channel_y; /* y-position of midpoint of the channel (for the dopesheet) */ + /* flags */ eKeyframeVertOk curflags; /* current flags for the keyframe we're reached in the iteration process */ eKeyframeIterFlags iterflags; /* settings for iteration process */ @@ -258,6 +266,18 @@ short bezt_to_cfraelem(KeyframeEditData *ked, struct BezTriple *bezt); */ void bezt_remap_times(KeyframeEditData *ked, struct BezTriple *bezt); +/* ------ 1.5-D Region Testing Uitls (Lasso/Circle Select) ------- */ +/* XXX: These are temporary, until we can unify GP/Mask Keyframe handling and standard FCurve Keyframe handling */ + +bool keyframe_region_lasso_test( + const KeyframeEdit_LassoData *data_lasso, + const float xy[2]); + +bool keyframe_region_circle_test( + const KeyframeEdit_CircleData *data_circle, + const float xy[2]); + + /* ************************************************ */ /* Destructive Editing API (keyframes_general.c) */ diff --git a/source/blender/editors/include/ED_mask.h b/source/blender/editors/include/ED_mask.h index 1f13b46ff2a..2ab788d5e2a 100644 --- a/source/blender/editors/include/ED_mask.h +++ b/source/blender/editors/include/ED_mask.h @@ -35,6 +35,7 @@ struct bContext; struct wmKeyConfig; struct MaskLayer; struct MaskLayerShape; +struct KeyframeEditData; /* mask_edit.c */ void ED_mask_get_size(struct ScrArea *sa, int *width, int *height); @@ -80,6 +81,7 @@ void ED_masklayer_make_cfra_list(struct MaskLayer *masklay, ListBase *elems, boo bool ED_masklayer_frame_select_check(struct MaskLayer *masklay); void ED_masklayer_frame_select_set(struct MaskLayer *masklay, short mode); void ED_masklayer_frames_select_border(struct MaskLayer *masklay, float min, float max, short select_mode); +void ED_masklayer_frames_select_region(struct KeyframeEditData *ked, struct MaskLayer *masklay, short tool, short select_mode); void ED_mask_select_frames(struct MaskLayer *masklay, short select_mode); void ED_mask_select_frame(struct MaskLayer *masklay, int selx, short select_mode); diff --git a/source/blender/editors/include/ED_node.h b/source/blender/editors/include/ED_node.h index 7fe9a0c320c..f7b9d6b4f9e 100644 --- a/source/blender/editors/include/ED_node.h +++ b/source/blender/editors/include/ED_node.h @@ -103,8 +103,6 @@ void ED_node_set_active(struct Main *bmain, struct bNodeTree *ntree, struct bNod void ED_node_composite_job(const struct bContext *C, struct bNodeTree *nodetree, struct Scene *scene_owner); -void ED_node_id_unref(struct SpaceNode *snode, const ID *id); - /* node_ops.c */ void ED_operatormacros_node(void); diff --git a/source/blender/editors/include/ED_outliner.h b/source/blender/editors/include/ED_outliner.h index af4af8e2f5d..73ee2542247 100644 --- a/source/blender/editors/include/ED_outliner.h +++ b/source/blender/editors/include/ED_outliner.h @@ -27,10 +27,4 @@ #ifndef __ED_OUTLINER_H__ #define __ED_OUTLINER_H__ -struct ID; -struct SpaceOops; - -/* Used to check whether a given texture context is valid in current context. */ -void ED_outliner_id_unref(struct SpaceOops *so, const struct ID *id); - #endif /* __ED_OUTLINER_H__ */ diff --git a/source/blender/editors/include/ED_physics.h b/source/blender/editors/include/ED_physics.h index 584e9a92bb6..fed842c969e 100644 --- a/source/blender/editors/include/ED_physics.h +++ b/source/blender/editors/include/ED_physics.h @@ -45,12 +45,12 @@ int PE_hair_poll(struct bContext *C); int PE_poll_view3d(struct bContext *C); /* rigidbody_object.c */ -bool ED_rigidbody_object_add(struct Scene *scene, struct Object *ob, int type, struct ReportList *reports); -void ED_rigidbody_object_remove(struct Scene *scene, struct Object *ob); +bool ED_rigidbody_object_add(struct Main *bmain, struct Scene *scene, struct Object *ob, int type, struct ReportList *reports); +void ED_rigidbody_object_remove(struct Main *bmain, struct Scene *scene, struct Object *ob); /* rigidbody_constraint.c */ -bool ED_rigidbody_constraint_add(struct Scene *scene, struct Object *ob, int type, struct ReportList *reports); -void ED_rigidbody_constraint_remove(struct Scene *scene, struct Object *ob); +bool ED_rigidbody_constraint_add(struct Main *bmain, struct Scene *scene, struct Object *ob, int type, struct ReportList *reports); +void ED_rigidbody_constraint_remove(struct Main *bmain, struct Scene *scene, struct Object *ob); /* operators */ void ED_operatortypes_physics(void); diff --git a/source/blender/editors/include/ED_transform_snap_object_context.h b/source/blender/editors/include/ED_transform_snap_object_context.h index baf4ed574cf..7944b434057 100644 --- a/source/blender/editors/include/ED_transform_snap_object_context.h +++ b/source/blender/editors/include/ED_transform_snap_object_context.h @@ -75,7 +75,7 @@ SnapObjectContext *ED_transform_snap_object_context_create( SnapObjectContext *ED_transform_snap_object_context_create_view3d( struct Main *bmain, struct Scene *scene, int flag, /* extra args for view3d */ - struct ARegion *ar, struct View3D *v3d); + const struct ARegion *ar, const struct View3D *v3d); void ED_transform_snap_object_context_destroy(SnapObjectContext *sctx); /* callbacks to filter how snap works */ diff --git a/source/blender/editors/include/ED_util.h b/source/blender/editors/include/ED_util.h index f143ea478c6..b6b80b93e0b 100644 --- a/source/blender/editors/include/ED_util.h +++ b/source/blender/editors/include/ED_util.h @@ -43,7 +43,7 @@ void ED_editors_exit(struct bContext *C); bool ED_editors_flush_edits(const struct bContext *C, bool for_render); -void ED_spacedata_id_unref(struct SpaceLink *sl, const struct ID *id); +void ED_spacedata_id_remap(struct ScrArea *sa, struct SpaceLink *sl, struct ID *old_id, struct ID *new_id); void ED_OT_flush_edits(struct wmOperatorType *ot); diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h index 54b4acec864..8bd8a14030f 100644 --- a/source/blender/editors/include/ED_view3d.h +++ b/source/blender/editors/include/ED_view3d.h @@ -208,10 +208,12 @@ eV3DProjStatus ED_view3d_project_float_global(const struct ARegion *ar, const fl eV3DProjStatus ED_view3d_project_float_object(const struct ARegion *ar, const float co[3], float r_co[2], const eV3DProjTest flag); float ED_view3d_calc_zfac(const struct RegionView3D *rv3d, const float co[3], bool *r_flip); -bool ED_view3d_win_to_ray(const struct ARegion *ar, struct View3D *v3d, const float mval[2], - float ray_start[3], float ray_normal[3], const bool do_clip); -bool ED_view3d_win_to_ray_ex(const struct ARegion *ar, struct View3D *v3d, const float mval[2], - float r_ray_co[3], float r_ray_normal[3], float r_ray_start[3], bool do_clip); +bool ED_view3d_win_to_ray( + const struct ARegion *ar, const struct View3D *v3d, const float mval[2], + float ray_start[3], float ray_normal[3], const bool do_clip); +bool ED_view3d_win_to_ray_ex( + const struct ARegion *ar, const struct View3D *v3d, const float mval[2], + float r_ray_co[3], float r_ray_normal[3], float r_ray_start[3], bool do_clip); void ED_view3d_global_to_vector(const struct RegionView3D *rv3d, const float coord[3], float vec[3]); void ED_view3d_win_to_3d(const struct ARegion *ar, const float depth_pt[3], const float mval[2], float out[3]); void ED_view3d_win_to_3d_int(const struct ARegion *ar, const float depth_pt[3], const int mval[2], float out[3]); @@ -403,4 +405,6 @@ void ED_view3d_shade_update(struct Main *bmain, struct Scene *scene, struct View #define V3D_IS_ZBUF(v3d) \ (((v3d)->flag & V3D_ZBUF_SELECT) && ((v3d)->drawtype > OB_WIRE)) +void ED_view3d_id_remap(struct View3D *v3d, const struct ID *old_id, struct ID *new_id); + #endif /* __ED_VIEW3D_H__ */ diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index 9aad340d2fb..a623f5cfb9c 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -1020,12 +1020,18 @@ bool UI_context_copy_to_selected_list( /* Helpers for Operators */ uiBut *UI_context_active_but_get(const struct bContext *C); -void UI_context_active_but_prop_get(const struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA **prop, int *index); +void UI_context_active_but_prop_get( + const struct bContext *C, + struct PointerRNA *r_ptr, struct PropertyRNA **r_prop, int *r_index); void UI_context_active_but_prop_handle(struct bContext *C); struct wmOperator *UI_context_active_operator_get(const struct bContext *C); void UI_context_update_anim_flag(const struct bContext *C); -void UI_context_active_but_prop_get_filebrowser(const struct bContext *C, struct PointerRNA *r_ptr, struct PropertyRNA **r_prop, bool *r_is_undo); -void UI_context_active_but_prop_get_templateID(struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA **prop); +void UI_context_active_but_prop_get_filebrowser( + const struct bContext *C, + struct PointerRNA *r_ptr, struct PropertyRNA **r_prop, bool *r_is_undo); +void UI_context_active_but_prop_get_templateID( + struct bContext *C, + struct PointerRNA *r_ptr, struct PropertyRNA **r_prop); /* Styled text draw */ void UI_fontstyle_set(const struct uiFontStyle *fs); diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c index fac1267cc62..ba7240be5d8 100644 --- a/source/blender/editors/interface/interface.c +++ b/source/blender/editors/interface/interface.c @@ -2576,9 +2576,11 @@ static void ui_set_but_soft_range(uiBut *but) } else if (but->poin && (but->pointype & UI_BUT_POIN_TYPES)) { float value = ui_but_value_get(but); - CLAMP(value, but->hardmin, but->hardmax); - but->softmin = min_ff(but->softmin, value); - but->softmax = max_ff(but->softmax, value); + if (isfinite(value)) { + CLAMP(value, but->hardmin, but->hardmax); + but->softmin = min_ff(but->softmin, value); + but->softmax = max_ff(but->softmax, value); + } } else { BLI_assert(0); @@ -4323,7 +4325,7 @@ uiBut *uiDefSearchBut(uiBlock *block, void *arg, int retval, int icon, int maxle /** - * \param sfunc, bfunc: both get it as \a arg. + * \param search_func, bfunc: both get it as \a arg. * \param arg: user value, * \param active: when set, button opens with this item visible and selected. */ diff --git a/source/blender/editors/interface/interface_draw.c b/source/blender/editors/interface/interface_draw.c index 8fbc545cb77..72a6a04feec 100644 --- a/source/blender/editors/interface/interface_draw.c +++ b/source/blender/editors/interface/interface_draw.c @@ -181,7 +181,6 @@ void UI_draw_roundbox_shade_x( coldown[1] = max_ff(0.0f, color[1] + shadedown); coldown[2] = max_ff(0.0f, color[2] + shadedown); - glShadeModel(GL_SMOOTH); glBegin(mode); /* start with corner right-bottom */ @@ -260,7 +259,6 @@ void UI_draw_roundbox_shade_x( } glEnd(); - glShadeModel(GL_FLAT); } /* linear vertical shade within button or in outline */ @@ -291,7 +289,6 @@ void UI_draw_roundbox_shade_y( colRight[1] = max_ff(0.0f, color[1] + shadeRight); colRight[2] = max_ff(0.0f, color[2] + shadeRight); - glShadeModel(GL_SMOOTH); glBegin(mode); /* start with corner right-bottom */ @@ -367,7 +364,6 @@ void UI_draw_roundbox_shade_y( } glEnd(); - glShadeModel(GL_FLAT); } /* plain antialiased unfilled rectangle */ @@ -531,7 +527,6 @@ static void histogram_draw_one( } else { /* under the curve */ - glShadeModel(GL_FLAT); glBegin(GL_TRIANGLE_STRIP); glVertex2f(x, y); glVertex2f(x, y + (data[0] * h)); @@ -1087,7 +1082,6 @@ void ui_draw_but_COLORBAND(uiBut *but, uiWidgetColors *UNUSED(wcol), const rcti GPU_basic_shader_bind(GPU_SHADER_USE_COLOR); /* layer: color ramp */ - glShadeModel(GL_FLAT); glEnable(GL_BLEND); CBData *cbd = coba->data; @@ -1133,7 +1127,6 @@ void ui_draw_but_COLORBAND(uiBut *but, uiWidgetColors *UNUSED(wcol), const rcti glEnd(); glDisable(GL_BLEND); - glShadeModel(GL_SMOOTH); /* layer: box outline */ glColor4f(0.0, 0.0, 0.0, 1.0); @@ -1212,9 +1205,8 @@ void ui_draw_but_UNITVEC(uiBut *but, uiWidgetColors *wcol, const rcti *rect) qobj = gluNewQuadric(); gluQuadricDrawStyle(qobj, GLU_FILL); - glShadeModel(GL_SMOOTH); + GPU_basic_shader_bind(GPU_basic_shader_bound_options()); gluSphere(qobj, 100.0, 32, 24); - glShadeModel(GL_FLAT); gluDeleteQuadric(qobj); glEndList(); @@ -1545,10 +1537,12 @@ void ui_draw_but_TRACKPREVIEW(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wc BLI_rctf_size_x(&rect), BLI_rctf_size_y(&rect)); + GPU_basic_shader_bind_enable(GPU_SHADER_LINE); + for (int a = 0; a < 2; a++) { if (a == 1) { - glLineStipple(3, 0xaaaa); - glEnable(GL_LINE_STIPPLE); + GPU_basic_shader_bind_enable(GPU_SHADER_STIPPLE); + GPU_basic_shader_line_stipple(3, 0xAAAA); UI_ThemeColor(TH_SEL_MARKER); } else { @@ -1562,9 +1556,10 @@ void ui_draw_but_TRACKPREVIEW(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wc glVertex2f(0.0f, 10.0f); glEnd(); } + + GPU_basic_shader_bind_disable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE); } - glDisable(GL_LINE_STIPPLE); glPopMatrix(); ok = true; @@ -1677,7 +1672,6 @@ static void ui_shadowbox(float minx, float miny, float maxx, float maxy, float s void UI_draw_box_shadow(unsigned char alpha, float minx, float miny, float maxx, float maxy) { glEnable(GL_BLEND); - glShadeModel(GL_SMOOTH); glBegin(GL_QUADS); @@ -1689,7 +1683,6 @@ void UI_draw_box_shadow(unsigned char alpha, float minx, float miny, float maxx, glEnd(); glDisable(GL_BLEND); - glShadeModel(GL_FLAT); } diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index 5b8b8ae5bdb..e0b8003d8a9 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -6014,20 +6014,15 @@ static int ui_do_but_CURVE(bContext *C, uiBlock *block, uiBut *but, uiHandleButt CurveMapping *cumap = (CurveMapping *)but->poin; CurveMap *cuma = cumap->cm + cumap->cur; CurveMapPoint *cmp; - float fx, fy, zoomx, zoomy, offsx, offsy; - float dist, mindist = 200.0f; // 14 pixels radius + const float m_xy[2] = {mx, my}; + float dist_min_sq = SQUARE(14.0f); /* 14 pixels radius */ int sel = -1; - zoomx = BLI_rctf_size_x(&but->rect) / BLI_rctf_size_x(&cumap->curr); - zoomy = BLI_rctf_size_y(&but->rect) / BLI_rctf_size_y(&cumap->curr); - offsx = cumap->curr.xmin; - offsy = cumap->curr.ymin; - if (event->ctrl) { - fx = ((float)mx - but->rect.xmin) / zoomx + offsx; - fy = ((float)my - but->rect.ymin) / zoomy + offsy; + float f_xy[2]; + BLI_rctf_transform_pt_v(&cumap->curr, &but->rect, f_xy, m_xy); - curvemap_insert(cuma, fx, fy); + curvemap_insert(cuma, f_xy[0], f_xy[1]); curvemapping_changed(cumap, false); changed = true; } @@ -6035,33 +6030,37 @@ static int ui_do_but_CURVE(bContext *C, uiBlock *block, uiBut *but, uiHandleButt /* check for selecting of a point */ cmp = cuma->curve; /* ctrl adds point, new malloc */ for (a = 0; a < cuma->totpoint; a++) { - fx = but->rect.xmin + zoomx * (cmp[a].x - offsx); - fy = but->rect.ymin + zoomy * (cmp[a].y - offsy); - dist = (fx - mx) * (fx - mx) + (fy - my) * (fy - my); - if (dist < mindist) { + float f_xy[2]; + BLI_rctf_transform_pt_v(&but->rect, &cumap->curr, f_xy, &cmp[a].x); + const float dist_sq = len_squared_v2v2(m_xy, f_xy); + if (dist_sq < dist_min_sq) { sel = a; - mindist = dist; + dist_min_sq = dist_sq; } } if (sel == -1) { int i; + float f_xy[2], f_xy_prev[2]; /* if the click didn't select anything, check if it's clicked on the * curve itself, and if so, add a point */ - fx = ((float)mx - but->rect.xmin) / zoomx + offsx; - fy = ((float)my - but->rect.ymin) / zoomy + offsy; - cmp = cuma->table; - /* loop through the curve segment table and find what's near the mouse. - * 0.05 is kinda arbitrary, but seems to be what works nicely. */ - for (i = 0; i <= CM_TABLE; i++) { - if ((fabsf(fx - cmp[i].x) < 0.05f) && - (fabsf(fy - cmp[i].y) < 0.05f)) - { - - curvemap_insert(cuma, fx, fy); + BLI_rctf_transform_pt_v(&but->rect, &cumap->curr, f_xy, &cmp[0].x); + + /* with 160px height 8px should translate to the old 0.05 coefficient at no zoom */ + dist_min_sq = SQUARE(8.0f); + + /* loop through the curve segment table and find what's near the mouse. */ + for (i = 1; i <= CM_TABLE; i++) { + copy_v2_v2(f_xy_prev, f_xy); + BLI_rctf_transform_pt_v(&but->rect, &cumap->curr, f_xy, &cmp[i].x); + + if (dist_squared_to_line_segment_v2(m_xy, f_xy_prev, f_xy) < dist_min_sq) { + BLI_rctf_transform_pt_v(&cumap->curr, &but->rect, f_xy, m_xy); + + curvemap_insert(cuma, f_xy[0], f_xy[1]); curvemapping_changed(cumap, false); changed = true; @@ -6070,10 +6069,11 @@ static int ui_do_but_CURVE(bContext *C, uiBlock *block, uiBut *but, uiHandleButt cmp = cuma->curve; /* find newly added point and make it 'sel' */ - for (a = 0; a < cuma->totpoint; a++) - if (cmp[a].x == fx) + for (a = 0; a < cuma->totpoint; a++) { + if (cmp[a].x == f_xy[0]) { sel = a; - + } + } break; } } @@ -6981,13 +6981,15 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent * !IS_EVENT_MOD(event, shift, oskey) && (event->val == KM_PRESS)) { - if (event->alt) - ui_but_anim_remove_driver(C); - else if (event->ctrl) - ui_but_anim_add_driver(C); - - ED_region_tag_redraw(data->region); - + /* quick check to prevent this opening within the popup menu its self */ + if (!ELEM(NULL, but->rnapoin.data, but->rnaprop)) { + if (event->alt) + ui_but_anim_remove_driver(C); + else if (event->ctrl) + ui_but_anim_add_driver(C); + + ED_region_tag_redraw(data->region); + } return WM_UI_HANDLER_BREAK; } /* handle keyingsets */ @@ -8011,20 +8013,21 @@ uiBut *UI_context_active_but_get(const struct bContext *C) } /* helper function for insert keyframe, reset to default, etc operators */ -void UI_context_active_but_prop_get(const bContext *C, struct PointerRNA *ptr, struct PropertyRNA **prop, int *index) +void UI_context_active_but_prop_get( + const bContext *C, + struct PointerRNA *r_ptr, struct PropertyRNA **r_prop, int *r_index) { uiBut *activebut = ui_context_rna_button_active(C); - memset(ptr, 0, sizeof(*ptr)); - if (activebut && activebut->rnapoin.data) { - *ptr = activebut->rnapoin; - *prop = activebut->rnaprop; - *index = activebut->rnaindex; + *r_ptr = activebut->rnapoin; + *r_prop = activebut->rnaprop; + *r_index = activebut->rnaindex; } else { - *prop = NULL; - *index = 0; + memset(r_ptr, 0, sizeof(*r_ptr)); + *r_prop = NULL; + *r_index = 0; } } @@ -8436,6 +8439,7 @@ static int ui_handle_list_event(bContext *C, const wmEvent *event, ARegion *ar, uiListDyn *dyn_data; int retval = WM_UI_HANDLER_CONTINUE; int type = event->type, val = event->val; + bool redraw = false; int mx, my; ui_list = listbox->custom_data; @@ -8525,7 +8529,7 @@ static int ui_handle_list_event(bContext *C, const wmEvent *event, ARegion *ar, ui_apply_but_undo(listbox); ui_list->flag |= UILST_SCROLL_TO_ACTIVE_ITEM; - ED_region_tag_redraw(ar); + redraw = true; } retval = WM_UI_HANDLER_BREAK; } @@ -8537,8 +8541,8 @@ static int ui_handle_list_event(bContext *C, const wmEvent *event, ARegion *ar, ui_list->list_grip += (type == WHEELUPMOUSE) ? -1 : 1; ui_list->flag |= UILST_SCROLL_TO_ACTIVE_ITEM; - ED_region_tag_redraw(ar); + redraw = true; retval = WM_UI_HANDLER_BREAK; } else if (ELEM(type, WHEELUPMOUSE, WHEELDOWNMOUSE)) { @@ -8546,13 +8550,22 @@ static int ui_handle_list_event(bContext *C, const wmEvent *event, ARegion *ar, /* list template will clamp */ ui_list->list_scroll += (type == WHEELUPMOUSE) ? -1 : 1; - ED_region_tag_redraw(ar); - + redraw = true; retval = WM_UI_HANDLER_BREAK; } } } + if (redraw) { + if (listbox->block->flag & UI_BLOCK_POPUP) { + /* popups need special refreshing */ + ED_region_tag_refresh_ui(ar); + } + else { + ED_region_tag_redraw(ar); + } + } + return retval; } @@ -9794,11 +9807,28 @@ static int ui_handle_menus_recursive( } else { uiBlock *block = menu->region->uiblocks.first; + uiBut *listbox = ui_list_find_mouse_over(menu->region, event); - if (block->flag & UI_BLOCK_RADIAL) + if (block->flag & UI_BLOCK_RADIAL) { retval = ui_pie_handler(C, event, menu); - else if (event->type == LEFTMOUSE || event->val != KM_DBL_CLICK) - retval = ui_handle_menu_event(C, event, menu, level, is_parent_inside, is_parent_menu, is_floating); + } + else if (event->type == LEFTMOUSE || event->val != KM_DBL_CLICK) { + bool handled = false; + + if (listbox) { + int retval_test = ui_handle_list_event(C, event, menu->region, listbox); + if (retval_test != WM_UI_HANDLER_CONTINUE) { + retval = retval_test; + handled = true; + } + } + + if (handled == false) { + retval = ui_handle_menu_event( + C, event, menu, level, + is_parent_inside, is_parent_menu, is_floating); + } + } } } diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c index 0a25a8fb3c6..6dc60f1d70b 100644 --- a/source/blender/editors/interface/interface_icons.c +++ b/source/blender/editors/interface/interface_icons.c @@ -368,7 +368,6 @@ static void vicon_disclosure_tri_right_draw(int x, int y, int w, int UNUSED(h), viconutil_set_point(pts[1], cx - d2, cy - d); viconutil_set_point(pts[2], cx + d2, cy); - glShadeModel(GL_SMOOTH); glBegin(GL_TRIANGLES); glColor4f(0.8f, 0.8f, 0.8f, alpha); glVertex2iv(pts[0]); @@ -376,7 +375,6 @@ static void vicon_disclosure_tri_right_draw(int x, int y, int w, int UNUSED(h), glColor4f(0.3f, 0.3f, 0.3f, alpha); glVertex2iv(pts[2]); glEnd(); - glShadeModel(GL_FLAT); glColor4f(0.0f, 0.0f, 0.0f, 1); viconutil_draw_lineloop_smooth(pts, 3); @@ -395,13 +393,11 @@ static void vicon_small_tri_right_draw(int x, int y, int w, int UNUSED(h), float glColor4f(0.2f, 0.2f, 0.2f, alpha); - glShadeModel(GL_SMOOTH); glBegin(GL_TRIANGLES); glVertex2iv(pts[0]); glVertex2iv(pts[1]); glVertex2iv(pts[2]); glEnd(); - glShadeModel(GL_FLAT); } static void vicon_disclosure_tri_down_draw(int x, int y, int w, int UNUSED(h), float alpha) @@ -415,7 +411,6 @@ static void vicon_disclosure_tri_down_draw(int x, int y, int w, int UNUSED(h), f viconutil_set_point(pts[1], cx - d, cy + d2); viconutil_set_point(pts[2], cx, cy - d2); - glShadeModel(GL_SMOOTH); glBegin(GL_TRIANGLES); glColor4f(0.8f, 0.8f, 0.8f, alpha); glVertex2iv(pts[0]); @@ -423,7 +418,6 @@ static void vicon_disclosure_tri_down_draw(int x, int y, int w, int UNUSED(h), f glColor4f(0.3f, 0.3f, 0.3f, alpha); glVertex2iv(pts[2]); glEnd(); - glShadeModel(GL_FLAT); glColor4f(0.0f, 0.0f, 0.0f, 1); viconutil_draw_lineloop_smooth(pts, 3); @@ -1220,8 +1214,13 @@ static void icon_draw_rect(float x, float y, int w, int h, float UNUSED(aspect), glaDrawPixelsSafe(draw_x, draw_y, draw_w, draw_h, draw_w, GL_RGBA, GL_UNSIGNED_BYTE, rect); } else { + int bound_options; + GPU_BASIC_SHADER_DISABLE_AND_STORE(bound_options); + glRasterPos2f(draw_x, draw_y); glDrawPixels(draw_w, draw_h, GL_RGBA, GL_UNSIGNED_BYTE, rect); + + GPU_BASIC_SHADER_ENABLE_AND_RESTORE(bound_options); } if (ima) diff --git a/source/blender/editors/interface/interface_panel.c b/source/blender/editors/interface/interface_panel.c index 62b373c58c8..79961eae79d 100644 --- a/source/blender/editors/interface/interface_panel.c +++ b/source/blender/editors/interface/interface_panel.c @@ -1763,12 +1763,10 @@ void UI_panel_category_draw_all(ARegion *ar, const char *category_id_active) ui_panel_category_draw_tab(GL_LINE_STRIP, rct->xmin - px, rct->ymin - px, rct->xmax - px, rct->ymax + px, tab_curve_radius, roundboxtype, true, true, NULL); /* tab highlight (3d look) */ - glShadeModel(GL_SMOOTH); glColor3ubv(is_active ? theme_col_tab_highlight : theme_col_tab_highlight_inactive); ui_panel_category_draw_tab(GL_LINE_STRIP, rct->xmin, rct->ymin, rct->xmax, rct->ymax, tab_curve_radius, roundboxtype, true, false, is_active ? theme_col_back : theme_col_tab_inactive); - glShadeModel(GL_FLAT); } /* tab blackline */ diff --git a/source/blender/editors/interface/interface_style.c b/source/blender/editors/interface/interface_style.c index 423c48e5f55..8b41302b5bb 100644 --- a/source/blender/editors/interface/interface_style.c +++ b/source/blender/editors/interface/interface_style.c @@ -417,6 +417,11 @@ void uiStyleInit(void) blf_mono_font = -1; } + if (blf_mono_font_render != -1) { + BLF_unload_id(blf_mono_font_render); + blf_mono_font_render = -1; + } + font = U.uifonts.first; /* default builtin */ @@ -516,7 +521,12 @@ void uiStyleInit(void) BLF_size(blf_mono_font, 12 * U.pixelsize, 72); - /* second for rendering else we get threading problems */ + /** + * Second for rendering else we get threading problems, + * + * \note This isn't good that the render font depends on the preferences, + * keep for now though, since without this there is no way to display many unicode chars. + */ if (blf_mono_font_render == -1) blf_mono_font_render = BLF_load_mem_unique("monospace", monofont_ttf, monofont_size); diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index a3b04e1c9bc..7f276bcc634 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -232,15 +232,17 @@ static uiBlock *id_search_menu(bContext *C, ARegion *ar, void *arg_litem) /* This is for browsing and editing the ID-blocks used */ /* for new/open operators */ -void UI_context_active_but_prop_get_templateID(bContext *C, PointerRNA *ptr, PropertyRNA **prop) +void UI_context_active_but_prop_get_templateID( + bContext *C, + PointerRNA *r_ptr, PropertyRNA **r_prop) { TemplateID *template; ARegion *ar = CTX_wm_region(C); uiBlock *block; uiBut *but; - memset(ptr, 0, sizeof(*ptr)); - *prop = NULL; + memset(r_ptr, 0, sizeof(*r_ptr)); + *r_prop = NULL; if (!ar) return; @@ -251,8 +253,8 @@ void UI_context_active_but_prop_get_templateID(bContext *C, PointerRNA *ptr, Pro if ((but->flag & (UI_BUT_LAST_ACTIVE | UI_ACTIVE))) { if (but->func_argN) { template = but->func_argN; - *ptr = template->ptr; - *prop = template->prop; + *r_ptr = template->ptr; + *r_prop = template->prop; return; } } @@ -2818,7 +2820,7 @@ static void uilist_prepare( layoutdata->end_idx = min_ii(layoutdata->start_idx + rows * columns, len); } -static void uilist_resize_update_cb(bContext *UNUSED(C), void *arg1, void *UNUSED(arg2)) +static void uilist_resize_update_cb(bContext *C, void *arg1, void *UNUSED(arg2)) { uiList *ui_list = arg1; uiListDyn *dyn_data = ui_list->dyn_data; @@ -2831,6 +2833,9 @@ static void uilist_resize_update_cb(bContext *UNUSED(C), void *arg1, void *UNUSE dyn_data->resize_prev += diff * UI_UNIT_Y; ui_list->flag |= UILST_SCROLL_TO_ACTIVE_ITEM; } + + /* In case uilist is in popup, we need special refreshing */ + ED_region_tag_refresh_ui(CTX_wm_menu(C)); } static void *uilist_item_use_dynamic_tooltip(PointerRNA *itemptr, const char *propname) diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c index 19e0b55374e..5098e701638 100644 --- a/source/blender/editors/interface/interface_widgets.c +++ b/source/blender/editors/interface/interface_widgets.c @@ -712,8 +712,7 @@ static void widgetbase_draw(uiWidgetBase *wtb, uiWidgetColors *wcol) unsigned char *col_pt = col_array; shadecolors4(col1, col2, wcol->inner, wcol->shadetop, wcol->shadedown); - - glShadeModel(GL_SMOOTH); + for (a = 0; a < wtb->totvert; a++, col_pt += 4) { round_box_shade_col4_r(col_pt, col1, col2, wtb->inner_uv[a][wtb->draw_shadedir ? 1 : 0]); } @@ -725,8 +724,6 @@ static void widgetbase_draw(uiWidgetBase *wtb, uiWidgetColors *wcol) glDrawArrays(GL_POLYGON, 0, wtb->totvert); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_COLOR_ARRAY); - - glShadeModel(GL_FLAT); } } @@ -2311,8 +2308,6 @@ static void ui_draw_but_HSVCIRCLE(uiBut *but, uiWidgetColors *wcol, const rcti * ui_color_picker_to_rgb(0.0f, 0.0f, hsv[2], colcent, colcent + 1, colcent + 2); - glShadeModel(GL_SMOOTH); - glBegin(GL_TRIANGLE_FAN); glColor3fv(colcent); glVertex2f(centx, centy); @@ -2330,8 +2325,6 @@ static void ui_draw_but_HSVCIRCLE(uiBut *but, uiWidgetColors *wcol, const rcti * } glEnd(); - glShadeModel(GL_FLAT); - /* fully rounded outline */ glPushMatrix(); glTranslatef(centx, centy, 0.0f); @@ -2363,7 +2356,6 @@ void ui_draw_gradient(const rcti *rect, const float hsv[3], const int type, cons float col1[4][3]; /* right half, rect bottom to top */ /* draw series of gouraud rects */ - glShadeModel(GL_SMOOTH); switch (type) { case UI_GRAD_SV: @@ -2486,8 +2478,6 @@ void ui_draw_gradient(const rcti *rect, const float hsv[3], const int type, cons } glEnd(); } - - glShadeModel(GL_FLAT); } bool ui_but_is_colorpicker_display_space(uiBut *but) diff --git a/source/blender/editors/io/io_collada.c b/source/blender/editors/io/io_collada.c index b1ca95efe04..b74c4b5f526 100644 --- a/source/blender/editors/io/io_collada.c +++ b/source/blender/editors/io/io_collada.c @@ -400,7 +400,7 @@ static int wm_collada_import_exec(bContext *C, wmOperator *op) C, filename, import_units, find_chains, - auto_connect, + auto_connect, fix_orientation, min_chain_length)) { @@ -482,7 +482,7 @@ void WM_OT_collada_import(wmOperatorType *ot) RNA_def_boolean(ot->srna, "auto_connect", 0, "Auto Connect", - "set use_connect for parent bones which have exactly one child bone"); + "Set use_connect for parent bones which have exactly one child bone"); RNA_def_int(ot->srna, "min_chain_length", diff --git a/source/blender/editors/mask/mask_draw.c b/source/blender/editors/mask/mask_draw.c index 9a8382b2136..2b4f94a37ef 100644 --- a/source/blender/editors/mask/mask_draw.c +++ b/source/blender/editors/mask/mask_draw.c @@ -51,6 +51,8 @@ #include "BIF_gl.h" #include "BIF_glutil.h" +#include "GPU_basic_shader.h" + #include "UI_resources.h" #include "UI_view2d.h" @@ -100,10 +102,10 @@ static void draw_spline_parents(MaskLayer *UNUSED(masklay), MaskSpline *spline) if (!spline->tot_point) return; - glColor3ub(0, 0, 0); - glEnable(GL_LINE_STIPPLE); - glLineStipple(1, 0xAAAA); + GPU_basic_shader_bind_enable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE); + GPU_basic_shader_line_stipple(1, 0xAAAA); + glColor3ub(0, 0, 0); glBegin(GL_LINES); for (i = 0; i < spline->tot_point; i++) { @@ -121,7 +123,7 @@ static void draw_spline_parents(MaskLayer *UNUSED(masklay), MaskSpline *spline) glEnd(); - glDisable(GL_LINE_STIPPLE); + GPU_basic_shader_bind_disable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE); } #endif @@ -455,7 +457,8 @@ static void mask_draw_curve_type(const bContext *C, MaskSpline *spline, float (* case MASK_DT_DASH: default: - glEnable(GL_LINE_STIPPLE); + GPU_basic_shader_bind_enable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE); + GPU_basic_shader_line_stipple(3, 0xAAAA); #ifdef USE_XOR glEnable(GL_COLOR_LOGIC_OP); @@ -463,7 +466,6 @@ static void mask_draw_curve_type(const bContext *C, MaskSpline *spline, float (* #endif mask_color_active_tint(rgb_tmp, rgb_spline, is_active); glColor4ubv(rgb_tmp); - glLineStipple(3, 0xaaaa); glEnableClientState(GL_VERTEX_ARRAY); glVertexPointer(2, GL_FLOAT, 0, points); glDrawArrays(draw_method, 0, tot_point); @@ -473,10 +475,10 @@ static void mask_draw_curve_type(const bContext *C, MaskSpline *spline, float (* #endif mask_color_active_tint(rgb_tmp, rgb_black, is_active); glColor4ubv(rgb_tmp); - glLineStipple(3, 0x5555); + GPU_basic_shader_line_stipple(3, 0x5555); glDrawArrays(draw_method, 0, tot_point); - glDisable(GL_LINE_STIPPLE); + GPU_basic_shader_bind_disable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE); break; diff --git a/source/blender/editors/mask/mask_editaction.c b/source/blender/editors/mask/mask_editaction.c index bcf9ee5c88d..16147bdc7f8 100644 --- a/source/blender/editors/mask/mask_editaction.c +++ b/source/blender/editors/mask/mask_editaction.c @@ -201,6 +201,36 @@ void ED_masklayer_frames_select_border(MaskLayer *masklay, float min, float max, } } +/* select the frames in this layer that occur within the lasso/circle region specified */ +void ED_masklayer_frames_select_region(KeyframeEditData *ked, MaskLayer *masklay, short tool, short select_mode) +{ + MaskLayerShape *masklay_shape; + + if (masklay == NULL) + return; + + /* only select frames which are within the region */ + for (masklay_shape = masklay->splines_shapes.first; masklay_shape; masklay_shape = masklay_shape->next) { + /* construct a dummy point coordinate to do this testing with */ + float pt[2] = {0}; + + pt[0] = masklay_shape->frame; + pt[1] = ked->channel_y; + + /* check the necessary regions */ + if (tool == BEZT_OK_CHANNEL_LASSO) { + /* Lasso */ + if (keyframe_region_lasso_test(ked->data, pt)) + masklayshape_select(masklay_shape, select_mode); + } + else if (tool == BEZT_OK_CHANNEL_CIRCLE) { + /* Circle */ + if (keyframe_region_circle_test(ked->data, pt)) + masklayshape_select(masklay_shape, select_mode); + } + } +} + /* ***************************************** */ /* Frame Editing Tools */ diff --git a/source/blender/editors/mesh/editface.c b/source/blender/editors/mesh/editface.c index 01be8f848aa..c4e87614732 100644 --- a/source/blender/editors/mesh/editface.c +++ b/source/blender/editors/mesh/editface.c @@ -53,6 +53,7 @@ #include "WM_api.h" #include "WM_types.h" +#include "GPU_draw.h" #include "GPU_buffers.h" /* own include */ @@ -433,7 +434,7 @@ int do_paintface_box_select(ViewContext *vc, rcti *rect, bool select, bool exten if (ENDIAN_ORDER == B_ENDIAN) { IMB_convert_rgba_to_abgr(ibuf); } - WM_framebuffer_to_index_array(ibuf->rect, size[0] * size[1]); + GPU_select_to_index_array(ibuf->rect, size[0] * size[1]); a = size[0] * size[1]; while (a--) { diff --git a/source/blender/editors/mesh/editmesh_bevel.c b/source/blender/editors/mesh/editmesh_bevel.c index 242cbf79a83..302ca407add 100644 --- a/source/blender/editors/mesh/editmesh_bevel.c +++ b/source/blender/editors/mesh/editmesh_bevel.c @@ -58,26 +58,45 @@ #define MVAL_PIXEL_MARGIN 5.0f +/* until implement profile = 0 case, need to clamp somewhat above zero */ +#define PROFILE_HARD_MIN 0.15f + +#define SEGMENTS_HARD_MAX 1000 + +/* which value is mouse movement and numeric input controlling? */ +#define OFFSET_VALUE 0 +#define OFFSET_VALUE_PERCENT 1 +#define PROFILE_VALUE 2 +#define SEGMENTS_VALUE 3 +#define NUM_VALUE_KINDS 4 + +static const char *value_rna_name[NUM_VALUE_KINDS] = {"offset", "offset", "profile", "segments"}; +static const float value_clamp_min[NUM_VALUE_KINDS] = {0.0f, 0.0f, PROFILE_HARD_MIN, 1.0f}; +static const float value_clamp_max[NUM_VALUE_KINDS] = {1e6, 100.0f, 1.0f, SEGMENTS_HARD_MAX}; +static const float value_start[NUM_VALUE_KINDS] = {0.0f, 0.0f, 0.5f, 1.0f}; +static const float value_scale_per_inch[NUM_VALUE_KINDS] = { 0.0f, 100.0f, 1.0f, 4.0f}; + typedef struct { BMEditMesh *em; - float initial_length; - float pixel_size; /* use when mouse input is interpreted as spatial distance */ + float initial_length[NUM_VALUE_KINDS]; + float scale[NUM_VALUE_KINDS]; + NumInput num_input[NUM_VALUE_KINDS]; + float shift_value[NUM_VALUE_KINDS]; /* The current value when shift is pressed. Negative when shift not active. */ bool is_modal; - NumInput num_input; - float shift_factor; /* The current factor when shift is pressed. Negative when shift not active. */ /* modal only */ float mcenter[2]; BMBackup mesh_backup; void *draw_handle_pixel; short twtype; + short value_mode; /* Which value does mouse movement and numeric input affect? */ float segments; /* Segments as float so smooth mouse pan works in small increments */ } BevelData; static void edbm_bevel_update_header(bContext *C, wmOperator *op) { const char *str = IFACE_("Confirm: (Enter/LMB), Cancel: (Esc/RMB), Mode: %s (M), Clamp Overlap: %s (C), " - "Vertex Only: %s (V), Offset: %s, Segments: %d"); + "Vertex Only: %s (V), Profile Control: %s (P), Offset: %s, Segments: %d, Profile: %.3f"); char msg[UI_MAX_DRAW_STR]; ScrArea *sa = CTX_wm_area(C); @@ -89,8 +108,8 @@ static void edbm_bevel_update_header(bContext *C, wmOperator *op) const char *type_str; PropertyRNA *prop = RNA_struct_find_property(op->ptr, "offset_type"); - if (hasNumInput(&opdata->num_input)) { - outputNumInput(&opdata->num_input, offset_str, &sce->unit); + if (hasNumInput(&opdata->num_input[OFFSET_VALUE])) { + outputNumInput(&opdata->num_input[OFFSET_VALUE], offset_str, &sce->unit); } else { BLI_snprintf(offset_str, NUM_STR_REP_LEN, "%f", RNA_float_get(op->ptr, "offset")); @@ -101,7 +120,8 @@ static void edbm_bevel_update_header(bContext *C, wmOperator *op) BLI_snprintf(msg, sizeof(msg), str, type_str, WM_bool_as_string(RNA_boolean_get(op->ptr, "clamp_overlap")), WM_bool_as_string(RNA_boolean_get(op->ptr, "vertex_only")), - offset_str, RNA_int_get(op->ptr, "segments")); + WM_bool_as_string(opdata->value_mode == PROFILE_VALUE), + offset_str, RNA_int_get(op->ptr, "segments"), RNA_float_get(op->ptr, "profile")); ED_area_headerprint(sa, msg); } @@ -113,6 +133,8 @@ static bool edbm_bevel_init(bContext *C, wmOperator *op, const bool is_modal) Scene *scene = CTX_data_scene(C); BMEditMesh *em = BKE_editmesh_from_object(obedit); BevelData *opdata; + float pixels_per_inch; + int i; if (em->bm->totvertsel == 0) { return false; @@ -122,13 +144,25 @@ static bool edbm_bevel_init(bContext *C, wmOperator *op, const bool is_modal) opdata->em = em; opdata->is_modal = is_modal; - opdata->shift_factor = -1.0f; - - initNumInput(&opdata->num_input); - opdata->num_input.idx_max = 0; - opdata->num_input.val_flag[0] |= NUM_NO_NEGATIVE; - opdata->num_input.unit_sys = scene->unit.system; - opdata->num_input.unit_type[0] = B_UNIT_NONE; /* Not sure this is a factor or a unit? */ + opdata->value_mode = OFFSET_VALUE; + pixels_per_inch = U.dpi * U.pixelsize; + + for (i = 0; i < NUM_VALUE_KINDS; i++) { + opdata->shift_value[i] = -1.0f; + /* note: scale for OFFSET_VALUE will get overwritten in edbm_bevel_invoke */ + opdata->scale[i] = value_scale_per_inch[i] / pixels_per_inch; + + initNumInput(&opdata->num_input[i]); + opdata->num_input[i].idx_max = 0; + opdata->num_input[i].val_flag[0] |= NUM_NO_NEGATIVE; + if (i == SEGMENTS_VALUE) { + opdata->num_input[i].val_flag[0] |= NUM_NO_FRACTION | NUM_NO_ZERO; + } + if (i == OFFSET_VALUE) { + opdata->num_input[i].unit_sys = scene->unit.system; + } + opdata->num_input[i].unit_type[0] = B_UNIT_NONE; /* Not sure this is a factor or a unit? */ + } /* avoid the cost of allocating a bm copy */ if (is_modal) { @@ -136,7 +170,8 @@ static bool edbm_bevel_init(bContext *C, wmOperator *op, const bool is_modal) ARegion *ar = CTX_wm_region(C); opdata->mesh_backup = EDBM_redo_state_store(em); - opdata->draw_handle_pixel = ED_region_draw_cb_activate(ar->type, ED_region_draw_mouse_line_cb, opdata->mcenter, REGION_DRAW_POST_PIXEL); + opdata->draw_handle_pixel = ED_region_draw_cb_activate(ar->type, ED_region_draw_mouse_line_cb, + opdata->mcenter, REGION_DRAW_POST_PIXEL); G.moving = G_TRANSFORM_EDIT; if (v3d) { @@ -167,13 +202,15 @@ static bool edbm_bevel_calc(wmOperator *op) EDBM_redo_state_restore(opdata->mesh_backup, em, false); } - if (em->ob) + if (em->ob) { material = CLAMPIS(material, -1, em->ob->totcol - 1); + } EDBM_op_init(em, &bmop, op, "bevel geom=%hev offset=%f segments=%i vertex_only=%b offset_type=%i profile=%f clamp_overlap=%b " "material=%i loop_slide=%b", - BM_ELEM_SELECT, offset, segments, vertex_only, offset_type, profile, clamp_overlap, material, loop_slide); + BM_ELEM_SELECT, offset, segments, vertex_only, offset_type, profile, + clamp_overlap, material, loop_slide); BMO_op_exec(em->bm, &bmop); @@ -185,8 +222,9 @@ static bool edbm_bevel_calc(wmOperator *op) } /* no need to de-select existing geometry */ - if (!EDBM_op_finish(em, &bmop, op, true)) + if (!EDBM_op_finish(em, &bmop, op, true)) { return false; + } EDBM_mesh_normals_update(opdata->em); @@ -250,12 +288,37 @@ static int edbm_bevel_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } +static void edbm_bevel_calc_initial_length(wmOperator *op, const wmEvent *event, bool mode_changed) +{ + BevelData *opdata; + float mlen[2], len, value, sc, st; + int vmode; + + opdata = op->customdata; + mlen[0] = opdata->mcenter[0] - event->mval[0]; + mlen[1] = opdata->mcenter[1] - event->mval[1]; + len = len_v2(mlen); + vmode = opdata->value_mode; + if (mode_changed) { + /* If current value is not default start value, adjust len so that + * the scaling and offset in edbm_bevel_mouse_set_value will + * start at current value */ + value = (vmode == SEGMENTS_VALUE) ? + opdata->segments : RNA_float_get(op->ptr, value_rna_name[vmode]); + sc = opdata->scale[vmode]; + st = value_start[vmode]; + if (value != value_start[vmode]) { + len = (st + sc * (len - MVAL_PIXEL_MARGIN) - value) / sc; + } + } + opdata->initial_length[opdata->value_mode] = len; +} + static int edbm_bevel_invoke(bContext *C, wmOperator *op, const wmEvent *event) { /* TODO make modal keymap (see fly mode) */ RegionView3D *rv3d = CTX_wm_region_view3d(C); BevelData *opdata; - float mlen[2]; float center_3d[3]; if (!edbm_bevel_init(C, op, true)) { @@ -270,10 +333,10 @@ static int edbm_bevel_invoke(bContext *C, wmOperator *op, const wmEvent *event) * ideally this will never happen and should be checked for above */ opdata->mcenter[0] = opdata->mcenter[1] = 0; } - mlen[0] = opdata->mcenter[0] - event->mval[0]; - mlen[1] = opdata->mcenter[1] - event->mval[1]; - opdata->initial_length = len_v2(mlen); - opdata->pixel_size = rv3d ? ED_view3d_pixel_size(rv3d, center_3d) : 1.0f; + edbm_bevel_calc_initial_length(op, event, false); + + /* for OFFSET_VALUE only, the scale is the size of a pixel under the mouse in 3d space */ + opdata->scale[OFFSET_VALUE] = rv3d ? ED_view3d_pixel_size(rv3d, center_3d) : 1.0f; edbm_bevel_update_header(C, op); @@ -287,59 +350,72 @@ static int edbm_bevel_invoke(bContext *C, wmOperator *op, const wmEvent *event) return OPERATOR_RUNNING_MODAL; } -static float edbm_bevel_mval_factor(wmOperator *op, const wmEvent *event) +static void edbm_bevel_mouse_set_value(wmOperator *op, const wmEvent *event) { BevelData *opdata = op->customdata; - bool use_dist; - bool is_percent; + int vmode = opdata->value_mode; float mdiff[2]; - float factor; + float value; mdiff[0] = opdata->mcenter[0] - event->mval[0]; mdiff[1] = opdata->mcenter[1] - event->mval[1]; - is_percent = (RNA_enum_get(op->ptr, "offset_type") == BEVEL_AMT_PERCENT); - use_dist = !is_percent; - factor = ((len_v2(mdiff) - MVAL_PIXEL_MARGIN) - opdata->initial_length) * opdata->pixel_size; + value = ((len_v2(mdiff) - MVAL_PIXEL_MARGIN) - opdata->initial_length[vmode]); + + /* Scale according to value mode */ + value = value_start[vmode] + value * opdata->scale[vmode]; /* Fake shift-transform... */ if (event->shift) { - if (opdata->shift_factor < 0.0f) { - opdata->shift_factor = RNA_float_get(op->ptr, "offset"); - if (is_percent) { - opdata->shift_factor /= 100.0f; - } + if (opdata->shift_value[vmode] < 0.0f) { + opdata->shift_value[vmode] = (vmode == SEGMENTS_VALUE) ? + opdata->segments : RNA_float_get(op->ptr, value_rna_name[vmode]); } - factor = (factor - opdata->shift_factor) * 0.1f + opdata->shift_factor; + value = (value - opdata->shift_value[vmode]) * 0.1f + opdata->shift_value[vmode]; } - else if (opdata->shift_factor >= 0.0f) { - opdata->shift_factor = -1.0f; + else if (opdata->shift_value[vmode] >= 0.0f) { + opdata->shift_value[vmode] = -1.0f; } - /* clamp differently based on distance/factor */ - if (use_dist) { - if (factor < 0.0f) factor = 0.0f; + /* clamp accordingto value mode, and store value back */ + CLAMP(value, value_clamp_min[vmode], value_clamp_max[vmode]); + if (vmode == SEGMENTS_VALUE) { + opdata->segments = value; + RNA_int_set(op->ptr, "segments", (int)(value + 0.5f)); } else { - CLAMP(factor, 0.0f, 1.0f); - if (is_percent) { - factor *= 100.0f; - } + RNA_float_set(op->ptr, value_rna_name[vmode], value); } +} - return factor; +static void edbm_bevel_numinput_set_value(wmOperator *op) +{ + BevelData *opdata = op->customdata; + float value; + int vmode; + + vmode = opdata->value_mode; + value = (vmode == SEGMENTS_VALUE) ? + opdata->segments : RNA_float_get(op->ptr, value_rna_name[vmode]); + applyNumInput(&opdata->num_input[vmode], &value); + CLAMP(value, value_clamp_min[vmode], value_clamp_max[vmode]); + if (vmode == SEGMENTS_VALUE) { + opdata->segments = value; + RNA_int_set(op->ptr, "segments", (int)value); + } + else { + RNA_float_set(op->ptr, value_rna_name[vmode], value); + } } static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event) { BevelData *opdata = op->customdata; - const bool has_numinput = hasNumInput(&opdata->num_input); + const bool has_numinput = hasNumInput(&opdata->num_input[opdata->value_mode]); /* Modal numinput active, try to handle numeric inputs first... */ - if (event->val == KM_PRESS && has_numinput && handleNumInput(C, &opdata->num_input, event)) { - float value = RNA_float_get(op->ptr, "offset"); - applyNumInput(&opdata->num_input, &value); - RNA_float_set(op->ptr, "offset", value); + if (event->val == KM_PRESS && has_numinput && handleNumInput(C, &opdata->num_input[opdata->value_mode], event)) { + edbm_bevel_numinput_set_value(op); edbm_bevel_calc(op); edbm_bevel_update_header(C, op); return OPERATOR_RUNNING_MODAL; @@ -354,9 +430,7 @@ static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event) case MOUSEMOVE: if (!has_numinput) { - const float factor = edbm_bevel_mval_factor(op, event); - RNA_float_set(op->ptr, "offset", factor); - + edbm_bevel_mouse_set_value(op, event); edbm_bevel_calc(op); edbm_bevel_update_header(C, op); handled = true; @@ -426,12 +500,18 @@ static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event) if (type > BEVEL_AMT_PERCENT) { type = BEVEL_AMT_OFFSET; } + if (opdata->value_mode == OFFSET_VALUE && type == BEVEL_AMT_PERCENT) + opdata->value_mode = OFFSET_VALUE_PERCENT; + else if (opdata->value_mode == OFFSET_VALUE_PERCENT && type != BEVEL_AMT_PERCENT) + opdata->value_mode = OFFSET_VALUE; RNA_property_enum_set(op->ptr, prop, type); } - /* Update factor accordingly to new offset_type. */ - if (!has_numinput) { - RNA_float_set(op->ptr, "offset", edbm_bevel_mval_factor(op, event)); - } + /* Update offset accordingly to new offset_type. */ + if (!has_numinput && + (opdata->value_mode == OFFSET_VALUE || opdata->value_mode == OFFSET_VALUE_PERCENT)) + { + edbm_bevel_mouse_set_value(op, event); + } edbm_bevel_calc(op); edbm_bevel_update_header(C, op); handled = true; @@ -448,6 +528,28 @@ static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event) edbm_bevel_update_header(C, op); handled = true; break; + case PKEY: + if (event->val == KM_RELEASE) + break; + if (opdata->value_mode == PROFILE_VALUE) { + opdata->value_mode = OFFSET_VALUE; + } + else { + opdata->value_mode = PROFILE_VALUE; + } + edbm_bevel_calc_initial_length(op, event, true); + break; + case SKEY: + if (event->val == KM_RELEASE) + break; + if (opdata->value_mode == SEGMENTS_VALUE) { + opdata->value_mode = OFFSET_VALUE; + } + else { + opdata->value_mode = SEGMENTS_VALUE; + } + edbm_bevel_calc_initial_length(op, event, true); + break; case VKEY: if (event->val == KM_RELEASE) break; @@ -464,10 +566,8 @@ static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event) } /* Modal numinput inactive, try to handle numeric inputs last... */ - if (!handled && event->val == KM_PRESS && handleNumInput(C, &opdata->num_input, event)) { - float value = RNA_float_get(op->ptr, "offset"); - applyNumInput(&opdata->num_input, &value); - RNA_float_set(op->ptr, "offset", value); + if (!handled && event->val == KM_PRESS && handleNumInput(C, &opdata->num_input[opdata->value_mode], event)) { + edbm_bevel_numinput_set_value(op); edbm_bevel_calc(op); edbm_bevel_update_header(C, op); return OPERATOR_RUNNING_MODAL; @@ -518,11 +618,13 @@ void MESH_OT_bevel(wmOperatorType *ot) RNA_def_enum(ot->srna, "offset_type", offset_type_items, 0, "Amount Type", "What distance Amount measures"); prop = RNA_def_float(ot->srna, "offset", 0.0f, -1e6f, 1e6f, "Amount", "", 0.0f, 1.0f); RNA_def_property_float_array_funcs_runtime(prop, NULL, NULL, mesh_ot_bevel_offset_range_func); - RNA_def_int(ot->srna, "segments", 1, 1, 50, "Segments", "Segments for curved edge", 1, 8); - RNA_def_float(ot->srna, "profile", 0.5f, 0.15f, 1.0f, "Profile", "Controls profile shape (0.5 = round)", 0.15f, 1.0f); + RNA_def_int(ot->srna, "segments", 1, 1, SEGMENTS_HARD_MAX, "Segments", "Segments for curved edge", 1, 8); + RNA_def_float(ot->srna, "profile", 0.5f, PROFILE_HARD_MIN, 1.0f, "Profile", + "Controls profile shape (0.5 = round)", PROFILE_HARD_MIN, 1.0f); RNA_def_boolean(ot->srna, "vertex_only", false, "Vertex Only", "Bevel only vertices"); RNA_def_boolean(ot->srna, "clamp_overlap", false, "Clamp Overlap", - "Do not allow beveled edges/vertices to overlap each other"); + "Do not allow beveled edges/vertices to overlap each other"); RNA_def_boolean(ot->srna, "loop_slide", true, "Loop Slide", "Prefer slide along edge to even widths"); - RNA_def_int(ot->srna, "material", -1, -1, INT_MAX, "Material", "Material for bevel faces (-1 means use adjacent faces)", -1, 100); + RNA_def_int(ot->srna, "material", -1, -1, INT_MAX, "Material", + "Material for bevel faces (-1 means use adjacent faces)", -1, 100); } diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c index 0fd56fbcc4e..a84b8d9dcc8 100644 --- a/source/blender/editors/mesh/editmesh_knife.c +++ b/source/blender/editors/mesh/editmesh_knife.c @@ -2283,7 +2283,7 @@ static void knife_make_face_cuts(KnifeTool_OpData *kcd, BMFace *f, ListBase *kfe BMEdge **edge_array = BLI_array_alloca(edge_array, edge_array_len); - /* point to knife edges we've created edges in, edge_array aligned */ + /* point to knife edges we've created edges in, edge_array aligned */ KnifeEdge **kfe_array = BLI_array_alloca(kfe_array, edge_array_len); BLI_assert(BLI_gset_size(kcd->edgenet.edge_visit) == 0); diff --git a/source/blender/editors/mesh/editmesh_rip.c b/source/blender/editors/mesh/editmesh_rip.c index 9e71e646b1a..8868827a11f 100644 --- a/source/blender/editors/mesh/editmesh_rip.c +++ b/source/blender/editors/mesh/editmesh_rip.c @@ -463,7 +463,7 @@ static void edbm_tagged_loop_pairs_do_fill_faces(BMesh *bm, UnorderedLoopPair *u if ((ulp->l_pair[0] && ulp->l_pair[1]) && (ulp->l_pair[0]->e != ulp->l_pair[1]->e)) { - /* time has come to make a face! */ + /* time has come to make a face! */ BMVert *v_shared = BM_edge_share_vert(ulp->l_pair[0]->e, ulp->l_pair[1]->e); BMFace *f, *f_example = ulp->l_pair[0]->f; BMLoop *l_iter; diff --git a/source/blender/editors/mesh/editmesh_select.c b/source/blender/editors/mesh/editmesh_select.c index 84ae35fae6e..5d5731a7e16 100644 --- a/source/blender/editors/mesh/editmesh_select.c +++ b/source/blender/editors/mesh/editmesh_select.c @@ -2453,7 +2453,7 @@ static void select_linked_delimit_begin(BMesh *bm, int delimit) const bool is_walk_ok = ( (select_linked_delimit_test(e, delimit, &delimit_data) == false)); - BMO_elem_flag_set(bm, e, BMO_ELE_TAG, is_walk_ok); + BMO_edge_flag_set(bm, e, BMO_ELE_TAG, is_walk_ok); } } } @@ -2496,7 +2496,7 @@ static int edbm_select_linked_exec(bContext *C, wmOperator *op) if (delimit) { BMEdge *e; BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) { - if (!BMO_elem_flag_test(bm, e, BMO_ELE_TAG)) { + if (!BMO_edge_flag_test(bm, e, BMO_ELE_TAG)) { BM_elem_flag_disable(e->v1, BM_ELEM_TAG); BM_elem_flag_disable(e->v2, BM_ELEM_TAG); } @@ -2552,7 +2552,7 @@ static int edbm_select_linked_exec(bContext *C, wmOperator *op) BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) { BM_elem_flag_set( e, BM_ELEM_TAG, - (BM_elem_flag_test(e, BM_ELEM_SELECT) && BMO_elem_flag_test(bm, e, BMO_ELE_TAG))); + (BM_elem_flag_test(e, BM_ELEM_SELECT) && BMO_edge_flag_test(bm, e, BMO_ELE_TAG))); } } else { diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c index efe179790da..9f1602ccfaf 100644 --- a/source/blender/editors/mesh/editmesh_tools.c +++ b/source/blender/editors/mesh/editmesh_tools.c @@ -2910,7 +2910,7 @@ static int edbm_knife_cut_exec(bContext *C, wmOperator *op) } } - BMO_elem_flag_set(bm, be, ELE_EDGE_CUT, is_cut); + BMO_edge_flag_set(bm, be, ELE_EDGE_CUT, is_cut); } @@ -2982,7 +2982,9 @@ static Base *mesh_separate_tagged(Main *bmain, Scene *scene, Base *base_old, BMe Object *obedit = base_old->object; BMesh *bm_new; - bm_new = BM_mesh_create(&bm_mesh_allocsize_default); + bm_new = BM_mesh_create( + &bm_mesh_allocsize_default, + &((struct BMeshCreateParams){.use_toolflags = true,})); BM_mesh_elem_toolflags_ensure(bm_new); /* needed for 'duplicate' bmo */ CustomData_copy(&bm_old->vdata, &bm_new->vdata, CD_MASK_BMESH, CD_CALLOC, 0); @@ -3294,7 +3296,9 @@ static int edbm_separate_exec(bContext *C, wmOperator *op) BMesh *bm_old = NULL; int retval_iter = 0; - bm_old = BM_mesh_create(&bm_mesh_allocsize_default); + bm_old = BM_mesh_create( + &bm_mesh_allocsize_default, + &((struct BMeshCreateParams){.use_toolflags = true,})); BM_mesh_bm_from_me(bm_old, me, (&(struct BMeshFromMeshParams){0})); diff --git a/source/blender/editors/mesh/editmesh_undo.c b/source/blender/editors/mesh/editmesh_undo.c index b9d3fd6c8be..b44fbc3ce45 100644 --- a/source/blender/editors/mesh/editmesh_undo.c +++ b/source/blender/editors/mesh/editmesh_undo.c @@ -49,7 +49,7 @@ # endif # include "BLI_array_store.h" -# include "BLI_math_base.h" +# include "BLI_array_store_utils.h" /* check on best size later... */ # define ARRAY_CHUNK_SIZE 256 @@ -89,8 +89,7 @@ typedef struct UndoMesh { #ifdef USE_ARRAY_STORE /* NULL arrays are considered empty */ - struct { - /* most data is stored as 'custom' data */ + struct { /* most data is stored as 'custom' data */ BArrayCustomData *vdata, *edata, *ldata, *pdata; BArrayState **keyblocks; BArrayState *mselect; @@ -105,8 +104,7 @@ typedef struct UndoMesh { * \{ */ static struct { - BArrayStore **bs_all; - int bs_all_len; + struct BArrayStore_AtSize bs_stride; int users; /* We could have the undo API pass in the previous state, for now store a local list */ @@ -118,57 +116,6 @@ static struct { } um_arraystore = {NULL}; -static BArrayStore *array_store_at_size_ensure(const int stride) -{ - if (um_arraystore.bs_all_len < stride) { - um_arraystore.bs_all_len = stride; - um_arraystore.bs_all = MEM_recallocN(um_arraystore.bs_all, sizeof(*um_arraystore.bs_all) * stride); - } - BArrayStore **bs_p = &um_arraystore.bs_all[stride - 1]; - - if ((*bs_p) == NULL) { -#if 0 - unsigned int chunk_count = ARRAY_CHUNK_SIZE; -#else - /* calculate best chunk-count to fit a power of two */ - unsigned int chunk_count = ARRAY_CHUNK_SIZE; - { - unsigned int size = chunk_count * stride; - size = power_of_2_max_u(size); - size = MEM_SIZE_OPTIMAL(size); - chunk_count = size / stride; - } -#endif - - (*bs_p) = BLI_array_store_create(stride, chunk_count); - } - return *bs_p; -} - -static BArrayStore *array_store_at_size_get(const int stride) -{ - BLI_assert(stride > 0 && stride <= um_arraystore.bs_all_len); - return um_arraystore.bs_all[stride - 1]; -} - -#ifdef DEBUG_PRINT -static void um_arraystore_memory_usage(size_t *r_size_expanded, size_t *r_size_compacted) -{ - size_t size_compacted = 0; - size_t size_expanded = 0; - for (int i = 0; i < um_arraystore.bs_all_len; i++) { - BArrayStore *bs = um_arraystore.bs_all[i]; - if (bs) { - size_compacted += BLI_array_store_calc_size_compacted_get(bs); - size_expanded += BLI_array_store_calc_size_expanded_get(bs); - } - } - - *r_size_expanded = size_expanded; - *r_size_compacted = size_compacted; -} -#endif - static void um_arraystore_cd_compact( struct CustomData *cdata, const size_t data_len, bool create, @@ -194,7 +141,7 @@ static void um_arraystore_cd_compact( } const int stride = CustomData_sizeof(type); - BArrayStore *bs = create ? array_store_at_size_ensure(stride) : NULL; + BArrayStore *bs = create ? BLI_array_store_at_size_ensure(&um_arraystore.bs_stride, stride, ARRAY_CHUNK_SIZE) : NULL; const int layer_len = layer_end - layer_start; if (create) { @@ -299,7 +246,7 @@ static void um_arraystore_cd_free(BArrayCustomData *bcd) while (bcd) { BArrayCustomData *bcd_next = bcd->next; const int stride = CustomData_sizeof(bcd->type); - BArrayStore *bs = array_store_at_size_get(stride); + BArrayStore *bs = BLI_array_store_at_size_get(&um_arraystore.bs_stride, stride); for (int i = 0; i < bcd->states_len; i++) { if (bcd->states[i]) { BLI_array_store_state_remove(bs, bcd->states[i]); @@ -328,7 +275,7 @@ static void um_arraystore_compact_ex( if (me->key && me->key->totkey) { const size_t stride = me->key->elemsize; - BArrayStore *bs = create ? array_store_at_size_ensure(stride) : NULL; + BArrayStore *bs = create ? BLI_array_store_at_size_ensure(&um_arraystore.bs_stride, stride, ARRAY_CHUNK_SIZE) : NULL; if (create) { um->store.keyblocks = MEM_mallocN(me->key->totkey * sizeof(*um->store.keyblocks), __func__); } @@ -355,7 +302,7 @@ static void um_arraystore_compact_ex( if (create) { BArrayState *state_reference = um_ref ? um_ref->store.mselect : NULL; const size_t stride = sizeof(*me->mselect); - BArrayStore *bs = array_store_at_size_ensure(stride); + BArrayStore *bs = BLI_array_store_at_size_ensure(&um_arraystore.bs_stride, stride, ARRAY_CHUNK_SIZE); um->store.mselect = BLI_array_store_state_add( bs, me->mselect, (size_t)me->totselect * stride, state_reference); } @@ -384,7 +331,7 @@ static void um_arraystore_compact_with_info(UndoMesh *um, const UndoMesh *um_ref { #ifdef DEBUG_PRINT size_t size_expanded_prev, size_compacted_prev; - um_arraystore_memory_usage(&size_expanded_prev, &size_compacted_prev); + BLI_array_store_at_size_calc_memory_usage(&um_arraystore.bs_stride, &size_expanded_prev, &size_compacted_prev); #endif #ifdef DEBUG_TIME @@ -400,7 +347,7 @@ static void um_arraystore_compact_with_info(UndoMesh *um, const UndoMesh *um_ref #ifdef DEBUG_PRINT { size_t size_expanded, size_compacted; - um_arraystore_memory_usage(&size_expanded, &size_compacted); + BLI_array_store_at_size_calc_memory_usage(&um_arraystore.bs_stride, &size_expanded, &size_compacted); const double percent_total = size_expanded ? (((double)size_compacted / (double)size_expanded) * 100.0) : -1.0; @@ -483,7 +430,7 @@ static void um_arraystore_free(UndoMesh *um) if (um->store.keyblocks) { const size_t stride = me->key->elemsize; - BArrayStore *bs = array_store_at_size_get(stride); + BArrayStore *bs = BLI_array_store_at_size_get(&um_arraystore.bs_stride, stride); for (int i = 0; i < me->key->totkey; i++) { BArrayState *state = um->store.keyblocks[i]; BLI_array_store_state_remove(bs, state); @@ -494,7 +441,7 @@ static void um_arraystore_free(UndoMesh *um) if (um->store.mselect) { const size_t stride = sizeof(*me->mselect); - BArrayStore *bs = array_store_at_size_get(stride); + BArrayStore *bs = BLI_array_store_at_size_get(&um_arraystore.bs_stride, stride); BArrayState *state = um->store.mselect; BLI_array_store_state_remove(bs, state); um->store.mselect = NULL; @@ -508,15 +455,7 @@ static void um_arraystore_free(UndoMesh *um) #ifdef DEBUG_PRINT printf("mesh undo store: freeing all data!\n"); #endif - for (int i = 0; i < um_arraystore.bs_all_len; i += 1) { - if (um_arraystore.bs_all[i]) { - BLI_array_store_destroy(um_arraystore.bs_all[i]); - } - } - - MEM_freeN(um_arraystore.bs_all); - um_arraystore.bs_all = NULL; - um_arraystore.bs_all_len = 0; + BLI_array_store_at_size_clear(&um_arraystore.bs_stride); #ifdef USE_ARRAY_STORE_THREAD BLI_task_pool_free(um_arraystore.task_pool); @@ -624,7 +563,9 @@ static void undoMesh_to_editbtMesh(void *um_v, void *em_v, void *obdata) EDBM_mesh_free(em); - bm = BM_mesh_create(&allocsize); + bm = BM_mesh_create( + &allocsize, + &((struct BMeshCreateParams){.use_toolflags = true,})); BM_mesh_bm_from_me( bm, &um->me, (&(struct BMeshFromMeshParams){ @@ -698,7 +639,7 @@ static void free_undo(void *um_v) MEM_freeN(me->key); } - BKE_mesh_free(me, false); + BKE_mesh_free(me); MEM_freeN(me); } diff --git a/source/blender/editors/mesh/editmesh_utils.c b/source/blender/editors/mesh/editmesh_utils.c index 99be37845ee..5101608246a 100644 --- a/source/blender/editors/mesh/editmesh_utils.c +++ b/source/blender/editors/mesh/editmesh_utils.c @@ -354,7 +354,9 @@ void EDBM_mesh_make(ToolSettings *ts, Object *ob, const bool add_key_index) BKE_mesh_convert_mfaces_to_mpolys(me); } - bm = BKE_mesh_to_bmesh(me, ob, add_key_index); + bm = BKE_mesh_to_bmesh( + me, ob, add_key_index, + &((struct BMeshCreateParams){.use_toolflags = true,})); if (me->edit_btmesh) { /* this happens when switching shape keys */ @@ -399,10 +401,25 @@ void EDBM_mesh_load(Object *ob) BKE_mesh_tessface_calc(me); #endif - /* free derived mesh. usually this would happen through depsgraph but there + /* Free derived mesh. usually this would happen through depsgraph but there * are exceptions like file save that will not cause this, and we want to - * avoid ending up with an invalid derived mesh then */ - BKE_object_free_derived_caches(ob); + * avoid ending up with an invalid derived mesh then. + * + * Do it for all objects which shares the same mesh datablock, since their + * derived meshes might also be referencing data which was just freed, + * + * Annoying enough, but currently seems most efficient way to avoid access + * of freed data on scene update, especially in cases when there are dependency + * cycles. + */ + for (Object *other_object = G.main->object.first; + other_object != NULL; + other_object = other_object->id.next) + { + if (other_object->data == ob->data) { + BKE_object_free_derived_caches(other_object); + } + } } /** diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c index 880417a00cf..08ed9813456 100644 --- a/source/blender/editors/object/object_add.c +++ b/source/blender/editors/object/object_add.c @@ -73,6 +73,7 @@ #include "BKE_lamp.h" #include "BKE_lattice.h" #include "BKE_library.h" +#include "BKE_library_query.h" #include "BKE_key.h" #include "BKE_main.h" #include "BKE_material.h" @@ -1112,12 +1113,18 @@ static void object_delete_check_glsl_update(Object *ob) /* note: now unlinks constraints as well */ void ED_base_object_free_and_unlink(Main *bmain, Scene *scene, Base *base) { - DAG_id_type_tag(bmain, ID_OB); + if (BKE_library_ID_is_indirectly_used(bmain, base->object) && ID_REAL_USERS(base->object) <= 1) { + /* We cannot delete indirectly used object... */ + printf("WARNING, undeletable object '%s', should have been catched before reaching this function!", + base->object->id.name + 2); + return; + } + BKE_scene_base_unlink(scene, base); object_delete_check_glsl_update(base->object); BKE_libblock_free_us(bmain, base->object); - if (scene->basact == base) scene->basact = NULL; MEM_freeN(base); + DAG_id_type_tag(bmain, ID_OB); } static int object_delete_exec(bContext *C, wmOperator *op) @@ -1134,6 +1141,19 @@ static int object_delete_exec(bContext *C, wmOperator *op) CTX_DATA_BEGIN (C, Base *, base, selected_bases) { + const bool is_indirectly_used = BKE_library_ID_is_indirectly_used(bmain, base->object); + if (base->object->id.tag & LIB_TAG_INDIRECT) { + /* Can this case ever happen? */ + BKE_reportf(op->reports, RPT_WARNING, "Cannot delete indirectly linked object '%s'", base->object->id.name + 2); + continue; + } + else if (is_indirectly_used && ID_REAL_USERS(base->object) <= 1) { + BKE_reportf(op->reports, RPT_WARNING, + "Cannot delete object '%s' from scene '%s', indirectly used objects need at least one user", + base->object->id.name + 2, scene->id.name + 2); + continue; + } + /* deselect object -- it could be used in other scenes */ base->object->flag &= ~SELECT; @@ -1149,6 +1169,12 @@ static int object_delete_exec(bContext *C, wmOperator *op) if (scene_iter != scene && !(scene_iter->id.lib)) { base_other = BKE_scene_base_find(scene_iter, base->object); if (base_other) { + if (is_indirectly_used && ID_REAL_USERS(base->object) <= 1) { + BKE_reportf(op->reports, RPT_WARNING, + "Cannot delete object '%s' from scene '%s', indirectly used objects need at least one user", + base->object->id.name + 2, scene_iter->id.name + 2); + break; + } ED_base_object_free_and_unlink(bmain, scene_iter, base_other); } } @@ -1292,7 +1318,7 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base, basen->object = ob; /* make sure apply works */ - BKE_animdata_free(&ob->id); + BKE_animdata_free(&ob->id, true); ob->adt = NULL; /* Proxies are not to be copied. */ @@ -1384,7 +1410,6 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base, } } - /* The same how BKE_object_unlink detects which object proxies to clear. */ if (base->object->transflag & OB_DUPLIGROUP && base->object->dup_group) { for (object = bmain->object.first; object; object = object->id.next) { if (object->proxy_group == base->object) { @@ -1605,7 +1630,7 @@ static int convert_exec(bContext *C, wmOperator *op) if (newob->type == OB_CURVE) { BKE_object_free_modifiers(newob); /* after derivedmesh calls! */ - ED_rigidbody_object_remove(scene, newob); + ED_rigidbody_object_remove(bmain, scene, newob); } } else if (ob->type == OB_MESH && ob->modifiers.first) { /* converting a mesh with no modifiers causes a segfault */ diff --git a/source/blender/editors/object/object_constraint.c b/source/blender/editors/object/object_constraint.c index efd1ebbd51b..d7b7fd7040e 100644 --- a/source/blender/editors/object/object_constraint.c +++ b/source/blender/editors/object/object_constraint.c @@ -1560,12 +1560,12 @@ void OBJECT_OT_constraints_copy(wmOperatorType *ot) /************************ add constraint operators *********************/ /* get the Object and/or PoseChannel to use as target */ -static short get_new_constraint_target(bContext *C, int con_type, Object **tar_ob, bPoseChannel **tar_pchan, short add) +static bool get_new_constraint_target(bContext *C, int con_type, Object **tar_ob, bPoseChannel **tar_pchan, bool add) { Object *obact = ED_object_active_context(C); bPoseChannel *pchanact = BKE_pose_channel_active(obact); - short only_curve = 0, only_mesh = 0, only_ob = 0; - short found = 0; + bool only_curve = false, only_mesh = false, only_ob = false; + bool found = false; /* clear tar_ob and tar_pchan fields before use * - assume for now that both always exist... @@ -1585,7 +1585,7 @@ static short get_new_constraint_target(bContext *C, int con_type, Object **tar_o case CONSTRAINT_TYPE_ROTLIMIT: case CONSTRAINT_TYPE_SIZELIMIT: case CONSTRAINT_TYPE_SAMEVOL: - return 0; + return false; /* restricted target-type constraints -------------- */ /* NOTE: for these, we cannot try to add a target object if no valid ones are found, since that doesn't work */ @@ -1593,26 +1593,26 @@ static short get_new_constraint_target(bContext *C, int con_type, Object **tar_o case CONSTRAINT_TYPE_CLAMPTO: case CONSTRAINT_TYPE_FOLLOWPATH: case CONSTRAINT_TYPE_SPLINEIK: - only_curve = 1; - only_ob = 1; - add = 0; + only_curve = true; + only_ob = true; + add = false; break; /* mesh only? */ case CONSTRAINT_TYPE_SHRINKWRAP: - only_mesh = 1; - only_ob = 1; - add = 0; + only_mesh = true; + only_ob = true; + add = false; break; /* object only - add here is ok? */ case CONSTRAINT_TYPE_RIGIDBODYJOINT: - only_ob = 1; + only_ob = true; break; } /* if the active Object is Armature, and we can search for bones, do so... */ - if ((obact->type == OB_ARMATURE) && (only_ob == 0)) { + if ((obact->type == OB_ARMATURE) && (only_ob == false)) { /* search in list of selected Pose-Channels for target */ CTX_DATA_BEGIN (C, bPoseChannel *, pchan, selected_pose_bones) { @@ -1620,7 +1620,7 @@ static short get_new_constraint_target(bContext *C, int con_type, Object **tar_o if (pchan != pchanact) { *tar_ob = obact; *tar_pchan = pchan; - found = 1; + found = true; break; } @@ -1629,36 +1629,50 @@ static short get_new_constraint_target(bContext *C, int con_type, Object **tar_o } /* if not yet found, try selected Objects... */ - if (found == 0) { + if (found == false) { /* search in selected objects context */ CTX_DATA_BEGIN (C, Object *, ob, selected_objects) { /* just use the first object we encounter (that isn't the active object) * and which fulfills the criteria for the object-target that we've got */ - if ((ob != obact) && - ((!only_curve) || (ob->type == OB_CURVE)) && - ((!only_mesh) || (ob->type == OB_MESH))) - { - /* set target */ - *tar_ob = ob; - found = 1; - - /* perform some special operations on the target */ - if (only_curve) { - /* Curve-Path option must be enabled for follow-path constraints to be able to work */ - Curve *cu = (Curve *)ob->data; - cu->flag |= CU_PATH; + if (ob != obact) { + /* for armatures in pose mode, look inside the armature for the active bone + * so that we set up cross-armature constraints with less effort + */ + if ((ob->type == OB_ARMATURE) && (ob->mode & OB_MODE_POSE) && + (!only_curve && !only_mesh)) + { + /* just use the active bone, and assume that it is visible + usable */ + *tar_ob = ob; + *tar_pchan = BKE_pose_channel_active(ob); + found = true; + + break; + } + else if (((!only_curve) || (ob->type == OB_CURVE)) && + ((!only_mesh) || (ob->type == OB_MESH))) + { + /* set target */ + *tar_ob = ob; + found = true; + + /* perform some special operations on the target */ + if (only_curve) { + /* Curve-Path option must be enabled for follow-path constraints to be able to work */ + Curve *cu = (Curve *)ob->data; + cu->flag |= CU_PATH; + } + + break; } - - break; } } CTX_DATA_END; } /* if still not found, add a new empty to act as a target (if allowed) */ - if ((found == 0) && (add)) { + if ((found == false) && (add)) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); Base *base = BASACT, *newbase = NULL; @@ -1692,7 +1706,7 @@ static short get_new_constraint_target(bContext *C, int con_type, Object **tar_o /* make our new target the new object */ *tar_ob = obt; - found = 1; + found = true; } /* return whether there's any target */ diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c index 06200778ee5..01a567931b3 100644 --- a/source/blender/editors/object/object_edit.c +++ b/source/blender/editors/object/object_edit.c @@ -946,6 +946,7 @@ static void copy_attr(Main *bmain, Scene *scene, View3D *v3d, short event) cu1 = base->object->data; cu1->spacemode = cu->spacemode; + cu1->align_y = cu->align_y; cu1->spacing = cu->spacing; cu1->linedist = cu->linedist; cu1->shear = cu->shear; diff --git a/source/blender/editors/object/object_group.c b/source/blender/editors/object/object_group.c index 76a8a68c42d..bcdd170c53c 100644 --- a/source/blender/editors/object/object_group.c +++ b/source/blender/editors/object/object_group.c @@ -43,6 +43,7 @@ #include "BKE_depsgraph.h" #include "BKE_group.h" #include "BKE_library.h" +#include "BKE_library_remap.h" #include "BKE_main.h" #include "BKE_report.h" #include "BKE_object.h" @@ -527,7 +528,8 @@ static int group_unlink_exec(bContext *C, wmOperator *UNUSED(op)) if (!group) return OPERATOR_CANCELLED; - BKE_group_unlink(bmain, group); + BKE_libblock_unlink(bmain, group, false, false); + BKE_libblock_free(bmain, group); WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, NULL); diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c index 2f10f83e276..94d1a258063 100644 --- a/source/blender/editors/object/object_relations.c +++ b/source/blender/editors/object/object_relations.c @@ -437,7 +437,7 @@ typedef enum eObClearParentTypes { EnumPropertyItem prop_clear_parent_types[] = { {CLEAR_PARENT_ALL, "CLEAR", 0, "Clear Parent", - "Completely clear the parenting relationship, including involved modifiers is any"}, + "Completely clear the parenting relationship, including involved modifiers if any"}, {CLEAR_PARENT_KEEP_TRANSFORM, "CLEAR_KEEP_TRANSFORM", 0, "Clear and Keep Transformation", "As 'Clear Parent', but keep the current visual transformations of the object"}, {CLEAR_PARENT_INVERSE, "CLEAR_INVERSE", 0, "Clear Parent Inverse", diff --git a/source/blender/editors/physics/particle_edit.c b/source/blender/editors/physics/particle_edit.c index 3da3a451d66..30c102b70c5 100644 --- a/source/blender/editors/physics/particle_edit.c +++ b/source/blender/editors/physics/particle_edit.c @@ -1173,7 +1173,7 @@ static void PE_update_selection(Scene *scene, Object *ob, int useflag) } } - psys_cache_edit_paths(scene, ob, edit, CFRA); + psys_cache_edit_paths(scene, ob, edit, CFRA, G.is_rendering); /* disable update flag */ @@ -1289,7 +1289,7 @@ void PE_update_object(Scene *scene, Object *ob, int useflag) PE_hide_keys_time(scene, edit, CFRA); /* regenerate path caches */ - psys_cache_edit_paths(scene, ob, edit, CFRA); + psys_cache_edit_paths(scene, ob, edit, CFRA, G.is_rendering); /* disable update flag */ LOOP_POINTS { @@ -1634,7 +1634,7 @@ static int select_random_exec(bContext *C, wmOperator *op) int p; int k; - const float randfac = RNA_float_get (op->ptr, "percent") / 100.0f; + const float randfac = RNA_float_get(op->ptr, "percent") / 100.0f; const int seed = WM_operator_properties_select_random_seed_increment_get(op); const bool select = (RNA_enum_get(op->ptr, "action") == SEL_SELECT); RNG *rng; @@ -2288,7 +2288,7 @@ static int remove_tagged_particles(Object *ob, ParticleSystem *psys, int mirror) npoint= new_points= MEM_callocN(new_totpart * sizeof(PTCacheEditPoint), "PTCacheEditKey array"); if (ELEM(NULL, new_pars, new_points)) { - /* allocation error! */ + /* allocation error! */ if (new_pars) MEM_freeN(new_pars); if (new_points) diff --git a/source/blender/editors/physics/rigidbody_constraint.c b/source/blender/editors/physics/rigidbody_constraint.c index f95599592b2..1bfc162a331 100644 --- a/source/blender/editors/physics/rigidbody_constraint.c +++ b/source/blender/editors/physics/rigidbody_constraint.c @@ -41,6 +41,7 @@ #include "BKE_depsgraph.h" #include "BKE_global.h" #include "BKE_group.h" +#include "BKE_main.h" #include "BKE_report.h" #include "BKE_rigidbody.h" @@ -70,7 +71,7 @@ static int ED_operator_rigidbody_con_active_poll(bContext *C) } -bool ED_rigidbody_constraint_add(Scene *scene, Object *ob, int type, ReportList *reports) +bool ED_rigidbody_constraint_add(Main *bmain, Scene *scene, Object *ob, int type, ReportList *reports) { RigidBodyWorld *rbw = BKE_rigidbody_get_world(scene); @@ -81,7 +82,7 @@ bool ED_rigidbody_constraint_add(Scene *scene, Object *ob, int type, ReportList } /* create constraint group if it doesn't already exits */ if (rbw->constraints == NULL) { - rbw->constraints = BKE_group_add(G.main, "RigidBodyConstraints"); + rbw->constraints = BKE_group_add(bmain, "RigidBodyConstraints"); } /* make rigidbody constraint settings */ ob->rigidbody_constraint = BKE_rigidbody_create_constraint(scene, ob, type); @@ -90,11 +91,12 @@ bool ED_rigidbody_constraint_add(Scene *scene, Object *ob, int type, ReportList /* add constraint to rigid body constraint group */ BKE_group_object_add(rbw->constraints, ob, scene, NULL); + DAG_relations_tag_update(bmain); DAG_id_tag_update(&ob->id, OB_RECALC_OB); return true; } -void ED_rigidbody_constraint_remove(Scene *scene, Object *ob) +void ED_rigidbody_constraint_remove(Main *bmain, Scene *scene, Object *ob) { RigidBodyWorld *rbw = BKE_rigidbody_get_world(scene); @@ -102,6 +104,7 @@ void ED_rigidbody_constraint_remove(Scene *scene, Object *ob) if (rbw) BKE_group_object_unlink(rbw->constraints, ob, scene, NULL); + DAG_relations_tag_update(bmain); DAG_id_tag_update(&ob->id, OB_RECALC_OB); } @@ -112,6 +115,7 @@ void ED_rigidbody_constraint_remove(Scene *scene, Object *ob) static int rigidbody_con_add_exec(bContext *C, wmOperator *op) { + Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); RigidBodyWorld *rbw = BKE_rigidbody_get_world(scene); Object *ob = (scene) ? OBACT : NULL; @@ -124,7 +128,7 @@ static int rigidbody_con_add_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } /* apply to active object */ - changed = ED_rigidbody_constraint_add(scene, ob, type, op->reports); + changed = ED_rigidbody_constraint_add(bmain, scene, ob, type, op->reports); if (changed) { /* send updates */ @@ -160,6 +164,7 @@ void RIGIDBODY_OT_constraint_add(wmOperatorType *ot) static int rigidbody_con_remove_exec(bContext *C, wmOperator *op) { + Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); Object *ob = (scene) ? OBACT : NULL; @@ -173,7 +178,7 @@ static int rigidbody_con_remove_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } else { - ED_rigidbody_constraint_remove(scene, ob); + ED_rigidbody_constraint_remove(bmain, scene, ob); } /* send updates */ diff --git a/source/blender/editors/physics/rigidbody_object.c b/source/blender/editors/physics/rigidbody_object.c index 26d8af82b2d..30597d95497 100644 --- a/source/blender/editors/physics/rigidbody_object.c +++ b/source/blender/editors/physics/rigidbody_object.c @@ -46,6 +46,7 @@ #include "BKE_depsgraph.h" #include "BKE_global.h" #include "BKE_group.h" +#include "BKE_main.h" #include "BKE_report.h" #include "BKE_rigidbody.h" @@ -87,7 +88,7 @@ static int ED_operator_rigidbody_add_poll(bContext *C) /* ----------------- */ -bool ED_rigidbody_object_add(Scene *scene, Object *ob, int type, ReportList *reports) +bool ED_rigidbody_object_add(Main *bmain, Scene *scene, Object *ob, int type, ReportList *reports) { RigidBodyWorld *rbw = BKE_rigidbody_get_world(scene); @@ -107,7 +108,7 @@ bool ED_rigidbody_object_add(Scene *scene, Object *ob, int type, ReportList *rep scene->rigidbody_world = rbw; } if (rbw->group == NULL) { - rbw->group = BKE_group_add(G.main, "RigidBodyWorld"); + rbw->group = BKE_group_add(bmain, "RigidBodyWorld"); } /* make rigidbody object settings */ @@ -120,12 +121,13 @@ bool ED_rigidbody_object_add(Scene *scene, Object *ob, int type, ReportList *rep /* add object to rigid body group */ BKE_group_object_add(rbw->group, ob, scene, NULL); + DAG_relations_tag_update(bmain); DAG_id_tag_update(&ob->id, OB_RECALC_OB); return true; } -void ED_rigidbody_object_remove(Scene *scene, Object *ob) +void ED_rigidbody_object_remove(Main *bmain, Scene *scene, Object *ob) { RigidBodyWorld *rbw = BKE_rigidbody_get_world(scene); @@ -133,6 +135,7 @@ void ED_rigidbody_object_remove(Scene *scene, Object *ob) if (rbw) BKE_group_object_unlink(rbw->group, ob, scene, NULL); + DAG_relations_tag_update(bmain); DAG_id_tag_update(&ob->id, OB_RECALC_OB); } @@ -143,13 +146,14 @@ void ED_rigidbody_object_remove(Scene *scene, Object *ob) static int rigidbody_object_add_exec(bContext *C, wmOperator *op) { + Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); Object *ob = ED_object_active_context(C); int type = RNA_enum_get(op->ptr, "type"); bool changed; /* apply to active object */ - changed = ED_rigidbody_object_add(scene, ob, type, op->reports); + changed = ED_rigidbody_object_add(bmain, scene, ob, type, op->reports); if (changed) { /* send updates */ @@ -186,13 +190,14 @@ void RIGIDBODY_OT_object_add(wmOperatorType *ot) static int rigidbody_object_remove_exec(bContext *C, wmOperator *op) { + Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); Object *ob = ED_object_active_context(C); bool changed = false; /* apply to active object */ if (!ELEM(NULL, ob, ob->rigidbody_object)) { - ED_rigidbody_object_remove(scene, ob); + ED_rigidbody_object_remove(bmain, scene, ob); changed = true; } @@ -232,13 +237,14 @@ void RIGIDBODY_OT_object_remove(wmOperatorType *ot) static int rigidbody_objects_add_exec(bContext *C, wmOperator *op) { + Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); int type = RNA_enum_get(op->ptr, "type"); bool changed = false; /* create rigid body objects and add them to the world's group */ CTX_DATA_BEGIN(C, Object *, ob, selected_objects) { - changed |= ED_rigidbody_object_add(scene, ob, type, op->reports); + changed |= ED_rigidbody_object_add(bmain, scene, ob, type, op->reports); } CTX_DATA_END; @@ -277,6 +283,7 @@ void RIGIDBODY_OT_objects_add(wmOperatorType *ot) static int rigidbody_objects_remove_exec(bContext *C, wmOperator *UNUSED(op)) { + Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); bool changed = false; @@ -284,7 +291,7 @@ static int rigidbody_objects_remove_exec(bContext *C, wmOperator *UNUSED(op)) CTX_DATA_BEGIN(C, Object *, ob, selected_objects) { if (ob->rigidbody_object) { - ED_rigidbody_object_remove(scene, ob); + ED_rigidbody_object_remove(bmain, scene, ob); changed = true; } } diff --git a/source/blender/editors/render/render_preview.c b/source/blender/editors/render/render_preview.c index f4260a0cd33..132c3fa5438 100644 --- a/source/blender/editors/render/render_preview.c +++ b/source/blender/editors/render/render_preview.c @@ -70,6 +70,7 @@ #include "BKE_icons.h" #include "BKE_lamp.h" #include "BKE_library.h" +#include "BKE_library_remap.h" #include "BKE_main.h" #include "BKE_material.h" #include "BKE_node.h" @@ -830,7 +831,7 @@ static void shader_preview_free(void *customdata) /* get rid of copied material */ BLI_remlink(&pr_main->mat, sp->matcopy); - BKE_material_free_ex(sp->matcopy, false); + BKE_material_free(sp->matcopy); properties = IDP_GetProperties((ID *)sp->matcopy, false); if (properties) { @@ -862,7 +863,9 @@ static void shader_preview_free(void *customdata) /* get rid of copied world */ BLI_remlink(&pr_main->world, sp->worldcopy); - BKE_world_free_ex(sp->worldcopy, true); /* [#32865] - we need to unlink the texture copies, unlike for materials */ + /* T32865 - we need to unlink the texture copies, unlike for materials */ + BKE_libblock_relink_ex(sp->worldcopy, NULL, NULL, true); + BKE_world_free(sp->worldcopy); properties = IDP_GetProperties((ID *)sp->worldcopy, false); if (properties) { @@ -878,6 +881,7 @@ static void shader_preview_free(void *customdata) /* get rid of copied lamp */ BLI_remlink(&pr_main->lamp, sp->lampcopy); + BKE_libblock_relink_ex(sp->lampcopy, NULL, NULL, true); BKE_lamp_free(sp->lampcopy); properties = IDP_GetProperties((ID *)sp->lampcopy, false); diff --git a/source/blender/editors/screen/glutil.c b/source/blender/editors/screen/glutil.c index cbf87062955..93bac3f6660 100644 --- a/source/blender/editors/screen/glutil.c +++ b/source/blender/editors/screen/glutil.c @@ -327,6 +327,13 @@ float glaGetOneFloat(int param) return v; } +int glaGetOneInt(int param) +{ + GLint v; + glGetIntegerv(param, &v); + return v; +} + void glaRasterPosSafe2f(float x, float y, float known_good_x, float known_good_y) { GLubyte dummy = 0; @@ -579,6 +586,10 @@ void glaDrawPixelsSafe(float x, float y, int img_w, int img_h, int row_w, int fo draw_h = min_ii(img_h - off_y, ceil((scissor[3] - rast_y) / yzoom)); if (draw_w > 0 && draw_h > 0) { + + int bound_options; + GPU_BASIC_SHADER_DISABLE_AND_STORE(bound_options); + /* Don't use safe RasterPos (slower) if we can avoid it. */ if (rast_x >= 0 && rast_y >= 0) { glRasterPos2f(rast_x, rast_y); @@ -610,6 +621,8 @@ void glaDrawPixelsSafe(float x, float y, int img_w, int img_h, int row_w, int fo } glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); + + GPU_BASIC_SHADER_ENABLE_AND_RESTORE(bound_options); } } diff --git a/source/blender/editors/screen/screen_edit.c b/source/blender/editors/screen/screen_edit.c index a459f982ada..62aeca4b9d1 100644 --- a/source/blender/editors/screen/screen_edit.c +++ b/source/blender/editors/screen/screen_edit.c @@ -45,6 +45,7 @@ #include "BKE_image.h" #include "BKE_global.h" #include "BKE_library.h" +#include "BKE_library_remap.h" #include "BKE_main.h" #include "BKE_node.h" #include "BKE_screen.h" @@ -1755,7 +1756,9 @@ bool ED_screen_delete_scene(bContext *C, Scene *scene) ED_screen_set_scene(C, CTX_wm_screen(C), newscene); - BKE_scene_unlink(bmain, scene, newscene); + BKE_libblock_remap(bmain, scene, newscene, ID_REMAP_SKIP_INDIRECT_USAGE | ID_REMAP_SKIP_NEVER_NULL_USAGE); + + BKE_libblock_free(bmain, scene); return true; } diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c index f340f716ccb..0c0a6c93b3e 100644 --- a/source/blender/editors/screen/screen_ops.c +++ b/source/blender/editors/screen/screen_ops.c @@ -2479,7 +2479,7 @@ static void SCREEN_OT_screen_full_area(wmOperatorType *ot) { PropertyRNA *prop; - ot->name = "Toggle Fullscreen Area"; + ot->name = "Toggle Maximize Area"; ot->description = "Toggle display selected area as fullscreen/maximized"; ot->idname = "SCREEN_OT_screen_full_area"; diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c index a716cae56dd..941f19ca0f0 100644 --- a/source/blender/editors/sculpt_paint/paint_image.c +++ b/source/blender/editors/sculpt_paint/paint_image.c @@ -401,7 +401,7 @@ static void image_undo_end(void) UndoImageTile *tmp_tile = tile->next; deallocsize += allocsize * ((tile->use_float) ? sizeof(float) : sizeof(char)); MEM_freeN(tile->rect.pt); - BLI_freelinkN (lb, tile); + BLI_freelinkN(lb, tile); tile = tmp_tile; } else { diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c index d273f8320a1..6ed969cb270 100644 --- a/source/blender/editors/sculpt_paint/paint_image_proj.c +++ b/source/blender/editors/sculpt_paint/paint_image_proj.c @@ -202,7 +202,7 @@ typedef struct ProjPaintImage { */ typedef struct ProjStrokeHandle { /* Support for painting from multiple views at once, - * currently used to impliment summetry painting, + * currently used to impliment symmetry painting, * we can assume at least the first is set while painting. */ struct ProjPaintState *ps_views[8]; int ps_views_tot; @@ -717,7 +717,7 @@ static bool project_paint_PickColor( } /** - * Check if 'pt' is infront of the 3 verts on the Z axis (used for screenspace occlusuion test) + * Check if 'pt' is infront of the 3 verts on the Z axis (used for screenspace occlusion test) * \return * - `0`: no occlusion * - `-1`: no occlusion but 2D intersection is true @@ -3717,7 +3717,7 @@ static void project_paint_prepare_all_faces( } /* tfbase here should be non-null! */ - BLI_assert (mloopuv_base != NULL); + BLI_assert(mloopuv_base != NULL); if (is_face_sel && tpage) { ProjPaintFaceCoSS coSS; @@ -5858,7 +5858,9 @@ static int add_simple_uvs_exec(bContext *C, wmOperator *UNUSED(op)) Mesh *me = ob->data; bool synch_selection = (scene->toolsettings->uv_flag & UV_SYNC_SELECTION) != 0; - BMesh *bm = BM_mesh_create(&bm_mesh_allocsize_default); + BMesh *bm = BM_mesh_create( + &bm_mesh_allocsize_default, + &((struct BMeshCreateParams){.use_toolflags = false,})); /* turn synch selection off, since we are not in edit mode we need to ensure only the uv flags are tested */ scene->toolsettings->uv_flag &= ~UV_SYNC_SELECTION; diff --git a/source/blender/editors/sculpt_paint/paint_intern.h b/source/blender/editors/sculpt_paint/paint_intern.h index b6a7d671882..7e05ab929ae 100644 --- a/source/blender/editors/sculpt_paint/paint_intern.h +++ b/source/blender/editors/sculpt_paint/paint_intern.h @@ -101,6 +101,10 @@ bool ED_wpaint_fill(struct VPaint *wp, struct Object *ob, float paintweight); bool ED_vpaint_smooth(struct Object *ob); +typedef void (*VPaintTransform_Callback)(const float col[3], const void *user_data, float r_col[3]); + +bool ED_vpaint_color_transform(struct Object *ob, VPaintTransform_Callback vpaint_tx_fn, const void *user_data); + void PAINT_OT_weight_paint_toggle(struct wmOperatorType *ot); void PAINT_OT_weight_paint(struct wmOperatorType *ot); void PAINT_OT_weight_set(struct wmOperatorType *ot); diff --git a/source/blender/editors/sculpt_paint/paint_ops.c b/source/blender/editors/sculpt_paint/paint_ops.c index da7667c775e..bf923415f01 100644 --- a/source/blender/editors/sculpt_paint/paint_ops.c +++ b/source/blender/editors/sculpt_paint/paint_ops.c @@ -315,6 +315,241 @@ static void PAINT_OT_vertex_color_smooth(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } + +/** \name Vertex Color Transformations + * \{ */ + +struct VPaintTx_BrightContrastData { + /* pre-calculated */ + float gain; + float offset; +}; + +static void vpaint_tx_brightness_contrast(const float col[3], const void *user_data, float r_col[3]) +{ + const struct VPaintTx_BrightContrastData *data = user_data; + + for (int i = 0; i < 3; i++) { + r_col[i] = data->gain * col[i] + data->offset; + } +} + +static int vertex_color_brightness_contrast_exec(bContext *C, wmOperator *op) +{ + Object *obact = CTX_data_active_object(C); + + float gain, offset; + { + float brightness = RNA_float_get(op->ptr, "brightness"); + float contrast = RNA_float_get(op->ptr, "contrast"); + brightness /= 100.0f; + float delta = contrast / 200.0f; + gain = 1.0f - delta * 2.0f; + /* + * The algorithm is by Werner D. Streidt + * (http://visca.com/ffactory/archives/5-99/msg00021.html) + * Extracted of OpenCV demhist.c + */ + if (contrast > 0) { + gain = 1.0f / ((gain != 0.0f) ? gain : FLT_EPSILON); + offset = gain * (brightness - delta); + } + else { + delta *= -1; + offset = gain * (brightness + delta); + } + } + + const struct VPaintTx_BrightContrastData user_data = { + .gain = gain, + .offset = offset, + }; + + if (ED_vpaint_color_transform(obact, vpaint_tx_brightness_contrast, &user_data)) { + ED_region_tag_redraw(CTX_wm_region(C)); + return OPERATOR_FINISHED; + } + else { + return OPERATOR_CANCELLED; + } +} + +static void PAINT_OT_vertex_color_brightness_contrast(wmOperatorType *ot) +{ + PropertyRNA *prop; + + /* identifiers */ + ot->name = "Vertex Paint Bright/Contrast"; + ot->idname = "PAINT_OT_vertex_color_brightness_contrast"; + ot->description = "Adjust vertex color brightness/contrast"; + + /* api callbacks */ + ot->exec = vertex_color_brightness_contrast_exec; + ot->poll = vertex_paint_mode_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* params */ + const float min = -100, max = +100; + prop = RNA_def_float(ot->srna, "brightness", 0.0f, min, max, "Brightness", "", min, max); + prop = RNA_def_float(ot->srna, "contrast", 0.0f, min, max, "Contrast", "", min, max); + RNA_def_property_ui_range(prop, min, max, 1, 1); +} + +struct VPaintTx_HueSatData { + float hue; + float sat; + float val; +}; + +static void vpaint_tx_hsv(const float col[3], const void *user_data, float r_col[3]) +{ + const struct VPaintTx_HueSatData *data = user_data; + float hsv[3]; + rgb_to_hsv_v(col, hsv); + + hsv[0] += (data->hue - 0.5f); + if (hsv[0] > 1.0f) { + hsv[0] -= 1.0f; + } + else if (hsv[0] < 0.0f) { + hsv[0] += 1.0f; + } + hsv[1] *= data->sat; + hsv[2] *= data->val; + + hsv_to_rgb_v(hsv, r_col); +} + +static int vertex_color_hsv_exec(bContext *C, wmOperator *op) +{ + Object *obact = CTX_data_active_object(C); + + const struct VPaintTx_HueSatData user_data = { + .hue = RNA_float_get(op->ptr, "h"), + .sat = RNA_float_get(op->ptr, "s"), + .val = RNA_float_get(op->ptr, "v"), + }; + + if (ED_vpaint_color_transform(obact, vpaint_tx_hsv, &user_data)) { + ED_region_tag_redraw(CTX_wm_region(C)); + return OPERATOR_FINISHED; + } + else { + return OPERATOR_CANCELLED; + } +} + +static void PAINT_OT_vertex_color_hsv(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Vertex Paint Hue Saturation Value"; + ot->idname = "PAINT_OT_vertex_color_hsv"; + ot->description = "Adjust vertex color HSV values"; + + /* api callbacks */ + ot->exec = vertex_color_hsv_exec; + ot->poll = vertex_paint_mode_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* params */ + RNA_def_float(ot->srna, "h", 0.5f, 0.0f, 1.0f, "Hue", "", 0.0f, 1.0f); + RNA_def_float(ot->srna, "s", 1.0f, 0.0f, 2.0f, "Saturation", "", 0.0f, 2.0f); + RNA_def_float(ot->srna, "v", 1.0f, 0.0f, 2.0f, "Value", "", 0.0f, 2.0f); +} + +static void vpaint_tx_invert(const float col[3], const void *UNUSED(user_data), float r_col[3]) +{ + for (int i = 0; i < 3; i++) { + r_col[i] = 1.0f - col[i]; + } +} + +static int vertex_color_invert_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Object *obact = CTX_data_active_object(C); + + if (ED_vpaint_color_transform(obact, vpaint_tx_invert, NULL)) { + ED_region_tag_redraw(CTX_wm_region(C)); + return OPERATOR_FINISHED; + } + else { + return OPERATOR_CANCELLED; + } +} + +static void PAINT_OT_vertex_color_invert(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Vertex Paint Invert"; + ot->idname = "PAINT_OT_vertex_color_invert"; + ot->description = "Invert RGB values"; + + /* api callbacks */ + ot->exec = vertex_color_invert_exec; + ot->poll = vertex_paint_mode_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + + +struct VPaintTx_LevelsData { + float gain; + float offset; +}; + +static void vpaint_tx_levels(const float col[3], const void *user_data, float r_col[3]) +{ + const struct VPaintTx_LevelsData *data = user_data; + for (int i = 0; i < 3; i++) { + r_col[i] = data->gain * (col[i] + data->offset); + } +} + +static int vertex_color_levels_exec(bContext *C, wmOperator *op) +{ + Object *obact = CTX_data_active_object(C); + + const struct VPaintTx_LevelsData user_data = { + .gain = RNA_float_get(op->ptr, "gain"), + .offset = RNA_float_get(op->ptr, "offset"), + }; + + if (ED_vpaint_color_transform(obact, vpaint_tx_levels, &user_data)) { + ED_region_tag_redraw(CTX_wm_region(C)); + return OPERATOR_FINISHED; + } + else { + return OPERATOR_CANCELLED; + } +} + +static void PAINT_OT_vertex_color_levels(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Vertex Paint Levels"; + ot->idname = "PAINT_OT_vertex_color_levels"; + ot->description = "Adjust levels of vertex colors"; + + /* api callbacks */ + ot->exec = vertex_color_levels_exec; + ot->poll = vertex_paint_mode_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* params */ + RNA_def_float(ot->srna, "offset", 0.0f, -1.0f, 1.0f, "Offset", "Value to add to colors", -1.0f, 1.0f); + RNA_def_float(ot->srna, "gain", 1.0f, 0.0f, FLT_MAX, "Gain", "Value to multiply colors by", 0.0f, 10.0f); +} + +/** \} */ + + static int brush_reset_exec(bContext *C, wmOperator *UNUSED(op)) { Paint *paint = BKE_paint_get_active_from_context(C); @@ -1112,6 +1347,11 @@ void ED_operatortypes_paint(void) WM_operatortype_append(PAINT_OT_vertex_color_set); WM_operatortype_append(PAINT_OT_vertex_color_smooth); + WM_operatortype_append(PAINT_OT_vertex_color_brightness_contrast); + WM_operatortype_append(PAINT_OT_vertex_color_hsv); + WM_operatortype_append(PAINT_OT_vertex_color_invert); + WM_operatortype_append(PAINT_OT_vertex_color_levels); + /* face-select */ WM_operatortype_append(PAINT_OT_face_select_linked); WM_operatortype_append(PAINT_OT_face_select_linked_pick); diff --git a/source/blender/editors/sculpt_paint/paint_stroke.c b/source/blender/editors/sculpt_paint/paint_stroke.c index 65857cccb15..aa17cb02fe5 100644 --- a/source/blender/editors/sculpt_paint/paint_stroke.c +++ b/source/blender/editors/sculpt_paint/paint_stroke.c @@ -58,6 +58,8 @@ #include "BIF_gl.h" #include "BIF_glutil.h" +#include "GPU_basic_shader.h" + #include "ED_screen.h" #include "ED_view3d.h" @@ -160,11 +162,11 @@ static void paint_draw_line_cursor(bContext *C, int x, int y, void *customdata) glEnable(GL_LINE_SMOOTH); glEnable(GL_BLEND); - glEnable(GL_LINE_STIPPLE); - glLineStipple(3, 0xAAAA); + GPU_basic_shader_bind_enable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE); + GPU_basic_shader_line_stipple(3, 0xAAAA); + GPU_basic_shader_line_width(3.0); glColor4ub(0, 0, 0, paint->paint_cursor_col[3]); - glLineWidth(3.0); if (stroke->constrain_line) { sdrawline((int)stroke->last_mouse_position[0], (int)stroke->last_mouse_position[1], stroke->constrained_pos[0], stroke->constrained_pos[1]); @@ -175,7 +177,7 @@ static void paint_draw_line_cursor(bContext *C, int x, int y, void *customdata) } glColor4ub(255, 255, 255, paint->paint_cursor_col[3]); - glLineWidth(1.0); + GPU_basic_shader_line_width(1.0); if (stroke->constrain_line) { sdrawline((int)stroke->last_mouse_position[0], (int)stroke->last_mouse_position[1], stroke->constrained_pos[0], stroke->constrained_pos[1]); @@ -185,7 +187,7 @@ static void paint_draw_line_cursor(bContext *C, int x, int y, void *customdata) x, y); } - glDisable(GL_LINE_STIPPLE); + GPU_basic_shader_bind_disable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE); glDisable(GL_BLEND); glDisable(GL_LINE_SMOOTH); @@ -1156,7 +1158,7 @@ int paint_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event) if (event->val == KM_RELEASE) { copy_v2_fl2(mouse, event->mval[0], event->mval[1]); paint_stroke_line_constrain(stroke, mouse); - paint_stroke_line_end (C, op, stroke, mouse); + paint_stroke_line_end(C, op, stroke, mouse); stroke_done(C, op); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c index 15ab4ca04a7..87855879ec5 100644 --- a/source/blender/editors/sculpt_paint/paint_vertex.c +++ b/source/blender/editors/sculpt_paint/paint_vertex.c @@ -502,6 +502,51 @@ bool ED_vpaint_smooth(Object *ob) return true; } +/** + * Apply callback to each vertex of the active vertex color layer. + */ +bool ED_vpaint_color_transform( + struct Object *ob, + VPaintTransform_Callback vpaint_tx_fn, + const void *user_data) +{ + Mesh *me; + const MPoly *mp; + + if (((me = BKE_mesh_from_object(ob)) == NULL) || + (me->mloopcol == NULL && (make_vertexcol(ob) == false))) + { + return false; + } + + const bool do_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0; + mp = me->mpoly; + + for (int i = 0; i < me->totpoly; i++, mp++) { + MLoopCol *lcol = &me->mloopcol[mp->loopstart]; + + if (do_face_sel && !(mp->flag & ME_FACE_SEL)) { + continue; + } + + for (int j = 0; j < mp->totloop; j++, lcol++) { + float col[3]; + rgb_uchar_to_float(col, &lcol->r); + + vpaint_tx_fn(col, user_data, col); + + rgb_float_to_uchar(&lcol->r, col); + } + } + + /* remove stale me->mcol, will be added later */ + BKE_mesh_tessface_clear(me); + + DAG_id_tag_update(&me->id, 0); + + return true; +} + /* XXX: should be re-implemented as a vertex/weight paint 'color correct' operator */ #if 0 void vpaint_dogamma(Scene *scene) @@ -1323,7 +1368,7 @@ static bool do_weight_paint_normalize_all_locked( /** * \note same as function above except it does a second pass without active group - * if nomalize fails with it. + * if normalize fails with it. */ static void do_weight_paint_normalize_all_locked_try_active( MDeformVert *dvert, const int defbase_tot, const bool *vgroup_validmap, @@ -1340,7 +1385,7 @@ static void do_weight_paint_normalize_all_locked_try_active( * - With 1.0 weight painted into active: * nonzero locked weight; first pass zeroed out unlocked weight; scale 1 down to fit. * - With 0.0 weight painted into active: - * no unlocked groups; first pass did nothing; increaze 0 to fit. + * no unlocked groups; first pass did nothing; increase 0 to fit. */ do_weight_paint_normalize_all_locked(dvert, defbase_tot, vgroup_validmap, lock_flags); } diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index c173156de3a..0931456058d 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -5001,7 +5001,9 @@ void sculpt_dynamic_topology_enable(bContext *C) BKE_mesh_mselect_clear(me); /* Create triangles-only BMesh */ - ss->bm = BM_mesh_create(&allocsize); + ss->bm = BM_mesh_create( + &allocsize, + &((struct BMeshCreateParams){.use_toolflags = false,})); BM_mesh_bm_from_me( ss->bm, me, (&(struct BMeshFromMeshParams){ @@ -5011,7 +5013,9 @@ void sculpt_dynamic_topology_enable(bContext *C) BM_data_layer_add(ss->bm, &ss->bm->vdata, CD_PAINT_MASK); sculpt_dyntopo_node_layers_add(ss); /* make sure the data for existing faces are initialized */ - BM_mesh_normals_update(ss->bm); + if (me->totpoly != ss->bm->totface) { + BM_mesh_normals_update(ss->bm); + } /* Enable dynamic topology */ me->flag |= ME_SCULPT_DYNAMIC_TOPOLOGY; @@ -5088,6 +5092,8 @@ static int sculpt_dynamic_topology_toggle_exec(bContext *C, wmOperator *UNUSED(o Object *ob = CTX_data_active_object(C); SculptSession *ss = ob->sculpt; + WM_cursor_wait(1); + if (ss->bm) { sculpt_undo_push_begin("Dynamic topology disable"); sculpt_undo_push_node(ob, NULL, SCULPT_UNDO_DYNTOPO_END); @@ -5100,16 +5106,24 @@ static int sculpt_dynamic_topology_toggle_exec(bContext *C, wmOperator *UNUSED(o } sculpt_undo_push_end(C); + WM_cursor_wait(0); + return OPERATOR_FINISHED; } +enum eDynTopoWarnFlag { + DYNTOPO_WARN_VDATA = (1 << 0), + DYNTOPO_WARN_EDATA = (1 << 1), + DYNTOPO_WARN_LDATA = (1 << 2), + DYNTOPO_WARN_MODIFIER = (1 << 3), +}; -static int dyntopo_warning_popup(bContext *C, wmOperatorType *ot, bool vdata, bool modifiers) +static int dyntopo_warning_popup(bContext *C, wmOperatorType *ot, enum eDynTopoWarnFlag flag) { uiPopupMenu *pup = UI_popup_menu_begin(C, IFACE_("Warning!"), ICON_ERROR); uiLayout *layout = UI_popup_menu_layout(pup); - if (vdata) { + if (flag & (DYNTOPO_WARN_VDATA | DYNTOPO_WARN_EDATA | DYNTOPO_WARN_LDATA)) { const char *msg_error = TIP_("Vertex Data Detected!"); const char *msg = TIP_("Dyntopo will not preserve vertex colors, UVs, or other customdata"); uiItemL(layout, msg_error, ICON_INFO); @@ -5117,7 +5131,7 @@ static int dyntopo_warning_popup(bContext *C, wmOperatorType *ot, bool vdata, bo uiItemS(layout); } - if (modifiers) { + if (flag & DYNTOPO_WARN_MODIFIER) { const char *msg_error = TIP_("Generative Modifiers Detected!"); const char *msg = TIP_("Keeping the modifiers will increase polycount when returning to object mode"); @@ -5133,33 +5147,35 @@ static int dyntopo_warning_popup(bContext *C, wmOperatorType *ot, bool vdata, bo return OPERATOR_INTERFACE; } - -static int sculpt_dynamic_topology_toggle_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +static enum eDynTopoWarnFlag sculpt_dynamic_topology_check(bContext *C) { Object *ob = CTX_data_active_object(C); Mesh *me = ob->data; SculptSession *ss = ob->sculpt; - if (!ss->bm) { - Scene *scene = CTX_data_scene(C); - ModifierData *md; - VirtualModifierData virtualModifierData; - int i; - bool vdata = false; - bool modifiers = false; - - for (i = 0; i < CD_NUMTYPES; i++) { - if (!ELEM(i, CD_MVERT, CD_MEDGE, CD_MFACE, CD_MLOOP, CD_MPOLY, CD_PAINT_MASK, CD_ORIGINDEX) && - (CustomData_has_layer(&me->vdata, i) || - CustomData_has_layer(&me->edata, i) || - CustomData_has_layer(&me->ldata, i))) - { - vdata = true; - break; + Scene *scene = CTX_data_scene(C); + enum eDynTopoWarnFlag flag = 0; + + BLI_assert(ss->bm == NULL); + UNUSED_VARS_NDEBUG(ss); + + for (int i = 0; i < CD_NUMTYPES; i++) { + if (!ELEM(i, CD_MVERT, CD_MEDGE, CD_MFACE, CD_MLOOP, CD_MPOLY, CD_PAINT_MASK, CD_ORIGINDEX)) { + if (CustomData_has_layer(&me->vdata, i)) { + flag |= DYNTOPO_WARN_VDATA; + } + if (CustomData_has_layer(&me->edata, i)) { + flag |= DYNTOPO_WARN_EDATA; + } + if (CustomData_has_layer(&me->ldata, i)) { + flag |= DYNTOPO_WARN_LDATA; } } + } - md = modifiers_getVirtualModifierList(ob, &virtualModifierData); + { + VirtualModifierData virtualModifierData; + ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData); /* exception for shape keys because we can edit those */ for (; md; md = md->next) { @@ -5167,14 +5183,26 @@ static int sculpt_dynamic_topology_toggle_invoke(bContext *C, wmOperator *op, co if (!modifier_isEnabled(scene, md, eModifierMode_Realtime)) continue; if (mti->type == eModifierTypeType_Constructive) { - modifiers = true; + flag |= DYNTOPO_WARN_MODIFIER; break; } } + } - if (vdata || modifiers) { + return flag; +} + +static int sculpt_dynamic_topology_toggle_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +{ + Object *ob = CTX_data_active_object(C); + SculptSession *ss = ob->sculpt; + + if (!ss->bm) { + enum eDynTopoWarnFlag flag = sculpt_dynamic_topology_check(C); + + if (flag) { /* The mesh has customdata that will be lost, let the user confirm this is OK */ - return dyntopo_warning_popup(C, op->type, vdata, modifiers); + return dyntopo_warning_popup(C, op->type, flag); } } @@ -5249,6 +5277,8 @@ static int sculpt_symmetrize_exec(bContext *C, wmOperator *UNUSED(op)) sculpt_undo_push_node(ob, NULL, SCULPT_UNDO_DYNTOPO_SYMMETRIZE); BM_log_before_all_removed(ss->bm, ss->bm_log); + BM_mesh_toolflags_set(ss->bm, true); + /* Symmetrize and re-triangulate */ BMO_op_callf(ss->bm, BMO_FLAG_DEFAULTS, "symmetrize input=%avef direction=%i dist=%f", @@ -5258,6 +5288,8 @@ static int sculpt_symmetrize_exec(bContext *C, wmOperator *UNUSED(op)) /* bisect operator flags edges (keep tags clean for edge queue) */ BM_mesh_elem_hflag_disable_all(ss->bm, BM_EDGE, BM_ELEM_TAG, false); + BM_mesh_toolflags_set(ss->bm, false); + /* Finish undo */ BM_log_all_added(ss->bm, ss->bm_log); sculpt_undo_push_end(C); @@ -5327,6 +5359,9 @@ static int sculpt_mode_toggle_exec(bContext *C, wmOperator *op) * mode to ensure the undo stack stays in a consistent * state */ sculpt_dynamic_topology_toggle_exec(C, NULL); + + /* store so we know to re-enable when entering sculpt mode */ + me->flag |= ME_SCULPT_DYNAMIC_TOPOLOGY; } /* Leave sculptmode */ @@ -5340,12 +5375,6 @@ static int sculpt_mode_toggle_exec(bContext *C, wmOperator *op) /* Enter sculptmode */ ob->mode |= mode_flag; - /* Remove dynamic-topology flag; this will be enabled if the - * file was saved with dynamic topology on, but we don't - * automatically re-enter dynamic-topology mode when loading a - * file. */ - me->flag &= ~ME_SCULPT_DYNAMIC_TOPOLOGY; - if (flush_recalc) DAG_id_tag_update(&ob->id, OB_RECALC_DATA); @@ -5399,6 +5428,49 @@ static int sculpt_mode_toggle_exec(bContext *C, wmOperator *op) BKE_paint_init(scene, ePaintSculpt, PAINT_CURSOR_SCULPT); paint_cursor_start(C, sculpt_poll_view3d); + + /* Check dynamic-topology flag; re-enter dynamic-topology mode when changing modes, + * As long as no data was added that is not supported. */ + if (me->flag & ME_SCULPT_DYNAMIC_TOPOLOGY) { + const char *message_unsupported = NULL; + if (me->totloop != me->totpoly * 3) { + message_unsupported = TIP_("non-triangle face"); + } + else if (mmd != NULL) { + message_unsupported = TIP_("multi-res modifier"); + } + else { + enum eDynTopoWarnFlag flag = sculpt_dynamic_topology_check(C); + if (flag == 0) { + /* pass */ + } + else if (flag & DYNTOPO_WARN_VDATA) { + message_unsupported = TIP_("vertex data"); + } + else if (flag & DYNTOPO_WARN_EDATA) { + message_unsupported = TIP_("edge data"); + } + else if (flag & DYNTOPO_WARN_LDATA) { + message_unsupported = TIP_("face data"); + } + else if (flag & DYNTOPO_WARN_MODIFIER) { + message_unsupported = TIP_("constructive modifier"); + } + else { + BLI_assert(0); + } + } + + if (message_unsupported == NULL) { + sculpt_dynamic_topology_enable(C); + } + else { + BKE_reportf(op->reports, RPT_WARNING, + "Dynamic Topology found: %s, disabled", + message_unsupported); + me->flag &= ~ME_SCULPT_DYNAMIC_TOPOLOGY; + } + } } if (ob->derivedFinal) /* VBO no longer valid */ diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c index ceefda99002..44bd872d107 100644 --- a/source/blender/editors/sculpt_paint/sculpt_undo.c +++ b/source/blender/editors/sculpt_paint/sculpt_undo.c @@ -366,7 +366,9 @@ static void sculpt_undo_bmesh_enable(Object *ob, sculpt_pbvh_clear(ob); /* Create empty BMesh and enable logging */ - ss->bm = BM_mesh_create(&bm_mesh_allocsize_default); + ss->bm = BM_mesh_create( + &bm_mesh_allocsize_default, + &((struct BMeshCreateParams){.use_toolflags = false,})); BM_data_layer_add(ss->bm, &ss->bm->vdata, CD_PAINT_MASK); sculpt_dyntopo_node_layers_add(ss); me->flag |= ME_SCULPT_DYNAMIC_TOPOLOGY; diff --git a/source/blender/editors/sound/sound_ops.c b/source/blender/editors/sound/sound_ops.c index a4d9a920cbb..4931426d62e 100644 --- a/source/blender/editors/sound/sound_ops.c +++ b/source/blender/editors/sound/sound_ops.c @@ -116,7 +116,7 @@ static int sound_open_exec(bContext *C, wmOperator *op) info = AUD_getInfo(sound->playback_handle); if (info.specs.channels == AUD_CHANNELS_INVALID) { - BKE_sound_delete(bmain, sound); + BKE_libblock_free(bmain, sound); if (op->customdata) MEM_freeN(op->customdata); BKE_report(op->reports, RPT_ERROR, "Unsupported audio format"); return OPERATOR_CANCELLED; diff --git a/source/blender/editors/space_action/action_intern.h b/source/blender/editors/space_action/action_intern.h index 50e10e7e154..408eb38d386 100644 --- a/source/blender/editors/space_action/action_intern.h +++ b/source/blender/editors/space_action/action_intern.h @@ -59,6 +59,8 @@ void draw_channel_strips(struct bAnimContext *ac, struct SpaceAction *saction, s void ACTION_OT_select_all_toggle(struct wmOperatorType *ot); void ACTION_OT_select_border(struct wmOperatorType *ot); +void ACTION_OT_select_lasso(struct wmOperatorType *ot); +void ACTION_OT_select_circle(struct wmOperatorType *ot); void ACTION_OT_select_column(struct wmOperatorType *ot); void ACTION_OT_select_linked(struct wmOperatorType *ot); void ACTION_OT_select_more(struct wmOperatorType *ot); diff --git a/source/blender/editors/space_action/action_ops.c b/source/blender/editors/space_action/action_ops.c index f69f9944f8a..a261202b690 100644 --- a/source/blender/editors/space_action/action_ops.c +++ b/source/blender/editors/space_action/action_ops.c @@ -59,6 +59,8 @@ void action_operatortypes(void) WM_operatortype_append(ACTION_OT_clickselect); WM_operatortype_append(ACTION_OT_select_all_toggle); WM_operatortype_append(ACTION_OT_select_border); + WM_operatortype_append(ACTION_OT_select_lasso); + WM_operatortype_append(ACTION_OT_select_circle); WM_operatortype_append(ACTION_OT_select_column); WM_operatortype_append(ACTION_OT_select_linked); WM_operatortype_append(ACTION_OT_select_more); @@ -178,6 +180,14 @@ static void action_keymap_keyframes(wmKeyConfig *keyconf, wmKeyMap *keymap) kmi = WM_keymap_add_item(keymap, "ACTION_OT_select_border", BKEY, KM_PRESS, KM_ALT, 0); RNA_boolean_set(kmi->ptr, "axis_range", true); + /* region select */ + kmi = WM_keymap_add_item(keymap, "ACTION_OT_select_lasso", EVT_TWEAK_A, KM_ANY, KM_CTRL, 0); + RNA_boolean_set(kmi->ptr, "deselect", false); + kmi = WM_keymap_add_item(keymap, "ACTION_OT_select_lasso", EVT_TWEAK_A, KM_ANY, KM_CTRL | KM_SHIFT, 0); + RNA_boolean_set(kmi->ptr, "deselect", true); + + WM_keymap_add_item(keymap, "ACTION_OT_select_circle", CKEY, KM_PRESS, 0, 0); + /* column select */ RNA_enum_set(WM_keymap_add_item(keymap, "ACTION_OT_select_column", KKEY, KM_PRESS, 0, 0)->ptr, "mode", ACTKEYS_COLUMNSEL_KEYS); RNA_enum_set(WM_keymap_add_item(keymap, "ACTION_OT_select_column", KKEY, KM_PRESS, KM_CTRL, 0)->ptr, "mode", ACTKEYS_COLUMNSEL_CFRA); diff --git a/source/blender/editors/space_action/action_select.c b/source/blender/editors/space_action/action_select.c index f2813b2a8d3..7900217e28e 100644 --- a/source/blender/editors/space_action/action_select.c +++ b/source/blender/editors/space_action/action_select.c @@ -36,6 +36,7 @@ #include "BLI_blenlib.h" #include "BLI_dlrbTree.h" +#include "BLI_lasso.h" #include "BLI_utildefines.h" #include "DNA_anim_types.h" @@ -375,6 +376,264 @@ void ACTION_OT_select_border(wmOperatorType *ot) ot->prop = RNA_def_boolean(ot->srna, "axis_range", 0, "Axis Range", ""); } +/* ******************** Region Select Operators ***************************** */ +/* "Region Select" operators include the Lasso and Circle Select operators. + * These two ended up being lumped together, as it was easier in the + * original Graph Editor implementation of these to do it this way. + */ + +static void region_select_action_keys(bAnimContext *ac, const rctf *rectf_view, short mode, short selectmode, void *data) +{ + ListBase anim_data = {NULL, NULL}; + bAnimListElem *ale; + int filter; + + KeyframeEditData ked; + KeyframeEditFunc ok_cb, select_cb; + View2D *v2d = &ac->ar->v2d; + rctf rectf, scaled_rectf; + float ymin = 0, ymax = (float)(-ACHANNEL_HEIGHT_HALF); + + /* convert mouse coordinates to frame ranges and channel coordinates corrected for view pan/zoom */ + UI_view2d_region_to_view_rctf(v2d, rectf_view, &rectf); + + /* filter data */ + filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS | ANIMFILTER_NODUPLIS); + ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); + + /* get beztriple editing/validation funcs */ + select_cb = ANIM_editkeyframes_select(selectmode); + ok_cb = ANIM_editkeyframes_ok(mode); + + /* init editing data */ + memset(&ked, 0, sizeof(KeyframeEditData)); + if (mode == BEZT_OK_CHANNEL_LASSO) { + KeyframeEdit_LassoData *data_lasso = data; + data_lasso->rectf_scaled = &scaled_rectf; + ked.data = data_lasso; + } + else if (mode == BEZT_OK_CHANNEL_CIRCLE) { + KeyframeEdit_CircleData *data_circle = data; + data_circle->rectf_scaled = &scaled_rectf; + ked.data = data; + } + else { + ked.data = &scaled_rectf; + } + + /* loop over data, doing region select */ + for (ale = anim_data.first; ale; ale = ale->next) { + AnimData *adt = ANIM_nla_mapping_get(ac, ale); + + /* get new vertical minimum extent of channel */ + ymin = ymax - ACHANNEL_STEP; + + /* compute midpoint of channel (used for testing if the key is in the region or not) */ + ked.channel_y = ymin + ACHANNEL_HEIGHT_HALF; + + /* if channel is mapped in NLA, apply correction + * - Apply to the bounds being checked, not all the keyframe points, + * to avoid having scaling everything + * - Save result to the scaled_rect, which is all that these operators + * will read from + */ + if (adt) { + ked.iterflags &= ~(KED_F1_NLA_UNMAP | KED_F2_NLA_UNMAP); + ked.f1 = BKE_nla_tweakedit_remap(adt, rectf.xmin, NLATIME_CONVERT_UNMAP); + ked.f2 = BKE_nla_tweakedit_remap(adt, rectf.xmax, NLATIME_CONVERT_UNMAP); + } + else { + ked.iterflags |= (KED_F1_NLA_UNMAP | KED_F2_NLA_UNMAP); /* for summary tracks */ + ked.f1 = rectf.xmin; + ked.f2 = rectf.xmax; + } + + /* Update values for scaled_rectf - which is used to compute the mapping in the callbacks + * NOTE: Since summary tracks need late-binding remapping, the callbacks may overwrite these + * with the properly remapped ked.f1/f2 values, when needed + */ + scaled_rectf.xmin = ked.f1; + scaled_rectf.xmax = ked.f2; + scaled_rectf.ymin = ymin; + scaled_rectf.ymax = ymax; + + /* perform vertical suitability check (if applicable) */ + if ((mode == ACTKEYS_BORDERSEL_FRAMERANGE) || + !((ymax < rectf.ymin) || (ymin > rectf.ymax))) + { + /* loop over data selecting */ + switch (ale->type) { + case ANIMTYPE_GPDATABLOCK: + { + bGPdata *gpd = ale->data; + bGPDlayer *gpl; + for (gpl = gpd->layers.first; gpl; gpl = gpl->next) { + ED_gplayer_frames_select_region(&ked, ale->data, mode, selectmode); + } + break; + } + case ANIMTYPE_GPLAYER: + { + ED_gplayer_frames_select_region(&ked, ale->data, mode, selectmode); + break; + } + case ANIMTYPE_MASKDATABLOCK: + { + Mask *mask = ale->data; + MaskLayer *masklay; + for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) { + ED_masklayer_frames_select_region(&ked, masklay, mode, selectmode); + } + break; + } + case ANIMTYPE_MASKLAYER: + { + ED_masklayer_frames_select_region(&ked, ale->data, mode, selectmode); + break; + } + default: + ANIM_animchannel_keyframes_loop(&ked, ac->ads, ale, ok_cb, select_cb, NULL); + break; + } + } + + /* set minimum extent to be the maximum of the next channel */ + ymax = ymin; + } + + /* cleanup */ + ANIM_animdata_freelist(&anim_data); +} + +/* ----------------------------------- */ + +static int actkeys_lassoselect_exec(bContext *C, wmOperator *op) +{ + bAnimContext ac; + + KeyframeEdit_LassoData data_lasso; + rcti rect; + rctf rect_fl; + + short selectmode; + bool extend; + + /* get editor data */ + if (ANIM_animdata_get_context(C, &ac) == 0) + return OPERATOR_CANCELLED; + + data_lasso.rectf_view = &rect_fl; + data_lasso.mcords = WM_gesture_lasso_path_to_array(C, op, &data_lasso.mcords_tot); + if (data_lasso.mcords == NULL) + return OPERATOR_CANCELLED; + + /* clear all selection if not extending selection */ + extend = RNA_boolean_get(op->ptr, "extend"); + if (!extend) + deselect_action_keys(&ac, 1, SELECT_SUBTRACT); + + if (!RNA_boolean_get(op->ptr, "deselect")) + selectmode = SELECT_ADD; + else + selectmode = SELECT_SUBTRACT; + + /* get settings from operator */ + BLI_lasso_boundbox(&rect, data_lasso.mcords, data_lasso.mcords_tot); + BLI_rctf_rcti_copy(&rect_fl, &rect); + + /* apply borderselect action */ + region_select_action_keys(&ac, &rect_fl, BEZT_OK_CHANNEL_LASSO, selectmode, &data_lasso); + + MEM_freeN((void *)data_lasso.mcords); + + /* send notifier that keyframe selection has changed */ + WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL); + + return OPERATOR_FINISHED; +} + +void ACTION_OT_select_lasso(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Lasso Select"; + ot->description = "Select keyframe points using lasso selection"; + ot->idname = "ACTION_OT_select_lasso"; + + /* api callbacks */ + ot->invoke = WM_gesture_lasso_invoke; + ot->modal = WM_gesture_lasso_modal; + ot->exec = actkeys_lassoselect_exec; + ot->poll = ED_operator_action_active; + ot->cancel = WM_gesture_lasso_cancel; + + /* flags */ + ot->flag = OPTYPE_UNDO; + + /* properties */ + RNA_def_collection_runtime(ot->srna, "path", &RNA_OperatorMousePath, "Path", ""); + RNA_def_boolean(ot->srna, "deselect", false, "Deselect", "Deselect rather than select items"); + RNA_def_boolean(ot->srna, "extend", true, "Extend", "Extend selection instead of deselecting everything first"); +} + +/* ------------------- */ + +static int action_circle_select_exec(bContext *C, wmOperator *op) +{ + bAnimContext ac; + const int gesture_mode = RNA_int_get(op->ptr, "gesture_mode"); + const short selectmode = (gesture_mode == GESTURE_MODAL_SELECT) ? SELECT_ADD : SELECT_SUBTRACT; + + KeyframeEdit_CircleData data = {0}; + rctf rect_fl; + + float x = RNA_int_get(op->ptr, "x"); + float y = RNA_int_get(op->ptr, "y"); + float radius = RNA_int_get(op->ptr, "radius"); + + /* get editor data */ + if (ANIM_animdata_get_context(C, &ac) == 0) + return OPERATOR_CANCELLED; + + data.mval[0] = x; + data.mval[1] = y; + data.radius_squared = radius * radius; + data.rectf_view = &rect_fl; + + rect_fl.xmin = x - radius; + rect_fl.xmax = x + radius; + rect_fl.ymin = y - radius; + rect_fl.ymax = y + radius; + + /* apply region select action */ + region_select_action_keys(&ac, &rect_fl, BEZT_OK_CHANNEL_CIRCLE, selectmode, &data); + + /* send notifier that keyframe selection has changed */ + WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL); + + return OPERATOR_FINISHED; +} + +void ACTION_OT_select_circle(wmOperatorType *ot) +{ + ot->name = "Circle Select"; + ot->description = "Select keyframe points using circle selection"; + ot->idname = "ACTION_OT_select_circle"; + + ot->invoke = WM_gesture_circle_invoke; + ot->modal = WM_gesture_circle_modal; + ot->exec = action_circle_select_exec; + ot->poll = ED_operator_action_active; + ot->cancel = WM_gesture_circle_cancel; + + /* flags */ + ot->flag = OPTYPE_UNDO; + + RNA_def_int(ot->srna, "x", 0, INT_MIN, INT_MAX, "X", "", INT_MIN, INT_MAX); + RNA_def_int(ot->srna, "y", 0, INT_MIN, INT_MAX, "Y", "", INT_MIN, INT_MAX); + RNA_def_int(ot->srna, "radius", 1, 1, INT_MAX, "Radius", "", 1, INT_MAX); + RNA_def_int(ot->srna, "gesture_mode", 0, INT_MIN, INT_MAX, "Event Type", "", INT_MIN, INT_MAX); +} + /* ******************** Column Select Operator **************************** */ /* This operator works in one of four ways: * - 1) select all keyframes in the same frame as a selected one (KKEY) diff --git a/source/blender/editors/space_action/space_action.c b/source/blender/editors/space_action/space_action.c index 60240109432..671d6bb083e 100644 --- a/source/blender/editors/space_action/space_action.c +++ b/source/blender/editors/space_action/space_action.c @@ -33,6 +33,7 @@ #include <stdio.h> #include "DNA_action_types.h" +#include "DNA_group_types.h" #include "DNA_scene_types.h" #include "MEM_guardedalloc.h" @@ -614,6 +615,19 @@ static void action_refresh(const bContext *C, ScrArea *sa) // XXX re-sizing y-extents of tot should go here? } +static void action_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID *new_id) +{ + SpaceAction *sact = (SpaceAction *)slink; + + if (!ELEM(GS(old_id->name), ID_GR)) { + return; + } + + if ((ID *)sact->ads.filter_grp == old_id) { + sact->ads.filter_grp = (Group *)new_id; + } +} + /* only called once, from space/spacetypes.c */ void ED_spacetype_action(void) { @@ -631,7 +645,8 @@ void ED_spacetype_action(void) st->keymap = action_keymap; st->listener = action_listener; st->refresh = action_refresh; - + st->id_remap = action_id_remap; + /* regions: main window */ art = MEM_callocN(sizeof(ARegionType), "spacetype action region"); art->regionid = RGN_TYPE_WINDOW; diff --git a/source/blender/editors/space_buttons/buttons_context.c b/source/blender/editors/space_buttons/buttons_context.c index 42e2d6b90f0..5b03bdd7761 100644 --- a/source/blender/editors/space_buttons/buttons_context.c +++ b/source/blender/editors/space_buttons/buttons_context.c @@ -1180,33 +1180,3 @@ ID *buttons_context_id_path(const bContext *C) return NULL; } - -void ED_buttons_id_unref(SpaceButs *sbuts, const ID *id) -{ - if (sbuts->pinid == id) { - sbuts->pinid = NULL; - sbuts->flag &= ~SB_PIN_CONTEXT; - } - - if (sbuts->path) { - ButsContextPath *path = sbuts->path; - int i; - - for (i = 0; i < path->len; i++) { - if (path->ptr[i].id.data == id) { - break; - } - } - - if (i == path->len) { - /* pass */ - } - else if (i == 0) { - MEM_SAFE_FREE(sbuts->path); - } - else { - memset(&path->ptr[i], 0, sizeof(path->ptr[i]) * (path->len - i)); - path->len = i; - } - } -} diff --git a/source/blender/editors/space_buttons/space_buttons.c b/source/blender/editors/space_buttons/space_buttons.c index 126a27c36cb..e4c23ad74f8 100644 --- a/source/blender/editors/space_buttons/space_buttons.c +++ b/source/blender/editors/space_buttons/space_buttons.c @@ -45,6 +45,8 @@ #include "WM_api.h" #include "WM_types.h" +#include "RNA_access.h" + #include "buttons_intern.h" /* own include */ /* ******************** default callbacks for buttons space ***************** */ @@ -389,6 +391,59 @@ static void buttons_area_listener(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier * ED_area_tag_redraw(sa); } +static void buttons_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID *new_id) +{ + SpaceButs *sbuts = (SpaceButs *)slink; + + if (sbuts->pinid == old_id) { + sbuts->pinid = new_id; + if (new_id == NULL) { + sbuts->flag &= ~SB_PIN_CONTEXT; + } + } + + if (sbuts->path) { + ButsContextPath *path = sbuts->path; + int i; + + for (i = 0; i < path->len; i++) { + if (path->ptr[i].id.data == old_id) { + break; + } + } + + if (i == path->len) { + /* pass */ + } + else if (new_id == NULL) { + if (i == 0) { + MEM_SAFE_FREE(sbuts->path); + } + else { + memset(&path->ptr[i], 0, sizeof(path->ptr[i]) * (path->len - i)); + path->len = i; + } + } + else { + RNA_id_pointer_create(new_id, &path->ptr[i]); + /* There is no easy way to check/make path downwards valid, just nullify it. + * Next redraw will rebuild this anyway. */ + i++; + memset(&path->ptr[i], 0, sizeof(path->ptr[i]) * (path->len - i)); + path->len = i; + } + } + + if (sbuts->texuser) { + ButsContextTexture *ct = sbuts->texuser; + if ((ID *)ct->texture == old_id) { + ct->texture = (Tex *)new_id; + } + BLI_freelistN(&ct->users); + ct->user = NULL; + } +} + /* only called once, from space/spacetypes.c */ void ED_spacetype_buttons(void) { @@ -406,7 +461,8 @@ void ED_spacetype_buttons(void) st->keymap = buttons_keymap; st->listener = buttons_area_listener; st->context = buttons_context; - + st->id_remap = buttons_id_remap; + /* regions: main window */ art = MEM_callocN(sizeof(ARegionType), "spacetype buttons region"); art->regionid = RGN_TYPE_WINDOW; diff --git a/source/blender/editors/space_clip/clip_draw.c b/source/blender/editors/space_clip/clip_draw.c index 1c5be3d1fb5..695d04d3850 100644 --- a/source/blender/editors/space_clip/clip_draw.c +++ b/source/blender/editors/space_clip/clip_draw.c @@ -336,8 +336,10 @@ static void draw_stabilization_border(SpaceClip *sc, ARegion *ar, int width, int /* draw boundary border for frame if stabilization is enabled */ if (sc->flag & SC_SHOW_STABLE && clip->tracking.stabilization.flag & TRACKING_2D_STABILIZATION) { glColor3f(0.0f, 0.0f, 0.0f); - glLineStipple(3, 0xaaaa); - glEnable(GL_LINE_STIPPLE); + + GPU_basic_shader_bind_enable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE); + GPU_basic_shader_line_stipple(3, 0xAAAA); + glEnable(GL_COLOR_LOGIC_OP); glLogicOp(GL_NOR); @@ -357,7 +359,7 @@ static void draw_stabilization_border(SpaceClip *sc, ARegion *ar, int width, int glPopMatrix(); glDisable(GL_COLOR_LOGIC_OP); - glDisable(GL_LINE_STIPPLE); + GPU_basic_shader_bind_disable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE); } } @@ -627,8 +629,8 @@ static void draw_marker_areas(SpaceClip *sc, MovieTrackingTrack *track, MovieTra glEnd(); glColor3f(0.0f, 0.0f, 0.0f); - glLineStipple(3, 0xaaaa); - glEnable(GL_LINE_STIPPLE); + GPU_basic_shader_bind_enable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE); + GPU_basic_shader_line_stipple(3, 0xAAAA); glEnable(GL_COLOR_LOGIC_OP); glLogicOp(GL_NOR); @@ -638,7 +640,7 @@ static void draw_marker_areas(SpaceClip *sc, MovieTrackingTrack *track, MovieTra glEnd(); glDisable(GL_COLOR_LOGIC_OP); - glDisable(GL_LINE_STIPPLE); + GPU_basic_shader_bind_disable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE); } } @@ -647,8 +649,11 @@ static void draw_marker_areas(SpaceClip *sc, MovieTrackingTrack *track, MovieTra glTranslate2fv(marker_pos); if (tiny) { - glLineStipple(3, 0xaaaa); - glEnable(GL_LINE_STIPPLE); + GPU_basic_shader_bind_enable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE); + GPU_basic_shader_line_stipple(3, 0xAAAA); + } + else { + GPU_basic_shader_bind_enable(GPU_SHADER_LINE); } if ((track->pat_flag & SELECT) == sel && (sc->flag & SC_SHOW_MARKER_PATTERN)) { @@ -713,8 +718,12 @@ static void draw_marker_areas(SpaceClip *sc, MovieTrackingTrack *track, MovieTra glEnd(); } - if (tiny) - glDisable(GL_LINE_STIPPLE); + if (tiny) { + GPU_basic_shader_bind_disable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE); + } + else { + GPU_basic_shader_bind_disable(GPU_SHADER_LINE); + } glPopMatrix(); } @@ -852,16 +861,12 @@ static void draw_marker_slide_zones(SpaceClip *sc, MovieTrackingTrack *track, Mo glLineWidth(outline ? 3.0f : 1.0f); - glEnable(GL_LINE_STIPPLE); - glLineStipple(3, 0xaaaa); - glBegin(GL_LINES); glVertex2f(0.0f, 0.0f); glVertex2fv(tilt_ctrl); glEnd(); - glDisable(GL_LINE_STIPPLE); - + GPU_basic_shader_bind_disable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE); /* slider to control pattern tilt */ draw_marker_slide_square(tilt_ctrl[0], tilt_ctrl[1], patdx, patdy, outline, px); @@ -1133,11 +1138,14 @@ static void draw_plane_marker_ex(SpaceClip *sc, Scene *scene, MovieTrackingPlane const bool thick = draw_outline && !tiny; if (stipple) { - glLineStipple(3, 0xaaaa); - glEnable(GL_LINE_STIPPLE); + GPU_basic_shader_bind_enable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE); + GPU_basic_shader_line_stipple(3, 0xAAAA); + } + else { + GPU_basic_shader_bind_enable(GPU_SHADER_LINE); } - glLineWidth(thick ? 3.0f : 1.0f); + GPU_basic_shader_line_width(thick ? 3.0f : 1.0f); /* Draw rectangle itself. */ glBegin(GL_LINE_LOOP); @@ -1169,8 +1177,12 @@ static void draw_plane_marker_ex(SpaceClip *sc, Scene *scene, MovieTrackingPlane glPopAttrib(); } - if (stipple) - glDisable(GL_LINE_STIPPLE); + if (stipple) { + GPU_basic_shader_bind_disable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE); + } + else { + GPU_basic_shader_bind_disable(GPU_SHADER_LINE); + } } /* Draw sliders. */ diff --git a/source/blender/editors/space_clip/space_clip.c b/source/blender/editors/space_clip/space_clip.c index e1d4e4fabc5..415839ab761 100644 --- a/source/blender/editors/space_clip/space_clip.c +++ b/source/blender/editors/space_clip/space_clip.c @@ -45,6 +45,7 @@ #include "BKE_context.h" #include "BKE_screen.h" +#include "BKE_library.h" #include "BKE_movieclip.h" #include "BKE_tracking.h" @@ -1512,6 +1513,25 @@ static void clip_properties_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED /********************* registration ********************/ +static void clip_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID *new_id) +{ + SpaceClip *sclip = (SpaceClip *)slink; + + if (!ELEM(GS(old_id->name), ID_MC, ID_MSK)) { + return; + } + + if ((ID *)sclip->clip == old_id) { + sclip->clip = (MovieClip *)new_id; + id_us_ensure_real(new_id); + } + + if ((ID *)sclip->mask_info.mask == old_id) { + sclip->mask_info.mask = (Mask *)new_id; + id_us_ensure_real(new_id); + } +} + /* only called once, from space/spacetypes.c */ void ED_spacetype_clip(void) { @@ -1531,6 +1551,7 @@ void ED_spacetype_clip(void) st->context = clip_context; st->dropboxes = clip_dropboxes; st->refresh = clip_refresh; + st->id_remap = clip_id_remap; /* regions: main window */ art = MEM_callocN(sizeof(ARegionType), "spacetype clip region"); diff --git a/source/blender/editors/space_file/file_intern.h b/source/blender/editors/space_file/file_intern.h index 71e38f72a7a..a55b18a2212 100644 --- a/source/blender/editors/space_file/file_intern.h +++ b/source/blender/editors/space_file/file_intern.h @@ -128,6 +128,7 @@ void file_panels_register(struct ARegionType *art); /* file_utils.c */ void file_tile_boundbox(const ARegion *ar, FileLayout *layout, const int file, rcti *r_bounds); +bool file_is_dir(struct SpaceFile *sfile, const char *path); #endif /* __FILE_INTERN_H__ */ diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c index d83a7d5ea62..c42ff120102 100644 --- a/source/blender/editors/space_file/file_ops.c +++ b/source/blender/editors/space_file/file_ops.c @@ -208,7 +208,7 @@ static FileSelect file_select_do(bContext *C, int selected_idx, bool do_diropen) BLI_add_slash(params->dir); } - ED_file_change_dir(C, false); + ED_file_change_dir(C); retval = FILE_SELECT_DIR; } } @@ -826,7 +826,7 @@ static int bookmark_select_exec(bContext *C, wmOperator *op) RNA_property_string_get(op->ptr, prop, entry); BLI_strncpy(params->dir, entry, sizeof(params->dir)); BLI_cleanup_dir(G.main->name, params->dir); - ED_file_change_dir(C, true); + ED_file_change_dir(C); WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL); } @@ -1379,7 +1379,7 @@ int file_exec(bContext *C, wmOperator *exec_op) BLI_add_slash(sfile->params->dir); } - ED_file_change_dir(C, false); + ED_file_change_dir(C); } /* opening file - sends events now, so things get handled on windowqueue level */ else if (sfile->op) { @@ -1447,19 +1447,7 @@ int file_parent_exec(bContext *C, wmOperator *UNUSED(unused)) if (sfile->params) { if (BLI_parent_dir(sfile->params->dir)) { BLI_cleanup_dir(G.main->name, sfile->params->dir); - /* if not browsing in .blend file, we still want to check whether the path is a directory */ - if (sfile->params->type == FILE_LOADLIB) { - char tdir[FILE_MAX]; - if (BLO_library_path_explode(sfile->params->dir, tdir, NULL, NULL)) { - ED_file_change_dir(C, false); - } - else { - ED_file_change_dir(C, true); - } - } - else { - ED_file_change_dir(C, true); - } + ED_file_change_dir(C); if (sfile->params->recursion_level > 1) { /* Disable 'dirtree' recursion when going up in tree. */ sfile->params->recursion_level = 0; @@ -1529,7 +1517,7 @@ int file_previous_exec(bContext *C, wmOperator *UNUSED(unused)) folderlist_popdir(sfile->folders_prev, sfile->params->dir); folderlist_pushdir(sfile->folders_next, sfile->params->dir); - ED_file_change_dir(C, true); + ED_file_change_dir(C); } WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL); @@ -1561,7 +1549,7 @@ int file_next_exec(bContext *C, wmOperator *UNUSED(unused)) // update folders_prev so we can check for it in folderlist_clear_next() folderlist_pushdir(sfile->folders_prev, sfile->params->dir); - ED_file_change_dir(C, true); + ED_file_change_dir(C); } WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL); @@ -1809,7 +1797,7 @@ int file_directory_new_exec(bContext *C, wmOperator *op) if (RNA_boolean_get(op->ptr, "open")) { BLI_strncpy(sfile->params->dir, path, sizeof(sfile->params->dir)); - ED_file_change_dir(C, true); + ED_file_change_dir(C); } WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL); @@ -1906,17 +1894,35 @@ void file_directory_enter_handle(bContext *C, void *UNUSED(arg_unused), void *UN file_expand_directory(C); /* special case, user may have pasted a filepath into the directory */ - if (BLI_is_file(sfile->params->dir)) { - char path[sizeof(sfile->params->dir)]; - BLI_strncpy(path, sfile->params->dir, sizeof(path)); - BLI_split_dirfile(path, sfile->params->dir, sfile->params->file, sizeof(sfile->params->dir), sizeof(sfile->params->file)); + if (!file_is_dir(sfile, sfile->params->dir)) { + char tdir[FILE_MAX_LIBEXTRA]; + char *group, *name; + + if (BLI_is_file(sfile->params->dir)) { + char path[sizeof(sfile->params->dir)]; + BLI_strncpy(path, sfile->params->dir, sizeof(path)); + BLI_split_dirfile(path, sfile->params->dir, sfile->params->file, + sizeof(sfile->params->dir), sizeof(sfile->params->file)); + } + else if (BLO_library_path_explode(sfile->params->dir, tdir, &group, &name)) { + if (group) { + BLI_path_append(tdir, sizeof(tdir), group); + } + BLI_strncpy(sfile->params->dir, tdir, sizeof(sfile->params->dir)); + if (name) { + BLI_strncpy(sfile->params->file, name, sizeof(sfile->params->file)); + } + else { + sfile->params->file[0] = '\0'; + } + } } BLI_cleanup_dir(G.main->name, sfile->params->dir); - if (BLI_exists(sfile->params->dir)) { + if (file_is_dir(sfile, sfile->params->dir)) { /* if directory exists, enter it immediately */ - ED_file_change_dir(C, true); + ED_file_change_dir(C); /* don't do for now because it selects entire text instead of * placing cursor at the end */ @@ -1931,20 +1937,26 @@ void file_directory_enter_handle(bContext *C, void *UNUSED(arg_unused), void *UN #endif else { const char *lastdir = folderlist_peeklastdir(sfile->folders_prev); + char tdir[FILE_MAX_LIBEXTRA]; - /* if not, ask to create it and enter if confirmed */ - wmOperatorType *ot = WM_operatortype_find("FILE_OT_directory_new", false); - PointerRNA ptr; - WM_operator_properties_create_ptr(&ptr, ot); - RNA_string_set(&ptr, "directory", sfile->params->dir); - RNA_boolean_set(&ptr, "open", true); - - if (lastdir) + /* If we are 'inside' a blend library, we cannot do anything... */ + if (lastdir && BLO_library_path_explode(lastdir, tdir, NULL, NULL)) { BLI_strncpy(sfile->params->dir, lastdir, sizeof(sfile->params->dir)); - - - WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &ptr); - WM_operator_properties_free(&ptr); + } + else { + /* if not, ask to create it and enter if confirmed */ + wmOperatorType *ot = WM_operatortype_find("FILE_OT_directory_new", false); + PointerRNA ptr; + WM_operator_properties_create_ptr(&ptr, ot); + RNA_string_set(&ptr, "directory", sfile->params->dir); + RNA_boolean_set(&ptr, "open", true); + + if (lastdir) + BLI_strncpy(sfile->params->dir, lastdir, sizeof(sfile->params->dir)); + + WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &ptr); + WM_operator_properties_free(&ptr); + } } WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL); @@ -1971,8 +1983,6 @@ void file_filename_enter_handle(bContext *C, void *UNUSED(arg_unused), void *arg BLI_filename_make_safe(sfile->params->file); if (matches) { - /* int i, numfiles = filelist_numfiles(sfile->files); */ /* XXX UNUSED */ - sfile->params->file[0] = '\0'; /* replace the pattern (or filename that the user typed in, with the first selected file of the match */ BLI_strncpy(sfile->params->file, matched_file, sizeof(sfile->params->file)); @@ -1980,30 +1990,17 @@ void file_filename_enter_handle(bContext *C, void *UNUSED(arg_unused), void *arg } if (matches == 1) { - BLI_join_dirfile(filepath, sizeof(sfile->params->dir), sfile->params->dir, sfile->params->file); /* if directory, open it and empty filename field */ - if (BLI_is_dir(filepath)) { + if (file_is_dir(sfile, filepath)) { BLI_cleanup_dir(G.main->name, filepath); BLI_strncpy(sfile->params->dir, filepath, sizeof(sfile->params->dir)); sfile->params->file[0] = '\0'; - ED_file_change_dir(C, true); + ED_file_change_dir(C); UI_textbutton_activate_but(C, but); WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL); } - else if (sfile->params->type == FILE_LOADLIB) { - char tdir[FILE_MAX]; - BLI_add_slash(filepath); - if (BLO_library_path_explode(filepath, tdir, NULL, NULL)) { - BLI_cleanup_dir(G.main->name, filepath); - BLI_strncpy(sfile->params->dir, filepath, sizeof(sfile->params->dir)); - sfile->params->file[0] = '\0'; - ED_file_change_dir(C, false); - UI_textbutton_activate_but(C, but); - WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL); - } - } } else if (matches > 1) { file_draw_check(C); diff --git a/source/blender/editors/space_file/file_utils.c b/source/blender/editors/space_file/file_utils.c index 3c007f25da3..f19e301064d 100644 --- a/source/blender/editors/space_file/file_utils.c +++ b/source/blender/editors/space_file/file_utils.c @@ -25,6 +25,9 @@ */ #include "BLI_rect.h" +#include "BLI_fileops.h" + +#include "BLO_readfile.h" #include "BKE_context.h" @@ -45,3 +48,17 @@ void file_tile_boundbox(const ARegion *ar, FileLayout *layout, const int file, r BLI_rcti_init(r_bounds, xmin, xmin + layout->tile_w + layout->tile_border_x, ymax - layout->tile_h - layout->tile_border_y, ymax); } + +/* Cannot directly use BLI_is_dir in libloading context... */ +bool file_is_dir(struct SpaceFile *sfile, const char *path) +{ + if (sfile->params->type == FILE_LOADLIB) { + char tdir[FILE_MAX_LIBEXTRA]; + char *name; + if (BLO_library_path_explode(sfile->params->dir, tdir, NULL, &name) && BLI_is_file(tdir)) { + /* .blend file itself and group are considered as directories, not final datablock names. */ + return name ? false : true; + } + } + return BLI_is_dir(path); +} diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c index 8e1f781827a..5e9eb1f9207 100644 --- a/source/blender/editors/space_file/filelist.c +++ b/source/blender/editors/space_file/filelist.c @@ -624,7 +624,7 @@ static bool is_filtered_file(FileListInternEntry *file, const char *UNUSED(root) static bool is_filtered_lib(FileListInternEntry *file, const char *root, FileListFilter *filter) { bool is_filtered; - char path[FILE_MAX_LIBEXTRA], dir[FILE_MAXDIR], *group, *name; + char path[FILE_MAX_LIBEXTRA], dir[FILE_MAX_LIBEXTRA], *group, *name; BLI_join_dirfile(path, sizeof(path), root, file->relpath); @@ -697,7 +697,7 @@ void filelist_filter(FileList *filelist) if (filelist->max_recursion) { /* Never show lib ID 'categories' directories when we are in 'flat' mode, unless * root path is a blend file. */ - char dir[FILE_MAXDIR]; + char dir[FILE_MAX_LIBEXTRA]; if (!filelist_islibrary(filelist, dir, NULL)) { filelist->filter_data.flags |= FLF_HIDE_LIB_DIR; } @@ -947,7 +947,7 @@ static void filelist_checkdir_dir(struct FileList *UNUSED(filelist), char *r_dir static void filelist_checkdir_lib(struct FileList *UNUSED(filelist), char *r_dir) { - char dir[FILE_MAXDIR]; + char dir[FILE_MAX_LIBEXTRA]; if (!BLO_library_path_explode(r_dir, dir, NULL, NULL)) { /* if not a valid library, we need it to be a valid directory! */ BLI_make_exist(r_dir); @@ -1925,7 +1925,8 @@ static bool file_is_blend_backup(const char *str) return (retval); } -static int path_extension_type(const char *path) +/* TODO: Maybe we should move this to BLI? On the other hand, it's using defines from spacefile area, so not sure... */ +int ED_path_extension_type(const char *path) { if (BLO_has_bfile_extension(path)) { return FILE_TYPE_BLENDER; @@ -1977,12 +1978,12 @@ static int file_extension_type(const char *dir, const char *relpath) { char path[FILE_MAX]; BLI_join_dirfile(path, sizeof(path), dir, relpath); - return path_extension_type(path); + return ED_path_extension_type(path); } int ED_file_extension_icon(const char *path) { - int type = path_extension_type(path); + const int type = ED_path_extension_type(path); switch (type) { case FILE_TYPE_BLENDER: @@ -2112,6 +2113,7 @@ unsigned int filelist_entry_select_index_get(FileList *filelist, const int index return 0; } +/* WARNING! dir must be FILE_MAX_LIBEXTRA long! */ bool filelist_islibrary(struct FileList *filelist, char *dir, char **group) { return BLO_library_path_explode(filelist->filelist.root, dir, group, NULL); @@ -2207,7 +2209,7 @@ static int filelist_readjob_list_lib(const char *root, ListBase *entries, const FileListInternEntry *entry; LinkNode *ln, *names; int i, nnames, idcode = 0, nbr_entries = 0; - char dir[FILE_MAX], *group; + char dir[FILE_MAX_LIBEXTRA], *group; bool ok; struct BlendHandle *libfiledata = NULL; diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c index bf90a4ea170..175d83506c6 100644 --- a/source/blender/editors/space_file/filesel.c +++ b/source/blender/editors/space_file/filesel.c @@ -576,7 +576,7 @@ FileLayout *ED_fileselect_get_layout(struct SpaceFile *sfile, ARegion *ar) return sfile->layout; } -void ED_file_change_dir(bContext *C, const bool checkdir) +void ED_file_change_dir(bContext *C) { wmWindowManager *wm = CTX_wm_manager(C); SpaceFile *sfile = CTX_wm_space_file(C); @@ -590,7 +590,7 @@ void ED_file_change_dir(bContext *C, const bool checkdir) sfile->params->filter_search[0] = '\0'; sfile->params->active_file = -1; - if (checkdir && !BLI_is_dir(sfile->params->dir)) { + if (!file_is_dir(sfile, sfile->params->dir)) { BLI_strncpy(sfile->params->dir, filelist_dir(sfile->files), sizeof(sfile->params->dir)); /* could return but just refresh the current dir */ } diff --git a/source/blender/editors/space_graph/graph_ops.c b/source/blender/editors/space_graph/graph_ops.c index 6b860990c10..478dbd3d9c0 100644 --- a/source/blender/editors/space_graph/graph_ops.c +++ b/source/blender/editors/space_graph/graph_ops.c @@ -555,19 +555,20 @@ static void graphedit_keymap_keyframes(wmKeyConfig *keyconf, wmKeyMap *keymap) kmi = WM_keymap_add_item(keymap, "GRAPH_OT_select_border", BKEY, KM_PRESS, KM_ALT, 0); RNA_boolean_set(kmi->ptr, "axis_range", true); RNA_boolean_set(kmi->ptr, "include_handles", false); - + kmi = WM_keymap_add_item(keymap, "GRAPH_OT_select_border", BKEY, KM_PRESS, KM_CTRL, 0); RNA_boolean_set(kmi->ptr, "axis_range", false); RNA_boolean_set(kmi->ptr, "include_handles", true); kmi = WM_keymap_add_item(keymap, "GRAPH_OT_select_border", BKEY, KM_PRESS, KM_CTRL | KM_ALT, 0); RNA_boolean_set(kmi->ptr, "axis_range", true); RNA_boolean_set(kmi->ptr, "include_handles", true); - + + /* region select */ kmi = WM_keymap_add_item(keymap, "GRAPH_OT_select_lasso", EVT_TWEAK_A, KM_ANY, KM_CTRL, 0); RNA_boolean_set(kmi->ptr, "deselect", false); kmi = WM_keymap_add_item(keymap, "GRAPH_OT_select_lasso", EVT_TWEAK_A, KM_ANY, KM_CTRL | KM_SHIFT, 0); RNA_boolean_set(kmi->ptr, "deselect", true); - + WM_keymap_add_item(keymap, "GRAPH_OT_select_circle", CKEY, KM_PRESS, 0, 0); /* column select */ diff --git a/source/blender/editors/space_graph/graph_select.c b/source/blender/editors/space_graph/graph_select.c index eb786d872ec..67b960bfa53 100644 --- a/source/blender/editors/space_graph/graph_select.c +++ b/source/blender/editors/space_graph/graph_select.c @@ -210,6 +210,8 @@ void GRAPH_OT_select_all_toggle(wmOperatorType *ot) * -> ALT-BKEY - depending on which axis of the region was larger... * -> 2) x-axis, so select all frames within frame range (validation with BEZT_OK_FRAMERANGE) * -> 3) y-axis, so select all frames within channels that region included (validation with BEZT_OK_VALUERANGE) + * + * The selection backend is also reused for the Lasso and Circle select operators. */ /* Borderselect only selects keyframes now, as overshooting handles often get caught too, @@ -245,12 +247,12 @@ static void borderselect_graphkeys( /* init editing data */ memset(&ked, 0, sizeof(KeyframeEditData)); if (mode == BEZT_OK_REGION_LASSO) { - struct KeyframeEdit_LassoData *data_lasso = data; + KeyframeEdit_LassoData *data_lasso = data; data_lasso->rectf_scaled = &scaled_rectf; ked.data = data_lasso; } else if (mode == BEZT_OK_REGION_CIRCLE) { - struct KeyframeEdit_CircleData *data_circle = data; + KeyframeEdit_CircleData *data_circle = data; data_circle->rectf_scaled = &scaled_rectf; ked.data = data; } @@ -265,27 +267,27 @@ static void borderselect_graphkeys( } else mapping_flag = ANIM_UNITCONV_ONLYKEYS; - + mapping_flag |= ANIM_get_normalization_flags(ac); - + /* loop over data, doing border select */ for (ale = anim_data.first; ale; ale = ale->next) { AnimData *adt = ANIM_nla_mapping_get(ac, ale); FCurve *fcu = (FCurve *)ale->key_data; float offset; float unit_scale = ANIM_unit_mapping_get_factor(ac->scene, ale->id, fcu, mapping_flag, &offset); - + /* apply NLA mapping to all the keyframes, since it's easier than trying to * guess when a callback might use something different */ if (adt) ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, incl_handles == 0); - + scaled_rectf.xmin = rectf.xmin; scaled_rectf.xmax = rectf.xmax; scaled_rectf.ymin = rectf.ymin / unit_scale - offset; scaled_rectf.ymax = rectf.ymax / unit_scale - offset; - + /* set horizontal range (if applicable) * NOTE: these values are only used for x-range and y-range but not region * (which uses ked.data, i.e. rectf) @@ -406,37 +408,41 @@ void GRAPH_OT_select_border(wmOperatorType *ot) RNA_def_boolean(ot->srna, "include_handles", 0, "Include Handles", "Are handles tested individually against the selection criteria"); } + +/* ------------------- */ + static int graphkeys_lassoselect_exec(bContext *C, wmOperator *op) { bAnimContext ac; + + KeyframeEdit_LassoData data_lasso = {0}; rcti rect; rctf rect_fl; + short selectmode; bool incl_handles; bool extend; - - struct KeyframeEdit_LassoData data_lasso; - + /* get editor data */ if (ANIM_animdata_get_context(C, &ac) == 0) return OPERATOR_CANCELLED; - + data_lasso.rectf_view = &rect_fl; data_lasso.mcords = WM_gesture_lasso_path_to_array(C, op, &data_lasso.mcords_tot); if (data_lasso.mcords == NULL) return OPERATOR_CANCELLED; - + /* clear all selection if not extending selection */ extend = RNA_boolean_get(op->ptr, "extend"); if (!extend) deselect_graph_keys(&ac, 1, SELECT_SUBTRACT, true); - + if (!RNA_boolean_get(op->ptr, "deselect")) selectmode = SELECT_ADD; else selectmode = SELECT_SUBTRACT; - - if (ac.spacetype == SPACE_IPO) { + + { SpaceIpo *sipo = (SpaceIpo *)ac.sl; if (selectmode == SELECT_ADD) { incl_handles = ((sipo->flag & SIPO_SELVHANDLESONLY) || @@ -446,60 +452,57 @@ static int graphkeys_lassoselect_exec(bContext *C, wmOperator *op) incl_handles = (sipo->flag & SIPO_NOHANDLES) == 0; } } - else { - incl_handles = false; - } - - + /* get settings from operator */ BLI_lasso_boundbox(&rect, data_lasso.mcords, data_lasso.mcords_tot); - BLI_rctf_rcti_copy(&rect_fl, &rect); - + /* apply borderselect action */ borderselect_graphkeys(&ac, &rect_fl, BEZT_OK_REGION_LASSO, selectmode, incl_handles, &data_lasso); - + MEM_freeN((void *)data_lasso.mcords); - - + /* send notifier that keyframe selection has changed */ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL); - + return OPERATOR_FINISHED; } - void GRAPH_OT_select_lasso(wmOperatorType *ot) { /* identifiers */ ot->name = "Lasso Select"; ot->description = "Select keyframe points using lasso selection"; ot->idname = "GRAPH_OT_select_lasso"; - + /* api callbacks */ ot->invoke = WM_gesture_lasso_invoke; ot->modal = WM_gesture_lasso_modal; ot->exec = graphkeys_lassoselect_exec; ot->poll = graphop_visible_keyframes_poll; ot->cancel = WM_gesture_lasso_cancel; - + /* flags */ ot->flag = OPTYPE_UNDO; - + /* properties */ RNA_def_collection_runtime(ot->srna, "path", &RNA_OperatorMousePath, "Path", ""); RNA_def_boolean(ot->srna, "deselect", false, "Deselect", "Deselect rather than select items"); RNA_def_boolean(ot->srna, "extend", true, "Extend", "Extend selection instead of deselecting everything first"); } +/* ------------------- */ + static int graph_circle_select_exec(bContext *C, wmOperator *op) { bAnimContext ac; const int gesture_mode = RNA_int_get(op->ptr, "gesture_mode"); - short selectmode; - bool incl_handles; + const short selectmode = (gesture_mode == GESTURE_MODAL_SELECT) ? SELECT_ADD : SELECT_SUBTRACT; + bool incl_handles = false; + + KeyframeEdit_CircleData data = {0}; rctf rect_fl; - struct KeyframeEdit_CircleData data; + float x = RNA_int_get(op->ptr, "x"); float y = RNA_int_get(op->ptr, "y"); float radius = RNA_int_get(op->ptr, "radius"); @@ -507,23 +510,18 @@ static int graph_circle_select_exec(bContext *C, wmOperator *op) /* get editor data */ if (ANIM_animdata_get_context(C, &ac) == 0) return OPERATOR_CANCELLED; - + data.mval[0] = x; data.mval[1] = y; data.radius_squared = radius * radius; data.rectf_view = &rect_fl; - if (gesture_mode == GESTURE_MODAL_SELECT) - selectmode = SELECT_ADD; - else - selectmode = SELECT_SUBTRACT; - rect_fl.xmin = x - radius; rect_fl.xmax = x + radius; rect_fl.ymin = y - radius; rect_fl.ymax = y + radius; - if (ac.spacetype == SPACE_IPO) { + { SpaceIpo *sipo = (SpaceIpo *)ac.sl; if (selectmode == SELECT_ADD) { incl_handles = ((sipo->flag & SIPO_SELVHANDLESONLY) || @@ -533,10 +531,7 @@ static int graph_circle_select_exec(bContext *C, wmOperator *op) incl_handles = (sipo->flag & SIPO_NOHANDLES) == 0; } } - else { - incl_handles = false; - } - + /* apply borderselect action */ borderselect_graphkeys(&ac, &rect_fl, BEZT_OK_REGION_CIRCLE, selectmode, incl_handles, &data); diff --git a/source/blender/editors/space_graph/space_graph.c b/source/blender/editors/space_graph/space_graph.c index c6a8a9753d1..8ae5932f3fd 100644 --- a/source/blender/editors/space_graph/space_graph.c +++ b/source/blender/editors/space_graph/space_graph.c @@ -33,6 +33,7 @@ #include <stdio.h> #include "DNA_anim_types.h" +#include "DNA_group_types.h" #include "DNA_scene_types.h" #include "MEM_guardedalloc.h" @@ -610,6 +611,51 @@ static void graph_refresh(const bContext *C, ScrArea *sa) } break; } + case FCURVE_COLOR_AUTO_YRGB: + { + /* Like FCURVE_COLOR_AUTO_RGB, except this is for quaternions... */ + float *col = fcu->color; + + switch (fcu->array_index) { + case 1: + UI_GetThemeColor3fv(TH_AXIS_X, col); + break; + case 2: + UI_GetThemeColor3fv(TH_AXIS_Y, col); + break; + case 3: + UI_GetThemeColor3fv(TH_AXIS_Z, col); + break; + + case 0: + { + /* Special Case: "W" channel should be yellowish, so blend X and Y channel colors... */ + float c1[3], c2[3]; + float h1[3], h2[3]; + float hresult[3]; + + /* - get colors (rgb) */ + UI_GetThemeColor3fv(TH_AXIS_X, c1); + UI_GetThemeColor3fv(TH_AXIS_Y, c2); + + /* - perform blending in HSV space (to keep brightness similar) */ + rgb_to_hsv_v(c1, h1); + rgb_to_hsv_v(c2, h2); + + interp_v3_v3v3(hresult, h1, h2, 0.5f); + + /* - convert back to RGB for display */ + hsv_to_rgb_v(hresult, col); + break; + } + + default: + /* 'unknown' color - bluish so as to not conflict with handles */ + col[0] = 0.3f; col[1] = 0.8f; col[2] = 1.0f; + break; + } + break; + } case FCURVE_COLOR_AUTO_RAINBOW: default: { @@ -627,6 +673,19 @@ static void graph_refresh(const bContext *C, ScrArea *sa) } } +static void graph_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID *new_id) +{ + SpaceIpo *sgraph = (SpaceIpo *)slink; + + if (!ELEM(GS(old_id->name), ID_GR)) { + return; + } + + if ((ID *)sgraph->ads->filter_grp == old_id) { + sgraph->ads->filter_grp = (Group *)new_id; + } +} + /* only called once, from space/spacetypes.c */ void ED_spacetype_ipo(void) { @@ -644,7 +703,8 @@ void ED_spacetype_ipo(void) st->keymap = graphedit_keymap; st->listener = graph_listener; st->refresh = graph_refresh; - + st->id_remap = graph_id_remap; + /* regions: main window */ art = MEM_callocN(sizeof(ARegionType), "spacetype graphedit region"); art->regionid = RGN_TYPE_WINDOW; diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c index 8db5a8f9bd3..06caf930988 100644 --- a/source/blender/editors/space_image/image_ops.c +++ b/source/blender/editors/space_image/image_ops.c @@ -2979,7 +2979,7 @@ static void image_sample_apply(bContext *C, wmOperator *op, const wmEvent *event if (ibuf->zbuf) { info->z = ibuf->zbuf[y * ibuf->x + x]; info->zp = &info->z; - if (ibuf->zbuf == (int*)ibuf->rect) { + if (ibuf->zbuf == (int *)ibuf->rect) { info->colp = NULL; } } diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c index 168f9c0dfdf..35a658eac23 100644 --- a/source/blender/editors/space_image/space_image.c +++ b/source/blender/editors/space_image/space_image.c @@ -28,6 +28,7 @@ * \ingroup spimage */ +#include "DNA_gpencil_types.h" #include "DNA_mesh_types.h" #include "DNA_mask_types.h" #include "DNA_meshdata_types.h" @@ -44,6 +45,7 @@ #include "BKE_colortools.h" #include "BKE_context.h" #include "BKE_image.h" +#include "BKE_library.h" #include "BKE_scene.h" #include "BKE_screen.h" @@ -981,6 +983,31 @@ static void image_header_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa } } +static void image_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID *new_id) +{ + SpaceImage *simg = (SpaceImage *)slink; + + if (!ELEM(GS(old_id->name), ID_IM, ID_GD, ID_MSK)) { + return; + } + + if ((ID *)simg->image == old_id) { + simg->image = (Image *)new_id; + id_us_ensure_real(new_id); + } + + if ((ID *)simg->gpd == old_id) { + simg->gpd = (bGPdata *)new_id; + id_us_min(old_id); + id_us_plus(new_id); + } + + if ((ID *)simg->mask_info.mask == old_id) { + simg->mask_info.mask = (Mask *)new_id; + id_us_ensure_real(new_id); + } +} + /**************************** spacetype *****************************/ /* only called once, from space/spacetypes.c */ @@ -1002,7 +1029,8 @@ void ED_spacetype_image(void) st->refresh = image_refresh; st->listener = image_listener; st->context = image_context; - + st->id_remap = image_id_remap; + /* regions: main window */ art = MEM_callocN(sizeof(ARegionType), "spacetype image region"); art->regionid = RGN_TYPE_WINDOW; diff --git a/source/blender/editors/space_logic/space_logic.c b/source/blender/editors/space_logic/space_logic.c index 243a522011b..69966e9bf34 100644 --- a/source/blender/editors/space_logic/space_logic.c +++ b/source/blender/editors/space_logic/space_logic.c @@ -38,7 +38,10 @@ #include "BLI_blenlib.h" #include "BLI_utildefines.h" +#include "DNA_gpencil_types.h" + #include "BKE_context.h" +#include "BKE_library.h" #include "BKE_screen.h" #include "ED_space_api.h" @@ -300,6 +303,21 @@ static void logic_header_region_draw(const bContext *C, ARegion *ar) /**************************** spacetype *****************************/ +static void logic_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID *new_id) +{ + SpaceLogic *slog = (SpaceLogic *)slink; + + if (!ELEM(GS(old_id->name), ID_GD)) { + return; + } + + if ((ID *)slog->gpd == old_id) { + slog->gpd = (bGPdata *)new_id; + id_us_min(old_id); + id_us_plus(new_id); + } +} + /* only called once, from space/spacetypes.c */ void ED_spacetype_logic(void) { @@ -317,7 +335,8 @@ void ED_spacetype_logic(void) st->keymap = logic_keymap; st->refresh = logic_refresh; st->context = logic_context; - + st->id_remap = logic_id_remap; + /* regions: main window */ art = MEM_callocN(sizeof(ARegionType), "spacetype logic region"); art->regionid = RGN_TYPE_WINDOW; diff --git a/source/blender/editors/space_nla/space_nla.c b/source/blender/editors/space_nla/space_nla.c index e2b36c5b5ae..3b5604087b9 100644 --- a/source/blender/editors/space_nla/space_nla.c +++ b/source/blender/editors/space_nla/space_nla.c @@ -33,6 +33,7 @@ #include <stdio.h> #include "DNA_anim_types.h" +#include "DNA_group_types.h" #include "DNA_scene_types.h" #include "MEM_guardedalloc.h" @@ -501,6 +502,19 @@ static void nla_listener(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *wmn) } } +static void nla_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID *new_id) +{ + SpaceNla *snla = (SpaceNla *)slink; + + if (!ELEM(GS(old_id->name), ID_GR)) { + return; + } + + if ((ID *)snla->ads->filter_grp == old_id) { + snla->ads->filter_grp = (Group *)new_id; + } +} + /* only called once, from space/spacetypes.c */ void ED_spacetype_nla(void) { @@ -517,7 +531,8 @@ void ED_spacetype_nla(void) st->operatortypes = nla_operatortypes; st->listener = nla_listener; st->keymap = nla_keymap; - + st->id_remap = nla_id_remap; + /* regions: main window */ art = MEM_callocN(sizeof(ARegionType), "spacetype nla region"); art->regionid = RGN_TYPE_WINDOW; diff --git a/source/blender/editors/space_node/node_edit.c b/source/blender/editors/space_node/node_edit.c index 6ae72e2a164..ffe510016ff 100644 --- a/source/blender/editors/space_node/node_edit.c +++ b/source/blender/editors/space_node/node_edit.c @@ -740,34 +740,6 @@ void ED_node_set_active(Main *bmain, bNodeTree *ntree, bNode *node) } } -void ED_node_id_unref(SpaceNode *snode, const ID *id) -{ - if (GS(id->name) == ID_SCE) { - if (snode->id == id) { - /* nasty DNA logic for SpaceNode: - * ideally should be handled by editor code, but would be bad level call - */ - bNodeTreePath *path, *path_next; - for (path = snode->treepath.first; path; path = path_next) { - path_next = path->next; - MEM_freeN(path); - } - BLI_listbase_clear(&snode->treepath); - - snode->id = NULL; - snode->from = NULL; - snode->nodetree = NULL; - snode->edittree = NULL; - } - } - else if (GS(id->name) == ID_OB) { - if (snode->from == id) { - snode->flag &= ~SNODE_PIN; - snode->from = NULL; - } - } -} - void ED_node_post_apply_transform(bContext *UNUSED(C), bNodeTree *UNUSED(ntree)) { /* XXX This does not work due to layout functions relying on node->block, diff --git a/source/blender/editors/space_node/space_node.c b/source/blender/editors/space_node/space_node.c index df484724fc5..4ef703c8994 100644 --- a/source/blender/editors/space_node/space_node.c +++ b/source/blender/editors/space_node/space_node.c @@ -28,6 +28,7 @@ * \ingroup spnode */ +#include "DNA_gpencil_types.h" #include "DNA_lamp_types.h" #include "DNA_material_types.h" #include "DNA_node_types.h" @@ -821,6 +822,41 @@ static int node_context(const bContext *C, const char *member, bContextDataResul return 0; } +static void node_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID *new_id) +{ + SpaceNode *snode = (SpaceNode *)slink; + + if (GS(old_id->name) == ID_SCE) { + if (snode->id == old_id) { + /* nasty DNA logic for SpaceNode: + * ideally should be handled by editor code, but would be bad level call + */ + BLI_freelistN(&snode->treepath); + + /* XXX Untested in case new_id != NULL... */ + snode->id = new_id; + snode->from = NULL; + snode->nodetree = NULL; + snode->edittree = NULL; + } + } + else if (GS(old_id->name) == ID_OB) { + if (snode->from == old_id) { + if (new_id == NULL) { + snode->flag &= ~SNODE_PIN; + } + snode->from = new_id; + } + } + else if (GS(old_id->name) == ID_GD) { + if ((ID *)snode->gpd == old_id) { + snode->gpd = (bGPdata *)new_id; + id_us_min(old_id); + id_us_plus(new_id); + } + } +} + /* only called once, from space/spacetypes.c */ void ED_spacetype_node(void) { @@ -840,6 +876,7 @@ void ED_spacetype_node(void) st->refresh = node_area_refresh; st->context = node_context; st->dropboxes = node_dropboxes; + st->id_remap = node_id_remap; /* regions: main window */ art = MEM_callocN(sizeof(ARegionType), "spacetype node region"); diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c index b624c7cba75..43e9c262172 100644 --- a/source/blender/editors/space_outliner/outliner_draw.c +++ b/source/blender/editors/space_outliner/outliner_draw.c @@ -502,6 +502,11 @@ static void namebutton_cb(bContext *C, void *tsep, char *oldname) BKE_reportf(CTX_wm_reports(C), RPT_ERROR, "Library path '%s' does not exist, correct this before saving", expanded); } + else if (lib->id.tag & LIB_TAG_MISSING) { + BKE_reportf(CTX_wm_reports(C), RPT_INFO, + "Library path '%s' is now valid, please reload the library", expanded); + lib->id.tag &= ~LIB_TAG_MISSING; + } } } else { @@ -1579,11 +1584,19 @@ static void outliner_draw_tree_element( glDisable(GL_BLEND); /* name */ - if (active == OL_DRAWSEL_NORMAL) UI_ThemeColor(TH_TEXT_HI); - else if (ELEM(tselem->type, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM)) UI_ThemeColorBlend(TH_BACK, TH_TEXT, 0.75f); - else UI_ThemeColor(TH_TEXT); - - UI_fontstyle_draw_simple(fstyle, startx + offsx, *starty + 5 * ufac, te->name); + if ((tselem->flag & TSE_TEXTBUT) == 0) { + if (active == OL_DRAWSEL_NORMAL) { + UI_ThemeColor(TH_TEXT_HI); + } + else if (ELEM(tselem->type, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM)) { + UI_ThemeColorBlend(TH_BACK, TH_TEXT, 0.75f); + } + else { + UI_ThemeColor(TH_TEXT); + } + + UI_fontstyle_draw_simple(fstyle, startx + offsx, *starty + 5 * ufac, te->name); + } offsx += (int)(UI_UNIT_X + UI_fontstyle_string_width(fstyle, te->name)); diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c index 2627b978b40..07608b59d2e 100644 --- a/source/blender/editors/space_outliner/outliner_edit.c +++ b/source/blender/editors/space_outliner/outliner_edit.c @@ -29,17 +29,23 @@ * \ingroup spoutliner */ +#include <string.h> + #include "MEM_guardedalloc.h" #include "DNA_anim_types.h" #include "DNA_group_types.h" +#include "DNA_ID.h" #include "DNA_scene_types.h" #include "DNA_object_types.h" #include "DNA_material_types.h" #include "BLI_blenlib.h" #include "BLI_utildefines.h" +#include "BLI_path_util.h" #include "BLI_mempool.h" +#include "BLI_stack.h" +#include "BLI_string.h" #include "BLT_translation.h" @@ -47,7 +53,10 @@ #include "BKE_context.h" #include "BKE_depsgraph.h" #include "BKE_global.h" +#include "BKE_idcode.h" #include "BKE_library.h" +#include "BKE_library_query.h" +#include "BKE_library_remap.h" #include "BKE_main.h" #include "BKE_outliner_treehash.h" #include "BKE_report.h" @@ -55,6 +64,8 @@ #include "BKE_material.h" #include "BKE_group.h" +#include "../blenloader/BLO_readfile.h" + #include "ED_object.h" #include "ED_outliner.h" #include "ED_screen.h" @@ -70,6 +81,9 @@ #include "RNA_access.h" #include "RNA_define.h" +#include "RNA_enum_types.h" + +#include "GPU_material.h" #include "outliner_intern.h" @@ -230,8 +244,9 @@ static void do_item_rename(ARegion *ar, TreeElement *te, TreeStoreElem *tselem, } } -void item_rename_cb(bContext *C, Scene *UNUSED(scene), TreeElement *te, - TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) +void item_rename_cb( + bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *te, + TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) { ARegion *ar = CTX_wm_region(C); ReportList *reports = CTX_wm_reports(C); // XXX @@ -291,64 +306,315 @@ void OUTLINER_OT_item_rename(wmOperatorType *ot) ot->poll = ED_operator_outliner_active; } -/* Library delete --------------------------------------------------- */ +/* ID delete --------------------------------------------------- */ -static void lib_delete(bContext *C, TreeElement *te, TreeStoreElem *tselem, ReportList *reports) +static void id_delete(bContext *C, ReportList *reports, TreeElement *te, TreeStoreElem *tselem) { - Library *lib = (Library *)tselem->id; - ListBase *lbarray[MAX_LIBARRAY]; - int a; + Main *bmain = CTX_data_main(C); + ID *id = tselem->id; - BLI_assert(te->idcode == ID_LI && lib != NULL); + BLI_assert(te->idcode != 0 && id != NULL); + BLI_assert(te->idcode != ID_LI || ((Library *)id)->parent == NULL); UNUSED_VARS_NDEBUG(te); - /* We simply set all ID from given lib (including lib itself) to zero user count. - * It is not possible to do a proper cleanup without a save/reload in current master. */ - a = set_listbasepointers(CTX_data_main(C), lbarray); - while (a--) { - ListBase *lb = lbarray[a]; - ID *id; - - for (id = lb->first; id; id = id->next) { - if (id->lib == lib) { - id_fake_user_clear(id); - id->us = 0; + if (id->tag & LIB_TAG_INDIRECT) { + BKE_reportf(reports, RPT_WARNING, "Cannot delete indirectly linked id '%s'", id->name); + return; + } + else if (BKE_library_ID_is_indirectly_used(bmain, id) && ID_REAL_USERS(id) <= 1) { + BKE_reportf(reports, RPT_WARNING, + "Cannot delete id '%s', indirectly used datablocks need at least one user", + id->name); + return; + } + + + BKE_libblock_delete(bmain, id); + + WM_event_add_notifier(C, NC_WINDOW, NULL); +} + +void id_delete_cb( + bContext *C, ReportList *reports, Scene *UNUSED(scene), + TreeElement *te, TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) +{ + id_delete(C, reports, te, tselem); +} + +static int outliner_id_delete_invoke_do(bContext *C, ReportList *reports, TreeElement *te, const float mval[2]) +{ + if (mval[1] > te->ys && mval[1] < te->ys + UI_UNIT_Y) { + TreeStoreElem *tselem = TREESTORE(te); + + if (te->idcode != 0 && tselem->id) { + if (te->idcode == ID_LI && ((Library *)tselem->id)->parent) { + BKE_reportf(reports, RPT_ERROR_INVALID_INPUT, + "Cannot delete indirectly linked library '%s'", ((Library *)tselem->id)->filepath); + return OPERATOR_CANCELLED; + } + id_delete(C, reports, te, tselem); + return OPERATOR_FINISHED; + } + } + else { + for (te = te->subtree.first; te; te = te->next) { + int ret; + if ((ret = outliner_id_delete_invoke_do(C, reports, te, mval))) { + return ret; + } + } + } + + return 0; +} + +static int outliner_id_delete_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + ARegion *ar = CTX_wm_region(C); + SpaceOops *soops = CTX_wm_space_outliner(C); + TreeElement *te; + float fmval[2]; + + BLI_assert(ar && soops); + + UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]); + + for (te = soops->tree.first; te; te = te->next) { + int ret; + + if ((ret = outliner_id_delete_invoke_do(C, op->reports, te, fmval))) { + return ret; + } + } + + return OPERATOR_CANCELLED; +} + +void OUTLINER_OT_id_delete(wmOperatorType *ot) +{ + ot->name = "Delete Datablock"; + ot->idname = "OUTLINER_OT_id_delete"; + ot->description = "Delete the ID under cursor"; + + ot->invoke = outliner_id_delete_invoke; + ot->poll = ED_operator_outliner_active; +} + +/* ID remap --------------------------------------------------- */ + +static int outliner_id_remap_exec(bContext *C, wmOperator *op) +{ + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + SpaceOops *soops = CTX_wm_space_outliner(C); + + const short id_type = (short)RNA_enum_get(op->ptr, "id_type"); + ID *old_id = BLI_findlink(which_libbase(CTX_data_main(C), id_type), RNA_enum_get(op->ptr, "old_id")); + ID *new_id = BLI_findlink(which_libbase(CTX_data_main(C), id_type), RNA_enum_get(op->ptr, "new_id")); + + /* check for invalid states */ + if (soops == NULL) { + return OPERATOR_CANCELLED; + } + + if (!(old_id && (old_id != new_id) && (GS(old_id->name) == GS(new_id->name)))) { + BKE_reportf(op->reports, RPT_ERROR_INVALID_INPUT, "Invalid old/new ID pair ('%s' / '%s')", + old_id->name, new_id->name); + return OPERATOR_CANCELLED; + } + + if (old_id->lib) { + BKE_reportf(op->reports, RPT_WARNING, + "Old ID '%s' is linked from a library, indirect usages of this datablock will not be remapped", + old_id->name); + } + + BKE_libblock_remap(bmain, old_id, new_id, + ID_REMAP_SKIP_INDIRECT_USAGE | ID_REMAP_SKIP_NEVER_NULL_USAGE); + + BKE_main_lib_objects_recalc_all(bmain); + + /* recreate dependency graph to include new objects */ + DAG_scene_relations_rebuild(bmain, scene); + + /* free gpu materials, some materials depend on existing objects, such as lamps so freeing correctly refreshes */ + GPU_materials_free(); + + WM_event_add_notifier(C, NC_WINDOW, NULL); + + return OPERATOR_FINISHED; +} + +static bool outliner_id_remap_find_tree_element(bContext *C, wmOperator *op, ListBase *tree, const float y) +{ + TreeElement *te; + + for (te = tree->first; te; te = te->next) { + if (y > te->ys && y < te->ys + UI_UNIT_Y) { + TreeStoreElem *tselem = TREESTORE(te); + + if (tselem->type == 0 && tselem->id) { + printf("found id %s (%p)!\n", tselem->id->name, tselem->id); + + RNA_enum_set(op->ptr, "id_type", GS(tselem->id->name)); + RNA_enum_set_identifier(C, op->ptr, "new_id", tselem->id->name + 2); + RNA_enum_set_identifier(C, op->ptr, "old_id", tselem->id->name + 2); + return true; } } + if (outliner_id_remap_find_tree_element(C, op, &te->subtree, y)) { + return true; + } + } + return false; +} + +static int outliner_id_remap_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + SpaceOops *soops = CTX_wm_space_outliner(C); + ARegion *ar = CTX_wm_region(C); + float fmval[2]; + + if (!RNA_property_is_set(op->ptr, RNA_struct_find_property(op->ptr, "id_type"))) { + UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]); + + outliner_id_remap_find_tree_element(C, op, &soops->tree, fmval[1]); } - BKE_reportf(reports, RPT_WARNING, - "Please save and reload .blend file to complete deletion of '%s' library", - ((Library *)tselem->id)->filepath); + return WM_operator_props_dialog_popup(C, op, 200, 100); +} + +static EnumPropertyItem *outliner_id_itemf(bContext *C, PointerRNA *ptr, PropertyRNA *UNUSED(prop), bool *r_free) +{ + EnumPropertyItem item_tmp = {0}, *item = NULL; + int totitem = 0; + int i = 0; + + short id_type = (short)RNA_enum_get(ptr, "id_type"); + ID *id = which_libbase(CTX_data_main(C), id_type)->first; + + for (; id; id = id->next) { + item_tmp.identifier = item_tmp.name = id->name + 2; + item_tmp.value = i++; + RNA_enum_item_add(&item, &totitem, &item_tmp); + } + + RNA_enum_item_end(&item, &totitem); + *r_free = true; + + return item; +} + +void OUTLINER_OT_id_remap(wmOperatorType *ot) +{ + PropertyRNA *prop; + + /* identifiers */ + ot->name = "Outliner ID data Remap"; + ot->idname = "OUTLINER_OT_id_remap"; + ot->description = ""; + + /* callbacks */ + ot->invoke = outliner_id_remap_invoke; + ot->exec = outliner_id_remap_exec; + ot->poll = ED_operator_outliner_active; + + ot->flag = 0; + + RNA_def_enum(ot->srna, "id_type", rna_enum_id_type_items, ID_OB, "ID Type", ""); + + prop = RNA_def_enum(ot->srna, "old_id", DummyRNA_NULL_items, 0, "Old ID", "Old ID to replace"); + RNA_def_property_enum_funcs_runtime(prop, NULL, NULL, outliner_id_itemf); + RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE | PROP_HIDDEN); + + ot->prop = RNA_def_enum(ot->srna, "new_id", DummyRNA_NULL_items, 0, + "New ID", "New ID to remap all selected IDs' users to"); + RNA_def_property_enum_funcs_runtime(ot->prop, NULL, NULL, outliner_id_itemf); + RNA_def_property_flag(ot->prop, PROP_ENUM_NO_TRANSLATE); } -void lib_delete_cb( - bContext *C, Scene *UNUSED(scene), TreeElement *te, +void id_remap_cb( + bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te), TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) { - lib_delete(C, te, tselem, CTX_wm_reports(C)); + wmOperatorType *ot = WM_operatortype_find("OUTLINER_OT_id_remap", false); + PointerRNA op_props; + + BLI_assert(tselem->id != NULL); + + WM_operator_properties_create_ptr(&op_props, ot); + + RNA_enum_set(&op_props, "id_type", GS(tselem->id->name)); + RNA_enum_set_identifier(C, &op_props, "old_id", tselem->id->name + 2); + + WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &op_props); + + WM_operator_properties_free(&op_props); +} + +/* Library relocate/reload --------------------------------------------------- */ + +static int lib_relocate( + bContext *C, TreeElement *te, TreeStoreElem *tselem, wmOperatorType *ot, const bool reload) +{ + PointerRNA op_props; + int ret = 0; + + BLI_assert(te->idcode == ID_LI && tselem->id != NULL); + UNUSED_VARS_NDEBUG(te); + + WM_operator_properties_create_ptr(&op_props, ot); + + RNA_string_set(&op_props, "library", tselem->id->name + 2); + + if (reload) { + Library *lib = (Library *)tselem->id; + char dir[FILE_MAXDIR], filename[FILE_MAX]; + + BLI_split_dirfile(lib->filepath, dir, filename, sizeof(dir), sizeof(filename)); + + printf("%s, %s\n", tselem->id->name, lib->filepath); + + /* We assume if both paths in lib are not the same then lib->name was relative... */ + RNA_boolean_set(&op_props, "relative_path", BLI_path_cmp(lib->filepath, lib->name) != 0); + + RNA_string_set(&op_props, "directory", dir); + RNA_string_set(&op_props, "filename", filename); + + ret = WM_operator_name_call_ptr(C, ot, WM_OP_EXEC_DEFAULT, &op_props); + } + else { + ret = WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &op_props); + } + + WM_operator_properties_free(&op_props); + + return ret; } -static int outliner_lib_delete_invoke_do(bContext *C, ReportList *reports, TreeElement *te, const float mval[2]) +static int outliner_lib_relocate_invoke_do( + bContext *C, ReportList *reports, TreeElement *te, const float mval[2], const bool reload) { if (mval[1] > te->ys && mval[1] < te->ys + UI_UNIT_Y) { TreeStoreElem *tselem = TREESTORE(te); if (te->idcode == ID_LI && tselem->id) { - if (((Library *)tselem->id)->parent) { + if (((Library *)tselem->id)->parent && !reload) { BKE_reportf(reports, RPT_ERROR_INVALID_INPUT, - "Cannot delete indirectly linked library '%s'", ((Library *)tselem->id)->filepath); + "Cannot relocate indirectly linked library '%s'", ((Library *)tselem->id)->filepath); return OPERATOR_CANCELLED; } + else { + wmOperatorType *ot = WM_operatortype_find(reload ? "WM_OT_lib_reload" : "WM_OT_lib_relocate", false); - lib_delete(C, te, tselem, reports); - return OPERATOR_FINISHED; + return lib_relocate(C, te, tselem, ot, reload); + } } } else { for (te = te->subtree.first; te; te = te->next) { int ret; - if ((ret = outliner_lib_delete_invoke_do(C, reports, te, mval))) { + if ((ret = outliner_lib_relocate_invoke_do(C, reports, te, mval, reload))) { return ret; } } @@ -357,7 +623,51 @@ static int outliner_lib_delete_invoke_do(bContext *C, ReportList *reports, TreeE return 0; } -static int outliner_lib_delete_invoke(bContext *C, wmOperator *op, const wmEvent *event) +static int outliner_lib_relocate_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + ARegion *ar = CTX_wm_region(C); + SpaceOops *soops = CTX_wm_space_outliner(C); + TreeElement *te; + float fmval[2]; + + BLI_assert(ar && soops); + + UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]); + + for (te = soops->tree.first; te; te = te->next) { + int ret; + + if ((ret = outliner_lib_relocate_invoke_do(C, op->reports, te, fmval, false))) { + return ret; + } + } + + return OPERATOR_CANCELLED; +} + +void OUTLINER_OT_lib_relocate(wmOperatorType *ot) +{ + ot->name = "Relocate Library"; + ot->idname = "OUTLINER_OT_lib_relocate"; + ot->description = "Relocate the library under cursor"; + + ot->invoke = outliner_lib_relocate_invoke; + ot->poll = ED_operator_outliner_active; +} + +/* XXX This does not work with several items + * (it is only called once in the end, due to the 'deferred' filebrowser invocation through event system...). */ +void lib_relocate_cb( + bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *te, + TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) +{ + wmOperatorType *ot = WM_operatortype_find("WM_OT_lib_relocate", false); + + lib_relocate(C, te, tselem, ot, false); +} + + +static int outliner_lib_reload_invoke(bContext *C, wmOperator *op, const wmEvent *event) { ARegion *ar = CTX_wm_region(C); SpaceOops *soops = CTX_wm_space_outliner(C); @@ -371,7 +681,7 @@ static int outliner_lib_delete_invoke(bContext *C, wmOperator *op, const wmEvent for (te = soops->tree.first; te; te = te->next) { int ret; - if ((ret = outliner_lib_delete_invoke_do(C, op->reports, te, fmval))) { + if ((ret = outliner_lib_relocate_invoke_do(C, op->reports, te, fmval, true))) { return ret; } } @@ -379,16 +689,25 @@ static int outliner_lib_delete_invoke(bContext *C, wmOperator *op, const wmEvent return OPERATOR_CANCELLED; } -void OUTLINER_OT_lib_delete(wmOperatorType *ot) +void OUTLINER_OT_lib_reload(wmOperatorType *ot) { - ot->name = "Delete Library"; - ot->idname = "OUTLINER_OT_lib_delete"; - ot->description = "Delete the library under cursor (needs a save/reload)"; + ot->name = "Reload Library"; + ot->idname = "OUTLINER_OT_lib_reload"; + ot->description = "Reload the library under cursor"; - ot->invoke = outliner_lib_delete_invoke; + ot->invoke = outliner_lib_reload_invoke; ot->poll = ED_operator_outliner_active; } +void lib_reload_cb( + bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *te, + TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) +{ + wmOperatorType *ot = WM_operatortype_find("WM_OT_lib_reload", false); + + lib_relocate(C, te, tselem, ot, true); +} + /* ************************************************************** */ /* Setting Toggling Operators */ @@ -468,8 +787,9 @@ int common_restrict_check(bContext *C, Object *ob) /* Toggle Visibility ---------------------------------------- */ -void object_toggle_visibility_cb(bContext *C, Scene *scene, TreeElement *te, - TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) +void object_toggle_visibility_cb( + bContext *C, ReportList *UNUSED(reports), Scene *scene, TreeElement *te, + TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) { Base *base = (Base *)te->directdata; Object *ob = (Object *)tselem->id; @@ -484,21 +804,22 @@ void object_toggle_visibility_cb(bContext *C, Scene *scene, TreeElement *te, } } -void group_toggle_visibility_cb(bContext *UNUSED(C), Scene *scene, TreeElement *UNUSED(te), - TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) +void group_toggle_visibility_cb( + bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *scene, TreeElement *UNUSED(te), + TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) { Group *group = (Group *)tselem->id; restrictbutton_gr_restrict_flag(scene, group, OB_RESTRICT_VIEW); } -static int outliner_toggle_visibility_exec(bContext *C, wmOperator *UNUSED(op)) +static int outliner_toggle_visibility_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); SpaceOops *soops = CTX_wm_space_outliner(C); Scene *scene = CTX_data_scene(C); ARegion *ar = CTX_wm_region(C); - outliner_do_object_operation(C, scene, soops, &soops->tree, object_toggle_visibility_cb); + outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, object_toggle_visibility_cb); DAG_id_type_tag(bmain, ID_OB); WM_event_add_notifier(C, NC_SCENE | ND_OB_VISIBLE, scene); @@ -523,8 +844,9 @@ void OUTLINER_OT_visibility_toggle(wmOperatorType *ot) /* Toggle Selectability ---------------------------------------- */ -void object_toggle_selectability_cb(bContext *UNUSED(C), Scene *scene, TreeElement *te, - TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) +void object_toggle_selectability_cb( + bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *scene, TreeElement *te, + TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) { Base *base = (Base *)te->directdata; @@ -534,20 +856,21 @@ void object_toggle_selectability_cb(bContext *UNUSED(C), Scene *scene, TreeEleme } } -void group_toggle_selectability_cb(bContext *UNUSED(C), Scene *scene, TreeElement *UNUSED(te), - TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) +void group_toggle_selectability_cb( + bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *scene, TreeElement *UNUSED(te), + TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) { Group *group = (Group *)tselem->id; restrictbutton_gr_restrict_flag(scene, group, OB_RESTRICT_SELECT); } -static int outliner_toggle_selectability_exec(bContext *C, wmOperator *UNUSED(op)) +static int outliner_toggle_selectability_exec(bContext *C, wmOperator *op) { SpaceOops *soops = CTX_wm_space_outliner(C); Scene *scene = CTX_data_scene(C); ARegion *ar = CTX_wm_region(C); - outliner_do_object_operation(C, scene, soops, &soops->tree, object_toggle_selectability_cb); + outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, object_toggle_selectability_cb); WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); ED_region_tag_redraw(ar); @@ -571,8 +894,9 @@ void OUTLINER_OT_selectability_toggle(wmOperatorType *ot) /* Toggle Renderability ---------------------------------------- */ -void object_toggle_renderability_cb(bContext *UNUSED(C), Scene *scene, TreeElement *te, - TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) +void object_toggle_renderability_cb( + bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *scene, TreeElement *te, + TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) { Base *base = (Base *)te->directdata; @@ -582,20 +906,21 @@ void object_toggle_renderability_cb(bContext *UNUSED(C), Scene *scene, TreeEleme } } -void group_toggle_renderability_cb(bContext *UNUSED(C), Scene *scene, TreeElement *UNUSED(te), - TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) +void group_toggle_renderability_cb( + bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *scene, TreeElement *UNUSED(te), + TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) { Group *group = (Group *)tselem->id; restrictbutton_gr_restrict_flag(scene, group, OB_RESTRICT_RENDER); } -static int outliner_toggle_renderability_exec(bContext *C, wmOperator *UNUSED(op)) +static int outliner_toggle_renderability_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); SpaceOops *soops = CTX_wm_space_outliner(C); Scene *scene = CTX_data_scene(C); - outliner_do_object_operation(C, scene, soops, &soops->tree, object_toggle_renderability_cb); + outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, object_toggle_renderability_cb); DAG_id_type_tag(bmain, ID_OB); WM_event_add_notifier(C, NC_SCENE | ND_OB_RENDER, scene); @@ -2079,36 +2404,3 @@ void OUTLINER_OT_group_link(wmOperatorType *ot) /* properties */ RNA_def_string(ot->srna, "object", "Object", MAX_ID_NAME, "Object", "Target Object"); } - -/******** Utils to clear any ref to freed ID... **********/ - -void ED_outliner_id_unref(SpaceOops *so, const ID *id) -{ - /* Some early out checks. */ - if (!TREESTORE_ID_TYPE(id)) { - return; /* ID type is not used by outilner... */ - } - - if (so->search_tse.id == id) { - so->search_tse.id = NULL; - } - - if (so->treestore) { - TreeStoreElem *tselem; - BLI_mempool_iter iter; - bool changed = false; - - BLI_mempool_iternew(so->treestore, &iter); - while ((tselem = BLI_mempool_iterstep(&iter))) { - if (tselem->id == id) { - tselem->id = NULL; - changed = true; - } - } - if (so->treehash && changed) { - /* rebuild hash table, because it depends on ids too */ - /* postpone a full rebuild because this can be called many times on-free */ - so->storeflag |= SO_TREESTORE_REBUILD; - } - } -} diff --git a/source/blender/editors/space_outliner/outliner_intern.h b/source/blender/editors/space_outliner/outliner_intern.h index dc81be7a8e0..d2666cd0b6d 100644 --- a/source/blender/editors/space_outliner/outliner_intern.h +++ b/source/blender/editors/space_outliner/outliner_intern.h @@ -153,35 +153,58 @@ eOLDrawState tree_element_active(struct bContext *C, struct Scene *scene, SpaceO int outliner_item_do_activate(struct bContext *C, int x, int y, bool extend, bool recursive); /* outliner_edit.c ---------------------------------------------- */ +typedef void (*outliner_operation_cb)( + struct bContext *C, struct ReportList *, struct Scene *scene, + struct TreeElement *, struct TreeStoreElem *, TreeStoreElem *, void *); void outliner_do_object_operation_ex( - struct bContext *C, struct Scene *scene, struct SpaceOops *soops, struct ListBase *lb, - void (*operation_cb)(struct bContext *C, struct Scene *scene, - struct TreeElement *, struct TreeStoreElem *, TreeStoreElem *, void *), - bool recurse_selected); + struct bContext *C, ReportList *reports, struct Scene *scene, struct SpaceOops *soops, struct ListBase *lb, + outliner_operation_cb operation_cb, bool recurse_selected); void outliner_do_object_operation( - struct bContext *C, struct Scene *scene, struct SpaceOops *soops, struct ListBase *lb, - void (*operation_cb)(struct bContext *C, struct Scene *scene, - struct TreeElement *, struct TreeStoreElem *, TreeStoreElem *, void *)); + struct bContext *C, ReportList *reports, struct Scene *scene, struct SpaceOops *soops, struct ListBase *lb, + outliner_operation_cb operation_cb); int common_restrict_check(struct bContext *C, struct Object *ob); int outliner_has_one_flag(struct SpaceOops *soops, ListBase *lb, short flag, const int curlevel); void outliner_set_flag(struct SpaceOops *soops, ListBase *lb, short flag, short set); -void object_toggle_visibility_cb(struct bContext *C, struct Scene *scene, TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data); -void object_toggle_selectability_cb(struct bContext *C, struct Scene *scene, TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data); -void object_toggle_renderability_cb(struct bContext *C, struct Scene *scene, TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data); - - -void group_toggle_visibility_cb(struct bContext *C, struct Scene *scene, TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data); -void group_toggle_selectability_cb(struct bContext *C, struct Scene *scene, TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data); -void group_toggle_renderability_cb(struct bContext *C, struct Scene *scene, TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data); - -void item_rename_cb(struct bContext *C, struct Scene *scene, TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data); +void object_toggle_visibility_cb( + struct bContext *C, struct ReportList *reports, struct Scene *scene, + TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data); +void object_toggle_selectability_cb( + struct bContext *C, struct ReportList *reports, struct Scene *scene, + TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data); +void object_toggle_renderability_cb( + struct bContext *C, struct ReportList *reports, struct Scene *scene, + TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data); + + +void group_toggle_visibility_cb( + struct bContext *C, struct ReportList *reports, struct Scene *scene, + TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data); +void group_toggle_selectability_cb( + struct bContext *C, struct ReportList *reports, struct Scene *scene, + TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data); +void group_toggle_renderability_cb( + struct bContext *C, struct ReportList *reports, struct Scene *scene, + TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data); + +void item_rename_cb( + struct bContext *C, struct ReportList *reports, struct Scene *scene, + TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data); +void lib_relocate_cb( + struct bContext *C, struct ReportList *reports, struct Scene *scene, struct TreeElement *te, + struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data); +void lib_reload_cb( + struct bContext *C, struct ReportList *reports, struct Scene *scene, struct TreeElement *te, + struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data); -void lib_delete_cb( - struct bContext *C, struct Scene *scene, struct TreeElement *te, +void id_delete_cb( + struct bContext *C, struct ReportList *reports, struct Scene *scene, struct TreeElement *te, + struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data); +void id_remap_cb( + struct bContext *C, struct ReportList *reports, struct Scene *scene, struct TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data); TreeElement *outliner_dropzone_find(const struct SpaceOops *soops, const float fmval[2], const bool children); @@ -190,8 +213,10 @@ TreeElement *outliner_dropzone_find(const struct SpaceOops *soops, const float f void OUTLINER_OT_item_activate(struct wmOperatorType *ot); void OUTLINER_OT_item_openclose(struct wmOperatorType *ot); void OUTLINER_OT_item_rename(struct wmOperatorType *ot); +void OUTLINER_OT_lib_relocate(struct wmOperatorType *ot); +void OUTLINER_OT_lib_reload(struct wmOperatorType *ot); -void OUTLINER_OT_lib_delete(struct wmOperatorType *ot); +void OUTLINER_OT_id_delete(struct wmOperatorType *ot); void OUTLINER_OT_show_one_level(struct wmOperatorType *ot); void OUTLINER_OT_show_active(struct wmOperatorType *ot); @@ -230,6 +255,7 @@ void OUTLINER_OT_object_operation(struct wmOperatorType *ot); void OUTLINER_OT_group_operation(struct wmOperatorType *ot); void OUTLINER_OT_lib_operation(struct wmOperatorType *ot); void OUTLINER_OT_id_operation(struct wmOperatorType *ot); +void OUTLINER_OT_id_remap(struct wmOperatorType *ot); void OUTLINER_OT_data_operation(struct wmOperatorType *ot); void OUTLINER_OT_animdata_operation(struct wmOperatorType *ot); void OUTLINER_OT_action_set(struct wmOperatorType *ot); diff --git a/source/blender/editors/space_outliner/outliner_ops.c b/source/blender/editors/space_outliner/outliner_ops.c index 720cfe12567..776717c8443 100644 --- a/source/blender/editors/space_outliner/outliner_ops.c +++ b/source/blender/editors/space_outliner/outliner_ops.c @@ -47,13 +47,15 @@ void outliner_operatortypes(void) WM_operatortype_append(OUTLINER_OT_select_border); WM_operatortype_append(OUTLINER_OT_item_openclose); WM_operatortype_append(OUTLINER_OT_item_rename); - WM_operatortype_append(OUTLINER_OT_lib_delete); WM_operatortype_append(OUTLINER_OT_operation); WM_operatortype_append(OUTLINER_OT_scene_operation); WM_operatortype_append(OUTLINER_OT_object_operation); WM_operatortype_append(OUTLINER_OT_group_operation); WM_operatortype_append(OUTLINER_OT_lib_operation); + WM_operatortype_append(OUTLINER_OT_lib_relocate); WM_operatortype_append(OUTLINER_OT_id_operation); + WM_operatortype_append(OUTLINER_OT_id_delete); + WM_operatortype_append(OUTLINER_OT_id_remap); WM_operatortype_append(OUTLINER_OT_data_operation); WM_operatortype_append(OUTLINER_OT_animdata_operation); WM_operatortype_append(OUTLINER_OT_action_set); diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c index 83677b6bd86..bfec62997e1 100644 --- a/source/blender/editors/space_outliner/outliner_tools.c +++ b/source/blender/editors/space_outliner/outliner_tools.c @@ -57,6 +57,8 @@ #include "BKE_fcurve.h" #include "BKE_group.h" #include "BKE_library.h" +#include "BKE_library_query.h" +#include "BKE_library_remap.h" #include "BKE_main.h" #include "BKE_report.h" #include "BKE_scene.h" @@ -133,15 +135,17 @@ static void set_operation_types(SpaceOops *soops, ListBase *lb, } } -static void unlink_action_cb(bContext *C, Scene *UNUSED(scene), TreeElement *UNUSED(te), - TreeStoreElem *tsep, TreeStoreElem *UNUSED(tselem), void *UNUSED(user_data)) +static void unlink_action_cb( + bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te), + TreeStoreElem *tsep, TreeStoreElem *UNUSED(tselem), void *UNUSED(user_data)) { /* just set action to NULL */ BKE_animdata_set_action(CTX_wm_reports(C), tsep->id, NULL); } -static void unlink_material_cb(bContext *UNUSED(C), Scene *UNUSED(scene), TreeElement *te, - TreeStoreElem *tsep, TreeStoreElem *UNUSED(tselem), void *UNUSED(user_data)) +static void unlink_material_cb( + bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *te, + TreeStoreElem *tsep, TreeStoreElem *UNUSED(tselem), void *UNUSED(user_data)) { Material **matar = NULL; int a, totcol = 0; @@ -180,8 +184,9 @@ static void unlink_material_cb(bContext *UNUSED(C), Scene *UNUSED(scene), TreeEl } } -static void unlink_texture_cb(bContext *UNUSED(C), Scene *UNUSED(scene), TreeElement *te, - TreeStoreElem *tsep, TreeStoreElem *UNUSED(tselem), void *UNUSED(user_data)) +static void unlink_texture_cb( + bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *te, + TreeStoreElem *tsep, TreeStoreElem *UNUSED(tselem), void *UNUSED(user_data)) { MTex **mtex = NULL; int a; @@ -217,7 +222,7 @@ static void unlink_texture_cb(bContext *UNUSED(C), Scene *UNUSED(scene), TreeEle } static void unlink_group_cb( - bContext *C, Scene *UNUSED(scene), TreeElement *UNUSED(te), + bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te), TreeStoreElem *tsep, TreeStoreElem *tselem, void *UNUSED(user_data)) { Group *group = (Group *)tselem->id; @@ -230,12 +235,14 @@ static void unlink_group_cb( } else { Main *bmain = CTX_data_main(C); - BKE_group_unlink(bmain, group); + BKE_libblock_unlink(bmain, group, false, false); + BKE_libblock_free(bmain, group); } } -static void unlink_world_cb(bContext *UNUSED(C), Scene *UNUSED(scene), TreeElement *UNUSED(te), - TreeStoreElem *tsep, TreeStoreElem *tselem, void *UNUSED(user_data)) +static void unlink_world_cb( + bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te), + TreeStoreElem *tsep, TreeStoreElem *tselem, void *UNUSED(user_data)) { Scene *parscene = (Scene *)tsep->id; World *wo = (World *)tselem->id; @@ -246,8 +253,8 @@ static void unlink_world_cb(bContext *UNUSED(C), Scene *UNUSED(scene), TreeEleme } static void outliner_do_libdata_operation( - bContext *C, Scene *scene, SpaceOops *soops, ListBase *lb, - void (*operation_cb)(bContext *C, Scene *scene, TreeElement *, TreeStoreElem *, TreeStoreElem *, void *), + bContext *C, ReportList *reports, Scene *scene, SpaceOops *soops, ListBase *lb, + outliner_operation_cb operation_cb, void *user_data) { TreeElement *te; @@ -258,11 +265,11 @@ static void outliner_do_libdata_operation( if (tselem->flag & TSE_SELECTED) { if (tselem->type == 0) { TreeStoreElem *tsep = te->parent ? TREESTORE(te->parent) : NULL; - operation_cb(C, scene, te, tsep, tselem, user_data); + operation_cb(C, reports, scene, te, tsep, tselem, user_data); } } if (TSELEM_OPEN(tselem, soops)) { - outliner_do_libdata_operation(C, scene, soops, &te->subtree, operation_cb, user_data); + outliner_do_libdata_operation(C, reports, scene, soops, &te->subtree, operation_cb, user_data); } } } @@ -352,8 +359,9 @@ void OUTLINER_OT_scene_operation(wmOperatorType *ot) } /* ******************************************** */ -static void object_select_cb(bContext *UNUSED(C), Scene *scene, TreeElement *te, - TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) +static void object_select_cb( + bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *scene, TreeElement *te, + TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) { Base *base = (Base *)te->directdata; @@ -364,8 +372,9 @@ static void object_select_cb(bContext *UNUSED(C), Scene *scene, TreeElement *te, } } -static void object_select_hierarchy_cb(bContext *C, Scene *UNUSED(scene), TreeElement *UNUSED(te), - TreeStoreElem *UNUSED(tsep), TreeStoreElem *UNUSED(tselem), void *UNUSED(user_data)) +static void object_select_hierarchy_cb( + bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te), + TreeStoreElem *UNUSED(tsep), TreeStoreElem *UNUSED(tselem), void *UNUSED(user_data)) { /* From where do i get the x,y coordinate of the mouse event ? */ wmWindow *win = CTX_wm_window(C); @@ -375,8 +384,9 @@ static void object_select_hierarchy_cb(bContext *C, Scene *UNUSED(scene), TreeEl } -static void object_deselect_cb(bContext *UNUSED(C), Scene *scene, TreeElement *te, - TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) +static void object_deselect_cb( + bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *scene, TreeElement *te, + TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) { Base *base = (Base *)te->directdata; @@ -387,14 +397,27 @@ static void object_deselect_cb(bContext *UNUSED(C), Scene *scene, TreeElement *t } } -static void object_delete_cb(bContext *C, Scene *scene, TreeElement *te, - TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) +static void object_delete_cb( + bContext *C, ReportList *reports, Scene *scene, TreeElement *te, + TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) { Base *base = (Base *)te->directdata; if (base == NULL) base = BKE_scene_base_find(scene, (Object *)tselem->id); if (base) { + Main *bmain = CTX_data_main(C); + if (base->object->id.tag & LIB_TAG_INDIRECT) { + BKE_reportf(reports, RPT_WARNING, "Cannot delete indirectly linked object '%s'", base->object->id.name + 2); + return; + } + else if (BKE_library_ID_is_indirectly_used(bmain, base->object) && ID_REAL_USERS(base->object) <= 1) { + BKE_reportf(reports, RPT_WARNING, + "Cannot delete object '%s' from scene '%s', indirectly used objects need at least one user", + base->object->id.name + 2, scene->id.name + 2); + return; + } + // check also library later if (scene->obedit == base->object) ED_object_editmode_exit(C, EM_FREEDATA | EM_FREEUNDO | EM_WAITCURSOR | EM_DO_UNDO); @@ -408,8 +431,9 @@ static void object_delete_cb(bContext *C, Scene *scene, TreeElement *te, } } -static void id_local_cb(bContext *C, Scene *UNUSED(scene), TreeElement *UNUSED(te), - TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) +static void id_local_cb( + bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te), + TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) { if (tselem->id->lib && (tselem->id->tag & LIB_TAG_EXTERN)) { /* if the ID type has no special local function, @@ -421,32 +445,36 @@ static void id_local_cb(bContext *C, Scene *UNUSED(scene), TreeElement *UNUSED(t } } -static void id_fake_user_set_cb(bContext *UNUSED(C), Scene *UNUSED(scene), TreeElement *UNUSED(te), - TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) +static void id_fake_user_set_cb( + bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te), + TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) { ID *id = tselem->id; id_fake_user_set(id); } -static void id_fake_user_clear_cb(bContext *UNUSED(C), Scene *UNUSED(scene), TreeElement *UNUSED(te), - TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) +static void id_fake_user_clear_cb( + bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te), + TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) { ID *id = tselem->id; id_fake_user_clear(id); } -static void id_select_linked_cb(bContext *C, Scene *UNUSED(scene), TreeElement *UNUSED(te), - TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) +static void id_select_linked_cb( + bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te), + TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) { ID *id = tselem->id; ED_object_select_linked_by_id(C, id); } -static void singleuser_action_cb(bContext *C, Scene *UNUSED(scene), TreeElement *UNUSED(te), - TreeStoreElem *tsep, TreeStoreElem *tselem, void *UNUSED(user_data)) +static void singleuser_action_cb( + bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te), + TreeStoreElem *tsep, TreeStoreElem *tselem, void *UNUSED(user_data)) { ID *id = tselem->id; @@ -462,8 +490,9 @@ static void singleuser_action_cb(bContext *C, Scene *UNUSED(scene), TreeElement } } -static void singleuser_world_cb(bContext *C, Scene *UNUSED(scene), TreeElement *UNUSED(te), - TreeStoreElem *tsep, TreeStoreElem *tselem, void *UNUSED(user_data)) +static void singleuser_world_cb( + bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te), + TreeStoreElem *tsep, TreeStoreElem *tselem, void *UNUSED(user_data)) { ID *id = tselem->id; @@ -480,8 +509,9 @@ static void singleuser_world_cb(bContext *C, Scene *UNUSED(scene), TreeElement * } } -static void group_linkobs2scene_cb(bContext *UNUSED(C), Scene *scene, TreeElement *UNUSED(te), - TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) +static void group_linkobs2scene_cb( + bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *scene, TreeElement *UNUSED(te), + TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) { Group *group = (Group *)tselem->id; GroupObject *gob; @@ -506,8 +536,9 @@ static void group_linkobs2scene_cb(bContext *UNUSED(C), Scene *scene, TreeElemen } } -static void group_instance_cb(bContext *C, Scene *scene, TreeElement *UNUSED(te), - TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) +static void group_instance_cb( + bContext *C, ReportList *UNUSED(reports), Scene *scene, TreeElement *UNUSED(te), + TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) { Group *group = (Group *)tselem->id; @@ -521,10 +552,8 @@ static void group_instance_cb(bContext *C, Scene *scene, TreeElement *UNUSED(te) * \param select_recurse: Set to false for operations which are already recursively operating on their children. */ void outliner_do_object_operation_ex( - bContext *C, Scene *scene_act, SpaceOops *soops, ListBase *lb, - void (*operation_cb)(bContext *C, Scene *scene, TreeElement *, - TreeStoreElem *, TreeStoreElem *, void *), - bool select_recurse) + bContext *C, ReportList *reports, Scene *scene_act, SpaceOops *soops, ListBase *lb, + outliner_operation_cb operation_cb, bool select_recurse) { TreeElement *te; @@ -541,23 +570,24 @@ void outliner_do_object_operation_ex( /* important to use 'scene_owner' not scene_act else deleting objects can crash. * only use 'scene_act' when 'scene_owner' is NULL, which can happen when the * outliner isn't showing scenes: Visible Layer draw mode for eg. */ - operation_cb(C, scene_owner ? scene_owner : scene_act, te, NULL, tselem, NULL); + operation_cb(C, reports, scene_owner ? scene_owner : scene_act, te, NULL, tselem, NULL); select_handled = true; } } if (TSELEM_OPEN(tselem, soops)) { if ((select_handled == false) || select_recurse) { - outliner_do_object_operation_ex(C, scene_act, soops, &te->subtree, operation_cb, select_recurse); + outliner_do_object_operation_ex( + C, reports, scene_act, soops, &te->subtree, operation_cb, select_recurse); } } } } void outliner_do_object_operation( - bContext *C, Scene *scene_act, SpaceOops *soops, ListBase *lb, - void (*operation_cb)(bContext *, Scene *, TreeElement *, TreeStoreElem *, TreeStoreElem *, void *)) + bContext *C, ReportList *reports, Scene *scene_act, SpaceOops *soops, ListBase *lb, + outliner_operation_cb operation_cb) { - outliner_do_object_operation_ex(C, scene_act, soops, lb, operation_cb, true); + outliner_do_object_operation_ex(C, reports, scene_act, soops, lb, operation_cb, true); } /* ******************************************** */ @@ -565,7 +595,7 @@ void outliner_do_object_operation( static void clear_animdata_cb(int UNUSED(event), TreeElement *UNUSED(te), TreeStoreElem *tselem, void *UNUSED(arg)) { - BKE_animdata_free(tselem->id); + BKE_animdata_free(tselem->id, true); } @@ -792,7 +822,7 @@ static void outliner_do_data_operation(SpaceOops *soops, int type, int event, Li } } -static Base *outline_delete_hierarchy(bContext *C, Scene *scene, Base *base) +static Base *outline_delete_hierarchy(bContext *C, ReportList *reports, Scene *scene, Base *base) { Base *child_base, *base_next; Object *parent; @@ -805,17 +835,30 @@ static Base *outline_delete_hierarchy(bContext *C, Scene *scene, Base *base) base_next = child_base->next; for (parent = child_base->object->parent; parent && (parent != base->object); parent = parent->parent); if (parent) { - base_next = outline_delete_hierarchy(C, scene, child_base); + base_next = outline_delete_hierarchy(C, reports, scene, child_base); } } base_next = base->next; + + Main *bmain = CTX_data_main(C); + if (base->object->id.tag & LIB_TAG_INDIRECT) { + BKE_reportf(reports, RPT_WARNING, "Cannot delete indirectly linked object '%s'", base->object->id.name + 2); + return base_next; + } + else if (BKE_library_ID_is_indirectly_used(bmain, base->object) && ID_REAL_USERS(base->object) <= 1) { + BKE_reportf(reports, RPT_WARNING, + "Cannot delete object '%s' from scene '%s', indirectly used objects need at least one user", + base->object->id.name + 2, scene->id.name + 2); + return base_next; + } ED_base_object_free_and_unlink(CTX_data_main(C), scene, base); return base_next; } static void object_delete_hierarchy_cb( - bContext *C, Scene *scene, TreeElement *te, TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) + bContext *C, ReportList *reports, Scene *scene, + TreeElement *te, TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) { Base *base = (Base *)te->directdata; Object *obedit = scene->obedit; @@ -830,7 +873,7 @@ static void object_delete_hierarchy_cb( ED_object_editmode_exit(C, EM_FREEDATA | EM_FREEUNDO | EM_WAITCURSOR | EM_DO_UNDO); } - outline_delete_hierarchy(C, scene, base); + outline_delete_hierarchy(C, reports, scene, base); /* leave for ED_outliner_id_unref to handle */ #if 0 te->directdata = NULL; @@ -849,6 +892,7 @@ enum { OL_OP_SELECT_HIERARCHY, OL_OP_DELETE, OL_OP_DELETE_HIERARCHY, + OL_OP_REMAP, OL_OP_LOCALIZED, /* disabled, see below */ OL_OP_TOGVIS, OL_OP_TOGSEL, @@ -862,6 +906,8 @@ static EnumPropertyItem prop_object_op_types[] = { {OL_OP_SELECT_HIERARCHY, "SELECT_HIERARCHY", 0, "Select Hierarchy", ""}, {OL_OP_DELETE, "DELETE", 0, "Delete", ""}, {OL_OP_DELETE_HIERARCHY, "DELETE_HIERARCHY", 0, "Delete Hierarchy", ""}, + {OL_OP_REMAP, "REMAP", 0, "Remap Users", + "Make all users of selected datablocks to use instead a new chosen one"}, {OL_OP_TOGVIS, "TOGVIS", 0, "Toggle Visible", ""}, {OL_OP_TOGSEL, "TOGSEL", 0, "Toggle Selectable", ""}, {OL_OP_TOGREN, "TOGREN", 0, "Toggle Renderable", ""}, @@ -885,7 +931,7 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op) if (event == OL_OP_SELECT) { Scene *sce = scene; // to be able to delete, scenes are set... - outliner_do_object_operation(C, scene, soops, &soops->tree, object_select_cb); + outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, object_select_cb); if (scene != sce) { ED_screen_set_scene(C, CTX_wm_screen(C), sce); } @@ -895,7 +941,7 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op) } else if (event == OL_OP_SELECT_HIERARCHY) { Scene *sce = scene; // to be able to delete, scenes are set... - outliner_do_object_operation_ex(C, scene, soops, &soops->tree, object_select_hierarchy_cb, false); + outliner_do_object_operation_ex(C, op->reports, scene, soops, &soops->tree, object_select_hierarchy_cb, false); if (scene != sce) { ED_screen_set_scene(C, CTX_wm_screen(C), sce); } @@ -903,12 +949,12 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op) WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); } else if (event == OL_OP_DESELECT) { - outliner_do_object_operation(C, scene, soops, &soops->tree, object_deselect_cb); + outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, object_deselect_cb); str = "Deselect Objects"; WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); } else if (event == OL_OP_DELETE) { - outliner_do_object_operation(C, scene, soops, &soops->tree, object_delete_cb); + outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, object_delete_cb); /* XXX: tree management normally happens from draw_outliner(), but when * you're clicking to fast on Delete object from context menu in @@ -922,7 +968,7 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op) WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene); } else if (event == OL_OP_DELETE_HIERARCHY) { - outliner_do_object_operation_ex(C, scene, soops, &soops->tree, object_delete_hierarchy_cb, false); + outliner_do_object_operation_ex(C, op->reports, scene, soops, &soops->tree, object_delete_hierarchy_cb, false); /* XXX: See OL_OP_DELETE comment above. */ outliner_cleanup_tree(soops); @@ -931,27 +977,31 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op) str = "Delete Object Hierarchy"; WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene); } + else if (event == OL_OP_REMAP) { + outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_remap_cb, NULL); + str = "Remap ID"; + } else if (event == OL_OP_LOCALIZED) { /* disabled, see above enum (ton) */ - outliner_do_object_operation(C, scene, soops, &soops->tree, id_local_cb); + outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, id_local_cb); str = "Localized Objects"; } else if (event == OL_OP_TOGVIS) { - outliner_do_object_operation(C, scene, soops, &soops->tree, object_toggle_visibility_cb); + outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, object_toggle_visibility_cb); str = "Toggle Visibility"; WM_event_add_notifier(C, NC_SCENE | ND_OB_VISIBLE, scene); } else if (event == OL_OP_TOGSEL) { - outliner_do_object_operation(C, scene, soops, &soops->tree, object_toggle_selectability_cb); + outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, object_toggle_selectability_cb); str = "Toggle Selectability"; WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); } else if (event == OL_OP_TOGREN) { - outliner_do_object_operation(C, scene, soops, &soops->tree, object_toggle_renderability_cb); + outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, object_toggle_renderability_cb); str = "Toggle Renderability"; WM_event_add_notifier(C, NC_SCENE | ND_OB_RENDER, scene); } else if (event == OL_OP_RENAME) { - outliner_do_object_operation(C, scene, soops, &soops->tree, item_rename_cb); + outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, item_rename_cb); str = "Rename Object"; } else { @@ -988,6 +1038,8 @@ typedef enum eOutliner_PropGroupOps { OL_GROUPOP_UNLINK = 1, OL_GROUPOP_LOCAL, OL_GROUPOP_LINK, + OL_GROUPOP_DELETE, + OL_GROUPOP_REMAP, OL_GROUPOP_INSTANCE, OL_GROUPOP_TOGVIS, OL_GROUPOP_TOGSEL, @@ -999,6 +1051,9 @@ static EnumPropertyItem prop_group_op_types[] = { {OL_GROUPOP_UNLINK, "UNLINK", 0, "Unlink Group", ""}, {OL_GROUPOP_LOCAL, "LOCAL", 0, "Make Local Group", ""}, {OL_GROUPOP_LINK, "LINK", 0, "Link Group Objects to Scene", ""}, + {OL_GROUPOP_DELETE, "DELETE", 0, "Delete Group", "WARNING: no undo"}, + {OL_GROUPOP_REMAP, "REMAP", 0, "Remap Users", + "Make all users of selected datablocks to use instead current (clicked) one"}, {OL_GROUPOP_INSTANCE, "INSTANCE", 0, "Instance Groups in Scene", ""}, {OL_GROUPOP_TOGVIS, "TOGVIS", 0, "Toggle Visible Group", ""}, {OL_GROUPOP_TOGSEL, "TOGSEL", 0, "Toggle Selectable", ""}, @@ -1021,38 +1076,41 @@ static int outliner_group_operation_exec(bContext *C, wmOperator *op) switch (event) { case OL_GROUPOP_UNLINK: - outliner_do_libdata_operation(C, scene, soops, &soops->tree, unlink_group_cb, NULL); + outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, unlink_group_cb, NULL); break; case OL_GROUPOP_LOCAL: - outliner_do_libdata_operation(C, scene, soops, &soops->tree, id_local_cb, NULL); + outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_local_cb, NULL); break; case OL_GROUPOP_LINK: - outliner_do_libdata_operation(C, scene, soops, &soops->tree, group_linkobs2scene_cb, NULL); + outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, group_linkobs2scene_cb, NULL); break; case OL_GROUPOP_INSTANCE: - outliner_do_libdata_operation(C, scene, soops, &soops->tree, group_instance_cb, NULL); + outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, group_instance_cb, NULL); + /* works without this except if you try render right after, see: 22027 */ + DAG_relations_tag_update(CTX_data_main(C)); + break; + case OL_GROUPOP_DELETE: + WM_operator_name_call(C, "OUTLINER_OT_id_delete", WM_OP_INVOKE_REGION_WIN, NULL); + break; + case OL_GROUPOP_REMAP: + outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_remap_cb, NULL); break; case OL_GROUPOP_TOGVIS: - outliner_do_libdata_operation(C, scene, soops, &soops->tree, group_toggle_visibility_cb, NULL); + outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, group_toggle_visibility_cb, NULL); break; case OL_GROUPOP_TOGSEL: - outliner_do_libdata_operation(C, scene, soops, &soops->tree, group_toggle_selectability_cb, NULL); + outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, group_toggle_selectability_cb, NULL); break; case OL_GROUPOP_TOGREN: - outliner_do_libdata_operation(C, scene, soops, &soops->tree, group_toggle_renderability_cb, NULL); + outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, group_toggle_renderability_cb, NULL); break; case OL_GROUPOP_RENAME: - outliner_do_libdata_operation(C, scene, soops, &soops->tree, item_rename_cb, NULL); + outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, item_rename_cb, NULL); break; default: BLI_assert(0); } - if (event == 3) { /* instance */ - /* works without this except if you try render right after, see: 22027 */ - DAG_relations_tag_update(CTX_data_main(C)); - } - ED_undo_push(C, prop_group_op_types[event - 1].name); WM_event_add_notifier(C, NC_GROUP, NULL); @@ -1085,6 +1143,8 @@ typedef enum eOutlinerIdOpTypes { OUTLINER_IDOP_UNLINK, OUTLINER_IDOP_LOCAL, OUTLINER_IDOP_SINGLE, + OUTLINER_IDOP_DELETE, + OUTLINER_IDOP_REMAP, OUTLINER_IDOP_FAKE_ADD, OUTLINER_IDOP_FAKE_CLEAR, @@ -1098,6 +1158,9 @@ static EnumPropertyItem prop_id_op_types[] = { {OUTLINER_IDOP_UNLINK, "UNLINK", 0, "Unlink", ""}, {OUTLINER_IDOP_LOCAL, "LOCAL", 0, "Make Local", ""}, {OUTLINER_IDOP_SINGLE, "SINGLE", 0, "Make Single User", ""}, + {OUTLINER_IDOP_DELETE, "DELETE", 0, "Delete", "WARNING: no undo"}, + {OUTLINER_IDOP_REMAP, "REMAP", 0, "Remap Users", + "Make all users of selected datablocks to use instead current (clicked) one"}, {OUTLINER_IDOP_FAKE_ADD, "ADD_FAKE", 0, "Add Fake User", "Ensure datablock gets saved even if it isn't in use (e.g. for motion and material libraries)"}, {OUTLINER_IDOP_FAKE_CLEAR, "CLEAR_FAKE", 0, "Clear Fake User", ""}, @@ -1127,25 +1190,25 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op) /* unlink datablock from its parent */ switch (idlevel) { case ID_AC: - outliner_do_libdata_operation(C, scene, soops, &soops->tree, unlink_action_cb, NULL); + outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, unlink_action_cb, NULL); WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, NULL); ED_undo_push(C, "Unlink action"); break; case ID_MA: - outliner_do_libdata_operation(C, scene, soops, &soops->tree, unlink_material_cb, NULL); + outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, unlink_material_cb, NULL); WM_event_add_notifier(C, NC_OBJECT | ND_OB_SHADING, NULL); ED_undo_push(C, "Unlink material"); break; case ID_TE: - outliner_do_libdata_operation(C, scene, soops, &soops->tree, unlink_texture_cb, NULL); + outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, unlink_texture_cb, NULL); WM_event_add_notifier(C, NC_OBJECT | ND_OB_SHADING, NULL); ED_undo_push(C, "Unlink texture"); break; case ID_WO: - outliner_do_libdata_operation(C, scene, soops, &soops->tree, unlink_world_cb, NULL); + outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, unlink_world_cb, NULL); WM_event_add_notifier(C, NC_SCENE | ND_WORLD, NULL); ED_undo_push(C, "Unlink world"); @@ -1159,7 +1222,7 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op) case OUTLINER_IDOP_LOCAL: { /* make local */ - outliner_do_libdata_operation(C, scene, soops, &soops->tree, id_local_cb, NULL); + outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_local_cb, NULL); ED_undo_push(C, "Localized Data"); break; } @@ -1168,14 +1231,14 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op) /* make single user */ switch (idlevel) { case ID_AC: - outliner_do_libdata_operation(C, scene, soops, &soops->tree, singleuser_action_cb, NULL); + outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, singleuser_action_cb, NULL); WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, NULL); ED_undo_push(C, "Single-User Action"); break; case ID_WO: - outliner_do_libdata_operation(C, scene, soops, &soops->tree, singleuser_world_cb, NULL); + outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, singleuser_world_cb, NULL); WM_event_add_notifier(C, NC_SCENE | ND_WORLD, NULL); ED_undo_push(C, "Single-User World"); @@ -1187,10 +1250,24 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op) } break; } + case OUTLINER_IDOP_DELETE: + { + if (idlevel > 0) { + outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_delete_cb, NULL); + } + break; + } + case OUTLINER_IDOP_REMAP: + { + if (idlevel > 0) { + outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_remap_cb, NULL); + } + break; + } case OUTLINER_IDOP_FAKE_ADD: { /* set fake user */ - outliner_do_libdata_operation(C, scene, soops, &soops->tree, id_fake_user_set_cb, NULL); + outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_fake_user_set_cb, NULL); WM_event_add_notifier(C, NC_ID | NA_EDITED, NULL); ED_undo_push(C, "Add Fake User"); @@ -1199,7 +1276,7 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op) case OUTLINER_IDOP_FAKE_CLEAR: { /* clear fake user */ - outliner_do_libdata_operation(C, scene, soops, &soops->tree, id_fake_user_clear_cb, NULL); + outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_fake_user_clear_cb, NULL); WM_event_add_notifier(C, NC_ID | NA_EDITED, NULL); ED_undo_push(C, "Clear Fake User"); @@ -1208,14 +1285,14 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op) case OUTLINER_IDOP_RENAME: { /* rename */ - outliner_do_libdata_operation(C, scene, soops, &soops->tree, item_rename_cb, NULL); + outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, item_rename_cb, NULL); WM_event_add_notifier(C, NC_ID | NA_EDITED, NULL); ED_undo_push(C, "Rename"); break; } case OUTLINER_IDOP_SELECT_LINKED: - outliner_do_libdata_operation(C, scene, soops, &soops->tree, id_select_linked_cb, NULL); + outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_select_linked_cb, NULL); ED_undo_push(C, "Select"); break; @@ -1258,13 +1335,16 @@ typedef enum eOutlinerLibOpTypes { OL_LIB_RENAME, OL_LIB_DELETE, + OL_LIB_RELOCATE, + OL_LIB_RELOAD, } eOutlinerLibOpTypes; static EnumPropertyItem outliner_lib_op_type_items[] = { {OL_LIB_RENAME, "RENAME", 0, "Rename", ""}, - {OL_LIB_DELETE, "DELETE", 0, "Delete", "Delete this library and all its item from Blender (needs a save/reload)"}, + {OL_LIB_DELETE, "DELETE", 0, "Delete", "Delete this library and all its item from Blender - WARNING: no undo"}, + {OL_LIB_RELOCATE, "RELOCATE", 0, "Relocate", "Select a new path for this library, and reload all its data"}, + {OL_LIB_RELOAD, "RELOAD", 0, "Reload", "Reload all data from this library"}, {0, NULL, 0, NULL, NULL} - }; static int outliner_lib_operation_exec(bContext *C, wmOperator *op) @@ -1286,7 +1366,7 @@ static int outliner_lib_operation_exec(bContext *C, wmOperator *op) case OL_LIB_RENAME: { /* rename */ - outliner_do_libdata_operation(C, scene, soops, &soops->tree, item_rename_cb, NULL); + outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, item_rename_cb, NULL); WM_event_add_notifier(C, NC_ID | NA_EDITED, NULL); ED_undo_push(C, "Rename"); @@ -1294,13 +1374,19 @@ static int outliner_lib_operation_exec(bContext *C, wmOperator *op) } case OL_LIB_DELETE: { - /* delete */ - outliner_do_libdata_operation(C, scene, soops, &soops->tree, lib_delete_cb, NULL); - - WM_event_add_notifier(C, NC_ID | NA_EDITED, NULL); - /* Note: no undo possible here really, not 100% sure why... - * Probably because of library optimizations in undo/redo process? */ - /* ED_undo_push(C, "Rename"); */ + outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_delete_cb, NULL); + break; + } + case OL_LIB_RELOCATE: + { + /* rename */ + outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, lib_relocate_cb, NULL); + break; + } + case OL_LIB_RELOAD: + { + /* rename */ + outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, lib_reload_cb, NULL); break; } default: diff --git a/source/blender/editors/space_outliner/space_outliner.c b/source/blender/editors/space_outliner/space_outliner.c index 1dd66366e5d..76bf9c701ed 100644 --- a/source/blender/editors/space_outliner/space_outliner.c +++ b/source/blender/editors/space_outliner/space_outliner.c @@ -486,6 +486,39 @@ static SpaceLink *outliner_duplicate(SpaceLink *sl) return (SpaceLink *)soutlinern; } +static void outliner_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID *new_id) +{ + SpaceOops *so = (SpaceOops *)slink; + + /* Some early out checks. */ + if (!TREESTORE_ID_TYPE(old_id)) { + return; /* ID type is not used by outilner... */ + } + + if (so->search_tse.id == old_id) { + so->search_tse.id = new_id; + } + + if (so->treestore) { + TreeStoreElem *tselem; + BLI_mempool_iter iter; + bool changed = false; + + BLI_mempool_iternew(so->treestore, &iter); + while ((tselem = BLI_mempool_iterstep(&iter))) { + if (tselem->id == old_id) { + tselem->id = new_id; + changed = true; + } + } + if (so->treehash && changed) { + /* rebuild hash table, because it depends on ids too */ + /* postpone a full rebuild because this can be called many times on-free */ + so->storeflag |= SO_TREESTORE_REBUILD; + } + } +} + /* only called once, from space_api/spacetypes.c */ void ED_spacetype_outliner(void) { @@ -502,7 +535,8 @@ void ED_spacetype_outliner(void) st->operatortypes = outliner_operatortypes; st->keymap = outliner_keymap; st->dropboxes = outliner_dropboxes; - + st->id_remap = outliner_id_remap; + /* regions: main window */ art = MEM_callocN(sizeof(ARegionType), "spacetype outliner region"); art->regionid = RGN_TYPE_WINDOW; diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c index 9c2d115108d..adb7cf4940c 100644 --- a/source/blender/editors/space_sequencer/sequencer_draw.c +++ b/source/blender/editors/space_sequencer/sequencer_draw.c @@ -593,7 +593,6 @@ void draw_shadedstrip(Sequence *seq, unsigned char col[3], float x1, float y1, f ymid1 = (y2 - y1) * 0.25f + y1; ymid2 = (y2 - y1) * 0.65f + y1; - glShadeModel(GL_SMOOTH); glBegin(GL_QUADS); if (seq->flag & SEQ_INVALID_EFFECT) { col[0] = 255; col[1] = 0; col[2] = 255; } @@ -840,25 +839,25 @@ static void draw_seq_strip(const bContext *C, SpaceSeq *sseq, Scene *scene, AReg else UI_GetColorPtrShade3ubv(col, col, outline_tint); - glColor3ubv((GLubyte *)col); - + if ((seq->type == SEQ_TYPE_META) || + ((seq->type == SEQ_TYPE_SCENE) && (seq->flag & SEQ_SCENE_STRIPS))) + { + drawmeta_contents(scene, seq, x1, y1, x2, y2); + } + if (seq->flag & SEQ_MUTE) { glEnable(GL_LINE_STIPPLE); glLineStipple(1, 0x8888); } + glColor3ubv((GLubyte *)col); + UI_draw_roundbox_shade_x(GL_LINE_LOOP, x1, y1, x2, y2, 0.0, 0.1, 0.0); if (seq->flag & SEQ_MUTE) { glDisable(GL_LINE_STIPPLE); } - if ((seq->type == SEQ_TYPE_META) || - ((seq->type == SEQ_TYPE_SCENE) && (seq->flag & SEQ_SCENE_STRIPS))) - { - drawmeta_contents(scene, seq, x1, y1, x2, y2); - } - /* calculate if seq is long enough to print a name */ x1 = seq->startdisp + handsize_clamped; x2 = seq->enddisp - handsize_clamped; @@ -1630,7 +1629,8 @@ void draw_timeline_seq(const bContext *C, ARegion *ar) // NOTE: the gridlines are currently spaced every 25 frames, which is only fine for 25 fps, but maybe not for 30... UI_view2d_constant_grid_draw(v2d); - if (sseq->draw_flag & SEQ_DRAW_BACKDROP) { + /* Only draw backdrop in pure sequence view. */ + if (sseq->view == SEQ_VIEW_SEQUENCE && sseq->draw_flag & SEQ_DRAW_BACKDROP) { draw_image_seq(C, scene, ar, sseq, scene->r.cfra, 0, false, true); UI_view2d_view_ortho(v2d); } diff --git a/source/blender/editors/space_sequencer/sequencer_select.c b/source/blender/editors/space_sequencer/sequencer_select.c index 3c2a66cd3af..48c49f36471 100644 --- a/source/blender/editors/space_sequencer/sequencer_select.c +++ b/source/blender/editors/space_sequencer/sequencer_select.c @@ -107,6 +107,7 @@ static void select_active_side(ListBase *seqbase, int sel_side, int channel, int break; case SEQ_SIDE_BOTH: seq->flag &= ~(SEQ_RIGHTSEL | SEQ_LEFTSEL); + seq->flag |= SELECT; break; } } @@ -812,7 +813,7 @@ static int sequencer_select_handles_exec(bContext *C, wmOperator *op) seq->flag |= SEQ_RIGHTSEL; break; case SEQ_SIDE_BOTH: - seq->flag |= SEQ_LEFTSEL + SEQ_RIGHTSEL; + seq->flag |= SEQ_LEFTSEL | SEQ_RIGHTSEL; break; } } @@ -942,16 +943,26 @@ void SEQUENCER_OT_select_border(wmOperatorType *ot) /* ****** Selected Grouped ****** */ +enum { + SEQ_SELECT_GROUP_TYPE, + SEQ_SELECT_GROUP_TYPE_BASIC, + SEQ_SELECT_GROUP_TYPE_EFFECT, + SEQ_SELECT_GROUP_DATA, + SEQ_SELECT_GROUP_EFFECT, + SEQ_SELECT_GROUP_EFFECT_LINK, + SEQ_SELECT_GROUP_OVERLAP, +}; + static EnumPropertyItem sequencer_prop_select_grouped_types[] = { - {1, "TYPE", 0, "Type", "Shared strip type"}, - {2, "TYPE_BASIC", 0, "Global Type", "All strips of same basic type (Graphical or Sound)"}, - {3, "TYPE_EFFECT", 0, "Effect Type", + {SEQ_SELECT_GROUP_TYPE, "TYPE", 0, "Type", "Shared strip type"}, + {SEQ_SELECT_GROUP_TYPE_BASIC, "TYPE_BASIC", 0, "Global Type", "All strips of same basic type (Graphical or Sound)"}, + {SEQ_SELECT_GROUP_TYPE_EFFECT, "TYPE_EFFECT", 0, "Effect Type", "Shared strip effect type (if active strip is not an effect one, select all non-effect strips)"}, - {4, "DATA", 0, "Data", "Shared data (scene, image, sound, etc.)"}, - {5, "EFFECT", 0, "Effect", "Shared effects"}, - {6, "EFFECT_LINK", 0, "Effect/Linked", + {SEQ_SELECT_GROUP_DATA, "DATA", 0, "Data", "Shared data (scene, image, sound, etc.)"}, + {SEQ_SELECT_GROUP_EFFECT, "EFFECT", 0, "Effect", "Shared effects"}, + {SEQ_SELECT_GROUP_EFFECT_LINK, "EFFECT_LINK", 0, "Effect/Linked", "Other strips affected by the active one (sharing some time, and below or effect-assigned)"}, - {7, "OVERLAP", 0, "Overlap", "Overlapping time"}, + {SEQ_SELECT_GROUP_OVERLAP, "OVERLAP", 0, "Overlap", "Overlapping time"}, {0, NULL, 0, NULL, NULL} }; @@ -961,14 +972,16 @@ static EnumPropertyItem sequencer_prop_select_grouped_types[] = { #define SEQ_USE_DATA(_seq) (ELEM(_seq->type, SEQ_TYPE_SCENE, SEQ_TYPE_MOVIECLIP, SEQ_TYPE_MASK) || SEQ_HAS_PATH(_seq)) -static bool select_grouped_type(Editing *ed, Sequence *actseq) +#define SEQ_CHANNEL_CHECK(_seq, _chan) (ELEM((_chan), 0, (_seq)->machine)) + +static bool select_grouped_type(Editing *ed, Sequence *actseq, const int channel) { Sequence *seq; bool changed = false; SEQP_BEGIN (ed, seq) { - if (seq->type == actseq->type) { + if (SEQ_CHANNEL_CHECK(seq, channel) && seq->type == actseq->type) { seq->flag |= SELECT; changed = true; } @@ -978,7 +991,7 @@ static bool select_grouped_type(Editing *ed, Sequence *actseq) return changed; } -static bool select_grouped_type_basic(Editing *ed, Sequence *actseq) +static bool select_grouped_type_basic(Editing *ed, Sequence *actseq, const int channel) { Sequence *seq; bool changed = false; @@ -986,7 +999,7 @@ static bool select_grouped_type_basic(Editing *ed, Sequence *actseq) SEQP_BEGIN (ed, seq) { - if (is_sound ? SEQ_IS_SOUND(seq) : !SEQ_IS_SOUND(seq)) { + if (SEQ_CHANNEL_CHECK(seq, channel) && (is_sound ? SEQ_IS_SOUND(seq) : !SEQ_IS_SOUND(seq))) { seq->flag |= SELECT; changed = true; } @@ -996,7 +1009,7 @@ static bool select_grouped_type_basic(Editing *ed, Sequence *actseq) return changed; } -static bool select_grouped_type_effect(Editing *ed, Sequence *actseq) +static bool select_grouped_type_effect(Editing *ed, Sequence *actseq, const int channel) { Sequence *seq; bool changed = false; @@ -1004,7 +1017,7 @@ static bool select_grouped_type_effect(Editing *ed, Sequence *actseq) SEQP_BEGIN (ed, seq) { - if (is_effect ? SEQ_IS_EFFECT(seq) : !SEQ_IS_EFFECT(seq)) { + if (SEQ_CHANNEL_CHECK(seq, channel) && (is_effect ? SEQ_IS_EFFECT(seq) : !SEQ_IS_EFFECT(seq))) { seq->flag |= SELECT; changed = true; } @@ -1014,7 +1027,7 @@ static bool select_grouped_type_effect(Editing *ed, Sequence *actseq) return changed; } -static bool select_grouped_data(Editing *ed, Sequence *actseq) +static bool select_grouped_data(Editing *ed, Sequence *actseq, const int channel) { Sequence *seq; bool changed = false; @@ -1026,7 +1039,7 @@ static bool select_grouped_data(Editing *ed, Sequence *actseq) if (SEQ_HAS_PATH(actseq) && dir) { SEQP_BEGIN (ed, seq) { - if (SEQ_HAS_PATH(seq) && seq->strip && STREQ(seq->strip->dir, dir)) { + if (SEQ_CHANNEL_CHECK(seq, channel) && SEQ_HAS_PATH(seq) && seq->strip && STREQ(seq->strip->dir, dir)) { seq->flag |= SELECT; changed = true; } @@ -1037,7 +1050,7 @@ static bool select_grouped_data(Editing *ed, Sequence *actseq) Scene *sce = actseq->scene; SEQP_BEGIN (ed, seq) { - if (seq->type == SEQ_TYPE_SCENE && seq->scene == sce) { + if (SEQ_CHANNEL_CHECK(seq, channel) && seq->type == SEQ_TYPE_SCENE && seq->scene == sce) { seq->flag |= SELECT; changed = true; } @@ -1048,7 +1061,7 @@ static bool select_grouped_data(Editing *ed, Sequence *actseq) MovieClip *clip = actseq->clip; SEQP_BEGIN (ed, seq) { - if (seq->type == SEQ_TYPE_MOVIECLIP && seq->clip == clip) { + if (SEQ_CHANNEL_CHECK(seq, channel) && seq->type == SEQ_TYPE_MOVIECLIP && seq->clip == clip) { seq->flag |= SELECT; changed = true; } @@ -1059,7 +1072,7 @@ static bool select_grouped_data(Editing *ed, Sequence *actseq) struct Mask *mask = actseq->mask; SEQP_BEGIN (ed, seq) { - if (seq->type == SEQ_TYPE_MASK && seq->mask == mask) { + if (SEQ_CHANNEL_CHECK(seq, channel) && seq->type == SEQ_TYPE_MASK && seq->mask == mask) { seq->flag |= SELECT; changed = true; } @@ -1070,7 +1083,7 @@ static bool select_grouped_data(Editing *ed, Sequence *actseq) return changed; } -static bool select_grouped_effect(Editing *ed, Sequence *actseq) +static bool select_grouped_effect(Editing *ed, Sequence *actseq, const int channel) { Sequence *seq; bool changed = false; @@ -1082,7 +1095,9 @@ static bool select_grouped_effect(Editing *ed, Sequence *actseq) SEQP_BEGIN (ed, seq) { - if ((seq->type & SEQ_TYPE_EFFECT) && ELEM(actseq, seq->seq1, seq->seq2, seq->seq3)) { + if (SEQ_CHANNEL_CHECK(seq, channel) && (seq->type & SEQ_TYPE_EFFECT) && + ELEM(actseq, seq->seq1, seq->seq2, seq->seq3)) + { effects[seq->type] = true; } } @@ -1090,7 +1105,7 @@ static bool select_grouped_effect(Editing *ed, Sequence *actseq) SEQP_BEGIN (ed, seq) { - if (effects[seq->type]) { + if (SEQ_CHANNEL_CHECK(seq, channel) && effects[seq->type]) { if (seq->seq1) seq->seq1->flag |= SELECT; if (seq->seq2) seq->seq2->flag |= SELECT; if (seq->seq3) seq->seq3->flag |= SELECT; @@ -1119,7 +1134,7 @@ static bool select_grouped_time_overlap(Editing *ed, Sequence *actseq) return changed; } -static bool select_grouped_effect_link(Editing *ed, Sequence *actseq) +static bool select_grouped_effect_link(Editing *ed, Sequence *actseq, const int channel) { Sequence *seq = NULL; bool changed = false; @@ -1143,7 +1158,8 @@ static bool select_grouped_effect_link(Editing *ed, Sequence *actseq) /* Ignore all seqs already selected! */ /* Ignore all seqs not sharing some time with active one. */ /* Ignore all seqs of incompatible types (audio vs video). */ - if ((seq->flag & SELECT) || (seq->startdisp >= enddisp) || (seq->enddisp < startdisp) || + if (!SEQ_CHANNEL_CHECK(seq, channel) || + (seq->flag & SELECT) || (seq->startdisp >= enddisp) || (seq->enddisp < startdisp) || (!is_audio && SEQ_IS_SOUND(seq)) || (is_audio && !((seq->type == SEQ_TYPE_META) || SEQ_IS_SOUND(seq)))) { @@ -1189,17 +1205,19 @@ static int sequencer_select_grouped_exec(bContext *C, wmOperator *op) Scene *scene = CTX_data_scene(C); Editing *ed = BKE_sequencer_editing_get(scene, false); Sequence *seq, *actseq = BKE_sequencer_active_get(scene); - int type = RNA_enum_get(op->ptr, "type"); - bool changed = false, extend; - extend = RNA_boolean_get(op->ptr, "extend"); + const int type = RNA_enum_get(op->ptr, "type"); + const int channel = RNA_boolean_get(op->ptr, "use_active_channel") ? actseq->machine : 0; + const bool extend = RNA_boolean_get(op->ptr, "extend"); + + bool changed = false; if (actseq == NULL) { BKE_report(op->reports, RPT_ERROR, "No active sequence!"); return OPERATOR_CANCELLED; } - if (extend == 0) { + if (!extend) { SEQP_BEGIN (ed, seq) { seq->flag &= ~SELECT; @@ -1208,13 +1226,32 @@ static int sequencer_select_grouped_exec(bContext *C, wmOperator *op) SEQ_END; } - if (type == 1) changed |= select_grouped_type(ed, actseq); - else if (type == 2) changed |= select_grouped_type_basic(ed, actseq); - else if (type == 3) changed |= select_grouped_type_effect(ed, actseq); - else if (type == 4) changed |= select_grouped_data(ed, actseq); - else if (type == 5) changed |= select_grouped_effect(ed, actseq); - else if (type == 6) changed |= select_grouped_effect_link(ed, actseq); - else if (type == 7) changed |= select_grouped_time_overlap(ed, actseq); + switch (type) { + case SEQ_SELECT_GROUP_TYPE: + changed |= select_grouped_type(ed, actseq, channel); + break; + case SEQ_SELECT_GROUP_TYPE_BASIC: + changed |= select_grouped_type_basic(ed, actseq, channel); + break; + case SEQ_SELECT_GROUP_TYPE_EFFECT: + changed |= select_grouped_type_effect(ed, actseq, channel); + break; + case SEQ_SELECT_GROUP_DATA: + changed |= select_grouped_data(ed, actseq, channel); + break; + case SEQ_SELECT_GROUP_EFFECT: + changed |= select_grouped_effect(ed, actseq, channel); + break; + case SEQ_SELECT_GROUP_EFFECT_LINK: + changed |= select_grouped_effect_link(ed, actseq, channel); + break; + case SEQ_SELECT_GROUP_OVERLAP: + changed |= select_grouped_time_overlap(ed, actseq); + break; + default: + BLI_assert(0); + break; + } if (changed) { WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene); @@ -1240,7 +1277,9 @@ void SEQUENCER_OT_select_grouped(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; /* properties */ - RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend selection instead of deselecting everything first"); ot->prop = RNA_def_enum(ot->srna, "type", sequencer_prop_select_grouped_types, 0, "Type", ""); + RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend selection instead of deselecting everything first"); + RNA_def_boolean(ot->srna, "use_active_channel", false, "Same Channel", + "Only consider strips on the same channel as the active one"); } diff --git a/source/blender/editors/space_sequencer/space_sequencer.c b/source/blender/editors/space_sequencer/space_sequencer.c index fce40f8ca59..a2a80297041 100644 --- a/source/blender/editors/space_sequencer/space_sequencer.c +++ b/source/blender/editors/space_sequencer/space_sequencer.c @@ -32,6 +32,7 @@ #include <string.h> #include <stdio.h> +#include "DNA_gpencil_types.h" #include "DNA_scene_types.h" #include "DNA_mask_types.h" @@ -41,6 +42,7 @@ #include "BLI_utildefines.h" #include "BKE_context.h" +#include "BKE_library.h" #include "BKE_screen.h" #include "BKE_sequencer.h" #include "BKE_global.h" @@ -687,6 +689,22 @@ static void sequencer_buttons_region_listener(bScreen *UNUSED(sc), ScrArea *UNUS break; } } + +static void sequencer_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID *new_id) +{ + SpaceSeq *sseq = (SpaceSeq *)slink; + + if (!ELEM(GS(old_id->name), ID_GD)) { + return; + } + + if ((ID *)sseq->gpd == old_id) { + sseq->gpd = (bGPdata *)new_id; + id_us_min(old_id); + id_us_plus(new_id); + } +} + /* ************************************* */ /* only called once, from space/spacetypes.c */ @@ -708,6 +726,7 @@ void ED_spacetype_sequencer(void) st->dropboxes = sequencer_dropboxes; st->refresh = sequencer_refresh; st->listener = sequencer_listener; + st->id_remap = sequencer_id_remap; /* regions: main window */ art = MEM_callocN(sizeof(ARegionType), "spacetype sequencer region"); diff --git a/source/blender/editors/space_text/space_text.c b/source/blender/editors/space_text/space_text.c index 0a6a9a81e63..686a10fc785 100644 --- a/source/blender/editors/space_text/space_text.c +++ b/source/blender/editors/space_text/space_text.c @@ -38,6 +38,7 @@ #include "BLI_blenlib.h" #include "BKE_context.h" +#include "BKE_library.h" #include "BKE_screen.h" #include "BKE_text.h" @@ -562,6 +563,20 @@ static void text_properties_region_draw(const bContext *C, ARegion *ar) } } +static void text_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID *new_id) +{ + SpaceText *stext = (SpaceText *)slink; + + if (!ELEM(GS(old_id->name), ID_TXT)) { + return; + } + + if ((ID *)stext->text == old_id) { + stext->text = (Text *)new_id; + id_us_ensure_real(new_id); + } +} + /********************* registration ********************/ /* only called once, from space/spacetypes.c */ @@ -582,7 +597,8 @@ void ED_spacetype_text(void) st->listener = text_listener; st->context = text_context; st->dropboxes = text_dropboxes; - + st->id_remap = text_id_remap; + /* regions: main window */ art = MEM_callocN(sizeof(ARegionType), "spacetype text region"); art->regionid = RGN_TYPE_WINDOW; diff --git a/source/blender/editors/space_text/text_autocomplete.c b/source/blender/editors/space_text/text_autocomplete.c index 04cff288b03..c38c57b9528 100644 --- a/source/blender/editors/space_text/text_autocomplete.c +++ b/source/blender/editors/space_text/text_autocomplete.c @@ -259,10 +259,8 @@ static void confirm_suggestion(Text *text) // for (i = 0; i < skipleft; i++) // txt_move_left(text, 0); - for (i = 0; i < over; i++) - txt_move_left(text, 1); - - txt_insert_buf(text, sel->name); + BLI_assert(memcmp(sel->name, &line[i], over) == 0); + txt_insert_buf(text, sel->name + over); // for (i = 0; i < skipleft; i++) // txt_move_right(text, 0); diff --git a/source/blender/editors/space_text/text_ops.c b/source/blender/editors/space_text/text_ops.c index d404e7aaf15..94ed280f792 100644 --- a/source/blender/editors/space_text/text_ops.c +++ b/source/blender/editors/space_text/text_ops.c @@ -384,8 +384,7 @@ static int text_unlink_exec(bContext *C, wmOperator *UNUSED(op)) } } - BKE_text_unlink(bmain, text); - BKE_libblock_free(bmain, text); + BKE_libblock_delete(bmain, text); text_drawcache_tag_update(st, 1); WM_event_add_notifier(C, NC_TEXT | NA_REMOVED, NULL); diff --git a/source/blender/editors/space_view3d/drawanimviz.c b/source/blender/editors/space_view3d/drawanimviz.c index 9872b05da63..cf738de0202 100644 --- a/source/blender/editors/space_view3d/drawanimviz.c +++ b/source/blender/editors/space_view3d/drawanimviz.c @@ -130,7 +130,6 @@ void draw_motion_path_instance(Scene *scene, mpv_start = (mpath->points + sind); /* draw curve-line of path */ - glShadeModel(GL_SMOOTH); glBegin(GL_LINE_STRIP); for (i = 0, mpv = mpv_start; i < len; i++, mpv++) { @@ -187,7 +186,6 @@ void draw_motion_path_instance(Scene *scene, } glEnd(); - glShadeModel(GL_FLAT); glPointSize(1.0); diff --git a/source/blender/editors/space_view3d/drawarmature.c b/source/blender/editors/space_view3d/drawarmature.c index f7c1e2ee981..1d9a515a5f2 100644 --- a/source/blender/editors/space_view3d/drawarmature.c +++ b/source/blender/editors/space_view3d/drawarmature.c @@ -431,10 +431,9 @@ static void draw_bonevert_solid(void) glNewList(displist, GL_COMPILE); qobj = gluNewQuadric(); - gluQuadricDrawStyle(qobj, GLU_FILL); - glShadeModel(GL_SMOOTH); + gluQuadricDrawStyle(qobj, GLU_FILL); + /* Draw tips of a bone */ gluSphere(qobj, 0.05, 8, 5); - glShadeModel(GL_FLAT); gluDeleteQuadric(qobj); glEndList(); @@ -890,7 +889,6 @@ static void draw_sphere_bone(const short dt, int armflag, int boneflag, short co GPU_basic_shader_bind(GPU_SHADER_LIGHTING | GPU_SHADER_USE_COLOR); gluQuadricDrawStyle(qobj, GLU_FILL); - glShadeModel(GL_SMOOTH); } else { gluQuadricDrawStyle(qobj, GLU_SILHOUETTE); @@ -968,7 +966,6 @@ static void draw_sphere_bone(const short dt, int armflag, int boneflag, short co /* restore */ if (dt == OB_SOLID) { - glShadeModel(GL_FLAT); GPU_basic_shader_bind(GPU_SHADER_USE_COLOR); } @@ -986,10 +983,11 @@ static GLubyte bm_dot7[] = {0x0, 0x38, 0x7C, 0xFE, 0xFE, 0xFE, 0x7C, 0x38}; static void draw_line_bone(int armflag, int boneflag, short constflag, unsigned int id, bPoseChannel *pchan, EditBone *ebone) { + /* call this once, avoid constant changing */ + BLI_assert(glaGetOneInt(GL_UNPACK_ALIGNMENT) == 1); + float length; - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - if (pchan) length = pchan->bone->length; else @@ -1769,7 +1767,6 @@ static void draw_pose_bones(Scene *scene, View3D *v3d, ARegion *ar, Base *base, /* and draw blended distances */ if (arm->flag & ARM_POSEMODE) { glEnable(GL_BLEND); - //glShadeModel(GL_SMOOTH); if (v3d->zbuf) glDisable(GL_DEPTH_TEST); @@ -1792,7 +1789,6 @@ static void draw_pose_bones(Scene *scene, View3D *v3d, ARegion *ar, Base *base, if (v3d->zbuf) glEnable(GL_DEPTH_TEST); glDisable(GL_BLEND); - //glShadeModel(GL_FLAT); } } @@ -2216,7 +2212,6 @@ static void draw_ebones(View3D *v3d, ARegion *ar, Object *ob, const short dt) /* and draw blended distances */ glEnable(GL_BLEND); - //glShadeModel(GL_SMOOTH); if (v3d->zbuf) glDisable(GL_DEPTH_TEST); @@ -2231,7 +2226,6 @@ static void draw_ebones(View3D *v3d, ARegion *ar, Object *ob, const short dt) if (v3d->zbuf) glEnable(GL_DEPTH_TEST); glDisable(GL_BLEND); - //glShadeModel(GL_FLAT); } /* if solid we draw it first */ @@ -2699,6 +2693,11 @@ bool draw_armature(Scene *scene, View3D *v3d, ARegion *ar, Base *base, if (v3d->flag2 & V3D_RENDER_OVERRIDE) return true; + /* needed for 'draw_line_bone' which draws pixel. */ + if (arm->drawtype == ARM_LINE) { + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + } + if (dt > OB_WIRE) { /* we use color for solid lighting */ if (ELEM(arm->drawtype, ARM_LINE, ARM_WIRE)) { @@ -2774,5 +2773,9 @@ bool draw_armature(Scene *scene, View3D *v3d, ARegion *ar, Base *base, /* restore */ glFrontFace(GL_CCW); + if (arm->drawtype == ARM_LINE) { + glPixelStorei(GL_UNPACK_ALIGNMENT, 4); + } + return retval; } diff --git a/source/blender/editors/space_view3d/drawmesh.c b/source/blender/editors/space_view3d/drawmesh.c index 0bc6447d028..755d4985518 100644 --- a/source/blender/editors/space_view3d/drawmesh.c +++ b/source/blender/editors/space_view3d/drawmesh.c @@ -369,15 +369,18 @@ static bool set_draw_settings_cached(int clearcache, MTexPoly *texface, Material } if (c_badtex) lit = 0; - if (lit != c_lit || ma != c_ma) { - if (lit) { - int options = GPU_SHADER_LIGHTING | GPU_SHADER_USE_COLOR; + if (lit != c_lit || ma != c_ma || textured != c_textured) { + int options = GPU_SHADER_USE_COLOR; - if (gtexdraw.two_sided_lighting) - options |= GPU_SHADER_TWO_SIDED; - if (c_textured && !c_badtex) - options |= GPU_SHADER_TEXTURE_2D; + if (c_textured && !c_badtex) { + options |= GPU_SHADER_TEXTURE_2D; + } + if (gtexdraw.two_sided_lighting) { + options |= GPU_SHADER_TWO_SIDED; + } + if (lit) { + options |= GPU_SHADER_LIGHTING; if (!ma) ma = give_current_material_or_def(NULL, 0); /* default material */ @@ -385,12 +388,10 @@ static bool set_draw_settings_cached(int clearcache, MTexPoly *texface, Material mul_v3_v3fl(specular, &ma->specr, ma->spec); GPU_basic_shader_colors(NULL, specular, ma->har, 1.0f); - GPU_basic_shader_bind(options); - } - else { - GPU_basic_shader_bind(GPU_SHADER_USE_COLOR); } + GPU_basic_shader_bind(options); + c_lit = lit; c_ma = ma; } @@ -495,7 +496,6 @@ static void draw_textured_begin(Scene *scene, View3D *v3d, RegionView3D *rv3d, O memcpy(Gtexdraw.obcol, obcol, sizeof(obcol)); set_draw_settings_cached(1, NULL, NULL, Gtexdraw); - glShadeModel(GL_SMOOTH); glCullFace(GL_BACK); } @@ -527,7 +527,6 @@ static void draw_textured_end(void) GPU_set_tpage(NULL, 0, 0); } - glShadeModel(GL_FLAT); glDisable(GL_CULL_FACE); GPU_basic_shader_bind(GPU_SHADER_USE_COLOR); @@ -980,10 +979,17 @@ static void draw_mesh_textured_old(Scene *scene, View3D *v3d, RegionView3D *rv3d if (ob == OBACT) { if (ob->mode & OB_MODE_WEIGHT_PAINT) { dm_draw_flag |= DM_DRAW_USE_COLORS | DM_DRAW_ALWAYS_SMOOTH | DM_DRAW_SKIP_HIDDEN; - } else if (ob->mode & OB_MODE_SCULPT) { - dm_draw_flag |= DM_DRAW_SKIP_HIDDEN; + dm_draw_flag |= DM_DRAW_SKIP_HIDDEN | DM_DRAW_USE_COLORS; + } + else if ((ob->mode & OB_MODE_TEXTURE_PAINT) == 0) { + dm_draw_flag |= DM_DRAW_USE_COLORS; + } + } + else { + if ((ob->mode & OB_MODE_TEXTURE_PAINT) == 0) { + dm_draw_flag |= DM_DRAW_USE_COLORS; } } @@ -1311,8 +1317,8 @@ void draw_mesh_paint_weight_edges(RegionView3D *rv3d, DerivedMesh *dm, } glColor4ub(255, 255, 255, 96); - glEnable(GL_LINE_STIPPLE); - glLineStipple(1, 0xAAAA); + GPU_basic_shader_bind_enable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE); + GPU_basic_shader_line_stipple(1, 0xAAAA); dm->drawMappedEdges(dm, (DMSetDrawOptions)edgemask_cb, user_data); @@ -1324,7 +1330,7 @@ void draw_mesh_paint_weight_edges(RegionView3D *rv3d, DerivedMesh *dm, glEnable(GL_DEPTH_TEST); } - glDisable(GL_LINE_STIPPLE); + GPU_basic_shader_bind_disable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE); if (use_alpha) { glDisable(GL_BLEND); diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c index 5768a37a0d9..acc20997b27 100644 --- a/source/blender/editors/space_view3d/drawobject.c +++ b/source/blender/editors/space_view3d/drawobject.c @@ -1209,7 +1209,7 @@ static void drawlamp(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base, if ((drawcone || drawshadowbox) && !v3d->transp) { /* in this case we need to draw delayed */ - ED_view3d_after_add(&v3d->afterdraw_transp, base, dflag); + ED_view3d_after_add(v3d->xray ? &v3d->afterdraw_xraytransp : &v3d->afterdraw_transp, base, dflag); return; } @@ -1409,8 +1409,8 @@ static void drawlamp(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base, float blend = z_abs * (1.0f - pow2f(la->spotblend)); /* hide line if it is zero size or overlaps with outer border, - * previously it adjusted to always to show it but that seems - * confusing because it doesn't show the actual blend size */ + * previously it adjusted to always to show it but that seems + * confusing because it doesn't show the actual blend size */ if (blend != 0.0f && blend != z_abs) { circ(0.0f, 0.0f, blend); } @@ -1600,12 +1600,9 @@ static void draw_bundle_sphere(void) displist = glGenLists(1); glNewList(displist, GL_COMPILE); - qobj = gluNewQuadric(); gluQuadricDrawStyle(qobj, GLU_FILL); - glShadeModel(GL_SMOOTH); gluSphere(qobj, 0.05, 8, 8); - glShadeModel(GL_FLAT); gluDeleteQuadric(qobj); glEndList(); @@ -1787,8 +1784,6 @@ static void draw_viewport_reconstruction( GPU_basic_shader_colors(NULL, NULL, 0, 1.0f); GPU_basic_shader_bind(GPU_SHADER_LIGHTING | GPU_SHADER_USE_COLOR); - glShadeModel(GL_SMOOTH); - tracking_object = tracking->objects.first; while (tracking_object) { draw_viewport_object_reconstruction( @@ -1799,7 +1794,6 @@ static void draw_viewport_reconstruction( } /* restore */ - glShadeModel(GL_FLAT); GPU_basic_shader_bind(GPU_SHADER_USE_COLOR); if ((dflag & DRAW_CONSTCOLOR) == 0) { @@ -1938,16 +1932,15 @@ static void drawcamera_stereo3d( if (is_stereo3d_cameras) { /* draw connecting lines */ - glPushAttrib(GL_ENABLE_BIT); - - glLineStipple(2, 0xAAAA); - glEnable(GL_LINE_STIPPLE); + GPU_basic_shader_bind_enable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE); + GPU_basic_shader_line_stipple(2, 0xAAAA); glBegin(GL_LINES); glVertex3fv(origin[0]); glVertex3fv(origin[1]); glEnd(); - glPopAttrib(); + + GPU_basic_shader_bind_disable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE); } /* draw convergence plane */ @@ -2359,7 +2352,6 @@ static void drawlattice(View3D *v3d, Object *ob) if (ob->defbase.first && lt->dvert) { actdef_wcol = ob->actdef; - glShadeModel(GL_SMOOTH); } } @@ -2388,10 +2380,6 @@ static void drawlattice(View3D *v3d, Object *ob) } } glEnd(); - - /* restoration for weight colors */ - if (actdef_wcol) - glShadeModel(GL_FLAT); if (is_edit) { BPoint *actbp = BKE_lattice_active_point_get(lt); @@ -3256,17 +3244,15 @@ static void draw_em_fancy_edges(BMEditMesh *em, Scene *scene, View3D *v3d, ((ts->selectmode & SCE_SELECT_VERTEX) || (me->drawflag & ME_DRAWEIGHT))) { if (draw_dm_edges_weight_check(me, v3d)) { - glShadeModel(GL_SMOOTH); + // Interpolate vertex weights draw_dm_edges_weight_interp(em, cageDM, ts->weightuser); - glShadeModel(GL_FLAT); } else if (ts->selectmode == SCE_SELECT_FACE) { draw_dm_edges_sel(em, cageDM, wireCol, selCol, actCol, eed_act); } else { - glShadeModel(GL_SMOOTH); + // Interpolate vertex selection draw_dm_edges_sel_interp(em, cageDM, wireCol, selCol); - glShadeModel(GL_FLAT); } } else { @@ -3766,7 +3752,7 @@ static void draw_em_fancy(Scene *scene, ARegion *ar, View3D *v3d, } if ((dt > OB_WIRE) && (v3d->flag2 & V3D_RENDER_SHADOW)) { - /* pass */ + /* pass */ } else { /* annoying but active faces is stored differently */ @@ -4272,12 +4258,15 @@ static bool draw_mesh_object(Scene *scene, ARegion *ar, View3D *v3d, RegionView3 if (ob == obedit || drawlinked) { DerivedMesh *finalDM, *cageDM; - if (obedit != ob) - finalDM = cageDM = editbmesh_get_derived_base(ob, em); - else + if (obedit != ob) { + finalDM = cageDM = editbmesh_get_derived_base( + ob, em, scene->customdata_mask); + } + else { cageDM = editbmesh_get_derived_cage_and_final( scene, ob, em, scene->customdata_mask, &finalDM); + } const bool use_material = ((me->drawflag & ME_DRAWEIGHT) == 0); @@ -4469,10 +4458,6 @@ static void drawDispListsolid(ListBase *lb, Object *ob, const short dflag, glEnableClientState(GL_VERTEX_ARRAY); - if (ob->type == OB_MBALL) { /* mball always smooth shaded */ - glShadeModel(GL_SMOOTH); - } - /* track current material, -1 for none (needed for lines) */ short col = -1; @@ -4494,7 +4479,6 @@ static void drawDispListsolid(ListBase *lb, Object *ob, const short dflag, // glVertexPointer(3, GL_FLOAT, 0, dl->verts); // glDrawArrays(GL_LINE_STRIP, 0, dl->nr); - glBegin(GL_LINE_STRIP); for (int nr = dl->nr; nr; nr--, data += 3) glVertex3fv(data); @@ -4525,15 +4509,15 @@ static void drawDispListsolid(ListBase *lb, Object *ob, const short dflag, GPU_object_material_bind(dl->col + 1, use_glsl ? &gattribs : NULL); col = dl->col; } - - if (dl->rt & CU_SMOOTH) glShadeModel(GL_SMOOTH); - else glShadeModel(GL_FLAT); + /* FLAT/SMOOTH shading for surfaces */ + glShadeModel((dl->rt & CU_SMOOTH) ? GL_SMOOTH : GL_FLAT); glEnableClientState(GL_NORMAL_ARRAY); glVertexPointer(3, GL_FLOAT, 0, dl->verts); glNormalPointer(GL_FLOAT, 0, dl->nors); glDrawElements(GL_QUADS, 4 * dl->totindex, GL_UNSIGNED_INT, dl->index); glDisableClientState(GL_NORMAL_ARRAY); + glShadeModel(GL_SMOOTH); } break; @@ -4578,7 +4562,6 @@ static void drawDispListsolid(ListBase *lb, Object *ob, const short dflag, } glDisableClientState(GL_VERTEX_ARRAY); - glShadeModel(GL_FLAT); glFrontFace(GL_CCW); if (col != -1) { @@ -5043,7 +5026,7 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv unsigned char tcol[4] = {0, 0, 0, 255}; /* 1. */ - if (part == NULL || !psys_check_enabled(ob, psys)) + if (part == NULL || !psys_check_enabled(ob, psys, G.is_rendering)) return; if (pars == NULL) return; @@ -5751,7 +5734,7 @@ static void draw_update_ptcache_edit(Scene *scene, Object *ob, PTCacheEdit *edit /* create path and child path cache if it doesn't exist already */ if (edit->pathcache == NULL) - psys_cache_edit_paths(scene, ob, edit, CFRA); + psys_cache_edit_paths(scene, ob, edit, CFRA, G.is_rendering); } static void draw_ptcache_edit(Scene *scene, View3D *v3d, PTCacheEdit *edit) @@ -5788,8 +5771,6 @@ static void draw_ptcache_edit(Scene *scene, View3D *v3d, PTCacheEdit *edit) glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_COLOR_ARRAY); - glShadeModel(GL_SMOOTH); - if (pset->brushtype == PE_BRUSH_WEIGHT) glLineWidth(2.0f); @@ -5904,7 +5885,6 @@ static void draw_ptcache_edit(Scene *scene, View3D *v3d, PTCacheEdit *edit) glDisableClientState(GL_COLOR_ARRAY); glDisableClientState(GL_NORMAL_ARRAY); glDisableClientState(GL_VERTEX_ARRAY); - glShadeModel(GL_FLAT); if (v3d->zbuf) glEnable(GL_DEPTH_TEST); } @@ -8247,7 +8227,7 @@ static void bbs_obmode_mesh_verts__mapFunc(void *userData, int index, const floa MVert *mv = &data->mvert[index]; if (!(mv->flag & ME_HIDE)) { - WM_framebuffer_index_set(data->offset + index); + GPU_select_index_set(data->offset + index); glVertex3fv(co); } } @@ -8272,7 +8252,7 @@ static void bbs_mesh_verts__mapFunc(void *userData, int index, const float co[3] BMVert *eve = BM_vert_at_index(data->bm, index); if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) { - WM_framebuffer_index_set(data->offset + index); + GPU_select_index_set(data->offset + index); glVertex3fv(co); } } @@ -8291,7 +8271,7 @@ static DMDrawOption bbs_mesh_wire__setDrawOptions(void *userData, int index) BMEdge *eed = BM_edge_at_index(data->bm, index); if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) { - WM_framebuffer_index_set(data->offset + index); + GPU_select_index_set(data->offset + index); return DM_DRAW_OPTION_NORMAL; } else { @@ -8305,7 +8285,7 @@ static void bbs_mesh_wire(BMEditMesh *em, DerivedMesh *dm, int offset) } /** - * dont set #WM_framebuffer_index_set. just use to mask other + * dont set #GPU_framebuffer_index_set. just use to mask other */ static DMDrawOption bbs_mesh_mask__setSolidDrawOptions(void *userData, int index) { @@ -8324,7 +8304,7 @@ static DMDrawOption bbs_mesh_solid__setSolidDrawOptions(void *userData, int inde BMFace *efa = BM_face_at_index(userData, index); if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) { - WM_framebuffer_index_set(index + 1); + GPU_select_index_set(index + 1); return DM_DRAW_OPTION_NORMAL; } else { @@ -8337,7 +8317,7 @@ static void bbs_mesh_solid__drawCenter(void *userData, int index, const float ce BMFace *efa = BM_face_at_index(userData, index); if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) { - WM_framebuffer_index_set(index + 1); + GPU_select_index_set(index + 1); glVertex3fv(cent); } @@ -8368,7 +8348,7 @@ static void bbs_mesh_solid_EM(BMEditMesh *em, Scene *scene, View3D *v3d, static DMDrawOption bbs_mesh_solid__setDrawOpts(void *UNUSED(userData), int index) { - WM_framebuffer_index_set(index + 1); + GPU_select_index_set(index + 1); return DM_DRAW_OPTION_NORMAL; } @@ -8377,7 +8357,7 @@ static DMDrawOption bbs_mesh_solid_hide__setDrawOpts(void *userData, int index) Mesh *me = userData; if (!(me->mpoly[index].flag & ME_HIDE)) { - WM_framebuffer_index_set(index + 1); + GPU_select_index_set(index + 1); return DM_DRAW_OPTION_NORMAL; } else { @@ -8385,7 +8365,7 @@ static DMDrawOption bbs_mesh_solid_hide__setDrawOpts(void *userData, int index) } } -/* must have called WM_framebuffer_index_set beforehand */ +/* must have called GPU_framebuffer_index_set beforehand */ static DMDrawOption bbs_mesh_solid_hide2__setDrawOpts(void *userData, int index) { Mesh *me = userData; @@ -8511,7 +8491,7 @@ static void draw_object_mesh_instance(Scene *scene, View3D *v3d, RegionView3D *r DerivedMesh *dm = NULL, *edm = NULL; if (ob->mode & OB_MODE_EDIT) { - edm = editbmesh_get_derived_base(ob, me->edit_btmesh); + edm = editbmesh_get_derived_base(ob, me->edit_btmesh, CD_MASK_BAREMESH); DM_update_materials(edm, ob); } else { diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c index 470fa80bb71..0805b81147f 100644 --- a/source/blender/editors/space_view3d/space_view3d.c +++ b/source/blender/editors/space_view3d/space_view3d.c @@ -1472,6 +1472,66 @@ static int view3d_context(const bContext *C, const char *member, bContextDataRes return -1; /* found but not available */ } +static void view3d_id_remap(ScrArea *sa, SpaceLink *slink, ID *old_id, ID *new_id) +{ + View3D *v3d; + ARegion *ar; + bool is_local = false; + + if (!ELEM(GS(old_id->name), ID_OB, ID_MA, ID_IM, ID_MC)) { + return; + } + + for (v3d = (View3D *)slink; v3d; v3d = v3d->localvd, is_local = true) { + if ((ID *)v3d->camera == old_id) { + v3d->camera = (Object *)new_id; + if (!new_id) { + for (ar = sa->regionbase.first; ar; ar = ar->next) { + if (ar->regiontype == RGN_TYPE_WINDOW) { + RegionView3D *rv3d = is_local ? ((RegionView3D *)ar->regiondata)->localvd : ar->regiondata; + if (rv3d && (rv3d->persp == RV3D_CAMOB)) { + rv3d->persp = RV3D_PERSP; + } + } + } + } + } + if ((ID *)v3d->ob_centre == old_id) { + v3d->ob_centre = (Object *)new_id; + if (new_id == NULL) { /* Otherwise, bonename may remain valid... We could be smart and check this, too? */ + v3d->ob_centre_bone[0] = '\0'; + } + } + + if ((ID *)v3d->defmaterial == old_id) { + v3d->defmaterial = (Material *)new_id; + } +#if 0 /* XXX Deprecated? */ + if ((ID *)v3d->gpd == old_id) { + v3d->gpd = (bGPData *)new_id; + } +#endif + + if (ELEM(GS(old_id->name), ID_IM, ID_MC)) { + for (BGpic *bgpic = v3d->bgpicbase.first; bgpic; bgpic = bgpic->next) { + if ((ID *)bgpic->ima == old_id) { + bgpic->ima = (Image *)new_id; + id_us_min(old_id); + id_us_plus(new_id); + } + if ((ID *)bgpic->clip == old_id) { + bgpic->clip = (MovieClip *)new_id; + id_us_min(old_id); + id_us_plus(new_id); + } + } + } + + if (is_local) { + break; + } + } +} /* only called once, from space/spacetypes.c */ void ED_spacetype_view3d(void) @@ -1491,7 +1551,8 @@ void ED_spacetype_view3d(void) st->keymap = view3d_keymap; st->dropboxes = view3d_dropboxes; st->context = view3d_context; - + st->id_remap = view3d_id_remap; + /* regions: main window */ art = MEM_callocN(sizeof(ARegionType), "spacetype view3d main region"); art->regionid = RGN_TYPE_WINDOW; diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c index 9fe4f1cc283..62059766bd6 100644 --- a/source/blender/editors/space_view3d/view3d_draw.c +++ b/source/blender/editors/space_view3d/view3d_draw.c @@ -659,7 +659,6 @@ static void draw_rotation_guide(RegionView3D *rv3d) glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glShadeModel(GL_SMOOTH); glPointSize(5); glEnable(GL_POINT_SMOOTH); glDepthMask(0); /* don't overwrite zbuf */ @@ -1491,7 +1490,7 @@ unsigned int ED_view3d_backbuf_sample(ViewContext *vc, int x, int y) BLI_endian_switch_uint32(&col); } - return WM_framebuffer_to_index(col); + return GPU_select_to_index(col); } /* reads full rect, converts indices */ @@ -1524,7 +1523,7 @@ ImBuf *ED_view3d_backbuf_read(ViewContext *vc, int xmin, int ymin, int xmax, int IMB_convert_rgba_to_abgr(ibuf_clip); } - WM_framebuffer_to_index_array(ibuf_clip->rect, size_clip[0] * size_clip[1]); + GPU_select_to_index_array(ibuf_clip->rect, size_clip[0] * size_clip[1]); if ((clip.xmin == xmin) && (clip.xmax == xmax) && @@ -3399,17 +3398,15 @@ static void view3d_main_region_clear(Scene *scene, View3D *v3d, ARegion *ar) glColor4f(0.0f, 0.0f, 0.0f, 1.0f); } } - + // Draw world glEnable(GL_DEPTH_TEST); glDepthFunc(GL_ALWAYS); - glShadeModel(GL_SMOOTH); glBegin(GL_TRIANGLE_STRIP); glVertex3f(-1.0, -1.0, 1.0); glVertex3f(1.0, -1.0, 1.0); glVertex3f(-1.0, 1.0, 1.0); glVertex3f(1.0, 1.0, 1.0); glEnd(); - glShadeModel(GL_FLAT); if (v3d->flag3 & V3D_SHOW_WORLD_DIFFUSE) { GPU_probe_sh_shader_unbind(); @@ -3460,8 +3457,6 @@ static void view3d_main_region_clear(Scene *scene, View3D *v3d, ARegion *ar) glPushMatrix(); glLoadIdentity(); - glShadeModel(GL_SMOOTH); - /* calculate buffers the first time only */ if (!buf_calculated) { for (x = 0; x < VIEWGRAD_RES_X; x++) { @@ -3547,8 +3542,6 @@ static void view3d_main_region_clear(Scene *scene, View3D *v3d, ARegion *ar) glMatrixMode(GL_MODELVIEW); glPopMatrix(); - glShadeModel(GL_FLAT); - #undef VIEWGRAD_RES_X #undef VIEWGRAD_RES_Y } @@ -3577,7 +3570,6 @@ static void view3d_main_region_clear(Scene *scene, View3D *v3d, ARegion *ar) glEnable(GL_DEPTH_TEST); glDepthFunc(GL_ALWAYS); - glShadeModel(GL_SMOOTH); glBegin(GL_QUADS); UI_ThemeColor(TH_LOW_GRAD); glVertex3f(-1.0, -1.0, 1.0); @@ -3586,8 +3578,6 @@ static void view3d_main_region_clear(Scene *scene, View3D *v3d, ARegion *ar) glVertex3f(1.0, 1.0, 1.0); glVertex3f(-1.0, 1.0, 1.0); glEnd(); - glShadeModel(GL_FLAT); - glDepthFunc(GL_LEQUAL); glDisable(GL_DEPTH_TEST); @@ -4506,6 +4496,10 @@ void view3d_main_region_draw(const bContext *C, ARegion *ar) view3d_main_region_draw_info(C, scene, ar, v3d, grid_unit, render_border); v3d->flag |= V3D_INVALID_BACKBUF; + + BLI_assert(BLI_listbase_is_empty(&v3d->afterdraw_transp)); + BLI_assert(BLI_listbase_is_empty(&v3d->afterdraw_xray)); + BLI_assert(BLI_listbase_is_empty(&v3d->afterdraw_xraytransp)); } #ifdef DEBUG_DRAW diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c index 155c7503acf..1bd0ec23d65 100644 --- a/source/blender/editors/space_view3d/view3d_edit.c +++ b/source/blender/editors/space_view3d/view3d_edit.c @@ -3620,7 +3620,7 @@ static int view3d_zoom_border_exec(bContext *C, wmOperator *op) dist_range[0] = v3d->near * 1.5f; } else { /* othographic */ - /* find the current window width and height */ + /* find the current window width and height */ vb[0] = ar->winx; vb[1] = ar->winy; @@ -4911,7 +4911,7 @@ static float view_autodist_depth_margin(ARegion *ar, const int mval[2], int marg * Get the world-space 3d location from a screen-space 2d point. * * \param mval: Input screen-space pixel location. - * \param mouse_worldloc: Output world-space loction. + * \param mouse_worldloc: Output world-space location. * \param fallback_depth_pt: Use this points depth when no depth can be found. */ bool ED_view3d_autodist( diff --git a/source/blender/editors/space_view3d/view3d_project.c b/source/blender/editors/space_view3d/view3d_project.c index 797d97586c7..ac05853e6d0 100644 --- a/source/blender/editors/space_view3d/view3d_project.c +++ b/source/blender/editors/space_view3d/view3d_project.c @@ -302,8 +302,9 @@ float ED_view3d_calc_zfac(const RegionView3D *rv3d, const float co[3], bool *r_f return zfac; } -static void view3d_win_to_ray_segment(const ARegion *ar, View3D *v3d, const float mval[2], - float r_ray_co[3], float r_ray_dir[3], float r_ray_start[3], float r_ray_end[3]) +static void view3d_win_to_ray_segment( + const ARegion *ar, const View3D *v3d, const float mval[2], + float r_ray_co[3], float r_ray_dir[3], float r_ray_start[3], float r_ray_end[3]) { RegionView3D *rv3d = ar->regiondata; float _ray_co[3], _ray_dir[3], start_offset, end_offset; @@ -346,7 +347,7 @@ static void view3d_win_to_ray_segment(const ARegion *ar, View3D *v3d, const floa } } -BLI_INLINE bool view3d_clip_segment(RegionView3D *rv3d, float ray_start[3], float ray_end[3]) +BLI_INLINE bool view3d_clip_segment(const RegionView3D *rv3d, float ray_start[3], float ray_end[3]) { if ((rv3d->rflag & RV3D_CLIPPING) && (clip_segment_v3_plane_n(ray_start, ray_end, rv3d->clip, 6, @@ -373,8 +374,9 @@ BLI_INLINE bool view3d_clip_segment(RegionView3D *rv3d, float ray_start[3], floa * \param do_clip Optionally clip the start of the ray by the view clipping planes. * \return success, false if the ray is totally clipped. */ -bool ED_view3d_win_to_ray_ex(const ARegion *ar, View3D *v3d, const float mval[2], - float r_ray_co[3], float r_ray_normal[3], float r_ray_start[3], bool do_clip) +bool ED_view3d_win_to_ray_ex( + const ARegion *ar, const View3D *v3d, const float mval[2], + float r_ray_co[3], float r_ray_normal[3], float r_ray_start[3], bool do_clip) { float ray_end[3]; @@ -382,7 +384,7 @@ bool ED_view3d_win_to_ray_ex(const ARegion *ar, View3D *v3d, const float mval[2] /* bounds clipping */ if (do_clip) { - return view3d_clip_segment((RegionView3D *)ar->regiondata, r_ray_start, ray_end); + return view3d_clip_segment(ar->regiondata, r_ray_start, ray_end); } return true; @@ -401,8 +403,9 @@ bool ED_view3d_win_to_ray_ex(const ARegion *ar, View3D *v3d, const float mval[2] * \param do_clip Optionally clip the start of the ray by the view clipping planes. * \return success, false if the ray is totally clipped. */ -bool ED_view3d_win_to_ray(const ARegion *ar, View3D *v3d, const float mval[2], - float r_ray_start[3], float r_ray_normal[3], const bool do_clip) +bool ED_view3d_win_to_ray( + const ARegion *ar, const View3D *v3d, const float mval[2], + float r_ray_start[3], float r_ray_normal[3], const bool do_clip) { return ED_view3d_win_to_ray_ex(ar, v3d, mval, NULL, r_ray_normal, r_ray_start, do_clip); } diff --git a/source/blender/editors/space_view3d/view3d_ruler.c b/source/blender/editors/space_view3d/view3d_ruler.c index c6951c79609..f46608b7d5e 100644 --- a/source/blender/editors/space_view3d/view3d_ruler.c +++ b/source/blender/editors/space_view3d/view3d_ruler.c @@ -259,6 +259,37 @@ static bool view3d_ruler_pick(RulerInfo *ruler_info, const float mval[2], } } +/** + * Ensure the 'snap_context' is only cached while dragging, + * needed since the user may toggle modes between tool use. + */ +static void ruler_state_set(bContext *C, RulerInfo *ruler_info, int state) +{ + if (state == ruler_info->state) { + return; + } + + /* always remove */ + if (ruler_info->snap_context) { + ED_transform_snap_object_context_destroy(ruler_info->snap_context); + ruler_info->snap_context = NULL; + } + + if (state == RULER_STATE_NORMAL) { + /* pass */ + } + else if (state == RULER_STATE_DRAG) { + ruler_info->snap_context = ED_transform_snap_object_context_create_view3d( + CTX_data_main(C), CTX_data_scene(C), SNAP_OBJECT_USE_CACHE, + ruler_info->ar, CTX_wm_view3d(C)); + } + else { + BLI_assert(0); + } + + ruler_info->state = state; +} + #define RULER_ID "RulerData3D" static bool view3d_ruler_to_gpencil(bContext *C, RulerInfo *ruler_info) { @@ -640,7 +671,9 @@ static void view3d_ruler_free(RulerInfo *ruler_info) { BLI_freelistN(&ruler_info->items); - ED_transform_snap_object_context_destroy(ruler_info->snap_context); + if (ruler_info->snap_context) { + ED_transform_snap_object_context_destroy(ruler_info->snap_context); + } MEM_freeN(ruler_info); } @@ -757,10 +790,6 @@ static int view3d_ruler_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSE op->customdata = ruler_info; - ruler_info->snap_context = ED_transform_snap_object_context_create_view3d( - CTX_data_main(C), CTX_data_scene(C), SNAP_OBJECT_USE_CACHE, - ar, CTX_wm_view3d(C)); - ruler_info->win = win; ruler_info->sa = sa; ruler_info->draw_handle_pixel = ED_region_draw_cb_activate(ar->type, ruler_info_draw_pixel, @@ -818,7 +847,7 @@ static int view3d_ruler_modal(bContext *C, wmOperator *op, const wmEvent *event) ruler_info->snap_flag &= ~RULER_SNAP_OK; do_draw = true; } - ruler_info->state = RULER_STATE_NORMAL; + ruler_state_set(C, ruler_info, RULER_STATE_NORMAL); } } else { @@ -835,7 +864,7 @@ static int view3d_ruler_modal(bContext *C, wmOperator *op, const wmEvent *event) RulerItem *ruler_item_prev = ruler_item_active_get(ruler_info); RulerItem *ruler_item; /* check if we want to drag an existing point or add a new one */ - ruler_info->state = RULER_STATE_DRAG; + ruler_state_set(C, ruler_info, RULER_STATE_DRAG); ruler_item = ruler_item_add(ruler_info); ruler_item_active_set(ruler_info, ruler_item); @@ -877,7 +906,7 @@ static int view3d_ruler_modal(bContext *C, wmOperator *op, const wmEvent *event) ruler_item_active_set(ruler_info, ruler_item_pick); ruler_item_pick->flag |= RULERITEM_USE_ANGLE; ruler_item_pick->co_index = 1; - ruler_info->state = RULER_STATE_DRAG; + ruler_state_set(C, ruler_info, RULER_STATE_DRAG); /* find the factor */ { @@ -904,7 +933,7 @@ static int view3d_ruler_modal(bContext *C, wmOperator *op, const wmEvent *event) else { ruler_item_active_set(ruler_info, ruler_item_pick); ruler_item_pick->co_index = co_index; - ruler_info->state = RULER_STATE_DRAG; + ruler_state_set(C, ruler_info, RULER_STATE_DRAG); /* store the initial depth */ copy_v3_v3(ruler_info->drag_start_co, ruler_item_pick->co[ruler_item_pick->co_index]); diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c index bedcf413bfa..a460d8900b4 100644 --- a/source/blender/editors/space_view3d/view3d_select.c +++ b/source/blender/editors/space_view3d/view3d_select.c @@ -94,6 +94,8 @@ #include "UI_interface.h" +#include "GPU_draw.h" + #include "view3d_intern.h" /* own include */ float ED_view3d_select_dist_px(void) @@ -1690,7 +1692,7 @@ static int do_paintvert_box_select(ViewContext *vc, rcti *rect, bool select, boo if (ENDIAN_ORDER == B_ENDIAN) { IMB_convert_rgba_to_abgr(ibuf); } - WM_framebuffer_to_index_array(ibuf->rect, size[0] * size[1]); + GPU_select_to_index_array(ibuf->rect, size[0] * size[1]); a = size[0] * size[1]; while (a--) { diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index 5b1a58497f0..95864474fc0 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -1202,8 +1202,12 @@ int transformEvent(TransInfo *t, const wmEvent *event) if (t->flag & T_PROP_EDIT) { float fac = 1.0f + 0.005f *(event->y - event->prevy); t->prop_size *= fac; - if (t->spacetype == SPACE_VIEW3D && t->persp != RV3D_ORTHO) - t->prop_size = min_ff(t->prop_size, ((View3D *)t->view)->far); + if (t->spacetype == SPACE_VIEW3D && t->persp != RV3D_ORTHO) { + t->prop_size = max_ff(min_ff(t->prop_size, ((View3D *)t->view)->far), T_PROP_SIZE_MIN); + } + else { + t->prop_size = max_ff(min_ff(t->prop_size, T_PROP_SIZE_MAX), T_PROP_SIZE_MIN); + } calculatePropRatio(t); t->redraw |= TREDRAW_HARD; handled = true; @@ -1212,8 +1216,12 @@ int transformEvent(TransInfo *t, const wmEvent *event) case TFM_MODAL_PROPSIZE_UP: if (t->flag & T_PROP_EDIT) { t->prop_size *= (t->modifiers & MOD_PRECISION) ? 1.01f : 1.1f; - if (t->spacetype == SPACE_VIEW3D && t->persp != RV3D_ORTHO) + if (t->spacetype == SPACE_VIEW3D && t->persp != RV3D_ORTHO) { t->prop_size = min_ff(t->prop_size, ((View3D *)t->view)->far); + } + else { + t->prop_size = min_ff(t->prop_size, T_PROP_SIZE_MAX); + } calculatePropRatio(t); t->redraw |= TREDRAW_HARD; handled = true; @@ -1222,6 +1230,7 @@ int transformEvent(TransInfo *t, const wmEvent *event) case TFM_MODAL_PROPSIZE_DOWN: if (t->flag & T_PROP_EDIT) { t->prop_size /= (t->modifiers & MOD_PRECISION) ? 1.01f : 1.1f; + t->prop_size = max_ff(t->prop_size, T_PROP_SIZE_MIN); calculatePropRatio(t); t->redraw |= TREDRAW_HARD; handled = true; @@ -4144,7 +4153,12 @@ static void initSnapSpatial(TransInfo *t, float r_snap[3]) r_snap[2] = r_snap[1] * 0.1f; } } - else if (ELEM(t->spacetype, SPACE_IMAGE, SPACE_CLIP)) { + else if (t->spacetype == SPACE_IMAGE) { + r_snap[0] = 0.0f; + r_snap[1] = 0.0625f; + r_snap[2] = 0.03125f; + } + else if (t->spacetype == SPACE_CLIP) { r_snap[0] = 0.0f; r_snap[1] = 0.125f; r_snap[2] = 0.0625f; @@ -5361,7 +5375,9 @@ static void slide_origdata_init_data( BMesh *bm = em->bm; sod->origfaces = BLI_ghash_ptr_new(__func__); - sod->bm_origfaces = BM_mesh_create(&bm_mesh_allocsize_default); + sod->bm_origfaces = BM_mesh_create( + &bm_mesh_allocsize_default, + &((struct BMeshCreateParams){.use_toolflags = false,})); /* we need to have matching customdata */ BM_mesh_copy_init_customdata(sod->bm_origfaces, bm, NULL); } diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h index 0e0d085bf6f..50168e78dda 100644 --- a/source/blender/editors/transform/transform.h +++ b/source/blender/editors/transform/transform.h @@ -592,6 +592,10 @@ typedef struct TransInfo { #define POINT_INIT 4 #define MULTI_POINTS 8 +/* Hard min/max for proportional size. */ +#define T_PROP_SIZE_MIN 1e-6f +#define T_PROP_SIZE_MAX 1e12f + bool initTransform(struct bContext *C, struct TransInfo *t, struct wmOperator *op, const struct wmEvent *event, int mode); void saveTransform(struct bContext *C, struct TransInfo *t, struct wmOperator *op); int transformEvent(TransInfo *t, const struct wmEvent *event); diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c index fa5e86813fa..707c60f8701 100644 --- a/source/blender/editors/transform/transform_conversions.c +++ b/source/blender/editors/transform/transform_conversions.c @@ -2676,6 +2676,20 @@ void flushTransSeq(TransInfo *t) BKE_sequence_calc(t->scene, seq); } } + + /* update effects inside meta's */ + for (a = 0, seq_prev = NULL, td = t->data, td2d = t->data2d; + a < t->total; + a++, td++, td2d++, seq_prev = seq) + { + tdsq = (TransDataSeq *)td->extra; + seq = tdsq->seq; + if ((seq != seq_prev) && (seq->depth != 0)) { + if (seq->seq1 || seq->seq2 || seq->seq3) { + BKE_sequence_calc(t->scene, seq); + } + } + } } /* need to do the overlap check in a new loop otherwise adjacent strips @@ -4920,44 +4934,47 @@ static void freeSeqData(TransInfo *t, TransCustomData *custom_data) { int overlap = 0; - seq_prev = NULL; - for (a = 0; a < t->total; a++, td++) { + for (a = 0, seq_prev = NULL; a < t->total; a++, td++, seq_prev = seq) { seq = ((TransDataSeq *)td->extra)->seq; if ((seq != seq_prev) && (seq->depth == 0) && (seq->flag & SEQ_OVERLAP)) { overlap = 1; break; } - seq_prev = seq; } if (overlap) { - bool has_effect = false; + bool has_effect_root = false, has_effect_any = false; for (seq = seqbasep->first; seq; seq = seq->next) seq->tmp = NULL; td = t->data; - seq_prev = NULL; - for (a = 0; a < t->total; a++, td++) { + for (a = 0, seq_prev = NULL; a < t->total; a++, td++, seq_prev = seq) { seq = ((TransDataSeq *)td->extra)->seq; if ((seq != seq_prev)) { /* check effects strips, we cant change their time */ if ((seq->type & SEQ_TYPE_EFFECT) && seq->seq1) { - has_effect = true; + has_effect_any = true; + if (seq->depth == 0) { + has_effect_root = true; + } } else { - /* Tag seq with a non zero value, used by BKE_sequence_base_shuffle_time to identify the ones to shuffle */ - seq->tmp = (void *)1; + /* Tag seq with a non zero value, + * used by BKE_sequence_base_shuffle_time to identify the ones to shuffle */ + if (seq->depth == 0) { + seq->tmp = (void *)1; + } } } + } if (t->flag & T_ALT_TRANSFORM) { int minframe = MAXFRAME; td = t->data; - seq_prev = NULL; - for (a = 0; a < t->total; a++, td++) { + for (a = 0, seq_prev = NULL; a < t->total; a++, td++, seq_prev = seq) { seq = ((TransDataSeq *)td->extra)->seq; - if ((seq != seq_prev)) { + if ((seq != seq_prev) && (seq->depth == 0)) { minframe = min_ii(minframe, seq->startdisp); } } @@ -4989,11 +5006,10 @@ static void freeSeqData(TransInfo *t, TransCustomData *custom_data) BKE_sequence_base_shuffle_time(seqbasep, t->scene); } - if (has_effect) { + if (has_effect_any) { /* update effects strips based on strips just moved in time */ td = t->data; - seq_prev = NULL; - for (a = 0; a < t->total; a++, td++) { + for (a = 0, seq_prev = NULL; a < t->total; a++, td++, seq_prev = seq) { seq = ((TransDataSeq *)td->extra)->seq; if ((seq != seq_prev)) { if ((seq->type & SEQ_TYPE_EFFECT) && seq->seq1) { @@ -5001,13 +5017,14 @@ static void freeSeqData(TransInfo *t, TransCustomData *custom_data) } } } + } + if (has_effect_root) { /* now if any effects _still_ overlap, we need to move them up */ td = t->data; - seq_prev = NULL; - for (a = 0; a < t->total; a++, td++) { + for (a = 0, seq_prev = NULL; a < t->total; a++, td++, seq_prev = seq) { seq = ((TransDataSeq *)td->extra)->seq; - if ((seq != seq_prev)) { + if ((seq != seq_prev) && (seq->depth == 0)) { if ((seq->type & SEQ_TYPE_EFFECT) && seq->seq1) { if (BKE_sequence_test_overlap(seqbasep, seq)) { BKE_sequence_base_shuffle(seqbasep, seq, t->scene); @@ -5874,6 +5891,7 @@ static void special_aftertrans_update__mesh(bContext *UNUSED(C), TransInfo *t) BMEditMesh *em = BKE_editmesh_from_object(t->obedit); BMesh *bm = em->bm; char hflag; + bool has_face_sel = (bm->totfacesel != 0); if (t->flag & T_MIRROR) { TransData *td; @@ -5897,8 +5915,10 @@ static void special_aftertrans_update__mesh(bContext *UNUSED(C), TransInfo *t) EDBM_automerge(t->scene, t->obedit, true, hflag); - if ((em->selectmode & SCE_SELECT_VERTEX) == 0) { - EDBM_select_flush(em); + /* Special case, this is needed or faces won't re-select. + * Flush selected edges to faces. */ + if (has_face_sel && (em->selectmode == SCE_SELECT_FACE)) { + EDBM_selectmode_flush_ex(em, SCE_SELECT_EDGE); } } } @@ -7587,7 +7607,7 @@ static void createTransPaintCurveVerts(bContext *C, TransInfo *t) for (pcp = pc->points, i = 0; i < pc->tot_points; i++, pcp++) { if (PC_IS_ANY_SEL(pcp)) { - PaintCurvePointToTransData (pcp, td, td2d, tdpc); + PaintCurvePointToTransData(pcp, td, td2d, tdpc); if (pcp->bez.f2 & SELECT) { td += 3; diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c index 5d49d1d9315..6e399d9fde3 100644 --- a/source/blender/editors/transform/transform_ops.c +++ b/source/blender/editors/transform/transform_ops.c @@ -528,7 +528,8 @@ void Transform_Properties(struct wmOperatorType *ot, int flags) prop = RNA_def_enum(ot->srna, "proportional_edit_falloff", rna_enum_proportional_falloff_items, 0, "Proportional Editing Falloff", "Falloff type for proportional editing mode"); RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_CURVE); /* Abusing id_curve :/ */ - RNA_def_float(ot->srna, "proportional_size", 1, 0.00001f, FLT_MAX, "Proportional Size", "", 0.001, 100); + RNA_def_float(ot->srna, "proportional_size", 1, T_PROP_SIZE_MIN, T_PROP_SIZE_MAX, + "Proportional Size", "", 0.001f, 100.0f); } if (flags & P_SNAP) { @@ -686,7 +687,7 @@ static void TRANSFORM_OT_tilt(struct wmOperatorType *ot) { /* identifiers */ ot->name = "Tilt"; - /* optionals - + /* optional - * "Tilt selected vertices" * "Specify an extra axis rotation for selected vertices of 3D curve" */ ot->description = "Tilt selected control vertices of 3D curve"; diff --git a/source/blender/editors/transform/transform_orientations.c b/source/blender/editors/transform/transform_orientations.c index 59d2485c964..90a4aa3614d 100644 --- a/source/blender/editors/transform/transform_orientations.c +++ b/source/blender/editors/transform/transform_orientations.c @@ -636,7 +636,7 @@ int getTransformOrientation_ex(const bContext *C, float normal[3], float plane[3 BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) { - BM_face_calc_plane(efa, vec); + BM_face_calc_tangent_auto(efa, vec); add_v3_v3(normal, efa->no); add_v3_v3(plane, vec); } @@ -690,7 +690,7 @@ int getTransformOrientation_ex(const bContext *C, float normal[3], float plane[3 sub_v3_v3v3(plane, v_pair[0]->co, v_pair[1]->co); } else { - BM_vert_tri_calc_plane(v_tri, plane); + BM_vert_tri_calc_tangent_edge(v_tri, plane); } } else { diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c index e1cf7436236..0bb64315845 100644 --- a/source/blender/editors/transform/transform_snap.c +++ b/source/blender/editors/transform/transform_snap.c @@ -599,15 +599,15 @@ static void initSnappingMode(TransInfo *t) if (t->spacetype == SPACE_VIEW3D) { if (t->tsnap.object_context == NULL) { t->tsnap.object_context = ED_transform_snap_object_context_create_view3d( - G.main, t->scene, SNAP_OBJECT_USE_CACHE, - t->ar, t->view); + G.main, t->scene, SNAP_OBJECT_USE_CACHE, + t->ar, t->view); ED_transform_snap_object_context_set_editmesh_callbacks( - t->tsnap.object_context, - (bool (*)(BMVert *, void *))BM_elem_cb_check_hflag_disabled, - bm_edge_is_snap_target, - bm_face_is_snap_target, - SET_UINT_IN_POINTER((BM_ELEM_SELECT | BM_ELEM_HIDDEN))); + t->tsnap.object_context, + (bool (*)(BMVert *, void *))BM_elem_cb_check_hflag_disabled, + bm_edge_is_snap_target, + bm_face_is_snap_target, + SET_UINT_IN_POINTER((BM_ELEM_SELECT | BM_ELEM_HIDDEN))); } } } @@ -842,6 +842,14 @@ static void ApplySnapTranslation(TransInfo *t, float vec[3]) vec[1] = point[1] - t->tsnap.snapTarget[1]; } else { + if (t->spacetype == SPACE_VIEW3D) { + if (t->options & CTX_PAINT_CURVE) { + if (ED_view3d_project_float_global(t->ar, point, point, V3D_PROJ_TEST_NOP) != V3D_PROJ_RET_OK) { + zero_v3(point); /* no good answer here... */ + } + } + } + sub_v3_v3v3(vec, point, t->tsnap.snapTarget); } } diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c index d7486372c36..e85b686b5b3 100644 --- a/source/blender/editors/transform/transform_snap_object.c +++ b/source/blender/editors/transform/transform_snap_object.c @@ -68,13 +68,13 @@ typedef struct SnapObjectData { typedef struct SnapObjectData_Mesh { SnapObjectData sd; - BVHTreeFromMesh *bvh_trees[2]; + BVHTreeFromMesh *bvh_trees[3]; } SnapObjectData_Mesh; typedef struct SnapObjectData_EditMesh { SnapObjectData sd; - BVHTreeFromEditMesh *bvh_trees[2]; + BVHTreeFromEditMesh *bvh_trees[3]; } SnapObjectData_EditMesh; @@ -87,8 +87,8 @@ struct SnapObjectContext { * otherwise this doesn't take viewport into account. */ bool use_v3d; struct { - struct View3D *v3d; - struct ARegion *ar; + const struct View3D *v3d; + const struct ARegion *ar; } v3d_data; @@ -198,7 +198,7 @@ static void raycast_all_cb(void *userdata, int index, const BVHTreeRay *ray, BVH mul_m3_v3((float(*)[3])data->timat, normal); normalize_v3(normal); - /* currently unused, and causes issues when looptri's havn't been calculated. + /* currently unused, and causes issues when looptri's haven't been calculated. * since theres some overhead in ensuring this data is valid, it may need to be optional. */ #if 0 if (data->dm) { @@ -222,9 +222,12 @@ static void raycast_all_cb(void *userdata, int index, const BVHTreeRay *ray, BVH * \{ */ static bool snapEdge( - ARegion *ar, const float v1co[3], const short v1no[3], const float v2co[3], const short v2no[3], - float obmat[4][4], float timat[3][3], const float mval_fl[2], float *dist_px, - const float ray_start[3], const float ray_start_local[3], const float ray_normal_local[3], float *ray_depth, + const ARegion *ar, const float v1co[3], const short v1no[3], const float v2co[3], const short v2no[3], + float obmat[4][4], float timat[3][3], const float mval_fl[2], + const float ray_start[3], const float ray_start_local[3], const float ray_normal_local[3], + /* read/write args */ + float *ray_depth, float *dist_px, + /* return args */ float r_loc[3], float r_no[3]) { float intersect[3] = {0, 0, 0}, ray_end[3], dvec[3]; @@ -312,9 +315,12 @@ static bool snapEdge( } static bool snapVertex( - ARegion *ar, const float vco[3], const float vno[3], - float obmat[4][4], float timat[3][3], const float mval_fl[2], float *dist_px, - const float ray_start[3], const float ray_start_local[3], const float ray_normal_local[3], float *ray_depth, + const ARegion *ar, const float vco[3], const float vno[3], + float obmat[4][4], float timat[3][3], const float mval_fl[2], + const float ray_start[3], const float ray_start_local[3], const float ray_normal_local[3], + /* read/write args */ + float *ray_depth, float *dist_px, + /* return args */ float r_loc[3], float r_no[3]) { bool retval = false; @@ -362,9 +368,12 @@ static bool snapVertex( } static bool snapArmature( - ARegion *ar, Object *ob, bArmature *arm, float obmat[4][4], - const float mval[2], float *dist_px, const short snap_to, - const float ray_start[3], const float ray_normal[3], float *ray_depth, + const ARegion *ar, Object *ob, bArmature *arm, float obmat[4][4], + const float mval[2], const short snap_to, + const float ray_start[3], const float ray_normal[3], + /* read/write args */ + float *ray_depth, float *dist_px, + /* return args */ float r_loc[3], float *UNUSED(r_no)) { float imat[4][4]; @@ -444,9 +453,12 @@ static bool snapArmature( } static bool snapCurve( - ARegion *ar, Object *ob, Curve *cu, float obmat[4][4], - const float mval[2], float *dist_px, const short snap_to, - const float ray_start[3], const float ray_normal[3], float *ray_depth, + const ARegion *ar, Object *ob, Curve *cu, float obmat[4][4], + const float mval[2], const short snap_to, + const float ray_start[3], const float ray_normal[3], + /* read/write args */ + float *ray_depth, float *dist_px, + /* return args */ float r_loc[3], float *UNUSED(r_no)) { float imat[4][4]; @@ -481,24 +493,27 @@ static bool snapCurve( break; } retval |= snapVertex( - ar, nu->bezt[u].vec[1], NULL, obmat, NULL, mval, dist_px, - ray_start, ray_start_local, ray_normal_local, ray_depth, + ar, nu->bezt[u].vec[1], NULL, obmat, NULL, mval, + ray_start, ray_start_local, ray_normal_local, + ray_depth, dist_px, r_loc, NULL); /* don't snap if handle is selected (moving), or if it is aligning to a moving handle */ if (!(nu->bezt[u].f1 & SELECT) && !(nu->bezt[u].h1 & HD_ALIGN && nu->bezt[u].f3 & SELECT)) { retval |= snapVertex( - ar, nu->bezt[u].vec[0], NULL, obmat, NULL, mval, dist_px, - ray_start, ray_start_local, ray_normal_local, ray_depth, + ar, nu->bezt[u].vec[0], NULL, obmat, NULL, mval, + ray_start, ray_start_local, ray_normal_local, + ray_depth, dist_px, r_loc, NULL); } if (!(nu->bezt[u].f3 & SELECT) && !(nu->bezt[u].h2 & HD_ALIGN && nu->bezt[u].f1 & SELECT)) { retval |= snapVertex( - ar, nu->bezt[u].vec[2], NULL, obmat, NULL, mval, dist_px, - ray_start, ray_start_local, ray_normal_local, ray_depth, + ar, nu->bezt[u].vec[2], NULL, obmat, NULL, mval, + ray_start, ray_start_local, ray_normal_local, + ray_depth, dist_px, r_loc, NULL); } } @@ -508,8 +523,9 @@ static bool snapCurve( break; } retval |= snapVertex( - ar, nu->bp[u].vec, NULL, obmat, NULL, mval, dist_px, - ray_start, ray_start_local, ray_normal_local, ray_depth, + ar, nu->bp[u].vec, NULL, obmat, NULL, mval, + ray_start, ray_start_local, ray_normal_local, + ray_depth, dist_px, r_loc, NULL); } } @@ -518,14 +534,16 @@ static bool snapCurve( if (nu->pntsu > 1) { if (nu->bezt) { retval |= snapVertex( - ar, nu->bezt[u].vec[1], NULL, obmat, NULL, mval, dist_px, - ray_start, ray_start_local, ray_normal_local, ray_depth, + ar, nu->bezt[u].vec[1], NULL, obmat, NULL, mval, + ray_start, ray_start_local, ray_normal_local, + ray_depth, dist_px, r_loc, NULL); } else { retval |= snapVertex( - ar, nu->bp[u].vec, NULL, obmat, NULL, mval, dist_px, - ray_start, ray_start_local, ray_normal_local, ray_depth, + ar, nu->bp[u].vec, NULL, obmat, NULL, mval, + ray_start, ray_start_local, ray_normal_local, + ray_depth, dist_px, r_loc, NULL); } } @@ -542,9 +560,12 @@ static bool snapCurve( /* may extend later (for now just snaps to empty center) */ static bool snapEmpty( - ARegion *ar, Object *ob, float obmat[4][4], - const float mval[2], float *dist_px, const short snap_to, - const float ray_start[3], const float ray_normal[3], float *ray_depth, + const ARegion *ar, Object *ob, float obmat[4][4], + const float mval[2], const short snap_to, + const float ray_start[3], const float ray_normal[3], + /* read/write args */ + float *ray_depth, float *dist_px, + /* return args */ float r_loc[3], float *UNUSED(r_no)) { float imat[4][4]; @@ -582,9 +603,12 @@ static bool snapEmpty( } static bool snapCamera( - ARegion *ar, Scene *scene, Object *object, float obmat[4][4], - const float mval[2], float *dist_px, const short snap_to, - const float ray_start[3], const float ray_normal[3], float *ray_depth, + const ARegion *ar, Scene *scene, Object *object, float obmat[4][4], + const float mval[2], const short snap_to, + const float ray_start[3], const float ray_normal[3], + /* read/write args */ + float *ray_depth, float *dist_px, + /* return args */ float r_loc[3], float *UNUSED(r_no)) { float orig_camera_mat[4][4], orig_camera_imat[4][4], imat[4][4]; @@ -674,16 +698,166 @@ static int dm_looptri_to_poly_index(DerivedMesh *dm, const MLoopTri *lt) return index_mp_to_orig ? index_mp_to_orig[lt->poly] : lt->poly; } +struct NearestDM_Data { + void *bvhdata; + bool is_persp; + const float *ray_depth_range; + + float *ray_depth; +}; + +static bool test_vert( + const float vco[3], const float vno[3], const float ray_co[3], const float ray_dir[3], + const float ray_depth_range[2], const float scale[3], const bool is_persp, + /* read/write args */ + float *ray_depth, float *dist_to_ray_sq, + /* return args */ + float r_co[3], float r_no[3]) +{ + const float vco_sc[3] = { + vco[0] * scale[0], + vco[1] * scale[1], + vco[2] * scale[2], + }; + const float co_sc[3] = { + ray_co[0] * scale[0], + ray_co[1] * scale[1], + ray_co[2] * scale[2], + }; + const float dir_sc[3] = { + ray_dir[0] * scale[0], + ray_dir[1] * scale[1], + ray_dir[2] * scale[2], + }; + + float depth; + float dist_sq = dist_squared_to_ray_v3(co_sc, dir_sc, vco_sc, &depth); + + if (depth < ray_depth_range[0]) + return false; + + if (is_persp) + dist_sq /= SQUARE(depth); + + if ((dist_sq < *dist_to_ray_sq) && (depth < *ray_depth)) { + *dist_to_ray_sq = dist_sq; + + copy_v3_v3(r_co, vco); + + if (vno) { + copy_v3_v3(r_no, vno); + } + + *ray_depth = depth; + return true; + } + return false; +} + +static bool test_edge( + const float v1[3], const float v2[3], const float ray_co[3], const float ray_dir[3], + const float ray_depth_range[2], const float scale[3], const bool is_persp, + /* read/write args */ + float *ray_depth, float *dist_to_ray_sq, + /* return args */ + float r_co[3], float r_no[3]) +{ + const float v1_sc[3] = { + v1[0] * scale[0], + v1[1] * scale[1], + v1[2] * scale[2], + }; + const float v2_sc[3] = { + v2[0] * scale[0], + v2[1] * scale[1], + v2[2] * scale[2], + }; + const float co_sc[3] = { + ray_co[0] * scale[0], + ray_co[1] * scale[1], + ray_co[2] * scale[2], + }; + const float dir_sc[3] = { + ray_dir[0] * scale[0], + ray_dir[1] * scale[1], + ray_dir[2] * scale[2], + }; + + float tmp_co[3], depth; + float dist_sq = dist_squared_ray_to_seg_v3(co_sc, dir_sc, v1_sc, v2_sc, tmp_co, &depth); + + if (depth < ray_depth_range[0]) + return false; + + if (is_persp) + dist_sq /= SQUARE(depth); + + if ((dist_sq < *dist_to_ray_sq) && (depth < *ray_depth)) { + *dist_to_ray_sq = dist_sq; + + tmp_co[0] /= scale[0]; + tmp_co[1] /= scale[1]; + tmp_co[2] /= scale[2]; + + copy_v3_v3(r_co, tmp_co); + + if (r_no) { + sub_v3_v3v3(r_no, v1, v2); + } + + *ray_depth = depth; + return true; + } + return false; +} + +static void test_vert_depth_cb( + void *userdata, const float origin[3], const float dir[3], + const float scale[3], int index, BVHTreeNearest *nearest) +{ + struct NearestDM_Data *ndata = userdata; + const BVHTreeFromMesh *data = ndata->bvhdata; + const MVert *vert = data->vert + index; + + if (test_vert( + vert->co, NULL, origin, dir, ndata->ray_depth_range, scale, ndata->is_persp, + ndata->ray_depth, &nearest->dist_sq, + nearest->co, NULL)) + { + normal_short_to_float_v3(nearest->no, vert->no); + nearest->index = index; + } +} + +static void test_edge_depth_cb( + void *userdata, const float origin[3], const float dir[3], + const float scale[3], int index, BVHTreeNearest *nearest) +{ + struct NearestDM_Data *ndata = userdata; + const BVHTreeFromMesh *data = ndata->bvhdata; + const MVert *vert = data->vert; + const MEdge *edge = data->edge + index; + + if (test_edge( + vert[edge->v1].co, vert[edge->v2].co, origin, dir, ndata->ray_depth_range, scale, ndata->is_persp, + ndata->ray_depth, &nearest->dist_sq, + nearest->co, nearest->no)) + { + nearest->index = index; + } +} + static bool snapDerivedMesh( SnapObjectContext *sctx, - Object *ob, DerivedMesh *dm, float obmat[4][4], - const float mval[2], float *dist_px, const short snap_to, bool do_bb, - const float ray_start[3], const float ray_normal[3], const float ray_origin[3], - float *ray_depth, unsigned int ob_index, + Object *ob, DerivedMesh *dm, float obmat[4][4], const unsigned int ob_index, + const short snap_to, bool do_bb, + const float ray_origin[3], const float ray_start[3], const float ray_normal[3], const float ray_depth_range[2], + /* read/write args */ + float *ray_depth, float *dist_to_ray_sq, float *dist_px, + /* return args */ float r_loc[3], float r_no[3], int *r_index, ListBase *r_hit_list) { - ARegion *ar = sctx->v3d_data.ar; bool retval = false; if (snap_to == SCE_SNAP_MODE_FACE) { @@ -703,10 +877,8 @@ static bool snapDerivedMesh( } { - const bool do_ray_start_correction = ( - ELEM(snap_to, SCE_SNAP_MODE_FACE, SCE_SNAP_MODE_VERTEX) && - (sctx->use_v3d && !((RegionView3D *)sctx->v3d_data.ar->regiondata)->is_persp)); - bool need_ray_start_correction_init = do_ray_start_correction; + const bool is_persp = sctx->use_v3d && ((RegionView3D *)sctx->v3d_data.ar->regiondata)->is_persp; + bool need_ray_start_correction_init = (snap_to == SCE_SNAP_MODE_FACE) && sctx->use_v3d && !is_persp; float imat[4][4]; float timat[3][3]; /* transpose inverse matrix for normals */ @@ -735,7 +907,7 @@ static bool snapDerivedMesh( if (bb) { BoundBox bb_temp; - /* We cannot aford a bbox with some null dimension, which may happen in some cases... + /* We cannot afford a bounding box with some null dimension, which may happen in some cases... * Threshold is rather high, but seems to be needed to get good behavior, see T46099. */ bb = BKE_boundbox_ensure_minimum_dimensions(bb, &bb_temp, 1e-1f); @@ -772,6 +944,9 @@ static bool snapDerivedMesh( int tree_index = -1; switch (snap_to) { case SCE_SNAP_MODE_FACE: + tree_index = 2; + break; + case SCE_SNAP_MODE_EDGE: tree_index = 1; break; case SCE_SNAP_MODE_VERTEX: @@ -793,10 +968,8 @@ static bool snapDerivedMesh( } } else { - if (ELEM(snap_to, SCE_SNAP_MODE_FACE, SCE_SNAP_MODE_VERTEX)) { - treedata = &treedata_stack; - memset(treedata, 0, sizeof(*treedata)); - } + treedata = &treedata_stack; + memset(treedata, 0, sizeof(*treedata)); } if (treedata && treedata->tree == NULL) { @@ -804,53 +977,56 @@ static bool snapDerivedMesh( case SCE_SNAP_MODE_FACE: bvhtree_from_mesh_looptri(treedata, dm, 0.0f, 4, 6); break; + case SCE_SNAP_MODE_EDGE: + bvhtree_from_mesh_edges(treedata, dm, 0.0f, 2, 6); + break; case SCE_SNAP_MODE_VERTEX: bvhtree_from_mesh_verts(treedata, dm, 0.0f, 2, 6); break; } } - - if (need_ray_start_correction_init) { - /* We *need* a reasonably valid len_diff in this case. - * Use BHVTree to find the closest face from ray_start_local. - */ - if (treedata && treedata->tree != NULL) { - BVHTreeNearest nearest; - nearest.index = -1; - nearest.dist_sq = FLT_MAX; - /* Compute and store result. */ - BLI_bvhtree_find_nearest( - treedata->tree, ray_start_local, &nearest, treedata->nearest_callback, treedata); - if (nearest.index != -1) { - len_diff = sqrtf(nearest.dist_sq); - } - } - } - /* Only use closer ray_start in case of ortho view! In perspective one, ray_start may already - * been *inside* boundbox, leading to snap failures (see T38409). - * Note also ar might be null (see T38435), in this case we assume ray_start is ok! - */ - if (do_ray_start_correction) { - float ray_org_local[3]; - - copy_v3_v3(ray_org_local, ray_origin); - mul_m4_v3(imat, ray_org_local); - - /* We pass a temp ray_start, set from object's boundbox, to avoid precision issues with very far - * away ray_start values (as returned in case of ortho view3d), see T38358. - */ - len_diff -= local_scale; /* make temp start point a bit away from bbox hit point. */ - madd_v3_v3v3fl(ray_start_local, ray_org_local, ray_normal_local, - len_diff - len_v3v3(ray_start_local, ray_org_local)); - local_depth -= len_diff; - } - else { - len_diff = 0.0f; - } - switch (snap_to) { case SCE_SNAP_MODE_FACE: { + /* Only use closer ray_start in case of ortho view! In perspective one, ray_start may already + * been *inside* boundbox, leading to snap failures (see T38409). + * Note also ar might be null (see T38435), in this case we assume ray_start is ok! + */ + if (sctx->use_v3d && !is_persp) { /* do_ray_start_correction */ + if (need_ray_start_correction_init) { + /* We *need* a reasonably valid len_diff in this case. + * Use BHVTree to find the closest face from ray_start_local. + */ + if (treedata && treedata->tree != NULL) { + BVHTreeNearest nearest; + nearest.index = -1; + nearest.dist_sq = FLT_MAX; + /* Compute and store result. */ + BLI_bvhtree_find_nearest( + treedata->tree, ray_start_local, &nearest, treedata->nearest_callback, treedata); + if (nearest.index != -1) { + float dvec[3]; + sub_v3_v3v3(dvec, nearest.co, ray_start_local); + len_diff = dot_v3v3(dvec, ray_normal_local); + } + } + } + float ray_org_local[3]; + + copy_v3_v3(ray_org_local, ray_origin); + mul_m4_v3(imat, ray_org_local); + + /* We pass a temp ray_start, set from object's boundbox, to avoid precision issues with very far + * away ray_start values (as returned in case of ortho view3d), see T38358. + */ + len_diff -= local_scale; /* make temp start point a bit away from bbox hit point. */ + madd_v3_v3v3fl(ray_start_local, ray_org_local, ray_normal_local, + len_diff + ray_depth_range[0]); + local_depth -= len_diff; + } + else { + len_diff = 0.0f; + } if (r_hit_list) { struct RayCastAll_Data data; @@ -861,7 +1037,7 @@ static bool snapDerivedMesh( data.len_diff = len_diff; data.local_scale = local_scale; data.ob = ob; - data.ob_uuid = ob_index, + data.ob_uuid = ob_index; data.dm = dm; data.hit_list = r_hit_list; data.retval = retval; @@ -907,40 +1083,90 @@ static bool snapDerivedMesh( } case SCE_SNAP_MODE_VERTEX: { + float ray_org_local[3]; + + copy_v3_v3(ray_org_local, ray_origin); + mul_m4_v3(imat, ray_org_local); + BVHTreeNearest nearest; nearest.index = -1; - nearest.dist_sq = local_depth * local_depth; - if (treedata->tree && + nearest.dist_sq = *dist_to_ray_sq; + + struct NearestDM_Data userdata; + userdata.bvhdata = treedata; + userdata.is_persp = is_persp; + userdata.ray_depth_range = ray_depth_range; + userdata.ray_depth = ray_depth; + + float ob_scale[3]; + mat4_to_size(ob_scale, obmat); + + if (treedata->tree && ( + is_persp ? + BLI_bvhtree_find_nearest_to_ray_angle( + treedata->tree, ray_org_local, ray_normal_local, + true, ob_scale, &nearest, test_vert_depth_cb, &userdata) : BLI_bvhtree_find_nearest_to_ray( - treedata->tree, ray_start_local, ray_normal_local, - &nearest, NULL, NULL) != -1) + treedata->tree, ray_org_local, ray_normal_local, + true, ob_scale, &nearest, test_vert_depth_cb, &userdata)) != -1) { - const MVert *v = &treedata->vert[nearest.index]; - float vno[3]; - normal_short_to_float_v3(vno, v->no); - retval = snapVertex( - ar, v->co, vno, obmat, timat, mval, dist_px, - ray_start, ray_start_local, ray_normal_local, ray_depth, - r_loc, r_no); + copy_v3_v3(r_loc, nearest.co); + mul_m4_v3(obmat, r_loc); + if (r_no) { + copy_v3_v3(r_no, nearest.no); + mul_m3_v3(timat, r_no); + normalize_v3(r_no); + } + *dist_px *= nearest.dist_sq / (*dist_to_ray_sq); + *dist_to_ray_sq = nearest.dist_sq; + + retval = true; } break; } case SCE_SNAP_MODE_EDGE: { - MVert *verts = dm->getVertArray(dm); - MEdge *edges = dm->getEdgeArray(dm); - int totedge = dm->getNumEdges(dm); - - for (int i = 0; i < totedge; i++) { - MEdge *e = edges + i; - retval |= snapEdge( - ar, verts[e->v1].co, verts[e->v1].no, verts[e->v2].co, verts[e->v2].no, - obmat, timat, mval, dist_px, - ray_start, ray_start_local, ray_normal_local, ray_depth, - r_loc, r_no); - } + float ray_org_local[3]; + + copy_v3_v3(ray_org_local, ray_origin); + mul_m4_v3(imat, ray_org_local); + BVHTreeNearest nearest; + + nearest.index = -1; + nearest.dist_sq = *dist_to_ray_sq; + + struct NearestDM_Data userdata; + userdata.bvhdata = treedata; + userdata.is_persp = is_persp; + userdata.ray_depth_range = ray_depth_range; + userdata.ray_depth = ray_depth; + + float ob_scale[3]; + mat4_to_size(ob_scale, obmat); + + if (treedata->tree && ( + is_persp ? + BLI_bvhtree_find_nearest_to_ray_angle( + treedata->tree, ray_org_local, ray_normal_local, + true, ob_scale, &nearest, test_edge_depth_cb, &userdata) : + BLI_bvhtree_find_nearest_to_ray( + treedata->tree, ray_org_local, ray_normal_local, + true, ob_scale, &nearest, test_edge_depth_cb, &userdata)) != -1) + { + copy_v3_v3(r_loc, nearest.co); + mul_m4_v3(obmat, r_loc); + if (r_no) { + copy_v3_v3(r_no, nearest.no); + mul_m3_v3(timat, r_no); + normalize_v3(r_no); + } + *dist_px *= nearest.dist_sq / (*dist_to_ray_sq); + *dist_to_ray_sq = nearest.dist_sq; + + retval = true; + } break; } } @@ -955,17 +1181,51 @@ static bool snapDerivedMesh( return retval; } +static void test_bmvert_depth_cb( + void *userdata, const float origin[3], const float dir[3], + const float scale[3], int index, BVHTreeNearest *nearest) +{ + struct NearestDM_Data *ndata = userdata; + const BMEditMesh *em = ndata->bvhdata; + BMVert *eve = BM_vert_at_index(em->bm, index); + + if (test_vert( + eve->co, eve->no, origin, dir, ndata->ray_depth_range, scale, ndata->is_persp, + ndata->ray_depth, &nearest->dist_sq, + nearest->co, nearest->no)) + { + nearest->index = index; + } +} + +static void test_bmedge_depth_cb( + void *userdata, const float origin[3], const float dir[3], + const float scale[3], int index, BVHTreeNearest *nearest) +{ + struct NearestDM_Data *ndata = userdata; + const BMEditMesh *em = ndata->bvhdata; + BMEdge *eed = BM_edge_at_index(em->bm, index); + + if (test_edge( + eed->v1->co, eed->v2->co, origin, dir, ndata->ray_depth_range, scale, ndata->is_persp, + ndata->ray_depth, &nearest->dist_sq, + nearest->co, nearest->no)) + { + nearest->index = index; + } +} static bool snapEditMesh( SnapObjectContext *sctx, - Object *ob, BMEditMesh *em, float obmat[4][4], - const float mval[2], float *dist_px, const short snap_to, - const float ray_start[3], const float ray_normal[3], const float ray_origin[3], - float *ray_depth, const unsigned int ob_index, + Object *ob, BMEditMesh *em, float obmat[4][4], const unsigned int ob_index, + float *dist_px, const short snap_to, + const float ray_origin[3], const float ray_start[3], const float ray_normal[3], const float ray_depth_range[2], + /* read/write args */ + float *ray_depth, float *dist_to_ray_sq, + /* return args */ float r_loc[3], float r_no[3], int *r_index, ListBase *r_hit_list) { - ARegion *ar = sctx->v3d_data.ar; bool retval = false; if (snap_to == SCE_SNAP_MODE_FACE) { @@ -985,31 +1245,19 @@ static bool snapEditMesh( } { - const bool do_ray_start_correction = ( - ELEM(snap_to, SCE_SNAP_MODE_FACE, SCE_SNAP_MODE_VERTEX) && - (sctx->use_v3d && !((RegionView3D *)sctx->v3d_data.ar->regiondata)->is_persp)); + const bool is_persp = (sctx->use_v3d && ((RegionView3D *)sctx->v3d_data.ar->regiondata)->is_persp); float imat[4][4]; float timat[3][3]; /* transpose inverse matrix for normals */ - float ray_start_local[3], ray_normal_local[3]; - float local_scale, local_depth; + float ray_normal_local[3]; invert_m4_m4(imat, obmat); transpose_m3_m4(timat, imat); - copy_v3_v3(ray_start_local, ray_start); copy_v3_v3(ray_normal_local, ray_normal); - mul_m4_v3(imat, ray_start_local); mul_mat3_m4_v3(imat, ray_normal_local); - /* local scale in normal direction */ - local_scale = normalize_v3(ray_normal_local); - local_depth = *ray_depth; - if (local_depth != BVH_RAYCAST_DIST_MAX) { - local_depth *= local_scale; - } - SnapObjectData_EditMesh *sod = NULL; BVHTreeFromEditMesh *treedata = NULL, treedata_stack; @@ -1027,6 +1275,9 @@ static bool snapEditMesh( int tree_index = -1; switch (snap_to) { case SCE_SNAP_MODE_FACE: + tree_index = 2; + break; + case SCE_SNAP_MODE_EDGE: tree_index = 1; break; case SCE_SNAP_MODE_VERTEX: @@ -1041,10 +1292,8 @@ static bool snapEditMesh( } } else { - if (ELEM(snap_to, SCE_SNAP_MODE_FACE, SCE_SNAP_MODE_VERTEX)) { - treedata = &treedata_stack; - memset(treedata, 0, sizeof(*treedata)); - } + treedata = &treedata_stack; + memset(treedata, 0, sizeof(*treedata)); } if (treedata && treedata->tree == NULL) { @@ -1059,12 +1308,29 @@ static bool snapEditMesh( em->bm, looptri_mask, sctx->callbacks.edit_mesh.test_face_fn, sctx->callbacks.edit_mesh.user_data); } - bvhtree_from_editmesh_looptri_ex(treedata, em, looptri_mask, looptri_num_active, 0.0f, 4, 6); + bvhtree_from_editmesh_looptri_ex(treedata, em, looptri_mask, looptri_num_active, 0.0f, 4, 6, NULL); if (looptri_mask) { MEM_freeN(looptri_mask); } break; } + case SCE_SNAP_MODE_EDGE: + { + BLI_bitmap *edges_mask = NULL; + int edges_num_active = -1; + if (sctx->callbacks.edit_mesh.test_edge_fn) { + edges_mask = BLI_BITMAP_NEW(em->bm->totedge, __func__); + edges_num_active = BM_iter_mesh_bitmap_from_filter( + BM_EDGES_OF_MESH, em->bm, edges_mask, + (bool (*)(BMElem *, void *))sctx->callbacks.edit_mesh.test_edge_fn, + sctx->callbacks.edit_mesh.user_data); + } + bvhtree_from_editmesh_edges_ex(treedata, em, edges_mask, edges_num_active, 0.0f, 2, 6); + if (edges_mask) { + MEM_freeN(edges_mask); + } + break; + } case SCE_SNAP_MODE_VERTEX: { BLI_bitmap *verts_mask = NULL; @@ -1085,43 +1351,56 @@ static bool snapEditMesh( } } - /* Only use closer ray_start in case of ortho view! In perspective one, ray_start may already - * been *inside* boundbox, leading to snap failures (see T38409). - * Note also ar might be null (see T38435), in this case we assume ray_start is ok! - */ - float len_diff = 0.0f; - if (do_ray_start_correction) { - /* We *need* a reasonably valid len_diff in this case. - * Use BHVTree to find the closest face from ray_start_local. - */ - if (treedata && treedata->tree != NULL) { - BVHTreeNearest nearest; - nearest.index = -1; - nearest.dist_sq = FLT_MAX; - /* Compute and store result. */ - if (BLI_bvhtree_find_nearest( - treedata->tree, ray_start_local, &nearest, treedata->nearest_callback, treedata) != -1) - { - len_diff = sqrtf(nearest.dist_sq); - float ray_org_local[3]; - - copy_v3_v3(ray_org_local, ray_origin); - mul_m4_v3(imat, ray_org_local); - - /* We pass a temp ray_start, set from object's boundbox, to avoid precision issues with very far - * away ray_start values (as returned in case of ortho view3d), see T38358. - */ - len_diff -= local_scale; /* make temp start point a bit away from bbox hit point. */ - madd_v3_v3v3fl(ray_start_local, ray_org_local, ray_normal_local, - len_diff - len_v3v3(ray_start_local, ray_org_local)); - local_depth -= len_diff; - } - } - } - switch (snap_to) { case SCE_SNAP_MODE_FACE: { + float ray_start_local[3]; + copy_v3_v3(ray_start_local, ray_start); + mul_m4_v3(imat, ray_start_local); + + /* local scale in normal direction */ + float local_scale = normalize_v3(ray_normal_local); + float local_depth = *ray_depth; + if (local_depth != BVH_RAYCAST_DIST_MAX) { + local_depth *= local_scale; + } + + /* Only use closer ray_start in case of ortho view! In perspective one, ray_start may already + * been *inside* boundbox, leading to snap failures (see T38409). + * Note also ar might be null (see T38435), in this case we assume ray_start is ok! + */ + float len_diff = 0.0f; + if (sctx->use_v3d && !is_persp) { /* do_ray_start_correction */ + /* We *need* a reasonably valid len_diff in this case. + * Use BHVTree to find the closest face from ray_start_local. + */ + if (treedata && treedata->tree != NULL) { + BVHTreeNearest nearest; + nearest.index = -1; + nearest.dist_sq = FLT_MAX; + /* Compute and store result. */ + if (BLI_bvhtree_find_nearest( + treedata->tree, ray_start_local, &nearest, NULL, NULL) != -1) + { + float dvec[3]; + sub_v3_v3v3(dvec, nearest.co, ray_start_local); + len_diff = dot_v3v3(dvec, ray_normal_local); + float ray_org_local[3]; + + copy_v3_v3(ray_org_local, ray_origin); + mul_m4_v3(imat, ray_org_local); + + /* We pass a temp ray_start, set from object's boundbox, + * to avoid precision issues with very far away ray_start values + * (as returned in case of ortho view3d), see T38358. + */ + len_diff -= local_scale; /* make temp start point a bit away from bbox hit point. */ + madd_v3_v3v3fl(ray_start_local, ray_org_local, ray_normal_local, + len_diff + ray_depth_range[0]); + local_depth -= len_diff; + } + } + } if (r_hit_list) { struct RayCastAll_Data data; @@ -1176,47 +1455,92 @@ static bool snapEditMesh( } break; } - case SCE_SNAP_MODE_VERTEX: + case SCE_SNAP_MODE_EDGE: { + float ray_org_local[3]; + + copy_v3_v3(ray_org_local, ray_origin); + mul_m4_v3(imat, ray_org_local); + BVHTreeNearest nearest; nearest.index = -1; - nearest.dist_sq = local_depth * local_depth; - if (treedata->tree && + nearest.dist_sq = *dist_to_ray_sq; + + struct NearestDM_Data userdata; + userdata.bvhdata = em; + userdata.is_persp = is_persp; + userdata.ray_depth_range = ray_depth_range; + userdata.ray_depth = ray_depth; + + float ob_scale[3]; + mat4_to_size(ob_scale, obmat); + + if (treedata->tree && ( + is_persp ? + BLI_bvhtree_find_nearest_to_ray_angle( + treedata->tree, ray_org_local, ray_normal_local, + false, ob_scale, &nearest, test_bmedge_depth_cb, &userdata) : BLI_bvhtree_find_nearest_to_ray( - treedata->tree, ray_start_local, ray_normal_local, - &nearest, NULL, NULL) != -1) + treedata->tree, ray_org_local, ray_normal_local, + false, ob_scale, &nearest, test_bmedge_depth_cb, &userdata)) != -1) { - const BMVert *v = BM_vert_at_index(em->bm, nearest.index); - retval = snapVertex( - ar, v->co, v->no, obmat, timat, mval, dist_px, - ray_start, ray_start_local, ray_normal_local, ray_depth, - r_loc, r_no); + copy_v3_v3(r_loc, nearest.co); + mul_m4_v3(obmat, r_loc); + if (r_no) { + copy_v3_v3(r_no, nearest.no); + mul_m3_v3(timat, r_no); + normalize_v3(r_no); + } + *dist_px *= nearest.dist_sq / (*dist_to_ray_sq); + *dist_to_ray_sq = nearest.dist_sq; + + retval = true; } break; } - case SCE_SNAP_MODE_EDGE: + case SCE_SNAP_MODE_VERTEX: { - BM_mesh_elem_table_ensure(em->bm, BM_EDGE); - int totedge = em->bm->totedge; - for (int i = 0; i < totedge; i++) { - BMEdge *eed = BM_edge_at_index(em->bm, i); - - if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN) && - !BM_elem_flag_test(eed->v1, BM_ELEM_SELECT) && - !BM_elem_flag_test(eed->v2, BM_ELEM_SELECT)) - { - short v1no[3], v2no[3]; - normal_float_to_short_v3(v1no, eed->v1->no); - normal_float_to_short_v3(v2no, eed->v2->no); - retval |= snapEdge( - ar, eed->v1->co, v1no, eed->v2->co, v2no, - obmat, timat, mval, dist_px, - ray_start, ray_start_local, ray_normal_local, ray_depth, - r_loc, r_no); + float ray_org_local[3]; + + copy_v3_v3(ray_org_local, ray_origin); + mul_m4_v3(imat, ray_org_local); + + BVHTreeNearest nearest; + + nearest.index = -1; + nearest.dist_sq = *dist_to_ray_sq; + + struct NearestDM_Data userdata; + userdata.bvhdata = em; + userdata.is_persp = is_persp; + userdata.ray_depth_range = ray_depth_range; + userdata.ray_depth = ray_depth; + + float ob_scale[3]; + mat4_to_size(ob_scale, obmat); + + if (treedata->tree && ( + is_persp ? + BLI_bvhtree_find_nearest_to_ray_angle( + treedata->tree, ray_org_local, ray_normal_local, + false, ob_scale, &nearest, test_bmvert_depth_cb, &userdata) : + BLI_bvhtree_find_nearest_to_ray( + treedata->tree, ray_org_local, ray_normal_local, + false, ob_scale, &nearest, test_bmedge_depth_cb, &userdata)) != -1) + { + copy_v3_v3(r_loc, nearest.co); + mul_m4_v3(obmat, r_loc); + if (r_no) { + copy_v3_v3(r_no, nearest.no); + mul_m3_v3(timat, r_no); + normalize_v3(r_no); } - } + *dist_px *= nearest.dist_sq / (*dist_to_ray_sq); + *dist_to_ray_sq = nearest.dist_sq; + retval = true; + } break; } } @@ -1231,18 +1555,28 @@ static bool snapEditMesh( return retval; } +/** + * \param use_obedit: Uses the coordinates of BMesh (if any) to do the snapping; + * \param ray_depth_range: + * - 0: distance from the ray_origin to the clipping plane min (can be negative). + * - 1: maximum distance, elements outside this are ignored. + * \param ray_depth: maximum depth allowed for r_co. + * + * \note Duplicate args here are documented at #snapObjectsRay + */ static bool snapObject( SnapObjectContext *sctx, - Object *ob, float obmat[4][4], bool use_obedit, const short snap_to, - const float mval[2], float *dist_px, const unsigned int ob_index, - const float ray_start[3], const float ray_normal[3], const float ray_origin[3], - float *ray_depth, + Object *ob, float obmat[4][4], const unsigned int ob_index, + bool use_obedit, const short snap_to, const float mval[2], + const float ray_origin[3], const float ray_start[3], const float ray_normal[3], const float ray_depth_range[2], + /* read/write args */ + float *ray_depth, float *dist_to_ray_sq, float *dist_px, /* return args */ float r_loc[3], float r_no[3], int *r_index, Object **r_ob, float r_obmat[4][4], ListBase *r_hit_list) { - ARegion *ar = sctx->v3d_data.ar; + const ARegion *ar = sctx->v3d_data.ar; bool retval = false; if (ob->type == OB_MESH) { @@ -1251,9 +1585,10 @@ static bool snapObject( if (use_obedit) { em = BKE_editmesh_from_object(ob); retval = snapEditMesh( - sctx, ob, em, obmat, mval, dist_px, snap_to, - ray_start, ray_normal, ray_origin, - ray_depth, ob_index, + sctx, ob, em, obmat, ob_index, + dist_px, snap_to, + ray_origin, ray_start, ray_normal, ray_depth_range, + ray_depth, dist_to_ray_sq, r_loc, r_no, r_index, r_hit_list); } @@ -1269,36 +1604,42 @@ static bool snapObject( dm = mesh_get_derived_final(sctx->scene, ob, CD_MASK_BAREMESH); } retval = snapDerivedMesh( - sctx, ob, dm, obmat, mval, dist_px, snap_to, true, - ray_start, ray_normal, ray_origin, - ray_depth, ob_index, - r_loc, r_no, r_index, r_hit_list); + sctx, ob, dm, obmat, ob_index, + snap_to, true, + ray_origin, ray_start, ray_normal, ray_depth_range, + ray_depth, dist_to_ray_sq, dist_px, + r_loc, r_no, + r_index, r_hit_list); dm->release(dm); } } else if (ob->type == OB_ARMATURE) { retval = snapArmature( - ar, ob, ob->data, obmat, mval, dist_px, snap_to, - ray_start, ray_normal, ray_depth, + ar, ob, ob->data, obmat, mval, snap_to, + ray_start, ray_normal, + ray_depth, dist_px, r_loc, r_no); } else if (ob->type == OB_CURVE) { retval = snapCurve( - ar, ob, ob->data, obmat, mval, dist_px, snap_to, - ray_start, ray_normal, ray_depth, + ar, ob, ob->data, obmat, mval, snap_to, + ray_start, ray_normal, + ray_depth, dist_px, r_loc, r_no); } else if (ob->type == OB_EMPTY) { retval = snapEmpty( - ar, ob, obmat, mval, dist_px, snap_to, - ray_start, ray_normal, ray_depth, + ar, ob, obmat, mval, snap_to, + ray_start, ray_normal, + ray_depth, dist_px, r_loc, r_no); } else if (ob->type == OB_CAMERA) { retval = snapCamera( - ar, sctx->scene, ob, obmat, mval, dist_px, snap_to, - ray_start, ray_normal, ray_depth, + ar, sctx->scene, ob, obmat, mval, snap_to, + ray_start, ray_normal, + ray_depth, dist_px, r_loc, r_no); } @@ -1312,18 +1653,68 @@ static bool snapObject( return retval; } +/** + * Main Snapping Function + * ====================== + * + * Walks through all objects in the scene to find the closest snap element ray. + * + * \param sctx: Snap context to store data. + * \param snap_to: Element to snap, Vertice, Edge or Face. + * Currently only works one at a time, but can eventually operate as flag. + * + * \param snap_select: from enum SnapSelect. + * + * \param use_object_edit_cage: Uses the coordinates of BMesh (if any) to do the snapping. + * \param mval: Optional screen-space 2D location we're snapping to (may phase out). + * \param ray_origin: ray_start before being moved toward the ray_normal at the distance from vew3d clip_min. + * \param ray_start: ray_origin moved for the start clipping plane (clip_min). + * \param ray_normal: Unit length direction of the ray. + * + * Read/Write Args + * --------------- + * + * \param ray_depth: maximum depth allowed for r_co, elements deeper than this value will be ignored. + * \param dist_to_ray_sq: Real distance (3D) or Tangent (view cone radius at distance 1.0) squared. + * resulting of the function #dist_px_to_dist3d_or_tangent. + * + * \param dist_px: Pixel distance to element, + * note that this will eventually be replaced entirely by \a dist_to_ray_sq. + * + * Output Args + * ----------- + * + * \param r_loc: Hit location. + * \param r_no: Hit normal (optional). + * \param r_index: Hit index or -1 when no valid index is found. + * (currently only set to the polygon index when when using ``snap_to == SCE_SNAP_MODE_FACE``). + * \param r_ob: Hit object. + * \param r_obmat: Object matrix (may not be #Object.obmat with dupli-instances). + * \param r_hit_list: List of #SnapObjectHitDepth (caller must free). + * + */ static bool snapObjectsRay( SnapObjectContext *sctx, const unsigned short snap_to, const SnapSelect snap_select, - const bool use_object_edit_cage, - const float mval[2], float *dist_px, - const float ray_start[3], const float ray_normal[3], const float ray_origin[3], float *ray_depth, + const bool use_object_edit_cage, const float mval[2], + const float ray_origin[3], const float ray_start[3], const float ray_normal[3], + /* read/write args */ + float *ray_depth, float *dist_to_ray_sq, float *dist_px, /* return args */ float r_loc[3], float r_no[3], int *r_index, Object **r_ob, float r_obmat[4][4], ListBase *r_hit_list) { bool retval = false; + + float dvec[3]; + sub_v3_v3v3(dvec, ray_start, ray_origin); + + const float ray_depth_range[2] = { + dot_v3v3(dvec, ray_normal), + *ray_depth, + }; + unsigned int ob_index = 0; Object *obedit = use_object_edit_cage ? sctx->scene->obedit : NULL; @@ -1337,9 +1728,10 @@ static bool snapObjectsRay( Object *ob = base_act->object; retval |= snapObject( - sctx, ob, ob->obmat, false, snap_to, - mval, dist_px, ob_index++, - ray_start, ray_normal, ray_origin, ray_depth, + sctx, ob, ob->obmat, ob_index++, + false, snap_to, mval, + ray_origin, ray_start, ray_normal, ray_depth_range, + ray_depth, dist_to_ray_sq, dist_px, r_loc, r_no, r_index, r_ob, r_obmat, r_hit_list); } @@ -1372,9 +1764,10 @@ static bool snapObjectsRay( Object *dupli_snap = (use_obedit_dupli) ? obedit : dupli_ob->ob; retval |= snapObject( - sctx, dupli_snap, dupli_ob->mat, use_obedit_dupli, snap_to, - mval, dist_px, ob_index++, - ray_start, ray_normal, ray_origin, ray_depth, + sctx, dupli_snap, dupli_ob->mat, ob_index++, + use_obedit_dupli, snap_to, mval, + ray_origin, ray_start, ray_normal, ray_depth_range, + ray_depth, dist_to_ray_sq, dist_px, r_loc, r_no, r_index, r_ob, r_obmat, r_hit_list); } @@ -1385,9 +1778,10 @@ static bool snapObjectsRay( Object *ob_snap = use_obedit ? obedit : ob; retval |= snapObject( - sctx, ob_snap, ob->obmat, use_obedit, snap_to, - mval, dist_px, ob_index++, - ray_start, ray_normal, ray_origin, ray_depth, + sctx, ob_snap, ob->obmat, ob_index++, + use_obedit, snap_to, mval, + ray_origin, ray_start, ray_normal, ray_depth_range, + ray_depth, dist_to_ray_sq, dist_px, r_loc, r_no, r_index, r_ob, r_obmat, r_hit_list); } } @@ -1419,7 +1813,7 @@ SnapObjectContext *ED_transform_snap_object_context_create( SnapObjectContext *ED_transform_snap_object_context_create_view3d( Main *bmain, Scene *scene, int flag, /* extra args for view3d */ - ARegion *ar, View3D *v3d) + const ARegion *ar, const View3D *v3d) { SnapObjectContext *sctx = ED_transform_snap_object_context_create(bmain, scene, flag); @@ -1489,15 +1883,19 @@ bool ED_transform_snap_object_project_ray_ex( SnapObjectContext *sctx, const unsigned short snap_to, const struct SnapObjectParams *params, - const float ray_start[3], const float ray_normal[3], float *ray_depth, + const float ray_start[3], const float ray_normal[3], + float *ray_depth, float r_loc[3], float r_no[3], int *r_index, Object **r_ob, float r_obmat[4][4]) { + float dist_to_ray_sq = 0.0f; + return snapObjectsRay( sctx, snap_to, params->snap_select, params->use_object_edit_cage, - NULL, NULL, - ray_start, ray_normal, ray_start, ray_depth, + NULL, + ray_start, ray_start, ray_normal, + ray_depth, &dist_to_ray_sq, NULL, r_loc, r_no, r_index, r_ob, r_obmat, NULL); } @@ -1516,6 +1914,8 @@ bool ED_transform_snap_object_project_ray_all( float ray_depth, bool sort, ListBase *r_hit_list) { + float dist_to_ray_sq = 0.0f; + if (ray_depth == -1.0f) { ray_depth = BVH_RAYCAST_DIST_MAX; } @@ -1526,9 +1926,9 @@ bool ED_transform_snap_object_project_ray_all( bool retval = snapObjectsRay( sctx, - snap_to, params->snap_select, params->use_object_edit_cage, - NULL, NULL, - ray_start, ray_normal, ray_start, &ray_depth, + snap_to, params->snap_select, params->use_object_edit_cage, NULL, + ray_start, ray_start, ray_normal, + &ray_depth, &dist_to_ray_sq, NULL, NULL, NULL, NULL, NULL, NULL, r_hit_list); @@ -1637,12 +2037,27 @@ static bool transform_snap_context_project_view3d_mixed_impl( } /** + * From a threshold (maximum distance to snap in pixels) returns: + * + * - The *real* distance (3D) if you are in orthographic-view. + * - The *tangent* (view cone radius at distance 1.0) if you are in perspective-view. + */ +static float dist_px_to_dist3d_or_tangent(const ARegion *ar, const float dist_px) +{ + const RegionView3D *rv3d = ar->regiondata; + if (ar->winx >= ar->winy) + return 2 * (dist_px / ar->winx) / rv3d->winmat[0][0]; + else + return 2 * (dist_px / ar->winy) / rv3d->winmat[1][1]; +} + +/** * Convenience function for performing snapping. * * Given a 2D region value, snap to vert/edge/face. * * \param sctx: Snap context. - * \param mval: Screenspace coordinate. + * \param mval_fl: Screenspace coordinate. * \param dist_px: Maximum distance to snap (in pixels). * \param use_depth: Snap to the closest element, use when using more than one snap type. * \param r_co: hit location. @@ -1672,7 +2087,7 @@ bool ED_transform_snap_object_project_view3d_ex( float *ray_depth, float r_loc[3], float r_no[3], int *r_index) { - float ray_start[3], ray_normal[3], ray_orgigin[3]; + float ray_start[3], ray_normal[3], ray_origin[3]; float ray_depth_fallback; if (ray_depth == NULL) { @@ -1682,16 +2097,37 @@ bool ED_transform_snap_object_project_view3d_ex( if (!ED_view3d_win_to_ray_ex( sctx->v3d_data.ar, sctx->v3d_data.v3d, - mval, ray_orgigin, ray_normal, ray_start, true)) + mval, ray_origin, ray_normal, ray_start, true)) { return false; } + float dist_to_ray_sq; + { + float radius = dist_px_to_dist3d_or_tangent(sctx->v3d_data.ar, *dist_px); + /** + * Workaround to use of cone (Instead of project the radius on view plane): + * In perspective view, the radius of the cone may decrease depending on the ray direction. + * This is more evident with small values of the `Viewport lens angle`. + * The threshold becomes distorted that way. + */ + RegionView3D *rv3d = sctx->v3d_data.ar->regiondata; + if (rv3d->is_persp) { + float view_dir[3]; + negate_v3_v3(view_dir, rv3d->viewinv[2]); + normalize_v3(view_dir); + radius *= dot_v3v3(ray_normal, view_dir); + } + + dist_to_ray_sq = SQUARE(radius); + } + return snapObjectsRay( sctx, snap_to, params->snap_select, params->use_object_edit_cage, - mval, dist_px, - ray_start, ray_normal, ray_orgigin, ray_depth, + mval, + ray_origin, ray_start, ray_normal, + ray_depth, &dist_to_ray_sq, dist_px, r_loc, r_no, r_index, NULL, NULL, NULL); } diff --git a/source/blender/editors/util/ed_util.c b/source/blender/editors/util/ed_util.c index 1f4ce926f16..e2f60955c81 100644 --- a/source/blender/editors/util/ed_util.c +++ b/source/blender/editors/util/ed_util.c @@ -57,6 +57,7 @@ #include "BKE_multires.h" #include "BKE_packedFile.h" #include "BKE_paint.h" +#include "BKE_screen.h" #include "ED_armature.h" #include "ED_buttons.h" @@ -326,22 +327,14 @@ void ED_region_draw_mouse_line_cb(const bContext *C, ARegion *ar, void *arg_info /** * Use to free ID references within runtime data (stored outside of DNA) * - * \note Typically notifiers take care of this, - * but there are times we have to free references immediately, see: T44376 + * \param new_id may be NULL to unlink \a old_id. */ -void ED_spacedata_id_unref(struct SpaceLink *sl, const ID *id) +void ED_spacedata_id_remap(struct ScrArea *sa, struct SpaceLink *sl, ID *old_id, ID *new_id) { + SpaceType *st = BKE_spacetype_from_id(sl->spacetype); - switch (sl->spacetype) { - case SPACE_OUTLINER: - ED_outliner_id_unref((SpaceOops *)sl, id); - break; - case SPACE_BUTS: - ED_buttons_id_unref((SpaceButs *)sl, id); - break; - case SPACE_NODE: - ED_node_id_unref((SpaceNode *)sl, id); - break; + if (st && st->id_remap) { + st->id_remap(sa, sl, old_id, new_id); } } diff --git a/source/blender/editors/uvedit/uvedit_draw.c b/source/blender/editors/uvedit/uvedit_draw.c index baa471e920b..94d69a0169f 100644 --- a/source/blender/editors/uvedit/uvedit_draw.c +++ b/source/blender/editors/uvedit/uvedit_draw.c @@ -279,8 +279,6 @@ static void draw_uvs_stretch(SpaceImage *sima, Scene *scene, BMEditMesh *em, MTe col[3] = 0.5f; /* hard coded alpha, not that nice */ - glShadeModel(GL_SMOOTH); - BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); @@ -344,8 +342,6 @@ static void draw_uvs_stretch(SpaceImage *sima, Scene *scene, BMEditMesh *em, MTe BLI_buffer_free(&av_buf); BLI_buffer_free(&auv_buf); - glShadeModel(GL_FLAT); - break; } } @@ -794,8 +790,7 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit) UI_GetThemeColor4ubv(TH_EDGE_SELECT, col1); if (interpedges) { - glShadeModel(GL_SMOOTH); - + GPU_basic_shader_bind(GPU_SHADER_USE_COLOR); BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { if (!BM_elem_flag_test(efa, BM_ELEM_TAG)) continue; @@ -810,8 +805,6 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit) } glEnd(); } - - glShadeModel(GL_FLAT); } else { BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { diff --git a/source/blender/editors/uvedit/uvedit_parametrizer.c b/source/blender/editors/uvedit/uvedit_parametrizer.c index 59f9cd16908..b3190ef784f 100644 --- a/source/blender/editors/uvedit/uvedit_parametrizer.c +++ b/source/blender/editors/uvedit/uvedit_parametrizer.c @@ -740,6 +740,16 @@ static PVert *p_vert_add(PHandle *handle, PHashKey key, const float co[3], PEdge { PVert *v = (PVert *)BLI_memarena_alloc(handle->arena, sizeof(*v)); copy_v3_v3(v->co, co); + + /* Sanity check, a single nan/inf point causes the entire result to be invalid. + * Note that values within the calculation may _become_ non-finite, + * so the rest of the code still needs to take this possability into account. */ + for (int i = 0; i < 3; i++) { + if (UNLIKELY(!isfinite(v->co[i]))) { + v->co[i] = 0.0f; + } + } + v->u.key = key; v->edge = e; v->flag = 0; @@ -3040,8 +3050,10 @@ static void p_chart_lscm_begin(PChart *chart, PBool live, PBool abf) p_chart_boundaries(chart, NULL, &outer); - if (!p_chart_symmetry_pins(chart, outer, &pin1, &pin2)) + /* outer can be NULL with non-finite coords. */ + if (outer && !p_chart_symmetry_pins(chart, outer, &pin1, &pin2)) { p_chart_extrema_verts(chart, &pin1, &pin2); + } chart->u.lscm.pin1 = pin1; chart->u.lscm.pin2 = pin2; diff --git a/source/blender/freestyle/intern/geometry/normal_cycle.h b/source/blender/freestyle/intern/geometry/normal_cycle.h index 53bc23c6eb3..8d06865e31b 100644 --- a/source/blender/freestyle/intern/geometry/normal_cycle.h +++ b/source/blender/freestyle/intern/geometry/normal_cycle.h @@ -63,13 +63,13 @@ template <class T> inline void ogf_swap(T& x, T& y) //_________________________________________________________ /** -* NormalCycle evaluates the curvature tensor in function -* of a set of dihedral angles and associated vectors. -* Reference: -* Restricted Delaunay Triangulation and Normal Cycle, -* D. Cohen-Steiner and J.M. Morvan, -* SOCG 2003 -*/ + * NormalCycle evaluates the curvature tensor in function + * of a set of dihedral angles and associated vectors. + * Reference: + * Restricted Delaunay Triangulation and Normal Cycle, + * D. Cohen-Steiner and J.M. Morvan, + * SOCG 2003 + */ class NormalCycle { public: NormalCycle(); diff --git a/source/blender/freestyle/intern/python/BPy_FrsNoise.cpp b/source/blender/freestyle/intern/python/BPy_FrsNoise.cpp index 3f29d9899e8..9efbe6b53be 100644 --- a/source/blender/freestyle/intern/python/BPy_FrsNoise.cpp +++ b/source/blender/freestyle/intern/python/BPy_FrsNoise.cpp @@ -111,7 +111,7 @@ static PyObject *FrsNoise_drand(BPy_FrsNoise * /*self*/, PyObject *args, PyObjec PyErr_SetString(PyExc_TypeError, "optional argument 1 must be of type int"); return NULL; } - if (seed){ + if (seed) { RandGen::srand48(seed); } return PyFloat_FromDouble(RandGen::drand48()); diff --git a/source/blender/freestyle/intern/python/Iterator/BPy_StrokeVertexIterator.cpp b/source/blender/freestyle/intern/python/Iterator/BPy_StrokeVertexIterator.cpp index e35076ec7fe..96a8bee9394 100644 --- a/source/blender/freestyle/intern/python/Iterator/BPy_StrokeVertexIterator.cpp +++ b/source/blender/freestyle/intern/python/Iterator/BPy_StrokeVertexIterator.cpp @@ -121,7 +121,7 @@ static PyObject *StrokeVertexIterator_iternext(BPy_StrokeVertexIterator *self) return NULL; } /* If at the start of the iterator, only return the object - * and don't increment, to keep for-loops in sync */ + * and don't increment, to keep for-loops in sync */ else if (self->at_start) { self->at_start = false; } diff --git a/source/blender/freestyle/intern/scene_graph/FrsMaterial.h b/source/blender/freestyle/intern/scene_graph/FrsMaterial.h index a00f983bbcf..220c966a5d0 100644 --- a/source/blender/freestyle/intern/scene_graph/FrsMaterial.h +++ b/source/blender/freestyle/intern/scene_graph/FrsMaterial.h @@ -298,9 +298,9 @@ public: inline void setShininess(const float s); /*! Sets the line color priority. - * \param priority - * Priority - */ + * \param priority + * Priority + */ inline void setPriority(const int priority); /* operators */ diff --git a/source/blender/freestyle/intern/stroke/AdvancedPredicates1D.h b/source/blender/freestyle/intern/stroke/AdvancedPredicates1D.h index f650e32b278..c65f121e9ba 100644 --- a/source/blender/freestyle/intern/stroke/AdvancedPredicates1D.h +++ b/source/blender/freestyle/intern/stroke/AdvancedPredicates1D.h @@ -46,8 +46,8 @@ namespace Predicates1D { // DensityLowerThanUP1D /*! Returns true if the density evaluated for the -* Interface1D is less than a user-defined density value. -*/ + * Interface1D is less than a user-defined density value. + */ class DensityLowerThanUP1D : public UnaryPredicate1D { public: diff --git a/source/blender/freestyle/intern/stroke/BasicStrokeShaders.h b/source/blender/freestyle/intern/stroke/BasicStrokeShaders.h index e3842f45eb0..cc935a7e311 100644 --- a/source/blender/freestyle/intern/stroke/BasicStrokeShaders.h +++ b/source/blender/freestyle/intern/stroke/BasicStrokeShaders.h @@ -619,9 +619,9 @@ public: } /*! Builds the shader. - * \param nodetree - * A node tree (of new shading nodes) to define textures. - */ + * \param nodetree + * A node tree (of new shading nodes) to define textures. + */ BlenderTextureShader(bNodeTree *nodetree) : StrokeShader() { _nodeTree = nodetree; diff --git a/source/blender/freestyle/intern/stroke/Stroke.h b/source/blender/freestyle/intern/stroke/Stroke.h index 5f0b4eab309..db96a27e073 100644 --- a/source/blender/freestyle/intern/stroke/Stroke.h +++ b/source/blender/freestyle/intern/stroke/Stroke.h @@ -605,15 +605,15 @@ public: */ int Resample(float iSampling); - /*! Removes all vertices from the Stroke. - */ - void RemoveAllVertices(); + /*! Removes all vertices from the Stroke. + */ + void RemoveAllVertices(); /*! Removes the stroke vertex iVertex - * from the stroke. - * The length and curvilinear abscissa are updated - * consequently. - */ + * from the stroke. + * The length and curvilinear abscissa are updated + * consequently. + */ void RemoveVertex(StrokeVertex *iVertex); /*! Inserts the stroke vertex iVertex in the stroke before next. diff --git a/source/blender/freestyle/intern/system/PythonInterpreter.h b/source/blender/freestyle/intern/system/PythonInterpreter.h index 5403ec6b13b..0e08af1bac8 100644 --- a/source/blender/freestyle/intern/system/PythonInterpreter.h +++ b/source/blender/freestyle/intern/system/PythonInterpreter.h @@ -84,8 +84,7 @@ public: Text *text = BKE_text_load(&_freestyle_bmain, fn, G.main->name); if (text) { ok = BPY_execute_text(_context, text, reports, false); - BKE_text_unlink(&_freestyle_bmain, text); - BKE_libblock_free(&_freestyle_bmain, text); + BKE_libblock_delete(&_freestyle_bmain, text); } else { BKE_reportf(reports, RPT_ERROR, "Cannot open file: %s", fn); diff --git a/source/blender/freestyle/intern/view_map/Functions0D.h b/source/blender/freestyle/intern/view_map/Functions0D.h index 647a3a530c6..f0009fca6ea 100644 --- a/source/blender/freestyle/intern/view_map/Functions0D.h +++ b/source/blender/freestyle/intern/view_map/Functions0D.h @@ -429,12 +429,12 @@ public: // QiF0D /*! Returns the quantitative invisibility of this Interface0D. -* This evaluation can be ambiguous (in the case of a TVertex for example). -* This functor tries to remove this ambiguity using the context offered by the 1D element to which the -* Interface0DIterator& belongs to. -* However, there still can be problematic cases, and the user willing to deal with this cases in a specific way -* should implement its own getQIF0D functor. -*/ + * This evaluation can be ambiguous (in the case of a TVertex for example). + * This functor tries to remove this ambiguity using the context offered by the 1D element to which the + * Interface0DIterator& belongs to. + * However, there still can be problematic cases, and the user willing to deal with this cases in a specific way + * should implement its own getQIF0D functor. + */ class QuantitativeInvisibilityF0D : public UnaryFunction0D<unsigned int> { public: diff --git a/source/blender/freestyle/intern/view_map/Silhouette.h b/source/blender/freestyle/intern/view_map/Silhouette.h index 0b20c9f6aa2..b9924e6ad95 100644 --- a/source/blender/freestyle/intern/view_map/Silhouette.h +++ b/source/blender/freestyle/intern/view_map/Silhouette.h @@ -1204,9 +1204,9 @@ public: } /*! Returns the index of the material of the face lying on the - * right of the FEdge. If this FEdge is a border, - * it has no Face on its right and therefore, no material. - */ + * right of the FEdge. If this FEdge is a border, + * it has no Face on its right and therefore, no material. + */ inline unsigned aFrsMaterialIndex() const { return _aFrsMaterialIndex; diff --git a/source/blender/freestyle/intern/winged_edge/Curvature.cpp b/source/blender/freestyle/intern/winged_edge/Curvature.cpp index 97dcc86cf31..989e101dd1a 100644 --- a/source/blender/freestyle/intern/winged_edge/Curvature.cpp +++ b/source/blender/freestyle/intern/winged_edge/Curvature.cpp @@ -372,21 +372,21 @@ void gts_vertex_principal_directions(WVertex *v, Vec3r Kh, real Kg, Vec3r &e1, V f2 = e->GetbFace(); /* We are solving for the values of the curvature tensor - * B = [ a b ; b c ]. - * The computations here are from section 5 of [Meyer et al 2002]. - * - * The first step is to calculate the linear equations governing the values of (a,b,c). These can be computed - * by setting the derivatives of the error E to zero (section 5.3). - * - * Since a + c = norm(Kh), we only compute the linear equations for dE/da and dE/db. (NB: [Meyer et al 2002] - * has the equation a + b = norm(Kh), but I'm almost positive this is incorrect). - * - * Note that the w_ij (defined in section 5.2) are all scaled by (1/8*A_mixed). We drop this uniform scale - * factor because the solution of the linear equations doesn't rely on it. - * - * The terms of the linear equations are xterm_dy with x in {a,b,c} and y in {a,b}. There are also const_dy - * terms that are the constant factors in the equations. - */ + * B = [ a b ; b c ]. + * The computations here are from section 5 of [Meyer et al 2002]. + * + * The first step is to calculate the linear equations governing the values of (a,b,c). These can be computed + * by setting the derivatives of the error E to zero (section 5.3). + * + * Since a + c = norm(Kh), we only compute the linear equations for dE/da and dE/db. (NB: [Meyer et al 2002] + * has the equation a + b = norm(Kh), but I'm almost positive this is incorrect). + * + * Note that the w_ij (defined in section 5.2) are all scaled by (1/8*A_mixed). We drop this uniform scale + * factor because the solution of the linear equations doesn't rely on it. + * + * The terms of the linear equations are xterm_dy with x in {a,b,c} and y in {a,b}. There are also const_dy + * terms that are the constant factors in the equations. + */ /* find the vector from v along edge e */ vec_edge = Vec3r(-1 * e->GetVec()); @@ -400,7 +400,7 @@ void gts_vertex_principal_directions(WVertex *v, Vec3r Kh, real Kg, Vec3r &e1, V /* section 5.2 */ /* I don't like performing a minimization where some of the weights can be negative (as can be the case - * if f1 or f2 are obtuse). To ensure all-positive weights, we check for obtuseness. */ + * if f1 or f2 are obtuse). To ensure all-positive weights, we check for obtuseness. */ weight = 0.0; if (!triangle_obtuse(v, f1)) { weight += ve2 * cotan(f1->GetNextOEdge(e->twin())->GetbVertex(), e->GetaVertex(), e->GetbVertex()) / 8.0; diff --git a/source/blender/gpu/GPU_basic_shader.h b/source/blender/gpu/GPU_basic_shader.h index df2da971845..d9bf3d1ced3 100644 --- a/source/blender/gpu/GPU_basic_shader.h +++ b/source/blender/gpu/GPU_basic_shader.h @@ -46,11 +46,13 @@ typedef enum GPUBasicShaderOption { GPU_SHADER_LIGHTING = (1 << 1), /* use lighting */ GPU_SHADER_TWO_SIDED = (1 << 2), /* flip normals towards viewer */ GPU_SHADER_TEXTURE_2D = (1 << 3), /* use 2D texture to replace diffuse color */ + GPU_SHADER_TEXTURE_RECT = (1 << 4), /* same as GPU_SHADER_TEXTURE_2D, for GL_TEXTURE_RECTANGLE */ - GPU_SHADER_SOLID_LIGHTING = (1 << 4), /* use faster lighting (set automatically) */ - GPU_SHADER_STIPPLE = (1 << 5), /* use stipple */ - GPU_SHADER_LINE = (1 << 6), /* draw lines */ - GPU_SHADER_OPTIONS_NUM = 7, + GPU_SHADER_SOLID_LIGHTING = (1 << 5), /* use faster lighting (set automatically) */ + GPU_SHADER_STIPPLE = (1 << 6), /* use stipple */ + GPU_SHADER_LINE = (1 << 7), /* draw lines */ + GPU_SHADER_FLAT_NORMAL = (1 << 8), /* use flat normals */ + GPU_SHADER_OPTIONS_NUM = 9, GPU_SHADER_OPTION_COMBINATIONS = (1 << GPU_SHADER_OPTIONS_NUM) } GPUBasicShaderOption; @@ -74,10 +76,30 @@ void GPU_basic_shaders_init(void); void GPU_basic_shaders_exit(void); void GPU_basic_shader_bind(int options); +void GPU_basic_shader_bind_enable(int options); +void GPU_basic_shader_bind_disable(int options); + int GPU_basic_shader_bound_options(void); -void GPU_basic_shader_colors(const float diffuse[3], const float specular[3], - int shininess, float alpha); +/* Only use for small blocks of code that don't support glsl shader. */ +#define GPU_BASIC_SHADER_DISABLE_AND_STORE(bound_options) \ +if (GPU_basic_shader_use_glsl_get()) { \ + if ((bound_options = GPU_basic_shader_bound_options())) { \ + GPU_basic_shader_bind(0); \ + } \ +} \ +else { bound_options = 0; } ((void)0) +#define GPU_BASIC_SHADER_ENABLE_AND_RESTORE(bound_options) \ +if (GPU_basic_shader_use_glsl_get()) { \ + if (bound_options) { \ + GPU_basic_shader_bind(bound_options); \ + } \ +} ((void)0) + + +void GPU_basic_shader_colors( + const float diffuse[3], const float specular[3], + int shininess, float alpha); /* Fixed Function Lighting */ @@ -110,6 +132,9 @@ void GPU_basic_shader_stipple(GPUBasicShaderStipple stipple_id); void GPU_basic_shader_line_stipple(GLint stipple_factor, GLushort stipple_pattern); void GPU_basic_shader_line_width(float line_width); +bool GPU_basic_shader_use_glsl_get(void); +void GPU_basic_shader_use_glsl_set(bool enabled); + #ifdef __cplusplus } #endif diff --git a/source/blender/gpu/GPU_buffers.h b/source/blender/gpu/GPU_buffers.h index aefaf1a0f54..7972d138b9b 100644 --- a/source/blender/gpu/GPU_buffers.h +++ b/source/blender/gpu/GPU_buffers.h @@ -230,7 +230,7 @@ GPU_PBVH_Buffers *GPU_build_mesh_pbvh_buffers( const int face_indices_len); GPU_PBVH_Buffers *GPU_build_grid_pbvh_buffers( - int *grid_indices, int totgrid,unsigned int **grid_hidden, int gridsize, const struct CCGKey *key, + int *grid_indices, int totgrid, unsigned int **grid_hidden, int gridsize, const struct CCGKey *key, struct GridCommonGPUBuffer **grid_common_gpu_buffer); GPU_PBVH_Buffers *GPU_build_bmesh_pbvh_buffers(bool smooth_shading); diff --git a/source/blender/gpu/GPU_draw.h b/source/blender/gpu/GPU_draw.h index 10a4491d770..d5dbd55279d 100644 --- a/source/blender/gpu/GPU_draw.h +++ b/source/blender/gpu/GPU_draw.h @@ -99,8 +99,9 @@ void GPU_clear_tpage(bool force); * - this affects fixed functions materials and texface, not glsl */ int GPU_default_lights(void); -int GPU_scene_object_lights(struct Scene *scene, struct Object *ob, - int lay, float viewmat[4][4], int ortho); +int GPU_scene_object_lights( + struct Scene *scene, struct Object *ob, + int lay, float viewmat[4][4], int ortho); /* Text render * - based on moving uv coordinates */ @@ -135,13 +136,15 @@ void GPU_set_gpu_mipmapping(int gpu_mipmap); void GPU_paint_update_image(struct Image *ima, struct ImageUser *iuser, int x, int y, int w, int h); void GPU_update_images_framechange(void); int GPU_update_image_time(struct Image *ima, double time); -int GPU_verify_image(struct Image *ima, - struct ImageUser *iuser, int textarget, int tftile, bool compare, bool mipmap, bool is_data, bool is_envmap); -void GPU_create_gl_tex(unsigned int *bind, unsigned int *rect, float *frect, int rectw, int recth, - int textarget, bool mipmap, bool use_hight_bit_depth, struct Image *ima, bool is_envmap); +int GPU_verify_image( + struct Image *ima, struct ImageUser *iuser, + int textarget, int tftile, bool compare, bool mipmap, bool is_data, bool is_envmap); +void GPU_create_gl_tex( + unsigned int *bind, unsigned int *rect, float *frect, int rectw, int recth, + int textarget, bool mipmap, bool use_hight_bit_depth, struct Image *ima, bool is_envmap); void GPU_create_gl_tex_compressed( - unsigned int *bind, unsigned int *pix, int x, int y, int mipmap, - int textarget, struct Image *ima, struct ImBuf *ibuf); + unsigned int *bind, unsigned int *pix, int x, int y, int mipmap, + int textarget, struct Image *ima, struct ImBuf *ibuf); bool GPU_upload_dxt_texture(struct ImBuf *ibuf); void GPU_free_image(struct Image *ima); void GPU_free_images(void); @@ -160,6 +163,12 @@ struct DerivedMesh; void GPU_draw_update_fvar_offset(struct DerivedMesh *dm); #endif +/* utilities */ +void GPU_select_index_set(int index); +void GPU_select_index_get(int index, int *r_col); +int GPU_select_to_index(unsigned int col); +void GPU_select_to_index_array(unsigned int *col, const unsigned int size); + #ifdef __cplusplus } #endif diff --git a/source/blender/gpu/GPU_material.h b/source/blender/gpu/GPU_material.h index 74fe1762bcb..d435935302f 100644 --- a/source/blender/gpu/GPU_material.h +++ b/source/blender/gpu/GPU_material.h @@ -263,6 +263,7 @@ void GPU_material_vertex_attributes(GPUMaterial *material, bool GPU_material_do_color_management(GPUMaterial *mat); bool GPU_material_use_new_shading_nodes(GPUMaterial *mat); +bool GPU_material_use_world_space_shading(GPUMaterial *mat); /* BRDF Shading */ diff --git a/source/blender/gpu/intern/gpu_basic_shader.c b/source/blender/gpu/intern/gpu_basic_shader.c index 088dac6f6cc..a2b89239344 100644 --- a/source/blender/gpu/intern/gpu_basic_shader.c +++ b/source/blender/gpu/intern/gpu_basic_shader.c @@ -51,8 +51,6 @@ /* State */ -static const bool USE_GLSL = false; - static struct { GPUShader *cached_shaders[GPU_SHADER_OPTION_COMBINATIONS]; bool failed_shaders[GPU_SHADER_OPTION_COMBINATIONS]; @@ -269,6 +267,24 @@ const GLubyte stipple_hexagon[128] = { 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22}; /* ********************************************* */ +/* GLSL State */ + +static bool USE_GLSL = false; + +/** + * \note this isn't part of the basic shader API, + * only set from the command line once on startup. + */ +void GPU_basic_shader_use_glsl_set(bool enabled) +{ + USE_GLSL = enabled; +} + +bool GPU_basic_shader_use_glsl_get(void) +{ + return USE_GLSL; +} + /* Init / exit */ void GPU_basic_shaders_init(void) @@ -308,6 +324,9 @@ static int detect_options() if (glIsEnabled(GL_TEXTURE_2D)) options |= GPU_SHADER_TEXTURE_2D; + if (glIsEnabled(GL_TEXTURE_RECTANGLE)) + options |= GPU_SHADER_TEXTURE_RECT; + GPU_SHADER_TEXTURE_RECT if (glIsEnabled(GL_COLOR_MATERIAL)) options |= GPU_SHADER_USE_COLOR; @@ -347,14 +366,18 @@ static GPUShader *gpu_basic_shader(int options) strcat(defines, "#define USE_COLOR\n"); if (options & GPU_SHADER_TWO_SIDED) strcat(defines, "#define USE_TWO_SIDED\n"); - if (options & GPU_SHADER_TEXTURE_2D) + if (options & (GPU_SHADER_TEXTURE_2D | GPU_SHADER_TEXTURE_RECT)) strcat(defines, "#define USE_TEXTURE\n"); + if (options & GPU_SHADER_TEXTURE_RECT) + strcat(defines, "#define USE_TEXTURE_RECTANGLE\n"); if (options & GPU_SHADER_STIPPLE) strcat(defines, "#define USE_STIPPLE\n"); if (options & GPU_SHADER_LINE) { strcat(defines, "#define DRAW_LINE\n"); geom_glsl = datatoc_gpu_shader_basic_geom_glsl; } + if (options & GPU_SHADER_FLAT_NORMAL) + strcat(defines, "#define USE_FLAT_NORMAL\n"); if (options & GPU_SHADER_SOLID_LIGHTING) strcat(defines, "#define USE_SOLID_LIGHTING\n"); else if (options & GPU_SHADER_LIGHTING) @@ -369,7 +392,7 @@ static GPUShader *gpu_basic_shader(int options) if (shader) { /* set texture map to first texture unit */ - if (options & GPU_SHADER_TEXTURE_2D) { + if (options & (GPU_SHADER_TEXTURE_2D | GPU_SHADER_TEXTURE_RECT)) { GPU_shader_bind(shader); glUniform1i(GPU_shader_get_uniform(shader, "texture_map"), 0); GPU_shader_unbind(); @@ -399,6 +422,23 @@ void GPU_basic_shader_bind(int options) { if (USE_GLSL) { if (options) { + const int bound_options = GPU_MATERIAL_STATE.bound_options; + + /* texture options need to be set for basic shader too */ + if (options & GPU_SHADER_TEXTURE_2D) { + glEnable(GL_TEXTURE_2D); + } + else if (bound_options & GPU_SHADER_TEXTURE_2D) { + glDisable(GL_TEXTURE_2D); + } + + if (options & GPU_SHADER_TEXTURE_RECT) { + glEnable(GL_TEXTURE_RECTANGLE); + } + else if (bound_options & GPU_SHADER_TEXTURE_RECT) { + glDisable(GL_TEXTURE_RECTANGLE); + } + GPUShader *shader = gpu_basic_shader(options); if (shader) { @@ -411,7 +451,7 @@ void GPU_basic_shader_bind(int options) } } else { - int bound_options = GPU_MATERIAL_STATE.bound_options; + const int bound_options = GPU_MATERIAL_STATE.bound_options; if (options & GPU_SHADER_LIGHTING) { glEnable(GL_LIGHTING); @@ -438,28 +478,59 @@ void GPU_basic_shader_bind(int options) glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, env_mode); } else if (bound_options & GPU_SHADER_TEXTURE_2D) { - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + if ((options & GPU_SHADER_TEXTURE_RECT) == 0) { + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + } glDisable(GL_TEXTURE_2D); } + if (options & GPU_SHADER_TEXTURE_RECT) { + GLint env_mode = (options & (GPU_SHADER_USE_COLOR | GPU_SHADER_LIGHTING)) ? GL_MODULATE : GL_REPLACE; + glEnable(GL_TEXTURE_RECTANGLE); + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, env_mode); + } + else if (bound_options & GPU_SHADER_TEXTURE_RECT) { + if ((options & GPU_SHADER_TEXTURE_2D) == 0) { + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + } + glDisable(GL_TEXTURE_RECTANGLE); + } + if ((options & GPU_SHADER_LINE) && (options & GPU_SHADER_STIPPLE)) { glEnable(GL_LINE_STIPPLE); } else if ((bound_options & GPU_SHADER_LINE) && (bound_options & GPU_SHADER_STIPPLE)) { glDisable(GL_LINE_STIPPLE); } - else { - if (options & GPU_SHADER_STIPPLE) - glEnable(GL_POLYGON_STIPPLE); - else if (bound_options & GPU_SHADER_STIPPLE) - glDisable(GL_POLYGON_STIPPLE); + + if (((options & GPU_SHADER_LINE) == 0) && (options & GPU_SHADER_STIPPLE)) { + glEnable(GL_POLYGON_STIPPLE); + } + else if (((bound_options & GPU_SHADER_LINE) == 0) && (bound_options & GPU_SHADER_STIPPLE)) { + glDisable(GL_POLYGON_STIPPLE); } + if (options & GPU_SHADER_FLAT_NORMAL) { + glShadeModel(GL_FLAT); + } + else if (bound_options & GPU_SHADER_FLAT_NORMAL) { + glShadeModel(GL_SMOOTH); + } } GPU_MATERIAL_STATE.bound_options = options; } +void GPU_basic_shader_bind_enable(int options) +{ + GPU_basic_shader_bind(GPU_MATERIAL_STATE.bound_options | options); +} + +void GPU_basic_shader_bind_disable(int options) +{ + GPU_basic_shader_bind(GPU_MATERIAL_STATE.bound_options & ~options); +} + int GPU_basic_shader_bound_options(void) { /* ideally this should disappear, anything that uses this is making fragile @@ -469,8 +540,9 @@ int GPU_basic_shader_bound_options(void) /* Material Colors */ -void GPU_basic_shader_colors(const float diffuse[3], const float specular[3], - int shininess, float alpha) +void GPU_basic_shader_colors( + const float diffuse[3], const float specular[3], + int shininess, float alpha) { float gl_diffuse[4], gl_specular[4]; diff --git a/source/blender/gpu/intern/gpu_buffers.c b/source/blender/gpu/intern/gpu_buffers.c index 2c6f204d9d0..36d297fb9fe 100644 --- a/source/blender/gpu/intern/gpu_buffers.c +++ b/source/blender/gpu/intern/gpu_buffers.c @@ -53,8 +53,6 @@ #include "BKE_mesh.h" #include "BKE_pbvh.h" -#include "DNA_userdef_types.h" - #include "GPU_buffers.h" #include "GPU_draw.h" #include "GPU_basic_shader.h" @@ -1845,15 +1843,15 @@ void GPU_draw_pbvh_buffers(GPU_PBVH_Buffers *buffers, DMSetMaterial setMaterial, if (buffers->vert_buf) { char *base = NULL; char *index_base = NULL; - int bound_options = 0; + /* weak inspection of bound options, should not be necessary ideally */ + const int bound_options_old = GPU_basic_shader_bound_options(); + int bound_options_new = 0; glEnableClientState(GL_VERTEX_ARRAY); if (!wireframe) { glEnableClientState(GL_NORMAL_ARRAY); glEnableClientState(GL_COLOR_ARRAY); - /* weak inspection of bound options, should not be necessary ideally */ - bound_options = GPU_basic_shader_bound_options(); - GPU_basic_shader_bind(bound_options | GPU_SHADER_USE_COLOR); + bound_options_new |= GPU_SHADER_USE_COLOR; } GPU_buffer_bind(buffers->vert_buf, GPU_BINDING_ARRAY); @@ -1865,10 +1863,18 @@ void GPU_draw_pbvh_buffers(GPU_PBVH_Buffers *buffers, DMSetMaterial setMaterial, GPU_buffer_bind(buffers->index_buf, GPU_BINDING_INDEX); } - if (wireframe) + if (wireframe) { glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - else - glShadeModel((buffers->smooth || buffers->face_indices_len) ? GL_SMOOTH : GL_FLAT); + } + else { + if ((buffers->smooth == false) && (buffers->face_indices_len == 0)) { + bound_options_new |= GPU_SHADER_FLAT_NORMAL; + } + } + + if (bound_options_new & ~bound_options_old) { + GPU_basic_shader_bind(bound_options_old | bound_options_new); + } if (buffers->tot_quad) { const char *offset = base; @@ -1942,7 +1948,10 @@ void GPU_draw_pbvh_buffers(GPU_PBVH_Buffers *buffers, DMSetMaterial setMaterial, if (!wireframe) { glDisableClientState(GL_NORMAL_ARRAY); glDisableClientState(GL_COLOR_ARRAY); - GPU_basic_shader_bind(bound_options); + } + + if (bound_options_new & ~bound_options_old) { + GPU_basic_shader_bind(bound_options_old); } } } diff --git a/source/blender/gpu/intern/gpu_codegen.c b/source/blender/gpu/intern/gpu_codegen.c index fae60031589..c8920039a19 100644 --- a/source/blender/gpu/intern/gpu_codegen.c +++ b/source/blender/gpu/intern/gpu_codegen.c @@ -98,8 +98,10 @@ typedef struct GPUFunction { } GPUFunction; /* Indices match the GPUType enum */ -static const char *GPU_DATATYPE_STR[17] = {"", "float", "vec2", "vec3", "vec4", - NULL, NULL, NULL, NULL, "mat3", NULL, NULL, NULL, NULL, NULL, NULL, "mat4"}; +static const char *GPU_DATATYPE_STR[17] = { + "", "float", "vec2", "vec3", "vec4", + NULL, NULL, NULL, NULL, "mat3", NULL, NULL, NULL, NULL, NULL, NULL, "mat4", +}; /* GLSL code parsing for finding function definitions. * These are stored in a hash for lookup when creating a material. */ diff --git a/source/blender/gpu/intern/gpu_compositing.c b/source/blender/gpu/intern/gpu_compositing.c index d015f7c715a..d1c54ea9865 100644 --- a/source/blender/gpu/intern/gpu_compositing.c +++ b/source/blender/gpu/intern/gpu_compositing.c @@ -34,17 +34,12 @@ #include "BLI_sys_types.h" #include "BLI_rect.h" #include "BLI_math.h" -#include "BLI_listbase.h" -#include "BLI_linklist.h" #include "BKE_colortools.h" #include "BKE_scene.h" #include "DNA_vec_types.h" -#include "DNA_view3d_types.h" #include "DNA_scene_types.h" -#include "DNA_object_types.h" -#include "DNA_camera_types.h" #include "DNA_gpu_types.h" #include "IMB_colormanagement.h" diff --git a/source/blender/gpu/intern/gpu_draw.c b/source/blender/gpu/intern/gpu_draw.c index 655b56aea90..ec274ebef54 100644 --- a/source/blender/gpu/intern/gpu_draw.c +++ b/source/blender/gpu/intern/gpu_draw.c @@ -39,7 +39,6 @@ #include <string.h> #include "GPU_glew.h" -#include "GPU_debug.h" #include "BLI_blenlib.h" #include "BLI_linklist.h" @@ -70,10 +69,11 @@ #include "BKE_main.h" #include "BKE_material.h" #include "BKE_node.h" -#include "BKE_object.h" #include "BKE_scene.h" -#include "BKE_subsurf.h" #include "BKE_DerivedMesh.h" +#ifdef WITH_GAMEENGINE +# include "BKE_object.h" +#endif #include "GPU_basic_shader.h" #include "GPU_buffers.h" @@ -87,9 +87,12 @@ #include "PIL_time.h" -#include "smoke_API.h" +#ifdef WITH_SMOKE +# include "smoke_API.h" +#endif #ifdef WITH_OPENSUBDIV +# include "BKE_subsurf.h" # include "BKE_editmesh.h" # include "gpu_codegen.h" @@ -568,7 +571,9 @@ static void gpu_verify_high_bit_srgb_buffer(float *srgb_frect, } } -int GPU_verify_image(Image *ima, ImageUser *iuser, int textarget, int tftile, bool compare, bool mipmap, bool is_data, bool is_envmap) +int GPU_verify_image( + Image *ima, ImageUser *iuser, + int textarget, int tftile, bool compare, bool mipmap, bool is_data, bool is_envmap) { unsigned int *bind = NULL; int tpx = 0, tpy = 0; @@ -850,8 +855,9 @@ static void gpu_del_cube_map(void **cube_map) } /* Image *ima can be NULL */ -void GPU_create_gl_tex(unsigned int *bind, unsigned int *rect, float *frect, int rectw, int recth, - int textarget, bool mipmap, bool use_high_bit_depth, Image *ima, bool is_envmap) +void GPU_create_gl_tex( + unsigned int *bind, unsigned int *rect, float *frect, int rectw, int recth, + int textarget, bool mipmap, bool use_high_bit_depth, Image *ima, bool is_envmap) { ImBuf *ibuf = NULL; @@ -2102,8 +2108,9 @@ int GPU_object_material_bind(int nr, void *attribs) } else { /* or do fixed function opengl material */ - GPU_basic_shader_colors(GMS.matbuf[nr].diff, - GMS.matbuf[nr].spec, GMS.matbuf[nr].hard, GMS.matbuf[nr].alpha); + GPU_basic_shader_colors( + GMS.matbuf[nr].diff, + GMS.matbuf[nr].spec, GMS.matbuf[nr].hard, GMS.matbuf[nr].alpha); if (GMS.two_sided_lighting) GPU_basic_shader_bind(GPU_SHADER_LIGHTING | GPU_SHADER_TWO_SIDED); @@ -2399,8 +2406,6 @@ void GPU_state_init(void) /* scaling matrices */ glEnable(GL_NORMALIZE); - glShadeModel(GL_FLAT); - glDisable(GL_ALPHA_TEST); glDisable(GL_BLEND); glDisable(GL_DEPTH_TEST); @@ -2479,3 +2484,152 @@ void GPU_draw_update_fvar_offset(DerivedMesh *dm) } } #endif + + +/** \name Framebuffer color depth, for selection codes + * \{ */ + +#ifdef __APPLE__ + +/* apple seems to round colors to below and up on some configs */ + +static unsigned int index_to_framebuffer(int index) +{ + unsigned int i = index; + + switch (GPU_color_depth()) { + case 12: + i = ((i & 0xF00) << 12) + ((i & 0xF0) << 8) + ((i & 0xF) << 4); + /* sometimes dithering subtracts! */ + i |= 0x070707; + break; + case 15: + case 16: + i = ((i & 0x7C00) << 9) + ((i & 0x3E0) << 6) + ((i & 0x1F) << 3); + i |= 0x030303; + break; + case 24: + break; + default: /* 18 bits... */ + i = ((i & 0x3F000) << 6) + ((i & 0xFC0) << 4) + ((i & 0x3F) << 2); + i |= 0x010101; + break; + } + + return i; +} + +#else + +/* this is the old method as being in use for ages.... seems to work? colors are rounded to lower values */ + +static unsigned int index_to_framebuffer(int index) +{ + unsigned int i = index; + + switch (GPU_color_depth()) { + case 8: + i = ((i & 48) << 18) + ((i & 12) << 12) + ((i & 3) << 6); + i |= 0x3F3F3F; + break; + case 12: + i = ((i & 0xF00) << 12) + ((i & 0xF0) << 8) + ((i & 0xF) << 4); + /* sometimes dithering subtracts! */ + i |= 0x0F0F0F; + break; + case 15: + case 16: + i = ((i & 0x7C00) << 9) + ((i & 0x3E0) << 6) + ((i & 0x1F) << 3); + i |= 0x070707; + break; + case 24: + break; + default: /* 18 bits... */ + i = ((i & 0x3F000) << 6) + ((i & 0xFC0) << 4) + ((i & 0x3F) << 2); + i |= 0x030303; + break; + } + + return i; +} + +#endif + + +void GPU_select_index_set(int index) +{ + const int col = index_to_framebuffer(index); + glColor3ub(( (col) & 0xFF), + (((col) >> 8) & 0xFF), + (((col) >> 16) & 0xFF)); +} + +void GPU_select_index_get(int index, int *r_col) +{ + const int col = index_to_framebuffer(index); + char *c_col = (char *)r_col; + c_col[0] = (col & 0xFF); /* red */ + c_col[1] = ((col >> 8) & 0xFF); /* green */ + c_col[2] = ((col >> 16) & 0xFF); /* blue */ + c_col[3] = 0xFF; /* alpha */ +} + + +#define INDEX_FROM_BUF_8(col) ((((col) & 0xC00000) >> 18) + (((col) & 0xC000) >> 12) + (((col) & 0xC0) >> 6)) +#define INDEX_FROM_BUF_12(col) ((((col) & 0xF00000) >> 12) + (((col) & 0xF000) >> 8) + (((col) & 0xF0) >> 4)) +#define INDEX_FROM_BUF_15_16(col) ((((col) & 0xF80000) >> 9) + (((col) & 0xF800) >> 6) + (((col) & 0xF8) >> 3)) +#define INDEX_FROM_BUF_18(col) ((((col) & 0xFC0000) >> 6) + (((col) & 0xFC00) >> 4) + (((col) & 0xFC) >> 2)) +#define INDEX_FROM_BUF_24(col) ((col) & 0xFFFFFF) + +int GPU_select_to_index(unsigned int col) +{ + if (col == 0) { + return 0; + } + + switch (GPU_color_depth()) { + case 8: return INDEX_FROM_BUF_8(col); + case 12: return INDEX_FROM_BUF_12(col); + case 15: + case 16: return INDEX_FROM_BUF_15_16(col); + case 24: return INDEX_FROM_BUF_24(col); + default: return INDEX_FROM_BUF_18(col); + } +} + +void GPU_select_to_index_array(unsigned int *col, const unsigned int size) +{ +#define INDEX_BUF_ARRAY(INDEX_FROM_BUF_BITS) \ + for (i = size; i--; col++) { \ + if ((c = *col)) { \ + *col = INDEX_FROM_BUF_BITS(c); \ + } \ + } ((void)0) + + if (size > 0) { + unsigned int i, c; + + switch (GPU_color_depth()) { + case 8: + INDEX_BUF_ARRAY(INDEX_FROM_BUF_8); + break; + case 12: + INDEX_BUF_ARRAY(INDEX_FROM_BUF_12); + break; + case 15: + case 16: + INDEX_BUF_ARRAY(INDEX_FROM_BUF_15_16); + break; + case 24: + INDEX_BUF_ARRAY(INDEX_FROM_BUF_24); + break; + default: + INDEX_BUF_ARRAY(INDEX_FROM_BUF_18); + break; + } + } + +#undef INDEX_BUF_ARRAY +} + +/** \} */ diff --git a/source/blender/gpu/intern/gpu_extensions.c b/source/blender/gpu/intern/gpu_extensions.c index 567925a130e..acec8a13520 100644 --- a/source/blender/gpu/intern/gpu_extensions.c +++ b/source/blender/gpu/intern/gpu_extensions.c @@ -32,9 +32,6 @@ * with checks for drivers and GPU support. */ -#include "MEM_guardedalloc.h" - -#include "BLI_blenlib.h" #include "BLI_utildefines.h" #include "BLI_math_base.h" #include "BLI_math_vector.h" @@ -42,7 +39,6 @@ #include "BKE_global.h" #include "GPU_basic_shader.h" -#include "GPU_draw.h" #include "GPU_extensions.h" #include "GPU_glew.h" #include "GPU_texture.h" diff --git a/source/blender/gpu/intern/gpu_framebuffer.c b/source/blender/gpu/intern/gpu_framebuffer.c index 3736d3f673f..d0a4d8a0ac0 100644 --- a/source/blender/gpu/intern/gpu_framebuffer.c +++ b/source/blender/gpu/intern/gpu_framebuffer.c @@ -30,7 +30,6 @@ #include "BLI_blenlib.h" #include "BLI_utildefines.h" #include "BLI_math_base.h" -#include "BLI_math_vector.h" #include "BKE_global.h" diff --git a/source/blender/gpu/intern/gpu_init_exit.c b/source/blender/gpu/intern/gpu_init_exit.c index 8fed6a9ee80..c72c83b6b07 100644 --- a/source/blender/gpu/intern/gpu_init_exit.c +++ b/source/blender/gpu/intern/gpu_init_exit.c @@ -29,11 +29,8 @@ * \ingroup gpu */ -#include "BKE_DerivedMesh.h" - #include "BLI_sys_types.h" #include "GPU_init_exit.h" /* interface */ -#include "GPU_buffers.h" #include "BKE_global.h" diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c index 29e31676ab8..77ad923faaa 100644 --- a/source/blender/gpu/intern/gpu_material.c +++ b/source/blender/gpu/intern/gpu_material.c @@ -31,7 +31,6 @@ * Manages materials, lights and textures. */ - #include <math.h> #include <string.h> @@ -50,7 +49,6 @@ #include "BKE_anim.h" #include "BKE_colortools.h" -#include "BKE_DerivedMesh.h" #include "BKE_global.h" #include "BKE_object.h" #include "BKE_image.h" @@ -73,7 +71,9 @@ #include "gpu_codegen.h" -#include <string.h> +#ifdef WITH_OPENSUBDIV +# include "BKE_DerivedMesh.h" +#endif /* Structs */ @@ -870,6 +870,11 @@ bool GPU_material_use_new_shading_nodes(GPUMaterial *mat) return BKE_scene_use_new_shading_nodes(mat->scene); } +bool GPU_material_use_world_space_shading(GPUMaterial *mat) +{ + return BKE_scene_use_world_space_shading(mat->scene); +} + static GPUNodeLink *lamp_get_lightcolor(GPUMaterial *mat, GPULamp *lamp, GPUNodeLink *lv) { // if (lamp->use_realistic_lighting) { diff --git a/source/blender/gpu/intern/gpu_shader.c b/source/blender/gpu/intern/gpu_shader.c index 6371259d32c..16cebf36a8e 100644 --- a/source/blender/gpu/intern/gpu_shader.c +++ b/source/blender/gpu/intern/gpu_shader.c @@ -27,7 +27,6 @@ #include "MEM_guardedalloc.h" -#include "BLI_blenlib.h" #include "BLI_utildefines.h" #include "BLI_math_base.h" #include "BLI_math_vector.h" diff --git a/source/blender/gpu/shaders/gpu_shader_basic_frag.glsl b/source/blender/gpu/shaders/gpu_shader_basic_frag.glsl index 6b6679b60df..01a335af048 100644 --- a/source/blender/gpu/shaders/gpu_shader_basic_frag.glsl +++ b/source/blender/gpu/shaders/gpu_shader_basic_frag.glsl @@ -3,6 +3,7 @@ * * USE_COLOR: use glColor for diffuse colors * USE_TEXTURE: use texture for diffuse colors + * USE_TEXTURE_RECTANGLE: use GL_TEXTURE_RECTANGLE instead of GL_TEXTURE_2D * USE_SCENE_LIGHTING: use lights (up to 8) * USE_SOLID_LIGHTING: assume 3 directional lights for solid draw mode * USE_TWO_SIDED: flip normal towards viewer @@ -27,8 +28,11 @@ #define STIPPLE_S3D_INTERLACE_CHECKERBOARD_SWAP 11 #if defined(USE_SOLID_LIGHTING) || defined(USE_SCENE_LIGHTING) +#if defined(USE_FLAT_NORMAL) +varying vec3 eyespace_vert_pos; +#else varying vec3 varying_normal; - +#endif #ifndef USE_SOLID_LIGHTING varying vec3 varying_position; #endif @@ -39,8 +43,16 @@ varying vec4 varying_vertex_color; #endif #ifdef USE_TEXTURE +#ifdef USE_TEXTURE_RECTANGLE +#define sampler2D_default sampler2DRect +#define texture2D_default texture2DRect +#else +#define sampler2D_default sampler2D +#define texture2D_default texture2D +#endif + varying vec2 varying_texture_coord; -uniform sampler2D texture_map; +uniform sampler2D_default texture_map; #endif #ifdef USE_STIPPLE @@ -137,7 +149,11 @@ void main() #if defined(USE_SOLID_LIGHTING) || defined(USE_SCENE_LIGHTING) /* compute normal */ +#if defined(USE_FLAT_NORMAL) + vec3 N = normalize(cross(dFdx(eyespace_vert_pos), dFdy(eyespace_vert_pos))); +#else vec3 N = normalize(varying_normal); +#endif #ifdef USE_TWO_SIDED if (!gl_FrontFacing) @@ -229,12 +245,12 @@ void main() float alpha; #if defined(USE_TEXTURE) && defined(USE_COLOR) - vec4 texture_color = texture2D(texture_map, varying_texture_coord); + vec4 texture_color = texture2D_default(texture_map, varying_texture_coord); L_diffuse *= texture_color.rgb * varying_vertex_color.rgb; alpha = texture_color.a * varying_vertex_color.a; #elif defined(USE_TEXTURE) - vec4 texture_color = texture2D(texture_map, varying_texture_coord); + vec4 texture_color = texture2D_default(texture_map, varying_texture_coord); L_diffuse *= texture_color.rgb; alpha = texture_color.a; @@ -259,9 +275,9 @@ void main() /* no lighting */ #if defined(USE_TEXTURE) && defined(USE_COLOR) - gl_FragColor = texture2D(texture_map, varying_texture_coord) * varying_vertex_color; + gl_FragColor = texture2D_default(texture_map, varying_texture_coord) * varying_vertex_color; #elif defined(USE_TEXTURE) - gl_FragColor = texture2D(texture_map, varying_texture_coord); + gl_FragColor = texture2D_default(texture_map, varying_texture_coord); #elif defined(USE_COLOR) gl_FragColor = varying_vertex_color; #else diff --git a/source/blender/gpu/shaders/gpu_shader_basic_vert.glsl b/source/blender/gpu/shaders/gpu_shader_basic_vert.glsl index cef28ea3026..42fbdadf1d1 100644 --- a/source/blender/gpu/shaders/gpu_shader_basic_vert.glsl +++ b/source/blender/gpu/shaders/gpu_shader_basic_vert.glsl @@ -1,6 +1,10 @@ #if defined(USE_SOLID_LIGHTING) || defined(USE_SCENE_LIGHTING) +#if defined(USE_FLAT_NORMAL) +varying vec3 eyespace_vert_pos; +#else varying vec3 varying_normal; +#endif #ifndef USE_SOLID_LIGHTING varying vec3 varying_position; @@ -28,7 +32,13 @@ void main() vec4 co = gl_ModelViewMatrix * gl_Vertex; #if defined(USE_SOLID_LIGHTING) || defined(USE_SCENE_LIGHTING) +#if !defined(USE_FLAT_NORMAL) varying_normal = normalize(gl_NormalMatrix * gl_Normal); +#endif +#if defined(USE_FLAT_NORMAL) + /* transform vertex into eyespace */ + eyespace_vert_pos = (gl_ModelViewMatrix * gl_Vertex).xyz; +#endif #ifndef USE_SOLID_LIGHTING varying_position = co.xyz; diff --git a/source/blender/gpu/shaders/gpu_shader_vertex.glsl b/source/blender/gpu/shaders/gpu_shader_vertex.glsl index 9a6537b4f09..db0068d2f3d 100644 --- a/source/blender/gpu/shaders/gpu_shader_vertex.glsl +++ b/source/blender/gpu/shaders/gpu_shader_vertex.glsl @@ -14,6 +14,9 @@ varying vec3 varnormal; varying float gl_ClipDistance[6]; #endif + +/* Color, keep in sync with: gpu_shader_vertex_world.glsl */ + float srgb_to_linearrgb(float c) { if (c < 0.04045) @@ -76,6 +79,9 @@ void set_var_from_attr(vec4 attr, int info, out vec4 var) } } +/* end color code */ + + void main() { #ifndef USE_OPENSUBDIV diff --git a/source/blender/gpu/shaders/gpu_shader_vertex_world.glsl b/source/blender/gpu/shaders/gpu_shader_vertex_world.glsl index fe02a883765..d45a4b316a8 100644 --- a/source/blender/gpu/shaders/gpu_shader_vertex_world.glsl +++ b/source/blender/gpu/shaders/gpu_shader_vertex_world.glsl @@ -2,6 +2,9 @@ varying vec3 varposition; varying vec3 varnormal; + +/* Color, keep in sync with: gpu_shader_vertex.glsl */ + float srgb_to_linearrgb(float c) { if (c < 0.04045) @@ -64,6 +67,9 @@ void set_var_from_attr(vec4 attr, int info, out vec4 var) } } +/* end color code */ + + void main() { /* position does not need to be transformed, we already have it */ diff --git a/source/blender/imbuf/intern/cineon/logImageCore.c b/source/blender/imbuf/intern/cineon/logImageCore.c index 5ec0a87890c..6fb1bccf491 100644 --- a/source/blender/imbuf/intern/cineon/logImageCore.c +++ b/source/blender/imbuf/intern/cineon/logImageCore.c @@ -296,10 +296,11 @@ static int logImageSetData10(LogImageFile *logImage, LogImageElement logElement, row[index] = swap_uint(pixel, logImage->isMSB); if (logimage_fwrite(row, rowLength, 1, logImage) == 0) { - if (verbose) printf("DPX/Cineon: Error while writing file.\n"); { - MEM_freeN(row); - return 1; + if (verbose) { + printf("DPX/Cineon: Error while writing file.\n"); } + MEM_freeN(row); + return 1; } } MEM_freeN(row); diff --git a/source/blender/imbuf/intern/openexr/openexr_api.cpp b/source/blender/imbuf/intern/openexr/openexr_api.cpp index fdadb783815..89e796fb7ee 100644 --- a/source/blender/imbuf/intern/openexr/openexr_api.cpp +++ b/source/blender/imbuf/intern/openexr/openexr_api.cpp @@ -77,7 +77,7 @@ extern "C" { // The following prevents a linking error in debug mode for MSVC using the libs in CVS -#if defined(WITH_OPENEXR) && defined(_WIN32) && defined(DEBUG) && !defined(__MINGW32__) +#if defined(WITH_OPENEXR) && defined(_WIN32) && defined(DEBUG) && !defined(__MINGW32__) && _MSC_VER < 1900 _CRTIMP void __cdecl _invalid_parameter_noinfo(void) { } @@ -127,7 +127,7 @@ class Mem_IStream : public Imf::IStream { public: - Mem_IStream (unsigned char *exrbuf, size_t exrsize) : + Mem_IStream(unsigned char *exrbuf, size_t exrsize) : IStream("dummy"), _exrpos(0), _exrsize(exrsize) { _exrbuf = exrbuf; diff --git a/source/blender/imbuf/intern/thumbs.c b/source/blender/imbuf/intern/thumbs.c index 95d061bcb75..3629332a4ac 100644 --- a/source/blender/imbuf/intern/thumbs.c +++ b/source/blender/imbuf/intern/thumbs.c @@ -46,6 +46,8 @@ #include "BLO_readfile.h" +#include "DNA_space_types.h" /* For FILE_MAX_LIBEXTRA */ + #include "IMB_imbuf_types.h" #include "IMB_imbuf.h" #include "IMB_thumbs.h" @@ -533,7 +535,7 @@ ImBuf *IMB_thumb_manage(const char *org_path, ThumbSize size, ThumbSource source char thumb_path[FILE_MAX]; char thumb_name[40]; char uri[URI_MAX]; - char path_buff[FILE_MAX]; + char path_buff[FILE_MAX_LIBEXTRA]; const char *file_path; const char *path; BLI_stat_t st; diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h index 0bf3c350263..b0812a81ee1 100644 --- a/source/blender/makesdna/DNA_ID.h +++ b/source/blender/makesdna/DNA_ID.h @@ -142,7 +142,6 @@ typedef struct ID { */ typedef struct Library { ID id; - ID *idblock; struct FileData *filedata; char name[1024]; /* path name used for reading, can be relative and edited in the outliner */ @@ -155,6 +154,9 @@ typedef struct Library { struct Library *parent; /* set for indirectly linked libs, used in the outliner and while reading */ struct PackedFile *packedfile; + + int temp_index; + int _pad; } Library; enum eIconSizes { diff --git a/source/blender/makesdna/DNA_anim_types.h b/source/blender/makesdna/DNA_anim_types.h index 4c1283452ff..6bd7b3a4999 100644 --- a/source/blender/makesdna/DNA_anim_types.h +++ b/source/blender/makesdna/DNA_anim_types.h @@ -537,8 +537,9 @@ typedef enum eFCurve_Extend { /* curve coloring modes */ typedef enum eFCurve_Coloring { FCURVE_COLOR_AUTO_RAINBOW = 0, /* automatically determine color using rainbow (calculated at drawtime) */ - FCURVE_COLOR_AUTO_RGB, /* automatically determine color using XYZ (array index) <-> RGB */ - FCURVE_COLOR_CUSTOM /* custom color */ + FCURVE_COLOR_AUTO_RGB = 1, /* automatically determine color using XYZ (array index) <-> RGB */ + FCURVE_COLOR_AUTO_YRGB = 3, /* automatically determine color where XYZ <-> RGB, but index(X) != 0 */ + FCURVE_COLOR_CUSTOM = 2, /* custom color */ } eFCurve_Coloring; /* ************************************************ */ diff --git a/source/blender/makesdna/DNA_camera_types.h b/source/blender/makesdna/DNA_camera_types.h index 68741578f27..52e40cbc098 100644 --- a/source/blender/makesdna/DNA_camera_types.h +++ b/source/blender/makesdna/DNA_camera_types.h @@ -85,8 +85,8 @@ typedef struct Camera { char sensor_fit; char pad[7]; - /* Stereo settings */ - struct CameraStereoSettings stereo; + /* Stereo settings */ + struct CameraStereoSettings stereo; } Camera; /* **************** CAMERA ********************* */ diff --git a/source/blender/makesdna/DNA_curve_types.h b/source/blender/makesdna/DNA_curve_types.h index 8f711c1b23b..61169e4b1b1 100644 --- a/source/blender/makesdna/DNA_curve_types.h +++ b/source/blender/makesdna/DNA_curve_types.h @@ -230,7 +230,7 @@ typedef struct Curve { /* font part */ short lines; - char spacemode, pad1; + char spacemode, align_y; float spacing, linedist, shear, fsize, wordspace, ulpos, ulheight; float xof, yof; float linewidth; @@ -322,11 +322,19 @@ enum { /* Curve.spacemode */ enum { - CU_LEFT = 0, - CU_MIDDLE = 1, - CU_RIGHT = 2, - CU_JUSTIFY = 3, - CU_FLUSH = 4, + CU_ALIGN_X_LEFT = 0, + CU_ALIGN_X_MIDDLE = 1, + CU_ALIGN_X_RIGHT = 2, + CU_ALIGN_X_JUSTIFY = 3, + CU_ALIGN_X_FLUSH = 4, +}; + +/* Curve.align_y */ +enum { + CU_ALIGN_Y_TOP_BASELINE = 0, + CU_ALIGN_Y_TOP = 1, + CU_ALIGN_Y_CENTER = 2, + CU_ALIGN_Y_BOTTOM = 3, }; /* Nurb.flag */ diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h index 457db70cd28..a58e995f1c6 100644 --- a/source/blender/makesdna/DNA_modifier_types.h +++ b/source/blender/makesdna/DNA_modifier_types.h @@ -1518,7 +1518,9 @@ typedef struct NormalEditModifierData { short mix_mode; char pad[2]; float mix_factor; + float mix_limit; float offset[3]; + float pad_f1; } NormalEditModifierData; /* NormalEditModifierData.mode */ diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index 354314ddc65..3a76c7f1063 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -913,7 +913,8 @@ typedef struct NodeSunBeams { #define SHD_GLOSSY_BECKMANN 0 #define SHD_GLOSSY_SHARP 1 #define SHD_GLOSSY_GGX 2 -#define SHD_GLOSSY_ASHIKHMIN_SHIRLEY 3 +#define SHD_GLOSSY_ASHIKHMIN_SHIRLEY 3 +#define SHD_GLOSSY_MULTI_GGX 4 /* vector transform */ #define SHD_VECT_TRANSFORM_TYPE_VECTOR 0 diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index 1bf044ffecb..79af1813a8f 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -1639,6 +1639,7 @@ typedef struct Scene { #define R_SIMPLIFY 0x1000000 #define R_EDGE_FRS 0x2000000 /* R_EDGE reserved for Freestyle */ #define R_PERSISTENT_DATA 0x4000000 /* keep data around for re-render */ +#define R_USE_WS_SHADING 0x8000000 /* use world space interpretation of lighting data */ /* seq_flag */ #define R_SEQ_GL_PREV 1 diff --git a/source/blender/makesdna/DNA_sdna_types.h b/source/blender/makesdna/DNA_sdna_types.h index 28204ebeb88..cb7a371c7c5 100644 --- a/source/blender/makesdna/DNA_sdna_types.h +++ b/source/blender/makesdna/DNA_sdna_types.h @@ -67,7 +67,7 @@ typedef struct SDNA { # typedef struct BHead { int code, len; - void *old; + const void *old; int SDNAnr, nr; } BHead; # diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h index 46b7d717991..9c177cdddd1 100644 --- a/source/blender/makesdna/DNA_space_types.h +++ b/source/blender/makesdna/DNA_space_types.h @@ -875,8 +875,6 @@ typedef struct SpaceImage { struct Image *image; struct ImageUser iuser; - struct CurveMapping *cumap DNA_DEPRECATED; /* was switched to scene's color management settings */ - struct Scopes scopes; /* histogram waveform and vectorscope */ struct Histogram sample_line_hist; /* sample line histogram */ diff --git a/source/blender/makesdna/intern/CMakeLists.txt b/source/blender/makesdna/intern/CMakeLists.txt index 52487edfd2b..0bb6e866bf4 100644 --- a/source/blender/makesdna/intern/CMakeLists.txt +++ b/source/blender/makesdna/intern/CMakeLists.txt @@ -56,8 +56,14 @@ add_executable(makesdna ${SRC} ${SRC_DNA_INC}) # Output dna.c add_custom_command( - OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/dna.c - COMMAND "$<TARGET_FILE:makesdna>" ${CMAKE_CURRENT_BINARY_DIR}/dna.c ${CMAKE_SOURCE_DIR}/source/blender/makesdna/ + OUTPUT + ${CMAKE_CURRENT_BINARY_DIR}/dna.c + ${CMAKE_CURRENT_BINARY_DIR}/dna_type_offsets.h + COMMAND + "$<TARGET_FILE:makesdna>" + ${CMAKE_CURRENT_BINARY_DIR}/dna.c + ${CMAKE_CURRENT_BINARY_DIR}/dna_type_offsets.h + ${CMAKE_SOURCE_DIR}/source/blender/makesdna/ DEPENDS makesdna ) @@ -78,7 +84,11 @@ set(SRC ${SRC_DNA_INC} ) -set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/dna.c PROPERTIES GENERATED TRUE) +set_source_files_properties( + ${CMAKE_CURRENT_BINARY_DIR}/dna.c + ${CMAKE_CURRENT_BINARY_DIR}/dna_type_offsets.h + PROPERTIES GENERATED TRUE +) blender_add_lib(bf_dna "${SRC}" "${INC}" "${INC_SYS}") @@ -94,10 +104,11 @@ set(INC_SYS ) set(SRC - ../../blenlib/intern/BLI_mempool.c - ../../blenlib/intern/listbase.c ../../blenlib/intern/BLI_ghash.c + ../../blenlib/intern/BLI_mempool.c + ../../blenlib/intern/endian_switch.c ../../blenlib/intern/hash_mm2a.c + ../../blenlib/intern/listbase.c ) blender_add_lib(bf_dna_blenlib "${SRC}" "${INC}" "${INC_SYS}") diff --git a/source/blender/makesdna/intern/dna_genfile.c b/source/blender/makesdna/intern/dna_genfile.c index 4f19e819625..99ab29fbdcc 100644 --- a/source/blender/makesdna/intern/dna_genfile.c +++ b/source/blender/makesdna/intern/dna_genfile.c @@ -43,6 +43,7 @@ #include "MEM_guardedalloc.h" // for MEM_freeN MEM_mallocN MEM_callocN #include "BLI_utildefines.h" +#include "BLI_endian_switch.h" #ifdef WITH_DNA_GHASH # include "BLI_ghash.h" @@ -1126,7 +1127,7 @@ void DNA_struct_switch_endian(SDNA *oldsdna, int oldSDNAnr, char *data) */ int a, mul, elemcount, elen, elena, firststructtypenr; const short *spo, *spc; - char *cpo, *cur, cval; + char *cur; const char *type, *name; if (oldSDNAnr == -1) return; @@ -1148,9 +1149,9 @@ void DNA_struct_switch_endian(SDNA *oldsdna, int oldSDNAnr, char *data) /* test: is type a struct? */ if (spc[0] >= firststructtypenr && !ispointer(name)) { - /* struct field type */ + /* struct field type */ /* where does the old data start (is there one?) */ - cpo = find_elem(oldsdna, type, name, spo, data, NULL); + char *cpo = find_elem(oldsdna, type, name, spo, data, NULL); if (cpo) { oldSDNAnr = DNA_struct_find_nr(oldsdna, type); @@ -1167,18 +1168,7 @@ void DNA_struct_switch_endian(SDNA *oldsdna, int oldSDNAnr, char *data) /* non-struct field type */ if (ispointer(name)) { if (oldsdna->pointerlen == 8) { - - mul = DNA_elem_array_size(name); - cpo = cur; - while (mul--) { - cval = cpo[0]; cpo[0] = cpo[7]; cpo[7] = cval; - cval = cpo[1]; cpo[1] = cpo[6]; cpo[6] = cval; - cval = cpo[2]; cpo[2] = cpo[5]; cpo[5] = cval; - cval = cpo[3]; cpo[3] = cpo[4]; cpo[4] = cval; - - cpo += 8; - } - + BLI_endian_switch_int64_array((int64_t *)cur, DNA_elem_array_size(name)); } } else { @@ -1191,14 +1181,7 @@ void DNA_struct_switch_endian(SDNA *oldsdna, int oldSDNAnr, char *data) } if (skip == false) { - mul = DNA_elem_array_size(name); - cpo = cur; - while (mul--) { - cval = cpo[0]; - cpo[0] = cpo[1]; - cpo[1] = cval; - cpo += 2; - } + BLI_endian_switch_int16_array((int16_t *)cur, DNA_elem_array_size(name)); } } else if (ELEM(spc[0], SDNA_TYPE_INT, SDNA_TYPE_FLOAT)) { @@ -1206,29 +1189,10 @@ void DNA_struct_switch_endian(SDNA *oldsdna, int oldSDNAnr, char *data) * but turns out we only used for runtime vars and * only once for a struct type thats no longer used. */ - mul = DNA_elem_array_size(name); - cpo = cur; - while (mul--) { - cval = cpo[0]; - cpo[0] = cpo[3]; - cpo[3] = cval; - cval = cpo[1]; - cpo[1] = cpo[2]; - cpo[2] = cval; - cpo += 4; - } + BLI_endian_switch_int32_array((int32_t *)cur, DNA_elem_array_size(name)); } else if (ELEM(spc[0], SDNA_TYPE_INT64, SDNA_TYPE_UINT64, SDNA_TYPE_DOUBLE)) { - mul = DNA_elem_array_size(name); - cpo = cur; - while (mul--) { - cval = cpo[0]; cpo[0] = cpo[7]; cpo[7] = cval; - cval = cpo[1]; cpo[1] = cpo[6]; cpo[6] = cval; - cval = cpo[2]; cpo[2] = cpo[5]; cpo[5] = cval; - cval = cpo[3]; cpo[3] = cpo[4]; cpo[4] = cval; - - cpo += 8; - } + BLI_endian_switch_int64_array((int64_t *)cur, DNA_elem_array_size(name)); } } } diff --git a/source/blender/makesdna/intern/makesdna.c b/source/blender/makesdna/intern/makesdna.c index fc94a8d9ff4..b78299316e1 100644 --- a/source/blender/makesdna/intern/makesdna.c +++ b/source/blender/makesdna/intern/makesdna.c @@ -968,7 +968,7 @@ void printStructLengths(void) } -static int make_structDNA(const char *baseDirectory, FILE *file) +static int make_structDNA(const char *baseDirectory, FILE *file, FILE *file_offsets) { int len, i; const short *sp; @@ -1159,6 +1159,19 @@ static int make_structDNA(const char *baseDirectory, FILE *file) /* end end padding test */ } + /* write a simple enum with all structs offsets, + * should only be accessed via SDNA_TYPE_FROM_STRUCT macro */ + { + fprintf(file_offsets, "#define SDNA_TYPE_FROM_STRUCT(id) _SDNA_TYPE_##id\n"); + fprintf(file_offsets, "enum {\n"); + for (i = 0; i < nr_structs; i++) { + const short *structpoin = structs[i]; + const int structtype = structpoin[0]; + fprintf(file_offsets, "\t_SDNA_TYPE_%s = %d,\n", types[structtype], i); + } + fprintf(file_offsets, "\tSDNA_TYPE_MAX = %d,\n", nr_structs); + fprintf(file_offsets, "};\n"); + } MEM_freeN(namedata); MEM_freeN(typedata); @@ -1190,43 +1203,53 @@ static void make_bad_file(const char *file, int line) int main(int argc, char **argv) { - FILE *file; int return_status = 0; - if (argc != 2 && argc != 3) { - printf("Usage: %s outfile.c [base directory]\n", argv[0]); + if (argc != 3 && argc != 4) { + printf("Usage: %s dna.c dna_struct_offsets.h [base directory]\n", argv[0]); return_status = 1; } else { - file = fopen(argv[1], "w"); - if (!file) { + FILE *file_dna = fopen(argv[1], "w"); + FILE *file_dna_offsets = fopen(argv[2], "w"); + if (!file_dna) { printf("Unable to open file: %s\n", argv[1]); return_status = 1; } + else if (!file_dna_offsets) { + printf("Unable to open file: %s\n", argv[2]); + return_status = 1; + } else { const char *baseDirectory; - if (argc == 3) { - baseDirectory = argv[2]; + if (argc == 4) { + baseDirectory = argv[3]; } else { baseDirectory = BASE_HEADER; } - fprintf(file, "const unsigned char DNAstr[] = {\n"); - if (make_structDNA(baseDirectory, file)) { + fprintf(file_dna, "const unsigned char DNAstr[] = {\n"); + if (make_structDNA(baseDirectory, file_dna, file_dna_offsets)) { /* error */ - fclose(file); + fclose(file_dna); + file_dna = NULL; make_bad_file(argv[1], __LINE__); return_status = 1; } else { - fprintf(file, "};\n"); - fprintf(file, "const int DNAlen = sizeof(DNAstr);\n"); - - fclose(file); + fprintf(file_dna, "};\n"); + fprintf(file_dna, "const int DNAlen = sizeof(DNAstr);\n"); } } + + if (file_dna) { + fclose(file_dna); + } + if (file_dna_offsets) { + fclose(file_dna_offsets); + } } diff --git a/source/blender/makesrna/RNA_types.h b/source/blender/makesrna/RNA_types.h index d8bea93bcbc..1d5f46a1814 100644 --- a/source/blender/makesrna/RNA_types.h +++ b/source/blender/makesrna/RNA_types.h @@ -285,6 +285,11 @@ typedef struct CollectionPointerLink { PointerRNA ptr; } CollectionPointerLink; +/* Copy of ListBase for RNA... */ +typedef struct CollectionListBase { + struct CollectionPointerLink *first, *last; +} CollectionListBase; + typedef enum RawPropertyType { PROP_RAW_UNSET = -1, PROP_RAW_INT, // XXX - abused for types that are not set, eg. MFace.verts, needs fixing. diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c index 535847cfc78..f9a46409aea 100644 --- a/source/blender/makesrna/intern/makesrna.c +++ b/source/blender/makesrna/intern/makesrna.c @@ -227,6 +227,10 @@ static const char *rna_safe_id(const char *id) return "operator_value"; else if (STREQ(id, "new")) return "create"; + else if (STREQ(id, "co_return")) { + /* MSVC2015, C++ uses for coroutines */ + return "coord_return"; + } return id; } @@ -466,7 +470,7 @@ static const char *rna_parameter_type_name(PropertyRNA *parm) } case PROP_COLLECTION: { - return "ListBase"; + return "CollectionListBase"; } default: return "<error, no type specified>"; diff --git a/source/blender/makesrna/intern/rna_ID.c b/source/blender/makesrna/intern/rna_ID.c index 63ea836e3de..dc6d30854a6 100644 --- a/source/blender/makesrna/intern/rna_ID.c +++ b/source/blender/makesrna/intern/rna_ID.c @@ -87,10 +87,13 @@ EnumPropertyItem rna_enum_id_type_items[] = { #include "DNA_anim_types.h" +#include "BLI_listbase.h" + #include "BKE_font.h" #include "BKE_idprop.h" #include "BKE_library.h" #include "BKE_library_query.h" +#include "BKE_library_remap.h" #include "BKE_animsys.h" #include "BKE_material.h" #include "BKE_depsgraph.h" @@ -333,6 +336,14 @@ static void rna_ID_user_clear(ID *id) id->us = 0; /* don't save */ } +static void rna_ID_user_remap(ID *id, Main *bmain, ID *new_id) +{ + if (GS(id->name) == GS(new_id->name)) { + /* For now, do not allow remapping data in linked data from here... */ + BKE_libblock_remap(bmain, id, new_id, ID_REMAP_SKIP_INDIRECT_USAGE | ID_REMAP_SKIP_NEVER_NULL_USAGE); + } +} + static AnimData * rna_ID_animation_data_create(ID *id, Main *bmain) { AnimData *adt = BKE_animdata_add_id(id); @@ -342,7 +353,7 @@ static AnimData * rna_ID_animation_data_create(ID *id, Main *bmain) static void rna_ID_animation_data_free(ID *id, Main *bmain) { - BKE_animdata_free(id); + BKE_animdata_free(id, true); DAG_relations_tag_update(bmain); } @@ -977,6 +988,12 @@ static void rna_def_ID(BlenderRNA *brna) RNA_def_function_ui_description(func, "Clear the user count of a data-block so its not saved, " "on reload the data will be removed"); + func = RNA_def_function(srna, "user_remap", "rna_ID_user_remap"); + RNA_def_function_ui_description(func, "Replace all usage in the .blend file of this ID by new given one"); + RNA_def_function_flag(func, FUNC_USE_MAIN); + parm = RNA_def_pointer(func, "new_id", "ID", "", "New ID to use"); + RNA_def_property_flag(parm, PROP_NEVER_NULL); + func = RNA_def_function(srna, "user_of_id", "BKE_library_ID_use_ID"); RNA_def_function_ui_description(func, "Count the number of times that ID uses/references given one"); parm = RNA_def_pointer(func, "id", "ID", "", "ID to count usages"); diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c index c49a6197a4e..0eaeabccd99 100644 --- a/source/blender/makesrna/intern/rna_access.c +++ b/source/blender/makesrna/intern/rna_access.c @@ -4678,7 +4678,7 @@ static void rna_path_array_multi_string_from_flat_index( } /** - * \param index_dim: The dimensiuon to show, 0 disables. 1 for 1d array, 2 for 2d. etc. + * \param index_dim: The dimension to show, 0 disables. 1 for 1d array, 2 for 2d. etc. * \param index: The *flattened* index to use when \a ``index_dim > 0``, * this is expanded when used with multi-dimensional arrays. */ diff --git a/source/blender/makesrna/intern/rna_camera.c b/source/blender/makesrna/intern/rna_camera.c index 678b0ac8f1f..492430fbda6 100644 --- a/source/blender/makesrna/intern/rna_camera.c +++ b/source/blender/makesrna/intern/rna_camera.c @@ -257,13 +257,15 @@ void RNA_def_camera(BlenderRNA *brna) prop = RNA_def_property(srna, "clip_start", PROP_FLOAT, PROP_DISTANCE); RNA_def_property_float_sdna(prop, NULL, "clipsta"); - RNA_def_property_range(prop, 0.001f, FLT_MAX); + RNA_def_property_range(prop, 1e-6f, FLT_MAX); + RNA_def_property_ui_range(prop, 0.001f, FLT_MAX, 10, 3); RNA_def_property_ui_text(prop, "Clip Start", "Camera near clipping distance"); RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL); prop = RNA_def_property(srna, "clip_end", PROP_FLOAT, PROP_DISTANCE); RNA_def_property_float_sdna(prop, NULL, "clipend"); - RNA_def_property_range(prop, 1.0f, FLT_MAX); + RNA_def_property_range(prop, 1e-6f, FLT_MAX); + RNA_def_property_ui_range(prop, 0.001f, FLT_MAX, 10, 3); RNA_def_property_ui_text(prop, "Clip End", "Camera far clipping distance"); RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL); diff --git a/source/blender/makesrna/intern/rna_curve.c b/source/blender/makesrna/intern/rna_curve.c index cb7a40a9238..fb4ff6f4856 100644 --- a/source/blender/makesrna/intern/rna_curve.c +++ b/source/blender/makesrna/intern/rna_curve.c @@ -952,23 +952,37 @@ static void rna_def_nurbs(BlenderRNA *UNUSED(brna), StructRNA *srna) static void rna_def_font(BlenderRNA *UNUSED(brna), StructRNA *srna) { PropertyRNA *prop; - + static EnumPropertyItem prop_align_items[] = { - {CU_LEFT, "LEFT", 0, "Left", "Align text to the left"}, - {CU_MIDDLE, "CENTER", 0, "Center", "Center text"}, - {CU_RIGHT, "RIGHT", 0, "Right", "Align text to the right"}, - {CU_JUSTIFY, "JUSTIFY", 0, "Justify", "Align to the left and the right"}, - {CU_FLUSH, "FLUSH", 0, "Flush", "Align to the left and the right, with equal character spacing"}, + {CU_ALIGN_X_LEFT, "LEFT", 0, "Left", "Align text to the left"}, + {CU_ALIGN_X_MIDDLE, "CENTER", 0, "Center", "Center text"}, + {CU_ALIGN_X_RIGHT, "RIGHT", 0, "Right", "Align text to the right"}, + {CU_ALIGN_X_JUSTIFY, "JUSTIFY", 0, "Justify", "Align to the left and the right"}, + {CU_ALIGN_X_FLUSH, "FLUSH", 0, "Flush", "Align to the left and the right, with equal character spacing"}, {0, NULL, 0, NULL, NULL} }; - + + static EnumPropertyItem prop_align_y_items[] = { + {CU_ALIGN_Y_TOP_BASELINE, "TOP_BASELINE", 0, "Top Base-Line", "Align to top but use the base-line of the text"}, + {CU_ALIGN_Y_TOP, "TOP", 0, "Top", "Align text to the top"}, + {CU_ALIGN_Y_CENTER, "CENTER", 0, "Center", "Align text to the middle"}, + {CU_ALIGN_Y_BOTTOM, "BOTTOM", 0, "Bottom", "Align text to the bottom"}, + {0, NULL, 0, NULL, NULL} + }; + /* Enums */ - prop = RNA_def_property(srna, "align", PROP_ENUM, PROP_NONE); + prop = RNA_def_property(srna, "align_x", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "spacemode"); RNA_def_property_enum_items(prop, prop_align_items); - RNA_def_property_ui_text(prop, "Text Align", "Text align from the object center"); + RNA_def_property_ui_text(prop, "Text Horizontal Align", "Text horizontal align from the object center"); RNA_def_property_update(prop, 0, "rna_Curve_update_data"); - + + prop = RNA_def_property(srna, "align_y", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "align_y"); + RNA_def_property_enum_items(prop, prop_align_y_items); + RNA_def_property_ui_text(prop, "Text Vertical Align", "Text vertical align from the object center"); + RNA_def_property_update(prop, 0, "rna_Curve_update_data"); + /* number values */ prop = RNA_def_property(srna, "size", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "fsize"); diff --git a/source/blender/makesrna/intern/rna_fcurve.c b/source/blender/makesrna/intern/rna_fcurve.c index 1487dfa074e..3043c5452c0 100644 --- a/source/blender/makesrna/intern/rna_fcurve.c +++ b/source/blender/makesrna/intern/rna_fcurve.c @@ -1844,6 +1844,8 @@ static void rna_def_fcurve(BlenderRNA *brna) "Cycle through the rainbow, trying to give each curve a unique color"}, {FCURVE_COLOR_AUTO_RGB, "AUTO_RGB", 0, "Auto XYZ to RGB", "Use axis colors for transform and color properties, and auto-rainbow for the rest"}, + {FCURVE_COLOR_AUTO_YRGB, "AUTO_YRGB", 0, "Auto WXYZ to YRGB", + "Use axis colors for XYZ parts of transform, and yellow for the 'W' channel"}, {FCURVE_COLOR_CUSTOM, "CUSTOM", 0, "User Defined", "Use custom hand-picked color for F-Curve"}, {0, NULL, 0, NULL, NULL} diff --git a/source/blender/makesrna/intern/rna_main_api.c b/source/blender/makesrna/intern/rna_main_api.c index 4b7ce640a56..c0a0bc0b55a 100644 --- a/source/blender/makesrna/intern/rna_main_api.c +++ b/source/blender/makesrna/intern/rna_main_api.c @@ -58,9 +58,11 @@ #include "BKE_armature.h" #include "BKE_lamp.h" #include "BKE_library.h" +#include "BKE_library_remap.h" #include "BKE_object.h" #include "BKE_material.h" #include "BKE_icons.h" +#include "BKE_idcode.h" #include "BKE_image.h" #include "BKE_texture.h" #include "BKE_scene.h" @@ -113,30 +115,38 @@ # include "BPY_extern.h" #endif + +static void rna_Main_ID_remove(Main *bmain, ReportList *reports, PointerRNA *id_ptr, int do_unlink) +{ + ID *id = id_ptr->data; + if (do_unlink) { + BKE_libblock_delete(bmain, id); + RNA_POINTER_INVALIDATE(id_ptr); + } + else if (ID_REAL_USERS(id) <= 0) { + BKE_libblock_free(bmain, id); + RNA_POINTER_INVALIDATE(id_ptr); + } + else { + BKE_reportf(reports, RPT_ERROR, + "%s '%s' must have zero users to be removed, found %d (try with unlink=True parameter)", + BKE_idcode_to_name(GS(id->name)), id->name + 2, ID_REAL_USERS(id)); + } +} + + static Camera *rna_Main_cameras_new(Main *bmain, const char *name) { ID *id = BKE_camera_add(bmain, name); id_us_min(id); return (Camera *)id; } -static void rna_Main_cameras_remove(Main *bmain, ReportList *reports, PointerRNA *camera_ptr) -{ - Camera *camera = camera_ptr->data; - if (ID_REAL_USERS(camera) <= 0) { - BKE_libblock_free(bmain, camera); - RNA_POINTER_INVALIDATE(camera_ptr); - } - else { - BKE_reportf(reports, RPT_ERROR, "Camera '%s' must have zero users to be removed, found %d", - camera->id.name + 2, ID_REAL_USERS(camera)); - } -} static Scene *rna_Main_scenes_new(Main *bmain, const char *name) { return BKE_scene_add(bmain, name); } -static void rna_Main_scenes_remove(Main *bmain, bContext *C, ReportList *reports, PointerRNA *scene_ptr) +static void rna_Main_scenes_remove(Main *bmain, bContext *C, ReportList *reports, PointerRNA *scene_ptr, int do_unlink) { /* don't call BKE_libblock_free(...) directly */ Scene *scene = scene_ptr->data; @@ -145,23 +155,23 @@ static void rna_Main_scenes_remove(Main *bmain, bContext *C, ReportList *reports if ((scene_new = scene->id.prev) || (scene_new = scene->id.next)) { - bScreen *sc = CTX_wm_screen(C); - if (sc->scene == scene) { + if (do_unlink) { + bScreen *sc = CTX_wm_screen(C); + if (sc->scene == scene) { #ifdef WITH_PYTHON - BPy_BEGIN_ALLOW_THREADS; + BPy_BEGIN_ALLOW_THREADS; #endif - ED_screen_set_scene(C, sc, scene_new); + ED_screen_set_scene(C, sc, scene_new); #ifdef WITH_PYTHON - BPy_END_ALLOW_THREADS; + BPy_END_ALLOW_THREADS; #endif + } } - - BKE_scene_unlink(bmain, scene, scene_new); - RNA_POINTER_INVALIDATE(scene_ptr); + rna_Main_ID_remove(bmain, reports, scene_ptr, do_unlink); } else { BKE_reportf(reports, RPT_ERROR, "Scene '%s' is the last, cannot be removed", scene->id.name + 2); @@ -222,38 +232,12 @@ static Object *rna_Main_objects_new(Main *bmain, ReportList *reports, const char return ob; } -static void rna_Main_objects_remove(Main *bmain, ReportList *reports, PointerRNA *object_ptr) -{ - Object *object = object_ptr->data; - if (ID_REAL_USERS(object) <= 0) { - BKE_object_unlink(bmain, object); /* needed or ID pointers to this are not cleared */ - BKE_libblock_free(bmain, object); - RNA_POINTER_INVALIDATE(object_ptr); - } - else { - BKE_reportf(reports, RPT_ERROR, "Object '%s' must have zero users to be removed, found %d", - object->id.name + 2, ID_REAL_USERS(object)); - } -} - static Material *rna_Main_materials_new(Main *bmain, const char *name) { ID *id = (ID *)BKE_material_add(bmain, name); id_us_min(id); return (Material *)id; } -static void rna_Main_materials_remove(Main *bmain, ReportList *reports, PointerRNA *material_ptr) -{ - Material *material = material_ptr->data; - if (ID_REAL_USERS(material) <= 0) { - BKE_libblock_free(bmain, material); - RNA_POINTER_INVALIDATE(material_ptr); - } - else { - BKE_reportf(reports, RPT_ERROR, "Material '%s' must have zero users to be removed, found %d", - material->id.name + 2, ID_REAL_USERS(material)); - } -} static EnumPropertyItem *rna_Main_nodetree_type_itemf(bContext *UNUSED(C), PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free) { @@ -271,18 +255,6 @@ static struct bNodeTree *rna_Main_nodetree_new(Main *bmain, const char *name, in else return NULL; } -static void rna_Main_nodetree_remove(Main *bmain, ReportList *reports, PointerRNA *ntree_ptr) -{ - bNodeTree *ntree = ntree_ptr->data; - if (ID_REAL_USERS(ntree) <= 0) { - BKE_libblock_free(bmain, ntree); - RNA_POINTER_INVALIDATE(ntree_ptr); - } - else { - BKE_reportf(reports, RPT_ERROR, "Node tree '%s' must have zero users to be removed, found %d", - ntree->id.name + 2, ID_REAL_USERS(ntree)); - } -} static Mesh *rna_Main_meshes_new(Main *bmain, const char *name) { @@ -312,19 +284,6 @@ Mesh *rna_Main_meshes_new_from_object( return BKE_mesh_new_from_object(bmain, sce, ob, apply_modifiers, settings, calc_tessface, calc_undeformed); } -static void rna_Main_meshes_remove(Main *bmain, ReportList *reports, PointerRNA *mesh_ptr) -{ - Mesh *mesh = mesh_ptr->data; - if (ID_REAL_USERS(mesh) <= 0) { - BKE_libblock_free(bmain, mesh); - RNA_POINTER_INVALIDATE(mesh_ptr); - } - else { - BKE_reportf(reports, RPT_ERROR, "Mesh '%s' must have zero users to be removed, found %d", - mesh->id.name + 2, ID_REAL_USERS(mesh)); - } -} - static Lamp *rna_Main_lamps_new(Main *bmain, const char *name, int type) { Lamp *lamp = BKE_lamp_add(bmain, name); @@ -332,18 +291,6 @@ static Lamp *rna_Main_lamps_new(Main *bmain, const char *name, int type) id_us_min(&lamp->id); return lamp; } -static void rna_Main_lamps_remove(Main *bmain, ReportList *reports, PointerRNA *lamp_ptr) -{ - Lamp *lamp = lamp_ptr->data; - if (ID_REAL_USERS(lamp) <= 0) { - BKE_libblock_free(bmain, lamp); - RNA_POINTER_INVALIDATE(lamp_ptr); - } - else { - BKE_reportf(reports, RPT_ERROR, "Lamp '%s' must have zero users to be removed, found %d", - lamp->id.name + 2, ID_REAL_USERS(lamp)); - } -} static Image *rna_Main_images_new(Main *bmain, const char *name, int width, int height, int alpha, int float_buffer, int stereo3d) { @@ -372,18 +319,6 @@ static Image *rna_Main_images_load(Main *bmain, ReportList *reports, const char id_us_min((ID *)ima); return ima; } -static void rna_Main_images_remove(Main *bmain, ReportList *reports, PointerRNA *image_ptr) -{ - Image *image = image_ptr->data; - if (ID_REAL_USERS(image) <= 0) { - BKE_libblock_free(bmain, image); - RNA_POINTER_INVALIDATE(image_ptr); - } - else { - BKE_reportf(reports, RPT_ERROR, "Image '%s' must have zero users to be removed, found %d", - image->id.name + 2, ID_REAL_USERS(image)); - } -} static Lattice *rna_Main_lattices_new(Main *bmain, const char *name) { @@ -391,18 +326,6 @@ static Lattice *rna_Main_lattices_new(Main *bmain, const char *name) id_us_min(<->id); return lt; } -static void rna_Main_lattices_remove(Main *bmain, ReportList *reports, PointerRNA *lt_ptr) -{ - Lattice *lt = lt_ptr->data; - if (ID_REAL_USERS(lt) <= 0) { - BKE_libblock_free(bmain, lt); - RNA_POINTER_INVALIDATE(lt_ptr); - } - else { - BKE_reportf(reports, RPT_ERROR, "Lattice '%s' must have zero users to be removed, found %d", - lt->id.name + 2, ID_REAL_USERS(lt)); - } -} static Curve *rna_Main_curves_new(Main *bmain, const char *name, int type) { @@ -410,18 +333,6 @@ static Curve *rna_Main_curves_new(Main *bmain, const char *name, int type) id_us_min(&cu->id); return cu; } -static void rna_Main_curves_remove(Main *bmain, ReportList *reports, PointerRNA *cu_ptr) -{ - Curve *cu = cu_ptr->data; - if (ID_REAL_USERS(cu) <= 0) { - BKE_libblock_free(bmain, cu); - RNA_POINTER_INVALIDATE(cu_ptr); - } - else { - BKE_reportf(reports, RPT_ERROR, "Curve '%s' must have zero users to be removed, found %d", - cu->id.name + 2, ID_REAL_USERS(cu)); - } -} static MetaBall *rna_Main_metaballs_new(Main *bmain, const char *name) { @@ -429,18 +340,6 @@ static MetaBall *rna_Main_metaballs_new(Main *bmain, const char *name) id_us_min(&mb->id); return mb; } -static void rna_Main_metaballs_remove(Main *bmain, ReportList *reports, PointerRNA *mb_ptr) -{ - MetaBall *mb = mb_ptr->data; - if (ID_REAL_USERS(mb) <= 0) { - BKE_libblock_free(bmain, mb); - RNA_POINTER_INVALIDATE(mb_ptr); - } - else { - BKE_reportf(reports, RPT_ERROR, "Metaball '%s' must have zero users to be removed, found %d", - mb->id.name + 2, ID_REAL_USERS(mb)); - } -} static VFont *rna_Main_fonts_load(Main *bmain, ReportList *reports, const char *filepath, int check_existing) { @@ -462,18 +361,6 @@ static VFont *rna_Main_fonts_load(Main *bmain, ReportList *reports, const char * return font; } -static void rna_Main_fonts_remove(Main *bmain, ReportList *reports, PointerRNA *vfont_ptr) -{ - VFont *vfont = vfont_ptr->data; - if (ID_REAL_USERS(vfont) <= 0) { - BKE_libblock_free(bmain, vfont); - RNA_POINTER_INVALIDATE(vfont_ptr); - } - else { - BKE_reportf(reports, RPT_ERROR, "Font '%s' must have zero users to be removed, found %d", - vfont->id.name + 2, ID_REAL_USERS(vfont)); - } -} static Tex *rna_Main_textures_new(Main *bmain, const char *name, int type) { @@ -482,18 +369,6 @@ static Tex *rna_Main_textures_new(Main *bmain, const char *name, int type) id_us_min(&tex->id); return tex; } -static void rna_Main_textures_remove(Main *bmain, ReportList *reports, PointerRNA *tex_ptr) -{ - Tex *tex = tex_ptr->data; - if (ID_REAL_USERS(tex) <= 0) { - BKE_libblock_free(bmain, tex); - RNA_POINTER_INVALIDATE(tex_ptr); - } - else { - BKE_reportf(reports, RPT_ERROR, "Texture '%s' must have zero users to be removed, found %d", - tex->id.name + 2, ID_REAL_USERS(tex)); - } -} static Brush *rna_Main_brushes_new(Main *bmain, const char *name, int mode) { @@ -502,50 +377,17 @@ static Brush *rna_Main_brushes_new(Main *bmain, const char *name, int mode) return brush; } -static void rna_Main_brushes_remove(Main *bmain, ReportList *reports, PointerRNA *brush_ptr) -{ - Brush *brush = brush_ptr->data; - if (ID_REAL_USERS(brush) <= 0) { - BKE_brush_unlink(bmain, brush); - BKE_libblock_free(bmain, brush); - RNA_POINTER_INVALIDATE(brush_ptr); - } - else { - BKE_reportf(reports, RPT_ERROR, "Brush '%s' must have zero users to be removed, found %d", - brush->id.name + 2, ID_REAL_USERS(brush)); - } -} - static World *rna_Main_worlds_new(Main *bmain, const char *name) { World *world = add_world(bmain, name); id_us_min(&world->id); return world; } -static void rna_Main_worlds_remove(Main *bmain, ReportList *reports, PointerRNA *world_ptr) -{ - Group *world = world_ptr->data; - if (ID_REAL_USERS(world) <= 0) { - BKE_libblock_free(bmain, world); - RNA_POINTER_INVALIDATE(world_ptr); - } - else { - BKE_reportf(reports, RPT_ERROR, "World '%s' must have zero users to be removed, found %d", - world->id.name + 2, ID_REAL_USERS(world)); - } -} static Group *rna_Main_groups_new(Main *bmain, const char *name) { return BKE_group_add(bmain, name); } -static void rna_Main_groups_remove(Main *bmain, PointerRNA *group_ptr) -{ - Group *group = group_ptr->data; - BKE_group_unlink(bmain, group); - BKE_libblock_free(bmain, group); - RNA_POINTER_INVALIDATE(group_ptr); -} static Speaker *rna_Main_speakers_new(Main *bmain, const char *name) { @@ -553,18 +395,6 @@ static Speaker *rna_Main_speakers_new(Main *bmain, const char *name) id_us_min(&speaker->id); return speaker; } -static void rna_Main_speakers_remove(Main *bmain, ReportList *reports, PointerRNA *speaker_ptr) -{ - Speaker *speaker = speaker_ptr->data; - if (ID_REAL_USERS(speaker) <= 0) { - BKE_libblock_free(bmain, speaker); - RNA_POINTER_INVALIDATE(speaker_ptr); - } - else { - BKE_reportf(reports, RPT_ERROR, "Speaker '%s' must have zero users to be removed, found %d", - speaker->id.name + 2, ID_REAL_USERS(speaker)); - } -} static bSound *rna_Main_sounds_load(Main *bmain, const char *name, int check_existing) { @@ -580,30 +410,11 @@ static bSound *rna_Main_sounds_load(Main *bmain, const char *name, int check_exi id_us_min(&sound->id); return sound; } -static void rna_Main_sounds_remove(Main *bmain, ReportList *reports, PointerRNA *sound_ptr) -{ - Speaker *sound = sound_ptr->data; - if (ID_REAL_USERS(sound) <= 0) { - BKE_libblock_free(bmain, sound); - RNA_POINTER_INVALIDATE(sound_ptr); - } - else { - BKE_reportf(reports, RPT_ERROR, "Sound '%s' must have zero users to be removed, found %d", - sound->id.name + 2, ID_REAL_USERS(sound)); - } -} static Text *rna_Main_texts_new(Main *bmain, const char *name) { return BKE_text_add(bmain, name); } -static void rna_Main_texts_remove(Main *bmain, PointerRNA *text_ptr) -{ - Text *text = text_ptr->data; - BKE_text_unlink(bmain, text); - BKE_libblock_free(bmain, text); - RNA_POINTER_INVALIDATE(text_ptr); -} static Text *rna_Main_texts_load(Main *bmain, ReportList *reports, const char *filepath, int is_internal) { @@ -625,18 +436,6 @@ static bArmature *rna_Main_armatures_new(Main *bmain, const char *name) id_us_min(&arm->id); return arm; } -static void rna_Main_armatures_remove(Main *bmain, ReportList *reports, PointerRNA *arm_ptr) -{ - bArmature *arm = arm_ptr->data; - if (ID_REAL_USERS(arm) <= 0) { - BKE_libblock_free(bmain, arm); - RNA_POINTER_INVALIDATE(arm_ptr); - } - else { - BKE_reportf(reports, RPT_ERROR, "Armature '%s' must have zero users to be removed, found %d", - arm->id.name + 2, ID_REAL_USERS(arm)); - } -} static bAction *rna_Main_actions_new(Main *bmain, const char *name) { @@ -644,18 +443,6 @@ static bAction *rna_Main_actions_new(Main *bmain, const char *name) id_fake_user_clear(&act->id); return act; } -static void rna_Main_actions_remove(Main *bmain, ReportList *reports, PointerRNA *act_ptr) -{ - bAction *act = act_ptr->data; - if (ID_REAL_USERS(act) <= 0) { - BKE_libblock_free(bmain, act); - RNA_POINTER_INVALIDATE(act_ptr); - } - else { - BKE_reportf(reports, RPT_ERROR, "Action '%s' must have zero users to be removed, found %d", - act->id.name + 2, ID_REAL_USERS(act)); - } -} static ParticleSettings *rna_Main_particles_new(Main *bmain, const char *name) { @@ -663,18 +450,6 @@ static ParticleSettings *rna_Main_particles_new(Main *bmain, const char *name) id_us_min(&part->id); return part; } -static void rna_Main_particles_remove(Main *bmain, ReportList *reports, PointerRNA *part_ptr) -{ - ParticleSettings *part = part_ptr->data; - if (ID_REAL_USERS(part) <= 0) { - BKE_libblock_free(bmain, part); - RNA_POINTER_INVALIDATE(part_ptr); - } - else { - BKE_reportf(reports, RPT_ERROR, "Particle settings '%s' must have zero users to be removed, found %d", - part->id.name + 2, ID_REAL_USERS(part)); - } -} static Palette *rna_Main_palettes_new(Main *bmain, const char *name) { @@ -682,18 +457,6 @@ static Palette *rna_Main_palettes_new(Main *bmain, const char *name) id_us_min(&palette->id); return (Palette *)palette; } -static void rna_Main_palettes_remove(Main *bmain, ReportList *reports, PointerRNA *palette_ptr) -{ - Palette *palette = palette_ptr->data; - if (ID_REAL_USERS(palette) <= 0) { - BKE_libblock_free(bmain, palette); - RNA_POINTER_INVALIDATE(palette_ptr); - } - else { - BKE_reportf(reports, RPT_ERROR, "Palette settings '%s' must have zero users to be removed, found %d", - palette->id.name + 2, ID_REAL_USERS(palette)); - } -} static MovieClip *rna_Main_movieclip_load(Main *bmain, ReportList *reports, const char *filepath, int check_existing) { @@ -716,14 +479,6 @@ static MovieClip *rna_Main_movieclip_load(Main *bmain, ReportList *reports, cons return clip; } -static void rna_Main_movieclips_remove(Main *bmain, PointerRNA *clip_ptr) -{ - MovieClip *clip = clip_ptr->data; - BKE_movieclip_unlink(bmain, clip); - BKE_libblock_free(bmain, clip); - RNA_POINTER_INVALIDATE(clip_ptr); -} - static Mask *rna_Main_mask_new(Main *bmain, const char *name) { Mask *mask; @@ -733,27 +488,6 @@ static Mask *rna_Main_mask_new(Main *bmain, const char *name) return mask; } -static void rna_Main_masks_remove(Main *bmain, PointerRNA *mask_ptr) -{ - Mask *mask = mask_ptr->data; - BKE_mask_free(bmain, mask); - BKE_libblock_free(bmain, mask); - RNA_POINTER_INVALIDATE(mask_ptr); -} - -static void rna_Main_grease_pencil_remove(Main *bmain, ReportList *reports, PointerRNA *gpd_ptr) -{ - bGPdata *gpd = gpd_ptr->data; - if (ID_REAL_USERS(gpd) <= 0) { - BKE_gpencil_free(gpd); - BKE_libblock_free(bmain, gpd); - RNA_POINTER_INVALIDATE(gpd_ptr); - } - else - BKE_reportf(reports, RPT_ERROR, "Grease pencil '%s' must have zero users to be removed, found %d", - gpd->id.name + 2, ID_REAL_USERS(gpd)); -} - static FreestyleLineStyle *rna_Main_linestyles_new(Main *bmain, const char *name) { FreestyleLineStyle *linestyle = BKE_linestyle_new(bmain, name); @@ -761,17 +495,6 @@ static FreestyleLineStyle *rna_Main_linestyles_new(Main *bmain, const char *name return linestyle; } -static void rna_Main_linestyles_remove(Main *bmain, ReportList *reports, FreestyleLineStyle *linestyle) -{ - if (ID_REAL_USERS(linestyle) <= 0) - BKE_libblock_free(bmain, linestyle); - else - BKE_reportf(reports, RPT_ERROR, "Line style '%s' must have zero users to be removed, found %d", - linestyle->id.name + 2, ID_REAL_USERS(linestyle)); - - /* XXX python now has invalid pointer? */ -} - /* tag and is_updated functions, all the same */ #define RNA_MAIN_ID_TAG_FUNCS_DEF(_func_name, _listbase_name, _id_type) \ static void rna_Main_##_func_name##_tag(Main *bmain, int value) { \ @@ -854,12 +577,15 @@ void RNA_def_main_cameras(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "camera", "Camera", "", "New camera data-block"); RNA_def_function_return(func, parm); - func = RNA_def_function(srna, "remove", "rna_Main_cameras_remove"); + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a camera from the current blendfile"); parm = RNA_def_pointer(func, "camera", "Camera", "", "Camera to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_boolean(func, "do_unlink", false, "", + "Unlink all usages of this camera before deleting it " + "(WARNING: will also delete objects instancing that camera data)"); func = RNA_def_function(srna, "tag", "rna_Main_cameras_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -896,6 +622,7 @@ void RNA_def_main_scenes(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "scene", "Scene", "", "Scene to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this scene before deleting it"); func = RNA_def_function(srna, "tag", "rna_Main_scenes_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -930,12 +657,13 @@ void RNA_def_main_objects(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "object", "Object", "", "New object data-block"); RNA_def_function_return(func, parm); - func = RNA_def_function(srna, "remove", "rna_Main_objects_remove"); + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); RNA_def_function_ui_description(func, "Remove a object from the current blendfile"); RNA_def_function_flag(func, FUNC_USE_REPORTS); parm = RNA_def_pointer(func, "object", "Object", "", "Object to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this object before deleting it"); func = RNA_def_function(srna, "tag", "rna_Main_objects_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -966,12 +694,13 @@ void RNA_def_main_materials(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "material", "Material", "", "New material data-block"); RNA_def_function_return(func, parm); - func = RNA_def_function(srna, "remove", "rna_Main_materials_remove"); + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a material from the current blendfile"); parm = RNA_def_pointer(func, "material", "Material", "", "Material to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this material before deleting it"); func = RNA_def_function(srna, "tag", "rna_Main_materials_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1009,12 +738,13 @@ void RNA_def_main_node_groups(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "tree", "NodeTree", "", "New node tree data-block"); RNA_def_function_return(func, parm); - func = RNA_def_function(srna, "remove", "rna_Main_nodetree_remove"); + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a node tree from the current blendfile"); parm = RNA_def_pointer(func, "tree", "NodeTree", "", "Node tree to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this node tree before deleting it"); func = RNA_def_function(srna, "tag", "rna_Main_node_groups_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1067,12 +797,15 @@ void RNA_def_main_meshes(BlenderRNA *brna, PropertyRNA *cprop) "Mesh created from object, remove it if it is only used for export"); RNA_def_function_return(func, parm); - func = RNA_def_function(srna, "remove", "rna_Main_meshes_remove"); + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a mesh from the current blendfile"); parm = RNA_def_pointer(func, "mesh", "Mesh", "", "Mesh to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_boolean(func, "do_unlink", false, "", + "Unlink all usages of this mesh before deleting it " + "(WARNING: will also delete objects instancing that mesh data)"); func = RNA_def_function(srna, "tag", "rna_Main_meshes_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1104,12 +837,15 @@ void RNA_def_main_lamps(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "lamp", "Lamp", "", "New lamp data-block"); RNA_def_function_return(func, parm); - func = RNA_def_function(srna, "remove", "rna_Main_lamps_remove"); + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a lamp from the current blendfile"); parm = RNA_def_pointer(func, "lamp", "Lamp", "", "Lamp to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_boolean(func, "do_unlink", false, "", + "Unlink all usages of this lamp before deleting it " + "(WARNING: will also delete objects instancing that lamp data)"); func = RNA_def_function(srna, "tag", "rna_Main_lamps_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1219,12 +955,13 @@ void RNA_def_main_images(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "image", "Image", "", "New image data-block"); RNA_def_function_return(func, parm); - func = RNA_def_function(srna, "remove", "rna_Main_images_remove"); + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove an image from the current blendfile"); parm = RNA_def_pointer(func, "image", "Image", "", "Image to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this image before deleting it"); func = RNA_def_function(srna, "tag", "rna_Main_images_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1255,12 +992,15 @@ void RNA_def_main_lattices(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "lattice", "Lattice", "", "New lattices data-block"); RNA_def_function_return(func, parm); - func = RNA_def_function(srna, "remove", "rna_Main_lattices_remove"); + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a lattice from the current blendfile"); parm = RNA_def_pointer(func, "lattice", "Lattice", "", "Lattice to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_boolean(func, "do_unlink", false, "", + "Unlink all usages of this lattice before deleting it " + "(WARNING: will also delete objects instancing that lattice data)"); func = RNA_def_function(srna, "tag", "rna_Main_lattices_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1292,12 +1032,15 @@ void RNA_def_main_curves(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "curve", "Curve", "", "New curve data-block"); RNA_def_function_return(func, parm); - func = RNA_def_function(srna, "remove", "rna_Main_curves_remove"); + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a curve from the current blendfile"); parm = RNA_def_pointer(func, "curve", "Curve", "", "Curve to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_boolean(func, "do_unlink", false, "", + "Unlink all usages of this curve before deleting it " + "(WARNING: will also delete objects instancing that curve data)"); func = RNA_def_function(srna, "tag", "rna_Main_curves_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1327,12 +1070,15 @@ void RNA_def_main_metaballs(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "metaball", "MetaBall", "", "New metaball data-block"); RNA_def_function_return(func, parm); - func = RNA_def_function(srna, "remove", "rna_Main_metaballs_remove"); + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a metaball from the current blendfile"); parm = RNA_def_pointer(func, "metaball", "MetaBall", "", "Metaball to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_boolean(func, "do_unlink", false, "", + "Unlink all usages of this metaball before deleting it " + "(WARNING: will also delete objects instancing that metaball data)"); func = RNA_def_function(srna, "tag", "rna_Main_metaballs_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1364,12 +1110,13 @@ void RNA_def_main_fonts(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "vfont", "VectorFont", "", "New font data-block"); RNA_def_function_return(func, parm); - func = RNA_def_function(srna, "remove", "rna_Main_fonts_remove"); + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a font from the current blendfile"); parm = RNA_def_pointer(func, "vfont", "VectorFont", "", "Font to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this font before deleting it"); func = RNA_def_function(srna, "tag", "rna_Main_fonts_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1401,12 +1148,13 @@ void RNA_def_main_textures(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "texture", "Texture", "", "New texture data-block"); RNA_def_function_return(func, parm); - func = RNA_def_function(srna, "remove", "rna_Main_textures_remove"); + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a texture from the current blendfile"); parm = RNA_def_pointer(func, "texture", "Texture", "", "Texture to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this texture before deleting it"); func = RNA_def_function(srna, "tag", "rna_Main_textures_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1437,12 +1185,13 @@ void RNA_def_main_brushes(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "brush", "Brush", "", "New brush data-block"); RNA_def_function_return(func, parm); - func = RNA_def_function(srna, "remove", "rna_Main_brushes_remove"); + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a brush from the current blendfile"); parm = RNA_def_pointer(func, "brush", "Brush", "", "Brush to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this brush before deleting it"); func = RNA_def_function(srna, "tag", "rna_Main_brushes_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1473,12 +1222,13 @@ void RNA_def_main_worlds(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "world", "World", "", "New world data-block"); RNA_def_function_return(func, parm); - func = RNA_def_function(srna, "remove", "rna_Main_worlds_remove"); + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a world from the current blendfile"); parm = RNA_def_pointer(func, "world", "World", "", "World to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this world before deleting it"); func = RNA_def_function(srna, "tag", "rna_Main_worlds_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1509,11 +1259,13 @@ void RNA_def_main_groups(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "group", "Group", "", "New group data-block"); RNA_def_function_return(func, parm); - func = RNA_def_function(srna, "remove", "rna_Main_groups_remove"); + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); RNA_def_function_ui_description(func, "Remove a group from the current blendfile"); + RNA_def_function_flag(func, FUNC_USE_REPORTS); parm = RNA_def_pointer(func, "group", "Group", "", "Group to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this group before deleting it"); func = RNA_def_function(srna, "tag", "rna_Main_groups_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1544,12 +1296,15 @@ void RNA_def_main_speakers(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "speaker", "Speaker", "", "New speaker data-block"); RNA_def_function_return(func, parm); - func = RNA_def_function(srna, "remove", "rna_Main_speakers_remove"); + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a speaker from the current blendfile"); parm = RNA_def_pointer(func, "speaker", "Speaker", "", "Speaker to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_boolean(func, "do_unlink", false, "", + "Unlink all usages of this speaker before deleting it " + "(WARNING: will also delete objects instancing that speaker data)"); func = RNA_def_function(srna, "tag", "rna_Main_speakers_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1580,11 +1335,13 @@ void RNA_def_main_texts(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "text", "Text", "", "New text data-block"); RNA_def_function_return(func, parm); - func = RNA_def_function(srna, "remove", "rna_Main_texts_remove"); + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); RNA_def_function_ui_description(func, "Remove a text from the current blendfile"); + RNA_def_function_flag(func, FUNC_USE_REPORTS); parm = RNA_def_pointer(func, "text", "Text", "", "Text to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this text before deleting it"); /* load func */ func = RNA_def_function(srna, "load", "rna_Main_texts_load"); @@ -1628,12 +1385,13 @@ void RNA_def_main_sounds(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "sound", "Sound", "", "New text data-block"); RNA_def_function_return(func, parm); - func = RNA_def_function(srna, "remove", "rna_Main_sounds_remove"); + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a sound from the current blendfile"); parm = RNA_def_pointer(func, "sound", "Sound", "", "Sound to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this sound before deleting it"); func = RNA_def_function(srna, "tag", "rna_Main_sounds_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1664,12 +1422,15 @@ void RNA_def_main_armatures(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "armature", "Armature", "", "New armature data-block"); RNA_def_function_return(func, parm); - func = RNA_def_function(srna, "remove", "rna_Main_armatures_remove"); + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a armature from the current blendfile"); parm = RNA_def_pointer(func, "armature", "Armature", "", "Armature to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_boolean(func, "do_unlink", false, "", + "Unlink all usages of this armature before deleting it " + "(WARNING: will also delete objects instancing that armature data)"); func = RNA_def_function(srna, "tag", "rna_Main_armatures_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1699,12 +1460,13 @@ void RNA_def_main_actions(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "action", "Action", "", "New action data-block"); RNA_def_function_return(func, parm); - func = RNA_def_function(srna, "remove", "rna_Main_actions_remove"); + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a action from the current blendfile"); parm = RNA_def_pointer(func, "action", "Action", "", "Action to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this action before deleting it"); func = RNA_def_function(srna, "tag", "rna_Main_actions_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1734,12 +1496,13 @@ void RNA_def_main_particles(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "particle", "ParticleSettings", "", "New particle settings data-block"); RNA_def_function_return(func, parm); - func = RNA_def_function(srna, "remove", "rna_Main_particles_remove"); + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a particle settings instance from the current blendfile"); parm = RNA_def_pointer(func, "particle", "ParticleSettings", "", "Particle Settings to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of those particle settings before deleting them"); func = RNA_def_function(srna, "tag", "rna_Main_particles_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1769,12 +1532,13 @@ void RNA_def_main_palettes(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "palette", "Palette", "", "New palette data-block"); RNA_def_function_return(func, parm); - func = RNA_def_function(srna, "remove", "rna_Main_palettes_remove"); + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a palette from the current blendfile"); parm = RNA_def_pointer(func, "palette", "Palette", "", "Palette to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this palette before deleting it"); func = RNA_def_function(srna, "tag", "rna_Main_palettes_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1808,12 +1572,13 @@ void RNA_def_main_gpencil(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "grease_pencil", "GreasePencil", "", "New grease pencil data-block"); RNA_def_function_return(func, parm); - func = RNA_def_function(srna, "remove", "rna_Main_grease_pencil_remove"); + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a grease pencil instance from the current blendfile"); parm = RNA_def_pointer(func, "grease_pencil", "GreasePencil", "", "Grease Pencil to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this grease pencil before deleting it"); prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE); RNA_def_property_clear_flag(prop, PROP_EDITABLE); @@ -1836,11 +1601,13 @@ void RNA_def_main_movieclips(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_boolean(func, "value", 0, "Value", ""); RNA_def_property_flag(parm, PROP_REQUIRED); - func = RNA_def_function(srna, "remove", "rna_Main_movieclips_remove"); + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); + RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a movie clip from the current blendfile."); parm = RNA_def_pointer(func, "clip", "MovieClip", "", "Movie clip to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this movie clip before deleting it"); /* load func */ func = RNA_def_function(srna, "load", "rna_Main_movieclip_load"); @@ -1886,11 +1653,13 @@ void RNA_def_main_masks(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_return(func, parm); /* remove func */ - func = RNA_def_function(srna, "remove", "rna_Main_masks_remove"); + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); + RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a masks from the current blendfile."); parm = RNA_def_pointer(func, "mask", "Mask", "", "Mask to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this mask before deleting it"); prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE); RNA_def_property_clear_flag(prop, PROP_EDITABLE); @@ -1921,11 +1690,13 @@ void RNA_def_main_linestyles(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "linestyle", "FreestyleLineStyle", "", "New line style data-block"); RNA_def_function_return(func, parm); - func = RNA_def_function(srna, "remove", "rna_Main_linestyles_remove"); + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a line style instance from the current blendfile"); parm = RNA_def_pointer(func, "linestyle", "FreestyleLineStyle", "", "Line style to remove"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); + RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this line style before deleting it"); prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE); RNA_def_property_clear_flag(prop, PROP_EDITABLE); diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c index 0c4b3ba485d..a7c9f29e7d3 100644 --- a/source/blender/makesrna/intern/rna_modifier.c +++ b/source/blender/makesrna/intern/rna_modifier.c @@ -1826,6 +1826,12 @@ static void rna_def_modifier_hook(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Hook Center", ""); RNA_def_property_update(prop, 0, "rna_Modifier_update"); + prop = RNA_def_property(srna, "matrix_inverse", PROP_FLOAT, PROP_MATRIX); + RNA_def_property_float_sdna(prop, NULL, "parentinv"); + RNA_def_property_multi_array(prop, 2, rna_matrix_dimsize_4x4); + RNA_def_property_ui_text(prop, "Matrix", "Reverse the transformation between this object and its target"); + RNA_def_property_update(prop, NC_OBJECT | ND_TRANSFORM, "rna_Modifier_update"); + prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE); RNA_def_property_ui_text(prop, "Object", "Parent Object for hook, also recalculates and clears offset"); RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK); @@ -4602,6 +4608,11 @@ static void rna_def_modifier_normaledit(BlenderRNA *brna) "How much of generated normals to mix with exiting ones", 0.0f, 1.0f); RNA_def_property_update(prop, 0, "rna_Modifier_update"); + prop = RNA_def_float(srna, "mix_limit", 1.0f, 0.0f, DEG2RADF(180.0f), "Max Angle", + "Maximum angle between old and new normals", 0.0f, DEG2RADF(180.0f)); + RNA_def_property_subtype(prop, PROP_ANGLE); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + prop = RNA_def_property(srna, "vertex_group", PROP_STRING, PROP_NONE); RNA_def_property_string_sdna(prop, NULL, "defgrp_name"); RNA_def_property_ui_text(prop, "Vertex Group", "Vertex group name for selecting/weighting the affected areas"); diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index bf7e4634c2f..7f2cd1e6080 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -3193,12 +3193,14 @@ static EnumPropertyItem node_glossy_items[] = { {SHD_GLOSSY_BECKMANN, "BECKMANN", 0, "Beckmann", ""}, {SHD_GLOSSY_GGX, "GGX", 0, "GGX", ""}, {SHD_GLOSSY_ASHIKHMIN_SHIRLEY, "ASHIKHMIN_SHIRLEY", 0, "Ashikhmin-Shirley", ""}, + {SHD_GLOSSY_MULTI_GGX, "MULTI_GGX", 0, "Multiscatter GGX", ""}, {0, NULL, 0, NULL, NULL} }; static EnumPropertyItem node_anisotropic_items[] = { {SHD_GLOSSY_BECKMANN, "BECKMANN", 0, "Beckmann", ""}, {SHD_GLOSSY_GGX, "GGX", 0, "GGX", ""}, + {SHD_GLOSSY_MULTI_GGX, "MULTI_GGX", 0, "Multiscatter GGX", ""}, {SHD_GLOSSY_ASHIKHMIN_SHIRLEY, "ASHIKHMIN_SHIRLEY", 0, "Ashikhmin-Shirley", ""}, {0, NULL, 0, NULL, NULL} }; @@ -3207,6 +3209,14 @@ static EnumPropertyItem node_glass_items[] = { {SHD_GLOSSY_SHARP, "SHARP", 0, "Sharp", ""}, {SHD_GLOSSY_BECKMANN, "BECKMANN", 0, "Beckmann", ""}, {SHD_GLOSSY_GGX, "GGX", 0, "GGX", ""}, + {SHD_GLOSSY_MULTI_GGX, "MULTI_GGX", 0, "Multiscatter GGX", ""}, + {0, NULL, 0, NULL, NULL} +}; + +static EnumPropertyItem node_refraction_items[] = { + {SHD_GLOSSY_SHARP, "SHARP", 0, "Sharp", ""}, + {SHD_GLOSSY_BECKMANN, "BECKMANN", 0, "Beckmann", ""}, + {SHD_GLOSSY_GGX, "GGX", 0, "GGX", ""}, {0, NULL, 0, NULL, NULL} }; @@ -4159,6 +4169,17 @@ static void def_glass(StructRNA *srna) RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } +static void def_refraction(StructRNA *srna) +{ + PropertyRNA *prop; + + prop = RNA_def_property(srna, "distribution", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "custom1"); + RNA_def_property_enum_items(prop, node_refraction_items); + RNA_def_property_ui_text(prop, "Distribution", ""); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); +} + static void def_anisotropic(StructRNA *srna) { PropertyRNA *prop; diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c index 55b3fd905dc..b31cdc38775 100644 --- a/source/blender/makesrna/intern/rna_object.c +++ b/source/blender/makesrna/intern/rna_object.c @@ -2480,6 +2480,8 @@ static void rna_def_object(BlenderRNA *brna) prop = RNA_def_property(srna, "dimensions", PROP_FLOAT, PROP_XYZ_LENGTH); RNA_def_property_array(prop, 3); + /* only for the transform-panel and conflicts with animating scale */ + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_float_funcs(prop, "rna_Object_dimensions_get", "rna_Object_dimensions_set", NULL); RNA_def_property_ui_range(prop, 0.0f, FLT_MAX, 1, 3); RNA_def_property_ui_text(prop, "Dimensions", "Absolute bounding box dimensions of the object"); diff --git a/source/blender/makesrna/intern/rna_particle.c b/source/blender/makesrna/intern/rna_particle.c index 3f401a29945..a52473b95f2 100644 --- a/source/blender/makesrna/intern/rna_particle.c +++ b/source/blender/makesrna/intern/rna_particle.c @@ -341,7 +341,7 @@ static void rna_ParticleSystem_co_hair(ParticleSystem *particlesystem, Object *o totchild = (int)((float)particlesystem->totchild * (float)(part->disp) / 100.0f); } - if (part == NULL || pars == NULL || !psys_check_enabled(object, particlesystem)) + if (part == NULL || pars == NULL || !psys_check_enabled(object, particlesystem, particlesystem->renderdata != NULL)) return; if (part->ren_as == PART_DRAW_OB || part->ren_as == PART_DRAW_GR || part->ren_as == PART_DRAW_NOT) @@ -586,7 +586,7 @@ static void rna_ParticleSystem_set_resolution(ParticleSystem *particlesystem, Sc psys_render_set(object, particlesystem, mat, mat, 1, 1, 0.f); psmd->flag &= ~eParticleSystemFlag_psys_updated; - particle_system_update(scene, object, particlesystem); + particle_system_update(scene, object, particlesystem, true); } else { ParticleSystemModifierData *psmd = psys_get_modifier(object, particlesystem); @@ -596,7 +596,7 @@ static void rna_ParticleSystem_set_resolution(ParticleSystem *particlesystem, Sc } psmd->flag &= ~eParticleSystemFlag_psys_updated; - particle_system_update(scene, object, particlesystem); + particle_system_update(scene, object, particlesystem, false); } } @@ -2635,35 +2635,35 @@ static void rna_def_particle_settings(BlenderRNA *brna) RNA_def_property_float_sdna(prop, NULL, "normfac"); /*optional if prop names are the same */ RNA_def_property_range(prop, -1000.0f, 1000.0f); RNA_def_property_ui_range(prop, 0, 100, 1, 3); - RNA_def_property_ui_text(prop, "Normal", "Let the surface normal give the particle a starting speed"); + RNA_def_property_ui_text(prop, "Normal", "Let the surface normal give the particle a starting velocity"); RNA_def_property_update(prop, 0, "rna_Particle_reset"); prop = RNA_def_property(srna, "object_factor", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "obfac"); RNA_def_property_range(prop, -200.0f, 200.0f); RNA_def_property_ui_range(prop, -1.0f, 1.0f, 0.1, 3); - RNA_def_property_ui_text(prop, "Object", "Let the object give the particle a starting speed"); + RNA_def_property_ui_text(prop, "Object", "Let the object give the particle a starting velocity"); RNA_def_property_update(prop, 0, "rna_Particle_reset"); prop = RNA_def_property(srna, "factor_random", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "randfac"); /*optional if prop names are the same */ RNA_def_property_range(prop, 0.0f, 200.0f); RNA_def_property_ui_range(prop, 0, 100, 1, 3); - RNA_def_property_ui_text(prop, "Random", "Give the starting speed a random variation"); + RNA_def_property_ui_text(prop, "Random", "Give the starting velocity a random variation"); RNA_def_property_update(prop, 0, "rna_Particle_reset"); prop = RNA_def_property(srna, "particle_factor", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "partfac"); RNA_def_property_range(prop, -200.0f, 200.0f); RNA_def_property_ui_range(prop, -1.0f, 1.0f, 0.1, 3); - RNA_def_property_ui_text(prop, "Particle", "Let the target particle give the particle a starting speed"); + RNA_def_property_ui_text(prop, "Particle", "Let the target particle give the particle a starting velocity"); RNA_def_property_update(prop, 0, "rna_Particle_reset"); prop = RNA_def_property(srna, "tangent_factor", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "tanfac"); RNA_def_property_range(prop, -1000.0f, 1000.0f); RNA_def_property_ui_range(prop, -100, 100, 1, 2); - RNA_def_property_ui_text(prop, "Tangent", "Let the surface tangent give the particle a starting speed"); + RNA_def_property_ui_text(prop, "Tangent", "Let the surface tangent give the particle a starting velocity"); RNA_def_property_update(prop, 0, "rna_Particle_reset"); prop = RNA_def_property(srna, "tangent_phase", PROP_FLOAT, PROP_NONE); @@ -2677,7 +2677,7 @@ static void rna_def_particle_settings(BlenderRNA *brna) RNA_def_property_range(prop, -10.0f, 10.0f); RNA_def_property_ui_text(prop, "Reactor", "Let the vector away from the target particle's location give the particle " - "a starting speed"); + "a starting velocity"); RNA_def_property_update(prop, 0, "rna_Particle_reset"); prop = RNA_def_property(srna, "object_align_factor", PROP_FLOAT, PROP_VELOCITY); @@ -2686,7 +2686,7 @@ static void rna_def_particle_settings(BlenderRNA *brna) RNA_def_property_range(prop, -200.0f, 200.0f); RNA_def_property_ui_range(prop, -100, 100, 1, 3); RNA_def_property_ui_text(prop, "Object Aligned", - "Let the emitter object orientation give the particle a starting speed"); + "Let the emitter object orientation give the particle a starting velocity"); RNA_def_property_update(prop, 0, "rna_Particle_reset"); prop = RNA_def_property(srna, "angular_velocity_factor", PROP_FLOAT, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_pose.c b/source/blender/makesrna/intern/rna_pose.c index 06823a26c77..1f34d8f23d4 100644 --- a/source/blender/makesrna/intern/rna_pose.c +++ b/source/blender/makesrna/intern/rna_pose.c @@ -898,7 +898,7 @@ static void rna_def_pose_channel(BlenderRNA *brna) prop = RNA_def_property(srna, "use_bbone_relative_start_handle", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "bboneflag", PCHAN_BBONE_CUSTOM_START_REL); RNA_def_property_ui_text(prop, "Relative B-Bone Start Handle", - "Use treat custom start handle position as a relative value"); + "Treat custom start handle position as a relative value"); RNA_def_property_editable_func(prop, "rna_PoseChannel_proxy_editable"); RNA_def_property_update(prop, NC_OBJECT | ND_POSE, "rna_Pose_update"); @@ -914,7 +914,7 @@ static void rna_def_pose_channel(BlenderRNA *brna) prop = RNA_def_property(srna, "use_bbone_relative_end_handle", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "bboneflag", PCHAN_BBONE_CUSTOM_END_REL); RNA_def_property_ui_text(prop, "Relative B-Bone End Handle", - "Use treat custom end handle position as a relative value"); + "Treat custom end handle position as a relative value"); RNA_def_property_editable_func(prop, "rna_PoseChannel_proxy_editable"); RNA_def_property_update(prop, NC_OBJECT | ND_POSE, "rna_Pose_update"); diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index 4d1a3d9400e..6882aea5d71 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -5577,6 +5577,11 @@ static void rna_def_scene_render_data(BlenderRNA *brna) RNA_def_property_boolean_sdna(prop, NULL, "mode", R_SSS); RNA_def_property_ui_text(prop, "Subsurface Scattering", "Calculate sub-surface scattering in materials rendering"); RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_glsl_update"); + + prop = RNA_def_property(srna, "use_world_space_shading", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "mode", R_USE_WS_SHADING); + RNA_def_property_ui_text(prop, "World Space Shading", "Use world space interpretation of lighting data for node materials"); + RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_glsl_update"); prop = RNA_def_property(srna, "use_raytrace", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "mode", R_RAYTRACE); diff --git a/source/blender/makesrna/intern/rna_scene_api.c b/source/blender/makesrna/intern/rna_scene_api.c index c3c66625c84..1d3537dc9a0 100644 --- a/source/blender/makesrna/intern/rna_scene_api.c +++ b/source/blender/makesrna/intern/rna_scene_api.c @@ -196,7 +196,7 @@ static void rna_Scene_collada_export( int use_ngons, int use_object_instantiation, - int use_blender_profile, + int use_blender_profile, int sort_by_name, int export_transformation_type, int open_sim) diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c index fd90c16405c..4dd5cd2624c 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -1831,7 +1831,7 @@ static void rna_FileBrowser_FSMenu_active_range( static void rna_FileBrowser_FSMenu_active_update(struct bContext *C, PointerRNA *UNUSED(ptr)) { - ED_file_change_dir(C, true); + ED_file_change_dir(C); } static int rna_FileBrowser_FSMenuSystem_active_get(PointerRNA *ptr) @@ -2577,14 +2577,16 @@ static void rna_def_space_view3d(BlenderRNA *brna) prop = RNA_def_property(srna, "clip_start", PROP_FLOAT, PROP_DISTANCE); RNA_def_property_float_sdna(prop, NULL, "near"); - RNA_def_property_range(prop, 0.001f, FLT_MAX); + RNA_def_property_range(prop, 1e-6f, FLT_MAX); + RNA_def_property_ui_range(prop, 0.001f, FLT_MAX, 10, 3); RNA_def_property_float_default(prop, 0.1f); RNA_def_property_ui_text(prop, "Clip Start", "3D View near clipping distance (perspective view only)"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); prop = RNA_def_property(srna, "clip_end", PROP_FLOAT, PROP_DISTANCE); RNA_def_property_float_sdna(prop, NULL, "far"); - RNA_def_property_range(prop, 1.0f, FLT_MAX); + RNA_def_property_range(prop, 1e-6f, FLT_MAX); + RNA_def_property_ui_range(prop, 0.001f, FLT_MAX, 10, 3); RNA_def_property_float_default(prop, 1000.0f); RNA_def_property_ui_text(prop, "Clip End", "3D View far clipping distance"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c index 5a1607aa7c7..d8dcbf1afd0 100644 --- a/source/blender/makesrna/intern/rna_userdef.c +++ b/source/blender/makesrna/intern/rna_userdef.c @@ -94,6 +94,13 @@ EnumPropertyItem rna_enum_navigation_mode_items[] = { {0, NULL, 0, NULL, NULL} }; +#if defined(WITH_INTERNATIONAL) || !defined(RNA_RUNTIME) +static EnumPropertyItem rna_enum_language_default_items[] = { + {0, "DEFAULT", 0, "Default (Default)", ""}, + {0, NULL, 0, NULL, NULL} +}; +#endif + #ifdef RNA_RUNTIME #include "DNA_object_types.h" @@ -642,7 +649,11 @@ static EnumPropertyItem *rna_userdef_audio_device_itemf(bContext *UNUSED(C), Poi static EnumPropertyItem *rna_lang_enum_properties_itemf(bContext *UNUSED(C), PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *UNUSED(r_free)) { - return BLT_lang_RNA_enum_properties(); + EnumPropertyItem *items = BLT_lang_RNA_enum_properties(); + if (items == NULL) { + items = rna_enum_language_default_items; + } + return items; } #endif @@ -3971,11 +3982,6 @@ static void rna_def_userdef_system(BlenderRNA *brna) {USER_MULTISAMPLE_16, "16", 0, "MultiSample: 16", "Use 16x OpenGL MultiSample (requires restart)"}, {0, NULL, 0, NULL, NULL} }; - - static EnumPropertyItem language_items[] = { - {0, "DEFAULT", 0, "Default (Default)", ""}, - {0, NULL, 0, NULL, NULL} - }; #ifdef WITH_CYCLES static EnumPropertyItem compute_device_items[] = { @@ -4058,7 +4064,7 @@ static void rna_def_userdef_system(BlenderRNA *brna) /* Language Selection */ prop = RNA_def_property(srna, "language", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_items(prop, language_items); + RNA_def_property_enum_items(prop, rna_enum_language_default_items); #ifdef WITH_INTERNATIONAL RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_lang_enum_properties_itemf"); #endif diff --git a/source/blender/makesrna/intern/rna_wm.c b/source/blender/makesrna/intern/rna_wm.c index 0d11414c878..026d2e209a3 100644 --- a/source/blender/makesrna/intern/rna_wm.c +++ b/source/blender/makesrna/intern/rna_wm.c @@ -469,13 +469,15 @@ EnumPropertyItem rna_enum_wm_report_items[] = { static wmOperator *rna_OperatorProperties_find_operator(PointerRNA *ptr) { wmWindowManager *wm = ptr->id.data; - IDProperty *properties = (IDProperty *)ptr->data; - wmOperator *op; - if (wm) - for (op = wm->operators.first; op; op = op->next) - if (op->properties == properties) + if (wm) { + IDProperty *properties = (IDProperty *)ptr->data; + for (wmOperator *op = wm->operators.last; op; op = op->prev) { + if (op->properties == properties) { return op; + } + } + } return NULL; } diff --git a/source/blender/modifiers/intern/MOD_boolean.c b/source/blender/modifiers/intern/MOD_boolean.c index 1fcf4c5ec79..3f418fa16f3 100644 --- a/source/blender/modifiers/intern/MOD_boolean.c +++ b/source/blender/modifiers/intern/MOD_boolean.c @@ -222,7 +222,7 @@ static DerivedMesh *applyModifier_bmesh( #ifdef DEBUG_TIME TIMEIT_START(boolean_bmesh); #endif - bm = BM_mesh_create(&allocsize); + bm = BM_mesh_create_ex(&allocsize, ); DM_to_bmesh_ex(dm_other, bm, true); DM_to_bmesh_ex(dm, bm, true); diff --git a/source/blender/modifiers/intern/MOD_correctivesmooth.c b/source/blender/modifiers/intern/MOD_correctivesmooth.c index 4046620592b..44515bfdf35 100644 --- a/source/blender/modifiers/intern/MOD_correctivesmooth.c +++ b/source/blender/modifiers/intern/MOD_correctivesmooth.c @@ -1,29 +1,29 @@ /* -* ***** 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. -* -* The Original Code is Copyright (C) 2015 by the Blender Foundation. -* All rights reserved. -* -* Contributor(s): Jack Simpson, -* Campbell Barton -* -* ***** END GPL LICENSE BLOCK ***** -* -*/ + * ***** 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. + * + * The Original Code is Copyright (C) 2005 by the Blender Foundation. + * All rights reserved. + * + * Contributor(s): Jack Simpson, + * Campbell Barton + * + * ***** END GPL LICENSE BLOCK ***** + * + */ /** \file blender/modifiers/intern/MOD_correctivesmooth.c * \ingroup modifiers diff --git a/source/blender/modifiers/intern/MOD_normal_edit.c b/source/blender/modifiers/intern/MOD_normal_edit.c index 355dd6d6677..2cfa746ab3c 100644 --- a/source/blender/modifiers/intern/MOD_normal_edit.c +++ b/source/blender/modifiers/intern/MOD_normal_edit.c @@ -110,7 +110,7 @@ static void generate_vert_coordinates( /* Note this modifies nos_new in-place. */ static void mix_normals( const float mix_factor, MDeformVert *dvert, const int defgrp_index, const bool use_invert_vgroup, - const short mix_mode, + const float mix_limit, const short mix_mode, const int num_verts, MLoop *mloop, float (*nos_old)[3], float (*nos_new)[3], const int num_loops) { /* Mix with org normals... */ @@ -143,7 +143,9 @@ static void mix_normals( case MOD_NORMALEDIT_MIX_COPY: break; } - interp_v3_v3v3_slerp_safe(*no_new, *no_old, *no_new, fac); + + interp_v3_v3v3_slerp_safe(*no_new, *no_old, *no_new, + (mix_limit < M_PI) ? min_ff(fac, mix_limit / angle_v3v3(*no_new, *no_old)) : fac); } MEM_SAFE_FREE(facs); @@ -156,6 +158,7 @@ static bool polygons_check_flip( MPoly *mpoly, float (*polynors)[3], const int num_polys) { MPoly *mp; + MDisps *mdisp = CustomData_get_layer(ldata, CD_MDISPS); int i; bool flipped = false; @@ -174,7 +177,7 @@ static bool polygons_check_flip( /* If average of new loop normals is opposed to polygon normal, flip polygon. */ if (dot_v3v3(polynors[i], norsum) < 0.0f) { - BKE_mesh_polygon_flip(mp, mloop, ldata); + BKE_mesh_polygon_flip_ex(mp, mloop, ldata, nos, mdisp, true); negate_v3(polynors[i]); flipped = true; } @@ -186,7 +189,7 @@ static bool polygons_check_flip( static void normalEditModifier_do_radial( NormalEditModifierData *smd, Object *ob, DerivedMesh *dm, short (*clnors)[2], float (*loopnors)[3], float (*polynors)[3], - const short mix_mode, const float mix_factor, + const short mix_mode, const float mix_factor, const float mix_limit, MDeformVert *dvert, const int defgrp_index, const bool use_invert_vgroup, MVert *mvert, const int num_verts, MEdge *medge, const int num_edges, MLoop *mloop, const int num_loops, MPoly *mpoly, const int num_polys) @@ -265,11 +268,13 @@ static void normalEditModifier_do_radial( if (loopnors) { mix_normals(mix_factor, dvert, defgrp_index, use_invert_vgroup, - mix_mode, num_verts, mloop, loopnors, nos, num_loops); + mix_limit, mix_mode, num_verts, mloop, loopnors, nos, num_loops); } if (polygons_check_flip(mloop, nos, dm->getLoopDataLayout(dm), mpoly, polynors, num_polys)) { dm->dirty |= DM_DIRTY_TESS_CDLAYERS; + /* We need to recompute vertex normals! */ + dm->calcNormals(dm); } BKE_mesh_normals_loop_custom_set(mvert, num_verts, medge, num_edges, mloop, nos, num_loops, @@ -283,7 +288,7 @@ static void normalEditModifier_do_radial( static void normalEditModifier_do_directional( NormalEditModifierData *smd, Object *ob, DerivedMesh *dm, short (*clnors)[2], float (*loopnors)[3], float (*polynors)[3], - const short mix_mode, const float mix_factor, + const short mix_mode, const float mix_factor, const float mix_limit, MDeformVert *dvert, const int defgrp_index, const bool use_invert_vgroup, MVert *mvert, const int num_verts, MEdge *medge, const int num_edges, MLoop *mloop, const int num_loops, MPoly *mpoly, const int num_polys) @@ -342,7 +347,7 @@ static void normalEditModifier_do_directional( if (loopnors) { mix_normals(mix_factor, dvert, defgrp_index, use_invert_vgroup, - mix_mode, num_verts, mloop, loopnors, nos, num_loops); + mix_limit, mix_mode, num_verts, mloop, loopnors, nos, num_loops); } if (polygons_check_flip(mloop, nos, dm->getLoopDataLayout(dm), mpoly, polynors, num_polys)) { @@ -384,7 +389,8 @@ static DerivedMesh *normalEditModifier_do(NormalEditModifierData *smd, Object *o const bool use_invert_vgroup = ((smd->flag & MOD_NORMALEDIT_INVERT_VGROUP) != 0); const bool use_current_clnors = !((smd->mix_mode == MOD_NORMALEDIT_MIX_COPY) && (smd->mix_factor == 1.0f) && - (smd->defgrp_name[0] == '\0')); + (smd->defgrp_name[0] == '\0') && + (smd->mix_limit == M_PI)); int defgrp_index; MDeformVert *dvert; @@ -439,13 +445,13 @@ static DerivedMesh *normalEditModifier_do(NormalEditModifierData *smd, Object *o if (smd->mode == MOD_NORMALEDIT_MODE_RADIAL) { normalEditModifier_do_radial( smd, ob, dm, clnors, loopnors, polynors, - smd->mix_mode, smd->mix_factor, dvert, defgrp_index, use_invert_vgroup, + smd->mix_mode, smd->mix_factor, smd->mix_limit, dvert, defgrp_index, use_invert_vgroup, mvert, num_verts, medge, num_edges, mloop, num_loops, mpoly, num_polys); } else if (smd->mode == MOD_NORMALEDIT_MODE_DIRECTIONAL) { normalEditModifier_do_directional( smd, ob, dm, clnors, loopnors, polynors, - smd->mix_mode, smd->mix_factor, dvert, defgrp_index, use_invert_vgroup, + smd->mix_mode, smd->mix_factor, smd->mix_limit, dvert, defgrp_index, use_invert_vgroup, mvert, num_verts, medge, num_edges, mloop, num_loops, mpoly, num_polys); } @@ -464,6 +470,7 @@ static void initData(ModifierData *md) smd->mix_mode = MOD_NORMALEDIT_MIX_COPY; smd->mix_factor = 1.0f; + smd->mix_limit = M_PI; } static void copyData(ModifierData *md, ModifierData *target) diff --git a/source/blender/modifiers/intern/MOD_particlesystem.c b/source/blender/modifiers/intern/MOD_particlesystem.c index 4791e41d433..d8cccca415c 100644 --- a/source/blender/modifiers/intern/MOD_particlesystem.c +++ b/source/blender/modifiers/intern/MOD_particlesystem.c @@ -101,7 +101,7 @@ static void deformVerts(ModifierData *md, Object *ob, DerivedMesh *derivedData, float (*vertexCos)[3], int UNUSED(numVerts), - ModifierApplyFlag UNUSED(flag)) + ModifierApplyFlag flag) { DerivedMesh *dm = derivedData; ParticleSystemModifierData *psmd = (ParticleSystemModifierData *) md; @@ -114,7 +114,7 @@ static void deformVerts(ModifierData *md, Object *ob, else return; - if (!psys_check_enabled(ob, psys)) + if (!psys_check_enabled(ob, psys, (flag & MOD_APPLY_RENDER) != 0)) return; if (dm == NULL) { @@ -186,7 +186,7 @@ static void deformVerts(ModifierData *md, Object *ob, if (!(ob->transflag & OB_NO_PSYS_UPDATE)) { psmd->flag &= ~eParticleSystemFlag_psys_updated; - particle_system_update(md->scene, ob, psys); + particle_system_update(md->scene, ob, psys, (flag & MOD_APPLY_RENDER) != 0); psmd->flag |= eParticleSystemFlag_psys_updated; } } diff --git a/source/blender/modifiers/intern/MOD_skin.c b/source/blender/modifiers/intern/MOD_skin.c index 9f1ec4de3d5..8ed623734be 100644 --- a/source/blender/modifiers/intern/MOD_skin.c +++ b/source/blender/modifiers/intern/MOD_skin.c @@ -1745,7 +1745,9 @@ static BMesh *build_skin(SkinNode *skin_nodes, int v; so.smd = smd; - so.bm = BM_mesh_create(&bm_mesh_allocsize_default); + so.bm = BM_mesh_create( + &bm_mesh_allocsize_default, + &((struct BMeshCreateParams){.use_toolflags = true,})); so.mat_nr = 0; /* BMESH_TODO: bumping up the stack level (see MOD_array.c) */ diff --git a/source/blender/modifiers/intern/MOD_wireframe.c b/source/blender/modifiers/intern/MOD_wireframe.c index fe21757d5c2..adadd4834d4 100644 --- a/source/blender/modifiers/intern/MOD_wireframe.c +++ b/source/blender/modifiers/intern/MOD_wireframe.c @@ -1,23 +1,23 @@ /* -* ***** 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. -* -* ***** END GPL LICENSE BLOCK ***** -* -*/ + * ***** 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. + * + * ***** END GPL LICENSE BLOCK ***** + * + */ /** \file blender/modifiers/intern/MOD_wireframe.c * \ingroup modifiers diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h index 9e1a0c926fa..171d5313c1d 100644 --- a/source/blender/nodes/NOD_static_types.h +++ b/source/blender/nodes/NOD_static_types.h @@ -82,7 +82,7 @@ DefNode( ShaderNode, SH_NODE_BSDF_ANISOTROPIC, def_anisotropic, "BS DefNode( ShaderNode, SH_NODE_BSDF_DIFFUSE, 0, "BSDF_DIFFUSE", BsdfDiffuse, "Diffuse BSDF", "" ) DefNode( ShaderNode, SH_NODE_BSDF_GLOSSY, def_glossy, "BSDF_GLOSSY", BsdfGlossy, "Glossy BSDF", "" ) DefNode( ShaderNode, SH_NODE_BSDF_GLASS, def_glass, "BSDF_GLASS", BsdfGlass, "Glass BSDF", "" ) -DefNode( ShaderNode, SH_NODE_BSDF_REFRACTION, def_glass, "BSDF_REFRACTION", BsdfRefraction, "Refraction BSDF", "" ) +DefNode( ShaderNode, SH_NODE_BSDF_REFRACTION, def_refraction, "BSDF_REFRACTION", BsdfRefraction, "Refraction BSDF", "" ) DefNode( ShaderNode, SH_NODE_BSDF_TRANSLUCENT, 0, "BSDF_TRANSLUCENT", BsdfTranslucent, "Translucent BSDF", "" ) DefNode( ShaderNode, SH_NODE_BSDF_TRANSPARENT, 0, "BSDF_TRANSPARENT", BsdfTransparent, "Transparent BSDF", "" ) DefNode( ShaderNode, SH_NODE_BSDF_VELVET, 0, "BSDF_VELVET", BsdfVelvet, "Velvet BSDF", "" ) diff --git a/source/blender/nodes/shader/node_shader_tree.c b/source/blender/nodes/shader/node_shader_tree.c index 29b1e5bc5c7..8523b7275bf 100644 --- a/source/blender/nodes/shader/node_shader_tree.c +++ b/source/blender/nodes/shader/node_shader_tree.c @@ -57,6 +57,8 @@ #include "RE_shader_ext.h" +#include "NOD_common.h" + #include "node_common.h" #include "node_exec.h" #include "node_util.h" @@ -199,6 +201,12 @@ void register_node_tree_type_sh(void) /* GPU material from shader nodes */ +static void ntree_shader_link_builtin_normal(bNodeTree *ntree, + bNode *node_from, + bNodeSocket *socket_from, + bNode *displacement_node, + bNodeSocket *displacement_socket); + /* Find an output node of the shader tree. * * NOTE: it will only return output which is NOT in the group, which isn't how @@ -277,32 +285,139 @@ static bool ntree_shader_has_displacement(bNodeTree *ntree, return displacement->link != NULL; } +static bool ntree_shader_relink_node_normal(bNodeTree *ntree, + bNode *node, + bNode *node_from, + bNodeSocket *socket_from) +{ + bNodeSocket *sock = ntree_shader_node_find_input(node, "Normal"); + /* TODO(sergey): Can we do something smarter here than just a name-based + * matching? + */ + if (sock == NULL) { + /* There's no Normal input, nothing to link. */ + return false; + } + if (sock->link != NULL) { + /* Something is linked to the normal input already. can't + * use other input for that. + */ + return false; + } + /* Create connection between specified node and the normal input. */ + nodeAddLink(ntree, node_from, socket_from, node, sock); + return true; +} + +static void ntree_shader_link_builtin_group_normal( + bNodeTree *ntree, + bNode *group_node, + bNode *node_from, + bNodeSocket *socket_from, + bNode *displacement_node, + bNodeSocket *displacement_socket) +{ + bNodeTree *group_ntree = (bNodeTree *)group_node->id; + /* Create input socket to plug displacement connection to. */ + bNodeSocket *group_normal_socket = + ntreeAddSocketInterface(group_ntree, + SOCK_IN, + "NodeSocketVector", + "Normal"); + /* Need to update tree so all node instances nodes gets proper sockets. */ + bNode *group_input_node = ntreeFindType(group_ntree, NODE_GROUP_INPUT); + node_group_verify(ntree, group_node, &group_ntree->id); + node_group_input_verify(group_ntree, group_input_node, &group_ntree->id); + ntreeUpdateTree(G.main, group_ntree); + /* Assumes sockets are always added at the end. */ + bNodeSocket *group_node_normal_socket = group_node->inputs.last; + if (displacement_node == group_node) { + /* If displacement is coming from this node group we need to perform + * some internal re-linking in order to avoid cycles. + */ + bNode *group_output_node = ntreeFindType(group_ntree, NODE_GROUP_OUTPUT); + BLI_assert(group_output_node != NULL); + bNodeSocket *group_output_node_displacement_socket = + nodeFindSocket(group_output_node, + SOCK_IN, + displacement_socket->identifier); + bNodeLink *group_displacement_link = group_output_node_displacement_socket->link; + if (group_displacement_link == NULL) { + /* Displacement output is not connected to anything, can just stop + * right away. + */ + return; + } + /* This code is similar to ntree_shader_relink_displacement() */ + bNode *group_displacement_node = group_displacement_link->fromnode; + bNodeSocket *group_displacement_socket = group_displacement_link->fromsock; + /* Create and link bump node. + * Can't re-use bump node from parent tree because it'll cause cycle. + */ + bNode *bump_node = nodeAddStaticNode(NULL, group_ntree, SH_NODE_BUMP); + bNodeSocket *bump_input_socket = ntree_shader_node_find_input(bump_node, "Height"); + bNodeSocket *bump_output_socket = ntree_shader_node_find_output(bump_node, "Normal"); + BLI_assert(bump_input_socket != NULL); + BLI_assert(bump_output_socket != NULL); + nodeAddLink(group_ntree, + group_displacement_node, group_displacement_socket, + bump_node, bump_input_socket); + /* Relink normals inside of the instanced tree. */ + ntree_shader_link_builtin_normal(group_ntree, + bump_node, + bump_output_socket, + group_displacement_node, + group_displacement_socket); + ntreeUpdateTree(G.main, group_ntree); + } + else { + /* Connect group node normal input. */ + nodeAddLink(ntree, + node_from, socket_from, + group_node, group_node_normal_socket); + BLI_assert(group_input_node != NULL); + bNodeSocket *group_input_node_normal_socket = + nodeFindSocket(group_input_node, + SOCK_OUT, + group_normal_socket->identifier); + BLI_assert(group_input_node_normal_socket != NULL); + /* Relink normals inside of the instanced tree. */ + ntree_shader_link_builtin_normal(group_ntree, + group_input_node, + group_input_node_normal_socket, + displacement_node, + displacement_socket); + ntreeUpdateTree(G.main, group_ntree); + } +} + /* Use specified node and socket as an input for unconnected normal sockets. */ static void ntree_shader_link_builtin_normal(bNodeTree *ntree, bNode *node_from, - bNodeSocket *socket_from) + bNodeSocket *socket_from, + bNode *displacement_node, + bNodeSocket *displacement_socket) { for (bNode *node = ntree->nodes.first; node != NULL; node = node->next) { if (node == node_from) { /* Don't connect node itself! */ continue; } - bNodeSocket *sock = ntree_shader_node_find_input(node, "Normal"); - /* TODO(sergey): Can we do something smarter here than just a name-based - * matching? - */ - if (sock == NULL) { - /* There's no Normal input, nothing to link. */ + if (node->type == NODE_GROUP && node->id) { + /* Special re-linking for group nodes. */ + ntree_shader_link_builtin_group_normal(ntree, + node, + node_from, + socket_from, + displacement_node, + displacement_socket); continue; } - if (sock->link != NULL) { - /* Something is linked to the normal input already. can't - * use other input for that. - */ + if (ELEM(node->type, NODE_GROUP_INPUT, NODE_GROUP_OUTPUT)) { + /* Group inputs and outputs needs nothing special. */ continue; } - /* Create connection between specified node and the normal input. */ - nodeAddLink(ntree, node_from, socket_from, node, sock); + ntree_shader_relink_node_normal(ntree, node, node_from, socket_from); } } @@ -346,7 +461,11 @@ static void ntree_shader_relink_displacement(bNodeTree *ntree, displacement_node, displacement_socket, bump_node, bump_input_socket); /* Connect all free-standing Normal inputs. */ - ntree_shader_link_builtin_normal(ntree, bump_node, bump_output_socket); + ntree_shader_link_builtin_normal(ntree, + bump_node, + bump_output_socket, + displacement_node, + displacement_socket); /* TODO(sergey): Reconnect Geometry Info->Normal sockets to the new * bump node. */ @@ -369,7 +488,7 @@ void ntreeGPUMaterialNodes(bNodeTree *ntree, GPUMaterial *mat, short compatibili ntreeExecGPUNodes(exec, mat, 1, compatibility); ntreeShaderEndExecTree(exec); - ntreeFreeTree_ex(localtree, false); + ntreeFreeTree(localtree); MEM_freeN(localtree); } diff --git a/source/blender/nodes/shader/nodes/node_shader_brightness.c b/source/blender/nodes/shader/nodes/node_shader_brightness.c index 8c873b57790..e992c0773c2 100644 --- a/source/blender/nodes/shader/nodes/node_shader_brightness.c +++ b/source/blender/nodes/shader/nodes/node_shader_brightness.c @@ -23,8 +23,7 @@ * Contributor(s): none yet. * * ***** END GPL LICENSE BLOCK ***** - -*/ + */ #include "node_shader_util.h" diff --git a/source/blender/nodes/shader/nodes/node_shader_gamma.c b/source/blender/nodes/shader/nodes/node_shader_gamma.c index 0264abe451f..37439569f77 100644 --- a/source/blender/nodes/shader/nodes/node_shader_gamma.c +++ b/source/blender/nodes/shader/nodes/node_shader_gamma.c @@ -23,8 +23,7 @@ * Contributor(s): none yet. * * ***** END GPL LICENSE BLOCK ***** - -*/ + */ #include "node_shader_util.h" diff --git a/source/blender/nodes/shader/nodes/node_shader_geom.c b/source/blender/nodes/shader/nodes/node_shader_geom.c index cd52c4e2547..b289d66efc3 100644 --- a/source/blender/nodes/shader/nodes/node_shader_geom.c +++ b/source/blender/nodes/shader/nodes/node_shader_geom.c @@ -78,6 +78,10 @@ static void node_shader_exec_geom(void *data, int UNUSED(thread), bNode *node, b copy_v3_v3(out[GEOM_OUT_UV]->vec, suv->uv); copy_v3_v3(out[GEOM_OUT_NORMAL]->vec, shi->vno); + if (shi->use_world_space_shading) { + negate_v3(out[GEOM_OUT_NORMAL]->vec); + mul_mat3_m4_v3((float (*)[4])RE_render_current_get_matrix(RE_VIEWINV_MATRIX), out[GEOM_OUT_NORMAL]->vec); + } if (shi->totcol) { /* find vertex color layer by name */ ShadeInputCol *scol = &shi->col[0]; @@ -132,9 +136,14 @@ static int gpu_shader_geom(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED( GPUNodeLink *mtface = GPU_attribute(CD_MTFACE, ngeo->uvname); GPUNodeLink *mcol = GPU_attribute(CD_MCOL, ngeo->colname); - return GPU_stack_link(mat, "geom", in, out, + bool ret = GPU_stack_link(mat, "geom", in, out, GPU_builtin(GPU_VIEW_POSITION), GPU_builtin(GPU_VIEW_NORMAL), GPU_builtin(GPU_INVERSE_VIEW_MATRIX), orco, mtface, mcol); + if (GPU_material_use_world_space_shading(mat)) { + GPU_link(mat, "vec_math_negate", out[5].link, &out[5].link); + ret &= GPU_link(mat, "direction_transform_m4v3", out[5].link, GPU_builtin(GPU_INVERSE_VIEW_MATRIX), &out[5].link); + } + return ret; } /* node type definition */ diff --git a/source/blender/nodes/shader/nodes/node_shader_lamp.c b/source/blender/nodes/shader/nodes/node_shader_lamp.c index 6ff5cb0e8c4..d3483c8c826 100644 --- a/source/blender/nodes/shader/nodes/node_shader_lamp.c +++ b/source/blender/nodes/shader/nodes/node_shader_lamp.c @@ -54,6 +54,8 @@ static void node_shader_exec_lamp(void *data, int UNUSED(thread), bNode *node, b shi->nodes = 1; /* temp hack to prevent trashadow recursion */ out[4]->vec[0] = RE_lamp_get_data(shi, ob, out[0]->vec, out[1]->vec, out[2]->vec, out[3]->vec); shi->nodes = 0; + if (shi->use_world_space_shading) + mul_mat3_m4_v3((float (*)[4])RE_render_current_get_matrix(RE_VIEWINV_MATRIX), out[1]->vec); } } } @@ -66,7 +68,10 @@ static int gpu_shader_lamp(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED( visifac = GPU_lamp_get_data(mat, lamp, &col, &lv, &dist, &shadow, &energy); - return GPU_stack_link(mat, "lamp", in, out, col, energy, lv, dist, shadow, visifac); + bool ret = GPU_stack_link(mat, "lamp", in, out, col, energy, lv, dist, shadow, visifac); + if (GPU_material_use_world_space_shading(mat)) + ret &= GPU_link(mat, "direction_transform_m4v3", out[1].link, GPU_builtin(GPU_INVERSE_VIEW_MATRIX), &out[1].link); + return ret; } return false; diff --git a/source/blender/nodes/shader/nodes/node_shader_material.c b/source/blender/nodes/shader/nodes/node_shader_material.c index fa13f6191ad..8b21b1ff33b 100644 --- a/source/blender/nodes/shader/nodes/node_shader_material.c +++ b/source/blender/nodes/shader/nodes/node_shader_material.c @@ -114,6 +114,10 @@ static void node_shader_exec_material(void *data, int UNUSED(thread), bNode *nod /* retrieve normal */ if (hasinput[MAT_IN_NORMAL]) { nodestack_get_vec(shi->vn, SOCK_VECTOR, in[MAT_IN_NORMAL]); + if (shi->use_world_space_shading) { + negate_v3(shi->vn); + mul_mat3_m4_v3((float (*)[4])RE_render_current_get_matrix(RE_VIEW_MATRIX), shi->vn); + } normalize_v3(shi->vn); } else @@ -181,7 +185,11 @@ static void node_shader_exec_material(void *data, int UNUSED(thread), bNode *nod } copy_v3_v3(out[MAT_OUT_NORMAL]->vec, shi->vn); - + + if (shi->use_world_space_shading) { + negate_v3(out[MAT_OUT_NORMAL]->vec); + mul_mat3_m4_v3((float (*)[4])RE_render_current_get_matrix(RE_VIEWINV_MATRIX), out[MAT_OUT_NORMAL]->vec); + } /* Extended material options */ if (node->type == SH_NODE_MATERIAL_EXT) { /* Shadow, Reflect, Refract, Radiosity, Speed seem to cause problems inside @@ -255,6 +263,10 @@ static int gpu_shader_material(GPUMaterial *mat, bNode *node, bNodeExecData *UNU if (hasinput[MAT_IN_NORMAL]) { GPUNodeLink *tmp; shi.vn = gpu_get_input_link(&in[MAT_IN_NORMAL]); + if (GPU_material_use_world_space_shading(mat)) { + GPU_link(mat, "vec_math_negate", shi.vn, &shi.vn); + GPU_link(mat, "direction_transform_m4v3", shi.vn, GPU_builtin(GPU_VIEW_MATRIX), &shi.vn); + } GPU_link(mat, "vec_math_normalize", shi.vn, &shi.vn, &tmp); } @@ -299,6 +311,10 @@ static int gpu_shader_material(GPUMaterial *mat, bNode *node, bNodeExecData *UNU if (node->custom1 & SH_NODE_MAT_NEG) GPU_link(mat, "vec_math_negate", shi.vn, &shi.vn); out[MAT_OUT_NORMAL].link = shi.vn; + if (GPU_material_use_world_space_shading(mat)) { + GPU_link(mat, "vec_math_negate", out[MAT_OUT_NORMAL].link, &out[MAT_OUT_NORMAL].link); + GPU_link(mat, "direction_transform_m4v3", out[MAT_OUT_NORMAL].link, GPU_builtin(GPU_INVERSE_VIEW_MATRIX), &out[MAT_OUT_NORMAL].link); + } if (node->type == SH_NODE_MATERIAL_EXT) { out[MAT_OUT_DIFFUSE].link = shr.diff; diff --git a/source/blender/nodes/shader/nodes/node_shader_normal_map.c b/source/blender/nodes/shader/nodes/node_shader_normal_map.c index 85e2c77662d..48d1688c386 100644 --- a/source/blender/nodes/shader/nodes/node_shader_normal_map.c +++ b/source/blender/nodes/shader/nodes/node_shader_normal_map.c @@ -89,20 +89,34 @@ static void node_shader_exec_normal_map(void *data, int UNUSED(thread), bNode *n for (int j = 0; j < 3; j++) out[0]->vec[j] = vecIn[0] * T[j] + vecIn[1] * B[j] + vecIn[2] * N[j]; interp_v3_v3v3(out[0]->vec, N, out[0]->vec, strength); + if (shi->use_world_space_shading) { + mul_mat3_m4_v3((float (*)[4])RE_render_current_get_matrix(RE_VIEWINV_MATRIX), out[0]->vec); + } break; case SHD_NORMAL_MAP_OBJECT: case SHD_NORMAL_MAP_BLENDER_OBJECT: - mul_mat3_m4_v3((float (*)[4])RE_object_instance_get_matrix(shi->obi, RE_OBJECT_INSTANCE_MATRIX_LOCALTOVIEW), vecIn); + if (shi->use_world_space_shading) { + mul_mat3_m4_v3((float (*)[4])RE_object_instance_get_matrix(shi->obi, RE_OBJECT_INSTANCE_MATRIX_OB), vecIn); + mul_mat3_m4_v3((float (*)[4])RE_render_current_get_matrix(RE_VIEWINV_MATRIX), N); + } + else + mul_mat3_m4_v3((float (*)[4])RE_object_instance_get_matrix(shi->obi, RE_OBJECT_INSTANCE_MATRIX_LOCALTOVIEW), vecIn); interp_v3_v3v3(out[0]->vec, N, vecIn, strength); break; case SHD_NORMAL_MAP_WORLD: case SHD_NORMAL_MAP_BLENDER_WORLD: - mul_mat3_m4_v3((float (*)[4])RE_render_current_get_matrix(RE_VIEW_MATRIX), vecIn); + if (shi->use_world_space_shading) + mul_mat3_m4_v3((float (*)[4])RE_render_current_get_matrix(RE_VIEWINV_MATRIX), N); + else + mul_mat3_m4_v3((float (*)[4])RE_render_current_get_matrix(RE_VIEW_MATRIX), vecIn); interp_v3_v3v3(out[0]->vec, N, vecIn, strength); break; } + if (shi->use_world_space_shading) { + negate_v3(out[0]->vec); + } normalize_v3(out[0]->vec); } } @@ -129,10 +143,13 @@ static int gpu_shader_normal_map(GPUMaterial *mat, bNode *node, bNodeExecData *U negnorm = GPU_builtin(GPU_VIEW_NORMAL); GPU_link(mat, "math_max", strength, GPU_uniform(d), &strength); - if (GPU_material_use_new_shading_nodes(mat)) { + if (GPU_material_use_world_space_shading(mat)) { - /* **************** CYCLES ******************** */ + /* ******* CYCLES or BLENDER INTERNAL with world space shading flag ******* */ + const char *color_to_normal_fnc_name = "color_to_normal_new_shading"; + if (nm->space == SHD_NORMAL_MAP_BLENDER_OBJECT || nm->space == SHD_NORMAL_MAP_BLENDER_WORLD || !GPU_material_use_new_shading_nodes(mat)) + color_to_normal_fnc_name = "color_to_blender_normal_new_shading"; switch (nm->space) { case SHD_NORMAL_MAP_TANGENT: GPU_link(mat, "color_to_normal_new_shading", realnorm, &realnorm); @@ -143,28 +160,22 @@ static int gpu_shader_normal_map(GPUMaterial *mat, bNode *node, bNodeExecData *U GPU_link(mat, "vect_normalize", out[0].link, &out[0].link); return true; case SHD_NORMAL_MAP_OBJECT: - GPU_link(mat, "direction_transform_m4v3", negnorm, GPU_builtin(GPU_INVERSE_VIEW_MATRIX), &negnorm); - GPU_link(mat, "color_to_normal_new_shading", realnorm, &realnorm); - GPU_link(mat, "direction_transform_m4v3", realnorm, GPU_builtin(GPU_OBJECT_MATRIX), &realnorm); - break; case SHD_NORMAL_MAP_BLENDER_OBJECT: GPU_link(mat, "direction_transform_m4v3", negnorm, GPU_builtin(GPU_INVERSE_VIEW_MATRIX), &negnorm); - GPU_link(mat, "color_to_blender_normal_new_shading", realnorm, &realnorm); - GPU_link(mat, "direction_transform_m4v3", realnorm, GPU_builtin(GPU_OBJECT_MATRIX), &realnorm); + GPU_link(mat, color_to_normal_fnc_name, realnorm, &realnorm); + GPU_link(mat, "direction_transform_m4v3", realnorm, GPU_builtin(GPU_OBJECT_MATRIX), &realnorm); break; case SHD_NORMAL_MAP_WORLD: - GPU_link(mat, "direction_transform_m4v3", negnorm, GPU_builtin(GPU_INVERSE_VIEW_MATRIX), &negnorm); - GPU_link(mat, "color_to_normal_new_shading", realnorm, &realnorm); - break; case SHD_NORMAL_MAP_BLENDER_WORLD: GPU_link(mat, "direction_transform_m4v3", negnorm, GPU_builtin(GPU_INVERSE_VIEW_MATRIX), &negnorm); - GPU_link(mat, "color_to_blender_normal_new_shading", realnorm, &realnorm); + GPU_link(mat, color_to_normal_fnc_name, realnorm, &realnorm); break; } - } else { + } + else { - /* *********** BLENDER INTERNAL *************** */ + /* ************** BLENDER INTERNAL without world space shading flag ******* */ GPU_link(mat, "color_to_normal", realnorm, &realnorm); GPU_link(mat, "mtex_negate_texnormal", realnorm, &realnorm); diff --git a/source/blender/physics/intern/implicit_blender.c b/source/blender/physics/intern/implicit_blender.c index 832d516b839..2ad8ee0547f 100644 --- a/source/blender/physics/intern/implicit_blender.c +++ b/source/blender/physics/intern/implicit_blender.c @@ -1586,8 +1586,11 @@ bool BPH_mass_spring_force_spring_linear(Implicit_Data *data, int i, int j, floa // calculate elonglation spring_length(data, i, j, extent, dir, &length, vel); - - if (length > restlen || no_compress) { + + /* This code computes not only the force, but also its derivative. + Zero derivative effectively disables the spring for the implicit solver. + Thus length > restlen makes cloth unconstrained at the start of simulation. */ + if ((length >= restlen && length > 0) || no_compress) { float stretch_force, f[3], dfdx[3][3], dfdv[3][3]; stretch_force = stiffness * (length - restlen); diff --git a/source/blender/python/bmesh/bmesh_py_api.c b/source/blender/python/bmesh/bmesh_py_api.c index 7c5d1961849..eb1594688c7 100644 --- a/source/blender/python/bmesh/bmesh_py_api.c +++ b/source/blender/python/bmesh/bmesh_py_api.c @@ -53,17 +53,31 @@ #include "bmesh_py_api.h" /* own include */ PyDoc_STRVAR(bpy_bm_new_doc, -".. method:: new()\n" +".. method:: new(use_operators=True)\n" "\n" +" :arg use_operators: Support calling operators in :mod:`bmesh.ops` (uses some extra memory per vert/edge/face).\n" +" :type use_operators: bool\n" " :return: Return a new, empty BMesh.\n" " :rtype: :class:`bmesh.types.BMesh`\n" ); -static PyObject *bpy_bm_new(PyObject *UNUSED(self)) +static PyObject *bpy_bm_new(PyObject *UNUSED(self), PyObject *args, PyObject *kw) { + static const char *kwlist[] = {"use_operators", NULL}; BMesh *bm; - bm = BM_mesh_create(&bm_mesh_allocsize_default); + bool use_operators = true; + + if (!PyArg_ParseTupleAndKeywords( + args, kw, "|$O&:new", (char **)kwlist, + PyC_ParseBool, &use_operators)) + { + return NULL; + } + + bm = BM_mesh_create( + &bm_mesh_allocsize_default, + &((struct BMeshCreateParams){.use_toolflags = use_operators,})); return BPy_BMesh_CreatePyObject(bm, BPY_BMFLAG_NOP); } @@ -155,7 +169,7 @@ static PyObject *bpy_bm_update_edit_mesh(PyObject *UNUSED(self), PyObject *args, } static struct PyMethodDef BPy_BM_methods[] = { - {"new", (PyCFunction)bpy_bm_new, METH_NOARGS, bpy_bm_new_doc}, + {"new", (PyCFunction)bpy_bm_new, METH_VARARGS | METH_KEYWORDS, bpy_bm_new_doc}, {"from_edit_mesh", (PyCFunction)bpy_bm_from_edit_mesh, METH_O, bpy_bm_from_edit_mesh_doc}, {"update_edit_mesh", (PyCFunction)bpy_bm_update_edit_mesh, METH_VARARGS | METH_KEYWORDS, bpy_bm_update_edit_mesh_doc}, {NULL, NULL, 0, NULL} diff --git a/source/blender/python/bmesh/bmesh_py_ops_call.c b/source/blender/python/bmesh/bmesh_py_ops_call.c index 1dc70c3d288..551a66d1ed8 100644 --- a/source/blender/python/bmesh/bmesh_py_ops_call.c +++ b/source/blender/python/bmesh/bmesh_py_ops_call.c @@ -698,6 +698,12 @@ PyObject *BPy_BMO_call(BPy_BMeshOpFunc *self, PyObject *args, PyObject *kw) BPY_BM_CHECK_OBJ(py_bm); bm = py_bm->bm; + if (bm->use_toolflags == false) { + PyErr_SetString(PyExc_ValueError, + "bmesh created with 'use_operators=False'"); + return NULL; + } + /* could complain about entering with exceptions... */ BMO_error_clear(bm); } diff --git a/source/blender/python/bmesh/bmesh_py_types.c b/source/blender/python/bmesh/bmesh_py_types.c index a0722af522b..fe4360d1e3b 100644 --- a/source/blender/python/bmesh/bmesh_py_types.c +++ b/source/blender/python/bmesh/bmesh_py_types.c @@ -1803,6 +1803,82 @@ static PyObject *bpy_bmface_calc_perimeter(BPy_BMFace *self) } +PyDoc_STRVAR(bpy_bmface_calc_tangent_edge_doc, +".. method:: calc_tangent_edge()\n" +"\n" +" Return face tangent based on longest edge.\n" +"\n" +" :return: a normalized vector.\n" +" :rtype: :class:`mathutils.Vector`\n" +); +static PyObject *bpy_bmface_calc_tangent_edge(BPy_BMFace *self) +{ + float tangent[3]; + + BPY_BM_CHECK_OBJ(self); + BM_face_calc_tangent_edge(self->f, tangent); + return Vector_CreatePyObject(tangent, 3, NULL); +} + + +PyDoc_STRVAR(bpy_bmface_calc_tangent_edge_pair_doc, +".. method:: calc_tangent_edge_pair()\n" +"\n" +" Return face tangent based on the two longest disconected edges.\n" +"\n" +" - Tris: Use the edge pair with the most similar lengths.\n" +" - Quads: Use the longest edge pair.\n" +" - NGons: Use the two longest disconnected edges.\n" +"\n" +" :return: a normalized vector.\n" +" :rtype: :class:`mathutils.Vector`\n" +); +static PyObject *bpy_bmface_calc_tangent_edge_pair(BPy_BMFace *self) +{ + float tangent[3]; + + BPY_BM_CHECK_OBJ(self); + BM_face_calc_tangent_edge_pair(self->f, tangent); + return Vector_CreatePyObject(tangent, 3, NULL); +} + + +PyDoc_STRVAR(bpy_bmface_calc_tangent_edge_diagonal_doc, +".. method:: calc_tangent_edge_diagonal()\n" +"\n" +" Return face tangent based on the edge farthest from any vertex.\n" +"\n" +" :return: a normalized vector.\n" +" :rtype: :class:`mathutils.Vector`\n" +); +static PyObject *bpy_bmface_calc_tangent_edge_diagonal(BPy_BMFace *self) +{ + float tangent[3]; + + BPY_BM_CHECK_OBJ(self); + BM_face_calc_tangent_edge_diagonal(self->f, tangent); + return Vector_CreatePyObject(tangent, 3, NULL); +} + + +PyDoc_STRVAR(bpy_bmface_calc_tangent_vert_diagonal_doc, +".. method:: calc_tangent_vert_diagonal()\n" +"\n" +" Return face tangent based on the two most distent vertices.\n" +"\n" +" :return: a normalized vector.\n" +" :rtype: :class:`mathutils.Vector`\n" +); +static PyObject *bpy_bmface_calc_tangent_vert_diagonal(BPy_BMFace *self) +{ + float tangent[3]; + + BPY_BM_CHECK_OBJ(self); + BM_face_calc_tangent_vert_diagonal(self->f, tangent); + return Vector_CreatePyObject(tangent, 3, NULL); +} + + PyDoc_STRVAR(bpy_bmface_calc_center_mean_doc, ".. method:: calc_center_median()\n" "\n" @@ -2702,6 +2778,10 @@ static struct PyMethodDef bpy_bmface_methods[] = { {"calc_area", (PyCFunction)bpy_bmface_calc_area, METH_NOARGS, bpy_bmface_calc_area_doc}, {"calc_perimeter", (PyCFunction)bpy_bmface_calc_perimeter, METH_NOARGS, bpy_bmface_calc_perimeter_doc}, + {"calc_tangent_edge", (PyCFunction)bpy_bmface_calc_tangent_edge, METH_NOARGS, bpy_bmface_calc_tangent_edge_doc}, + {"calc_tangent_edge_pair", (PyCFunction)bpy_bmface_calc_tangent_edge_pair, METH_NOARGS, bpy_bmface_calc_tangent_edge_pair_doc}, + {"calc_tangent_edge_diagonal", (PyCFunction)bpy_bmface_calc_tangent_edge_diagonal, METH_NOARGS, bpy_bmface_calc_tangent_edge_diagonal_doc}, + {"calc_tangent_vert_diagonal", (PyCFunction)bpy_bmface_calc_tangent_vert_diagonal, METH_NOARGS, bpy_bmface_calc_tangent_vert_diagonal_doc}, {"calc_center_median", (PyCFunction)bpy_bmface_calc_center_mean, METH_NOARGS, bpy_bmface_calc_center_mean_doc}, {"calc_center_median_weighted", (PyCFunction)bpy_bmface_calc_center_mean_weighted, METH_NOARGS, bpy_bmface_calc_center_mean_weighted_doc}, {"calc_center_bounds", (PyCFunction)bpy_bmface_calc_center_bounds, METH_NOARGS, bpy_bmface_calc_center_bounds_doc}, diff --git a/source/blender/python/generic/bgl.c b/source/blender/python/generic/bgl.c index 4bd2e9d8d62..3ea10228ad4 100644 --- a/source/blender/python/generic/bgl.c +++ b/source/blender/python/generic/bgl.c @@ -983,7 +983,7 @@ static PyObject *Buffer_repr(Buffer *self) switch (self->type) { case GL_BYTE: typestr = "GL_BYTE"; break; case GL_SHORT: typestr = "GL_SHORT"; break; - case GL_INT: typestr = "GL_BYTE"; break; + case GL_INT: typestr = "GL_INT"; break; case GL_FLOAT: typestr = "GL_FLOAT"; break; case GL_DOUBLE: typestr = "GL_DOUBLE"; break; default: typestr = "UNKNOWN"; break; diff --git a/source/blender/python/intern/bpy_interface.c b/source/blender/python/intern/bpy_interface.c index 11af0836e1c..311f621e13b 100644 --- a/source/blender/python/intern/bpy_interface.c +++ b/source/blender/python/intern/bpy_interface.c @@ -901,8 +901,8 @@ static void bpy_module_free(void *UNUSED(mod)) bool BPY_string_is_keyword(const char *str) { /* list is from... - * ", ".join(['"%s"' % kw for kw in __import__("keyword").kwlist]) - */ + * ", ".join(['"%s"' % kw for kw in __import__("keyword").kwlist]) + */ const char *kwlist[] = { "False", "None", "True", "and", "as", "assert", "break", diff --git a/source/blender/python/intern/bpy_operator.c b/source/blender/python/intern/bpy_operator.c index d6c57f4c302..eaa96e6243c 100644 --- a/source/blender/python/intern/bpy_operator.c +++ b/source/blender/python/intern/bpy_operator.c @@ -264,6 +264,11 @@ static PyObject *pyop_call(PyObject *UNUSED(self), PyObject *args) if ((reports->flag & RPT_FREE) == 0) { MEM_freeN(reports); } + else { + /* The WM is now responsible for running the modal operator, + * show reports in the info window. */ + reports->flag &= ~RPT_OP_HOLD; + } } WM_operator_properties_free(&ptr); diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c index 49b806347d6..1c6471c2cca 100644 --- a/source/blender/python/intern/bpy_rna.c +++ b/source/blender/python/intern/bpy_rna.c @@ -5220,7 +5220,7 @@ static PyObject *pyrna_param_to_py(PointerRNA *ptr, PropertyRNA *prop, void *dat } case PROP_COLLECTION: { - ListBase *lb = (ListBase *)data; + CollectionListBase *lb = (CollectionListBase *)data; CollectionPointerLink *link; ret = PyList_New(0); diff --git a/source/blender/render/extern/include/RE_shader_ext.h b/source/blender/render/extern/include/RE_shader_ext.h index 8b6dfb88b73..73867de6b2e 100644 --- a/source/blender/render/extern/include/RE_shader_ext.h +++ b/source/blender/render/extern/include/RE_shader_ext.h @@ -172,6 +172,7 @@ typedef struct ShadeInput { /* from initialize, part or renderlayer */ bool do_preview; /* for nodes, in previewrender */ bool do_manage; /* color management flag */ + bool use_world_space_shading; short thread, sample; /* sample: ShadeSample array index */ short nodes; /* indicate node shading, temp hack to prevent recursion */ diff --git a/source/blender/render/intern/include/rayintersection.h b/source/blender/render/intern/include/rayintersection.h index 3607e66a237..1935e4ef59c 100644 --- a/source/blender/render/intern/include/rayintersection.h +++ b/source/blender/render/intern/include/rayintersection.h @@ -38,6 +38,8 @@ extern "C" { #endif +#include "BLI_math_geom.h" + struct RayObject; /* Ray Hints */ @@ -101,6 +103,9 @@ typedef struct Isect { #ifdef RE_RAYCOUNTER RayCounter *raycounter; #endif + + /* Precalculated coefficients for watertight intersection check. */ + struct IsectRayPrecalc isect_precalc; } Isect; /* ray types */ diff --git a/source/blender/render/intern/raytrace/rayobject.cpp b/source/blender/render/intern/raytrace/rayobject.cpp index de6b9139363..f511042749e 100644 --- a/source/blender/render/intern/raytrace/rayobject.cpp +++ b/source/blender/render/intern/raytrace/rayobject.cpp @@ -138,80 +138,29 @@ MALWAYS_INLINE int vlr_check_bake(Isect *is, ObjectInstanceRen *obi, VlakRen *UN /* Ray Triangle/Quad Intersection */ -MALWAYS_INLINE int isec_tri_quad(float start[3], float dir[3], RayFace *face, float uv[2], float *lambda) +MALWAYS_INLINE int isec_tri_quad(float start[3], const struct IsectRayPrecalc *isect_precalc, RayFace *face, float r_uv[2], float *lambda) { - float co1[3], co2[3], co3[3], co4[3]; - float t0[3], t1[3], x[3], r[3], m[3], u, v, divdet, det1, l; - int quad; - - quad = RE_rayface_isQuad(face); - - copy_v3_v3(co1, face->v1); - copy_v3_v3(co2, face->v2); - copy_v3_v3(co3, face->v3); - - copy_v3_v3(r, dir); - - /* intersect triangle */ - sub_v3_v3v3(t0, co3, co2); - sub_v3_v3v3(t1, co3, co1); - - cross_v3_v3v3(x, r, t1); - divdet = dot_v3v3(t0, x); - - sub_v3_v3v3(m, start, co3); - det1 = dot_v3v3(m, x); - - if (divdet != 0.0f) { - divdet = 1.0f / divdet; - v = det1 * divdet; - - if (v < RE_RAYTRACE_EPSILON && v > -(1.0f + RE_RAYTRACE_EPSILON)) { - float cros[3]; - - cross_v3_v3v3(cros, m, t0); - u = divdet * dot_v3v3(cros, r); - - if (u < RE_RAYTRACE_EPSILON && (v + u) > -(1.0f + RE_RAYTRACE_EPSILON)) { - l = divdet * dot_v3v3(cros, t1); - - /* check if intersection is within ray length */ - if (l > -RE_RAYTRACE_EPSILON && l < *lambda) { - uv[0] = u; - uv[1] = v; - *lambda = l; - return 1; - } - } + float uv[2], l; + + if (isect_ray_tri_watertight_v3(start, isect_precalc, face->v1, face->v2, face->v3, &l, uv)) { + /* check if intersection is within ray length */ + if (l > -RE_RAYTRACE_EPSILON && l < *lambda) { + r_uv[0] = uv[0]; + r_uv[1] = uv[1]; + *lambda = l; + return 1; } } /* intersect second triangle in quad */ - if (quad) { - copy_v3_v3(co4, face->v4); - sub_v3_v3v3(t0, co3, co4); - divdet = dot_v3v3(t0, x); - - if (divdet != 0.0f) { - divdet = 1.0f / divdet; - v = det1 * divdet; - - if (v < RE_RAYTRACE_EPSILON && v > -(1.0f + RE_RAYTRACE_EPSILON)) { - float cros[3]; - - cross_v3_v3v3(cros, m, t0); - u = divdet * dot_v3v3(cros, r); - - if (u < RE_RAYTRACE_EPSILON && (v + u) > -(1.0f + RE_RAYTRACE_EPSILON)) { - l = divdet * dot_v3v3(cros, t1); - - if (l > -RE_RAYTRACE_EPSILON && l < *lambda) { - uv[0] = u; - uv[1] = -(1.0f + v + u); - *lambda = l; - return 2; - } - } + if (RE_rayface_isQuad(face)) { + if (isect_ray_tri_watertight_v3(start, isect_precalc, face->v1, face->v3, face->v4, &l, uv)) { + /* check if intersection is within ray length */ + if (l > -RE_RAYTRACE_EPSILON && l < *lambda) { + r_uv[0] = uv[0]; + r_uv[1] = uv[1]; + *lambda = l; + return 2; } } } @@ -223,62 +172,23 @@ MALWAYS_INLINE int isec_tri_quad(float start[3], float dir[3], RayFace *face, fl MALWAYS_INLINE int isec_tri_quad_neighbour(float start[3], float dir[3], RayFace *face) { - float co1[3], co2[3], co3[3], co4[3]; - float t0[3], t1[3], x[3], r[3], m[3], u, v, divdet, det1; - int quad; - - quad = RE_rayface_isQuad(face); + float r[3]; + struct IsectRayPrecalc isect_precalc; + float uv[2], l; - copy_v3_v3(co1, face->v1); - copy_v3_v3(co2, face->v2); - copy_v3_v3(co3, face->v3); negate_v3_v3(r, dir); /* note, different than above function */ - /* intersect triangle */ - sub_v3_v3v3(t0, co3, co2); - sub_v3_v3v3(t1, co3, co1); - - cross_v3_v3v3(x, r, t1); - divdet = dot_v3v3(t0, x); - - sub_v3_v3v3(m, start, co3); - det1 = dot_v3v3(m, x); - - if (divdet != 0.0f) { - divdet = 1.0f / divdet; - v = det1 * divdet; - - if (v < RE_RAYTRACE_EPSILON && v > -(1.0f + RE_RAYTRACE_EPSILON)) { - float cros[3]; - - cross_v3_v3v3(cros, m, t0); - u = divdet * dot_v3v3(cros, r); + isect_ray_tri_watertight_v3_precalc(&isect_precalc, r); - if (u < RE_RAYTRACE_EPSILON && (v + u) > -(1.0f + RE_RAYTRACE_EPSILON)) - return 1; - } + if (isect_ray_tri_watertight_v3(start, &isect_precalc, face->v1, face->v2, face->v3, &l, uv)) { + return 1; } /* intersect second triangle in quad */ - if (quad) { - copy_v3_v3(co4, face->v4); - sub_v3_v3v3(t0, co3, co4); - divdet = dot_v3v3(t0, x); - - if (divdet != 0.0f) { - divdet = 1.0f / divdet; - v = det1 * divdet; - - if (v < RE_RAYTRACE_EPSILON && v > -(1.0f + RE_RAYTRACE_EPSILON)) { - float cros[3]; - - cross_v3_v3v3(cros, m, t0); - u = divdet * dot_v3v3(cros, r); - - if (u < RE_RAYTRACE_EPSILON && (v + u) > -(1.0f + RE_RAYTRACE_EPSILON)) - return 2; - } + if (RE_rayface_isQuad(face)) { + if (isect_ray_tri_watertight_v3(start, &isect_precalc, face->v1, face->v3, face->v4, &l, uv)) { + return 2; } } @@ -317,7 +227,7 @@ MALWAYS_INLINE int intersect_rayface(RayObject *hit_obj, RayFace *face, Isect *i RE_RC_COUNT(is->raycounter->faces.test); dist = is->dist; - ok = isec_tri_quad(is->start, is->dir, face, uv, &dist); + ok = isec_tri_quad(is->start, &is->isect_precalc, face, uv, &dist); if (ok) { @@ -389,6 +299,9 @@ int RE_rayobject_raycast(RayObject *r, Isect *isec) { int i; + /* Pre-calculate orientation for watertight intersection checks. */ + isect_ray_tri_watertight_v3_precalc(&isec->isect_precalc, isec->dir); + RE_RC_COUNT(isec->raycounter->raycast.test); /* setup vars used on raycast */ diff --git a/source/blender/render/intern/source/convertblender.c b/source/blender/render/intern/source/convertblender.c index b6ee88de290..907974e20dc 100644 --- a/source/blender/render/intern/source/convertblender.c +++ b/source/blender/render/intern/source/convertblender.c @@ -1330,7 +1330,7 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem part=psys->part; pars=psys->particles; - if (part==NULL || pars==NULL || !psys_check_enabled(ob, psys)) + if (part==NULL || pars==NULL || !psys_check_enabled(ob, psys, G.is_rendering)) return 0; if (part->ren_as==PART_DRAW_OB || part->ren_as==PART_DRAW_GR || part->ren_as==PART_DRAW_NOT) @@ -2816,7 +2816,7 @@ static void init_render_curve(Render *re, ObjectRen *obr, int timeoffset) } } - if (dl->bevelSplitFlag || timeoffset==0) { + if (dl->bevel_split || timeoffset == 0) { const int startvlak= obr->totvlak; for (a=0; a<dl->parts; a++) { @@ -2856,10 +2856,15 @@ static void init_render_curve(Render *re, ObjectRen *obr, int timeoffset) } } - if (dl->bevelSplitFlag) { - for (a=0; a<dl->parts-1+!!(dl->flag&DL_CYCL_V); a++) - if (dl->bevelSplitFlag[a>>5]&(1<<(a&0x1F))) - split_v_renderfaces(obr, startvlak, startvert, dl->parts, dl->nr, a, dl->flag&DL_CYCL_V, dl->flag&DL_CYCL_U); + if (dl->bevel_split) { + for (a = 0; a < dl->parts - 1 + !!(dl->flag & DL_CYCL_V); a++) { + if (BLI_BITMAP_TEST(dl->bevel_split, a)) { + split_v_renderfaces( + obr, startvlak, startvert, dl->parts, dl->nr, a, + /* intentionally swap (v, u) --> (u, v) */ + dl->flag & DL_CYCL_V, dl->flag & DL_CYCL_U); + } + } } /* vertex normals */ @@ -3167,9 +3172,8 @@ static void init_render_mesh(Render *re, ObjectRen *obr, int timeoffset) /* exception for tangent space baking */ if (me->mtpoly==NULL) { need_orco= 1; - need_tangent= 1; } - need_nmap_tangent_concrete = true; + need_tangent= 1; } /* check autosmooth and displacement, we then have to skip only-verts optimize @@ -4697,7 +4701,7 @@ static void add_render_object(Render *re, Object *ob, Object *par, DupliObject * if (ob->particlesystem.first) { psysindex= 1; for (psys=ob->particlesystem.first; psys; psys=psys->next, psysindex++) { - if (!psys_check_enabled(ob, psys)) + if (!psys_check_enabled(ob, psys, G.is_rendering)) continue; obr= RE_addRenderObject(re, ob, par, index, psysindex, ob->lay); diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c index c88e3b36e27..7af63051dfe 100644 --- a/source/blender/render/intern/source/pipeline.c +++ b/source/blender/render/intern/source/pipeline.c @@ -66,6 +66,7 @@ #include "BKE_global.h" #include "BKE_image.h" #include "BKE_library.h" +#include "BKE_library_remap.h" #include "BKE_main.h" #include "BKE_modifier.h" #include "BKE_node.h" @@ -2177,12 +2178,12 @@ static void init_freestyle(Render *re) re->freestyle_bmain = BKE_main_new(); /* We use the same window manager for freestyle bmain as - * real bmain uses. This is needed because freestyle's - * bmain could be used to tag scenes for update, which - * implies call of ED_render_scene_update in some cases - * and that function requires proper window manager - * to present (sergey) - */ + * real bmain uses. This is needed because freestyle's + * bmain could be used to tag scenes for update, which + * implies call of ED_render_scene_update in some cases + * and that function requires proper window manager + * to present (sergey) + */ re->freestyle_bmain->wm = re->main->wm; FRS_init_stroke_renderer(re); @@ -2267,7 +2268,8 @@ static void free_all_freestyle_renders(void) if (freestyle_render) { freestyle_scene = freestyle_render->scene; RE_FreeRender(freestyle_render); - BKE_scene_unlink(re1->freestyle_bmain, freestyle_scene, NULL); + BKE_libblock_unlink(re1->freestyle_bmain, freestyle_scene, false, false); + BKE_libblock_free(re1->freestyle_bmain, freestyle_scene); } } BLI_freelistN(&re1->freestyle_renders); diff --git a/source/blender/render/intern/source/pointdensity.c b/source/blender/render/intern/source/pointdensity.c index 59aaad661c9..e4da4302efe 100644 --- a/source/blender/render/intern/source/pointdensity.c +++ b/source/blender/render/intern/source/pointdensity.c @@ -211,7 +211,7 @@ static void pointdensity_cache_psys(Scene *scene, CD_MASK_BAREMESH | CD_MASK_MTFACE | CD_MASK_MCOL); } - if (!psys_check_enabled(ob, psys)) { + if (!psys_check_enabled(ob, psys, use_render_params)) { psys_render_restore(ob, psys); return; } diff --git a/source/blender/render/intern/source/render_texture.c b/source/blender/render/intern/source/render_texture.c index 8f61f4159e6..530ebc084be 100644 --- a/source/blender/render/intern/source/render_texture.c +++ b/source/blender/render/intern/source/render_texture.c @@ -3806,6 +3806,7 @@ void RE_sample_material_free(Material *mat) MTex *mtex= mat->mtex[tex_nr]; if (mtex->tex) { + /* don't update user counts as we are freeing a duplicate */ BKE_texture_free(mtex->tex); MEM_freeN(mtex->tex); mtex->tex = NULL; @@ -3814,7 +3815,7 @@ void RE_sample_material_free(Material *mat) } /* don't update user counts as we are freeing a duplicate */ - BKE_material_free_ex(mat, false); + BKE_material_free(mat); MEM_freeN(mat); } diff --git a/source/blender/render/intern/source/shadeinput.c b/source/blender/render/intern/source/shadeinput.c index 6e01921a6a7..20602314526 100644 --- a/source/blender/render/intern/source/shadeinput.c +++ b/source/blender/render/intern/source/shadeinput.c @@ -1339,6 +1339,7 @@ void shade_input_initialize(ShadeInput *shi, RenderPart *pa, RenderLayer *rl, in shi->do_preview = (R.r.scemode & R_MATNODE_PREVIEW) != 0; shi->do_manage = BKE_scene_check_color_management_enabled(R.scene); + shi->use_world_space_shading = BKE_scene_use_world_space_shading(R.scene); shi->lay = rl->lay; shi->layflag = rl->layflag; diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h index 388837af67a..7a247d9791b 100644 --- a/source/blender/windowmanager/WM_api.h +++ b/source/blender/windowmanager/WM_api.h @@ -191,7 +191,7 @@ void WM_ndof_deadzone_set(float deadzone); void WM_event_add_notifier(const struct bContext *C, unsigned int type, void *reference); void WM_main_add_notifier(unsigned int type, void *reference); void WM_main_remove_notifier_reference(const void *reference); -void WM_main_remove_editor_id_reference(const struct ID *id); +void WM_main_remap_editor_id_reference(struct ID *old_id, struct ID *new_id); /* reports */ void WM_report_banner_show(void); @@ -413,12 +413,6 @@ void wmOrtho2 (float x1, float x2, float y1, float y2); void wmOrtho2_region_pixelspace(const struct ARegion *ar); void wmOrtho2_pixelspace(const float x, const float y); - /* utilities */ -void WM_framebuffer_index_set(int index); -void WM_framebuffer_index_get(int index, int *r_col); -int WM_framebuffer_to_index(unsigned int col); -void WM_framebuffer_to_index_array(unsigned int *col, const unsigned int size); - /* threaded Jobs Manager */ enum { WM_JOB_PRIORITY = (1 << 0), diff --git a/source/blender/windowmanager/intern/wm_draw.c b/source/blender/windowmanager/intern/wm_draw.c index 8f15d94f538..962ed3c040d 100644 --- a/source/blender/windowmanager/intern/wm_draw.c +++ b/source/blender/windowmanager/intern/wm_draw.c @@ -437,8 +437,6 @@ void wm_triple_draw_textures(wmWindow *win, wmDrawTriple *triple, float alpha) float halfx, halfy, ratiox, ratioy; - glEnable(triple->target); - /* wmOrtho for the screen has this same offset */ ratiox = sizex; ratioy = sizey; @@ -453,6 +451,8 @@ void wm_triple_draw_textures(wmWindow *win, wmDrawTriple *triple, float alpha) halfy /= triple->y; } + GPU_basic_shader_bind((triple->target == GL_TEXTURE_2D) ? GPU_SHADER_TEXTURE_2D : GPU_SHADER_TEXTURE_RECT); + glBindTexture(triple->target, triple->bind); glColor4f(1.0f, 1.0f, 1.0f, alpha); @@ -471,7 +471,8 @@ void wm_triple_draw_textures(wmWindow *win, wmDrawTriple *triple, float alpha) glEnd(); glBindTexture(triple->target, 0); - glDisable(triple->target); + + GPU_basic_shader_bind(GPU_SHADER_USE_COLOR); } static void wm_triple_copy_textures(wmWindow *win, wmDrawTriple *triple) diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index 4f9d48450f6..4515ae92f66 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -241,7 +241,7 @@ void WM_main_remove_notifier_reference(const void *reference) } } -void WM_main_remove_editor_id_reference(const ID *id) +void WM_main_remap_editor_id_reference(ID *old_id, ID *new_id) { Main *bmain = G.main; bScreen *sc; @@ -253,7 +253,7 @@ void WM_main_remove_editor_id_reference(const ID *id) SpaceLink *sl; for (sl = sa->spacedata.first; sl; sl = sl->next) { - ED_spacedata_id_unref(sl, id); + ED_spacedata_id_remap(sa, sl, old_id, new_id); } } } @@ -793,7 +793,10 @@ static int wm_operator_exec(bContext *C, wmOperator *op, const bool repeat, cons wm_operator_finished(C, op, repeat); } else if (repeat == 0) { - WM_operator_free(op); + /* warning: modal from exec is bad practice, but avoid crashing. */ + if (retval & (OPERATOR_FINISHED | OPERATOR_CANCELLED)) { + WM_operator_free(op); + } } return retval | OPERATOR_HANDLED; diff --git a/source/blender/windowmanager/intern/wm_files_link.c b/source/blender/windowmanager/intern/wm_files_link.c index 2e4a4b63b7a..12ad8f91064 100644 --- a/source/blender/windowmanager/intern/wm_files_link.c +++ b/source/blender/windowmanager/intern/wm_files_link.c @@ -61,6 +61,7 @@ #include "BKE_context.h" #include "BKE_depsgraph.h" #include "BKE_library.h" +#include "BKE_library_remap.h" #include "BKE_global.h" #include "BKE_main.h" #include "BKE_report.h" @@ -211,7 +212,8 @@ static WMLinkAppendDataItem *wm_link_append_data_item_add( } static void wm_link_do( - WMLinkAppendData *lapp_data, ReportList *reports, Main *bmain, Scene *scene, View3D *v3d) + WMLinkAppendData *lapp_data, ReportList *reports, Main *bmain, Scene *scene, View3D *v3d, + const bool use_placeholders, const bool force_indirect) { Main *mainl; BlendHandle *bh; @@ -258,9 +260,11 @@ static void wm_link_do( continue; } - new_id = BLO_library_link_named_part_ex(mainl, &bh, item->idcode, item->name, flag, scene, v3d); + new_id = BLO_library_link_named_part_ex( + mainl, &bh, item->idcode, item->name, flag, scene, v3d, use_placeholders, force_indirect); + if (new_id) { - /* If the link is sucessful, clear item's libs 'todo' flags. + /* If the link is successful, clear item's libs 'todo' flags. * This avoids trying to link same item with other libraries to come. */ BLI_BITMAP_SET_ALL(item->libraries, false, lapp_data->num_libraries); item->new_id = new_id; @@ -401,7 +405,7 @@ static int wm_link_append_exec(bContext *C, wmOperator *op) /* XXX We'd need re-entrant locking on Main for this to work... */ /* BKE_main_lock(bmain); */ - wm_link_do(lapp_data, op->reports, bmain, scene, CTX_wm_view3d(C)); + wm_link_do(lapp_data, op->reports, bmain, scene, CTX_wm_view3d(C), false, false); /* BKE_main_unlock(bmain); */ @@ -518,3 +522,393 @@ void WM_OT_append(wmOperatorType *ot) RNA_def_boolean(ot->srna, "use_recursive", true, "Localize All", "Localize all appended data, including those indirectly linked from other libraries"); } + +/** \name Reload/relocate libraries. + * + * \{ */ + +static int wm_lib_relocate_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +{ + Library *lib; + char lib_name[MAX_NAME]; + + RNA_string_get(op->ptr, "library", lib_name); + lib = (Library *)BKE_libblock_find_name_ex(CTX_data_main(C), ID_LI, lib_name); + + if (lib) { + if (lib->parent) { + BKE_reportf(op->reports, RPT_ERROR_INVALID_INPUT, + "Cannot relocate indirectly linked library '%s'", lib->filepath); + return OPERATOR_CANCELLED; + } + RNA_string_set(op->ptr, "filepath", lib->filepath); + + WM_event_add_fileselect(C, op); + + return OPERATOR_RUNNING_MODAL; + } + + return OPERATOR_CANCELLED; +} + +/* Note that IDs listed in lapp_data items *must* have been removed from bmain by caller. */ +static void lib_relocate_do(Main *bmain, WMLinkAppendData *lapp_data, ReportList *reports, const bool do_reload) +{ + ListBase *lbarray[MAX_LIBARRAY]; + int lba_idx; + + LinkNode *itemlink; + int item_idx; + + BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, true); + + /* We do not want any instanciation here! */ + wm_link_do(lapp_data, reports, bmain, NULL, NULL, do_reload, do_reload); + + BKE_main_lock(bmain); + + /* We add back old id to bmain. + * We need to do this in a first, separated loop, otherwise some of those may not be handled by + * ID remapping, which means they would still reference old data to be deleted... */ + for (item_idx = 0, itemlink = lapp_data->items.list; itemlink; item_idx++, itemlink = itemlink->next) { + WMLinkAppendDataItem *item = itemlink->link; + ID *old_id = item->customdata; + + BLI_assert(old_id); + BLI_addtail(which_libbase(bmain, GS(old_id->name)), old_id); + } + + /* Note that in reload case, we also want to replace indirect usages. */ + const short remap_flags = ID_REMAP_SKIP_NEVER_NULL_USAGE | (do_reload ? 0 : ID_REMAP_SKIP_INDIRECT_USAGE); + for (item_idx = 0, itemlink = lapp_data->items.list; itemlink; item_idx++, itemlink = itemlink->next) { + WMLinkAppendDataItem *item = itemlink->link; + ID *old_id = item->customdata; + ID *new_id = item->new_id; + + BLI_assert(old_id); + if (do_reload) { + /* Since we asked for placeholders in case of missing IDs, we expect to always get a valid one. */ + BLI_assert(new_id); + } + if (new_id) { +#ifdef PRINT_DEBUG + printf("before remap, old_id users: %d, new_id users: %d\n", old_id->us, new_id->us); +#endif + BKE_libblock_remap_locked(bmain, old_id, new_id, remap_flags); + + if (old_id->flag & LIB_FAKEUSER) { + id_fake_user_clear(old_id); + id_fake_user_set(new_id); + } + +#ifdef PRINT_DEBUG + printf("after remap, old_id users: %d, new_id users: %d\n", old_id->us, new_id->us); +#endif + + /* In some cases, new_id might become direct link, remove parent of library in this case. */ + if (new_id->lib->parent && (new_id->tag & LIB_TAG_INDIRECT) == 0) { + if (do_reload) { + BLI_assert(0); /* Should not happen in 'pure' reload case... */ + } + new_id->lib->parent = NULL; + } + } + + if (old_id->us > 0 && new_id && old_id->lib == new_id->lib) { + /* Note that this *should* not happen - but better be safe than sorry in this area, at least until we are + * 100% sure this cannot ever happen. + * Also, we can safely assume names were unique so far, so just replacing '.' by '~' should work, + * but this does not totally rules out the possibility of name collision. */ + size_t len = strlen(old_id->name); + size_t dot_pos; + bool has_num = false; + + for (dot_pos = len; dot_pos--;) { + char c = old_id->name[dot_pos]; + if (c == '.') { + break; + } + else if (c < '0' || c > '9') { + has_num = false; + break; + } + has_num = true; + } + + if (has_num) { + old_id->name[dot_pos] = '~'; + } + else { + len = MIN2(len, MAX_ID_NAME - 7); + BLI_strncpy(&old_id->name[len], "~000", 7); + } + + id_sort_by_name(which_libbase(bmain, GS(old_id->name)), old_id); + + BKE_reportf(reports, RPT_WARNING, + "Lib Reload: Replacing all references to old datablock '%s' by reloaded one failed, " + "old one (%d remaining users) had to be kept and was renamed to '%s'", + new_id->name, old_id->us, old_id->name); + } + } + + BKE_main_unlock(bmain); + + for (item_idx = 0, itemlink = lapp_data->items.list; itemlink; item_idx++, itemlink = itemlink->next) { + WMLinkAppendDataItem *item = itemlink->link; + ID *old_id = item->customdata; + + if (old_id->us == 0) { + BKE_libblock_free(bmain, old_id); + } + } + + /* Some datablocks can get reloaded/replaced 'silently' because they are not linkable (shape keys e.g.), + * so we need another loop here to clear old ones if possible. */ + lba_idx = set_listbasepointers(bmain, lbarray); + while (lba_idx--) { + ID *id, *id_next; + for (id = lbarray[lba_idx]->first; id; id = id_next) { + id_next = id->next; + /* XXX That check may be a bit to generic/permissive? */ + if (id->lib && (id->flag & LIB_TAG_PRE_EXISTING) && id->us == 0) { + BKE_libblock_free(bmain, id); + } + } + } + + /* Get rid of no more used libraries... */ + BKE_main_id_tag_idcode(bmain, ID_LI, LIB_TAG_DOIT, true); + lba_idx = set_listbasepointers(bmain, lbarray); + while (lba_idx--) { + ID *id; + for (id = lbarray[lba_idx]->first; id; id = id->next) { + if (id->lib) { + id->lib->id.tag &= ~LIB_TAG_DOIT; + } + } + } + Library *lib, *lib_next; + for (lib = which_libbase(bmain, ID_LI)->first; lib; lib = lib_next) { + lib_next = lib->id.next; + if (lib->id.tag & LIB_TAG_DOIT) { + id_us_clear_real(&lib->id); + if (lib->id.us == 0) { + BKE_libblock_free(bmain, (ID *)lib); + } + } + } +} + +static int wm_lib_relocate_exec_do(bContext *C, wmOperator *op, bool do_reload) +{ + Library *lib; + char lib_name[MAX_NAME]; + + RNA_string_get(op->ptr, "library", lib_name); + lib = (Library *)BKE_libblock_find_name_ex(CTX_data_main(C), ID_LI, lib_name); + + if (lib) { + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + PropertyRNA *prop; + WMLinkAppendData *lapp_data; + + ListBase *lbarray[MAX_LIBARRAY]; + int lba_idx; + + char path[FILE_MAX], root[FILE_MAXDIR], libname[FILE_MAX], relname[FILE_MAX]; + short flag = 0; + + if (RNA_boolean_get(op->ptr, "relative_path")) { + flag |= FILE_RELPATH; + } + + if (lib->parent && !do_reload) { + BKE_reportf(op->reports, RPT_ERROR_INVALID_INPUT, + "Cannot relocate indirectly linked library '%s'", lib->filepath); + return OPERATOR_CANCELLED; + } + + RNA_string_get(op->ptr, "directory", root); + RNA_string_get(op->ptr, "filename", libname); + + if (!BLO_has_bfile_extension(libname)) { + BKE_report(op->reports, RPT_ERROR, "Not a library"); + return OPERATOR_CANCELLED; + } + + BLI_join_dirfile(path, sizeof(path), root, libname); + + if (!BLI_exists(path)) { + BKE_reportf(op->reports, RPT_ERROR_INVALID_INPUT, + "Trying to reload or relocate library '%s' to invalid path '%s'", lib->id.name, path); + return OPERATOR_CANCELLED; + } + + if (BLI_path_cmp(lib->filepath, path) == 0) { +#ifdef PRINT_DEBUG + printf("We are supposed to reload '%s' lib (%d)...\n", lib->filepath, lib->id.us); +#endif + + do_reload = true; + + lapp_data = wm_link_append_data_new(flag); + wm_link_append_data_library_add(lapp_data, path); + } + else { + int totfiles = 0; + +#ifdef PRINT_DEBUG + printf("We are supposed to relocate '%s' lib to new '%s' one...\n", lib->filepath, libname); +#endif + + /* Check if something is indicated for relocate. */ + prop = RNA_struct_find_property(op->ptr, "files"); + if (prop) { + totfiles = RNA_property_collection_length(op->ptr, prop); + if (totfiles == 0) { + if (!libname[0]) { + BKE_report(op->reports, RPT_ERROR, "Nothing indicated"); + return OPERATOR_CANCELLED; + } + } + } + + lapp_data = wm_link_append_data_new(flag); + + if (totfiles) { + RNA_BEGIN (op->ptr, itemptr, "files") + { + RNA_string_get(&itemptr, "name", relname); + + BLI_join_dirfile(path, sizeof(path), root, relname); + + if (BLI_path_cmp(path, lib->filepath) == 0 || !BLO_has_bfile_extension(relname)) { + continue; + } + +#ifdef PRINT_DEBUG + printf("\t candidate new lib to reload datablocks from: %s\n", path); +#endif + wm_link_append_data_library_add(lapp_data, path); + } + RNA_END; + } + else { +#ifdef PRINT_DEBUG + printf("\t candidate new lib to reload datablocks from: %s\n", path); +#endif + wm_link_append_data_library_add(lapp_data, path); + } + } + + lba_idx = set_listbasepointers(bmain, lbarray); + while (lba_idx--) { + ID *id = lbarray[lba_idx]->first; + const short idcode = id ? GS(id->name) : 0; + + if (!id || !BKE_idcode_is_linkable(idcode)) { + /* No need to reload non-linkable datatypes, those will get relinked with their 'users ID'. */ + continue; + } + + for (; id; id = id->next) { + if (id->lib == lib) { + WMLinkAppendDataItem *item; + + /* We remove it from current Main, and add it to items to link... */ + /* Note that non-linkable IDs (like e.g. shapekeys) are also explicitely linked here... */ + BLI_remlink(lbarray[lba_idx], id); + item = wm_link_append_data_item_add(lapp_data, id->name + 2, idcode, id); + BLI_BITMAP_SET_ALL(item->libraries, true, lapp_data->num_libraries); + +#ifdef PRINT_DEBUG + printf("\tdatablock to seek for: %s\n", id->name); +#endif + } + } + } + + lib_relocate_do(bmain, lapp_data, op->reports, do_reload); + + wm_link_append_data_free(lapp_data); + + BKE_main_lib_objects_recalc_all(bmain); + IMB_colormanagement_check_file_config(bmain); + + /* important we unset, otherwise these object wont + * link into other scenes from this blend file */ + BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false); + + /* recreate dependency graph to include new objects */ + DAG_scene_relations_rebuild(bmain, scene); + + /* free gpu materials, some materials depend on existing objects, such as lamps so freeing correctly refreshes */ + GPU_materials_free(); + + /* XXX TODO: align G.lib with other directory storage (like last opened image etc...) */ + BLI_strncpy(G.lib, root, FILE_MAX); + + WM_event_add_notifier(C, NC_WINDOW, NULL); + + return OPERATOR_FINISHED; + } + + return OPERATOR_CANCELLED; +} + +static int wm_lib_relocate_exec(bContext *C, wmOperator *op) +{ + return wm_lib_relocate_exec_do(C, op, false); +} + +void WM_OT_lib_relocate(wmOperatorType *ot) +{ + PropertyRNA *prop; + + ot->name = "Relocate Library"; + ot->idname = "WM_OT_lib_relocate"; + ot->description = "Relocate the given library to one or several others"; + + ot->invoke = wm_lib_relocate_invoke; + ot->exec = wm_lib_relocate_exec; + + ot->flag |= OPTYPE_UNDO; + + prop = RNA_def_string(ot->srna, "library", NULL, MAX_NAME, "Library", "Library to relocate"); + RNA_def_property_flag(prop, PROP_HIDDEN); + + WM_operator_properties_filesel( + ot, FILE_TYPE_FOLDER | FILE_TYPE_BLENDER, FILE_BLENDER, FILE_OPENFILE, + WM_FILESEL_FILEPATH | WM_FILESEL_DIRECTORY | WM_FILESEL_FILENAME | WM_FILESEL_FILES | WM_FILESEL_RELPATH, + FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA); +} + +static int wm_lib_reload_exec(bContext *C, wmOperator *op) +{ + return wm_lib_relocate_exec_do(C, op, true); +} + +void WM_OT_lib_reload(wmOperatorType *ot) +{ + PropertyRNA *prop; + + ot->name = "Reload Library"; + ot->idname = "WM_OT_lib_reload"; + ot->description = "Reload the given library"; + + ot->exec = wm_lib_reload_exec; + + ot->flag |= OPTYPE_UNDO; + + prop = RNA_def_string(ot->srna, "library", NULL, MAX_NAME, "Library", "Library to reload"); + RNA_def_property_flag(prop, PROP_HIDDEN); + + WM_operator_properties_filesel( + ot, FILE_TYPE_FOLDER | FILE_TYPE_BLENDER, FILE_BLENDER, FILE_OPENFILE, + WM_FILESEL_FILEPATH | WM_FILESEL_DIRECTORY | WM_FILESEL_FILENAME | WM_FILESEL_RELPATH, + FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA); +} + +/** \} */ diff --git a/source/blender/windowmanager/intern/wm_gesture.c b/source/blender/windowmanager/intern/wm_gesture.c index 26d1d4c3266..1357729e898 100644 --- a/source/blender/windowmanager/intern/wm_gesture.c +++ b/source/blender/windowmanager/intern/wm_gesture.c @@ -233,19 +233,15 @@ static void wm_gesture_draw_circle(wmGesture *gt) } struct LassoFillData { - unsigned int *px; + unsigned char *px; int width; }; static void draw_filled_lasso_px_cb(int x, int x_end, int y, void *user_data) { struct LassoFillData *data = user_data; - unsigned char *col = (unsigned char *)&(data->px[(y * data->width) + x]); - do { - col[0] = col[1] = col[2] = 0xff; - col[3] = 0x10; - col += 4; - } while (++x != x_end); + unsigned char *col = &(data->px[(y * data->width) + x]); + memset(col, 0x10, x_end - x); } static void draw_filled_lasso(wmWindow *win, wmGesture *gt) @@ -273,7 +269,7 @@ static void draw_filled_lasso(wmWindow *win, wmGesture *gt) if (BLI_rcti_is_empty(&rect) == false) { const int w = BLI_rcti_size_x(&rect); const int h = BLI_rcti_size_y(&rect); - unsigned int *pixel_buf = MEM_callocN(sizeof(*pixel_buf) * w * h, __func__); + unsigned char *pixel_buf = MEM_callocN(sizeof(*pixel_buf) * w * h, __func__); struct LassoFillData lasso_fill_data = {pixel_buf, w}; fill_poly_v2i_n( @@ -281,14 +277,27 @@ static void draw_filled_lasso(wmWindow *win, wmGesture *gt) (const int (*)[2])moves, tot, draw_filled_lasso_px_cb, &lasso_fill_data); - glEnable(GL_BLEND); - // glColor4f(1.0, 1.0, 1.0, 0.05); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - glRasterPos2f(rect.xmin, rect.ymin); + glColor4f(1, 1, 1, 1); + glPixelTransferf(GL_RED_BIAS, 1); + glPixelTransferf(GL_GREEN_BIAS, 1); + glPixelTransferf(GL_BLUE_BIAS, 1); - glDrawPixels(w, h, GL_RGBA, GL_UNSIGNED_BYTE, pixel_buf); + GPU_basic_shader_bind(GPU_SHADER_TEXTURE_2D | GPU_SHADER_USE_COLOR); + glEnable(GL_BLEND); + glaDrawPixelsTex(rect.xmin, rect.ymin, w, h, GL_ALPHA, GL_UNSIGNED_BYTE, GL_NEAREST, pixel_buf); glDisable(GL_BLEND); + + GPU_basic_shader_bind(GPU_SHADER_USE_COLOR); + + glPixelTransferf(GL_RED_BIAS, 0); + glPixelTransferf(GL_GREEN_BIAS, 0); + glPixelTransferf(GL_BLUE_BIAS, 0); + + glPixelStorei(GL_UNPACK_ALIGNMENT, 4); + MEM_freeN(pixel_buf); } diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c index 6300d2ed3c7..9d1083bbf63 100644 --- a/source/blender/windowmanager/intern/wm_init_exit.c +++ b/source/blender/windowmanager/intern/wm_init_exit.c @@ -61,6 +61,7 @@ #include "BKE_global.h" #include "BKE_icons.h" #include "BKE_library.h" +#include "BKE_library_remap.h" #include "BKE_main.h" #include "BKE_mball_tessellate.h" #include "BKE_node.h" @@ -140,6 +141,11 @@ static void wm_free_reports(bContext *C) BKE_reports_clear(reports); } +static void wm_undo_kill_callback(bContext *C) +{ + WM_jobs_kill_all_except(CTX_wm_manager(C), CTX_wm_screen(C)); +} + bool wm_start_with_console = false; /* used in creator.c */ /* only called once, for startup */ @@ -158,11 +164,13 @@ void WM_init(bContext *C, int argc, const char **argv) WM_menutype_init(); WM_uilisttype_init(); + BKE_undo_callback_wm_kill_jobs_set(wm_undo_kill_callback); + BKE_library_callback_free_window_manager_set(wm_close_and_free); /* library.c */ BKE_library_callback_free_notifier_reference_set(WM_main_remove_notifier_reference); /* library.c */ - BKE_library_callback_free_editor_id_reference_set(WM_main_remove_editor_id_reference); /* library.c */ + BKE_library_callback_remap_editor_id_reference_set(WM_main_remap_editor_id_reference); /* library.c */ BKE_blender_callback_test_break_set(wm_window_testbreak); /* blender.c */ - BKE_spacedata_callback_id_unref_set(ED_spacedata_id_unref); /* screen.c */ + BKE_spacedata_callback_id_remap_set(ED_spacedata_id_remap); /* screen.c */ DAG_editors_update_cb(ED_render_id_flush_update, ED_render_scene_update, ED_render_scene_update_pre); /* depsgraph.c */ @@ -533,7 +541,7 @@ void WM_exit_ext(bContext *C, const bool do_python) #ifdef WITH_PYTHON /* option not to close python so we can use 'atexit' */ - if (do_python) { + if (do_python && ((C == NULL) || CTX_py_init_get(C))) { /* XXX - old note */ /* before BKE_blender_free so py's gc happens while library still exists */ /* needed at least for a rare sigsegv that can happen in pydrivers */ @@ -578,6 +586,8 @@ void WM_exit_ext(bContext *C, const bool do_python) BLI_threadapi_exit(); + BKE_blender_atexit(); + if (MEM_get_memory_blocks_in_use() != 0) { size_t mem_in_use = MEM_get_memory_in_use() + MEM_get_memory_in_use(); printf("Error: Not freed memory blocks: %u, total unfreed memory %f MB\n", diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c index b4295bb2607..8968c2a4543 100644 --- a/source/blender/windowmanager/intern/wm_operators.c +++ b/source/blender/windowmanager/intern/wm_operators.c @@ -1391,7 +1391,7 @@ static void dialog_exec_cb(bContext *C, void *arg1, void *arg2) } } -static void dialog_check_cb(bContext *C, void *op_ptr, void *UNUSED(arg)) +static void popup_check_cb(bContext *C, void *op_ptr, void *UNUSED(arg)) { wmOperator *op = op_ptr; if (op->type->check) { @@ -1423,7 +1423,7 @@ static uiBlock *wm_block_dialog_create(bContext *C, ARegion *ar, void *userData) layout = UI_block_layout(block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 0, 0, data->width, data->height, 0, style); - UI_block_func_set(block, dialog_check_cb, op, NULL); + UI_block_func_set(block, popup_check_cb, op, NULL); uiLayoutOperatorButs(C, layout, op, NULL, 'H', UI_LAYOUT_OP_SHOW_TITLE); @@ -1463,9 +1463,13 @@ static uiBlock *wm_operator_ui_create(bContext *C, ARegion *ar, void *userData) layout = UI_block_layout(block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 0, 0, data->width, data->height, 0, style); + UI_block_func_set(block, popup_check_cb, op, NULL); + /* since ui is defined the auto-layout args are not used */ uiLayoutOperatorButs(C, layout, op, NULL, 'V', 0); + UI_block_func_set(block, NULL, NULL, NULL); + UI_block_bounds_set_popup(block, 4, 0, 0); return block; @@ -4123,6 +4127,8 @@ void wm_operatortype_init(void) WM_operatortype_append(WM_OT_revert_mainfile); WM_operatortype_append(WM_OT_link); WM_operatortype_append(WM_OT_append); + WM_operatortype_append(WM_OT_lib_relocate); + WM_operatortype_append(WM_OT_lib_reload); WM_operatortype_append(WM_OT_recover_last_session); WM_operatortype_append(WM_OT_recover_auto_save); WM_operatortype_append(WM_OT_save_as_mainfile); @@ -4202,7 +4208,8 @@ static void gesture_circle_modal_keymap(wmKeyConfig *keyconf) WM_modalkeymap_assign(keymap, "MASK_OT_select_circle"); WM_modalkeymap_assign(keymap, "NODE_OT_select_circle"); WM_modalkeymap_assign(keymap, "GPENCIL_OT_select_circle"); - WM_modalkeymap_assign(keymap, "GRAPH_OT_select_circle"); + WM_modalkeymap_assign(keymap, "GRAPH_OT_select_circle"); + WM_modalkeymap_assign(keymap, "ACTION_OT_select_circle"); } diff --git a/source/blender/windowmanager/intern/wm_subwindow.c b/source/blender/windowmanager/intern/wm_subwindow.c index 6526d419914..458ac4a121a 100644 --- a/source/blender/windowmanager/intern/wm_subwindow.c +++ b/source/blender/windowmanager/intern/wm_subwindow.c @@ -378,149 +378,5 @@ void wmOrtho2_pixelspace(const float x, const float y) wmOrtho2_offset(x, y, -GLA_PIXEL_OFS); } -/* *************************** Framebuffer color depth, for selection codes ********************** */ - -#ifdef __APPLE__ - -/* apple seems to round colors to below and up on some configs */ - -unsigned int index_to_framebuffer(int index) -{ - unsigned int i = index; - - switch (GPU_color_depth()) { - case 12: - i = ((i & 0xF00) << 12) + ((i & 0xF0) << 8) + ((i & 0xF) << 4); - /* sometimes dithering subtracts! */ - i |= 0x070707; - break; - case 15: - case 16: - i = ((i & 0x7C00) << 9) + ((i & 0x3E0) << 6) + ((i & 0x1F) << 3); - i |= 0x030303; - break; - case 24: - break; - default: /* 18 bits... */ - i = ((i & 0x3F000) << 6) + ((i & 0xFC0) << 4) + ((i & 0x3F) << 2); - i |= 0x010101; - break; - } - - return i; -} - -#else - -/* this is the old method as being in use for ages.... seems to work? colors are rounded to lower values */ - -unsigned int index_to_framebuffer(int index) -{ - unsigned int i = index; - - switch (GPU_color_depth()) { - case 8: - i = ((i & 48) << 18) + ((i & 12) << 12) + ((i & 3) << 6); - i |= 0x3F3F3F; - break; - case 12: - i = ((i & 0xF00) << 12) + ((i & 0xF0) << 8) + ((i & 0xF) << 4); - /* sometimes dithering subtracts! */ - i |= 0x0F0F0F; - break; - case 15: - case 16: - i = ((i & 0x7C00) << 9) + ((i & 0x3E0) << 6) + ((i & 0x1F) << 3); - i |= 0x070707; - break; - case 24: - break; - default: /* 18 bits... */ - i = ((i & 0x3F000) << 6) + ((i & 0xFC0) << 4) + ((i & 0x3F) << 2); - i |= 0x030303; - break; - } - - return i; -} - -#endif - -void WM_framebuffer_index_set(int index) -{ - const int col = index_to_framebuffer(index); - cpack(col); -} - -void WM_framebuffer_index_get(int index, int *r_col) -{ - const int col = index_to_framebuffer(index); - char *c_col = (char *)r_col; - c_col[0] = (col & 0xFF); /* red */ - c_col[1] = ((col >> 8) & 0xFF); /* green */ - c_col[2] = ((col >> 16) & 0xFF); /* blue */ - c_col[3] = 0xFF; /* alpha */ -} - - - -#define INDEX_FROM_BUF_8(col) (((col & 0xC00000) >> 18) + ((col & 0xC000) >> 12) + ((col & 0xC0) >> 6)) -#define INDEX_FROM_BUF_12(col) (((col & 0xF00000) >> 12) + ((col & 0xF000) >> 8) + ((col & 0xF0) >> 4)) -#define INDEX_FROM_BUF_15_16(col) (((col & 0xF80000) >> 9) + ((col & 0xF800) >> 6) + ((col & 0xF8) >> 3)) -#define INDEX_FROM_BUF_18(col) (((col & 0xFC0000) >> 6) + ((col & 0xFC00) >> 4) + ((col & 0xFC) >> 2)) -#define INDEX_FROM_BUF_24(col) (col & 0xFFFFFF) - -int WM_framebuffer_to_index(unsigned int col) -{ - if (col == 0) { - return 0; - } - - switch (GPU_color_depth()) { - case 8: return INDEX_FROM_BUF_8(col); - case 12: return INDEX_FROM_BUF_12(col); - case 15: - case 16: return INDEX_FROM_BUF_15_16(col); - case 24: return INDEX_FROM_BUF_24(col); - default: return INDEX_FROM_BUF_18(col); - } -} - -void WM_framebuffer_to_index_array(unsigned int *col, const unsigned int size) -{ -#define INDEX_BUF_ARRAY(INDEX_FROM_BUF_BITS) \ - for (i = size; i--; col++) { \ - if ((c = *col)) { \ - *col = INDEX_FROM_BUF_BITS(c); \ - } \ - } ((void)0) - - if (size > 0) { - unsigned int i, c; - - switch (GPU_color_depth()) { - case 8: - INDEX_BUF_ARRAY(INDEX_FROM_BUF_8); - break; - case 12: - INDEX_BUF_ARRAY(INDEX_FROM_BUF_12); - break; - case 15: - case 16: - INDEX_BUF_ARRAY(INDEX_FROM_BUF_15_16); - break; - case 24: - INDEX_BUF_ARRAY(INDEX_FROM_BUF_24); - break; - default: - INDEX_BUF_ARRAY(INDEX_FROM_BUF_18); - break; - } - } - -#undef INDEX_BUF_ARRAY -} - - /* ********** END MY WINDOW ************** */ diff --git a/source/blender/windowmanager/wm_event_types.h b/source/blender/windowmanager/wm_event_types.h index e2b95da29a1..3085f138846 100644 --- a/source/blender/windowmanager/wm_event_types.h +++ b/source/blender/windowmanager/wm_event_types.h @@ -311,14 +311,17 @@ enum { TIMERNOTIFIER = 0x0118, /* timer event, notifier sender */ TIMERF = 0x011F, /* last timer */ - /* Tweak, gestures: 0x500x, 0x501x */ + /* Actionzones, tweak, gestures: 0x500x, 0x501x */ EVT_ACTIONZONE_AREA = 0x5000, EVT_ACTIONZONE_REGION = 0x5001, EVT_ACTIONZONE_FULLSCREEN = 0x5011, /* NOTE: these values are saved in keymap files, do not change them but just add new ones */ - /* tweak events, for L M R mousebuttons */ + /* Tweak events: + * Sent as additional event with the mouse coordinates from where the initial click was placed. */ + + /* tweak events for L M R mousebuttons */ EVT_TWEAK_L = 0x5002, EVT_TWEAK_M = 0x5003, EVT_TWEAK_R = 0x5004, diff --git a/source/blender/windowmanager/wm_files.h b/source/blender/windowmanager/wm_files.h index 2eae9cdb012..396907a3f6d 100644 --- a/source/blender/windowmanager/wm_files.h +++ b/source/blender/windowmanager/wm_files.h @@ -59,5 +59,8 @@ void WM_OT_save_mainfile(struct wmOperatorType *ot); void WM_OT_link(struct wmOperatorType *ot); void WM_OT_append(struct wmOperatorType *ot); +void WM_OT_lib_relocate(struct wmOperatorType *ot); +void WM_OT_lib_reload(struct wmOperatorType *ot); + #endif /* __WM_FILES_H__ */ diff --git a/source/blender/windowmanager/wm_subwindow.h b/source/blender/windowmanager/wm_subwindow.h index 2a8118a726b..cc9abf87514 100644 --- a/source/blender/windowmanager/wm_subwindow.h +++ b/source/blender/windowmanager/wm_subwindow.h @@ -48,7 +48,5 @@ void wm_subwindow_matrix_get(wmWindow *win, int swinid, float mat[4][4]); void wm_subwindow_rect_get(wmWindow *win, int swinid, struct rcti *r_rect); void wm_subwindow_rect_set(wmWindow *win, int swinid, const rcti *rect); -unsigned int index_to_framebuffer(int index); - #endif /* __WM_SUBWINDOW_H__ */ diff --git a/source/blenderplayer/CMakeLists.txt b/source/blenderplayer/CMakeLists.txt index 6f32d50c2fe..206007b8d8b 100644 --- a/source/blenderplayer/CMakeLists.txt +++ b/source/blenderplayer/CMakeLists.txt @@ -215,6 +215,14 @@ endif() list(APPEND BLENDER_SORTED_LIBS bf_intern_locale) endif() + if(WITH_GAMEENGINE_DECKLINK) + list(APPEND BLENDER_SORTED_LIBS bf_intern_decklink) + endif() + + if(WIN32) + list(APPEND BLENDER_SORTED_LIBS bf_intern_gpudirect) + endif() + if(WITH_OPENSUBDIV) list(APPEND BLENDER_SORTED_LIBS bf_intern_opensubdiv) endif() diff --git a/source/blenderplayer/bad_level_call_stubs/stubs.c b/source/blenderplayer/bad_level_call_stubs/stubs.c index 95abfdc4f4c..7c7958a4acd 100644 --- a/source/blenderplayer/bad_level_call_stubs/stubs.c +++ b/source/blenderplayer/bad_level_call_stubs/stubs.c @@ -326,8 +326,6 @@ bool WM_uilisttype_add(struct uiListType *ult) RET_ZERO void WM_uilisttype_freelink(struct uiListType *ult) RET_NONE void WM_uilisttype_free(void) RET_NONE -void WM_framebuffer_index_get(int index, int *r_col) RET_NONE - struct wmKeyMapItem *WM_keymap_item_find_id(struct wmKeyMap *keymap, int id) RET_NULL int WM_enum_search_invoke(struct bContext *C, struct wmOperator *op, const struct wmEvent *event) RET_ZERO void WM_event_add_notifier(const struct bContext *C, unsigned int type, void *reference) RET_NONE @@ -380,7 +378,7 @@ void ED_area_tag_redraw_regiontype(struct ScrArea *sa, int regiontype) RET_NONE void ED_render_engine_changed(struct Main *bmain) RET_NONE void ED_file_read_bookmarks(void) RET_NONE -void ED_file_change_dir(struct bContext *C, const bool checkdir) RET_NONE +void ED_file_change_dir(struct bContext *C) RET_NONE void ED_preview_kill_jobs(struct wmWindowManager *wm, struct Main *bmain) RET_NONE struct FSMenu *ED_fsmenu_get(void) RET_NULL struct FSMenuEntry *ED_fsmenu_get_category(struct FSMenu *fsmenu, FSMenuCategory category) RET_NULL @@ -526,7 +524,7 @@ SnapObjectContext *ED_transform_snap_object_context_create( struct Main *bmain, struct Scene *scene, int flag) RET_NULL SnapObjectContext *ED_transform_snap_object_context_create_view3d( struct Main *bmain, struct Scene *scene, int flag, - struct ARegion *ar, struct View3D *v3d) RET_NULL + const struct ARegion *ar, const struct View3D *v3d) RET_NULL void ED_transform_snap_object_context_destroy(SnapObjectContext *sctx) RET_NONE bool ED_transform_snap_object_project_ray_ex( struct SnapObjectContext *sctx, diff --git a/source/creator/CMakeLists.txt b/source/creator/CMakeLists.txt index 122c10ef216..4e8dd6f9fd3 100644 --- a/source/creator/CMakeLists.txt +++ b/source/creator/CMakeLists.txt @@ -172,18 +172,28 @@ if(WITH_BUILDINFO) include_directories(${CMAKE_CURRENT_BINARY_DIR}) - # XXX, "_buildinfo.h" is used twice here, + # XXX, ${buildinfo_h_fake} is used here, # because we rely on that file being detected as missing # every build so that the real header "buildinfo.h" is updated. # # Keep this until we find a better way to resolve! + set(buildinfo_h_real "${CMAKE_CURRENT_BINARY_DIR}/buildinfo.h") + set(buildinfo_h_fake "${CMAKE_CURRENT_BINARY_DIR}/buildinfo.h_fake") + + if(EXISTS ${buildinfo_h_fake}) + message(FATAL_ERROR "File \"${buildinfo_h_fake}\" found, this should never be created, remove!") + endif() + # a custom target that is always built add_custom_target(buildinfo ALL - DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/_buildinfo.h) + DEPENDS ${buildinfo_h_fake}) # creates buildinfo.h using cmake script - add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/_buildinfo.h + add_custom_command( + OUTPUT + ${buildinfo_h_fake} # ensure we always run + ${buildinfo_h_real} COMMAND ${CMAKE_COMMAND} -DSOURCE_DIR=${CMAKE_SOURCE_DIR} # overrides only used when non-empty strings @@ -192,10 +202,14 @@ if(WITH_BUILDINFO) -P ${CMAKE_SOURCE_DIR}/build_files/cmake/buildinfo.cmake) # buildinfo.h is a generated file - set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/buildinfo.h + set_source_files_properties( + ${buildinfo_h_real} PROPERTIES GENERATED TRUE HEADER_FILE_ONLY TRUE) + unset(buildinfo_h_real) + unset(buildinfo_h_fake) + # add deps below, after adding blender # -------------- done with header values. @@ -338,6 +352,8 @@ if(WITH_PYTHON) DIRECTORY ${CMAKE_SOURCE_DIR}/release/scripts DESTINATION ${TARGETDIR_VER} PATTERN ".git" EXCLUDE + PATTERN ".gitignore" EXCLUDE + PATTERN ".arcconfig" EXCLUDE PATTERN "__pycache__" EXCLUDE PATTERN "${ADDON_EXCLUDE_CONDITIONAL}" EXCLUDE PATTERN "${FREESTYLE_EXCLUDE_CONDITIONAL}" EXCLUDE @@ -538,6 +554,7 @@ if(UNIX AND NOT APPLE) DIRECTORY ${PYTHON_LIBPATH}/python${PYTHON_VERSION} DESTINATION ${TARGETDIR_VER}/python/${_target_LIB} PATTERN "__pycache__" EXCLUDE # * any cache * + PATTERN "config-${PYTHON_VERSION}m/*.a" EXCLUDE # static lib PATTERN "lib2to3" EXCLUDE # ./lib2to3 PATTERN "site-packages/*" EXCLUDE # ./site-packages/* PATTERN "tkinter" EXCLUDE # ./tkinter @@ -914,6 +931,7 @@ elseif(APPLE) PATTERN "__pycache__" EXCLUDE PATTERN "__MACOSX" EXCLUDE PATTERN ".DS_Store" EXCLUDE + PATTERN "config-${PYTHON_VERSION}m/*.a" EXCLUDE # static lib ) endmacro() diff --git a/source/creator/creator.c b/source/creator/creator.c index 315d0d40243..e2761c9ef38 100644 --- a/source/creator/creator.c +++ b/source/creator/creator.c @@ -148,6 +148,35 @@ static void main_callback_setup(void) MEM_set_error_callback(callback_mem_error); } +/* free data on early exit (if Python calls 'sys.exit()' while parsing args for eg). */ +struct CreatorAtExitData { + bArgs *ba; +#ifdef WIN32 + const char **argv; + int argv_num; +#endif +}; + +static void callback_main_atexit(void *user_data) +{ + struct CreatorAtExitData *app_init_data = user_data; + + if (app_init_data->ba) { + BLI_argsFree(app_init_data->ba); + app_init_data->ba = NULL; + } + +#ifdef WIN32 + if (app_init_data->argv) { + while (app_init_data->argv_num) { + free(app_init_data->argv[--app_init_data->argv_num]); + } + free(app_init_data->argv); + app_init_data->argv = NULL; + } +#endif +} + /** \} */ @@ -199,6 +228,9 @@ int main( /* --- end declarations --- */ + /* ensure we free data on early-exit */ + struct CreatorAtExitData app_init_data = {NULL}; + BKE_blender_atexit_register(callback_main_atexit, &app_init_data); #ifdef WIN32 /* We delay loading of openmp so we can set the policy here. */ @@ -222,6 +254,10 @@ int main( argv[argv_num] = alloc_utf_8_from_16(argv_16[argv_num], 0); } LocalFree(argv_16); + + /* free on early-exit */ + app_init_data.argv = argv; + app_init_data.argv_num = argv_num; } #endif /* WIN32 */ @@ -336,6 +372,10 @@ int main( /* first test for background */ #ifndef WITH_PYTHON_MODULE ba = BLI_argsInit(argc, (const char **)argv); /* skip binary path */ + + /* ensure we free on early exit */ + app_init_data.ba = ba; + main_args_setup(C, ba, &syshandle); BLI_argsParse(ba, 1, NULL, NULL); @@ -432,16 +472,22 @@ int main( #endif + /* Explicitly free data allocated for argument parsing: + * - 'ba' + * - 'argv' on WIN32. + */ + callback_main_atexit(&app_init_data); + BKE_blender_atexit_unregister(callback_main_atexit, &app_init_data); + + /* paranoid, avoid accidental re-use */ #ifndef WITH_PYTHON_MODULE - BLI_argsFree(ba); + ba = NULL; + (void)ba; #endif #ifdef WIN32 - while (argv_num) { - free(argv[--argv_num]); - } - free(argv); argv = NULL; + (void)argv; #endif #ifdef WITH_PYTHON_MODULE diff --git a/source/creator/creator_args.c b/source/creator/creator_args.c index 3b27ad6f693..c89cdea4e29 100644 --- a/source/creator/creator_args.c +++ b/source/creator/creator_args.c @@ -72,6 +72,7 @@ #include "WM_api.h" +#include "GPU_basic_shader.h" #include "GPU_draw.h" #include "GPU_extensions.h" @@ -591,6 +592,7 @@ static int arg_handle_print_help(int UNUSED(argc), const char **UNUSED(argv), vo printf("\n"); printf("Experimental Features:\n"); BLI_argsPrintArgDoc(ba, "--enable-new-depsgraph"); + BLI_argsPrintArgDoc(ba, "--enable-new-basic-shader-glsl"); printf("\n"); printf("Argument Parsing:\n"); @@ -1172,6 +1174,16 @@ static int arg_handle_depsgraph_use_new(int UNUSED(argc), const char **UNUSED(ar return 0; } +static const char arg_handle_basic_shader_glsl_use_new_doc[] = +"\n\tUse new GLSL basic shader" +; +static int arg_handle_basic_shader_glsl_use_new(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data)) +{ + printf("Using new GLSL basic shader.\n"); + GPU_basic_shader_use_glsl_set(true); + return 0; +} + static const char arg_handle_verbosity_set_doc[] = "<verbose>\n" "\tSet logging verbosity level." @@ -1807,6 +1819,7 @@ void main_args_setup(bContext *C, bArgs *ba, SYS_SystemHandle *syshandle) CB_EX(arg_handle_debug_mode_generic_set, gpumem), (void *)G_DEBUG_GPU_MEM); BLI_argsAdd(ba, 1, NULL, "--enable-new-depsgraph", CB(arg_handle_depsgraph_use_new), NULL); + BLI_argsAdd(ba, 1, NULL, "--enable-new-basic-shader-glsl", CB(arg_handle_basic_shader_glsl_use_new), NULL); BLI_argsAdd(ba, 1, NULL, "--verbose", CB(arg_handle_verbosity_set), NULL); diff --git a/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp b/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp index c5fc55a8e68..91683f4d6e7 100644 --- a/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp +++ b/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp @@ -341,6 +341,7 @@ extern "C" void StartKetsjiShell(struct bContext *C, struct ARegion *ar, rcti *c ketsjiengine->SetUseFixedTime(usefixed); ketsjiengine->SetTimingDisplay(frameRate, profile, properties); ketsjiengine->SetRestrictAnimationFPS(restrictAnimFPS); + ketsjiengine->SetRender(true); KX_KetsjiEngine::SetExitKey(ConvertKeyCode(startscene->gm.exitkey)); //set the global settings (carried over if restart/load new files) diff --git a/source/gameengine/Converter/BL_BlenderDataConversion.cpp b/source/gameengine/Converter/BL_BlenderDataConversion.cpp index 14dc0d71b83..4751e60996d 100644 --- a/source/gameengine/Converter/BL_BlenderDataConversion.cpp +++ b/source/gameengine/Converter/BL_BlenderDataConversion.cpp @@ -1366,7 +1366,7 @@ static void BL_CreatePhysicsObjectNew(KX_GameObject* gameobj, /* When the parent is not OB_DYNAMIC and has no OB_COLLISION then it gets no bullet controller * and cant be apart of the parents compound shape, same goes for OB_SOFT_BODY */ if (parent && (parent->gameflag & (OB_DYNAMIC | OB_COLLISION))) { - if( (parent->gameflag & OB_CHILD)!=0 && (blenderobject->gameflag & OB_CHILD) && !(parent->gameflag & OB_SOFT_BODY)) { + if ((parent->gameflag & OB_CHILD)!=0 && (blenderobject->gameflag & OB_CHILD) && !(parent->gameflag & OB_SOFT_BODY)) { isCompoundChild = true; } } diff --git a/source/gameengine/Converter/KX_ConvertActuators.cpp b/source/gameengine/Converter/KX_ConvertActuators.cpp index 455fef0aceb..974dcbca95b 100644 --- a/source/gameengine/Converter/KX_ConvertActuators.cpp +++ b/source/gameengine/Converter/KX_ConvertActuators.cpp @@ -394,8 +394,9 @@ void BL_ConvertActuators(const char* maggiename, soundActuatorType); // if we made it mono, we have to free it - if(sound && snd_sound && snd_sound != sound->playback_handle) + if (sound && snd_sound && snd_sound != sound->playback_handle) { AUD_Sound_free(snd_sound); + } tmpsoundact->SetName(bact->name); baseact = tmpsoundact; diff --git a/source/gameengine/Expressions/EXP_PyObjectPlus.h b/source/gameengine/Expressions/EXP_PyObjectPlus.h index dd612a08494..32dc79cf6eb 100644 --- a/source/gameengine/Expressions/EXP_PyObjectPlus.h +++ b/source/gameengine/Expressions/EXP_PyObjectPlus.h @@ -73,7 +73,7 @@ typedef struct { wlink.warn_done = true; \ wlink.link = NULL; \ \ - if(wlink_last) { \ + if (wlink_last) { \ wlink_last->link= (void *)&(wlink); \ PyObjectPlus::SetDeprecationWarningLinkLast(&(wlink)); \ } \ @@ -195,7 +195,7 @@ public: \ PyObject *Py##method_name(PyObject *args, PyObject *kwds); \ static PyObject * \ sPy##method_name(PyObject *self, PyObject *args, PyObject *kwds) { \ - if(BGE_PROXY_REF(self)==NULL) { \ + if (BGE_PROXY_REF(self)==NULL) { \ PyErr_SetString(PyExc_RuntimeError, \ #class_name "." #method_name "() - " \ BGE_PROXY_ERROR_MSG); \ @@ -208,7 +208,7 @@ public: \ PyObject *Py##method_name(PyObject *args); \ static PyObject* \ sPy##method_name(PyObject *self, PyObject *args) { \ - if(BGE_PROXY_REF(self)==NULL) { \ + if (BGE_PROXY_REF(self)==NULL) { \ PyErr_SetString(PyExc_RuntimeError, \ #class_name "." #method_name "() - " \ BGE_PROXY_ERROR_MSG); return NULL; \ @@ -220,7 +220,7 @@ public: \ PyObject *Py##method_name(); \ static PyObject* \ sPy##method_name(PyObject *self) { \ - if(BGE_PROXY_REF(self)==NULL) { \ + if (BGE_PROXY_REF(self)==NULL) { \ PyErr_SetString(PyExc_RuntimeError, \ #class_name "." #method_name "() - " \ BGE_PROXY_ERROR_MSG); return NULL; \ @@ -232,7 +232,7 @@ public: \ PyObject *Py##method_name(PyObject *value); \ static PyObject* \ sPy##method_name(PyObject *self, PyObject *value) { \ - if(BGE_PROXY_REF(self)==NULL) { \ + if (BGE_PROXY_REF(self)==NULL) { \ PyErr_SetString(PyExc_RuntimeError, \ #class_name "." #method_name "(value) - " \ BGE_PROXY_ERROR_MSG); return NULL; \ @@ -244,7 +244,7 @@ public: \ PyObject *Py##method_name(PyObject *args, PyObject *kwds); \ static PyObject* \ sPy##method_name(PyObject *self, PyObject *args, PyObject *kwds) { \ - if(BGE_PROXY_REF(self)==NULL) { \ + if (BGE_PROXY_REF(self)==NULL) { \ PyErr_SetString(PyExc_RuntimeError, \ #class_name "." #method_name "(...) - " \ BGE_PROXY_ERROR_MSG); return NULL; \ @@ -257,7 +257,7 @@ public: \ PyObject *Py##method_name(PyObject *args); \ static PyObject* \ sPy##method_name(PyObject *self, PyObject *args) { \ - if(BGE_PROXY_REF(self)==NULL) { \ + if (BGE_PROXY_REF(self)==NULL) { \ PyErr_SetString(PyExc_RuntimeError, \ #class_name "." #method_name "(...) - " \ BGE_PROXY_ERROR_MSG); \ @@ -271,7 +271,7 @@ public: \ PyObject *Py##method_name(PyObject *value); \ static PyObject * \ sPy##method_name(PyObject *self, PyObject *value) { \ - if(BGE_PROXY_REF(self)==NULL) { \ + if (BGE_PROXY_REF(self)==NULL) { \ PyErr_SetString(PyExc_RuntimeError, \ #class_name "." #method_name "(value) - " \ BGE_PROXY_ERROR_MSG); \ @@ -285,7 +285,7 @@ public: \ PyObject *Py##method_name(); \ static PyObject * \ sPy##method_name(PyObject *self) { \ - if(BGE_PROXY_REF(self)==NULL) { \ + if (BGE_PROXY_REF(self)==NULL) { \ PyErr_SetString(PyExc_RuntimeError, \ #class_name "." #method_name "() - " \ BGE_PROXY_ERROR_MSG); \ diff --git a/source/gameengine/Expressions/intern/IntValue.cpp b/source/gameengine/Expressions/intern/IntValue.cpp index 25aff5b32ab..7b2e841f13f 100644 --- a/source/gameengine/Expressions/intern/IntValue.cpp +++ b/source/gameengine/Expressions/intern/IntValue.cpp @@ -3,17 +3,17 @@ */ // IntValue.cpp: implementation of the CIntValue class. /* -* Copyright (c) 1996-2000 Erwin Coumans <coockie@acm.org> -* -* Permission to use, copy, modify, distribute and sell this software -* and its documentation for any purpose is hereby granted without fee, -* provided that the above copyright notice appear in all copies and -* that both that copyright notice and this permission notice appear -* in supporting documentation. Erwin Coumans makes no -* representations about the suitability of this software for any -* purpose. It is provided "as is" without express or implied warranty. -* -*/ + * Copyright (c) 1996-2000 Erwin Coumans <coockie@acm.org> + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Erwin Coumans makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + */ #include <stdio.h> diff --git a/source/gameengine/GameLogic/SCA_PropertySensor.cpp b/source/gameengine/GameLogic/SCA_PropertySensor.cpp index 82f3bee86b2..abb64cf1733 100644 --- a/source/gameengine/GameLogic/SCA_PropertySensor.cpp +++ b/source/gameengine/GameLogic/SCA_PropertySensor.cpp @@ -199,7 +199,7 @@ bool SCA_PropertySensor::CheckPropertyCondition() const float max = m_checkpropmaxval.ToFloat(); float val; - if (orgprop->GetValueType() == VALUE_STRING_TYPE){ + if (orgprop->GetValueType() == VALUE_STRING_TYPE) { val = orgprop->GetText().ToFloat(); } else { @@ -240,7 +240,7 @@ bool SCA_PropertySensor::CheckPropertyCondition() const float ref = m_checkpropval.ToFloat(); float val; - if (orgprop->GetValueType() == VALUE_STRING_TYPE){ + if (orgprop->GetValueType() == VALUE_STRING_TYPE) { val = orgprop->GetText().ToFloat(); } else { diff --git a/source/gameengine/GamePlayer/ghost/GPG_Application.cpp b/source/gameengine/GamePlayer/ghost/GPG_Application.cpp index f0a7bd47ca3..e697306e038 100644 --- a/source/gameengine/GamePlayer/ghost/GPG_Application.cpp +++ b/source/gameengine/GamePlayer/ghost/GPG_Application.cpp @@ -301,7 +301,7 @@ bool GPG_Application::startScreenSaverFullScreen( const int stereoMode, const GHOST_TUns16 samples) { - bool ret = startFullScreen(width, height, bpp, frequency, stereoVisual, stereoMode, samples); + bool ret = startFullScreen(width, height, bpp, frequency, stereoVisual, stereoMode, 0, samples); if (ret) { HWND ghost_hwnd = findGhostWindowHWND(m_mainWindow); @@ -325,6 +325,7 @@ bool GPG_Application::startWindow( int windowHeight, const bool stereoVisual, const int stereoMode, + const int alphaBackground, const GHOST_TUns16 samples) { GHOST_GLSettings glSettings = {0}; @@ -333,6 +334,8 @@ bool GPG_Application::startWindow( //STR_String title ("Blender Player - GHOST"); if (stereoVisual) glSettings.flags |= GHOST_glStereoVisual; + if (alphaBackground) + glSettings.flags |= GHOST_glAlphaBackground; glSettings.numOfAASamples = samples; m_mainWindow = fSystem->createWindow(title, windowLeft, windowTop, windowWidth, windowHeight, GHOST_kWindowStateNormal, @@ -360,6 +363,7 @@ bool GPG_Application::startEmbeddedWindow( const GHOST_TEmbedderWindowID parentWindow, const bool stereoVisual, const int stereoMode, + const int alphaBackground, const GHOST_TUns16 samples) { GHOST_TWindowState state = GHOST_kWindowStateNormal; @@ -367,6 +371,8 @@ bool GPG_Application::startEmbeddedWindow( if (stereoVisual) glSettings.flags |= GHOST_glStereoVisual; + if (alphaBackground) + glSettings.flags |= GHOST_glAlphaBackground; glSettings.numOfAASamples = samples; if (parentWindow != 0) @@ -394,6 +400,7 @@ bool GPG_Application::startFullScreen( int bpp,int frequency, const bool stereoVisual, const int stereoMode, + const int alphaBackground, const GHOST_TUns16 samples, bool useDesktop) { @@ -407,7 +414,7 @@ bool GPG_Application::startFullScreen( setting.bpp = bpp; setting.frequency = frequency; - fSystem->beginFullScreen(setting, &m_mainWindow, stereoVisual, samples); + fSystem->beginFullScreen(setting, &m_mainWindow, stereoVisual, alphaBackground, samples); m_mainWindow->setCursorVisibility(false); /* note that X11 ignores this (it uses a window internally for fullscreen) */ m_mainWindow->setState(GHOST_kWindowStateFullScreen); @@ -626,7 +633,9 @@ bool GPG_Application::initEngine(GHOST_IWindow* window, const int stereoMode) if (!m_rasterizer) goto initFailed; - + + m_rasterizer->PrintHardwareInfo(); + // create the inputdevices m_keyboard = new GPG_KeyboardDevice(); if (!m_keyboard) @@ -671,6 +680,7 @@ bool GPG_Application::initEngine(GHOST_IWindow* window, const int stereoMode) //set the global settings (carried over if restart/load new files) m_ketsjiengine->SetGlobalSettings(m_globalSettings); + m_ketsjiengine->SetRender(true); m_engineInitialized = true; } diff --git a/source/gameengine/GamePlayer/ghost/GPG_Application.h b/source/gameengine/GamePlayer/ghost/GPG_Application.h index b6f545c2de8..e757cc10e32 100644 --- a/source/gameengine/GamePlayer/ghost/GPG_Application.h +++ b/source/gameengine/GamePlayer/ghost/GPG_Application.h @@ -65,13 +65,13 @@ public: bool startWindow(STR_String& title, int windowLeft, int windowTop, int windowWidth, int windowHeight, - const bool stereoVisual, const int stereoMode, const GHOST_TUns16 samples=0); + const bool stereoVisual, const int stereoMode, const int alphaBackground=0, const GHOST_TUns16 samples=0); bool startFullScreen(int width, int height, int bpp, int frequency, - const bool stereoVisual, const int stereoMode, + const bool stereoVisual, const int stereoMode, const int alphaBackground = 0, const GHOST_TUns16 samples=0, bool useDesktop=false); bool startEmbeddedWindow(STR_String& title, const GHOST_TEmbedderWindowID parent_window, - const bool stereoVisual, const int stereoMode, const GHOST_TUns16 samples=0); + const bool stereoVisual, const int stereoMode, const int alphaBackground=0, const GHOST_TUns16 samples=0); #ifdef WIN32 bool startScreenSaverFullScreen(int width, int height, int bpp, int frequency, diff --git a/source/gameengine/GamePlayer/ghost/GPG_ghost.cpp b/source/gameengine/GamePlayer/ghost/GPG_ghost.cpp index ac2e4dfa563..9c3f94f1918 100644 --- a/source/gameengine/GamePlayer/ghost/GPG_ghost.cpp +++ b/source/gameengine/GamePlayer/ghost/GPG_ghost.cpp @@ -46,8 +46,8 @@ #include "KX_PyConstraintBinding.h" // for PHY_SetActiveEnvironment /********************************** -* Begin Blender include block -**********************************/ + * Begin Blender include block + **********************************/ #ifdef __cplusplus extern "C" { @@ -74,6 +74,7 @@ extern "C" #include "BKE_node.h" #include "BKE_report.h" #include "BKE_library.h" +#include "BKE_library_remap.h" #include "BKE_modifier.h" #include "BKE_material.h" #include "BKE_text.h" @@ -102,8 +103,8 @@ extern char datatoc_bmonofont_ttf[]; #include "GPU_draw.h" /********************************** -* End Blender include block -**********************************/ + * End Blender include block + **********************************/ #include "BL_System.h" #include "GPG_Application.h" @@ -444,6 +445,7 @@ int main( int validArguments=0; bool samplesParFound = false; GHOST_TUns16 aasamples = 0; + int alphaBackground = 0; #ifdef WIN32 char **argv; @@ -461,8 +463,8 @@ int main( /* Win32 Unicode Args */ /* NOTE: cannot use guardedalloc malloc here, as it's not yet initialized - * (it depends on the args passed in, which is what we're getting here!) - */ + * (it depends on the args passed in, which is what we're getting here!) + */ { wchar_t **argv_16 = CommandLineToArgvW(GetCommandLineW(), &argc); argv = (char**)malloc(argc * sizeof(char *)); @@ -838,6 +840,12 @@ int main( } break; } + case 'a': // allow window to blend with display background + { + i++; + alphaBackground = 1; + break; + } default: //not recognized { printf("Unknown argument: %s\n", argv[i++]); @@ -1041,7 +1049,7 @@ int main( #endif { app.startFullScreen(fullScreenWidth, fullScreenHeight, fullScreenBpp, fullScreenFrequency, - stereoWindow, stereomode, aasamples, (scene->gm.playerflag & GAME_PLAYER_DESKTOP_RESOLUTION)); + stereoWindow, stereomode, alphaBackground, aasamples, (scene->gm.playerflag & GAME_PLAYER_DESKTOP_RESOLUTION)); } } else @@ -1088,7 +1096,7 @@ int main( app.startEmbeddedWindow(title, parentWindow, stereoWindow, stereomode, aasamples); else app.startWindow(title, windowLeft, windowTop, windowWidth, windowHeight, - stereoWindow, stereomode, aasamples); + stereoWindow, stereomode, alphaBackground, aasamples); if (SYS_GetCommandLineInt(syshandle, "nomipmap", 0)) { GPU_set_mipmap(0); diff --git a/source/gameengine/Ketsji/BL_Shader.cpp b/source/gameengine/Ketsji/BL_Shader.cpp index 6613780a0f8..72815cadc70 100644 --- a/source/gameengine/Ketsji/BL_Shader.cpp +++ b/source/gameengine/Ketsji/BL_Shader.cpp @@ -32,6 +32,7 @@ #include "MT_Matrix4x4.h" #include "MT_Matrix3x3.h" #include "KX_PyMath.h" +#include "KX_PythonInit.h" #include "MEM_guardedalloc.h" #include "RAS_MeshObject.h" @@ -67,15 +68,16 @@ BL_Uniform::~BL_Uniform() #endif } -void BL_Uniform::Apply(class BL_Shader *shader) +bool BL_Uniform::Apply(class BL_Shader *shader) { #ifdef SORT_UNIFORMS + RAS_IRasterizer *ras; MT_assert(mType > UNI_NONE && mType < UNI_MAX && mData); - if (!mDirty) { - return; - } + if (!mDirty) + return false; + mDirty = false; switch (mType) { case UNI_FLOAT: { @@ -83,6 +85,15 @@ void BL_Uniform::Apply(class BL_Shader *shader) glUniform1fARB(mLoc, (GLfloat)*f); break; } + case UNI_FLOAT_EYE: + { + float *f = (float*)mData; + ras = KX_GetActiveEngine()->GetRasterizer(); + *f = (ras->GetEye() == RAS_IRasterizer::RAS_STEREO_LEFTEYE) ? 0.0f : 0.5f; + glUniform1fARB(mLoc, (GLfloat)*f); + mDirty = (ras->Stereo()) ? true : false; + break; + } case UNI_INT: { int *f = (int *)mData; @@ -138,7 +149,7 @@ void BL_Uniform::Apply(class BL_Shader *shader) break; } } - mDirty = false; + return mDirty; #endif } @@ -274,11 +285,10 @@ void BL_Shader::ApplyShader() return; } - for (unsigned int i = 0; i < mUniforms.size(); i++) { - mUniforms[i]->Apply(this); - } - mDirty = false; + for (unsigned int i=0; i<mUniforms.size(); i++) { + mDirty |= mUniforms[i]->Apply(this); + } #endif } @@ -314,64 +324,70 @@ bool BL_Shader::LinkProgram() return false; } - // -- vertex shader ------------------ - tmpVert = glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB); - glShaderSourceARB(tmpVert, 1, (const char **)&vertProg, 0); - glCompileShaderARB(tmpVert); - glGetObjectParameterivARB(tmpVert, GL_OBJECT_INFO_LOG_LENGTH_ARB, (GLint *)&vertlen); - - // print info if any - if (vertlen > 0 && vertlen < MAX_LOG_LEN) { - logInf = (char *)MEM_mallocN(vertlen, "vert-log"); - glGetInfoLogARB(tmpVert, vertlen, (GLsizei *)&char_len, logInf); - - if (char_len > 0) { - spit("---- Vertex Shader Error ----"); - spit(logInf); + if (vertProg[0] != 0) { + // -- vertex shader ------------------ + tmpVert = glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB); + glShaderSourceARB(tmpVert, 1, (const char**)&vertProg, 0); + glCompileShaderARB(tmpVert); + glGetObjectParameterivARB(tmpVert, GL_OBJECT_INFO_LOG_LENGTH_ARB, (GLint*)&vertlen); + + // print info if any + if (vertlen > 0 && vertlen < MAX_LOG_LEN) { + logInf = (char*)MEM_mallocN(vertlen, "vert-log"); + glGetInfoLogARB(tmpVert, vertlen, (GLsizei*)&char_len, logInf); + if (char_len > 0) { + spit("---- Vertex Shader Error ----"); + spit(logInf); + } + MEM_freeN(logInf); + logInf = 0; + } + // check for compile errors + glGetObjectParameterivARB(tmpVert, GL_OBJECT_COMPILE_STATUS_ARB, (GLint*)&vertstatus); + if (!vertstatus) { + spit("---- Vertex shader failed to compile ----"); + goto programError; } - - MEM_freeN(logInf); - logInf = 0; - } - - // check for compile errors - glGetObjectParameterivARB(tmpVert, GL_OBJECT_COMPILE_STATUS_ARB, (GLint *)&vertstatus); - if (!vertstatus) { - spit("---- Vertex shader failed to compile ----"); - goto programError; } - // -- fragment shader ---------------- - tmpFrag = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB); - glShaderSourceARB(tmpFrag, 1, (const char **)&fragProg, 0); - glCompileShaderARB(tmpFrag); - glGetObjectParameterivARB(tmpFrag, GL_OBJECT_INFO_LOG_LENGTH_ARB, (GLint *)&fraglen); - - if (fraglen > 0 && fraglen < MAX_LOG_LEN) { - logInf = (char *)MEM_mallocN(fraglen, "frag-log"); - glGetInfoLogARB(tmpFrag, fraglen, (GLsizei *)&char_len, logInf); - - if (char_len > 0) { - spit("---- Fragment Shader Error ----"); - spit(logInf); + if (fragProg[0] != 0) { + // -- fragment shader ---------------- + tmpFrag = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB); + glShaderSourceARB(tmpFrag, 1, (const char**)&fragProg, 0); + glCompileShaderARB(tmpFrag); + glGetObjectParameterivARB(tmpFrag, GL_OBJECT_INFO_LOG_LENGTH_ARB, (GLint*)&fraglen); + if (fraglen > 0 && fraglen < MAX_LOG_LEN) { + logInf = (char*)MEM_mallocN(fraglen, "frag-log"); + glGetInfoLogARB(tmpFrag, fraglen, (GLsizei*)&char_len, logInf); + if (char_len > 0) { + spit("---- Fragment Shader Error ----"); + spit(logInf); + } + MEM_freeN(logInf); + logInf = 0; } - MEM_freeN(logInf); - logInf = 0; + glGetObjectParameterivARB(tmpFrag, GL_OBJECT_COMPILE_STATUS_ARB, (GLint*)&fragstatus); + if (!fragstatus) { + spit("---- Fragment shader failed to compile ----"); + goto programError; + } } - - glGetObjectParameterivARB(tmpFrag, GL_OBJECT_COMPILE_STATUS_ARB, (GLint *)&fragstatus); - - if (!fragstatus) { - spit("---- Fragment shader failed to compile ----"); + + if (!tmpFrag && !tmpVert) { + spit("---- No shader given ----"); goto programError; } // -- program ------------------------ // set compiled vert/frag shader & link tmpProg = glCreateProgramObjectARB(); - glAttachObjectARB(tmpProg, tmpVert); - glAttachObjectARB(tmpProg, tmpFrag); + if (tmpVert) { + glAttachObjectARB(tmpProg, tmpVert); + } + if (tmpFrag) { + glAttachObjectARB(tmpProg, tmpFrag); + } glLinkProgramARB(tmpProg); glGetObjectParameterivARB(tmpProg, GL_OBJECT_INFO_LOG_LENGTH_ARB, (GLint *)&proglen); glGetObjectParameterivARB(tmpProg, GL_OBJECT_LINK_STATUS_ARB, (GLint *)&progstatus); @@ -396,8 +412,12 @@ bool BL_Shader::LinkProgram() // set mShader = tmpProg; - glDeleteObjectARB(tmpVert); - glDeleteObjectARB(tmpFrag); + if (tmpVert) { + glDeleteObjectARB(tmpVert); + } + if (tmpFrag) { + glDeleteObjectARB(tmpFrag); + } mOk = 1; mError = 0; return true; @@ -748,6 +768,7 @@ PyMethodDef BL_Shader::Methods[] = { KX_PYMETHODTABLE(BL_Shader, validate), // access functions KX_PYMETHODTABLE(BL_Shader, isValid), + KX_PYMETHODTABLE(BL_Shader, setUniformEyef), KX_PYMETHODTABLE(BL_Shader, setUniform1f), KX_PYMETHODTABLE(BL_Shader, setUniform2f), KX_PYMETHODTABLE(BL_Shader, setUniform3f), @@ -1019,6 +1040,27 @@ KX_PYMETHODDEF_DOC(BL_Shader, setUniform4f, "setUniform4f(name, fx,fy,fz, fw) ") return NULL; } +KX_PYMETHODDEF_DOC(BL_Shader, setUniformEyef, "setUniformEyef(name)") +{ + if (mError) { + Py_RETURN_NONE; + } + const char *uniform; + float value = 0.0f; + if (PyArg_ParseTuple(args, "s:setUniformEyef", &uniform)) { + int loc = GetUniformLocation(uniform); + if (loc != -1) { +#ifdef SORT_UNIFORMS + SetUniformfv(loc, BL_Uniform::UNI_FLOAT_EYE, &value, sizeof(float)); +#else + SetUniform(loc, (int)value); +#endif + } + Py_RETURN_NONE; + } + return NULL; +} + KX_PYMETHODDEF_DOC(BL_Shader, setUniform1i, "setUniform1i(name, ix)") { if (mError) { diff --git a/source/gameengine/Ketsji/BL_Shader.h b/source/gameengine/Ketsji/BL_Shader.h index aef4b42a85a..5de715d67d4 100644 --- a/source/gameengine/Ketsji/BL_Shader.h +++ b/source/gameengine/Ketsji/BL_Shader.h @@ -64,10 +64,11 @@ public: UNI_FLOAT4, UNI_MAT3, UNI_MAT4, + UNI_FLOAT_EYE, UNI_MAX }; - void Apply(class BL_Shader *shader); + bool Apply(class BL_Shader *shader); void SetData(int location, int type, bool transpose = false); int GetLocation() { return mLoc; } void *getData() { return mData; } @@ -226,6 +227,7 @@ public: KX_PYMETHOD_DOC(BL_Shader, setUniform3i); KX_PYMETHOD_DOC(BL_Shader, setUniform2i); KX_PYMETHOD_DOC(BL_Shader, setUniform1i); + KX_PYMETHOD_DOC(BL_Shader, setUniformEyef); KX_PYMETHOD_DOC(BL_Shader, setUniformfv); KX_PYMETHOD_DOC(BL_Shader, setUniformiv); KX_PYMETHOD_DOC(BL_Shader, setUniformMatrix4); diff --git a/source/gameengine/Ketsji/KX_Dome.cpp b/source/gameengine/Ketsji/KX_Dome.cpp index 6585b9dc831..d08372e47d4 100644 --- a/source/gameengine/Ketsji/KX_Dome.cpp +++ b/source/gameengine/Ketsji/KX_Dome.cpp @@ -1600,7 +1600,7 @@ void KX_Dome::RotateCamera(KX_Camera* cam, int i) MT_Transform camtrans(cam->GetWorldToCamera()); MT_Matrix4x4 viewmat(camtrans); - m_rasterizer->SetViewMatrix(viewmat, cam->NodeGetWorldOrientation(), cam->NodeGetWorldPosition(), cam->GetCameraData()->m_perspective); + m_rasterizer->SetViewMatrix(viewmat, cam->NodeGetWorldOrientation(), cam->NodeGetWorldPosition(), cam->NodeGetLocalScaling(), cam->GetCameraData()->m_perspective); cam->SetModelviewMatrix(viewmat); // restore the original orientation @@ -2035,7 +2035,7 @@ void KX_Dome::RenderDomeFrame(KX_Scene* scene, KX_Camera* cam, int i) MT_Transform camtrans(cam->GetWorldToCamera()); MT_Matrix4x4 viewmat(camtrans); - m_rasterizer->SetViewMatrix(viewmat, cam->NodeGetWorldOrientation(), cam->NodeGetWorldPosition(), 1.0f); + m_rasterizer->SetViewMatrix(viewmat, cam->NodeGetWorldOrientation(), cam->NodeGetWorldPosition(), cam->NodeGetLocalScaling(), 1.0f); cam->SetModelviewMatrix(viewmat); // restore the original orientation diff --git a/source/gameengine/Ketsji/KX_GameObject.cpp b/source/gameengine/Ketsji/KX_GameObject.cpp index 69c1af35bd9..3244400e1bd 100644 --- a/source/gameengine/Ketsji/KX_GameObject.cpp +++ b/source/gameengine/Ketsji/KX_GameObject.cpp @@ -142,7 +142,7 @@ KX_GameObject::~KX_GameObject() } // Unregister collision callbacks // Do this before we start freeing physics information like m_pClient_info - if (m_collisionCallbacks){ + if (m_collisionCallbacks) { UnregisterCollisionCallbacks(); Py_CLEAR(m_collisionCallbacks); } @@ -1564,7 +1564,7 @@ void KX_GameObject::UnregisterCollisionCallbacks() PHY_IPhysicsEnvironment* pe = scene->GetPhysicsEnvironment(); PHY_IPhysicsController* spc = GetPhysicsController(); // If we are the last to unregister on this physics controller - if (pe->RemoveCollisionCallback(spc)){ + if (pe->RemoveCollisionCallback(spc)) { // If we are a sensor object if (m_pClient_info->isSensor()) // Remove sensor body from physics world @@ -1584,7 +1584,7 @@ void KX_GameObject::RegisterCollisionCallbacks() PHY_IPhysicsEnvironment* pe = scene->GetPhysicsEnvironment(); PHY_IPhysicsController* spc = GetPhysicsController(); // If we are the first to register on this physics controller - if (pe->RequestCollisionCallback(spc)){ + if (pe->RequestCollisionCallback(spc)) { // If we are a sensor object if (m_pClient_info->isSensor()) // Add sensor body to physics world diff --git a/source/gameengine/Ketsji/KX_KetsjiEngine.cpp b/source/gameengine/Ketsji/KX_KetsjiEngine.cpp index 7237c473332..b0a8e376eb6 100644 --- a/source/gameengine/Ketsji/KX_KetsjiEngine.cpp +++ b/source/gameengine/Ketsji/KX_KetsjiEngine.cpp @@ -108,7 +108,7 @@ double KX_KetsjiEngine::m_suspendeddelta = 0.0; double KX_KetsjiEngine::m_average_framerate = 0.0; bool KX_KetsjiEngine::m_restrict_anim_fps = false; short KX_KetsjiEngine::m_exitkey = 130; // ESC Key - +bool KX_KetsjiEngine::m_doRender = true; /** * Constructor of the Ketsji Engine @@ -173,6 +173,7 @@ KX_KetsjiEngine::KX_KetsjiEngine(KX_ISystem* system) m_overrideFrameColorR(0.0f), m_overrideFrameColorG(0.0f), m_overrideFrameColorB(0.0f), + m_overrideFrameColorA(0.0f), m_usedome(false) { @@ -381,7 +382,7 @@ void KX_KetsjiEngine::RenderDome() m_overrideFrameColorR, m_overrideFrameColorG, m_overrideFrameColorB, - 1.0 + m_overrideFrameColorA ); } else @@ -749,6 +750,9 @@ bool KX_KetsjiEngine::NextFrame() scene->setSuspendedTime(m_clockTime); m_logger->StartLog(tc_services, m_kxsystem->GetTimeInSeconds(), true); + + // invalidates the shadow buffer from previous render/ImageRender because the scene has changed + scene->SetShadowDone(false); } // update system devices @@ -771,7 +775,7 @@ bool KX_KetsjiEngine::NextFrame() // Start logging time spent outside main loop m_logger->StartLog(tc_outside, m_kxsystem->GetTimeInSeconds(), true); - return doRender; + return doRender && m_doRender; } @@ -805,7 +809,7 @@ void KX_KetsjiEngine::Render() m_overrideFrameColorR, m_overrideFrameColorG, m_overrideFrameColorB, - 1.0 + m_overrideFrameColorA ); } else @@ -1133,6 +1137,8 @@ void KX_KetsjiEngine::RenderShadowBuffers(KX_Scene *scene) cam->Release(); } } + /* remember that we have a valid shadow buffer for that scene */ + scene->SetShadowDone(true); } // update graphics @@ -1252,7 +1258,7 @@ void KX_KetsjiEngine::RenderFrame(KX_Scene* scene, KX_Camera* cam) MT_Transform camtrans(cam->GetWorldToCamera()); MT_Matrix4x4 viewmat(camtrans); - m_rasterizer->SetViewMatrix(viewmat, cam->NodeGetWorldOrientation(), cam->NodeGetWorldPosition(), cam->GetCameraData()->m_perspective); + m_rasterizer->SetViewMatrix(viewmat, cam->NodeGetWorldOrientation(), cam->NodeGetWorldPosition(), cam->NodeGetLocalScaling(), cam->GetCameraData()->m_perspective); cam->SetModelviewMatrix(viewmat); // The following actually reschedules all vertices to be @@ -1925,6 +1931,16 @@ short KX_KetsjiEngine::GetExitKey() return m_exitkey; } +void KX_KetsjiEngine::SetRender(bool render) +{ + m_doRender = render; +} + +bool KX_KetsjiEngine::GetRender() +{ + return m_doRender; +} + void KX_KetsjiEngine::SetShowFramerate(bool frameRate) { m_show_framerate = frameRate; @@ -2023,19 +2039,21 @@ bool KX_KetsjiEngine::GetUseOverrideFrameColor(void) const } -void KX_KetsjiEngine::SetOverrideFrameColor(float r, float g, float b) +void KX_KetsjiEngine::SetOverrideFrameColor(float r, float g, float b, float a) { m_overrideFrameColorR = r; m_overrideFrameColorG = g; m_overrideFrameColorB = b; + m_overrideFrameColorA = a; } -void KX_KetsjiEngine::GetOverrideFrameColor(float& r, float& g, float& b) const +void KX_KetsjiEngine::GetOverrideFrameColor(float& r, float& g, float& b, float& a) const { r = m_overrideFrameColorR; g = m_overrideFrameColorG; b = m_overrideFrameColorB; + a = m_overrideFrameColorA; } diff --git a/source/gameengine/Ketsji/KX_KetsjiEngine.h b/source/gameengine/Ketsji/KX_KetsjiEngine.h index 3b8cec2ac82..1756214b6dd 100644 --- a/source/gameengine/Ketsji/KX_KetsjiEngine.h +++ b/source/gameengine/Ketsji/KX_KetsjiEngine.h @@ -129,6 +129,8 @@ private: static short m_exitkey; /* Key used to exit the BGE */ + static bool m_doRender; /* whether or not the scene should be rendered after the logic frame */ + int m_exitcode; STR_String m_exitstring; @@ -199,6 +201,8 @@ private: float m_overrideFrameColorG; /** Blue component of framing bar color. */ float m_overrideFrameColorB; + /** alpha component of framing bar color. */ + float m_overrideFrameColorA; /** Settings that doesn't go away with Game Actuator */ GlobalSettings m_globalsettings; @@ -209,7 +213,6 @@ private: void RenderFrame(KX_Scene* scene, KX_Camera* cam); void PostRenderScene(KX_Scene* scene); void RenderDebugProperties(); - void RenderShadowBuffers(KX_Scene *scene); public: KX_KetsjiEngine(class KX_ISystem* system); @@ -249,6 +252,7 @@ public: ///returns true if an update happened to indicate -> Render bool NextFrame(); void Render(); + void RenderShadowBuffers(KX_Scene *scene); void StartEngine(bool clearIpo); void StopEngine(); @@ -401,6 +405,16 @@ public: static short GetExitKey(); /** + * Activate or deactivates the render of the scene after the logic frame + * \param render true (render) or false (do not render) + */ + static void SetRender(bool render); + /** + * Get the current render flag value + */ + static bool GetRender(); + + /** * \Sets the display for frame rate on or off. */ void SetShowFramerate(bool frameRate); @@ -485,7 +499,7 @@ public: * \param g Green component of the override color. * \param b Blue component of the override color. */ - void SetOverrideFrameColor(float r, float g, float b); + void SetOverrideFrameColor(float r, float g, float b, float a); /** * Returns the color used for framing bar color instead of the one in the Blender file's scenes. @@ -493,7 +507,7 @@ public: * \param g Green component of the override color. * \param b Blue component of the override color. */ - void GetOverrideFrameColor(float& r, float& g, float& b) const; + void GetOverrideFrameColor(float& r, float& g, float& b, float& a) const; KX_Scene* CreateScene(const STR_String& scenename); KX_Scene* CreateScene(Scene *scene, bool libloading=false); diff --git a/source/gameengine/Ketsji/KX_Light.cpp b/source/gameengine/Ketsji/KX_Light.cpp index 9ccf60b15ce..5f490747c2b 100644 --- a/source/gameengine/Ketsji/KX_Light.cpp +++ b/source/gameengine/Ketsji/KX_Light.cpp @@ -195,7 +195,7 @@ int KX_LightObject::pyattr_set_layer(void *self_v, const KX_PYATTRIBUTE_DEF *att PyErr_Format(PyExc_TypeError, "expected an integer greater than 1 for attribute \"%s\"", attrdef->m_name); return PY_SET_ATTR_FAIL; } - else if(layer > MAX_LIGHT_LAYERS) { + else if (layer > MAX_LIGHT_LAYERS) { PyErr_Format(PyExc_TypeError, "expected an integer less than %i for attribute \"%s\"", MAX_LIGHT_LAYERS, attrdef->m_name); return PY_SET_ATTR_FAIL; } diff --git a/source/gameengine/Ketsji/KX_PythonInit.cpp b/source/gameengine/Ketsji/KX_PythonInit.cpp index 9f173a567ee..cdc2f9f3644 100644 --- a/source/gameengine/Ketsji/KX_PythonInit.cpp +++ b/source/gameengine/Ketsji/KX_PythonInit.cpp @@ -104,6 +104,7 @@ extern "C" { #include "BL_ArmatureObject.h" #include "RAS_IRasterizer.h" #include "RAS_ICanvas.h" +#include "RAS_IOffScreen.h" #include "RAS_BucketManager.h" #include "RAS_2DFilterManager.h" #include "MT_Vector3.h" @@ -469,6 +470,21 @@ static PyObject *gPyGetExitKey(PyObject *) return PyLong_FromLong(KX_KetsjiEngine::GetExitKey()); } +static PyObject *gPySetRender(PyObject *, PyObject *args) +{ + int render; + if (!PyArg_ParseTuple(args, "i:setRender", &render)) + return NULL; + KX_KetsjiEngine::SetRender(render); + Py_RETURN_NONE; +} + +static PyObject *gPyGetRender(PyObject *) +{ + return PyBool_FromLong(KX_KetsjiEngine::GetRender()); +} + + static PyObject *gPySetMaxLogicFrame(PyObject *, PyObject *args) { int frame; @@ -909,6 +925,8 @@ static struct PyMethodDef game_methods[] = { {"setAnimRecordFrame", (PyCFunction) gPySetAnimRecordFrame, METH_VARARGS, (const char *)"Sets the current frame number used for animation recording"}, {"getExitKey", (PyCFunction) gPyGetExitKey, METH_NOARGS, (const char *)"Gets the key used to exit the game engine"}, {"setExitKey", (PyCFunction) gPySetExitKey, METH_VARARGS, (const char *)"Sets the key used to exit the game engine"}, + {"setRender", (PyCFunction) gPySetRender, METH_VARARGS, (const char *)"Set the global render flag"}, + {"getRender", (PyCFunction) gPyGetRender, METH_NOARGS, (const char *)"get the global render flag value"}, {"getUseExternalClock", (PyCFunction) gPyGetUseExternalClock, METH_NOARGS, (const char *)"Get if we use the time provided by an external clock"}, {"setUseExternalClock", (PyCFunction) gPySetUseExternalClock, METH_VARARGS, (const char *)"Set if we use the time provided by an external clock"}, {"getClockTime", (PyCFunction) gPyGetClockTime, METH_NOARGS, (const char *)"Get the last BGE render time. " @@ -1457,6 +1475,158 @@ static PyObject *gPyGetDisplayDimensions(PyObject *) return result; } + +/* python wrapper around RAS_IOffScreen + * Should eventually gets its own file + */ + +static void PyRASOffScreen__tp_dealloc(PyRASOffScreen *self) +{ + if (self->ofs) + delete self->ofs; + Py_TYPE(self)->tp_free((PyObject *)self); +} + +PyDoc_STRVAR(py_RASOffScreen_doc, +"RASOffscreen(width, height) -> new GPU Offscreen object" +"initialized to hold a framebuffer object of ``width`` x ``height``.\n" +"" +); + +PyDoc_STRVAR(RASOffScreen_width_doc, "Offscreen buffer width.\n\n:type: integer"); +static PyObject *RASOffScreen_width_get(PyRASOffScreen *self, void *UNUSED(type)) +{ + return PyLong_FromLong(self->ofs->GetWidth()); +} + +PyDoc_STRVAR(RASOffScreen_height_doc, "Offscreen buffer height.\n\n:type: GLsizei"); +static PyObject *RASOffScreen_height_get(PyRASOffScreen *self, void *UNUSED(type)) +{ + return PyLong_FromLong(self->ofs->GetHeight()); +} + +PyDoc_STRVAR(RASOffScreen_color_doc, "Offscreen buffer texture object (if target is RAS_OFS_RENDER_TEXTURE).\n\n:type: GLuint"); +static PyObject *RASOffScreen_color_get(PyRASOffScreen *self, void *UNUSED(type)) +{ + return PyLong_FromLong(self->ofs->GetColor()); +} + +static PyGetSetDef RASOffScreen_getseters[] = { + {(char *)"width", (getter)RASOffScreen_width_get, (setter)NULL, RASOffScreen_width_doc, NULL}, + {(char *)"height", (getter)RASOffScreen_height_get, (setter)NULL, RASOffScreen_height_doc, NULL}, + {(char *)"color", (getter)RASOffScreen_color_get, (setter)NULL, RASOffScreen_color_doc, NULL}, + {NULL, NULL, NULL, NULL, NULL} /* Sentinel */ +}; + +static int PyRASOffScreen__tp_init(PyRASOffScreen *self, PyObject *args, PyObject *kwargs) +{ + int width, height, samples, target; + const char *keywords[] = {"width", "height", "samples", "target", NULL}; + + samples = 0; + target = RAS_IOffScreen::RAS_OFS_RENDER_BUFFER; + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ii|ii:RASOffscreen", (char **)keywords, &width, &height, &samples, &target)) { + return -1; + } + + if (width <= 0) { + PyErr_SetString(PyExc_ValueError, "negative 'width' given"); + return -1; + } + + if (height <= 0) { + PyErr_SetString(PyExc_ValueError, "negative 'height' given"); + return -1; + } + + if (samples < 0) { + PyErr_SetString(PyExc_ValueError, "negative 'samples' given"); + return -1; + } + + if (target != RAS_IOffScreen::RAS_OFS_RENDER_BUFFER && target != RAS_IOffScreen::RAS_OFS_RENDER_TEXTURE) + { + PyErr_SetString(PyExc_ValueError, "invalid 'target' given, can only be RAS_OFS_RENDER_BUFFER or RAS_OFS_RENDER_TEXTURE"); + return -1; + } + if (!gp_Rasterizer) + { + PyErr_SetString(PyExc_SystemError, "no rasterizer"); + return -1; + } + self->ofs = gp_Rasterizer->CreateOffScreen(width, height, samples, target); + if (!self->ofs) { + PyErr_SetString(PyExc_SystemError, "creation failed"); + return -1; + } + return 0; +} + +PyTypeObject PyRASOffScreen_Type = { + PyVarObject_HEAD_INIT(NULL, 0) + "RASOffScreen", /* tp_name */ + sizeof(PyRASOffScreen), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)PyRASOffScreen__tp_dealloc, /* tp_dealloc */ + NULL, /* tp_print */ + NULL, /* tp_getattr */ + NULL, /* tp_setattr */ + NULL, /* tp_compare */ + NULL, /* tp_repr */ + NULL, /* tp_as_number */ + NULL, /* tp_as_sequence */ + NULL, /* tp_as_mapping */ + NULL, /* tp_hash */ + NULL, /* tp_call */ + NULL, /* tp_str */ + NULL, /* tp_getattro */ + NULL, /* tp_setattro */ + NULL, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + py_RASOffScreen_doc, /* Documentation string */ + NULL, /* tp_traverse */ + NULL, /* tp_clear */ + NULL, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + NULL, /* tp_iter */ + NULL, /* tp_iternext */ + NULL, /* tp_methods */ + NULL, /* tp_members */ + RASOffScreen_getseters, /* tp_getset */ + NULL, /* tp_base */ + NULL, /* tp_dict */ + NULL, /* tp_descr_get */ + NULL, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)PyRASOffScreen__tp_init, /* tp_init */ + (allocfunc)PyType_GenericAlloc, /* tp_alloc */ + (newfunc)PyType_GenericNew, /* tp_new */ + (freefunc)0, /* tp_free */ + NULL, /* tp_is_gc */ + NULL, /* tp_bases */ + NULL, /* tp_mro */ + NULL, /* tp_cache */ + NULL, /* tp_subclasses */ + NULL, /* tp_weaklist */ + (destructor) NULL /* tp_del */ +}; + + +static PyObject *gPyOffScreenCreate(PyObject *UNUSED(self), PyObject *args) +{ + int width; + int height; + int samples; + int target; + + samples = 0; + if (!PyArg_ParseTuple(args, "ii|ii:offScreenCreate", &width, &height, &samples, &target)) + return NULL; + + return PyObject_CallObject((PyObject *) &PyRASOffScreen_Type, args); +} + PyDoc_STRVAR(Rasterizer_module_documentation, "This is the Python API for the game engine of Rasterizer" ); @@ -1511,6 +1681,7 @@ static struct PyMethodDef rasterizer_methods[] = { {"showProperties",(PyCFunction) gPyShowProperties, METH_VARARGS, "show or hide the debug properties"}, {"autoDebugList",(PyCFunction) gPyAutoDebugList, METH_VARARGS, "enable or disable auto adding debug properties to the debug list"}, {"clearDebugList",(PyCFunction) gPyClearDebugList, METH_NOARGS, "clears the debug property list"}, + {"offScreenCreate", (PyCFunction) gPyOffScreenCreate, METH_VARARGS, "create an offscreen buffer object, arguments are width and height in pixels"}, { NULL, (PyCFunction) NULL, 0, NULL } }; @@ -2330,6 +2501,8 @@ PyMODINIT_FUNC initRasterizerPythonBinding() PyObject *m; PyObject *d; + PyType_Ready(&PyRASOffScreen_Type); + m = PyModule_Create(&Rasterizer_module_def); PyDict_SetItemString(PySys_GetObject("modules"), Rasterizer_module_def.m_name, m); @@ -2357,6 +2530,11 @@ PyMODINIT_FUNC initRasterizerPythonBinding() KX_MACRO_addTypesToDict(d, LEFT_EYE, RAS_IRasterizer::RAS_STEREO_LEFTEYE); KX_MACRO_addTypesToDict(d, RIGHT_EYE, RAS_IRasterizer::RAS_STEREO_RIGHTEYE); + /* offscreen render */ + KX_MACRO_addTypesToDict(d, RAS_OFS_RENDER_BUFFER, RAS_IOffScreen::RAS_OFS_RENDER_BUFFER); + KX_MACRO_addTypesToDict(d, RAS_OFS_RENDER_TEXTURE, RAS_IOffScreen::RAS_OFS_RENDER_TEXTURE); + + // XXXX Add constants here // Check for errors diff --git a/source/gameengine/Ketsji/KX_Scene.cpp b/source/gameengine/Ketsji/KX_Scene.cpp index a5a418b5e78..c0d99d16a4c 100644 --- a/source/gameengine/Ketsji/KX_Scene.cpp +++ b/source/gameengine/Ketsji/KX_Scene.cpp @@ -172,6 +172,7 @@ KX_Scene::KX_Scene(class SCA_IInputDevice* keyboarddevice, m_activity_culling = false; m_suspend = false; m_isclearingZbuffer = true; + m_isShadowDone = false; m_tempObjectList = new CListValue(); m_objectlist = new CListValue(); m_parentlist = new CListValue(); @@ -1784,7 +1785,7 @@ void KX_Scene::UpdateObjectLods(void) for (int i = 0; i < this->GetObjectList()->GetCount(); i++) { gameobj = (KX_GameObject*) GetObjectList()->GetValue(i); - if (!gameobj->GetCulled()){ + if (!gameobj->GetCulled()) { gameobj->UpdateLod(cam_pos); } } diff --git a/source/gameengine/Ketsji/KX_Scene.h b/source/gameengine/Ketsji/KX_Scene.h index c43b7be45dc..6d8ae8a321b 100644 --- a/source/gameengine/Ketsji/KX_Scene.h +++ b/source/gameengine/Ketsji/KX_Scene.h @@ -172,6 +172,11 @@ protected: bool m_isclearingZbuffer; /** + * Does the shadow buffer needs calculing + */ + bool m_isShadowDone; + + /** * The name of the scene */ STR_String m_sceneName; @@ -572,6 +577,8 @@ public: bool IsSuspended(); bool IsClearingZBuffer(); void EnableZBufferClearing(bool isclearingZbuffer); + bool IsShadowDone() { return m_isShadowDone; } + void SetShadowDone(bool b) { m_isShadowDone = b; } // use of DBVT tree for camera culling void SetDbvtCulling(bool b) { m_dbvt_culling = b; } bool GetDbvtCulling() { return m_dbvt_culling; } diff --git a/source/gameengine/Ketsji/KX_SoundActuator.cpp b/source/gameengine/Ketsji/KX_SoundActuator.cpp index 1c42d65ae75..a27f37c0441 100644 --- a/source/gameengine/Ketsji/KX_SoundActuator.cpp +++ b/source/gameengine/Ketsji/KX_SoundActuator.cpp @@ -79,21 +79,18 @@ KX_SoundActuator::KX_SoundActuator(SCA_IObject* gameobj, KX_SoundActuator::~KX_SoundActuator() { - if(m_handle) - { + if (m_handle) { AUD_Handle_stop(m_handle); } - if(m_sound) - { + if (m_sound) { AUD_Sound_free(m_sound); } } void KX_SoundActuator::play() { - if(m_handle) - { + if (m_handle) { AUD_Handle_stop(m_handle); m_handle = NULL; } @@ -130,10 +127,8 @@ void KX_SoundActuator::play() if(sound != m_sound) AUD_Sound_free(sound); - if (m_handle != NULL) - { - if (m_is3d) - { + if (m_handle != NULL) { + if (m_is3d) { AUD_Handle_setRelative(m_handle, true); AUD_Handle_setVolumeMaximum(m_handle, m_3d.max_gain); AUD_Handle_setVolumeMinimum(m_handle, m_3d.min_gain); diff --git a/source/gameengine/Ketsji/KX_TrackToActuator.cpp b/source/gameengine/Ketsji/KX_TrackToActuator.cpp index beccdfaad93..a8fa9b0815d 100644 --- a/source/gameengine/Ketsji/KX_TrackToActuator.cpp +++ b/source/gameengine/Ketsji/KX_TrackToActuator.cpp @@ -207,7 +207,7 @@ static MT_Matrix3x3 vectomat(MT_Vector3 vec, short axis, short upflag, short thr vec = vec.safe_normalized_vec(z); /* if 2D doesn't move the up vector */ - if (!threedimup){ + if (!threedimup) { vec.setValue(MT_Scalar(vec[0]), MT_Scalar(vec[1]), MT_Scalar(0.0f)); vec = (vec - z.dot(vec)*z).safe_normalized_vec(z); } diff --git a/source/gameengine/Ketsji/KX_VehicleWrapper.cpp b/source/gameengine/Ketsji/KX_VehicleWrapper.cpp index c1af6de127e..ddae645802c 100644 --- a/source/gameengine/Ketsji/KX_VehicleWrapper.cpp +++ b/source/gameengine/Ketsji/KX_VehicleWrapper.cpp @@ -89,17 +89,17 @@ PyObject *KX_VehicleWrapper::PyAddWheel(PyObject *args) if (gameOb->GetSGNode()) { MT_Vector3 attachPos,attachDir,attachAxle; - if(!PyVecTo(pylistPos,attachPos)) { + if (!PyVecTo(pylistPos,attachPos)) { PyErr_SetString(PyExc_AttributeError, "addWheel(...) Unable to add wheel. attachPos must be a vector with 3 elements."); return NULL; } - if(!PyVecTo(pylistDir,attachDir)) { + if (!PyVecTo(pylistDir,attachDir)) { PyErr_SetString(PyExc_AttributeError, "addWheel(...) Unable to add wheel. downDir must be a vector with 3 elements."); return NULL; } - if(!PyVecTo(pylistAxleDir,attachAxle)) { + if (!PyVecTo(pylistAxleDir,attachAxle)) { PyErr_SetString(PyExc_AttributeError, "addWheel(...) Unable to add wheel. axleDir must be a vector with 3 elements."); return NULL; @@ -108,7 +108,7 @@ PyObject *KX_VehicleWrapper::PyAddWheel(PyObject *args) //someone reverse some conventions inside Bullet (axle winding) attachAxle = -attachAxle; - if(wheelRadius<=0) { + if (wheelRadius <= 0) { PyErr_SetString(PyExc_AttributeError, "addWheel(...) Unable to add wheel. wheelRadius must be positive."); return NULL; diff --git a/source/gameengine/Physics/Bullet/CcdPhysicsController.h b/source/gameengine/Physics/Bullet/CcdPhysicsController.h index 58ea5e2e390..831e7346df7 100644 --- a/source/gameengine/Physics/Bullet/CcdPhysicsController.h +++ b/source/gameengine/Physics/Bullet/CcdPhysicsController.h @@ -430,7 +430,7 @@ public: // PHY_ICharacter interface virtual void Jump() { jump(); } - virtual bool OnGround(){ return onGround(); } + virtual bool OnGround() { return onGround(); } virtual float GetGravity() { return getGravity(); } virtual void SetGravity(float gravity) { setGravity(gravity); } virtual unsigned char GetMaxJumps() { return getMaxJumps(); } @@ -542,14 +542,14 @@ protected: CcdPhysicsController (const CcdConstructionInfo& ci); /** - * Delete the current Bullet shape used in the rigid body. - */ + * Delete the current Bullet shape used in the rigid body. + */ bool DeleteControllerShape(); /** - * Delete the old Bullet shape and set the new Bullet shape : newShape - * \param newShape The new Bullet shape to set, if is NULL we create a new Bullet shape - */ + * Delete the old Bullet shape and set the new Bullet shape : newShape + * \param newShape The new Bullet shape to set, if is NULL we create a new Bullet shape + */ bool ReplaceControllerShape(btCollisionShape *newShape); virtual ~CcdPhysicsController(); diff --git a/source/gameengine/Physics/common/PHY_ICharacter.h b/source/gameengine/Physics/common/PHY_ICharacter.h index 81c567ef08a..1a924904b7d 100644 --- a/source/gameengine/Physics/common/PHY_ICharacter.h +++ b/source/gameengine/Physics/common/PHY_ICharacter.h @@ -15,7 +15,7 @@ class PHY_ICharacter { public: - virtual ~PHY_ICharacter(){}; + virtual ~PHY_ICharacter() {}; virtual void Jump()= 0; virtual bool OnGround()= 0; diff --git a/source/gameengine/Physics/common/PHY_IController.h b/source/gameengine/Physics/common/PHY_IController.h index 284d77ca221..741fae8d2ad 100644 --- a/source/gameengine/Physics/common/PHY_IController.h +++ b/source/gameengine/Physics/common/PHY_IController.h @@ -48,7 +48,7 @@ class PHY_IPhysicsEnvironment; class PHY_IController { public: - virtual ~PHY_IController(){}; + virtual ~PHY_IController() {}; // clientinfo for raycasts for example virtual void* GetNewClientInfo()=0; virtual void SetNewClientInfo(void* clientinfo)=0; diff --git a/source/gameengine/Physics/common/PHY_IMotionState.h b/source/gameengine/Physics/common/PHY_IMotionState.h index d40b8da9451..e803d658713 100644 --- a/source/gameengine/Physics/common/PHY_IMotionState.h +++ b/source/gameengine/Physics/common/PHY_IMotionState.h @@ -44,7 +44,7 @@ class PHY_IMotionState { public: - virtual ~PHY_IMotionState(){}; + virtual ~PHY_IMotionState() {}; virtual void GetWorldPosition(float& posX,float& posY,float& posZ)=0; virtual void GetWorldScaling(float& scaleX,float& scaleY,float& scaleZ)=0; diff --git a/source/gameengine/Physics/common/PHY_IPhysicsController.h b/source/gameengine/Physics/common/PHY_IPhysicsController.h index 62b163536dd..4c6e8c71ef7 100644 --- a/source/gameengine/Physics/common/PHY_IPhysicsController.h +++ b/source/gameengine/Physics/common/PHY_IPhysicsController.h @@ -53,7 +53,7 @@ class PHY_IPhysicsController : public PHY_IController { public: - virtual ~PHY_IPhysicsController(){}; + virtual ~PHY_IPhysicsController() {}; /** * SynchronizeMotionStates ynchronizes dynas, kinematic and deformable entities (and do 'late binding') */ diff --git a/source/gameengine/Physics/common/PHY_IPhysicsEnvironment.h b/source/gameengine/Physics/common/PHY_IPhysicsEnvironment.h index 2997048805f..72ec7b1edd0 100644 --- a/source/gameengine/Physics/common/PHY_IPhysicsEnvironment.h +++ b/source/gameengine/Physics/common/PHY_IPhysicsEnvironment.h @@ -116,7 +116,7 @@ public: class PHY_IPhysicsEnvironment { public: - virtual ~PHY_IPhysicsEnvironment(){} + virtual ~PHY_IPhysicsEnvironment() {} virtual void BeginFrame() = 0; virtual void EndFrame() = 0; /// Perform an integration step of duration 'timeStep'. diff --git a/source/gameengine/Physics/common/PHY_IVehicle.h b/source/gameengine/Physics/common/PHY_IVehicle.h index 1dcec69a335..7e4a49e923e 100644 --- a/source/gameengine/Physics/common/PHY_IVehicle.h +++ b/source/gameengine/Physics/common/PHY_IVehicle.h @@ -18,7 +18,7 @@ class PHY_IMotionState; class PHY_IVehicle { public: - virtual ~PHY_IVehicle(){}; + virtual ~PHY_IVehicle() {}; virtual void AddWheel( PHY_IMotionState* motionState, diff --git a/source/gameengine/Rasterizer/CMakeLists.txt b/source/gameengine/Rasterizer/CMakeLists.txt index 496a864244b..c65fcac5161 100644 --- a/source/gameengine/Rasterizer/CMakeLists.txt +++ b/source/gameengine/Rasterizer/CMakeLists.txt @@ -65,6 +65,8 @@ set(SRC RAS_IPolygonMaterial.h RAS_IRasterizer.h RAS_ILightObject.h + RAS_IOffScreen.h + RAS_ISync.h RAS_MaterialBucket.h RAS_MeshObject.h RAS_ObjectColor.h diff --git a/source/gameengine/Rasterizer/RAS_IOffScreen.h b/source/gameengine/Rasterizer/RAS_IOffScreen.h new file mode 100644 index 00000000000..d61a31504b8 --- /dev/null +++ b/source/gameengine/Rasterizer/RAS_IOffScreen.h @@ -0,0 +1,84 @@ +/* + * ***** 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. + * + * The Original Code is Copyright (C) 2015, Blender Foundation + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Blender Foundation. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file RAS_IOffScreen.h + * \ingroup bgerast + */ + +#ifndef __RAS_OFFSCREEN_H__ +#define __RAS_OFFSCREEN_H__ + +#include "EXP_Python.h" + +class RAS_ICanvas; + +class MT_Transform; + +struct Image; + +class RAS_IOffScreen +{ +public: + enum RAS_OFS_BIND_MODE { + RAS_OFS_BIND_RENDER = 0, + RAS_OFS_BIND_READ, + }; + enum RAS_OFS_RENDER_TARGET { + RAS_OFS_RENDER_BUFFER = 0, // use render buffer as render target + RAS_OFS_RENDER_TEXTURE, // use texture as render target + }; + + int m_width; + int m_height; + int m_samples; + int m_color; // if used, holds the texture object, 0 if not used + + virtual ~RAS_IOffScreen() {} + + virtual bool Create(int width, int height, int samples, RAS_OFS_RENDER_TARGET target) = 0; + virtual void Destroy() = 0; + virtual void Bind(RAS_OFS_BIND_MODE mode) = 0; + virtual void Blit() = 0; + virtual void Unbind() = 0; + virtual void MipMap() = 0; + + virtual int GetWidth() { return m_width; } + virtual int GetHeight() { return m_height; } + virtual int GetSamples() { return m_samples; } + virtual int GetColor() { return m_color; } +}; + +#ifdef WITH_PYTHON +typedef struct { + PyObject_HEAD + RAS_IOffScreen *ofs; +} PyRASOffScreen; + +extern PyTypeObject PyRASOffScreen_Type; +#endif + +#endif /* __RAS_OFFSCREEN_H__ */ diff --git a/source/gameengine/Rasterizer/RAS_IRasterizer.h b/source/gameengine/Rasterizer/RAS_IRasterizer.h index a92b87773c7..dc92408915b 100644 --- a/source/gameengine/Rasterizer/RAS_IRasterizer.h +++ b/source/gameengine/Rasterizer/RAS_IRasterizer.h @@ -55,6 +55,8 @@ class RAS_IPolyMaterial; class RAS_MeshSlot; class RAS_ILightObject; class SCA_IScene; +class RAS_IOffScreen; +class RAS_ISync; typedef vector<unsigned short> KX_IndexArray; typedef vector<RAS_TexVert> KX_VertexArray; @@ -258,6 +260,18 @@ public: virtual float GetFocalLength() = 0; /** + * Create an offscreen render buffer that can be used as target for render. + * For the time being, it is only used in VideoTexture for custom render. + */ + virtual RAS_IOffScreen *CreateOffScreen(int width, int height, int samples, int target) = 0; + + /** + * Create a sync object + * For use with offscreen render + */ + virtual RAS_ISync *CreateSync(int type) = 0; + + /** * SwapBuffers swaps the back buffer with the front buffer. */ virtual void SwapBuffers() = 0; @@ -287,7 +301,7 @@ public: * Sets the modelview matrix. */ virtual void SetViewMatrix(const MT_Matrix4x4 &mat, const MT_Matrix3x3 &ori, - const MT_Point3 &pos, bool perspective) = 0; + const MT_Point3 &pos, const MT_Vector3 &scale, bool perspective) = 0; /** */ diff --git a/source/gameengine/Rasterizer/RAS_ISync.h b/source/gameengine/Rasterizer/RAS_ISync.h new file mode 100644 index 00000000000..7e34172c2a3 --- /dev/null +++ b/source/gameengine/Rasterizer/RAS_ISync.h @@ -0,0 +1,48 @@ +/* + * ***** 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. + * + * The Original Code is Copyright (C) 2015, Blender Foundation + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Blender Foundation. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file RAS_ISync.h + * \ingroup bgerast + */ + +#ifndef __RAS_ISYNC_H__ +#define __RAS_ISYNC_H__ + +class RAS_ISync +{ +public: + enum RAS_SYNC_TYPE { + RAS_SYNC_TYPE_FENCE = 0, + }; + virtual ~RAS_ISync() {} + + virtual bool Create(RAS_SYNC_TYPE type) = 0; + virtual void Destroy() = 0; + virtual void Wait() = 0; +}; + +#endif /* __RAS_ISYNC_H__ */ diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/CMakeLists.txt b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/CMakeLists.txt index 9f95e2c82af..89e31b62b41 100644 --- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/CMakeLists.txt +++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/CMakeLists.txt @@ -51,6 +51,8 @@ set(INC_SYS set(SRC RAS_ListRasterizer.cpp RAS_OpenGLLight.cpp + RAS_OpenGLOffScreen.cpp + RAS_OpenGLSync.cpp RAS_OpenGLRasterizer.cpp RAS_StorageVA.cpp RAS_StorageVBO.cpp @@ -58,6 +60,8 @@ set(SRC RAS_IStorage.h RAS_ListRasterizer.h RAS_OpenGLLight.h + RAS_OpenGLOffScreen.h + RAS_OpenGLSync.h RAS_OpenGLRasterizer.h RAS_StorageVA.h RAS_StorageVBO.h diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLLight.cpp b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLLight.cpp index 6f6513b001a..9190e8f2338 100644 --- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLLight.cpp +++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLLight.cpp @@ -242,7 +242,7 @@ void RAS_OpenGLLight::BindShadowBuffer(RAS_ICanvas *canvas, KX_Camera *cam, MT_T RAS_IRasterizer::StereoMode stereomode = m_rasterizer->GetStereoMode(); m_rasterizer->SetStereoMode(RAS_IRasterizer::RAS_STEREO_NOSTEREO); m_rasterizer->SetProjectionMatrix(projectionmat); - m_rasterizer->SetViewMatrix(modelviewmat, cam->NodeGetWorldOrientation(), cam->NodeGetWorldPosition(), cam->GetCameraData()->m_perspective); + m_rasterizer->SetViewMatrix(modelviewmat, cam->NodeGetWorldOrientation(), cam->NodeGetWorldPosition(), cam->NodeGetLocalScaling(), cam->GetCameraData()->m_perspective); m_rasterizer->SetStereoMode(stereomode); } diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLOffScreen.cpp b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLOffScreen.cpp new file mode 100644 index 00000000000..e589bffcaf1 --- /dev/null +++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLOffScreen.cpp @@ -0,0 +1,347 @@ +/* + * ***** 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. + * + * The Original Code is Copyright (C) 2015, Blender Foundation + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Blender Foundation. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "glew-mx.h" + +#include <stdio.h> + +#include "RAS_OpenGLOffScreen.h" +#include "RAS_ICanvas.h" + +RAS_OpenGLOffScreen::RAS_OpenGLOffScreen(RAS_ICanvas *canvas) + :m_canvas(canvas), m_depthrb(0), m_colorrb(0), m_depthtx(0), m_colortx(0), + m_fbo(0), m_blitfbo(0), m_blitrbo(0), m_blittex(0), m_target(RAS_OFS_RENDER_BUFFER), m_bound(false) +{ + m_width = 0; + m_height = 0; + m_samples = 0; + m_color = 0; +} + +RAS_OpenGLOffScreen::~RAS_OpenGLOffScreen() +{ + Destroy(); +} + +bool RAS_OpenGLOffScreen::Create(int width, int height, int samples, RAS_OFS_RENDER_TARGET target) +{ + GLenum status; + GLuint glo[2], fbo; + GLint max_samples; + GLenum textarget; + + if (m_fbo) { + printf("RAS_OpenGLOffScreen::Create(): buffer exists already, destroy first\n"); + return false; + } + if (target != RAS_IOffScreen::RAS_OFS_RENDER_BUFFER && + target != RAS_IOffScreen::RAS_OFS_RENDER_TEXTURE) + { + printf("RAS_OpenGLOffScreen::Create(): invalid offscren target\n"); + return false; + } + if (!GLEW_EXT_framebuffer_object) { + printf("RAS_OpenGLOffScreen::Create(): frame buffer not supported\n"); + return false; + } + if (samples) { + if (!GLEW_EXT_framebuffer_multisample || + !GLEW_EXT_framebuffer_blit) + { + samples = 0; + } + } + if (samples && target == RAS_OFS_RENDER_TEXTURE) { + // we need this in addition if we use multisample textures + if (!GLEW_ARB_texture_multisample || + !GLEW_EXT_framebuffer_multisample_blit_scaled) + { + samples = 0; + } + } + if (samples) { + max_samples = 0; + glGetIntegerv(GL_MAX_SAMPLES_EXT , &max_samples); + if (samples > max_samples) + samples = max_samples; + } + m_target = target; + fbo = 0; + glGenFramebuffersEXT(1, &fbo); + if (fbo == 0) { + printf("RAS_OpenGLOffScreen::Create(): frame buffer creation failed: %d\n", (int)glGetError()); + return false; + } + m_fbo = fbo; + glo[0] = glo[1] = 0; + if (target == RAS_OFS_RENDER_TEXTURE) { + glGenTextures(2, glo); + if (glo[0] == 0 || glo[1] == 0) { + printf("RAS_OpenGLOffScreen::Create(): texture creation failed: %d\n", (int)glGetError()); + goto L_ERROR; + } + m_depthtx = glo[0]; + m_color = m_colortx = glo[1]; + if (samples) { + textarget = GL_TEXTURE_2D_MULTISAMPLE; + glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, m_depthtx); + glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, samples, GL_DEPTH_COMPONENT, width, height, true); + glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, m_colortx); + glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, samples, GL_RGBA8, width, height, true); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, 0); + } + else { + textarget = GL_TEXTURE_2D; + glBindTexture(GL_TEXTURE_2D, m_depthtx); + glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, width, height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL); + glBindTexture(GL_TEXTURE_2D, m_colortx); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + glBindTexture(GL_TEXTURE_2D, 0); + } + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fbo); + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, textarget, m_depthtx, 0); + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, textarget, m_colortx, 0); + } + else { + glGenRenderbuffersEXT(2, glo); + if (glo[0] == 0 || glo[1] == 0) { + printf("RAS_OpenGLOffScreen::Create(): render buffer creation failed: %d\n", (int)glGetError()); + goto L_ERROR; + } + m_depthrb = glo[0]; + m_colorrb = glo[1]; + glBindRenderbufferEXT(GL_RENDERBUFFER, m_depthrb); + glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER, samples, GL_DEPTH_COMPONENT, width, height); + glBindRenderbufferEXT(GL_RENDERBUFFER, m_colorrb); + glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER, samples, GL_RGBA8, width, height); + glBindRenderbufferEXT(GL_RENDERBUFFER, 0); + + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fbo); + glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER, m_depthrb); + glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER, m_colorrb); + } + status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + + if (status != GL_FRAMEBUFFER_COMPLETE_EXT) { + printf("RAS_OpenGLOffScreen::Create(): frame buffer incomplete: %d\n", (int)status); + goto L_ERROR; + } + m_width = width; + m_height = height; + + if (samples > 0) { + GLuint blit_tex; + GLuint blit_fbo; + // create a secondary FBO to blit to before the pixel can be read + + /* write into new single-sample buffer */ + glGenFramebuffersEXT(1, &blit_fbo); + if (!blit_fbo) { + printf("RAS_OpenGLOffScreen::Create(): failed creating a FBO for multi-sample offscreen buffer\n"); + goto L_ERROR; + } + m_blitfbo = blit_fbo; + blit_tex = 0; + if (target == RAS_OFS_RENDER_TEXTURE) { + glGenTextures(1, &blit_tex); + if (!blit_tex) { + printf("RAS_OpenGLOffScreen::Create(): failed creating a texture for multi-sample offscreen buffer\n"); + goto L_ERROR; + } + // m_color is the texture where the final render goes, the blit texture in this case + m_color = m_blittex = blit_tex; + glBindTexture(GL_TEXTURE_2D, m_blittex); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glBindTexture(GL_TEXTURE_2D, 0); + glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, m_blitfbo); + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, m_blittex, 0); + } + else { + /* create render buffer for new 'fbo_blit' */ + glGenRenderbuffersEXT(1, &blit_tex); + if (!blit_tex) { + printf("RAS_OpenGLOffScreen::Create(): failed creating a render buffer for multi-sample offscreen buffer\n"); + goto L_ERROR; + } + m_blitrbo = blit_tex; + glBindRenderbufferEXT(GL_RENDERBUFFER, m_blitrbo); + glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER, 0, GL_RGBA8, width, height); + glBindRenderbufferEXT(GL_RENDERBUFFER, 0); + glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, m_blitfbo); + glFramebufferRenderbufferEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER, m_blitrbo); + } + status = glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER_EXT); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, 0); + if (status != GL_FRAMEBUFFER_COMPLETE) { + printf("RAS_OpenGLOffScreen::Create(): frame buffer for multi-sample offscreen buffer incomplete: %d\n", (int)status); + goto L_ERROR; + } + // remember that multisample is enabled + m_samples = 1; + } + return true; + +L_ERROR: + Destroy(); + return false; +} + +void RAS_OpenGLOffScreen::Destroy() +{ + GLuint globj; + Unbind(); + if (m_fbo) { + globj = m_fbo; + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fbo); + if (m_target == RAS_OFS_RENDER_TEXTURE) { + GLenum textarget = (m_samples) ? GL_TEXTURE_2D_MULTISAMPLE : GL_TEXTURE_2D; + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, textarget, 0, 0); + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, textarget, 0, 0); + } + else { + glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0); + glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, 0); + } + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + glDeleteFramebuffersEXT(1, &globj); + m_fbo = 0; + } + if (m_depthrb) { + globj = m_depthrb; + glDeleteRenderbuffers(1, &globj); + m_depthrb = 0; + } + if (m_colorrb) { + globj = m_colorrb; + glDeleteRenderbuffers(1, &globj); + m_colorrb = 0; + } + if (m_depthtx) { + globj = m_depthtx; + glDeleteTextures(1, &globj); + m_depthtx = 0; + } + if (m_colortx) { + globj = m_colortx; + glDeleteTextures(1, &globj); + m_colortx = 0; + } + if (m_blitfbo) { + globj = m_blitfbo; + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_blitfbo); + if (m_target == RAS_OFS_RENDER_TEXTURE) { + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, 0, 0); + } + else { + glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, 0); + } + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + glDeleteFramebuffersEXT(1, &globj); + m_blitfbo = 0; + } + if (m_blitrbo) { + globj = m_blitrbo; + glDeleteRenderbuffers(1, &globj); + m_blitrbo = 0; + } + if (m_blittex) { + globj = m_blittex; + glDeleteTextures(1, &globj); + m_blittex = 0; + } + m_width = 0; + m_height = 0; + m_samples = 0; + m_color = 0; + m_target = RAS_OFS_RENDER_BUFFER; +} + +void RAS_OpenGLOffScreen::Bind(RAS_OFS_BIND_MODE mode) +{ + if (m_fbo) { + if (mode == RAS_OFS_BIND_RENDER) { + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fbo); + glReadBuffer(GL_COLOR_ATTACHMENT0_EXT); + glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT); + glViewport(0, 0, m_width, m_height); + glDisable(GL_SCISSOR_TEST); + } + else if (!m_blitfbo) { + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fbo); + glReadBuffer(GL_COLOR_ATTACHMENT0_EXT); + } + else { + glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, m_blitfbo); + glReadBuffer(GL_COLOR_ATTACHMENT0_EXT); + } + m_bound = true; + } +} + +void RAS_OpenGLOffScreen::Unbind() +{ + if (!m_bound) + return; + + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + glEnable(GL_SCISSOR_TEST); + glReadBuffer(GL_BACK); + glDrawBuffer(GL_BACK); + m_bound = false; +} + +void RAS_OpenGLOffScreen::MipMap() +{ + if (m_color) { + glBindTexture(GL_TEXTURE_2D, m_color); + glGenerateMipmap(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, 0); + } +} + +void RAS_OpenGLOffScreen::Blit() +{ + if (m_bound && m_blitfbo) { + // set the draw target to the secondary FBO, the read target is still the multisample FBO + glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER, m_blitfbo); + + // sample the primary + glBlitFramebufferEXT(0, 0, m_width, m_height, 0, 0, m_width, m_height, GL_COLOR_BUFFER_BIT, GL_NEAREST); + + // make sure the next glReadPixels will read from the secondary buffer + glBindFramebufferEXT(GL_READ_FRAMEBUFFER, m_blitfbo); + } +} diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLOffScreen.h b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLOffScreen.h new file mode 100644 index 00000000000..3f6845f1e21 --- /dev/null +++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLOffScreen.h @@ -0,0 +1,65 @@ +/* + * ***** 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. + * + * The Original Code is Copyright (C) 2015, Blender Foundation + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Blender Foundation. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef __RAS_OPENGLOFFSCREEN__ +#define __RAS_OPENGLOFFSCREEN__ + +#include "RAS_IOffScreen.h" +#include "GPU_extensions.h" + +class RAS_ICanvas; + +class RAS_OpenGLOffScreen : public RAS_IOffScreen +{ + RAS_ICanvas *m_canvas; + // these are GL objects + unsigned int m_depthrb; + unsigned int m_colorrb; + unsigned int m_depthtx; + unsigned int m_colortx; + unsigned int m_fbo; + unsigned int m_blitfbo; + unsigned int m_blitrbo; + unsigned int m_blittex; + RAS_OFS_RENDER_TARGET m_target; + bool m_bound; + + +public: + RAS_OpenGLOffScreen(RAS_ICanvas *canvas); + ~RAS_OpenGLOffScreen(); + + bool Create(int width, int height, int samples, RAS_OFS_RENDER_TARGET target); + void Destroy(); + void Bind(RAS_OFS_BIND_MODE mode); + void Blit(); + void Unbind(); + void MipMap(); +}; + +#endif /* __RAS_OPENGLOFFSCREEN__ */ + diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp index ec6489ee13a..66c2fde908b 100644 --- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp +++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp @@ -46,6 +46,8 @@ #include "MT_CmMatrix4x4.h" #include "RAS_OpenGLLight.h" +#include "RAS_OpenGLOffScreen.h" +#include "RAS_OpenGLSync.h" #include "RAS_StorageVA.h" #include "RAS_StorageVBO.h" @@ -92,6 +94,7 @@ RAS_OpenGLRasterizer::RAS_OpenGLRasterizer(RAS_ICanvas* canvas, RAS_STORAGE_TYPE m_time(0.0f), m_campos(0.0f, 0.0f, 0.0f), m_camortho(false), + m_camnegscale(false), m_stereomode(RAS_STEREO_NOSTEREO), m_curreye(RAS_STEREO_LEFTEYE), m_eyeseparation(0.0f), @@ -138,8 +141,6 @@ RAS_OpenGLRasterizer::RAS_OpenGLRasterizer(RAS_ICanvas* canvas, RAS_STORAGE_TYPE glGetIntegerv(GL_MAX_LIGHTS, (GLint *) &m_numgllights); if (m_numgllights < 8) m_numgllights = 8; - - PrintHardwareInfo(); } @@ -207,7 +208,7 @@ void RAS_OpenGLRasterizer::SetBackColor(float color[3]) m_redback = color[0]; m_greenback = color[1]; m_blueback = color[2]; - m_alphaback = 1.0f; + m_alphaback = 0.0f; } void RAS_OpenGLRasterizer::SetFog(short type, float start, float dist, float intensity, float color[3]) @@ -600,6 +601,31 @@ float RAS_OpenGLRasterizer::GetFocalLength() return m_focallength; } +RAS_IOffScreen *RAS_OpenGLRasterizer::CreateOffScreen(int width, int height, int samples, int target) +{ + RAS_IOffScreen *ofs; + + ofs = new RAS_OpenGLOffScreen(m_2DCanvas); + + if (!ofs->Create(width, height, samples, (RAS_IOffScreen::RAS_OFS_RENDER_TARGET)target)) { + delete ofs; + return NULL; + } + return ofs; +} + +RAS_ISync *RAS_OpenGLRasterizer::CreateSync(int type) +{ + RAS_ISync *sync; + + sync = new RAS_OpenGLSync(); + + if (!sync->Create((RAS_ISync::RAS_SYNC_TYPE)type)) { + delete sync; + return NULL; + } + return sync; +} void RAS_OpenGLRasterizer::SwapBuffers() { @@ -924,6 +950,7 @@ MT_Matrix4x4 RAS_OpenGLRasterizer::GetOrthoMatrix( void RAS_OpenGLRasterizer::SetViewMatrix(const MT_Matrix4x4 &mat, const MT_Matrix3x3 & camOrientMat3x3, const MT_Point3 & pos, + const MT_Vector3 &scale, bool perspective) { m_viewmatrix = mat; @@ -966,6 +993,12 @@ void RAS_OpenGLRasterizer::SetViewMatrix(const MT_Matrix4x4 &mat, } } + bool negX = (scale[0] < 0.0f); + bool negY = (scale[0] < 0.0f); + bool negZ = (scale[0] < 0.0f); + if (negX || negY || negZ) { + m_viewmatrix.tscale((negX)?-1.0f:1.0f, (negY)?-1.0f:1.0f, (negZ)?-1.0f:1.0f, 1.0); + } m_viewinvmatrix = m_viewmatrix; m_viewinvmatrix.invert(); @@ -976,6 +1009,7 @@ void RAS_OpenGLRasterizer::SetViewMatrix(const MT_Matrix4x4 &mat, glMatrixMode(GL_MODELVIEW); glLoadMatrixf(glviewmat); m_campos = pos; + m_camnegscale = negX ^ negY ^ negZ; } @@ -1108,6 +1142,9 @@ void RAS_OpenGLRasterizer::SetAlphaBlend(int alphablend) void RAS_OpenGLRasterizer::SetFrontFace(bool ccw) { + if (m_camnegscale) + ccw = !ccw; + if (m_last_frontface == ccw) return; diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.h b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.h index 4c22d1de611..9561e207dba 100644 --- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.h +++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.h @@ -96,6 +96,7 @@ class RAS_OpenGLRasterizer : public RAS_IRasterizer MT_Matrix4x4 m_viewinvmatrix; MT_Point3 m_campos; bool m_camortho; + bool m_camnegscale; StereoMode m_stereomode; StereoEye m_curreye; @@ -180,7 +181,8 @@ public: virtual float GetEyeSeparation(); virtual void SetFocalLength(const float focallength); virtual float GetFocalLength(); - + virtual RAS_IOffScreen *CreateOffScreen(int width, int height, int samples, int target); + virtual RAS_ISync *CreateSync(int type); virtual void SwapBuffers(); virtual void IndexPrimitives(class RAS_MeshSlot &ms); @@ -189,7 +191,12 @@ public: virtual void SetProjectionMatrix(MT_CmMatrix4x4 &mat); virtual void SetProjectionMatrix(const MT_Matrix4x4 &mat); - virtual void SetViewMatrix(const MT_Matrix4x4 &mat, const MT_Matrix3x3 &ori, const MT_Point3 &pos, bool perspective); + virtual void SetViewMatrix( + const MT_Matrix4x4 &mat, + const MT_Matrix3x3 &ori, + const MT_Point3 &pos, + const MT_Vector3 &scale, + bool perspective); virtual const MT_Point3& GetCameraPosition(); virtual bool GetCameraOrtho(); diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLSync.cpp b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLSync.cpp new file mode 100644 index 00000000000..d54b3232067 --- /dev/null +++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLSync.cpp @@ -0,0 +1,82 @@ +/* + * ***** 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. + * + * The Original Code is Copyright (C) 2015, Blender Foundation + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Blender Foundation. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "glew-mx.h" + +#include <stdio.h> + +#include "RAS_OpenGLSync.h" + +RAS_OpenGLSync::RAS_OpenGLSync() + :m_sync(NULL) +{ +} + +RAS_OpenGLSync::~RAS_OpenGLSync() +{ + Destroy(); +} + +bool RAS_OpenGLSync::Create(RAS_SYNC_TYPE type) +{ + if (m_sync) { + printf("RAS_OpenGLSync::Create(): sync already exists, destroy first\n"); + return false; + } + if (type != RAS_SYNC_TYPE_FENCE) { + printf("RAS_OpenGLSync::Create(): only RAS_SYNC_TYPE_FENCE are currently supported\n"); + return false; + } + if (!GLEW_ARB_sync) { + printf("RAS_OpenGLSync::Create(): ARB_sync extension is needed to create sync object\n"); + return false; + } + m_sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); + if (!m_sync) { + printf("RAS_OpenGLSync::Create(): glFenceSync() failed"); + return false; + } + return true; +} + +void RAS_OpenGLSync::Destroy() +{ + if (m_sync) { + glDeleteSync(m_sync); + m_sync = NULL; + } +} + +void RAS_OpenGLSync::Wait() +{ + if (m_sync) { + // this is needed to ensure that the sync is in the GPU + glFlush(); + // block until the operation have completed + glWaitSync(m_sync, 0, GL_TIMEOUT_IGNORED); + } +} diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLSync.h b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLSync.h new file mode 100644 index 00000000000..4ba96903856 --- /dev/null +++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLSync.h @@ -0,0 +1,50 @@ +/* + * ***** 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. + * + * The Original Code is Copyright (C) 2015, Blender Foundation + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Blender Foundation. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef __RAS_OPENGLSYNC__ +#define __RAS_OPENGLSYNC__ + + +#include "RAS_ISync.h" + +struct __GLsync; + +class RAS_OpenGLSync : public RAS_ISync +{ +private: + struct __GLsync *m_sync; + +public: + RAS_OpenGLSync(); + ~RAS_OpenGLSync(); + + virtual bool Create(RAS_SYNC_TYPE type); + virtual void Destroy(); + virtual void Wait(); +}; + +#endif /* __RAS_OPENGLSYNC__ */ diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVA.h b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVA.h index 34fdca23ee6..a5a3170ed77 100644 --- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVA.h +++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVA.h @@ -45,7 +45,7 @@ public: virtual void IndexPrimitives(RAS_MeshSlot& ms); - virtual void SetDrawingMode(int drawingmode){m_drawingmode=drawingmode;}; + virtual void SetDrawingMode(int drawingmode) {m_drawingmode = drawingmode;}; protected: int m_drawingmode; diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVBO.h b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVBO.h index 9cb3449bed5..4c8e4a8931c 100644 --- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVBO.h +++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVBO.h @@ -76,7 +76,7 @@ public: virtual void IndexPrimitives(RAS_MeshSlot& ms); - virtual void SetDrawingMode(int drawingmode){m_drawingmode=drawingmode;}; + virtual void SetDrawingMode(int drawingmode) {m_drawingmode = drawingmode;}; protected: int m_drawingmode; diff --git a/source/gameengine/VideoTexture/CMakeLists.txt b/source/gameengine/VideoTexture/CMakeLists.txt index 4be9a9abe5c..1eb09b02e05 100644 --- a/source/gameengine/VideoTexture/CMakeLists.txt +++ b/source/gameengine/VideoTexture/CMakeLists.txt @@ -45,6 +45,9 @@ set(INC ../../../intern/glew-mx ../../../intern/guardedalloc ../../../intern/string + ../../../intern/decklink + ../../../intern/gpudirect + ../../../intern/atomic ) set(INC_SYS @@ -68,8 +71,10 @@ set(SRC ImageViewport.cpp PyTypeList.cpp Texture.cpp + DeckLink.cpp VideoBase.cpp VideoFFmpeg.cpp + VideoDeckLink.cpp blendVideoTex.cpp BlendType.h @@ -87,8 +92,10 @@ set(SRC ImageViewport.h PyTypeList.h Texture.h + DeckLink.h VideoBase.h VideoFFmpeg.h + VideoDeckLink.h ) if(WITH_CODEC_FFMPEG) @@ -100,7 +107,13 @@ if(WITH_CODEC_FFMPEG) remove_strict_flags_file( VideoFFmpeg.cpp + VideoDeckLink + DeckLink ) endif() +if(WITH_GAMEENGINE_DECKLINK) + add_definitions(-DWITH_GAMEENGINE_DECKLINK) +endif() + blender_add_lib(ge_videotex "${SRC}" "${INC}" "${INC_SYS}") diff --git a/source/gameengine/VideoTexture/Common.h b/source/gameengine/VideoTexture/Common.h index 90f7e66452a..22ea177addc 100644 --- a/source/gameengine/VideoTexture/Common.h +++ b/source/gameengine/VideoTexture/Common.h @@ -36,7 +36,8 @@ #define NULL 0 #endif -#ifndef HRESULT +#ifndef _HRESULT_DEFINED +#define _HRESULT_DEFINED #define HRESULT long #endif diff --git a/source/gameengine/VideoTexture/DeckLink.cpp b/source/gameengine/VideoTexture/DeckLink.cpp new file mode 100644 index 00000000000..fa8ab8c641c --- /dev/null +++ b/source/gameengine/VideoTexture/DeckLink.cpp @@ -0,0 +1,813 @@ +/* + * ***** 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. + * + * The Original Code is Copyright (C) 2015, Blender Foundation + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Blender Foundation. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file gameengine/VideoTexture/Texture.cpp + * \ingroup bgevideotex + */ + +#ifdef WITH_GAMEENGINE_DECKLINK + +// implementation + +// FFmpeg defines its own version of stdint.h on Windows. +// Decklink needs FFmpeg, so it uses its version of stdint.h +// this is necessary for INT64_C macro +#ifndef __STDC_CONSTANT_MACROS +#define __STDC_CONSTANT_MACROS +#endif +// this is necessary for UINTPTR_MAX (used by atomic-ops) +#ifndef __STDC_LIMIT_MACROS +#define __STDC_LIMIT_MACROS +#endif + +#include "atomic_ops.h" + +#include "EXP_PyObjectPlus.h" +#include "KX_KetsjiEngine.h" +#include "KX_PythonInit.h" +#include "DeckLink.h" + +#include <memory.h> + +// macro for exception handling and logging +#define CATCH_EXCP catch (Exception & exp) \ +{ exp.report(); return NULL; } + +static struct +{ + const char *name; + BMDDisplayMode mode; +} sModeStringTab[] = { + { "NTSC", bmdModeNTSC }, + { "NTSC2398", bmdModeNTSC2398 }, + { "PAL", bmdModePAL }, + { "NTSCp", bmdModeNTSCp }, + { "PALp", bmdModePALp }, + + /* HD 1080 Modes */ + + { "HD1080p2398", bmdModeHD1080p2398 }, + { "HD1080p24", bmdModeHD1080p24 }, + { "HD1080p25", bmdModeHD1080p25 }, + { "HD1080p2997", bmdModeHD1080p2997 }, + { "HD1080p30", bmdModeHD1080p30 }, + { "HD1080i50", bmdModeHD1080i50 }, + { "HD1080i5994", bmdModeHD1080i5994 }, + { "HD1080i6000", bmdModeHD1080i6000 }, + { "HD1080p50", bmdModeHD1080p50 }, + { "HD1080p5994", bmdModeHD1080p5994 }, + { "HD1080p6000", bmdModeHD1080p6000 }, + + /* HD 720 Modes */ + + { "HD720p50", bmdModeHD720p50 }, + { "HD720p5994", bmdModeHD720p5994 }, + { "HD720p60", bmdModeHD720p60 }, + + /* 2k Modes */ + + { "2k2398", bmdMode2k2398 }, + { "2k24", bmdMode2k24 }, + { "2k25", bmdMode2k25 }, + + /* DCI Modes (output only) */ + + { "2kDCI2398", bmdMode2kDCI2398 }, + { "2kDCI24", bmdMode2kDCI24 }, + { "2kDCI25", bmdMode2kDCI25 }, + + /* 4k Modes */ + + { "4K2160p2398", bmdMode4K2160p2398 }, + { "4K2160p24", bmdMode4K2160p24 }, + { "4K2160p25", bmdMode4K2160p25 }, + { "4K2160p2997", bmdMode4K2160p2997 }, + { "4K2160p30", bmdMode4K2160p30 }, + { "4K2160p50", bmdMode4K2160p50 }, + { "4K2160p5994", bmdMode4K2160p5994 }, + { "4K2160p60", bmdMode4K2160p60 }, + // sentinel + { NULL } +}; + +static struct +{ + const char *name; + BMDPixelFormat format; +} sFormatStringTab[] = { + { "8BitYUV", bmdFormat8BitYUV }, + { "10BitYUV", bmdFormat10BitYUV }, + { "8BitARGB", bmdFormat8BitARGB }, + { "8BitBGRA", bmdFormat8BitBGRA }, + { "10BitRGB", bmdFormat10BitRGB }, + { "12BitRGB", bmdFormat12BitRGB }, + { "12BitRGBLE", bmdFormat12BitRGBLE }, + { "10BitRGBXLE", bmdFormat10BitRGBXLE }, + { "10BitRGBX", bmdFormat10BitRGBX }, + // sentinel + { NULL } +}; + +ExceptionID DeckLinkBadDisplayMode, DeckLinkBadPixelFormat; +ExpDesc DeckLinkBadDisplayModeDesc(DeckLinkBadDisplayMode, "Invalid or unsupported display mode"); +ExpDesc DeckLinkBadPixelFormatDesc(DeckLinkBadPixelFormat, "Invalid or unsupported pixel format"); + +HRESULT decklink_ReadDisplayMode(const char *format, size_t len, BMDDisplayMode *displayMode) +{ + int i; + + if (len == 0) + len = strlen(format); + for (i = 0; sModeStringTab[i].name != NULL; i++) { + if (strlen(sModeStringTab[i].name) == len && + !strncmp(sModeStringTab[i].name, format, len)) + { + *displayMode = sModeStringTab[i].mode; + return S_OK; + } + } + if (len != 4) + THRWEXCP(DeckLinkBadDisplayMode, S_OK); + // assume the user entered directly the mode value as a 4 char string + *displayMode = (BMDDisplayMode)((((uint32_t)format[0]) << 24) + (((uint32_t)format[1]) << 16) + (((uint32_t)format[2]) << 8) + ((uint32_t)format[3])); + return S_OK; +} + +HRESULT decklink_ReadPixelFormat(const char *format, size_t len, BMDPixelFormat *pixelFormat) +{ + int i; + + if (!len) + len = strlen(format); + for (i = 0; sFormatStringTab[i].name != NULL; i++) { + if (strlen(sFormatStringTab[i].name) == len && + !strncmp(sFormatStringTab[i].name, format, len)) + { + *pixelFormat = sFormatStringTab[i].format; + return S_OK; + } + } + if (len != 4) + THRWEXCP(DeckLinkBadPixelFormat, S_OK); + // assume the user entered directly the mode value as a 4 char string + *pixelFormat = (BMDPixelFormat)((((uint32_t)format[0]) << 24) + (((uint32_t)format[1]) << 16) + (((uint32_t)format[2]) << 8) + ((uint32_t)format[3])); + return S_OK; +} + +class DeckLink3DFrameWrapper : public IDeckLinkVideoFrame, IDeckLinkVideoFrame3DExtensions +{ +public: + // IUnknown + virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, LPVOID *ppv) + { + if (!memcmp(&iid, &IID_IDeckLinkVideoFrame3DExtensions, sizeof(iid))) { + if (mpRightEye) { + *ppv = (IDeckLinkVideoFrame3DExtensions*)this; + return S_OK; + } + } + return E_NOTIMPL; + } + virtual ULONG STDMETHODCALLTYPE AddRef(void) { return 1U; } + virtual ULONG STDMETHODCALLTYPE Release(void) { return 1U; } + // IDeckLinkVideoFrame + virtual long STDMETHODCALLTYPE GetWidth(void) { return mpLeftEye->GetWidth(); } + virtual long STDMETHODCALLTYPE GetHeight(void) { return mpLeftEye->GetHeight(); } + virtual long STDMETHODCALLTYPE GetRowBytes(void) { return mpLeftEye->GetRowBytes(); } + virtual BMDPixelFormat STDMETHODCALLTYPE GetPixelFormat(void) { return mpLeftEye->GetPixelFormat(); } + virtual BMDFrameFlags STDMETHODCALLTYPE GetFlags(void) { return mpLeftEye->GetFlags(); } + virtual HRESULT STDMETHODCALLTYPE GetBytes(void **buffer) { return mpLeftEye->GetBytes(buffer); } + virtual HRESULT STDMETHODCALLTYPE GetTimecode(BMDTimecodeFormat format,IDeckLinkTimecode **timecode) + { return mpLeftEye->GetTimecode(format, timecode); } + virtual HRESULT STDMETHODCALLTYPE GetAncillaryData(IDeckLinkVideoFrameAncillary **ancillary) + { return mpLeftEye->GetAncillaryData(ancillary); } + // IDeckLinkVideoFrame3DExtensions + virtual BMDVideo3DPackingFormat STDMETHODCALLTYPE Get3DPackingFormat(void) + { + return bmdVideo3DPackingLeftOnly; + } + virtual HRESULT STDMETHODCALLTYPE GetFrameForRightEye( + /* [out] */ IDeckLinkVideoFrame **rightEyeFrame) + { + mpRightEye->AddRef(); + *rightEyeFrame = mpRightEye; + return S_OK; + } + // Constructor + DeckLink3DFrameWrapper(IDeckLinkVideoFrame *leftEye, IDeckLinkVideoFrame *rightEye) + { + mpLeftEye = leftEye; + mpRightEye = rightEye; + } + // no need for a destructor, it's just a wrapper +private: + IDeckLinkVideoFrame *mpLeftEye; + IDeckLinkVideoFrame *mpRightEye; +}; + +static void decklink_Reset(DeckLink *self) +{ + self->m_lastClock = 0.0; + self->mDLOutput = NULL; + self->mUse3D = false; + self->mDisplayMode = bmdModeUnknown; + self->mKeyingSupported = false; + self->mHDKeyingSupported = false; + self->mSize[0] = 0; + self->mSize[1] = 0; + self->mFrameSize = 0; + self->mLeftFrame = NULL; + self->mRightFrame = NULL; + self->mKeyer = NULL; + self->mUseKeying = false; + self->mKeyingLevel = 255; + self->mUseExtend = false; +} + +#ifdef __BIG_ENDIAN__ +#define CONV_PIXEL(i) ((((i)>>16)&0xFF00)+(((i)&0xFF00)<<16)+((i)&0xFF00FF)) +#else +#define CONV_PIXEL(i) ((((i)&0xFF)<<16)+(((i)>>16)&0xFF)+((i)&0xFF00FF00)) +#endif + +// adapt the pixel format and picture size from VideoTexture (RGBA) to DeckLink (BGRA) +static void decklink_ConvImage(uint32_t *dest, const short *destSize, const uint32_t *source, const short *srcSize, bool extend) +{ + short w, h, x, y; + const uint32_t *s; + uint32_t *d, p; + bool sameSize = (destSize[0] == srcSize[0] && destSize[1] == srcSize[1]); + + if (sameSize || !extend) { + // here we convert pixel by pixel + w = (destSize[0] < srcSize[0]) ? destSize[0] : srcSize[0]; + h = (destSize[1] < srcSize[1]) ? destSize[1] : srcSize[1]; + for (y = 0; y < h; ++y) { + s = source + y*srcSize[0]; + d = dest + y*destSize[0]; + for (x = 0; x < w; ++x, ++s, ++d) { + *d = CONV_PIXEL(*s); + } + } + } + else { + // here we scale + // interpolation accumulator + int accHeight = srcSize[1] >> 1; + d = dest; + s = source; + // process image rows + for (y = 0; y < srcSize[1]; ++y) { + // increase height accum + accHeight += destSize[1]; + // if pixel row has to be drawn + if (accHeight >= srcSize[1]) { + // decrease accum + accHeight -= srcSize[1]; + // width accum + int accWidth = srcSize[0] >> 1; + // process row + for (x = 0; x < srcSize[0]; ++x, ++s) { + // increase width accum + accWidth += destSize[0]; + // convert pixel + p = CONV_PIXEL(*s); + // if pixel has to be drown one or more times + while (accWidth >= srcSize[0]) { + // decrease accum + accWidth -= srcSize[0]; + *d++ = p; + } + } + // if there should be more identical lines + while (accHeight >= srcSize[1]) { + accHeight -= srcSize[1]; + // copy previous line + memcpy(d, d - destSize[0], 4 * destSize[0]); + d += destSize[0]; + } + } + else { + // if we skip a source line + s += srcSize[0]; + } + } + } +} + +// DeckLink object allocation +static PyObject *DeckLink_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + // allocate object + DeckLink * self = reinterpret_cast<DeckLink*>(type->tp_alloc(type, 0)); + // initialize object structure + decklink_Reset(self); + // m_leftEye is a python object, it's handled by python + self->m_leftEye = NULL; + self->m_rightEye = NULL; + // return allocated object + return reinterpret_cast<PyObject*>(self); +} + + +// forward declaration +PyObject *DeckLink_close(DeckLink *self); +int DeckLink_setSource(DeckLink *self, PyObject *value, void *closure); + + +// DeckLink object deallocation +static void DeckLink_dealloc(DeckLink *self) +{ + // release renderer + Py_XDECREF(self->m_leftEye); + // close decklink + PyObject *ret = DeckLink_close(self); + Py_DECREF(ret); + // release object + Py_TYPE((PyObject *)self)->tp_free((PyObject *)self); +} + + +ExceptionID AutoDetectionNotAvail, DeckLinkOpenCard, DeckLinkBadFormat, DeckLinkInternalError; +ExpDesc AutoDetectionNotAvailDesc(AutoDetectionNotAvail, "Auto detection not yet available"); +ExpDesc DeckLinkOpenCardDesc(DeckLinkOpenCard, "Cannot open card for output"); +ExpDesc DeckLinkBadFormatDesc(DeckLinkBadFormat, "Invalid or unsupported output format, use <mode>[/3D]"); +ExpDesc DeckLinkInternalErrorDesc(DeckLinkInternalError, "DeckLink API internal error, please report"); + +// DeckLink object initialization +static int DeckLink_init(DeckLink *self, PyObject *args, PyObject *kwds) +{ + IDeckLinkIterator* pIterator; + IDeckLinkAttributes* pAttributes; + IDeckLinkDisplayModeIterator* pDisplayModeIterator; + IDeckLinkDisplayMode* pDisplayMode; + IDeckLink* pDL; + char* p3D; + BOOL flag; + size_t len; + int i; + uint32_t displayFlags; + BMDVideoOutputFlags outputFlags; + BMDDisplayModeSupport support; + uint32_t* bytes; + + + // material ID + short cardIdx = 0; + // texture ID + char *format = NULL; + + static const char *kwlist[] = {"cardIdx", "format", NULL}; + // get parameters + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|hs", + const_cast<char**>(kwlist), &cardIdx, &format)) + return -1; + + try { + if (format == NULL) { + THRWEXCP(AutoDetectionNotAvail, S_OK); + } + + if ((p3D = strchr(format, '/')) != NULL && strcmp(p3D, "/3D")) + THRWEXCP(DeckLinkBadFormat, S_OK); + self->mUse3D = (p3D) ? true : false; + // read the mode + len = (p3D) ? (size_t)(p3D - format) : strlen(format); + // throws if bad mode + decklink_ReadDisplayMode(format, len, &self->mDisplayMode); + + pIterator = BMD_CreateDeckLinkIterator(); + pDL = NULL; + if (pIterator) { + i = 0; + while (pIterator->Next(&pDL) == S_OK) { + if (i == cardIdx) { + break; + } + i++; + pDL->Release(); + pDL = NULL; + } + pIterator->Release(); + } + + if (!pDL) { + THRWEXCP(DeckLinkOpenCard, S_OK); + } + // detect the capabilities + if (pDL->QueryInterface(IID_IDeckLinkAttributes, (void**)&pAttributes) == S_OK) { + if (pAttributes->GetFlag(BMDDeckLinkSupportsInternalKeying, &flag) == S_OK && flag) { + self->mKeyingSupported = true; + if (pAttributes->GetFlag(BMDDeckLinkSupportsHDKeying, &flag) == S_OK && flag) { + self->mHDKeyingSupported = true; + } + } + pAttributes->Release(); + } + + if (pDL->QueryInterface(IID_IDeckLinkOutput, (void**)&self->mDLOutput) != S_OK) { + self->mDLOutput = NULL; + } + if (self->mKeyingSupported) { + pDL->QueryInterface(IID_IDeckLinkKeyer, (void **)&self->mKeyer); + } + // we don't need the device anymore, release to avoid leaking + pDL->Release(); + + if (!self->mDLOutput) + THRWEXCP(DeckLinkOpenCard, S_OK); + + if (self->mDLOutput->GetDisplayModeIterator(&pDisplayModeIterator) != S_OK) + THRWEXCP(DeckLinkInternalError, S_OK); + + displayFlags = (self->mUse3D) ? bmdDisplayModeSupports3D : 0; + outputFlags = (self->mUse3D) ? bmdVideoOutputDualStream3D : bmdVideoOutputFlagDefault; + pDisplayMode = NULL; + i = 0; + while (pDisplayModeIterator->Next(&pDisplayMode) == S_OK) { + if (pDisplayMode->GetDisplayMode() == self->mDisplayMode + && (pDisplayMode->GetFlags() & displayFlags) == displayFlags) { + if (self->mDLOutput->DoesSupportVideoMode(self->mDisplayMode, bmdFormat8BitBGRA, outputFlags, &support, NULL) != S_OK || + support == bmdDisplayModeNotSupported) + { + printf("Warning: DeckLink card %d reports no BGRA support, proceed anyway\n", cardIdx); + } + break; + } + pDisplayMode->Release(); + pDisplayMode = NULL; + i++; + } + pDisplayModeIterator->Release(); + + if (!pDisplayMode) + THRWEXCP(DeckLinkBadFormat, S_OK); + self->mSize[0] = pDisplayMode->GetWidth(); + self->mSize[1] = pDisplayMode->GetHeight(); + self->mFrameSize = 4*self->mSize[0]*self->mSize[1]; + pDisplayMode->Release(); + if (self->mDLOutput->EnableVideoOutput(self->mDisplayMode, outputFlags) != S_OK) + // this shouldn't fail + THRWEXCP(DeckLinkOpenCard, S_OK); + + if (self->mDLOutput->CreateVideoFrame(self->mSize[0], self->mSize[1], self->mSize[0] * 4, bmdFormat8BitBGRA, bmdFrameFlagFlipVertical, &self->mLeftFrame) != S_OK) + THRWEXCP(DeckLinkInternalError, S_OK); + // clear alpha channel in the frame buffer + self->mLeftFrame->GetBytes((void **)&bytes); + memset(bytes, 0, self->mFrameSize); + if (self->mUse3D) { + if (self->mDLOutput->CreateVideoFrame(self->mSize[0], self->mSize[1], self->mSize[0] * 4, bmdFormat8BitBGRA, bmdFrameFlagFlipVertical, &self->mRightFrame) != S_OK) + THRWEXCP(DeckLinkInternalError, S_OK); + // clear alpha channel in the frame buffer + self->mRightFrame->GetBytes((void **)&bytes); + memset(bytes, 0, self->mFrameSize); + } + } + catch (Exception & exp) + { + printf("DeckLink: exception when opening card %d: %s\n", cardIdx, exp.what()); + exp.report(); + // normally, the object should be deallocated + return -1; + } + // initialization succeeded + return 0; +} + + +// close added decklink +PyObject *DeckLink_close(DeckLink * self) +{ + if (self->mLeftFrame) + self->mLeftFrame->Release(); + if (self->mRightFrame) + self->mRightFrame->Release(); + if (self->mKeyer) + self->mKeyer->Release(); + if (self->mDLOutput) + self->mDLOutput->Release(); + decklink_Reset(self); + Py_RETURN_NONE; +} + + +// refresh decklink key frame +static PyObject *DeckLink_refresh(DeckLink *self, PyObject *args) +{ + // get parameter - refresh source + PyObject *param; + double ts = -1.0; + + if (!PyArg_ParseTuple(args, "O|d:refresh", ¶m, &ts) || !PyBool_Check(param)) { + // report error + PyErr_SetString(PyExc_TypeError, "The value must be a bool"); + return NULL; + } + // some trick here: we are in the business of loading a key frame in decklink, + // no use to do it if we are still in the same rendering frame. + // We find this out by looking at the engine current clock time + KX_KetsjiEngine* engine = KX_GetActiveEngine(); + if (engine->GetClockTime() != self->m_lastClock) + { + self->m_lastClock = engine->GetClockTime(); + // set source refresh + bool refreshSource = (param == Py_True); + uint32_t *leftEye = NULL; + uint32_t *rightEye = NULL; + // try to process key frame from source + try { + // check if optimization is possible + if (self->m_leftEye != NULL) { + ImageBase *leftImage = self->m_leftEye->m_image; + short * srcSize = leftImage->getSize(); + self->mLeftFrame->GetBytes((void **)&leftEye); + if (srcSize[0] == self->mSize[0] && srcSize[1] == self->mSize[1]) + { + // buffer has same size, can load directly + if (!leftImage->loadImage(leftEye, self->mFrameSize, GL_BGRA, ts)) + leftEye = NULL; + } + else { + // scaling is required, go the hard way + unsigned int *src = leftImage->getImage(0, ts); + if (src != NULL) + decklink_ConvImage(leftEye, self->mSize, src, srcSize, self->mUseExtend); + else + leftEye = NULL; + } + } + if (leftEye) { + if (self->mUse3D && self->m_rightEye != NULL) { + ImageBase *rightImage = self->m_rightEye->m_image; + short * srcSize = rightImage->getSize(); + self->mRightFrame->GetBytes((void **)&rightEye); + if (srcSize[0] == self->mSize[0] && srcSize[1] == self->mSize[1]) + { + // buffer has same size, can load directly + rightImage->loadImage(rightEye, self->mFrameSize, GL_BGRA, ts); + } + else { + // scaling is required, go the hard way + unsigned int *src = rightImage->getImage(0, ts); + if (src != NULL) + decklink_ConvImage(rightEye, self->mSize, src, srcSize, self->mUseExtend); + } + } + if (self->mUse3D) { + DeckLink3DFrameWrapper frame3D( + (IDeckLinkVideoFrame*)self->mLeftFrame, + (IDeckLinkVideoFrame*)self->mRightFrame); + self->mDLOutput->DisplayVideoFrameSync(&frame3D); + } + else { + self->mDLOutput->DisplayVideoFrameSync((IDeckLinkVideoFrame*)self->mLeftFrame); + } + } + // refresh texture source, if required + if (refreshSource) { + if (self->m_leftEye) + self->m_leftEye->m_image->refresh(); + if (self->m_rightEye) + self->m_rightEye->m_image->refresh(); + } + } + CATCH_EXCP; + } + Py_RETURN_NONE; +} + +// get source object +static PyObject *DeckLink_getSource(DeckLink *self, PyObject *value, void *closure) +{ + // if source exists + if (self->m_leftEye != NULL) { + Py_INCREF(self->m_leftEye); + return reinterpret_cast<PyObject*>(self->m_leftEye); + } + // otherwise return None + Py_RETURN_NONE; +} + + +// set source object +int DeckLink_setSource(DeckLink *self, PyObject *value, void *closure) +{ + // check new value + if (value == NULL || !pyImageTypes.in(Py_TYPE(value))) { + // report value error + PyErr_SetString(PyExc_TypeError, "Invalid type of value"); + return -1; + } + // increase ref count for new value + Py_INCREF(value); + // release previous + Py_XDECREF(self->m_leftEye); + // set new value + self->m_leftEye = reinterpret_cast<PyImage*>(value); + // return success + return 0; +} + +// get source object +static PyObject *DeckLink_getRight(DeckLink *self, PyObject *value, void *closure) +{ + // if source exists + if (self->m_rightEye != NULL) + { + Py_INCREF(self->m_rightEye); + return reinterpret_cast<PyObject*>(self->m_rightEye); + } + // otherwise return None + Py_RETURN_NONE; +} + + +// set source object +static int DeckLink_setRight(DeckLink *self, PyObject *value, void *closure) +{ + // check new value + if (value == NULL || !pyImageTypes.in(Py_TYPE(value))) + { + // report value error + PyErr_SetString(PyExc_TypeError, "Invalid type of value"); + return -1; + } + // increase ref count for new value + Py_INCREF(value); + // release previous + Py_XDECREF(self->m_rightEye); + // set new value + self->m_rightEye = reinterpret_cast<PyImage*>(value); + // return success + return 0; +} + + +static PyObject *DeckLink_getKeying(DeckLink *self, PyObject *value, void *closure) +{ + if (self->mUseKeying) Py_RETURN_TRUE; + else Py_RETURN_FALSE; +} + +static int DeckLink_setKeying(DeckLink *self, PyObject *value, void *closure) +{ + if (value == NULL || !PyBool_Check(value)) + { + PyErr_SetString(PyExc_TypeError, "The value must be a bool"); + return -1; + } + if (self->mKeyer != NULL) + { + if (value == Py_True) + { + if (self->mKeyer->Enable(false) != S_OK) + { + PyErr_SetString(PyExc_RuntimeError, "Error enabling keyer"); + return -1; + } + self->mUseKeying = true; + self->mKeyer->SetLevel(self->mKeyingLevel); + } + else + { + self->mKeyer->Disable(); + self->mUseKeying = false; + } + } + // success + return 0; +} + +static PyObject *DeckLink_getLevel(DeckLink *self, PyObject *value, void *closure) +{ + return Py_BuildValue("h", self->mKeyingLevel); +} + +static int DeckLink_setLevel(DeckLink *self, PyObject *value, void *closure) +{ + long level; + if (value == NULL || !PyLong_Check(value)) { + PyErr_SetString(PyExc_TypeError, "The value must be an integer from 0 to 255"); + return -1; + } + level = PyLong_AsLong(value); + if (level > 255) + level = 255; + else if (level < 0) + level = 0; + self->mKeyingLevel = (uint8_t)level; + if (self->mUseKeying) { + if (self->mKeyer->SetLevel(self->mKeyingLevel) != S_OK) { + PyErr_SetString(PyExc_RuntimeError, "Error changin level of keyer"); + return -1; + } + } + // success + return 0; +} + +static PyObject *DeckLink_getExtend(DeckLink *self, PyObject *value, void *closure) +{ + if (self->mUseExtend) Py_RETURN_TRUE; + else Py_RETURN_FALSE; +} + +static int DeckLink_setExtend(DeckLink *self, PyObject *value, void *closure) +{ + if (value == NULL || !PyBool_Check(value)) + { + PyErr_SetString(PyExc_TypeError, "The value must be a bool"); + return -1; + } + self->mUseExtend = (value == Py_True); + return 0; +} + +// class DeckLink methods +static PyMethodDef decklinkMethods[] = +{ + { "close", (PyCFunction)DeckLink_close, METH_NOARGS, "Close dynamic decklink and restore original"}, + { "refresh", (PyCFunction)DeckLink_refresh, METH_VARARGS, "Refresh decklink from source"}, + {NULL} /* Sentinel */ +}; + +// class DeckLink attributes +static PyGetSetDef decklinkGetSets[] = +{ + { (char*)"source", (getter)DeckLink_getSource, (setter)DeckLink_setSource, (char*)"source of decklink (left eye)", NULL}, + { (char*)"right", (getter)DeckLink_getRight, (setter)DeckLink_setRight, (char*)"source of decklink (right eye)", NULL }, + { (char*)"keying", (getter)DeckLink_getKeying, (setter)DeckLink_setKeying, (char*)"whether keying is enabled (frame is alpha-composited with passthrough output)", NULL }, + { (char*)"level", (getter)DeckLink_getLevel, (setter)DeckLink_setLevel, (char*)"change the level of keying (overall alpha level of key frame, 0 to 255)", NULL }, + { (char*)"extend", (getter)DeckLink_getExtend, (setter)DeckLink_setExtend, (char*)"whether image should stretched to fit frame", NULL }, + { NULL } +}; + + +// class DeckLink declaration +PyTypeObject DeckLinkType = +{ + PyVarObject_HEAD_INIT(NULL, 0) + "VideoTexture.DeckLink", /*tp_name*/ + sizeof(DeckLink), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + (destructor)DeckLink_dealloc,/*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + &imageBufferProcs, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ + "DeckLink objects", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + decklinkMethods, /* tp_methods */ + 0, /* tp_members */ + decklinkGetSets, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)DeckLink_init, /* tp_init */ + 0, /* tp_alloc */ + DeckLink_new, /* tp_new */ +}; + +#endif /* WITH_GAMEENGINE_DECKLINK */ diff --git a/source/gameengine/VideoTexture/DeckLink.h b/source/gameengine/VideoTexture/DeckLink.h new file mode 100644 index 00000000000..4528fe7cec0 --- /dev/null +++ b/source/gameengine/VideoTexture/DeckLink.h @@ -0,0 +1,86 @@ +/* + * ***** 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. + * + * The Original Code is Copyright (C) 2015, Blender Foundation + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Blender Foundation. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file VideoTexture/DeckLink.h + * \ingroup bgevideotex + */ + +#ifndef __DECKLINK_H__ +#define __DECKLINK_H__ + +#ifdef WITH_GAMEENGINE_DECKLINK + +#include "EXP_PyObjectPlus.h" +#include <structmember.h> + +#include "DNA_image_types.h" + +#include "DeckLinkAPI.h" + +#include "ImageBase.h" +#include "BlendType.h" +#include "Exception.h" + + +// type DeckLink declaration +struct DeckLink +{ + PyObject_HEAD + + // last refresh + double m_lastClock; + // decklink card to which we output + IDeckLinkOutput * mDLOutput; + IDeckLinkKeyer * mKeyer; + IDeckLinkMutableVideoFrame *mLeftFrame; + IDeckLinkMutableVideoFrame *mRightFrame; + bool mUse3D; + bool mUseKeying; + bool mUseExtend; + bool mKeyingSupported; + bool mHDKeyingSupported; + uint8_t mKeyingLevel; + BMDDisplayMode mDisplayMode; + short mSize[2]; + uint32_t mFrameSize; + + // image source + PyImage * m_leftEye; + PyImage * m_rightEye; +}; + + +// DeckLink type description +extern PyTypeObject DeckLinkType; + +// helper function +HRESULT decklink_ReadDisplayMode(const char *format, size_t len, BMDDisplayMode *displayMode); +HRESULT decklink_ReadPixelFormat(const char *format, size_t len, BMDPixelFormat *displayMode); + +#endif /* WITH_GAMEENGINE_DECKLINK */ + +#endif /* __DECKLINK_H__ */ diff --git a/source/gameengine/VideoTexture/Exception.cpp b/source/gameengine/VideoTexture/Exception.cpp index 08616e0c41c..9f82987ea62 100644 --- a/source/gameengine/VideoTexture/Exception.cpp +++ b/source/gameengine/VideoTexture/Exception.cpp @@ -213,6 +213,7 @@ void registerAllExceptions(void) ImageSizesNotMatchDesc.registerDesc(); ImageHasExportsDesc.registerDesc(); InvalidColorChannelDesc.registerDesc(); + InvalidImageModeDesc.registerDesc(); SceneInvalidDesc.registerDesc(); CameraInvalidDesc.registerDesc(); ObserverInvalidDesc.registerDesc(); @@ -223,4 +224,18 @@ void registerAllExceptions(void) MirrorTooSmallDesc.registerDesc(); SourceVideoEmptyDesc.registerDesc(); SourceVideoCreationDesc.registerDesc(); + OffScreenInvalidDesc.registerDesc(); +#ifdef WITH_GAMEENGINE_DECKLINK + AutoDetectionNotAvailDesc.registerDesc(); + DeckLinkBadDisplayModeDesc.registerDesc(); + DeckLinkBadPixelFormatDesc.registerDesc(); + DeckLinkOpenCardDesc.registerDesc(); + DeckLinkBadFormatDesc.registerDesc(); + DeckLinkInternalErrorDesc.registerDesc(); + SourceVideoOnlyCaptureDesc.registerDesc(); + VideoDeckLinkBadFormatDesc.registerDesc(); + VideoDeckLinkOpenCardDesc.registerDesc(); + VideoDeckLinkDvpInternalErrorDesc.registerDesc(); + VideoDeckLinkPinMemoryErrorDesc.registerDesc(); +#endif } diff --git a/source/gameengine/VideoTexture/Exception.h b/source/gameengine/VideoTexture/Exception.h index c3c27abe019..c4de85ff34d 100644 --- a/source/gameengine/VideoTexture/Exception.h +++ b/source/gameengine/VideoTexture/Exception.h @@ -46,7 +46,7 @@ throw Exception (err, macroHRslt, __FILE__, __LINE__); \ } -#define THRWEXCP(err,hRslt) throw Exception (err, hRslt, __FILE__, __LINE__); +#define THRWEXCP(err,hRslt) throw Exception (err, hRslt, __FILE__, __LINE__) #if defined WIN32 @@ -209,9 +209,11 @@ extern ExpDesc MaterialNotAvailDesc; extern ExpDesc ImageSizesNotMatchDesc; extern ExpDesc ImageHasExportsDesc; extern ExpDesc InvalidColorChannelDesc; +extern ExpDesc InvalidImageModeDesc; extern ExpDesc SceneInvalidDesc; extern ExpDesc CameraInvalidDesc; extern ExpDesc ObserverInvalidDesc; +extern ExpDesc OffScreenInvalidDesc; extern ExpDesc MirrorInvalidDesc; extern ExpDesc MirrorSizeInvalidDesc; extern ExpDesc MirrorNormalInvalidDesc; @@ -219,7 +221,19 @@ extern ExpDesc MirrorHorizontalDesc; extern ExpDesc MirrorTooSmallDesc; extern ExpDesc SourceVideoEmptyDesc; extern ExpDesc SourceVideoCreationDesc; - +extern ExpDesc DeckLinkBadDisplayModeDesc; +extern ExpDesc DeckLinkBadPixelFormatDesc; +extern ExpDesc AutoDetectionNotAvailDesc; +extern ExpDesc DeckLinkOpenCardDesc; +extern ExpDesc DeckLinkBadFormatDesc; +extern ExpDesc DeckLinkInternalErrorDesc; +extern ExpDesc SourceVideoOnlyCaptureDesc; +extern ExpDesc VideoDeckLinkBadFormatDesc; +extern ExpDesc VideoDeckLinkOpenCardDesc; +extern ExpDesc VideoDeckLinkDvpInternalErrorDesc; +extern ExpDesc VideoDeckLinkPinMemoryErrorDesc; + +extern ExceptionID InvalidImageMode; void registerAllExceptions(void); #endif diff --git a/source/gameengine/VideoTexture/FilterBase.h b/source/gameengine/VideoTexture/FilterBase.h index 498917e2375..db688d551d0 100644 --- a/source/gameengine/VideoTexture/FilterBase.h +++ b/source/gameengine/VideoTexture/FilterBase.h @@ -44,6 +44,13 @@ #define VT_A(v) ((unsigned char*)&v)[3] #define VT_RGBA(v,r,g,b,a) VT_R(v)=(unsigned char)r, VT_G(v)=(unsigned char)g, VT_B(v)=(unsigned char)b, VT_A(v)=(unsigned char)a +#ifdef __BIG_ENDIAN__ +# define VT_SWAPBR(i) ((((i) >> 16) & 0xFF00) + (((i) & 0xFF00) << 16) + ((i) & 0xFF00FF)) +#else +# define VT_SWAPBR(i) ((((i) & 0xFF) << 16) + (((i) >> 16) & 0xFF) + ((i) & 0xFF00FF00)) +#endif + + // forward declaration class FilterBase; diff --git a/source/gameengine/VideoTexture/FilterSource.h b/source/gameengine/VideoTexture/FilterSource.h index bc80b2b36cc..820576dfff9 100644 --- a/source/gameengine/VideoTexture/FilterSource.h +++ b/source/gameengine/VideoTexture/FilterSource.h @@ -81,6 +81,30 @@ protected: } }; +/// class for BGRA32 conversion +class FilterBGRA32 : public FilterBase +{ +public: + /// constructor + FilterBGRA32 (void) {} + /// destructor + virtual ~FilterBGRA32 (void) {} + + /// get source pixel size + virtual unsigned int getPixelSize (void) { return 4; } + +protected: + /// filter pixel, source byte buffer + virtual unsigned int filter( + unsigned char *src, short x, short y, + short * size, unsigned int pixSize, unsigned int val) + { + VT_RGBA(val,src[2],src[1],src[0],src[3]); + return val; + } +}; + + /// class for BGR24 conversion class FilterBGR24 : public FilterBase { diff --git a/source/gameengine/VideoTexture/ImageBase.cpp b/source/gameengine/VideoTexture/ImageBase.cpp index 8be152c7b8e..0db1fa293da 100644 --- a/source/gameengine/VideoTexture/ImageBase.cpp +++ b/source/gameengine/VideoTexture/ImageBase.cpp @@ -32,7 +32,6 @@ extern "C" { #include "bgl.h" } -#include "glew-mx.h" #include <vector> #include <string.h> @@ -50,6 +49,14 @@ extern "C" { // ImageBase class implementation +ExceptionID ImageHasExports; +ExceptionID InvalidColorChannel; +ExceptionID InvalidImageMode; + +ExpDesc ImageHasExportsDesc(ImageHasExports, "Image has exported buffers, cannot resize"); +ExpDesc InvalidColorChannelDesc(InvalidColorChannel, "Invalid or too many color channels specified. At most 4 values within R, G, B, A, 0, 1"); +ExpDesc InvalidImageModeDesc(InvalidImageMode, "Invalid image mode, only RGBA and BGRA are supported"); + // constructor ImageBase::ImageBase (bool staticSrc) : m_image(NULL), m_imgSize(0), m_avail(false), m_scale(false), m_scaleChange(false), m_flip(false), @@ -111,6 +118,28 @@ unsigned int * ImageBase::getImage (unsigned int texId, double ts) return m_avail ? m_image : NULL; } +bool ImageBase::loadImage(unsigned int *buffer, unsigned int size, unsigned int format, double ts) +{ + unsigned int *d, *s, v, len; + if (getImage(0, ts) != NULL && size >= getBuffSize()) { + switch (format) { + case GL_RGBA: + memcpy(buffer, m_image, getBuffSize()); + break; + case GL_BGRA: + len = (unsigned int)m_size[0] * m_size[1]; + for (s=m_image, d=buffer; len; len--) { + v = *s++; + *d++ = VT_SWAPBR(v); + } + break; + default: + THRWEXCP(InvalidImageMode,S_OK); + } + return true; + } + return false; +} // refresh image source void ImageBase::refresh (void) @@ -179,11 +208,18 @@ void ImageBase::setFilter (PyFilter * filt) m_pyfilter = filt; } -ExceptionID ImageHasExports; -ExceptionID InvalidColorChannel; +void ImageBase::swapImageBR() +{ + unsigned int size, v, *s; -ExpDesc ImageHasExportsDesc(ImageHasExports, "Image has exported buffers, cannot resize"); -ExpDesc InvalidColorChannelDesc(InvalidColorChannel, "Invalid or too many color channels specified. At most 4 values within R, G, B, A, 0, 1"); + if (m_avail) { + size = 1 * m_size[0] * m_size[1]; + for (s=m_image; size; size--) { + v = *s; + *s++ = VT_SWAPBR(v); + } + } +} // initialize image data void ImageBase::init (short width, short height) @@ -500,10 +536,57 @@ PyObject *Image_getSize (PyImage *self, void *closure) } // refresh image -PyObject *Image_refresh (PyImage *self) -{ +PyObject *Image_refresh (PyImage *self, PyObject *args) +{ + Py_buffer buffer; + bool done = true; + char *mode = NULL; + double ts = -1.0; + unsigned int format; + + memset(&buffer, 0, sizeof(buffer)); + if (PyArg_ParseTuple(args, "|s*sd:refresh", &buffer, &mode, &ts)) { + if (buffer.buf) { + // a target buffer is provided, verify its format + if (buffer.readonly) { + PyErr_SetString(PyExc_TypeError, "Buffers passed in argument must be writable"); + } + else if (!PyBuffer_IsContiguous(&buffer, 'C')) { + PyErr_SetString(PyExc_TypeError, "Buffers passed in argument must be contiguous in memory"); + } + else if (((intptr_t)buffer.buf & 3) != 0) { + PyErr_SetString(PyExc_TypeError, "Buffers passed in argument must be aligned to 4 bytes boundary"); + } + else { + // ready to get the image into our buffer + try { + if (mode == NULL || !strcmp(mode, "RGBA")) + format = GL_RGBA; + else if (!strcmp(mode, "BGRA")) + format = GL_BGRA; + else + THRWEXCP(InvalidImageMode,S_OK); + + done = self->m_image->loadImage((unsigned int *)buffer.buf, buffer.len, format, ts); + } + catch (Exception & exp) { + exp.report(); + } + } + PyBuffer_Release(&buffer); + if (PyErr_Occurred()) { + return NULL; + } + } + } + else { + return NULL; + } + self->m_image->refresh(); - Py_RETURN_NONE; + if (done) + Py_RETURN_TRUE; + Py_RETURN_FALSE; } // get scale diff --git a/source/gameengine/VideoTexture/ImageBase.h b/source/gameengine/VideoTexture/ImageBase.h index f646d145365..4c9fc5a58fb 100644 --- a/source/gameengine/VideoTexture/ImageBase.h +++ b/source/gameengine/VideoTexture/ImageBase.h @@ -40,6 +40,7 @@ #include "FilterBase.h" +#include "glew-mx.h" // forward declarations struct PyImage; @@ -104,6 +105,13 @@ public: /// calculate size(nearest power of 2) static short calcSize(short size); + /// calculate image from sources and send it to a target buffer instead of a texture + /// format is GL_RGBA or GL_BGRA + virtual bool loadImage(unsigned int *buffer, unsigned int size, unsigned int format, double ts); + + /// swap the B and R channel in-place in the image buffer + void swapImageBR(); + /// number of buffer pointing to m_image, public because not handled by this class int m_exports; @@ -348,7 +356,7 @@ PyObject *Image_getImage(PyImage *self, char *mode); // get image size PyObject *Image_getSize(PyImage *self, void *closure); // refresh image - invalidate current content -PyObject *Image_refresh(PyImage *self); +PyObject *Image_refresh(PyImage *self, PyObject *args); // get scale PyObject *Image_getScale(PyImage *self, void *closure); diff --git a/source/gameengine/VideoTexture/ImageMix.cpp b/source/gameengine/VideoTexture/ImageMix.cpp index 973be52e0fc..2de00f5ba05 100644 --- a/source/gameengine/VideoTexture/ImageMix.cpp +++ b/source/gameengine/VideoTexture/ImageMix.cpp @@ -156,7 +156,7 @@ static PyMethodDef imageMixMethods[] = { {"getWeight", (PyCFunction)getWeight, METH_VARARGS, "get image source weight"}, {"setWeight", (PyCFunction)setWeight, METH_VARARGS, "set image source weight"}, // methods from ImageBase class - {"refresh", (PyCFunction)Image_refresh, METH_NOARGS, "Refresh image - invalidate its current content"}, + {"refresh", (PyCFunction)Image_refresh, METH_VARARGS, "Refresh image - invalidate its current content"}, {NULL} }; // attributes structure diff --git a/source/gameengine/VideoTexture/ImageRender.cpp b/source/gameengine/VideoTexture/ImageRender.cpp index a374fbba2df..9991bf42a9f 100644 --- a/source/gameengine/VideoTexture/ImageRender.cpp +++ b/source/gameengine/VideoTexture/ImageRender.cpp @@ -43,6 +43,8 @@ #include "RAS_CameraData.h" #include "RAS_MeshObject.h" #include "RAS_Polygon.h" +#include "RAS_IOffScreen.h" +#include "RAS_ISync.h" #include "BLI_math.h" #include "ImageRender.h" @@ -51,11 +53,12 @@ #include "Exception.h" #include "Texture.h" -ExceptionID SceneInvalid, CameraInvalid, ObserverInvalid; +ExceptionID SceneInvalid, CameraInvalid, ObserverInvalid, OffScreenInvalid; ExceptionID MirrorInvalid, MirrorSizeInvalid, MirrorNormalInvalid, MirrorHorizontal, MirrorTooSmall; ExpDesc SceneInvalidDesc(SceneInvalid, "Scene object is invalid"); ExpDesc CameraInvalidDesc(CameraInvalid, "Camera object is invalid"); ExpDesc ObserverInvalidDesc(ObserverInvalid, "Observer object is invalid"); +ExpDesc OffScreenInvalidDesc(OffScreenInvalid, "Offscreen object is invalid"); ExpDesc MirrorInvalidDesc(MirrorInvalid, "Mirror object is invalid"); ExpDesc MirrorSizeInvalidDesc(MirrorSizeInvalid, "Mirror has no vertex or no size"); ExpDesc MirrorNormalInvalidDesc(MirrorNormalInvalid, "Cannot determine mirror plane"); @@ -63,12 +66,15 @@ ExpDesc MirrorHorizontalDesc(MirrorHorizontal, "Mirror is horizontal in local sp ExpDesc MirrorTooSmallDesc(MirrorTooSmall, "Mirror is too small"); // constructor -ImageRender::ImageRender (KX_Scene *scene, KX_Camera * camera) : - ImageViewport(), +ImageRender::ImageRender (KX_Scene *scene, KX_Camera * camera, PyRASOffScreen * offscreen) : + ImageViewport(offscreen), m_render(true), + m_done(false), m_scene(scene), m_camera(camera), m_owncamera(false), + m_offscreen(offscreen), + m_sync(NULL), m_observer(NULL), m_mirror(NULL), m_clip(100.f), @@ -81,6 +87,10 @@ ImageRender::ImageRender (KX_Scene *scene, KX_Camera * camera) : m_engine = KX_GetActiveEngine(); m_rasterizer = m_engine->GetRasterizer(); m_canvas = m_engine->GetCanvas(); + // keep a reference to the offscreen buffer + if (m_offscreen) { + Py_INCREF(m_offscreen); + } } // destructor @@ -88,6 +98,9 @@ ImageRender::~ImageRender (void) { if (m_owncamera) m_camera->Release(); + if (m_sync) + delete m_sync; + Py_XDECREF(m_offscreen); } // get background color @@ -121,30 +134,41 @@ void ImageRender::setBackgroundFromScene (KX_Scene *scene) // capture image from viewport -void ImageRender::calcImage (unsigned int texId, double ts) +void ImageRender::calcViewport (unsigned int texId, double ts, unsigned int format) { - if (m_rasterizer->GetDrawingMode() != RAS_IRasterizer::KX_TEXTURED || // no need for texture - m_camera->GetViewport() || // camera must be inactive - m_camera == m_scene->GetActiveCamera()) - { - // no need to compute texture in non texture rendering - m_avail = false; - return; - } // render the scene from the camera - Render(); - // get image from viewport - ImageViewport::calcImage(texId, ts); - // restore OpenGL state - m_canvas->EndFrame(); + if (!m_done) { + if (!Render()) { + return; + } + } + else if (m_offscreen) { + m_offscreen->ofs->Bind(RAS_IOffScreen::RAS_OFS_BIND_READ); + } + // wait until all render operations are completed + WaitSync(); + // get image from viewport (or FBO) + ImageViewport::calcViewport(texId, ts, format); + if (m_offscreen) { + m_offscreen->ofs->Unbind(); + } } -void ImageRender::Render() +bool ImageRender::Render() { RAS_FrameFrustum frustum; - if (!m_render) - return; + if (!m_render || + m_rasterizer->GetDrawingMode() != RAS_IRasterizer::KX_TEXTURED || // no need for texture + m_camera->GetViewport() || // camera must be inactive + m_camera == m_scene->GetActiveCamera()) + { + // no need to compute texture in non texture rendering + return false; + } + + if (!m_scene->IsShadowDone()) + m_engine->RenderShadowBuffers(m_scene); if (m_mirror) { @@ -164,7 +188,7 @@ void ImageRender::Render() MT_Scalar observerDistance = mirrorPlaneDTerm - observerWorldPos.dot(mirrorWorldZ); // if distance < 0.01 => observer is on wrong side of mirror, don't render if (observerDistance < 0.01) - return; + return false; // set camera world position = observerPos + normal * 2 * distance MT_Point3 cameraWorldPos = observerWorldPos + (MT_Scalar(2.0)*observerDistance)*mirrorWorldZ; m_camera->GetSGNode()->SetLocalPosition(cameraWorldPos); @@ -215,7 +239,15 @@ void ImageRender::Render() RAS_Rect area = m_canvas->GetWindowArea(); // The screen area that ImageViewport will copy is also the rendering zone - m_canvas->SetViewPort(m_position[0], m_position[1], m_position[0]+m_capSize[0]-1, m_position[1]+m_capSize[1]-1); + if (m_offscreen) { + // bind the fbo and set the viewport to full size + m_offscreen->ofs->Bind(RAS_IOffScreen::RAS_OFS_BIND_RENDER); + // this is needed to stop crashing in canvas check + m_canvas->UpdateViewPort(0, 0, m_offscreen->ofs->GetWidth(), m_offscreen->ofs->GetHeight()); + } + else { + m_canvas->SetViewPort(m_position[0], m_position[1], m_position[0]+m_capSize[0]-1, m_position[1]+m_capSize[1]-1); + } m_canvas->ClearColor(m_background[0], m_background[1], m_background[2], m_background[3]); m_canvas->ClearBuffer(RAS_ICanvas::COLOR_BUFFER|RAS_ICanvas::DEPTH_BUFFER); m_rasterizer->BeginFrame(m_engine->GetClockTime()); @@ -292,17 +324,18 @@ void ImageRender::Render() MT_Transform camtrans(m_camera->GetWorldToCamera()); MT_Matrix4x4 viewmat(camtrans); - m_rasterizer->SetViewMatrix(viewmat, m_camera->NodeGetWorldOrientation(), m_camera->NodeGetWorldPosition(), m_camera->GetCameraData()->m_perspective); + m_rasterizer->SetViewMatrix(viewmat, m_camera->NodeGetWorldOrientation(), m_camera->NodeGetWorldPosition(), m_camera->NodeGetLocalScaling(), m_camera->GetCameraData()->m_perspective); m_camera->SetModelviewMatrix(viewmat); // restore the stereo mode now that the matrix is computed m_rasterizer->SetStereoMode(stereomode); - if (stereomode == RAS_IRasterizer::RAS_STEREO_QUADBUFFERED) { - // In QUAD buffer stereo mode, the GE render pass ends with the right eye on the right buffer - // but we need to draw on the left buffer to capture the render - // TODO: implement an explicit function in rasterizer to restore the left buffer. - m_rasterizer->SetEye(RAS_IRasterizer::RAS_STEREO_LEFTEYE); - } + if (m_rasterizer->Stereo()) { + // stereo mode change render settings that disturb this render, cancel them all + // we don't need to restore them as they are set before each frame render. + glDrawBuffer(GL_BACK_LEFT); + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + glDisable(GL_POLYGON_STIPPLE); + } m_scene->CalculateVisibleMeshes(m_rasterizer,m_camera); @@ -314,8 +347,48 @@ void ImageRender::Render() // restore the canvas area now that the render is completed m_canvas->GetWindowArea() = area; + m_canvas->EndFrame(); + + // In case multisample is active, blit the FBO + if (m_offscreen) + m_offscreen->ofs->Blit(); + // end of all render operations, let's create a sync object just in case + if (m_sync) { + // a sync from a previous render, should not happen + delete m_sync; + m_sync = NULL; + } + m_sync = m_rasterizer->CreateSync(RAS_ISync::RAS_SYNC_TYPE_FENCE); + // remember that we have done render + m_done = true; + // the image is not available at this stage + m_avail = false; + return true; +} + +void ImageRender::Unbind() +{ + if (m_offscreen) + { + m_offscreen->ofs->Unbind(); + } } +void ImageRender::WaitSync() +{ + if (m_sync) { + m_sync->Wait(); + // done with it, deleted it + delete m_sync; + m_sync = NULL; + } + if (m_offscreen) { + // this is needed to finalize the image if the target is a texture + m_offscreen->ofs->MipMap(); + } + // all rendered operation done and complete, invalidate render for next time + m_done = false; +} // cast Image pointer to ImageRender inline ImageRender * getImageRender (PyImage *self) @@ -337,11 +410,13 @@ static int ImageRender_init(PyObject *pySelf, PyObject *args, PyObject *kwds) PyObject *scene; // camera object PyObject *camera; + // offscreen buffer object + PyRASOffScreen *offscreen = NULL; // parameter keywords - static const char *kwlist[] = {"sceneObj", "cameraObj", NULL}; + static const char *kwlist[] = {"sceneObj", "cameraObj", "ofsObj", NULL}; // get parameters - if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO", - const_cast<char**>(kwlist), &scene, &camera)) + if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO|O", + const_cast<char**>(kwlist), &scene, &camera, &offscreen)) return -1; try { @@ -357,11 +432,16 @@ static int ImageRender_init(PyObject *pySelf, PyObject *args, PyObject *kwds) // throw exception if camera is not available if (cameraPtr == NULL) THRWEXCP(CameraInvalid, S_OK); + if (offscreen) { + if (Py_TYPE(offscreen) != &PyRASOffScreen_Type) { + THRWEXCP(OffScreenInvalid, S_OK); + } + } // get pointer to image structure PyImage *self = reinterpret_cast<PyImage*>(pySelf); // create source object if (self->m_image != NULL) delete self->m_image; - self->m_image = new ImageRender(scenePtr, cameraPtr); + self->m_image = new ImageRender(scenePtr, cameraPtr, offscreen); } catch (Exception & exp) { @@ -372,6 +452,55 @@ static int ImageRender_init(PyObject *pySelf, PyObject *args, PyObject *kwds) return 0; } +static PyObject *ImageRender_refresh(PyImage *self, PyObject *args) +{ + ImageRender *imageRender = getImageRender(self); + + if (!imageRender) { + PyErr_SetString(PyExc_TypeError, "Incomplete ImageRender() object"); + return NULL; + } + if (PyArg_ParseTuple(args, "")) { + // refresh called with no argument. + // For other image objects it simply invalidates the image buffer + // For ImageRender it triggers a render+sync + // Note that this only makes sense when doing offscreen render on texture + if (!imageRender->isDone()) { + if (!imageRender->Render()) { + Py_RETURN_FALSE; + } + // as we are not trying to read the pixels, just unbind + imageRender->Unbind(); + } + // wait until all render operations are completed + // this will also finalize the texture + imageRender->WaitSync(); + Py_RETURN_TRUE; + } + else { + // fallback on standard processing + PyErr_Clear(); + return Image_refresh(self, args); + } +} + +// refresh image +static PyObject *ImageRender_render(PyImage *self) +{ + ImageRender *imageRender = getImageRender(self); + + if (!imageRender) { + PyErr_SetString(PyExc_TypeError, "Incomplete ImageRender() object"); + return NULL; + } + if (!imageRender->Render()) { + Py_RETURN_FALSE; + } + // we are not reading the pixels now, unbind + imageRender->Unbind(); + Py_RETURN_TRUE; +} + // get background color static PyObject *getBackground (PyImage *self, void *closure) @@ -410,7 +539,8 @@ static int setBackground(PyImage *self, PyObject *value, void *closure) // methods structure static PyMethodDef imageRenderMethods[] = { // methods from ImageBase class - {"refresh", (PyCFunction)Image_refresh, METH_NOARGS, "Refresh image - invalidate its current content"}, + {"refresh", (PyCFunction)ImageRender_refresh, METH_VARARGS, "Refresh image - invalidate its current content after optionally transferring its content to a target buffer"}, + {"render", (PyCFunction)ImageRender_render, METH_NOARGS, "Render scene - run before refresh() to performs asynchronous render"}, {NULL} }; // attributes structure @@ -601,7 +731,9 @@ static PyGetSetDef imageMirrorGetSets[] = ImageRender::ImageRender (KX_Scene *scene, KX_GameObject *observer, KX_GameObject *mirror, RAS_IPolyMaterial *mat) : ImageViewport(), m_render(false), + m_done(false), m_scene(scene), + m_offscreen(NULL), m_observer(observer), m_mirror(mirror), m_clip(100.f) diff --git a/source/gameengine/VideoTexture/ImageRender.h b/source/gameengine/VideoTexture/ImageRender.h index ef55e4dea84..d062db44348 100644 --- a/source/gameengine/VideoTexture/ImageRender.h +++ b/source/gameengine/VideoTexture/ImageRender.h @@ -39,6 +39,8 @@ #include "DNA_screen_types.h" #include "RAS_ICanvas.h" #include "RAS_IRasterizer.h" +#include "RAS_IOffScreen.h" +#include "RAS_ISync.h" #include "ImageViewport.h" @@ -48,7 +50,7 @@ class ImageRender : public ImageViewport { public: /// constructor - ImageRender(KX_Scene *scene, KX_Camera *camera); + ImageRender(KX_Scene *scene, KX_Camera *camera, PyRASOffScreen *offscreen); ImageRender(KX_Scene *scene, KX_GameObject *observer, KX_GameObject *mirror, RAS_IPolyMaterial * mat); /// destructor @@ -63,16 +65,30 @@ public: float getClip (void) { return m_clip; } /// set whole buffer use void setClip (float clip) { m_clip = clip; } + /// render status + bool isDone() { return m_done; } + /// render frame (public so that it is accessible from python) + bool Render(); + /// in case fbo is used, method to unbind + void Unbind(); + /// wait for render to complete + void WaitSync(); protected: /// true if ready to render bool m_render; + /// is render done already? + bool m_done; /// rendered scene KX_Scene * m_scene; /// camera for render KX_Camera * m_camera; /// do we own the camera? bool m_owncamera; + /// if offscreen render + PyRASOffScreen *m_offscreen; + /// object to synchronize render even if no buffer transfer + RAS_ISync *m_sync; /// for mirror operation KX_GameObject * m_observer; KX_GameObject * m_mirror; @@ -91,15 +107,15 @@ protected: KX_KetsjiEngine* m_engine; /// background color - float m_background[4]; + float m_background[4]; /// render 3d scene to image - virtual void calcImage (unsigned int texId, double ts); + virtual void calcImage (unsigned int texId, double ts) { calcViewport(texId, ts, GL_RGBA); } + + /// render 3d scene to image + virtual void calcViewport (unsigned int texId, double ts, unsigned int format); - void Render(); - void SetupRenderFrame(KX_Scene *scene, KX_Camera* cam); - void RenderFrame(KX_Scene* scene, KX_Camera* cam); void setBackgroundFromScene(KX_Scene *scene); void SetWorldSettings(KX_WorldInfo* wi); }; diff --git a/source/gameengine/VideoTexture/ImageViewport.cpp b/source/gameengine/VideoTexture/ImageViewport.cpp index 820a019832e..8852c190053 100644 --- a/source/gameengine/VideoTexture/ImageViewport.cpp +++ b/source/gameengine/VideoTexture/ImageViewport.cpp @@ -45,14 +45,22 @@ // constructor -ImageViewport::ImageViewport (void) : m_alpha(false), m_texInit(false) +ImageViewport::ImageViewport (PyRASOffScreen *offscreen) : m_alpha(false), m_texInit(false) { // get viewport rectangle - RAS_Rect rect = KX_GetActiveEngine()->GetCanvas()->GetWindowArea(); - m_viewport[0] = rect.GetLeft(); - m_viewport[1] = rect.GetBottom(); - m_viewport[2] = rect.GetWidth(); - m_viewport[3] = rect.GetHeight(); + if (offscreen) { + m_viewport[0] = 0; + m_viewport[1] = 0; + m_viewport[2] = offscreen->ofs->GetWidth(); + m_viewport[3] = offscreen->ofs->GetHeight(); + } + else { + RAS_Rect rect = KX_GetActiveEngine()->GetCanvas()->GetWindowArea(); + m_viewport[0] = rect.GetLeft(); + m_viewport[1] = rect.GetBottom(); + m_viewport[2] = rect.GetWidth(); + m_viewport[3] = rect.GetHeight(); + } //glGetIntegerv(GL_VIEWPORT, m_viewport); // create buffer for viewport image @@ -60,7 +68,7 @@ ImageViewport::ImageViewport (void) : m_alpha(false), m_texInit(false) // float (1 float = 4 bytes per pixel) m_viewportImage = new BYTE [4 * getViewportSize()[0] * getViewportSize()[1]]; // set attributes - setWhole(false); + setWhole((offscreen) ? true : false); } // destructor @@ -126,25 +134,26 @@ void ImageViewport::setPosition (GLint pos[2]) // capture image from viewport -void ImageViewport::calcImage (unsigned int texId, double ts) +void ImageViewport::calcViewport (unsigned int texId, double ts, unsigned int format) { // if scale was changed if (m_scaleChange) // reset image init(m_capSize[0], m_capSize[1]); // if texture wasn't initialized - if (!m_texInit) { + if (!m_texInit && texId != 0) { // initialize it loadTexture(texId, m_image, m_size); m_texInit = true; } // if texture can be directly created - if (texId != 0 && m_pyfilter == NULL && m_capSize[0] == calcSize(m_capSize[0]) - && m_capSize[1] == calcSize(m_capSize[1]) && !m_flip && !m_zbuff && !m_depth) + if (texId != 0 && m_pyfilter == NULL && m_size[0] == m_capSize[0] && + m_size[1] == m_capSize[1] && !m_flip && !m_zbuff && !m_depth) { // just copy current viewport to texture glBindTexture(GL_TEXTURE_2D, texId); glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_upLeft[0], m_upLeft[1], (GLsizei)m_capSize[0], (GLsizei)m_capSize[1]); + glBindTexture(GL_TEXTURE_2D, 0); // image is not available m_avail = false; } @@ -176,11 +185,33 @@ void ImageViewport::calcImage (unsigned int texId, double ts) // get frame buffer data if (m_alpha) { - glReadPixels(m_upLeft[0], m_upLeft[1], (GLsizei)m_capSize[0], (GLsizei)m_capSize[1], GL_RGBA, - GL_UNSIGNED_BYTE, m_viewportImage); - // filter loaded data - FilterRGBA32 filt; - filterImage(filt, m_viewportImage, m_capSize); + // as we are reading the pixel in the native format, we can read directly in the image buffer + // if we are sure that no processing is needed on the image + if (m_size[0] == m_capSize[0] && + m_size[1] == m_capSize[1] && + !m_flip && + !m_pyfilter) + { + glReadPixels(m_upLeft[0], m_upLeft[1], (GLsizei)m_capSize[0], (GLsizei)m_capSize[1], format, + GL_UNSIGNED_BYTE, m_image); + m_avail = true; + } + else if (!m_pyfilter) { + glReadPixels(m_upLeft[0], m_upLeft[1], (GLsizei)m_capSize[0], (GLsizei)m_capSize[1], format, + GL_UNSIGNED_BYTE, m_viewportImage); + FilterRGBA32 filt; + filterImage(filt, m_viewportImage, m_capSize); + } + else { + glReadPixels(m_upLeft[0], m_upLeft[1], (GLsizei)m_capSize[0], (GLsizei)m_capSize[1], GL_RGBA, + GL_UNSIGNED_BYTE, m_viewportImage); + FilterRGBA32 filt; + filterImage(filt, m_viewportImage, m_capSize); + if (format == GL_BGRA) { + // in place byte swapping + swapImageBR(); + } + } } else { glReadPixels(m_upLeft[0], m_upLeft[1], (GLsizei)m_capSize[0], (GLsizei)m_capSize[1], GL_RGB, @@ -188,12 +219,46 @@ void ImageViewport::calcImage (unsigned int texId, double ts) // filter loaded data FilterRGB24 filt; filterImage(filt, m_viewportImage, m_capSize); + if (format == GL_BGRA) { + // in place byte swapping + swapImageBR(); + } } } } } } +bool ImageViewport::loadImage(unsigned int *buffer, unsigned int size, unsigned int format, double ts) +{ + unsigned int *tmp_image; + bool ret; + + // if scale was changed + if (m_scaleChange) { + // reset image + init(m_capSize[0], m_capSize[1]); + } + + // size must be identical + if (size < getBuffSize()) + return false; + + if (m_avail) { + // just copy + return ImageBase::loadImage(buffer, size, format, ts); + } + else { + tmp_image = m_image; + m_image = buffer; + calcViewport(0, ts, format); + ret = m_avail; + m_image = tmp_image; + // since the image was not loaded to our buffer, it's not valid + m_avail = false; + } + return ret; +} // cast Image pointer to ImageViewport @@ -336,7 +401,7 @@ int ImageViewport_setCaptureSize(PyImage *self, PyObject *value, void *closure) // methods structure static PyMethodDef imageViewportMethods[] = { // methods from ImageBase class - {"refresh", (PyCFunction)Image_refresh, METH_NOARGS, "Refresh image - invalidate its current content"}, + {"refresh", (PyCFunction)Image_refresh, METH_VARARGS, "Refresh image - invalidate its current content"}, {NULL} }; // attributes structure diff --git a/source/gameengine/VideoTexture/ImageViewport.h b/source/gameengine/VideoTexture/ImageViewport.h index 10d894a9fb8..8a7e9cfd2ba 100644 --- a/source/gameengine/VideoTexture/ImageViewport.h +++ b/source/gameengine/VideoTexture/ImageViewport.h @@ -35,6 +35,7 @@ #include "Common.h" #include "ImageBase.h" +#include "RAS_IOffScreen.h" /// class for viewport access @@ -42,7 +43,7 @@ class ImageViewport : public ImageBase { public: /// constructor - ImageViewport (void); + ImageViewport (PyRASOffScreen *offscreen=NULL); /// destructor virtual ~ImageViewport (void); @@ -67,6 +68,9 @@ public: /// set position in viewport void setPosition (GLint pos[2] = NULL); + /// capture image from viewport to user buffer + virtual bool loadImage(unsigned int *buffer, unsigned int size, unsigned int format, double ts); + protected: /// frame buffer rectangle GLint m_viewport[4]; @@ -89,7 +93,10 @@ protected: bool m_texInit; /// capture image from viewport - virtual void calcImage (unsigned int texId, double ts); + virtual void calcImage (unsigned int texId, double ts) { calcViewport(texId, ts, GL_RGBA); } + + /// capture image from viewport + virtual void calcViewport (unsigned int texId, double ts, unsigned int format); /// get viewport size GLint * getViewportSize (void) { return m_viewport + 2; } diff --git a/source/gameengine/VideoTexture/Texture.cpp b/source/gameengine/VideoTexture/Texture.cpp index f1c7bc303ee..bb995747360 100644 --- a/source/gameengine/VideoTexture/Texture.cpp +++ b/source/gameengine/VideoTexture/Texture.cpp @@ -393,9 +393,10 @@ static PyObject *Texture_refresh(Texture *self, PyObject *args) } // load texture for rendering loadTexture(self->m_actTex, texture, size, self->m_mipmap); - - // refresh texture source, if required - if (refreshSource) self->m_source->m_image->refresh(); + } + // refresh texture source, if required + if (refreshSource) { + self->m_source->m_image->refresh(); } } } diff --git a/source/gameengine/VideoTexture/VideoBase.cpp b/source/gameengine/VideoTexture/VideoBase.cpp index 9c8df0ca8c4..d373055b5df 100644 --- a/source/gameengine/VideoTexture/VideoBase.cpp +++ b/source/gameengine/VideoTexture/VideoBase.cpp @@ -137,8 +137,53 @@ PyObject *Video_getStatus(PyImage *self, void *closure) } // refresh video -PyObject *Video_refresh(PyImage *self) +PyObject *Video_refresh(PyImage *self, PyObject *args) { + Py_buffer buffer; + char *mode = NULL; + unsigned int format; + double ts = -1.0; + + memset(&buffer, 0, sizeof(buffer)); + if (PyArg_ParseTuple(args, "|s*sd:refresh", &buffer, &mode, &ts)) { + if (buffer.buf) { + // a target buffer is provided, verify its format + if (buffer.readonly) { + PyErr_SetString(PyExc_TypeError, "Buffers passed in argument must be writable"); + } + else if (!PyBuffer_IsContiguous(&buffer, 'C')) { + PyErr_SetString(PyExc_TypeError, "Buffers passed in argument must be contiguous in memory"); + } + else if (((intptr_t)buffer.buf & 3) != 0) { + PyErr_SetString(PyExc_TypeError, "Buffers passed in argument must be aligned to 4 bytes boundary"); + } + else { + // ready to get the image into our buffer + try { + if (mode == NULL || !strcmp(mode, "RGBA")) + format = GL_RGBA; + else if (!strcmp(mode, "BGRA")) + format = GL_BGRA; + else + THRWEXCP(InvalidImageMode,S_OK); + + if (!self->m_image->loadImage((unsigned int *)buffer.buf, buffer.len, format, ts)) { + PyErr_SetString(PyExc_TypeError, "Could not load the buffer, perhaps size is not compatible"); + } + } + catch (Exception & exp) { + exp.report(); + } + } + PyBuffer_Release(&buffer); + if (PyErr_Occurred()) + return NULL; + } + } + else + { + return NULL; + } getVideo(self)->refresh(); return Video_getStatus(self, NULL); } diff --git a/source/gameengine/VideoTexture/VideoBase.h b/source/gameengine/VideoTexture/VideoBase.h index 6f35c474300..77f46fdccd8 100644 --- a/source/gameengine/VideoTexture/VideoBase.h +++ b/source/gameengine/VideoTexture/VideoBase.h @@ -190,7 +190,7 @@ void Video_open(VideoBase *self, char *file, short captureID); PyObject *Video_play(PyImage *self); PyObject *Video_pause(PyImage *self); PyObject *Video_stop(PyImage *self); -PyObject *Video_refresh(PyImage *self); +PyObject *Video_refresh(PyImage *self, PyObject *args); PyObject *Video_getStatus(PyImage *self, void *closure); PyObject *Video_getRange(PyImage *self, void *closure); int Video_setRange(PyImage *self, PyObject *value, void *closure); diff --git a/source/gameengine/VideoTexture/VideoDeckLink.cpp b/source/gameengine/VideoTexture/VideoDeckLink.cpp new file mode 100644 index 00000000000..4f5e34896fc --- /dev/null +++ b/source/gameengine/VideoTexture/VideoDeckLink.cpp @@ -0,0 +1,1228 @@ +/* + * ***** 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. + * + * The Original Code is Copyright (C) 2015, Blender Foundation + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Blender Foundation. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file gameengine/VideoTexture/VideoDeckLink.cpp + * \ingroup bgevideotex + */ + +#ifdef WITH_GAMEENGINE_DECKLINK + +// FFmpeg defines its own version of stdint.h on Windows. +// Decklink needs FFmpeg, so it uses its version of stdint.h +// this is necessary for INT64_C macro +#ifndef __STDC_CONSTANT_MACROS +#define __STDC_CONSTANT_MACROS +#endif +// this is necessary for UINTPTR_MAX (used by atomic-ops) +#ifndef __STDC_LIMIT_MACROS +#define __STDC_LIMIT_MACROS +#ifdef __STDC_LIMIT_MACROS /* else it may be unused */ +#endif +#endif +#include <stdint.h> +#include <string.h> +#ifndef WIN32 +#include <sys/time.h> +#include <sys/resource.h> +#include <sys/mman.h> +#endif + +#include "atomic_ops.h" + +#include "MEM_guardedalloc.h" +#include "PIL_time.h" +#include "VideoDeckLink.h" +#include "DeckLink.h" +#include "Exception.h" +#include "KX_KetsjiEngine.h" +#include "KX_PythonInit.h" + +extern ExceptionID DeckLinkInternalError; +ExceptionID SourceVideoOnlyCapture, VideoDeckLinkBadFormat, VideoDeckLinkOpenCard, VideoDeckLinkDvpInternalError, VideoDeckLinkPinMemoryError; +ExpDesc SourceVideoOnlyCaptureDesc(SourceVideoOnlyCapture, "This video source only allows live capture"); +ExpDesc VideoDeckLinkBadFormatDesc(VideoDeckLinkBadFormat, "Invalid or unsupported capture format, should be <mode>/<pixel>[/3D]"); +ExpDesc VideoDeckLinkOpenCardDesc(VideoDeckLinkOpenCard, "Cannot open capture card, check if driver installed"); +ExpDesc VideoDeckLinkDvpInternalErrorDesc(VideoDeckLinkDvpInternalError, "DVP API internal error, please report"); +ExpDesc VideoDeckLinkPinMemoryErrorDesc(VideoDeckLinkPinMemoryError, "Error pinning memory"); + + +#ifdef WIN32 +//////////////////////////////////////////// +// SynInfo +// +// Sets up a semaphore which is shared between the GPU and CPU and used to +// synchronise access to DVP buffers. +#define DVP_CHECK(cmd) if ((cmd) != DVP_STATUS_OK) THRWEXCP(VideoDeckLinkDvpInternalError, S_OK) + +struct SyncInfo +{ + SyncInfo(uint32_t semaphoreAllocSize, uint32_t semaphoreAddrAlignment) + { + mSemUnaligned = (uint32_t*)malloc(semaphoreAllocSize + semaphoreAddrAlignment - 1); + + // Apply alignment constraints + uint64_t val = (uint64_t)mSemUnaligned; + val += semaphoreAddrAlignment - 1; + val &= ~((uint64_t)semaphoreAddrAlignment - 1); + mSem = (uint32_t*)val; + + // Initialise + mSem[0] = 0; + mReleaseValue = 0; + mAcquireValue = 0; + + // Setup DVP sync object and import it + DVPSyncObjectDesc syncObjectDesc; + syncObjectDesc.externalClientWaitFunc = NULL; + syncObjectDesc.sem = (uint32_t*)mSem; + + DVP_CHECK(dvpImportSyncObject(&syncObjectDesc, &mDvpSync)); + + } + ~SyncInfo() + { + dvpFreeSyncObject(mDvpSync); + free((void*)mSemUnaligned); + } + + volatile uint32_t* mSem; + volatile uint32_t* mSemUnaligned; + volatile uint32_t mReleaseValue; + volatile uint32_t mAcquireValue; + DVPSyncObjectHandle mDvpSync; +}; + +//////////////////////////////////////////// +// TextureTransferDvp: transfer with GPUDirect +//////////////////////////////////////////// + +class TextureTransferDvp : public TextureTransfer +{ +public: + TextureTransferDvp(DVPBufferHandle dvpTextureHandle, TextureDesc *pDesc, void *address, uint32_t allocatedSize) + { + DVPSysmemBufferDesc sysMemBuffersDesc; + + mExtSync = NULL; + mGpuSync = NULL; + mDvpSysMemHandle = 0; + mDvpTextureHandle = 0; + mTextureHeight = 0; + mAllocatedSize = 0; + mBuffer = NULL; + + if (!_PinBuffer(address, allocatedSize)) + THRWEXCP(VideoDeckLinkPinMemoryError, S_OK); + mAllocatedSize = allocatedSize; + mBuffer = address; + + try { + if (!mBufferAddrAlignment) { + DVP_CHECK(dvpGetRequiredConstantsGLCtx(&mBufferAddrAlignment, &mBufferGpuStrideAlignment, + &mSemaphoreAddrAlignment, &mSemaphoreAllocSize, + &mSemaphorePayloadOffset, &mSemaphorePayloadSize)); + } + mExtSync = new SyncInfo(mSemaphoreAllocSize, mSemaphoreAddrAlignment); + mGpuSync = new SyncInfo(mSemaphoreAllocSize, mSemaphoreAddrAlignment); + sysMemBuffersDesc.width = pDesc->width; + sysMemBuffersDesc.height = pDesc->height; + sysMemBuffersDesc.stride = pDesc->stride; + switch (pDesc->format) { + case GL_RED_INTEGER: + sysMemBuffersDesc.format = DVP_RED_INTEGER; + break; + default: + sysMemBuffersDesc.format = DVP_BGRA; + break; + } + switch (pDesc->type) { + case GL_UNSIGNED_BYTE: + sysMemBuffersDesc.type = DVP_UNSIGNED_BYTE; + break; + case GL_UNSIGNED_INT_2_10_10_10_REV: + sysMemBuffersDesc.type = DVP_UNSIGNED_INT_2_10_10_10_REV; + break; + case GL_UNSIGNED_INT_8_8_8_8: + sysMemBuffersDesc.type = DVP_UNSIGNED_INT_8_8_8_8; + break; + case GL_UNSIGNED_INT_10_10_10_2: + sysMemBuffersDesc.type = DVP_UNSIGNED_INT_10_10_10_2; + break; + default: + sysMemBuffersDesc.type = DVP_UNSIGNED_INT; + break; + } + sysMemBuffersDesc.size = pDesc->width * pDesc->height * 4; + sysMemBuffersDesc.bufAddr = mBuffer; + DVP_CHECK(dvpCreateBuffer(&sysMemBuffersDesc, &mDvpSysMemHandle)); + DVP_CHECK(dvpBindToGLCtx(mDvpSysMemHandle)); + mDvpTextureHandle = dvpTextureHandle; + mTextureHeight = pDesc->height; + } + catch (Exception &) { + clean(); + throw; + } + } + ~TextureTransferDvp() + { + clean(); + } + + virtual void PerformTransfer() + { + // perform the transfer + // tell DVP that the old texture buffer will no longer be used + dvpMapBufferEndAPI(mDvpTextureHandle); + // do we need this? + mGpuSync->mReleaseValue++; + dvpBegin(); + // Copy from system memory to GPU texture + dvpMapBufferWaitDVP(mDvpTextureHandle); + dvpMemcpyLined(mDvpSysMemHandle, mExtSync->mDvpSync, mExtSync->mAcquireValue, DVP_TIMEOUT_IGNORED, + mDvpTextureHandle, mGpuSync->mDvpSync, mGpuSync->mReleaseValue, 0, mTextureHeight); + dvpMapBufferEndDVP(mDvpTextureHandle); + dvpEnd(); + dvpMapBufferWaitAPI(mDvpTextureHandle); + // the transfer is now complete and the texture is ready for use + } + +private: + static uint32_t mBufferAddrAlignment; + static uint32_t mBufferGpuStrideAlignment; + static uint32_t mSemaphoreAddrAlignment; + static uint32_t mSemaphoreAllocSize; + static uint32_t mSemaphorePayloadOffset; + static uint32_t mSemaphorePayloadSize; + + void clean() + { + if (mDvpSysMemHandle) { + dvpUnbindFromGLCtx(mDvpSysMemHandle); + dvpDestroyBuffer(mDvpSysMemHandle); + } + if (mExtSync) + delete mExtSync; + if (mGpuSync) + delete mGpuSync; + if (mBuffer) + _UnpinBuffer(mBuffer, mAllocatedSize); + } + SyncInfo* mExtSync; + SyncInfo* mGpuSync; + DVPBufferHandle mDvpSysMemHandle; + DVPBufferHandle mDvpTextureHandle; + uint32_t mTextureHeight; + uint32_t mAllocatedSize; + void* mBuffer; +}; + +uint32_t TextureTransferDvp::mBufferAddrAlignment; +uint32_t TextureTransferDvp::mBufferGpuStrideAlignment; +uint32_t TextureTransferDvp::mSemaphoreAddrAlignment; +uint32_t TextureTransferDvp::mSemaphoreAllocSize; +uint32_t TextureTransferDvp::mSemaphorePayloadOffset; +uint32_t TextureTransferDvp::mSemaphorePayloadSize; + +#endif + +//////////////////////////////////////////// +// TextureTransferOGL: transfer using standard OGL buffers +//////////////////////////////////////////// + +class TextureTransferOGL : public TextureTransfer +{ +public: + TextureTransferOGL(GLuint texId, TextureDesc *pDesc, void *address) + { + memcpy(&mDesc, pDesc, sizeof(mDesc)); + mTexId = texId; + mBuffer = address; + + // as we cache transfer object, we will create one texture to hold the buffer + glGenBuffers(1, &mUnpinnedTextureBuffer); + // create a storage for it + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, mUnpinnedTextureBuffer); + glBufferData(GL_PIXEL_UNPACK_BUFFER, pDesc->size, NULL, GL_DYNAMIC_DRAW); + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); + } + ~TextureTransferOGL() + { + glDeleteBuffers(1, &mUnpinnedTextureBuffer); + } + + virtual void PerformTransfer() + { + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, mUnpinnedTextureBuffer); + glBufferSubData(GL_PIXEL_UNPACK_BUFFER, 0, mDesc.size, mBuffer); + glBindTexture(GL_TEXTURE_2D, mTexId); + // NULL for last arg indicates use current GL_PIXEL_UNPACK_BUFFER target as texture data + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, mDesc.width, mDesc.height, mDesc.format, mDesc.type, NULL); + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); + } +private: + // intermediate texture to receive the buffer + GLuint mUnpinnedTextureBuffer; + // target texture to receive the image + GLuint mTexId; + // buffer + void *mBuffer; + // characteristic of the image + TextureDesc mDesc; +}; + +//////////////////////////////////////////// +// TextureTransferPMB: transfer using pinned memory buffer +//////////////////////////////////////////// + +class TextureTransferPMD : public TextureTransfer +{ +public: + TextureTransferPMD(GLuint texId, TextureDesc *pDesc, void *address, uint32_t allocatedSize) + { + memcpy(&mDesc, pDesc, sizeof(mDesc)); + mTexId = texId; + mBuffer = address; + mAllocatedSize = allocatedSize; + + _PinBuffer(address, allocatedSize); + + // as we cache transfer object, we will create one texture to hold the buffer + glGenBuffers(1, &mPinnedTextureBuffer); + // create a storage for it + glBindBuffer(GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD, mPinnedTextureBuffer); + glBufferData(GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD, pDesc->size, address, GL_STREAM_DRAW); + glBindBuffer(GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD, 0); + } + ~TextureTransferPMD() + { + glDeleteBuffers(1, &mPinnedTextureBuffer); + if (mBuffer) + _UnpinBuffer(mBuffer, mAllocatedSize); + } + + virtual void PerformTransfer() + { + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, mPinnedTextureBuffer); + glBindTexture(GL_TEXTURE_2D, mTexId); + // NULL for last arg indicates use current GL_PIXEL_UNPACK_BUFFER target as texture data + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, mDesc.width, mDesc.height, mDesc.format, mDesc.type, NULL); + // wait for the trasnfer to complete + GLsync fence = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); + glClientWaitSync(fence, GL_SYNC_FLUSH_COMMANDS_BIT, 40 * 1000 * 1000); // timeout in nanosec + glDeleteSync(fence); + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); + } +private: + // intermediate texture to receive the buffer + GLuint mPinnedTextureBuffer; + // target texture to receive the image + GLuint mTexId; + // buffer + void *mBuffer; + // the allocated size + uint32_t mAllocatedSize; + // characteristic of the image + TextureDesc mDesc; +}; + +bool TextureTransfer::_PinBuffer(void *address, uint32_t size) +{ +#ifdef WIN32 + return VirtualLock(address, size); +#elif defined(_POSIX_MEMLOCK_RANGE) + return !mlock(address, size); +#endif +} + +void TextureTransfer::_UnpinBuffer(void* address, uint32_t size) +{ +#ifdef WIN32 + VirtualUnlock(address, size); +#elif defined(_POSIX_MEMLOCK_RANGE) + munlock(address, size); +#endif +} + + + +//////////////////////////////////////////// +// PinnedMemoryAllocator +//////////////////////////////////////////// + + +// static members +bool PinnedMemoryAllocator::mGPUDirectInitialized = false; +bool PinnedMemoryAllocator::mHasDvp = false; +bool PinnedMemoryAllocator::mHasAMDPinnedMemory = false; +size_t PinnedMemoryAllocator::mReservedProcessMemory = 0; + +bool PinnedMemoryAllocator::ReserveMemory(size_t size) +{ +#ifdef WIN32 + // Increase the process working set size to allow pinning of memory. + if (size <= mReservedProcessMemory) + return true; + SIZE_T dwMin = 0, dwMax = 0; + HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_SET_QUOTA, FALSE, GetCurrentProcessId()); + if (!hProcess) + return false; + + // Retrieve the working set size of the process. + if (!dwMin && !GetProcessWorkingSetSize(hProcess, &dwMin, &dwMax)) + return false; + + BOOL res = SetProcessWorkingSetSize(hProcess, (size - mReservedProcessMemory) + dwMin, (size - mReservedProcessMemory) + dwMax); + if (!res) + return false; + mReservedProcessMemory = size; + CloseHandle(hProcess); + return true; +#else + struct rlimit rlim; + if (getrlimit(RLIMIT_MEMLOCK, &rlim) == 0) { + if (rlim.rlim_cur < size) { + if (rlim.rlim_max < size) + rlim.rlim_max = size; + rlim.rlim_cur = size; + return !setrlimit(RLIMIT_MEMLOCK, &rlim); + } + } + return false; +#endif +} + +PinnedMemoryAllocator::PinnedMemoryAllocator(unsigned cacheSize, size_t memSize) : +mRefCount(1U), +#ifdef WIN32 +mDvpCaptureTextureHandle(0), +#endif +mTexId(0), +mBufferCacheSize(cacheSize) +{ + pthread_mutex_init(&mMutex, NULL); + // do it once + if (!mGPUDirectInitialized) { +#ifdef WIN32 + // In windows, AMD_pinned_memory option is not available, + // we must use special DVP API only available for Quadro cards + const char* renderer = (const char *)glGetString(GL_RENDERER); + mHasDvp = (strstr(renderer, "Quadro") != NULL); + + if (mHasDvp) { + // In case the DLL is not in place, don't fail, just fallback on OpenGL + if (dvpInitGLContext(DVP_DEVICE_FLAGS_SHARE_APP_CONTEXT) != DVP_STATUS_OK) { + printf("Warning: Could not initialize DVP context, fallback on OpenGL transfer.\nInstall dvp.dll to take advantage of nVidia GPUDirect.\n"); + mHasDvp = false; + } + } +#endif + if (GLEW_AMD_pinned_memory) + mHasAMDPinnedMemory = true; + + mGPUDirectInitialized = true; + } + if (mHasDvp || mHasAMDPinnedMemory) { + ReserveMemory(memSize); + } +} + +PinnedMemoryAllocator::~PinnedMemoryAllocator() +{ + void *address; + // first clean the cache if not already done + while (!mBufferCache.empty()) { + address = mBufferCache.back(); + mBufferCache.pop_back(); + _ReleaseBuffer(address); + } + // clean preallocated buffers + while (!mAllocatedSize.empty()) { + address = mAllocatedSize.begin()->first; + _ReleaseBuffer(address); + } + +#ifdef WIN32 + if (mDvpCaptureTextureHandle) + dvpDestroyBuffer(mDvpCaptureTextureHandle); +#endif +} + +void PinnedMemoryAllocator::TransferBuffer(void* address, TextureDesc* texDesc, GLuint texId) +{ + uint32_t allocatedSize = 0; + TextureTransfer *pTransfer = NULL; + + Lock(); + if (mAllocatedSize.count(address) > 0) + allocatedSize = mAllocatedSize[address]; + Unlock(); + if (!allocatedSize) + // internal error!! + return; + if (mTexId != texId) + { + // first time we try to send data to the GPU, allocate a buffer for the texture + glBindTexture(GL_TEXTURE_2D, texId); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); + glTexImage2D(GL_TEXTURE_2D, 0, texDesc->internalFormat, texDesc->width, texDesc->height, 0, texDesc->format, texDesc->type, NULL); + glBindTexture(GL_TEXTURE_2D, 0); + mTexId = texId; + } +#ifdef WIN32 + if (mHasDvp) + { + if (!mDvpCaptureTextureHandle) + { + // bind DVP to the OGL texture + DVP_CHECK(dvpCreateGPUTextureGL(texId, &mDvpCaptureTextureHandle)); + } + } +#endif + Lock(); + if (mPinnedBuffer.count(address) > 0) + { + pTransfer = mPinnedBuffer[address]; + } + Unlock(); + if (!pTransfer) + { +#ifdef WIN32 + if (mHasDvp) + pTransfer = new TextureTransferDvp(mDvpCaptureTextureHandle, texDesc, address, allocatedSize); + else +#endif + if (mHasAMDPinnedMemory) { + pTransfer = new TextureTransferPMD(texId, texDesc, address, allocatedSize); + } + else { + pTransfer = new TextureTransferOGL(texId, texDesc, address); + } + if (pTransfer) + { + Lock(); + mPinnedBuffer[address] = pTransfer; + Unlock(); + } + } + if (pTransfer) + pTransfer->PerformTransfer(); +} + +// IUnknown methods +HRESULT STDMETHODCALLTYPE PinnedMemoryAllocator::QueryInterface(REFIID /*iid*/, LPVOID* /*ppv*/) +{ + return E_NOTIMPL; +} + +ULONG STDMETHODCALLTYPE PinnedMemoryAllocator::AddRef(void) +{ + return atomic_add_uint32(&mRefCount, 1U); +} + +ULONG STDMETHODCALLTYPE PinnedMemoryAllocator::Release(void) +{ + uint32_t newCount = atomic_sub_uint32(&mRefCount, 1U); + if (newCount == 0) + delete this; + return (ULONG)newCount; +} + +// IDeckLinkMemoryAllocator methods +HRESULT STDMETHODCALLTYPE PinnedMemoryAllocator::AllocateBuffer(dl_size_t bufferSize, void* *allocatedBuffer) +{ + Lock(); + if (mBufferCache.empty()) + { + // Allocate memory on a page boundary + // Note: aligned alloc exist in Blender but only for small alignment, use direct allocation then. + // Note: the DeckLink API tries to allocate up to 65 buffer in advance, we will limit this to 3 + // because we don't need any caching + if (mAllocatedSize.size() >= mBufferCacheSize) + *allocatedBuffer = NULL; + else { +#ifdef WIN32 + *allocatedBuffer = VirtualAlloc(NULL, bufferSize, MEM_COMMIT | MEM_RESERVE | MEM_WRITE_WATCH, PAGE_READWRITE); +#else + if (posix_memalign(allocatedBuffer, 4096, bufferSize) != 0) + *allocatedBuffer = NULL; +#endif + mAllocatedSize[*allocatedBuffer] = bufferSize; + } + } + else { + // Re-use most recently ReleaseBuffer'd address + *allocatedBuffer = mBufferCache.back(); + mBufferCache.pop_back(); + } + Unlock(); + return (*allocatedBuffer) ? S_OK : E_OUTOFMEMORY; +} + +HRESULT STDMETHODCALLTYPE PinnedMemoryAllocator::ReleaseBuffer(void* buffer) +{ + HRESULT result = S_OK; + Lock(); + if (mBufferCache.size() < mBufferCacheSize) { + mBufferCache.push_back(buffer); + } + else { + result = _ReleaseBuffer(buffer); + } + Unlock(); + return result; +} + + +HRESULT PinnedMemoryAllocator::_ReleaseBuffer(void* buffer) +{ + TextureTransfer *pTransfer; + if (mAllocatedSize.count(buffer) == 0) { + // Internal error!! + return S_OK; + } + else { + // No room left in cache, so un-pin (if it was pinned) and free this buffer + if (mPinnedBuffer.count(buffer) > 0) { + pTransfer = mPinnedBuffer[buffer]; + mPinnedBuffer.erase(buffer); + delete pTransfer; + } +#ifdef WIN32 + VirtualFree(buffer, 0, MEM_RELEASE); +#else + free(buffer); +#endif + mAllocatedSize.erase(buffer); + } + return S_OK; +} + +HRESULT STDMETHODCALLTYPE PinnedMemoryAllocator::Commit() +{ + return S_OK; +} + +HRESULT STDMETHODCALLTYPE PinnedMemoryAllocator::Decommit() +{ + void *buffer; + Lock(); + while (!mBufferCache.empty()) { + // Cleanup any frames allocated and pinned in AllocateBuffer() but not freed in ReleaseBuffer() + buffer = mBufferCache.back(); + mBufferCache.pop_back(); + _ReleaseBuffer(buffer); + } + Unlock(); + return S_OK; +} + + +//////////////////////////////////////////// +// Capture Delegate Class +//////////////////////////////////////////// + +CaptureDelegate::CaptureDelegate(VideoDeckLink* pOwner) : mpOwner(pOwner) +{ +} + +HRESULT CaptureDelegate::VideoInputFrameArrived(IDeckLinkVideoInputFrame* inputFrame, IDeckLinkAudioInputPacket* /*audioPacket*/) +{ + if (!inputFrame) { + // It's possible to receive a NULL inputFrame, but a valid audioPacket. Ignore audio-only frame. + return S_OK; + } + if ((inputFrame->GetFlags() & bmdFrameHasNoInputSource) == bmdFrameHasNoInputSource) { + // let's not bother transferring frames if there is no source + return S_OK; + } + mpOwner->VideoFrameArrived(inputFrame); + return S_OK; +} + +HRESULT CaptureDelegate::VideoInputFormatChanged(BMDVideoInputFormatChangedEvents notificationEvents, IDeckLinkDisplayMode *newDisplayMode, BMDDetectedVideoInputFormatFlags detectedSignalFlags) +{ + return S_OK; +} + + + + +// macro for exception handling and logging +#define CATCH_EXCP catch (Exception & exp) \ +{ exp.report(); m_status = SourceError; } + +// class VideoDeckLink + + +// constructor +VideoDeckLink::VideoDeckLink (HRESULT * hRslt) : VideoBase(), +mDLInput(NULL), +mUse3D(false), +mFrameWidth(0), +mFrameHeight(0), +mpAllocator(NULL), +mpCaptureDelegate(NULL), +mpCacheFrame(NULL), +mClosing(false) +{ + mDisplayMode = (BMDDisplayMode)0; + mPixelFormat = (BMDPixelFormat)0; + pthread_mutex_init(&mCacheMutex, NULL); +} + +// destructor +VideoDeckLink::~VideoDeckLink () +{ + LockCache(); + mClosing = true; + if (mpCacheFrame) + { + mpCacheFrame->Release(); + mpCacheFrame = NULL; + } + UnlockCache(); + if (mDLInput != NULL) + { + // Cleanup for Capture + mDLInput->StopStreams(); + mDLInput->SetCallback(NULL); + mDLInput->DisableVideoInput(); + mDLInput->DisableAudioInput(); + mDLInput->FlushStreams(); + if (mDLInput->Release() != 0) { + printf("Reference count not NULL on DeckLink device when closing it, please report!\n"); + } + mDLInput = NULL; + } + + if (mpAllocator) + { + // if the device was properly cleared, this should be 0 + if (mpAllocator->Release() != 0) { + printf("Reference count not NULL on Allocator when closing it, please report!\n"); + } + mpAllocator = NULL; + } + if (mpCaptureDelegate) + { + delete mpCaptureDelegate; + mpCaptureDelegate = NULL; + } +} + +void VideoDeckLink::refresh(void) +{ + m_avail = false; +} + +// release components +bool VideoDeckLink::release() +{ + // release + return true; +} + +// open video file +void VideoDeckLink::openFile (char *filename) +{ + // only live capture on this device + THRWEXCP(SourceVideoOnlyCapture, S_OK); +} + + +// open video capture device +void VideoDeckLink::openCam (char *format, short camIdx) +{ + IDeckLinkDisplayModeIterator* pDLDisplayModeIterator; + BMDDisplayModeSupport modeSupport; + IDeckLinkDisplayMode* pDLDisplayMode; + IDeckLinkIterator* pIterator; + BMDTimeValue frameDuration; + BMDTimeScale frameTimescale; + IDeckLink* pDL; + uint32_t displayFlags, inputFlags; + char *pPixel, *p3D, *pEnd, *pSize; + size_t len; + int i, modeIdx, cacheSize; + + // format is constructed as <displayMode>/<pixelFormat>[/3D][:<cacheSize>] + // <displayMode> takes the form of BMDDisplayMode identifier minus the 'bmdMode' prefix. + // This implementation understands all the modes defined in SDK 10.3.1 but you can alternatively + // use the 4 characters internal representation of the mode (e.g. 'HD1080p24' == '24ps') + // <pixelFormat> takes the form of BMDPixelFormat identifier minus the 'bmdFormat' prefix. + // This implementation understand all the formats defined in SDK 10.32.1 but you can alternatively + // use the 4 characters internal representation of the format (e.g. '10BitRGB' == 'r210') + // Not all combinations of mode and pixel format are possible and it also depends on the card! + // Use /3D postfix if you are capturing a 3D stream with frame packing + // Example: To capture FullHD 1920x1080@24Hz with 3D packing and 4:4:4 10 bits RGB pixel format, use + // "HD1080p24/10BitRGB/3D" (same as "24ps/r210/3D") + // (this will be the normal capture format for FullHD on the DeckLink 4k extreme) + + if ((pSize = strchr(format, ':')) != NULL) { + cacheSize = strtol(pSize+1, &pEnd, 10); + } + else { + cacheSize = 8; + pSize = format + strlen(format); + } + if ((pPixel = strchr(format, '/')) == NULL || + ((p3D = strchr(pPixel + 1, '/')) != NULL && strncmp(p3D, "/3D", pSize-p3D))) + THRWEXCP(VideoDeckLinkBadFormat, S_OK); + mUse3D = (p3D) ? true : false; + // to simplify pixel format parsing + if (!p3D) + p3D = pSize; + + // read the mode + len = (size_t)(pPixel - format); + // accept integer display mode + + try { + // throws if bad mode + decklink_ReadDisplayMode(format, len, &mDisplayMode); + // found a valid mode, remember that we do not look for an index + modeIdx = -1; + } + catch (Exception &) { + // accept also purely numerical mode as a mode index + modeIdx = strtol(format, &pEnd, 10); + if (pEnd != pPixel || modeIdx < 0) + // not a pure number, give up + throw; + } + + // skip / + pPixel++; + len = (size_t)(p3D - pPixel); + // throws if bad format + decklink_ReadPixelFormat(pPixel, len, &mPixelFormat); + + // Caution: DeckLink API used from this point, make sure entity are released before throwing + // open the card + pIterator = BMD_CreateDeckLinkIterator(); + if (pIterator) { + i = 0; + while (pIterator->Next(&pDL) == S_OK) { + if (i == camIdx) { + if (pDL->QueryInterface(IID_IDeckLinkInput, (void**)&mDLInput) != S_OK) + mDLInput = NULL; + pDL->Release(); + break; + } + i++; + pDL->Release(); + } + pIterator->Release(); + } + if (!mDLInput) + THRWEXCP(VideoDeckLinkOpenCard, S_OK); + + + // check if display mode and pixel format are supported + if (mDLInput->GetDisplayModeIterator(&pDLDisplayModeIterator) != S_OK) + THRWEXCP(DeckLinkInternalError, S_OK); + + pDLDisplayMode = NULL; + displayFlags = (mUse3D) ? bmdDisplayModeSupports3D : 0; + inputFlags = (mUse3D) ? bmdVideoInputDualStream3D : bmdVideoInputFlagDefault; + while (pDLDisplayModeIterator->Next(&pDLDisplayMode) == S_OK) + { + if (modeIdx == 0 || pDLDisplayMode->GetDisplayMode() == mDisplayMode) { + // in case we get here because of modeIdx, make sure we have mDisplayMode set + mDisplayMode = pDLDisplayMode->GetDisplayMode(); + if ((pDLDisplayMode->GetFlags() & displayFlags) == displayFlags && + mDLInput->DoesSupportVideoMode(mDisplayMode, mPixelFormat, inputFlags, &modeSupport, NULL) == S_OK && + modeSupport == bmdDisplayModeSupported) + { + break; + } + } + pDLDisplayMode->Release(); + pDLDisplayMode = NULL; + if (modeIdx-- == 0) { + // reached the correct mode index but it does not meet the pixel format, give up + break; + } + } + pDLDisplayModeIterator->Release(); + + if (pDLDisplayMode == NULL) + THRWEXCP(VideoDeckLinkBadFormat, S_OK); + + mFrameWidth = pDLDisplayMode->GetWidth(); + mFrameHeight = pDLDisplayMode->GetHeight(); + mTextureDesc.height = (mUse3D) ? 2 * mFrameHeight : mFrameHeight; + pDLDisplayMode->GetFrameRate(&frameDuration, &frameTimescale); + pDLDisplayMode->Release(); + // for information, in case the application wants to know + m_size[0] = mFrameWidth; + m_size[1] = mTextureDesc.height; + m_frameRate = (float)frameTimescale / (float)frameDuration; + + switch (mPixelFormat) + { + case bmdFormat8BitYUV: + // 2 pixels per word + mTextureDesc.stride = mFrameWidth * 2; + mTextureDesc.width = mFrameWidth / 2; + mTextureDesc.internalFormat = GL_RGBA; + mTextureDesc.format = GL_BGRA; + mTextureDesc.type = GL_UNSIGNED_BYTE; + break; + case bmdFormat10BitYUV: + // 6 pixels in 4 words, rounded to 48 pixels + mTextureDesc.stride = ((mFrameWidth + 47) / 48) * 128; + mTextureDesc.width = mTextureDesc.stride/4; + mTextureDesc.internalFormat = GL_RGB10_A2; + mTextureDesc.format = GL_BGRA; + mTextureDesc.type = GL_UNSIGNED_INT_2_10_10_10_REV; + break; + case bmdFormat8BitARGB: + mTextureDesc.stride = mFrameWidth * 4; + mTextureDesc.width = mFrameWidth; + mTextureDesc.internalFormat = GL_RGBA; + mTextureDesc.format = GL_BGRA; + mTextureDesc.type = GL_UNSIGNED_INT_8_8_8_8; + break; + case bmdFormat8BitBGRA: + mTextureDesc.stride = mFrameWidth * 4; + mTextureDesc.width = mFrameWidth; + mTextureDesc.internalFormat = GL_RGBA; + mTextureDesc.format = GL_BGRA; + mTextureDesc.type = GL_UNSIGNED_BYTE; + break; + case bmdFormat10BitRGBXLE: + // 1 pixel per word, rounded to 64 pixels + mTextureDesc.stride = ((mFrameWidth + 63) / 64) * 256; + mTextureDesc.width = mTextureDesc.stride/4; + mTextureDesc.internalFormat = GL_RGB10_A2; + mTextureDesc.format = GL_RGBA; + mTextureDesc.type = GL_UNSIGNED_INT_10_10_10_2; + break; + case bmdFormat10BitRGBX: + case bmdFormat10BitRGB: + // 1 pixel per word, rounded to 64 pixels + mTextureDesc.stride = ((mFrameWidth + 63) / 64) * 256; + mTextureDesc.width = mTextureDesc.stride/4; + mTextureDesc.internalFormat = GL_R32UI; + mTextureDesc.format = GL_RED_INTEGER; + mTextureDesc.type = GL_UNSIGNED_INT; + break; + case bmdFormat12BitRGB: + case bmdFormat12BitRGBLE: + // 8 pixels in 9 word + mTextureDesc.stride = (mFrameWidth * 36) / 8; + mTextureDesc.width = mTextureDesc.stride/4; + mTextureDesc.internalFormat = GL_R32UI; + mTextureDesc.format = GL_RED_INTEGER; + mTextureDesc.type = GL_UNSIGNED_INT; + break; + default: + // for unknown pixel format, this will be resolved when a frame arrives + mTextureDesc.format = GL_RED_INTEGER; + mTextureDesc.type = GL_UNSIGNED_INT; + break; + } + // reserve memory for cache frame + 1 to accomodate for pixel format that we don't know yet + // note: we can't use stride as it is not yet known if the pixel format is unknown + // use instead the frame width as in worst case it's not much different (e.g. HD720/10BITYUV: 1296 pixels versus 1280) + // note: some pixel format take more than 4 bytes take that into account (9/8 versus 1) + mpAllocator = new PinnedMemoryAllocator(cacheSize, mFrameWidth*mTextureDesc.height * 4 * (1+cacheSize*9/8)); + + if (mDLInput->SetVideoInputFrameMemoryAllocator(mpAllocator) != S_OK) + THRWEXCP(DeckLinkInternalError, S_OK); + + mpCaptureDelegate = new CaptureDelegate(this); + if (mDLInput->SetCallback(mpCaptureDelegate) != S_OK) + THRWEXCP(DeckLinkInternalError, S_OK); + + if (mDLInput->EnableVideoInput(mDisplayMode, mPixelFormat, ((mUse3D) ? bmdVideoInputDualStream3D : bmdVideoInputFlagDefault)) != S_OK) + // this shouldn't failed, we tested above + THRWEXCP(DeckLinkInternalError, S_OK); + + // just in case it is needed to capture from certain cards, we don't check error because we don't need audio + mDLInput->EnableAudioInput(bmdAudioSampleRate48kHz, bmdAudioSampleType16bitInteger, 2); + + // open base class + VideoBase::openCam(format, camIdx); + + // ready to capture, will start when application calls play() +} + +// play video +bool VideoDeckLink::play (void) +{ + try + { + // if object is able to play + if (VideoBase::play()) + { + mDLInput->FlushStreams(); + return (mDLInput->StartStreams() == S_OK); + } + } + CATCH_EXCP; + return false; +} + + +// pause video +bool VideoDeckLink::pause (void) +{ + try + { + if (VideoBase::pause()) + { + mDLInput->PauseStreams(); + return true; + } + } + CATCH_EXCP; + return false; +} + +// stop video +bool VideoDeckLink::stop (void) +{ + try + { + VideoBase::stop(); + mDLInput->StopStreams(); + return true; + } + CATCH_EXCP; + return false; +} + + +// set video range +void VideoDeckLink::setRange (double start, double stop) +{ +} + +// set framerate +void VideoDeckLink::setFrameRate (float rate) +{ +} + + +// image calculation +// send cache frame directly to GPU +void VideoDeckLink::calcImage (unsigned int texId, double ts) +{ + IDeckLinkVideoInputFrame* pFrame; + LockCache(); + pFrame = mpCacheFrame; + mpCacheFrame = NULL; + UnlockCache(); + if (pFrame) { + // BUG: the dvpBindToGLCtx function fails the first time it is used, don't know why. + // This causes an exception to be thrown. + // This should be fixed but in the meantime we will catch the exception because + // it is crucial that we release the frame to keep the reference count right on the DeckLink device + try { + uint32_t rowSize = pFrame->GetRowBytes(); + uint32_t textureSize = rowSize * pFrame->GetHeight(); + void* videoPixels = NULL; + void* rightEyePixels = NULL; + if (!mTextureDesc.stride) { + // we could not compute the texture size earlier (unknown pixel size) + // let's do it now + mTextureDesc.stride = rowSize; + mTextureDesc.width = mTextureDesc.stride / 4; + } + if (mTextureDesc.stride != rowSize) { + // unexpected frame size, ignore + // TBD: print a warning + } + else { + pFrame->GetBytes(&videoPixels); + if (mUse3D) { + IDeckLinkVideoFrame3DExtensions *if3DExtensions = NULL; + IDeckLinkVideoFrame *rightEyeFrame = NULL; + if (pFrame->QueryInterface(IID_IDeckLinkVideoFrame3DExtensions, (void **)&if3DExtensions) == S_OK && + if3DExtensions->GetFrameForRightEye(&rightEyeFrame) == S_OK) { + rightEyeFrame->GetBytes(&rightEyePixels); + textureSize += ((uint64_t)rightEyePixels - (uint64_t)videoPixels); + } + if (rightEyeFrame) + rightEyeFrame->Release(); + if (if3DExtensions) + if3DExtensions->Release(); + } + mTextureDesc.size = mTextureDesc.width * mTextureDesc.height * 4; + if (mTextureDesc.size == textureSize) { + // this means that both left and right frame are contiguous and that there is no padding + // do the transfer + mpAllocator->TransferBuffer(videoPixels, &mTextureDesc, texId); + } + } + } + catch (Exception &) { + pFrame->Release(); + throw; + } + // this will trigger PinnedMemoryAllocator::RealaseBuffer + pFrame->Release(); + } + // currently we don't pass the image to the application + m_avail = false; +} + +// A frame is available from the board +// Called from an internal thread, just pass the frame to the main thread +void VideoDeckLink::VideoFrameArrived(IDeckLinkVideoInputFrame* inputFrame) +{ + IDeckLinkVideoInputFrame* pOldFrame = NULL; + LockCache(); + if (!mClosing) + { + pOldFrame = mpCacheFrame; + mpCacheFrame = inputFrame; + inputFrame->AddRef(); + } + UnlockCache(); + // old frame no longer needed, just release it + if (pOldFrame) + pOldFrame->Release(); +} + +// python methods + +// object initialization +static int VideoDeckLink_init(PyObject *pySelf, PyObject *args, PyObject *kwds) +{ + static const char *kwlist[] = { "format", "capture", NULL }; + PyImage *self = reinterpret_cast<PyImage*>(pySelf); + // see openCam for a description of format + char * format = NULL; + // capture device number, i.e. DeckLink card number, default first one + short capt = 0; + + if (!GLEW_VERSION_1_5) { + PyErr_SetString(PyExc_RuntimeError, "VideoDeckLink requires at least OpenGL 1.5"); + return -1; + } + // get parameters + if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|h", + const_cast<char**>(kwlist), &format, &capt)) + return -1; + + try { + // create video object + Video_init<VideoDeckLink>(self); + + // open video source, control comes back to VideoDeckLink::openCam + Video_open(getVideo(self), format, capt); + } + catch (Exception & exp) { + exp.report(); + return -1; + } + // initialization succeded + return 0; +} + +// methods structure +static PyMethodDef videoMethods[] = +{ // methods from VideoBase class + {"play", (PyCFunction)Video_play, METH_NOARGS, "Play (restart) video"}, + {"pause", (PyCFunction)Video_pause, METH_NOARGS, "pause video"}, + {"stop", (PyCFunction)Video_stop, METH_NOARGS, "stop video (play will replay it from start)"}, + {"refresh", (PyCFunction)Video_refresh, METH_VARARGS, "Refresh video - get its status"}, + {NULL} +}; +// attributes structure +static PyGetSetDef videoGetSets[] = +{ // methods from VideoBase class + {(char*)"status", (getter)Video_getStatus, NULL, (char*)"video status", NULL}, + {(char*)"framerate", (getter)Video_getFrameRate, NULL, (char*)"frame rate", NULL}, + // attributes from ImageBase class + {(char*)"valid", (getter)Image_valid, NULL, (char*)"bool to tell if an image is available", NULL}, + {(char*)"image", (getter)Image_getImage, NULL, (char*)"image data", NULL}, + {(char*)"size", (getter)Image_getSize, NULL, (char*)"image size", NULL}, + {(char*)"scale", (getter)Image_getScale, (setter)Image_setScale, (char*)"fast scale of image (near neighbor)", NULL}, + {(char*)"flip", (getter)Image_getFlip, (setter)Image_setFlip, (char*)"flip image vertically", NULL}, + {(char*)"filter", (getter)Image_getFilter, (setter)Image_setFilter, (char*)"pixel filter", NULL}, + {NULL} +}; + +// python type declaration +PyTypeObject VideoDeckLinkType = +{ + PyVarObject_HEAD_INIT(NULL, 0) + "VideoTexture.VideoDeckLink", /*tp_name*/ + sizeof(PyImage), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + (destructor)Image_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + &imageBufferProcs, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ + "DeckLink video source", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + videoMethods, /* tp_methods */ + 0, /* tp_members */ + videoGetSets, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)VideoDeckLink_init, /* tp_init */ + 0, /* tp_alloc */ + Image_allocNew, /* tp_new */ +}; + + + +//////////////////////////////////////////// +// DeckLink Capture Delegate Class +//////////////////////////////////////////// + +#endif // WITH_GAMEENGINE_DECKLINK + diff --git a/source/gameengine/VideoTexture/VideoDeckLink.h b/source/gameengine/VideoTexture/VideoDeckLink.h new file mode 100644 index 00000000000..50099d2ead4 --- /dev/null +++ b/source/gameengine/VideoTexture/VideoDeckLink.h @@ -0,0 +1,256 @@ +/* + * ***** 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. + * + * The Original Code is Copyright (C) 2015, Blender Foundation + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Blender Foundation. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file VideoDeckLink.h + * \ingroup bgevideotex + */ + +#ifndef __VIDEODECKLINK_H__ +#define __VIDEODECKLINK_H__ + +#ifdef WITH_GAMEENGINE_DECKLINK + +/* this needs to be parsed with __cplusplus defined before included through DeckLink_compat.h */ +#if defined(__FreeBSD__) +# include <inttypes.h> +#endif +#include <map> +#include <set> + +extern "C" { +#include <pthread.h> +#include "DNA_listBase.h" +#include "BLI_threads.h" +#include "BLI_blenlib.h" +} +#include "GL/glew.h" +#ifdef WIN32 +#include "dvpapi.h" +#endif +#include "DeckLinkAPI.h" +#include "VideoBase.h" + +class PinnedMemoryAllocator; + +struct TextureDesc +{ + uint32_t width; + uint32_t height; + uint32_t stride; + uint32_t size; + GLenum internalFormat; + GLenum format; + GLenum type; + TextureDesc() + { + width = 0; + height = 0; + stride = 0; + size = 0; + internalFormat = 0; + format = 0; + type = 0; + } +}; + +class CaptureDelegate; + +// type VideoDeckLink declaration +class VideoDeckLink : public VideoBase +{ + friend class CaptureDelegate; +public: + /// constructor + VideoDeckLink (HRESULT * hRslt); + /// destructor + virtual ~VideoDeckLink (); + + /// open video/image file + virtual void openFile(char *file); + /// open video capture device + virtual void openCam(char *driver, short camIdx); + + /// release video source + virtual bool release (void); + /// overwrite base refresh to handle fixed image + virtual void refresh(void); + /// play video + virtual bool play (void); + /// pause video + virtual bool pause (void); + /// stop video + virtual bool stop (void); + /// set play range + virtual void setRange (double start, double stop); + /// set frame rate + virtual void setFrameRate (float rate); + +protected: + // format and codec information + /// image calculation + virtual void calcImage (unsigned int texId, double ts); + +private: + void VideoFrameArrived(IDeckLinkVideoInputFrame* inputFrame); + void LockCache() + { + pthread_mutex_lock(&mCacheMutex); + } + void UnlockCache() + { + pthread_mutex_unlock(&mCacheMutex); + } + + IDeckLinkInput* mDLInput; + BMDDisplayMode mDisplayMode; + BMDPixelFormat mPixelFormat; + bool mUse3D; + uint32_t mFrameWidth; + uint32_t mFrameHeight; + TextureDesc mTextureDesc; + PinnedMemoryAllocator* mpAllocator; + CaptureDelegate* mpCaptureDelegate; + + // cache frame in transit between the callback thread and the main BGE thread + // keep only one frame in cache because we just want to keep up with real time + pthread_mutex_t mCacheMutex; + IDeckLinkVideoInputFrame* mpCacheFrame; + bool mClosing; + +}; + +inline VideoDeckLink *getDeckLink(PyImage *self) +{ + return static_cast<VideoDeckLink*>(self->m_image); +} + +//////////////////////////////////////////// +// TextureTransfer : Abstract class to perform a transfer to GPU memory using fast transfer if available +//////////////////////////////////////////// +class TextureTransfer +{ +public: + TextureTransfer() {} + virtual ~TextureTransfer() { } + + virtual void PerformTransfer() = 0; +protected: + static bool _PinBuffer(void *address, uint32_t size); + static void _UnpinBuffer(void* address, uint32_t size); +}; + +//////////////////////////////////////////// +// PinnedMemoryAllocator +//////////////////////////////////////////// + +// PinnedMemoryAllocator implements the IDeckLinkMemoryAllocator interface and can be used instead of the +// built-in frame allocator, by setting with SetVideoInputFrameMemoryAllocator() or SetVideoOutputFrameMemoryAllocator(). +// +// For this sample application a custom frame memory allocator is used to ensure each address +// of frame memory is aligned on a 4kB boundary required by the OpenGL pinned memory extension. +// If the pinned memory extension is not available, this allocator will still be used and +// demonstrates how to cache frame allocations for efficiency. +// +// The frame cache delays the releasing of buffers until the cache fills up, thereby avoiding an +// allocate plus pin operation for every frame, followed by an unpin and deallocate on every frame. + + +class PinnedMemoryAllocator : public IDeckLinkMemoryAllocator +{ +public: + PinnedMemoryAllocator(unsigned cacheSize, size_t memSize); + virtual ~PinnedMemoryAllocator(); + + void TransferBuffer(void* address, TextureDesc* texDesc, GLuint texId); + + // IUnknown methods + virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, LPVOID *ppv); + virtual ULONG STDMETHODCALLTYPE AddRef(void); + virtual ULONG STDMETHODCALLTYPE Release(void); + + // IDeckLinkMemoryAllocator methods + virtual HRESULT STDMETHODCALLTYPE AllocateBuffer(dl_size_t bufferSize, void* *allocatedBuffer); + virtual HRESULT STDMETHODCALLTYPE ReleaseBuffer(void* buffer); + virtual HRESULT STDMETHODCALLTYPE Commit(); + virtual HRESULT STDMETHODCALLTYPE Decommit(); + +private: + static bool mGPUDirectInitialized; + static bool mHasDvp; + static bool mHasAMDPinnedMemory; + static size_t mReservedProcessMemory; + static bool ReserveMemory(size_t size); + + void Lock() + { + pthread_mutex_lock(&mMutex); + } + void Unlock() + { + pthread_mutex_unlock(&mMutex); + } + HRESULT _ReleaseBuffer(void* buffer); + + uint32_t mRefCount; + // protect the cache and the allocated map, + // not the pinnedBuffer map as it is only used from main thread + pthread_mutex_t mMutex; + std::map<void*, uint32_t> mAllocatedSize; + std::vector<void*> mBufferCache; + std::map<void *, TextureTransfer*> mPinnedBuffer; +#ifdef WIN32 + DVPBufferHandle mDvpCaptureTextureHandle; +#endif + // target texture in GPU + GLuint mTexId; + uint32_t mBufferCacheSize; +}; + +//////////////////////////////////////////// +// Capture Delegate Class +//////////////////////////////////////////// + +class CaptureDelegate : public IDeckLinkInputCallback +{ + VideoDeckLink* mpOwner; + +public: + CaptureDelegate(VideoDeckLink* pOwner); + + // IUnknown needs only a dummy implementation + virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, LPVOID *ppv) { return E_NOINTERFACE; } + virtual ULONG STDMETHODCALLTYPE AddRef() { return 1; } + virtual ULONG STDMETHODCALLTYPE Release() { return 1; } + + virtual HRESULT STDMETHODCALLTYPE VideoInputFrameArrived(IDeckLinkVideoInputFrame *videoFrame, IDeckLinkAudioInputPacket *audioPacket); + virtual HRESULT STDMETHODCALLTYPE VideoInputFormatChanged(BMDVideoInputFormatChangedEvents notificationEvents, IDeckLinkDisplayMode *newDisplayMode, BMDDetectedVideoInputFormatFlags detectedSignalFlags); +}; + + +#endif /* WITH_GAMEENGINE_DECKLINK */ + +#endif /* __VIDEODECKLINK_H__ */ diff --git a/source/gameengine/VideoTexture/VideoFFmpeg.cpp b/source/gameengine/VideoTexture/VideoFFmpeg.cpp index 5fed1211d6c..083e9e28502 100644 --- a/source/gameengine/VideoTexture/VideoFFmpeg.cpp +++ b/source/gameengine/VideoTexture/VideoFFmpeg.cpp @@ -1203,7 +1203,7 @@ static PyMethodDef videoMethods[] = {"play", (PyCFunction)Video_play, METH_NOARGS, "Play (restart) video"}, {"pause", (PyCFunction)Video_pause, METH_NOARGS, "pause video"}, {"stop", (PyCFunction)Video_stop, METH_NOARGS, "stop video (play will replay it from start)"}, - {"refresh", (PyCFunction)Video_refresh, METH_NOARGS, "Refresh video - get its status"}, + {"refresh", (PyCFunction)Video_refresh, METH_VARARGS, "Refresh video - get its status"}, {NULL} }; // attributes structure @@ -1326,7 +1326,7 @@ static PyObject *Image_reload(PyImage *self, PyObject *args) // methods structure static PyMethodDef imageMethods[] = { // methods from VideoBase class - {"refresh", (PyCFunction)Video_refresh, METH_NOARGS, "Refresh image, i.e. load it"}, + {"refresh", (PyCFunction)Video_refresh, METH_VARARGS, "Refresh image, i.e. load it"}, {"reload", (PyCFunction)Image_reload, METH_VARARGS, "Reload image, i.e. reopen it"}, {NULL} }; diff --git a/source/gameengine/VideoTexture/blendVideoTex.cpp b/source/gameengine/VideoTexture/blendVideoTex.cpp index a62ffee3137..9b046d46412 100644 --- a/source/gameengine/VideoTexture/blendVideoTex.cpp +++ b/source/gameengine/VideoTexture/blendVideoTex.cpp @@ -128,6 +128,10 @@ static PyMethodDef moduleMethods[] = extern PyTypeObject VideoFFmpegType; extern PyTypeObject ImageFFmpegType; #endif +#ifdef WITH_GAMEENGINE_DECKLINK +extern PyTypeObject VideoDeckLinkType; +extern PyTypeObject DeckLinkType; +#endif extern PyTypeObject FilterBlueScreenType; extern PyTypeObject FilterGrayType; extern PyTypeObject FilterColorType; @@ -145,6 +149,9 @@ static void registerAllTypes(void) pyImageTypes.add(&VideoFFmpegType, "VideoFFmpeg"); pyImageTypes.add(&ImageFFmpegType, "ImageFFmpeg"); #endif +#ifdef WITH_GAMEENGINE_DECKLINK + pyImageTypes.add(&VideoDeckLinkType, "VideoDeckLink"); +#endif pyImageTypes.add(&ImageBuffType, "ImageBuff"); pyImageTypes.add(&ImageMixType, "ImageMix"); pyImageTypes.add(&ImageRenderType, "ImageRender"); @@ -194,6 +201,10 @@ PyMODINIT_FUNC initVideoTexturePythonBinding(void) return NULL; if (PyType_Ready(&TextureType) < 0) return NULL; +#ifdef WITH_GAMEENGINE_DECKLINK + if (PyType_Ready(&DeckLinkType) < 0) + return NULL; +#endif m = PyModule_Create(&VideoTexture_module_def); PyDict_SetItemString(PySys_GetObject("modules"), VideoTexture_module_def.m_name, m); @@ -207,6 +218,10 @@ PyMODINIT_FUNC initVideoTexturePythonBinding(void) Py_INCREF(&TextureType); PyModule_AddObject(m, "Texture", (PyObject *)&TextureType); +#ifdef WITH_GAMEENGINE_DECKLINK + Py_INCREF(&DeckLinkType); + PyModule_AddObject(m, "DeckLink", (PyObject *)&DeckLinkType); +#endif PyModule_AddIntConstant(m, "SOURCE_ERROR", SourceError); PyModule_AddIntConstant(m, "SOURCE_EMPTY", SourceEmpty); PyModule_AddIntConstant(m, "SOURCE_READY", SourceReady); diff --git a/tests/gtests/blenlib/BLI_array_store_test.cc b/tests/gtests/blenlib/BLI_array_store_test.cc index 33fb454ec2f..b71dc4575f1 100644 --- a/tests/gtests/blenlib/BLI_array_store_test.cc +++ b/tests/gtests/blenlib/BLI_array_store_test.cc @@ -528,15 +528,6 @@ static unsigned int rand_range_i(RNG *rng, unsigned int min_i, unsigned int max_ return min_i + value; } -static void rand_bytes(RNG *rng, char *data, int data_len) -{ - BLI_assert(data_len != 0); - while (data_len--) { - *data = BLI_rng_get_uint(rng) % 256; - data++; - } -} - static void testbuffer_list_state_random_data( ListBase *lb, const size_t stride, @@ -548,7 +539,7 @@ static void testbuffer_list_state_random_data( char *data = (char *)MEM_mallocN(data_len, __func__); if (lb->last == NULL) { - rand_bytes(rng, data, data_len); + BLI_rng_get_char_n(rng, data, data_len); } else { TestBuffer *tb_last = (TestBuffer *)lb->last; @@ -557,7 +548,7 @@ static void testbuffer_list_state_random_data( } else { memcpy(data, tb_last->data, tb_last->data_len); - rand_bytes(rng, &data[tb_last->data_len], data_len - tb_last->data_len); + BLI_rng_get_char_n(rng, &data[tb_last->data_len], data_len - tb_last->data_len); } /* perform multiple small mutations to the array. */ @@ -583,7 +574,7 @@ static void testbuffer_list_state_random_data( data_len += stride; data = (char *)MEM_reallocN((void *)data, data_len); memmove(&data[offset + stride], &data[offset], data_len - (offset + stride)); - rand_bytes(rng, &data[offset], stride); + BLI_rng_get_char_n(rng, &data[offset], stride); } break; } @@ -608,7 +599,7 @@ static void testbuffer_list_state_random_data( { if (data_len > 0) { const unsigned int offset = rand_range_i(rng, 0, data_len - stride, stride); - rand_bytes(rng, &data[offset], stride); + BLI_rng_get_char_n(rng, &data[offset], stride); } break; } @@ -667,7 +658,7 @@ static void random_chunk_generate( const size_t chunk_size_bytes = stride * chunk_count; for (int i = 0; i < chunks_per_buffer; i++) { char *data_chunk = (char *)MEM_mallocN(chunk_size_bytes, __func__); - rand_bytes(rng, data_chunk, chunk_size_bytes); + BLI_rng_get_char_n(rng, data_chunk, chunk_size_bytes); testchunk_list_add(lb, data_chunk, chunk_size_bytes); } BLI_rng_free(rng); diff --git a/tests/gtests/blenlib/BLI_array_utils_test.cc b/tests/gtests/blenlib/BLI_array_utils_test.cc index e532419691a..eabf5bc72cf 100644 --- a/tests/gtests/blenlib/BLI_array_utils_test.cc +++ b/tests/gtests/blenlib/BLI_array_utils_test.cc @@ -5,6 +5,7 @@ extern "C" { #include "BLI_utildefines.h" #include "BLI_array_utils.h" +#include "BLI_stackdefines.h" } /* -------------------------------------------------------------------- */ @@ -44,33 +45,102 @@ TEST(array_utils, ReverseInt4) TEST(array_utils, FindIndexStringEmpty) { char data[] = "", find = '0'; - EXPECT_EQ(-1, BLI_array_findindex(data, ARRAY_SIZE(data) - 1, &find)); + EXPECT_EQ(-1, BLI_array_findindex(data, ARRAY_SIZE(data) - 1, &find)); + EXPECT_EQ(-1, BLI_array_rfindindex(data, ARRAY_SIZE(data) - 1, &find)); } TEST(array_utils, FindIndexStringSingle) { char data[] = "0", find = '0'; - EXPECT_EQ(0, BLI_array_findindex(data, ARRAY_SIZE(data) - 1, &find)); + EXPECT_EQ(0, BLI_array_findindex(data, ARRAY_SIZE(data) - 1, &find)); + EXPECT_EQ(0, BLI_array_rfindindex(data, ARRAY_SIZE(data) - 1, &find)); } TEST(array_utils, FindIndexStringSingleMissing) { char data[] = "1", find = '0'; - EXPECT_EQ(-1, BLI_array_findindex(data, ARRAY_SIZE(data) - 1, &find)); + EXPECT_EQ(-1, BLI_array_findindex(data, ARRAY_SIZE(data) - 1, &find)); + EXPECT_EQ(-1, BLI_array_rfindindex(data, ARRAY_SIZE(data) - 1, &find)); } TEST(array_utils, FindIndexString4) { char data[] = "0123", find = '3'; - EXPECT_EQ(3, BLI_array_findindex(data, ARRAY_SIZE(data) - 1, &find)); + EXPECT_EQ(3, BLI_array_findindex(data, ARRAY_SIZE(data) - 1, &find)); + EXPECT_EQ(3, BLI_array_rfindindex(data, ARRAY_SIZE(data) - 1, &find)); } TEST(array_utils, FindIndexInt4) { - int data[] = {0, 1, 2, 3}, find = 2; - EXPECT_EQ(2, BLI_array_findindex(data, ARRAY_SIZE(data) - 1, &find)); + int data[] = {0, 1, 2, 3}, find = 3; + EXPECT_EQ(3, BLI_array_findindex(data, ARRAY_SIZE(data), &find)); + EXPECT_EQ(3, BLI_array_rfindindex(data, ARRAY_SIZE(data), &find)); } +TEST(array_utils, FindIndexInt4_DupeEnd) +{ + int data[] = {0, 1, 2, 0}, find = 0; + EXPECT_EQ(0, BLI_array_findindex(data, ARRAY_SIZE(data), &find)); + EXPECT_EQ(3, BLI_array_rfindindex(data, ARRAY_SIZE(data), &find)); +} + +TEST(array_utils, FindIndexInt4_DupeMid) +{ + int data[] = {1, 0, 0, 3}, find = 0; + EXPECT_EQ(1, BLI_array_findindex(data, ARRAY_SIZE(data), &find)); + EXPECT_EQ(2, BLI_array_rfindindex(data, ARRAY_SIZE(data), &find)); +} + +TEST(array_utils, FindIndexPointer) +{ + const char *data[4] = {NULL}; + STACK_DECLARE(data); + + STACK_INIT(data, ARRAY_SIZE(data)); + + const char *a = "a", *b = "b", *c = "c", *d = "d"; + +#define STACK_PUSH_AND_CHECK_FORWARD(v, i) { \ + STACK_PUSH(data, v); \ + EXPECT_EQ(i, BLI_array_findindex(data, STACK_SIZE(data), &(v))); \ +} ((void)0) + +#define STACK_PUSH_AND_CHECK_BACKWARD(v, i) { \ + STACK_PUSH(data, v); \ + EXPECT_EQ(i, BLI_array_rfindindex(data, STACK_SIZE(data), &(v))); \ +} ((void)0) + +#define STACK_PUSH_AND_CHECK_BOTH(v, i) { \ + STACK_PUSH(data, v); \ + EXPECT_EQ(i, BLI_array_findindex(data, STACK_SIZE(data), &(v))); \ + EXPECT_EQ(i, BLI_array_rfindindex(data, STACK_SIZE(data), &(v))); \ +} ((void)0) + + STACK_PUSH_AND_CHECK_BOTH(a, 0); + STACK_PUSH_AND_CHECK_BOTH(b, 1); + STACK_PUSH_AND_CHECK_BOTH(c, 2); + STACK_PUSH_AND_CHECK_BOTH(d, 3); + + STACK_POP(data); + STACK_PUSH_AND_CHECK_BACKWARD(a, 3); + + STACK_POP(data); + STACK_PUSH_AND_CHECK_FORWARD(a, 0); + + STACK_POP(data); + STACK_POP(data); + + STACK_PUSH_AND_CHECK_BACKWARD(b, 2); + STACK_PUSH_AND_CHECK_BACKWARD(a, 3); + +#undef STACK_PUSH_AND_CHECK_FORWARD +#undef STACK_PUSH_AND_CHECK_BACKWARD +#undef STACK_PUSH_AND_CHECK_BOTH + +} + + + /* BLI_array_binary_and */ #define BINARY_AND_TEST(data_cmp, data_a, data_b, data_combine, length) \ { \ diff --git a/tests/python/cycles_render_tests.py b/tests/python/cycles_render_tests.py index 36fad175cfa..fb9e63aa222 100755 --- a/tests/python/cycles_render_tests.py +++ b/tests/python/cycles_render_tests.py @@ -3,6 +3,7 @@ import argparse import os +import shutil import subprocess import sys import tempfile @@ -53,19 +54,23 @@ def verify_output(filepath): dirpath = os.path.dirname(filepath) reference_dirpath = os.path.join(dirpath, "reference_renders") reference_image = os.path.join(reference_dirpath, testname + ".png") + failed_image = os.path.join(reference_dirpath, testname + ".fail.png") if not os.path.exists(reference_image): return False command = ( IDIFF, - "-fail", "0.01", + "-fail", "0.015", "-failpercent", "1", reference_image, TEMP_FILE, ) try: subprocess.check_output(command) + if os.path.exists(failed_image): + os.remove(failed_image) return True except subprocess.CalledProcessError as e: + shutil.copy(TEMP_FILE, failed_image) if VERBOSE: print(e.output.decode("utf-8")) return e.returncode == 1 |