Merge branch 'master' into blender2.8
Conflicts: source/blender/blenloader/intern/versioning_270.c source/blender/depsgraph/intern/builder/deg_builder_nodes.cc source/blender/depsgraph/intern/builder/deg_builder_relations.cc source/blender/editors/space_view3d/drawobject.c
This commit is contained in:
commit
559bd75766
|
@ -129,8 +129,10 @@ if(NOT DEFINED LIBDIR)
|
|||
message(STATUS "32 bit compiler detected.")
|
||||
set(LIBDIR_BASE "windows")
|
||||
endif()
|
||||
|
||||
if(MSVC_VERSION EQUAL 1900)
|
||||
if(MSVC_VERSION EQUAL 1910)
|
||||
message(STATUS "Visual Studio 2017 detected.")
|
||||
set(LIBDIR ${CMAKE_SOURCE_DIR}/../lib/${LIBDIR_BASE}_vc14)
|
||||
elseif(MSVC_VERSION EQUAL 1900)
|
||||
message(STATUS "Visual Studio 2015 detected.")
|
||||
set(LIBDIR ${CMAKE_SOURCE_DIR}/../lib/${LIBDIR_BASE}_vc14)
|
||||
else()
|
||||
|
|
|
@ -1156,15 +1156,21 @@ class CyclesPreferences(bpy.types.AddonPreferences):
|
|||
return cuda_devices, opencl_devices
|
||||
|
||||
|
||||
def has_active_device(self):
|
||||
def get_num_gpu_devices(self):
|
||||
import _cycles
|
||||
device_list = _cycles.available_devices()
|
||||
num = 0
|
||||
for device in device_list:
|
||||
if device[1] != self.compute_device_type:
|
||||
continue
|
||||
if any(dev.use and dev.id == device[2] for dev in self.devices):
|
||||
return True
|
||||
return False
|
||||
for dev in self.devices:
|
||||
if dev.use and dev.id == device[2]:
|
||||
num += 1
|
||||
return num
|
||||
|
||||
|
||||
def has_active_device(self):
|
||||
return self.get_num_gpu_devices() > 0
|
||||
|
||||
|
||||
def draw_impl(self, layout, context):
|
||||
|
|
|
@ -1556,7 +1556,7 @@ def draw_device(self, context):
|
|||
sub = row.split(align=True)
|
||||
sub.active = show_device_selection(context)
|
||||
sub.prop(cscene, "device", text="")
|
||||
row.operator("wm.addon_userpref_show", text="Preferences", icon='PREFERENCES').module = __package__
|
||||
row.operator("wm.addon_userpref_show", text="", icon='PREFERENCES').module = __package__
|
||||
|
||||
if engine.with_osl() and use_cpu(context):
|
||||
layout.prop(cscene, "shading_system")
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include "util_color.h"
|
||||
#include "util_foreach.h"
|
||||
#include "util_function.h"
|
||||
#include "util_hash.h"
|
||||
#include "util_logging.h"
|
||||
#include "util_progress.h"
|
||||
#include "util_time.h"
|
||||
|
@ -498,7 +499,8 @@ void BlenderSession::render()
|
|||
scene->film->tag_update(scene);
|
||||
scene->integrator->tag_update(scene);
|
||||
|
||||
for(b_rr.views.begin(b_view_iter); b_view_iter != b_rr.views.end(); ++b_view_iter) {
|
||||
int view_index = 0;
|
||||
for(b_rr.views.begin(b_view_iter); b_view_iter != b_rr.views.end(); ++b_view_iter, ++view_index) {
|
||||
b_rview_name = b_view_iter->name();
|
||||
|
||||
/* set the current view */
|
||||
|
@ -514,6 +516,12 @@ void BlenderSession::render()
|
|||
&python_thread_state,
|
||||
b_rlay_name.c_str());
|
||||
|
||||
/* Make sure all views have different noise patterns. - hardcoded value just to make it random */
|
||||
if(view_index != 0) {
|
||||
scene->integrator->seed += hash_int_2d(scene->integrator->seed, hash_int(view_index * 0xdeadbeef));
|
||||
scene->integrator->tag_update(scene);
|
||||
}
|
||||
|
||||
/* Update number of samples per layer. */
|
||||
int samples = sync->get_layer_samples();
|
||||
bool bound_samples = sync->get_layer_bound_samples();
|
||||
|
|
16
make.bat
16
make.bat
|
@ -61,6 +61,9 @@ if NOT "%1" == "" (
|
|||
set BUILD_ARCH=x86
|
||||
) else if "%1" == "x64" (
|
||||
set BUILD_ARCH=x64
|
||||
) else if "%1" == "2017" (
|
||||
set BUILD_VS_VER=15
|
||||
set BUILD_VS_YEAR=2017
|
||||
) else if "%1" == "2015" (
|
||||
set BUILD_VS_VER=14
|
||||
set BUILD_VS_YEAR=2015
|
||||
|
@ -140,7 +143,7 @@ if "%target%"=="Release" (
|
|||
)
|
||||
|
||||
:DetectMSVC
|
||||
REM Detect MSVC Installation
|
||||
REM Detect MSVC Installation for 2013-2015
|
||||
if DEFINED VisualStudioVersion goto msvc_detect_finally
|
||||
set VALUE_NAME=ProductDir
|
||||
REM Check 64 bits
|
||||
|
@ -153,7 +156,18 @@ for /F "usebackq skip=2 tokens=1-2*" %%A IN (`REG QUERY %KEY_NAME% /v %VALUE_NAM
|
|||
if DEFINED MSVC_VC_DIR goto msvc_detect_finally
|
||||
:msvc_detect_finally
|
||||
if DEFINED MSVC_VC_DIR call "%MSVC_VC_DIR%\vcvarsall.bat"
|
||||
if DEFINED MSVC_VC_DIR goto sanity_checks
|
||||
|
||||
rem MSVC Build environment 2017 and up.
|
||||
for /F "usebackq skip=2 tokens=1-2*" %%A IN (`REG QUERY "HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\VisualStudio\SXS\VS7" /v %BUILD_VS_VER%.0 2^>nul`) DO set MSVC_VS_DIR=%%C
|
||||
if DEFINED MSVC_VS_DIR goto msvc_detect_finally_2017
|
||||
REM Check 32 bits
|
||||
for /F "usebackq skip=2 tokens=1-2*" %%A IN (`REG QUERY "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\sxs\vs7" /v %BUILD_VS_VER%.0 2^>nul`) DO set MSVC_VS_DIR=%%C
|
||||
if DEFINED MSVC_VS_DIR goto msvc_detect_finally_2017
|
||||
:msvc_detect_finally_2017
|
||||
if DEFINED MSVC_VS_DIR call "%MSVC_VS_DIR%\Common7\Tools\VsDevCmd.bat"
|
||||
|
||||
:sanity_checks
|
||||
REM Sanity Checks
|
||||
where /Q msbuild
|
||||
if %ERRORLEVEL% NEQ 0 (
|
||||
|
|
|
@ -154,8 +154,6 @@ def load_scripts(reload_scripts=False, refresh_scripts=False):
|
|||
original_modules = _sys.modules.values()
|
||||
|
||||
if reload_scripts:
|
||||
_bpy_types.TypeMap.clear()
|
||||
|
||||
# just unload, don't change user defaults, this means we can sync
|
||||
# to reload. note that they will only actually reload of the
|
||||
# modification time changes. This `won't` work for packages so...
|
||||
|
@ -163,6 +161,9 @@ def load_scripts(reload_scripts=False, refresh_scripts=False):
|
|||
for module_name in [ext.module for ext in _user_preferences.addons]:
|
||||
_addon_utils.disable(module_name)
|
||||
|
||||
# *AFTER* unregistering all add-ons, otherwise all calls to unregister_module() will silently fail (do nothing).
|
||||
_bpy_types.TypeMap.clear()
|
||||
|
||||
def register_module_call(mod):
|
||||
register = getattr(mod, "register", None)
|
||||
if register:
|
||||
|
|
|
@ -189,6 +189,14 @@ def object_data_add(context, obdata, operator=None, use_active_layer=True, name=
|
|||
scene.update() # apply location
|
||||
# scene.objects.active = obj_new
|
||||
|
||||
# Match up UV layers, this is needed so adding an object with UV's
|
||||
# doesn't create new layers when there happens to be a naming mis-match.
|
||||
uv_new = obdata.uv_layers.active
|
||||
if uv_new is not None:
|
||||
uv_act = obj_act.data.uv_layers.active
|
||||
if uv_act is not None:
|
||||
uv_new.name = uv_act.name
|
||||
|
||||
bpy.ops.object.join() # join into the active.
|
||||
if obdata:
|
||||
bpy.data.meshes.remove(obdata)
|
||||
|
|
|
@ -84,26 +84,27 @@ def add_torus(major_rad, minor_rad, major_seg, minor_seg):
|
|||
|
||||
def add_uvs(mesh, minor_seg, major_seg):
|
||||
mesh.uv_textures.new()
|
||||
uv_layer = mesh.uv_layers.active
|
||||
u_step = 1.0/major_seg
|
||||
v_step = 1.0/minor_seg
|
||||
uv_data = mesh.uv_layers.active.data
|
||||
polygons = mesh.polygons
|
||||
u_step = 1.0 / major_seg
|
||||
v_step = 1.0 / minor_seg
|
||||
vertex_index = 0
|
||||
|
||||
u = 0.5
|
||||
for major_index in range(major_seg):
|
||||
v = 0.5
|
||||
for minor_index in range(minor_seg):
|
||||
loops = mesh.polygons[vertex_index].loop_indices
|
||||
if minor_index == minor_seg-1 and major_index == 0:
|
||||
uv_layer.data[loops[1]].uv = (u, v)
|
||||
uv_layer.data[loops[2]].uv = (u + u_step, v)
|
||||
uv_layer.data[loops[0]].uv = (u, v + v_step)
|
||||
uv_layer.data[loops[3]].uv = (u + u_step, v + v_step)
|
||||
loops = polygons[vertex_index].loop_indices
|
||||
if minor_index == minor_seg - 1 and major_index == 0:
|
||||
uv_data[loops[1]].uv = (u, v)
|
||||
uv_data[loops[2]].uv = (u + u_step, v)
|
||||
uv_data[loops[0]].uv = (u, v + v_step)
|
||||
uv_data[loops[3]].uv = (u + u_step, v + v_step)
|
||||
else:
|
||||
uv_layer.data[loops[0]].uv = (u, v)
|
||||
uv_layer.data[loops[1]].uv = (u + u_step, v)
|
||||
uv_layer.data[loops[3]].uv = (u, v + v_step)
|
||||
uv_layer.data[loops[2]].uv = (u + u_step, v + v_step)
|
||||
uv_data[loops[0]].uv = (u, v)
|
||||
uv_data[loops[1]].uv = (u + u_step, v)
|
||||
uv_data[loops[3]].uv = (u, v + v_step)
|
||||
uv_data[loops[2]].uv = (u + u_step, v + v_step)
|
||||
v = (v + v_step) % 1.0
|
||||
vertex_index += 1
|
||||
u = (u + u_step) % 1.0
|
||||
|
|
|
@ -117,16 +117,14 @@ def brush_texpaint_common(panel, context, layout, brush, settings, projpaint=Fal
|
|||
col.label("Gradient Colors")
|
||||
col.template_color_ramp(brush, "gradient", expand=True)
|
||||
|
||||
if brush.image_tool != 'FILL':
|
||||
if brush.image_tool == 'DRAW':
|
||||
col.label("Background Color")
|
||||
row = col.row(align=True)
|
||||
panel.prop_unified_color(row, context, brush, "secondary_color", text="")
|
||||
|
||||
if brush.image_tool == 'DRAW':
|
||||
col.prop(brush, "gradient_stroke_mode", text="Mode")
|
||||
if brush.gradient_stroke_mode in {'SPACING_REPEAT', 'SPACING_CLAMP'}:
|
||||
col.prop(brush, "grad_spacing")
|
||||
elif brush.image_tool == 'FILL':
|
||||
else: # if brush.image_tool == 'FILL':
|
||||
col.prop(brush, "gradient_fill_mode")
|
||||
else:
|
||||
row = col.row(align=True)
|
||||
|
@ -137,6 +135,9 @@ def brush_texpaint_common(panel, context, layout, brush, settings, projpaint=Fal
|
|||
panel.prop_unified_color(row, context, brush, "secondary_color", text="")
|
||||
row.separator()
|
||||
row.operator("paint.brush_colors_flip", icon='FILE_REFRESH', text="")
|
||||
else:
|
||||
if brush.image_tool == 'FILL' and not projpaint:
|
||||
col.prop(brush, "fill_threshold")
|
||||
|
||||
elif brush.image_tool == 'SOFTEN':
|
||||
col = layout.column(align=True)
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
* and keep comment above the defines.
|
||||
* Use STRINGIFY() rather than defining with quotes */
|
||||
#define BLENDER_VERSION 278
|
||||
#define BLENDER_SUBVERSION 3
|
||||
#define BLENDER_SUBVERSION 4
|
||||
/* Several breakages with 270, e.g. constraint deg vs rad */
|
||||
#define BLENDER_MINVERSION 270
|
||||
#define BLENDER_MINSUBVERSION 6
|
||||
|
|
|
@ -320,7 +320,7 @@ const char *BKE_undo_get_name(int nr, bool *r_active)
|
|||
}
|
||||
|
||||
/* return the name of the last item */
|
||||
const char *BKE_undo_get_name_last()
|
||||
const char *BKE_undo_get_name_last(void)
|
||||
{
|
||||
UndoElem *uel = undobase.last;
|
||||
return (uel ? uel->name : NULL);
|
||||
|
|
|
@ -1244,7 +1244,6 @@ char BKE_imtype_valid_channels(const char imtype, bool write_file)
|
|||
case R_IMF_IMTYPE_RAWTGA:
|
||||
case R_IMF_IMTYPE_IRIS:
|
||||
case R_IMF_IMTYPE_PNG:
|
||||
case R_IMF_IMTYPE_RADHDR:
|
||||
case R_IMF_IMTYPE_TIFF:
|
||||
case R_IMF_IMTYPE_OPENEXR:
|
||||
case R_IMF_IMTYPE_MULTILAYER:
|
||||
|
|
|
@ -377,6 +377,18 @@ static void libblock_remap_data_postprocess_obdata_relink(Main *UNUSED(bmain), O
|
|||
}
|
||||
}
|
||||
|
||||
static void libblock_remap_data_postprocess_nodetree_update(Main *bmain, ID *new_id)
|
||||
{
|
||||
/* Verify all nodetree user nodes. */
|
||||
ntreeVerifyNodes(bmain, new_id);
|
||||
|
||||
/* Update node trees as necessary. */
|
||||
FOREACH_NODETREE(bmain, ntree, id) {
|
||||
/* make an update call for the tree */
|
||||
ntreeUpdateTree(bmain, ntree);
|
||||
} FOREACH_NODETREE_END
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the 'data' part of the remapping (that is, all ID pointers from other ID datablocks).
|
||||
*
|
||||
|
@ -550,6 +562,8 @@ void BKE_libblock_remap_locked(
|
|||
default:
|
||||
break;
|
||||
}
|
||||
/* Node trees may virtually use any kind of data-block... */
|
||||
libblock_remap_data_postprocess_nodetree_update(bmain, new_id);
|
||||
|
||||
/* Full rebuild of DAG! */
|
||||
DAG_relations_tag_update(bmain);
|
||||
|
|
|
@ -736,11 +736,14 @@ void nodeRemoveAllSockets(bNodeTree *ntree, bNode *node)
|
|||
node_socket_free(ntree, sock, node);
|
||||
MEM_freeN(sock);
|
||||
}
|
||||
BLI_listbase_clear(&node->inputs);
|
||||
|
||||
for (sock = node->outputs.first; sock; sock = sock_next) {
|
||||
sock_next = sock->next;
|
||||
node_socket_free(ntree, sock, node);
|
||||
MEM_freeN(sock);
|
||||
}
|
||||
BLI_listbase_clear(&node->outputs);
|
||||
|
||||
node->update |= NODE_UPDATE;
|
||||
}
|
||||
|
|
|
@ -1367,6 +1367,13 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
|
|||
}
|
||||
}
|
||||
|
||||
if (!MAIN_VERSION_ATLEAST(main, 278, 4)) {
|
||||
const float sqrt_3 = (float)M_SQRT3;
|
||||
for (Brush *br = main->brush.first; br; br = br->id.next) {
|
||||
br->fill_threshold /= sqrt_3;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
if (!DNA_struct_elem_find(fd->filesdna, "View3DDebug", "char", "background")) {
|
||||
bScreen *screen;
|
||||
|
|
|
@ -912,20 +912,22 @@ static void write_curvemapping(WriteData *wd, CurveMapping *cumap)
|
|||
static void write_node_socket(WriteData *wd, bNodeTree *UNUSED(ntree), bNode *node, bNodeSocket *sock)
|
||||
{
|
||||
#ifdef USE_NODE_COMPAT_CUSTOMNODES
|
||||
/* forward compatibility code, so older blenders still open */
|
||||
sock->stack_type = 1;
|
||||
/* forward compatibility code, so older blenders still open (not for undo) */
|
||||
if (wd->current == NULL) {
|
||||
sock->stack_type = 1;
|
||||
|
||||
if (node->type == NODE_GROUP) {
|
||||
bNodeTree *ngroup = (bNodeTree *)node->id;
|
||||
if (ngroup) {
|
||||
/* for node groups: look up the deprecated groupsock pointer */
|
||||
sock->groupsock = ntreeFindSocketInterface(ngroup, sock->in_out, sock->identifier);
|
||||
BLI_assert(sock->groupsock != NULL);
|
||||
if (node->type == NODE_GROUP) {
|
||||
bNodeTree *ngroup = (bNodeTree *)node->id;
|
||||
if (ngroup) {
|
||||
/* for node groups: look up the deprecated groupsock pointer */
|
||||
sock->groupsock = ntreeFindSocketInterface(ngroup, sock->in_out, sock->identifier);
|
||||
BLI_assert(sock->groupsock != NULL);
|
||||
|
||||
/* node group sockets now use the generic identifier string to verify group nodes,
|
||||
* old blender uses the own_index.
|
||||
*/
|
||||
sock->own_index = sock->groupsock->own_index;
|
||||
/* node group sockets now use the generic identifier string to verify group nodes,
|
||||
* old blender uses the own_index.
|
||||
*/
|
||||
sock->own_index = sock->groupsock->own_index;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -2682,8 +2682,10 @@ BMVert *bmesh_urmv_loop(BMesh *bm, BMLoop *l_sep)
|
|||
|
||||
/**
|
||||
* A version of #bmesh_urmv_loop that disconnects multiple loops at once.
|
||||
* The loops must all share the same vertex, can be in any order
|
||||
* and are all moved to use a single new vertex - which is returned.
|
||||
*
|
||||
* Handles the task of finding fans boundaries.
|
||||
* This function handles the details of finding fans boundaries.
|
||||
*/
|
||||
BMVert *bmesh_urmv_loop_multi(
|
||||
BMesh *bm, BMLoop **larr, int larr_len)
|
||||
|
|
|
@ -64,7 +64,7 @@ bool BM_mesh_validate(BMesh *bm)
|
|||
|
||||
int i, j;
|
||||
|
||||
errtot = -1;
|
||||
errtot = -1; /* 'ERRMSG' next line will set at zero */
|
||||
fprintf(stderr, "\n");
|
||||
ERRMSG("This is a debugging function and not intended for general use, running slow test!");
|
||||
|
||||
|
@ -187,15 +187,22 @@ bool BM_mesh_validate(BMesh *bm)
|
|||
} while ((l_iter = l_iter->next) != l_first);
|
||||
|
||||
if (j != f->len) {
|
||||
ERRMSG("face %d: has length if %d but should be %d", i, f->len, j);
|
||||
ERRMSG("face %d: has length of %d but should be %d", i, f->len, j);
|
||||
}
|
||||
|
||||
/* leave elements un-tagged, not essential but nice to avoid unintended dirty tag use later. */
|
||||
do {
|
||||
BM_elem_flag_disable(l_iter, BM_ELEM_INTERNAL_TAG);
|
||||
BM_elem_flag_disable(l_iter->v, BM_ELEM_INTERNAL_TAG);
|
||||
BM_elem_flag_disable(l_iter->e, BM_ELEM_INTERNAL_TAG);
|
||||
} while ((l_iter = l_iter->next) != l_first);
|
||||
}
|
||||
|
||||
BLI_edgehash_free(edge_hash, NULL);
|
||||
|
||||
const bool is_valid = (errtot == 0);
|
||||
ERRMSG("Finished - errors %d", errtot);
|
||||
|
||||
return (errtot == 0);
|
||||
return is_valid;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -346,7 +346,7 @@ BMFace *BM_face_split_n(
|
|||
BMLoop **r_l, BMEdge *example)
|
||||
{
|
||||
BMFace *f_new, *f_tmp;
|
||||
BMLoop *l_dummy;
|
||||
BMLoop *l_new;
|
||||
BMEdge *e, *e_new;
|
||||
BMVert *v_new;
|
||||
// BMVert *v_a = l_a->v; /* UNUSED */
|
||||
|
@ -368,24 +368,21 @@ BMFace *BM_face_split_n(
|
|||
}
|
||||
|
||||
f_tmp = BM_face_copy(bm, bm, f, true, true);
|
||||
|
||||
if (!r_l)
|
||||
r_l = &l_dummy;
|
||||
|
||||
#ifdef USE_BMESH_HOLES
|
||||
f_new = bmesh_sfme(bm, f, l_a, l_b, r_l, NULL, example, false);
|
||||
f_new = bmesh_sfme(bm, f, l_a, l_b, &l_new, NULL, example, false);
|
||||
#else
|
||||
f_new = bmesh_sfme(bm, f, l_a, l_b, r_l, example, false);
|
||||
f_new = bmesh_sfme(bm, f, l_a, l_b, &l_new, example, false);
|
||||
#endif
|
||||
/* bmesh_sfme returns in r_l a Loop for f_new going from v_a to v_b.
|
||||
* The radial_next is for f and goes from v_b to v_a */
|
||||
/* bmesh_sfme returns in 'l_new' a Loop for f_new going from 'v_a' to 'v_b'.
|
||||
* The radial_next is for 'f' and goes from 'v_b' to 'v_a' */
|
||||
|
||||
if (f_new) {
|
||||
e = (*r_l)->e;
|
||||
e = l_new->e;
|
||||
for (i = 0; i < n; i++) {
|
||||
v_new = bmesh_semv(bm, v_b, e, &e_new);
|
||||
BLI_assert(v_new != NULL);
|
||||
/* bmesh_semv returns in e_new the edge going from v_new to tv */
|
||||
/* bmesh_semv returns in 'e_new' the edge going from 'v_new' to 'v_b' */
|
||||
copy_v3_v3(v_new->co, cos[i]);
|
||||
|
||||
/* interpolate the loop data for the loops with (v == v_new), using orig face */
|
||||
|
@ -405,6 +402,10 @@ BMFace *BM_face_split_n(
|
|||
|
||||
BM_face_verts_kill(bm, f_tmp);
|
||||
|
||||
if (r_l) {
|
||||
*r_l = l_new;
|
||||
}
|
||||
|
||||
return f_new;
|
||||
}
|
||||
|
||||
|
|
|
@ -225,24 +225,16 @@ void BM_face_calc_point_in_face(const BMFace *f, float r_co[3])
|
|||
*/
|
||||
float BM_face_calc_area(const BMFace *f)
|
||||
{
|
||||
/* inline 'area_poly_v3' logic, avoid creating a temp array */
|
||||
const BMLoop *l_iter, *l_first;
|
||||
float (*verts)[3] = BLI_array_alloca(verts, f->len);
|
||||
float area;
|
||||
unsigned int i = 0;
|
||||
float n[3];
|
||||
|
||||
zero_v3(n);
|
||||
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
|
||||
do {
|
||||
copy_v3_v3(verts[i++], l_iter->v->co);
|
||||
add_newell_cross_v3_v3v3(n, l_iter->v->co, l_iter->next->v->co);
|
||||
} while ((l_iter = l_iter->next) != l_first);
|
||||
|
||||
if (f->len == 3) {
|
||||
area = area_tri_v3(verts[0], verts[1], verts[2]);
|
||||
}
|
||||
else {
|
||||
area = area_poly_v3((const float (*)[3])verts, f->len);
|
||||
}
|
||||
|
||||
return area;
|
||||
return len_v3(n) * 0.5f;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -135,7 +135,7 @@ BMLoop *BM_face_find_longest_loop(BMFace *f) ATTR_WARN_UNUSED_RESULT ATTR_NONNUL
|
|||
BMEdge *BM_edge_exists(BMVert *v1, BMVert *v2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
|
||||
BMEdge *BM_edge_find_double(BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
|
||||
|
||||
BMFace* BM_face_exists(BMVert **varr, int len) ATTR_NONNULL(1);
|
||||
BMFace *BM_face_exists(BMVert **varr, int len) ATTR_NONNULL(1);
|
||||
|
||||
bool BM_face_exists_multi(BMVert **varr, BMEdge **earr, int len) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
|
||||
bool BM_face_exists_multi_edge(BMEdge **earr, int len) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
|
||||
|
|
|
@ -1174,7 +1174,7 @@ void BM_mesh_calc_uvs_sphere(BMesh *bm, const short oflag)
|
|||
}
|
||||
|
||||
BMIter iter2;
|
||||
BMLoop* l;
|
||||
BMLoop *l;
|
||||
int loop_index;
|
||||
float minx = 1.0f;
|
||||
|
||||
|
@ -1236,14 +1236,14 @@ void bmo_create_monkey_exec(BMesh *bm, BMOperator *op)
|
|||
int uvi = 0;
|
||||
const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
|
||||
for (i = 0; i < monkeynf; i++) {
|
||||
BMFace* temp1 = BM_face_create_quad_tri(bm,
|
||||
BMFace *f_new_a = BM_face_create_quad_tri(bm,
|
||||
tv[monkeyf[i][0] + i - monkeyo],
|
||||
tv[monkeyf[i][1] + i - monkeyo],
|
||||
tv[monkeyf[i][2] + i - monkeyo],
|
||||
(monkeyf[i][3] != monkeyf[i][2]) ? tv[monkeyf[i][3] + i - monkeyo] : NULL,
|
||||
NULL, BM_CREATE_NOP);
|
||||
|
||||
BMFace* temp2 = BM_face_create_quad_tri(bm,
|
||||
BMFace *f_new_b = BM_face_create_quad_tri(bm,
|
||||
tv[monkeynv + monkeyf[i][2] + i - monkeyo],
|
||||
tv[monkeynv + monkeyf[i][1] + i - monkeyo],
|
||||
tv[monkeynv + monkeyf[i][0] + i - monkeyo],
|
||||
|
@ -1252,20 +1252,19 @@ void bmo_create_monkey_exec(BMesh *bm, BMOperator *op)
|
|||
|
||||
/* Set the UVs here, the iteration order of the faces is not guaranteed,
|
||||
* so it's best to set the UVs right after the face is created. */
|
||||
if(calc_uvs) {
|
||||
BMLoop* l;
|
||||
if (calc_uvs) {
|
||||
BMLoop *l;
|
||||
BMIter liter;
|
||||
int loop_index;
|
||||
BM_ITER_ELEM_INDEX (l, &liter, temp1, BM_LOOPS_OF_FACE, loop_index) {
|
||||
BM_ITER_ELEM (l, &liter, f_new_a, BM_LOOPS_OF_FACE) {
|
||||
MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
|
||||
luv->uv[0] = monkeyuvs[uvi*2 + 0];
|
||||
luv->uv[1] = monkeyuvs[uvi*2 + 1];
|
||||
luv->uv[0] = monkeyuvs[uvi * 2 + 0];
|
||||
luv->uv[1] = monkeyuvs[uvi * 2 + 1];
|
||||
uvi++;
|
||||
}
|
||||
BM_ITER_ELEM_INDEX (l, &liter, temp2, BM_LOOPS_OF_FACE, loop_index) {
|
||||
BM_ITER_ELEM (l, &liter, f_new_b, BM_LOOPS_OF_FACE) {
|
||||
MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
|
||||
luv->uv[0] = monkeyuvs[uvi*2 + 0];
|
||||
luv->uv[1] = monkeyuvs[uvi*2 + 1];
|
||||
luv->uv[0] = monkeyuvs[uvi * 2 + 0];
|
||||
luv->uv[1] = monkeyuvs[uvi * 2 + 1];
|
||||
uvi++;
|
||||
}
|
||||
|
||||
|
|
|
@ -43,9 +43,13 @@ set(SRC
|
|||
intern/builder/deg_builder.cc
|
||||
intern/builder/deg_builder_cycle.cc
|
||||
intern/builder/deg_builder_nodes.cc
|
||||
intern/builder/deg_builder_nodes_rig.cc
|
||||
intern/builder/deg_builder_nodes_scene.cc
|
||||
intern/builder/deg_builder_pchanmap.cc
|
||||
intern/builder/deg_builder_relations.cc
|
||||
intern/builder/deg_builder_relations_keys.cc
|
||||
intern/builder/deg_builder_relations_rig.cc
|
||||
intern/builder/deg_builder_relations_scene.cc
|
||||
intern/builder/deg_builder_transitive.cc
|
||||
intern/debug/deg_debug_graphviz.cc
|
||||
intern/eval/deg_eval.cc
|
||||
|
|
|
@ -85,7 +85,7 @@ void deg_graph_build_finalize(Depsgraph *graph)
|
|||
*/
|
||||
GHASH_FOREACH_BEGIN(IDDepsNode *, id_node, graph->id_hash)
|
||||
{
|
||||
if (id_node->layers == 0 || 1) {
|
||||
if (id_node->layers == 0) {
|
||||
ID *id = id_node->id;
|
||||
if (GS(id->name) == ID_OB) {
|
||||
Object *object = (Object *)id;
|
||||
|
|
|
@ -55,8 +55,10 @@ extern "C" {
|
|||
#include "DNA_key_types.h"
|
||||
#include "DNA_lamp_types.h"
|
||||
#include "DNA_material_types.h"
|
||||
#include "DNA_mask_types.h"
|
||||
#include "DNA_mesh_types.h"
|
||||
#include "DNA_meta_types.h"
|
||||
#include "DNA_movieclip_types.h"
|
||||
#include "DNA_node_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
#include "DNA_rigidbody_types.h"
|
||||
|
@ -103,6 +105,7 @@ extern "C" {
|
|||
#include "intern/nodes/deg_node_operation.h"
|
||||
#include "intern/depsgraph_types.h"
|
||||
#include "intern/depsgraph_intern.h"
|
||||
#include "util/deg_util_foreach.h"
|
||||
|
||||
namespace DEG {
|
||||
|
||||
|
@ -315,92 +318,6 @@ OperationDepsNode *DepsgraphNodeBuilder::find_operation_node(
|
|||
|
||||
/* **** Build functions for entity nodes **** */
|
||||
|
||||
void DepsgraphNodeBuilder::build_scene(Main *bmain, Scene *scene)
|
||||
{
|
||||
/* LIB_TAG_DOIT is used to indicate whether node for given ID was already
|
||||
* created or not. This flag is being set in add_id_node(), so functions
|
||||
* shouldn't bother with setting it, they only might query this flag when
|
||||
* needed.
|
||||
*/
|
||||
BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
|
||||
/* XXX nested node trees are not included in tag-clearing above,
|
||||
* so we need to do this manually.
|
||||
*/
|
||||
FOREACH_NODETREE(bmain, nodetree, id) {
|
||||
if (id != (ID *)nodetree)
|
||||
nodetree->id.tag &= ~LIB_TAG_DOIT;
|
||||
} FOREACH_NODETREE_END
|
||||
|
||||
/* scene ID block */
|
||||
add_id_node(&scene->id);
|
||||
|
||||
/* timesource */
|
||||
add_time_source(NULL);
|
||||
|
||||
/* build subgraph for set, and link this in... */
|
||||
// XXX: depending on how this goes, that scene itself could probably store its
|
||||
// own little partial depsgraph?
|
||||
if (scene->set) {
|
||||
build_scene(bmain, scene->set);
|
||||
}
|
||||
|
||||
/* scene objects */
|
||||
for (Base *base = (Base *)scene->base.first; base; base = base->next) {
|
||||
Object *ob = base->object;
|
||||
|
||||
/* object itself */
|
||||
build_object(scene, base, ob);
|
||||
|
||||
/* object that this is a proxy for */
|
||||
// XXX: the way that proxies work needs to be completely reviewed!
|
||||
if (ob->proxy) {
|
||||
ob->proxy->proxy_from = ob;
|
||||
build_object(scene, base, ob->proxy);
|
||||
}
|
||||
|
||||
/* Object dupligroup. */
|
||||
if (ob->dup_group) {
|
||||
build_group(scene, base, ob->dup_group);
|
||||
}
|
||||
}
|
||||
|
||||
/* rigidbody */
|
||||
if (scene->rigidbody_world) {
|
||||
build_rigidbody(scene);
|
||||
}
|
||||
|
||||
/* scene's animation and drivers */
|
||||
if (scene->adt) {
|
||||
build_animdata(&scene->id);
|
||||
}
|
||||
|
||||
/* world */
|
||||
if (scene->world) {
|
||||
build_world(scene->world);
|
||||
}
|
||||
|
||||
/* compo nodes */
|
||||
if (scene->nodetree) {
|
||||
build_compositor(scene);
|
||||
}
|
||||
|
||||
/* sequencer */
|
||||
// XXX...
|
||||
|
||||
/* grease pencil */
|
||||
if (scene->gpd) {
|
||||
build_gpencil(scene->gpd);
|
||||
}
|
||||
|
||||
/* cache files */
|
||||
for (CacheFile *cachefile = static_cast<CacheFile *>(bmain->cachefiles.first);
|
||||
cachefile;
|
||||
cachefile = static_cast<CacheFile *>(cachefile->id.next))
|
||||
{
|
||||
build_cachefile(cachefile);
|
||||
}
|
||||
}
|
||||
|
||||
void DepsgraphNodeBuilder::build_group(Scene *scene,
|
||||
Base *base,
|
||||
Group *group)
|
||||
|
@ -411,10 +328,7 @@ void DepsgraphNodeBuilder::build_group(Scene *scene,
|
|||
}
|
||||
group_id->tag |= LIB_TAG_DOIT;
|
||||
|
||||
for (GroupObject *go = (GroupObject *)group->gobject.first;
|
||||
go != NULL;
|
||||
go = go->next)
|
||||
{
|
||||
LINKLIST_FOREACH (GroupObject *, go, &group->gobject) {
|
||||
build_object(scene, base, go->ob);
|
||||
}
|
||||
}
|
||||
|
@ -431,10 +345,7 @@ SubgraphDepsNode *DepsgraphNodeBuilder::build_subgraph(Group *group)
|
|||
DepsgraphNodeBuilder subgraph_builder(m_bmain, subgraph);
|
||||
|
||||
/* add group objects */
|
||||
for (GroupObject *go = (GroupObject *)group->gobject.first;
|
||||
go != NULL;
|
||||
go = go->next)
|
||||
{
|
||||
LINKLIST_FOREACH (GroupObject *, go, &group->gobject) {
|
||||
/*Object *ob = go->ob;*/
|
||||
|
||||
/* Each "group object" is effectively a separate instance of the
|
||||
|
@ -619,14 +530,6 @@ void DepsgraphNodeBuilder::build_object_constraints(Scene *scene, Object *ob)
|
|||
DEG_OPCODE_TRANSFORM_CONSTRAINTS);
|
||||
}
|
||||
|
||||
void DepsgraphNodeBuilder::build_pose_constraints(Object *ob, bPoseChannel *pchan)
|
||||
{
|
||||
/* create node for constraint stack */
|
||||
add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name,
|
||||
DEPSOP_TYPE_EXEC, function_bind(BKE_pose_constraints_evaluate, _1, ob, pchan),
|
||||
DEG_OPCODE_BONE_CONSTRAINTS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build graph nodes for AnimData block
|
||||
* \param id: ID-Block which hosts the AnimData
|
||||
|
@ -654,7 +557,7 @@ void DepsgraphNodeBuilder::build_animdata(ID *id)
|
|||
}
|
||||
|
||||
/* drivers */
|
||||
for (FCurve *fcu = (FCurve *)adt->drivers.first; fcu; fcu = fcu->next) {
|
||||
LINKLIST_FOREACH (FCurve *, fcu, &adt->drivers) {
|
||||
/* create driver */
|
||||
build_driver(id, fcu);
|
||||
}
|
||||
|
@ -767,7 +670,7 @@ void DepsgraphNodeBuilder::build_rigidbody(Scene *scene)
|
|||
|
||||
/* objects - simulation participants */
|
||||
if (rbw->group) {
|
||||
for (GroupObject *go = (GroupObject *)rbw->group->gobject.first; go; go = go->next) {
|
||||
LINKLIST_FOREACH (GroupObject *, go, &rbw->group->gobject) {
|
||||
Object *ob = go->ob;
|
||||
|
||||
if (!ob || (ob->type != OB_MESH))
|
||||
|
@ -782,207 +685,6 @@ void DepsgraphNodeBuilder::build_rigidbody(Scene *scene)
|
|||
}
|
||||
}
|
||||
|
||||
/* IK Solver Eval Steps */
|
||||
void DepsgraphNodeBuilder::build_ik_pose(Scene *scene, Object *ob, bPoseChannel *pchan, bConstraint *con)
|
||||
{
|
||||
bKinematicConstraint *data = (bKinematicConstraint *)con->data;
|
||||
|
||||
/* Find the chain's root. */
|
||||
bPoseChannel *rootchan = BKE_armature_ik_solver_find_root(pchan, data);
|
||||
|
||||
if (has_operation_node(&ob->id, DEPSNODE_TYPE_EVAL_POSE, rootchan->name,
|
||||
DEG_OPCODE_POSE_IK_SOLVER))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* Operation node for evaluating/running IK Solver. */
|
||||
add_operation_node(&ob->id, DEPSNODE_TYPE_EVAL_POSE, rootchan->name,
|
||||
DEPSOP_TYPE_SIM, function_bind(BKE_pose_iktree_evaluate, _1, scene, ob, rootchan),
|
||||
DEG_OPCODE_POSE_IK_SOLVER);
|
||||
}
|
||||
|
||||
/* Spline IK Eval Steps */
|
||||
void DepsgraphNodeBuilder::build_splineik_pose(Scene *scene, Object *ob, bPoseChannel *pchan, bConstraint *con)
|
||||
{
|
||||
bSplineIKConstraint *data = (bSplineIKConstraint *)con->data;
|
||||
|
||||
/* Find the chain's root. */
|
||||
bPoseChannel *rootchan = BKE_armature_splineik_solver_find_root(pchan, data);
|
||||
|
||||
/* Operation node for evaluating/running Spline IK Solver.
|
||||
* Store the "root bone" of this chain in the solver, so it knows where to start.
|
||||
*/
|
||||
add_operation_node(&ob->id, DEPSNODE_TYPE_EVAL_POSE, rootchan->name,
|
||||
DEPSOP_TYPE_SIM, function_bind(BKE_pose_splineik_evaluate, _1, scene, ob, rootchan),
|
||||
DEG_OPCODE_POSE_SPLINE_IK_SOLVER);
|
||||
}
|
||||
|
||||
/* Pose/Armature Bones Graph */
|
||||
void DepsgraphNodeBuilder::build_rig(Scene *scene, Object *ob)
|
||||
{
|
||||
bArmature *arm = (bArmature *)ob->data;
|
||||
|
||||
/* animation and/or drivers linking posebones to base-armature used to define them
|
||||
* NOTE: AnimData here is really used to control animated deform properties,
|
||||
* which ideally should be able to be unique across different instances.
|
||||
* Eventually, we need some type of proxy/isolation mechanism in-between here
|
||||
* to ensure that we can use same rig multiple times in same scene...
|
||||
*/
|
||||
build_animdata(&arm->id);
|
||||
|
||||
/* Rebuild pose if not up to date. */
|
||||
if (ob->pose == NULL || (ob->pose->flag & POSE_RECALC)) {
|
||||
BKE_pose_rebuild_ex(ob, arm, false);
|
||||
/* XXX: Without this animation gets lost in certain circumstances
|
||||
* after loading file. Need to investigate further since it does
|
||||
* not happen with simple scenes..
|
||||
*/
|
||||
if (ob->adt) {
|
||||
ob->adt->recalc |= ADT_RECALC_ANIM;
|
||||
}
|
||||
}
|
||||
|
||||
/* speed optimization for animation lookups */
|
||||
if (ob->pose) {
|
||||
BKE_pose_channels_hash_make(ob->pose);
|
||||
if (ob->pose->flag & POSE_CONSTRAINTS_NEED_UPDATE_FLAGS) {
|
||||
BKE_pose_update_constraint_flags(ob->pose);
|
||||
}
|
||||
}
|
||||
|
||||
/* Make sure pose is up-to-date with armature updates. */
|
||||
add_operation_node(&arm->id,
|
||||
DEPSNODE_TYPE_PARAMETERS,
|
||||
DEPSOP_TYPE_EXEC,
|
||||
NULL,
|
||||
DEG_OPCODE_PLACEHOLDER,
|
||||
"Armature Eval");
|
||||
|
||||
/**
|
||||
* Pose Rig Graph
|
||||
* ==============
|
||||
*
|
||||
* Pose Component:
|
||||
* - Mainly used for referencing Bone components.
|
||||
* - This is where the evaluation operations for init/exec/cleanup
|
||||
* (ik) solvers live, and are later hooked up (so that they can be
|
||||
* interleaved during runtime) with bone-operations they depend on/affect.
|
||||
* - init_pose_eval() and cleanup_pose_eval() are absolute first and last
|
||||
* steps of pose eval process. ALL bone operations must be performed
|
||||
* between these two...
|
||||
*
|
||||
* Bone Component:
|
||||
* - Used for representing each bone within the rig
|
||||
* - Acts to encapsulate the evaluation operations (base matrix + parenting,
|
||||
* and constraint stack) so that they can be easily found.
|
||||
* - Everything else which depends on bone-results hook up to the component only
|
||||
* so that we can redirect those to point at either the the post-IK/
|
||||
* post-constraint/post-matrix steps, as needed.
|
||||
*/
|
||||
|
||||
/* pose eval context */
|
||||
add_operation_node(&ob->id, DEPSNODE_TYPE_EVAL_POSE,
|
||||
DEPSOP_TYPE_INIT, function_bind(BKE_pose_eval_init, _1, scene, ob, ob->pose), DEG_OPCODE_POSE_INIT);
|
||||
|
||||
add_operation_node(&ob->id, DEPSNODE_TYPE_EVAL_POSE,
|
||||
DEPSOP_TYPE_POST, function_bind(BKE_pose_eval_flush, _1, scene, ob, ob->pose), DEG_OPCODE_POSE_DONE);
|
||||
|
||||
/* bones */
|
||||
for (bPoseChannel *pchan = (bPoseChannel *)ob->pose->chanbase.first; pchan; pchan = pchan->next) {
|
||||
/* node for bone eval */
|
||||
add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name,
|
||||
DEPSOP_TYPE_INIT, NULL, // XXX: BKE_pose_eval_bone_local
|
||||
DEG_OPCODE_BONE_LOCAL);
|
||||
|
||||
add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name,
|
||||
DEPSOP_TYPE_EXEC, function_bind(BKE_pose_eval_bone, _1, scene, ob, pchan), // XXX: BKE_pose_eval_bone_pose
|
||||
DEG_OPCODE_BONE_POSE_PARENT);
|
||||
|
||||
add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name,
|
||||
DEPSOP_TYPE_OUT, NULL, /* NOTE: dedicated noop for easier relationship construction */
|
||||
DEG_OPCODE_BONE_READY);
|
||||
|
||||
add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name,
|
||||
DEPSOP_TYPE_POST, function_bind(BKE_pose_bone_done, _1, pchan),
|
||||
DEG_OPCODE_BONE_DONE);
|
||||
|
||||
/* constraints */
|
||||
if (pchan->constraints.first != NULL) {
|
||||
build_pose_constraints(ob, pchan);
|
||||
}
|
||||
|
||||
/**
|
||||
* IK Solvers...
|
||||
*
|
||||
* - These require separate processing steps are pose-level
|
||||
* to be executed between chains of bones (i.e. once the
|
||||
* base transforms of a bunch of bones is done)
|
||||
*
|
||||
* Unsolved Issues:
|
||||
* - Care is needed to ensure that multi-headed trees work out the same as in ik-tree building
|
||||
* - Animated chain-lengths are a problem...
|
||||
*/
|
||||
for (bConstraint *con = (bConstraint *)pchan->constraints.first; con; con = con->next) {
|
||||
switch (con->type) {
|
||||
case CONSTRAINT_TYPE_KINEMATIC:
|
||||
build_ik_pose(scene, ob, pchan, con);
|
||||
break;
|
||||
|
||||
case CONSTRAINT_TYPE_SPLINEIK:
|
||||
build_splineik_pose(scene, ob, pchan, con);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DepsgraphNodeBuilder::build_proxy_rig(Object *ob)
|
||||
{
|
||||
ID *obdata = (ID *)ob->data;
|
||||
build_animdata(obdata);
|
||||
|
||||
BLI_assert(ob->pose != NULL);
|
||||
|
||||
/* speed optimization for animation lookups */
|
||||
BKE_pose_channels_hash_make(ob->pose);
|
||||
if (ob->pose->flag & POSE_CONSTRAINTS_NEED_UPDATE_FLAGS) {
|
||||
BKE_pose_update_constraint_flags(ob->pose);
|
||||
}
|
||||
|
||||
add_operation_node(&ob->id,
|
||||
DEPSNODE_TYPE_EVAL_POSE,
|
||||
DEPSOP_TYPE_INIT,
|
||||
function_bind(BKE_pose_eval_proxy_copy, _1, ob),
|
||||
DEG_OPCODE_POSE_INIT);
|
||||
|
||||
for (bPoseChannel *pchan = (bPoseChannel *)ob->pose->chanbase.first;
|
||||
pchan != NULL;
|
||||
pchan = pchan->next)
|
||||
{
|
||||
add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name,
|
||||
DEPSOP_TYPE_INIT, NULL,
|
||||
DEG_OPCODE_BONE_LOCAL);
|
||||
|
||||
add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name,
|
||||
DEPSOP_TYPE_EXEC, NULL,
|
||||
DEG_OPCODE_BONE_READY);
|
||||
|
||||
add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name,
|
||||
DEPSOP_TYPE_POST, NULL,
|
||||
DEG_OPCODE_BONE_DONE);
|
||||
}
|
||||
|
||||
add_operation_node(&ob->id,
|
||||
DEPSNODE_TYPE_EVAL_POSE,
|
||||
DEPSOP_TYPE_POST,
|
||||
NULL,
|
||||
DEG_OPCODE_POSE_DONE);
|
||||
}
|
||||
|
||||
/* Shapekeys */
|
||||
void DepsgraphNodeBuilder::build_shapekeys(Key *key)
|
||||
{
|
||||
|
@ -1033,33 +735,26 @@ void DepsgraphNodeBuilder::build_obdata_geom(Scene *scene, Object *ob)
|
|||
// TODO: "Done" operation
|
||||
|
||||
/* Modifiers */
|
||||
if (ob->modifiers.first) {
|
||||
for (ModifierData *md = (ModifierData *)ob->modifiers.first;
|
||||
md != NULL;
|
||||
md = md->next)
|
||||
{
|
||||
add_operation_node(&ob->id,
|
||||
DEPSNODE_TYPE_GEOMETRY,
|
||||
DEPSOP_TYPE_EXEC,
|
||||
function_bind(BKE_object_eval_modifier,
|
||||
_1,
|
||||
scene,
|
||||
ob,
|
||||
md),
|
||||
DEG_OPCODE_GEOMETRY_MODIFIER,
|
||||
md->name);
|
||||
}
|
||||
LINKLIST_FOREACH (ModifierData *, md, &ob->modifiers) {
|
||||
add_operation_node(&ob->id,
|
||||
DEPSNODE_TYPE_GEOMETRY,
|
||||
DEPSOP_TYPE_EXEC,
|
||||
function_bind(BKE_object_eval_modifier,
|
||||
_1,
|
||||
scene,
|
||||
ob,
|
||||
md),
|
||||
DEG_OPCODE_GEOMETRY_MODIFIER,
|
||||
md->name);
|
||||
}
|
||||
|
||||
/* materials */
|
||||
if (ob->totcol) {
|
||||
for (int a = 1; a <= ob->totcol; a++) {
|
||||
Material *ma = give_current_material(ob, a);
|
||||
if (ma != NULL) {
|
||||
// XXX?!
|
||||
ComponentDepsNode *geom_node = add_component_node(&ob->id, DEPSNODE_TYPE_GEOMETRY);
|
||||
build_material(geom_node, ma);
|
||||
}
|
||||
for (int a = 1; a <= ob->totcol; a++) {
|
||||
Material *ma = give_current_material(ob, a);
|
||||
if (ma != NULL) {
|
||||
// XXX?!
|
||||
ComponentDepsNode *geom_node = add_component_node(&ob->id, DEPSNODE_TYPE_GEOMETRY);
|
||||
build_material(geom_node, ma);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1155,7 +850,7 @@ void DepsgraphNodeBuilder::build_obdata_geom(Scene *scene, Object *ob)
|
|||
build_object(scene, NULL, cu->bevobj);
|
||||
}
|
||||
if (cu->taperobj != NULL) {
|
||||
build_object(scene, NULL, cu->bevobj);
|
||||
build_object(scene, NULL, cu->taperobj);
|
||||
}
|
||||
if (ob->type == OB_FONT && cu->textoncurve != NULL) {
|
||||
build_object(scene, NULL, cu->textoncurve);
|
||||
|
@ -1253,7 +948,7 @@ void DepsgraphNodeBuilder::build_nodetree(DepsNode *owner_node, bNodeTree *ntree
|
|||
DEG_OPCODE_PLACEHOLDER, "Parameters Eval");
|
||||
|
||||
/* nodetree's nodes... */
|
||||
for (bNode *bnode = (bNode *)ntree->nodes.first; bnode; bnode = bnode->next) {
|
||||
LINKLIST_FOREACH (bNode *, bnode, &ntree->nodes) {
|
||||
ID *id = bnode->id;
|
||||
if (id != NULL) {
|
||||
short id_type = GS(id->name);
|
||||
|
@ -1384,7 +1079,6 @@ void DepsgraphNodeBuilder::build_cachefile(CacheFile *cache_file)
|
|||
ID *cache_file_id = &cache_file->id;
|
||||
|
||||
add_component_node(cache_file_id, DEPSNODE_TYPE_CACHE);
|
||||
|
||||
add_operation_node(cache_file_id, DEPSNODE_TYPE_CACHE,
|
||||
DEPSOP_TYPE_EXEC, NULL,
|
||||
DEG_OPCODE_PLACEHOLDER, "Cache File Update");
|
||||
|
@ -1393,4 +1087,17 @@ void DepsgraphNodeBuilder::build_cachefile(CacheFile *cache_file)
|
|||
build_animdata(cache_file_id);
|
||||
}
|
||||
|
||||
void DepsgraphNodeBuilder::build_mask(Mask *mask)
|
||||
{
|
||||
ID *mask_id = &mask->id;
|
||||
add_id_node(mask_id);
|
||||
build_animdata(mask_id);
|
||||
}
|
||||
|
||||
void DepsgraphNodeBuilder::build_movieclip(MovieClip *clip) {
|
||||
ID *clip_id = &clip->id;
|
||||
add_id_node(clip_id);
|
||||
build_animdata(clip_id);
|
||||
}
|
||||
|
||||
} // namespace DEG
|
||||
|
|
|
@ -44,7 +44,9 @@ struct Group;
|
|||
struct Key;
|
||||
struct Main;
|
||||
struct Material;
|
||||
struct Mask;
|
||||
struct MTex;
|
||||
struct MovieClip;
|
||||
struct bNodeTree;
|
||||
struct Object;
|
||||
struct bPoseChannel;
|
||||
|
@ -154,6 +156,8 @@ struct DepsgraphNodeBuilder {
|
|||
void build_compositor(Scene *scene);
|
||||
void build_gpencil(bGPdata *gpd);
|
||||
void build_cachefile(CacheFile *cache_file);
|
||||
void build_mask(Mask *mask);
|
||||
void build_movieclip(MovieClip *clip);
|
||||
|
||||
protected:
|
||||
Main *m_bmain;
|
||||
|
|
|
@ -0,0 +1,273 @@
|
|||
/*
|
||||
* ***** BEGIN GPL LICENSE BLOCK *****
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* The Original Code is Copyright (C) 2013 Blender Foundation.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Original Author: Joshua Leung
|
||||
* Contributor(s): Based on original depsgraph.c code - Blender Foundation (2005-2013)
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
/** \file blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc
|
||||
* \ingroup depsgraph
|
||||
*
|
||||
* Methods for constructing depsgraph's nodes
|
||||
*/
|
||||
|
||||
#include "intern/builder/deg_builder_nodes.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
extern "C" {
|
||||
#include "BLI_blenlib.h"
|
||||
#include "BLI_string.h"
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
#include "DNA_anim_types.h"
|
||||
#include "DNA_armature_types.h"
|
||||
#include "DNA_constraint_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
|
||||
#include "BKE_action.h"
|
||||
#include "BKE_armature.h"
|
||||
|
||||
#include "DEG_depsgraph.h"
|
||||
#include "DEG_depsgraph_build.h"
|
||||
} /* extern "C" */
|
||||
|
||||
#include "intern/builder/deg_builder.h"
|
||||
#include "intern/nodes/deg_node.h"
|
||||
#include "intern/nodes/deg_node_component.h"
|
||||
#include "intern/nodes/deg_node_operation.h"
|
||||
#include "intern/depsgraph_types.h"
|
||||
#include "intern/depsgraph_intern.h"
|
||||
#include "util/deg_util_foreach.h"
|
||||
|
||||
namespace DEG {
|
||||
|
||||
void DepsgraphNodeBuilder::build_pose_constraints(Object *ob, bPoseChannel *pchan)
|
||||
{
|
||||
/* create node for constraint stack */
|
||||
add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name,
|
||||
DEPSOP_TYPE_EXEC, function_bind(BKE_pose_constraints_evaluate, _1, ob, pchan),
|
||||
DEG_OPCODE_BONE_CONSTRAINTS);
|
||||
}
|
||||
|
||||
/* IK Solver Eval Steps */
|
||||
void DepsgraphNodeBuilder::build_ik_pose(Scene *scene, Object *ob, bPoseChannel *pchan, bConstraint *con)
|
||||
{
|
||||
bKinematicConstraint *data = (bKinematicConstraint *)con->data;
|
||||
|
||||
/* Find the chain's root. */
|
||||
bPoseChannel *rootchan = BKE_armature_ik_solver_find_root(pchan, data);
|
||||
|
||||
if (has_operation_node(&ob->id, DEPSNODE_TYPE_EVAL_POSE, rootchan->name,
|
||||
DEG_OPCODE_POSE_IK_SOLVER))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* Operation node for evaluating/running IK Solver. */
|
||||
add_operation_node(&ob->id, DEPSNODE_TYPE_EVAL_POSE, rootchan->name,
|
||||
DEPSOP_TYPE_SIM, function_bind(BKE_pose_iktree_evaluate, _1, scene, ob, rootchan),
|
||||
DEG_OPCODE_POSE_IK_SOLVER);
|
||||
}
|
||||
|
||||
/* Spline IK Eval Steps */
|
||||
void DepsgraphNodeBuilder::build_splineik_pose(Scene *scene, Object *ob, bPoseChannel *pchan, bConstraint *con)
|
||||
{
|
||||
bSplineIKConstraint *data = (bSplineIKConstraint *)con->data;
|
||||
|
||||
/* Find the chain's root. */
|
||||
bPoseChannel *rootchan = BKE_armature_splineik_solver_find_root(pchan, data);
|
||||
|
||||
/* Operation node for evaluating/running Spline IK Solver.
|
||||
* Store the "root bone" of this chain in the solver, so it knows where to start.
|
||||
*/
|
||||
add_operation_node(&ob->id, DEPSNODE_TYPE_EVAL_POSE, rootchan->name,
|
||||
DEPSOP_TYPE_SIM, function_bind(BKE_pose_splineik_evaluate, _1, scene, ob, rootchan),
|
||||
DEG_OPCODE_POSE_SPLINE_IK_SOLVER);
|
||||
}
|
||||
|
||||
/* Pose/Armature Bones Graph */
|
||||
void DepsgraphNodeBuilder::build_rig(Scene *scene, Object *ob)
|
||||
{
|
||||
bArmature *arm = (bArmature *)ob->data;
|
||||
|
||||
/* animation and/or drivers linking posebones to base-armature used to define them
|
||||
* NOTE: AnimData here is really used to control animated deform properties,
|
||||
* which ideally should be able to be unique across different instances.
|
||||
* Eventually, we need some type of proxy/isolation mechanism in-between here
|
||||
* to ensure that we can use same rig multiple times in same scene...
|
||||
*/
|
||||
build_animdata(&arm->id);
|
||||
|
||||
/* Rebuild pose if not up to date. */
|
||||
if (ob->pose == NULL || (ob->pose->flag & POSE_RECALC)) {
|
||||
BKE_pose_rebuild_ex(ob, arm, false);
|
||||
/* XXX: Without this animation gets lost in certain circumstances
|
||||
* after loading file. Need to investigate further since it does
|
||||
* not happen with simple scenes..
|
||||
*/
|
||||
if (ob->adt) {
|
||||
ob->adt->recalc |= ADT_RECALC_ANIM;
|
||||
}
|
||||
}
|
||||
|
||||
/* speed optimization for animation lookups */
|
||||
if (ob->pose) {
|
||||
BKE_pose_channels_hash_make(ob->pose);
|
||||
if (ob->pose->flag & POSE_CONSTRAINTS_NEED_UPDATE_FLAGS) {
|
||||
BKE_pose_update_constraint_flags(ob->pose);
|
||||
}
|
||||
}
|
||||
|
||||
/* Make sure pose is up-to-date with armature updates. */
|
||||
add_operation_node(&arm->id,
|
||||
DEPSNODE_TYPE_PARAMETERS,
|
||||
DEPSOP_TYPE_EXEC,
|
||||
NULL,
|
||||
DEG_OPCODE_PLACEHOLDER,
|
||||
"Armature Eval");
|
||||
|
||||
/**
|
||||
* Pose Rig Graph
|
||||
* ==============
|
||||
*
|
||||
* Pose Component:
|
||||
* - Mainly used for referencing Bone components.
|
||||
* - This is where the evaluation operations for init/exec/cleanup
|
||||
* (ik) solvers live, and are later hooked up (so that they can be
|
||||
* interleaved during runtime) with bone-operations they depend on/affect.
|
||||
* - init_pose_eval() and cleanup_pose_eval() are absolute first and last
|
||||
* steps of pose eval process. ALL bone operations must be performed
|
||||
* between these two...
|
||||
*
|
||||
* Bone Component:
|
||||
* - Used for representing each bone within the rig
|
||||
* - Acts to encapsulate the evaluation operations (base matrix + parenting,
|
||||
* and constraint stack) so that they can be easily found.
|
||||
* - Everything else which depends on bone-results hook up to the component only
|
||||
* so that we can redirect those to point at either the the post-IK/
|
||||
* post-constraint/post-matrix steps, as needed.
|
||||
*/
|
||||
|
||||
/* pose eval context */
|
||||
add_operation_node(&ob->id, DEPSNODE_TYPE_EVAL_POSE,
|
||||
DEPSOP_TYPE_INIT, function_bind(BKE_pose_eval_init, _1, scene, ob, ob->pose), DEG_OPCODE_POSE_INIT);
|
||||
|
||||
add_operation_node(&ob->id, DEPSNODE_TYPE_EVAL_POSE,
|
||||
DEPSOP_TYPE_POST, function_bind(BKE_pose_eval_flush, _1, scene, ob, ob->pose), DEG_OPCODE_POSE_DONE);
|
||||
|
||||
/* bones */
|
||||
LINKLIST_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) {
|
||||
/* node for bone eval */
|
||||
add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name,
|
||||
DEPSOP_TYPE_INIT, NULL, // XXX: BKE_pose_eval_bone_local
|
||||
DEG_OPCODE_BONE_LOCAL);
|
||||
|
||||
add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name,
|
||||
DEPSOP_TYPE_EXEC, function_bind(BKE_pose_eval_bone, _1, scene, ob, pchan), // XXX: BKE_pose_eval_bone_pose
|
||||
DEG_OPCODE_BONE_POSE_PARENT);
|
||||
|
||||
add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name,
|
||||
DEPSOP_TYPE_OUT, NULL, /* NOTE: dedicated noop for easier relationship construction */
|
||||
DEG_OPCODE_BONE_READY);
|
||||
|
||||
add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name,
|
||||
DEPSOP_TYPE_POST, function_bind(BKE_pose_bone_done, _1, pchan),
|
||||
DEG_OPCODE_BONE_DONE);
|
||||
|
||||
/* constraints */
|
||||
if (pchan->constraints.first != NULL) {
|
||||
build_pose_constraints(ob, pchan);
|
||||
}
|
||||
|
||||
/**
|
||||
* IK Solvers...
|
||||
*
|
||||
* - These require separate processing steps are pose-level
|
||||
* to be executed between chains of bones (i.e. once the
|
||||
* base transforms of a bunch of bones is done)
|
||||
*
|
||||
* Unsolved Issues:
|
||||
* - Care is needed to ensure that multi-headed trees work out the same as in ik-tree building
|
||||
* - Animated chain-lengths are a problem...
|
||||
*/
|
||||
LINKLIST_FOREACH (bConstraint *, con, &pchan->constraints) {
|
||||
switch (con->type) {
|
||||
case CONSTRAINT_TYPE_KINEMATIC:
|
||||
build_ik_pose(scene, ob, pchan, con);
|
||||
break;
|
||||
|
||||
case CONSTRAINT_TYPE_SPLINEIK:
|
||||
build_splineik_pose(scene, ob, pchan, con);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DepsgraphNodeBuilder::build_proxy_rig(Object *ob)
|
||||
{
|
||||
ID *obdata = (ID *)ob->data;
|
||||
build_animdata(obdata);
|
||||
|
||||
BLI_assert(ob->pose != NULL);
|
||||
|
||||
/* speed optimization for animation lookups */
|
||||
BKE_pose_channels_hash_make(ob->pose);
|
||||
if (ob->pose->flag & POSE_CONSTRAINTS_NEED_UPDATE_FLAGS) {
|
||||
BKE_pose_update_constraint_flags(ob->pose);
|
||||
}
|
||||
|
||||
add_operation_node(&ob->id,
|
||||
DEPSNODE_TYPE_EVAL_POSE,
|
||||
DEPSOP_TYPE_INIT,
|
||||
function_bind(BKE_pose_eval_proxy_copy, _1, ob),
|
||||
DEG_OPCODE_POSE_INIT);
|
||||
|
||||
LINKLIST_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) {
|
||||
add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name,
|
||||
DEPSOP_TYPE_INIT, NULL,
|
||||
DEG_OPCODE_BONE_LOCAL);
|
||||
|
||||
add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name,
|
||||
DEPSOP_TYPE_EXEC, NULL,
|
||||
DEG_OPCODE_BONE_READY);
|
||||
|
||||
add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name,
|
||||
DEPSOP_TYPE_POST, NULL,
|
||||
DEG_OPCODE_BONE_DONE);
|
||||
}
|
||||
|
||||
add_operation_node(&ob->id,
|
||||
DEPSNODE_TYPE_EVAL_POSE,
|
||||
DEPSOP_TYPE_POST,
|
||||
NULL,
|
||||
DEG_OPCODE_POSE_DONE);
|
||||
}
|
||||
|
||||
} // namespace DEG
|
|
@ -0,0 +1,159 @@
|
|||
/*
|
||||
* ***** BEGIN GPL LICENSE BLOCK *****
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* The Original Code is Copyright (C) 2013 Blender Foundation.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Original Author: Joshua Leung
|
||||
* Contributor(s): Based on original depsgraph.c code - Blender Foundation (2005-2013)
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
/** \file blender/depsgraph/intern/builder/deg_builder_nodes_scene.cc
|
||||
* \ingroup depsgraph
|
||||
*
|
||||
* Methods for constructing depsgraph's nodes
|
||||
*/
|
||||
|
||||
#include "intern/builder/deg_builder_nodes.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
extern "C" {
|
||||
#include "BLI_blenlib.h"
|
||||
#include "BLI_string.h"
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
#include "DNA_node_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
#include "DNA_scene_types.h"
|
||||
|
||||
#include "BKE_main.h"
|
||||
#include "BKE_node.h"
|
||||
|
||||
#include "DEG_depsgraph.h"
|
||||
#include "DEG_depsgraph_build.h"
|
||||
} /* extern "C" */
|
||||
|
||||
#include "intern/builder/deg_builder.h"
|
||||
#include "intern/nodes/deg_node.h"
|
||||
#include "intern/nodes/deg_node_component.h"
|
||||
#include "intern/nodes/deg_node_operation.h"
|
||||
#include "intern/depsgraph_types.h"
|
||||
#include "intern/depsgraph_intern.h"
|
||||
#include "util/deg_util_foreach.h"
|
||||
|
||||
namespace DEG {
|
||||
|
||||
void DepsgraphNodeBuilder::build_scene(Main *bmain, Scene *scene)
|
||||
{
|
||||
/* LIB_TAG_DOIT is used to indicate whether node for given ID was already
|
||||
* created or not. This flag is being set in add_id_node(), so functions
|
||||
* shouldn't bother with setting it, they only might query this flag when
|
||||
* needed.
|
||||
*/
|
||||
BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
|
||||
/* XXX nested node trees are not included in tag-clearing above,
|
||||
* so we need to do this manually.
|
||||
*/
|
||||
FOREACH_NODETREE(bmain, nodetree, id) {
|
||||
if (id != (ID *)nodetree)
|
||||
nodetree->id.tag &= ~LIB_TAG_DOIT;
|
||||
} FOREACH_NODETREE_END
|
||||
|
||||
/* scene ID block */
|
||||
add_id_node(&scene->id);
|
||||
|
||||
/* timesource */
|
||||
add_time_source(NULL);
|
||||
|
||||
/* build subgraph for set, and link this in... */
|
||||
// XXX: depending on how this goes, that scene itself could probably store its
|
||||
// own little partial depsgraph?
|
||||
if (scene->set) {
|
||||
build_scene(bmain, scene->set);
|
||||
}
|
||||
|
||||
/* scene objects */
|
||||
LINKLIST_FOREACH (Base *, base, &scene->base) {
|
||||
Object *ob = base->object;
|
||||
|
||||
/* object itself */
|
||||
build_object(scene, base, ob);
|
||||
|
||||
/* object that this is a proxy for */
|
||||
// XXX: the way that proxies work needs to be completely reviewed!
|
||||
if (ob->proxy) {
|
||||
ob->proxy->proxy_from = ob;
|
||||
build_object(scene, base, ob->proxy);
|
||||
}
|
||||
|
||||
/* Object dupligroup. */
|
||||
if (ob->dup_group) {
|
||||
build_group(scene, base, ob->dup_group);
|
||||
}
|
||||
}
|
||||
|
||||
/* rigidbody */
|
||||
if (scene->rigidbody_world) {
|
||||
build_rigidbody(scene);
|
||||
}
|
||||
|
||||
/* scene's animation and drivers */
|
||||
if (scene->adt) {
|
||||
build_animdata(&scene->id);
|
||||
}
|
||||
|
||||
/* world */
|
||||
if (scene->world) {
|
||||
build_world(scene->world);
|
||||
}
|
||||
|
||||
/* compo nodes */
|
||||
if (scene->nodetree) {
|
||||
build_compositor(scene);
|
||||
}
|
||||
|
||||
/* sequencer */
|
||||
// XXX...
|
||||
|
||||
/* grease pencil */
|
||||
if (scene->gpd) {
|
||||
build_gpencil(scene->gpd);
|
||||
}
|
||||
|
||||
/* Cache file. */
|
||||
LINKLIST_FOREACH (CacheFile *, cachefile, &bmain->cachefiles) {
|
||||
build_cachefile(cachefile);
|
||||
}
|
||||
|
||||
/* Masks. */
|
||||
LINKLIST_FOREACH (Mask *, mask, &bmain->mask) {
|
||||
build_mask(mask);
|
||||
}
|
||||
|
||||
/* Movie clips. */
|
||||
LINKLIST_FOREACH (MovieClip *, clip, &bmain->movieclip) {
|
||||
build_movieclip(clip);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace DEG
|
|
@ -55,8 +55,10 @@ extern "C" {
|
|||
#include "DNA_key_types.h"
|
||||
#include "DNA_lamp_types.h"
|
||||
#include "DNA_material_types.h"
|
||||
#include "DNA_mask_types.h"
|
||||
#include "DNA_mesh_types.h"
|
||||
#include "DNA_meta_types.h"
|
||||
#include "DNA_movieclip_types.h"
|
||||
#include "DNA_node_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
#include "DNA_rigidbody_types.h"
|
||||
|
@ -320,88 +322,6 @@ void DepsgraphRelationBuilder::add_forcefield_relations(const OperationKey &key,
|
|||
|
||||
/* **** Functions to build relations between entities **** */
|
||||
|
||||
void DepsgraphRelationBuilder::build_scene(Main *bmain, Scene *scene)
|
||||
{
|
||||
/* LIB_TAG_DOIT is used to indicate whether node for given ID was already
|
||||
* created or not.
|
||||
*/
|
||||
BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
|
||||
/* XXX nested node trees are not included in tag-clearing above,
|
||||
* so we need to do this manually.
|
||||
*/
|
||||
FOREACH_NODETREE(bmain, nodetree, id) {
|
||||
if (id != (ID *)nodetree)
|
||||
nodetree->id.tag &= ~LIB_TAG_DOIT;
|
||||
} FOREACH_NODETREE_END
|
||||
|
||||
if (scene->set) {
|
||||
// TODO: link set to scene, especially our timesource...
|
||||
}
|
||||
|
||||
/* scene objects */
|
||||
for (Base *base = (Base *)scene->base.first; base; base = base->next) {
|
||||
Object *ob = base->object;
|
||||
|
||||
/* object itself */
|
||||
build_object(bmain, scene, ob);
|
||||
|
||||
/* object that this is a proxy for */
|
||||
if (ob->proxy) {
|
||||
ob->proxy->proxy_from = ob;
|
||||
build_object(bmain, scene, ob->proxy);
|
||||
/* TODO(sergey): This is an inverted relation, matches old depsgraph
|
||||
* behavior and need to be investigated if it still need to be inverted.
|
||||
*/
|
||||
ComponentKey ob_pose_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE);
|
||||
ComponentKey proxy_pose_key(&ob->proxy->id, DEPSNODE_TYPE_EVAL_POSE);
|
||||
add_relation(ob_pose_key, proxy_pose_key, DEPSREL_TYPE_TRANSFORM, "Proxy");
|
||||
}
|
||||
|
||||
/* Object dupligroup. */
|
||||
if (ob->dup_group) {
|
||||
build_group(bmain, scene, ob, ob->dup_group);
|
||||
}
|
||||
}
|
||||
|
||||
/* rigidbody */
|
||||
if (scene->rigidbody_world) {
|
||||
build_rigidbody(scene);
|
||||
}
|
||||
|
||||
/* scene's animation and drivers */
|
||||
if (scene->adt) {
|
||||
build_animdata(&scene->id);
|
||||
}
|
||||
|
||||
/* world */
|
||||
if (scene->world) {
|
||||
build_world(scene->world);
|
||||
}
|
||||
|
||||
/* compo nodes */
|
||||
if (scene->nodetree) {
|
||||
build_compositor(scene);
|
||||
}
|
||||
|
||||
/* grease pencil */
|
||||
if (scene->gpd) {
|
||||
build_gpencil(&scene->id, scene->gpd);
|
||||
}
|
||||
|
||||
for (Depsgraph::OperationNodes::const_iterator it_op = m_graph->operations.begin();
|
||||
it_op != m_graph->operations.end();
|
||||
++it_op)
|
||||
{
|
||||
OperationDepsNode *node = *it_op;
|
||||
IDDepsNode *id_node = node->owner->owner;
|
||||
ID *id = id_node->id;
|
||||
if (GS(id->name) == ID_OB) {
|
||||
Object *object = (Object *)id;
|
||||
object->customdata_mask |= node->customdata_mask;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DepsgraphRelationBuilder::build_group(Main *bmain,
|
||||
Scene *scene,
|
||||
Object *object,
|
||||
|
@ -412,10 +332,7 @@ void DepsgraphRelationBuilder::build_group(Main *bmain,
|
|||
OperationKey object_local_transform_key(&object->id,
|
||||
DEPSNODE_TYPE_TRANSFORM,
|
||||
DEG_OPCODE_TRANSFORM_LOCAL);
|
||||
for (GroupObject *go = (GroupObject *)group->gobject.first;
|
||||
go != NULL;
|
||||
go = go->next)
|
||||
{
|
||||
LINKLIST_FOREACH (GroupObject *, go, &group->gobject) {
|
||||
if (!group_done) {
|
||||
build_object(bmain, scene, go->ob);
|
||||
}
|
||||
|
@ -687,9 +604,10 @@ void DepsgraphRelationBuilder::build_constraints(Scene *scene, ID *id, eDepsNode
|
|||
ListBase targets = {NULL, NULL};
|
||||
cti->get_constraint_targets(con, &targets);
|
||||
|
||||
for (bConstraintTarget *ct = (bConstraintTarget *)targets.first; ct; ct = ct->next) {
|
||||
if (!ct->tar)
|
||||
LINKLIST_FOREACH (bConstraintTarget *, ct, &targets) {
|
||||
if (ct->tar == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ELEM(con->type, CONSTRAINT_TYPE_KINEMATIC, CONSTRAINT_TYPE_SPLINEIK)) {
|
||||
/* ignore IK constraints - these are handled separately (on pose level) */
|
||||
|
@ -816,7 +734,7 @@ void DepsgraphRelationBuilder::build_animdata(ID *id)
|
|||
}
|
||||
|
||||
/* drivers */
|
||||
for (FCurve *fcu = (FCurve *)adt->drivers.first; fcu; fcu = fcu->next) {
|
||||
LINKLIST_FOREACH (FCurve *, fcu, &adt->drivers) {
|
||||
OperationKey driver_key(id,
|
||||
DEPSNODE_TYPE_PARAMETERS,
|
||||
DEG_OPCODE_DRIVER,
|
||||
|
@ -840,10 +758,7 @@ void DepsgraphRelationBuilder::build_animdata(ID *id)
|
|||
*/
|
||||
if (fcu->array_index > 0) {
|
||||
FCurve *fcu_prev = NULL;
|
||||
for (FCurve *fcu_candidate = (FCurve *)adt->drivers.first;
|
||||
fcu_candidate != NULL;
|
||||
fcu_candidate = fcu_candidate->next)
|
||||
{
|
||||
LINKLIST_FOREACH (FCurve *, fcu_candidate, &adt->drivers) {
|
||||
/* Writing to different RNA paths is */
|
||||
if (!STREQ(fcu_candidate->rna_path, fcu->rna_path)) {
|
||||
continue;
|
||||
|
@ -1007,7 +922,7 @@ void DepsgraphRelationBuilder::build_driver(ID *id, FCurve *fcu)
|
|||
// XXX: the data itself could also set this, if it were to be truly initialised later?
|
||||
|
||||
/* loop over variables to get the target relationships */
|
||||
for (DriverVar *dvar = (DriverVar *)driver->variables.first; dvar; dvar = dvar->next) {
|
||||
LINKLIST_FOREACH (DriverVar *, dvar, &driver->variables) {
|
||||
/* only used targets */
|
||||
DRIVER_TARGETS_USED_LOOPER(dvar)
|
||||
{
|
||||
|
@ -1127,10 +1042,11 @@ void DepsgraphRelationBuilder::build_rigidbody(Scene *scene)
|
|||
|
||||
/* objects - simulation participants */
|
||||
if (rbw->group) {
|
||||
for (GroupObject *go = (GroupObject *)rbw->group->gobject.first; go; go = go->next) {
|
||||
LINKLIST_FOREACH (GroupObject *, go, &rbw->group->gobject) {
|
||||
Object *ob = go->ob;
|
||||
if (!ob || ob->type != OB_MESH)
|
||||
if (ob == NULL || ob->type != OB_MESH) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* hook up evaluation order...
|
||||
* 1) flushing rigidbody results follows base transforms being applied
|
||||
|
@ -1178,10 +1094,11 @@ void DepsgraphRelationBuilder::build_rigidbody(Scene *scene)
|
|||
|
||||
/* constraints */
|
||||
if (rbw->constraints) {
|
||||
for (GroupObject *go = (GroupObject *)rbw->constraints->gobject.first; go; go = go->next) {
|
||||
LINKLIST_FOREACH (GroupObject *, go, &rbw->constraints->gobject) {
|
||||
Object *ob = go->ob;
|
||||
if (!ob || !ob->rigidbody_constraint)
|
||||
if (ob == NULL || !ob->rigidbody_constraint) {
|
||||
continue;
|
||||
}
|
||||
|
||||
RigidBodyCon *rbc = ob->rigidbody_constraint;
|
||||
|
||||
|
@ -1202,391 +1119,6 @@ void DepsgraphRelationBuilder::build_rigidbody(Scene *scene)
|
|||
}
|
||||
}
|
||||
|
||||
/* IK Solver Eval Steps */
|
||||
void DepsgraphRelationBuilder::build_ik_pose(Object *ob,
|
||||
bPoseChannel *pchan,
|
||||
bConstraint *con,
|
||||
RootPChanMap *root_map)
|
||||
{
|
||||
bKinematicConstraint *data = (bKinematicConstraint *)con->data;
|
||||
|
||||
/* attach owner to IK Solver too
|
||||
* - assume that owner is always part of chain
|
||||
* - see notes on direction of rel below...
|
||||
*/
|
||||
bPoseChannel *rootchan = BKE_armature_ik_solver_find_root(pchan, data);
|
||||
OperationKey solver_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, rootchan->name, DEG_OPCODE_POSE_IK_SOLVER);
|
||||
|
||||
/* IK target */
|
||||
// XXX: this should get handled as part of the constraint code
|
||||
if (data->tar != NULL) {
|
||||
/* TODO(sergey): For until we'll store partial matricies in the depsgraph,
|
||||
* we create dependency between target object and pose eval component.
|
||||
*
|
||||
* This way we ensuring the whole subtree is updated from scratch without
|
||||
* need of intermediate matricies. This is an overkill, but good enough for
|
||||
* testing IK solver.
|
||||
*/
|
||||
// FIXME: geometry targets...
|
||||
ComponentKey pose_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE);
|
||||
if ((data->tar->type == OB_ARMATURE) && (data->subtarget[0])) {
|
||||
/* TODO(sergey): This is only for until granular update stores intermediate result. */
|
||||
if (data->tar != ob) {
|
||||
/* different armature - can just read the results */
|
||||
ComponentKey target_key(&data->tar->id, DEPSNODE_TYPE_BONE, data->subtarget);
|
||||
add_relation(target_key, pose_key, DEPSREL_TYPE_TRANSFORM, con->name);
|
||||
}
|
||||
else {
|
||||
/* same armature - we'll use the ready state only, just in case this bone is in the chain we're solving */
|
||||
OperationKey target_key(&data->tar->id, DEPSNODE_TYPE_BONE, data->subtarget, DEG_OPCODE_BONE_DONE);
|
||||
add_relation(target_key, solver_key, DEPSREL_TYPE_TRANSFORM, con->name);
|
||||
}
|
||||
}
|
||||
else if (ELEM(data->tar->type, OB_MESH, OB_LATTICE) && (data->subtarget[0])) {
|
||||
/* vertex group target */
|
||||
/* NOTE: for now, we don't need to represent vertex groups separately... */
|
||||
ComponentKey target_key(&data->tar->id, DEPSNODE_TYPE_GEOMETRY);
|
||||
add_relation(target_key, solver_key, DEPSREL_TYPE_GEOMETRY_EVAL, con->name);
|
||||
|
||||
if (data->tar->type == OB_MESH) {
|
||||
OperationDepsNode *node2 = find_operation_node(target_key);
|
||||
if (node2 != NULL) {
|
||||
node2->customdata_mask |= CD_MASK_MDEFORMVERT;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Standard Object Target */
|
||||
ComponentKey target_key(&data->tar->id, DEPSNODE_TYPE_TRANSFORM);
|
||||
add_relation(target_key, pose_key, DEPSREL_TYPE_TRANSFORM, con->name);
|
||||
}
|
||||
|
||||
if ((data->tar == ob) && (data->subtarget[0])) {
|
||||
/* Prevent target's constraints from linking to anything from same
|
||||
* chain that it controls.
|
||||
*/
|
||||
root_map->add_bone(data->subtarget, rootchan->name);
|
||||
}
|
||||
}
|
||||
|
||||
/* Pole Target */
|
||||
// XXX: this should get handled as part of the constraint code
|
||||
if (data->poletar != NULL) {
|
||||
if ((data->poletar->type == OB_ARMATURE) && (data->polesubtarget[0])) {
|
||||
// XXX: same armature issues - ready vs done?
|
||||
ComponentKey target_key(&data->poletar->id, DEPSNODE_TYPE_BONE, data->polesubtarget);
|
||||
add_relation(target_key, solver_key, DEPSREL_TYPE_TRANSFORM, con->name);
|
||||
}
|
||||
else if (ELEM(data->poletar->type, OB_MESH, OB_LATTICE) && (data->polesubtarget[0])) {
|
||||
/* vertex group target */
|
||||
/* NOTE: for now, we don't need to represent vertex groups separately... */
|
||||
ComponentKey target_key(&data->poletar->id, DEPSNODE_TYPE_GEOMETRY);
|
||||
add_relation(target_key, solver_key, DEPSREL_TYPE_GEOMETRY_EVAL, con->name);
|
||||
|
||||
if (data->poletar->type == OB_MESH) {
|
||||
OperationDepsNode *node2 = find_operation_node(target_key);
|
||||
if (node2 != NULL) {
|
||||
node2->customdata_mask |= CD_MASK_MDEFORMVERT;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
ComponentKey target_key(&data->poletar->id, DEPSNODE_TYPE_TRANSFORM);
|
||||
add_relation(target_key, solver_key, DEPSREL_TYPE_TRANSFORM, con->name);
|
||||
}
|
||||
}
|
||||
|
||||
DEG_DEBUG_PRINTF("\nStarting IK Build: pchan = %s, target = (%s, %s), segcount = %d\n",
|
||||
pchan->name, data->tar->id.name, data->subtarget, data->rootbone);
|
||||
|
||||
bPoseChannel *parchan = pchan;
|
||||
/* exclude tip from chain? */
|
||||
if (!(data->flag & CONSTRAINT_IK_TIP)) {
|
||||
OperationKey tip_transforms_key(&ob->id, DEPSNODE_TYPE_BONE,
|
||||
parchan->name, DEG_OPCODE_BONE_LOCAL);
|
||||
add_relation(solver_key, tip_transforms_key,
|
||||
DEPSREL_TYPE_TRANSFORM, "IK Solver Result");
|
||||
parchan = pchan->parent;
|
||||
}
|
||||
|
||||
root_map->add_bone(parchan->name, rootchan->name);
|
||||
|
||||
OperationKey parchan_transforms_key(&ob->id, DEPSNODE_TYPE_BONE,
|
||||
parchan->name, DEG_OPCODE_BONE_READY);
|
||||
add_relation(parchan_transforms_key, solver_key,
|
||||
DEPSREL_TYPE_TRANSFORM, "IK Solver Owner");
|
||||
|
||||
/* Walk to the chain's root */
|
||||
//size_t segcount = 0;
|
||||
int segcount = 0;
|
||||
|
||||
while (parchan) {
|
||||
/* Make IK-solver dependent on this bone's result,
|
||||
* since it can only run after the standard results
|
||||
* of the bone are know. Validate links step on the
|
||||
* bone will ensure that users of this bone only
|
||||
* grab the result with IK solver results...
|
||||
*/
|
||||
if (parchan != pchan) {
|
||||
OperationKey parent_key(&ob->id, DEPSNODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_READY);
|
||||
add_relation(parent_key, solver_key, DEPSREL_TYPE_TRANSFORM, "IK Chain Parent");
|
||||
|
||||
OperationKey done_key(&ob->id, DEPSNODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_DONE);
|
||||
add_relation(solver_key, done_key, DEPSREL_TYPE_TRANSFORM, "IK Chain Result");
|
||||
}
|
||||
else {
|
||||
OperationKey final_transforms_key(&ob->id, DEPSNODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_DONE);
|
||||
add_relation(solver_key, final_transforms_key, DEPSREL_TYPE_TRANSFORM, "IK Solver Result");
|
||||
}
|
||||
parchan->flag |= POSE_DONE;
|
||||
|
||||
|
||||
root_map->add_bone(parchan->name, rootchan->name);
|
||||
|
||||
/* continue up chain, until we reach target number of items... */
|
||||
DEG_DEBUG_PRINTF(" %d = %s\n", segcount, parchan->name);
|
||||
segcount++;
|
||||
if ((segcount == data->rootbone) || (segcount > 255)) break; /* 255 is weak */
|
||||
|
||||
parchan = parchan->parent;
|
||||
}
|
||||
|
||||
OperationKey flush_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_DONE);
|
||||
add_relation(solver_key, flush_key, DEPSREL_TYPE_OPERATION, "PoseEval Result-Bone Link");
|
||||
}
|
||||
|
||||
/* Spline IK Eval Steps */
|
||||
void DepsgraphRelationBuilder::build_splineik_pose(Object *ob,
|
||||
bPoseChannel *pchan,
|
||||
bConstraint *con,
|
||||
RootPChanMap *root_map)
|
||||
{
|
||||
bSplineIKConstraint *data = (bSplineIKConstraint *)con->data;
|
||||
bPoseChannel *rootchan = BKE_armature_splineik_solver_find_root(pchan, data);
|
||||
OperationKey transforms_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_READY);
|
||||
OperationKey solver_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, rootchan->name, DEG_OPCODE_POSE_SPLINE_IK_SOLVER);
|
||||
|
||||
/* attach owner to IK Solver too
|
||||
* - assume that owner is always part of chain
|
||||
* - see notes on direction of rel below...
|
||||
*/
|
||||
add_relation(transforms_key, solver_key, DEPSREL_TYPE_TRANSFORM, "Spline IK Solver Owner");
|
||||
|
||||
/* attach path dependency to solver */
|
||||
if (data->tar) {
|
||||
/* TODO(sergey): For until we'll store partial matricies in the depsgraph,
|
||||
* we create dependency between target object and pose eval component.
|
||||
* See IK pose for a bit more information.
|
||||
*/
|
||||
// TODO: the bigggest point here is that we need the curve PATH and not just the general geometry...
|
||||
ComponentKey target_key(&data->tar->id, DEPSNODE_TYPE_GEOMETRY);
|
||||
ComponentKey pose_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE);
|
||||
add_relation(target_key, pose_key, DEPSREL_TYPE_TRANSFORM, "[Curve.Path -> Spline IK] DepsRel");
|
||||
}
|
||||
|
||||
pchan->flag |= POSE_DONE;
|
||||
OperationKey final_transforms_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_DONE);
|
||||
add_relation(solver_key, final_transforms_key, DEPSREL_TYPE_TRANSFORM, "Spline IK Result");
|
||||
|
||||
root_map->add_bone(pchan->name, rootchan->name);
|
||||
|
||||
/* Walk to the chain's root */
|
||||
//size_t segcount = 0;
|
||||
int segcount = 0;
|
||||
|
||||
for (bPoseChannel *parchan = pchan->parent; parchan; parchan = parchan->parent) {
|
||||
/* Make Spline IK solver dependent on this bone's result,
|
||||
* since it can only run after the standard results
|
||||
* of the bone are know. Validate links step on the
|
||||
* bone will ensure that users of this bone only
|
||||
* grab the result with IK solver results...
|
||||
*/
|
||||
if (parchan != pchan) {
|
||||
OperationKey parent_key(&ob->id, DEPSNODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_READY);
|
||||
add_relation(parent_key, solver_key, DEPSREL_TYPE_TRANSFORM, "Spline IK Solver Update");
|
||||
|
||||
OperationKey done_key(&ob->id, DEPSNODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_DONE);
|
||||
add_relation(solver_key, done_key, DEPSREL_TYPE_TRANSFORM, "IK Chain Result");
|
||||
}
|
||||
parchan->flag |= POSE_DONE;
|
||||
|
||||
OperationKey final_transforms_key(&ob->id, DEPSNODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_DONE);
|
||||
add_relation(solver_key, final_transforms_key, DEPSREL_TYPE_TRANSFORM, "Spline IK Solver Result");
|
||||
|
||||
root_map->add_bone(parchan->name, rootchan->name);
|
||||
|
||||
/* continue up chain, until we reach target number of items... */
|
||||
segcount++;
|
||||
if ((segcount == data->chainlen) || (segcount > 255)) break; /* 255 is weak */
|
||||
}
|
||||
|
||||
OperationKey flush_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_DONE);
|
||||
add_relation(solver_key, flush_key, DEPSREL_TYPE_OPERATION, "PoseEval Result-Bone Link");
|
||||
}
|
||||
|
||||
/* Pose/Armature Bones Graph */
|
||||
void DepsgraphRelationBuilder::build_rig(Scene *scene, Object *ob)
|
||||
{
|
||||
/* Armature-Data */
|
||||
bArmature *arm = (bArmature *)ob->data;
|
||||
|
||||
// TODO: selection status?
|
||||
|
||||
/* attach links between pose operations */
|
||||
OperationKey init_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_INIT);
|
||||
OperationKey flush_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_DONE);
|
||||
|
||||
add_relation(init_key, flush_key, DEPSREL_TYPE_COMPONENT_ORDER, "[Pose Init -> Pose Cleanup]");
|
||||
|
||||
/* Make sure pose is up-to-date with armature updates. */
|
||||
OperationKey armature_key(&arm->id,
|
||||
DEPSNODE_TYPE_PARAMETERS,
|
||||
DEG_OPCODE_PLACEHOLDER,
|
||||
"Armature Eval");
|
||||
add_relation(armature_key, init_key, DEPSREL_TYPE_COMPONENT_ORDER, "Data dependency");
|
||||
|
||||
if (needs_animdata_node(&ob->id)) {
|
||||
ComponentKey animation_key(&ob->id, DEPSNODE_TYPE_ANIMATION);
|
||||
add_relation(animation_key, init_key, DEPSREL_TYPE_OPERATION, "Rig Animation");
|
||||
}
|
||||
|
||||
/* IK Solvers...
|
||||
* - These require separate processing steps are pose-level
|
||||
* to be executed between chains of bones (i.e. once the
|
||||
* base transforms of a bunch of bones is done)
|
||||
*
|
||||
* - We build relations for these before the dependencies
|
||||
* between ops in the same component as it is necessary
|
||||
* to check whether such bones are in the same IK chain
|
||||
* (or else we get weird issues with either in-chain
|
||||
* references, or with bones being parented to IK'd bones)
|
||||
*
|
||||
* Unsolved Issues:
|
||||
* - Care is needed to ensure that multi-headed trees work out the same as in ik-tree building
|
||||
* - Animated chain-lengths are a problem...
|
||||
*/
|
||||
RootPChanMap root_map;
|
||||
bool pose_depends_on_local_transform = false;
|
||||
for (bPoseChannel *pchan = (bPoseChannel *)ob->pose->chanbase.first; pchan; pchan = pchan->next) {
|
||||
for (bConstraint *con = (bConstraint *)pchan->constraints.first; con; con = con->next) {
|
||||
switch (con->type) {
|
||||
case CONSTRAINT_TYPE_KINEMATIC:
|
||||
build_ik_pose(ob, pchan, con, &root_map);
|
||||
pose_depends_on_local_transform = true;
|
||||
break;
|
||||
|
||||
case CONSTRAINT_TYPE_SPLINEIK:
|
||||
build_splineik_pose(ob, pchan, con, &root_map);
|
||||
pose_depends_on_local_transform = true;
|
||||
break;
|
||||
|
||||
/* Constraints which needs world's matrix for transform.
|
||||
* TODO(sergey): More constraints here?
|
||||
*/
|
||||
case CONSTRAINT_TYPE_ROTLIKE:
|
||||
case CONSTRAINT_TYPE_SIZELIKE:
|
||||
case CONSTRAINT_TYPE_LOCLIKE:
|
||||
case CONSTRAINT_TYPE_TRANSLIKE:
|
||||
/* TODO(sergey): Add used space check. */
|
||||
pose_depends_on_local_transform = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
//root_map.print_debug();
|
||||
|
||||
if (pose_depends_on_local_transform) {
|
||||
/* TODO(sergey): Once partial updates are possible use relation between
|
||||
* object transform and solver itself in it's build function.
|
||||
*/
|
||||
ComponentKey pose_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE);
|
||||
ComponentKey local_transform_key(&ob->id, DEPSNODE_TYPE_TRANSFORM);
|
||||
add_relation(local_transform_key, pose_key, DEPSREL_TYPE_TRANSFORM, "Local Transforms");
|
||||
}
|
||||
|
||||
|
||||
/* links between operations for each bone */
|
||||
for (bPoseChannel *pchan = (bPoseChannel *)ob->pose->chanbase.first; pchan; pchan = pchan->next) {
|
||||
OperationKey bone_local_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_LOCAL);
|
||||
OperationKey bone_pose_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_POSE_PARENT);
|
||||
OperationKey bone_ready_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_READY);
|
||||
OperationKey bone_done_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_DONE);
|
||||
|
||||
pchan->flag &= ~POSE_DONE;
|
||||
|
||||
/* pose init to bone local */
|
||||
add_relation(init_key, bone_local_key, DEPSREL_TYPE_OPERATION, "PoseEval Source-Bone Link");
|
||||
|
||||
/* local to pose parenting operation */
|
||||
add_relation(bone_local_key, bone_pose_key, DEPSREL_TYPE_OPERATION, "Bone Local - PoseSpace Link");
|
||||
|
||||
/* parent relation */
|
||||
if (pchan->parent != NULL) {
|
||||
eDepsOperation_Code parent_key_opcode;
|
||||
|
||||
/* NOTE: this difference in handling allows us to prevent lockups while ensuring correct poses for separate chains */
|
||||
if (root_map.has_common_root(pchan->name, pchan->parent->name)) {
|
||||
parent_key_opcode = DEG_OPCODE_BONE_READY;
|
||||
}
|
||||
else {
|
||||
parent_key_opcode = DEG_OPCODE_BONE_DONE;
|
||||
}
|
||||
|
||||
OperationKey parent_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->parent->name, parent_key_opcode);
|
||||
add_relation(parent_key, bone_pose_key, DEPSREL_TYPE_TRANSFORM, "[Parent Bone -> Child Bone]");
|
||||
}
|
||||
|
||||
/* constraints */
|
||||
if (pchan->constraints.first != NULL) {
|
||||
/* constraints stack and constraint dependencies */
|
||||
build_constraints(scene, &ob->id, DEPSNODE_TYPE_BONE, pchan->name, &pchan->constraints, &root_map);
|
||||
|
||||
/* pose -> constraints */
|
||||
OperationKey constraints_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_CONSTRAINTS);
|
||||
add_relation(bone_pose_key, constraints_key, DEPSREL_TYPE_OPERATION, "Constraints Stack");
|
||||
|
||||
/* constraints -> ready */
|
||||
// TODO: when constraint stack is exploded, this step should occur before the first IK solver
|
||||
add_relation(constraints_key, bone_ready_key, DEPSREL_TYPE_OPERATION, "Constraints -> Ready");
|
||||
}
|
||||
else {
|
||||
/* pose -> ready */
|
||||
add_relation(bone_pose_key, bone_ready_key, DEPSREL_TYPE_OPERATION, "Pose -> Ready");
|
||||
}
|
||||
|
||||
/* bone ready -> done
|
||||
* NOTE: For bones without IK, this is all that's needed.
|
||||
* For IK chains however, an additional rel is created from IK to done,
|
||||
* with transitive reduction removing this one...
|
||||
*/
|
||||
add_relation(bone_ready_key, bone_done_key, DEPSREL_TYPE_OPERATION, "Ready -> Done");
|
||||
|
||||
/* assume that all bones must be done for the pose to be ready (for deformers) */
|
||||
add_relation(bone_done_key, flush_key, DEPSREL_TYPE_OPERATION, "PoseEval Result-Bone Link");
|
||||
}
|
||||
}
|
||||
|
||||
void DepsgraphRelationBuilder::build_proxy_rig(Object *ob)
|
||||
{
|
||||
OperationKey pose_init_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_INIT);
|
||||
OperationKey pose_done_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_DONE);
|
||||
for (bPoseChannel *pchan = (bPoseChannel *)ob->pose->chanbase.first;
|
||||
pchan != NULL;
|
||||
pchan = pchan->next)
|
||||
{
|
||||
OperationKey bone_local_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_LOCAL);
|
||||
OperationKey bone_ready_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_READY);
|
||||
OperationKey bone_done_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_DONE);
|
||||
add_relation(pose_init_key, bone_local_key, DEPSREL_TYPE_OPERATION, "Pose Init -> Bone Local");
|
||||
add_relation(bone_local_key, bone_ready_key, DEPSREL_TYPE_OPERATION, "Local -> Ready");
|
||||
add_relation(bone_ready_key, bone_done_key, DEPSREL_TYPE_OPERATION, "Ready -> Done");
|
||||
add_relation(bone_done_key, pose_done_key, DEPSREL_TYPE_OPERATION, "Bone Done -> Pose Done");
|
||||
}
|
||||
}
|
||||
|
||||
/* Shapekeys */
|
||||
void DepsgraphRelationBuilder::build_shapekeys(ID *obdata, Key *key)
|
||||
{
|
||||
|
@ -1647,10 +1179,9 @@ void DepsgraphRelationBuilder::build_obdata_geom(Main *bmain, Scene *scene, Obje
|
|||
|
||||
/* Modifiers */
|
||||
if (ob->modifiers.first) {
|
||||
ModifierData *md;
|
||||
OperationKey prev_mod_key;
|
||||
|
||||
for (md = (ModifierData *)ob->modifiers.first; md; md = md->next) {
|
||||
LINKLIST_FOREACH (ModifierData *, md, &ob->modifiers) {
|
||||
const ModifierTypeInfo *mti = modifierType_getInfo((ModifierType)md->type);
|
||||
OperationKey mod_key(&ob->id, DEPSNODE_TYPE_GEOMETRY, DEG_OPCODE_GEOMETRY_MODIFIER, md->name);
|
||||
|
||||
|
@ -1885,7 +1416,7 @@ void DepsgraphRelationBuilder::build_nodetree(ID *owner, bNodeTree *ntree)
|
|||
"Parameters Eval");
|
||||
|
||||
/* nodetree's nodes... */
|
||||
for (bNode *bnode = (bNode *)ntree->nodes.first; bnode; bnode = bnode->next) {
|
||||
LINKLIST_FOREACH (bNode *, bnode, &ntree->nodes) {
|
||||
if (bnode->id) {
|
||||
if (GS(bnode->id->name) == ID_MA) {
|
||||
build_material(owner, (Material *)bnode->id);
|
||||
|
@ -1989,4 +1520,21 @@ bool DepsgraphRelationBuilder::needs_animdata_node(ID *id)
|
|||
return false;
|
||||
}
|
||||
|
||||
void DepsgraphRelationBuilder::build_cachefile(CacheFile *cache_file) {
|
||||
/* Animation. */
|
||||
build_animdata(&cache_file->id);
|
||||
}
|
||||
|
||||
void DepsgraphRelationBuilder::build_mask(Mask *mask)
|
||||
{
|
||||
/* Animation. */
|
||||
build_animdata(&mask->id);
|
||||
}
|
||||
|
||||
void DepsgraphRelationBuilder::build_movieclip(MovieClip *clip)
|
||||
{
|
||||
/* Animation. */
|
||||
build_animdata(&clip->id);
|
||||
}
|
||||
|
||||
} // namespace DEG
|
||||
|
|
|
@ -47,6 +47,7 @@
|
|||
|
||||
struct Base;
|
||||
struct bGPdata;
|
||||
struct CacheFile;
|
||||
struct ListBase;
|
||||
struct GHash;
|
||||
struct ID;
|
||||
|
@ -54,8 +55,10 @@ struct FCurve;
|
|||
struct Group;
|
||||
struct Key;
|
||||
struct Main;
|
||||
struct Mask;
|
||||
struct Material;
|
||||
struct MTex;
|
||||
struct MovieClip;
|
||||
struct bNodeTree;
|
||||
struct Object;
|
||||
struct bPoseChannel;
|
||||
|
@ -220,6 +223,9 @@ struct DepsgraphRelationBuilder
|
|||
void build_texture_stack(ID *owner, MTex **texture_stack);
|
||||
void build_compositor(Scene *scene);
|
||||
void build_gpencil(ID *owner, bGPdata *gpd);
|
||||
void build_cachefile(CacheFile *cache_file);
|
||||
void build_mask(Mask *mask);
|
||||
void build_movieclip(MovieClip *clip);
|
||||
|
||||
void add_collision_relations(const OperationKey &key, Scene *scene, Object *ob, Group *group, int layer, bool dupli, const char *name);
|
||||
void add_forcefield_relations(const OperationKey &key, Scene *scene, Object *ob, EffectorWeights *eff, bool add_absorption, const char *name);
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
/** \file blender/depsgraph/intern/builder/deg_builder_relations.cc
|
||||
/** \file blender/depsgraph/intern/builder/deg_builder_relations_keys.cc
|
||||
* \ingroup depsgraph
|
||||
*
|
||||
* Methods for constructing depsgraph
|
||||
|
|
|
@ -0,0 +1,455 @@
|
|||
/*
|
||||
* ***** BEGIN GPL LICENSE BLOCK *****
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* The Original Code is Copyright (C) 2013 Blender Foundation.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Original Author: Joshua Leung
|
||||
* Contributor(s): Based on original depsgraph.c code - Blender Foundation (2005-2013)
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
/** \file blender/depsgraph/intern/builder/deg_builder_relations_rig.cc
|
||||
* \ingroup depsgraph
|
||||
*
|
||||
* Methods for constructing depsgraph
|
||||
*/
|
||||
|
||||
#include "intern/builder/deg_builder_relations.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <cstring> /* required for STREQ later on. */
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
extern "C" {
|
||||
#include "BLI_blenlib.h"
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
#include "DNA_action_types.h"
|
||||
#include "DNA_anim_types.h"
|
||||
#include "DNA_armature_types.h"
|
||||
#include "DNA_constraint_types.h"
|
||||
#include "DNA_customdata_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
|
||||
#include "BKE_action.h"
|
||||
#include "BKE_armature.h"
|
||||
|
||||
#include "DEG_depsgraph.h"
|
||||
#include "DEG_depsgraph_build.h"
|
||||
} /* extern "C" */
|
||||
|
||||
#include "intern/builder/deg_builder.h"
|
||||
#include "intern/builder/deg_builder_pchanmap.h"
|
||||
|
||||
#include "intern/nodes/deg_node.h"
|
||||
#include "intern/nodes/deg_node_component.h"
|
||||
#include "intern/nodes/deg_node_operation.h"
|
||||
|
||||
#include "intern/depsgraph_intern.h"
|
||||
#include "intern/depsgraph_types.h"
|
||||
|
||||
#include "util/deg_util_foreach.h"
|
||||
|
||||
namespace DEG {
|
||||
|
||||
/* IK Solver Eval Steps */
|
||||
void DepsgraphRelationBuilder::build_ik_pose(Object *ob,
|
||||
bPoseChannel *pchan,
|
||||
bConstraint *con,
|
||||
RootPChanMap *root_map)
|
||||
{
|
||||
bKinematicConstraint *data = (bKinematicConstraint *)con->data;
|
||||
|
||||
/* attach owner to IK Solver too
|
||||
* - assume that owner is always part of chain
|
||||
* - see notes on direction of rel below...
|
||||
*/
|
||||
bPoseChannel *rootchan = BKE_armature_ik_solver_find_root(pchan, data);
|
||||
OperationKey solver_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, rootchan->name, DEG_OPCODE_POSE_IK_SOLVER);
|
||||
|
||||
/* IK target */
|
||||
// XXX: this should get handled as part of the constraint code
|
||||
if (data->tar != NULL) {
|
||||
/* TODO(sergey): For until we'll store partial matricies in the depsgraph,
|
||||
* we create dependency between target object and pose eval component.
|
||||
*
|
||||
* This way we ensuring the whole subtree is updated from scratch without
|
||||
* need of intermediate matricies. This is an overkill, but good enough for
|
||||
* testing IK solver.
|
||||
*/
|
||||
// FIXME: geometry targets...
|
||||
ComponentKey pose_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE);
|
||||
if ((data->tar->type == OB_ARMATURE) && (data->subtarget[0])) {
|
||||
/* TODO(sergey): This is only for until granular update stores intermediate result. */
|
||||
if (data->tar != ob) {
|
||||
/* different armature - can just read the results */
|
||||
ComponentKey target_key(&data->tar->id, DEPSNODE_TYPE_BONE, data->subtarget);
|
||||
add_relation(target_key, pose_key, DEPSREL_TYPE_TRANSFORM, con->name);
|
||||
}
|
||||
else {
|
||||
/* same armature - we'll use the ready state only, just in case this bone is in the chain we're solving */
|
||||
OperationKey target_key(&data->tar->id, DEPSNODE_TYPE_BONE, data->subtarget, DEG_OPCODE_BONE_DONE);
|
||||
add_relation(target_key, solver_key, DEPSREL_TYPE_TRANSFORM, con->name);
|
||||
}
|
||||
}
|
||||
else if (ELEM(data->tar->type, OB_MESH, OB_LATTICE) && (data->subtarget[0])) {
|
||||
/* vertex group target */
|
||||
/* NOTE: for now, we don't need to represent vertex groups separately... */
|
||||
ComponentKey target_key(&data->tar->id, DEPSNODE_TYPE_GEOMETRY);
|
||||
add_relation(target_key, solver_key, DEPSREL_TYPE_GEOMETRY_EVAL, con->name);
|
||||
|
||||
if (data->tar->type == OB_MESH) {
|
||||
OperationDepsNode *node2 = find_operation_node(target_key);
|
||||
if (node2 != NULL) {
|
||||
node2->customdata_mask |= CD_MASK_MDEFORMVERT;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Standard Object Target */
|
||||
ComponentKey target_key(&data->tar->id, DEPSNODE_TYPE_TRANSFORM);
|
||||
add_relation(target_key, pose_key, DEPSREL_TYPE_TRANSFORM, con->name);
|
||||
}
|
||||
|
||||
if ((data->tar == ob) && (data->subtarget[0])) {
|
||||
/* Prevent target's constraints from linking to anything from same
|
||||
* chain that it controls.
|
||||
*/
|
||||
root_map->add_bone(data->subtarget, rootchan->name);
|
||||
}
|
||||
}
|
||||
|
||||
/* Pole Target */
|
||||
// XXX: this should get handled as part of the constraint code
|
||||
if (data->poletar != NULL) {
|
||||
if ((data->poletar->type == OB_ARMATURE) && (data->polesubtarget[0])) {
|
||||
// XXX: same armature issues - ready vs done?
|
||||
ComponentKey target_key(&data->poletar->id, DEPSNODE_TYPE_BONE, data->polesubtarget);
|
||||
add_relation(target_key, solver_key, DEPSREL_TYPE_TRANSFORM, con->name);
|
||||
}
|
||||
else if (ELEM(data->poletar->type, OB_MESH, OB_LATTICE) && (data->polesubtarget[0])) {
|
||||
/* vertex group target */
|
||||
/* NOTE: for now, we don't need to represent vertex groups separately... */
|
||||
ComponentKey target_key(&data->poletar->id, DEPSNODE_TYPE_GEOMETRY);
|
||||
add_relation(target_key, solver_key, DEPSREL_TYPE_GEOMETRY_EVAL, con->name);
|
||||
|
||||
if (data->poletar->type == OB_MESH) {
|
||||
OperationDepsNode *node2 = find_operation_node(target_key);
|
||||
if (node2 != NULL) {
|
||||
node2->customdata_mask |= CD_MASK_MDEFORMVERT;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
ComponentKey target_key(&data->poletar->id, DEPSNODE_TYPE_TRANSFORM);
|
||||
add_relation(target_key, solver_key, DEPSREL_TYPE_TRANSFORM, con->name);
|
||||
}
|
||||
}
|
||||
|
||||
DEG_DEBUG_PRINTF("\nStarting IK Build: pchan = %s, target = (%s, %s), segcount = %d\n",
|
||||
pchan->name, data->tar->id.name, data->subtarget, data->rootbone);
|
||||
|
||||
bPoseChannel *parchan = pchan;
|
||||
/* exclude tip from chain? */
|
||||
if (!(data->flag & CONSTRAINT_IK_TIP)) {
|
||||
OperationKey tip_transforms_key(&ob->id, DEPSNODE_TYPE_BONE,
|
||||
parchan->name, DEG_OPCODE_BONE_LOCAL);
|
||||
add_relation(solver_key, tip_transforms_key,
|
||||
DEPSREL_TYPE_TRANSFORM, "IK Solver Result");
|
||||
parchan = pchan->parent;
|
||||
}
|
||||
|
||||
root_map->add_bone(parchan->name, rootchan->name);
|
||||
|
||||
OperationKey parchan_transforms_key(&ob->id, DEPSNODE_TYPE_BONE,
|
||||
parchan->name, DEG_OPCODE_BONE_READY);
|
||||
add_relation(parchan_transforms_key, solver_key,
|
||||
DEPSREL_TYPE_TRANSFORM, "IK Solver Owner");
|
||||
|
||||
/* Walk to the chain's root */
|
||||
//size_t segcount = 0;
|
||||
int segcount = 0;
|
||||
|
||||
while (parchan) {
|
||||
/* Make IK-solver dependent on this bone's result,
|
||||
* since it can only run after the standard results
|
||||
* of the bone are know. Validate links step on the
|
||||
* bone will ensure that users of this bone only
|
||||
* grab the result with IK solver results...
|
||||
*/
|
||||
if (parchan != pchan) {
|
||||
OperationKey parent_key(&ob->id, DEPSNODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_READY);
|
||||
add_relation(parent_key, solver_key, DEPSREL_TYPE_TRANSFORM, "IK Chain Parent");
|
||||
|
||||
OperationKey done_key(&ob->id, DEPSNODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_DONE);
|
||||
add_relation(solver_key, done_key, DEPSREL_TYPE_TRANSFORM, "IK Chain Result");
|
||||
}
|
||||
else {
|
||||
OperationKey final_transforms_key(&ob->id, DEPSNODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_DONE);
|
||||
add_relation(solver_key, final_transforms_key, DEPSREL_TYPE_TRANSFORM, "IK Solver Result");
|
||||
}
|
||||
parchan->flag |= POSE_DONE;
|
||||
|
||||
|
||||
root_map->add_bone(parchan->name, rootchan->name);
|
||||
|
||||
/* continue up chain, until we reach target number of items... */
|
||||
DEG_DEBUG_PRINTF(" %d = %s\n", segcount, parchan->name);
|
||||
segcount++;
|
||||
if ((segcount == data->rootbone) || (segcount > 255)) break; /* 255 is weak */
|
||||
|
||||
parchan = parchan->parent;
|
||||
}
|
||||
|
||||
OperationKey flush_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_DONE);
|
||||
add_relation(solver_key, flush_key, DEPSREL_TYPE_OPERATION, "PoseEval Result-Bone Link");
|
||||
}
|
||||
|
||||
/* Spline IK Eval Steps */
|
||||
void DepsgraphRelationBuilder::build_splineik_pose(Object *ob,
|
||||
bPoseChannel *pchan,
|
||||
bConstraint *con,
|
||||
RootPChanMap *root_map)
|
||||
{
|
||||
bSplineIKConstraint *data = (bSplineIKConstraint *)con->data;
|
||||
bPoseChannel *rootchan = BKE_armature_splineik_solver_find_root(pchan, data);
|
||||
OperationKey transforms_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_READY);
|
||||
OperationKey solver_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, rootchan->name, DEG_OPCODE_POSE_SPLINE_IK_SOLVER);
|
||||
|
||||
/* attach owner to IK Solver too
|
||||
* - assume that owner is always part of chain
|
||||
* - see notes on direction of rel below...
|
||||
*/
|
||||
add_relation(transforms_key, solver_key, DEPSREL_TYPE_TRANSFORM, "Spline IK Solver Owner");
|
||||
|
||||
/* attach path dependency to solver */
|
||||
if (data->tar) {
|
||||
/* TODO(sergey): For until we'll store partial matricies in the depsgraph,
|
||||
* we create dependency between target object and pose eval component.
|
||||
* See IK pose for a bit more information.
|
||||
*/
|
||||
// TODO: the bigggest point here is that we need the curve PATH and not just the general geometry...
|
||||
ComponentKey target_key(&data->tar->id, DEPSNODE_TYPE_GEOMETRY);
|
||||
ComponentKey pose_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE);
|
||||
add_relation(target_key, pose_key, DEPSREL_TYPE_TRANSFORM, "[Curve.Path -> Spline IK] DepsRel");
|
||||
}
|
||||
|
||||
pchan->flag |= POSE_DONE;
|
||||
OperationKey final_transforms_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_DONE);
|
||||
add_relation(solver_key, final_transforms_key, DEPSREL_TYPE_TRANSFORM, "Spline IK Result");
|
||||
|
||||
root_map->add_bone(pchan->name, rootchan->name);
|
||||
|
||||
/* Walk to the chain's root */
|
||||
//size_t segcount = 0;
|
||||
int segcount = 0;
|
||||
|
||||
for (bPoseChannel *parchan = pchan->parent; parchan; parchan = parchan->parent) {
|
||||
/* Make Spline IK solver dependent on this bone's result,
|
||||
* since it can only run after the standard results
|
||||
* of the bone are know. Validate links step on the
|
||||
* bone will ensure that users of this bone only
|
||||
* grab the result with IK solver results...
|
||||
*/
|
||||
if (parchan != pchan) {
|
||||
OperationKey parent_key(&ob->id, DEPSNODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_READY);
|
||||
add_relation(parent_key, solver_key, DEPSREL_TYPE_TRANSFORM, "Spline IK Solver Update");
|
||||
|
||||
OperationKey done_key(&ob->id, DEPSNODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_DONE);
|
||||
add_relation(solver_key, done_key, DEPSREL_TYPE_TRANSFORM, "IK Chain Result");
|
||||
}
|
||||
parchan->flag |= POSE_DONE;
|
||||
|
||||
OperationKey final_transforms_key(&ob->id, DEPSNODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_DONE);
|
||||
add_relation(solver_key, final_transforms_key, DEPSREL_TYPE_TRANSFORM, "Spline IK Solver Result");
|
||||
|
||||
root_map->add_bone(parchan->name, rootchan->name);
|
||||
|
||||
/* continue up chain, until we reach target number of items... */
|
||||
segcount++;
|
||||
if ((segcount == data->chainlen) || (segcount > 255)) break; /* 255 is weak */
|
||||
}
|
||||
|
||||
OperationKey flush_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_DONE);
|
||||
add_relation(solver_key, flush_key, DEPSREL_TYPE_OPERATION, "PoseEval Result-Bone Link");
|
||||
}
|
||||
|
||||
/* Pose/Armature Bones Graph */
|
||||
void DepsgraphRelationBuilder::build_rig(Scene *scene, Object *ob)
|
||||
{
|
||||
/* Armature-Data */
|
||||
bArmature *arm = (bArmature *)ob->data;
|
||||
|
||||
// TODO: selection status?
|
||||
|
||||
/* attach links between pose operations */
|
||||
OperationKey init_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_INIT);
|
||||
OperationKey flush_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_DONE);
|
||||
|
||||
add_relation(init_key, flush_key, DEPSREL_TYPE_COMPONENT_ORDER, "[Pose Init -> Pose Cleanup]");
|
||||
|
||||
/* Make sure pose is up-to-date with armature updates. */
|
||||
OperationKey armature_key(&arm->id,
|
||||
DEPSNODE_TYPE_PARAMETERS,
|
||||
DEG_OPCODE_PLACEHOLDER,
|
||||
"Armature Eval");
|
||||
add_relation(armature_key, init_key, DEPSREL_TYPE_COMPONENT_ORDER, "Data dependency");
|
||||
|
||||
if (needs_animdata_node(&ob->id)) {
|
||||
ComponentKey animation_key(&ob->id, DEPSNODE_TYPE_ANIMATION);
|
||||
add_relation(animation_key, init_key, DEPSREL_TYPE_OPERATION, "Rig Animation");
|
||||
}
|
||||
|
||||
/* IK Solvers...
|
||||
* - These require separate processing steps are pose-level
|
||||
* to be executed between chains of bones (i.e. once the
|
||||
* base transforms of a bunch of bones is done)
|
||||
*
|
||||
* - We build relations for these before the dependencies
|
||||
* between ops in the same component as it is necessary
|
||||
* to check whether such bones are in the same IK chain
|
||||
* (or else we get weird issues with either in-chain
|
||||
* references, or with bones being parented to IK'd bones)
|
||||
*
|
||||
* Unsolved Issues:
|
||||
* - Care is needed to ensure that multi-headed trees work out the same as in ik-tree building
|
||||
* - Animated chain-lengths are a problem...
|
||||
*/
|
||||
RootPChanMap root_map;
|
||||
bool pose_depends_on_local_transform = false;
|
||||
LINKLIST_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) {
|
||||
LINKLIST_FOREACH (bConstraint *, con, &pchan->constraints) {
|
||||
switch (con->type) {
|
||||
case CONSTRAINT_TYPE_KINEMATIC:
|
||||
build_ik_pose(ob, pchan, con, &root_map);
|
||||
pose_depends_on_local_transform = true;
|
||||
break;
|
||||
|
||||
case CONSTRAINT_TYPE_SPLINEIK:
|
||||
build_splineik_pose(ob, pchan, con, &root_map);
|
||||
pose_depends_on_local_transform = true;
|
||||
break;
|
||||
|
||||
/* Constraints which needs world's matrix for transform.
|
||||
* TODO(sergey): More constraints here?
|
||||
*/
|
||||
case CONSTRAINT_TYPE_ROTLIKE:
|
||||
case CONSTRAINT_TYPE_SIZELIKE:
|
||||
case CONSTRAINT_TYPE_LOCLIKE:
|
||||
case CONSTRAINT_TYPE_TRANSLIKE:
|
||||
/* TODO(sergey): Add used space check. */
|
||||
pose_depends_on_local_transform = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
//root_map.print_debug();
|
||||
|
||||
if (pose_depends_on_local_transform) {
|
||||
/* TODO(sergey): Once partial updates are possible use relation between
|
||||
* object transform and solver itself in it's build function.
|
||||
*/
|
||||
ComponentKey pose_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE);
|
||||
ComponentKey local_transform_key(&ob->id, DEPSNODE_TYPE_TRANSFORM);
|
||||
add_relation(local_transform_key, pose_key, DEPSREL_TYPE_TRANSFORM, "Local Transforms");
|
||||
}
|
||||
|
||||
|
||||
/* links between operations for each bone */
|
||||
LINKLIST_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) {
|
||||
OperationKey bone_local_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_LOCAL);
|
||||
OperationKey bone_pose_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_POSE_PARENT);
|
||||
OperationKey bone_ready_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_READY);
|
||||
OperationKey bone_done_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_DONE);
|
||||
|
||||
pchan->flag &= ~POSE_DONE;
|
||||
|
||||
/* pose init to bone local */
|
||||
add_relation(init_key, bone_local_key, DEPSREL_TYPE_OPERATION, "PoseEval Source-Bone Link");
|
||||
|
||||
/* local to pose parenting operation */
|
||||
add_relation(bone_local_key, bone_pose_key, DEPSREL_TYPE_OPERATION, "Bone Local - PoseSpace Link");
|
||||
|
||||
/* parent relation */
|
||||
if (pchan->parent != NULL) {
|
||||
eDepsOperation_Code parent_key_opcode;
|
||||
|
||||
/* NOTE: this difference in handling allows us to prevent lockups while ensuring correct poses for separate chains */
|
||||
if (root_map.has_common_root(pchan->name, pchan->parent->name)) {
|
||||
parent_key_opcode = DEG_OPCODE_BONE_READY;
|
||||
}
|
||||
else {
|
||||
parent_key_opcode = DEG_OPCODE_BONE_DONE;
|
||||
}
|
||||
|
||||
OperationKey parent_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->parent->name, parent_key_opcode);
|
||||
add_relation(parent_key, bone_pose_key, DEPSREL_TYPE_TRANSFORM, "[Parent Bone -> Child Bone]");
|
||||
}
|
||||
|
||||
/* constraints */
|
||||
if (pchan->constraints.first != NULL) {
|
||||
/* constraints stack and constraint dependencies */
|
||||
build_constraints(scene, &ob->id, DEPSNODE_TYPE_BONE, pchan->name, &pchan->constraints, &root_map);
|
||||
|
||||
/* pose -> constraints */
|
||||
OperationKey constraints_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_CONSTRAINTS);
|
||||
add_relation(bone_pose_key, constraints_key, DEPSREL_TYPE_OPERATION, "Constraints Stack");
|
||||
|
||||
/* constraints -> ready */
|
||||
// TODO: when constraint stack is exploded, this step should occur before the first IK solver
|
||||
add_relation(constraints_key, bone_ready_key, DEPSREL_TYPE_OPERATION, "Constraints -> Ready");
|
||||
}
|
||||
else {
|
||||
/* pose -> ready */
|
||||
add_relation(bone_pose_key, bone_ready_key, DEPSREL_TYPE_OPERATION, "Pose -> Ready");
|
||||
}
|
||||
|
||||
/* bone ready -> done
|
||||
* NOTE: For bones without IK, this is all that's needed.
|
||||
* For IK chains however, an additional rel is created from IK to done,
|
||||
* with transitive reduction removing this one...
|
||||
*/
|
||||
add_relation(bone_ready_key, bone_done_key, DEPSREL_TYPE_OPERATION, "Ready -> Done");
|
||||
|
||||
/* assume that all bones must be done for the pose to be ready (for deformers) */
|
||||
add_relation(bone_done_key, flush_key, DEPSREL_TYPE_OPERATION, "PoseEval Result-Bone Link");
|
||||
}
|
||||
}
|
||||
|
||||
void DepsgraphRelationBuilder::build_proxy_rig(Object *ob)
|
||||
{
|
||||
OperationKey pose_init_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_INIT);
|
||||
OperationKey pose_done_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_DONE);
|
||||
LINKLIST_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) {
|
||||
OperationKey bone_local_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_LOCAL);
|
||||
OperationKey bone_ready_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_READY);
|
||||
OperationKey bone_done_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_DONE);
|
||||
add_relation(pose_init_key, bone_local_key, DEPSREL_TYPE_OPERATION, "Pose Init -> Bone Local");
|
||||
add_relation(bone_local_key, bone_ready_key, DEPSREL_TYPE_OPERATION, "Local -> Ready");
|
||||
add_relation(bone_ready_key, bone_done_key, DEPSREL_TYPE_OPERATION, "Ready -> Done");
|
||||
add_relation(bone_done_key, pose_done_key, DEPSREL_TYPE_OPERATION, "Bone Done -> Pose Done");
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace DEG
|
|
@ -0,0 +1,162 @@
|
|||
/*
|
||||
* ***** BEGIN GPL LICENSE BLOCK *****
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* The Original Code is Copyright (C) 2013 Blender Foundation.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Original Author: Joshua Leung
|
||||
* Contributor(s): Based on original depsgraph.c code - Blender Foundation (2005-2013)
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
/** \file blender/depsgraph/intern/builder/deg_builder_relations_scene.cc
|
||||
* \ingroup depsgraph
|
||||
*
|
||||
* Methods for constructing depsgraph
|
||||
*/
|
||||
|
||||
#include "intern/builder/deg_builder_relations.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <cstring> /* required for STREQ later on. */
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
extern "C" {
|
||||
#include "BLI_blenlib.h"
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
#include "DNA_node_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
#include "DNA_scene_types.h"
|
||||
|
||||
#include "BKE_main.h"
|
||||
#include "BKE_node.h"
|
||||
|
||||
#include "DEG_depsgraph.h"
|
||||
#include "DEG_depsgraph_build.h"
|
||||
} /* extern "C" */
|
||||
|
||||
#include "intern/builder/deg_builder.h"
|
||||
#include "intern/builder/deg_builder_pchanmap.h"
|
||||
|
||||
#include "intern/nodes/deg_node.h"
|
||||
#include "intern/nodes/deg_node_component.h"
|
||||
#include "intern/nodes/deg_node_operation.h"
|
||||
|
||||
#include "intern/depsgraph_intern.h"
|
||||
#include "intern/depsgraph_types.h"
|
||||
|
||||
#include "util/deg_util_foreach.h"
|
||||
|
||||
namespace DEG {
|
||||
|
||||
void DepsgraphRelationBuilder::build_scene(Main *bmain, Scene *scene)
|
||||
{
|
||||
/* LIB_TAG_DOIT is used to indicate whether node for given ID was already
|
||||
* created or not.
|
||||
*/
|
||||
BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
|
||||
/* XXX nested node trees are not included in tag-clearing above,
|
||||
* so we need to do this manually.
|
||||
*/
|
||||
FOREACH_NODETREE(bmain, nodetree, id) {
|
||||
if (id != (ID *)nodetree)
|
||||
nodetree->id.tag &= ~LIB_TAG_DOIT;
|
||||
} FOREACH_NODETREE_END
|
||||
|
||||
if (scene->set) {
|
||||
// TODO: link set to scene, especially our timesource...
|
||||
}
|
||||
|
||||
/* scene objects */
|
||||
LINKLIST_FOREACH (Base *, base, &scene->base) {
|
||||
Object *ob = base->object;
|
||||
|
||||
/* object itself */
|
||||
build_object(bmain, scene, ob);
|
||||
|
||||
/* object that this is a proxy for */
|
||||
if (ob->proxy) {
|
||||
ob->proxy->proxy_from = ob;
|
||||
build_object(bmain, scene, ob->proxy);
|
||||
/* TODO(sergey): This is an inverted relation, matches old depsgraph
|
||||
* behavior and need to be investigated if it still need to be inverted.
|
||||
*/
|
||||
ComponentKey ob_pose_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE);
|
||||
ComponentKey proxy_pose_key(&ob->proxy->id, DEPSNODE_TYPE_EVAL_POSE);
|
||||
add_relation(ob_pose_key, proxy_pose_key, DEPSREL_TYPE_TRANSFORM, "Proxy");
|
||||
}
|
||||
|
||||
/* Object dupligroup. */
|
||||
if (ob->dup_group) {
|
||||
build_group(bmain, scene, ob, ob->dup_group);
|
||||
}
|
||||
}
|
||||
|
||||
/* rigidbody */
|
||||
if (scene->rigidbody_world) {
|
||||
build_rigidbody(scene);
|
||||
}
|
||||
|
||||
/* scene's animation and drivers */
|
||||
if (scene->adt) {
|
||||
build_animdata(&scene->id);
|
||||
}
|
||||
|
||||
/* world */
|
||||
if (scene->world) {
|
||||
build_world(scene->world);
|
||||
}
|
||||
|
||||
/* compo nodes */
|
||||
if (scene->nodetree) {
|
||||
build_compositor(scene);
|
||||
}
|
||||
|
||||
/* grease pencil */
|
||||
if (scene->gpd) {
|
||||
build_gpencil(&scene->id, scene->gpd);
|
||||
}
|
||||
|
||||
/* Masks. */
|
||||
LINKLIST_FOREACH (Mask *, mask, &bmain->mask) {
|
||||
build_mask(mask);
|
||||
}
|
||||
|
||||
/* Movie clips. */
|
||||
LINKLIST_FOREACH (MovieClip *, clip, &bmain->movieclip) {
|
||||
build_movieclip(clip);
|
||||
}
|
||||
|
||||
for (Depsgraph::OperationNodes::const_iterator it_op = m_graph->operations.begin();
|
||||
it_op != m_graph->operations.end();
|
||||
++it_op)
|
||||
{
|
||||
OperationDepsNode *node = *it_op;
|
||||
IDDepsNode *id_node = node->owner->owner;
|
||||
ID *id = id_node->id;
|
||||
if (GS(id->name) == ID_OB) {
|
||||
Object *object = (Object *)id;
|
||||
object->customdata_mask |= node->customdata_mask;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace DEG
|
|
@ -66,3 +66,8 @@
|
|||
#define GSET_FOREACH_END() \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#define LINKLIST_FOREACH(type, var, list) \
|
||||
for (type var = (type)((list)->first); \
|
||||
var != NULL; \
|
||||
var = (type)(((Link*)(var))->next))
|
||||
|
|
|
@ -99,6 +99,10 @@ void ui_but_anim_flag(uiBut *but, float cfra)
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \a str can be NULL to only perform check if \a but has an expression at all.
|
||||
* \return if button has an expression.
|
||||
*/
|
||||
bool ui_but_anim_expression_get(uiBut *but, char *str, size_t maxlen)
|
||||
{
|
||||
FCurve *fcu;
|
||||
|
@ -111,7 +115,9 @@ bool ui_but_anim_expression_get(uiBut *but, char *str, size_t maxlen)
|
|||
driver = fcu->driver;
|
||||
|
||||
if (driver && driver->type == DRIVER_TYPE_PYTHON) {
|
||||
BLI_strncpy(str, driver->expression, maxlen);
|
||||
if (str) {
|
||||
BLI_strncpy(str, driver->expression, maxlen);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3067,7 +3067,7 @@ static void ui_textedit_begin(bContext *C, uiBut *but, uiHandleButtonData *data)
|
|||
data->str = ui_but_string_get_dynamic(but, &data->maxlen);
|
||||
}
|
||||
|
||||
if (ui_but_is_float(but) && !ui_but_is_unit(but)) {
|
||||
if (ui_but_is_float(but) && !ui_but_is_unit(but) && !ui_but_anim_expression_get(but, NULL, 0)) {
|
||||
BLI_str_rstrip_float_zero(data->str, '\0');
|
||||
}
|
||||
|
||||
|
|
|
@ -552,8 +552,11 @@ static void screen_opengl_render_apply(OGLRender *oglrender)
|
|||
BLI_assert(view_id < oglrender->views_len);
|
||||
RE_SetActiveRenderView(oglrender->re, rv->name);
|
||||
oglrender->view_id = view_id;
|
||||
/* add grease pencil passes */
|
||||
add_gpencil_renderpass(oglrender, rr, rv);
|
||||
/* add grease pencil passes. For sequencer, the render does not include renderpasses
|
||||
* TODO: The sequencer render of grease pencil should be rethought */
|
||||
if (!oglrender->is_sequencer) {
|
||||
add_gpencil_renderpass(oglrender, rr, rv);
|
||||
}
|
||||
/* render composite */
|
||||
screen_opengl_render_doit(oglrender, rr);
|
||||
}
|
||||
|
|
|
@ -1489,7 +1489,8 @@ void paint_2d_bucket_fill(
|
|||
float image_init[2];
|
||||
int minx = ibuf->x, miny = ibuf->y, maxx = 0, maxy = 0;
|
||||
float pixel_color[4];
|
||||
float threshold_sq = br->fill_threshold * br->fill_threshold;
|
||||
/* We are comparing to sum of three squared values (assumed in range [0,1]), so need to multiply... */
|
||||
float threshold_sq = br->fill_threshold * br->fill_threshold * 3;
|
||||
|
||||
UI_view2d_region_to_view(s->v2d, mouse_init[0], mouse_init[1], &image_init[0], &image_init[1]);
|
||||
|
||||
|
|
|
@ -855,6 +855,42 @@ static void node_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID
|
|||
id_us_plus(new_id);
|
||||
}
|
||||
}
|
||||
else if (GS(old_id->name) == ID_NT) {
|
||||
bNodeTreePath *path, *path_next;
|
||||
|
||||
for (path = snode->treepath.first; path; path = path->next) {
|
||||
if ((ID *)path->nodetree == old_id) {
|
||||
path->nodetree = (bNodeTree *)new_id;
|
||||
id_us_min(old_id);
|
||||
id_us_plus(new_id);
|
||||
}
|
||||
if (path == snode->treepath.first) {
|
||||
/* first nodetree in path is same as snode->nodetree */
|
||||
snode->nodetree = path->nodetree;
|
||||
}
|
||||
if (path->nodetree == NULL) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* remaining path entries are invalid, remove */
|
||||
for (; path; path = path_next) {
|
||||
path_next = path->next;
|
||||
|
||||
BLI_remlink(&snode->treepath, path);
|
||||
MEM_freeN(path);
|
||||
}
|
||||
|
||||
/* edittree is just the last in the path,
|
||||
* set this directly since the path may have been shortened above */
|
||||
if (snode->treepath.last) {
|
||||
path = snode->treepath.last;
|
||||
snode->edittree = path->nodetree;
|
||||
}
|
||||
else {
|
||||
snode->edittree = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* only called once, from space/spacetypes.c */
|
||||
|
|
|
@ -972,7 +972,7 @@ void drawaxes(const float viewmat_local[4][4], float size, char drawtype, const
|
|||
|
||||
|
||||
/* Function to draw an Image on an empty Object */
|
||||
static void draw_empty_image(Object *ob, const short dflag, const unsigned char ob_wire_col[4])
|
||||
static void draw_empty_image(Object *ob, const short dflag, const unsigned char ob_wire_col[4], StereoViews sview)
|
||||
{
|
||||
Image *ima = ob->data;
|
||||
|
||||
|
@ -982,13 +982,22 @@ static void draw_empty_image(Object *ob, const short dflag, const unsigned char
|
|||
int bindcode = 0;
|
||||
|
||||
if (ima) {
|
||||
ImageUser iuser = *ob->iuser;
|
||||
|
||||
/* Support multi-view */
|
||||
if (ima && (sview == STEREO_RIGHT_ID)) {
|
||||
iuser.multiview_eye = sview;
|
||||
iuser.flag |= IMA_SHOW_STEREO;
|
||||
BKE_image_multiview_index(ima, &iuser);
|
||||
}
|
||||
|
||||
if (ob_alpha > 0.0f) {
|
||||
bindcode = GPU_verify_image(ima, ob->iuser, GL_TEXTURE_2D, 0, false, false, false);
|
||||
bindcode = GPU_verify_image(ima, &iuser, GL_TEXTURE_2D, 0, false, false, false);
|
||||
/* don't bother drawing the image if alpha = 0 */
|
||||
}
|
||||
|
||||
int w, h;
|
||||
BKE_image_get_size(ima, ob->iuser, &w, &h);
|
||||
BKE_image_get_size(ima, &iuser, &w, &h);
|
||||
width = w;
|
||||
height = h;
|
||||
}
|
||||
|
@ -7685,7 +7694,7 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
|
|||
case OB_EMPTY:
|
||||
if (!render_override) {
|
||||
if (ob->empty_drawtype == OB_EMPTY_IMAGE) {
|
||||
draw_empty_image(ob, dflag, ob_wire_col);
|
||||
draw_empty_image(ob, dflag, ob_wire_col, v3d->multiview_eye);
|
||||
}
|
||||
else {
|
||||
drawaxes(rv3d->viewmatob, ob->empty_drawsize, ob->empty_drawtype, ob_wire_col);
|
||||
|
@ -8420,7 +8429,7 @@ void draw_object_instance(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object
|
|||
case OB_EMPTY:
|
||||
if (ob->empty_drawtype == OB_EMPTY_IMAGE) {
|
||||
/* CONSTCOLOR == no wire outline */
|
||||
draw_empty_image(ob, DRAW_CONSTCOLOR, NULL);
|
||||
draw_empty_image(ob, DRAW_CONSTCOLOR, NULL, v3d->multiview_eye);
|
||||
}
|
||||
else {
|
||||
drawaxes(rv3d->viewmatob, ob->empty_drawsize, ob->empty_drawtype, NULL); /* TODO: use proper color */
|
||||
|
|
|
@ -114,6 +114,10 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
|
|||
mcmd->reader,
|
||||
ob,
|
||||
mcmd->object_path);
|
||||
if (!mcmd->reader) {
|
||||
modifier_setError(md, "Could not create Alembic reader for file %s", cache_file->filepath);
|
||||
return dm;
|
||||
}
|
||||
}
|
||||
|
||||
DerivedMesh *result = ABC_read_mesh(mcmd->reader,
|
||||
|
|
|
@ -178,9 +178,14 @@ void node_group_verify(struct bNodeTree *ntree, struct bNode *node, struct ID *i
|
|||
{
|
||||
/* check inputs and outputs, and remove or insert them */
|
||||
if (id == node->id) {
|
||||
bNodeTree *ngroup = (bNodeTree *)node->id;
|
||||
group_verify_socket_list(ntree, node, &ngroup->inputs, &node->inputs, SOCK_IN);
|
||||
group_verify_socket_list(ntree, node, &ngroup->outputs, &node->outputs, SOCK_OUT);
|
||||
if (id == NULL) {
|
||||
nodeRemoveAllSockets(ntree, node);
|
||||
}
|
||||
else {
|
||||
bNodeTree *ngroup = (bNodeTree *)node->id;
|
||||
group_verify_socket_list(ntree, node, &ngroup->inputs, &node->inputs, SOCK_IN);
|
||||
group_verify_socket_list(ntree, node, &ngroup->outputs, &node->outputs, SOCK_OUT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1144,6 +1144,9 @@ void wm_autosave_timer(const bContext *C, wmWindowManager *wm, wmTimer *UNUSED(w
|
|||
for (handler = win->modalhandlers.first; handler; handler = handler->next) {
|
||||
if (handler->op) {
|
||||
wm->autosavetimer = WM_event_add_timer(wm, NULL, TIMERAUTOSAVE, 10.0);
|
||||
if (G.debug) {
|
||||
printf("Skipping auto-save, modal operator running, retrying in ten seconds...\n");
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -1161,7 +1164,7 @@ void wm_autosave_timer(const bContext *C, wmWindowManager *wm, wmTimer *UNUSED(w
|
|||
|
||||
ED_editors_flush_edits(C, false);
|
||||
|
||||
/* no error reporting to console */
|
||||
/* Error reporting into console */
|
||||
BLO_write_file(CTX_data_main(C), filepath, fileflags, NULL, NULL);
|
||||
}
|
||||
/* do timer after file write, just in case file write takes a long time */
|
||||
|
|
|
@ -714,7 +714,7 @@ elseif(WIN32)
|
|||
|
||||
if(WITH_PYTHON_INSTALL_NUMPY)
|
||||
set(PYTHON_NUMPY_VERSION 1.9)
|
||||
if(MSVC_VERSION EQUAL 1900)
|
||||
if((MSVC_VERSION EQUAL 1900) OR (MSVC_VERSION EQUAL 1910))
|
||||
set(PYTHON_NUMPY_VERSION 1.11)
|
||||
endif()
|
||||
add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${BLENDER_VERSION}/python/lib/site-packages
|
||||
|
|
Loading…
Reference in New Issue