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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt8
-rw-r--r--build_files/scons/config/aix4-config.py3
-rw-r--r--build_files/scons/config/darwin-config.py2
-rw-r--r--build_files/scons/config/freebsd7-config.py3
-rw-r--r--build_files/scons/config/freebsd8-config.py3
-rw-r--r--build_files/scons/config/freebsd9-config.py3
-rw-r--r--build_files/scons/config/irix6-config.py2
-rw-r--r--build_files/scons/config/linux2-config.py3
-rw-r--r--build_files/scons/config/linuxcross-config.py3
-rw-r--r--build_files/scons/config/openbsd3-config.py3
-rw-r--r--build_files/scons/config/sunos5-config.py3
-rw-r--r--build_files/scons/config/win32-mingw-config.py3
-rw-r--r--build_files/scons/config/win32-vc-config.py3
-rw-r--r--build_files/scons/config/win64-vc-config.py3
-rw-r--r--build_files/scons/tools/btools.py4
-rwxr-xr-xdoc/blender_file_format/BlendFileDnaExporter_25.py477
-rw-r--r--doc/blender_file_format/BlendFileReader.py446
-rw-r--r--doc/blender_file_format/README29
-rw-r--r--doc/blender_file_format/mystery_of_the_blend.css204
-rw-r--r--doc/blender_file_format/mystery_of_the_blend.html835
-rw-r--r--intern/ghost/SConscript3
-rw-r--r--intern/ghost/intern/GHOST_WindowCarbon.cpp6
-rw-r--r--intern/ghost/intern/GHOST_WindowCocoa.mm12
-rw-r--r--intern/ghost/intern/GHOST_WindowWin32.cpp9
-rw-r--r--intern/ghost/intern/GHOST_WindowX11.cpp9
-rw-r--r--source/SConscript11
-rw-r--r--source/blender/blenkernel/BKE_brush.h14
-rw-r--r--source/blender/blenkernel/BKE_paint.h2
-rw-r--r--source/blender/blenkernel/intern/brush.c69
-rw-r--r--source/blender/blenkernel/intern/material.c21
-rw-r--r--source/blender/blenkernel/intern/object.c4
-rw-r--r--source/blender/blenlib/BLI_cpu.h2
-rw-r--r--source/blender/blenlib/BLI_pbvh.h4
-rw-r--r--source/blender/blenlib/intern/cpu.c2
-rw-r--r--source/blender/blenlib/intern/pbvh.c70
-rw-r--r--source/blender/blenloader/intern/readfile.c88
-rw-r--r--source/blender/editors/include/ED_sculpt.h4
-rw-r--r--source/blender/editors/sculpt_paint/SConscript3
-rw-r--r--source/blender/editors/sculpt_paint/paint_stroke.c1398
-rw-r--r--source/blender/editors/sculpt_paint/paint_utils.c5
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c1418
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_undo.c2
-rw-r--r--source/blender/editors/space_info/info_draw.c2
-rw-r--r--source/blender/editors/space_info/info_report.c2
-rw-r--r--source/blender/editors/space_info/textview.c2
-rw-r--r--source/blender/editors/space_info/textview.h2
-rw-r--r--source/blender/editors/space_view3d/drawmesh.c4
-rw-r--r--source/blender/editors/space_view3d/drawobject.c6
-rw-r--r--source/blender/editors/space_view3d/space_view3d.c8
-rw-r--r--source/blender/editors/space_view3d/view3d_draw.c5
-rw-r--r--source/blender/editors/space_view3d/view3d_fly.c2
-rw-r--r--source/blender/gpu/intern/gpu_codegen.c4
-rw-r--r--source/blender/gpu/intern/gpu_draw.c86
-rw-r--r--source/blender/gpu/intern/gpu_material.c8
-rw-r--r--source/blender/makesdna/DNA_brush_types.h48
-rw-r--r--source/blender/makesdna/DNA_object_types.h1
-rw-r--r--source/blender/makesdna/DNA_scene_types.h4
-rw-r--r--source/blender/makesdna/DNA_texture_types.h1
-rw-r--r--source/blender/makesdna/DNA_userdef_types.h9
-rw-r--r--source/blender/makesdna/DNA_view3d_types.h5
-rw-r--r--source/blender/makesrna/SConscript3
-rw-r--r--source/blender/makesrna/intern/rna_brush.c107
-rw-r--r--source/blender/makesrna/intern/rna_object.c1
-rw-r--r--source/blender/makesrna/intern/rna_sculpt_paint.c29
-rw-r--r--source/blender/makesrna/intern/rna_sequencer_api.c2
-rw-r--r--source/blender/makesrna/intern/rna_space.c16
-rw-r--r--source/blender/makesrna/intern/rna_texture.c1
-rwxr-xr-xsource/blender/makesrna/rna_cleanup/rna_cleaner.py321
-rwxr-xr-xsource/blender/makesrna/rna_cleanup/rna_cleaner_merge.py61
-rw-r--r--source/blender/makesrna/rna_cleanup/rna_properties.txt1
-rwxr-xr-xsource/blender/makesrna/rna_cleanup/rna_update.sh13
-rw-r--r--source/blender/python/generic/mathutils_geometry.c2
-rw-r--r--source/blender/python/generic/mathutils_geometry.h2
-rw-r--r--source/blender/windowmanager/SConscript3
-rw-r--r--source/blender/windowmanager/intern/wm_draw.c453
-rw-r--r--source/blender/windowmanager/intern/wm_operators.c340
-rw-r--r--source/blenderplayer/CMakeLists.txt17
-rw-r--r--source/tests/CMakeLists.txt293
-rw-r--r--source/tests/batch_import.py202
-rw-r--r--source/tests/bl_load_addons.py78
-rw-r--r--source/tests/bl_load_py_modules.py145
-rw-r--r--source/tests/bl_run_operators.py176
-rw-r--r--source/tests/bl_test.py197
-rw-r--r--source/tests/pep8.py118
-rw-r--r--source/tests/rna_array.py297
-rw-r--r--source/tests/rna_info_dump.py131
86 files changed, 3620 insertions, 4784 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 0f140d537d1..aba98f6b342 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -156,6 +156,7 @@ if(UNIX AND NOT APPLE)
option(WITH_INSTALL_PORTABLE "Install redistributeable runtime, otherwise install into CMAKE_INSTALL_PREFIX" ON)
endif()
option(WITH_PYTHON_INSTALL "Copy system python into the blender install folder" ON)
+option(WITH_ONSURFACEBRUSH "Enable use of the 'on-surface brush' for paint/sculpt. Requires a stencil buffer, GL_depth_texture, and GLSL" ON)
# disable for now, but plan to support on all platforms eventually
option(WITH_MEM_JEMALLOC "Enable malloc replacement (http://www.canonware.com/jemalloc)" OFF)
@@ -440,6 +441,9 @@ if(UNIX AND NOT APPLE)
# GNU Compiler
if(CMAKE_COMPILER_IS_GNUCC)
set(PLATFORM_CFLAGS "-pipe -fPIC -funsigned-char -fno-strict-aliasing")
+ if(WITH_ONSURFACEBRUSH)
+ add_defintion(-DWITH_ONSURFACEBRUSH)
+ endif(WITH_ONSURFACEBRUSH)
# Intel C++ Compiler
elseif(CMAKE_C_COMPILER_ID MATCHES "Intel")
# think these next two are broken
@@ -534,6 +538,10 @@ elseif(WIN32)
add_definitions(-D__SSE__ -D__MMX__)
endif()
+ if(WITH_ONSURFACEBRUSH)
+ add_defintion(-DWITH_ONSURFACEBRUSH)
+ endif(WITH_ONSURFACEBRUSH)
+
if(MSVC)
if(CMAKE_CL_64)
set(LLIBS ws2_32 vfw32 winmm kernel32 user32 gdi32 comdlg32 advapi32 shfolder shell32 ole32 oleaut32 uuid )
diff --git a/build_files/scons/config/aix4-config.py b/build_files/scons/config/aix4-config.py
index e8004338271..bb1a0f3d3ac 100644
--- a/build_files/scons/config/aix4-config.py
+++ b/build_files/scons/config/aix4-config.py
@@ -149,6 +149,9 @@ BF_REDCODE_LIB = ''
BF_REDCODE_INC = '${BF_REDCODE}/include'
BF_REDCODE_LIBPATH='${BF_REDCODE}/lib'
+#On-Surface Brush
+WITH_BF_ONSURFACEBRUSH = True
+
# Mesa Libs should go here if your using them as well....
WITH_BF_STATICOPENGL = 'false'
BF_OPENGL = '/usr'
diff --git a/build_files/scons/config/darwin-config.py b/build_files/scons/config/darwin-config.py
index 0c51476a6d0..03cae53f5ab 100644
--- a/build_files/scons/config/darwin-config.py
+++ b/build_files/scons/config/darwin-config.py
@@ -265,6 +265,8 @@ if MACOSX_ARCHITECTURE == 'i386':
elif MACOSX_ARCHITECTURE == 'x86_64':
BF_RAYOPTIMIZATION_SSE_FLAGS = ['-msse','-msse2']
+#On-Surface Brush
+WITH_BF_ONSURFACEBRUSH = True
#############################################################################
################### various compile settings and flags ##################
diff --git a/build_files/scons/config/freebsd7-config.py b/build_files/scons/config/freebsd7-config.py
index a73574abf67..ab8b32d22f7 100644
--- a/build_files/scons/config/freebsd7-config.py
+++ b/build_files/scons/config/freebsd7-config.py
@@ -174,6 +174,9 @@ WITH_BF_OPENMP = True
WITH_BF_RAYOPTIMIZATION = True
BF_RAYOPTIMIZATION_SSE_FLAGS = ['-msse','-pthread']
+#On-Surface Brush
+WITH_BF_ONSURFACEBRUSH = True
+
CCFLAGS = ['-pipe','-fPIC','-funsigned-char','-fno-strict-aliasing','-D_LARGEFILE_SOURCE','-D_FILE_OFFSET_BITS=64','-D_LARGEFILE64_SOURCE']
CPPFLAGS = []
diff --git a/build_files/scons/config/freebsd8-config.py b/build_files/scons/config/freebsd8-config.py
index dd7ab5f9ab9..169bbf1d9c4 100644
--- a/build_files/scons/config/freebsd8-config.py
+++ b/build_files/scons/config/freebsd8-config.py
@@ -174,6 +174,9 @@ WITH_BF_OPENMP = True
WITH_BF_RAYOPTIMIZATION = True
BF_RAYOPTIMIZATION_SSE_FLAGS = ['-msse','-pthread']
+#On-Surface Brush
+WITH_BF_ONSURFACEBRUSH = True
+
CCFLAGS = ['-pipe','-fPIC','-funsigned-char','-fno-strict-aliasing','-D_LARGEFILE_SOURCE','-D_FILE_OFFSET_BITS=64','-D_LARGEFILE64_SOURCE']
CPPFLAGS = []
diff --git a/build_files/scons/config/freebsd9-config.py b/build_files/scons/config/freebsd9-config.py
index 9c53d52ce71..f26c85e361c 100644
--- a/build_files/scons/config/freebsd9-config.py
+++ b/build_files/scons/config/freebsd9-config.py
@@ -174,6 +174,9 @@ WITH_BF_OPENMP = True
WITH_BF_RAYOPTIMIZATION = True
BF_RAYOPTIMIZATION_SSE_FLAGS = ['-msse','-pthread']
+#On-Surface Brush
+WITH_BF_ONSURFACEBRUSH = True
+
CCFLAGS = ['-pipe','-fPIC','-funsigned-char','-fno-strict-aliasing','-D_LARGEFILE_SOURCE','-D_FILE_OFFSET_BITS=64','-D_LARGEFILE64_SOURCE']
CPPFLAGS = []
diff --git a/build_files/scons/config/irix6-config.py b/build_files/scons/config/irix6-config.py
index 4ca7bcc7b64..fdc6b059c98 100644
--- a/build_files/scons/config/irix6-config.py
+++ b/build_files/scons/config/irix6-config.py
@@ -154,6 +154,8 @@ BF_OPENGL_LIB = 'GL GLU X11 Xi Xext'
BF_OPENGL_LIBPATH = '/usr/X11R6/lib'
BF_OPENGL_LIB_STATIC = '${BF_OPENGL}/libGL.a ${BF_OPENGL}/libGLU.a ${BF_OPENGL}/libXxf86vm.a ${BF_OPENGL}/libX11.a ${BF_OPENGL}/libXi.a ${BF_OPENGL}/libXext.a ${BF_OPENGL}/libXxf86vm.a'
+#On-Surface Brush
+WITH_BF_ONSURFACEBRUSH = True
CC = 'c99'
CXX = 'CC'
diff --git a/build_files/scons/config/linux2-config.py b/build_files/scons/config/linux2-config.py
index bc2917055fb..e217570e5dc 100644
--- a/build_files/scons/config/linux2-config.py
+++ b/build_files/scons/config/linux2-config.py
@@ -192,6 +192,9 @@ WITH_BF_OPENMP = True
WITH_BF_RAYOPTIMIZATION = True
BF_RAYOPTIMIZATION_SSE_FLAGS = ['-msse','-pthread']
+#On-Surface Brush
+WITH_BF_ONSURFACEBRUSH = True
+
##
CC = 'gcc'
CXX = 'g++'
diff --git a/build_files/scons/config/linuxcross-config.py b/build_files/scons/config/linuxcross-config.py
index 62474527825..75e3a9bd5dd 100644
--- a/build_files/scons/config/linuxcross-config.py
+++ b/build_files/scons/config/linuxcross-config.py
@@ -172,6 +172,9 @@ BF_OPENCOLLADA_LIBPATH = '${BF_OPENCOLLADA}/lib ${BF_ICONV_LIBPATH}'
WITH_BF_RAYOPTIMIZATION = True
BF_RAYOPTIMIZATION_SSE_FLAGS = ['-msse']
+#On-Surface Brush
+WITH_BF_ONSURFACEBRUSH = True
+
CCFLAGS = [ '-pipe', '-funsigned-char', '-fno-strict-aliasing' ]
CPPFLAGS = ['-DWIN32', '-DFREE_WINDOWS', '-D_LARGEFILE_SOURCE', '-D_FILE_OFFSET_BITS=64', '-D_LARGEFILE64_SOURCE']
diff --git a/build_files/scons/config/openbsd3-config.py b/build_files/scons/config/openbsd3-config.py
index 67d850ff48d..700d45deb93 100644
--- a/build_files/scons/config/openbsd3-config.py
+++ b/build_files/scons/config/openbsd3-config.py
@@ -111,6 +111,9 @@ BF_OPENGL_LIB = 'GL GLU X11 Xi'
BF_OPENGL_LIBPATH = '${BF_OPENGL}/lib'
BF_OPENGL_LIB_STATIC = '${BF_OPENGL_LIBPATH}/libGL.a ${BF_OPENGL_LIBPATH}/libGLU.a ${BF_OPENGL_LIBPATH}/libXxf86vm.a ${BF_OPENGL_LIBPATH}/libX11.a ${BF_OPENGL_LIBPATH}/libXi.a ${BF_OPENGL_LIBPATH}/libXext.a ${BF_OPENGL_LIBPATH}/libXxf86vm.a'
+#On-Surface Brush
+WITH_BF_ONSURFACEBRUSH = True
+
##
##CC = gcc
##CCC = g++
diff --git a/build_files/scons/config/sunos5-config.py b/build_files/scons/config/sunos5-config.py
index 828e286efee..e9768f624e1 100644
--- a/build_files/scons/config/sunos5-config.py
+++ b/build_files/scons/config/sunos5-config.py
@@ -128,6 +128,9 @@ BF_OPENGL_LIB = 'GL GLU X11 Xi'
BF_OPENGL_LIBPATH = '${BF_OPENGL}/lib'
BF_OPENGL_LIB_STATIC = '${BF_OPENGL_LIBPATH}/libGL.a ${BF_OPENGL_LIBPATH}/libGLU.a ${BF_OPENGL_LIBPATH}/libXxf86vm.a ${BF_OPENGL_LIBPATH}/libX11.a ${BF_OPENGL_LIBPATH}/libXi.a ${BF_OPENGL_LIBPATH}/libXext.a ${BF_OPENGL_LIBPATH}/libXxf86vm.a'
+#On-Surface Brush
+WITH_BF_ONSURFACEBRUSH = True
+
##
CC = 'gcc'
CXX = 'g++'
diff --git a/build_files/scons/config/win32-mingw-config.py b/build_files/scons/config/win32-mingw-config.py
index 6dac29b37f7..e3e4b371681 100644
--- a/build_files/scons/config/win32-mingw-config.py
+++ b/build_files/scons/config/win32-mingw-config.py
@@ -158,6 +158,9 @@ BF_OPENCOLLADA_LIBPATH = '${BF_OPENCOLLADA}/lib'
WITH_BF_RAYOPTIMIZATION = False
BF_RAYOPTIMIZATION_SSE_FLAGS = ['-msse']
+#On-Surface Brush
+WITH_BF_ONSURFACEBRUSH = True
+
##
CC = 'gcc'
CXX = 'g++'
diff --git a/build_files/scons/config/win32-vc-config.py b/build_files/scons/config/win32-vc-config.py
index 65076be85ed..a7e66ccb471 100644
--- a/build_files/scons/config/win32-vc-config.py
+++ b/build_files/scons/config/win32-vc-config.py
@@ -153,6 +153,9 @@ BF_OPENCOLLADA_LIBPATH = '${BF_OPENCOLLADA}/lib'
WITH_BF_RAYOPTIMIZATION = True
BF_RAYOPTIMIZATION_SSE_FLAGS = ['/arch:SSE']
+#On-Surface Brush
+WITH_BF_ONSURFACEBRUSH = True
+
WITH_BF_STATICOPENGL = False
BF_OPENGL_INC = '${BF_OPENGL}/include'
BF_OPENGL_LIBINC = '${BF_OPENGL}/lib'
diff --git a/build_files/scons/config/win64-vc-config.py b/build_files/scons/config/win64-vc-config.py
index 2c990941764..e7d467fb8d1 100644
--- a/build_files/scons/config/win64-vc-config.py
+++ b/build_files/scons/config/win64-vc-config.py
@@ -155,6 +155,9 @@ BF_OPENCOLLADA_LIBPATH = '${BF_OPENCOLLADA}/lib'
WITH_BF_RAYOPTIMIZATION = True
BF_RAYOPTIMIZATION_SSE_FLAGS = ['/arch:SSE','/arch:SSE2']
+#On-Surface Brush
+WITH_BF_ONSURFACEBRUSH = True
+
WITH_BF_STATICOPENGL = False
BF_OPENGL_INC = '${BF_OPENGL}/include'
BF_OPENGL_LIBINC = '${BF_OPENGL}/lib'
diff --git a/build_files/scons/tools/btools.py b/build_files/scons/tools/btools.py
index accdde0d2cf..f920aaefc78 100644
--- a/build_files/scons/tools/btools.py
+++ b/build_files/scons/tools/btools.py
@@ -132,6 +132,7 @@ def validate_arguments(args, bc):
'BF_GHOST_DEBUG',
'WITH_BF_RAYOPTIMIZATION',
'BF_RAYOPTIMIZATION_SSE_FLAGS',
+ 'WITH_BF_ONSURFACEBRUSH',
'BF_NO_ELBEEM',
'WITH_BF_CXX_GUARDEDALLOC',
'WITH_BF_JEMALLOC', 'WITH_BF_STATICJEMALLOC', 'BF_JEMALLOC', 'BF_JEMALLOC_INC', 'BF_JEMALLOC_LIBPATH', 'BF_JEMALLOC_LIB', 'BF_JEMALLOC_LIB_STATIC'
@@ -501,6 +502,9 @@ def read_opts(env, cfg, args):
(BoolVariable('WITH_BF_RAYOPTIMIZATION', 'Enable raytracer SSE/SIMD optimization.', False)),
('BF_RAYOPTIMIZATION_SSE_FLAGS', 'SSE flags', ''),
+
+ (BoolVariable('WITH_BF_ONSURFACEBRUSH', 'Enable use of the "on-surface brush" for paint/sculpt. Requires a stencil buffer, GL_depth_texture, and GLSL', True)),
+
(BoolVariable('WITH_BF_CXX_GUARDEDALLOC', 'Enable GuardedAlloc for C++ memory allocation tracking.', False))
) # end of opts.AddOptions()
diff --git a/doc/blender_file_format/BlendFileDnaExporter_25.py b/doc/blender_file_format/BlendFileDnaExporter_25.py
deleted file mode 100755
index afc58ce6730..00000000000
--- a/doc/blender_file_format/BlendFileDnaExporter_25.py
+++ /dev/null
@@ -1,477 +0,0 @@
-#! /usr/bin/env python3
-
-# ***** 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-#
-# ***** END GPL LICENCE BLOCK *****
-
-######################################################
-#
-# Name:
-# dna.py
-#
-# Description:
-# Creates a browsable DNA output to HTML.
-#
-# Author:
-# Jeroen Bakker
-#
-# Version:
-# v0.1 (12-05-2009) - migration of original source code to python.
-# Added code to support blender 2.5 branch
-# v0.2 (25-05-2009) - integrated with BlendFileReader.py
-#
-# Input:
-# blender build executable
-#
-# Output:
-# dna.html
-# dna.css (will only be created when not existing)
-#
-# Startup:
-# ./blender -P BlendFileDnaExporter.py
-#
-# Process:
-# 1: write blend file with SDNA info
-# 2: read blend header from blend file
-# 3: seek DNA1 file-block
-# 4: read dna record from blend file
-# 5: close and eventually delete temp blend file
-# 6: export dna to html and css
-# 7: quit blender
-#
-######################################################
-
-import struct
-import sys
-import getopt # command line arguments handling
-from string import Template # strings completion
-
-
-# logs
-import logging
-log = logging.getLogger("BlendFileDnaExporter")
-
-if '--dna-debug' in sys.argv:
- logging.basicConfig(level=logging.DEBUG)
-else:
- logging.basicConfig(level=logging.INFO)
-
-
-class DNACatalogHTML:
- '''
- DNACatalog is a catalog of all information in the DNA1 file-block
- '''
-
- def __init__(self, catalog, bpy_module = None):
- self.Catalog = catalog
- self.bpy = bpy_module
-
- def WriteToHTML(self, handle):
-
- dna_html_template = """
- <!DOCTYPE html PUBLIC -//W3C//DTD HTML 4.01 Transitional//EN http://www.w3.org/TR/html4/loose.dtd>
- <html>
- <head>
- <link rel="stylesheet" type="text/css" href="dna.css" media="screen, print" />
- <meta http-equiv="Content-Type" content="text/html"; charset="ISO-8859-1" />
- <title>The mystery of the blend</title>
- </head>
- <body>
- <div class=title>
- Blender ${version}<br/>
- Internal SDNA structures
- </div>
- Architecture: ${bitness} ${endianness}<br/>
- Build revision: <a href="https://svn.blender.org/svnroot/bf-blender/!svn/bc/${revision}/trunk/">${revision}</a><br/>
- File format reference: <a href="mystery_of_the_blend.html">The mystery of the blend</a> by Jeroen Bakker<br/>
- <h1>Index of blender structures</h1>
- <ul class=multicolumn>
- ${structs_list}
- </ul>
- ${structs_content}
- </body>
- </html>"""
-
- header = self.Catalog.Header
- bpy = self.bpy
-
- # ${version} and ${revision}
- if bpy:
- version = '.'.join(map(str, bpy.app.version))
- revision = bpy.app.build_revision[:-1]
- else:
- version = str(header.Version)
- revision = 'Unknown'
-
- # ${bitness}
- if header.PointerSize == 8:
- bitness = '64 bit'
- else:
- bitness = '32 bit'
-
- # ${endianness}
- if header.LittleEndianness:
- endianess= 'Little endianness'
- else:
- endianess= 'Big endianness'
-
- # ${structs_list}
- log.debug("Creating structs index")
- structs_list = ''
- list_item = '<li class="multicolumn">({0}) <a href="#{1}">{1}</a></li>\n'
- structureIndex = 0
- for structure in self.Catalog.Structs:
- structs_list += list_item.format(structureIndex, structure.Type.Name)
- structureIndex+=1
-
- # ${structs_content}
- log.debug("Creating structs content")
- structs_content = ''
- for structure in self.Catalog.Structs:
- log.debug(structure.Type.Name)
- structs_content += self.Structure(structure)
-
- d = dict(
- version = version,
- revision = revision,
- bitness = bitness,
- endianness = endianess,
- structs_list = structs_list,
- structs_content = structs_content
- )
-
- dna_html = Template(dna_html_template).substitute(d)
- dna_html = self.format(dna_html)
- handle.write(dna_html)
-
- def Structure(self, structure):
- struct_table_template = """
- <table><a name="${struct_name}"></a>
- <caption><a href="#${struct_name}">${struct_name}</a></caption>
- <thead>
- <tr>
- <th>reference</th>
- <th>structure</th>
- <th>type</th>
- <th>name</th>
- <th>offset</th>
- <th>size</th>
- </tr>
- </thead>
- <tbody>
- ${fields}
- </tbody>
- </table>
- <label>Total size: ${size} bytes</label><br/>
- <label>(<a href="#top">top</a>)</label><br/>"""
-
- d = dict(
- struct_name = structure.Type.Name,
- fields = self.StructureFields(structure, None, 0),
- size = str(structure.Type.Size)
- )
-
- struct_table = Template(struct_table_template).substitute(d)
- return struct_table
-
- def StructureFields(self, structure, parentReference, offset):
- fields = ''
- for field in structure.Fields:
- fields += self.StructureField(field, structure, parentReference, offset)
- offset += field.Size(self.Catalog.Header)
- return fields
-
- def StructureField(self, field, structure, parentReference, offset):
- structure_field_template = """
- <tr>
- <td>${reference}</td>
- <td>${struct}</td>
- <td>${type}</td>
- <td>${name}</td>
- <td>${offset}</td>
- <td>${size}</td>
- </tr>"""
-
- if field.Type.Structure == None or field.Name.IsPointer():
-
- # ${reference}
- reference = field.Name.AsReference(parentReference)
-
- # ${struct}
- if parentReference != None:
- struct = '<a href="#{0}">{0}</a>'.format(structure.Type.Name)
- else:
- struct = structure.Type.Name
-
- # ${type}
- type = field.Type.Name
-
- # ${name}
- name = field.Name.Name
-
- # ${offset}
- # offset already set
-
- # ${size}
- size = field.Size(self.Catalog.Header)
-
- d = dict(
- reference = reference,
- struct = struct,
- type = type,
- name = name,
- offset = offset,
- size = size
- )
-
- structure_field = Template(structure_field_template).substitute(d)
-
- elif field.Type.Structure != None:
- reference = field.Name.AsReference(parentReference)
- structure_field = self.StructureFields(field.Type.Structure, reference, offset)
-
- return structure_field
-
- def indent(self, input, dent, startswith = ''):
- output = ''
- if dent < 0:
- for line in input.split('\n'):
- dent = abs(dent)
- output += line[dent:] + '\n' # unindent of a desired amount
- elif dent == 0:
- for line in input.split('\n'):
- output += line.lstrip() + '\n' # remove indentation completely
- elif dent > 0:
- for line in input.split('\n'):
- output += ' '* dent + line + '\n'
- return output
-
- def format(self, input):
- diff = {
- '\n<!DOCTYPE':'<!DOCTYPE',
- '\n</ul>' :'</ul>',
- '<a name' :'\n<a name',
- '<tr>\n' :'<tr>',
- '<tr>' :' <tr>',
- '</th>\n' :'</th>',
- '</td>\n' :'</td>',
- '<tbody>\n' :'<tbody>'
- }
- output = self.indent(input, 0)
- for key, value in diff.items():
- output = output.replace(key, value)
- return output
-
- def WriteToCSS(self, handle):
- '''
- Write the Cascading stylesheet template to the handle
- It is expected that the handle is a Filehandle
- '''
- css = """
- @CHARSET "ISO-8859-1";
-
- body {
- font-family: verdana;
- font-size: small;
- }
-
- div.title {
- font-size: large;
- text-align: center;
- }
-
- h1 {
- page-break-before: always;
- }
-
- h1, h2 {
- background-color: #D3D3D3;
- color:#404040;
- margin-right: 3%;
- padding-left: 40px;
- }
-
- h1:hover{
- background-color: #EBEBEB;
- }
-
- h3 {
- padding-left: 40px;
- }
-
- table {
- border-width: 1px;
- border-style: solid;
- border-color: #000000;
- border-collapse: collapse;
- width: 94%;
- margin: 20px 3% 10px;
- }
-
- caption {
- margin-bottom: 5px;
- }
-
- th {
- background-color: #000000;
- color:#ffffff;
- padding-left:5px;
- padding-right:5px;
- }
-
- tr {
- }
-
- td {
- border-width: 1px;
- border-style: solid;
- border-color: #a0a0a0;
- padding-left:5px;
- padding-right:5px;
- }
-
- label {
- float:right;
- margin-right: 3%;
- }
-
- ul.multicolumn {
- list-style:none;
- float:left;
- padding-right:0px;
- margin-right:0px;
- }
-
- li.multicolumn {
- float:left;
- width:200px;
- margin-right:0px;
- }
-
- a {
- color:#a000a0;
- text-decoration:none;
- }
-
- a:hover {
- color:#a000a0;
- text-decoration:underline;
- }
- """
-
- css = self.indent(css, 0)
-
- handle.write(css)
-
-
-def usage():
- print("\nUsage: \n\tblender2.5 -b -P BlendFileDnaExporter_25.py [-- [options]]")
- print("Options:")
- print("\t--dna-keep-blend: doesn't delete the produced blend file DNA export to html")
- print("\t--dna-debug: sets the logging level to DEBUG (lots of additional info)")
- print("\t--dna-versioned saves version informations in the html and blend filenames")
- print("\t--dna-overwrite-css overwrite dna.css, useful when modifying css in the script")
- print("Examples:")
- print("\tdefault: % blender2.5 -b -P BlendFileDnaExporter_25.py")
- print("\twith options: % blender2.5 -b -P BlendFileDnaExporter_25.py -- --dna-keep-blend --dna-debug\n")
-
-
-######################################################
-# Main
-######################################################
-
-def main():
-
- import os, os.path
-
- try:
- bpy = __import__('bpy')
-
- # Files
- if '--dna-versioned' in sys.argv:
- blender_version = '_'.join(map(str, bpy.app.version))
- filename = 'dna-{0}-{1}_endian-{2}-r{3}'.format(sys.arch, sys.byteorder, blender_version, bpy.app.build_revision[2:-1])
- else:
- filename = 'dna'
- dir = os.path.dirname(__file__)
- Path_Blend = os.path.join(dir, filename + '.blend') # temporary blend file
- Path_HTML = os.path.join(dir, filename + '.html') # output html file
- Path_CSS = os.path.join(dir, 'dna.css') # output css file
-
- # create a blend file for dna parsing
- if not os.path.exists(Path_Blend):
- log.info("1: write temp blend file with SDNA info")
- log.info(" saving to: " + Path_Blend)
- try:
- bpy.ops.wm.save_as_mainfile(filepath = Path_Blend, copy = True, compress = False)
- except:
- log.error("Filename {0} does not exist and can't be created... quitting".format(Path_Blend))
- return
- else:
- log.info("1: found blend file with SDNA info")
- log.info(" " + Path_Blend)
-
- # read blend header from blend file
- log.info("2: read file:")
-
- if not dir in sys.path:
- sys.path.append(dir)
- import BlendFileReader
-
- handle = BlendFileReader.openBlendFile(Path_Blend)
- blendfile = BlendFileReader.BlendFile(handle)
- catalog = DNACatalogHTML(blendfile.Catalog, bpy)
-
- # close temp file
- handle.close()
-
- # deleting or not?
- if '--dna-keep-blend' in sys.argv:
- # keep the blend, useful for studying hexdumps
- log.info("5: closing blend file:")
- log.info(" {0}".format(Path_Blend))
- else:
- # delete the blend
- log.info("5: close and delete temp blend:")
- log.info(" {0}".format(Path_Blend))
- os.remove(Path_Blend)
-
- # export dna to xhtml
- log.info("6: export sdna to xhtml file")
- handleHTML = open(Path_HTML, "w")
- catalog.WriteToHTML(handleHTML)
- handleHTML.close()
-
- # only write the css when doesn't exist or at explicit request
- if not os.path.exists(Path_CSS) or '--dna-overwrite-css' in sys.argv:
- handleCSS = open(Path_CSS, "w")
- catalog.WriteToCSS(handleCSS)
- handleCSS.close()
-
- # quit blender
- if not bpy.app.background:
- log.info("7: quit blender")
- bpy.ops.wm.exit_blender()
-
- except ImportError:
- log.warning(" skipping, not running in Blender")
- usage()
- sys.exit(2)
-
-
-if __name__ == '__main__':
- main()
diff --git a/doc/blender_file_format/BlendFileReader.py b/doc/blender_file_format/BlendFileReader.py
deleted file mode 100644
index 7003af10ac7..00000000000
--- a/doc/blender_file_format/BlendFileReader.py
+++ /dev/null
@@ -1,446 +0,0 @@
-#! /usr/bin/env python3
-
-# ***** 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-#
-# ***** END GPL LICENCE BLOCK *****
-
-######################################################
-# Importing modules
-######################################################
-
-import os
-import struct
-import gzip
-import tempfile
-
-import logging
-log = logging.getLogger("BlendFileReader")
-
-######################################################
-# module global routines
-######################################################
-
-def ReadString(handle, length):
- '''
- ReadString reads a String of given length or a zero terminating String
- from a file handle
- '''
- if length != 0:
- return handle.read(length).decode()
- else:
- # length == 0 means we want a zero terminating string
- result = ""
- s = ReadString(handle, 1)
- while s!="\0":
- result += s
- s = ReadString(handle, 1)
- return result
-
-
-def Read(type, handle, fileheader):
- '''
- Reads the chosen type from a file handle
- '''
- def unpacked_bytes(type_char, size):
- return struct.unpack(fileheader.StructPre + type_char, handle.read(size))[0]
-
- if type == 'ushort':
- return unpacked_bytes("H", 2) # unsigned short
- elif type == 'short':
- return unpacked_bytes("h", 2) # short
- elif type == 'uint':
- return unpacked_bytes("I", 4) # unsigned int
- elif type == 'int':
- return unpacked_bytes("i", 4) # int
- elif type == 'float':
- return unpacked_bytes("f", 4) # float
- elif type == 'ulong':
- return unpacked_bytes("Q", 8) # unsigned long
- elif type == 'pointer':
- # The pointersize is given by the header (BlendFileHeader).
- if fileheader.PointerSize == 4:
- return Read('uint', handle, fileheader)
- if fileheader.PointerSize == 8:
- return Read('ulong', handle, fileheader)
-
-
-def openBlendFile(filename):
- '''
- Open a filename, determine if the file is compressed and returns a handle
- '''
- handle = open(filename, 'rb')
- magic = ReadString(handle, 7)
- if magic in ("BLENDER", "BULLETf"):
- log.debug("normal blendfile detected")
- handle.seek(0, os.SEEK_SET)
- return handle
- else:
- log.debug("gzip blendfile detected?")
- handle.close()
- log.debug("decompressing started")
- fs = gzip.open(filename, "rb")
- handle = tempfile.TemporaryFile()
- data = fs.read(1024*1024)
- while data:
- handle.write(data)
- data = fs.read(1024*1024)
- log.debug("decompressing finished")
- fs.close()
- log.debug("resetting decompressed file")
- handle.seek(0, os.SEEK_SET)
- return handle
-
-
-def Align(handle):
- '''
- Aligns the filehandle on 4 bytes
- '''
- offset = handle.tell()
- trim = offset % 4
- if trim != 0:
- handle.seek(4-trim, os.SEEK_CUR)
-
-
-######################################################
-# module classes
-######################################################
-
-class BlendFile:
- '''
- Reads a blendfile and store the header, all the fileblocks, and catalogue
- structs foound in the DNA fileblock
-
- - BlendFile.Header (BlendFileHeader instance)
- - BlendFile.Blocks (list of BlendFileBlock instances)
- - BlendFile.Catalog (DNACatalog instance)
- '''
-
- def __init__(self, handle):
- log.debug("initializing reading blend-file")
- self.Header = BlendFileHeader(handle)
- self.Blocks = []
- fileblock = BlendFileBlock(handle, self)
- found_dna_block = False
- while not found_dna_block:
- if fileblock.Header.Code in ("DNA1", "SDNA"):
- self.Catalog = DNACatalog(self.Header, handle)
- found_dna_block = True
- else:
- fileblock.Header.skip(handle)
-
- self.Blocks.append(fileblock)
- fileblock = BlendFileBlock(handle, self)
-
- # appending last fileblock, "ENDB"
- self.Blocks.append(fileblock)
-
- # seems unused?
- """
- def FindBlendFileBlocksWithCode(self, code):
- #result = []
- #for block in self.Blocks:
- #if block.Header.Code.startswith(code) or block.Header.Code.endswith(code):
- #result.append(block)
- #return result
- """
-
-
-class BlendFileHeader:
- '''
- BlendFileHeader allocates the first 12 bytes of a blend file.
- It contains information about the hardware architecture.
- Header example: BLENDER_v254
-
- BlendFileHeader.Magic (str)
- BlendFileHeader.PointerSize (int)
- BlendFileHeader.LittleEndianness (bool)
- BlendFileHeader.StructPre (str) see http://docs.python.org/py3k/library/struct.html#byte-order-size-and-alignment
- BlendFileHeader.Version (int)
- '''
-
- def __init__(self, handle):
- log.debug("reading blend-file-header")
-
- self.Magic = ReadString(handle, 7)
- log.debug(self.Magic)
-
- pointersize = ReadString(handle, 1)
- log.debug(pointersize)
- if pointersize == "-":
- self.PointerSize = 8
- if pointersize == "_":
- self.PointerSize = 4
-
- endianness = ReadString(handle, 1)
- log.debug(endianness)
- if endianness == "v":
- self.LittleEndianness = True
- self.StructPre = "<"
- if endianness == "V":
- self.LittleEndianness = False
- self.StructPre = ">"
-
- version = ReadString(handle, 3)
- log.debug(version)
- self.Version = int(version)
-
- log.debug("{0} {1} {2} {3}".format(self.Magic, self.PointerSize, self.LittleEndianness, version))
-
-
-class BlendFileBlock:
- '''
- BlendFileBlock.File (BlendFile)
- BlendFileBlock.Header (FileBlockHeader)
- '''
-
- def __init__(self, handle, blendfile):
- self.File = blendfile
- self.Header = FileBlockHeader(handle, blendfile.Header)
-
- def Get(self, handle, path):
- log.debug("find dna structure")
- dnaIndex = self.Header.SDNAIndex
- dnaStruct = self.File.Catalog.Structs[dnaIndex]
- log.debug("found " + dnaStruct.Type.Name)
- handle.seek(self.Header.FileOffset, os.SEEK_SET)
- return dnaStruct.GetField(self.File.Header, handle, path)
-
-
-class FileBlockHeader:
- '''
- FileBlockHeader contains the information in a file-block-header.
- The class is needed for searching to the correct file-block (containing Code: DNA1)
-
- Code (str)
- Size (int)
- OldAddress (pointer)
- SDNAIndex (int)
- Count (int)
- FileOffset (= file pointer of datablock)
- '''
-
- def __init__(self, handle, fileheader):
- self.Code = ReadString(handle, 4).strip()
- if self.Code != "ENDB":
- self.Size = Read('uint', handle, fileheader)
- self.OldAddress = Read('pointer', handle, fileheader)
- self.SDNAIndex = Read('uint', handle, fileheader)
- self.Count = Read('uint', handle, fileheader)
- self.FileOffset = handle.tell()
- else:
- self.Size = Read('uint', handle, fileheader)
- self.OldAddress = 0
- self.SDNAIndex = 0
- self.Count = 0
- self.FileOffset = handle.tell()
- #self.Code += ' ' * (4 - len(self.Code))
- log.debug("found blend-file-block-fileheader {0} {1}".format(self.Code, self.FileOffset))
-
- def skip(self, handle):
- handle.read(self.Size)
-
-
-class DNACatalog:
- '''
- DNACatalog is a catalog of all information in the DNA1 file-block
-
- Header = None
- Names = None
- Types = None
- Structs = None
- '''
-
- def __init__(self, fileheader, handle):
- log.debug("building DNA catalog")
- self.Names=[]
- self.Types=[]
- self.Structs=[]
- self.Header = fileheader
-
- SDNA = ReadString(handle, 4)
-
- # names
- NAME = ReadString(handle, 4)
- numberOfNames = Read('uint', handle, fileheader)
- log.debug("building #{0} names".format(numberOfNames))
- for i in range(numberOfNames):
- name = ReadString(handle,0)
- self.Names.append(DNAName(name))
- Align(handle)
-
- # types
- TYPE = ReadString(handle, 4)
- numberOfTypes = Read('uint', handle, fileheader)
- log.debug("building #{0} types".format(numberOfTypes))
- for i in range(numberOfTypes):
- type = ReadString(handle,0)
- self.Types.append(DNAType(type))
- Align(handle)
-
- # type lengths
- TLEN = ReadString(handle, 4)
- log.debug("building #{0} type-lengths".format(numberOfTypes))
- for i in range(numberOfTypes):
- length = Read('ushort', handle, fileheader)
- self.Types[i].Size = length
- Align(handle)
-
- # structs
- STRC = ReadString(handle, 4)
- numberOfStructures = Read('uint', handle, fileheader)
- log.debug("building #{0} structures".format(numberOfStructures))
- for structureIndex in range(numberOfStructures):
- type = Read('ushort', handle, fileheader)
- Type = self.Types[type]
- structure = DNAStructure(Type)
- self.Structs.append(structure)
-
- numberOfFields = Read('ushort', handle, fileheader)
- for fieldIndex in range(numberOfFields):
- fTypeIndex = Read('ushort', handle, fileheader)
- fNameIndex = Read('ushort', handle, fileheader)
- fType = self.Types[fTypeIndex]
- fName = self.Names[fNameIndex]
- structure.Fields.append(DNAField(fType, fName))
-
-
-class DNAName:
- '''
- DNAName is a C-type name stored in the DNA.
-
- Name = str
- '''
-
- def __init__(self, name):
- self.Name = name
-
- def AsReference(self, parent):
- if parent == None:
- result = ""
- else:
- result = parent+"."
-
- result = result + self.ShortName()
- return result
-
- def ShortName(self):
- result = self.Name;
- result = result.replace("*", "")
- result = result.replace("(", "")
- result = result.replace(")", "")
- Index = result.find("[")
- if Index != -1:
- result = result[0:Index]
- return result
-
- def IsPointer(self):
- return self.Name.find("*")>-1
-
- def IsMethodPointer(self):
- return self.Name.find("(*")>-1
-
- def ArraySize(self):
- result = 1
- Temp = self.Name
- Index = Temp.find("[")
-
- while Index != -1:
- Index2 = Temp.find("]")
- result*=int(Temp[Index+1:Index2])
- Temp = Temp[Index2+1:]
- Index = Temp.find("[")
-
- return result
-
-
-class DNAType:
- '''
- DNAType is a C-type stored in the DNA
-
- Name = str
- Size = int
- Structure = DNAStructure
- '''
-
- def __init__(self, aName):
- self.Name = aName
- self.Structure=None
-
-
-class DNAStructure:
- '''
- DNAType is a C-type structure stored in the DNA
-
- Type = DNAType
- Fields = [DNAField]
- '''
-
- def __init__(self, aType):
- self.Type = aType
- self.Type.Structure = self
- self.Fields=[]
-
- def GetField(self, header, handle, path):
- splitted = path.partition(".")
- name = splitted[0]
- rest = splitted[2]
- offset = 0;
- for field in self.Fields:
- if field.Name.ShortName() == name:
- log.debug("found "+name+"@"+str(offset))
- handle.seek(offset, os.SEEK_CUR)
- return field.DecodeField(header, handle, rest)
- else:
- offset += field.Size(header)
-
- log.debug("error did not find "+path)
- return None
-
-
-class DNAField:
- '''
- DNAField is a coupled DNAType and DNAName.
-
- Type = DNAType
- Name = DNAName
- '''
-
- def __init__(self, aType, aName):
- self.Type = aType
- self.Name = aName
-
- def Size(self, header):
- if self.Name.IsPointer() or self.Name.IsMethodPointer():
- return header.PointerSize*self.Name.ArraySize()
- else:
- return self.Type.Size*self.Name.ArraySize()
-
- def DecodeField(self, header, handle, path):
- if path == "":
- if self.Name.IsPointer():
- return Read('pointer', handle, header)
- if self.Type.Name=="int":
- return Read('int', handle, header)
- if self.Type.Name=="short":
- return Read('short', handle, header)
- if self.Type.Name=="float":
- return Read('float', handle, header)
- if self.Type.Name=="char":
- return ReadString(handle, self.Name.ArraySize())
- else:
- return self.Type.Structure.GetField(header, handle, path)
-
diff --git a/doc/blender_file_format/README b/doc/blender_file_format/README
deleted file mode 100644
index 55dc3b83e49..00000000000
--- a/doc/blender_file_format/README
+++ /dev/null
@@ -1,29 +0,0 @@
-To inspect the blend-file-format used by a certain version of blender 2.5x,
-navigate to this folder and run this command:
-
-blender2.5 -b -P BlendFileDnaExporter_25.py
-
-where "blender2.5" is your blender executable or a symlink to it.
-
-This creates a temporary dna.blend to be inspected and it produces two new files:
-
-* dna.html: the list of all the structures saved in a blend file with the blender2.5
- executable you have used. If you enable build informations when you build blender,
- the dna.html file will also show which svn revision the html refers to.
-* dna.css: the css for the html above
-
-Below you have the help message with a list of options you can use.
-
-
-Usage:
- blender2.5 -b -P BlendFileDnaExporter_25.py [-- [options]]
-Options:
- --dna-keep-blend: doesn't delete the produced blend file DNA export to html
- --dna-debug: sets the logging level to DEBUG (lots of additional info)
- --dna-versioned saves version informations in the html and blend filenames
- --dna-overwrite-css overwrite dna.css, useful when modifying css in the script
-Examples:
- default: % blender2.5 -b -P BlendFileDnaExporter_25.py
- with options: % blender2.5 -b -P BlendFileDnaExporter_25.py -- --dna-keep-blend --dna-debug
-
-
diff --git a/doc/blender_file_format/mystery_of_the_blend.css b/doc/blender_file_format/mystery_of_the_blend.css
deleted file mode 100644
index df287b54a06..00000000000
--- a/doc/blender_file_format/mystery_of_the_blend.css
+++ /dev/null
@@ -1,204 +0,0 @@
-@CHARSET "ISO-8859-1";
-
-table {
- border-width: 1px;
- border-style: solid;
- border-color: #000000;
- border-collapse: collapse;
- width: 94%;
- margin: 10px 3%;
-}
-
-DIV.title {
- font-size: 30px;
- font-weight: bold;
- text-align: center
-}
-
-DIV.subtitle {
- font-size: large;
- text-align: center
-}
-
-DIV.contact {
- margin:30px 3%;
-}
-
-@media print {
- DIV.contact {
- margin-top: 300px;
- }
- DIV.title {
- margin-top: 400px;
- }
-}
-
-label {
- font-weight: bold;
- width: 100px;
- float: left;
-}
-
-label:after {
- content: ":";
-}
-
-TH {
- background-color: #000000;
- color: #ffffff;
- padding-left: 5px;
- padding-right: 5px;
-}
-
-TR {
-}
-
-TD {
- border-width: 1px;
- border-style: solid;
- border-color: #a0a0a0;
- padding-left: 5px;
- padding-right: 5px;
-}
-
-BODY {
- font-family: verdana;
- font-size: small;
-}
-
-H1 {
- page-break-before: always;
-}
-
-H1, H2, H3, H4 {
- margin-top: 30px;
- margin-right: 3%;
- padding: 3px 3%;
- color: #404040;
- cursor: pointer;
-}
-
-H1, H2 {
- background-color: #D3D3D3;
-}
-
-H3, H4 {
- padding-top: 5px;
- padding-bottom: 5px;
-}
-
-H1:hover, H2:hover, H3:hover, H4:hover {
- background-color: #EBEBEB;
-}
-
-CODE.evidence {
- font-size:larger
-}
-
-CODE.block {
- color: #000000;
- background-color: #DDDC75;
- margin: 10px 0;
- padding: 5px;
- border-width: 1px;
- border-style: dotted;
- border-color: #000000;
- white-space: pre;
- display: block;
- font-size: 2 em;
-}
-
-ul {
- margin: 10px 3%;
-}
-
-li {
- margin: 0 -15px;
-}
-
-ul.multicolumn {
- list-style: none;
- float: left;
- padding-right: 0px;
- margin-right: 0px;
-}
-
-li.multicolumn {
- float: left;
- width: 200px;
- margin-right: 0px;
-}
-
-@media screen {
- p {
- margin: 10px 3%;
- line-height: 130%;
- }
-}
-
-span.fade {
- color: gray;
-}
-
-span.header {
- color: green;
-}
-
-span.header-greyed {
- color: #4CBE4B;
-}
-
-span.data {
- color: blue;
-}
-
-span.data-greyed {
- color: #5D99C4;
-}
-
-span.descr {
- color: red;
-}
-
-div.box {
- margin: 15px 3%;
- border-style: dotted;
- border-width: 1px;
-}
-
-div.box-solid {
- margin: 15px 3%;
- border-style: solid;
- border-width: 1px;
-}
-
-p.box-title {
- font-style: italic;
- font-size: 110%;
- cursor: pointer;
-}
-
-p.box-title:hover {
- background-color: #EBEBEB;
-}
-
-p.code {
- font-family: "Courier New", Courier, monospace;
-}
-
-a {
- color: #a000a0;
- text-decoration: none;
-}
-
-a:hover {
- color: #a000a0;
- text-decoration: underline;
-}
-
-td.skip {
- color: #808080;
- padding-top: 10px;
- padding-bottom: 10px;
- text-align: center;
-}
diff --git a/doc/blender_file_format/mystery_of_the_blend.html b/doc/blender_file_format/mystery_of_the_blend.html
deleted file mode 100644
index b34493ffa3e..00000000000
--- a/doc/blender_file_format/mystery_of_the_blend.html
+++ /dev/null
@@ -1,835 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
-<html>
-<head>
- <link rel="stylesheet" type="text/css" href="mystery_of_the_blend.css" media="screen, print">
- <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
- <title>The mystery of the blend</title>
-</head>
-
-<body>
-<div class="title">The mystery of the blend</div>
-<div class="subtitle">The blender file-format explained</div>
-<div class="contact">
-<label>Author</label> Jeroen Bakker<br>
-<label>Email</label> <a href="mailto:j.bakker@atmind.nl">j.bakker@atmind.nl</a><br>
-<label>Website</label> <a href="http://www.atmind.nl/blender/">http://www.atmind.nl/blender</a><br>
-<label>Version</label> 06-10-2010<br>
-</div>
-
-<a name="introduction" href="#introduction" ><h2>Introduction</h2></a>
-</a>
-
-<p>In this article I will describe the
- blend-file-format with a request to tool-makers to support blend-file.
-
-</p>
-<p>First I'll describe how Blender works with blend-files. You'll notice
- why the blend-file-format is not that well documented, as from
-Blender's perspective this is not needed.
-We look at the global file-structure of a blend-file (the file-header
-and file-blocks).
-After this is explained, we go deeper to the core of the blend-file, the
- DNA-structures. They hold the blue-prints of the blend-file and the key
- asset of understanding blend-files.
-When that's done we can use these DNA-structures to read information
-from elsewhere in the blend-file.
-
-</p>
-<p>
-In this article we'll be using the default blend-file from Blender 2.54,
- with the goal to read the output resolution from the Scene.
-The article is written to be programming language independent and I've
-setup a web-site for support.
-</p>
-
-<a name="loading-and-saving-in-blender" href="#loading-and-saving-in-blender">
-<h2>Loading and saving in Blender</h2>
-</a>
-
-<p>
-Loading and saving in Blender is very fast and Blender is known to
-have excellent downward and upward compatibility. Ton Roosendaal
-demonstrated that in December 2008 by loading a 1.0 blend-file using
-Blender 2.48a [ref: <a href="http://www.blendernation.com/2008/12/01/blender-dna-rna-and-backward-compatibility/">http://www.blendernation.com/2008/12/01/blender-dna-rna-and-backward-compatibility/</a>].
-</p>
-
-<p>
-Saving complex scenes in Blender is done within seconds. Blender
-achieves this by saving data in memory to disk without any
-transformations or translations. Blender only adds file-block-headers to
- this data. A file-block-header contains clues on how to interpret the
-data. After the data, all internally Blender structures are stored.
-These structures will act as blue-prints when Blender loads the file.
-Blend-files can be different when stored on different hardware platforms
- or Blender releases. There is no effort taken to make blend-files
-binary the same. Blender creates the blend-files in this manner since
-release 1.0. Backward and upwards compatibility is not implemented when
-saving the file, this is done during loading.
-</p>
-
-<p>
-When Blender loads a blend-file, the DNA-structures are read first.
-Blender creates a catalog of these DNA-structures. Blender uses this
-catalog together with the data in the file, the internal Blender
-structures of the Blender release you're using and a lot of
-transformation and translation logic to implement the backward and
-upward compatibility. In the source code of blender there is actually
-logic which can transform and translate every structure used by a
-Blender release to the one of the release you're using [ref: <a href="http://download.blender.org/source/blender-2.48a.tar.gz">http://download.blender.org/source/blender-2.48a.tar.gz</a>
- <a href="https://svn.blender.org/svnroot/bf-blender/tags/blender-2.48-release/source/blender/blenloader/intern/readfile.c">blender/blenloader/intern/readfile.c</a> lines
-4946-7960]. The more difference between releases the more logic is
-executed.
-</p>
-
-<p>
-The blend-file-format is not well documented, as it does not differ from
- internally used structures and the file can really explain itself.
-</p>
-
-<a name="global-file-structure" href="#global-file-structure">
-<h2>Global file-structure</h2>
-</a>
-
-<p>
-This section explains how the global file-structure can be read.
-</p>
-
-<ul>
-<li>A blend-file always start with the <b>file-header</b></li>
-<li>After the file-header, follows a list of <b>file-blocks</b> (the default blend file of Blender 2.48 contains more than 400 of these file-blocks).</li>
-<li>Each file-block has a <b>file-block header</b> and <b>file-block data</b></li>
-<li>At the end of the blend-file there is a section called "<a href="#structure-DNA" style="font-weight:bold">Structure DNA</a>", which lists all the internal structures of the Blender release the file was created in</li>
-<li>The blend-file ends with a file-block called 'ENDB'</li>
-</ul>
-
-<!-- file scheme -->
-<div class="box-solid" style="width:20%; margin-left:35%; font-size:0.8em;">
-
- <p class="code"><b>File.blend</b></p>
-
- <div class="box"><p class="code">File-header</p></div>
-
- <div class="box-solid"><p class="code">File-block</p>
- <div class="box"><p class="code">Header</p></div>
- <div class="box"><p class="code">Data</p></div>
- </div>
-
- <div class="box" style="border-style:dashed"><p class="code">File-block</p></div>
- <div class="box" style="border-style:dashed"><p class="code">File-block</p></div>
-
- <div class="box-solid"><p class="code">File-block 'Structure DNA'</p>
- <div class="box"><p class="code">Header ('DNA1')</p></div>
- <div class="box-solid">
- <p class="code">Data ('SDNA')</p>
- <div class="box">
- <p class="code">Names ('NAME')</p>
- </div>
- <div class="box">
- <p class="code">Types ('TYPE')</p>
- </div>
- <div class="box">
- <p class="code">Lengths ('TLEN')</p>
- </div>
- <div class="box">
- <p class="code">Structures ('STRC')</p>
- </div>
- </div>
- </div>
-
- <div class="box-solid"><p class="code">File-Block 'ENDB'</p></div>
-
-</div><!-- end of file scheme -->
-
-<a name="file-header" href="#file-header">
-<h3>File-Header</h3>
-</a>
-
-<p>
-The first 12 bytes of every blend-file is the file-header. The
-file-header has information on Blender (version-number) and the PC the
-blend-file was saved on (pointer-size and endianness). This is required
-as all data inside the blend-file is ordered in that way, because no
-translation or transformation is done during saving.
-The next table describes the information in the file-header.
-</p>
-
-<table>
-<caption>File-header</caption>
-<thead>
-<tr><th>reference</th>
- <th>structure</th>
- <th>type</th>
- <th>offset</th>
- <th>size</th></tr>
-</thead>
-<tbody>
-<tr><td>identifier</td>
- <td>char[7]</td>
- <td>File identifier (always 'BLENDER')</td>
- <td>0</td>
- <td>7</td></tr>
-<tr><td>pointer-size</td>
- <td>char</td>
- <td>Size of a pointer; all pointers in the file are stored in this format. '_' means 4 bytes or 32 bit and '-' means 8 bytes or 64 bits.</td>
- <td>7</td>
- <td>1</td></tr>
-<tr><td>endianness</td>
- <td>char</td>
- <td>Type of byte ordering used; 'v' means little endian and 'V' means big endian.</td>
- <td>8</td>
- <td>1</td></tr>
-<tr><td>version-number</td>
- <td>char[3]</td>
- <td>Version of Blender the file was created in; '254' means version 2.54</td>
- <td>9</td>
- <td>3</td></tr>
-</tbody>
-</table>
-
-<p>
-<a href="http://en.wikipedia.org/wiki/Endianness">Endianness</a> addresses the way values are ordered in a sequence of bytes(see the <a href="#example-endianess">example</a> below):
-</p>
-
-<ul>
- <li>in a big endian ordering, the largest part of the value is placed on the first byte and
- the lowest part of the value is placed on the last byte,</li>
- <li>in a little endian ordering, largest part of the value is placed on the last byte
- and the smallest part of the value is placed on the first byte.</li>
-</ul>
-
-<p>
-Nowadays, little-endian is the most commonly used.
-</p>
-
-<a name="example-endianess"></a>
-<div class="box">
-<p onclick="location.href='#example-endianess'" class="box-title">
-Endianess Example
-</p>
-<p>
-Writing the integer <code class="evidence">0x4A3B2C1Dh</code>, will be ordered:
-<ul>
-<li>in big endian as <code class="evidence">0x4Ah</code>, <code class="evidence">0x3Bh</code>, <code class="evidence">0x2Ch</code>, <code class="evidence">0x1Dh</code></li>
-<li>in little endian as <code class="evidence">0x1Dh</code>, <code class="evidence">0x2Ch</code>, <code class="evidence">0x3Bh</code>, <code class="evidence">0x4Ah</code></li>
-</ul>
-</p>
-</div>
-
-<p>
-Blender supports little-endian and big-endian.<br>
-This means that when the endianness
-is different between the blend-file and the PC your using, Blender changes it to the byte ordering
-of your PC.
-</p>
-
-<a name="example-file-header"></a>
-<div class="box">
-<p onclick="location.href='#example-file-header'" class="box-title">
-File-header Example
-</p>
-
-<p>
-This hex-dump describes a file-header created with <code>blender</code> <code>2.54.0</code> on <code>little-endian</code> hardware with a <code>32 bits</code> pointer length.
-<code class="block"> <span class="descr">pointer-size version-number
- | |</span>
-0000 0000: [42 4C 45 4E 44 45 52] [5F] [76] [32 35 34] BLENDER_v254 <span class="descr">
- | |
- identifier endianness</span></code>
-</p>
-</div>
-
-<a name="file-blocks" href="#file-blocks"><h3>File-blocks</h3></a>
-
-<p>
-File-blocks contain a "<a href="#file-block-header">file-block header</a>" and "file-block data".
-</p>
-
-<a name="file-block-header" href="#file-block-header"><h3>File-block headers</h3></a>
-
-<p>
-The file-block-header describes:
-</p>
-
-<ul>
-<li>the type of information stored in the
-file-block</li>
-<li>the total length of the data</li>
-<li>the old memory
-pointer at the moment the data was written to disk</li>
-<li>the number of items of this information</li>
-</ul>
-
-<p>
-As we can see below, depending on the pointer-size stored in the file-header, a file-block-header
-can be 20 or 24 bytes long, hence it is always aligned at 4 bytes.
-</p>
-
-<table>
-<caption>File-block-header</caption>
-<thead>
-<tr>
-<th>reference</th>
- <th>structure</th>
- <th>type</th>
- <th>offset</th>
- <th>size</th></tr></thead>
-<tbody>
-<tr><td>code</td>
- <td>char[4]</td>
- <td>File-block identifier</td>
- <td>0</td>
- <td>4</td></tr>
-<tr><td>size</td>
- <td>integer</td>
- <td>Total length of the data after the file-block-header</td>
- <td>4</td>
- <td>4</td></tr>
-<tr><td>old memory address</td>
- <td>void*</td>
- <td>Memory address the structure was located when written to disk</td>
- <td>8</td>
- <td>pointer-size (4/8)</td></tr>
-<tr><td>SDNA index</td>
- <td>integer</td>
- <td>Index of the SDNA structure</td>
- <td>8+pointer-size</td>
- <td>4</td></tr>
-<tr><td>count</td>
- <td>integer</td>
- <td>Number of structure located in this file-block</td>
- <td>12+pointer-size</td>
- <td>4</td></tr>
-</tbody>
-</table>
-
-<p>
-The above table describes how a file-block-header is structured:
-</p>
-
-<ul>
-<li><code>Code</code> describes different types of file-blocks. The code determines with what logic the data must be read. <br>
-These codes also allows fast finding of data like Library, Scenes, Object or Materials as they all have a specific code. </li>
-<li><code>Size</code> contains the total length of data after the file-block-header.
-After the data a new file-block starts. The last file-block in the file
-has code 'ENDB'.</li>
-<li><code>Old memory address</code> contains the memory address when the structure
-was last stored. When loading the file the structures can be placed on
-different memory addresses. Blender updates pointers to these structures
- to the new memory addresses.</li>
-<li><code>SDNA index</code> contains the index in the DNA structures to be used when
-reading this file-block-data. <br>
-More information about this subject will be explained in the <a href="#reading-scene-information">Reading scene information section</a>.</li>
-<li><code>Count</code> tells how many elements of the specific SDNA structure can be found in the data.</li>
-</ul>
-
-<a name="example-file-block-header"></a>
-<div class="box">
-<p onclick="location.href='#example-file-block-header'" class="box-title">
-Example
-</p>
-<p>
-This hex-dump describes a File-block (= <span class="header">File-block header</span> + <span class="data">File-block data</span>) created with <code>blender</code> <code>2.54</code> on <code>little-endian</code> hardware with a <code>32 bits</code> pointer length.<br>
-<code class="block"><span class="descr"> file-block
- identifier='SC' data size=1404 old pointer SDNA index=150
- | | | |</span>
-0000 4420: <span class="header">[53 43 00 00] [7C 05 00 00] [68 34 FB 0B] [96 00 00 00]</span> SC.. `... ./.. ....
-0000 4430: <span class="header">[01 00 00 00]</span> <span class="data">[xx xx xx xx xx xx xx xx xx xx xx xx</span> .... xxxx xxxx xxxx<span class="descr">
- | |
- count=1 file-block data (next 1404 bytes)</span>
-</code>
-</p>
-
-<ul>
-<li>The code <code>'SC'+0x00h</code> identifies that it is a Scene. </li>
-<li>Size of the data is 1404 bytes (0x0000057Ch = 0x7Ch + 0x05h * 256 = 124 + 1280)</li>
-<li>The old pointer is 0x0BFB3468h</li>
-<li>The SDNA index is 150 (0x00000096h = 6 + 9 * 16 = 6 + 144)</li>
-<li>The section contains a single scene (count = 1).</li>
-</ul>
-
-<p>
-Before we can interpret the data of this file-block we first have to read the DNA structures in the file.
-The section "<a href="#structure-DNA">Structure DNA</a>" will show how to do that.
-</p>
-</div>
-
-<a name="structure-DNA" href="#structure-DNA"><h2>Structure DNA</h2></a>
-
-<a name="DNA1-file-block" href="#DNA1-file-block"><h3>The DNA1 file-block</h3></a>
-
-<p>
-Structure DNA is stored in a file-block with code 'DNA1'. It can be just before the 'ENDB' file-block.
-</p>
-
-<p>
-The 'DNA1' file-block contains all internal structures of the Blender release the
-file was created in. <br>
-These structure can be described as C-structures: they can hold fields, arrays and
-pointers to other structures, just like a normal C-structure.
-
-<p>
-<code class="block">struct SceneRenderLayer {
- struct SceneRenderLayer *next, *prev;
- char name[32];
- struct Material *mat_override;
- struct Group *light_override;
- unsigned int lay;
- unsigned int lay_zmask;
- int layflag;
- int pad;
- int passflag;
- int pass_xor;
-};
-</code>
-</p>
-
-<p>
-For example,a blend-file created with Blender 2.54 the 'DNA1' file-block is 57796 bytes long and contains 398 structures.
-</p>
-
-<a name="DNA1-file-block-header" href="#DNA1-file-block-header"><h3>DNA1 file-block-header</h3></a>
-
-<p>
-The DNA1 file-block header follows the same rules of any other file-block, see the example below.
-</p>
-
-<a name="example-DNA1-file-block-header"></a>
-<div class="box">
-<p onclick="location.href='#example-DNA1-file-block-header'" class="box-title">
-Example
-</p>
-<p>
-This hex-dump describes the file-block 'DNA1' header created with <code>blender</code> <code>2.54.0</code> on <code>little-endian</code> hardware with a <code>32 bits</code> pointer length.<br>
-<code class="block"><span class="descr"> (file-block
- identifier='DNA1') data size=57796 old pointer SDNA index=0
- | | | |</span>
-0004 B060 <span class="header">[44 4E 41 31] [C4 E1 00 00] [C8 00 84 0B] [00 00 00 00]</span> DNA1............
-0004 B070 <span class="header">[01 00 00 00]</span> <span class="fade">[53 44 4E 41 4E 41 4D 45 CB 0B 00 00</span> ....<span class="fade">SDNANAME....</span><span class="descr">
- | |
- count=1 'DNA1' file-block data (next 57796 bytes)</span>
-</code>
-</p>
-</div>
-
-<a name="DNA1-file-block-data" href="#DNA1-file-block-data"><h3>DNA1 file-block data</h3></a>
-<p>
-The next section describes how this information is ordered in the <b>data</b> of the 'DNA1' file-block.
-</p>
-
-<table>
-<caption>Structure of the DNA file-block-data</caption>
-<thead>
- <tr><th colspan="2">repeat condition</th>
- <th>name</th>
- <th>type</th>
- <th>length</th>
- <th>description</th></tr>
-</thead>
-<tbody>
-<tr><td></td>
- <td></td>
- <td>identifier</td>
- <td>char[4]</td>
- <td>4</td>
- <td>'SDNA'</td></tr>
-<tr><td></td>
- <td></td>
- <td>name identifier</td>
- <td>char[4]</td>
- <td>4</td>
- <td>'NAME'</td></tr>
-<tr><td></td>
- <td></td>
- <td>#names</td>
- <td>integer</td>
- <td>4</td>
- <td>Number of names follows</td></tr>
-<tr><td>for(#names)</td>
- <td></td>
- <td>name</td>
- <td>char[]</td>
- <td>?</td>
- <td>Zero terminating string of name, also contains pointer and simple array definitions (e.g. '*vertex[3]\0')</td></tr>
-<tr><td></td>
- <td></td>
- <td>type identifier</td>
- <td>char[4]</td>
- <td>4</td>
- <td>'TYPE' this field is aligned at 4 bytes</td></tr>
-<tr><td></td>
- <td></td>
- <td>#types</td>
- <td>integer</td>
- <td>4</td>
- <td>Number of types follows</td></tr>
-<tr><td>for(#types)</td>
- <td></td>
- <td>type</td>
- <td>char[]</td>
- <td>?</td>
- <td>Zero terminating string of type (e.g. 'int\0')</td></tr>
-<tr><td></td>
- <td></td>
- <td>length identifier</td>
- <td>char[4]</td>
- <td>4</td>
- <td>'TLEN' this field is aligned at 4 bytes</td></tr>
-<tr><td>for(#types)</td>
- <td></td>
- <td>length</td>
- <td>short</td>
- <td>2</td>
- <td>Length in bytes of type (e.g. 4)</td></tr>
-<tr><td></td>
- <td></td>
- <td>structure identifier</td>
- <td>char[4]</td>
- <td>4</td>
- <td>'STRC' this field is aligned at 4 bytes</td></tr>
-<tr><td></td>
- <td></td>
- <td>#structures</td>
- <td>integer</td>
- <td>4</td>
- <td>Number of structures follows</td></tr>
-<tr><td>for(#structures)</td>
- <td></td>
- <td>structure type</td>
- <td>short</td>
- <td>2</td>
- <td>Index in types containing the name of the structure</td></tr>
-<tr><td>..</td>
- <td></td>
- <td>#fields</td>
- <td>short</td>
- <td>2</td>
- <td>Number of fields in this structure</td></tr>
-<tr><td>..</td>
- <td>for(#field)</td>
- <td>field type</td>
- <td>short</td>
- <td>2</td>
- <td>Index in type</td></tr>
-<tr><td>for end</td>
- <td>for end</td>
- <td>field name</td>
- <td>short</td>
- <td>2</td>
- <td>Index in name</td></tr>
-</tbody>
-</table>
-
-<p>
-As you can see, the structures are stored in 4 arrays: names, types,
-lengths and structures. Every structure also contains an array of
-fields. A field is the combination of a type and a name. From this
-information a catalog of all structures can be constructed.
-The names are stored as how a C-developer defines them. This means that
-the name also defines pointers and arrays.
-(When a name starts with '*' it is used as a pointer. when the name
-contains for example '[3]' it is used as a array of 3 long.)
-In the types you'll find simple-types (like: 'integer', 'char',
-'float'), but also complex-types like 'Scene' and 'MetaBall'.
-'TLEN' part describes the length of the types. A 'char' is 1 byte, an
-'integer' is 4 bytes and a 'Scene' is 1376 bytes long.
-</p>
-
-<div class="box">
-<p class="box-title">
-Note
-</p>
-<p>
-All identifiers, are arrays of 4 chars, hence they are all aligned at 4 bytes.
-</p>
-</div>
-
-<a name="example-DNA1-file-block-data"></a>
-<div class="box">
-<p onclick="location.href='#example-DNA1-file-block-data'" class="box-title">
-Example
-</p>
-<p>
-Created with <code>blender</code> <code>2.54.0</code> on <code>little-endian</code> hardware with a <code>32 bits</code> pointer length.
-</p>
-
-<a name="DNA1-data-array-names" href="#DNA1-data-array-names"><h4>The names array</h4></a>
-<p>
-The first names are: *next, *prev, *data, *first, *last, x, y, xmin, xmax, ymin, ymax, *pointer, group, val, val2, type, subtype, flag, name[32], ...
-<code class="block"><span class="descr"> file-block-data identifier='SDNA' array-id='NAME' number of names=3019
- | | |</span>
-0004 B070 <span class="fade">01 00 00 00 [53 44 4E 41]</span><span class="data">[4E 41 4D 45] [CB 0B 00 00]</span> <span class="fade">....SDNA</span>NAME....
-0004 B080 <span class="data">[2A 6E 65 78 74 00][2A 70 72 65 76 00] [2A 64 61 74</span> *next.*prev.*dat<span class="descr">
- | | |
- '*next\0' '*prev\0' '*dat'</span><span class="fade">
- ....
- .... (3019 names)</span>
-</code>
-</p>
-
-<div class="box">
-<p class="box-title">
-Note
-</p>
-<p>
-While reading the DNA you'll will come across some strange
-names like '(*doit)()'. These are method pointers and Blender updates
-them to the correct methods.
-</p>
-</div>
-
-<a name="DNA1-data-array-types" href="#DNA1-data-array-types"><h4>The types array</h4></a>
-<p>
-The first types are: char, uchar, short, ushort, int, long, ulong, float, double, void, Link, LinkData, ListBase, vec2s, vec2f, ...
-<code class="block"><span class="descr"> array-id='TYPE'
- |</span>
-0005 2440 <span class="fade">6F 6C 64 5B 34 5D 5B 34 5D 00 00 00</span> [54 59 50 45] <span class="fade">old[4][4]...</span>TYPE
-0005 2450 [C9 01 00 00] [63 68 61 72 00] [75 63 68 61 72 00][73 ....char.uchar.s<span class="descr">
- | | | |
- number of types=457 'char\0' 'uchar\0' 's'</span><span class="fade">
- ....
- .... (457 types)</span>
-</code>
-</p>
-
-<a name="DNA1-data-array-lengths" href="#DNA1-data-array-lengths"><h4>The lengths array</h4></a>
-<p>
-<code class="block"><span class="descr"> char uchar ushort short
- array-id length length length length
- 'TLEN' 1 1 2 2</span>
-0005 3AA0 <span class="fade">45 00 00 00</span> [54 4C 45 4E] [01 00] [01 00] [02 00] [02 00] <span class="fade">E...</span>TLEN........
- <span class="fade">....</span>
-0005 3AC0 [08 00] [04 00] [08 00] [10 00] [10 00] [14 00] [4C 00] [34 00] ............L.4.<span class="descr">
- 8 4 8
- ListBase vec2s vec2f ... etc
- length len length </span><span class="fade">
- ....
- .... (457 lengths, same as number of types)</span>
-</code>
-</p>
-
-<a name="DNA1-data-array-structures" href="#DNA1-data-array-structures"><h4>The structures array</h4></a>
-<p>
-<code class="block"><span class="descr"> array-id='STRC'
- |</span>
-0005 3E30 <span class="fade">40 00 38 00 60 00 00 00 00 00 00 00</span> [53 54 52 43] <span class="fade">@.8.`.......</span>STRC
-0005 3E40 [8E 01 00 00] [0A 00] [02 00] [0A 00] [00 00] [0A 00] [01 00] ................<span class="descr">
- 398 10 2 10 0 10 0
- number of index fields index index index index
- structures in <a href="#DNA1-data-array-types">types</a> in <a href="#DNA1-data-array-types">types</a> in <a href="#DNA1-data-array-names">names</a> in <a href="#DNA1-data-array-types">types</a> in <a href="#DNA1-data-array-names">names</a></span><span class="fade">
- ' '----------------' '-----------------' '
- ' field 0 field 1 '
- '--------------------------------------------------------'
- structure 0
- ....
- .... (398 structures, each one describeing own type, and type/name for each field)</span>
-</code>
-</p>
-</div>
-
-<p>
-The DNA structures inside a Blender 2.48 blend-file can be found at <a href="http://www.atmind.nl/blender/blender-sdna.html">http://www.atmind.nl/blender/blender-sdna.html</a>.
-
-If we understand the DNA part of the file it is now possible to read
-information from other parts file-blocks. The next section will tell us
-how.
-</p>
-
-<a name="reading-scene-information" href="#reading-scene-information"><h2>Reading scene information</h2></a>
-
-<p>
-Let us look at <a href="#example-file-block-header">the file-block header we have seen earlier</a>:<br>
-</p>
-<ul>
-<li>the file-block identifier is <code>'SC'+0x00h</code></li>
-<li>the SDNA index is 150</li>
-<li>the file-block size is 1404 bytes</li>
-</ul>
-<p>
-Now note that:
-<ul>
-<li>the structure at index 150 in the DNA is a structure of type 'Scene' (counting from 0).</li>
-<li>the associated type ('Scene') in the DNA has the length of 1404 bytes.</li>
-</ul>
-</p>
-
-<p>
-We can map the Scene structure on the data of the file-blocks.
-But before we can do that, we have to flatten the Scene-structure.
-
-<code class="block">struct Scene {
- ID id; <span class="descr">// 52 bytes long (ID is different a structure)</span>
- AnimData *adt; <span class="descr">// 4 bytes long (pointer to an AnimData structure)</span>
- Object *camera; <span class="descr">// 4 bytes long (pointer to an Object structure)</span>
- World *world; <span class="descr">// 4 bytes long (pointer to an Object structure)</span>
- ...
- float cursor[3]; <span class="descr">// 12 bytes long (array of 3 floats)</span>
- ...
-};
-</code>
-
-The first field in the Scene-structure is of type 'ID' with the name 'id'.
-Inside the list of DNA structures there is a structure defined for type 'ID' (structure index 17).
-
-<code class="block">struct ID {
- void *next, *prev;
- struct ID *newid;
- struct Library *lib;
- char name[24];
- short us;
- short flag;
- int icon_id;
- IDProperty *properties;
-};
-</code>
-
-The first field in this structure has type 'void' and name '*next'. <br>
-Looking in the structure list there is no structure defined for type 'void': it is a simple type and therefore the data should be read.
-The name '*next' describes a pointer.
-As we see, the first 4 bytes of the data can be mapped to 'id.next'.
-</p>
-
-<p>
-Using this method we'll map a structure to its data. If we want to
-read a specific field we know at which offset in the data it is located
-and how much space it takes.<br>
-The next table shows the output of this flattening process for some
-parts of the Scene-structure. Not all rows are described in the table as
- there is a lot of information in a Scene-structure.
-</p>
-
-<table>
-<caption>Flattened SDNA structure 150: Scene</caption>
-<thead>
-<tr><th>reference</th>
- <th>structure</th>
- <th>type</th><th>name</th>
- <th>offset</th><th>size</th>
- <th>description</th></tr>
-</thead>
-<tbody>
-<tr><td>id.next</td><td><a href="#struct:ID">ID</a></td>
- <td>void</td><td>*next</td>
- <td>0</td>
- <td>4</td>
- <td>Refers to the next scene</td></tr>
-<tr><td>id.prev</td><td><a href="#struct:ID">ID</a></td>
- <td>void</td><td>*prev</td>
- <td>4</td>
- <td>4</td>
- <td>Refers to the previous scene</td></tr>
-<tr><td>id.newid</td><td><a href="#struct:ID">ID</a></td>
- <td>ID</td><td>*newid</td>
- <td>8</td>
- <td>4</td>
- <td></td></tr>
-<tr><td>id.lib</td><td><a href="#struct:ID">ID</a></td>
- <td>Library</td><td>*lib</td>
- <td>12</td>
- <td>4</td>
- <td></td></tr>
-<tr><td>id.name</td><td><a href="#struct:ID">ID</a></td>
- <td>char</td><td>name[24]</td>
- <td>16</td>
- <td>24</td>
- <td>'SC'+the name of the scene as displayed in Blender</td></tr>
-<tr><td>id.us</td><td><a href="#struct:ID">ID</a></td>
- <td>short</td><td>us</td>
- <td>40</td>
- <td>2</td>
- <td></td></tr>
-<tr><td>id.flag</td><td><a href="#struct:ID">ID</a></td>
- <td>short</td><td>flag</td><td>42</td><td>2</td>
- <td></td></tr>
-<tr><td>id.icon_id</td><td><a href="#struct:ID">ID</a></td>
- <td>int</td><td>icon_id</td><td>44</td>
- <td>4</td>
- <td></td></tr>
-<tr><td>id.properties</td><td><a href="#struct:ID">ID</a></td>
- <td>IDProperty</td><td>*properties</td>
- <td>48</td>
- <td>4</td>
- <td></td></tr>
-<tr><td>adt</td><td>Scene</td><td>AnimData</td>
- <td>*adt</td>
- <td>52</td>
- <td>4</td>
- <td></td></tr>
-<tr><td>camera</td><td>Scene</td>
- <td>Object</td>
- <td>*camera</td>
- <td>56</td>
- <td>4</td>
- <td>Pointer to the current camera</td></tr>
-<tr><td>world</td><td>Scene</td>
- <td>World</td>
- <td>*world</td>
- <td>60</td>
- <td>4</td>
- <td>Pointer to the current world</td></tr>
-
-<tr><td class="skip" colspan="7">Skipped rows</td></tr>
-
-<tr><td>r.xsch</td><td><a href="#struct:RenderData">RenderData</a>
- </td><td>short</td><td>xsch</td><td>382</td><td>2</td>
- <td>X-resolution of the output when rendered at 100%</td></tr>
-<tr><td>r.ysch</td><td><a href="#struct:RenderData">RenderData</a>
- </td><td>short</td><td>ysch</td><td>384</td><td>2</td>
- <td>Y-resolution of the output when rendered at 100%</td></tr>
-<tr><td>r.xparts</td><td><a href="#struct:RenderData">RenderData</a>
- </td><td>short</td><td>xparts</td><td>386</td><td>2</td>
- <td>Number of x-part used by the renderer</td></tr>
-<tr><td>r.yparts</td><td><a href="#struct:RenderData">RenderData</a>
- </td><td>short</td><td>yparts</td><td>388</td><td>2</td>
- <td>Number of x-part used by the renderer</td></tr>
-
-<tr><td class="skip" colspan="7">Skipped rows</td></tr>
-
-<tr><td>gpd</td><td>Scene</td><td>bGPdata</td><td>*gpd</td><td>1376</td><td>4</td>
- <td></td></tr>
-<tr><td>physics_settings.gravity</td><td><a href="#struct:PhysicsSettings">PhysicsSettings</a>
- </td><td>float</td><td>gravity[3]</td><td>1380</td><td>12</td>
- <td></td></tr>
-<tr><td>physics_settings.flag</td><td><a href="#struct:PhysicsSettings">PhysicsSettings</a>
- </td><td>int</td><td>flag</td><td>1392</td><td>4</td>
- <td></td></tr>
-<tr><td>physics_settings.quick_cache_step</td><td><a href="#struct:PhysicsSettings">PhysicsSettings</a>
- </td><td>int</td><td>quick_cache_step</td><td>1396</td><td>4</td>
- <td></td></tr>
-<tr><td>physics_settings.rt</td><td><a href="#struct:PhysicsSettings">PhysicsSettings</a>
- </td><td>int</td><td>rt</td><td>1400</td><td>4</td>
- <td></td></tr>
-</tbody>
-</table>
-
-<p>
-We can now read the X and Y resolution of the Scene:
-<ul>
-<li>the X-resolution is located on offset 382 of the file-block-data and must be read as a
-short.</li>
-<li>the Y-resolution is located on offset 384 and is also a short</li>
-</ul>
-</p>
-
-<div class="box">
-<p class="box-title">
-Note
-</p>
-<p>
-An array of chars can mean 2 things. The field contains readable
-text or it contains an array of flags (not humanly readable).
-</p>
-</div>
-
-<div class="box">
-<p class="box-title">
-Note
-</p>
-<p>
-A file-block containing a list refers to the DNA structure and has a count larger
-than 1. For example Vertexes and Faces are stored in this way.
-</p>
-</div>
-
-</body>
-</html>
-
diff --git a/intern/ghost/SConscript b/intern/ghost/SConscript
index b67545f216a..6843c5fbcb2 100644
--- a/intern/ghost/SConscript
+++ b/intern/ghost/SConscript
@@ -60,6 +60,9 @@ else:
if env['BF_GHOST_DEBUG']:
defs.append('BF_GHOST_DEBUG')
+if env['WITH_BF_ONSURFACEBRUSH']:
+ defs.append('WITH_ONSURFACEBRUSH')
+
incs = '. ../string #extern/glew/include #source/blender/imbuf #source/blender/makesdna ' + env['BF_OPENGL_INC']
if window_system in ('win32-vc', 'win32-mingw', 'cygwin', 'linuxcross', 'win64-vc'):
incs = env['BF_WINTAB_INC'] + ' ' + incs
diff --git a/intern/ghost/intern/GHOST_WindowCarbon.cpp b/intern/ghost/intern/GHOST_WindowCarbon.cpp
index 1ffd117d658..9588ebce1b8 100644
--- a/intern/ghost/intern/GHOST_WindowCarbon.cpp
+++ b/intern/ghost/intern/GHOST_WindowCarbon.cpp
@@ -52,6 +52,9 @@ AGL_RGBA,
AGL_DOUBLEBUFFER,
AGL_ACCELERATED,
AGL_DEPTH_SIZE, 32,
+#ifdef WITH_ONSURFACEBRUSH
+AGL_STENCIL_SIZE, 8,
+#endif
AGL_NONE,
};
@@ -61,6 +64,9 @@ AGL_DOUBLEBUFFER,
AGL_ACCELERATED,
AGL_FULLSCREEN,
AGL_DEPTH_SIZE, 32,
+#ifdef WITH_ONSURFACEBRUSH
+AGL_STENCIL_SIZE, 8,
+#endif
AGL_NONE,
};
diff --git a/intern/ghost/intern/GHOST_WindowCocoa.mm b/intern/ghost/intern/GHOST_WindowCocoa.mm
index fb7d4a459c7..587046fb3a2 100644
--- a/intern/ghost/intern/GHOST_WindowCocoa.mm
+++ b/intern/ghost/intern/GHOST_WindowCocoa.mm
@@ -365,6 +365,13 @@ GHOST_WindowCocoa::GHOST_WindowCocoa(
pixelFormatAttrsWindow[i++] = NSOpenGLPFAAccelerated;
//pixelFormatAttrsWindow[i++] = NSOpenGLPFAAllowOfflineRenderers,; // Removed to allow 10.4 builds, and 2 GPUs rendering is not used anyway
+
+
+#ifdef WITH_ONSURFACEBRUSH
+ pixelFormatAttrsWindow[i++] = NSOpenGLPFAStencilSize;
+ pixelFormatAttrsWindow[i++] = (NSOpenGLPixelFormatAttribute) 8;
+#endif
+
pixelFormatAttrsWindow[i++] = NSOpenGLPFADepthSize;
pixelFormatAttrsWindow[i++] = (NSOpenGLPixelFormatAttribute) 32;
@@ -376,6 +383,11 @@ GHOST_WindowCocoa::GHOST_WindowCocoa(
// Multisample anti-aliasing
pixelFormatAttrsWindow[i++] = NSOpenGLPFAMultisample;
+#ifdef WITH_ONSURFACEBRUSH
+ pixelFormatAttrsWindow[i++] = NSOpenGLPFAStencilSize;
+ pixelFormatAttrsWindow[i++] = (NSOpenGLPixelFormatAttribute) 8;
+#endif
+
pixelFormatAttrsWindow[i++] = NSOpenGLPFASampleBuffers;
pixelFormatAttrsWindow[i++] = (NSOpenGLPixelFormatAttribute) 1;
diff --git a/intern/ghost/intern/GHOST_WindowWin32.cpp b/intern/ghost/intern/GHOST_WindowWin32.cpp
index aae1509fda1..b69f8fb6a45 100644
--- a/intern/ghost/intern/GHOST_WindowWin32.cpp
+++ b/intern/ghost/intern/GHOST_WindowWin32.cpp
@@ -98,7 +98,11 @@ static PIXELFORMATDESCRIPTOR sPreferredFormat = {
0, /* no accumulation buffer */
0, 0, 0, 0, /* accum bits (ignored) */
32, /* depth buffer */
+#ifdef WITH_ONSURFACEBRUSH
+ 8, /* stencil buffer */
+#else
0, /* no stencil buffer */
+#endif
0, /* no auxiliary buffers */
PFD_MAIN_PLANE, /* main layer */
0, /* reserved */
@@ -1281,6 +1285,11 @@ static int WeightPixelFormat(PIXELFORMATDESCRIPTOR& pfd) {
!(pfd.dwFlags & PFD_DOUBLEBUFFER) || /* Blender _needs_ this */
( pfd.cDepthBits <= 8 ) ||
!(pfd.iPixelType == PFD_TYPE_RGBA))
+ !(pfd.iPixelType == PFD_TYPE_RGBA)
+#ifdef WITH_ONSURFACEBRUSH
+ || ( pfd.cStencilBits == 0)
+#endif
+ )
return 0;
weight = 1; /* it's usable */
diff --git a/intern/ghost/intern/GHOST_WindowX11.cpp b/intern/ghost/intern/GHOST_WindowX11.cpp
index aea5b5156d9..5dd1042eb6e 100644
--- a/intern/ghost/intern/GHOST_WindowX11.cpp
+++ b/intern/ghost/intern/GHOST_WindowX11.cpp
@@ -182,7 +182,7 @@ GHOST_WindowX11(
Atom atoms[2];
int natom;
int glxVersionMajor, glxVersionMinor; // As in GLX major.minor
-
+
/* initialize incase X11 fails to load */
memset(&m_xtablet, 0, sizeof(m_xtablet));
m_visual= NULL;
@@ -212,6 +212,9 @@ GHOST_WindowX11(
attributes[i++] = GLX_BLUE_SIZE; attributes[i++] = 1;
attributes[i++] = GLX_GREEN_SIZE; attributes[i++] = 1;
attributes[i++] = GLX_DEPTH_SIZE; attributes[i++] = 1;
+#ifdef WITH_ONSURFACEBRUSH
+ attributes[i++] = GLX_STENCIL_SIZE; attributes[i++] = 8;
+#endif
/* GLX >= 1.4 required for multi-sample */
if(samples && (glxVersionMajor >= 1) && (glxVersionMinor >= 4)) {
attributes[i++] = GLX_SAMPLE_BUFFERS; attributes[i++] = 1;
@@ -1289,11 +1292,11 @@ GHOST_WindowX11::
if(m_xtablet.EraserDevice)
XCloseDevice(m_display, m_xtablet.EraserDevice);
#endif /* WITH_X11_XINPUT */
-
+
if (m_context != s_firstContext) {
glXDestroyContext(m_display, m_context);
}
-
+
if (p_owner == m_window) {
XSetSelectionOwner(m_display, Primary_atom, None, CurrentTime);
}
diff --git a/source/SConscript b/source/SConscript
index 0002cb4cf0b..3944a3c6df5 100644
--- a/source/SConscript
+++ b/source/SConscript
@@ -1,13 +1,14 @@
#!/usr/bin/python
Import ('env')
-SConscript(['blender/SConscript', 'creator/SConscript'])
-
+SConscript(['blender/SConscript',
+ 'kernel/SConscript',
+ 'creator/SConscript'])
if env['WITH_BF_GAMEENGINE']:
- SConscript (['gameengine/SConscript'])
+ SConscript (['gameengine/SConscript'])
if env['WITH_BF_PLAYER']:
- SConscript (['blenderplayer/bad_level_call_stubs/SConscript'])
+ SConscript (['blenderplayer/bad_level_call_stubs/SConscript'])
if env['OURPLATFORM'] in ('win64-vc', 'win32-vc', 'win32-mingw', 'linuxcross'):
- SConscript (['icons/SConscript'])
+ SConscript (['icons/SConscript'])
diff --git a/source/blender/blenkernel/BKE_brush.h b/source/blender/blenkernel/BKE_brush.h
index ad736cd07bf..15e9c812505 100644
--- a/source/blender/blenkernel/BKE_brush.h
+++ b/source/blender/blenkernel/BKE_brush.h
@@ -40,7 +40,7 @@ struct Brush;
struct ImBuf;
struct Scene;
struct wmOperator;
-// enum CurveMappingPreset;
+//enum CurveMappingPreset;
/* datablock functions */
struct Brush *add_brush(const char *name);
@@ -94,22 +94,22 @@ struct ImBuf *brush_gen_radial_control_imbuf(struct Brush *br);
/* unified strength and size */
-int brush_size(struct Brush *brush);
+int brush_size(const struct Brush *brush);
void brush_set_size(struct Brush *brush, int value);
-int brush_use_locked_size(struct Brush *brush);
+int brush_use_locked_size(const struct Brush *brush);
void brush_set_use_locked_size(struct Brush *brush, int value);
-int brush_use_alpha_pressure(struct Brush *brush);
+int brush_use_alpha_pressure(const struct Brush *brush);
void brush_set_use_alpha_pressure(struct Brush *brush, int value);
-int brush_use_size_pressure(struct Brush *brush);
+int brush_use_size_pressure(const struct Brush *brush);
void brush_set_use_size_pressure(struct Brush *brush, int value);
-float brush_unprojected_radius(struct Brush *brush);
+float brush_unprojected_radius(const struct Brush *brush);
void brush_set_unprojected_radius(struct Brush *brush, float value);
-float brush_alpha(struct Brush *brush);
+float brush_alpha(const struct Brush *brush);
void brush_set_alpha(struct Brush *brush, float value);
/* debugging only */
diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h
index ef16129e1e7..ca6bb7002eb 100644
--- a/source/blender/blenkernel/BKE_paint.h
+++ b/source/blender/blenkernel/BKE_paint.h
@@ -52,7 +52,7 @@ void free_paint(struct Paint *p);
void copy_paint(struct Paint *src, struct Paint *tar);
struct Paint *paint_get_active(struct Scene *sce);
-struct Brush *paint_brush(struct Paint *paint);
+struct Brush *paint_brush(const struct Paint *paint);
void paint_brush_set(struct Paint *paint, struct Brush *br);
/* testing face select mode
diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c
index 98c540f53b7..a4dd2270027 100644
--- a/source/blender/blenkernel/intern/brush.c
+++ b/source/blender/blenkernel/intern/brush.c
@@ -81,6 +81,7 @@ static void brush_set_defaults(Brush *brush)
brush->autosmooth_factor= 0.0f;
brush->crease_pinch_factor= 0.5f;
brush->sculpt_plane = SCULPT_DISP_DIR_AREA;
+ brush->sculpt_plane_range= 1;
brush->plane_offset= 0.0f; /* how far above or below the plane that is found by averaging the faces */
brush->plane_trim= 0.5f;
brush->clone.alpha= 0.5f;
@@ -93,7 +94,7 @@ static void brush_set_defaults(Brush *brush)
brush->rgb[2]= 1.0f;
/* BRUSH STROKE SETTINGS */
- brush->flag |= (BRUSH_SPACE|BRUSH_SPACE_ATTEN);
+ brush->flag |= (BRUSH_SPACE|BRUSH_SPACE_ATTEN|BRUSH_ADAPTIVE_SPACE);
brush->spacing= 10; /* how far each brush dot should be spaced as a percentage of brush diameter */
brush->smooth_stroke_radius= 75;
@@ -103,6 +104,10 @@ static void brush_set_defaults(Brush *brush)
brush->jitter= 0.0f;
+ brush->adaptive_space_factor= 1;
+
+ brush->frontface_angle= (float)(M_PI_2 * 80.0/90.0);
+
/* BRUSH TEXTURE SETTINGS */
default_mtex(&brush->mtex);
@@ -192,7 +197,7 @@ void make_local_brush(Brush *brush)
* - only local users: set flag
* - mixed: make copy
*/
-
+
Main *bmain= G.main;
Scene *scene;
int local= 0, lib= 0;
@@ -1139,7 +1144,7 @@ unsigned int *brush_gen_texture_cache(Brush *br, int half_side)
TexResult texres= {0};
int hasrgb, ix, iy;
int side = half_side * 2;
-
+
if(mtex->tex) {
float x, y, step = 2.0 / side, co[3];
@@ -1206,6 +1211,16 @@ struct ImBuf *brush_gen_radial_control_imbuf(Brush *br)
}
}
+ /* XXX: combine with loop above */
+ /* XXX: sqrt and pow seem like they could be eliminated */
+ /* invert the texture */
+ for(i=0; i<side; ++i) {
+ for(j=0; j<side; ++j) {
+ if (sqrt(pow(i - half, 2) + pow(j - half, 2)) < half)
+ im->rect_float[i*side+j]= 1.0f - im->rect_float[i*side+j];
+ }
+ }
+
MEM_freeN(texcache);
}
@@ -1214,7 +1229,15 @@ struct ImBuf *brush_gen_radial_control_imbuf(Brush *br)
/* Unified Size and Strength */
-static void set_unified_settings(Brush *brush, short flag, int value)
+// XXX: unified settings are stored in scene toolsettings
+// to simplify things (from an API standpoint, not implementation),
+// all of the flags in each scene are set to the same value.
+// the 'get' functions return first value, since all should be the same
+// This arrangement seems odd, is there a better whay?
+// At this point, I think UserPrefs had been ruled out, but I do not know why.
+// ~~~~jwilkins
+
+static void set_unified_settings(const Brush *brush, short flag, int value)
{
Scene *sce;
for (sce= G.main->scene.first; sce; sce= sce->id.next) {
@@ -1233,7 +1256,7 @@ static void set_unified_settings(Brush *brush, short flag, int value)
}
}
-static short unified_settings(Brush *brush)
+static short unified_settings(const Brush *brush)
{
Scene *sce;
for (sce= G.main->scene.first; sce; sce= sce->id.next) {
@@ -1251,7 +1274,7 @@ static short unified_settings(Brush *brush)
return 0;
}
-static void set_unified_size(Brush *brush, int value)
+static void set_unified_size(const Brush *brush, int value)
{
Scene *sce;
for (sce= G.main->scene.first; sce; sce= sce->id.next) {
@@ -1267,7 +1290,7 @@ static void set_unified_size(Brush *brush, int value)
}
}
-static int unified_size(Brush *brush)
+static int unified_size(const Brush *brush)
{
Scene *sce;
for (sce= G.main->scene.first; sce; sce= sce->id.next) {
@@ -1285,7 +1308,7 @@ static int unified_size(Brush *brush)
return 35; // XXX magic number
}
-static void set_unified_alpha(Brush *brush, float value)
+static void set_unified_alpha(const Brush *brush, float value)
{
Scene *sce;
for (sce= G.main->scene.first; sce; sce= sce->id.next) {
@@ -1301,7 +1324,7 @@ static void set_unified_alpha(Brush *brush, float value)
}
}
-static float unified_alpha(Brush *brush)
+static float unified_alpha(const Brush *brush)
{
Scene *sce;
for (sce= G.main->scene.first; sce; sce= sce->id.next) {
@@ -1319,7 +1342,7 @@ static float unified_alpha(Brush *brush)
return 0.5f; // XXX magic number
}
-static void set_unified_unprojected_radius(Brush *brush, float value)
+static void set_unified_unprojected_radius(const Brush *brush, float value)
{
Scene *sce;
for (sce= G.main->scene.first; sce; sce= sce->id.next) {
@@ -1335,7 +1358,7 @@ static void set_unified_unprojected_radius(Brush *brush, float value)
}
}
-static float unified_unprojected_radius(Brush *brush)
+static float unified_unprojected_radius(const Brush *brush)
{
Scene *sce;
for (sce= G.main->scene.first; sce; sce= sce->id.next) {
@@ -1358,11 +1381,9 @@ void brush_set_size(Brush *brush, int size)
set_unified_size(brush, size);
else
brush->size= size;
-
- //WM_main_add_notifier(NC_BRUSH|NA_EDITED, brush);
}
-int brush_size(Brush *brush)
+int brush_size(const Brush *brush)
{
return (unified_settings(brush) & SCULPT_PAINT_USE_UNIFIED_SIZE) ? unified_size(brush) : brush->size;
}
@@ -1378,11 +1399,9 @@ void brush_set_use_locked_size(Brush *brush, int value)
else
brush->flag &= ~BRUSH_LOCK_SIZE;
}
-
- //WM_main_add_notifier(NC_BRUSH|NA_EDITED, brush);
}
-int brush_use_locked_size(Brush *brush)
+int brush_use_locked_size(const Brush *brush)
{
return (unified_settings(brush) & SCULPT_PAINT_USE_UNIFIED_SIZE) ? (unified_settings(brush) & SCULPT_PAINT_UNIFIED_LOCK_BRUSH_SIZE) : (brush->flag & BRUSH_LOCK_SIZE);
}
@@ -1398,11 +1417,9 @@ void brush_set_use_size_pressure(Brush *brush, int value)
else
brush->flag &= ~BRUSH_SIZE_PRESSURE;
}
-
- //WM_main_add_notifier(NC_BRUSH|NA_EDITED, brush);
}
-int brush_use_size_pressure(Brush *brush)
+int brush_use_size_pressure(const Brush *brush)
{
return (unified_settings(brush) & SCULPT_PAINT_USE_UNIFIED_SIZE) ? (unified_settings(brush) & SCULPT_PAINT_UNIFIED_SIZE_PRESSURE) : (brush->flag & BRUSH_SIZE_PRESSURE);
}
@@ -1418,11 +1435,9 @@ void brush_set_use_alpha_pressure(Brush *brush, int value)
else
brush->flag &= ~BRUSH_ALPHA_PRESSURE;
}
-
- //WM_main_add_notifier(NC_BRUSH|NA_EDITED, brush);
}
-int brush_use_alpha_pressure(Brush *brush)
+int brush_use_alpha_pressure(const Brush *brush)
{
return (unified_settings(brush) & SCULPT_PAINT_USE_UNIFIED_ALPHA) ? (unified_settings(brush) & SCULPT_PAINT_UNIFIED_ALPHA_PRESSURE) : (brush->flag & BRUSH_ALPHA_PRESSURE);
}
@@ -1433,11 +1448,9 @@ void brush_set_unprojected_radius(Brush *brush, float unprojected_radius)
set_unified_unprojected_radius(brush, unprojected_radius);
else
brush->unprojected_radius= unprojected_radius;
-
- //WM_main_add_notifier(NC_BRUSH|NA_EDITED, brush);
}
-float brush_unprojected_radius(Brush *brush)
+float brush_unprojected_radius(const Brush *brush)
{
return (unified_settings(brush) & SCULPT_PAINT_USE_UNIFIED_SIZE) ? unified_unprojected_radius(brush) : brush->unprojected_radius;
}
@@ -1448,11 +1461,9 @@ void brush_set_alpha(Brush *brush, float alpha)
set_unified_alpha(brush, alpha);
else
brush->alpha= alpha;
-
- //WM_main_add_notifier(NC_BRUSH|NA_EDITED, brush);
}
-float brush_alpha(Brush *brush)
+float brush_alpha(const Brush *brush)
{
return (unified_settings(brush) & SCULPT_PAINT_USE_UNIFIED_ALPHA) ? unified_alpha(brush) : brush->alpha;
}
diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c
index 334f018efc9..954834b51d7 100644
--- a/source/blender/blenkernel/intern/material.c
+++ b/source/blender/blenkernel/intern/material.c
@@ -68,10 +68,31 @@
/* used in UI and render */
Material defmaterial;
+// initialize a slot for the current MatCap
+static void init_matcap(void)
+{
+ default_tex(&matcap_tex);
+ matcap_tex.type = TEX_IMAGE;
+
+ default_mtex(&matcap_mtex);
+ matcap_mtex.texco = TEXCO_NORM;
+ matcap_mtex.tex = &matcap_tex;
+
+ //XXX: this is a hack to eliminate artifacts around the edges
+ //matcap_mtex.size[0] = 0.95f;
+ //matcap_mtex.size[1] = 0.95f;
+
+ init_material(&matcap_ma);
+ matcap_ma.mode |= MA_SHLESS;
+ matcap_ma.shade_flag |= MA_OBCOLOR;
+ matcap_ma.mtex[0] = &matcap_mtex;
+}
+
/* called on startup, creator.c */
void init_def_material(void)
{
init_material(&defmaterial);
+ init_matcap();
}
/* not material itself */
diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c
index e2a07427ce2..467dad756bc 100644
--- a/source/blender/blenkernel/intern/object.c
+++ b/source/blender/blenkernel/intern/object.c
@@ -1047,7 +1047,9 @@ Object *add_only_object(int type, const char *name)
unit_m4(ob->constinv);
unit_m4(ob->parentinv);
unit_m4(ob->obmat);
- ob->dt= OB_TEXTURE;
+
+ ob->dt= OB_MATCAP;
+
ob->empty_drawtype= OB_PLAINAXES;
ob->empty_drawsize= 1.0;
diff --git a/source/blender/blenlib/BLI_cpu.h b/source/blender/blenlib/BLI_cpu.h
index addcf1273b3..cb25fa0ed2b 100644
--- a/source/blender/blenlib/BLI_cpu.h
+++ b/source/blender/blenlib/BLI_cpu.h
@@ -1,5 +1,5 @@
/*
- * $Id$
+ * $Id: BLI_cpu.h 34966 2011-02-18 13:58:08Z jesterking $
*
* ***** BEGIN GPL LICENSE BLOCK *****
*
diff --git a/source/blender/blenlib/BLI_pbvh.h b/source/blender/blenlib/BLI_pbvh.h
index 89dcf9bf02d..a4d131104fa 100644
--- a/source/blender/blenlib/BLI_pbvh.h
+++ b/source/blender/blenlib/BLI_pbvh.h
@@ -245,6 +245,10 @@ void BLI_pbvh_node_free_proxies(PBVHNode* node);
PBVHProxyNode* BLI_pbvh_node_add_proxy(PBVH* bvh, PBVHNode* node);
void BLI_pbvh_gather_proxies(PBVH* pbvh, PBVHNode*** nodes, int* totnode);
+void BLI_pbvh_draw_nodes_in_sphere(PBVH *bvh, float location[3], float radius);
+void BLI_pbvh_gather_nodes_in_sphere(PBVH *bvh, float location[3], float radius, PBVHNode ***nodes, int *totnode);
+void BLI_pbvh_node_array_draw(PBVH *bvh, PBVHNode **nodes, int totnode);
+
//void BLI_pbvh_node_BB_reset(PBVHNode* node);
//void BLI_pbvh_node_BB_expand(PBVHNode* node, float co[3]);
diff --git a/source/blender/blenlib/intern/cpu.c b/source/blender/blenlib/intern/cpu.c
index 860a0cae2d1..ad3cac5db84 100644
--- a/source/blender/blenlib/intern/cpu.c
+++ b/source/blender/blenlib/intern/cpu.c
@@ -1,6 +1,6 @@
/*
*
- * $Id$
+ * $Id: cpu.c 35246 2011-02-27 20:37:56Z jesterking $
*
* ***** BEGIN GPL LICENSE BLOCK *****
*
diff --git a/source/blender/blenlib/intern/pbvh.c b/source/blender/blenlib/intern/pbvh.c
index f7b79b35cbc..3ce389f162b 100644
--- a/source/blender/blenlib/intern/pbvh.c
+++ b/source/blender/blenlib/intern/pbvh.c
@@ -398,6 +398,7 @@ static void build_grids_leaf_node(PBVH *bvh, PBVHNode *node)
GPU_build_grid_buffers(bvh->grids, node->prim_indices,
node->totprim, bvh->gridsize);
}
+
node->flag |= PBVH_UpdateDrawBuffers;
}
@@ -717,7 +718,7 @@ static PBVHNode *pbvh_iter_next_occluded(PBVHIter *iter)
node= iter->stack[iter->stacksize].node;
/* on a mesh with no faces this can happen
- * can remove this check if we know meshes have at least 1 face */
+ * can remove this check if we know meshes have at least 1 face */
if(node==NULL) return NULL;
if(iter->scb && !iter->scb(node, iter->search_data)) continue; /* don't traverse, outside of search zone */
@@ -792,6 +793,8 @@ void BLI_pbvh_search_callback(PBVH *bvh,
pbvh_iter_end(&iter);
}
+// XXX: todo: benchmark the cost of using malloc/free for this binary tree
+
typedef struct node_tree {
PBVHNode* data;
@@ -1321,7 +1324,7 @@ static int ray_face_intersection(float ray_start[3], float ray_normal[3],
float dist;
if ((isect_ray_tri_epsilon_v3(ray_start, ray_normal, t0, t1, t2, &dist, NULL, 0.1f) && dist < *fdist) ||
- (t3 && isect_ray_tri_epsilon_v3(ray_start, ray_normal, t0, t2, t3, &dist, NULL, 0.1f) && dist < *fdist))
+ (t3 && isect_ray_tri_epsilon_v3(ray_start, ray_normal, t0, t2, t3, &dist, NULL, 0.1f) && dist < *fdist))
{
*fdist = dist;
return 1;
@@ -1633,3 +1636,66 @@ void BLI_pbvh_gather_proxies(PBVH* pbvh, PBVHNode*** r_array, int* r_tot)
*r_array= array;
*r_tot= tot;
}
+
+typedef struct {
+ float location[3];
+ float radius_squared;
+} SearchSphereData;
+
+/* Test AABB against sphere */
+static int search_sphere_cb(PBVHNode *node, void *data_v)
+{
+ SearchSphereData *data = data_v;
+ float *center = data->location, nearest[3];
+ float t[3], bb_min[3], bb_max[3];
+ int i;
+
+ BLI_pbvh_node_get_BB(node, bb_min, bb_max);
+
+ for(i = 0; i < 3; ++i) {
+ if(bb_min[i] > center[i])
+ nearest[i] = bb_min[i];
+ else if(bb_max[i] < center[i])
+ nearest[i] = bb_max[i];
+ else
+ nearest[i] = center[i];
+ }
+
+ sub_v3_v3v3(t, center, nearest);
+
+ return dot_v3v3(t, t) < data->radius_squared;
+}
+
+void BLI_pbvh_gather_nodes_in_sphere(PBVH *bvh, float location[3], float radius, PBVHNode ***nodes, int *totnode)
+{
+ SearchSphereData data;
+
+ copy_v3_v3(data.location, location);
+ data.radius_squared= radius*radius;
+
+ BLI_pbvh_search_gather(bvh, search_sphere_cb, &data, nodes, totnode);
+}
+
+void BLI_pbvh_node_array_draw(PBVH *bvh, PBVHNode **nodes, int totnode)
+{
+ int i;
+
+ pbvh_update_normals(bvh, nodes, totnode, NULL);
+ pbvh_update_draw_buffers(bvh, nodes, totnode, 1);
+
+ for (i= 0; i < totnode; i++)
+ BLI_pbvh_node_draw(nodes[i], 0);
+}
+
+void BLI_pbvh_draw_nodes_in_sphere(PBVH *bvh, float location[3], float radius)
+{
+ PBVHNode **nodes;
+ int totnode;
+
+ BLI_pbvh_gather_nodes_in_sphere(bvh, location, radius, &nodes, &totnode);
+
+ if (nodes) {
+ BLI_pbvh_node_array_draw(bvh, nodes, totnode);
+ MEM_freeN(nodes);
+ }
+}
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index 5f984a9268d..0d349739226 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -3697,7 +3697,7 @@ static void lib_link_object(FileData *fd, Main *main)
ob->gpd= newlibadr_us(fd, ob->id.lib, ob->gpd);
ob->duplilist= NULL;
-
+
ob->id.flag -= LIB_NEEDLINK;
/* if id.us==0 a new base will be created later on */
@@ -4128,7 +4128,7 @@ static void direct_link_modifiers(FileData *fd, ListBase *lb)
if(tmd->curfalloff)
direct_link_curvemapping(fd, tmd->curfalloff);
}
- }
+}
}
static void direct_link_object(FileData *fd, Object *ob)
@@ -4816,6 +4816,8 @@ static void lib_link_screen(FileData *fd, Main *main)
if(v3d->localvd) {
v3d->localvd->camera= newlibadr(fd, sc->id.lib, v3d->localvd->camera);
}
+
+ v3d->matcap_ima= newlibadr_us(fd, sc->id.lib, v3d->matcap_ima);
}
else if(sl->spacetype==SPACE_IPO) {
SpaceIpo *sipo= (SpaceIpo *)sl;
@@ -5048,6 +5050,7 @@ void lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *curscene)
/* not very nice, but could help */
if((v3d->layact & v3d->lay)==0) v3d->layact= v3d->lay;
+ v3d->matcap_ima = restore_pointer_by_name(newmain, (ID *)v3d->matcap_ima, 1);
}
else if(sl->spacetype==SPACE_IPO) {
SpaceIpo *sipo= (SpaceIpo *)sl;
@@ -6530,10 +6533,10 @@ static void area_add_window_regions(ScrArea *sa, SpaceLink *sl, ListBase *lb)
ar->v2d.min[0]= 0.0f;
ar->v2d.min[1]= 0.0f;
-
+
ar->v2d.max[0]= MAXFRAMEF;
ar->v2d.max[1]= FLT_MAX;
-
+
ar->v2d.minzoom= 0.01f;
ar->v2d.maxzoom= 50;
ar->v2d.scroll = (V2D_SCROLL_BOTTOM|V2D_SCROLL_SCALE_HORIZONTAL);
@@ -11252,10 +11255,27 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
}
}
- /* GSOC 2010 Sculpt - New settings for Brush */
+ /* Sanity check on Sculpt/Paint settings */
+ /* These sanity checks apply to all versions */
+ {
+ Scene *sce;
+ for (sce= main->scene.first; sce; sce= sce->id.next) {
+ if (sce->toolsettings->sculpt_paint_unified_alpha == 0)
+ sce->toolsettings->sculpt_paint_unified_alpha = 0.5f;
+ if (sce->toolsettings->sculpt_paint_unified_unprojected_radius == 0)
+ sce->toolsettings->sculpt_paint_unified_unprojected_radius = 0.125f;
+
+ if (sce->toolsettings->sculpt_paint_unified_size == 0)
+ sce->toolsettings->sculpt_paint_unified_size = 35;
+ }
+ }
+
+ {
+ Brush *brush;
for (brush= main->brush.first; brush; brush= brush->id.next) {
- /* Sanity Check */
+ /* Sanity Check for Brushes 2.52 */
+ /* These sanity checks apply to all versions */
// infinite number of dabs
if (brush->spacing == 0)
@@ -11268,6 +11288,7 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
// bad radius
if (brush->unprojected_radius == 0)
brush->unprojected_radius = 0.125f;
+ brush->unprojected_radius = 0.125;
// unusable size
if (brush->size == 0)
@@ -11295,11 +11316,26 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
// same as dots
if (brush->rate == 0)
- brush->rate = 0.1f;
+ brush->rate= 0.1f;
+
+ /* Sanity Check for Brushes 2.53 */
+
+ // divide by zero
+ if (brush->adaptive_space_factor == 0)
+ brush->adaptive_space_factor= 1;
+
+ if (brush->sculpt_plane_range == 0)
+ brush->sculpt_plane_range= 1;
+
+ if (brush->frontface_angle== 0)
+ brush->frontface_angle= (float)(M_PI_2 * 80.0/90.0);
+
+ if (brush->layer_distance== 0)
+ brush->layer_distance= 0.25f;
- /* New Settings */
if (main->versionfile < 252 || (main->versionfile == 252 && main->subversionfile < 5)) {
brush->flag |= BRUSH_SPACE_ATTEN; // explicitly enable adaptive space
+ brush->flag |= BRUSH_SPACE_ATTEN; // explicitly enable adaptive strength
// spacing was originally in pixels, convert it to percentage for new version
// size should not be zero due to sanity check above
@@ -11323,21 +11359,25 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
brush->sub_col[2] = 1.00f;
}
}
+
+ if (main->versionfile < 253)
+ brush->flag |= BRUSH_ADAPTIVE_SPACE; // explicitly enable adaptive space
}
}
- /* GSOC Sculpt 2010 - Sanity check on Sculpt/Paint settings */
+ /* GSOC Sculpt 2011 - MatCap */
if (main->versionfile < 253) {
- Scene *sce;
- for (sce= main->scene.first; sce; sce= sce->id.next) {
- if (sce->toolsettings->sculpt_paint_unified_alpha == 0)
- sce->toolsettings->sculpt_paint_unified_alpha = 0.5f;
+ Object *ob;
- if (sce->toolsettings->sculpt_paint_unified_unprojected_radius == 0)
- sce->toolsettings->sculpt_paint_unified_unprojected_radius = 0.125f;
+ /* MatCaps */
+ for (ob=main->object.first; ob; ob=ob->id.next) {
+ Scene *sce;
- if (sce->toolsettings->sculpt_paint_unified_size == 0)
- sce->toolsettings->sculpt_paint_unified_size = 35;
+ for (sce= main->scene.first; sce; sce= sce->id.next) {
+ /* If max drawtype is textured then assume user won't mind if we bump it up to use MatCaps, */
+ /* Otherwise, assume that if max drawtype is less than textured then user doesn't want to use MatCaps */
+ if (ob->dt == OB_TEXTURE)
+ ob->dt = OB_MATCAP;
}
}
@@ -11556,11 +11596,7 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
sc->redraws_flag = TIME_ALL_3D_WIN|TIME_ALL_ANIM_WIN;
}
}
-
- for (brush= main->brush.first; brush; brush= brush->id.next) {
- if(brush->height == 0)
- brush->height= 0.4f;
- }
+ }
/* replace 'rim material' option for in offset*/
for(ob = main->object.first; ob; ob = ob->id.next) {
@@ -12389,13 +12425,13 @@ static void expand_object_expandModifiers(void *userData, Object *UNUSED(ob),
ID **idpoin)
{
struct { FileData *fd; Main *mainvar; } *data= userData;
-
+
FileData *fd= data->fd;
Main *mainvar= data->mainvar;
-
+
expand_doit(fd, mainvar, *idpoin);
-}
-
+ }
+
static void expand_object(FileData *fd, Main *mainvar, Object *ob)
{
ParticleSystem *psys;
diff --git a/source/blender/editors/include/ED_sculpt.h b/source/blender/editors/include/ED_sculpt.h
index 33d2dfcf4c5..3fd700aa48a 100644
--- a/source/blender/editors/include/ED_sculpt.h
+++ b/source/blender/editors/include/ED_sculpt.h
@@ -58,4 +58,8 @@ int ED_undo_paint_step(struct bContext *C, int type, int step, const char *name)
void ED_undo_paint_free(void);
int ED_undo_paint_valid(int type, const char *name);
+void ED_draw_paint_overlay(const struct bContext *C, struct ARegion *ar);
+void ED_draw_on_surface_cursor(float modelview[16], float projection[16], float col[3], float alpha, float size[3], int viewport[4], float location[3], float inner_radius, float outer_radius, int brush_size);
+void ED_draw_fixed_overlay_on_surface(float modelview[16], float projection[16], float size[3], int viewport[4], float location[3], float outer_radius, struct Sculpt *sd, struct Brush *brush, struct ViewContext *vc, float t, float b, float l, float r, float angle);
+
#endif
diff --git a/source/blender/editors/sculpt_paint/SConscript b/source/blender/editors/sculpt_paint/SConscript
index 90b56ded2cd..f35250d4863 100644
--- a/source/blender/editors/sculpt_paint/SConscript
+++ b/source/blender/editors/sculpt_paint/SConscript
@@ -21,4 +21,7 @@ if env['OURPLATFORM'] == 'linuxcross':
if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc'):
incs += ' ' + env['BF_PTHREADS_INC']
+if env['WITH_BF_ONSURFACEBRUSH']:
+ defs.append('WITH_ONSURFACEBRUSH')
+
env.BlenderLib ( 'bf_editors_sculpt_paint', sources, Split(incs), defines=defs, libtype=['core'], priority=[40] )
diff --git a/source/blender/editors/sculpt_paint/paint_stroke.c b/source/blender/editors/sculpt_paint/paint_stroke.c
index 58c3446673c..87f964a8928 100644
--- a/source/blender/editors/sculpt_paint/paint_stroke.c
+++ b/source/blender/editors/sculpt_paint/paint_stroke.c
@@ -30,7 +30,6 @@
* \ingroup edsculpt
*/
-
#include "MEM_guardedalloc.h"
#include "BLI_math.h"
@@ -39,6 +38,7 @@
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DNA_brush_types.h"
+#include "DNA_meshdata_types.h"
#include "RNA_access.h"
@@ -58,7 +58,9 @@
#include "paint_intern.h"
/* still needed for sculpt_stroke_get_location, should be
removed eventually (TODO) */
-#include "sculpt_intern.h"
+#include "sculpt_intern.h" // XXX, for expedience in getting this working, refactor later (or this just shows that this needs unification)
+
+#include "BKE_DerivedMesh.h"
#include <float.h>
#include <math.h>
@@ -81,7 +83,10 @@ typedef struct PaintStroke {
int stroke_started;
/* event that started stroke, for modal() return */
int event_type;
-
+
+ /* event that started stroke, for modal() return */
+ int event_type;
+
StrokeGetLocation get_location;
StrokeTestStart test_start;
StrokeUpdateStep update_step;
@@ -108,6 +113,107 @@ static void paint_draw_smooth_stroke(bContext *C, int x, int y, void *customdata
glDisable(GL_LINE_SMOOTH);
}
+#if 0
+
+// grid texture for testing
+
+#define GRID_WIDTH 8
+#define GRID_LENGTH 8
+
+#define W (0xFFFFFFFF)
+#define G (0x00888888)
+#define E (0xE1E1E1E1)
+#define C (0xC3C3C3C3)
+#define O (0xB4B4B4B4)
+#define Q (0xA9A9A9A9)
+
+static unsigned grid_texture0[256] =
+{
+ W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,
+ W,G,G,G,G,G,G,G,G,G,G,G,G,G,G,W,
+ W,G,G,G,G,G,G,G,G,G,G,G,G,G,G,W,
+ W,G,G,G,G,G,G,G,G,G,G,G,G,G,G,W,
+ W,G,G,G,G,G,G,G,G,G,G,G,G,G,G,W,
+ W,G,G,G,G,G,G,G,G,G,G,G,G,G,G,W,
+ W,G,G,G,G,G,G,G,G,G,G,G,G,G,G,W,
+ W,G,G,G,G,G,G,G,G,G,G,G,G,G,G,W,
+ W,G,G,G,G,G,G,G,G,G,G,G,G,G,G,W,
+ W,G,G,G,G,G,G,G,G,G,G,G,G,G,G,W,
+ W,G,G,G,G,G,G,G,G,G,G,G,G,G,G,W,
+ W,G,G,G,G,G,G,G,G,G,G,G,G,G,G,W,
+ W,G,G,G,G,G,G,G,G,G,G,G,G,G,G,W,
+ W,G,G,G,G,G,G,G,G,G,G,G,G,G,G,W,
+ W,G,G,G,G,G,G,G,G,G,G,G,G,G,G,W,
+ W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,
+};
+
+static unsigned grid_texture1[64] =
+{
+ C,C,C,C,C,C,C,C,
+ C,G,G,G,G,G,G,C,
+ C,G,G,G,G,G,G,C,
+ C,G,G,G,G,G,G,C,
+ C,G,G,G,G,G,G,C,
+ C,G,G,G,G,G,G,C,
+ C,G,G,G,G,G,G,C,
+ C,C,C,C,C,C,C,C,
+};
+
+static unsigned grid_texture2[16] =
+{
+ O,O,O,O,
+ O,G,G,O,
+ O,G,G,O,
+ O,O,O,O,
+};
+
+static unsigned grid_texture3[4] =
+{
+ Q,Q,
+ Q,Q,
+};
+
+static unsigned grid_texture4[1] =
+{
+ Q,
+};
+
+#undef W
+#undef G
+#undef E
+#undef C
+#undef O
+#undef Q
+
+static void load_grid()
+{
+ static GLuint overlay_texture;
+
+ if (!overlay_texture) {
+ //GLfloat largest_supported_anisotropy;
+
+ glGenTextures(1, &overlay_texture);
+ glBindTexture(GL_TEXTURE_2D, overlay_texture);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, grid_texture0);
+ glTexImage2D(GL_TEXTURE_2D, 1, GL_RGB, 8, 8, 0, GL_RGBA, GL_UNSIGNED_BYTE, grid_texture1);
+ glTexImage2D(GL_TEXTURE_2D, 2, GL_RGB, 4, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE, grid_texture2);
+ glTexImage2D(GL_TEXTURE_2D, 3, GL_RGB, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, grid_texture3);
+ glTexImage2D(GL_TEXTURE_2D, 4, GL_RGB, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, grid_texture4);
+ glEnable(GL_TEXTURE_2D);
+ glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_LINEAR);
+
+ //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
+ //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
+
+ //glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &largest_supported_anisotropy);
+ //glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, largest_supported_anisotropy);
+ }
+}
+
+#endif
+
typedef struct Snapshot {
float size[3];
float ofs[3];
@@ -119,7 +225,7 @@ typedef struct Snapshot {
int curve_changed_timestamp;
} Snapshot;
-static int same_snap(Snapshot* snap, Brush* brush, ViewContext* vc)
+static int same_snap(Snapshot* snap, Brush* brush, ARegion *ar)
{
MTex* mtex = &brush->mtex;
@@ -131,14 +237,15 @@ static int same_snap(Snapshot* snap, Brush* brush, ViewContext* vc)
mtex->size[0] == snap->size[0] &&
mtex->size[1] == snap->size[1] &&
mtex->size[2] == snap->size[2] &&
- mtex->rot == snap->rot) &&
- ((mtex->brush_map_mode == MTEX_MAP_MODE_FIXED && brush_size(brush) <= snap->brush_size) || (brush_size(brush) == snap->brush_size)) && // make brush smaller shouldn't cause a resample
- mtex->brush_map_mode == snap->brush_map_mode &&
- vc->ar->winx == snap->winx &&
- vc->ar->winy == snap->winy;
+ (ELEM(mtex->brush_map_mode, MTEX_MAP_MODE_WRAP, MTEX_MAP_MODE_FIXED) || mtex->rot == snap->rot)) && // rotation does not cause fixed texture to be regenerated
+ ((ELEM(mtex->brush_map_mode, MTEX_MAP_MODE_WRAP, MTEX_MAP_MODE_FIXED) && brush_size(brush) <= snap->brush_size) || (brush_size(brush) == snap->brush_size)) && // make brush smaller shouldn't cause a resample
+ (mtex->brush_map_mode == snap->brush_map_mode ||
+ (ELEM(mtex->brush_map_mode, MTEX_MAP_MODE_WRAP, MTEX_MAP_MODE_FIXED) && ELEM(snap->brush_map_mode, MTEX_MAP_MODE_WRAP, MTEX_MAP_MODE_FIXED))) && // texture doesn't have to be redone if switching from fixed to wrapped or visa versa
+ ar->winx == snap->winx &&
+ ar->winy == snap->winy;
}
-static void make_snap(Snapshot* snap, Brush* brush, ViewContext* vc)
+static void make_snap(Snapshot* snap, Brush* brush, ARegion *ar)
{
if (brush->mtex.tex) {
snap->brush_map_mode = brush->mtex.brush_map_mode;
@@ -148,17 +255,17 @@ static void make_snap(Snapshot* snap, Brush* brush, ViewContext* vc)
}
else {
snap->brush_map_mode = -1;
- snap->ofs[0]= snap->ofs[1]= snap->ofs[2]= -1;
- snap->size[0]= snap->size[1]= snap->size[2]= -1;
+ snap->ofs[0]= snap->ofs[0]= snap->ofs[0]= -1;
+ snap->size[0]= snap->size[0]= snap->size[0]= -1;
snap->rot = -1;
}
snap->brush_size = brush_size(brush);
- snap->winx = vc->ar->winx;
- snap->winy = vc->ar->winy;
+ snap->winx = ar->winx;
+ snap->winy = ar->winy;
}
-static int load_tex(Sculpt *sd, Brush* br, ViewContext* vc)
+static int paint_load_overlay_tex(Sculpt *sd, Brush* br, ViewContext* vc)
{
static GLuint overlay_texture = 0;
static int init = 0;
@@ -178,7 +285,7 @@ static int load_tex(Sculpt *sd, Brush* br, ViewContext* vc)
#endif
if (br->mtex.brush_map_mode == MTEX_MAP_MODE_TILED && !br->mtex.tex) return 0;
-
+
refresh =
!overlay_texture ||
(br->mtex.tex &&
@@ -186,7 +293,7 @@ static int load_tex(Sculpt *sd, Brush* br, ViewContext* vc)
br->mtex.tex->preview->changed_timestamp[0] != tex_changed_timestamp)) ||
!br->curve ||
br->curve->changed_timestamp != curve_changed_timestamp ||
- !same_snap(&snap, br, vc);
+ !same_snap(&snap, br, ar);
if (refresh) {
if (br->mtex.tex && br->mtex.tex->preview)
@@ -195,9 +302,9 @@ static int load_tex(Sculpt *sd, Brush* br, ViewContext* vc)
if (br->curve)
curve_changed_timestamp = br->curve->changed_timestamp;
- make_snap(&snap, br, vc);
+ make_snap(&snap, br, ar);
- if (br->mtex.brush_map_mode == MTEX_MAP_MODE_FIXED) {
+ if (ELEM(br->mtex.brush_map_mode, MTEX_MAP_MODE_WRAP, MTEX_MAP_MODE_FIXED)) {
int s = brush_size(br);
int r = 1;
@@ -226,7 +333,7 @@ static int load_tex(Sculpt *sd, Brush* br, ViewContext* vc)
old_size = size;
}
- buffer = MEM_mallocN(sizeof(GLubyte)*size*size, "load_tex");
+ buffer = MEM_mallocN(sizeof(GLubyte)*size*size, "paint_load_overlay_tex");
#pragma omp parallel for schedule(static) if (sd->flags & SCULPT_USE_OPENMP)
for (j= 0; j < size; j++) {
@@ -239,7 +346,7 @@ static int load_tex(Sculpt *sd, Brush* br, ViewContext* vc)
// largely duplicated from tex_strength
const float rotation = -br->mtex.rot;
- float radius = brush_size(br);
+ float diameter = brush_size(br);
int index = j*size + i;
float x;
float avg;
@@ -251,8 +358,8 @@ static int load_tex(Sculpt *sd, Brush* br, ViewContext* vc)
y -= 0.5f;
if (br->mtex.brush_map_mode == MTEX_MAP_MODE_TILED) {
- x *= vc->ar->winx / radius;
- y *= vc->ar->winy / radius;
+ x *= ar->winx / diameter;
+ y *= ar->winy / diameter;
}
else {
x *= 2;
@@ -265,8 +372,11 @@ static int load_tex(Sculpt *sd, Brush* br, ViewContext* vc)
/* it is probably worth optimizing for those cases where
the texture is not rotated by skipping the calls to
atan2, sqrtf, sin, and cos. */
- if (br->mtex.tex && (rotation > 0.001f || rotation < -0.001f)) {
- const float angle = atan2f(y, x) + rotation;
+ if ((br->mtex.brush_map_mode == MTEX_MAP_MODE_TILED) &&
+ br->mtex.tex &&
+ (rotation > 0.001f || rotation < -0.001f))
+ {
+ const float angle= atan2(y, x) + rotation;
x = len * cosf(angle);
y = len * sinf(angle);
@@ -282,7 +392,7 @@ static int load_tex(Sculpt *sd, Brush* br, ViewContext* vc)
avg += br->texture_sample_bias;
- if (br->mtex.brush_map_mode == MTEX_MAP_MODE_FIXED)
+ if (ELEM(br->mtex.brush_map_mode, MTEX_MAP_MODE_WRAP, MTEX_MAP_MODE_FIXED))
avg *= brush_curve_strength(br, len, 1); /* Falloff curve */
buffer[index] = 255 - (GLubyte)(255*avg);
@@ -321,14 +431,79 @@ static int load_tex(Sculpt *sd, Brush* br, ViewContext* vc)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- if (br->mtex.brush_map_mode == MTEX_MAP_MODE_FIXED) {
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
+ if (ELEM(br->mtex.brush_map_mode, MTEX_MAP_MODE_WRAP, MTEX_MAP_MODE_FIXED)) {
+ float clear[4]= {0,0,0,0};
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
+ glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, clear);
}
return 1;
}
+void ED_draw_paint_overlay(const bContext* C, ARegion *ar)
+{
+ Paint *paint = paint_get_active(CTX_data_scene(C));
+ Brush *brush = paint_brush(paint);
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+
+ if (!sd->sculpting &&
+ brush &&
+ brush->mtex.brush_map_mode == MTEX_MAP_MODE_TILED &&
+ brush->flag & BRUSH_TEXTURE_OVERLAY)
+ {
+ glPushAttrib(
+ GL_COLOR_BUFFER_BIT|
+ GL_CURRENT_BIT|
+ GL_DEPTH_BUFFER_BIT|
+ GL_ENABLE_BIT|
+ GL_LINE_BIT|
+ GL_POLYGON_BIT|
+ GL_STENCIL_BUFFER_BIT|
+ GL_TRANSFORM_BIT|
+ GL_VIEWPORT_BIT|
+ GL_TEXTURE_BIT);
+
+ if (paint_load_overlay_tex(sd, brush, ar)) {
+ glEnable(GL_BLEND);
+
+ glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+ glDepthMask(GL_FALSE);
+ glDepthFunc(GL_ALWAYS);
+
+ glMatrixMode(GL_TEXTURE);
+ glPushMatrix();
+ glLoadIdentity();
+
+ glColor4f(
+ U.sculpt_paint_overlay_col[0],
+ U.sculpt_paint_overlay_col[1],
+ U.sculpt_paint_overlay_col[2],
+ brush->texture_overlay_alpha / 100.0f);
+
+ glBegin(GL_QUADS);
+ glTexCoord2f(0.0f, 0.0f);
+ glVertex2f(0.0f, 0.0f);
+
+ glTexCoord2f(1.0f, 0.0f);
+ glVertex2f(ar->winx, 0.0f);
+
+ glTexCoord2f(1.0f, 1.0f);
+ glVertex2f(ar->winx, ar->winy);
+
+ glTexCoord2f(0.0f, 1.0f);
+ glVertex2f(0.0f, ar->winy);
+ glEnd();
+
+ glPopMatrix();
+
+ glMatrixMode(GL_MODELVIEW);
+ }
+
+ glPopAttrib();
+ }
+}
+
static int project_brush_radius(RegionView3D* rv3d, float radius, float location[3], bglMats* mats)
{
float view[3], nonortho[3], ortho[3], offset[3], p1[2], p2[2];
@@ -369,8 +544,15 @@ static int project_brush_radius(RegionView3D* rv3d, float radius, float location
return len_v2v2(p1, p2);
}
-static int sculpt_get_brush_geometry(bContext* C, int x, int y, int* pixel_radius,
- float location[3])
+static int sculpt_get_brush_geometry(
+ bContext* C,
+ int x,
+ int y,
+ int* pixel_radius,
+ float location[3],
+ float modelview[16],
+ float projection[16],
+ int viewport[4])
{
struct PaintStroke *stroke;
float window[2];
@@ -381,11 +563,20 @@ static int sculpt_get_brush_geometry(bContext* C, int x, int y, int* pixel_radiu
window[0] = x + stroke->vc.ar->winrct.xmin;
window[1] = y + stroke->vc.ar->winrct.ymin;
- if(stroke->vc.obact->sculpt && stroke->vc.obact->sculpt->pbvh &&
- sculpt_stroke_get_location(C, stroke, location, window)) {
- *pixel_radius = project_brush_radius(stroke->vc.rv3d,
- brush_unprojected_radius(stroke->brush),
- location, &stroke->mats);
+ memcpy(modelview, stroke->vc.rv3d->viewmat, sizeof(float[16]));
+ memcpy(projection, stroke->vc.rv3d->winmat, sizeof(float[16]));
+ memcpy(viewport, stroke->mats.viewport, sizeof(int[4]));
+
+ if (stroke->vc.obact->sculpt &&
+ stroke->vc.obact->sculpt->pbvh &&
+ sculpt_stroke_get_location(C, stroke, location, window))
+ {
+ *pixel_radius =
+ project_brush_radius(
+ stroke->vc.rv3d,
+ brush_unprojected_radius(stroke->brush),
+ location,
+ &stroke->mats);
if (*pixel_radius == 0)
*pixel_radius = brush_size(stroke->brush);
@@ -407,174 +598,689 @@ static int sculpt_get_brush_geometry(bContext* C, int x, int y, int* pixel_radiu
return hit;
}
-/* Draw an overlay that shows what effect the brush's texture will
- have on brush strength */
-/* TODO: sculpt only for now */
-static void paint_draw_alpha_overlay(Sculpt *sd, Brush *brush,
- ViewContext *vc, int x, int y)
-{
- rctf quad;
-
- /* check for overlay mode */
- if(!(brush->flag & BRUSH_TEXTURE_OVERLAY) ||
- !(ELEM(brush->mtex.brush_map_mode, MTEX_MAP_MODE_FIXED, MTEX_MAP_MODE_TILED)))
- return;
-
- /* save lots of GL state
- TODO: check on whether all of these are needed? */
- glPushAttrib(GL_COLOR_BUFFER_BIT|
- GL_CURRENT_BIT|
- GL_DEPTH_BUFFER_BIT|
- GL_ENABLE_BIT|
- GL_LINE_BIT|
- GL_POLYGON_BIT|
- GL_STENCIL_BUFFER_BIT|
- GL_TRANSFORM_BIT|
- GL_VIEWPORT_BIT|
- GL_TEXTURE_BIT);
-
- if(load_tex(sd, brush, vc)) {
- glEnable(GL_BLEND);
+static void set_brush_dot_location(float *modelview, float location[3], const char symm, const char axis, float angle)
+{
+ glLoadMatrixf(modelview);
+
+ angle *= (float)(180.0/M_PI);
+ switch (axis) {
+ case 'X':
+ glRotatef(angle, 1.0f, 0.0f, 0.0f);
+ break;
+
+ case 'Y':
+ glRotatef(angle, 0.0f, 1.0f, 0.0f);
+ break;
+
+ case 'Z':
+ glRotatef(angle, 0.0f, 0.0f, 1.0f);
+ break;
+ }
+
+ glTranslatef(
+ !(symm & SCULPT_SYMM_X) ? location[0]: -location[0],
+ !(symm & SCULPT_SYMM_Y) ? location[1]: -location[1],
+ !(symm & SCULPT_SYMM_Z) ? location[2]: -location[2]);
+}
+
+static void draw_brush_dot(GLUquadric *sphere, float radius)
+{
+ gluSphere(sphere, radius, 20, 20);
+}
+
+static void draw_radial_symmetry_dot(float *modelview, float location[3], const char symm, int radial_symm[3], const int axis, GLUquadric *sphere, float radius)
+{
+ int i;
+
+ for(i = 1; i < radial_symm[axis-'X']; ++i) {
+ const float angle = 2*M_PI*i/radial_symm[axis-'X'];
+ set_brush_dot_location(modelview, location, symm, axis, angle);
+ draw_brush_dot(sphere, radius);
+ }
+}
+
+static void draw_symmetric_brush_dots(Sculpt *sd, float location[3], float col[3], float *modelview, float *projection, int viewport[4], float radius, int draw_first)
+{
+ int i;
+ short symm= sd->flags & 7;
+
+ GLUquadric* sphere;
+
+ sphere = gluNewQuadric();
+
+ glPushAttrib(
+ GL_COLOR_BUFFER_BIT|
+ GL_CURRENT_BIT|
+ GL_DEPTH_BUFFER_BIT|
+ GL_ENABLE_BIT|
+ GL_LINE_BIT|
+ GL_POLYGON_BIT|
+ GL_STENCIL_BUFFER_BIT|
+ GL_TRANSFORM_BIT|
+ GL_VIEWPORT_BIT|
+ GL_TEXTURE_BIT);
+
+ glColor4f(col[0], col[1], col[2], 0.5f);
+
+ glEnable(GL_BLEND);
+
+ glViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
+
+ glMatrixMode(GL_PROJECTION);
+ glPushMatrix();
+ glLoadMatrixf(projection);
+
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+
+ glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+ glDepthMask(GL_FALSE);
+
+ glEnable(GL_DEPTH_TEST);
+
+ glEnable(GL_CULL_FACE);
+
+ /* symm is a bit combination of XYZ - 1 is mirror X; 2 is Y; 3 is XY; 4 is Z; 5 is XZ; 6 is YZ; 7 is XYZ */
+ for(i = 0; i <= symm; ++i) {
+ if(i == 0 || (symm & i && (symm != 5 || i != 3) && (symm != 6 || (i != 3 && i != 5)))) {
+
+ if (draw_first) {
+ set_brush_dot_location(modelview, location, i, 0, 0);
+ draw_brush_dot(sphere, radius);
+ }
+
+ draw_radial_symmetry_dot(modelview, location, i, sd->radial_symm, 'X', sphere, radius);
+ draw_radial_symmetry_dot(modelview, location, i, sd->radial_symm, 'Y', sphere, radius);
+ draw_radial_symmetry_dot(modelview, location, i, sd->radial_symm, 'Z', sphere, radius);
+ }
+ }
+
+ glPopAttrib();
+}
+
+static void draw_fixed_overlay(Sculpt *sd, Brush *brush, ViewContext *vc, rctf* quad, float angle)
+{
+ glPushAttrib(
+ GL_COLOR_BUFFER_BIT|
+ GL_DEPTH_BUFFER_BIT|
+ GL_ENABLE_BIT|
+ GL_TRANSFORM_BIT|
+ GL_CURRENT_BIT|
+ GL_TEXTURE_BIT);
+
+ if (paint_load_overlay_tex(sd, brush, vc->ar)) {
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glDepthMask(GL_FALSE);
glDepthFunc(GL_ALWAYS);
+ glEnable(GL_BLEND);
+
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+ glLoadIdentity();
+
glMatrixMode(GL_TEXTURE);
glPushMatrix();
glLoadIdentity();
- if(brush->mtex.brush_map_mode == MTEX_MAP_MODE_FIXED) {
- /* brush rotation */
- glTranslatef(0.5, 0.5, 0);
- glRotatef((double)((brush->flag & BRUSH_RAKE) ?
- sd->last_angle : sd->special_rotation) * (180.0/M_PI),
- 0.0, 0.0, 1.0);
- glTranslatef(-0.5f, -0.5f, 0);
-
- /* scale based on tablet pressure */
- if(sd->draw_pressure && brush_use_size_pressure(brush)) {
- glTranslatef(0.5f, 0.5f, 0);
- glScalef(1.0f/sd->pressure_value, 1.0f/sd->pressure_value, 1);
- glTranslatef(-0.5f, -0.5f, 0);
- }
+ glTranslatef(0.5f, 0.5f, 0.0f);
- if(sd->draw_anchored) {
- const float *aim = sd->anchored_initial_mouse;
- const rcti *win = &vc->ar->winrct;
- quad.xmin = aim[0]-sd->anchored_size - win->xmin;
- quad.ymin = aim[1]-sd->anchored_size - win->ymin;
- quad.xmax = aim[0]+sd->anchored_size - win->xmin;
- quad.ymax = aim[1]+sd->anchored_size - win->ymin;
- }
- else {
- const int radius= brush_size(brush);
- quad.xmin = x - radius;
- quad.ymin = y - radius;
- quad.xmax = x + radius;
- quad.ymax = y + radius;
- }
- }
- else {
- quad.xmin = 0;
- quad.ymin = 0;
- quad.xmax = vc->ar->winrct.xmax - vc->ar->winrct.xmin;
- quad.ymax = vc->ar->winrct.ymax - vc->ar->winrct.ymin;
+ glRotatef(angle, 0.0f, 0.0f, 1.0f);
+
+ glTranslatef(-0.5f, -0.5f, 0.0f);
+
+ if (sd->draw_pressure && (brush->flag & BRUSH_SIZE_PRESSURE)) {
+ glTranslatef(0.5f, 0.5f, 0.0f);
+ glScalef(1.0f/sd->pressure_value, 1.0f/sd->pressure_value, 1);
+ glTranslatef(-0.5f, -0.5f, 0.0f);
}
- /* set quad color */
- glColor4f(U.sculpt_paint_overlay_col[0],
- U.sculpt_paint_overlay_col[1],
- U.sculpt_paint_overlay_col[2],
- brush->texture_overlay_alpha / 100.0f);
+ glColor4f(
+ U.sculpt_paint_overlay_col[0],
+ U.sculpt_paint_overlay_col[1],
+ U.sculpt_paint_overlay_col[2],
+ brush->texture_overlay_alpha / 100.0f);
- /* draw textured quad */
glBegin(GL_QUADS);
- glTexCoord2f(0, 0);
- glVertex2f(quad.xmin, quad.ymin);
- glTexCoord2f(1, 0);
- glVertex2f(quad.xmax, quad.ymin);
- glTexCoord2f(1, 1);
- glVertex2f(quad.xmax, quad.ymax);
- glTexCoord2f(0, 1);
- glVertex2f(quad.xmin, quad.ymax);
+ glTexCoord2f(0.0f, 0.0f);
+ glVertex2f(quad->xmin, quad->ymin);
+
+ glTexCoord2f(1.0f, 0.0f);
+ glVertex2f(quad->xmax, quad->ymin);
+
+ glTexCoord2f(1.0f, 1.0f);
+ glVertex2f(quad->xmax, quad->ymax);
+
+ glTexCoord2f(0.0f, 1.0f);
+ glVertex2f(quad->xmin, quad->ymax);
glEnd();
glPopMatrix();
+
+ glMatrixMode(GL_MODELVIEW);
+ glPopMatrix();
}
glPopAttrib();
}
-/* Special actions taken when paint cursor goes over mesh */
-/* TODO: sculpt only for now */
-static void paint_cursor_on_hit(Sculpt *sd, Brush *brush, ViewContext *vc,
- float location[3], float *visual_strength)
+void ED_draw_on_surface_cursor(float modelview[16], float projection[16], float col[3], float alpha, float size[3], int viewport[4], float location[3], float inner_radius, float outer_radius, int brush_size)
{
- float unprojected_radius, projected_radius;
+ GLUquadric* sphere;
+
+ glPushAttrib(
+ GL_COLOR_BUFFER_BIT|
+ GL_CURRENT_BIT|
+ GL_DEPTH_BUFFER_BIT|
+ GL_ENABLE_BIT|
+ GL_LINE_BIT|
+ GL_POLYGON_BIT|
+ GL_STENCIL_BUFFER_BIT|
+ GL_TRANSFORM_BIT|
+ GL_VIEWPORT_BIT|
+ GL_TEXTURE_BIT);
+
+ glColor4f(col[0], col[1], col[2], alpha);
- /* TODO: check whether this should really only be done when
- brush is over mesh? */
- if(sd->draw_pressure && brush_use_alpha_pressure(brush))
- (*visual_strength) *= sd->pressure_value;
+ glEnable(GL_BLEND);
- if(sd->draw_anchored)
- projected_radius = sd->anchored_size;
- else {
- if(brush->flag & BRUSH_ANCHORED)
- projected_radius = 8;
- else
- projected_radius = brush_size(brush);
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+ glLoadMatrixf(modelview);
+
+ glTranslatef(location[0], location[1], location[2]);
+
+ glScalef(size[0], size[1], size[2]);
+
+ glMatrixMode(GL_PROJECTION);
+ glPushMatrix();
+ glLoadMatrixf(projection);
+
+ glViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
+
+ glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
+ glDepthMask(GL_FALSE);
+
+ glDisable(GL_CULL_FACE);
+
+ glEnable(GL_DEPTH_TEST);
+
+ glClearStencil(0);
+ glClear(GL_STENCIL_BUFFER_BIT);
+ glEnable(GL_STENCIL_TEST);
+
+ glStencilFunc(GL_ALWAYS, 3, 0xFF);
+ glStencilOp(GL_KEEP, GL_REPLACE, GL_KEEP);
+
+ sphere = gluNewQuadric();
+
+ gluSphere(sphere, outer_radius, 40, 40);
+
+ glStencilFunc(GL_ALWAYS, 1, 0xFF);
+ glStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
+
+ if (brush_size >= 8)
+ gluSphere(sphere, inner_radius, 40, 40);
+
+ glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+
+ glStencilFunc(GL_EQUAL, 1, 0xFF);
+ glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
+
+ gluSphere(sphere, outer_radius, 40, 40);
+
+ glStencilFunc(GL_EQUAL, 3, 0xFF);
+ glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
+
+ gluSphere(sphere, outer_radius, 40, 40);
+
+ gluDeleteQuadric(sphere);
+
+ glPopMatrix();
+
+ glMatrixMode(GL_MODELVIEW);
+ glPopMatrix();
+
+ glPopAttrib();
+}
+
+static void stencil_brush_on_surface(float modelview[16], float projection[16], float size[3], int viewport[4], float location[3], float outer_radius)
+{
+ GLUquadric* sphere;
+
+ glPushAttrib(
+ GL_COLOR_BUFFER_BIT|
+ GL_CURRENT_BIT|
+ GL_DEPTH_BUFFER_BIT|
+ GL_ENABLE_BIT|
+ GL_LINE_BIT|
+ GL_POLYGON_BIT|
+ GL_STENCIL_BUFFER_BIT|
+ GL_TRANSFORM_BIT|
+ GL_VIEWPORT_BIT|
+ GL_TEXTURE_BIT);
+
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+ glLoadMatrixf(modelview);
+
+ glTranslatef(location[0], location[1], location[2]);
+
+ glScalef(size[0], size[1], size[2]);
+
+ glMatrixMode(GL_PROJECTION);
+ glPushMatrix();
+ glLoadMatrixf(projection);
+
+ glViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
+
+ glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
+ glDepthMask(GL_FALSE);
+
+ glDisable(GL_CULL_FACE);
+
+ glEnable(GL_DEPTH_TEST);
+
+ glClearStencil(0);
+ glClear(GL_STENCIL_BUFFER_BIT);
+ glEnable(GL_STENCIL_TEST);
+
+ glStencilFunc(GL_ALWAYS, 3, 0xFF);
+ glStencilOp(GL_KEEP, GL_REPLACE, GL_KEEP);
+
+ sphere = gluNewQuadric();
+
+ gluSphere(sphere, outer_radius, 40, 40);
+
+ glStencilFunc(GL_ALWAYS, 1, 0xFF);
+ glStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
+
+ gluSphere(sphere, outer_radius, 40, 40);
+
+ glPopMatrix();
+
+ glMatrixMode(GL_MODELVIEW);
+ glPopMatrix();
+
+ glPopAttrib();
+}
+
+void ED_draw_fixed_overlay_on_surface(float modelview[16], float projection[16], float size[3], int viewport[4], float location[3], float outer_radius, Sculpt *sd, Brush *brush, ViewContext *vc, rctf* quad, float angle)
+{
+ stencil_brush_on_surface(modelview, projection, size, viewport, location, outer_radius);
+
+ glPushAttrib(GL_STENCIL_BUFFER_BIT);
+
+ glEnable(GL_STENCIL_TEST);
+ glStencilFunc(GL_EQUAL, 2, 0xFF);
+ glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
+
+ draw_fixed_overlay(sd, brush, vc, quad, angle);
+
+ glPopAttrib();
+}
+
+typedef struct SphereTest {
+ float radius_squared;
+ float location[3];
+ float dist;
+} SphereTest;
+
+static void sphere_test_init(float radius_squared, float location[3], SphereTest *test)
+{
+ test->radius_squared= radius_squared;
+ copy_v3_v3(test->location, location);
+}
+
+static int sphere_test_fast(SphereTest *test, float co[3])
+{
+ return len_squared_v3v3(co, test->location) <= test->radius_squared;
+}
+
+static void add_norm_if(float view_vec[3], float out[3], float out_flip[3], float fno[3])
+{
+ if(!view_vec || dot_v3v3(view_vec, fno) > 0) {
+ add_v3_v3(out, fno);
+ } else {
+ add_v3_v3(out_flip, fno); /* out_flip is used when out is {0,0,0} */
}
- unprojected_radius = paint_calc_object_space_radius(vc, location,
- projected_radius);
+}
+
+static void PBVH_area_normal(float out[3], float view_vec[3], float radius, float location[3], PBVH* pbvh, PBVHNode **nodes, int totnode, int use_openmp)
+{
+ int n;
+
+ float out_flip[3] = {0.0f, 0.0f, 0.0f};
+
+ zero_v3(out);
+
+ #pragma omp parallel for schedule(guided) if (use_openmp)
+ for(n=0; n<totnode; n++) {
+ PBVHVertexIter vd;
+ SphereTest test;
+ float private_an[3] = {0.0f, 0.0f, 0.0f};
+ float private_out_flip[3] = {0.0f, 0.0f, 0.0f};
+
+ sphere_test_init(radius, location, &test);
+
+ BLI_pbvh_vertex_iter_begin(pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if(sphere_test_fast(&test, vd.co)) {
+ if(vd.no) {
+ float fno[3];
- if(sd->draw_pressure && brush_use_size_pressure(brush))
- unprojected_radius *= sd->pressure_value;
+ normal_short_to_float_v3(fno, vd.no);
+ add_norm_if(view_vec, private_an, private_out_flip, fno);
+ }
+ else {
+ add_norm_if(view_vec, private_an, private_out_flip, vd.fno);
+ }
+ }
+ }
+ BLI_pbvh_vertex_iter_end;
- if(!brush_use_locked_size(brush))
- brush_set_unprojected_radius(brush, unprojected_radius);
+ #pragma omp critical
+ {
+ add_v3_v3(out, private_an);
+ add_v3_v3(out_flip, private_out_flip);
+ }
+ }
+
+ if (is_zero_v3(out))
+ copy_v3_v3(out, out_flip);
+
+ normalize_v3(out);
+}
+
+static void paint_sculpt_disp_vector(float out[3], int disp_type, float view_vec[3], float radius, float location[3], PBVH *pbvh, PBVHNode **nodes, int totnode, int use_openmp)
+{
+ switch (disp_type) {
+ case SCULPT_DISP_DIR_VIEW:
+ if (view_vec)
+ copy_v3_v3(out, view_vec);
+ else
+ zero_v3(out);
+
+ break;
+
+ case SCULPT_DISP_DIR_X:
+ out[1] = 0.0;
+ out[2] = 0.0;
+ out[0] = 1.0;
+ break;
+
+ case SCULPT_DISP_DIR_Y:
+ out[0] = 0.0;
+ out[2] = 0.0;
+ out[1] = 1.0;
+ break;
+
+ case SCULPT_DISP_DIR_Z:
+ out[0] = 0.0;
+ out[1] = 0.0;
+ out[2] = 1.0;
+ break;
+
+ case SCULPT_DISP_DIR_AREA:
+ PBVH_area_normal(out, view_vec, radius, location, pbvh, nodes, totnode, use_openmp);
+ break;
+
+ default:
+ break;
+ }
+}
+
+static void calc_brush_local_mat(float out[4][4], const Brush *brush, float up_vec[3], float location[3], float disp_vec[3])
+{
+ float mat[4][4];
+ float scale[4][4];
+ float tmat[4][4];
+
+ // first row, x axis is perpendicular to both the up vector and the displacement vector
+ cross_v3_v3v3(mat[0], up_vec, disp_vec);
+ mat[0][3] = 0;
+
+ // second row, y axis is perpendicular to the x axis and displacement vector
+ cross_v3_v3v3(mat[1], disp_vec, mat[0]);
+ mat[1][3] = 0;
+
+ // third row, z axis is simply the displacement vector
+ copy_v3_v3(mat[2], disp_vec);
+ mat[2][3] = 0;
+
+ // fourth row, the origin of the coordinate system is the location of the brush
+ copy_v3_v3(mat[3], location);
+ mat[3][3] = 1;
+
+ // normalize the coordinate system so that points inside the brush are within a unit sphere
+ normalize_m4(mat);
+ scale_m4_fl(scale, brush_unprojected_radius(brush));
+ mul_m4_m4m4(tmat, scale, mat);
+
+ // the inverse of the matrix describing the coordinate system of the
+ // brush is a matrix that will transform a point into 'local brush space'
+ invert_m4_m4(out, tmat);
+}
+
+static void draw_wrapped_overlay(float modelview[16], float projection[16], float size[3], int viewport[4], float location[3], float unprojected_radius, Sculpt *sd, Brush *brush, ViewContext *vc, float angle, float up_vec[3])
+{
+ glPushAttrib(
+ GL_COLOR_BUFFER_BIT|
+ GL_CURRENT_BIT|
+ GL_DEPTH_BUFFER_BIT|
+ GL_ENABLE_BIT|
+ GL_LINE_BIT|
+ GL_POLYGON_BIT|
+ GL_STENCIL_BUFFER_BIT|
+ GL_TRANSFORM_BIT|
+ GL_VIEWPORT_BIT|
+ GL_TEXTURE_BIT);
+
+ if (paint_load_overlay_tex(sd, brush, vc->ar)) {
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+ glLoadMatrixf(modelview);
+
+ glMatrixMode(GL_PROJECTION);
+ glPushMatrix();
+ glLoadMatrixf(projection);
+
+ glMatrixMode(GL_TEXTURE);
+ glPushMatrix();
+ glLoadIdentity();
+ glTranslatef(0.5f, 0.5f, 0.5f);
+ glScalef(0.5f, 0.5f, 0.5f);
+
+ //glTranslatef(ob->orig[0], ob->orig[1], ob->orig[2]);
+
+ glScalef(size[0], size[1], size[2]);
+
+ glRotatef(angle, 0, 0, 1);
+
+ {
+ float disp_vec[3];
+ float view_vec[3];
+ float brush_local_mat[4][4];
+
+ PBVHNode **nodes;
+ int totnode;
+
+ viewvector(vc->rv3d, vc->rv3d->twmat[3], view_vec);
+
+ BLI_pbvh_gather_nodes_in_sphere(
+ vc->obact->sculpt->pbvh,
+ location,
+ brush_unprojected_radius(brush),
+ &nodes,
+ &totnode);
+
+ paint_sculpt_disp_vector(
+ disp_vec,
+ brush->sculpt_plane,
+ view_vec,
+ brush_unprojected_radius(brush),
+ location,
+ vc->obact->sculpt->pbvh,
+ nodes,
+ totnode,
+ sd->flags & SCULPT_USE_OPENMP);
+
+ if (nodes)
+ MEM_freeN(nodes);
+
+ calc_brush_local_mat(
+ brush_local_mat,
+ brush,
+ up_vec,
+ location,
+ disp_vec);
+
+ glMultMatrixf(brush_local_mat);
+ }
+
+ {
+ float plane_x[4]= {1,0,0,0};
+ float plane_y[4]= {0,1,0,0};
+ float plane_z[4]= {0,0,1,0};
+ float plane_w[4]= {0,0,0,1};
+ glTexGenf(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
+ glTexGenf(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
+ glTexGenf(GL_R, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
+ glTexGenf(GL_Q, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
+ glTexGenfv(GL_S, GL_OBJECT_PLANE, plane_x);
+ glTexGenfv(GL_T, GL_OBJECT_PLANE, plane_y);
+ glTexGenfv(GL_R, GL_OBJECT_PLANE, plane_z);
+ glTexGenfv(GL_Q, GL_OBJECT_PLANE, plane_w);
+ glEnable(GL_TEXTURE_GEN_S);
+ glEnable(GL_TEXTURE_GEN_T);
+ glEnable(GL_TEXTURE_GEN_R);
+ glEnable(GL_TEXTURE_GEN_Q);
+ }
+
+ glViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
+
+ glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+ glDepthMask(GL_FALSE);
+
+ glColor4f(
+ U.sculpt_paint_overlay_col[0],
+ U.sculpt_paint_overlay_col[1],
+ U.sculpt_paint_overlay_col[2],
+ brush->texture_overlay_alpha / 100.0f);
+
+ glEnable(GL_BLEND);
+
+ glEnable(GL_CULL_FACE);
+
+ glDepthFunc(GL_LEQUAL);
+ glEnable(GL_DEPTH_TEST);
+
+ glPolygonOffset(-1, 1);
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ glEnable(GL_POLYGON_OFFSET_FILL);
+
+ BLI_pbvh_draw_nodes_in_sphere(vc->obact->sculpt->pbvh, location, unprojected_radius);
+
+ glPopMatrix();
+
+ glMatrixMode(GL_PROJECTION);
+ glPopMatrix();
+
+ glMatrixMode(GL_MODELVIEW);
+ glPopMatrix();
+ }
+
+ glPopAttrib();
+}
+
+void ED_draw_wrapped_overlay_on_surface(float modelview[16], float projection[16], float size[3], int viewport[4], float location[3], float unprojected_radius, Sculpt *sd, Brush *brush, ViewContext *vc, float angle, float up_vec[3])
+{
+ stencil_brush_on_surface(modelview, projection, size, viewport, location, unprojected_radius);
+
+ glPushAttrib(GL_STENCIL_BUFFER_BIT);
+
+ glEnable(GL_STENCIL_TEST);
+ glStencilFunc(GL_EQUAL, 2, 0xFF);
+ glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
+
+ draw_wrapped_overlay(modelview, projection, size, viewport, location, unprojected_radius, sd, brush, vc, angle, up_vec);
+
+ glPopAttrib();
+}
+
+static void update_rake_delta(float out[3], float location[3], int x, int y, ViewContext *vc, float mat[4][4])
+{
+ static float old_location[3], old_delta[3];
+
+ float delta[3], imat[4][4];
+
+ /* compute 3d coordinate at same z from original location + mouse */
+ initgrabz(vc->rv3d, old_location[0], old_location[1], old_location[2]);
+ window_to_3d_delta(vc->ar, delta, x, y);
+
+ /* compute delta to move verts by */
+ sub_v3_v3v3(out, delta, old_delta);
+ invert_m4_m4(imat, mat);
+ mul_mat3_m4_v3(imat, out);
+
+ copy_v3_v3(old_delta, delta);
+
+ if (len_v3v3(old_location, location) > 1000)
+ copy_v3_v3(old_location, location);
}
+// XXX paint cursor now does a lot of the same work that is needed during a sculpt stroke
+// problem: all this stuff was not intended to be used at this point, so things feel a
+// bit hacked. I've put lots of stuff in Brush that probably better goes in Paint
+// Functions should be refactored so that they can be used between sculpt.c and
+// paint_stroke.c clearly and optimally and the lines of communication between the
+// two modules should be more clearly defined.
static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
{
Paint *paint = paint_get_active(CTX_data_scene(C));
Brush *brush = paint_brush(paint);
+
ViewContext vc;
- float final_radius;
- float translation[2];
- float outline_alpha, *outline_col;
-
- /* set various defaults */
- translation[0] = x;
- translation[1] = y;
- outline_alpha = 0.5;
- outline_col = brush->add_col;
- final_radius = brush_size(brush);
- /* check that brush drawing is enabled */
- if(!(paint->flags & PAINT_SHOW_BRUSH))
- return;
+ /* sd->last_angle, sd->last_y, sd->last_x, and set_brush_size need to be
+ updated even if we are not drawing the cursor, so we cannot return
+ until they are updated. */
/* can't use stroke vc here because this will be called during
- mouse over too, not just during a stroke */
+ mouse over too, not just during a stroke */
view3d_set_viewcontext(C, &vc);
/* TODO: as sculpt and other paint modes are unified, this
special mode of drawing will go away */
- if(vc.obact->sculpt) {
+ if (vc.obact->sculpt) {
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
- float location[3];
- int pixel_radius, hit;
+
+ int pixel_radius, viewport[4];
+ float location[3], modelview[16], projection[16];
+
+ int hit;
+
+ int flip;
+ int sign;
+
+ float* col;
+ float alpha;
+
const float root_alpha = brush_alpha(brush);
float visual_strength = root_alpha*root_alpha;
- const float min_alpha = 0.20f;
- const float max_alpha = 0.80f;
- /* this is probably here so that rake takes into
+ const float min_alpha = sd->sculpting ? 0.10f : 0.20f;
+ const float max_alpha = sd->sculpting ? 0.40f : 0.80f;
+
+ float angle;
+
+ rctf quad;
+
+ float rake_delta[3];
+
+ /* XXX: This is here so that rake takes into
account the brush movements before the stroke
- starts, but this doesn't really belong in draw code
- (TODO) */
+ starts. Is there a cleaner way? */
{
const float u = 0.5f;
const float v = 1 - u;
@@ -583,7 +1289,7 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
const float dx = sd->last_x - x;
const float dy = sd->last_y - y;
- if(dx*dx + dy*dy >= r*r) {
+ if (dx*dx + dy*dy >= r*r) {
sd->last_angle = atan2(dx, dy);
sd->last_x = u*sd->last_x + v*x;
@@ -591,106 +1297,262 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
}
}
- /* test if brush is over the mesh */
- hit = sculpt_get_brush_geometry(C, x, y, &pixel_radius, location);
+ /* can leave now if brush size is not locked and
+ drawing brush is not enabled */
+ if(!brush_use_locked_size(brush) && !(paint->flags & PAINT_SHOW_BRUSH))
+ return;
- /* draw overlay */
- paint_draw_alpha_overlay(sd, brush, &vc, x, y);
+ hit = sculpt_get_brush_geometry(C, x, y, &pixel_radius, location, modelview, projection, viewport);
- if(brush_use_locked_size(brush))
+ if (brush_use_locked_size(brush))
brush_set_size(brush, pixel_radius);
+ /* XXX: need to determine if there is a condition that allows exiting
+ from this point */
+
/* check if brush is subtracting, use different color then */
- /* TODO: no way currently to know state of pen flip or
+ /* XXX: no way currently to know state of pen flip or
invert key modifier without starting a stroke */
- if((!(brush->flag & BRUSH_INVERTED) ^
- !(brush->flag & BRUSH_DIR_IN)) &&
- ELEM5(brush->sculpt_tool, SCULPT_TOOL_DRAW,
- SCULPT_TOOL_INFLATE, SCULPT_TOOL_CLAY,
- SCULPT_TOOL_PINCH, SCULPT_TOOL_CREASE))
- outline_col = brush->sub_col;
+ flip = brush->flag & BRUSH_INVERTED ? -1 : 1;
+
+ sign = flip * ((brush->flag & BRUSH_DIR_IN)? -1 : 1);
+
+ if (sign < 0 &&
+ ELEM6(brush->sculpt_tool,
+ SCULPT_TOOL_DRAW,
+ SCULPT_TOOL_GRAVITY,
+ SCULPT_TOOL_INFLATE,
+ SCULPT_TOOL_CLAY,
+ SCULPT_TOOL_PINCH,
+ SCULPT_TOOL_CREASE))
+ {
+ col = brush->sub_col;
+ }
+ else {
+ col = brush->add_col;
+ }
- /* only do if brush is over the mesh */
- if(hit)
- paint_cursor_on_hit(sd, brush, &vc, location, &visual_strength);
+ alpha = (paint->flags & PAINT_SHOW_BRUSH_ON_SURFACE) ? min_alpha + (visual_strength*(max_alpha-min_alpha)) : 0.50f;
+
+ if (sd->draw_anchored) {
+ quad.xmin = sd->anchored_initial_mouse[0]-sd->anchored_size - vc.ar->winrct.xmin;
+ quad.ymin = sd->anchored_initial_mouse[1]-sd->anchored_size - vc.ar->winrct.ymin;
+ quad.xmax = sd->anchored_initial_mouse[0]+sd->anchored_size - vc.ar->winrct.xmin;
+ quad.ymax = sd->anchored_initial_mouse[1]+sd->anchored_size - vc.ar->winrct.ymin;
+ }
+ else {
+ const int size= brush_size(brush);
+ quad.xmin= (float)x-size;
+ quad.ymin= (float)y-size;
+ quad.xmax= (float)x+size;
+ quad.ymax= (float)y+size;
+ }
+
+ if (brush->flag & BRUSH_RAKE) {
+ angle= sd->last_angle*(float)(180.0/M_PI);
+ }
+ else {
+ angle= sd->special_rotation*(float)(180.0/M_PI);
+ }
- /* don't show effect of strength past the soft limit */
- if(visual_strength > 1)
- visual_strength = 1;
+ angle -= brush->mtex.rot*(float)(180.0/M_PI);
- outline_alpha = ((paint->flags & PAINT_SHOW_BRUSH_ON_SURFACE) ?
- min_alpha + (visual_strength*(max_alpha-min_alpha)) : 0.50f);
+ update_rake_delta(rake_delta, location, x+vc.ar->winrct.xmin, y+vc.ar->winrct.ymin, &vc, CTX_data_active_object(C)->obmat);
- if(sd->draw_anchored) {
- final_radius = sd->anchored_size;
- translation[0] = sd->anchored_initial_mouse[0] - vc.ar->winrct.xmin;
- translation[1] = sd->anchored_initial_mouse[1] - vc.ar->winrct.ymin;
+ /* draw overlay */
+ if (!sd->sculpting &&
+ (!hit || !(paint->flags & PAINT_SHOW_BRUSH_ON_SURFACE)) &&
+ brush->flag & BRUSH_TEXTURE_OVERLAY)
+ {
+ if (!hit || brush->mtex.brush_map_mode == MTEX_MAP_MODE_FIXED) {
+ draw_fixed_overlay(sd, brush, &vc, &quad, angle);
+ }
+ else if (brush->mtex.brush_map_mode == MTEX_MAP_MODE_WRAP) {
+ float up_vec[3]= {0,1,0};
+ Object *ob= CTX_data_active_object(C);
+
+ // if raking, up is the direction of the mouse (grab delta),
+ if (brush->flag & BRUSH_RAKE) {
+ negate_v3_v3(up_vec, rake_delta);
+ draw_wrapped_overlay(modelview, projection, ob->size, viewport, location, brush_unprojected_radius(brush), sd, brush, &vc, 0, up_vec);
+ }
+ // otherwise, it is the view up vector
+ else {
+ mul_mat3_m4_v3(vc.rv3d->viewinv, up_vec);
+ draw_wrapped_overlay(modelview, projection, ob->size, viewport, location, brush_unprojected_radius(brush), sd, brush, &vc, angle, up_vec);
+ }
+ }
}
- }
- /* make lines pretty */
- glEnable(GL_BLEND);
- glEnable(GL_LINE_SMOOTH);
+ /* only do if brush is over the mesh */
+ if (hit) {
+ float projected_radius;
+ float unprojected_radius;
- /* set brush color */
- glColor4f(outline_col[0], outline_col[1], outline_col[2], outline_alpha);
+ if (sd->draw_pressure && (brush->flag & BRUSH_ALPHA_PRESSURE))
+ visual_strength *= sd->pressure_value;
- /* draw brush outline */
- glTranslatef(translation[0], translation[1], 0);
- glutil_draw_lined_arc(0.0, M_PI*2.0, final_radius, 40);
- glTranslatef(-translation[0], -translation[1], 0);
+ // don't show effect of strength past the soft limit
+ if (visual_strength > 1) visual_strength = 1;
- /* restore GL state */
- glDisable(GL_BLEND);
- glDisable(GL_LINE_SMOOTH);
-}
+ if(sd->draw_anchored) {
+ projected_radius = sd->anchored_size;
+ }
+ else {
+ if(brush->flag & BRUSH_ANCHORED)
+ projected_radius = 8;
+ else
+ projected_radius = brush_size(brush);
+ }
-/* if this is a tablet event, return tablet pressure and set *pen_flip
- to 1 if the eraser tool is being used, 0 otherwise */
-static float event_tablet_data(wmEvent *event, int *pen_flip)
-{
- int erasor = 0;
- float pressure = 1;
+ unprojected_radius =
+ paint_calc_object_space_radius(vc, location, projected_radius);
+
+ if (sd->draw_pressure && (brush->flag & BRUSH_SIZE_PRESSURE))
+ unprojected_radius *= sd->pressure_value;
+
+ if (!brush_use_locked_size(brush))
+ brush_set_unprojected_radius(brush, unprojected_radius);
+
+ /* can leave now if brush drawing is off */
+ if(!(paint->flags & PAINT_SHOW_BRUSH))
+ return;
+
+#ifdef WITH_ONSURFACEBRUSH
+ if (paint->flags & PAINT_SHOW_BRUSH_ON_SURFACE) {
+ const float max_thickness= 0.12;
+ const float min_thickness= 0.06;
+ const float thickness= 1.0 - min_thickness - visual_strength*max_thickness;
+ const float inner_radius= sd->draw_anchored ? unprojected_radius : unprojected_radius*thickness;
+ const float outer_radius= sd->draw_anchored ? 1.0f/thickness * unprojected_radius : unprojected_radius;
+ Object *ob= CTX_data_active_object(C);
+
+ float *location0 = sd->draw_anchored ? sd->anchored_location : location;
+
+ if (!sd->sculpting && brush->flag & BRUSH_TEXTURE_OVERLAY) {
+ if (brush->mtex.brush_map_mode == MTEX_MAP_MODE_FIXED)
+ ED_draw_fixed_overlay_on_surface(modelview, projection, ob->size, viewport, location0, outer_radius, sd, brush, &vc, &quad, angle);
+ else if (brush->mtex.brush_map_mode == MTEX_MAP_MODE_WRAP) {
+ float up_vec[3]= {0,1,0};
+
+ // if raking, up is the direction of the mouse (grab delta),
+ if (brush->flag & BRUSH_RAKE) {
+ negate_v3_v3(up_vec, rake_delta);
+ ED_draw_wrapped_overlay_on_surface(modelview, projection, ob->size, viewport, location0, outer_radius, sd, brush, &vc, 0, up_vec);
+ }
+ // otherwise, it is the view up vector
+ else {
+ mul_mat3_m4_v3(vc.rv3d->viewinv, up_vec);
+ ED_draw_wrapped_overlay_on_surface(modelview, projection, ob->size, viewport, location0, outer_radius, sd, brush, &vc, angle, up_vec);
+ }
+ }
+ }
- if(event->custom == EVT_DATA_TABLET) {
- wmTabletData *wmtab= event->customdata;
+ ED_draw_on_surface_cursor(modelview, projection, col, alpha, ob->size, viewport, location0, inner_radius, outer_radius, brush_size(brush));
- erasor = (wmtab->Active == EVT_TABLET_ERASER);
- pressure = (wmtab->Active != EVT_TABLET_NONE) ? wmtab->Pressure : 1;
+ {
+ float scale = 1.0f/(20.0f*(brush_size(brush)/100.0f));
+ draw_symmetric_brush_dots(sd, sd->draw_anchored ? sd->anchored_location : location0, col, modelview, projection, viewport,scale*inner_radius, brush_size(brush) >= 8);
+ }
+ }
+#endif
+ }
+
+#ifdef WITH_ONSURFACEBRUSH
+ if (!hit || !(paint->flags & PAINT_SHOW_BRUSH_ON_SURFACE)) {
+#endif
+ glPushAttrib(
+ GL_COLOR_BUFFER_BIT|
+ GL_CURRENT_BIT|
+ GL_DEPTH_BUFFER_BIT|
+ GL_ENABLE_BIT|
+ GL_LINE_BIT|
+ GL_POLYGON_BIT|
+ GL_STENCIL_BUFFER_BIT|
+ GL_TRANSFORM_BIT|
+ GL_VIEWPORT_BIT|
+ GL_TEXTURE_BIT);
+
+ glColor4f(col[0], col[1], col[2], alpha);
+
+ glEnable(GL_BLEND);
+
+ glEnable(GL_LINE_SMOOTH);
+
+ if (sd->draw_anchored) {
+ glTranslatef(sd->anchored_initial_mouse[0] - vc.ar->winrct.xmin, sd->anchored_initial_mouse[1] - vc.ar->winrct.ymin, 0.0f);
+ glutil_draw_lined_arc(0.0f, (float)(M_PI*2.0), sd->anchored_size, 40);
+ glTranslatef(-sd->anchored_initial_mouse[0] + vc.ar->winrct.xmin, -sd->anchored_initial_mouse[1] + vc.ar->winrct.xmin, 0.0f);
+ }
+ else {
+ glTranslatef((float)x, (float)y, 0.0f);
+ glutil_draw_lined_arc(0.0f, (float)(M_PI*2.0), brush_size(brush), 40);
+ glTranslatef(-(float)x, -(float)y, 0.0f);
+ }
+
+ glPopAttrib();
+#ifdef WITH_ONSURFACEBRUSH
+ }
+#endif
}
+ else {
+ if(!(paint->flags & PAINT_SHOW_BRUSH))
+ return;
- if(pen_flip)
- (*pen_flip) = erasor;
+ glColor4ubv(paint_get_active(CTX_data_scene(C))->paint_cursor_col);
+ glEnable(GL_LINE_SMOOTH);
+ glEnable(GL_BLEND);
- return pressure;
+ glTranslatef((float)x, (float)y, 0.0f);
+ glutil_draw_lined_arc(0.0, M_PI*2.0, brush_size(brush), 40); // XXX: make sure this the right size to use in non-sculpt modes
+ glTranslatef((float)-x, (float)-y, 0.0f);
+
+ glDisable(GL_BLEND);
+ glDisable(GL_LINE_SMOOTH);
+ }
}
/* Put the location of the next stroke dot into the stroke RNA and apply it to the mesh */
static void paint_brush_stroke_add_step(bContext *C, wmOperator *op, wmEvent *event, float mouse_in[2])
{
- Paint *paint = paint_get_active(CTX_data_scene(C));
- Brush *brush = paint_brush(paint);
- PaintStroke *stroke = op->customdata;
+ Paint *paint = paint_get_active(CTX_data_scene(C)); // XXX
+ Brush *brush = paint_brush(paint); // XXX
+
float mouse[3];
+
PointerRNA itemptr;
+
float location[3];
+
float pressure;
- int pen_flip;
+ int pen_flip;
- /* see if tablet affects event */
- pressure = event_tablet_data(event, &pen_flip);
+ ViewContext vc; // XXX
- /* TODO: as sculpt and other paint modes are unified, this
- separation will go away */
- if(stroke->vc.obact->sculpt) {
+ PaintStroke *stroke = op->customdata;
+
+ view3d_set_viewcontext(C, &vc); // XXX
+
+ /* Tablet */
+ if(event->custom == EVT_DATA_TABLET) {
+ wmTabletData *wmtab= event->customdata;
+
+ pressure = (wmtab->Active != EVT_TABLET_NONE) ? wmtab->Pressure : 1;
+ pen_flip = (wmtab->Active == EVT_TABLET_ERASER);
+ }
+ else {
+ pressure = 1;
+ pen_flip = 0;
+ }
+
+ // XXX: temporary check for sculpt mode until things are more unified
+ if (vc.obact->sculpt) {
float delta[3];
brush_jitter_pos(brush, mouse_in, mouse);
- /* XXX: meh, this is round about because
- brush_jitter_pos isn't written in the best way to
- be reused here */
- if(brush->flag & BRUSH_JITTER_PRESSURE) {
+ // XXX: meh, this is round about because brush_jitter_pos isn't written in the best way to be reused here
+ if (brush->flag & BRUSH_JITTER_PRESSURE) {
sub_v3_v3v3(delta, mouse, mouse_in);
mul_v3_fl(delta, pressure);
add_v3_v3v3(mouse, mouse_in, delta);
@@ -699,7 +1561,7 @@ static void paint_brush_stroke_add_step(bContext *C, wmOperator *op, wmEvent *ev
else
copy_v3_v3(mouse, mouse_in);
- /* TODO: can remove the if statement once all modes have this */
+ /* XXX: can remove the if statement once all modes have this */
if(stroke->get_location)
stroke->get_location(C, stroke, location, mouse);
else
@@ -708,10 +1570,10 @@ static void paint_brush_stroke_add_step(bContext *C, wmOperator *op, wmEvent *ev
/* Add to stroke */
RNA_collection_add(op->ptr, "stroke", &itemptr);
- RNA_float_set_array(&itemptr, "location", location);
- RNA_float_set_array(&itemptr, "mouse", mouse);
- RNA_boolean_set(&itemptr, "pen_flip", pen_flip);
- RNA_float_set(&itemptr, "pressure", pressure);
+ RNA_float_set_array(&itemptr, "location", location);
+ RNA_float_set_array(&itemptr, "mouse", mouse);
+ RNA_boolean_set (&itemptr, "pen_flip", pen_flip);
+ RNA_float_set (&itemptr, "pressure", pressure);
stroke->last_mouse_position[0] = mouse[0];
stroke->last_mouse_position[1] = mouse[1];
@@ -753,35 +1615,67 @@ static int paint_space_stroke(bContext *C, wmOperator *op, wmEvent *event, const
int cnt = 0;
if(paint_space_stroke_enabled(stroke->brush)) {
- float mouse[2];
float vec[2];
float length, scale;
+ float start_mouse[2];
- copy_v2_v2(mouse, stroke->last_mouse_position);
- sub_v2_v2v2(vec, final_mouse, mouse);
+ copy_v2_v2(start_mouse, stroke->last_mouse_position);
+ sub_v2_v2v2(vec, final_mouse, start_mouse);
- length = len_v2(vec);
+ length= len_v2(vec);
if(length > FLT_EPSILON) {
- int steps;
- int i;
- float pressure= 1.0f;
-
- /* XXX mysterious :) what has 'use size' do with this here... if you don't check for it, pressure fails */
- if(brush_use_size_pressure(stroke->brush))
- pressure = event_tablet_data(event, NULL);
-
- if(pressure > FLT_EPSILON) {
- scale = (brush_size(stroke->brush)*pressure*stroke->brush->spacing/50.0f) / length;
- if(scale > FLT_EPSILON) {
- mul_v2_fl(vec, scale);
-
- steps = (int)(1.0f / scale);
-
- for(i = 0; i < steps; ++i, ++cnt) {
- add_v2_v2(mouse, vec);
- paint_brush_stroke_add_step(C, op, event, mouse);
- }
+ float pressure = 1;
+ float dvec[2];
+ float mouse[2];
+
+ pressure = brush_use_size_pressure(stroke->brush) ? event_tablet_data(event, NULL) : 1.0;
+
+ scale = (brush_size(stroke->brush)*pressure*stroke->brush->spacing/50.0f) / length;
+
+ // XXX: this code checks for very small numbers, which could lead to
+ // a large number of iterations. perhaps this code should just
+ // bail out or break if numbers are too small. Investigate this.
+
+ if (scale < FLT_EPSILON) // make sure scale is big enough have an effect when added
+ scale= FLT_EPSILON;
+
+ if (stroke->brush->flag & BRUSH_ADAPTIVE_SPACE) {
+ float t= 0;
+
+ for(;;) {
+ float f;
+ float d;
+
+ f= stroke->brush->adaptive_space_factor;
+ CLAMP(f, 0.1f, 1); // make sure that adaptive strength never sets spacing to zero
+
+ d= f*scale;
+ CLAMP(d, FLT_EPSILON, scale); // d has to be big enough to increment t
+
+ t += d;
+
+ if (t > 1) break;
+
+ mul_v2_v2fl(dvec, vec, t);
+ add_v2_v2v2(mouse, start_mouse, dvec);
+
+ paint_brush_stroke_add_step(C, op, event, mouse);
+
+ cnt++;
+ }
+ }
+ else {
+ int i, steps;
+
+ copy_v2_v2(mouse, start_mouse);
+ mul_v2_fl(vec, scale);
+
+ steps = (int)(1.0f / scale);
+
+ for(i = 0; i < steps; ++i, ++cnt) {
+ add_v2_v2(mouse, vec);
+ paint_brush_stroke_add_step(C, op, event, mouse);
}
}
}
@@ -796,7 +1690,7 @@ PaintStroke *paint_stroke_new(bContext *C,
StrokeGetLocation get_location,
StrokeTestStart test_start,
StrokeUpdateStep update_step,
- StrokeDone done, int event_type)
+ StrokeDone done, int event_type)
{
PaintStroke *stroke = MEM_callocN(sizeof(PaintStroke), "PaintStroke");
@@ -809,7 +1703,7 @@ PaintStroke *paint_stroke_new(bContext *C,
stroke->update_step = update_step;
stroke->done = done;
stroke->event_type= event_type; /* for modal, return event */
-
+
return stroke;
}
diff --git a/source/blender/editors/sculpt_paint/paint_utils.c b/source/blender/editors/sculpt_paint/paint_utils.c
index 09f5c32bea0..6cabed19ea7 100644
--- a/source/blender/editors/sculpt_paint/paint_utils.c
+++ b/source/blender/editors/sculpt_paint/paint_utils.c
@@ -286,7 +286,10 @@ void BRUSH_OT_curve_preset(wmOperatorType *ot)
ot->exec= brush_curve_preset_exec;
ot->poll= brush_curve_preset_poll;
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+ // XXX: check the meaning of these flags, removed OPTYPE_REGISTER becauase
+ // that seems to mean display a panel in the lower left, but this operator
+ // as no meaningful UI to present the user in that area
+ ot->flag= OPTYPE_UNDO;
RNA_def_enum(ot->srna, "shape", prop_shape_items, CURVE_PRESET_SMOOTH, "Mode", "");
}
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index 20e74702067..2eec1bdbadb 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -34,7 +34,6 @@
* \ingroup edsculpt
*/
-
#include "MEM_guardedalloc.h"
#include "BLI_math.h"
@@ -93,6 +92,8 @@
#include <omp.h>
#endif
+static void calc_sculpt_normal(const Sculpt *sd, const SculptSession *ss, float an[3], PBVHNode **nodes, int totnode, float range);
+
void ED_sculpt_force_update(bContext *C)
{
Object *ob= CTX_data_active_object(C);
@@ -147,8 +148,10 @@ struct MultiresModifierData *sculpt_multires_active(Scene *scene, Object *ob)
if(!modifier_isEnabled(scene, md, eModifierMode_Realtime))
continue;
- if(mmd->sculptlvl > 0) return mmd;
- else return NULL;
+ if (mmd->sculptlvl > 0)
+ return mmd;
+ else
+ return NULL;
}
}
@@ -178,22 +181,29 @@ static int sculpt_modifiers_active(Scene *scene, Sculpt *sd, Object *ob)
Mesh *me= (Mesh*)ob->data;
MultiresModifierData *mmd= sculpt_multires_active(scene, ob);
- if(mmd) return 0;
+ if (mmd)
+ return 0;
- /* non-locked shaoe keys could be handled in the same way as deformed mesh */
- if((ob->shapeflag&OB_SHAPE_LOCK)==0 && me->key && ob->shapenr)
+ /* non-locked shape keys could be handled in the same way as deformed mesh */
+ if ((ob->shapeflag&OB_SHAPE_LOCK)==0 && me->key && ob->shapenr)
return 1;
md= modifiers_getVirtualModifierList(ob);
-
+
/* exception for shape keys because we can edit those */
for(; md; md= md->next) {
ModifierTypeInfo *mti = modifierType_getInfo(md->type);
- if(!modifier_isEnabled(scene, md, eModifierMode_Realtime)) continue;
- if(md->type==eModifierType_ShapeKey) continue;
+ if (!modifier_isEnabled(scene, md, eModifierMode_Realtime))
+ continue;
+
+ if (md->type==eModifierType_ShapeKey)
+ continue;
- if(mti->type==eModifierTypeType_OnlyDeform) return 1;
- else if((sd->flags & SCULPT_ONLY_DEFORM)==0) return 1;
+ if (mti->type==eModifierTypeType_OnlyDeform)
+ return 1;
+
+ if (!(sd->flags & SCULPT_ONLY_DEFORM))
+ return 1;
}
return 0;
@@ -261,6 +271,15 @@ typedef struct StrokeCache {
float last_rake[2]; /* Last location of updating rake rotation */
int original;
+ /* used for orienting brush local space when raking is enabled */
+ float orig_rake_location[3];
+ float old_rake_location[3];
+ float rake_delta[3];
+ float rake_delta_symmetry[3];
+
+ float brush_local_mat[4][4];
+ float symm_brush_local_mat[4][4];
+
float vertex_rotation;
char saved_active_brush_name[24];
@@ -268,14 +287,23 @@ typedef struct StrokeCache {
float plane_trim_squared;
+ float frontface_start, frontface_range;
+
rcti previous_r; /* previous redraw rectangle */
} StrokeCache;
+/* rotation direction is flipped in different symmetrical passes */
+static const int rotation_flip[8] = { 1, -1, -1, 1, -1, 1, 1, -1 };
+
+
/*** BVH Tree ***/
/* Get a screen-space rectangle of the modified area */
-static int sculpt_get_redraw_rect(ARegion *ar, RegionView3D *rv3d,
- Object *ob, rcti *rect)
+static int sculpt_get_redraw_rect(
+ ARegion *ar,
+ RegionView3D *rv3d,
+ Object *ob,
+ rcti *rect)
{
PBVH *pbvh= ob->sculpt->pbvh;
float bb_min[3], bb_max[3], pmat[4][4];
@@ -309,22 +337,30 @@ static int sculpt_get_redraw_rect(ARegion *ar, RegionView3D *rv3d,
}
}
}
-
+
if (rect->xmin < rect->xmax && rect->ymin < rect->ymax) {
/* expand redraw rect with redraw rect from previous step to prevent
partial-redraw issues caused by fast strokes. This is needed here (not in sculpt_flush_update)
as it was before because redraw rectangle should be the same in both of
optimized PBVH draw function and 3d view redraw (if not -- some mesh parts could
disapper from screen (sergey) */
- SculptSession *ss = ob->sculpt;
- if (ss->cache) {
- if (!BLI_rcti_is_empty(&ss->cache->previous_r))
- BLI_union_rcti(rect, &ss->cache->previous_r);
+ if (ob->sculpt->cache) {
+ rcti* previous_r = &(ob->sculpt->cache->previous_r);
+
+ if (!BLI_rcti_is_empty(previous_r))
+ BLI_union_rcti(rect, previous_r);
}
return 1;
}
+ else {
+ return rect->xmin < rect->xmax && rect->ymin < rect->ymax;
+ }
+}
+
+ return 1;
+ }
return 0;
}
@@ -367,17 +403,27 @@ void sculpt_get_redraw_planes(float planes[4][4], ARegion *ar,
/************************ Brush Testing *******************/
+// XXX: consider rewriting not to use struct
typedef struct SculptBrushTest {
float radius_squared;
float location[3];
float dist;
} SculptBrushTest;
-static void sculpt_brush_test_init(SculptSession *ss, SculptBrushTest *test)
+static void sculpt_brush_test_init(const SculptSession *ss, SculptBrushTest *test)
{
test->radius_squared= ss->cache->radius_squared;
copy_v3_v3(test->location, ss->cache->location);
- test->dist= 0.0f; /* just for initialize */
+
+ /* XXX: no need to initialize, consider not using struct at all and
+ trusting compiler to properly inline arguments */
+ //test->dist = -1;
+}
+
+static void sculpt_brush_range_test_init(const SculptSession *ss, SculptBrushTest *test, float range)
+{
+ test->radius_squared= ss->cache->radius_squared*range*range;
+ copy_v3_v3(test->location, ss->cache->location);
}
static int sculpt_brush_test(SculptBrushTest *test, float co[3])
@@ -411,7 +457,7 @@ static int sculpt_brush_test_fast(SculptBrushTest *test, float co[3])
return len_squared_v3v3(co, test->location) <= test->radius_squared;
}
-static int sculpt_brush_test_cube(SculptBrushTest *test, float co[3], float local[4][4])
+static int sculpt_brush_test_cube(SculptBrushTest *test, float *fade, float co[3], float local[4][4])
{
static const float side = 0.70710678118654752440084436210485; // sqrt(.5);
@@ -424,7 +470,18 @@ static int sculpt_brush_test_cube(SculptBrushTest *test, float co[3], float loca
local_co[2] = fabs(local_co[2]);
if (local_co[0] <= side && local_co[1] <= side && local_co[2] <= side) {
- test->dist = MAX3(local_co[0], local_co[1], local_co[2]) / side;
+ float cmin, cmax;
+ int i;
+
+ for (i= 0; i < 3; i++) {
+ cmin = MIN2(local_co[0]-0.1f, side);
+ cmax = MIN2(local_co[0]+0.1f, side);
+
+ (*fade) *= (10*cmax)-(10*cmin);
+ }
+
+
+ test->dist = len_v3v3(co, test->location);
return 1;
}
@@ -433,24 +490,42 @@ static int sculpt_brush_test_cube(SculptBrushTest *test, float co[3], float loca
}
}
-static float frontface(Brush *brush, float sculpt_normal[3], short no[3], float fno[3])
+static float frontface(Brush *brush, float start, float range, float sculpt_normal[3], short no[3])
{
if (brush->flag & BRUSH_FRONTFACE) {
- float dot;
+ float angle;
+ float tmp[3];
- if (no) {
- float tmp[3];
+ normal_short_to_float_v3(tmp, no);
+ angle= angle_normalized_v3v3(tmp, sculpt_normal);
- normal_short_to_float_v3(tmp, no);
- dot= dot_v3v3(tmp, sculpt_normal);
+ if (angle >= start+range) {
+ return 0;
}
- else {
- dot= dot_v3v3(fno, sculpt_normal);
+ else if (angle > start) {
+ return (start+range-angle) / range;
}
- return dot > 0 ? dot : 0;
+ }
+
+ return 1;
+}
+
+static void set_adaptive_space_factor(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode, float an_in[3])
+{
+ Brush *brush = paint_brush(&(sd->paint));
+
+ if (brush->flag & BRUSH_ADAPTIVE_SPACE) {
+ float an[3];
+
+ if (an_in)
+ copy_v3_v3(an, an_in);
+ else
+ calc_sculpt_normal(sd, ss, an, nodes, totnode, brush->sculpt_plane_range);
+
+ brush->adaptive_space_factor= dot_v3v3(an, ss->cache->view_normal);
}
else {
- return 1;
+ brush->adaptive_space_factor= 1;
}
}
@@ -486,7 +561,7 @@ static int sculpt_brush_test_cyl(SculptBrushTest *test, float co[3], float locat
static float overlapped_curve(Brush* br, float x)
{
int i;
- const int n = 100 / br->spacing;
+ const int n = 100 / ((br->flag&BRUSH_ADAPTIVE_SPACE ? br->adaptive_space_factor : 1.0f) * br->spacing);
const float h = br->spacing / 50.0f;
const float x0 = x-1;
@@ -550,7 +625,7 @@ static float calc_overlap(StrokeCache *cache, const char symm, const char axis,
//flip_coord(mirror, cache->traced_location, symm);
flip_coord(mirror, cache->true_location, symm);
- if(axis != 0) {
+ if(axis >= 'X' && axis <= 'Z') {
float mat[4][4]= MAT4_UNITY;
rotate_m4(mat, axis, angle);
mul_m4_v3(mat, mirror);
@@ -560,7 +635,7 @@ static float calc_overlap(StrokeCache *cache, const char symm, const char axis,
distsq = len_squared_v3v3(mirror, cache->true_location);
if (distsq <= 4.0f*(cache->radius_squared))
- return (2.0f*(cache->radius) - sqrtf(distsq)) / (2.0f*(cache->radius));
+ return (2.0f*(cache->radius) - sqrt(distsq)) / (2.0f*(cache->radius));
else
return 0;
}
@@ -581,7 +656,9 @@ static float calc_radial_symmetry_feather(Sculpt *sd, StrokeCache *cache, const
static float calc_symmetry_feather(Sculpt *sd, StrokeCache* cache)
{
- if (sd->flags & SCULPT_SYMMETRY_FEATHER) {
+ Brush *brush= paint_brush(&(sd->paint));
+
+ if (brush->flag & BRUSH_SYMMETRY_FEATHER) {
float overlap;
int symm = cache->symmetry;
int i;
@@ -625,8 +702,9 @@ static float brush_strength(Sculpt *sd, StrokeCache *cache, float feather)
switch(brush->sculpt_tool){
case SCULPT_TOOL_CLAY:
- case SCULPT_TOOL_CLAY_TUBES:
+ case SCULPT_TOOL_CLAY_STRIPS:
case SCULPT_TOOL_DRAW:
+ case SCULPT_TOOL_GRAVITY:
case SCULPT_TOOL_LAYER:
return alpha * flip * pressure * overlap * feather;
@@ -684,7 +762,98 @@ static float brush_strength(Sculpt *sd, StrokeCache *cache, float feather)
}
}
+/* Texture Sampling */
+
+static void set_brush_local_mat(const Sculpt *sd, const SculptSession *ss, const Brush *brush, PBVHNode **nodes, int totnode, float *an_in)
+{
+ float tmat[4][4];
+
+ if (brush->mtex.brush_map_mode == MTEX_MAP_MODE_WRAP) {
+ if (ss->cache->mirror_symmetry_pass == 0 && ss->cache->radial_symmetry_pass == 0) {
+ float mat[4][4];
+ float scale[4][4];
+ float an[3];
+
+ if (an_in)
+ copy_v3_v3(an, an_in);
+ else
+ calc_sculpt_normal(sd, ss, an, nodes, totnode, brush->sculpt_plane_range);
+
+ if (brush->flag & BRUSH_RAKE) {
+ cross_v3_v3v3(mat[0], an, ss->cache->rake_delta_symmetry); mat[0][3] = 0;
+ }
+ else {
+ float up[4]= {0,1,0,0}; // homogeneous up vector
+
+ mul_m4_v4(ss->cache->vc->rv3d->viewinv, up);
+ cross_v3_v3v3(mat[0], up, an); mat[0][3] = 0;
+ }
+
+ cross_v3_v3v3(mat[1], an, mat[0]); mat[1][3] = 0;
+ copy_v3_v3(mat[2], an); mat[2][3] = 0;
+ copy_v3_v3(mat[3], ss->cache->location); mat[3][3] = 1;
+ normalize_m4(mat);
+ scale_m4_fl(scale, ss->cache->radius);
+ mul_m4_m4m4(tmat, scale, mat);
+ invert_m4_m4(ss->cache->brush_local_mat, tmat);
+
+ copy_m4_m4(ss->cache->symm_brush_local_mat, ss->cache->brush_local_mat);
+ }
+ else {
+ copy_m4_m4(tmat, ss->cache->symm_brush_local_mat);
+ mul_m4_m4m4(ss->cache->symm_brush_local_mat, tmat, ss->cache->symm_rot_mat);
+
+ flip_coord(ss->cache->symm_brush_local_mat[0], ss->cache->brush_local_mat[0], ss->cache->mirror_symmetry_pass);
+ flip_coord(ss->cache->symm_brush_local_mat[1], ss->cache->brush_local_mat[1], ss->cache->mirror_symmetry_pass);
+ flip_coord(ss->cache->symm_brush_local_mat[2], ss->cache->brush_local_mat[2], ss->cache->mirror_symmetry_pass);
+ flip_coord(ss->cache->symm_brush_local_mat[3], ss->cache->brush_local_mat[3], ss->cache->mirror_symmetry_pass);
+ }
+ }
+}
+
+#if 0
+
+/* Get a pixel from the texcache at (px, py) */
+static unsigned char get_texcache_pixel(const SculptSession *ss, int px, int py)
+{
+ unsigned *p;
+ p = ss->texcache + py * ss->texcache_side + px;
+ return ((unsigned char*)(p))[0];
+}
+
+static float get_texcache_pixel_bilinear(const SculptSession *ss, float u, float v)
+{
+ unsigned x, y, x2, y2;
+ const int tc_max = ss->texcache_side - 1;
+ float urat, vrat, uopp;
+
+ if(u < 0) u = 0;
+ else if(u >= ss->texcache_side) u = tc_max;
+ if(v < 0) v = 0;
+ else if(v >= ss->texcache_side) v = tc_max;
+
+ x = floor(u);
+ y = floor(v);
+ x2 = x + 1;
+ y2 = y + 1;
+
+ if(x2 > ss->texcache_side) x2 = tc_max;
+ if(y2 > ss->texcache_side) y2 = tc_max;
+
+ urat = u - x;
+ vrat = v - y;
+ uopp = 1 - urat;
+
+ return ((get_texcache_pixel(ss, x, y) * uopp +
+ get_texcache_pixel(ss, x2, y) * urat) * (1 - vrat) +
+ (get_texcache_pixel(ss, x, y2) * uopp +
+ get_texcache_pixel(ss, x2, y2) * urat) * vrat) / 255.0;
+}
+
+#endif
+
/* Return a multiplier for brush strength on a particular vertex. */
+/* XXX: a lot of this code is the same as code in paint_stroke for loading the overlay */
static float tex_strength(SculptSession *ss, Brush *br, float *point, const float len)
{
MTex *mtex = &br->mtex;
@@ -699,9 +868,9 @@ static float tex_strength(SculptSession *ss, Brush *br, float *point, const floa
/* Get strength by feeding the vertex
location directly into a texture */
externtex(mtex, point, &avg,
- &jnk, &jnk, &jnk, &jnk, 0);
+ &jnk, &jnk, &jnk, &jnk, 0); // XXX: minor, is last argument a pointer?
}
- else if(ss->texcache) {
+ else if(ELEM(mtex->brush_map_mode, MTEX_MAP_MODE_FIXED, MTEX_MAP_MODE_TILED)) {
float rotation = -mtex->rot;
float x, y, point_2d[3];
float radius;
@@ -734,7 +903,7 @@ static float tex_strength(SculptSession *ss, Brush *br, float *point, const floa
leave the coordinates relative to the screen */
{
radius = brush_size(br); // use unadjusted size for tiled mode
-
+
x = point_2d[0] - ss->cache->vc->ar->winrct.xmin;
y = point_2d[1] - ss->cache->vc->ar->winrct.ymin;
}
@@ -746,7 +915,7 @@ static float tex_strength(SculptSession *ss, Brush *br, float *point, const floa
x -= 0.5f;
y -= 0.5f;
}
-
+
x *= ss->cache->vc->ar->winx / radius;
y *= ss->cache->vc->ar->winy / radius;
@@ -754,7 +923,7 @@ static float tex_strength(SculptSession *ss, Brush *br, float *point, const floa
the texture is not rotated by skipping the calls to
atan2, sqrtf, sin, and cos. */
if (rotation > 0.001f || rotation < -0.001f) {
- const float angle = atan2f(y, x) + rotation;
+ const float angle = atan2(y, x) + rotation;
const float flen = sqrtf(x*x + y*y);
x = flen * cosf(angle);
@@ -769,6 +938,49 @@ static float tex_strength(SculptSession *ss, Brush *br, float *point, const floa
avg = paint_get_tex_pixel(br, x, y);
}
+ // XXX: redunancy here can be refactored once this has been debugged
+ else /* mtex->brush_map_mode == MTEX_MAP_MODE_WRAP */{
+ float rotation = -mtex->rot;
+ float x, y, point_2d[3];
+
+ /* if the active area is being applied for symmetry, flip it
+ across the symmetry axis and rotate it back to the orignal
+ position in order to project it. This insures that the
+ brush texture will be oriented correctly. */
+
+ flip_coord(point_2d, point, ss->cache->mirror_symmetry_pass);
+
+ if (ss->cache->radial_symmetry_pass)
+ mul_m4_v3(ss->cache->symm_rot_mat_inv, point_2d);
+
+ mul_m4_v3(ss->cache->symm_brush_local_mat, point_2d);
+
+ x = point_2d[0];
+ y = point_2d[1];
+
+ if (br->flag & BRUSH_RANDOM_ROTATION)
+ rotation += ss->cache->special_rotation;
+
+ /* it is probably worth optimizing for those cases where
+ the texture is not rotated by skipping the calls to
+ atan2, sqrtf, sin, and cos. */
+
+ if (rotation > 0.001 || rotation < -0.001) {
+ const float angle = (atan2(y, x) + rotation) * rotation_flip[ss->cache->mirror_symmetry_pass];
+ const float flen = sqrtf(x*x + y*y);
+
+ x = flen * cos(angle);
+ y = flen * sin(angle);
+ }
+
+ x *= br->mtex.size[0];
+ y *= br->mtex.size[1];
+
+ x += br->mtex.ofs[0];
+ y += br->mtex.ofs[1];
+
+ avg = paint_get_tex_pixel(br, x, y);
+ }
avg += br->texture_sample_bias;
@@ -836,7 +1048,7 @@ static void add_norm_if(float view_vec[3], float out[3], float out_flip[3], floa
}
}
-static void calc_area_normal(Sculpt *sd, Object *ob, float an[3], PBVHNode **nodes, int totnode)
+static void calc_area_normal(const Sculpt *sd, const Object *ob, float an[3], PBVHNode **nodes, int totnode, float range)
{
SculptSession *ss = ob->sculpt;
int n;
@@ -844,7 +1056,7 @@ static void calc_area_normal(Sculpt *sd, Object *ob, float an[3], PBVHNode **nod
float out_flip[3] = {0.0f, 0.0f, 0.0f};
(void)sd; /* unused w/o openmp */
-
+
zero_v3(an);
#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
@@ -856,7 +1068,7 @@ static void calc_area_normal(Sculpt *sd, Object *ob, float an[3], PBVHNode **nod
float private_out_flip[3] = {0.0f, 0.0f, 0.0f};
unode = sculpt_undo_push_node(ob, nodes[n]);
- sculpt_brush_test_init(ss, &test);
+ sculpt_brush_range_test_init(ss, &test, range);
if(ss->cache->original) {
BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
@@ -901,7 +1113,7 @@ static void calc_area_normal(Sculpt *sd, Object *ob, float an[3], PBVHNode **nod
/* This initializes the faces to be moved for this sculpt for draw/layer/flatten; then it
finds average normal for all active vertices - note that this is called once for each mirroring direction */
-static void calc_sculpt_normal(Sculpt *sd, Object *ob, float an[3], PBVHNode **nodes, int totnode)
+static void calc_sculpt_normal(const Sculpt *sd, const Object *ob, float an[3], PBVHNode **nodes, int totnode, float range)
{
SculptSession *ss = ob->sculpt;
Brush *brush = paint_brush(&sd->paint);
@@ -934,7 +1146,7 @@ static void calc_sculpt_normal(Sculpt *sd, Object *ob, float an[3], PBVHNode **n
break;
case SCULPT_DISP_DIR_AREA:
- calc_area_normal(sd, ob, an, nodes, totnode);
+ calc_area_normal(sd, ob, an, nodes, totnode, range);
default:
break;
@@ -963,8 +1175,10 @@ static void neighbor_average(SculptSession *ss, float avg[3], const unsigned ver
/* Don't modify corner vertices */
if(ncount==1) {
- if(ss->deform_cos) copy_v3_v3(avg, ss->deform_cos[vert]);
- else copy_v3_v3(avg, ss->mvert[vert].co);
+ if (ss->deform_cos)
+ copy_v3_v3(avg, ss->deform_cos[vert]);
+ else
+ copy_v3_v3(avg, ss->mvert[vert].co);
return;
}
@@ -981,8 +1195,11 @@ static void neighbor_average(SculptSession *ss, float avg[3], const unsigned ver
for(i=0; i<(f->v4?4:3); ++i) {
if(i != skip && (ncount!=2 || BLI_countlist(&ss->fmap[(&f->v1)[i]]) <= 2)) {
- if(ss->deform_cos) add_v3_v3(avg, ss->deform_cos[(&f->v1)[i]]);
- else add_v3_v3(avg, ss->mvert[(&f->v1)[i]].co);
+ if (ss->deform_cos)
+ add_v3_v3(avg, ss->deform_cos[(&f->v1)[i]]);
+ else
+ add_v3_v3(avg, ss->mvert[(&f->v1)[i]].co);
+
++total;
}
}
@@ -990,11 +1207,14 @@ static void neighbor_average(SculptSession *ss, float avg[3], const unsigned ver
node= node->next;
}
- if(total>0)
+ if (total > 0) {
mul_v3_fl(avg, 1.0f / total);
+ }
else {
- if(ss->deform_cos) copy_v3_v3(avg, ss->deform_cos[vert]);
- else copy_v3_v3(avg, ss->mvert[vert].co);
+ if (ss->deform_cos)
+ copy_v3_v3(avg, ss->deform_cos[vert]);
+ else
+ copy_v3_v3(avg, ss->mvert[vert].co);
}
}
@@ -1003,14 +1223,20 @@ static void do_mesh_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode *node,
Brush *brush = paint_brush(&sd->paint);
PBVHVertexIter vd;
SculptBrushTest test;
-
+
CLAMP(bstrength, 0.0f, 1.0f);
sculpt_brush_test_init(ss, &test);
BLI_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE) {
+ short (*origno)[3];
+ SculptUndoNode *unode;
+
+ unode= sculpt_undo_push_node(ss, node);
+ origno= unode->no;
+
if(sculpt_brush_test(&test, vd.co)) {
- const float fade = bstrength*tex_strength(ss, brush, vd.co, test.dist)*frontface(brush, ss->cache->view_normal, vd.no, vd.fno);
+ const float fade = bstrength*tex_strength(ss, brush, vd.co, test.dist)*frontface(brush, ss->cache->frontface_start, ss->cache->frontface_range, ss->cache->view_normal, origno[vd.i]);
float avg[3], val[3];
neighbor_average(ss, avg, vd.vert_indices[vd.i]);
@@ -1036,7 +1262,13 @@ static void do_multires_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode *no
DMGridAdjacency *gridadj, *adj;
float (*tmpgrid)[3], (*tmprow)[3];
int v1, v2, v3, v4;
- int *grid_indices, totgrid, gridsize, i, x, y;
+ int *grid_indices, totgrid, gridsize, i, k, x, y;
+
+ short (*origno)[3];
+ SculptUndoNode *unode;
+
+ unode= sculpt_undo_push_node(ss, node);
+ origno= unode->no;
sculpt_brush_test_init(ss, &test);
@@ -1051,7 +1283,7 @@ static void do_multires_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode *no
tmprow= MEM_mallocN(sizeof(float)*3*gridsize, "tmprow");
}
- for(i = 0; i < totgrid; ++i) {
+ for(i = 0, k= 0; i < totgrid; ++i) {
data = griddata[grid_indices[i]];
adj = &gridadj[grid_indices[i]];
@@ -1080,8 +1312,8 @@ static void do_multires_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode *no
}
/* blend with existing coordinates */
- for(y = 0; y < gridsize; ++y) {
- for(x = 0; x < gridsize; ++x) {
+ for(y= 0; y < gridsize; ++y) {
+ for(x= 0; x < gridsize; ++x, ++k) {
float *co;
float *fno;
int index;
@@ -1103,7 +1335,7 @@ static void do_multires_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode *no
fno= data[index].no;
if(sculpt_brush_test(&test, co)) {
- const float fade = bstrength*tex_strength(ss, brush, co, test.dist)*frontface(brush, ss->cache->view_normal, NULL, fno);
+ const float fade = bstrength*tex_strength(ss, brush, co, test.dist)*frontface(brush, ss->cache->frontface_start, ss->cache->frontface_range, ss->cache->view_normal, origno[k]);
float *avg, val[3];
float n;
@@ -1144,15 +1376,21 @@ static void smooth(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float
const float fract = 1.0f/max_iterations;
int iteration, n, count;
float last;
+ Brush *brush = paint_brush(&sd->paint);
CLAMP(bstrength, 0, 1);
count = (int)(bstrength*max_iterations);
last = max_iterations*(bstrength - count*fract);
+ set_brush_local_mat(sd, ob, brush, nodes, totnode, NULL);
+
+ set_adaptive_space_factor(sd, ob, nodes, totnode, NULL);
+
for(iteration = 0; iteration <= count; ++iteration) {
#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
for(n=0; n<totnode; n++) {
+
if(ss->multires) {
do_multires_smooth_brush(sd, ss, nodes[n], iteration != count ? 1.0f : last);
}
@@ -1167,22 +1405,25 @@ static void smooth(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float
static void do_smooth_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
{
- SculptSession *ss = ob->sculpt;
- smooth(sd, ob, nodes, totnode, ss->cache->bstrength);
+ smooth(sd, ob, nodes, totnode, ob->sculpt->cache->bstrength);
}
static void do_draw_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
{
SculptSession *ss = ob->sculpt;
Brush *brush = paint_brush(&sd->paint);
- float offset[3], area_normal[3];
+ float offset[3], an[3];
float bstrength= ss->cache->bstrength;
int n;
- calc_sculpt_normal(sd, ob, area_normal, nodes, totnode);
-
+ calc_sculpt_normal(sd, ob, an, nodes, totnode, brush->sculpt_plane_range);
+
+ set_brush_local_mat(sd, ob, brush, NULL, 0, an);
+
+ set_adaptive_space_factor(sd, ob, NULL, 0, an);
+
/* offset with as much as possible factored in already */
- mul_v3_v3fl(offset, area_normal, ss->cache->radius);
+ mul_v3_v3fl(offset, an, ss->cache->radius);
mul_v3_v3(offset, ss->cache->scale);
mul_v3_fl(offset, bstrength);
@@ -1192,6 +1433,11 @@ static void do_draw_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
PBVHVertexIter vd;
SculptBrushTest test;
float (*proxy)[3];
+ short (*origno)[3];
+ SculptUndoNode *unode;
+
+ unode= sculpt_undo_push_node(ob, nodes[n]);
+ origno= unode->no;
proxy= BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
@@ -1199,9 +1445,9 @@ static void do_draw_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
if (sculpt_brush_test(&test, vd.co)) {
- //if(sculpt_brush_test_cyl(&test, vd.co, ss->cache->location, area_normal)) {
+ //if(sculpt_brush_test_cyl(&test, vd.co, ss->cache->location, an)) {
/* offset vertex */
- float fade = tex_strength(ss, brush, vd.co, test.dist)*frontface(brush, area_normal, vd.no, vd.fno);
+ float fade = tex_strength(ss, brush, vd.co, test.dist)*frontface(brush, ss->cache->frontface_start, ss->cache->frontface_range, an, origno[vd.i]);
mul_v3_v3fl(proxy[vd.i], offset, fade);
@@ -1213,22 +1459,85 @@ static void do_draw_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
}
}
+static void gravity(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float bstrength)
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = paint_brush(&sd->paint);
+ float offset[3], an[3];
+ int n;
+ float gravity[3];
+
+ gravity[0]= gravity[1]= 0;
+ gravity[2]= -ss->cache->radius;
+
+ calc_sculpt_normal(sd, ob, an, nodes, totnode, brush->sculpt_plane_range);
+
+ set_brush_local_mat(sd, ob, brush, NULL, 0, an);
+
+ set_adaptive_space_factor(sd, ob, NULL, 0, an);
+
+ /* offset with as much as possible factored in already */
+ mul_v3_v3fl(offset, gravity, ss->cache->radius);
+ mul_v3_v3(offset, ss->cache->scale);
+ mul_v3_fl(offset, bstrength);
+
+ /* threaded loop over nodes */
+ #pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
+ for(n=0; n<totnode; n++) {
+ PBVHVertexIter vd;
+ SculptBrushTest test;
+ float (*proxy)[3];
+ short (*origno)[3];
+ SculptUndoNode *unode;
+
+ unode= sculpt_undo_push_node(ob, nodes[n]);
+ origno= unode->no;
+
+ proxy= BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
+
+ sculpt_brush_test_init(ss, &test);
+
+ BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if (sculpt_brush_test(&test, vd.co)) {
+ //if(sculpt_brush_test_cyl(&test, vd.co, ss->cache->location, an)) {
+ /* offset vertex */
+ float fade = tex_strength(ss, brush, vd.co, test.dist)*frontface(brush, ss->cache->frontface_start, ss->cache->frontface_range, an, origno[vd.i]);
+
+ mul_v3_v3fl(proxy[vd.i], offset, fade);
+
+ if(vd.mvert)
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BLI_pbvh_vertex_iter_end;
+ }
+}
+
+static void do_gravity_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode)
+{
+ gravity(sd, ss, nodes, totnode, ss->cache->bstrength);
+}
+
static void do_crease_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
{
SculptSession *ss = ob->sculpt;
Brush *brush = paint_brush(&sd->paint);
- float offset[3], area_normal[3];
+ float offset[3], an[3];
float bstrength= ss->cache->bstrength;
float flippedbstrength, crease_correction;
int n;
- calc_sculpt_normal(sd, ob, area_normal, nodes, totnode);
-
+ calc_sculpt_normal(sd, ob, an, nodes, totnode, brush->sculpt_plane_range);
+
+ set_brush_local_mat(sd, ob, brush, NULL, 0, an);
+
+ set_adaptive_space_factor(sd, ob, NULL, 0, an);
+
/* offset with as much as possible factored in already */
- mul_v3_v3fl(offset, area_normal, ss->cache->radius);
+ mul_v3_v3fl(offset, an, ss->cache->radius);
mul_v3_v3(offset, ss->cache->scale);
mul_v3_fl(offset, bstrength);
-
+
/* we divide out the squared alpha and multiply by the squared crease to give us the pinch strength */
if(brush_alpha(brush) > 0.0f)
@@ -1247,6 +1556,11 @@ static void do_crease_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod
PBVHVertexIter vd;
SculptBrushTest test;
float (*proxy)[3];
+ short (*origno)[3];
+ SculptUndoNode *unode;
+
+ unode= sculpt_undo_push_node(ob, nodes[n]);
+ origno= unode->no;
proxy= BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
@@ -1255,7 +1569,7 @@ static void do_crease_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod
BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
if(sculpt_brush_test(&test, vd.co)) {
/* offset vertex */
- const float fade = tex_strength(ss, brush, vd.co, test.dist)*frontface(brush, area_normal, vd.no, vd.fno);
+ const float fade = tex_strength(ss, brush, vd.co, test.dist)*frontface(brush, ss->cache->frontface_start, ss->cache->frontface_start, an, origno[vd.i]);
float val1[3];
float val2[3];
@@ -1284,11 +1598,20 @@ static void do_pinch_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
float bstrength= ss->cache->bstrength;
int n;
+ set_brush_local_mat(sd, ob, brush, nodes, totnode, NULL);
+
+ set_adaptive_space_factor(sd, ob, nodes, totnode, NULL);
+
#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
for(n=0; n<totnode; n++) {
PBVHVertexIter vd;
SculptBrushTest test;
float (*proxy)[3];
+ short (*origno)[3];
+ SculptUndoNode *unode;
+
+ unode= sculpt_undo_push_node(ob, nodes[n]);
+ origno= unode->no;
proxy= BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
@@ -1296,7 +1619,7 @@ static void do_pinch_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
if(sculpt_brush_test(&test, vd.co)) {
- float fade = bstrength*tex_strength(ss, brush, vd.co, test.dist)*frontface(brush, ss->cache->view_normal, vd.no, vd.fno);
+ float fade = bstrength*tex_strength(ss, brush, vd.co, test.dist)*frontface(brush, ss->cache->frontface_start, ss->cache->frontface_range, ss->cache->view_normal, origno[vd.i]);
float val[3];
sub_v3_v3v3(val, test.location, vd.co);
@@ -1304,7 +1627,7 @@ static void do_pinch_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
if(vd.mvert)
vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
+ }
}
BLI_pbvh_vertex_iter_end;
}
@@ -1319,6 +1642,8 @@ static void do_grab_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
int n;
float len;
+ // XXX: this probably needs to be done for thumb and rotate as well
+ // but not for nudge or snakehook
if (brush->normal_weight > 0 || brush->flag & BRUSH_FRONTFACE) {
int cache= 1;
/* grab brush requires to test on original data */
@@ -1326,7 +1651,11 @@ static void do_grab_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
calc_sculpt_normal(sd, ob, an, nodes, totnode);
SWAP(int, ss->cache->original, cache);
}
-
+
+ set_brush_local_mat(sd, ob, brush, nodes, totnode, brush->normal_weight > 0 ? an : NULL);
+
+ set_adaptive_space_factor(sd, ob, nodes, totnode, brush->normal_weight > 0 ? an : NULL);
+
copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry);
len = len_v3(grab_delta);
@@ -1356,7 +1685,7 @@ static void do_grab_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
if(sculpt_brush_test(&test, origco[vd.i])) {
- const float fade = bstrength*tex_strength(ss, brush, origco[vd.i], test.dist)*frontface(brush, an, origno[vd.i], NULL);
+ const float fade = bstrength*tex_strength(ss, brush, origco[vd.i], test.dist)*frontface(brush, ss->cache->frontface_start, ss->cache->frontface_range, an, origno[vd.i]);
mul_v3_v3fl(proxy[vd.i], grab_delta, fade);
@@ -1380,7 +1709,11 @@ static void do_nudge_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry);
- calc_sculpt_normal(sd, ob, an, nodes, totnode);
+ calc_sculpt_normal(sd, ob, an, nodes, totnode, brush->sculpt_plane_range);
+
+ set_brush_local_mat(sd, ob, brush, NULL, 0, an);
+
+ set_adaptive_space_factor(sd, ob, NULL, 0, an);
cross_v3_v3v3(tmp, an, grab_delta);
cross_v3_v3v3(cono, tmp, an);
@@ -1390,6 +1723,11 @@ static void do_nudge_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
PBVHVertexIter vd;
SculptBrushTest test;
float (*proxy)[3];
+ short (*origno)[3];
+ SculptUndoNode *unode;
+
+ unode= sculpt_undo_push_node(ob, nodes[n]);
+ origno= unode->no;
proxy= BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
@@ -1397,7 +1735,7 @@ static void do_nudge_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
if(sculpt_brush_test(&test, vd.co)) {
- const float fade = bstrength*tex_strength(ss, brush, vd.co, test.dist)*frontface(brush, an, vd.no, vd.fno);
+ const float fade = bstrength*tex_strength(ss, brush, vd.co, test.dist)*frontface(brush, ss->cache->frontface_start, ss->cache->frontface_range, an, origno[vd.i]);
mul_v3_v3fl(proxy[vd.i], cono, fade);
@@ -1419,7 +1757,11 @@ static void do_snake_hook_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int to
float len;
if (brush->normal_weight > 0 || brush->flag & BRUSH_FRONTFACE)
- calc_sculpt_normal(sd, ob, an, nodes, totnode);
+ calc_sculpt_normal(sd, ob, an, nodes, totnode, brush->sculpt_plane_range);
+
+ set_brush_local_mat(sd, ob, brush, nodes, totnode, brush->normal_weight > 0 ? an : NULL);
+
+ set_adaptive_space_factor(sd, ob, nodes, totnode, brush->normal_weight > 0 ? an : NULL);
copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry);
@@ -1439,6 +1781,11 @@ static void do_snake_hook_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int to
PBVHVertexIter vd;
SculptBrushTest test;
float (*proxy)[3];
+ short (*origno)[3];
+ SculptUndoNode *unode;
+
+ unode= sculpt_undo_push_node(ob, nodes[n]);
+ origno= unode->no;
proxy= BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
@@ -1446,7 +1793,7 @@ static void do_snake_hook_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int to
BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
if(sculpt_brush_test(&test, vd.co)) {
- const float fade = bstrength*tex_strength(ss, brush, vd.co, test.dist)*frontface(brush, an, vd.no, vd.fno);
+ const float fade = bstrength*tex_strength(ss, brush, vd.co, test.dist)*frontface(brush, ss->cache->frontface_start, ss->cache->frontface_range, an, origno[vd.i]);
mul_v3_v3fl(proxy[vd.i], grab_delta, fade);
@@ -1470,7 +1817,11 @@ static void do_thumb_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry);
- calc_sculpt_normal(sd, ob, an, nodes, totnode);
+ calc_sculpt_normal(sd, ob, an, nodes, totnode, brush->sculpt_plane_range);
+
+ set_brush_local_mat(sd, ob, brush, NULL, 0, an);
+
+ set_adaptive_space_factor(sd, ob, NULL, 0, an);
cross_v3_v3v3(tmp, an, grab_delta);
cross_v3_v3v3(cono, tmp, an);
@@ -1494,7 +1845,7 @@ static void do_thumb_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
if(sculpt_brush_test(&test, origco[vd.i])) {
- const float fade = bstrength*tex_strength(ss, brush, origco[vd.i], test.dist)*frontface(brush, an, origno[vd.i], NULL);
+ const float fade = bstrength*tex_strength(ss, brush, origco[vd.i], test.dist)*frontface(brush, ss->cache->frontface_start, ss->cache->frontface_range, an, origno[vd.i]);
mul_v3_v3fl(proxy[vd.i], cono, fade);
@@ -1514,10 +1865,13 @@ static void do_rotate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod
float an[3];
int n;
float m[3][3];
- static const int flip[8] = { 1, -1, -1, 1, -1, 1, 1, -1 };
- float angle = ss->cache->vertex_rotation * flip[ss->cache->mirror_symmetry_pass];
+ float angle = ss->cache->vertex_rotation * rotation_flip[ss->cache->mirror_symmetry_pass];
+
+ calc_sculpt_normal(sd, ob, an, nodes, totnode, brush->sculpt_plane_range);
- calc_sculpt_normal(sd, ob, an, nodes, totnode);
+ set_brush_local_mat(sd, ob, brush, NULL, 0, an);
+
+ set_adaptive_space_factor(sd, ob, NULL, 0, an);
axis_angle_to_mat3(m, an, angle);
@@ -1540,7 +1894,7 @@ static void do_rotate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod
BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
if(sculpt_brush_test(&test, origco[vd.i])) {
- const float fade = bstrength*tex_strength(ss, brush, origco[vd.i], test.dist)*frontface(brush, an, origno[vd.i], NULL);
+ const float fade = bstrength*tex_strength(ss, brush, origco[vd.i], test.dist)*frontface(brush, ss->cache->frontface_start, ss->cache->frontface_range, an, origno[vd.i]);
mul_v3_m3v3(proxy[vd.i], m, origco[vd.i]);
sub_v3_v3(proxy[vd.i], origco[vd.i]);
@@ -1554,21 +1908,26 @@ static void do_rotate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod
}
}
+#if 0
static void do_layer_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
{
SculptSession *ss = ob->sculpt;
Brush *brush = paint_brush(&sd->paint);
float bstrength= ss->cache->bstrength;
- float area_normal[3], offset[3];
+ float an[3], offset[3];
float lim= brush->height;
int n;
if(bstrength < 0)
lim = -lim;
- calc_sculpt_normal(sd, ob, area_normal, nodes, totnode);
+ calc_sculpt_normal(sd, ob, an, nodes, totnode, brush->sculpt_plane_range);
+
+ set_brush_local_mat(sd, ob, brush, NULL, 0, an);
- mul_v3_v3v3(offset, ss->cache->scale, area_normal);
+ set_adaptive_space_factor(sd, ob, NULL, 0, an);
+
+ mul_v3_v3v3(offset, ss->cache->scale, an);
#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
for(n=0; n<totnode; n++) {
@@ -1579,7 +1938,9 @@ static void do_layer_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
//float (*proxy)[3]; // XXX layer brush needs conversion to proxy but its more complicated
//proxy= BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
-
+
+ short (*origno)[3];
+
unode= sculpt_undo_push_node(ob, nodes[n]);
origco=unode->co;
if(!unode->layer_disp)
@@ -1590,11 +1951,13 @@ static void do_layer_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
layer_disp= unode->layer_disp;
+ origno= unode->no;
+
sculpt_brush_test_init(ss, &test);
BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
- if(sculpt_brush_test(&test, origco[vd.i])) {
- const float fade = bstrength*tex_strength(ss, brush, vd.co, test.dist)*frontface(brush, area_normal, vd.no, vd.fno);
+ if(sculpt_brush_test(&test, vd.co)) {
+ const float fade = bstrength*ss->cache->radius*tex_strength(ss, brush, vd.co, test.dist)*frontface(brush, ss->cache->frontface_start, ss->cache->frontface_range, an, origno[vd.i]);
float *disp= &layer_disp[vd.i];
float val[3];
@@ -1625,6 +1988,7 @@ static void do_layer_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
BLI_pbvh_vertex_iter_end;
}
}
+#endif
static void do_inflate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
{
@@ -1633,11 +1997,20 @@ static void do_inflate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totno
float bstrength= ss->cache->bstrength;
int n;
+ set_brush_local_mat(sd, ob, brush, nodes, totnode, NULL);
+
+ set_adaptive_space_factor(sd, ob, nodes, totnode, NULL);
+
#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
for(n=0; n<totnode; n++) {
PBVHVertexIter vd;
SculptBrushTest test;
float (*proxy)[3];
+ short (*origno)[3];
+ SculptUndoNode* unode;
+
+ unode= sculpt_undo_push_node(ob, nodes[n]);
+ origno= unode->no;
proxy= BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
@@ -1645,7 +2018,7 @@ static void do_inflate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totno
BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
if(sculpt_brush_test(&test, vd.co)) {
- const float fade = bstrength*tex_strength(ss, brush, vd.co, test.dist)*frontface(brush, ss->cache->view_normal, vd.no, vd.fno);
+ const float fade = bstrength*tex_strength(ss, brush, vd.co, test.dist)*frontface(brush, ss->cache->frontface_start, ss->cache->frontface_range, ss->cache->view_normal, origno[vd.i]);
float val[3];
if(vd.fno) copy_v3_v3(val, vd.fno);
@@ -1715,7 +2088,7 @@ static void calc_flatten_center(Sculpt *sd, Object *ob, PBVHNode **nodes, int to
/* this calculates flatten center and area normal together,
amortizing the memory bandwidth and loop overhead to calculate both at the same time */
-static void calc_area_normal_and_flatten_center(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float an[3], float fc[3])
+static void calc_area_normal_and_flatten_center(Sculpt *sd, Ojbect *ob, PBVHNode **nodes, int totnode, float range, float an[3], float fc[3])
{
SculptSession *ss = ob->sculpt;
int n;
@@ -1727,7 +2100,7 @@ static void calc_area_normal_and_flatten_center(Sculpt *sd, Object *ob, PBVHNode
float count = 0;
(void)sd; /* unused w/o openmp */
-
+
// an
zero_v3(an);
@@ -1745,7 +2118,7 @@ static void calc_area_normal_and_flatten_center(Sculpt *sd, Object *ob, PBVHNode
int private_count = 0;
unode = sculpt_undo_push_node(ob, nodes[n]);
- sculpt_brush_test_init(ss, &test);
+ sculpt_brush_range_test_init(ss, &test, range);
if(ss->cache->original) {
BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
@@ -1812,7 +2185,7 @@ static void calc_area_normal_and_flatten_center(Sculpt *sd, Object *ob, PBVHNode
}
}
-static void calc_sculpt_plane(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float an[3], float fc[3])
+static void calc_sculpt_plane(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float range, float an[3], float fc[3])
{
SculptSession *ss = ob->sculpt;
Brush *brush = paint_brush(&sd->paint);
@@ -1845,7 +2218,7 @@ static void calc_sculpt_plane(Sculpt *sd, Object *ob, PBVHNode **nodes, int totn
break;
case SCULPT_DISP_DIR_AREA:
- calc_area_normal_and_flatten_center(sd, ob, nodes, totnode, an, fc);
+ calc_area_normal_and_flatten_center(sd, ob, nodes, totnode, range, an, fc);
default:
break;
@@ -1886,35 +2259,53 @@ static void calc_sculpt_plane(Sculpt *sd, Object *ob, PBVHNode **nodes, int totn
/* Projects a point onto a plane along the plane's normal */
static void point_plane_project(float intr[3], float co[3], float plane_normal[3], float plane_center[3])
{
- sub_v3_v3v3(intr, co, plane_center);
- mul_v3_v3fl(intr, plane_normal, dot_v3v3(plane_normal, intr));
- sub_v3_v3v3(intr, co, intr);
+ sub_v3_v3v3(intr, co, plane_center);
+ mul_v3_v3fl(intr, plane_normal, dot_v3v3(plane_normal, intr));
+ sub_v3_v3v3(intr, co, intr);
}
-static int plane_trim(StrokeCache *cache, Brush *brush, float val[3])
+static int plane_trim(StrokeCache *cache, Brush *brush, float val[3], float *fade)
{
- return !(brush->flag & BRUSH_PLANE_TRIM) || (dot_v3v3(val, val) <= cache->radius_squared*cache->plane_trim_squared);
+ if (brush->flag & BRUSH_PLANE_TRIM) {
+ float len_squared= dot_v3v3(val, val);
+ float trim_squared= cache->radius_squared*cache->plane_trim_squared;
+
+ if (len_squared > trim_squared) {
+ return 0;
+ }
+ else {
+ *fade= 1 - sqrt(len_squared)/sqrt(trim_squared);
+
+ return 1;
+ }
+ }
+ else {
+ *fade= 1;
+
+ return 1;
+ }
+
}
static int plane_point_side_flip(float co[3], float plane_normal[3], float plane_center[3], int flip)
{
- float delta[3];
- float d;
+ float delta[3];
+ float d;
- sub_v3_v3v3(delta, co, plane_center);
- d = dot_v3v3(plane_normal, delta);
+ sub_v3_v3v3(delta, co, plane_center);
+ d = dot_v3v3(plane_normal, delta);
- if (flip) d = -d;
+ if (flip) d = -d;
- return d <= 0.0f;
+ return d <= 0.0f;
}
static int plane_point_side(float co[3], float plane_normal[3], float plane_center[3])
{
- float delta[3];
+ float delta[3];
- sub_v3_v3v3(delta, co, plane_center);
- return dot_v3v3(plane_normal, delta) <= 0.0f;
+ sub_v3_v3v3(delta, co, plane_center);
+ return dot_v3v3(plane_normal, delta) <= 0.0f;
}
static float get_offset(Sculpt *sd, SculptSession *ss)
@@ -1949,7 +2340,11 @@ static void do_flatten_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totno
float temp[3];
- calc_sculpt_plane(sd, ob, nodes, totnode, an, fc);
+ calc_sculpt_plane(sd, obs, nodes, totnode, brush->sculpt_plane_range, an, fc);
+
+ set_brush_local_mat(sd, ob, brush, NULL, 0, an);
+
+ set_adaptive_space_factor(sd, ob, NULL, 0, an);
displace = radius*offset;
@@ -1962,6 +2357,11 @@ static void do_flatten_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totno
PBVHVertexIter vd;
SculptBrushTest test;
float (*proxy)[3];
+ short (*origno)[3];
+ SculptUndoNode* unode;
+
+ unode= sculpt_undo_push_node(ob, nodes[n]);
+ origno= unode->no;
proxy= BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
@@ -1971,13 +2371,14 @@ static void do_flatten_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totno
if (sculpt_brush_test_sq(&test, vd.co)) {
float intr[3];
float val[3];
+ float fade;
point_plane_project(intr, vd.co, an, fc);
sub_v3_v3v3(val, intr, vd.co);
- if (plane_trim(ss->cache, brush, val)) {
- const float fade = bstrength*tex_strength(ss, brush, vd.co, sqrt(test.dist))*frontface(brush, an, vd.no, vd.fno);
+ if (plane_trim(ss->cache, brush, val, &fade)) {
+ fade *= bstrength*tex_strength(ss, brush, vd.co, sqrt(test.dist))*frontface(brush, ss->cache->frontface_start, ss->cache->frontface_range, an, origno[vd.i]);
mul_v3_v3fl(proxy[vd.i], val, fade);
@@ -2011,7 +2412,11 @@ static void do_clay_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
int flip;
- calc_sculpt_plane(sd, ob, nodes, totnode, an, fc);
+ calc_sculpt_plane(sd, ob, nodes, totnode, brush->sculpt_plane_range, an, fc);
+
+ set_brush_local_mat(sd, ob, brush, NULL, 0, an);
+
+ set_adaptive_space_factor(sd, ob, NULL, 0, an);
flip = bstrength < 0;
@@ -2033,6 +2438,11 @@ static void do_clay_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
PBVHVertexIter vd;
SculptBrushTest test;
float (*proxy)[3];
+ short (*origno)[3];
+ SculptUndoNode* unode;
+
+ unode= sculpt_undo_push_node(ob, nodes[n]);
+ origno= unode->no;
proxy= BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
@@ -2044,13 +2454,14 @@ static void do_clay_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
//if (sculpt_brush_test_cyl(&test, vd.co, ss->cache->location, p)) {
float intr[3];
float val[3];
+ float fade;
point_plane_project(intr, vd.co, an, fc);
sub_v3_v3v3(val, intr, vd.co);
- if (plane_trim(ss->cache, brush, val)) {
- const float fade = bstrength*tex_strength(ss, brush, vd.co, sqrt(test.dist))*frontface(brush, an, vd.no, vd.fno);
+ if (plane_trim(ss->cache, brush, val, &fade)) {
+ fade *= bstrength*tex_strength(ss, brush, vd.co, sqrt(test.dist))*frontface(brush, ss->cache->frontface_start, ss->cache->frontface_range, an, origno[vd.i]);
mul_v3_v3fl(proxy[vd.i], val, fade);
@@ -2064,7 +2475,7 @@ static void do_clay_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
}
}
-static void do_clay_tubes_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+static void do_clay_strips_brush(Sculpt *sd, Object* ob, PBVHNode **nodes, int totnode)
{
SculptSession *ss = ob->sculpt;
Brush *brush = paint_brush(&sd->paint);
@@ -2088,10 +2499,14 @@ static void do_clay_tubes_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int to
int flip;
- calc_sculpt_plane(sd, ob, nodes, totnode, sn, fc);
+ calc_sculpt_plane(sd, ob, nodes, totnode, brush->sculpt_plane_range, sn, fc);
+
+ set_brush_local_mat(sd, ob, brush, NULL, 0, sn);
+
+ set_adaptive_space_factor(sd, ob, NULL, 0, sn);
if (brush->sculpt_plane != SCULPT_DISP_DIR_AREA || (brush->flag & BRUSH_ORIGINAL_NORMAL))
- calc_area_normal(sd, ob, an, nodes, totnode);
+ calc_area_normal(sd, ob, an, nodes, totnode, brush->sculpt_plane_range);
else
copy_v3_v3(an, sn);
@@ -2111,7 +2526,7 @@ static void do_clay_tubes_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int to
mul_v3_fl(temp, displace);
add_v3_v3(fc, temp);
- cross_v3_v3v3(mat[0], an, ss->cache->grab_delta_symmetry); mat[0][3] = 0;
+ cross_v3_v3v3(mat[0], an, ss->cache->rake_delta_symmetry); mat[0][3] = 0;
cross_v3_v3v3(mat[1], an, mat[0]); mat[1][3] = 0;
copy_v3_v3(mat[2], an); mat[2][3] = 0;
copy_v3_v3(mat[3], ss->cache->location); mat[3][3] = 1;
@@ -2125,23 +2540,31 @@ static void do_clay_tubes_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int to
PBVHVertexIter vd;
SculptBrushTest test;
float (*proxy)[3];
+ float cube_fade;
+ short (*origno)[3];
+ SculptUndoNode* unode;
+
+ unode= sculpt_undo_push_node(ob, nodes[n]);
+ origno= unode->no;
proxy= BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
sculpt_brush_test_init(ss, &test);
BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
- if (sculpt_brush_test_cube(&test, vd.co, mat)) {
+ cube_fade = 1;
+ if (sculpt_brush_test_cube(&test, &cube_fade, vd.co, mat)) {
if (plane_point_side_flip(vd.co, sn, fc, flip)) {
float intr[3];
float val[3];
+ float fade;
point_plane_project(intr, vd.co, sn, fc);
sub_v3_v3v3(val, intr, vd.co);
- if (plane_trim(ss->cache, brush, val)) {
- const float fade = bstrength*tex_strength(ss, brush, vd.co, ss->cache->radius*test.dist)*frontface(brush, an, vd.no, vd.fno);
+ if (plane_trim(ss->cache, brush, val, &fade)) {
+ fade *= cube_fade*bstrength*tex_strength(ss, brush, vd.co, test.dist)*frontface(brush, ss->cache->frontface_start, ss->cache->frontface_range, an, origno[vd.i]);
mul_v3_v3fl(proxy[vd.i], val, fade);
@@ -2173,7 +2596,11 @@ static void do_fill_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
float temp[3];
- calc_sculpt_plane(sd, ob, nodes, totnode, an, fc);
+ calc_sculpt_plane(sd, ob, nodes, totnode, brush->sculpt_plane_range, an, fc);
+
+ set_brush_local_mat(sd, ob, brush, NULL, 0, an);
+
+ set_adaptive_space_factor(sd, ob, NULL, 0, an);
displace = radius*offset;
@@ -2186,6 +2613,11 @@ static void do_fill_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
PBVHVertexIter vd;
SculptBrushTest test;
float (*proxy)[3];
+ short (*origno)[3];
+ SculptUndoNode* unode;
+
+ unode= sculpt_undo_push_node(ob, nodes[n]);
+ origno= unode->no;
proxy= BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
@@ -2196,13 +2628,14 @@ static void do_fill_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
if (plane_point_side(vd.co, an, fc)) {
float intr[3];
float val[3];
+ float fade;
point_plane_project(intr, vd.co, an, fc);
sub_v3_v3v3(val, intr, vd.co);
- if (plane_trim(ss->cache, brush, val)) {
- const float fade = bstrength*tex_strength(ss, brush, vd.co, sqrt(test.dist))*frontface(brush, an, vd.no, vd.fno);
+ if (plane_trim(ss->cache, brush, val, &fade)) {
+ fade *= bstrength*tex_strength(ss, brush, vd.co, sqrt(test.dist))*frontface(brush, ss->cache->frontface_start, ss->cache->frontface_range, an, origno[vd.i]);
mul_v3_v3fl(proxy[vd.i], val, fade);
@@ -2216,7 +2649,7 @@ static void do_fill_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
}
}
-static void do_scrape_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+static void do_scrape_brush(Sculpt *sd, Object* ob, PBVHNode **nodes, int totnode)
{
SculptSession *ss = ob->sculpt;
Brush *brush = paint_brush(&sd->paint);
@@ -2234,7 +2667,11 @@ static void do_scrape_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod
float temp[3];
- calc_sculpt_plane(sd, ob, nodes, totnode, an, fc);
+ calc_sculpt_plane(sd, ob, nodes, totnode, brush->sculpt_plane_range, an, fc);
+
+ set_brush_local_mat(sd, ob, brush, NULL, 0, an);
+
+ set_adaptive_space_factor(sd, ob, NULL, 0, an);
displace = -radius*offset;
@@ -2247,6 +2684,11 @@ static void do_scrape_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod
PBVHVertexIter vd;
SculptBrushTest test;
float (*proxy)[3];
+ short (*origno)[3];
+ SculptUndoNode* unode;
+
+ unode= sculpt_undo_push_node(ob, nodes[n]);
+ origno= unode->no;
proxy= BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
@@ -2257,13 +2699,14 @@ static void do_scrape_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod
if (!plane_point_side(vd.co, an, fc)) {
float intr[3];
float val[3];
+ float fade;
point_plane_project(intr, vd.co, an, fc);
sub_v3_v3v3(val, intr, vd.co);
- if (plane_trim(ss->cache, brush, val)) {
- const float fade = bstrength*tex_strength(ss, brush, vd.co, sqrt(test.dist))*frontface(brush, an, vd.no, vd.fno);
+ if (plane_trim(ss->cache, brush, val, &fade)) {
+ fade *= bstrength*tex_strength(ss, brush, vd.co, sqrt(test.dist))*frontface(brush, ss->cache->frontface_start, ss->cache->frontface_range, an, origno[vd.i]);
mul_v3_v3fl(proxy[vd.i], val, fade);
@@ -2327,9 +2770,79 @@ void sculpt_vertcos_to_key(Object *ob, KeyBlock *kb, float (*vertCos)[3])
vertcos_to_key(ob, kb, vertCos);
}
-static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush)
+/* copy the modified vertices from bvh to the active key */
+static void sculpt_update_keyblock(Object *ob)
{
SculptSession *ss = ob->sculpt;
+ float (*vertCos)[3];
+
+ /* Keyblock update happens after hadning deformation caused by modifiers,
+ so ss->orig_cos would be updated with new stroke */
+ if(ss->orig_cos) vertCos = ss->orig_cos;
+ else vertCos = BLI_pbvh_get_vertCos(ss->pbvh);
+
+ if (vertCos) {
+ sculpt_vertcos_to_key(ob, ss->kb, vertCos);
+
+ if(vertCos != ss->orig_cos)
+ MEM_freeN(vertCos);
+ }
+}
+
+/* flush displacement from deformed PBVH to original layer */
+static void sculpt_flush_stroke_deform(Sculpt *sd, Object *ob)
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush= paint_brush(&sd->paint);
+
+ if(brush->sculpt_tool == SCULPT_TOOL_SMOOTH) {
+ /* smooth brushes does not use proxies, so sculpt_combine_proxies()
+ does not propagate needed deformation to original base */
+
+ int n, totnode;
+ Mesh *me= (Mesh*)ob->data;
+ PBVHNode** nodes;
+ float (*vertCos)[3]= NULL;
+
+ if(ss->kb)
+ vertCos= MEM_callocN(sizeof(*vertCos)*me->totvert, "flushStrokeDeofrm keyVerts");
+
+ BLI_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode);
+
+ #pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
+ for (n= 0; n < totnode; n++) {
+ PBVHVertexIter vd;
+
+ BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
+ sculpt_flush_pbvhvert_deform(ob, &vd);
+
+ if(vertCos) {
+ int index= vd.vert_indices[vd.i];
+ copy_v3_v3(vertCos[index], ss->orig_cos[index]);
+ }
+ }
+ BLI_pbvh_vertex_iter_end;
+ }
+
+ if(vertCos) {
+ sculpt_vertcos_to_key(ob, ss->kb, vertCos);
+ MEM_freeN(vertCos);
+ }
+
+ MEM_freeN(nodes);
+
+ /* Modifiers could depend on mesh normals, so we should update them/
+ Note, then if sculpting happens on locked key, normals should be re-calculated
+ after applying coords from keyblock on base mesh */
+ mesh_calc_normals(me->mvert, me->totvert, me->mface, me->totface, NULL);
+ }
+ else if (ss->kb) {
+ sculpt_update_keyblock(ob);
+ }
+}
+
+static void do_brush_action(Sculpt *sd, Object* ob, Brush *brush)
+{
SculptSearchSphereData data;
PBVHNode **nodes = NULL;
int n, totnode;
@@ -2343,6 +2856,7 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush)
/* Only act if some verts are inside the brush area */
if (totnode) {
+ // XXX: is pushing unode here, then pushing again in brush redundant?
#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
for (n= 0; n < totnode; n++) {
sculpt_undo_push_node(ob, nodes[n]);
@@ -2354,6 +2868,9 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush)
case SCULPT_TOOL_DRAW:
do_draw_brush(sd, ob, nodes, totnode);
break;
+ case SCULPT_TOOL_GRAVITY:
+ do_gravity_brush(sd, ob, nodes, totnode);
+ break;
case SCULPT_TOOL_SMOOTH:
do_smooth_brush(sd, ob, nodes, totnode);
break;
@@ -2385,7 +2902,8 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush)
do_thumb_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_LAYER:
- do_layer_brush(sd, ob, nodes, totnode);
+ //do_layer_brush(sd, ob, nodes, totnode);
+ do_draw_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_FLATTEN:
do_flatten_brush(sd, ob, nodes, totnode);
@@ -2393,8 +2911,8 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush)
case SCULPT_TOOL_CLAY:
do_clay_brush(sd, ob, nodes, totnode);
break;
- case SCULPT_TOOL_CLAY_TUBES:
- do_clay_tubes_brush(sd, ob, nodes, totnode);
+ case SCULPT_TOOL_CLAY_STRIPS:
+ do_clay_strips_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_FILL:
do_fill_brush(sd, ob, nodes, totnode);
@@ -2413,6 +2931,9 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush)
}
}
+ if (brush->sculpt_tool != SCULPT_TOOL_GRAVITY && brush->gravity_factor > 0)
+ gravity(sd, ob, nodes, totnode, brush->gravity_factor);
+
MEM_freeN(nodes);
}
}
@@ -2441,172 +2962,183 @@ static void sculpt_combine_proxies(Sculpt *sd, Object *ob)
SculptSession *ss = ob->sculpt;
Brush *brush= paint_brush(&sd->paint);
PBVHNode** nodes;
- int totnode, n;
+ int totnode;
+ int n;
+
+ if (brush->sculpt_tool == SCULPT_TOOL_SMOOTH)
+ return;
BLI_pbvh_gather_proxies(ss->pbvh, &nodes, &totnode);
- if(!ELEM(brush->sculpt_tool, SCULPT_TOOL_SMOOTH, SCULPT_TOOL_LAYER)) {
- /* these brushes start from original coordinates */
- const int use_orco = (ELEM3(brush->sculpt_tool, SCULPT_TOOL_GRAB,
- SCULPT_TOOL_ROTATE, SCULPT_TOOL_THUMB));
+ switch (brush->sculpt_tool) {
+ case SCULPT_TOOL_GRAB:
+ case SCULPT_TOOL_ROTATE:
+ case SCULPT_TOOL_THUMB:
+ #pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
+ for (n= 0; n < totnode; n++) {
+ PBVHVertexIter vd;
+ PBVHProxyNode* proxies;
+ int proxy_count;
+ float (*origco)[3];
- #pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
- for (n= 0; n < totnode; n++) {
- PBVHVertexIter vd;
- PBVHProxyNode* proxies;
- int proxy_count;
- float (*orco)[3];
+ origco= sculpt_undo_push_node(ob, nodes[n])->co;
- if(use_orco)
- orco= sculpt_undo_push_node(ob, nodes[n])->co;
+ BLI_pbvh_node_get_proxies(nodes[n], &proxies, &proxy_count);
- BLI_pbvh_node_get_proxies(nodes[n], &proxies, &proxy_count);
+ BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
+ float val[3];
+ int p;
- BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
- float val[3];
- int p;
+ copy_v3_v3(val, origco[vd.i]);
- if(use_orco)
- copy_v3_v3(val, orco[vd.i]);
- else
- copy_v3_v3(val, vd.co);
+ for (p= 0; p < proxy_count; p++)
+ add_v3_v3(val, proxies[p].co[vd.i]);
- for (p= 0; p < proxy_count; p++)
- add_v3_v3(val, proxies[p].co[vd.i]);
+ sculpt_clip(sd, ss, vd.co, val);
- sculpt_clip(sd, ss, vd.co, val);
+ if (ss->modifiers_active)
+ sculpt_flush_pbvhvert_deform(ob, &vd);
+ }
+ BLI_pbvh_vertex_iter_end;
- if(ss->modifiers_active)
- sculpt_flush_pbvhvert_deform(ob, &vd);
+ BLI_pbvh_node_free_proxies(nodes[n]);
}
- BLI_pbvh_vertex_iter_end;
- BLI_pbvh_node_free_proxies(nodes[n]);
- }
- }
+ break;
- if (nodes)
- MEM_freeN(nodes);
-}
+ case SCULPT_TOOL_DRAW:
+ case SCULPT_TOOL_GRAVITY:
+ case SCULPT_TOOL_CLAY:
+ case SCULPT_TOOL_CLAY_STRIPS:
+ case SCULPT_TOOL_CREASE:
+ case SCULPT_TOOL_BLOB:
+ case SCULPT_TOOL_FILL:
+ case SCULPT_TOOL_FLATTEN:
+ case SCULPT_TOOL_INFLATE:
+ case SCULPT_TOOL_NUDGE:
+ case SCULPT_TOOL_PINCH:
+ case SCULPT_TOOL_SCRAPE:
+ case SCULPT_TOOL_SNAKE_HOOK:
+ case SCULPT_TOOL_LAYER:
+ #pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
+ for (n= 0; n < totnode; n++) {
+ PBVHVertexIter vd;
+ PBVHProxyNode* proxies;
+ int proxy_count;
-/* copy the modified vertices from bvh to the active key */
-static void sculpt_update_keyblock(Object *ob)
-{
- SculptSession *ss = ob->sculpt;
- float (*vertCos)[3];
+ BLI_pbvh_node_get_proxies(nodes[n], &proxies, &proxy_count);
- /* Keyblock update happens after hadning deformation caused by modifiers,
- so ss->orig_cos would be updated with new stroke */
- if(ss->orig_cos) vertCos = ss->orig_cos;
- else vertCos = BLI_pbvh_get_vertCos(ss->pbvh);
+ BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
+ float val[3];
+ int p;
- if (vertCos) {
- sculpt_vertcos_to_key(ob, ss->kb, vertCos);
+ copy_v3_v3(val, vd.co);
+ for (p= 0; p < proxy_count; p++)
+ add_v3_v3(val, proxies[p].co[vd.i]);
+
+ if (brush->sculpt_tool == SCULPT_TOOL_LAYER || brush->flag & BRUSH_LAYER) {
+ float disp[3];
+ float len;
+ float *base;
+
+ if (ss->layer_co && (brush->flag & BRUSH_PERSISTENT)) {
+ int index= vd.vert_indices[vd.i];
+
+ /* persistent base */
+ base= ss->layer_co[index];
+ }
+ else {
+ base= sculpt_undo_push_node(ob, nodes[n])->co[vd.i];
+ }
+
+ sub_v3_v3v3(disp, val, base);
+ len= len_v3(disp);
+
+ if (len > ss->cache->radius*brush->layer_distance) {
+ normalize_v3(disp);
+ mul_v3_fl(disp, ss->cache->radius*brush->layer_distance);
+ add_v3_v3v3(val, disp, base);
+ }
+ }
- if(vertCos != ss->orig_cos)
- MEM_freeN(vertCos);
- }
-}
+ sculpt_clip(sd, ss, vd.co, val);
-/* flush displacement from deformed PBVH to original layer */
-static void sculpt_flush_stroke_deform(Sculpt *sd, Object *ob)
-{
- SculptSession *ss = ob->sculpt;
- Brush *brush= paint_brush(&sd->paint);
+ if (ss->modifiers_active)
+ sculpt_flush_pbvhvert_deform(ob, &vd);
+ }
+ BLI_pbvh_vertex_iter_end;
- if(ELEM(brush->sculpt_tool, SCULPT_TOOL_SMOOTH, SCULPT_TOOL_LAYER)) {
- /* this brushes aren't using proxies, so sculpt_combine_proxies() wouldn't
- propagate needed deformation to original base */
+ BLI_pbvh_node_free_proxies(nodes[n]);
+ PBVHVertexIter vd;
- int n, totnode;
- Mesh *me= (Mesh*)ob->data;
- PBVHNode** nodes;
- float (*vertCos)[3]= NULL;
+ }
- if(ss->kb)
- vertCos= MEM_callocN(sizeof(*vertCos)*me->totvert, "flushStrokeDeofrm keyVerts");
+ break;
- BLI_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode);
+ case SCULPT_TOOL_SMOOTH:
+ default:
+ break;
+ }
- #pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
- for (n= 0; n < totnode; n++) {
- PBVHVertexIter vd;
+ if (nodes)
+ MEM_freeN(nodes);
+}
- BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
- sculpt_flush_pbvhvert_deform(ob, &vd);
+#if 0
+static int max_overlap_count(Sculpt *sd)
+{
+ int count[3];
+ int i, j;
- if(vertCos) {
- int index= vd.vert_indices[vd.i];
- copy_v3_v3(vertCos[index], ss->orig_cos[index]);
- }
- }
- BLI_pbvh_vertex_iter_end;
- }
+ for (i= 0; i < 3; i++) {
+ count[i] = sd->radial_symm[i];
- if(vertCos) {
- sculpt_vertcos_to_key(ob, ss->kb, vertCos);
- MEM_freeN(vertCos);
+ for (j= 0; j < 3; j++) {
+ if (i != j && sd->flags & (SCULPT_SYMM_X<<i))
+ count[i] *= 2;
}
+ }
- MEM_freeN(nodes);
-
- /* Modifiers could depend on mesh normals, so we should update them/
- Note, then if sculpting happens on locked key, normals should be re-calculated
- after applying coords from keyblock on base mesh */
- mesh_calc_normals(me->mvert, me->totvert, me->mface, me->totface, NULL);
- } else if (ss->kb)
- sculpt_update_keyblock(ob);
+ return MAX3(count[0], count[1], count[2]);
}
-
-//static int max_overlap_count(Sculpt *sd)
-//{
-// int count[3];
-// int i, j;
-//
-// for (i= 0; i < 3; i++) {
-// count[i] = sd->radial_symm[i];
-//
-// for (j= 0; j < 3; j++) {
-// if (i != j && sd->flags & (SCULPT_SYMM_X<<i))
-// count[i] *= 2;
-// }
-// }
-//
-// return MAX3(count[0], count[1], count[2]);
-//}
+#endif
/* Flip all the editdata across the axis/axes specified by symm. Used to
calculate multiple modifications to the mesh when symmetry is enabled. */
static void calc_brushdata_symm(Sculpt *sd, StrokeCache *cache, const char symm, const char axis, const float angle, const float UNUSED(feather))
{
- (void)sd; /* unused */
-
flip_coord(cache->location, cache->true_location, symm);
flip_coord(cache->grab_delta_symmetry, cache->grab_delta, symm);
+ flip_coord(cache->rake_delta_symmetry, cache->rake_delta, symm);
flip_coord(cache->view_normal, cache->true_view_normal, symm);
+#if 0
// XXX This reduces the length of the grab delta if it approaches the line of symmetry
// XXX However, a different approach appears to be needed
- //if (sd->flags & SCULPT_SYMMETRY_FEATHER) {
- // float frac = 1.0f/max_overlap_count(sd);
- // float reduce = (feather-frac)/(1-frac);
+ if (sd->flags & SCULPT_SYMMETRY_FEATHER) {
+ float frac = 1.0f/max_overlap_count(sd);
+ float reduce = (feather-frac)/(1-frac);
- // printf("feather: %f frac: %f reduce: %f\n", feather, frac, reduce);
+ printf("feather: %f frac: %f reduce: %f\n", feather, frac, reduce);
- // if (frac < 1)
- // mul_v3_fl(cache->grab_delta_symmetry, reduce);
- //}
+ if (frac < 1)
+ mul_v3_fl(cache->grab_delta_symmetry, reduce);
+ }
+#else
+ (void)sd; /* XXX: unused as long as symmetry feather is disabled */
+#endif
unit_m4(cache->symm_rot_mat);
unit_m4(cache->symm_rot_mat_inv);
- if(axis) { /* expects XYZ */
+ if(axis >= 'X' && axis <= 'Z') { /* expects XYZ */
rotate_m4(cache->symm_rot_mat, axis, angle);
rotate_m4(cache->symm_rot_mat_inv, axis, -angle);
}
mul_m4_v3(cache->symm_rot_mat, cache->location);
mul_m4_v3(cache->symm_rot_mat, cache->grab_delta_symmetry);
+ mul_m4_v3(cache->symm_rot_mat, cache->rake_delta_symmetry);
}
static void do_radial_symmetry(Sculpt *sd, Object *ob, Brush *brush, const char symm, const int axis, const float feather)
@@ -2637,6 +3169,7 @@ static void sculpt_fix_noise_tear(Sculpt *sd, Object *ob)
static void do_symmetrical_brush_actions(Sculpt *sd, Object *ob)
{
+ SculptSession *ss = ob->sculpt;
Brush *brush = paint_brush(&sd->paint);
SculptSession *ss = ob->sculpt;
StrokeCache *cache = ss->cache;
@@ -2704,7 +3237,7 @@ void sculpt_free_deformMats(SculptSession *ss)
ss->deform_imats = NULL;
}
-void sculpt_update_mesh_elements(Scene *scene, Sculpt *sd, Object *ob, int need_fmap)
+void sculpt_update_mesh_elements(Scene *scene, Sculpt* sd, Object *ob, int need_fmap)
{
DerivedMesh *dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH);
SculptSession *ss = ob->sculpt;
@@ -2712,8 +3245,10 @@ void sculpt_update_mesh_elements(Scene *scene, Sculpt *sd, Object *ob, int need_
ss->modifiers_active= sculpt_modifiers_active(scene, sd, ob);
- if(!mmd) ss->kb= ob_get_keyblock(ob);
- else ss->kb= NULL;
+ if (!mmd)
+ ss->kb= ob_get_keyblock(ob);
+ else
+ ss->kb= NULL;
if(mmd) {
ss->multires = mmd;
@@ -2736,8 +3271,8 @@ void sculpt_update_mesh_elements(Scene *scene, Sculpt *sd, Object *ob, int need_
ss->pbvh = dm->getPBVH(ob, dm);
ss->fmap = (need_fmap && dm->getFaceMap)? dm->getFaceMap(ob, dm): NULL;
- if(ss->modifiers_active) {
- if(!ss->orig_cos) {
+ if (ss->modifiers_active) {
+ if (!ss->orig_cos) {
int a;
sculpt_free_deformMats(ss);
@@ -2751,7 +3286,10 @@ void sculpt_update_mesh_elements(Scene *scene, Sculpt *sd, Object *ob, int need_
for(a = 0; a < ((Mesh*)ob->data)->totvert; ++a)
invert_m3(ss->deform_imats[a]);
}
- } else sculpt_free_deformMats(ss);
+ }
+ else {
+ sculpt_free_deformMats(ss);
+ }
/* if pbvh is deformed, key block is already applied to it */
if (ss->kb && !BLI_pbvh_isDeformed(ss->pbvh)) {
@@ -2782,40 +3320,107 @@ static const char *sculpt_tool_name(Sculpt *sd)
switch(brush->sculpt_tool) {
case SCULPT_TOOL_DRAW:
- return "Draw Brush"; break;
+ return "Draw Brush";
+ case SCULPT_TOOL_GRAVITY:
+ return "Gravity Brush";
case SCULPT_TOOL_SMOOTH:
- return "Smooth Brush"; break;
+ return "Smooth Brush";
case SCULPT_TOOL_CREASE:
- return "Crease Brush"; break;
+ return "Crease Brush";
case SCULPT_TOOL_BLOB:
- return "Blob Brush"; break;
+ return "Blob Brush";
case SCULPT_TOOL_PINCH:
- return "Pinch Brush"; break;
+ return "Pinch Brush";
case SCULPT_TOOL_INFLATE:
- return "Inflate Brush"; break;
+ return "Inflate Brush";
case SCULPT_TOOL_GRAB:
- return "Grab Brush"; break;
+ return "Grab Brush";
case SCULPT_TOOL_NUDGE:
- return "Nudge Brush"; break;
+ return "Nudge Brush";
case SCULPT_TOOL_THUMB:
- return "Thumb Brush"; break;
+ return "Thumb Brush";
case SCULPT_TOOL_LAYER:
- return "Layer Brush"; break;
+ return "Layer Brush";
case SCULPT_TOOL_FLATTEN:
- return "Flatten Brush"; break;
+ return "Flatten Brush";
case SCULPT_TOOL_CLAY:
- return "Clay Brush"; break;
- case SCULPT_TOOL_CLAY_TUBES:
- return "Clay Tubes Brush"; break;
+ return "Clay Brush";
+ case SCULPT_TOOL_CLAY_STRIPS:
+ return "Clay Strips Brush";
case SCULPT_TOOL_FILL:
- return "Fill Brush"; break;
+ return "Fill Brush";
case SCULPT_TOOL_SCRAPE:
- return "Scrape Brush"; break;
+ return "Scrape Brush";
default:
- return "Sculpting"; break;
+ return "Sculpting";
}
}
+#if 0
+// XXX: before I had 'on-surface' working with the radial control
+// with all the changes to the radial control I am probably doing to
+// have to completely reimplement it
+/**** Radial control ****/
+static int sculpt_radial_control_invoke(bContext *C, wmOperator *op, wmEvent *event)
+{
+ Paint *p = paint_get_active(CTX_data_scene(C));
+ Brush *brush = paint_brush(p);
+ float col[4], tex_col[4];
+
+ WM_paint_cursor_end(CTX_wm_manager(C), p->paint_cursor);
+ p->paint_cursor = NULL;
+ brush_radial_control_invoke(op, brush, 1);
+
+ // XXX: add/sub color needs to be determined in one place so it's consistant. this same code is in paint_stroke
+ if((brush->flag & BRUSH_DIR_IN) && ELEM6(brush->sculpt_tool, SCULPT_TOOL_DRAW, SCULPT_TOOL_INFLATE, SCULPT_TOOL_CLAY, SCULPT_TOOL_CLAY_TUBES, SCULPT_TOOL_PINCH, SCULPT_TOOL_CREASE))
+ copy_v3_v3(col, brush->sub_col);
+ else
+ copy_v3_v3(col, brush->add_col);
+ col[3]= 0.5f;
+
+ copy_v3_v3(tex_col, U.sculpt_paint_overlay_col);
+ tex_col[3]= (brush->texture_overlay_alpha / 100.0f);
+
+ RNA_float_set_array(op->ptr, "color", col);
+ RNA_float_set_array(op->ptr, "texture_color", tex_col);
+
+ return WM_radial_control_invoke(C, op, event);
+}
+
+static int sculpt_radial_control_modal(bContext *C, wmOperator *op, wmEvent *event)
+{
+ int ret = WM_radial_control_modal(C, op, event);
+ if(ret != OPERATOR_RUNNING_MODAL)
+ paint_cursor_start(C, sculpt_poll);
+ return ret;
+}
+
+static int sculpt_radial_control_exec(bContext *C, wmOperator *op)
+{
+ Brush *brush = paint_brush(&CTX_data_tool_settings(C)->sculpt->paint);
+ int ret = brush_radial_control_exec(op, brush, 1);
+
+ WM_event_add_notifier(C, NC_BRUSH|NA_EDITED, brush);
+
+ return ret;
+}
+
+static void SCULPT_OT_radial_control(wmOperatorType *ot)
+{
+ WM_OT_radial_control_partial(ot);
+
+ ot->name= "Sculpt Radial Control";
+ ot->idname= "SCULPT_OT_radial_control";
+
+ ot->invoke= sculpt_radial_control_invoke;
+ ot->modal= sculpt_radial_control_modal;
+ ot->exec= sculpt_radial_control_exec;
+ ot->poll= sculpt_poll;
+
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO|OPTYPE_BLOCKING;
+}
+#endif
+
/**** Operator for applying a stroke (various attributes including mouse path)
using the current brush. ****/
@@ -2897,8 +3502,10 @@ static void sculpt_update_cache_invariants(bContext* C, Sculpt *sd, SculptSessio
/* not very nice, but with current events system implementation
we can't handle brush appearance inversion hotkey separately (sergey) */
- if(cache->invert) brush->flag |= BRUSH_INVERTED;
- else brush->flag &= ~BRUSH_INVERTED;
+ if (cache->invert)
+ brush->flag |= BRUSH_INVERTED;
+ else
+ brush->flag &= ~BRUSH_INVERTED;
/* Alt-Smooth */
if (ss->cache->alt_smooth) {
@@ -2909,10 +3516,10 @@ static void sculpt_update_cache_invariants(bContext* C, Sculpt *sd, SculptSessio
br= (Brush *)find_id("BR", "Smooth");
if(br) {
- paint_brush_set(p, br);
- brush = br;
+ paint_brush_set(p, br);
+ brush = br;
+ }
}
- }
copy_v2_v2(cache->mouse, cache->initial_mouse);
copy_v2_v2(cache->tex_mouse, cache->initial_mouse);
@@ -2935,11 +3542,12 @@ static void sculpt_update_cache_invariants(bContext* C, Sculpt *sd, SculptSessio
ss->layer_co= MEM_mallocN(sizeof(float) * 3 * ss->totvert,
"sculpt mesh vertices copy");
- if(ss->deform_cos) memcpy(ss->layer_co, ss->deform_cos, ss->totvert);
+ if (ss->deform_cos) {
+ memcpy(ss->layer_co, ss->deform_cos, ss->totvert);
+ }
else {
- for(i = 0; i < ss->totvert; ++i) {
+ for(i= 0; i < ss->totvert; ++i)
copy_v3_v3(ss->layer_co[i], ss->mvert[i].co);
- }
}
}
}
@@ -2956,7 +3564,7 @@ static void sculpt_update_cache_invariants(bContext* C, Sculpt *sd, SculptSessio
cache->original = 1;
}
- if(ELEM8(brush->sculpt_tool, SCULPT_TOOL_DRAW, SCULPT_TOOL_CREASE, SCULPT_TOOL_BLOB, SCULPT_TOOL_LAYER, SCULPT_TOOL_INFLATE, SCULPT_TOOL_CLAY, SCULPT_TOOL_CLAY_TUBES, SCULPT_TOOL_ROTATE))
+ if(ELEM9(brush->sculpt_tool, SCULPT_TOOL_DRAW, SCULPT_TOOL_GRAVITY, SCULPT_TOOL_CREASE, SCULPT_TOOL_BLOB, SCULPT_TOOL_LAYER, SCULPT_TOOL_INFLATE, SCULPT_TOOL_CLAY, SCULPT_TOOL_CLAY_STRIPS, SCULPT_TOOL_ROTATE))
if(!(brush->flag & BRUSH_ACCUMULATE))
cache->original = 1;
@@ -2967,8 +3575,12 @@ static void sculpt_update_cache_invariants(bContext* C, Sculpt *sd, SculptSessio
cache->first_time= 1;
cache->vertex_rotation= 0;
+
+ cache->frontface_start= brush->frontface_angle;
+ cache->frontface_range= (brush->frontface_angle + M_PI_2) / 2 - cache->frontface_start;
}
+#if 0
static void sculpt_update_brush_delta(Sculpt *sd, Object *ob, Brush *brush)
{
SculptSession *ss = ob->sculpt;
@@ -2977,7 +3589,7 @@ static void sculpt_update_brush_delta(Sculpt *sd, Object *ob, Brush *brush)
if(ELEM5(tool,
SCULPT_TOOL_GRAB, SCULPT_TOOL_NUDGE,
- SCULPT_TOOL_CLAY_TUBES, SCULPT_TOOL_SNAKE_HOOK,
+ SCULPT_TOOL_CLAY_STRIPS, SCULPT_TOOL_SNAKE_HOOK,
SCULPT_TOOL_THUMB)) {
float grab_location[3], imat[4][4], delta[3];
@@ -3006,7 +3618,7 @@ static void sculpt_update_brush_delta(Sculpt *sd, Object *ob, Brush *brush)
mul_mat3_m4_v3(imat, delta);
add_v3_v3(cache->grab_delta, delta);
break;
- case SCULPT_TOOL_CLAY_TUBES:
+ case SCULPT_TOOL_CLAY_STRIPS:
case SCULPT_TOOL_NUDGE:
sub_v3_v3v3(cache->grab_delta, grab_location, cache->old_grab_location);
invert_m4_m4(imat, ob->obmat);
@@ -3040,6 +3652,7 @@ static void sculpt_update_brush_delta(Sculpt *sd, Object *ob, Brush *brush)
}
}
}
+#endif
/* Initialize the stroke cache variants from operator properties */
static void sculpt_update_cache_variants(bContext *C, Sculpt *sd, Object *ob, struct PaintStroke *stroke, PointerRNA *ptr)
@@ -3069,6 +3682,10 @@ static void sculpt_update_cache_variants(bContext *C, Sculpt *sd, Object *ob, st
brush coord/pressure/etc.
It's more an events design issue, which doesn't split coordinate/pressure/angle
changing events. We should avoid this after events system re-design */
+ /* XXX: jwilkins - I seem to remember pressure and thumb working just fine,
+ I need to investigate this further. Actually seems like grab/thumb should
+ totally ignore pressure, since grab should be based on pen position
+ and little else */
if(paint_space_stroke_enabled(brush) || cache->first_time)
cache->pressure = RNA_float_get(ptr, "pressure");
@@ -3090,7 +3707,7 @@ static void sculpt_update_cache_variants(bContext *C, Sculpt *sd, Object *ob, st
}
if (ELEM(brush->sculpt_tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_SNAKE_HOOK))
- cache->initial_radius *= 2.0f;
+ cache->initial_radius *= 1.5f;
}
if(brush_use_size_pressure(brush)) {
@@ -3105,8 +3722,8 @@ static void sculpt_update_cache_variants(bContext *C, Sculpt *sd, Object *ob, st
if(!(brush->flag & BRUSH_ANCHORED || ELEM4(brush->sculpt_tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_SNAKE_HOOK, SCULPT_TOOL_THUMB, SCULPT_TOOL_ROTATE))) {
copy_v2_v2(cache->tex_mouse, cache->mouse);
- if ( (brush->mtex.brush_map_mode == MTEX_MAP_MODE_FIXED) &&
- (brush->flag & BRUSH_RANDOM_ROTATION) &&
+ if (ELEM(brush->mtex.brush_map_mode, MTEX_MAP_MODE_FIXED, MTEX_MAP_MODE_WRAP) &&
+ (brush->flag & BRUSH_RANDOM_ROTATION) &&
!(brush->flag & BRUSH_RAKE))
{
cache->special_rotation = 2.0f*(float)M_PI*BLI_frand();
@@ -3127,8 +3744,8 @@ static void sculpt_update_cache_variants(bContext *C, Sculpt *sd, Object *ob, st
float halfway[2];
float out[3];
- halfway[0] = (float)dx * 0.5f + cache->initial_mouse[0];
- halfway[1] = (float)dy * 0.5f + cache->initial_mouse[1];
+ halfway[0] = (float)dx * 0.5f + cache->initial_mouse[0];
+ halfway[1] = (float)dy * 0.5f + cache->initial_mouse[1];
if (sculpt_stroke_get_location(C, stroke, out, halfway)) {
copy_v3_v3(sd->anchored_location, out);
@@ -3170,8 +3787,129 @@ static void sculpt_update_cache_variants(bContext *C, Sculpt *sd, Object *ob, st
}
}
- sculpt_update_brush_delta(sd, ob, brush);
+#if 1
+ /* Find the grab delta */
+ if(brush->sculpt_tool == SCULPT_TOOL_GRAB) {
+ float grab_location[3], imat[4][4];
+
+ if(cache->first_time)
+ copy_v3_v3(cache->orig_grab_location, cache->true_location);
+
+ /* compute 3d coordinate at same z from original location + mouse */
+ initgrabz(cache->vc->rv3d, cache->orig_grab_location[0],
+ cache->orig_grab_location[1], cache->orig_grab_location[2]);
+ ED_view3d_win_to_delta(cache->vc->ar, cache->mouse, grab_location);
+
+ /* compute delta to move verts by */
+ if(!cache->first_time) {
+ float delta[3];
+ sub_v3_v3v3(delta, grab_location, cache->old_grab_location);
+ invert_m4_m4(imat, ss->ob->obmat);
+ mul_mat3_m4_v3(imat, delta);
+ add_v3_v3(cache->grab_delta, delta);
+ }
+ else {
+ zero_v3(cache->grab_delta);
+ }
+
+ copy_v3_v3(cache->old_grab_location, grab_location);
+
+ /* location stays the same for finding vertices in brush radius */
+ copy_v3_v3(cache->true_location, cache->orig_grab_location);
+
+ sd->draw_anchored = 1;
+ copy_v3_v3(sd->anchored_location, cache->true_location);
+ copy_v3_v3(sd->anchored_initial_mouse, cache->initial_mouse);
+ sd->anchored_size = cache->pixel_radius;
+ }
+ /* Find the nudge/clay tubes delta */
+ else if(brush->sculpt_tool == SCULPT_TOOL_NUDGE) {
+ float grab_location[3], imat[4][4];
+
+ if(cache->first_time)
+ copy_v3_v3(cache->orig_grab_location, cache->true_location);
+
+ /* compute 3d coordinate at same z from original location + mouse */
+ initgrabz(cache->vc->rv3d, cache->orig_grab_location[0],
+ cache->orig_grab_location[1], cache->orig_grab_location[2]);
+ ED_view3d_win_to_delta(cache->vc->ar, cache->mouse, grab_location);
+
+ /* compute delta to move verts by */
+ if (!cache->first_time) {
+ sub_v3_v3v3(cache->grab_delta, grab_location, cache->old_grab_location);
+ invert_m4_m4(imat, ss->ob->obmat);
+ mul_mat3_m4_v3(imat, cache->grab_delta);
+ }
+ else {
+ zero_v3(cache->grab_delta);
+ }
+
+ copy_v3_v3(cache->old_grab_location, grab_location);
+ }
+ /* Find the snake hook delta */
+ else if(brush->sculpt_tool == SCULPT_TOOL_SNAKE_HOOK) {
+ float grab_location[3], imat[4][4];
+
+ if(cache->first_time)
+ copy_v3_v3(cache->orig_grab_location, cache->true_location);
+ else
+ add_v3_v3(cache->true_location, cache->grab_delta);
+
+ /* compute 3d coordinate at same z from original location + mouse */
+ initgrabz(cache->vc->rv3d, cache->orig_grab_location[0],
+ cache->orig_grab_location[1], cache->orig_grab_location[2]);
+ window_to_3d_delta(cache->vc->ar, grab_location, cache->mouse[0], cache->mouse[1]);
+
+ /* compute delta to move verts by */
+ if (!cache->first_time) {
+ sub_v3_v3v3(cache->grab_delta, grab_location, cache->old_grab_location);
+ invert_m4_m4(imat, ss->ob->obmat);
+ mul_mat3_m4_v3(imat, cache->grab_delta);
+ }
+ else {
+ zero_v3(cache->grab_delta);
+ }
+
+ copy_v3_v3(cache->old_grab_location, grab_location);
+ }
+ /* Find the thumb delta */
+ else if(brush->sculpt_tool == SCULPT_TOOL_THUMB) {
+ float grab_location[3], imat[4][4];
+
+ if(cache->first_time)
+ copy_v3_v3(cache->orig_grab_location, cache->true_location);
+
+ /* compute 3d coordinate at same z from original location + mouse */
+ initgrabz(cache->vc->rv3d, cache->orig_grab_location[0],
+ cache->orig_grab_location[1], cache->orig_grab_location[2]);
+ window_to_3d_delta(cache->vc->ar, grab_location, cache->mouse[0], cache->mouse[1]);
+
+ /* compute delta to move verts by */
+ if (!cache->first_time) {
+ float delta[3];
+ sub_v3_v3v3(delta, grab_location, cache->old_grab_location);
+ invert_m4_m4(imat, ss->ob->obmat);
+ mul_mat3_m4_v3(imat, delta);
+ add_v3_v3(cache->grab_delta, delta);
+ }
+ else {
+ zero_v3(cache->grab_delta);
+ }
+
+ copy_v3_v3(cache->old_grab_location, grab_location);
+
+ /* location stays the same for finding vertices in brush radius */
+ copy_v3_v3(cache->true_location, cache->orig_grab_location);
+ sd->draw_anchored = 1;
+ copy_v3_v3(sd->anchored_location, cache->orig_grab_location);
+ copy_v3_v3(sd->anchored_initial_mouse, cache->initial_mouse);
+ sd->anchored_size = cache->pixel_radius;
+ }
+ else
+#else
+ sculpt_update_brush_delta(sd, ob, brush);
+#endif
if(brush->sculpt_tool == SCULPT_TOOL_ROTATE) {
dx = cache->mouse[0] - cache->initial_mouse[0];
dy = cache->mouse[1] - cache->initial_mouse[1];
@@ -3185,6 +3923,30 @@ static void sculpt_update_cache_variants(bContext *C, Sculpt *sd, Object *ob, st
}
sd->special_rotation = cache->special_rotation;
+
+ if (brush->sculpt_tool == SCULPT_TOOL_CLAY_STRIPS || (brush->mtex.brush_map_mode == MTEX_MAP_MODE_WRAP && brush->flag & BRUSH_RAKE)) {
+ float rake_location[3], imat[4][4];
+
+ if(cache->first_time)
+ copy_v3_v3(cache->orig_rake_location, cache->true_location);
+
+ /* compute 3d coordinate at same z from original location + mouse */
+ initgrabz(cache->vc->rv3d, cache->orig_rake_location[0],
+ cache->orig_rake_location[1], cache->orig_rake_location[2]);
+ window_to_3d_delta(cache->vc->ar, rake_location, cache->mouse[0], cache->mouse[1]);
+
+ /* compute delta to move verts by */
+ if (!cache->first_time) {
+ sub_v3_v3v3(cache->rake_delta, rake_location, cache->old_rake_location);
+ invert_m4_m4(imat, ss->ob->obmat);
+ mul_mat3_m4_v3(imat, cache->rake_delta);
+ }
+ else {
+ zero_v3(cache->rake_delta);
+ }
+
+ copy_v3_v3(cache->old_rake_location, rake_location);
+ }
}
static void sculpt_stroke_modifiers_check(bContext *C, Object *ob)
@@ -3283,10 +4045,12 @@ static void sculpt_brush_init_tex(Sculpt *sd, SculptSession *ss)
/* TODO: Shouldn't really have to do this at the start of every
stroke, but sculpt would need some sort of notification when
changes are made to the texture. */
+ /* XXX: jwilkins - I recall adding a notification when the texture changes
+ that that I use for updating the overlay */
sculpt_update_tex(sd, ss);
}
-static int sculpt_brush_stroke_init(bContext *C, wmOperator *op)
+static int sculpt_brush_stroke_init(bContext *C, ReportList wmOperator *op)
{
Scene *scene= CTX_data_scene(C);
Object *ob= CTX_data_active_object(C);
@@ -3294,15 +4058,15 @@ static int sculpt_brush_stroke_init(bContext *C, wmOperator *op)
SculptSession *ss = CTX_data_active_object(C)->sculpt;
Brush *brush = paint_brush(&sd->paint);
int mode= RNA_enum_get(op->ptr, "mode");
- int is_smooth= 0;
view3d_operator_needs_opengl(C);
sculpt_brush_init_tex(sd, ss);
- is_smooth|= mode == BRUSH_STROKE_SMOOTH;
- is_smooth|= brush->sculpt_tool == SCULPT_TOOL_SMOOTH;
-
- sculpt_update_mesh_elements(scene, sd, ob, is_smooth);
+ sculpt_update_mesh_elements(
+ scene,
+ sd,
+ ob,
+ mode==BRUCH_STROKE_SMOOTH || brush->sculpt_tool==SCULPT_TOOL_SMOOTH);
return 1;
}
@@ -3431,6 +4195,10 @@ static int sculpt_stroke_test_start(bContext *C, struct wmOperator *op,
omp_set_num_threads(2*num_procs);
}
#endif
+ sd->sculpting= 1;
+
+ // redraw full screen at beginning of stroke so overlay can be erased
+ WM_main_add_notifier(NC_SPACE|ND_SPACE_VIEW3D, NULL);
return 1;
}
@@ -3443,7 +4211,7 @@ static void sculpt_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
Object *ob = CTX_data_active_object(C);
SculptSession *ss = ob->sculpt;
-
+
sculpt_stroke_modifiers_check(C, ob);
sculpt_update_cache_variants(C, sd, ob, stroke, itemptr);
sculpt_restore_mesh(sd, ss);
@@ -3472,21 +4240,24 @@ static void sculpt_stroke_done(bContext *C, struct PaintStroke *UNUSED(stroke))
sd->draw_anchored= 0;
sd->draw_pressure= 0;
sd->special_rotation= 0;
+ sd->sculpting= 0;
/* Finished */
if(ss->cache) {
- Brush *brush= paint_brush(&sd->paint);
- brush->flag &= ~BRUSH_INVERTED;
+ {
+ Brush *brush= paint_brush(&sd->paint);
+ brush->flag &= ~BRUSH_INVERTED;
+ }
sculpt_stroke_modifiers_check(C, ob);
/* Alt-Smooth */
if (ss->cache->alt_smooth) {
Paint *p= &sd->paint;
- brush= (Brush *)find_id("BR", ss->cache->saved_active_brush_name);
- if(brush) {
- paint_brush_set(p, brush);
- }
+ Brush* brush= (Brush *)find_id("BR", ss->cache->saved_active_brush_name);
+
+ if (brush)
+ paint_brush_set(p, br);
}
sculpt_cache_free(ss->cache);
@@ -3521,10 +4292,13 @@ static int sculpt_brush_stroke_invoke(bContext *C, wmOperator *op, wmEvent *even
if(!sculpt_brush_stroke_init(C, op))
return OPERATOR_CANCELLED;
- stroke = paint_stroke_new(C, sculpt_stroke_get_location,
- sculpt_stroke_test_start,
- sculpt_stroke_update_step,
- sculpt_stroke_done, event->type);
+ stroke= paint_stroke_new(
+ C,
+ sculpt_stroke_get_location,
+ sculpt_stroke_test_start,
+ sculpt_stroke_update_step,
+ sculpt_stroke_done,
+ event->type);
op->customdata = stroke;
@@ -3550,8 +4324,14 @@ static int sculpt_brush_stroke_exec(bContext *C, wmOperator *op)
if(!sculpt_brush_stroke_init(C, op))
return OPERATOR_CANCELLED;
- op->customdata = paint_stroke_new(C, sculpt_stroke_get_location, sculpt_stroke_test_start,
- sculpt_stroke_update_step, sculpt_stroke_done, 0);
+ op->customdata=
+ paint_stroke_new(
+ C,
+ sculpt_stroke_get_location,
+ sculpt_stroke_test_start,
+ sculpt_stroke_update_step,
+ sculpt_stroke_done,
+ 0);
/* frees op->customdata */
paint_stroke_exec(C, op);
@@ -3562,10 +4342,10 @@ static int sculpt_brush_stroke_exec(bContext *C, wmOperator *op)
static void SCULPT_OT_brush_stroke(wmOperatorType *ot)
{
static EnumPropertyItem stroke_mode_items[] = {
- {BRUSH_STROKE_NORMAL, "NORMAL", 0, "Normal", "Apply brush normally"},
- {BRUSH_STROKE_INVERT, "INVERT", 0, "Invert", "Invert action of brush for duration of stroke"},
- {BRUSH_STROKE_SMOOTH, "SMOOTH", 0, "Smooth", "Switch brush to smooth mode for duration of stroke"},
- {0}
+ { BRUSH_STROKE_NORMAL, "NORMAL", 0, "Normal", "Apply brush normally" },
+ { BRUSH_STROKE_INVERT, "INVERT", 0, "Invert", "Invert action of brush for duration of stroke" },
+ { BRUSH_STROKE_SMOOTH, "SMOOTH", 0, "Smooth", "Switch brush to smooth mode for duration of stroke" },
+ { 0 }
};
/* identifiers */
@@ -3697,12 +4477,16 @@ static void SCULPT_OT_sculptmode_toggle(wmOperatorType *ot)
/* api callbacks */
ot->exec= sculpt_toggle_mode;
ot->poll= ED_operator_object_active_editable_mesh;
-
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ // XXX: I don't think sculpt mode needs to register and
+ // it handles its own undo, but unsure how this should be set.
+ ot->flag= 0;
+ //ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
}
void ED_operatortypes_sculpt(void)
{
+ //WM_operatortype_append(SCULPT_OT_radial_control); // XXX: need to reimplement on-surface radial control
WM_operatortype_append(SCULPT_OT_brush_stroke);
WM_operatortype_append(SCULPT_OT_sculptmode_toggle);
WM_operatortype_append(SCULPT_OT_set_persistent_base);
diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c
index c4ea5c9478c..c58195b8d4a 100644
--- a/source/blender/editors/sculpt_paint/sculpt_undo.c
+++ b/source/blender/editors/sculpt_paint/sculpt_undo.c
@@ -1,5 +1,5 @@
/*
- * $Id$
+ * $Id: sculpt_undo.c 36485 2011-05-04 13:15:42Z nazgul $
*
* ***** BEGIN GPL LICENSE BLOCK *****
*
diff --git a/source/blender/editors/space_info/info_draw.c b/source/blender/editors/space_info/info_draw.c
index 3121ddaa3b4..50a23568bfd 100644
--- a/source/blender/editors/space_info/info_draw.c
+++ b/source/blender/editors/space_info/info_draw.c
@@ -1,5 +1,5 @@
/*
- * $Id$
+ * $Id: info_draw.c 35242 2011-02-27 20:29:51Z jesterking $
*
* ***** BEGIN GPL LICENSE BLOCK *****
*
diff --git a/source/blender/editors/space_info/info_report.c b/source/blender/editors/space_info/info_report.c
index 937b683e880..5a94e3bd148 100644
--- a/source/blender/editors/space_info/info_report.c
+++ b/source/blender/editors/space_info/info_report.c
@@ -1,5 +1,5 @@
/*
- * $Id$
+ * $Id: info_report.c 36644 2011-05-12 16:47:36Z campbellbarton $
*
* ***** BEGIN GPL LICENSE BLOCK *****
*
diff --git a/source/blender/editors/space_info/textview.c b/source/blender/editors/space_info/textview.c
index afe8aa39c16..bf4e4cacc5f 100644
--- a/source/blender/editors/space_info/textview.c
+++ b/source/blender/editors/space_info/textview.c
@@ -1,5 +1,5 @@
/*
- * $Id$
+ * $Id: textview.c 35242 2011-02-27 20:29:51Z jesterking $
*
* ***** BEGIN GPL LICENSE BLOCK *****
*
diff --git a/source/blender/editors/space_info/textview.h b/source/blender/editors/space_info/textview.h
index a30c082575a..a249bbd7be5 100644
--- a/source/blender/editors/space_info/textview.h
+++ b/source/blender/editors/space_info/textview.h
@@ -1,5 +1,5 @@
/*
- * $Id$
+ * $Id: textview.h 35242 2011-02-27 20:29:51Z jesterking $
*
* ***** BEGIN GPL LICENSE BLOCK *****
*
diff --git a/source/blender/editors/space_view3d/drawmesh.c b/source/blender/editors/space_view3d/drawmesh.c
index f070bae4e54..ce5fa4a518a 100644
--- a/source/blender/editors/space_view3d/drawmesh.c
+++ b/source/blender/editors/space_view3d/drawmesh.c
@@ -359,7 +359,7 @@ static void draw_textured_begin(Scene *scene, View3D *v3d, RegionView3D *rv3d, O
int istex, solidtex= 0;
// XXX scene->obedit warning
- if(v3d->drawtype==OB_SOLID || ((ob->mode & OB_MODE_EDIT) && v3d->drawtype!=OB_TEXTURE)) {
+ if(v3d->drawtype==OB_SOLID || ((ob->mode & OB_MODE_EDIT) && !ELEM(v3d->drawtype, OB_TEXTURE, OB_MATCAP))) {
/* draw with default lights in solid draw mode and edit mode */
solidtex= 1;
Gtexdraw.islit= -1;
@@ -375,7 +375,7 @@ static void draw_textured_begin(Scene *scene, View3D *v3d, RegionView3D *rv3d, O
obcol[3]= CLAMPIS(ob->col[3]*255, 0, 255);
glCullFace(GL_BACK); glEnable(GL_CULL_FACE);
- if(solidtex || v3d->drawtype==OB_TEXTURE) istex= 1;
+ if(solidtex || ELEM(v3d->drawtype, OB_TEXTURE, OB_MATCAP)) istex= 1;
else istex= 0;
Gtexdraw.ob = ob;
diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c
index d122f8f0642..bb49a9ea17f 100644
--- a/source/blender/editors/space_view3d/drawobject.c
+++ b/source/blender/editors/space_view3d/drawobject.c
@@ -104,7 +104,7 @@
/* this condition has been made more complex since editmode can draw textures */
#define CHECK_OB_DRAWTEXTURE(vd, dt) \
-((vd->drawtype==OB_TEXTURE && dt>OB_SOLID) || \
+((ELEM(vd->drawtype, OB_TEXTURE, OB_MATCAP) && dt>OB_SOLID) || \
(vd->drawtype==OB_SOLID && vd->flag2 & V3D_SOLID_TEX))
static void draw_bounding_volume(Scene *scene, Object *ob);
@@ -126,7 +126,7 @@ static int check_ob_drawface_dot(Scene *sce, View3D *vd, char dt)
return 1;
/* if its drawing textures with zbuf sel, then dont draw dots */
- if(dt==OB_TEXTURE && vd->drawtype==OB_TEXTURE)
+ if(ELEM(dt, OB_TEXTURE, OB_MATCAP) && ELEM(vd->drawtype, OB_TEXTURE, OB_MATCAP))
return 0;
if(vd->drawtype>=OB_SOLID && vd->flag2 & V3D_SOLID_TEX)
@@ -215,7 +215,7 @@ int draw_glsl_material(Scene *scene, Object *ob, View3D *v3d, int dt)
if(ob==OBACT && (ob && ob->mode & OB_MODE_WEIGHT_PAINT))
return 0;
- return (scene->gm.matmode == GAME_MAT_GLSL) && (dt >= OB_SHADED);
+ return ((dt == OB_MATCAP) || (scene->gm.matmode == GAME_MAT_GLSL)) && (dt >= OB_SHADED);
}
static int check_material_alpha(Base *base, Mesh *me, int glsl)
diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c
index fb67e38cbf7..cfb19fce12f 100644
--- a/source/blender/editors/space_view3d/space_view3d.c
+++ b/source/blender/editors/space_view3d/space_view3d.c
@@ -313,6 +313,9 @@ static void view3d_free(SpaceLink *sl)
}
BLI_freelistN(&vd->bgpicbase);
+ if (vd->matcap_ima)
+ vd->matcap_ima->id.us--;
+
if(vd->localvd) MEM_freeN(vd->localvd);
if(vd->properties_storage) MEM_freeN(vd->properties_storage);
@@ -349,6 +352,11 @@ static SpaceLink *view3d_duplicate(SpaceLink *sl)
if(bgpic->ima)
bgpic->ima->id.us++;
+ v3dn->matcap_ima= v3do->matcap_ima;
+
+ if (v3dn->matcap_ima)
+ v3dn->matcap_ima->id.us++;
+
v3dn->properties_storage= NULL;
return (SpaceLink *)v3dn;
diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c
index 573951da4ca..67035247038 100644
--- a/source/blender/editors/space_view3d/view3d_draw.c
+++ b/source/blender/editors/space_view3d/view3d_draw.c
@@ -2104,6 +2104,11 @@ CustomDataMask ED_viewedit_datamask(bScreen *screen)
if(sa->spacetype == SPACE_VIEW3D) {
mask |= ED_view3d_datamask(scene, (View3D *)sa->spacedata.first);
}
+ if(ELEM(view->drawtype, OB_TEXTURE, OB_MATCAP) || ((view->drawtype == OB_SOLID) && (view->flag2 & V3D_SOLID_TEX))) {
+ mask |= CD_MASK_MTFACE | CD_MASK_MCOL;
+
+ if(scene->gm.matmode == GAME_MAT_GLSL)
+ mask |= CD_MASK_ORCO;
}
/* check if we need mcols due to vertex paint or weightpaint */
diff --git a/source/blender/editors/space_view3d/view3d_fly.c b/source/blender/editors/space_view3d/view3d_fly.c
index fdee5c6f6d9..c61aa63f6e7 100644
--- a/source/blender/editors/space_view3d/view3d_fly.c
+++ b/source/blender/editors/space_view3d/view3d_fly.c
@@ -1,5 +1,5 @@
/*
- * $Id$
+ * $Id: view3d_fly.c 36824 2011-05-23 02:53:30Z campbellbarton $
*
* ***** BEGIN GPL LICENSE BLOCK *****
*
diff --git a/source/blender/gpu/intern/gpu_codegen.c b/source/blender/gpu/intern/gpu_codegen.c
index 470b99de00b..92ee80489bf 100644
--- a/source/blender/gpu/intern/gpu_codegen.c
+++ b/source/blender/gpu/intern/gpu_codegen.c
@@ -366,10 +366,14 @@ GPUFunction *GPU_lookup_function(const char *name)
void GPU_extensions_exit(void)
{
extern Material defmaterial; // render module abuse...
+ extern Material matcap_ma;
if(defmaterial.gpumaterial.first)
GPU_material_free(&defmaterial);
+ if(matcap_ma.gpumaterial.first)
+ GPU_material_free(&matcap_ma);
+
if(FUNCTION_HASH) {
BLI_ghash_free(FUNCTION_HASH, NULL, (GHashValFreeFP)MEM_freeN);
FUNCTION_HASH = NULL;
diff --git a/source/blender/gpu/intern/gpu_draw.c b/source/blender/gpu/intern/gpu_draw.c
index 0e7df43bd34..8005e231e39 100644
--- a/source/blender/gpu/intern/gpu_draw.c
+++ b/source/blender/gpu/intern/gpu_draw.c
@@ -1,5 +1,5 @@
-/*
* $Id$
+/*
*
* ***** BEGIN GPL LICENSE BLOCK *****
*
@@ -213,7 +213,7 @@ static int is_pow2_limit(int num)
/* XXX: texturepaint not global!
if (G.f & G_TEXTUREPAINT)
- return 1;*/
+ return 1;*/
if (U.glreslimit != 0 && num > U.glreslimit)
return 0;
@@ -953,6 +953,7 @@ static Material *gpu_active_node_material(Material *ma)
void GPU_begin_object_materials(View3D *v3d, RegionView3D *rv3d, Scene *scene, Object *ob, int glsl, int *do_alpha_pass)
{
+ extern Material matcap_ma;
Material *ma;
GPUMaterial *gpumat;
GPUBlendMode blendmode;
@@ -987,51 +988,70 @@ void GPU_begin_object_materials(View3D *v3d, RegionView3D *rv3d, Scene *scene, O
GMS.blendmode= GMS.blendmode_fixed;
}
- /* no materials assigned? */
- if(ob->totcol==0) {
+ if (MIN2(v3d->drawtype, ob->dt) != OB_MATCAP) {
+ /* no materials assigned? */
+ if(ob->totcol==0) {
gpu_material_to_fixed(&GMS.matbuf[0], &defmaterial, 0, ob);
- /* do material 1 too, for displists! */
+ /* do material 1 too, for displists! */
memcpy(&GMS.matbuf[1], &GMS.matbuf[0], sizeof(GPUMaterialFixed));
- if(glsl) {
- GMS.gmatbuf[0]= &defmaterial;
- GPU_material_from_blender(GMS.gscene, &defmaterial);
- }
+ if(glsl) {
+ GMS.gmatbuf[0]= &defmaterial;
+ GPU_material_from_blender(GMS.gscene, &defmaterial);
+ }
- GMS.blendmode[0]= GPU_BLEND_SOLID;
- }
-
- /* setup materials */
- for(a=1; a<=ob->totcol; a++) {
- /* find a suitable material */
- ma= give_current_material(ob, a);
- if(!glsl) ma= gpu_active_node_material(ma);
- if(ma==NULL) ma= &defmaterial;
-
- /* create glsl material if requested */
- gpumat = (glsl)? GPU_material_from_blender(GMS.gscene, ma): NULL;
-
- if(gpumat) {
- /* do glsl only if creating it succeed, else fallback */
- GMS.gmatbuf[a]= ma;
- blendmode = GPU_material_blend_mode(gpumat, ob->col);
+ GMS.blendmode[0]= GPU_BLEND_SOLID;
}
- else {
- /* fixed function opengl materials */
+
+ /* setup materials */
+ for(a=1; a<=ob->totcol; a++) {
+ /* find a suitable material */
+ ma= give_current_material(ob, a);
+ if(!glsl) ma= gpu_active_node_material(ma);
+ if(ma==NULL) ma= &defmaterial;
+
+ /* create glsl material if requested */
+ gpumat = (glsl)? GPU_material_from_blender(GMS.gscene, ma): NULL;
+
+ if(gpumat) {
+ /* do glsl only if creating it succeed, else fallback */
+ GMS.gmatbuf[a]= ma;
+ blendmode = GPU_material_blend_mode(gpumat, ob->col);
+ }
+ else {
+ /* fixed function opengl materials */
gpu_material_to_fixed(&GMS.matbuf[a], ma, gamma, ob);
- blendmode = (ma->alpha == 1.0f)? GPU_BLEND_SOLID: GPU_BLEND_ALPHA;
- if(do_alpha_pass && GMS.alphapass)
+ blendmode = (ma->alpha == 1.0f)? GPU_BLEND_SOLID: GPU_BLEND_ALPHA;
+ if(do_alpha_pass && GMS.alphapass)
GMS.matbuf[a].diff[3]= ma->alpha;
- else
+ else
GMS.matbuf[a].diff[3]= 1.0f;
+ }
+
+ /* setting do_alpha_pass = 1 indicates this object needs to be
+ * drawn in a second alpha pass for improved blending */
+ if(do_alpha_pass) {
+ GMS.blendmode[a]= blendmode;
+ if(ELEM(blendmode, GPU_BLEND_ALPHA, GPU_BLEND_ADD) && !GMS.alphapass)
+ *do_alpha_pass= 1;
+ }
}
+ }
+ else /* MatCap */ {
+ a = ob->totcol ? 1 : 0;
+
+ matcap_ma.mtex[0]->tex->ima= v3d->matcap_ima;
+
+ gpumat= GPU_material_from_blender(GMS.gscene, &matcap_ma);
+
+ GMS.gmatbuf[a]= &matcap_ma;
+ blendmode= GPU_material_blend_mode(gpumat, ob->col);
- /* setting do_alpha_pass = 1 indicates this object needs to be
- * drawn in a second alpha pass for improved blending */
if(do_alpha_pass) {
GMS.blendmode[a]= blendmode;
+
if(ELEM(blendmode, GPU_BLEND_ALPHA, GPU_BLEND_ADD) && !GMS.alphapass)
*do_alpha_pass= 1;
}
diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c
index e936f35574d..50e65b5ddbb 100644
--- a/source/blender/gpu/intern/gpu_material.c
+++ b/source/blender/gpu/intern/gpu_material.c
@@ -1049,7 +1049,7 @@ static void do_material_tex(GPUShadeInput *shi)
GPU_link(mat, "mtex_negate_texnormal", tnor, &tnor);
if(mtex->normapspace == MTEX_NSPACE_TANGENT)
- {
+ {
if(iFirstTimeNMap!=0)
{
// use unnormalized normal (this is how we bake it - closer to gamedev)
@@ -1065,7 +1065,7 @@ static void do_material_tex(GPUShadeInput *shi)
}
else
newnor = tnor;
-
+
norfac = MIN2(fabsf(mtex->norfac), 1.0f);
if(norfac == 1.0f && !GPU_link_changed(stencil)) {
@@ -1104,7 +1104,7 @@ static void do_material_tex(GPUShadeInput *shi)
iBumpSpacePrev = 0;
init_done = 1;
}
-
+
// find current bump space
if( mtex->texflag & MTEX_BUMP_OBJECTSPACE )
iBumpSpace = 1;
@@ -1427,11 +1427,13 @@ void GPU_materials_free(void)
Object *ob;
Material *ma;
extern Material defmaterial;
+ extern Material matcap_ma;
for(ma=G.main->mat.first; ma; ma=ma->id.next)
GPU_material_free(ma);
GPU_material_free(&defmaterial);
+ GPU_material_free(&matcap_ma);
for(ob=G.main->object.first; ob; ob=ob->id.next)
GPU_lamp_free(ob);
diff --git a/source/blender/makesdna/DNA_brush_types.h b/source/blender/makesdna/DNA_brush_types.h
index 3d143dc3d0f..9354d5fcdab 100644
--- a/source/blender/makesdna/DNA_brush_types.h
+++ b/source/blender/makesdna/DNA_brush_types.h
@@ -79,9 +79,12 @@ typedef struct Brush {
float alpha; /* opacity */
int sculpt_plane; /* the direction of movement for sculpt vertices */
+ float sculpt_plane_range; /* adjust the range for determining the sculpt plane normal and center */
float plane_offset; /* offset for plane brushes (clay, flatten, fill, scrape) */
+ float frontface_angle;
+
char sculpt_tool; /* active sculpt tool */
char vertexpaint_tool; /* active vertex/weight paint tool/blend mode */
char imagepaint_tool; /* active image paint tool */
@@ -91,14 +94,20 @@ typedef struct Brush {
float crease_pinch_factor;
+ float gravity_factor;
+
float plane_trim;
float height; /* affectable height of brush (layer height for layer tool, i.e.) */
+ float layer_distance, pad2;
+
float texture_sample_bias;
int texture_overlay_alpha;
float unprojected_radius;
+ float adaptive_space_factor;
+
float add_col[3];
float sub_col[3];
} Brush;
@@ -132,30 +141,33 @@ typedef struct Brush {
#define BRUSH_PLANE_TRIM (1<<26)
#define BRUSH_FRONTFACE (1<<27)
#define BRUSH_CUSTOM_ICON (1<<28)
+#define BRUSH_SYMMETRY_FEATHER (1<<29)
+#define BRUSH_LAYER (1<<30)
/* temporary flag which sets up autmatically for correct
brush drawing when inverted modal operator is running */
#define BRUSH_INVERTED (1<<29)
/* Brush.sculpt_tool */
-#define SCULPT_TOOL_DRAW 1
-#define SCULPT_TOOL_SMOOTH 2
-#define SCULPT_TOOL_PINCH 3
-#define SCULPT_TOOL_INFLATE 4
-#define SCULPT_TOOL_GRAB 5
-#define SCULPT_TOOL_LAYER 6
-#define SCULPT_TOOL_FLATTEN 7
-#define SCULPT_TOOL_CLAY 8
-#define SCULPT_TOOL_FILL 9
-#define SCULPT_TOOL_SCRAPE 10
-#define SCULPT_TOOL_NUDGE 11
-#define SCULPT_TOOL_THUMB 12
-#define SCULPT_TOOL_SNAKE_HOOK 13
-#define SCULPT_TOOL_ROTATE 14
-//#define SCULPT_TOOL_WAX 15 // XXX: reuse this slot later
-#define SCULPT_TOOL_CREASE 16
-#define SCULPT_TOOL_BLOB 17
-#define SCULPT_TOOL_CLAY_TUBES 18
+#define SCULPT_TOOL_DRAW 1
+#define SCULPT_TOOL_SMOOTH 2
+#define SCULPT_TOOL_PINCH 3
+#define SCULPT_TOOL_INFLATE 4
+#define SCULPT_TOOL_GRAB 5
+#define SCULPT_TOOL_LAYER 6
+#define SCULPT_TOOL_FLATTEN 7
+#define SCULPT_TOOL_CLAY 8
+#define SCULPT_TOOL_FILL 9
+#define SCULPT_TOOL_SCRAPE 10
+#define SCULPT_TOOL_NUDGE 11
+#define SCULPT_TOOL_THUMB 12
+#define SCULPT_TOOL_SNAKE_HOOK 13
+#define SCULPT_TOOL_ROTATE 14
+//#define SCULPT_TOOL_WAX 15 // XXX: reuse this slot later
+#define SCULPT_TOOL_CREASE 16
+#define SCULPT_TOOL_BLOB 17
+#define SCULPT_TOOL_CLAY_STRIPS 18
+#define SCULPT_TOOL_GRAVITY 19
/* ImagePaintSettings.tool */
#define PAINT_TOOL_DRAW 0
diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h
index 54a885a0860..66dc138d3ba 100644
--- a/source/blender/makesdna/DNA_object_types.h
+++ b/source/blender/makesdna/DNA_object_types.h
@@ -381,6 +381,7 @@ extern Object workob;
#define OB_SOLID 3
#define OB_SHADED 4
#define OB_TEXTURE 5
+#define OB_MATCAP 6
/* dtx: flags, char! */
#define OB_AXIS 2
diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h
index 657bfb1c884..ea990b1bc51 100644
--- a/source/blender/makesdna/DNA_scene_types.h
+++ b/source/blender/makesdna/DNA_scene_types.h
@@ -596,7 +596,7 @@ typedef struct Sculpt {
float special_rotation;
- int pad;
+ int sculpting;
} Sculpt;
typedef struct VPaint {
@@ -1157,7 +1157,7 @@ typedef enum SculptFlags {
SCULPT_LOCK_X = (1<<3),
SCULPT_LOCK_Y = (1<<4),
SCULPT_LOCK_Z = (1<<5),
- SCULPT_SYMMETRY_FEATHER = (1<<6),
+// SCULPT_SYMMETRY_FEATHER = (1<<6),// flag made per-brush, reuse flag later
SCULPT_USE_OPENMP = (1<<7),
SCULPT_ONLY_DEFORM = (1<<8),
} SculptFlags;
diff --git a/source/blender/makesdna/DNA_texture_types.h b/source/blender/makesdna/DNA_texture_types.h
index e81a9979c12..f6dd79c715f 100644
--- a/source/blender/makesdna/DNA_texture_types.h
+++ b/source/blender/makesdna/DNA_texture_types.h
@@ -489,6 +489,7 @@ typedef struct TexMapping {
#define MTEX_MAP_MODE_FIXED 0
#define MTEX_MAP_MODE_TILED 1
#define MTEX_MAP_MODE_3D 2
+#define MTEX_MAP_MODE_WRAP 3
/* **************** EnvMap ********************* */
diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h
index 1057eeae40f..2dd57e9628b 100644
--- a/source/blender/makesdna/DNA_userdef_types.h
+++ b/source/blender/makesdna/DNA_userdef_types.h
@@ -351,6 +351,7 @@ typedef struct UserDef {
short gp_settings;
short tb_leftmouse, tb_rightmouse;
struct SolidLight light[3];
+ short sculpt_paint_settings; /* user preferences for sculpt and paint */
short tw_hotspot, tw_flag, tw_handlesize, tw_size;
short textimeout,texcollectrate;
short wmdrawmethod; /* removed wmpad */
@@ -388,8 +389,7 @@ typedef struct UserDef {
struct ColorBand coba_weight; /* from texture.h */
- float sculpt_paint_overlay_col[3];
- int pad3;
+ float sculpt_paint_overlay_col[4];
char author[80]; /* author name for file formats supporting it */
} UserDef;
@@ -549,6 +549,11 @@ extern UserDef U; /* from blenkernel blender.c */
#define GP_PAINT_DOSMOOTH (1<<0)
#define GP_PAINT_DOSIMPLIFY (1<<1)
+/* sculpt_paint_settings */
+#define SCULPT_PAINT_USE_UNIFIED_SIZE (1<<0)
+#define SCULPT_PAINT_USE_UNIFIED_ALPHA (1<<1)
+#define SCULPT_PAINT_UNIFIED_LOCK_BRUSH_SIZE (1<<2)
+
/* color picker types */
#define USER_CP_CIRCLE 0
#define USER_CP_SQUARE_SV 1
diff --git a/source/blender/makesdna/DNA_view3d_types.h b/source/blender/makesdna/DNA_view3d_types.h
index 7379493003d..f90fbb24264 100644
--- a/source/blender/makesdna/DNA_view3d_types.h
+++ b/source/blender/makesdna/DNA_view3d_types.h
@@ -163,7 +163,7 @@ typedef struct View3D {
/**
* The drawing mode for the 3d display. Set to OB_WIRE, OB_SOLID,
- * OB_SHADED or OB_TEXTURE */
+ * OB_SHADED, OB_TEXTURE, or OB_MATCAP */
short drawtype;
short ob_centre_cursor; /* optional bool for 3d cursor to define center */
short scenelock, around;
@@ -198,6 +198,7 @@ typedef struct View3D {
/* XXX depricated? */
struct bGPdata *gpd; /* Grease-Pencil Data (annotation layers) */
+ struct Image *matcap_ima;
} View3D;
@@ -233,7 +234,7 @@ typedef struct View3D {
#define RV3D_VIEW_FRONT 1
#define RV3D_VIEW_BACK 2
#define RV3D_VIEW_LEFT 3
-#define RV3D_VIEW_RIGHT 4
+#define RV3D_VIEW_RIGHT 4
#define RV3D_VIEW_TOP 5
#define RV3D_VIEW_BOTTOM 6
#define RV3D_VIEW_PERSPORTHO 7
diff --git a/source/blender/makesrna/SConscript b/source/blender/makesrna/SConscript
index b706db5e64c..5ca67f929c5 100644
--- a/source/blender/makesrna/SConscript
+++ b/source/blender/makesrna/SConscript
@@ -54,6 +54,9 @@ if env['WITH_BF_PYTHON']:
if env['WITH_BF_COLLADA']:
defs.append('WITH_COLLADA')
+if env['WITH_BF_ONSURFACEBRUSH']:
+ defs.append('WITH_ONSURFACEBRUSH')
+
if env['OURPLATFORM'] == 'linux2':
cflags='-pthread'
incs += ' ../../../extern/binreloc/include'
diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c
index a6e26583a6a..d8eba424e94 100644
--- a/source/blender/makesrna/intern/rna_brush.c
+++ b/source/blender/makesrna/intern/rna_brush.c
@@ -49,11 +49,19 @@ static EnumPropertyItem prop_direction_items[]= {
{BRUSH_DIR_IN, "SUBTRACT", 0, "Subtract", "Subtract effect of brush"},
{0, NULL, 0, NULL, NULL}};
+static EnumPropertyItem texture_angle_source_items[] = {
+ {0, "USER", 0, "User", ""},
+ {BRUSH_RAKE, "RAKE", 0, "Rake", ""},
+ {BRUSH_RANDOM_ROTATION, "RANDOM", 0, "Random", ""},
+ {0, NULL, 0, NULL, NULL}};
+
EnumPropertyItem brush_sculpt_tool_items[] = {
{SCULPT_TOOL_BLOB, "BLOB", ICON_BRUSH_BLOB, "Blob", ""},
{SCULPT_TOOL_CLAY, "CLAY", ICON_BRUSH_CLAY, "Clay", ""},
+ {SCULPT_TOOL_CLAY_STRIPS, "CLAY_STRIPS", ICON_BRUSH_CLAY, "Clay Strips", ""},
{SCULPT_TOOL_CREASE, "CREASE",ICON_BRUSH_CREASE, "Crease", ""},
{SCULPT_TOOL_DRAW, "DRAW", ICON_BRUSH_SCULPT_DRAW, "Draw", ""},
+ {SCULPT_TOOL_GRAVITY, "GRAVITY", ICON_BRUSH_SCULPT_DRAW, "Gravity", ""},
{SCULPT_TOOL_FILL, "FILL", ICON_BRUSH_FILL, "Fill", ""},
{SCULPT_TOOL_FLATTEN, "FLATTEN", ICON_BRUSH_FLATTEN, "Flatten", ""},
{SCULPT_TOOL_GRAB, "GRAB", ICON_BRUSH_GRAB, "Grab", ""},
@@ -120,7 +128,13 @@ static void rna_Brush_update(Main *bmain, Scene *scene, PointerRNA *ptr)
{
Brush *br= (Brush*)ptr->data;
WM_main_add_notifier(NC_BRUSH|NA_EDITED, br);
- //WM_main_add_notifier(NC_SPACE|ND_SPACE_VIEW3D, NULL);
+}
+
+static void rna_Brush_texture_overlay_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+ Brush *br= (Brush*)ptr->data;
+ WM_main_add_notifier(NC_BRUSH|NA_EDITED, br);
+ WM_main_add_notifier(NC_SPACE|ND_SPACE_VIEW3D, NULL);
}
static void rna_Brush_sculpt_tool_update(Main *bmain, Scene *scene, PointerRNA *ptr)
@@ -295,6 +309,26 @@ static EnumPropertyItem *rna_Brush_direction_itemf(bContext *C, PointerRNA *ptr,
}
}
+static EnumPropertyItem *rna_Brush_texture_angle_source_itemf(bContext *C, PointerRNA *ptr, int *free)
+{
+ Brush *me= (Brush*)(ptr->data);
+
+ static EnumPropertyItem texture_angle_source_no_random_items[] = {
+ {0, "USER", 0, "User", ""},
+ {BRUSH_RAKE, "RAKE", 0, "Rake", ""},
+ {0, NULL, 0, NULL, NULL}};
+
+ if (!(me->flag & BRUSH_ANCHORED) &&
+ !ELEM4(me->sculpt_tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_SNAKE_HOOK, SCULPT_TOOL_THUMB, SCULPT_TOOL_ROTATE) &&
+ ELEM(me->mtex.brush_map_mode, MTEX_MAP_MODE_FIXED, MTEX_MAP_MODE_WRAP))
+ {
+ return texture_angle_source_items;
+ }
+ else {
+ return texture_angle_source_no_random_items;
+ }
+}
+
#else
static void rna_def_brush_texture_slot(BlenderRNA *brna)
@@ -303,6 +337,7 @@ static void rna_def_brush_texture_slot(BlenderRNA *brna)
PropertyRNA *prop;
static EnumPropertyItem prop_map_mode_items[] = {
+ {MTEX_MAP_MODE_WRAP, "WRAP", 0, "Wrap", ""},
{MTEX_MAP_MODE_FIXED, "FIXED", 0, "Fixed", ""},
{MTEX_MAP_MODE_TILED, "TILED", 0, "Tiled", ""},
{MTEX_MAP_MODE_3D, "3D", 0, "3D", ""},
@@ -349,17 +384,6 @@ static void rna_def_brush(BlenderRNA *brna)
{BRUSH_AIRBRUSH, "AIRBRUSH", 0, "Airbrush", "Keep applying paint effect while holding mouse (spray)"},
{0, NULL, 0, NULL, NULL}};
- static EnumPropertyItem texture_angle_source_items[] = {
- {0, "USER", 0, "User", "Rotate the brush texture by given angle"},
- {BRUSH_RAKE, "RAKE", 0, "Rake", "Rotate the brush texture to match the stroke direction"},
- {BRUSH_RANDOM_ROTATION, "RANDOM", 0, "Random", "Rotate the brush texture at random"},
- {0, NULL, 0, NULL, NULL}};
-
- static EnumPropertyItem texture_angle_source_no_random_items[] = {
- {0, "USER", 0, "User", "Rotate the brush texture by given angle"},
- {BRUSH_RAKE, "RAKE", 0, "Rake", "Rotate the brush texture to match the stroke direction"},
- {0, NULL, 0, NULL, NULL}};
-
static EnumPropertyItem brush_sculpt_plane_items[] = {
{SCULPT_DISP_DIR_AREA, "AREA", 0, "Area Plane", ""},
{SCULPT_DISP_DIR_VIEW, "VIEW", 0, "View Plane", ""},
@@ -411,12 +435,7 @@ static void rna_def_brush(BlenderRNA *brna)
prop= RNA_def_property(srna, "texture_angle_source_random", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag");
RNA_def_property_enum_items(prop, texture_angle_source_items);
- RNA_def_property_ui_text(prop, "Texture Angle Source", "");
- RNA_def_property_update(prop, 0, "rna_Brush_update");
-
- prop= RNA_def_property(srna, "texture_angle_source_no_random", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag");
- RNA_def_property_enum_items(prop, texture_angle_source_no_random_items);
+ RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_Brush_texture_angle_source_itemf");
RNA_def_property_ui_text(prop, "Texture Angle Source", "");
RNA_def_property_update(prop, 0, "rna_Brush_update");
@@ -450,7 +469,7 @@ static void rna_def_brush(BlenderRNA *brna)
RNA_def_property_int_sdna(prop, NULL, "spacing");
RNA_def_property_range(prop, 1, 1000);
RNA_def_property_ui_range(prop, 1, 500, 5, 0);
- RNA_def_property_ui_text(prop, "Spacing", "Spacing between brush daubs as a percentage of brush diameter");
+ RNA_def_property_ui_text(prop, "Spacing", "Spacing between brush dabs as a percentage of brush diameter");
RNA_def_property_update(prop, 0, "rna_Brush_update");
prop= RNA_def_property(srna, "smooth_stroke_radius", PROP_INT, PROP_DISTANCE);
@@ -536,6 +555,37 @@ static void rna_def_brush(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Autosmooth", "Amount of smoothing to automatically apply to each stroke");
RNA_def_property_update(prop, 0, "rna_Brush_update");
+ prop= RNA_def_property(srna, "gravity_factor", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "gravity_factor");
+ RNA_def_property_float_default(prop, 0);
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.001, 0.001);
+ RNA_def_property_ui_text(prop, "Gravity", "Amount of gravity to apply to each stroke");
+ RNA_def_property_update(prop, 0, "rna_Brush_update");
+
+ prop= RNA_def_property(srna, "sculpt_plane_range", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "sculpt_plane_range");
+ RNA_def_property_range(prop, 0, 10);
+ RNA_def_property_float_default(prop, 1);
+ RNA_def_property_ui_range(prop, 0, 2, 0, 0);
+ RNA_def_property_ui_text(prop, "Sculpt Plane Range", "Determines the range, in brush radii, to sample vertexes when determining the area sculpt plane");
+ RNA_def_property_update(prop, 0, "rna_Brush_update");
+
+ prop= RNA_def_property(srna, "frontface_angle", PROP_FLOAT, PROP_ANGLE);
+ RNA_def_property_float_sdna(prop, NULL, "frontface_angle");
+ RNA_def_property_range(prop, 0, 90);
+ RNA_def_property_float_default(prop, 80);
+ RNA_def_property_ui_text(prop, "Front-Face Angle", "Angle where effect of brush starts to be reduced to prevent it affecting back-faces");
+ RNA_def_property_update(prop, 0, "rna_Brush_update");
+
+ prop= RNA_def_property(srna, "layer_distance", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "layer_distance");
+ RNA_def_property_float_default(prop, 0);
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.001, 0.001);
+ RNA_def_property_ui_text(prop, "Layer Distance", "Limit to how far a vertex can travel in a single stroke as a fraction of brush radius");
+ RNA_def_property_update(prop, 0, "rna_Brush_update");
+
/* flag */
prop= RNA_def_property(srna, "use_airbrush", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_AIRBRUSH);
@@ -610,6 +660,16 @@ static void rna_def_brush(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Use Front-Face", "Brush only affects vertexes that face the viewer");
RNA_def_property_update(prop, 0, "rna_Brush_update");
+ prop= RNA_def_property(srna, "use_symmetry_feather", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_SYMMETRY_FEATHER);
+ RNA_def_property_ui_text(prop, "Symmetry Feathering", "Reduce the strength of the brush where it overlaps symmetrical dabs");
+ RNA_def_property_update(prop, 0, "rna_Brush_update");
+
+ prop= RNA_def_property(srna, "use_layer", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_LAYER);
+ RNA_def_property_ui_text(prop, "Use Layer", "Sets a limit on how far a vertex can travel during a single stroke");
+ RNA_def_property_update(prop, 0, "rna_Brush_update");
+
prop= RNA_def_property(srna, "use_anchor", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_ANCHORED);
RNA_def_property_ui_text(prop, "Anchored", "Keep the brush anchored to the initial location");
@@ -640,10 +700,9 @@ static void rna_def_brush(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Use Automatic Strength Adjustment", "Automatically adjusts strength to give consistent results for different spacings");
RNA_def_property_update(prop, 0, "rna_Brush_update");
- /* adaptive space is not implemented yet */
prop= RNA_def_property(srna, "use_adaptive_space", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_ADAPTIVE_SPACE);
- RNA_def_property_ui_text(prop, "Adaptive Spacing", "Space daubs according to surface orientation instead of screen space");
+ RNA_def_property_ui_text(prop, "Adaptive Spacing", "Space dabs according to surface orientation instead of screen space");
RNA_def_property_update(prop, 0, "rna_Brush_update");
prop= RNA_def_property(srna, "use_locked_size", PROP_BOOLEAN, PROP_NONE);
@@ -655,7 +714,7 @@ static void rna_def_brush(BlenderRNA *brna)
prop= RNA_def_property(srna, "use_texture_overlay", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_TEXTURE_OVERLAY);
RNA_def_property_ui_text(prop, "Use Texture Overlay", "Show texture in viewport");
- RNA_def_property_update(prop, 0, "rna_Brush_update");
+ RNA_def_property_update(prop, 0, "rna_Brush_texture_overlay_update");
prop= RNA_def_property(srna, "use_edge_to_edge", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_EDGE_TO_EDGE);
@@ -711,13 +770,13 @@ static void rna_def_brush(BlenderRNA *brna)
RNA_def_property_pointer_sdna(prop, NULL, "mtex.tex");
RNA_def_property_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Texture", "");
- RNA_def_property_update(prop, NC_TEXTURE, "rna_Brush_update");
+ RNA_def_property_update(prop, NC_TEXTURE, "rna_Brush_texture_overlay_update");
prop= RNA_def_property(srna, "texture_overlay_alpha", PROP_INT, PROP_PERCENTAGE);
RNA_def_property_int_sdna(prop, NULL, "texture_overlay_alpha");
RNA_def_property_range(prop, 1, 100);
RNA_def_property_ui_text(prop, "Texture Overlay Alpha", "");
- RNA_def_property_update(prop, 0, "rna_Brush_update");
+ RNA_def_property_update(prop, 0, "rna_Brush_texture_overlay_update");
prop= RNA_def_property(srna, "cursor_color_add", PROP_FLOAT, PROP_COLOR);
RNA_def_property_float_sdna(prop, NULL, "add_col");
diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c
index 5e1b22dbc9e..7bf53f74fd8 100644
--- a/source/blender/makesrna/intern/rna_object.c
+++ b/source/blender/makesrna/intern/rna_object.c
@@ -1720,6 +1720,7 @@ static void rna_def_object(BlenderRNA *brna)
{OB_SOLID, "SOLID", 0, "Solid", "Draw the object as a solid (If solid drawing is enabled in the viewport)"},
// disabled {OB_SHADED, "SHADED", 0, "Shaded", ""},
{OB_TEXTURE, "TEXTURED", 0, "Textured", "Draw the object with textures (If textures are enabled in the viewport)"},
+ {OB_MATCAP, "MATCAP", 0, "MatCap", ""},
{0, NULL, 0, NULL, NULL}};
static EnumPropertyItem boundtype_items[] = {
diff --git a/source/blender/makesrna/intern/rna_sculpt_paint.c b/source/blender/makesrna/intern/rna_sculpt_paint.c
index 452131d829c..be5b41a7b64 100644
--- a/source/blender/makesrna/intern/rna_sculpt_paint.c
+++ b/source/blender/makesrna/intern/rna_sculpt_paint.c
@@ -194,6 +194,20 @@ static void rna_Sculpt_update(Main *bmain, Scene *scene, PointerRNA *ptr)
}
}
+static int rna_Paint_is_on_surface_brush_capable(Paint* unused)
+{
+#ifdef WITH_ONSURFACEBRUSH
+ int bits;
+
+ (void)unused;
+
+ glGetIntegerv(GL_STENCIL_BITS, &bits);
+ return bits > 0;
+#else
+ return 0;
+#endif
+}
+
#else
static void rna_def_paint(BlenderRNA *brna)
@@ -201,6 +215,9 @@ static void rna_def_paint(BlenderRNA *brna)
StructRNA *srna;
PropertyRNA *prop;
+ FunctionRNA *func;
+ PropertyRNA *parm;
+
srna= RNA_def_struct(brna, "Paint", NULL);
RNA_def_struct_ui_text(srna, "Paint", "");
@@ -222,6 +239,12 @@ static void rna_def_paint(BlenderRNA *brna)
prop= RNA_def_property(srna, "show_low_resolution", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", PAINT_FAST_NAVIGATE);
RNA_def_property_ui_text(prop, "Fast Navigate", "For multires, show low resolution while navigating the view");
+
+ /* functions */
+ func= RNA_def_function(srna, "is_on_surface_brush_capable", "rna_Paint_is_on_surface_brush_capable");
+ RNA_def_function_ui_description(func, "Returns true if on-surface brush is configured and all capabilities are present.");
+ parm= RNA_def_boolean(func, "ret", 0, "", "");
+ RNA_def_function_return(func, parm);
}
static void rna_def_sculpt(BlenderRNA *brna)
@@ -263,10 +286,6 @@ static void rna_def_sculpt(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "flags", SCULPT_LOCK_Z);
RNA_def_property_ui_text(prop, "Lock Z", "Disallow changes to the Z axis of vertices");
- prop= RNA_def_property(srna, "use_symmetry_feather", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flags", SCULPT_SYMMETRY_FEATHER);
- RNA_def_property_ui_text(prop, "Symmetry Feathering", "Reduce the strength of the brush where it overlaps symmetrical daubs");
-
prop= RNA_def_property(srna, "use_threaded", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", SCULPT_USE_OPENMP);
RNA_def_property_ui_text(prop, "Use OpenMP", "Take advantage of multiple CPU cores to improve sculpting performance");
@@ -289,7 +308,7 @@ static void rna_def_vertex_paint(BlenderRNA *brna)
prop= RNA_def_property(srna, "use_all_faces", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", VP_AREA);
RNA_def_property_ui_text(prop, "All Faces", "Paint on all faces inside brush");
-
+
prop= RNA_def_property(srna, "use_normal", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", VP_NORMALS);
RNA_def_property_ui_text(prop, "Normals", "Applies the vertex normal before painting");
diff --git a/source/blender/makesrna/intern/rna_sequencer_api.c b/source/blender/makesrna/intern/rna_sequencer_api.c
index d2c2787784b..4ea6ae9f6a1 100644
--- a/source/blender/makesrna/intern/rna_sequencer_api.c
+++ b/source/blender/makesrna/intern/rna_sequencer_api.c
@@ -1,5 +1,5 @@
/*
- * $Id$
+ * $Id: rna_sequencer_api.c 35238 2011-02-27 20:20:01Z jesterking $
*
* ***** BEGIN GPL LICENSE BLOCK *****
*
diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c
index 463df7ae233..17e44c14b44 100644
--- a/source/blender/makesrna/intern/rna_space.c
+++ b/source/blender/makesrna/intern/rna_space.c
@@ -100,6 +100,7 @@ EnumPropertyItem viewport_shade_items[] = {
{OB_SOLID, "SOLID", ICON_SOLID, "Solid", "Display the object solid, lit with default OpenGL lights"},
//{OB_SHADED, "SHADED", ICON_SMOOTH, "Shaded", "Display the object solid, with preview shading interpolated at vertices"},
{OB_TEXTURE, "TEXTURED", ICON_POTATO, "Textured", "Display the object solid, with face-assigned textures"},
+ {OB_MATCAP, "MATCAP", ICON_SMOOTH, "MatCap", "Display the object solid, with MatCap texture"},
{0, NULL, 0, NULL, NULL}};
#ifdef RNA_RUNTIME
@@ -834,6 +835,14 @@ static float rna_BackgroundImage_opacity_get(PointerRNA *ptr)
return 1.0f-bgpic->blend;
}
+static void rna_View3D_matcap_image_changed(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+ extern Material matcap_ma;
+
+ if(matcap_ma.gpumaterial.first)
+ GPU_material_free(&matcap_ma);
+}
+
static void rna_BackgroundImage_opacity_set(PointerRNA *ptr, float value)
{
BGpic *bgpic= (BGpic *)ptr->data;
@@ -1392,6 +1401,13 @@ static void rna_def_space_view3d(BlenderRNA *brna)
RNA_def_property_pointer_funcs(prop, "rna_SpaceView3D_region_quadview_get", NULL, NULL, NULL);
RNA_def_property_ui_text(prop, "Quad View Region", "3D region that defines the quad view settings");
+ prop= RNA_def_property(srna, "matcap_image", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "matcap_ima");
+ RNA_def_property_struct_type(prop, "Image");
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "MatCap Image", "");
+ RNA_def_property_update(prop, NC_SPACE|ND_SPACE_VIEW3D, "rna_View3D_matcap_image_changed");
+
/* region */
srna= RNA_def_struct(brna, "RegionView3D", NULL);
diff --git a/source/blender/makesrna/intern/rna_texture.c b/source/blender/makesrna/intern/rna_texture.c
index 3a80207ba15..9cf710976f8 100644
--- a/source/blender/makesrna/intern/rna_texture.c
+++ b/source/blender/makesrna/intern/rna_texture.c
@@ -191,6 +191,7 @@ void rna_TextureSlot_update(Main *bmain, Scene *scene, PointerRNA *ptr)
break;
case ID_BR:
WM_main_add_notifier(NC_BRUSH, id);
+ WM_main_add_notifier(NC_SPACE|ND_SPACE_VIEW3D, NULL);
break;
case ID_PA:
{
diff --git a/source/blender/makesrna/rna_cleanup/rna_cleaner.py b/source/blender/makesrna/rna_cleanup/rna_cleaner.py
deleted file mode 100755
index ae17ade36d7..00000000000
--- a/source/blender/makesrna/rna_cleanup/rna_cleaner.py
+++ /dev/null
@@ -1,321 +0,0 @@
-#! /usr/bin/env python3.1
-
-"""
-This script is used to help cleaning RNA api.
-
-Typical line in the input file (elements in [] are optional).
-
-[comment *] ToolSettings.snap_align_rotation -> use_snap_align_rotation: boolean [Align rotation with the snapping target]
-
-Geterate output format from blender run this:
- ./blender.bin --background --python ./release/scripts/modules/rna_info.py 2> source/blender/makesrna/rna_cleanup/out.txt
-"""
-
-
-def font_bold(mystring):
- """
- Formats the string as bold, to be used in printouts.
- """
- font_bold = "\033[1m"
- font_reset = "\033[0;0m"
- return font_bold + mystring + font_reset
-
-
-def usage():
- """
- Prints script usage.
- """
- import sys
- scriptname = sys.argv[0]
- sort_choices_string = '|'.join(sort_choices)
- message = "\nUSAGE:"
- message += "\n%s input-file (.txt|.py) order-priority (%s).\n" % (font_bold(scriptname), sort_choices_string)
- message += "%s -h for help\n" % font_bold(scriptname)
- print(message)
- exit()
-
-
-def help():
- """
- Prints script' help.
- """
- message = '\nHELP:'
- message += '\nRun this script to re-format the edits you make in the input file.\n'
- message += 'Do quick modification to important fields like \'to\' and don\'t care about fields like \'changed\' or \'description\' and save.\n'
- message += 'The script outputs 3 files:\n'
- message += ' 1) *_clean.txt: is formatted same as the .txt input, can be edited by user.\n'
- message += ' 2) *_clean.py: is formatted same as the .py input, can be edited by user.\n'
- message += ' 3) rna_api.py is not formatted for readability and go under complete check. Can be used for rna cleanup.\n'
- print(message)
- usage()
-
-
-def check_commandline():
- """
- Takes parameters from the commandline.
- """
- import sys
- # Usage
- if len(sys.argv)==1 or len(sys.argv)>3:
- usage()
- if sys.argv[1] == '-h':
- help()
- elif not (sys.argv[1].endswith(".txt") or sys.argv[1].endswith(".py")):
- print ('\nBad input file extension... exiting.')
- usage()
- else:
- inputfile = sys.argv[1]
- if len(sys.argv) == 2:
- sort_priority = default_sort_choice
- print ('\nSecond parameter missing: choosing to order by %s.' % font_bold(sort_priority))
- elif len(sys.argv)==3:
- sort_priority = sys.argv[2]
- if sort_priority not in sort_choices:
- print('\nWrong sort_priority... exiting.')
- usage()
- return (inputfile, sort_priority)
-
-
-def check_prefix(prop, btype):
- # reminder: props=[comment, changed, bclass, bfrom, bto, kwcheck, btype, description]
- if btype == "boolean":
- if '_' in prop:
- prefix = prop.split('_')[0]
- if prefix not in kw_prefixes:
- return 'BAD-PREFIX: ' + prefix
- else:
- return prefix + '_'
- elif prop in kw:
- return 'SPECIAL-KEYWORD: ' + prop
- else:
- return 'BAD-KEYWORD: ' + prop
- else:
- return ""
-
-
-def check_if_changed(a,b):
- if a != b: return 'changed'
- else: return 'same'
-
-
-def get_props_from_txt(input_filename):
- """
- If the file is *.txt, the script assumes it is formatted as outlined in this script docstring
- """
-
- file=open(input_filename,'r')
- file_lines=file.readlines()
- file.close()
-
- props_list=[]
- props_length_max=[0,0,0,0,0,0,0,0]
-
- done_text = "+"
- done = 0
- tot = 0
-
- for iii, line in enumerate(file_lines):
-
- # debug
- #print(line)
- line_strip = line.strip()
- # empty line or comment
- if not line_strip:
- continue
-
- if line_strip == "EOF":
- break
-
- if line.startswith("#"):
- line = line[1:]
-
- # class
- [bclass, tail] = [x.strip() for x in line.split('.', 1)]
-
- # comment
- if '*' in bclass:
- [comment, bclass] = [x.strip() for x in bclass.split('*', 1)]
- else:
- comment= ''
-
- # skipping the header if we have one.
- # the header is assumed to be "NOTE * CLASS.FROM -> TO: TYPE DESCRIPTION"
- if comment == 'NOTE' and bclass == 'CLASS':
- continue
-
- # from
- [bfrom, tail] = [x.strip() for x in tail.split('->', 1)]
-
- # to
- [bto, tail] = [x.strip() for x in tail.split(':', 1)]
-
- # type, description
- try:
- [btype, description] = tail.split(None, 1)
- # make life easy and strip quotes
- description = description.replace("'", "").replace('"', "").replace("\\", "").strip()
- except ValueError:
- [btype, description] = [tail,'NO DESCRIPTION']
-
- # keyword-check
- kwcheck = check_prefix(bto, btype)
-
- # changed
- changed = check_if_changed(bfrom, bto)
-
- # lists formatting
- props=[comment, changed, bclass, bfrom, bto, kwcheck, btype, description]
- props_list.append(props)
- props_length_max=list(map(max,zip(props_length_max,list(map(len,props)))))
-
- if done_text in comment:
- done += 1
- tot += 1
-
- print("Total done %.2f" % (done / tot * 100.0) )
-
- return (props_list,props_length_max)
-
-
-def get_props_from_py(input_filename):
- """
- If the file is *.py, the script assumes it contains a python list (as "rna_api=[...]")
- This means that this script executes the text in the py file with an exec(text).
- """
- # adds the list "rna_api" to this function's scope
- rna_api = __import__(input_filename[:-3]).rna_api
-
- props_length_max = [0 for i in rna_api[0]] # this way if the vector will take more elements we are safe
- for index,props in enumerate(rna_api):
- comment, changed, bclass, bfrom, bto, kwcheck, btype, description = props
- kwcheck = check_prefix(bto, btype) # keyword-check
- changed = check_if_changed(bfrom, bto) # changed?
- description = repr(description)
- description = description.replace("'", "").replace('"', "").replace("\\", "").strip()
- rna_api[index] = [comment, changed, bclass, bfrom, bto, kwcheck, btype, description]
- props_length = list(map(len,props)) # lengths
- props_length_max = list(map(max,zip(props_length_max,props_length))) # max lengths
- return (rna_api,props_length_max)
-
-
-def get_props(input_filename):
- if input_filename.endswith(".txt"):
- props_list,props_length_max = get_props_from_txt(input_filename)
- elif input_filename.endswith(".py"):
- props_list,props_length_max = get_props_from_py(input_filename)
- return (props_list,props_length_max)
-
-
-def sort(props_list, sort_priority):
- """
- reminder
- props=[comment, changed, bclass, bfrom, bto, kwcheck, btype, description]
- """
-
- # order based on the i-th element in lists
- if sort_priority == "class.to":
- props_list = sorted(props_list, key=lambda p: (p[2], p[4]))
- else:
- i = sort_choices.index(sort_priority)
- if i == 0:
- props_list = sorted(props_list, key=lambda p: p[i], reverse=True)
- else:
- props_list = sorted(props_list, key=lambda p: p[i])
-
- print ('\nSorted by %s.' % font_bold(sort_priority))
- return props_list
-
-
-def file_basename(input_filename):
- # if needed will use os.path
- if input_filename.endswith(".txt"):
- if input_filename.endswith("_work.txt"):
- base_filename = input_filename.replace("_work.txt", "")
- else:
- base_filename = input_filename.replace(".txt", "")
- elif input_filename.endswith(".py"):
- if input_filename.endswith("_work.py"):
- base_filename = input_filename.replace("_work.py", "")
- else:
- base_filename = input_filename.replace(".py", "")
-
- return base_filename
-
-
-def write_files(basename, props_list, props_length_max):
- """
- Writes in 3 files:
- * output_filename_work.txt: formatted as txt input file (can be edited)
- * output_filename_work.py: formatted for readability (can be edited)
- * rna_api.py: unformatted, just as final output
- """
-
- f_rna = open("rna_api.py",'w')
- f_txt = open(basename + '_work.txt','w')
- f_py = open(basename + '_work.py','w')
-
- # reminder: props=[comment, changed, bclass, bfrom, bto, kwcheck, btype, description]
- # [comment *] ToolSettings.snap_align_rotation -> use_snap_align_rotation: boolean [Align rotation with the snapping target]
- rna = py = txt = ''
- props_list = [['NOTE', 'CHANGED', 'CLASS', 'FROM', 'TO', 'KEYWORD-CHECK', 'TYPE', 'DESCRIPTION']] + props_list
- for props in props_list:
- #txt
-
- # quick way we can tell if it changed
- if props[3] == props[4]: txt += "#"
- else: txt += " "
-
- if props[0] != '': txt += '%s * ' % props[0] # comment
- txt += '%s.%s -> %s: %s "%s"\n' % tuple(props[2:5] + props[6:]) # skipping keyword-check
- # rna_api
- if props[0] == 'NOTE': indent = '# '
- else: indent = ' '
- rna += indent + '("%s", "%s", "%s", "%s", "%s"),\n' % tuple(props[2:5] + props[6:]) # description is already string formatted
- # py
- blanks = [' '* (x[0]-x[1]) for x in zip(props_length_max,list(map(len,props)))]
- props = [('"%s"%s' if props[-1] != x[0] else "%s%s") % (x[0],x[1]) for x in zip(props,blanks)]
- py += indent + '(%s, %s, %s, %s, %s, %s, %s, "%s"),\n' % tuple(props)
-
- f_txt.write(txt)
- f_py.write("rna_api = [\n%s]\n" % py)
- f_rna.write("rna_api = [\n%s]\n" % rna)
-
- # write useful py script, wont hurt
- f_py.write("\n'''\n")
- f_py.write("for p_note, p_changed, p_class, p_from, p_to, p_check, p_type, p_desc in rna_api:\n")
- f_py.write(" print(p_to)\n")
- f_py.write("\n'''\n")
-
- f_txt.close()
- f_py.close()
- f_rna.close()
-
- print ('\nSaved %s, %s and %s.\n' % (font_bold(f_txt.name), font_bold(f_py.name), font_bold(f_rna.name) ) )
-
-
-def main():
-
- global sort_choices, default_sort_choice
- global kw_prefixes, kw
-
- sort_choices = ['note','changed','class','from','to','kw', 'class.to']
- default_sort_choice = sort_choices[-1]
- kw_prefixes = [ 'active','apply','bl','exclude','has','invert','is','lock', \
- 'pressed','show','show_only','use','use_only','layers','states', 'select']
- kw = ['active','hide','invert','select','layers','mute','states','use','lock']
-
- input_filename, sort_priority = check_commandline()
- props_list,props_length_max = get_props(input_filename)
- props_list = sort(props_list,sort_priority)
-
- output_basename = file_basename(input_filename)
- write_files(output_basename, props_list,props_length_max)
-
-
-if __name__=='__main__':
- import sys
- if not sys.version.startswith("3"):
- print("Incorrect python version, use python 3!")
- else:
- main()
-
diff --git a/source/blender/makesrna/rna_cleanup/rna_cleaner_merge.py b/source/blender/makesrna/rna_cleanup/rna_cleaner_merge.py
deleted file mode 100755
index 8d2fe07b774..00000000000
--- a/source/blender/makesrna/rna_cleanup/rna_cleaner_merge.py
+++ /dev/null
@@ -1,61 +0,0 @@
-#! /usr/bin/env python3.1
-
-import sys
-
-'''
-Example usage:
- python3 rna_cleaner_merge.py out_work.py rna_booleans_work.py
-'''
-def main():
-
- def work_line_id(line):
- return line[2].split("|")[-1], line[3] # class/from
-
-
- if not (sys.argv[-1].endswith(".py") and sys.argv[-2].endswith(".py")):
- print("Only accepts 2 py files as arguments.")
-
- sys.path.insert(0, ".")
-
- mod_from = __import__(sys.argv[-1][:-3])
- mod_to = __import__(sys.argv[-2][:-3])
-
- mod_to_dict = dict([(work_line_id(line), line) for line in mod_to.rna_api])
- mod_from_dict = dict([(work_line_id(line), line) for line in mod_from.rna_api])
-
- rna_api_new = []
-
- for key, val_orig in mod_to_dict.items():
- try:
- val_new = mod_from_dict.pop(key)
- except:
- # print("not found", key)
- val_new = val_orig
-
- # always take the class from the base
- val = list(val_orig)
- val[0] = val_new[0] # comment
- val[4] = val_new[4] # -> to
- val = tuple(val)
- rna_api_new.append(val)
-
- def write_work_file(file_path, rna_api):
- rna_api = list(rna_api)
- rna_api.sort(key=work_line_id)
- file_out = open(file_path, "w")
- file_out.write("rna_api = [\n")
- for line in rna_api:
- file_out.write(" %s,\n" % (repr(line)))
- file_out.write("]\n")
- file_out.close()
-
- file_path = sys.argv[-2][:-3] + "_merged.py"
- write_work_file(file_path, rna_api_new)
-
- if mod_from_dict:
- file_path = sys.argv[-2][:-3] + "_lost.py"
- write_work_file(file_path, list(mod_from_dict.values()))
- print("Warning '%s' contains lost %d items from module %s.py" % (file_path, len(mod_from_dict), mod_from.__name__))
-
-if __name__ == "__main__":
- main()
diff --git a/source/blender/makesrna/rna_cleanup/rna_properties.txt b/source/blender/makesrna/rna_cleanup/rna_properties.txt
deleted file mode 100644
index 030fecec20e..00000000000
--- a/source/blender/makesrna/rna_cleanup/rna_properties.txt
+++ /dev/null
@@ -1 +0,0 @@
-# See svn history for example formatting for this file, currently this isnt in use.
diff --git a/source/blender/makesrna/rna_cleanup/rna_update.sh b/source/blender/makesrna/rna_cleanup/rna_update.sh
deleted file mode 100755
index a4d686cc482..00000000000
--- a/source/blender/makesrna/rna_cleanup/rna_update.sh
+++ /dev/null
@@ -1,13 +0,0 @@
-cd ../../../../
-./blender.bin --background --python ./release/scripts/modules/rna_info.py 2> source/blender/makesrna/rna_cleanup/out.txt
-cd ./source/blender/makesrna/rna_cleanup/
-./rna_cleaner.py out.txt
-./rna_cleaner.py rna_properties.txt
-./rna_cleaner_merge.py out_work.py rna_properties_work.py
-./rna_cleaner.py out_work_merged.py
-./rna_cleaner.py out_work_lost.py
-mv out_work_merged_work.txt rna_properties.txt # overwrite
-mv out_work_lost_work.txt rna_properties_lost.txt
-cat rna_properties.txt | grep -v "^#" > rna_properties_edits.txt
-./rna_cleaner.py rna_properties.txt
-echo "Updated: rna_properties.txt rna_properties_edits.txt rna_properties_lost.txt "
diff --git a/source/blender/python/generic/mathutils_geometry.c b/source/blender/python/generic/mathutils_geometry.c
index c4917199e59..e3ef790cac9 100644
--- a/source/blender/python/generic/mathutils_geometry.c
+++ b/source/blender/python/generic/mathutils_geometry.c
@@ -1,5 +1,5 @@
/*
- * $Id$
+ * $Id: mathutils_geometry.c 36871 2011-05-24 16:05:51Z campbellbarton $
*
* ***** BEGIN GPL LICENSE BLOCK *****
*
diff --git a/source/blender/python/generic/mathutils_geometry.h b/source/blender/python/generic/mathutils_geometry.h
index 929b8cc8d75..2f9e3f20ef5 100644
--- a/source/blender/python/generic/mathutils_geometry.h
+++ b/source/blender/python/generic/mathutils_geometry.h
@@ -1,5 +1,5 @@
/*
- * $Id$
+ * $Id: mathutils_geometry.h 35236 2011-02-27 20:10:08Z jesterking $
*
* ***** BEGIN GPL LICENSE BLOCK *****
*
diff --git a/source/blender/windowmanager/SConscript b/source/blender/windowmanager/SConscript
index f52ac8ba3cb..6b8adaf6e72 100644
--- a/source/blender/windowmanager/SConscript
+++ b/source/blender/windowmanager/SConscript
@@ -38,4 +38,7 @@ if env['WITH_GHOST_COCOA']:
if env['BF_BUILDINFO']:
defs.append('NAN_BUILDINFO')
+if env['WITH_BF_ONSURFACEBRUSH']:
+ defs.append('WITH_ONSURFACEBRUSH')
+
env.BlenderLib ( 'bf_windowmanager', sources, Split(incs), defines=defs, libtype=['core'], priority=[5] )
diff --git a/source/blender/windowmanager/intern/wm_draw.c b/source/blender/windowmanager/intern/wm_draw.c
index 4fe82917705..59feb2c5327 100644
--- a/source/blender/windowmanager/intern/wm_draw.c
+++ b/source/blender/windowmanager/intern/wm_draw.c
@@ -340,6 +340,20 @@ typedef struct wmDrawTriple {
int x[MAX_N_TEX], y[MAX_N_TEX];
int nx, ny;
GLenum target;
+
+#ifdef WITH_ONSURFACEBRUSH
+ char* depth;
+ GLenum depth_type;
+
+ GLuint depth_bind[MAX_N_TEX*MAX_N_TEX];
+ int depth_x[MAX_N_TEX], depth_y[MAX_N_TEX];
+ int depth_nx, depth_ny;
+ GLenum depth_target;
+
+ GLenum depth_vertex_shader;
+ GLenum depth_fragment_shader;
+ GLenum depth_program;
+#endif
} wmDrawTriple;
static int is_pow2(int n)
@@ -408,6 +422,18 @@ static void wm_draw_triple_free(wmWindow *win)
wmDrawTriple *triple= win->drawdata;
glDeleteTextures(triple->nx*triple->ny, triple->bind);
+#ifdef WITH_ONSURFACEBRUSH
+ glDeleteTextures(triple->depth_nx*triple->depth_ny, triple->depth_bind);
+
+ if (GLEW_ARB_shader_objects) {
+ glDeleteObjectARB(triple->depth_vertex_shader);
+ glDeleteObjectARB(triple->depth_fragment_shader);
+ glDeleteObjectARB(triple->depth_program);
+ }
+
+ if (triple->depth)
+ MEM_freeN(triple->depth);
+#endif
MEM_freeN(triple);
@@ -558,6 +584,419 @@ static void wm_triple_copy_textures(wmWindow *win, wmDrawTriple *triple)
glBindTexture(triple->target, 0);
}
+#ifdef WITH_ONSURFACEBRUSH
+static void get_shading_language_version(int* major, int* minor)
+{
+ const char* version;
+
+ version = glGetString(GL_SHADING_LANGUAGE_VERSION);
+ *major = atol(version);
+ version = strstr(version, ".");
+ *minor = atol(version+1);
+}
+
+/* compile and link the shader program needed to write a depth texture to the depth buffer */
+static void load_depth_shader_program(wmDrawTriple* triple)
+{
+ int success;
+ GLsizei len;
+ GLbyte infoLog[1000];
+ int major, minor;
+
+ /* This vertex program just passes the texture coordinate through and transforms the vertex position */
+ /* This program should be compatible up to OpenGL 4.0 with the fixed-function compatibility profile */
+ static const GLcharARB* depth_vertex_shader_source_100[] = {
+ "void main()\n",
+ "{\n",
+ " gl_TexCoord[0] = gl_MultiTexCoord0;\n",
+ " gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n",
+ "}\n",
+ };
+
+ /* This fragment program is used non-rectangle textures */
+ /* Compatible with version 1.0-1.2 w/o GL_ARB_texture_rectangle */
+ static const GLcharARB* depth_fragment_shader_source_100[] = {
+ "uniform sampler2D depth_texture;\n",
+ "void main()\n",
+ "{\n",
+ " gl_FragDepth = texture2D(depth_texture, gl_TexCoord[0].xy).x;\n",
+ "}\n",
+ };
+
+ /* This fragment program is used for rectangular textures */
+ /* Compatible with version 1.0-1.2 w/ GL_ARB_texture_rectangle */
+ static const GLcharARB* depth_fragment_shader_rect_source_100[] = {
+ "#extension GL_ARB_texture_rectangle : enable\n",
+ "uniform sampler2DRect depth_texture;\n",
+ "void main()\n",
+ "{\n",
+ " gl_FragDepth = texture2DRect(depth_texture, gl_TexCoord[0].xy).x;\n",
+ "}\n",
+ };
+
+ /* This fragment program is used non-rectangle textures */
+ /* Compatible with version 1.3 w/o GL_ARB_texture_rectangle */
+ static const GLcharARB* depth_fragment_shader_source_130[] = {
+ "#version 130\n",
+ "uniform sampler2D depth_texture;\n",
+ "void main()\n",
+ "{\n",
+ " gl_FragDepth = texture(depth_texture, gl_TexCoord[0].xy).x;\n",
+ "}\n",
+ };
+
+ /* This fragment program is used for rectangular textures */
+ /* Compatible with version 1.3 w/ GL_ARB_texture_rectangle */
+ static const GLcharARB* depth_fragment_shader_rect_source_130[] = {
+ "#version 130\n",
+ "#extension GL_ARB_texture_rectangle : enable\n",
+ "uniform sampler2DRect depth_texture;\n",
+ "void main()\n",
+ "{\n",
+ " gl_FragDepth = texture(depth_texture, gl_TexCoord[0].xy).x;\n",
+ "}\n",
+ };
+
+ const GLcharARB** source;
+ int source_lines;
+
+ get_shading_language_version(&major, &minor);
+
+ /* compile the vertex program */
+
+ triple->depth_vertex_shader = glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB);
+
+ glShaderSourceARB(triple->depth_vertex_shader, sizeof(depth_vertex_shader_source_100)/sizeof(GLcharARB*), depth_vertex_shader_source_100, NULL);
+ glCompileShaderARB(triple->depth_vertex_shader);
+
+ /* print any errors/warnings gotten while compiling the vertex program */
+
+ glGetObjectParameterivARB(triple->depth_vertex_shader, GL_OBJECT_COMPILE_STATUS_ARB, &success);
+ glGetInfoLogARB(triple->depth_vertex_shader, 1000, &len, infoLog);
+
+ if (len > 0)
+ printf("triple depth buffer vertex program compilation messages:\n%s\n", infoLog);
+
+ /* compile the appropriate fragment program depending on support for rectangular textures */
+
+ triple->depth_fragment_shader = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);
+
+ if (major == 1 && minor < 30) {
+ if (GLEW_ARB_texture_rectangle) {
+ source = depth_fragment_shader_rect_source_100;
+ source_lines = sizeof(depth_fragment_shader_rect_source_100)/sizeof(GLcharARB*);
+ }
+ else {
+ source = depth_fragment_shader_source_100;
+ source_lines = sizeof(depth_fragment_shader_source_100)/sizeof(GLcharARB*);
+ }
+ }
+ else {
+ if (GLEW_ARB_texture_rectangle) {
+ source = depth_fragment_shader_rect_source_130;
+ source_lines = sizeof(depth_fragment_shader_rect_source_130)/sizeof(GLcharARB*);
+ }
+ else {
+ source = depth_fragment_shader_source_130;
+ source_lines = sizeof(depth_fragment_shader_source_130)/sizeof(GLcharARB*);
+ }
+ }
+
+ glShaderSourceARB(triple->depth_fragment_shader, source_lines, source, NULL);
+ glCompileShaderARB(triple->depth_fragment_shader);
+
+ /* print any errors/warnings gotten while compiling the fragment program */
+
+ glGetObjectParameterivARB(triple->depth_fragment_shader, GL_OBJECT_COMPILE_STATUS_ARB, &success);
+ glGetInfoLogARB(triple->depth_fragment_shader, 1000, &len, infoLog);
+
+ if (len > 0)
+ printf("triple depth buffer fragment program compilation messages:\n%s\n", infoLog);
+
+ /* link the shaders into a complete program */
+
+ triple->depth_program = glCreateProgramObjectARB();
+
+ glAttachObjectARB(triple->depth_program, triple->depth_vertex_shader);
+ glAttachObjectARB(triple->depth_program, triple->depth_fragment_shader);
+
+ glLinkProgramARB(triple->depth_program);
+
+ /* print any errors/warnings gotten while linking the final program */
+
+ glGetObjectParameterivARB(triple->depth_program, GL_OBJECT_LINK_STATUS_ARB, &success);
+ glGetInfoLogARB(triple->depth_program, 1000, &len, infoLog);
+
+ if (len > 0)
+ printf("triple depth buffer program linker messages:\n%s\n", infoLog);
+}
+
+static int wm_triple_gen_depth_buffer(wmWindow *win, wmDrawTriple *triple)
+{
+ /* To do this fast we need support for depth textures and GLSL */
+ if (GLEW_ARB_depth_texture &&
+ GLEW_ARB_shader_objects &&
+ GLEW_ARB_vertex_shader &&
+ GLEW_ARB_fragment_shader &&
+ GLEW_ARB_shading_language_100)
+ {
+ GLint maxsize;
+ int x, y;
+
+ /* XXX: this is copied from wm_triple_gen_textures.
+ can probably combine them together once this is accepted into trunk */
+
+ /* compute texture sizes */
+ if(GLEW_ARB_texture_rectangle) {
+ triple->depth_target= GL_TEXTURE_RECTANGLE_ARB;
+ triple->depth_nx= 1;
+ triple->depth_ny= 1;
+ triple->depth_x[0]= win->sizex;
+ triple->depth_y[0]= win->sizey;
+ }
+ else if(GPU_non_power_of_two_support()) {
+ triple->depth_target= GL_TEXTURE_2D;
+ triple->depth_nx= 1;
+ triple->depth_ny= 1;
+ triple->depth_x[0]= win->sizex;
+ triple->depth_y[0]= win->sizey;
+ }
+ else {
+ triple->depth_target= GL_TEXTURE_2D;
+ triple->depth_nx= 0;
+ triple->depth_ny= 0;
+ split_width(win->sizex, MAX_N_TEX, triple->depth_x, &triple->depth_nx);
+ split_width(win->sizey, MAX_N_TEX, triple->depth_y, &triple->depth_ny);
+ }
+
+ /* generate texture names */
+ glGenTextures(triple->depth_nx*triple->depth_ny, triple->depth_bind);
+
+ if(!triple->depth_bind[0]) {
+ /* not the typical failure case but we handle it anyway */
+ printf("WM: failed to allocate depth texture for triple buffer drawing (glGenTextures).\n");
+ return 0;
+ }
+
+ for(y=0; y<triple->depth_ny; y++) {
+ for(x=0; x<triple->depth_nx; x++) {
+ /* proxy texture is only guaranteed to test for the cases that
+ * there is only one texture in use, which may not be the case */
+ glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxsize);
+
+ if(triple->depth_x[x] > maxsize || triple->depth_y[y] > maxsize) {
+ glBindTexture(triple->depth_target, 0);
+ printf("WM: failed to allocate texture for triple buffer drawing (texture too large for graphics card).\n");
+ return 0;
+ }
+
+ /* setup actual texture */
+ glBindTexture(triple->depth_target, triple->depth_bind[x + y*triple->depth_nx]);
+
+ /* important difference from wm_triple_gen_textures!
+ use GL_DEPTH_COMPONENT as format and internalformat */
+ glTexImage2D(triple->depth_target, 0, GL_DEPTH_COMPONENT, triple->depth_x[x], triple->depth_y[y], 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL);
+
+ glTexParameteri(triple->depth_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(triple->depth_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+
+ /* important difference from wm_triple_gen_textures!
+ turn off depth comparison mode that would be used if this was a shadow map */
+ glTexParameteri(triple->depth_target, GL_TEXTURE_COMPARE_MODE, GL_NONE);
+
+ glBindTexture(triple->depth_target, 0);
+
+ /* not sure if this works everywhere .. */
+ if(glGetError() == GL_OUT_OF_MEMORY) {
+ printf("WM: failed to allocate depth texture for triple buffer drawing (out of memory).\n");
+ return 0;
+ }
+ }
+ }
+
+ load_depth_shader_program(triple);
+ }
+ /* otherwise, we have to fall back to the more compatible glReadBuffer/glDrawBuffer method */
+ else {
+ const int count = win->sizex * win->sizey;
+ const int size = count*sizeof(GLfloat);
+
+ triple->depth_type = GL_FLOAT;
+ triple->depth = MEM_mallocN(size, "wm_triple_gen_depth_buffer");
+ }
+
+ return 1;
+}
+
+static void wm_triple_copy_depth_buffer(wmWindow *win, wmDrawTriple *triple)
+{
+ /* To do this fast we need support for depth textures and GLSL */
+ if (GLEW_ARB_depth_texture &&
+ GLEW_ARB_shader_objects &&
+ GLEW_ARB_vertex_shader &&
+ GLEW_ARB_fragment_shader &&
+ GLEW_ARB_shading_language_100)
+ {
+ int x, y, sizex, sizey, offx, offy;
+
+ /* XXX this is pretty much identical to wm_triple_copy_textures,
+ the fact that the textures are GL_DEPTH_COMPONENT format is what makes the difference */
+
+ for(y=0, offy=0; y<triple->depth_ny; offy+=triple->depth_y[y], y++) {
+ for(x=0, offx=0; x<triple->depth_nx; offx+=triple->depth_x[x], x++) {
+ sizex= (x == triple->depth_nx-1)? win->sizex-offx: triple->depth_x[x];
+ sizey= (y == triple->depth_ny-1)? win->sizey-offy: triple->depth_y[y];
+
+ glBindTexture(triple->depth_target, triple->depth_bind[x + y*triple->depth_nx]);
+ glCopyTexSubImage2D(triple->depth_target, 0, 0, 0, offx, offy, sizex, sizey);
+ }
+ }
+
+ glBindTexture(triple->depth_target, 0);
+ }
+ else if (triple->depth) {
+ /* For the compatibility fallback, we set the pixel store state to the defaults,
+ anything else is very unlikely to be even remotely fast (and it is already slow
+ using these defaults) */
+
+ glPushAttrib(GL_PIXEL_MODE_BIT);
+
+ glPixelStorei(GL_PACK_SWAP_BYTES, GL_FALSE);
+ glPixelStorei(GL_PACK_ROW_LENGTH, 0);
+ glPixelStorei(GL_PACK_SKIP_ROWS, 0);
+ glPixelStorei(GL_PACK_SKIP_PIXELS, 0);
+ glPixelStorei(GL_PACK_ALIGNMENT, 4);
+
+ glPixelTransferi(GL_DEPTH_SCALE, 1);
+ glPixelTransferi(GL_DEPTH_BIAS, 0);
+
+ glReadPixels(0, 0, win->sizex, win->sizey, GL_DEPTH_COMPONENT, triple->depth_type, triple->depth);
+
+ glPopAttrib();
+ }
+}
+
+static void wm_triple_draw_depth_buffer(wmWindow *win, wmDrawTriple *triple)
+{
+ /* To do this fast we need support for depth textures and GLSL */
+ if (GLEW_ARB_depth_texture &&
+ GLEW_ARB_shader_objects &&
+ GLEW_ARB_vertex_shader &&
+ GLEW_ARB_fragment_shader &&
+ GLEW_ARB_shading_language_100)
+ {
+ float halfx, halfy, ratiox, ratioy;
+ int x, y, sizex, sizey, offx, offy;
+ GLint depth_texture;
+
+ glPushAttrib(
+ GL_COLOR_BUFFER_BIT|
+ GL_DEPTH_BUFFER_BIT);
+
+ /* depth test has to be enabled to write to depth buffer,
+ set GL_ALWAYS so that what is in the texture overwrites what
+ is there, and make sure the buffer is set to be writable */
+ glEnable(GL_DEPTH_TEST);
+ glDepthFunc(GL_ALWAYS);
+ glDepthMask(GL_TRUE);
+
+ /* since the fragment shader does not write gl_FragColor what it would
+ write to the color buffer is actually undefined. Regardless, do not
+ write to color buffer. */
+ glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
+
+ /* load the shader and bind the sampler2D to the 0th texture unit */
+ glUseProgramObjectARB(triple->depth_program);
+ depth_texture = glGetUniformLocationARB(triple->depth_program, "depth_texture");
+ glActiveTextureARB(GL_TEXTURE0_ARB);
+ glUniform1iARB(depth_texture, 0);
+
+ glEnable(triple->depth_target);
+
+ for(y=0, offy=0; y<triple->depth_ny; offy+=triple->depth_y[y], y++) {
+ for(x=0, offx=0; x<triple->depth_nx; offx+=triple->depth_x[x], x++) {
+ sizex= (x == triple->depth_nx-1)? win->sizex-offx: triple->depth_x[x];
+ sizey= (y == triple->depth_ny-1)? win->sizey-offy: triple->depth_y[y];
+
+ /* wmOrtho for the screen has this same offset */
+ ratiox= sizex;
+ ratioy= sizey;
+ halfx= 0.375f;
+ halfy= 0.375f;
+
+ /* texture rectangle has unnormalized coordinates */
+ if(triple->depth_target == GL_TEXTURE_2D) {
+ ratiox /= triple->depth_x[x];
+ ratioy /= triple->depth_y[y];
+ halfx /= triple->depth_x[x];
+ halfy /= triple->depth_y[y];
+ }
+
+ glBindTexture(triple->depth_target, triple->depth_bind[x + y*triple->depth_nx]);
+
+ glBegin(GL_QUADS);
+ glTexCoord2f(halfx, halfy);
+ glVertex2f(offx, offy);
+
+ glTexCoord2f(ratiox+halfx, halfy);
+ glVertex2f(offx+sizex, offy);
+
+ glTexCoord2f(ratiox+halfx, ratioy+halfy);
+ glVertex2f(offx+sizex, offy+sizey);
+
+ glTexCoord2f(halfx, ratioy+halfy);
+ glVertex2f(offx, offy+sizey);
+ glEnd();
+ }
+ }
+
+ glBindTexture(triple->depth_target, 0);
+ glDisable(triple->depth_target);
+
+ /* go back to using the fixed function pipeline */
+ glUseProgramObjectARB(0);
+
+ glPopAttrib();
+ }
+ else {
+ if (triple->depth) {
+ glPushAttrib(
+ GL_COLOR_BUFFER_BIT|
+ GL_DEPTH_BUFFER_BIT|
+ GL_ENABLE_BIT|
+ GL_PIXEL_MODE_BIT);
+
+ /* About the only chance this will be remotely fast is if we use the default values */
+
+ glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE);
+ glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
+ glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
+ glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
+
+ glPixelTransferi(GL_DEPTH_SCALE, 1);
+ glPixelTransferi(GL_DEPTH_BIAS, 0);
+
+ glPixelZoom(1.0, 1.0);
+
+ /* important, cannot write the depth buffer unless this is enabled */
+ glEnable(GL_DEPTH_TEST);
+ glDepthMask(GL_TRUE);
+ glDepthFunc(GL_ALWAYS);
+
+ /* make sure color buffer isn't overwritten */
+ glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
+
+ /* send the saved depth buffer to the screen */
+ glRasterPos2i(0, 0);
+ glDrawPixels(win->sizex, win->sizey, GL_DEPTH_COMPONENT, triple->depth_type, triple->depth);
+
+ glPopAttrib();
+ }
+ }
+}
+#endif
+
static void wm_method_draw_triple(bContext *C, wmWindow *win)
{
wmWindowManager *wm= CTX_wm_manager(C);
@@ -574,11 +1013,20 @@ static void wm_method_draw_triple(bContext *C, wmWindow *win)
wmSubWindowSet(win, screen->mainwin);
wm_triple_draw_textures(win, win->drawdata);
+#ifdef WITH_ONSURFACEBRUSH
+ wm_triple_draw_depth_buffer(win, win->drawdata);
+#endif
+
+ triple= win->drawdata;
}
else {
win->drawdata= MEM_callocN(sizeof(wmDrawTriple), "wmDrawTriple");
- if(!wm_triple_gen_textures(win, win->drawdata))
+ if(!wm_triple_gen_textures(win, win->drawdata)
+#ifdef WITH_ONSURFACEBRUSH
+ || !wm_triple_gen_depth_buffer(win, win->drawdata)
+#endif
+ )
{
wm_draw_triple_fail(C, win);
return;
@@ -610,6 +1058,9 @@ static void wm_method_draw_triple(bContext *C, wmWindow *win)
ED_area_overdraw(C);
wm_triple_copy_textures(win, triple);
+#ifdef WITH_ONSURFACEBRUSH
+ wm_triple_copy_depth_buffer(win, triple);
+#endif
}
/* after area regions so we can do area 'overlay' drawing */
diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c
index f5a1b6b0298..e03d32ee7c8 100644
--- a/source/blender/windowmanager/intern/wm_operators.c
+++ b/source/blender/windowmanager/intern/wm_operators.c
@@ -2700,6 +2700,346 @@ void WM_OT_straightline_gesture(wmOperatorType *ot)
/* *********************** radial control ****************** */
static const int WM_RADIAL_CONTROL_DISPLAY_SIZE = 200;
+#if 0
+typedef struct wmRadialControl {
+ int mode;
+ float initial_value, value, max_value;
+ float col[4], tex_col[4];
+ int initial_mouse[2];
+ void *cursor;
+ GLuint tex;
+} wmRadialControl;
+
+extern Paint *paint_get_active(Scene *sce);
+extern struct Brush *paint_brush(struct Paint *paint);
+#ifdef WITH_ONSURFACEBRUSH
+extern int sculpt_get_brush_geometry(bContext* C, int x, int y, int* pixel_radius, float location[3], float modelview[16], float projection[16], int viewport[4]);
+extern float unproject_brush_radius(Object *ob, ViewContext *vc, float center[3], float offset);
+#endif
+
+static void wm_radial_control_paint(bContext *C, int x, int y, void *customdata)
+{
+ wmRadialControl *rc = (wmRadialControl*)customdata;
+ ARegion *ar = CTX_wm_region(C);
+ float r1=0.0f, r2=0.0f, r3=0.0f, angle=0.0f;
+
+ // int hit = 0;
+ int hit = 0;
+
+ if(rc->mode == WM_RADIALCONTROL_STRENGTH)
+ rc->tex_col[3]= (rc->value + 0.5f);
+
+ if(rc->mode == WM_RADIALCONTROL_SIZE) {
+ r1= rc->value;
+ r2= rc->initial_value;
+ r3= r1;
+ } else if(rc->mode == WM_RADIALCONTROL_STRENGTH) {
+ r1= (1 - rc->value) * WM_RADIAL_CONTROL_DISPLAY_SIZE;
+ r2= r3= (float)WM_RADIAL_CONTROL_DISPLAY_SIZE;
+ } else if(rc->mode == WM_RADIALCONTROL_ANGLE) {
+ r1= r2= r3= (float)WM_RADIAL_CONTROL_DISPLAY_SIZE;
+ angle = rc->value;
+ }
+
+ /* Keep cursor in the original place */
+ x = rc->initial_mouse[0] - ar->winrct.xmin;
+ y = rc->initial_mouse[1] - ar->winrct.ymin;
+
+#ifdef WITH_ONSURFACEBRUSH
+ if ((paint->flags & PAINT_SHOW_BRUSH_ON_SURFACE) && vc.obact->sculpt) {
+ float alpha;
+
+ int pixel_radius, viewport[4];
+ float location[3], modelview[16], projection[16];
+
+ float visual_strength = rc->mode == WM_RADIALCONTROL_STRENGTH ? rc->value*rc->value : brush_alpha(brush)*brush_alpha(brush);
+
+ const float min_alpha = 0.20f;
+ const float max_alpha = 0.80f;
+
+ hit = sculpt_get_brush_geometry(C, x, y, &pixel_radius, location, modelview, projection, viewport);
+
+ alpha = min_alpha + (visual_strength*(max_alpha-min_alpha));
+
+ if (hit) {
+ Object *ob= CTX_data_active_object(C);
+
+ {
+ const float unprojected_radius= unproject_brush_radius(CTX_data_active_object(C), &vc, location, r1);
+ const float max_thickness= 0.12;
+ const float min_thickness= 0.06;
+ const float thickness= 1.0 - min_thickness - visual_strength*max_thickness;
+ const float inner_radius= unprojected_radius*thickness;
+ const float outer_radius= unprojected_radius;
+
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+
+ ED_draw_fixed_overlay_on_surface(modelview, projection, ob->size, viewport, location, outer_radius, sd, brush, &vc, y+r3, y-r3, x-r3, x+r3, -angle);
+
+ ED_draw_on_surface_cursor(modelview, projection, col, alpha, ob->size, viewport, location, inner_radius, outer_radius, brush_size(brush));
+
+ if(rc->mode == WM_RADIALCONTROL_ANGLE) {
+ glTranslatef((float)x, (float)y, 0.0f);
+ glEnable(GL_BLEND);
+ glColor4f(col[0], col[1], col[2], 0.5f);
+ glEnable(GL_LINE_SMOOTH);
+ fdrawline(0, 0, WM_RADIAL_CONTROL_DISPLAY_SIZE, 0);
+ glRotatef(angle, 0, 0, 1);
+ fdrawline(0, 0, WM_RADIAL_CONTROL_DISPLAY_SIZE, 0);
+ glDisable(GL_LINE_SMOOTH);
+ }
+ }
+
+ {
+ const float unprojected_radius= unproject_brush_radius(CTX_data_active_object(C), &vc, location, r2);
+ const float max_thickness= 0.12;
+ const float min_thickness= 0.06;
+ const float thickness= 1.0 - min_thickness - visual_strength*max_thickness;
+ const float inner_radius= unprojected_radius*thickness;
+ const float outer_radius= unprojected_radius;
+
+ ED_draw_on_surface_cursor(modelview, projection, col, alpha, ob->size, viewport, location, inner_radius, outer_radius, brush_size(brush));
+ }
+ }
+ }
+
+ if (!hit) {
+#endif
+ glTranslatef((float)x, (float)y, 0.0f);
+
+ glEnable(GL_BLEND);
+
+ if(rc->mode == WM_RADIALCONTROL_ANGLE) {
+ glRotatef(angle, 0, 0, 1);
+ }
+
+ if (rc->tex) {
+ glBindTexture(GL_TEXTURE_2D, rc->tex);
+
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+ glEnable(GL_TEXTURE_2D);
+ glBegin(GL_QUADS);
+ glColor4fv(rc->tex_col);
+ glTexCoord2f(0,0);
+ glVertex2f(-r3, -r3);
+ glTexCoord2f(1,0);
+ glVertex2f(r3, -r3);
+ glTexCoord2f(1,1);
+ glVertex2f(r3, r3);
+ glTexCoord2f(0,1);
+ glVertex2f(-r3, r3);
+ glEnd();
+ glDisable(GL_TEXTURE_2D);
+ }
+
+ if(rc->mode == WM_RADIALCONTROL_ANGLE) {
+ glColor4fv(rc->col);
+ glEnable(GL_LINE_SMOOTH);
+ glRotatef(-angle, 0, 0, 1);
+ fdrawline(0.0f, 0.0f, (float)WM_RADIAL_CONTROL_DISPLAY_SIZE, 0.0f);
+ glRotatef(angle, 0, 0, 1);
+ fdrawline(0.0f, 0.0f, (float)WM_RADIAL_CONTROL_DISPLAY_SIZE, 0.0f);
+ glDisable(GL_LINE_SMOOTH);
+ }
+
+ glColor4fv(rc->col);
+ glutil_draw_lined_arc(0.0, (float)(M_PI*2.0), r1, 40);
+ glutil_draw_lined_arc(0.0, (float)(M_PI*2.0), r2, 40);
+ glDisable(GL_BLEND);
+#ifdef WITH_ONSURFACEBRUSH
+ }
+#endif
+}
+
+int WM_radial_control_modal(bContext *C, wmOperator *op, wmEvent *event)
+{
+ wmRadialControl *rc = (wmRadialControl*)op->customdata;
+ int mode, initial_mouse[2], delta[2];
+ float dist;
+ double new_value = RNA_float_get(op->ptr, "new_value");
+ int ret = OPERATOR_RUNNING_MODAL;
+ // float initial_value = RNA_float_get(op->ptr, "initial_value");
+
+ mode = RNA_enum_get(op->ptr, "mode");
+ RNA_int_get_array(op->ptr, "initial_mouse", initial_mouse);
+
+ switch(event->type) {
+ case MOUSEMOVE:
+ delta[0]= initial_mouse[0] - event->x;
+ delta[1]= initial_mouse[1] - event->y;
+
+ //if (mode == WM_RADIALCONTROL_SIZE)
+ // delta[0]+= initial_value;
+ //else if(mode == WM_RADIALCONTROL_STRENGTH)
+ // delta[0]+= WM_RADIAL_CONTROL_DISPLAY_SIZE * (1 - initial_value);
+ //else if(mode == WM_RADIALCONTROL_ANGLE) {
+ // delta[0]+= WM_RADIAL_CONTROL_DISPLAY_SIZE * cos(initial_value*M_PI/180.0f);
+ // delta[1]+= WM_RADIAL_CONTROL_DISPLAY_SIZE * sin(initial_value*M_PI/180.0f);
+ //}
+
+ dist= sqrtf(delta[0]*delta[0]+delta[1]*delta[1]);
+
+ if(mode == WM_RADIALCONTROL_SIZE)
+ new_value = dist;
+ else if(mode == WM_RADIALCONTROL_STRENGTH) {
+ new_value = 1 - dist / WM_RADIAL_CONTROL_DISPLAY_SIZE;
+ } else if(mode == WM_RADIALCONTROL_ANGLE)
+ new_value = ((int)(atan2f(delta[1], delta[0]) * (float)(180.0 / M_PI)) + 180);
+
+ if(event->ctrl) {
+ if(mode == WM_RADIALCONTROL_STRENGTH)
+ new_value = ((int)ceilf(new_value * 10.f) * 10.0f) / 100.f;
+ else
+ new_value = ((int)new_value + 5) / 10*10;
+ }
+
+ break;
+ case ESCKEY:
+ case RIGHTMOUSE:
+ ret = OPERATOR_CANCELLED;
+ break;
+ case LEFTMOUSE:
+ case PADENTER:
+ op->type->exec(C, op);
+ ret = OPERATOR_FINISHED;
+ break;
+ }
+
+ /* Clamp */
+ if(new_value > rc->max_value)
+ new_value = rc->max_value;
+ else if(new_value < 0)
+ new_value = 0;
+
+ /* Update paint data */
+ rc->value = (float)new_value;
+
+ RNA_float_set(op->ptr, "new_value", rc->value);
+
+ if(ret != OPERATOR_RUNNING_MODAL) {
+ WM_paint_cursor_end(CTX_wm_manager(C), rc->cursor);
+ MEM_freeN(rc);
+ }
+
+ ED_region_tag_redraw(CTX_wm_region(C));
+
+ //if (ret != OPERATOR_RUNNING_MODAL) {
+ // wmWindow *win = CTX_wm_window(C);
+ // WM_cursor_restore(win);
+ //}
+
+ return ret;
+}
+
+/* Expects the operator customdata to be an ImBuf (or NULL) */
+int WM_radial_control_invoke(bContext *C, wmOperator *op, wmEvent *event)
+{
+ wmRadialControl *rc = MEM_callocN(sizeof(wmRadialControl), "radial control");
+ // wmWindow *win = CTX_wm_window(C);
+ int mode = RNA_enum_get(op->ptr, "mode");
+ float initial_value = RNA_float_get(op->ptr, "initial_value");
+ //float initial_size = RNA_float_get(op->ptr, "initial_size");
+ int mouse[2];
+
+ mouse[0]= event->x;
+ mouse[1]= event->y;
+
+ //if (initial_size == 0)
+ // initial_size = WM_RADIAL_CONTROL_DISPLAY_SIZE;
+
+ if(mode == WM_RADIALCONTROL_SIZE) {
+ rc->max_value = 200;
+ mouse[0]-= (int)initial_value;
+ }
+ else if(mode == WM_RADIALCONTROL_STRENGTH) {
+ rc->max_value = 1;
+ mouse[0]-= (int)(WM_RADIAL_CONTROL_DISPLAY_SIZE * (1.0f - initial_value));
+ }
+ else if(mode == WM_RADIALCONTROL_ANGLE) {
+ rc->max_value = 360;
+ mouse[0]-= (int)(WM_RADIAL_CONTROL_DISPLAY_SIZE * cos(initial_value));
+ mouse[1]-= (int)(WM_RADIAL_CONTROL_DISPLAY_SIZE * sin(initial_value));
+ initial_value *= 180.0f/(float)M_PI;
+ }
+
+ if(op->customdata) {
+ ImBuf *im = (ImBuf*)op->customdata;
+ /* Build GL texture */
+ glGenTextures(1, &rc->tex);
+ glBindTexture(GL_TEXTURE_2D, rc->tex);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, im->x, im->y, 0, GL_ALPHA, GL_FLOAT, im->rect_float);
+ MEM_freeN(im->rect_float);
+ MEM_freeN(im);
+ }
+
+ RNA_float_get_array(op->ptr, "color", rc->col);
+ RNA_float_get_array(op->ptr, "texture_color", rc->tex_col);
+
+ RNA_int_set_array(op->ptr, "initial_mouse", mouse);
+ RNA_float_set(op->ptr, "new_value", initial_value);
+
+ op->customdata = rc;
+ rc->mode = mode;
+ rc->initial_value = initial_value;
+ rc->initial_mouse[0] = mouse[0];
+ rc->initial_mouse[1] = mouse[1];
+ rc->cursor = WM_paint_cursor_activate(CTX_wm_manager(C), op->type->poll,
+ wm_radial_control_paint, op->customdata);
+
+ //WM_cursor_modal(win, CURSOR_NONE);
+
+ /* add modal handler */
+ WM_event_add_modal_handler(C, op);
+
+ WM_radial_control_modal(C, op, event);
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+/* Gets a descriptive string of the operation */
+void WM_radial_control_string(wmOperator *op, char str[], int maxlen)
+{
+ int mode = RNA_enum_get(op->ptr, "mode");
+ float v = RNA_float_get(op->ptr, "new_value");
+
+ if(mode == WM_RADIALCONTROL_SIZE)
+ BLI_snprintf(str, maxlen, "Size: %d", (int)v);
+ else if(mode == WM_RADIALCONTROL_STRENGTH)
+ BLI_snprintf(str, maxlen, "Strength: %d", (int)v);
+ else if(mode == WM_RADIALCONTROL_ANGLE)
+ BLI_snprintf(str, maxlen, "Angle: %d", (int)(v * 180.0f/(float)M_PI));
+}
+
+/** Important: this doesn't define an actual operator, it
+ just sets up the common parts of the radial control op. **/
+void WM_OT_radial_control_partial(wmOperatorType *ot)
+{
+ static EnumPropertyItem radial_mode_items[] = {
+ {WM_RADIALCONTROL_SIZE, "SIZE", 0, "Size", ""},
+ {WM_RADIALCONTROL_STRENGTH, "STRENGTH", 0, "Strength", ""},
+ {WM_RADIALCONTROL_ANGLE, "ANGLE", 0, "Angle", ""},
+ {0, NULL, 0, NULL, NULL}};
+ static float color[4] = {1.0f, 1.0f, 1.0f, 0.5f};
+ static float tex_color[4] = {1.0f, 1.0f, 1.0f, 1.0f};
+
+ /* Should be set in custom invoke() */
+ RNA_def_float(ot->srna, "initial_value", 0, 0, FLT_MAX, "Initial Value", "", 0, FLT_MAX);
+
+ /* Set internally, should be used in custom exec() to get final value */
+ RNA_def_float(ot->srna, "new_value", 0, 0, FLT_MAX, "New Value", "", 0, FLT_MAX);
+
+ /* Should be set before calling operator */
+ RNA_def_enum(ot->srna, "mode", radial_mode_items, 0, "Mode", "");
+
+ /* Internal */
+ RNA_def_int_vector(ot->srna, "initial_mouse", 2, NULL, INT_MIN, INT_MAX, "Initial Mouse", "", INT_MIN, INT_MAX);
+
+ RNA_def_float_color(ot->srna, "color", 4, color, 0.0f, FLT_MAX, "Color", "Radial control color", 0.0f, 1.0f);
+ RNA_def_float_color(ot->srna, "texture_color", 4, tex_color, 0.0f, FLT_MAX, "Texture Color", "Radial control texture color", 0.0f, 1.0f);
+}
+#endif
typedef struct {
PropertyType type;
diff --git a/source/blenderplayer/CMakeLists.txt b/source/blenderplayer/CMakeLists.txt
index 901aaea3eca..34782ff9307 100644
--- a/source/blenderplayer/CMakeLists.txt
+++ b/source/blenderplayer/CMakeLists.txt
@@ -87,13 +87,12 @@ endif()
ge_player_ghost
ge_player_common
bf_intern_string
- bf_intern_ghost
+ bf_intern_ghost
bf_rna
bf_blenkernel
bf_blenloader
bf_blenpluginapi
ge_blen_routines
- bf_editor_datafiles
ge_converter
ge_logic_ketsji
ge_phys_bullet
@@ -104,10 +103,10 @@ endif()
ge_oglrasterizer
ge_logic_expressions
ge_scenegraph
- bf_ikplugin
- bf_intern_itasc
- bf_intern_ik
- bf_intern_smoke
+ bf_ikplugin
+ bf_intern_itasc
+ bf_intern_ik
+ bf_intern_smoke
bf_modifiers
bf_intern_moto
bf_nodes
@@ -124,7 +123,7 @@ endif()
bf_blenlib
bf_imbuf_cineon
bf_imbuf_openexr
- extern_openjpeg
+ extern_openjpeg
extern_redcode
bf_imbuf_dds
bf_dna
@@ -134,11 +133,9 @@ endif()
blenkernel_blc
extern_binreloc
extern_minilzo
- bf_intern_ghost # duplicate for linking
- bf_blenkernel # duplicate for linking
bf_intern_mikktspace
)
-
+
if(WITH_BUILTIN_GLEW)
list(APPEND BLENDER_SORTED_LIBS extern_glew)
endif()
diff --git a/source/tests/CMakeLists.txt b/source/tests/CMakeLists.txt
deleted file mode 100644
index 97e46bd44f2..00000000000
--- a/source/tests/CMakeLists.txt
+++ /dev/null
@@ -1,293 +0,0 @@
-# -*- mode: cmake; indent-tabs-mode: t; -*-
-# $Id: CMakeLists.txt 34198 2011-01-09 15:12:08Z campbellbarton $
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# Contributor(s): Jacques Beaurain.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-# --env-system-scripts allows to run without the install target.
-
-# Use '--write-blend=/tmp/test.blend' to view output
-
-
-set(TEST_SRC_DIR ${CMAKE_SOURCE_DIR}/../lib/tests)
-set(TEST_OUT_DIR ${CMAKE_BINARY_DIR}/tests)
-
-# ugh, any better way to do this on testing only?
-execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory ${TEST_OUT_DIR})
-
-#~ if(NOT IS_DIRECTORY ${TEST_SRC_DIR})
-#~ message(FATAL_ERROR "CMake test directory not found!")
-#~ endif()
-
-# all calls to blender use this
-if(APPLE)
- set(TEST_BLENDER_EXE ${EXECUTABLE_OUTPUT_PATH}/blender.app/Contents/MacOS/blender)
-else()
- set(TEST_BLENDER_EXE ${EXECUTABLE_OUTPUT_PATH}/blender)
-endif()
-
-# for testing with valgrind prefix: valgrind --track-origins=yes --error-limit=no
-set(TEST_BLENDER_EXE ${TEST_BLENDER_EXE} --background --factory-startup --env-system-scripts ${CMAKE_SOURCE_DIR}/release/scripts)
-
-
-# ------------------------------------------------------------------------------
-# GENERAL PYTHON CORRECTNESS TESTS
-add_test(script_load_addons ${TEST_BLENDER_EXE}
- --python ${CMAKE_CURRENT_LIST_DIR}/bl_load_addons.py
-)
-
-add_test(script_load_modules ${TEST_BLENDER_EXE}
- --python ${CMAKE_CURRENT_LIST_DIR}/bl_load_py_modules.py
-)
-
-# test running operators doesn't segfault under various conditions
-add_test(script_run_operators ${TEST_BLENDER_EXE}
- --python ${CMAKE_CURRENT_LIST_DIR}/bl_run_operators.py
-)
-
-# ------------------------------------------------------------------------------
-# IO TESTS
-
-# OBJ Import tests
-add_test(import_obj_cube ${TEST_BLENDER_EXE}
- --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py --
- --run={'FINISHED'}&bpy.ops.import_scene.obj\(filepath='${TEST_SRC_DIR}/io_tests/obj/cube.obj'\)
- --md5=4d090508b812b5e08168aa2614746bda --md5_method=SCENE
- --write-blend=${TEST_OUT_DIR}/import_obj_cube.blend
-)
-
-add_test(import_obj_nurbs_cyclic ${TEST_BLENDER_EXE}
- --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py --
- --run={'FINISHED'}&bpy.ops.import_scene.obj\(filepath='${TEST_SRC_DIR}/io_tests/obj/nurbs_cyclic.obj'\)
- --md5=9e0da7b65b4c4f818a203d56af2d3a4b --md5_method=SCENE
- --write-blend=${TEST_OUT_DIR}/import_obj_nurbs_cyclic.blend
-)
-
-add_test(import_obj_makehuman ${TEST_BLENDER_EXE}
- --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py --
- --run={'FINISHED'}&bpy.ops.import_scene.obj\(filepath='${TEST_SRC_DIR}/io_tests/obj/makehuman.obj'\)
- --md5=e0829dc078b0789e1d81f1071235bc4f --md5_method=SCENE
- --write-blend=${TEST_OUT_DIR}/import_obj_makehuman.blend
-)
-
-# OBJ Export tests
-add_test(export_obj_cube ${TEST_BLENDER_EXE}
- ${TEST_SRC_DIR}/io_tests/blend_geometry/all_quads.blend
- --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py --
- --run={'FINISHED'}&bpy.ops.export_scene.obj\(filepath='${TEST_OUT_DIR}/export_obj_cube.obj',use_selection=False\)
- --md5_source=${TEST_OUT_DIR}/export_obj_cube.obj
- --md5_source=${TEST_OUT_DIR}/export_obj_cube.mtl
- --md5=f0580f0e5d7b379e0460f11d8fde244d --md5_method=FILE
-)
-
-add_test(export_obj_nurbs ${TEST_BLENDER_EXE}
- ${TEST_SRC_DIR}/io_tests/blend_geometry/nurbs.blend
- --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py --
- --run={'FINISHED'}&bpy.ops.export_scene.obj\(filepath='${TEST_OUT_DIR}/export_obj_nurbs.obj',use_selection=False,use_nurbs=True\)
- --md5_source=${TEST_OUT_DIR}/export_obj_nurbs.obj
- --md5_source=${TEST_OUT_DIR}/export_obj_nurbs.mtl
- --md5=aa00875343e0feea449739146d26d7d0 --md5_method=FILE
-)
-
-add_test(export_obj_all_objects ${TEST_BLENDER_EXE}
- ${TEST_SRC_DIR}/io_tests/blend_scene/all_objects.blend
- --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py --
- --run={'FINISHED'}&bpy.ops.export_scene.obj\(filepath='${TEST_OUT_DIR}/export_obj_all_objects.obj',use_selection=False,use_nurbs=True\)
- --md5_source=${TEST_OUT_DIR}/export_obj_all_objects.obj
- --md5_source=${TEST_OUT_DIR}/export_obj_all_objects.mtl
- --md5=4c93980ecfb7d02ca68d3da8e2fced69 --md5_method=FILE
-)
-
-
-
-# PLY Import tests
-add_test(import_ply_cube ${TEST_BLENDER_EXE}
- --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py --
- --run={'FINISHED'}&bpy.ops.import_mesh.ply\(filepath='${TEST_SRC_DIR}/io_tests/ply/cube_ascii.ply'\)
- --md5=527134343c27fc0ea73115b85fbfd3ac --md5_method=SCENE
- --write-blend=${TEST_OUT_DIR}/import_ply_cube.blend
-)
-
-add_test(import_ply_bunny ${TEST_BLENDER_EXE}
- --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py --
- --run={'FINISHED'}&bpy.ops.import_mesh.ply\(filepath='${TEST_SRC_DIR}/io_tests/ply/bunny2.ply'\)
- --md5=6ea5b8533400a17accf928b8fd024eaa --md5_method=SCENE
- --write-blend=${TEST_OUT_DIR}/import_ply_bunny.blend
-)
-
-add_test(import_ply_small_holes ${TEST_BLENDER_EXE}
- --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py --
- --run={'FINISHED'}&bpy.ops.import_mesh.ply\(filepath='${TEST_SRC_DIR}/io_tests/ply/many_small_holes.ply'\)
- --md5=c3093e26ecae5b6d59fbbcf2a0d0b39f --md5_method=SCENE
- --write-blend=${TEST_OUT_DIR}/import_ply_small_holes.blend
-)
-
-# PLY Export tests (TODO)
-
-
-
-# STL Import tests
-add_test(import_stl_cube ${TEST_BLENDER_EXE}
- --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py --
- --run={'FINISHED'}&bpy.ops.import_mesh.stl\(filepath='${TEST_SRC_DIR}/io_tests/stl/cube.stl'\)
- --md5=8ceb5bb7e1cb5f4342fa1669988c66b4 --md5_method=SCENE
- --write-blend=${TEST_OUT_DIR}/import_stl_cube.blend
-)
-
-add_test(import_stl_conrod ${TEST_BLENDER_EXE}
- --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py --
- --run={'FINISHED'}&bpy.ops.import_mesh.stl\(filepath='${TEST_SRC_DIR}/io_tests/stl/conrod.stl'\)
- --md5=690a4b8eb9002dcd8631c5a575ea7348 --md5_method=SCENE
- --write-blend=${TEST_OUT_DIR}/import_stl_conrod.blend
-)
-
-add_test(import_stl_knot_max_simplified ${TEST_BLENDER_EXE}
- --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py --
- --run={'FINISHED'}&bpy.ops.import_mesh.stl\(filepath='${TEST_SRC_DIR}/io_tests/stl/knot_max_simplified.stl'\)
- --md5=baf82803f45a84ec4ddbad9cef57dd3e --md5_method=SCENE
- --write-blend=${TEST_OUT_DIR}/import_stl_knot_max_simplified.blend
-)
-
-# STL Export tests (TODO)
-
-
-
-# X3D Import
-add_test(import_x3d_cube ${TEST_BLENDER_EXE}
- --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py --
- --run={'FINISHED'}&bpy.ops.import_scene.x3d\(filepath='${TEST_SRC_DIR}/io_tests/x3d/color_cube.x3d'\)
- --md5=330c0cf6e8c44d5fe5b662d30b75be89 --md5_method=SCENE
- --write-blend=${TEST_OUT_DIR}/import_x3d_cube.blend
-)
-
-add_test(import_x3d_teapot ${TEST_BLENDER_EXE}
- --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py --
- --run={'FINISHED'}&bpy.ops.import_scene.x3d\(filepath='${TEST_SRC_DIR}/io_tests/x3d/teapot.x3d'\)
- --md5=b2f02157bc918b54b835d1e6ece70423 --md5_method=SCENE
- --write-blend=${TEST_OUT_DIR}/import_x3d_teapot.blend
-)
-
-add_test(import_x3d_suzanne_material ${TEST_BLENDER_EXE}
- --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py --
- --run={'FINISHED'}&bpy.ops.import_scene.x3d\(filepath='${TEST_SRC_DIR}/io_tests/x3d/suzanne_material.x3d'\)
- --md5=11837901cbbfabef52b6ab4f26fe97b3 --md5_method=SCENE
- --write-blend=${TEST_OUT_DIR}/import_x3d_suzanne_material.blend
-)
-
-# X3D Export
-add_test(export_x3d_cube ${TEST_BLENDER_EXE}
- ${TEST_SRC_DIR}/io_tests/blend_geometry/all_quads.blend
- --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py --
- --run={'FINISHED'}&bpy.ops.export_scene.x3d\(filepath='${TEST_OUT_DIR}/export_x3d_cube.x3d',use_selection=False\)
- --md5_source=${TEST_OUT_DIR}/export_x3d_cube.x3d
- --md5=9198ca86f19b68a4f1eb75bb48cb3dea --md5_method=FILE
-)
-
-add_test(export_x3d_nurbs ${TEST_BLENDER_EXE}
- ${TEST_SRC_DIR}/io_tests/blend_geometry/nurbs.blend
- --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py --
- --run={'FINISHED'}&bpy.ops.export_scene.x3d\(filepath='${TEST_OUT_DIR}/export_x3d_nurbs.x3d',use_selection=False\)
- --md5_source=${TEST_OUT_DIR}/export_x3d_nurbs.x3d
- --md5=078c0ca5a08f123cd2cdac48afb54853 --md5_method=FILE
-)
-
-add_test(export_x3d_all_objects ${TEST_BLENDER_EXE}
- ${TEST_SRC_DIR}/io_tests/blend_scene/all_objects.blend
- --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py --
- --run={'FINISHED'}&bpy.ops.export_scene.x3d\(filepath='${TEST_OUT_DIR}/export_x3d_all_objects.x3d',use_selection=False\)
- --md5_source=${TEST_OUT_DIR}/export_x3d_all_objects.x3d
- --md5=090f4f36c450826a043f9cd074d9cbb4 --md5_method=FILE
-)
-
-
-
-# 3DS Import
-add_test(import_3ds_cube ${TEST_BLENDER_EXE}
- --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py --
- --run={'FINISHED'}&bpy.ops.import_scene.autodesk_3ds\(filepath='${TEST_SRC_DIR}/io_tests/3ds/cube.3ds'\)
- --md5=cb5a45c35a343c3f5beca2a918472951 --md5_method=SCENE
- --write-blend=${TEST_OUT_DIR}/import_3ds_cube.blend
-)
-
-add_test(import_3ds_hierarchy_lara ${TEST_BLENDER_EXE}
- --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py --
- --run={'FINISHED'}&bpy.ops.import_scene.autodesk_3ds\(filepath='${TEST_SRC_DIR}/io_tests/3ds/hierarchy_lara.3ds'\)
- --md5=2e9812099b26ad607fdcf4c7be918c71 --md5_method=SCENE
- --write-blend=${TEST_OUT_DIR}/import_3ds_hierarchy_lara.blend
-)
-
-add_test(import_3ds_hierarchy_greek_trireme ${TEST_BLENDER_EXE}
- --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py --
- --run={'FINISHED'}&bpy.ops.import_scene.autodesk_3ds\(filepath='${TEST_SRC_DIR}/io_tests/3ds/hierarchy_greek_trireme.3ds'\)
- --md5=d05b922d7be20356d8409d1f768a3a9a --md5_method=SCENE
- --write-blend=${TEST_OUT_DIR}/import_3ds_hierarchy_greek_trireme.blend
-)
-
-# 3DS Export
-add_test(export_3ds_cube ${TEST_BLENDER_EXE}
- ${TEST_SRC_DIR}/io_tests/blend_geometry/all_quads.blend
- --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py --
- --run={'FINISHED'}&bpy.ops.export_scene.autodesk_3ds\(filepath='${TEST_OUT_DIR}/export_3ds_cube.3ds',use_selection=False\)
- --md5_source=${TEST_OUT_DIR}/export_3ds_cube.3ds
- --md5=0df6cfb130052d01e31ef77d391d4cc0 --md5_method=FILE
-)
-
-add_test(export_3ds_nurbs ${TEST_BLENDER_EXE}
- ${TEST_SRC_DIR}/io_tests/blend_geometry/nurbs.blend
- --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py --
- --run={'FINISHED'}&bpy.ops.export_scene.autodesk_3ds\(filepath='${TEST_OUT_DIR}/export_3ds_nurbs.3ds',use_selection=False\)
- --md5_source=${TEST_OUT_DIR}/export_3ds_nurbs.3ds
- --md5=ba1a6d43346fee3bcadc7e30e3c95935 --md5_method=FILE
-)
-
-add_test(export_3ds_all_objects ${TEST_BLENDER_EXE}
- ${TEST_SRC_DIR}/io_tests/blend_scene/all_objects.blend
- --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py --
- --run={'FINISHED'}&bpy.ops.export_scene.autodesk_3ds\(filepath='${TEST_OUT_DIR}/export_3ds_all_objects.3ds',use_selection=False\)
- --md5_source=${TEST_OUT_DIR}/export_3ds_all_objects.3ds
- --md5=87349a4699f1006e8194fb0ac05ac9c8 --md5_method=FILE
-)
-
-
-
-# FBX Export
-# 'use_metadata=False' for reliable md5's
-add_test(export_fbx_cube ${TEST_BLENDER_EXE}
- ${TEST_SRC_DIR}/io_tests/blend_geometry/all_quads.blend
- --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py --
- --run={'FINISHED'}&bpy.ops.export_scene.fbx\(filepath='${TEST_OUT_DIR}/export_fbx_cube.fbx',use_selection=False,use_metadata=False\)
- --md5_source=${TEST_OUT_DIR}/export_fbx_cube.fbx
- --md5=b2428e11b9ae650819f8d8b38cd869f7 --md5_method=FILE
-)
-
-add_test(export_fbx_nurbs ${TEST_BLENDER_EXE}
- ${TEST_SRC_DIR}/io_tests/blend_geometry/nurbs.blend
- --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py --
- --run={'FINISHED'}&bpy.ops.export_scene.fbx\(filepath='${TEST_OUT_DIR}/export_fbx_nurbs.fbx',use_selection=False,use_metadata=False\)
- --md5_source=${TEST_OUT_DIR}/export_fbx_nurbs.fbx
- --md5=741b536e98d6b105952766d0f290f270 --md5_method=FILE
-)
-
-add_test(export_fbx_all_objects ${TEST_BLENDER_EXE}
- ${TEST_SRC_DIR}/io_tests/blend_scene/all_objects.blend
- --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py --
- --run={'FINISHED'}&bpy.ops.export_scene.fbx\(filepath='${TEST_OUT_DIR}/export_fbx_all_objects.fbx',use_selection=False,use_metadata=False\)
- --md5_source=${TEST_OUT_DIR}/export_fbx_all_objects.fbx
- --md5=d6b8b027cd2a0e99d88e5c3d77932748 --md5_method=FILE
-)
diff --git a/source/tests/batch_import.py b/source/tests/batch_import.py
deleted file mode 100644
index 5c228c014ca..00000000000
--- a/source/tests/batch_import.py
+++ /dev/null
@@ -1,202 +0,0 @@
-# ##### 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 #####
-
-# <pep8 compliant>
-
-"""
-Example Usage:
-
-./blender.bin --background --python source/tests/batch_import.py -- \
- --operator="bpy.ops.import_scene.obj" \
- --path="/fe/obj" \
- --match="*.obj" \
- --start=0 --end=10 \
- --save_path=/tmp/test
-
-./blender.bin --background --python source/tests/batch_import.py -- \
- --operator="bpy.ops.import_scene.autodesk_3ds" \
- --path="/fe/" \
- --match="*.3ds" \
- --start=0 --end=1000 \
- --save_path=/tmp/test
-
-./blender.bin --background --addons io_curve_svg --python source/tests/batch_import.py -- \
- --operator="bpy.ops.import_curve.svg" \
- --path="/usr/" \
- --match="*.svg" \
- --start=0 --end=1000 \
- --save_path=/tmp/test
-
-"""
-
-import os
-import sys
-
-
-def clear_scene():
- import bpy
- unique_obs = set()
- for scene in bpy.data.scenes:
- for obj in scene.objects[:]:
- scene.objects.unlink(obj)
- unique_obs.add(obj)
-
- # remove obdata, for now only worry about the startup scene
- for bpy_data_iter in (bpy.data.objects, bpy.data.meshes, bpy.data.lamps, bpy.data.cameras):
- for id_data in bpy_data_iter:
- bpy_data_iter.remove(id_data)
-
-
-def batch_import(operator="",
- path="",
- save_path="",
- match="",
- start=0,
- end=sys.maxsize,
- ):
- import addon_utils
- _reset_all = addon_utils.reset_all # XXX, hack
-
- import fnmatch
-
- path = os.path.normpath(path)
- path = os.path.abspath(path)
-
- match_upper = match.upper()
- pattern_match = lambda a: fnmatch.fnmatchcase(a.upper(), match_upper)
-
- def file_generator(path):
- for dirpath, dirnames, filenames in os.walk(path):
-
- # skip '.svn'
- if dirpath.startswith("."):
- continue
-
- for filename in filenames:
- if pattern_match(filename):
- yield os.path.join(dirpath, filename)
-
- print("Collecting %r files in %s" % (match, path), end="")
-
- files = list(file_generator(path))
- files_len = len(files)
- end = min(end, len(files))
- print(" found %d" % files_len, end="")
-
- files.sort()
- files = files[start:end]
- if len(files) != files_len:
- print(" using a subset in (%d, %d), total %d" % (start, end, len(files)), end="")
-
- import bpy
- op = eval(operator)
-
- tot_done = 0
- tot_fail = 0
-
- for i, f in enumerate(files):
- print(" %s(filepath=%r) # %d of %d" % (operator, f, i + start, len(files)))
-
- # hack so loading the new file doesnt undo our loaded addons
- addon_utils.reset_all = lambda: None # XXX, hack
-
- bpy.ops.wm.read_factory_settings()
-
- addon_utils.reset_all = _reset_all # XXX, hack
- clear_scene()
-
- result = op(filepath=f)
-
- if 'FINISHED' in result:
- tot_done += 1
- else:
- tot_fail += 1
-
- if save_path:
- fout = os.path.join(save_path, os.path.relpath(f, path))
- fout_blend = os.path.splitext(fout)[0] + ".blend"
-
- print("\tSaving: %r" % fout_blend)
-
- fout_dir = os.path.dirname(fout_blend)
- if not os.path.exists(fout_dir):
- os.makedirs(fout_dir)
-
- bpy.ops.wm.save_as_mainfile(filepath=fout_blend)
-
- print("finished, done:%d, fail:%d" % (tot_done, tot_fail))
-
-
-def main():
- import optparse
-
- # get the args passed to blender after "--", all of which are ignored by blender specifically
- # so python may receive its own arguments
- argv = sys.argv
-
- if "--" not in argv:
- argv = [] # as if no args are passed
- else:
- argv = argv[argv.index("--") + 1:] # get all args after "--"
-
- # When --help or no args are given, print this help
- usage_text = "Run blender in background mode with this script:"
- usage_text += " blender --background --python " + __file__ + " -- [options]"
-
- parser = optparse.OptionParser(usage=usage_text)
-
- # Example background utility, add some text and renders or saves it (with options)
- # Possible types are: string, int, long, choice, float and complex.
- parser.add_option("-o", "--operator", dest="operator", help="This text will be used to render an image", type="string")
- parser.add_option("-p", "--path", dest="path", help="Path to use for searching for files", type='string')
- parser.add_option("-m", "--match", dest="match", help="Wildcard to match filename", type="string")
- parser.add_option("-s", "--save_path", dest="save_path", help="Save the input file to a blend file in a new location", metavar='string')
- parser.add_option("-S", "--start", dest="start", help="From collected files, start with this index", metavar='int')
- parser.add_option("-E", "--end", dest="end", help="From collected files, end with this index", metavar='int')
-
- options, args = parser.parse_args(argv) # In this example we wont use the args
-
- if not argv:
- parser.print_help()
- return
-
- if not options.operator:
- print("Error: --operator=\"some string\" argument not given, aborting.")
- parser.print_help()
- return
-
- if options.start is None:
- options.start = 0
-
- if options.end is None:
- options.end = sys.maxsize
-
- # Run the example function
- batch_import(operator=options.operator,
- path=options.path,
- save_path=options.save_path,
- match=options.match,
- start=int(options.start),
- end=int(options.end),
- )
-
- print("batch job finished, exiting")
-
-
-if __name__ == "__main__":
- main()
diff --git a/source/tests/bl_load_addons.py b/source/tests/bl_load_addons.py
deleted file mode 100644
index 5bd83abbcb6..00000000000
--- a/source/tests/bl_load_addons.py
+++ /dev/null
@@ -1,78 +0,0 @@
-# ##### 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 #####
-
-# <pep8 compliant>
-
-# simple script to enable all addons, and disable
-
-import bpy
-import addon_utils
-
-import sys
-import imp
-
-
-def reload_addons(do_reload=True, do_reverse=True):
- modules = addon_utils.modules({})
- modules.sort(key=lambda mod: mod.__name__)
- addons = bpy.context.user_preferences.addons
-
- # first disable all
- for mod_name in list(addons.keys()):
- addon_utils.disable(mod_name)
-
- assert(bool(addons) == False)
-
- # Run twice each time.
- for i in (0, 1):
- for mod in modules:
- mod_name = mod.__name__
- print("\tenabling:", mod_name)
- addon_utils.enable(mod_name)
- assert(mod_name in addons)
-
- for mod in addon_utils.modules({}):
- mod_name = mod.__name__
- print("\tdisabling:", mod_name)
- addon_utils.disable(mod_name)
- assert(not (mod_name in addons))
-
- # now test reloading
- if do_reload:
- imp.reload(sys.modules[mod_name])
-
- if do_reverse:
- # incase order matters when it shouldnt
- modules.reverse()
-
-
-def main():
- reload_addons(do_reload=False, do_reverse=False)
- reload_addons(do_reload=False, do_reverse=True)
- reload_addons(do_reload=True, do_reverse=True)
-
-
-if __name__ == "__main__":
-
- # So a python error exits(1)
- try:
- main()
- except:
- import traceback
- traceback.print_exc()
- sys.exit(1)
diff --git a/source/tests/bl_load_py_modules.py b/source/tests/bl_load_py_modules.py
deleted file mode 100644
index 5a65578d8d3..00000000000
--- a/source/tests/bl_load_py_modules.py
+++ /dev/null
@@ -1,145 +0,0 @@
-# ##### 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 #####
-
-# <pep8 compliant>
-
-# simple script to enable all addons, and disable
-
-import bpy
-import addon_utils
-
-import sys
-import os
-import imp
-
-
-def source_list(path, filename_check=None):
- from os.path import join
- for dirpath, dirnames, filenames in os.walk(path):
- # skip '.svn'
- if dirpath.startswith("."):
- continue
-
- for filename in filenames:
- filepath = join(dirpath, filename)
- if filename_check is None or filename_check(filepath):
- yield filepath
-
-
-def load_addons():
- modules = addon_utils.modules({})
- modules.sort(key=lambda mod: mod.__name__)
- addons = bpy.context.user_preferences.addons
-
- # first disable all
- for mod_name in list(addons.keys()):
- addon_utils.disable(mod_name)
-
- assert(bool(addons) == False)
-
- for mod in modules:
- mod_name = mod.__name__
- addon_utils.enable(mod_name)
- assert(mod_name in addons)
-
-
-def load_modules():
- modules = []
- module_paths = []
-
- # paths blender stores scripts in.
- paths = bpy.utils.script_paths()
-
- #
- # find all sys.path we added
- for script_path in paths:
- for mod_dir in sys.path:
- if mod_dir.startswith(script_path):
- module_paths.append(mod_dir)
-
- #
- # collect modules from our paths.
- for mod_dir in module_paths:
- # print("mod_dir", mod_dir)
- for mod, mod_full in bpy.path.module_names(mod_dir):
- modules.append(__import__(mod))
-
- #
- # now submodules
- for m in modules:
- filepath = m.__file__
- if os.path.basename(filepath).startswith("__init__."):
- mod_dir = os.path.dirname(filepath)
- for submod, submod_full in bpy.path.module_names(mod_dir):
- # fromlist is ignored, ugh.
- mod_name_full = m.__name__ + "." + submod
- __import__(mod_name_full)
- mod_imp = sys.modules[mod_name_full]
-
- # check we load what we ask for.
- assert(os.path.samefile(mod_imp.__file__, submod_full))
-
- modules.append(mod_imp)
-
- #
- # check which filepaths we didnt load
- source_files = []
- for mod_dir in module_paths:
- source_files.extend(source_list(mod_dir, filename_check=lambda f: f.endswith(".py")))
-
- source_files = list(set(source_files))
- source_files.sort()
-
- #
- # remove loaded files
- loaded_files = list({m.__file__ for m in modules})
- loaded_files.sort()
-
- for f in loaded_files:
- source_files.remove(f)
-
- #
- # test we tested all files except for presets and templates
- ignore_paths = [
- os.sep + "presets" + os.sep,
- os.sep + "templates" + os.sep,
- ]
-
- for f in source_files:
- ok = False
- for ignore in ignore_paths:
- if ignore in f:
- ok = True
- if not ok:
- raise Exception("Source file %r not loaded in test" % f)
-
- print("loaded %d modules" % len(loaded_files))
-
-
-def main():
- load_addons()
- load_modules()
-
-if __name__ == "__main__":
- # So a python error exits(1)
- try:
- main()
- except:
- import traceback
- traceback.print_exc()
- sys.exit(1)
diff --git a/source/tests/bl_run_operators.py b/source/tests/bl_run_operators.py
deleted file mode 100644
index 668b4e69228..00000000000
--- a/source/tests/bl_run_operators.py
+++ /dev/null
@@ -1,176 +0,0 @@
-# ##### 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 #####
-
-# <pep8 compliant>
-
-# semi-useful script, runs all operators in a number of different
-# contexts, cheap way to find misc small bugs but is in no way a complete test.
-#
-# only error checked for here is a segfault.
-
-import bpy
-import sys
-
-op_blacklist = (
- "script.reload",
- "export*.*",
- "import*.*",
- "*.save_*",
- "*.read_*",
- "*.open_*",
- "*.link_append",
- "render.render",
- "*.*_export",
- "*.*_import",
- "wm.url_open",
- "wm.doc_view",
- "wm.path_open",
- "help.operator_cheat_sheet",
- )
-
-
-def filter_op_list(operators):
- from fnmatch import fnmatchcase
-
- def is_op_ok(op):
- for op_match in op_blacklist:
- if fnmatchcase(op, op_match):
- print(" skipping: %s (%s)" % (op, op_match))
- return False
- return True
-
- operators[:] = [op for op in operators if is_op_ok(op[0])]
-
-
-def run_ops(operators, setup_func=None):
- print("\ncontext:", setup_func.__name__)
- # first invoke
- for op_id, op in operators:
- if op.poll():
- print(" operator:", op_id)
- sys.stdout.flush() # incase of crash
-
- # disable will get blender in a bad state and crash easy!
- bpy.ops.wm.read_factory_settings()
-
- setup_func()
-
- for mode in ('EXEC_DEFAULT', 'INVOKE_DEFAULT'):
- try:
- op(mode)
- except:
- #import traceback
- #traceback.print_exc()
- pass
-
-
-# contexts
-def ctx_clear_scene(): # copied from batch_import.py
- unique_obs = set()
- for scene in bpy.data.scenes:
- for obj in scene.objects[:]:
- scene.objects.unlink(obj)
- unique_obs.add(obj)
-
- # remove obdata, for now only worry about the startup scene
- for bpy_data_iter in (bpy.data.objects, bpy.data.meshes, bpy.data.lamps, bpy.data.cameras):
- for id_data in bpy_data_iter:
- bpy_data_iter.remove(id_data)
-
-
-def ctx_editmode_mesh():
- bpy.ops.object.mode_set(mode='EDIT')
- bpy.ops.object.vertex_group_add()
-
-
-def ctx_editmode_curves():
- bpy.ops.curve.primitive_nurbs_circle_add()
- bpy.ops.object.mode_set(mode='EDIT')
-
-
-def ctx_editmode_surface():
- bpy.ops.surface.primitive_nurbs_surface_torus_add()
- bpy.ops.object.mode_set(mode='EDIT')
-
-
-def ctx_editmode_mball():
- bpy.ops.object.metaball_add()
- bpy.ops.object.mode_set(mode='EDIT')
-
-
-def ctx_editmode_text():
- bpy.ops.object.text_add()
- bpy.ops.object.mode_set(mode='EDIT')
-
-
-def ctx_editmode_armature():
- bpy.ops.object.armature_add()
- bpy.ops.object.mode_set(mode='EDIT')
-
-
-def ctx_editmode_lattice():
- bpy.ops.object.add(type='LATTICE')
- bpy.ops.object.mode_set(mode='EDIT')
- # bpy.ops.object.vertex_group_add()
-
-
-def ctx_object_empty():
- bpy.ops.object.add(type='EMPTY')
-
-
-def ctx_weightpaint():
- bpy.ops.object.mode_set(mode='WEIGHT_PAINT')
-
-
-def main():
- # bpy.ops.wm.read_factory_settings()
- import bpy
- operators = []
- for mod_name in dir(bpy.ops):
- mod = getattr(bpy.ops, mod_name)
- for submod_name in dir(mod):
- op = getattr(mod, submod_name)
- operators.append(("%s.%s" % (mod_name, submod_name), op))
-
- operators.sort(key=lambda op: op[0])
-
- filter_op_list(operators)
-
- # for testing, mix the list up.
- #operators.reverse()
-
- #import random
- #random.shuffle(operators)
-
- # Run the operator tests in different contexts
- run_ops(operators, setup_func=lambda: None)
- run_ops(operators, setup_func=ctx_editmode_surface)
- run_ops(operators, setup_func=ctx_object_empty)
- run_ops(operators, setup_func=ctx_editmode_armature)
- run_ops(operators, setup_func=ctx_editmode_mesh)
- run_ops(operators, setup_func=ctx_clear_scene)
- run_ops(operators, setup_func=ctx_editmode_curves)
- run_ops(operators, setup_func=ctx_editmode_mball)
- run_ops(operators, setup_func=ctx_editmode_text)
- run_ops(operators, setup_func=ctx_weightpaint)
- run_ops(operators, setup_func=ctx_editmode_lattice)
-
- print("finished")
-
-if __name__ == "__main__":
- main()
diff --git a/source/tests/bl_test.py b/source/tests/bl_test.py
deleted file mode 100644
index cfe91356444..00000000000
--- a/source/tests/bl_test.py
+++ /dev/null
@@ -1,197 +0,0 @@
-# ##### 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 #####
-
-# <pep8 compliant>
-
-import sys
-import os
-
-
-# may split this out into a new file
-def replace_bpy_app_version():
- """ So MD5's are predictable from output which uses blenders versions.
- """
-
- import bpy
-
- app = bpy.app
- app_fake = type(bpy)("bpy.app")
-
- for attr in dir(app):
- if not attr.startswith("_"):
- setattr(app_fake, attr, getattr(app, attr))
-
- app_fake.version = 0, 0, 0
- app_fake.version_string = "0.00 (sub 0)"
- bpy.app = app_fake
-
-
-def clear_startup_blend():
- import bpy
-
- for scene in bpy.data.scenes:
- for obj in scene.objects:
- scene.objects.unlink(obj)
-
-
-def blend_to_md5():
- import bpy
- scene = bpy.context.scene
- ROUND = 4
-
- def matrix2str(matrix):
- return "".join([str(round(axis, ROUND)) for vector in matrix for axis in vector]).encode('ASCII')
-
- def coords2str(seq, attr):
- return "".join([str(round(axis, ROUND)) for vertex in seq for axis in getattr(vertex, attr)]).encode('ASCII')
-
- import hashlib
-
- md5 = hashlib.new("md5")
- md5_update = md5.update
-
- for obj in scene.objects:
- md5_update(matrix2str(obj.matrix_world))
- data = obj.data
-
- if type(data) == bpy.types.Mesh:
- md5_update(coords2str(data.vertices, "co"))
- elif type(data) == bpy.types.Curve:
- for spline in data.splines:
- md5_update(coords2str(spline.bezier_points, "co"))
- md5_update(coords2str(spline.points, "co"))
-
- return md5.hexdigest()
-
-
-def main():
- argv = sys.argv
- print(" args:", " ".join(argv))
- argv = argv[argv.index("--") + 1:]
-
- def arg_extract(arg, optional=True, array=False):
- arg += "="
- if array:
- value = []
- else:
- value = None
-
- i = 0
- while i < len(argv):
- if argv[i].startswith(arg):
- item = argv[i][len(arg):]
- del argv[i]
- i -= 1
-
- if array:
- value.append(item)
- else:
- value = item
- break
-
- i += 1
-
- if (not value) and (not optional):
- print(" '%s' not set" % arg)
- sys.exit(1)
-
- return value
-
- run = arg_extract("--run", optional=False)
- md5 = arg_extract("--md5", optional=False)
- md5_method = arg_extract("--md5_method", optional=False) # 'SCENE' / 'FILE'
-
- # only when md5_method is 'FILE'
- md5_source = arg_extract("--md5_source", optional=True, array=True)
-
- # save blend file, for testing
- write_blend = arg_extract("--write-blend", optional=True)
-
- # ensure files are written anew
- for f in md5_source:
- if os.path.exists(f):
- os.remove(f)
-
- import bpy
-
- replace_bpy_app_version()
- if not bpy.data.filepath:
- clear_startup_blend()
-
- print(" Running: '%s'" % run)
- print(" MD5: '%s'!" % md5)
-
- try:
- result = eval(run)
- except:
- import traceback
- traceback.print_exc()
- sys.exit(1)
-
- if write_blend is not None:
- print(" Writing Blend: %s" % write_blend)
- bpy.ops.wm.save_mainfile(filepath=write_blend, check_existing=False)
-
- print(" Result: '%s'" % str(result))
- if not result:
- print(" Running: %s -> False" % run)
- sys.exit(1)
-
- if md5_method == 'SCENE':
- md5_new = blend_to_md5()
- elif md5_method == 'FILE':
- if not md5_source:
- print(" Missing --md5_source argument")
- sys.exit(1)
-
- for f in md5_source:
- if not os.path.exists(f):
- print(" Missing --md5_source=%r argument does not point to a file")
- sys.exit(1)
-
- import hashlib
-
- md5_instance = hashlib.new("md5")
- md5_update = md5_instance.update
-
- for f in md5_source:
- filehandle = open(f, "rb")
- md5_update(filehandle.read())
- filehandle.close()
-
- md5_new = md5_instance.hexdigest()
-
- else:
- print(" Invalid --md5_method=%s argument is not a valid source")
- sys.exit(1)
-
- if md5 != md5_new:
- print(" Running: %s\n MD5 Recieved: %s\n MD5 Expected: %s" % (run, md5_new, md5))
- sys.exit(1)
-
- print(" Success: %s" % run)
-
-
-if __name__ == "__main__":
- # So a python error exits(1)
- try:
- main()
- except:
- import traceback
- traceback.print_exc()
- sys.exit(1)
diff --git a/source/tests/pep8.py b/source/tests/pep8.py
deleted file mode 100644
index f7c416553b2..00000000000
--- a/source/tests/pep8.py
+++ /dev/null
@@ -1,118 +0,0 @@
-# ##### 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 #####
-
-# <pep8 compliant>
-
-import os
-
-# depends on pep8, pyflakes, pylint
-# for ubuntu
-#
-# sudo apt-get install pylint pyflakes
-#
-# sudo apt-get install python-setuptools python-pip
-# sudo pip install pep8
-#
-# in debian install pylint pyflakes pep8 with apt-get/aptitude/etc
-#
-# on *nix run
-# python source/tests/pep8.py > test_pep8.log 2>&1
-
-# how many lines to read into the file, pep8 comment
-# should be directly after the licence header, ~20 in most cases
-PEP8_SEEK_COMMENT = 40
-SKIP_PREFIX = "./tools", "./config", "./scons", "./extern"
-
-
-def file_list_py(path):
- for dirpath, dirnames, filenames in os.walk(path):
- for filename in filenames:
- if filename.endswith(".py") or filename.endswith(".cfg"):
- yield os.path.join(dirpath, filename)
-
-
-def is_pep8(path):
- print(path)
- if open(path, 'rb').read(3) == b'\xef\xbb\xbf':
- print("\nfile contains BOM, remove first 3 bytes: %r\n" % path)
-
- # templates dont have a header but should be pep8
- for d in ("presets", "templates", "examples"):
- if ("%s%s%s" % (os.sep, d, os.sep)) in path:
- return 1
-
- f = open(path, 'r', encoding="utf8")
- for i in range(PEP8_SEEK_COMMENT):
- line = f.readline()
- if line.startswith("# <pep8"):
- if line.startswith("# <pep8 compliant>"):
- return 1
- elif line.startswith("# <pep8-80 compliant>"):
- return 2
- f.close()
- return 0
-
-
-def main():
- files = []
- files_skip = []
- for f in file_list_py("."):
- if [None for prefix in SKIP_PREFIX if f.startswith(prefix)]:
- continue
-
- pep8_type = is_pep8(f)
-
- if pep8_type:
- # so we can batch them for each tool.
- files.append((os.path.abspath(f), pep8_type))
- else:
- files_skip.append(f)
-
- print("\nSkipping...")
- for f in files_skip:
- print(" %s" % f)
-
- # strict imports
- print("\n\n\n# running pep8...")
- import re
- import_check = re.compile(r"\s*from\s+[A-z\.]+\s+import \*\s*")
- for f, pep8_type in files:
- for i, l in enumerate(open(f, 'r', encoding='utf8')):
- if import_check.match(l):
- print("%s:%d:0: global import bad practice" % (f, i + 1))
-
- print("\n\n\n# running pep8...")
- for f, pep8_type in files:
- if pep8_type == 1:
- # E501:80 line length
- os.system("pep8 --repeat --ignore=E501 '%s'" % (f))
- else:
- os.system("pep8 --repeat '%s'" % (f))
-
- # pyflakes
- print("\n\n\n# running pyflakes...")
- for f, pep8_type in files:
- os.system("pyflakes '%s'" % f)
-
- print("\n\n\n# running pylint...")
- for f, pep8_type in files:
- # let pep8 complain about line length
- os.system("pylint --reports=n --max-line-length=1000 '%s'" % f)
-
-if __name__ == "__main__":
- main()
diff --git a/source/tests/rna_array.py b/source/tests/rna_array.py
deleted file mode 100644
index 06b4735cc0d..00000000000
--- a/source/tests/rna_array.py
+++ /dev/null
@@ -1,297 +0,0 @@
-# ##### 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 #####
-
-import unittest
-import random
-
-test= bpy.data.test
-
-# farr - 1-dimensional array of float
-# fdarr - dynamic 1-dimensional array of float
-# fmarr - 3-dimensional ([3][4][5]) array of float
-# fdmarr - dynamic 3-dimensional (ditto size) array of float
-
-# same as above for other types except that the first letter is "i" for int and "b" for bool
-
-class TestArray(unittest.TestCase):
- # test that assignment works by: assign -> test value
- # - rvalue = list of float
- # - rvalue = list of numbers
- # test.object
- # bpy.data.test.farr[3], iarr[3], barr[...], fmarr, imarr, bmarr
-
- def setUp(self):
- test.farr= (1.0, 2.0, 3.0)
- test.iarr= (7, 8, 9)
- test.barr= (False, True, False)
-
- # test access
- # test slice access, negative indices
- def test_access(self):
- rvals= ([1.0, 2.0, 3.0], [7, 8, 9], [False, True, False])
- for arr, rval in zip((test.farr, test.iarr, test.barr), rvals):
- self.assertEqual(prop_to_list(arr), rval)
- self.assertEqual(arr[0:3], rval)
- self.assertEqual(arr[1:2], rval[1:2])
- self.assertEqual(arr[-1], arr[2])
- self.assertEqual(arr[-2], arr[1])
- self.assertEqual(arr[-3], arr[0])
-
- # fail when index out of bounds
- def test_access_fail(self):
- for arr in (test.farr, test.iarr, test.barr):
- self.assertRaises(IndexError, lambda : arr[4])
-
- # test assignment of a whole array
- def test_assign_array(self):
- # should accept int as float
- test.farr= (1, 2, 3)
-
- # fail when: unexpected no. of items, invalid item type
- def test_assign_array_fail(self):
- def assign_empty_list(arr):
- setattr(test, arr, ())
-
- for arr in ("farr", "iarr", "barr"):
- self.assertRaises(ValueError, assign_empty_list, arr)
-
- def assign_invalid_float():
- test.farr= (1.0, 2.0, "3.0")
-
- def assign_invalid_int():
- test.iarr= ("1", 2, 3)
-
- def assign_invalid_bool():
- test.barr= (True, 0.123, False)
-
- for func in [assign_invalid_float, assign_invalid_int, assign_invalid_bool]:
- self.assertRaises(TypeError, func)
-
- # shouldn't accept float as int
- def assign_float_as_int():
- test.iarr= (1, 2, 3.0)
- self.assertRaises(TypeError, assign_float_as_int)
-
- # non-dynamic arrays cannot change size
- def assign_different_size(arr, val):
- setattr(test, arr, val)
- for arr, val in zip(("iarr", "farr", "barr"), ((1, 2), (1.0, 2.0), (True, False))):
- self.assertRaises(ValueError, assign_different_size, arr, val)
-
- # test assignment of specific items
- def test_assign_item(self):
- for arr, rand_func in zip((test.farr, test.iarr, test.barr), (rand_float, rand_int, rand_bool)):
- for i in range(len(arr)):
- val= rand_func()
- arr[i]= val
-
- self.assertEqual(arr[i], val)
-
- # float prop should accept also int
- for i in range(len(test.farr)):
- val= rand_int()
- test.farr[i]= val
- self.assertEqual(test.farr[i], float(val))
-
- #
-
- def test_assign_item_fail(self):
- def assign_bad_index(arr):
- arr[4] = 1.0
-
- def assign_bad_type(arr):
- arr[1]= "123"
-
- for arr in [test.farr, test.iarr, test.barr]:
- self.assertRaises(IndexError, assign_bad_index, arr)
-
- # not testing bool because bool allows not only (True|False)
- for arr in [test.farr, test.iarr]:
- self.assertRaises(TypeError, assign_bad_type, arr)
-
- def test_dynamic_assign_array(self):
- # test various lengths here
- for arr, rand_func in zip(("fdarr", "idarr", "bdarr"), (rand_float, rand_int, rand_bool)):
- for length in range(1, 64):
- rval= make_random_array(length, rand_func)
- setattr(test, arr, rval)
- self.assertEqual(prop_to_list(getattr(test, arr)), rval)
-
- def test_dynamic_assign_array_fail(self):
- # could also test too big length here
-
- def assign_empty_list(arr):
- setattr(test, arr, ())
-
- for arr in ("fdarr", "idarr", "bdarr"):
- self.assertRaises(ValueError, assign_empty_list, arr)
-
-
-class TestMArray(unittest.TestCase):
- def setUp(self):
- # reset dynamic array sizes
- for arr, func in zip(("fdmarr", "idmarr", "bdmarr"), (rand_float, rand_int, rand_bool)):
- setattr(test, arr, make_random_3d_array((3, 4, 5), func))
-
- # test assignment
- def test_assign_array(self):
- for arr, func in zip(("fmarr", "imarr", "bmarr"), (rand_float, rand_int, rand_bool)):
- # assignment of [3][4][5]
- rval= make_random_3d_array((3, 4, 5), func)
- setattr(test, arr, rval)
- self.assertEqual(prop_to_list(getattr(test, arr)), rval)
-
- # test assignment of [2][4][5], [1][4][5] should work on dynamic arrays
-
- def test_assign_array_fail(self):
- def assign_empty_array():
- test.fmarr= ()
- self.assertRaises(ValueError, assign_empty_array)
-
- def assign_invalid_size(arr, rval):
- setattr(test, arr, rval)
-
- # assignment of 3,4,4 or 3,3,5 should raise ex
- for arr, func in zip(("fmarr", "imarr", "bmarr"), (rand_float, rand_int, rand_bool)):
- rval= make_random_3d_array((3, 4, 4), func)
- self.assertRaises(ValueError, assign_invalid_size, arr, rval)
-
- rval= make_random_3d_array((3, 3, 5), func)
- self.assertRaises(ValueError, assign_invalid_size, arr, rval)
-
- rval= make_random_3d_array((3, 3, 3), func)
- self.assertRaises(ValueError, assign_invalid_size, arr, rval)
-
- def test_assign_item(self):
- # arr[i] = x
- for arr, func in zip(("fmarr", "imarr", "bmarr", "fdmarr", "idmarr", "bdmarr"), (rand_float, rand_int, rand_bool) * 2):
- rval= make_random_2d_array((4, 5), func)
-
- for i in range(3):
- getattr(test, arr)[i]= rval
- self.assertEqual(prop_to_list(getattr(test, arr)[i]), rval)
-
- # arr[i][j] = x
- for arr, func in zip(("fmarr", "imarr", "bmarr", "fdmarr", "idmarr", "bdmarr"), (rand_float, rand_int, rand_bool) * 2):
-
- arr= getattr(test, arr)
- rval= make_random_array(5, func)
-
- for i in range(3):
- for j in range(4):
- arr[i][j]= rval
- self.assertEqual(prop_to_list(arr[i][j]), rval)
-
-
- def test_assign_item_fail(self):
- def assign_wrong_size(arr, i, rval):
- getattr(test, arr)[i]= rval
-
- # assign wrong size at level 2
- for arr, func in zip(("fmarr", "imarr", "bmarr"), (rand_float, rand_int, rand_bool)):
- rval1= make_random_2d_array((3, 5), func)
- rval2= make_random_2d_array((4, 3), func)
-
- for i in range(3):
- self.assertRaises(ValueError, assign_wrong_size, arr, i, rval1)
- self.assertRaises(ValueError, assign_wrong_size, arr, i, rval2)
-
- def test_dynamic_assign_array(self):
- for arr, func in zip(("fdmarr", "idmarr", "bdmarr"), (rand_float, rand_int, rand_bool)):
- # assignment of [3][4][5]
- rval= make_random_3d_array((3, 4, 5), func)
- setattr(test, arr, rval)
- self.assertEqual(prop_to_list(getattr(test, arr)), rval)
-
- # [2][4][5]
- rval= make_random_3d_array((2, 4, 5), func)
- setattr(test, arr, rval)
- self.assertEqual(prop_to_list(getattr(test, arr)), rval)
-
- # [1][4][5]
- rval= make_random_3d_array((1, 4, 5), func)
- setattr(test, arr, rval)
- self.assertEqual(prop_to_list(getattr(test, arr)), rval)
-
-
- # test access
- def test_access(self):
- pass
-
- # test slice access, negative indices
- def test_access_fail(self):
- pass
-
-random.seed()
-
-def rand_int():
- return random.randint(-1000, 1000)
-
-def rand_float():
- return float(rand_int())
-
-def rand_bool():
- return bool(random.randint(0, 1))
-
-def make_random_array(len, rand_func):
- arr= []
- for i in range(len):
- arr.append(rand_func())
-
- return arr
-
-def make_random_2d_array(dimsize, rand_func):
- marr= []
- for i in range(dimsize[0]):
- marr.append([])
-
- for j in range(dimsize[1]):
- marr[-1].append(rand_func())
-
- return marr
-
-def make_random_3d_array(dimsize, rand_func):
- marr= []
- for i in range(dimsize[0]):
- marr.append([])
-
- for j in range(dimsize[1]):
- marr[-1].append([])
-
- for k in range(dimsize[2]):
- marr[-1][-1].append(rand_func())
-
- return marr
-
-def prop_to_list(prop):
- ret= []
-
- for x in prop:
- if type(x) not in (bool, int, float):
- ret.append(prop_to_list(x))
- else:
- ret.append(x)
-
- return ret
-
-def suite():
- return unittest.TestSuite([unittest.TestLoader().loadTestsFromTestCase(TestArray), unittest.TestLoader().loadTestsFromTestCase(TestMArray)])
-
-if __name__ == "__main__":
- unittest.TextTestRunner(verbosity=2).run(suite())
-
diff --git a/source/tests/rna_info_dump.py b/source/tests/rna_info_dump.py
deleted file mode 100644
index 62c1248d733..00000000000
--- a/source/tests/rna_info_dump.py
+++ /dev/null
@@ -1,131 +0,0 @@
-# ##### 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 #####
-
-# <pep8 compliant>
-
-# Used for generating API diff's between releases
-# ./blender.bin --background --python release/test/rna_info_dump.py
-
-import bpy
-
-
-def api_dump(use_properties=True, use_functions=True):
-
- def prop_type(prop):
- if prop.type == "pointer":
- return prop.fixed_type.identifier
- else:
- return prop.type
-
- def func_to_str(struct_id_str, func_id, func):
-
- args = []
- for prop in func.args:
- data_str = "%s %s" % (prop_type(prop), prop.identifier)
- if prop.array_length:
- data_str += "[%d]" % prop.array_length
- if not prop.is_required:
- data_str += "=%s" % prop.default_str
- args.append(data_str)
-
- data_str = "%s.%s(%s)" % (struct_id_str, func_id, ", ".join(args))
- if func.return_values:
- return_args = ", ".join(prop_type(arg) for arg in func.return_values)
- if len(func.return_values) > 1:
- data_str += " --> (%s)" % return_args
- else:
- data_str += " --> %s" % return_args
- return data_str
-
- def prop_to_str(struct_id_str, prop_id, prop):
-
- prop_str = " <-- %s" % prop_type(prop)
- if prop.array_length:
- prop_str += "[%d]" % prop.array_length
-
- data_str = "%s.%s %s" % (struct_id_str, prop_id, prop_str)
- return data_str
-
- def struct_full_id(v):
- struct_id_str = v.identifier # "".join(sid for sid in struct_id if struct_id)
-
- for base in v.get_bases():
- struct_id_str = base.identifier + "|" + struct_id_str
-
- return struct_id_str
-
- def dump_funcs():
- data = []
- for struct_id, v in sorted(struct.items()):
- struct_id_str = struct_full_id(v)
-
- funcs = [(func.identifier, func) for func in v.functions]
-
- for func_id, func in funcs:
- data.append(func_to_str(struct_id_str, func_id, func))
-
- for prop in v.properties:
- if prop.collection_type:
- funcs = [(prop.identifier + "." + func.identifier, func) for func in prop.collection_type.functions]
- for func_id, func in funcs:
- data.append(func_to_str(struct_id_str, func_id, func))
- data.sort()
- data.append("# * functions *")
- return data
-
- def dump_props():
- data = []
- for struct_id, v in sorted(struct.items()):
- struct_id_str = struct_full_id(v)
-
- props = [(prop.identifier, prop) for prop in v.properties]
-
- for prop_id, prop in props:
- data.append(prop_to_str(struct_id_str, prop_id, prop))
-
- for prop in v.properties:
- if prop.collection_type:
- props = [(prop.identifier + "." + prop_sub.identifier, prop_sub) for prop_sub in prop.collection_type.properties]
- for prop_sub_id, prop_sub in props:
- data.append(prop_to_str(struct_id_str, prop_sub_id, prop_sub))
- data.sort()
- data.insert(0, "# * properties *")
- return data
-
- import rna_info
- struct = rna_info.BuildRNAInfo()[0]
- data = []
-
- if use_functions:
- data.extend(dump_funcs())
-
- if use_properties:
- data.extend(dump_props())
-
- if bpy.app.background:
- import sys
- sys.stderr.write("\n".join(data))
- sys.stderr.write("\n\nEOF\n")
- else:
- text = bpy.data.texts.new(name="api.py")
- text.from_string(data)
-
- print("END")
-
-if __name__ == "__main__":
- api_dump()