Пример #1
0
/* create new expression for button (i.e. a "scripted driver"), if it can be created... */
bool ui_but_anim_expression_create(uiBut *but, const char *str)
{
	bContext *C = but->block->evil_C;
	ID *id;
	FCurve *fcu;
	char *path;
	bool ok = false;
	
	/* button must have RNA-pointer to a numeric-capable property */
	if (ELEM(NULL, but->rnapoin.data, but->rnaprop)) {
		if (G.debug & G_DEBUG)
			printf("ERROR: create expression failed - button has no RNA info attached\n");
		return false;
	}
	
	if (RNA_property_array_check(but->rnaprop) != 0) {
		if (but->rnaindex == -1) {
			if (G.debug & G_DEBUG)
				printf("ERROR: create expression failed - can't create expression for entire array\n");
			return false;
		}
	}
	
	/* make sure we have animdata for this */
	/* FIXME: until materials can be handled by depsgraph, don't allow drivers to be created for them */
	id = (ID *)but->rnapoin.id.data;
	if ((id == NULL) || (GS(id->name) == ID_MA) || (GS(id->name) == ID_TE)) {
		if (G.debug & G_DEBUG)
			printf("ERROR: create expression failed - invalid id-datablock for adding drivers (%p)\n", id);
		return false;
	}
	
	/* get path */
	path = RNA_path_from_ID_to_property(&but->rnapoin, but->rnaprop);
	
	/* create driver */
	fcu = verify_driver_fcurve(id, path, but->rnaindex, 1);
	if (fcu) {
		ChannelDriver *driver = fcu->driver;
		
		if (driver) {
			/* set type of driver */
			driver->type = DRIVER_TYPE_PYTHON;

			/* set the expression */
			/* TODO: need some way of identifying variables used */
			BLI_strncpy_utf8(driver->expression, str, sizeof(driver->expression));

			/* updates */
			driver->flag |= DRIVER_FLAG_RECOMPILE;
			WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME, NULL);
			ok = true;
		}
	}
	
	MEM_freeN(path);
	
	return ok;
}
Пример #2
0
/* Main Driver Management API calls:
 * Add a new driver for the specified property on the given ID block or replace an existing one
 * with the driver + driver-curve data from the buffer
 */
bool ANIM_paste_driver(
    ReportList *reports, ID *id, const char rna_path[], int array_index, short UNUSED(flag))
{
  PointerRNA id_ptr, ptr;
  PropertyRNA *prop;
  FCurve *fcu;

  /* validate pointer first - exit if failure */
  RNA_id_pointer_create(id, &id_ptr);
  if (RNA_path_resolve_property(&id_ptr, rna_path, &ptr, &prop) == false) {
    BKE_reportf(
        reports,
        RPT_ERROR,
        "Could not paste driver, as RNA path is invalid for the given ID (ID = %s, path = %s)",
        id->name,
        rna_path);
    return 0;
  }

  /* if the buffer is empty, cannot paste... */
  if (channeldriver_copypaste_buf == NULL) {
    BKE_report(reports, RPT_ERROR, "Paste driver: no driver to paste");
    return 0;
  }

  /* create Driver F-Curve, but without data which will be copied across... */
  fcu = verify_driver_fcurve(id, rna_path, array_index, -1);

  if (fcu) {
    /* copy across the curve data from the buffer curve
     * NOTE: this step needs care to not miss new settings
     */
    /* keyframes/samples */
    fcu->bezt = MEM_dupallocN(channeldriver_copypaste_buf->bezt);
    fcu->fpt = MEM_dupallocN(channeldriver_copypaste_buf->fpt);
    fcu->totvert = channeldriver_copypaste_buf->totvert;

    /* modifiers */
    copy_fmodifiers(&fcu->modifiers, &channeldriver_copypaste_buf->modifiers);

    /* extrapolation mode */
    fcu->extend = channeldriver_copypaste_buf->extend;

    /* the 'juicy' stuff - the driver */
    fcu->driver = fcurve_copy_driver(channeldriver_copypaste_buf->driver);
  }

  /* done */
  return (fcu != NULL);
}
Пример #3
0
/* Main Driver Management API calls:
 *  Make a copy of the driver for the specified property on the given ID block
 */
