Merge branch 'master' into blender2.8
This commit is contained in:
commit
c327cf489c
|
@ -76,8 +76,6 @@ ccl_device_inline int3 clamp(const int3& a, int3& mn, int mx)
|
|||
clamp(a.z, mn.z, mx));
|
||||
#endif
|
||||
}
|
||||
#endif /* !__KERNEL_OPENCL__ */
|
||||
|
||||
|
||||
ccl_device_inline bool operator==(const int3 &a, const int3 &b)
|
||||
{
|
||||
|
@ -93,6 +91,7 @@ ccl_device_inline bool operator<(const int3 &a, const int3 &b)
|
|||
{
|
||||
return a.x < b.x && a.y < b.y && a.z < b.z;
|
||||
}
|
||||
#endif /* !__KERNEL_OPENCL__ */
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
||||
|
|
|
@ -1917,28 +1917,29 @@ static void samevolume_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *
|
|||
bSameVolumeConstraint *data = con->data;
|
||||
|
||||
float volume = data->volume;
|
||||
float fac = 1.0f;
|
||||
float fac = 1.0f, total_scale;
|
||||
float obsize[3];
|
||||
|
||||
mat4_to_size(obsize, cob->matrix);
|
||||
|
||||
/* calculate normalizing scale factor for non-essential values */
|
||||
if (obsize[data->flag] != 0)
|
||||
fac = sqrtf(volume / obsize[data->flag]);
|
||||
total_scale = obsize[0] * obsize[1] * obsize[2];
|
||||
if (total_scale != 0)
|
||||
fac = sqrtf(volume / total_scale);
|
||||
|
||||
/* apply scaling factor to the channels not being kept */
|
||||
switch (data->flag) {
|
||||
case SAMEVOL_X:
|
||||
mul_v3_fl(cob->matrix[1], fac / obsize[1]);
|
||||
mul_v3_fl(cob->matrix[2], fac / obsize[2]);
|
||||
mul_v3_fl(cob->matrix[1], fac);
|
||||
mul_v3_fl(cob->matrix[2], fac);
|
||||
break;
|
||||
case SAMEVOL_Y:
|
||||
mul_v3_fl(cob->matrix[0], fac / obsize[0]);
|
||||
mul_v3_fl(cob->matrix[2], fac / obsize[2]);
|
||||
mul_v3_fl(cob->matrix[0], fac);
|
||||
mul_v3_fl(cob->matrix[2], fac);
|
||||
break;
|
||||
case SAMEVOL_Z:
|
||||
mul_v3_fl(cob->matrix[0], fac / obsize[0]);
|
||||
mul_v3_fl(cob->matrix[1], fac / obsize[1]);
|
||||
mul_v3_fl(cob->matrix[0], fac);
|
||||
mul_v3_fl(cob->matrix[1], fac);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,6 +46,8 @@
|
|||
|
||||
namespace DEG {
|
||||
|
||||
namespace {
|
||||
|
||||
typedef enum eCyclicCheckVisitedState {
|
||||
/* Not is not visited at all during traversal. */
|
||||
NODE_NOT_VISITED = 0,
|
||||
|
@ -55,6 +57,30 @@ typedef enum eCyclicCheckVisitedState {
|
|||
NODE_IN_STACK = 2,
|
||||
} eCyclicCheckVisitedState;
|
||||
|
||||
struct StackEntry {
|
||||
OperationDepsNode *node;
|
||||
StackEntry *from;
|
||||
DepsRelation *via_relation;
|
||||
};
|
||||
|
||||
struct CyclesSolverState {
|
||||
CyclesSolverState(Depsgraph *graph)
|
||||
: graph(graph),
|
||||
traversal_stack(BLI_stack_new(sizeof(StackEntry),
|
||||
"DEG detect cycles stack")),
|
||||
num_cycles(0) {
|
||||
}
|
||||
~CyclesSolverState() {
|
||||
BLI_stack_free(traversal_stack);
|
||||
if (num_cycles != 0) {
|
||||
printf("Detected %d dependency cycles\n", num_cycles);
|
||||
}
|
||||
}
|
||||
Depsgraph *graph;
|
||||
BLI_Stack *traversal_stack;
|
||||
int num_cycles;
|
||||
};
|
||||
|
||||
BLI_INLINE void set_node_visited_state(DepsNode *node,
|
||||
eCyclicCheckVisitedState state)
|
||||
{
|
||||
|
@ -76,19 +102,20 @@ BLI_INLINE int get_node_num_visited_children(DepsNode *node)
|
|||
return node->done >> 2;
|
||||
}
|
||||
|
||||
void deg_graph_detect_cycles(Depsgraph *graph)
|
||||
void schedule_node_to_stack(CyclesSolverState *state, OperationDepsNode *node)
|
||||
{
|
||||
struct StackEntry {
|
||||
OperationDepsNode *node;
|
||||
StackEntry *from;
|
||||
DepsRelation *via_relation;
|
||||
};
|
||||
StackEntry entry;
|
||||
entry.node = node;
|
||||
entry.from = NULL;
|
||||
entry.via_relation = NULL;
|
||||
BLI_stack_push(state->traversal_stack, &entry);
|
||||
set_node_visited_state(node, NODE_IN_STACK);
|
||||
}
|
||||
|
||||
BLI_Stack *traversal_stack = BLI_stack_new(sizeof(StackEntry),
|
||||
"DEG detect cycles stack");
|
||||
|
||||
int num_cycles = 0;
|
||||
foreach (OperationDepsNode *node, graph->operations) {
|
||||
/* Schedule leaf nodes (node without input links) for traversal. */
|
||||
void schedule_leaf_nodes(CyclesSolverState *state)
|
||||
{
|
||||
foreach (OperationDepsNode *node, state->graph->operations) {
|
||||
bool has_inlinks = false;
|
||||
foreach (DepsRelation *rel, node->inlinks) {
|
||||
if (rel->from->type == DEG_NODE_TYPE_OPERATION) {
|
||||
|
@ -97,18 +124,32 @@ void deg_graph_detect_cycles(Depsgraph *graph)
|
|||
}
|
||||
node->done = 0;
|
||||
if (has_inlinks == false) {
|
||||
StackEntry entry;
|
||||
entry.node = node;
|
||||
entry.from = NULL;
|
||||
entry.via_relation = NULL;
|
||||
BLI_stack_push(traversal_stack, &entry);
|
||||
set_node_visited_state(node, NODE_IN_STACK);
|
||||
schedule_node_to_stack(state, node);
|
||||
}
|
||||
else {
|
||||
set_node_visited_state(node, NODE_NOT_VISITED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Schedule node which was not checked yet for being belong to
|
||||
* any of dependency cycle.
|
||||
*/
|
||||
bool schedule_non_checked_node(CyclesSolverState *state)
|
||||
{
|
||||
foreach (OperationDepsNode *node, state->graph->operations) {
|
||||
if (get_node_visited_state(node) == NODE_NOT_VISITED) {
|
||||
schedule_node_to_stack(state, node);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Solve cycles with all nodes which are scheduled for traversal. */
|
||||
void solve_cycles(CyclesSolverState *state)
|
||||
{
|
||||
BLI_Stack *traversal_stack = state->traversal_stack;
|
||||
while (!BLI_stack_is_empty(traversal_stack)) {
|
||||
StackEntry *entry = (StackEntry *)BLI_stack_peek(traversal_stack);
|
||||
OperationDepsNode *node = entry->node;
|
||||
|
@ -137,7 +178,7 @@ void deg_graph_detect_cycles(Depsgraph *graph)
|
|||
}
|
||||
/* TODO(sergey): So called russian roulette cycle solver. */
|
||||
rel->flag |= DEPSREL_FLAG_CYCLIC;
|
||||
++num_cycles;
|
||||
++state->num_cycles;
|
||||
}
|
||||
else if (to_state == NODE_NOT_VISITED) {
|
||||
StackEntry new_entry;
|
||||
|
@ -157,11 +198,23 @@ void deg_graph_detect_cycles(Depsgraph *graph)
|
|||
BLI_stack_discard(traversal_stack);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BLI_stack_free(traversal_stack);
|
||||
} // namespace
|
||||
|
||||
if (num_cycles != 0) {
|
||||
printf("Detected %d dependency cycles\n", num_cycles);
|
||||
void deg_graph_detect_cycles(Depsgraph *graph)
|
||||
{
|
||||
CyclesSolverState state(graph);
|
||||
/* First we solve cycles which are reachable from leaf nodes. */
|
||||
schedule_leaf_nodes(&state);
|
||||
solve_cycles(&state);
|
||||
/* We are not done yet. It is possible to have closed loop cycle,
|
||||
* for example A -> B -> C -> A. These nodes were not scheduled
|
||||
* yet (since they all have inlinks), and were not traversed since
|
||||
* nobody else points to them.
|
||||
*/
|
||||
while (schedule_non_checked_node(&state)) {
|
||||
solve_cycles(&state);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -285,6 +285,22 @@ OperationDepsNode *DepsgraphNodeBuilder::add_operation_node(
|
|||
name_tag);
|
||||
}
|
||||
|
||||
OperationDepsNode *DepsgraphNodeBuilder::ensure_operation_node(
|
||||
ID *id,
|
||||
eDepsNode_Type comp_type,
|
||||
const DepsEvalOperationCb& op,
|
||||
eDepsOperation_Code opcode,
|
||||
const char *name,
|
||||
int name_tag)
|
||||
{
|
||||
OperationDepsNode *operation =
|
||||
find_operation_node(id, comp_type, opcode, name, name_tag);
|
||||
if (operation != NULL) {
|
||||
return operation;
|
||||
}
|
||||
return add_operation_node(id, comp_type, op, opcode, name, name_tag);
|
||||
}
|
||||
|
||||
bool DepsgraphNodeBuilder::has_operation_node(ID *id,
|
||||
eDepsNode_Type comp_type,
|
||||
const char *comp_name,
|
||||
|
@ -693,37 +709,57 @@ void DepsgraphNodeBuilder::build_animdata(ID *id)
|
|||
* \param id: ID-Block that driver is attached to
|
||||
* \param fcu: Driver-FCurve
|
||||
*/
|
||||
OperationDepsNode *DepsgraphNodeBuilder::build_driver(ID *id, FCurve *fcu)
|
||||
void DepsgraphNodeBuilder::build_driver(ID *id, FCurve *fcurve)
|
||||
{
|
||||
ID *id_cow = get_cow_id(id);
|
||||
|
||||
/* Create data node for this driver */
|
||||
/* TODO(sergey): Avoid creating same operation multiple times,
|
||||
* in the future we need to avoid lookup of the operation as well
|
||||
* and use some tagging magic instead.
|
||||
*/
|
||||
OperationDepsNode *driver_op = find_operation_node(
|
||||
id,
|
||||
DEG_NODE_TYPE_PARAMETERS,
|
||||
DEG_OPCODE_DRIVER,
|
||||
fcu->rna_path ? fcu->rna_path : "",
|
||||
fcu->array_index);
|
||||
/* TODO(sergey): Shall we use COW of fcu itself here? */
|
||||
ensure_operation_node(id,
|
||||
DEG_NODE_TYPE_PARAMETERS,
|
||||
function_bind(BKE_animsys_eval_driver, _1, id_cow, fcurve),
|
||||
DEG_OPCODE_DRIVER,
|
||||
fcurve->rna_path ? fcurve->rna_path : "",
|
||||
fcurve->array_index);
|
||||
build_driver_variables(id, fcurve);
|
||||
}
|
||||
|
||||
if (driver_op == NULL) {
|
||||
/* TODO(sergey): Shall we use COW of fcu itself here? */
|
||||
driver_op = add_operation_node(id,
|
||||
DEG_NODE_TYPE_PARAMETERS,
|
||||
function_bind(BKE_animsys_eval_driver,
|
||||
_1,
|
||||
id_cow,
|
||||
fcu),
|
||||
DEG_OPCODE_DRIVER,
|
||||
fcu->rna_path ? fcu->rna_path : "",
|
||||
fcu->array_index);
|
||||
void DepsgraphNodeBuilder::build_driver_variables(ID * id, FCurve *fcurve)
|
||||
{
|
||||
build_driver_id_property(id, fcurve->rna_path);
|
||||
LISTBASE_FOREACH (DriverVar *, dvar, &fcurve->driver->variables) {
|
||||
DRIVER_TARGETS_USED_LOOPER(dvar)
|
||||
{
|
||||
build_driver_id_property(dtar->id, dtar->rna_path);
|
||||
}
|
||||
DRIVER_TARGETS_LOOPER_END
|
||||
}
|
||||
}
|
||||
|
||||
/* return driver node created */
|
||||
return driver_op;
|
||||
void DepsgraphNodeBuilder::build_driver_id_property(ID *id,
|
||||
const char *rna_path)
|
||||
{
|
||||
if (id == NULL || rna_path == NULL) {
|
||||
return;
|
||||
}
|
||||
PointerRNA id_ptr, ptr;
|
||||
PropertyRNA *prop;
|
||||
RNA_id_pointer_create(id, &id_ptr);
|
||||
if (!RNA_path_resolve_full(&id_ptr, rna_path, &ptr, &prop, NULL)) {
|
||||
return;
|
||||
}
|
||||
if (prop == NULL) {
|
||||
return;
|
||||
}
|
||||
if (!RNA_property_is_idprop(prop)) {
|
||||
return;
|
||||
}
|
||||
const char *prop_identifier = RNA_property_identifier((PropertyRNA *)prop);
|
||||
ensure_operation_node(id,
|
||||
DEG_NODE_TYPE_PARAMETERS,
|
||||
NULL,
|
||||
DEG_OPCODE_ID_PROPERTY,
|
||||
prop_identifier);
|
||||
}
|
||||
|
||||
/* Recursively build graph for world */
|
||||
|
|
|
@ -140,6 +140,13 @@ struct DepsgraphNodeBuilder {
|
|||
const char *name = "",
|
||||
int name_tag = -1);
|
||||
|
||||
OperationDepsNode *ensure_operation_node(ID *id,
|
||||
eDepsNode_Type comp_type,
|
||||
const DepsEvalOperationCb& op,
|
||||
eDepsOperation_Code opcode,
|
||||
const char *name = "",
|
||||
int name_tag = -1);
|
||||
|
||||
bool has_operation_node(ID *id,
|
||||
eDepsNode_Type comp_type,
|
||||
const char *comp_name,
|
||||
|
@ -179,7 +186,9 @@ struct DepsgraphNodeBuilder {
|
|||
void build_particle_settings(ParticleSettings *part);
|
||||
void build_cloth(Object *object);
|
||||
void build_animdata(ID *id);
|
||||
OperationDepsNode *build_driver(ID *id, FCurve *fcurve);
|
||||
void build_driver(ID *id, FCurve *fcurve);
|
||||
void build_driver_variables(ID *id, FCurve *fcurve);
|
||||
void build_driver_id_property(ID *id, const char *rna_path);
|
||||
void build_ik_pose(Object *object,
|
||||
bPoseChannel *pchan,
|
||||
bConstraint *con);
|
||||
|
|
|
@ -1178,6 +1178,26 @@ void DepsgraphRelationBuilder::build_driver_data(ID *id, FCurve *fcu)
|
|||
}
|
||||
}
|
||||
}
|
||||
if (RNA_pointer_is_null(&target_key.ptr)) {
|
||||
/* TODO(sergey): This would only mean that driver is broken.
|
||||
* so we can't create relation anyway. However, we need to avoid
|
||||
* adding drivers which are known to be buggy to a dependency
|
||||
* graph, in order to save computational power.
|
||||
*/
|
||||
}
|
||||
else {
|
||||
if (target_key.prop != NULL &&
|
||||
RNA_property_is_idprop(target_key.prop))
|
||||
{
|
||||
OperationKey parameters_key(id,
|
||||
DEG_NODE_TYPE_PARAMETERS,
|
||||
DEG_OPCODE_PARAMETERS_EVAL);
|
||||
add_relation(target_key,
|
||||
parameters_key,
|
||||
"Driver Target -> Properties");
|
||||
}
|
||||
add_relation(driver_key, target_key, "Driver -> Target");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -140,7 +140,7 @@ static bool pointer_to_component_node_criteria(
|
|||
*type = DEG_NODE_TYPE_PARAMETERS;
|
||||
*subdata = "";
|
||||
*operation_code = DEG_OPCODE_PARAMETERS_EVAL;
|
||||
*operation_name = pchan->name;;
|
||||
*operation_name = pchan->name;
|
||||
}
|
||||
else {
|
||||
/* Bone - generally, we just want the bone component. */
|
||||
|
@ -230,10 +230,18 @@ static bool pointer_to_component_node_criteria(
|
|||
}
|
||||
if (prop != NULL) {
|
||||
/* All unknown data effectively falls under "parameter evaluation". */
|
||||
*type = DEG_NODE_TYPE_PARAMETERS;
|
||||
*operation_code = DEG_OPCODE_PARAMETERS_EVAL;
|
||||
*operation_name = "";
|
||||
*operation_name_tag = -1;
|
||||
if (RNA_property_is_idprop(prop)) {
|
||||
*type = DEG_NODE_TYPE_PARAMETERS;
|
||||
*operation_code = DEG_OPCODE_ID_PROPERTY;
|
||||
*operation_name = RNA_property_identifier((PropertyRNA *)prop);
|
||||
*operation_name_tag = -1;
|
||||
}
|
||||
else {
|
||||
*type = DEG_NODE_TYPE_PARAMETERS;
|
||||
*operation_code = DEG_OPCODE_PARAMETERS_EVAL;
|
||||
*operation_name = "";
|
||||
*operation_name_tag = -1;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
|
@ -81,6 +81,7 @@ static const char *stringify_opcode(eDepsOperation_Code opcode)
|
|||
#define STRINGIFY_OPCODE(name) case DEG_OPCODE_##name: return #name
|
||||
/* Generic Operations. */
|
||||
STRINGIFY_OPCODE(OPERATION);
|
||||
STRINGIFY_OPCODE(ID_PROPERTY);
|
||||
STRINGIFY_OPCODE(PARAMETERS_EVAL);
|
||||
STRINGIFY_OPCODE(PLACEHOLDER);
|
||||
/* Animation, Drivers, etc. */
|
||||
|
|
|
@ -162,6 +162,7 @@ typedef enum eDepsOperation_Code {
|
|||
DEG_OPCODE_OPERATION = 0,
|
||||
|
||||
/* Generic parameters evaluation. */
|
||||
DEG_OPCODE_ID_PROPERTY,
|
||||
DEG_OPCODE_PARAMETERS_EVAL,
|
||||
|
||||
// XXX: Placeholder while porting depsgraph code
|
||||
|
|
|
@ -58,11 +58,10 @@ def with_tempdir(wrapped):
|
|||
class AbstractBlenderRunnerTest(unittest.TestCase):
|
||||
"""Base class for all test suites which needs to run Blender"""
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
global args
|
||||
cls.blender = args.blender
|
||||
cls.testdir = pathlib.Path(args.testdir)
|
||||
# Set in a subclass
|
||||
blender: pathlib.Path = None
|
||||
testdir: pathlib.Path = None
|
||||
|
||||
|
||||
def run_blender(self, filepath: str, python_script: str, timeout: int=300) -> str:
|
||||
"""Runs Blender by opening a blendfile and executing a script.
|
||||
|
@ -73,6 +72,9 @@ class AbstractBlenderRunnerTest(unittest.TestCase):
|
|||
:param timeout: in seconds
|
||||
"""
|
||||
|
||||
assert self.blender, "Path to Blender binary is to be set in setUpClass()"
|
||||
assert self.testdir, "Path to tests binary is to be set in setUpClass()"
|
||||
|
||||
blendfile = self.testdir / filepath
|
||||
|
||||
command = (
|
||||
|
|
Loading…
Reference in New Issue