Merged revision(s) 58059-58092 from trunk/blender into soc-2013-dingto.

This commit is contained in:
2013-07-09 00:58:25 +00:00
47 changed files with 1294 additions and 738 deletions

View File

@@ -25,6 +25,10 @@ elseif(CMAKE_COMPILER_IS_GNUCC)
set(CYCLES_SSE2_KERNEL_FLAGS "-ffast-math -msse -msse2 -mfpmath=sse")
set(CYCLES_SSE3_KERNEL_FLAGS "-ffast-math -msse -msse2 -msse3 -mssse3 -mfpmath=sse")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ffast-math")
elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
set(CYCLES_SSE2_KERNEL_FLAGS "-ffast-math -msse -msse2")
set(CYCLES_SSE3_KERNEL_FLAGS "-ffast-math -msse -msse2 -msse3 -mssse3")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ffast-math")
endif()
# for OSL

View File

@@ -462,6 +462,9 @@ Mesh *BlenderSync::sync_mesh(BL::Object b_ob, bool object_updated, bool hide_tri
mesh->name = ustring(b_ob_data.name().c_str());
if(render_layer.use_surfaces || render_layer.use_hair) {
if(preview)
b_ob.update_from_editmode();
BL::Mesh b_mesh = object_to_mesh(b_data, b_ob, b_scene, true, !preview, need_undeformed);
if(b_mesh) {

View File

@@ -223,7 +223,7 @@ bool RenderBuffers::get_pass_rect(PassType type, float exposure, int sample, int
float3 f = make_float3(in[0], in[1], in[2]);
float3 f_divide = make_float3(in_divide[0], in_divide[1], in_divide[2]);
f = safe_divide_color(f*exposure, f_divide);
f = safe_divide_even_color(f*exposure, f_divide);
pixels[0] = f.x;
pixels[1] = f.y;

View File

@@ -1100,6 +1100,42 @@ __device_inline float3 safe_divide_color(float3 a, float3 b)
return make_float3(x, y, z);
}
__device_inline float3 safe_divide_even_color(float3 a, float3 b)
{
float x, y, z;
x = (b.x != 0.0f)? a.x/b.x: 0.0f;
y = (b.y != 0.0f)? a.y/b.y: 0.0f;
z = (b.z != 0.0f)? a.z/b.z: 0.0f;
/* try to get grey even if b is zero */
if(b.x == 0.0f) {
if(b.y == 0.0f) {
x = z;
y = z;
}
else if(b.z == 0.0f) {
x = y;
z = y;
}
else
x = 0.5f*(y + z);
}
else if(b.y == 0.0f) {
if(b.z == 0.0f) {
y = x;
z = x;
}
else
y = 0.5f*(x + z);
}
else if(b.z == 0.0f) {
z = 0.5f*(x + y);
}
return make_float3(x, y, z);
}
/* Rotation of point around axis and angle */
__device_inline float3 rotate_around_axis(float3 p, float3 axis, float angle)

View File

@@ -32,7 +32,7 @@ from freestyle import BackboneStretcherShader, BezierCurveShader, BinaryPredicat
FalseBP1D, FalseUP1D, GuidingLinesShader, Interface0DIterator, Nature, Noise, Normal2DF0D, Operators, \
PolygonalizationShader, QuantitativeInvisibilityF1D, QuantitativeInvisibilityUP1D, SamplingShader, \
SpatialNoiseShader, StrokeAttribute, StrokeShader, TipRemoverShader, TrueBP1D, TrueUP1D, UnaryPredicate0D, \
UnaryPredicate1D, VertexOrientation2DF0D, WithinImageBoundaryUP1D
UnaryPredicate1D, VertexOrientation2DF0D, WithinImageBoundaryUP1D, ContextFunctions
from Functions0D import CurveMaterialF0D
from PredicatesU1D import pyNatureUP1D
from logical_operators import AndUP1D, NotUP1D, OrUP1D
@@ -1046,17 +1046,7 @@ def process(layer_name, lineset_name):
selection_criteria.append(upred)
# prepare selection criteria by image border
if lineset.select_by_image_border:
fac = scene.render.resolution_percentage / 100.0
w = scene.render.resolution_x * fac
h = scene.render.resolution_y * fac
if scene.render.use_border:
xmin = scene.render.border_min_x * w
xmax = scene.render.border_max_x * w
ymin = scene.render.border_min_y * h
ymax = scene.render.border_max_y * h
else:
xmin, xmax = 0.0, float(w)
ymin, ymax = 0.0, float(h)
xmin, ymin, xmax, ymax = ContextFunctions.get_border()
upred = WithinImageBoundaryUP1D(xmin, ymin, xmax, ymax)
selection_criteria.append(upred)
# select feature edges

View File

@@ -0,0 +1,384 @@
# ##### 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>
__all__ = (
"draw_entry",
"draw_km",
"draw_kmi",
"draw_filtered",
"draw_hierarchy",
"draw_keymaps",
)
import bpy
from bpy.app.translations import pgettext_iface as iface_
from bpy.app.translations import contexts as i18n_contexts
def _indented_layout(layout, level):
indentpx = 16
if level == 0:
level = 0.0001 # Tweak so that a percentage of 0 won't split by half
indent = level * indentpx / bpy.context.region.width
split = layout.split(percentage=indent)
col = split.column()
col = split.column()
return col
def draw_entry(display_keymaps, entry, col, level=0):
idname, spaceid, regionid, children = entry
for km, kc in display_keymaps:
if km.name == idname and km.space_type == spaceid and km.region_type == regionid:
draw_km(display_keymaps, kc, km, children, col, level)
'''
km = kc.keymaps.find(idname, space_type=spaceid, region_type=regionid)
if not km:
kc = defkc
km = kc.keymaps.find(idname, space_type=spaceid, region_type=regionid)
if km:
draw_km(kc, km, children, col, level)
'''
def draw_km(display_keymaps, kc, km, children, layout, level):
km = km.active()
layout.context_pointer_set("keymap", km)
col = _indented_layout(layout, level)
row = col.row()
row.prop(km, "show_expanded_children", text="", emboss=False)
row.label(text=km.name, text_ctxt=i18n_contexts.id_windowmanager)
row.label()
row.label()
if km.is_modal:
row.label(text="", icon='LINKED')
if km.is_user_modified:
row.operator("wm.keymap_restore", text="Restore")
else:
row.label()
if km.show_expanded_children:
if children:
# Put the Parent key map's entries in a 'global' sub-category
# equal in hierarchy to the other children categories
subcol = _indented_layout(col, level + 1)
subrow = subcol.row()
subrow.prop(km, "show_expanded_items", text="", emboss=False)
subrow.label(text=iface_("%s (Global)") % km.name, translate=False)
else:
km.show_expanded_items = True
# Key Map items
if km.show_expanded_items:
for kmi in km.keymap_items:
draw_kmi(display_keymaps, kc, km, kmi, col, level + 1)
# "Add New" at end of keymap item list
col = _indented_layout(col, level + 1)
subcol = col.split(percentage=0.2).column()
subcol.operator("wm.keyitem_add", text="Add New", text_ctxt=i18n_contexts.id_windowmanager,
icon='ZOOMIN')
col.separator()
# Child key maps
if children:
subcol = col.column()
row = subcol.row()
for entry in children:
draw_entry(display_keymaps, entry, col, level + 1)
def draw_kmi(display_keymaps, kc, km, kmi, layout, level):
map_type = kmi.map_type
col = _indented_layout(layout, level)
if kmi.show_expanded:
col = col.column(align=True)
box = col.box()
else:
box = col.column()
split = box.split(percentage=0.05)
# header bar
row = split.row()
row.prop(kmi, "show_expanded", text="", emboss=False)
row = split.row()
row.prop(kmi, "active", text="", emboss=False)
if km.is_modal:
row.prop(kmi, "propvalue", text="")
else:
row.label(text=kmi.name)
row = split.row()
row.prop(kmi, "map_type", text="")
if map_type == 'KEYBOARD':
row.prop(kmi, "type", text="", full_event=True)
elif map_type == 'MOUSE':
row.prop(kmi, "type", text="", full_event=True)
elif map_type == 'NDOF':
row.prop(kmi, "type", text="", full_event=True)
elif map_type == 'TWEAK':
subrow = row.row()
subrow.prop(kmi, "type", text="")
subrow.prop(kmi, "value", text="")
elif map_type == 'TIMER':
row.prop(kmi, "type", text="")
else:
row.label()
if (not kmi.is_user_defined) and kmi.is_user_modified:
row.operator("wm.keyitem_restore", text="", icon='BACK').item_id = kmi.id
else:
row.operator("wm.keyitem_remove", text="", icon='X').item_id = kmi.id
# Expanded, additional event settings
if kmi.show_expanded:
box = col.box()
split = box.split(percentage=0.4)
sub = split.row()
if km.is_modal:
sub.prop(kmi, "propvalue", text="")
else:
# One day...
#~ sub.prop_search(kmi, "idname", bpy.context.window_manager, "operators_all", text="")
sub.prop(kmi, "idname", text="")
if map_type not in {'TEXTINPUT', 'TIMER'}:
sub = split.column()
subrow = sub.row(align=True)
if map_type == 'KEYBOARD':
subrow.prop(kmi, "type", text="", event=True)
subrow.prop(kmi, "value", text="")
elif map_type in {'MOUSE', 'NDOF'}:
subrow.prop(kmi, "type", text="")
subrow.prop(kmi, "value", text="")
subrow = sub.row()
subrow.scale_x = 0.75
subrow.prop(kmi, "any")
subrow.prop(kmi, "shift")
subrow.prop(kmi, "ctrl")
subrow.prop(kmi, "alt")
subrow.prop(kmi, "oskey", text="Cmd")
subrow.prop(kmi, "key_modifier", text="", event=True)
# Operator properties
box.template_keymap_item_properties(kmi)
# Modal key maps attached to this operator
if not km.is_modal:
kmm = kc.keymaps.find_modal(kmi.idname)
if kmm:
draw_km(display_keymaps, kc, kmm, None, layout, level + 1)
layout.context_pointer_set("keymap", km)
_EVENT_TYPES = set()
_EVENT_TYPE_MAP = {}
def draw_filtered(display_keymaps, filter_type, filter_text, layout):
if filter_type == 'NAME':
def filter_func(kmi):
return (filter_text in kmi.idname.lower() or
filter_text in kmi.name.lower())
else:
if not _EVENT_TYPES:
enum = bpy.types.Event.bl_rna.properties["type"].enum_items
_EVENT_TYPES.update(enum.keys())
_EVENT_TYPE_MAP.update({item.name.replace(" ", "_").upper(): key
for key, item in enum.items()})
del enum
_EVENT_TYPE_MAP.update({
"`": 'ACCENT_GRAVE',
"*": 'NUMPAD_ASTERIX',
"/": 'NUMPAD_SLASH',
"RMB": 'RIGHTMOUSE',
"LMB": 'LEFTMOUSE',
"MMB": 'MIDDLEMOUSE',
})
_EVENT_TYPE_MAP.update({
"%d" % i: "NUMPAD_%d" % i for i in range(9)
})
# done with once off init
filter_text_split = filter_text.strip()
filter_text_split = filter_text.split()
# Modifier {kmi.attribute: name} mapping
key_mod = {
"ctrl": "ctrl",
"alt": "alt",
"shift": "shift",
"cmd": "oskey",
"oskey": "oskey",
"any": "any",
}
# KeyMapItem like dict, use for comparing against
# attr: state
kmi_test_dict = {}
# initialize? - so if a if a kmi has a MOD assigned it wont show up.
#~ for kv in key_mod.values():
#~ kmi_test_dict[kv] = False
# altname: attr
for kk, kv in key_mod.items():
if kk in filter_text_split:
filter_text_split.remove(kk)
kmi_test_dict[kv] = True
# whats left should be the event type
if len(filter_text_split) > 1:
return False
elif filter_text_split:
kmi_type = filter_text_split[0].upper()
if kmi_type not in _EVENT_TYPES:
# replacement table
kmi_type_test = _EVENT_TYPE_MAP.get(kmi_type)
if kmi_type_test is None:
# print("Unknown Type:", kmi_type)
# Partial match
for k, v in _EVENT_TYPE_MAP.items():
if kmi_type in k:
kmi_type_test = v
break
if kmi_type in v:
kmi_type_test = v
break
if kmi_type_test is None:
return False
kmi_type = kmi_type_test
del kmi_type_test
kmi_test_dict["type"] = kmi_type
# main filter func, runs many times
def filter_func(kmi):
for kk, ki in kmi_test_dict.items():
if getattr(kmi, kk) != ki:
return False
return True
for km, kc in display_keymaps:
km = km.active()
layout.context_pointer_set("keymap", km)
filtered_items = [kmi for kmi in km.keymap_items if filter_func(kmi)]
if filtered_items:
col = layout.column()
row = col.row()
row.label(text=km.name, icon='DOT')
row.label()
row.label()
if km.is_user_modified:
row.operator("wm.keymap_restore", text="Restore")
else:
row.label()
for kmi in filtered_items:
draw_kmi(display_keymaps, kc, km, kmi, col, 1)
# "Add New" at end of keymap item list
col = _indented_layout(layout, 1)
subcol = col.split(percentage=0.2).column()
subcol.operator("wm.keyitem_add", text="Add New", icon='ZOOMIN')
return True
def draw_hierarchy(display_keymaps, layout):
from bpy_extras import keyconfig_utils
for entry in keyconfig_utils.KM_HIERARCHY:
draw_entry(display_keymaps, entry, layout)
def draw_keymaps(context, layout):
from bpy_extras import keyconfig_utils
wm = context.window_manager
kc = wm.keyconfigs.user
spref = context.space_data
col = layout.column()
sub = col.column()
subsplit = sub.split()
subcol = subsplit.column()
row = subcol.row(align=True)
#~ row.prop_search(wm.keyconfigs, "active", wm, "keyconfigs", text="Key Config:")
text = bpy.path.display_name(wm.keyconfigs.active.name)
if not text:
text = "Blender (default)"
row.menu("USERPREF_MT_keyconfigs", text=text)
row.operator("wm.keyconfig_preset_add", text="", icon='ZOOMIN')
row.operator("wm.keyconfig_preset_add", text="", icon='ZOOMOUT').remove_active = True
#~ layout.context_pointer_set("keyconfig", wm.keyconfigs.active)
#~ row.operator("wm.keyconfig_remove", text="", icon='X')
row.separator()
rowsub = row.split(align=True, percentage=0.33)
# postpone drawing into rowsub, so we can set alert!
col.separator()
display_keymaps = keyconfig_utils.keyconfig_merge(kc, kc)
filter_type = spref.filter_type
filter_text = spref.filter_text.strip()
if filter_text:
filter_text = filter_text.lower()
ok = draw_filtered(display_keymaps, filter_type, filter_text, col)
else:
draw_hierarchy(display_keymaps, col)
ok = True
# go back and fill in rowsub
rowsub.prop(spref, "filter_type", text="")
rowsubsub = rowsub.row(align=True)
if not ok:
rowsubsub.alert = True
rowsubsub.prop(spref, "filter_text", text="", icon='VIEWZOOM')

View File

@@ -72,7 +72,6 @@ _modules = [
"space_sequencer",
"space_text",
"space_time",
"space_userpref_keymap",
"space_userpref",
"space_view3d",
"space_view3d_toolbar",

View File

@@ -917,9 +917,6 @@ class USERPREF_PT_file(Panel):
col.prop(system, "author", text="")
from bl_ui.space_userpref_keymap import InputKeyMapPanel
class USERPREF_MT_ndof_settings(Menu):
# accessed from the window key-bindings in C (only)
bl_label = "3D Mouse Settings"
@@ -960,9 +957,25 @@ class USERPREF_MT_ndof_settings(Menu):
layout.prop(input_prefs, "ndof_lock_horizon", icon='NDOF_DOM')
class USERPREF_PT_input(Panel, InputKeyMapPanel):
class USERPREF_MT_keyconfigs(Menu):
bl_label = "KeyPresets"
preset_subdir = "keyconfig"
preset_operator = "wm.keyconfig_activate"
def draw(self, context):
props = self.layout.operator("wm.context_set_value", text="Blender (default)")
props.data_path = "window_manager.keyconfigs.active"
props.value = "context.window_manager.keyconfigs.default"
# now draw the presets
Menu.draw_preset(self, context)
class USERPREF_PT_input(Panel):
bl_space_type = 'USER_PREFERENCES'
bl_label = "Input"
bl_region_type = 'WINDOW'
bl_options = {'HIDE_HEADER'}
@classmethod
def poll(cls, context):
@@ -1039,6 +1052,8 @@ class USERPREF_PT_input(Panel, InputKeyMapPanel):
row.separator()
def draw(self, context):
from rna_keymap_ui import draw_keymaps
layout = self.layout
#import time
@@ -1055,7 +1070,7 @@ class USERPREF_PT_input(Panel, InputKeyMapPanel):
self.draw_input_prefs(inputs, split)
# Keymap Settings
self.draw_keymaps(context, split)
draw_keymaps(context, split)
#print("runtime", time.time() - start)

View File

@@ -1,391 +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 bpy
from bpy.types import Menu
from bpy.app.translations import pgettext_iface as iface_
from bpy.app.translations import contexts as i18n_contexts
class USERPREF_MT_keyconfigs(Menu):
bl_label = "KeyPresets"
preset_subdir = "keyconfig"
preset_operator = "wm.keyconfig_activate"
def draw(self, context):
props = self.layout.operator("wm.context_set_value", text="Blender (default)")
props.data_path = "window_manager.keyconfigs.active"
props.value = "context.window_manager.keyconfigs.default"
# now draw the presets
Menu.draw_preset(self, context)
class InputKeyMapPanel:
bl_space_type = 'USER_PREFERENCES'
bl_label = "Input"
bl_region_type = 'WINDOW'
bl_options = {'HIDE_HEADER'}
def draw_entry(self, display_keymaps, entry, col, level=0):
idname, spaceid, regionid, children = entry
for km, kc in display_keymaps:
if km.name == idname and km.space_type == spaceid and km.region_type == regionid:
self.draw_km(display_keymaps, kc, km, children, col, level)
'''
km = kc.keymaps.find(idname, space_type=spaceid, region_type=regionid)
if not km:
kc = defkc
km = kc.keymaps.find(idname, space_type=spaceid, region_type=regionid)
if km:
self.draw_km(kc, km, children, col, level)
'''
def indented_layout(self, layout, level):
indentpx = 16
if level == 0:
level = 0.0001 # Tweak so that a percentage of 0 won't split by half
indent = level * indentpx / bpy.context.region.width
split = layout.split(percentage=indent)
col = split.column()
col = split.column()
return col
def draw_km(self, display_keymaps, kc, km, children, layout, level):
km = km.active()
layout.context_pointer_set("keymap", km)
col = self.indented_layout(layout, level)
row = col.row()
row.prop(km, "show_expanded_children", text="", emboss=False)
row.label(text=km.name, text_ctxt=i18n_contexts.id_windowmanager)
row.label()
row.label()
if km.is_modal:
row.label(text="", icon='LINKED')
if km.is_user_modified:
row.operator("wm.keymap_restore", text="Restore")
else:
row.label()
if km.show_expanded_children:
if children:
# Put the Parent key map's entries in a 'global' sub-category
# equal in hierarchy to the other children categories
subcol = self.indented_layout(col, level + 1)
subrow = subcol.row()
subrow.prop(km, "show_expanded_items", text="", emboss=False)
subrow.label(text=iface_("%s (Global)") % km.name, translate=False)
else:
km.show_expanded_items = True
# Key Map items
if km.show_expanded_items:
for kmi in km.keymap_items:
self.draw_kmi(display_keymaps, kc, km, kmi, col, level + 1)
# "Add New" at end of keymap item list
col = self.indented_layout(col, level + 1)
subcol = col.split(percentage=0.2).column()
subcol.operator("wm.keyitem_add", text="Add New", text_ctxt=i18n_contexts.id_windowmanager,
icon='ZOOMIN')
col.separator()
# Child key maps
if children:
subcol = col.column()
row = subcol.row()
for entry in children:
self.draw_entry(display_keymaps, entry, col, level + 1)
def draw_kmi(self, display_keymaps, kc, km, kmi, layout, level):
map_type = kmi.map_type
col = self.indented_layout(layout, level)
if kmi.show_expanded:
col = col.column(align=True)
box = col.box()
else:
box = col.column()
split = box.split(percentage=0.05)
# header bar
row = split.row()
row.prop(kmi, "show_expanded", text="", emboss=False)
row = split.row()
row.prop(kmi, "active", text="", emboss=False)
if km.is_modal:
row.prop(kmi, "propvalue", text="")
else:
row.label(text=kmi.name)
row = split.row()
row.prop(kmi, "map_type", text="")
if map_type == 'KEYBOARD':
row.prop(kmi, "type", text="", full_event=True)
elif map_type == 'MOUSE':
row.prop(kmi, "type", text="", full_event=True)
elif map_type == 'NDOF':
row.prop(kmi, "type", text="", full_event=True)
elif map_type == 'TWEAK':
subrow = row.row()
subrow.prop(kmi, "type", text="")
subrow.prop(kmi, "value", text="")
elif map_type == 'TIMER':
row.prop(kmi, "type", text="")
else:
row.label()
if (not kmi.is_user_defined) and kmi.is_user_modified:
row.operator("wm.keyitem_restore", text="", icon='BACK').item_id = kmi.id
else:
row.operator("wm.keyitem_remove", text="", icon='X').item_id = kmi.id
# Expanded, additional event settings
if kmi.show_expanded:
box = col.box()
split = box.split(percentage=0.4)
sub = split.row()
if km.is_modal:
sub.prop(kmi, "propvalue", text="")
else:
# One day...
#~ sub.prop_search(kmi, "idname", bpy.context.window_manager, "operators_all", text="")
sub.prop(kmi, "idname", text="")
if map_type not in {'TEXTINPUT', 'TIMER'}:
sub = split.column()
subrow = sub.row(align=True)
if map_type == 'KEYBOARD':
subrow.prop(kmi, "type", text="", event=True)
subrow.prop(kmi, "value", text="")
elif map_type in {'MOUSE', 'NDOF'}:
subrow.prop(kmi, "type", text="")
subrow.prop(kmi, "value", text="")
subrow = sub.row()
subrow.scale_x = 0.75
subrow.prop(kmi, "any")
subrow.prop(kmi, "shift")
subrow.prop(kmi, "ctrl")
subrow.prop(kmi, "alt")
subrow.prop(kmi, "oskey", text="Cmd")
subrow.prop(kmi, "key_modifier", text="", event=True)
# Operator properties
box.template_keymap_item_properties(kmi)
# Modal key maps attached to this operator
if not km.is_modal:
kmm = kc.keymaps.find_modal(kmi.idname)
if kmm:
self.draw_km(display_keymaps, kc, kmm, None, layout, level + 1)
layout.context_pointer_set("keymap", km)
_EVENT_TYPES = set()
_EVENT_TYPE_MAP = {}
def draw_filtered(self, display_keymaps, filter_type, filter_text, layout):
if filter_type == 'NAME':
def filter_func(kmi):
return (filter_text in kmi.idname.lower() or
filter_text in kmi.name.lower())
else:
if not self._EVENT_TYPES:
enum = bpy.types.Event.bl_rna.properties["type"].enum_items
self._EVENT_TYPES.update(enum.keys())
self._EVENT_TYPE_MAP.update({item.name.replace(" ", "_").upper(): key for key, item in enum.items()})
del enum
self._EVENT_TYPE_MAP.update({
"`": 'ACCENT_GRAVE',
"*": 'NUMPAD_ASTERIX',
"/": 'NUMPAD_SLASH',
"RMB": 'RIGHTMOUSE',
"LMB": 'LEFTMOUSE',
"MMB": 'MIDDLEMOUSE',
})
self._EVENT_TYPE_MAP.update({
"%d" % i: "NUMPAD_%d" % i for i in range(9)
})
# done with once off init
filter_text_split = filter_text.strip()
filter_text_split = filter_text.split()
# Modifier {kmi.attribute: name} mapping
key_mod = {
"ctrl": "ctrl",
"alt": "alt",
"shift": "shift",
"cmd": "oskey",
"oskey": "oskey",
"any": "any",
}
# KeyMapItem like dict, use for comparing against
# attr: state
kmi_test_dict = {}
# initialize? - so if a if a kmi has a MOD assigned it wont show up.
#~ for kv in key_mod.values():
#~ kmi_test_dict[kv] = False
# altname: attr
for kk, kv in key_mod.items():
if kk in filter_text_split:
filter_text_split.remove(kk)
kmi_test_dict[kv] = True
# whats left should be the event type
if len(filter_text_split) > 1:
return False
elif filter_text_split:
kmi_type = filter_text_split[0].upper()
if kmi_type not in self._EVENT_TYPES:
# replacement table
kmi_type_test = self._EVENT_TYPE_MAP.get(kmi_type)
if kmi_type_test is None:
# print("Unknown Type:", kmi_type)
# Partial match
for k, v in self._EVENT_TYPE_MAP.items():
if kmi_type in k:
kmi_type_test = v
break
if kmi_type in v:
kmi_type_test = v
break
if kmi_type_test is None:
return False
kmi_type = kmi_type_test
del kmi_type_test
kmi_test_dict["type"] = kmi_type
# main filter func, runs many times
def filter_func(kmi):
for kk, ki in kmi_test_dict.items():
if getattr(kmi, kk) != ki:
return False
return True
for km, kc in display_keymaps:
km = km.active()
layout.context_pointer_set("keymap", km)
filtered_items = [kmi for kmi in km.keymap_items if filter_func(kmi)]
if filtered_items:
col = layout.column()
row = col.row()
row.label(text=km.name, icon='DOT')
row.label()
row.label()
if km.is_user_modified:
row.operator("wm.keymap_restore", text="Restore")
else:
row.label()
for kmi in filtered_items:
self.draw_kmi(display_keymaps, kc, km, kmi, col, 1)
# "Add New" at end of keymap item list
col = self.indented_layout(layout, 1)
subcol = col.split(percentage=0.2).column()
subcol.operator("wm.keyitem_add", text="Add New", icon='ZOOMIN')
return True
def draw_hierarchy(self, display_keymaps, layout):
from bpy_extras import keyconfig_utils
for entry in keyconfig_utils.KM_HIERARCHY:
self.draw_entry(display_keymaps, entry, layout)
def draw_keymaps(self, context, layout):
from bpy_extras import keyconfig_utils
wm = context.window_manager
kc = wm.keyconfigs.user
spref = context.space_data
col = layout.column()
sub = col.column()
subsplit = sub.split()
subcol = subsplit.column()
row = subcol.row(align=True)
#~ row.prop_search(wm.keyconfigs, "active", wm, "keyconfigs", text="Key Config:")
text = bpy.path.display_name(wm.keyconfigs.active.name)
if not text:
text = "Blender (default)"
row.menu("USERPREF_MT_keyconfigs", text=text)
row.operator("wm.keyconfig_preset_add", text="", icon='ZOOMIN')
row.operator("wm.keyconfig_preset_add", text="", icon='ZOOMOUT').remove_active = True
#~ layout.context_pointer_set("keyconfig", wm.keyconfigs.active)
#~ row.operator("wm.keyconfig_remove", text="", icon='X')
row.separator()
rowsub = row.split(align=True, percentage=0.33)
# postpone drawing into rowsub, so we can set alert!
col.separator()
display_keymaps = keyconfig_utils.keyconfig_merge(kc, kc)
filter_type = spref.filter_type
filter_text = spref.filter_text.strip()
if filter_text:
filter_text = filter_text.lower()
ok = self.draw_filtered(display_keymaps, filter_type, filter_text, col)
else:
self.draw_hierarchy(display_keymaps, col)
ok = True
# go back and fill in rowsub
rowsub.prop(spref, "filter_type", text="")
rowsubsub = rowsub.row(align=True)
if not ok:
rowsubsub.alert = True
rowsubsub.prop(spref, "filter_text", text="", icon='VIEWZOOM')
if __name__ == "__main__": # only for live edit.
bpy.utils.register_module(__name__)

View File

@@ -617,8 +617,8 @@ class VIEW3D_MT_select_edit_mesh(Menu):
layout.separator()
layout.operator("mesh.select_less", text="Less")
layout.operator("mesh.select_more", text="More")
layout.operator("mesh.select_less", text="Less")
layout.separator()

View File

@@ -131,6 +131,18 @@ void BLI_rw_mutex_free(ThreadRWMutex *mutex);
void BLI_rw_mutex_lock(ThreadRWMutex *mutex, int mode);
void BLI_rw_mutex_unlock(ThreadRWMutex *mutex);
/* Ticket Mutex Lock
*
* This is a 'fair' mutex in that it will grant the lock to the first thread
* that requests it. */
typedef struct TicketMutex TicketMutex;
TicketMutex *BLI_ticket_mutex_alloc(void);
void BLI_ticket_mutex_free(TicketMutex *ticket);
void BLI_ticket_mutex_lock(TicketMutex *ticket);
void BLI_ticket_mutex_unlock(TicketMutex *ticket);
/* ThreadedWorker
*
* A simple tool for dispatching work to a limited number of threads

View File

@@ -508,6 +508,52 @@ void BLI_rw_mutex_free(ThreadRWMutex *mutex)
MEM_freeN(mutex);
}
/* Ticket Mutex Lock */
struct TicketMutex {
pthread_cond_t cond;
pthread_mutex_t mutex;
unsigned int queue_head, queue_tail;
};
TicketMutex *BLI_ticket_mutex_alloc(void)
{
TicketMutex *ticket = MEM_callocN(sizeof(TicketMutex), "TicketMutex");
pthread_cond_init(&ticket->cond, NULL);
pthread_mutex_init(&ticket->mutex, NULL);
return ticket;
}
void BLI_ticket_mutex_free(TicketMutex *ticket)
{
pthread_mutex_destroy(&ticket->mutex);
pthread_cond_destroy(&ticket->cond);
MEM_freeN(ticket);
}
void BLI_ticket_mutex_lock(TicketMutex *ticket)
{
unsigned int queue_me;
pthread_mutex_lock(&ticket->mutex);
queue_me = ticket->queue_tail++;
while (queue_me != ticket->queue_head)
pthread_cond_wait(&ticket->cond, &ticket->mutex);
pthread_mutex_unlock(&ticket->mutex);
}
void BLI_ticket_mutex_unlock(TicketMutex *ticket)
{
pthread_mutex_lock(&ticket->mutex);
ticket->queue_head++;
pthread_cond_broadcast(&ticket->cond);
pthread_mutex_unlock(&ticket->mutex);
}
/* ************************************************ */
typedef struct ThreadedWorker {

View File

@@ -5708,8 +5708,9 @@ static void lib_link_screen(FileData *fd, Main *main)
ntree = nodetree_from_id(snode->id);
if (ntree)
snode->nodetree = ntree;
else
snode->nodetree = newlibadr(fd, sc->id.lib, snode->nodetree);
else {
snode->nodetree = newlibadr_us(fd, sc->id.lib, snode->nodetree);
}
for (path = snode->treepath.first; path; path = path->next) {
if (path == snode->treepath.first) {
@@ -5717,7 +5718,7 @@ static void lib_link_screen(FileData *fd, Main *main)
path->nodetree = snode->nodetree;
}
else
path->nodetree = newlibadr(fd, sc->id.lib, path->nodetree);
path->nodetree = newlibadr_us(fd, sc->id.lib, path->nodetree);
if (!path->nodetree)
break;
@@ -6046,7 +6047,7 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc
path->nodetree = snode->nodetree;
}
else
path->nodetree= restore_pointer_by_name(newmain, (ID*)path->nodetree, 0);
path->nodetree= restore_pointer_by_name(newmain, (ID*)path->nodetree, 2);
if (!path->nodetree)
break;

View File

@@ -56,6 +56,7 @@ set(SRC
operators/bmo_join_triangles.c
operators/bmo_mesh_conv.c
operators/bmo_mirror.c
operators/bmo_normals.c
operators/bmo_poke.c
operators/bmo_primitive.c
operators/bmo_removedoubles.c

View File

@@ -150,7 +150,6 @@ static BMOpDefine bmo_recalc_face_normals_def = {
"recalc_face_normals",
/* slots_in */
{{"faces", BMO_OP_SLOT_ELEMENT_BUF, {BM_FACE}},
{"use_face_tag", BMO_OP_SLOT_BOOL}, /* Tag faces that have been flipped */
{{'\0'}},
},
{{{'\0'}}}, /* no output */

View File

@@ -1758,6 +1758,119 @@ float BM_mesh_calc_volume(BMesh *bm, bool is_signed)
return vol;
}
/**
* TODO (as we need)
* - option to walk over faces by verts.
* - option to walk over non manifold edges.
*
* \param bm the BMesh.
* \param r_groups_array Array of ints to fill in, length of bm->totface.
* \param r_group_index index, length pairs into \a r_groups_array, size of return value
* int pairs: (array_start, array_length).
* \return The number of groups found.
*/
int BM_mesh_calc_face_groups(BMesh *bm, int *r_groups_array, int (**r_group_index)[2],
void *user_data, bool (*filter_fn)(BMEdge *, void *user_data))
{
#ifdef DEBUG
int group_index_len = 1;
#else
int group_index_len = 32;
#endif
int (*group_index)[2] = MEM_mallocN(sizeof(*group_index) * group_index_len, __func__);
int *group_array = r_groups_array;
STACK_DECLARE(group_array);
int group_curr = 0;
const unsigned int tot_faces = bm->totface;
unsigned int tot_touch = 0;
BMFace **fstack;
STACK_DECLARE(fstack);
BMIter iter;
BMFace *f;
int i;
STACK_INIT(group_array);
/* init the array */
BM_ITER_MESH_INDEX (f, &iter, bm, BM_FACES_OF_MESH, i) {
BM_elem_index_set(f, i); /* set_inline */
BM_elem_flag_disable(f, BM_ELEM_TAG);
}
bm->elem_index_dirty &= ~BM_FACE;
/* detect groups */
fstack = MEM_mallocN(sizeof(*fstack) * tot_faces, __func__);
while (tot_touch != tot_faces) {
int *fg;
bool ok = false;
BLI_assert(tot_touch < tot_faces);
STACK_INIT(fstack);
BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
if (BM_elem_flag_test(f, BM_ELEM_TAG) == false) {
BM_elem_flag_enable(f, BM_ELEM_TAG);
STACK_PUSH(fstack, f);
ok = true;
break;
}
}
BLI_assert(ok == true);
/* manage arrays */
if (group_index_len == group_curr) {
group_index_len *= 2;
group_index = MEM_reallocN(group_index, sizeof(*group_index) * group_index_len);
}
fg = group_index[group_curr];
fg[0] = STACK_SIZE(group_array);
fg[1] = 0;
while ((f = STACK_POP(fstack))) {
BMLoop *l_iter, *l_first;
/* add face */
STACK_PUSH(group_array, BM_elem_index_get(f));
tot_touch++;
fg[1]++;
/* done */
/* search for other faces */
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
do {
BMLoop *l_other = l_iter->radial_next;
if ((l_other != l_iter) && filter_fn(l_iter->e, user_data)) {
if (BM_elem_flag_test(l_other->f, BM_ELEM_TAG) == false) {
BM_elem_flag_enable(l_other->f, BM_ELEM_TAG);
STACK_PUSH(fstack, l_other->f);
}
}
} while ((l_iter = l_iter->next) != l_first);
}
group_curr++;
}
MEM_freeN(fstack);
/* reduce alloc to required size */
group_index = MEM_reallocN(group_index, sizeof(*group_index) * group_curr);
*r_group_index = group_index;
return group_curr;
}
float bmesh_subd_falloff_calc(const int falloff, float val)
{
switch (falloff) {

View File

@@ -115,6 +115,8 @@ bool BM_face_is_any_vert_flag_test(BMFace *f, const char hflag);
bool BM_face_is_any_edge_flag_test(BMFace *f, const char hflag);
float BM_mesh_calc_volume(BMesh *bm, bool is_signed);
int BM_mesh_calc_face_groups(BMesh *bm, int *r_groups_array, int (**r_group_index)[2],
void *user_data, bool (*filter_fn)(BMEdge *, void *user_data));
/* not really any good place to put this */
float bmesh_subd_falloff_calc(const int falloff, float val);

View File

@@ -0,0 +1,186 @@
/*
* ***** 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): Joseph Eagar, Campbell Barton
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file blender/bmesh/operators/bmo_normals.c
* \ingroup bmesh
*
* normal recalculation.
*/
#include "MEM_guardedalloc.h"
#include "BLI_math.h"
#include "bmesh.h"
#include "intern/bmesh_operators_private.h" /* own include */
/********* righthand faces implementation ****** */
#define FACE_FLAG (1 << 0)
#define FACE_FLIP (1 << 1)
#define FACE_TEMP (1 << 2)
static bool bmo_recalc_normal_edge_filter_cb(BMEdge *e, void *UNUSED(user_data))
{
return BM_edge_is_manifold(e);
}
/**
* Given an array of faces, recalcualte their normals.
* this functions assumes all faces in the array are connected by edges.
*
* \param bm
* \param faces Array of connected faces.
* \param faces_len Length of \a faces
* \param oflag Flag to check before doing the actual face flipping.
*/
static void bmo_recalc_face_normals_array(BMesh *bm, BMFace **faces, const int faces_len, const short oflag)
{
float cent[3];
float (*faces_center)[3] = MEM_mallocN(sizeof(*faces_center) * faces_len, __func__);
const float cent_fac = 1.0f / (float)faces_len;
int i, f_start_index;
const short oflag_flip = oflag | FACE_FLIP;
float f_len_best;
BMFace *f;
BMFace **fstack = MEM_mallocN(sizeof(*fstack) * faces_len, __func__);
STACK_DECLARE(fstack);
zero_v3(cent);
/* first calculate the center */
for (i = 0; i < faces_len; i++) {
float *f_cent = faces_center[i];
BM_face_calc_center_mean_weighted(faces[i], f_cent);
madd_v3_v3fl(cent, f_cent, cent_fac);
BLI_assert(BMO_elem_flag_test(bm, faces[i], FACE_TEMP) == 0);
}
f_len_best = -FLT_MAX;
for (i = 0; i < faces_len; i++) {
float f_len_test;
if ((f_len_test = len_squared_v3v3(faces_center[i], cent)) > f_len_best) {
f_len_best = f_len_test;
f_start_index = i;
}
}
/* make sure the starting face has the correct winding */
if (dot_v3v3(faces_center[f_start_index], faces[f_start_index]->no) < 0.0f) {
BMO_elem_flag_enable(bm, faces[f_start_index], FACE_FLIP);
}
MEM_freeN(faces_center);
/* now that we've found our starting face, make all connected faces
* have the same winding. this is done recursively, using a manual
* stack (if we use simple function recursion, we'd end up overloading
* the stack on large meshes). */
STACK_INIT(fstack);
STACK_PUSH(fstack, faces[f_start_index]);
BMO_elem_flag_enable(bm, faces[f_start_index], FACE_TEMP);
while ((f = STACK_POP(fstack))) {
const bool flip_state = BMO_elem_flag_test_bool(bm, f, FACE_FLIP);
BMLoop *l_iter, *l_first;
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
do {
BMLoop *l_other = l_iter->radial_next;
if ((l_other != l_iter) && bmo_recalc_normal_edge_filter_cb(l_iter->e, NULL)) {
if (!BMO_elem_flag_test(bm, l_other->f, FACE_TEMP)) {
BMO_elem_flag_enable(bm, l_other->f, FACE_TEMP);
BMO_elem_flag_set(bm, l_other->f, FACE_FLIP, (l_other->v == l_iter->v) != flip_state);
STACK_PUSH(fstack, l_other->f);
}
}
} while ((l_iter = l_iter->next) != l_first);
}
MEM_freeN(fstack);
/* apply flipping to oflag'd faces */
for (i = 0; i < faces_len; i++) {
if (BMO_elem_flag_test(bm, faces[i], oflag_flip) == oflag_flip) {
BM_face_normal_flip(bm, faces[i]);
}
BMO_elem_flag_disable(bm, faces[i], FACE_TEMP);
}
}
/*
* put normal to the outside, and set the first direction flags in edges
*
* then check the object, and set directions / direction-flags: but only for edges with 1 or 2 faces
* this is in fact the 'select connected'
*
* in case all faces were not done: start over with 'find the ultimate ...' */
void bmo_recalc_face_normals_exec(BMesh *bm, BMOperator *op)
{
int *groups_array = MEM_mallocN(sizeof(groups_array) * bm->totface, __func__);
int faces_len;
BMFace **faces_arr = BM_iter_as_arrayN(bm, BM_FACES_OF_MESH, NULL, &faces_len, NULL, 0);
BMFace **faces_grp = MEM_mallocN(sizeof(faces_grp) * bm->totface, __func__);
int (*group_index)[2];
const int group_tot = BM_mesh_calc_face_groups(bm, groups_array, &group_index,
NULL, bmo_recalc_normal_edge_filter_cb);
int i;
BMO_slot_buffer_flag_enable(bm, op->slots_in, "faces", BM_FACE, FACE_FLAG);
for (i = 0; i < group_tot; i++) {
const int fg_sta = group_index[i][0];
const int fg_len = group_index[i][1];
int j;
bool is_calc = false;
for (j = 0; j < fg_len; j++) {
faces_grp[j] = faces_arr[groups_array[fg_sta + j]];
if (is_calc == false) {
is_calc = BMO_elem_flag_test_bool(bm, faces_grp[j], FACE_FLAG);
}
}
if (is_calc) {
bmo_recalc_face_normals_array(bm, faces_grp, fg_len, FACE_FLAG);
}
}
if (faces_arr) MEM_freeN(faces_arr);
MEM_freeN(faces_grp);
MEM_freeN(groups_array);
MEM_freeN(group_index);
}

View File

@@ -278,131 +278,6 @@ void bmo_region_extend_exec(BMesh *bm, BMOperator *op)
BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "geom.out", BM_ALL_NOLOOP, SEL_FLAG);
}
/********* righthand faces implementation ****** */
#define FACE_VIS 1
#define FACE_FLAG 2
// #define FACE_MARK 4 /* UNUSED */
#define FACE_FLIP 8
/* NOTE: these are the original recalc_face_normals comment in editmesh_mods.c,
* copied here for reference. */
/* based at a select-connected to witness loose objects */
/* count per edge the amount of faces
* find the ultimate left, front, upper face (not manhattan dist!!)
* also evaluate both triangle cases in quad, since these can be non-flat
*
* put normal to the outside, and set the first direction flags in edges
*
* then check the object, and set directions / direction-flags: but only for edges with 1 or 2 faces
* this is in fact the 'select connected'
*
* in case (selected) faces were not done: start over with 'find the ultimate ...' */
/* NOTE: this function uses recursion, which is a little unusual for a bmop
* function, but acceptable I think. */
/* NOTE: BM_ELEM_TAG is used on faces to tell if they are flipped. */
void bmo_recalc_face_normals_exec(BMesh *bm, BMOperator *op)
{
BMIter liter, liter2;
BMOIter siter;
BMFace *f, *startf;
BMFace **fstack;
STACK_DECLARE(fstack);
BMLoop *l, *l2;
float maxx, maxx_test, cent[3];
const bool use_flip = BMO_slot_bool_get(op->slots_in, "use_face_tag");
startf = NULL;
maxx = -1.0e10;
BMO_slot_buffer_flag_enable(bm, op->slots_in, "faces", BM_FACE, FACE_FLAG);
/* find a starting face */
BMO_ITER (f, &siter, op->slots_in, "faces", BM_FACE) {
/* clear dirty flag */
BM_elem_flag_disable(f, BM_ELEM_TAG);
if (BMO_elem_flag_test(bm, f, FACE_VIS))
continue;
if (!startf) startf = f;
BM_face_calc_center_bounds(f, cent);
if ((maxx_test = dot_v3v3(cent, cent)) > maxx) {
maxx = maxx_test;
startf = f;
}
}
if (!startf) return;
BM_face_calc_center_bounds(startf, cent);
/* make sure the starting face has the correct winding */
if (dot_v3v3(cent, startf->no) < 0.0f) {
BM_face_normal_flip(bm, startf);
BMO_elem_flag_toggle(bm, startf, FACE_FLIP);
if (use_flip)
BM_elem_flag_toggle(startf, BM_ELEM_TAG);
}
/* now that we've found our starting face, make all connected faces
* have the same winding. this is done recursively, using a manual
* stack (if we use simple function recursion, we'd end up overloading
* the stack on large meshes). */
fstack = MEM_mallocN(sizeof(*fstack) * BMO_slot_buffer_count(op->slots_in, "faces"), __func__);
STACK_INIT(fstack);
STACK_PUSH(fstack, startf);
BMO_elem_flag_enable(bm, startf, FACE_VIS);
while ((f = STACK_POP(fstack))) {
BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
BM_ITER_ELEM (l2, &liter2, l, BM_LOOPS_OF_LOOP) {
if (!BMO_elem_flag_test(bm, l2->f, FACE_FLAG) || l2 == l)
continue;
if (!BMO_elem_flag_test(bm, l2->f, FACE_VIS)) {
BMO_elem_flag_enable(bm, l2->f, FACE_VIS);
if (l2->v == l->v) {
BM_face_normal_flip(bm, l2->f);
BMO_elem_flag_toggle(bm, l2->f, FACE_FLIP);
if (use_flip)
BM_elem_flag_toggle(l2->f, BM_ELEM_TAG);
}
else if (BM_elem_flag_test(l2->f, BM_ELEM_TAG) || BM_elem_flag_test(l->f, BM_ELEM_TAG)) {
if (use_flip) {
BM_elem_flag_disable(l->f, BM_ELEM_TAG);
BM_elem_flag_disable(l2->f, BM_ELEM_TAG);
}
}
STACK_PUSH(fstack, l2->f);
}
}
}
}
MEM_freeN(fstack);
/* check if we have faces yet to do. if so, recurse */
BMO_ITER (f, &siter, op->slots_in, "faces", BM_FACE) {
if (!BMO_elem_flag_test(bm, f, FACE_VIS)) {
bmo_recalc_face_normals_exec(bm, op);
break;
}
}
}
void bmo_smooth_vert_exec(BMesh *UNUSED(bm), BMOperator *op)
{
BMOIter siter;

View File

@@ -2223,6 +2223,7 @@ static void bevel_build_edge_polygons(BMesh *bm, BevelParams *bp, BMEdge *bme)
BMVert *bmv1, *bmv2, *bmv3, *bmv4, *bmv1i, *bmv2i, *bmv3i, *bmv4i;
VMesh *vm1, *vm2;
EdgeHalf *e1, *e2;
BMEdge *bme1, *bme2;
BMFace *f1, *f2, *f;
int k, nseg, i1, i2, odd, mid;
@@ -2294,6 +2295,13 @@ static void bevel_build_edge_polygons(BMesh *bm, BevelParams *bp, BMEdge *bme)
bev_merge_end_uvs(bm, bv1, e1);
if (!e2->is_seam && bv2->vmesh->mesh_kind == M_NONE)
bev_merge_end_uvs(bm, bv2, e2);
/* Copy edge data to first and last edge */
bme1 = BM_edge_exists(bmv1, bmv2);
bme2 = BM_edge_exists(bmv3, bmv4);
BLI_assert(bme1 && bme2);
BM_elem_attrs_copy(bm, bm, bme, bme1);
BM_elem_attrs_copy(bm, bm, bme, bme2);
}
/*

View File

@@ -2833,6 +2833,44 @@ void CURVE_OT_reveal(wmOperatorType *ot)
/********************** subdivide operator *********************/
static BezTriple *next_spline_bezier_point_get(Nurb *nu, BezTriple *bezt)
{
BezTriple *nextbezt;
if (bezt == nu->bezt + nu->pntsu - 1) {
if (nu->flagu & CU_NURB_CYCLIC) {
nextbezt = nu->bezt;
}
else {
nextbezt = NULL;
}
}
else {
nextbezt = bezt + 1;
}
return nextbezt;
}
static BPoint *next_spline_bpoint_get(Nurb *nu, BPoint *bp)
{
BPoint *nextbp;
if (bp == nu->bp + nu->pntsu - 1) {
if (nu->flagu & CU_NURB_CYCLIC) {
nextbp = nu->bp;
}
else {
nextbp = NULL;
}
}
else {
nextbp = bp + 1;
}
return nextbp;
}
/** Divide the line segments associated with the currently selected
* curve nodes (Bezier or NURB). If there are no valid segment
* selections within the current selection, nothing happens.
@@ -2842,7 +2880,7 @@ static void subdividenurb(Object *obedit, int number_cuts)
Curve *cu = obedit->data;
EditNurb *editnurb = cu->editnurb;
Nurb *nu;
BezTriple *prevbezt, *bezt, *beztnew, *beztn;
BezTriple *bezt, *beztnew, *beztn;
BPoint *bp, *prevbp, *bpnew, *bpn;
float vec[15];
int a, b, sel, amount, *usel, *vsel, i;
@@ -2853,25 +2891,25 @@ static void subdividenurb(Object *obedit, int number_cuts)
for (nu = editnurb->nurbs.first; nu; nu = nu->next) {
amount = 0;
if (nu->type == CU_BEZIER) {
BezTriple *nextbezt;
/*
* Insert a point into a 2D Bezier curve.
* Endpoints are preserved. Otherwise, all selected and inserted points are
* newly created. Old points are discarded.
*/
/* count */
if (nu->flagu & CU_NURB_CYCLIC) {
a = nu->pntsu;
bezt = nu->bezt;
prevbezt = bezt + (a - 1);
}
else {
a = nu->pntsu - 1;
prevbezt = nu->bezt;
bezt = prevbezt + 1;
}
a = nu->pntsu;
bezt = nu->bezt;
while (a--) {
if (BEZSELECTED_HIDDENHANDLES(cu, prevbezt) && BEZSELECTED_HIDDENHANDLES(cu, bezt) ) amount += number_cuts;
prevbezt = bezt;
nextbezt = next_spline_bezier_point_get(nu, bezt);
if (nextbezt == NULL) {
break;
}
if (BEZSELECTED_HIDDENHANDLES(cu, bezt) && BEZSELECTED_HIDDENHANDLES(cu, nextbezt)) {
amount += number_cuts;
}
bezt++;
}
@@ -2879,35 +2917,32 @@ static void subdividenurb(Object *obedit, int number_cuts)
/* insert */
beztnew = (BezTriple *)MEM_mallocN((amount + nu->pntsu) * sizeof(BezTriple), "subdivNurb");
beztn = beztnew;
if (nu->flagu & CU_NURB_CYCLIC) {
a = nu->pntsu;
bezt = nu->bezt;
prevbezt = bezt + (a - 1);
}
else {
a = nu->pntsu - 1;
prevbezt = nu->bezt;
bezt = prevbezt + 1;
}
a = nu->pntsu;
bezt = nu->bezt;
while (a--) {
memcpy(beztn, prevbezt, sizeof(BezTriple));
keyIndex_updateBezt(editnurb, prevbezt, beztn, 1);
memcpy(beztn, bezt, sizeof(BezTriple));
keyIndex_updateBezt(editnurb, bezt, beztn, 1);
beztn++;
if (BEZSELECTED_HIDDENHANDLES(cu, prevbezt) && BEZSELECTED_HIDDENHANDLES(cu, bezt)) {
nextbezt = next_spline_bezier_point_get(nu, bezt);
if (nextbezt == NULL) {
break;
}
if (BEZSELECTED_HIDDENHANDLES(cu, bezt) && BEZSELECTED_HIDDENHANDLES(cu, nextbezt)) {
float prevvec[3][3];
memcpy(prevvec, prevbezt->vec, sizeof(float) * 9);
memcpy(prevvec, bezt->vec, sizeof(float) * 9);
for (i = 0; i < number_cuts; i++) {
factor = 1.0f / (number_cuts + 1 - i);
memcpy(beztn, bezt, sizeof(BezTriple));
memcpy(beztn, nextbezt, sizeof(BezTriple));
/* midpoint subdividing */
interp_v3_v3v3(vec, prevvec[1], prevvec[2], factor);
interp_v3_v3v3(vec + 3, prevvec[2], bezt->vec[0], factor);
interp_v3_v3v3(vec + 6, bezt->vec[0], bezt->vec[1], factor);
interp_v3_v3v3(vec + 3, prevvec[2], nextbezt->vec[0], factor);
interp_v3_v3v3(vec + 6, nextbezt->vec[0], nextbezt->vec[1], factor);
interp_v3_v3v3(vec + 9, vec, vec + 3, factor);
interp_v3_v3v3(vec + 12, vec + 3, vec + 6, factor);
@@ -2920,24 +2955,18 @@ static void subdividenurb(Object *obedit, int number_cuts)
copy_v3_v3(beztn->vec[2], vec + 12);
/* handle of next bezt */
if (a == 0 && i == number_cuts - 1 && (nu->flagu & CU_NURB_CYCLIC)) { copy_v3_v3(beztnew->vec[0], vec + 6); }
else { copy_v3_v3(bezt->vec[0], vec + 6); }
else { copy_v3_v3(nextbezt->vec[0], vec + 6); }
beztn->radius = (prevbezt->radius + bezt->radius) / 2;
beztn->weight = (prevbezt->weight + bezt->weight) / 2;
beztn->radius = (bezt->radius + nextbezt->radius) / 2;
beztn->weight = (bezt->weight + nextbezt->weight) / 2;
memcpy(prevvec, beztn->vec, sizeof(float) * 9);
beztn++;
}
}
prevbezt = bezt;
bezt++;
}
/* last point */
if ((nu->flagu & CU_NURB_CYCLIC) == 0) {
memcpy(beztn, prevbezt, sizeof(BezTriple));
keyIndex_updateBezt(editnurb, prevbezt, beztn, 1);
}
MEM_freeN(nu->bezt);
nu->bezt = beztnew;
@@ -2947,6 +2976,8 @@ static void subdividenurb(Object *obedit, int number_cuts)
}
} /* End of 'if (nu->type == CU_BEZIER)' */
else if (nu->pntsv == 1) {
BPoint *nextbp;
/*
* All flat lines (ie. co-planar), except flat Nurbs. Flat NURB curves
* are handled together with the regular NURB plane division, as it
@@ -2954,19 +2985,17 @@ static void subdividenurb(Object *obedit, int number_cuts)
* stable... nzc 30-5-'00
*/
/* count */
if (nu->flagu & CU_NURB_CYCLIC) {
a = nu->pntsu;
bp = nu->bp;
prevbp = bp + (a - 1);
}
else {
a = nu->pntsu - 1;
prevbp = nu->bp;
bp = prevbp + 1;
}
a = nu->pntsu;
bp = nu->bp;
while (a--) {
if ( (bp->f1 & SELECT) && (prevbp->f1 & SELECT) ) amount += number_cuts;
prevbp = bp;
nextbp = next_spline_bpoint_get(nu, bp);
if (nextbp == NULL) {
break;
}
if ((bp->f1 & SELECT) && (nextbp->f1 & SELECT)) {
amount += number_cuts;
}
bp++;
}
@@ -2975,39 +3004,33 @@ static void subdividenurb(Object *obedit, int number_cuts)
bpnew = (BPoint *)MEM_mallocN((amount + nu->pntsu) * sizeof(BPoint), "subdivNurb2");
bpn = bpnew;
if (nu->flagu & CU_NURB_CYCLIC) {
a = nu->pntsu;
bp = nu->bp;
prevbp = bp + (a - 1);
}
else {
a = nu->pntsu - 1;
prevbp = nu->bp;
bp = prevbp + 1;
}
a = nu->pntsu;
bp = nu->bp;
while (a--) {
memcpy(bpn, prevbp, sizeof(BPoint));
keyIndex_updateBP(editnurb, prevbp, bpn, 1);
/* Copy "old" point. */
memcpy(bpn, bp, sizeof(BPoint));
keyIndex_updateBP(editnurb, bp, bpn, 1);
bpn++;
if ((bp->f1 & SELECT) && (prevbp->f1 & SELECT)) {
nextbp = next_spline_bpoint_get(nu, bp);
if (nextbp == NULL) {
break;
}
if ((bp->f1 & SELECT) && (nextbp->f1 & SELECT)) {
// printf("*** subdivideNurb: insert 'linear' point\n");
for (i = 0; i < number_cuts; i++) {
factor = (float)(i + 1) / (number_cuts + 1);
memcpy(bpn, bp, sizeof(BPoint));
interp_v4_v4v4(bpn->vec, prevbp->vec, bp->vec, factor);
memcpy(bpn, nextbp, sizeof(BPoint));
interp_v4_v4v4(bpn->vec, bp->vec, nextbp->vec, factor);
bpn++;
}
}
prevbp = bp;
bp++;
}
if ((nu->flagu & CU_NURB_CYCLIC) == 0) { /* last point */
memcpy(bpn, prevbp, sizeof(BPoint));
keyIndex_updateBP(editnurb, prevbp, bpn, 1);
}
MEM_freeN(nu->bp);
nu->bp = bpnew;

View File

@@ -52,6 +52,8 @@ void ED_render_engine_changed(struct Main *bmain);
void ED_render_engine_area_exit(struct ScrArea *sa);
void ED_render_scene_update(struct Main *bmain, struct Scene *scene, int updated);
void ED_viewport_render_kill_jobs(const struct bContext *C);
/* render_preview.c */
/* stores rendered preview - is also used for icons */

View File

@@ -3018,16 +3018,16 @@ static void template_keymap_item_properties(uiLayout *layout, const char *title,
/* recurse for nested properties */
if (RNA_property_type(prop) == PROP_POINTER) {
PointerRNA propptr = RNA_property_pointer_get(ptr, prop);
const char *name = RNA_property_ui_name(prop);
if (propptr.data && RNA_struct_is_a(propptr.type, &RNA_OperatorProperties)) {
const char *name = RNA_property_ui_name(prop);
template_keymap_item_properties(layout, name, &propptr);
continue;
}
}
/* add property */
uiItemR(flow, ptr, RNA_property_identifier(prop), 0, NULL, ICON_NONE);
uiItemFullR(flow, ptr, prop, -1, 0, 0, NULL, ICON_NONE);
}
RNA_STRUCT_END;
}

View File

@@ -1066,7 +1066,7 @@ static int edbm_normals_make_consistent_exec(bContext *C, wmOperator *op)
/* doflip has to do with bmesh_rationalize_normals, it's an internal
* thing */
if (!EDBM_op_callf(em, op, "recalc_face_normals faces=%hf use_face_tag=%b", BM_ELEM_SELECT, true))
if (!EDBM_op_callf(em, op, "recalc_face_normals faces=%hf", BM_ELEM_SELECT))
return OPERATOR_CANCELLED;
if (RNA_boolean_get(op->ptr, "inside"))

View File

@@ -83,7 +83,7 @@ void TEXTURE_OT_envmap_clear_all(struct wmOperatorType *ot);
/* render_internal.c */
void RENDER_OT_render(struct wmOperatorType *ot);
void render_view3d(struct RenderEngine *engine, const struct bContext *C);
void render_view3d_update(struct RenderEngine *engine, const struct bContext *C);
void render_view3d_draw(struct RenderEngine *engine, const struct bContext *C);
/* render_opengl.c uses this */

View File

@@ -728,11 +728,13 @@ void RENDER_OT_render(wmOperatorType *ot)
#define PR_UPDATE_VIEW 1
#define PR_UPDATE_RENDERSIZE 2
#define PR_UPDATE_MATERIAL 4
#define PR_UPDATE_DATABASE 8
typedef struct RenderPreview {
/* from wmJob */
void *owner;
short *stop, *do_update;
wmJob *job;
Scene *scene;
ScrArea *sa;
@@ -743,8 +745,6 @@ typedef struct RenderPreview {
RenderEngine *engine;
float viewmat[4][4];
int keep_data;
} RenderPreview;
static int render_view3d_disprect(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D *rv3d, rcti *disprect)
@@ -845,7 +845,13 @@ static void render_view3d_startjob(void *customdata, short *stop, short *do_upda
float clipsta, clipend, pixsize;
bool orth, restore = 0;
char name[32];
int update_flag;
update_flag = rp->engine->job_update_flag;
rp->engine->job_update_flag = 0;
//printf("ma %d res %d view %d db %d\n", update_flag & PR_UPDATE_MATERIAL, update_flag & PR_UPDATE_RENDERSIZE, update_flag & PR_UPDATE_VIEW, update_flag & PR_UPDATE_DATABASE);
G.is_break = FALSE;
if (false == render_view3d_get_rects(rp->ar, rp->v3d, rp->rv3d, &viewplane, rp->engine, &clipsta, &clipend, &pixsize, &orth))
@@ -860,13 +866,6 @@ static void render_view3d_startjob(void *customdata, short *stop, short *do_upda
sprintf(name, "View3dPreview %p", (void *)rp->ar);
re = rp->engine->re = RE_GetRender(name);
if (rp->engine->re == NULL) {
re = rp->engine->re = RE_NewRender(name);
rp->keep_data = 0;
}
/* set this always, rp is different for each job */
RE_test_break_cb(re, rp, render_view3d_break);
RE_display_draw_cb(re, rp, render_view3d_draw_update);
@@ -874,7 +873,7 @@ static void render_view3d_startjob(void *customdata, short *stop, short *do_upda
rstats = RE_GetStats(re);
if (rp->keep_data == 0 || rstats->convertdone == 0 || (rp->keep_data & PR_UPDATE_RENDERSIZE)) {
if ((update_flag & (PR_UPDATE_RENDERSIZE|PR_UPDATE_DATABASE)) || rstats->convertdone == 0) {
/* no osa, blur, seq, layers, etc for preview render */
rdata = rp->scene->r;
rdata.mode &= ~(R_OSA | R_MBLUR | R_BORDER | R_PANORAMA);
@@ -900,11 +899,7 @@ static void render_view3d_startjob(void *customdata, short *stop, short *do_upda
RE_SetPixelSize(re, pixsize);
/* database free can crash on a empty Render... */
if (rp->keep_data == 0 && rstats->convertdone)
RE_Database_Free(re);
if (rstats->convertdone == 0) {
if ((update_flag & PR_UPDATE_DATABASE) || rstats->convertdone == 0) {
unsigned int lay = rp->scene->lay;
/* allow localview render for objects with lights in normal layers */
@@ -913,8 +908,20 @@ static void render_view3d_startjob(void *customdata, short *stop, short *do_upda
else lay = rp->v3d->lay;
RE_SetView(re, rp->viewmat);
/* copying blender data while main thread is locked, to avoid crashes */
WM_job_main_thread_lock_acquire(rp->job);
RE_Database_Free(re);
RE_Database_FromScene(re, rp->bmain, rp->scene, lay, 0); // 0= dont use camera view
WM_job_main_thread_lock_release(rp->job);
/* do preprocessing like building raytree, shadows, volumes, SSS */
RE_Database_Preprocess(re);
/* conversion not completed, need to do it again */
if (!rstats->convertdone)
rp->engine->job_update_flag |= PR_UPDATE_DATABASE;
// printf("dbase update\n");
}
else {
@@ -932,8 +939,6 @@ static void render_view3d_startjob(void *customdata, short *stop, short *do_upda
/* always rotate back */
if (restore)
RE_DataBase_IncrementalView(re, rp->viewmat, 1);
rp->engine->flag &= ~RE_ENGINE_DO_UPDATE;
}
}
@@ -944,21 +949,99 @@ static void render_view3d_free(void *customdata)
MEM_freeN(rp);
}
static void render_view3d_do(RenderEngine *engine, const bContext *C, int keep_data)
static bool render_view3d_flag_changed(RenderEngine *engine, const bContext *C)
{
RegionView3D *rv3d = CTX_wm_region_view3d(C);
View3D *v3d = CTX_wm_view3d(C);
ARegion *ar = CTX_wm_region(C);
Scene *scene = CTX_data_scene(C);
Render *re;
rctf viewplane;
rcti disprect;
float clipsta, clipend;
bool orth;
int job_update_flag = 0;
char name[32];
/* ensure render engine exists */
re = engine->re;
if (!re) {
sprintf(name, "View3dPreview %p", (void *)ar);
re = engine->re = RE_GetRender(name);
if (!re)
re = engine->re = RE_NewRender(name);
engine->update_flag |= RE_ENGINE_UPDATE_DATABASE;
}
/* check update_flag */
if (engine->update_flag & RE_ENGINE_UPDATE_MA)
job_update_flag |= PR_UPDATE_MATERIAL;
if (engine->update_flag & RE_ENGINE_UPDATE_OTHER)
job_update_flag |= PR_UPDATE_MATERIAL;
if (engine->update_flag & RE_ENGINE_UPDATE_DATABASE) {
job_update_flag |= PR_UPDATE_DATABASE;
/* load editmesh */
if (scene->obedit)
ED_object_editmode_load(scene->obedit);
}
engine->update_flag = 0;
/* check if viewport changed */
if (engine->last_winx != ar->winx || engine->last_winy != ar->winy) {
engine->last_winx = ar->winx;
engine->last_winy = ar->winy;
job_update_flag |= PR_UPDATE_RENDERSIZE;
}
if (compare_m4m4(engine->last_viewmat, rv3d->viewmat, 0.00001f) == 0) {
copy_m4_m4(engine->last_viewmat, rv3d->viewmat);
job_update_flag |= PR_UPDATE_VIEW;
}
render_view3d_get_rects(ar, v3d, rv3d, &viewplane, engine, &clipsta, &clipend, NULL, &orth);
if (BLI_rctf_compare(&viewplane, &engine->last_viewplane, 0.00001f) == 0) {
engine->last_viewplane = viewplane;
job_update_flag |= PR_UPDATE_VIEW;
}
render_view3d_disprect(scene, ar, v3d, rv3d, &disprect);
if (BLI_rcti_compare(&disprect, &engine->last_disprect) == 0) {
engine->last_disprect = disprect;
job_update_flag |= PR_UPDATE_RENDERSIZE;
}
/* any changes? go ahead and rerender */
if (job_update_flag) {
engine->job_update_flag |= job_update_flag;
return true;
}
return false;
}
static void render_view3d_do(RenderEngine *engine, const bContext *C)
{
wmJob *wm_job;
RenderPreview *rp;
Scene *scene = CTX_data_scene(C);
if (CTX_wm_window(C) == NULL) {
engine->flag |= RE_ENGINE_DO_UPDATE;
if (CTX_wm_window(C) == NULL)
return;
if (!render_view3d_flag_changed(engine, C))
return;
}
wm_job = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), CTX_wm_region(C), "Render Preview",
WM_JOB_EXCL_RENDER, WM_JOB_TYPE_RENDER_PREVIEW);
rp = MEM_callocN(sizeof(RenderPreview), "render preview");
rp->job = wm_job;
/* customdata for preview thread */
rp->scene = scene;
rp->engine = engine;
@@ -967,7 +1050,6 @@ static void render_view3d_do(RenderEngine *engine, const bContext *C, int keep_d
rp->v3d = rp->sa->spacedata.first;
rp->rv3d = CTX_wm_region_view3d(C);
rp->bmain = CTX_data_main(C);
rp->keep_data = keep_data;
copy_m4_m4(rp->viewmat, rp->rv3d->viewmat);
/* dont alloc in threads */
@@ -982,80 +1064,33 @@ static void render_view3d_do(RenderEngine *engine, const bContext *C, int keep_d
WM_jobs_start(CTX_wm_manager(C), wm_job);
engine->flag &= ~RE_ENGINE_DO_UPDATE;
}
/* callback for render engine , on changes */
void render_view3d(RenderEngine *engine, const bContext *C)
void render_view3d_update(RenderEngine *engine, const bContext *C)
{
render_view3d_do(engine, C, 0);
}
/* this shouldn't be needed and causes too many database rebuilds, but we
* aren't actually tracking updates for all relevent datablocks so this is
* a catch-all for updates */
engine->update_flag |= RE_ENGINE_UPDATE_DATABASE;
static int render_view3d_changed(RenderEngine *engine, const bContext *C)
{
ARegion *ar = CTX_wm_region(C);
Render *re;
int update = 0;
char name[32];
sprintf(name, "View3dPreview %p", (void *)ar);
re = RE_GetRender(name);
if (re) {
RegionView3D *rv3d = CTX_wm_region_view3d(C);
View3D *v3d = CTX_wm_view3d(C);
Scene *scene = CTX_data_scene(C);
rctf viewplane, viewplane1;
rcti disprect, disprect1;
float mat[4][4];
float clipsta, clipend;
bool orth;
if (engine->update_flag & RE_ENGINE_UPDATE_MA)
update |= PR_UPDATE_MATERIAL;
if (engine->update_flag & RE_ENGINE_UPDATE_OTHER)
update |= PR_UPDATE_MATERIAL;
engine->update_flag = 0;
if (engine->resolution_x != ar->winx || engine->resolution_y != ar->winy)
update |= PR_UPDATE_RENDERSIZE;
RE_GetView(re, mat);
if (compare_m4m4(mat, rv3d->viewmat, 0.00001f) == 0) {
update |= PR_UPDATE_VIEW;
}
render_view3d_get_rects(ar, v3d, rv3d, &viewplane, engine, &clipsta, &clipend, NULL, &orth);
RE_GetViewPlane(re, &viewplane1, &disprect1);
if (BLI_rctf_compare(&viewplane, &viewplane1, 0.00001f) == 0)
update |= PR_UPDATE_VIEW;
render_view3d_disprect(scene, ar, v3d, rv3d, &disprect);
if (BLI_rcti_compare(&disprect, &disprect1) == 0)
update |= PR_UPDATE_RENDERSIZE;
if (update)
engine->flag |= RE_ENGINE_DO_UPDATE;
//if (update)
// printf("changed ma %d res %d view %d\n", update & PR_UPDATE_MATERIAL, update & PR_UPDATE_RENDERSIZE, update & PR_UPDATE_VIEW);
}
return update;
render_view3d_do(engine, C);
}
void render_view3d_draw(RenderEngine *engine, const bContext *C)
{
Render *re = engine->re;
RenderResult rres;
int keep_data = render_view3d_changed(engine, C);
char name[32];
if (engine->flag & RE_ENGINE_DO_UPDATE)
render_view3d_do(engine, C, keep_data);
if (re == NULL) return;
render_view3d_do(engine, C);
if (re == NULL) {
sprintf(name, "View3dPreview %p", (void *)CTX_wm_region(C));
re = RE_GetRender(name);
if (re == NULL) return;
}
RE_AcquireResultImage(re, &rres);
@@ -1105,3 +1140,52 @@ void render_view3d_draw(RenderEngine *engine, const bContext *C)
RE_ReleaseResultImage(re);
}
void ED_viewport_render_kill_jobs(const bContext *C)
{
wmWindowManager *wm = CTX_wm_manager(C);
Main *bmain = CTX_data_main(C);
bScreen *sc;
ScrArea *sa;
ARegion *ar;
if (!wm)
return;
/* kill all actively running jobs */
WM_jobs_kill(wm, NULL, render_view3d_startjob);
/* loop over 3D view render engines */
for (sc = bmain->screen.first; sc; sc = sc->id.next) {
for (sa = sc->areabase.first; sa; sa = sa->next) {
if (sa->spacetype != SPACE_VIEW3D)
continue;
for (ar = sa->regionbase.first; ar; ar = ar->next) {
RegionView3D *rv3d;
if (ar->regiontype != RGN_TYPE_WINDOW)
continue;
rv3d = ar->regiondata;
if (rv3d->render_engine) {
/* free render database now before we change data, because
* RE_Database_Free will also loop over blender data */
char name[32];
Render *re;
sprintf(name, "View3dPreview %p", (void *)ar);
re = RE_GetRender(name);
if (re)
RE_Database_Free(re);
/* tag render engine to update entire database */
rv3d->render_engine->update_flag |= RE_ENGINE_UPDATE_DATABASE;
}
}
}
}
}

View File

@@ -539,7 +539,7 @@ void ED_render_internal_init(void)
{
RenderEngineType *ret = RE_engines_find("BLENDER_RENDER");
ret->view_update = render_view3d;
ret->view_update = render_view3d_update;
ret->view_draw = render_view3d_draw;
}

View File

@@ -908,11 +908,19 @@ static void region_overlap_fix(ScrArea *sa, ARegion *ar)
/* overlapping regions only in the following restricted cases */
static int region_is_overlap(wmWindow *win, ScrArea *sa, ARegion *ar)
{
if (U.uiflag2 & USER_REGION_OVERLAP)
if (WM_is_draw_triple(win))
if (ELEM4(sa->spacetype, SPACE_VIEW3D, SPACE_IMAGE, SPACE_SEQ, SPACE_CLIP))
if (U.uiflag2 & USER_REGION_OVERLAP) {
if (WM_is_draw_triple(win)) {
if (ELEM(sa->spacetype, SPACE_VIEW3D, SPACE_SEQ)) {
if (ELEM3(ar->regiontype, RGN_TYPE_TOOLS, RGN_TYPE_UI, RGN_TYPE_TOOL_PROPS))
return 1;
}
else if (ELEM(sa->spacetype, SPACE_IMAGE, SPACE_CLIP)) {
if (ELEM4(ar->regiontype, RGN_TYPE_TOOLS, RGN_TYPE_UI, RGN_TYPE_TOOL_PROPS, RGN_TYPE_PREVIEW))
return 1;
}
}
}
return 0;
}

View File

@@ -2820,6 +2820,8 @@ static void project_paint_begin(ProjPaintState *ps)
const int diameter = 2 * BKE_brush_size_get(ps->scene, ps->brush);
bool reset_threads = false;
/* ---- end defines ---- */
if (ps->source == PROJ_SRC_VIEW)
@@ -3064,6 +3066,10 @@ static void project_paint_begin(ProjPaintState *ps)
/* printf("\tscreenspace bucket division x:%d y:%d\n", ps->buckets_x, ps->buckets_y); */
if (ps->buckets_x > PROJ_BUCKET_RECT_MAX || ps->buckets_y > PROJ_BUCKET_RECT_MAX) {
reset_threads = true;
}
/* really high values could cause problems since it has to allocate a few
* (ps->buckets_x*ps->buckets_y) sized arrays */
CLAMP(ps->buckets_x, PROJ_BUCKET_RECT_MIN, PROJ_BUCKET_RECT_MAX);
@@ -3089,6 +3095,11 @@ static void project_paint_begin(ProjPaintState *ps)
ps->thread_tot = BKE_scene_num_threads(ps->scene);
/* workaround for #35057, disable threading if diameter is less than is possible for
* optimum bucket number generation */
if (reset_threads)
ps->thread_tot = 1;
for (a = 0; a < ps->thread_tot; a++) {
ps->arena_mt[a] = BLI_memarena_new(1 << 16, "project paint arena");
}

View File

@@ -577,9 +577,10 @@ void snode_set_context(const bContext *C)
if (!treetype ||
(treetype->poll && !treetype->poll(C, treetype)))
{
/* invalid tree type, disable */
snode->tree_idname[0] = '\0';
ED_node_tree_start(snode, NULL, NULL, NULL);
/* invalid tree type, skip
* NB: not resetting the node path here, invalid bNodeTreeType
* may still be registered at a later point.
*/
return;
}

View File

@@ -41,6 +41,7 @@
#include "BLI_math.h"
#include "BKE_context.h"
#include "BKE_library.h"
#include "BKE_screen.h"
#include "BKE_node.h"
@@ -83,6 +84,8 @@ void ED_node_tree_start(SpaceNode *snode, bNodeTree *ntree, ID *id, ID *from)
BLI_strncpy(path->node_name, id->name + 2, sizeof(path->node_name));
BLI_addtail(&snode->treepath, path);
id_us_ensure_real(&ntree->id);
}
/* update current tree */
@@ -116,6 +119,8 @@ void ED_node_tree_push(SpaceNode *snode, bNodeTree *ntree, bNode *gnode)
BLI_addtail(&snode->treepath, path);
id_us_ensure_real(&ntree->id);
/* update current tree */
snode->edittree = ntree;

View File

@@ -3273,7 +3273,7 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D
Object *ob = base->object;
Mesh *me = ob->data;
Material *ma = give_current_material(ob, 1);
const short hasHaloMat = (ma && (ma->material_type == MA_TYPE_HALO));
const short hasHaloMat = (ma && (ma->material_type == MA_TYPE_HALO) && !BKE_scene_use_new_shading_nodes(scene));
eWireDrawMode draw_wire = OBDRAW_WIRE_OFF;
int /* totvert,*/ totedge, totface;
DerivedMesh *dm = mesh_get_derived_final(scene, ob, scene->customdata_mask);

View File

@@ -59,6 +59,7 @@
#include "ED_mball.h"
#include "ED_mesh.h"
#include "ED_object.h"
#include "ED_render.h"
#include "ED_screen.h"
#include "ED_sculpt.h"
#include "ED_util.h"
@@ -140,9 +141,12 @@ static int ed_undo_step(bContext *C, int step, const char *undoname)
SpaceImage *sima = (SpaceImage *)sa->spacedata.first;
if ((obact && (obact->mode & OB_MODE_TEXTURE_PAINT)) || (sima->mode == SI_MODE_PAINT)) {
if (!ED_undo_paint_step(C, UNDO_PAINT_IMAGE, step, undoname) && undoname)
if (U.uiflag & USER_GLOBALUNDO)
if (!ED_undo_paint_step(C, UNDO_PAINT_IMAGE, step, undoname) && undoname) {
if (U.uiflag & USER_GLOBALUNDO) {
ED_viewport_render_kill_jobs(C);
BKE_undo_name(C, undoname);
}
}
WM_event_add_notifier(C, NC_WINDOW, NULL);
return OPERATOR_FINISHED;
@@ -192,6 +196,8 @@ static int ed_undo_step(bContext *C, int step, const char *undoname)
/* for example, texface stores image pointers */
undo_editmode_clear();
ED_viewport_render_kill_jobs(C);
if (undoname)
BKE_undo_name(C, undoname);
else
@@ -363,6 +369,8 @@ int ED_undo_operator_repeat(bContext *C, struct wmOperator *op)
{
int retval;
ED_viewport_render_kill_jobs(C);
if (G.debug & G_DEBUG)
printf("redo_cb: operator redo %s\n", op->type->name);
ED_undo_pop_op(C, op);
@@ -529,6 +537,7 @@ static int undo_history_exec(bContext *C, wmOperator *op)
WM_event_add_notifier(C, NC_GEOM | ND_DATA, NULL);
}
else {
ED_viewport_render_kill_jobs(C);
BKE_undo_number(C, item);
WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, CTX_data_scene(C));
}

View File

@@ -79,6 +79,26 @@ ContextFunctions_get_canvas_height(PyObject *self)
return PyLong_FromLong(ContextFunctions::GetCanvasHeightCF());
}
static char ContextFunctions_get_border___doc__[] =
".. method:: get_border()\n"
"\n"
" Returns the border.\n"
"\n"
" :return: A tuple of 4 numbers (xmin, ymin, xmax, ymax).\n"
" :rtype: tuple\n";
static PyObject *
ContextFunctions_get_border(PyObject *self)
{
BBox<Vec2i> border(ContextFunctions::GetBorderCF());
PyObject *v = PyTuple_New(4);
PyTuple_SET_ITEM(v, 0, PyLong_FromLong(border.getMin().x()));
PyTuple_SET_ITEM(v, 1, PyLong_FromLong(border.getMin().y()));
PyTuple_SET_ITEM(v, 2, PyLong_FromLong(border.getMax().x()));
PyTuple_SET_ITEM(v, 3, PyLong_FromLong(border.getMax().y()));
return v;
}
static char ContextFunctions_load_map___doc__[] =
".. function:: load_map(file_name, map_name, num_levels=4, sigma=1.0)\n"
"\n"
@@ -232,6 +252,8 @@ static PyMethodDef module_functions[] = {
ContextFunctions_get_canvas_width___doc__},
{"get_canvas_height", (PyCFunction)ContextFunctions_get_canvas_height, METH_NOARGS,
ContextFunctions_get_canvas_height___doc__},
{"get_border", (PyCFunction)ContextFunctions_get_border, METH_NOARGS,
ContextFunctions_get_border___doc__},
{"load_map", (PyCFunction)ContextFunctions_load_map, METH_VARARGS | METH_KEYWORDS,
ContextFunctions_load_map___doc__},
{"read_map_pixel", (PyCFunction)ContextFunctions_read_map_pixel, METH_VARARGS | METH_KEYWORDS,

View File

@@ -195,6 +195,7 @@ public:
virtual int width() const = 0;
virtual int height() const = 0;
virtual BBox<Vec2i> border() const = 0;
virtual BBox<Vec3r> scene3DBBox() const = 0;
inline const StrokeRenderer *renderer() const

View File

@@ -51,6 +51,11 @@ unsigned GetCanvasHeightCF()
return Canvas::getInstance()->height();
}
BBox<Vec2i> GetBorderCF()
{
return Canvas::getInstance()->border();
}
void LoadMapCF(const char *iFileName, const char *iMapName, unsigned iNbLevels, float iSigma)
{
return Canvas::getInstance()->loadMap(iFileName, iMapName, iNbLevels, iSigma);

View File

@@ -54,10 +54,15 @@ LIB_STROKE_EXPORT
unsigned GetCanvasWidthCF();
// GetCanvasHeight
/*! Returns the canvas width */
/*! Returns the canvas height */
LIB_STROKE_EXPORT
unsigned GetCanvasHeightCF();
// GetBorder
/*! Returns the border */
LIB_STROKE_EXPORT
BBox<Vec2i> GetBorderCF();
// Load map
/*! Loads an image map for further reading */
LIB_STROKE_EXPORT

View File

@@ -6385,6 +6385,15 @@ bool RNA_property_equals(PointerRNA *a, PointerRNA *b, PropertyRNA *prop, bool i
return equals;
}
case PROP_POINTER:
{
if (!STREQ(RNA_property_identifier(prop), "rna_type")) {
PointerRNA propptr_a = RNA_property_pointer_get(a, prop);
PointerRNA propptr_b = RNA_property_pointer_get(b, prop);
return RNA_struct_equals(&propptr_a, &propptr_b, is_strict);
}
}
default:
break;
}

View File

@@ -1531,7 +1531,7 @@ void IDP_spit(IDProperty *prop)
ret_str = PyObject_Repr(ret_dict);
Py_DECREF(ret_dict);
printf("IDProperty: %s\n", _PyUnicode_AsString(ret_str));
printf("IDProperty(%p): %s\n", prop, _PyUnicode_AsString(ret_str));
Py_DECREF(ret_str);

View File

@@ -66,7 +66,7 @@ typedef void (*RNA_SetIndexFunc)(PointerRNA *, PropertyRNA *, int index, void *)
/* arr[3] = x, self->arraydim is 0, lvalue_dim is 1 */
/* Ensures that a python sequence has expected number of items/sub-items and items are of desired type. */
static int validate_array_type(PyObject *seq, int dim, int totdim, int dimsize[],
static int validate_array_type(PyObject *seq, int dim, int totdim, int dimsize[], const bool is_dynamic,
ItemTypeCheckFunc check_item_type, const char *item_type_str, const char *error_prefix)
{
Py_ssize_t i;
@@ -110,7 +110,9 @@ static int validate_array_type(PyObject *seq, int dim, int totdim, int dimsize[]
error_prefix, dim + 1, dimsize[dim + 1], item_seq_size);
ok = 0;
}
else if (validate_array_type(item, dim + 1, totdim, dimsize, check_item_type, item_type_str, error_prefix) == -1) {
else if (validate_array_type(item, dim + 1, totdim, dimsize, is_dynamic,
check_item_type, item_type_str, error_prefix) == -1)
{
ok = 0;
}
@@ -129,7 +131,7 @@ static int validate_array_type(PyObject *seq, int dim, int totdim, int dimsize[]
error_prefix, dim + 1, Py_TYPE(seq)->tp_name);
return -1;
}
else if (seq_size != dimsize[dim]) {
else if ((seq_size != dimsize[dim]) && (is_dynamic == false)) {
PyErr_Format(PyExc_ValueError, "%s sequences of dimension %d should contain %d items, not %d",
error_prefix, dim, dimsize[dim], seq_size);
return -1;
@@ -315,8 +317,12 @@ static int validate_array(PyObject *rvalue, PointerRNA *ptr, PropertyRNA *prop,
{
if (validate_array_type(rvalue, lvalue_dim, totdim, dimsize, check_item_type, item_type_str, error_prefix) == -1)
const int prop_flag = RNA_property_flag(prop);
if (validate_array_type(rvalue, lvalue_dim, totdim, dimsize, (prop_flag & PROP_DYNAMIC) != 0,
check_item_type, item_type_str, error_prefix) == -1)
{
return -1;
}
return validate_array_length(rvalue, ptr, prop, lvalue_dim, totitem, error_prefix);
}

View File

@@ -70,6 +70,7 @@ struct Scene;
/* RenderEngine.update_flag, used by internal now */
#define RE_ENGINE_UPDATE_MA 1
#define RE_ENGINE_UPDATE_OTHER 2
#define RE_ENGINE_UPDATE_DATABASE 4
extern ListBase R_engines;
@@ -97,7 +98,7 @@ typedef struct RenderEngine {
RenderEngineType *type;
void *py_instance;
int flag, update_flag;
int flag;
struct Object *camera_override;
int tile_x;
@@ -110,6 +111,15 @@ typedef struct RenderEngine {
int resolution_x, resolution_y;
struct ReportList *reports;
/* for blender internal only */
int update_flag;
int job_update_flag;
rctf last_viewplane;
rcti last_disprect;
float last_viewmat[4][4];
int last_winx, last_winy;
} RenderEngine;
RenderEngine *RE_engine_create(RenderEngineType *type);

View File

@@ -207,6 +207,7 @@ void RE_GetViewPlane(struct Render *re, rctf *viewplane, rcti *disprect);
/* make or free the dbase */
void RE_Database_FromScene(struct Render *re, struct Main *bmain, struct Scene *scene, unsigned int lay, int use_camera_view);
void RE_Database_Preprocess(struct Render *re);
void RE_Database_Free(struct Render *re);
/* project dbase again, when viewplane/perspective changed */

View File

@@ -4863,7 +4863,11 @@ static void init_render_object(Render *re, Object *ob, Object *par, DupliObject
void RE_Database_Free(Render *re)
{
LampRen *lar;
/* will crash if we try to free empty database */
if (!re->i.convertdone)
return;
/* statistics for debugging render memory usage */
if ((G.debug & G_DEBUG) && (G.is_rendering)) {
if ((re->r.scemode & (R_BUTS_PREVIEW|R_VIEWPORT_PREVIEW))==0) {
@@ -5321,14 +5325,10 @@ void RE_Database_FromScene(Render *re, Main *bmain, Scene *scene, unsigned int l
database_init_objects(re, lay, 0, 0, 0, 0);
if (!re->test_break(re->tbh)) {
int tothalo;
set_material_lightgroups(re);
for (sce= re->scene; sce; sce= sce->set)
set_renderlayer_lightgroups(re, sce);
slurph_opt= 1;
/* for now some clumsy copying still */
re->i.totvert= re->totvert;
re->i.totface= re->totvlak;
@@ -5336,7 +5336,16 @@ void RE_Database_FromScene(Render *re, Main *bmain, Scene *scene, unsigned int l
re->i.tothalo= re->tothalo;
re->i.totlamp= re->totlamp;
re->stats_draw(re->sdh, &re->i);
}
slurph_opt= 1;
}
void RE_Database_Preprocess(Render *re)
{
if (!re->test_break(re->tbh)) {
int tothalo;
/* don't sort stars */
tothalo= re->tothalo;
if (!re->test_break(re->tbh)) {
@@ -5392,11 +5401,12 @@ void RE_Database_FromScene(Render *re, Main *bmain, Scene *scene, unsigned int l
if (!re->test_break(re->tbh))
if (re->r.mode & R_RAYTRACE)
volume_precache(re);
}
if (re->test_break(re->tbh))
if (re->test_break(re->tbh)) {
re->i.convertdone = TRUE;
RE_Database_Free(re);
}
else
re->i.convertdone = TRUE;
@@ -5866,8 +5876,10 @@ void RE_Database_FromScene_Vectors(Render *re, Main *bmain, Scene *sce, unsigned
RE_Database_Free(re);
re->strandsurface= strandsurface;
if (!re->test_break(re->tbh))
if (!re->test_break(re->tbh)) {
RE_Database_FromScene(re, bmain, sce, lay, 1);
RE_Database_Preprocess(re);
}
if (!re->test_break(re->tbh)) {
int vectorlay= get_vector_renderlayers(re->scene);

View File

@@ -1142,10 +1142,13 @@ static void do_render_3d(Render *re)
re->draw_lock(re->dlh, 1);
/* make render verts/faces/halos/lamps */
if (render_scene_needs_vector(re))
if (render_scene_needs_vector(re)) {
RE_Database_FromScene_Vectors(re, re->main, re->scene, re->lay);
else
}
else {
RE_Database_FromScene(re, re->main, re->scene, re->lay, 1);
RE_Database_Preprocess(re);
}
/* clear UI drawing locks */
if (re->draw_lock)
@@ -1676,6 +1679,9 @@ static void add_freestyle(Render *re, int render)
}
FRS_finish_stroke_rendering(re);
/* restore the global R value (invalidated by nested execution of the internal renderer) */
R = *re;
}
/* merges the results of Freestyle stroke rendering into a given render result */

View File

@@ -404,6 +404,9 @@ void WM_jobs_kill_type(struct wmWindowManager *wm, int job_type);
int WM_jobs_has_running(struct wmWindowManager *wm);
void WM_job_main_thread_lock_acquire(struct wmJob *job);
void WM_job_main_thread_lock_release(struct wmJob *job);
/* clipboard */
char *WM_clipboard_text_get(int selection);
void WM_clipboard_text_set(char *buf, int selection);

View File

@@ -128,8 +128,43 @@ struct wmJob {
ListBase threads;
double start_time;
/* ticket mutex for main thread locking while some job accesses
* data that the main thread might modify at the same time */
TicketMutex *main_thread_mutex;
bool main_thread_mutex_ending;
};
/* Main thread locking */
void WM_job_main_thread_lock_acquire(wmJob *wm_job)
{
BLI_ticket_mutex_lock(wm_job->main_thread_mutex);
/* if BLI_end_threads is being called to stop the job before it's finished,
* we no longer need to lock to get access to the main thread as it's
* waiting and can't respond */
if (wm_job->main_thread_mutex_ending)
BLI_ticket_mutex_unlock(wm_job->main_thread_mutex);
}
void WM_job_main_thread_lock_release(wmJob *wm_job)
{
if (!wm_job->main_thread_mutex_ending)
BLI_ticket_mutex_unlock(wm_job->main_thread_mutex);
}
static void wm_job_main_thread_yield(wmJob *wm_job, bool ending)
{
if (ending)
wm_job->main_thread_mutex_ending = true;
/* unlock and lock the ticket mutex. because it's a fair mutex any job that
* is waiting to acquire the lock will get it first, before we can lock */
BLI_ticket_mutex_unlock(wm_job->main_thread_mutex);
BLI_ticket_mutex_lock(wm_job->main_thread_mutex);
}
/* finds:
* if type, compare for it, otherwise any matching job
*/
@@ -162,13 +197,16 @@ wmJob *WM_jobs_get(wmWindowManager *wm, wmWindow *win, void *owner, const char *
if (wm_job == NULL) {
wm_job = MEM_callocN(sizeof(wmJob), "new job");
BLI_addtail(&wm->jobs, wm_job);
wm_job->win = win;
wm_job->owner = owner;
wm_job->flag = flag;
wm_job->job_type = job_type;
BLI_strncpy(wm_job->name, name, sizeof(wm_job->name));
wm_job->main_thread_mutex = BLI_ticket_mutex_alloc();
BLI_ticket_mutex_lock(wm_job->main_thread_mutex);
}
/* else: a running job, be careful */
@@ -369,12 +407,21 @@ void WM_jobs_start(wmWindowManager *wm, wmJob *wm_job)
}
}
static void wm_job_free(wmWindowManager *wm, wmJob *wm_job)
{
BLI_remlink(&wm->jobs, wm_job);
BLI_ticket_mutex_unlock(wm_job->main_thread_mutex);
BLI_ticket_mutex_free(wm_job->main_thread_mutex);
MEM_freeN(wm_job);
}
/* stop job, end thread, free data completely */
static void wm_jobs_kill_job(wmWindowManager *wm, wmJob *wm_job)
{
if (wm_job->running) {
/* signal job to end */
wm_job->stop = TRUE;
wm_job_main_thread_yield(wm_job, true);
BLI_end_threads(&wm_job->threads);
if (wm_job->endjob)
@@ -389,9 +436,7 @@ static void wm_jobs_kill_job(wmWindowManager *wm, wmJob *wm_job)
wm_job->run_free(wm_job->run_customdata);
/* remove wm_job */
BLI_remlink(&wm->jobs, wm_job);
MEM_freeN(wm_job);
wm_job_free(wm, wm_job);
}
/* wait until every job ended */
@@ -483,7 +528,6 @@ void wm_jobs_timer(const bContext *C, wmWindowManager *wm, wmTimer *wt)
float total_progress = 0.f;
float jobs_progress = 0;
for (wm_job = wm->jobs.first; wm_job; wm_job = wm_jobnext) {
wm_jobnext = wm_job->next;
@@ -491,6 +535,9 @@ void wm_jobs_timer(const bContext *C, wmWindowManager *wm, wmTimer *wt)
/* running threads */
if (wm_job->threads.first) {
/* let threads get temporary lock over main thread if needed */
wm_job_main_thread_yield(wm_job, false);
/* always call note and update when ready */
if (wm_job->do_update || wm_job->ready) {
@@ -522,7 +569,9 @@ void wm_jobs_timer(const bContext *C, wmWindowManager *wm, wmTimer *wt)
}
wm_job->running = FALSE;
wm_job_main_thread_yield(wm_job, true);
BLI_end_threads(&wm_job->threads);
wm_job->main_thread_mutex_ending = false;
if (wm_job->endnote)
WM_event_add_notifier(C, wm_job->endnote, NULL);
@@ -539,8 +588,7 @@ void wm_jobs_timer(const bContext *C, wmWindowManager *wm, wmTimer *wt)
wm_job->wt = NULL;
/* remove wm_job */
BLI_remlink(&wm->jobs, wm_job);
MEM_freeN(wm_job);
wm_job_free(wm, wm_job);
}
}
else if (wm_job->flag & WM_JOB_PROGRESS) {

View File

@@ -1880,6 +1880,7 @@ static void WM_OT_userpref_autoexec_path_add(wmOperatorType *ot)
{
ot->name = "Add Autoexec Path";
ot->idname = "WM_OT_userpref_autoexec_path_add";
ot->description = "Add path to exclude from autoexecution";
ot->exec = wm_userpref_autoexec_add_exec;
ot->poll = WM_operator_winactive;
@@ -1901,6 +1902,7 @@ static void WM_OT_userpref_autoexec_path_remove(wmOperatorType *ot)
{
ot->name = "Remove Autoexec Path";
ot->idname = "WM_OT_userpref_autoexec_path_remove";
ot->description = "Remove path to exclude from autoexecution";
ot->exec = wm_userpref_autoexec_remove_exec;
ot->poll = WM_operator_winactive;