bool ANIM_copy_driver(
    ReportList *reports, ID *id, const char rna_path[], int array_index, short UNUSED(flag))
{
  PointerRNA id_ptr, ptr;
  PropertyRNA *prop;
  FCurve *fcu;

  /* validate pointer first - exit if failure */
  RNA_id_pointer_create(id, &id_ptr);
  if (RNA_path_resolve_property(&id_ptr, rna_path, &ptr, &prop) == false) {
    BKE_reportf(reports,
                RPT_ERROR,
                "Could not find driver to copy, as RNA path is invalid for the given ID (ID = %s, "
                "path = %s)",
                id->name,
                rna_path);
    return 0;
  }

  /* try to get F-Curve with Driver */
  fcu = verify_driver_fcurve(id, rna_path, array_index, 0);

  /* clear copy/paste buffer first (for consistency with other copy/paste buffers) */
  ANIM_drivers_copybuf_free();

  /* copy this to the copy/paste buf if it exists */
  if (fcu && fcu->driver) {
    /* Make copies of some info such as the rna_path, then clear this info from the
     * F-Curve temporarily so that we don't end up wasting memory storing the path
     * which won't get used ever.
     */
    char *tmp_path = fcu->rna_path;
    fcu->rna_path = NULL;

    /* make a copy of the F-Curve with */
    channeldriver_copypaste_buf = copy_fcurve(fcu);

    /* restore the path */
    fcu->rna_path = tmp_path;

    /* copied... */
    return 1;
  }

  /* done */
  return 0;
}
Пример #4
0
/* Main Driver Management API calls:
 * Remove the driver for the specified property on the given ID block (if available)
 */
bool ANIM_remove_driver(ReportList *UNUSED(reports),
                        ID *id,
                        const char rna_path[],
                        int array_index,
                        short UNUSED(flag))
{
  AnimData *adt;
  FCurve *fcu;
  bool success = false;

  /* we don't check the validity of the path here yet, but it should be ok... */
  adt = BKE_animdata_from_id(id);

  if (adt) {
    if (array_index == -1) {
      /* step through all drivers, removing all of those with the same base path */
      FCurve *fcu_iter = adt->drivers.first;

      while ((fcu = iter_step_fcurve(fcu_iter, rna_path)) != NULL) {
        /* store the next fcurve for looping  */
        fcu_iter = fcu->next;

        /* remove F-Curve from driver stack, then free it */
        BLI_remlink(&adt->drivers, fcu);
        free_fcurve(fcu);

        /* done successfully */
        success = true;
      }
    }
    else {
      /* find the matching driver and remove it only
       * Note: here is one of the places where we don't want new F-Curve + Driver added!
       *      so 'add' var must be 0
       */
      fcu = verify_driver_fcurve(id, rna_path, array_index, 0);
      if (fcu) {
        BLI_remlink(&adt->drivers, fcu);
        free_fcurve(fcu);

        success = true;
      }
    }
  }

  return success;
}
Пример #5
0
/* Main Driver Management API calls:
 *  Add a new driver for the specified property on the given ID block
 */
