Merged revision(s) 58059-58092 from trunk/blender into soc-2013-dingto.
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
384
release/scripts/modules/rna_keymap_ui.py
Normal file
384
release/scripts/modules/rna_keymap_ui.py
Normal 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')
|
||||
@@ -72,7 +72,6 @@ _modules = [
|
||||
"space_sequencer",
|
||||
"space_text",
|
||||
"space_time",
|
||||
"space_userpref_keymap",
|
||||
"space_userpref",
|
||||
"space_view3d",
|
||||
"space_view3d_toolbar",
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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__)
|
||||
@@ -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()
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
186
source/blender/bmesh/operators/bmo_normals.c
Normal file
186
source/blender/bmesh/operators/bmo_normals.c
Normal 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);
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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"))
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
12
source/blender/render/extern/include/RE_engine.h
vendored
12
source/blender/render/extern/include/RE_engine.h
vendored
@@ -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);
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user