int ANIM_add_driver(ReportList *reports, ID *id, const char rna_path[], int array_index, short flag, int type)
{	
	PointerRNA id_ptr, ptr;
	PropertyRNA *prop;
	FCurve *fcu;
	int array_index_max;
	int done_tot = 0;
	
	/* validate pointer first - exit if failure */
	RNA_id_pointer_create(id, &id_ptr);
	if (RNA_path_resolve_property(&id_ptr, rna_path, &ptr, &prop) == false) {
		BKE_reportf(reports, RPT_ERROR, 
		            "Could not add driver, as RNA path is invalid for the given ID (ID = %s, path = %s)",
		            id->name, rna_path);
		return 0;
	}
	
	/* key entire array convenience method */
	if (array_index == -1) {
		array_index_max = RNA_property_array_length(&ptr, prop);
		array_index = 0;
	}
	else
		array_index_max = array_index;
	
	/* maximum index should be greater than the start index */
	if (array_index == array_index_max)
		array_index_max += 1;
	
	/* will only loop once unless the array index was -1 */
	for (; array_index < array_index_max; array_index++) {
		short add_mode = (flag & CREATEDRIVER_WITH_FMODIFIER) ? 2 : 1;
		
		/* create F-Curve with Driver */
		fcu = verify_driver_fcurve(id, rna_path, array_index, add_mode);
		
		if (fcu && fcu->driver) {
			ChannelDriver *driver = fcu->driver;
			
			/* set the type of the driver */
			driver->type = type;
			
			/* creating drivers for buttons will create the driver(s) with type 
			 * "scripted expression" so that their values won't be lost immediately,
			 * so here we copy those values over to the driver's expression
			 */
			if (type == DRIVER_TYPE_PYTHON) {
				PropertyType proptype = RNA_property_type(prop);
				int array = RNA_property_array_length(&ptr, prop);
				char *expression = driver->expression;
				int val, maxlen = sizeof(driver->expression);
				float fval;
				
				if (proptype == PROP_BOOLEAN) {
					if (!array) val = RNA_property_boolean_get(&ptr, prop);
					else val = RNA_property_boolean_get_index(&ptr, prop, array_index);
					
					BLI_strncpy(expression, (val) ? "True" : "False", maxlen);
				}
				else if (proptype == PROP_INT) {
					if (!array) val = RNA_property_int_get(&ptr, prop);
					else val = RNA_property_int_get_index(&ptr, prop, array_index);
					
					BLI_snprintf(expression, maxlen, "%d", val);
				}
				else if (proptype == PROP_FLOAT) {
					if (!array) fval = RNA_property_float_get(&ptr, prop);
					else fval = RNA_property_float_get_index(&ptr, prop, array_index);
					
					BLI_snprintf(expression, maxlen, "%.3f", fval);
				}
			}
			
			/* for easier setup of drivers from UI, a driver variable should be 
			 * added if flag is set (UI calls only)
			 */
			if (flag & CREATEDRIVER_WITH_DEFAULT_DVAR) {
				/* assume that users will mostly want this to be of type "Transform Channel" too,
				 * since this allows the easiest setting up of common rig components
				 */
				DriverVar *dvar = driver_add_new_variable(driver);
				driver_change_variable_type(dvar, DVAR_TYPE_TRANSFORM_CHAN);
			}
		}
		
		/* set the done status */
		done_tot += (fcu != NULL);
	}
	
	/* done */
	return done_tot;
}
Пример #6
0
/* Helper for ANIM_add_driver_with_target - Adds the actual driver */
static int add_driver_with_target(ReportList *UNUSED(reports),
                                  ID *dst_id,
                                  const char dst_path[],
                                  int dst_index,
                                  ID *src_id,
                                  const char src_path[],
                                  int src_index,
                                  PointerRNA *dst_ptr,
                                  PropertyRNA *dst_prop,
                                  PointerRNA *src_ptr,
                                  PropertyRNA *src_prop,
                                  short flag,
                                  int driver_type)
{
  FCurve *fcu;
  short add_mode = (flag & CREATEDRIVER_WITH_FMODIFIER) ? 2 : 1;
  const char *prop_name = RNA_property_identifier(src_prop);

  /* Create F-Curve with Driver */
  fcu = verify_driver_fcurve(dst_id, dst_path, dst_index, add_mode);

  if (fcu && fcu->driver) {
    ChannelDriver *driver = fcu->driver;
    DriverVar *dvar;

    /* Set the type of the driver */
    driver->type = driver_type;

    /* Set driver expression, so that the driver works out of the box
     *
     * The following checks define a bit of "autodetection magic" we use
     * to ensure that the drivers will behave as expected out of the box
     * when faced with properties with different units.
     */
    /* XXX: if we have N-1 mapping, should we include all those in the expression? */
    if ((RNA_property_unit(dst_prop) == PROP_UNIT_ROTATION) &&
        (RNA_property_unit(src_prop) != PROP_UNIT_ROTATION)) {
      /* Rotation Destination:  normal -> radians,  so convert src to radians
       * (However, if both input and output is a rotation, don't apply such corrections)
       */
      BLI_strncpy(driver->expression, "radians(var)", sizeof(driver->expression));
    }
    else if ((RNA_property_unit(src_prop) == PROP_UNIT_ROTATION) &&
             (RNA_property_unit(dst_prop) != PROP_UNIT_ROTATION)) {
      /* Rotation Source:  radians -> normal,  so convert src to degrees
       * (However, if both input and output is a rotation, don't apply such corrections)
       */
      BLI_strncpy(driver->expression, "degrees(var)", sizeof(driver->expression));
    }
    else {
      /* Just a normal property without any unit problems */
      BLI_strncpy(driver->expression, "var", sizeof(driver->expression));
    }

    /* Create a driver variable for the target
     *   - For transform properties, we want to automatically use "transform channel" instead
     *     (The only issue is with quat rotations vs euler channels...)
     *   - To avoid problems with transform properties depending on the final transform that they
     *     control (thus creating pseudo-cycles - see T48734), we don't use transform channels
     *     when both the source and destinations are in same places.
     */
    dvar = driver_add_new_variable(driver);

    if (ELEM(src_ptr->type, &RNA_Object, &RNA_PoseBone) &&
        (STREQ(prop_name, "location") || STREQ(prop_name, "scale") ||
         STRPREFIX(prop_name, "rotation_")) &&
        (src_ptr->data != dst_ptr->data)) {
      /* Transform Channel */
      DriverTarget *dtar;

      driver_change_variable_type(dvar, DVAR_TYPE_TRANSFORM_CHAN);
      dtar = &dvar->targets[0];

      /* Bone or Object target? */
      dtar->id = src_id;
      dtar->idtype = GS(src_id->name);

      if (src_ptr->type == &RNA_PoseBone) {
        RNA_string_get(src_ptr, "name", dtar->pchan_name);
      }

      /* Transform channel depends on type */
      if (STREQ(prop_name, "location")) {
        if (src_index == 2) {
          dtar->transChan = DTAR_TRANSCHAN_LOCZ;
        }
        else if (src_index == 1) {
          dtar->transChan = DTAR_TRANSCHAN_LOCY;
        }
        else {
          dtar->transChan = DTAR_TRANSCHAN_LOCX;
        }
      }
      else if (STREQ(prop_name, "scale")) {
        if (src_index == 2) {
          dtar->transChan = DTAR_TRANSCHAN_SCALEZ;
        }
        else if (src_index == 1) {
          dtar->transChan = DTAR_TRANSCHAN_SCALEY;
        }
        else {
          dtar->transChan = DTAR_TRANSCHAN_SCALEX;
        }
      }
      else {
        /* XXX: With quaternions and axis-angle, this mapping might not be correct...
         *      But since those have 4 elements instead, there's not much we can do
         */
        if (src_index == 2) {
          dtar->transChan = DTAR_TRANSCHAN_ROTZ;
        }
        else if (src_index == 1) {
          dtar->transChan = DTAR_TRANSCHAN_ROTY;
        }
        else {
          dtar->transChan = DTAR_TRANSCHAN_ROTX;
        }
      }
    }
    else {
      /* Single RNA Property */
      DriverTarget *dtar = &dvar->targets[0];

      /* ID is as-is */
      dtar->id = src_id;
      dtar->idtype = GS(src_id->name);

      /* Need to make a copy of the path (or build one with array index built in) */
      if (RNA_property_array_check(src_prop)) {
        dtar->rna_path = BLI_sprintfN("%s[%d]", src_path, src_index);
      }
      else {
        dtar->rna_path = BLI_strdup(src_path);
      }
    }
  }

  /* set the done status */
  return (fcu != NULL);
}
Пример #7
0
/* create new expression for button (i.e. a "scripted driver"), if it can be created... */
int ui_but_anim_expression_create(uiBut *but, const char *str)
{
	bContext *C = but->block->evil_C;
	ID *id;
	FCurve *fcu;
	char *path;
	short ok=0;
	
	/* button must have RNA-pointer to a numeric-capable property */
	if (ELEM(NULL, but->rnapoin.data, but->rnaprop)) {
		if (G.f & G_DEBUG) 
			printf("ERROR: create expression failed - button has no RNA info attached\n");
		return 0;
	}
	
	/* make sure we have animdata for this */
	// FIXME: until materials can be handled by depsgraph, don't allow drivers to be created for them
	id = (ID *)but->rnapoin.id.data;
	if ((id == NULL) || (GS(id->name)==ID_MA) || (GS(id->name)==ID_TE)) {
		if (G.f & G_DEBUG)
			printf("ERROR: create expression failed - invalid id-datablock for adding drivers (%p)\n", id);
		return 0;
	}
	
	/* get path */
	path = RNA_path_from_ID_to_property(&but->rnapoin, but->rnaprop);
	
	/* create driver */
	fcu = verify_driver_fcurve(id, path, but->rnaindex, 1);
	if (fcu) {
		ChannelDriver *driver= fcu->driver;
		
		if (driver) {
			/* set type of driver */
			driver->type = DRIVER_TYPE_PYTHON;
			
			/* set the expression */
			// TODO: need some way of identifying variables used
			BLI_strncpy(driver->expression, str, sizeof(driver->expression));
			
			/* FIXME: for now, assume that 
			 * 	- for expressions, users are likely to be using "frame" -> current frame" as a variable
			 *	- driver_add_new_variable() adds a single-prop variable by default
			 */
			{
				DriverVar *dvar;
				DriverTarget *dtar;
				
				dvar = driver_add_new_variable(driver);
				BLI_strncpy(dvar->name, "frame", sizeof(dvar->name));
				
				dtar = &dvar->targets[0];
				dtar->id = (ID *)CTX_data_scene(C); // XXX: should we check that C is valid first?
				dtar->rna_path = BLI_sprintfN("frame_current");
			}
			
			/* updates */
			driver->flag |= DRIVER_FLAG_RECOMPILE;
			WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME, NULL);
		}
	}
	
	MEM_freeN(path);
	
	return ok;
}