diff options
author | Benoit Bolsee <benoit.bolsee@online.be> | 2011-09-07 19:34:04 +0400 |
---|---|---|
committer | Benoit Bolsee <benoit.bolsee@online.be> | 2011-09-07 19:34:04 +0400 |
commit | dbd6658d737b1592a633ddf6397be14e50e434d9 (patch) | |
tree | 57081721d70622a3c3141909b258f9bce8a5b1e3 /source/blender/blenkernel | |
parent | b5bd86e5907c3fa98546dabeda9703dfb15862f4 (diff) | |
parent | 884fc84793be1c5fdd6643ad267331381f8e1c6b (diff) |
svn merge -r 37306:39975 https://svn.blender.org/svnroot/bf-blender/trunk/blender
Diffstat (limited to 'source/blender/blenkernel')
82 files changed, 3437 insertions, 4161 deletions
diff --git a/source/blender/blenkernel/BKE_DerivedMesh.h b/source/blender/blenkernel/BKE_DerivedMesh.h index 55ade5fe5d9..6e17b056685 100644 --- a/source/blender/blenkernel/BKE_DerivedMesh.h +++ b/source/blender/blenkernel/BKE_DerivedMesh.h @@ -283,7 +283,8 @@ struct DerivedMesh { int (*setDrawOptions)(void *userData, int index, int *drawSmooth_r), void *userData, int useColors, - int (*setMaterial)(int, void *attribs)); + int (*setMaterial)(int, void *attribs), + int (*compareDrawOptions)(void *userData, int cur_index, int next_index)); /* Draw mapped faces using MTFace * o Drawing options too complicated to enumerate, look at code. @@ -526,7 +527,7 @@ void weight_to_rgb(float input, float *fr, float *fg, float *fb); typedef struct DMVertexAttribs { struct { struct MTFace *array; - int emOffset, glIndex; + int emOffset, glIndex, glTexco; } tface[MAX_MTFACE]; struct { @@ -541,7 +542,7 @@ typedef struct DMVertexAttribs { struct { float (*array)[3]; - int emOffset, glIndex; + int emOffset, glIndex, glTexco; } orco; int tottface, totmcol, tottang, totorco; diff --git a/source/blender/blenkernel/BKE_action.h b/source/blender/blenkernel/BKE_action.h index 698f0f0fecf..67efb7752ea 100644 --- a/source/blender/blenkernel/BKE_action.h +++ b/source/blender/blenkernel/BKE_action.h @@ -1,6 +1,4 @@ /* - * $Id$ - * * ***** BEGIN GPL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or @@ -216,7 +214,7 @@ void pose_remove_group(struct Object *ob); /* Assorted Evaluation ----------------- */ /* Used for the Action Constraint */ -void what_does_obaction(struct Scene *scene, struct Object *ob, struct Object *workob, struct bPose *pose, struct bAction *act, char groupname[], float cframe); +void what_does_obaction(struct Object *ob, struct Object *workob, struct bPose *pose, struct bAction *act, char groupname[], float cframe); /* for proxy */ void copy_pose_result(struct bPose *to, struct bPose *from); diff --git a/source/blender/blenkernel/BKE_anim.h b/source/blender/blenkernel/BKE_anim.h index 25165eeaee7..44aebdf6205 100644 --- a/source/blender/blenkernel/BKE_anim.h +++ b/source/blender/blenkernel/BKE_anim.h @@ -1,6 +1,4 @@ /* - * $Id$ - * * ***** BEGIN GPL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or diff --git a/source/blender/blenkernel/BKE_animsys.h b/source/blender/blenkernel/BKE_animsys.h index 348b967f9c4..98f9ee14c7e 100644 --- a/source/blender/blenkernel/BKE_animsys.h +++ b/source/blender/blenkernel/BKE_animsys.h @@ -1,6 +1,4 @@ /* - * $Id$ - * * ***** BEGIN GPL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or @@ -41,6 +39,7 @@ struct KeyingSet; struct KS_Path; struct PointerRNA; +struct ReportList; struct bAction; struct bActionGroup; struct AnimMapper; @@ -57,6 +56,9 @@ struct AnimData *BKE_animdata_from_id(struct ID *id); /* Add AnimData to the given ID-block */ struct AnimData *BKE_id_add_animdata(struct ID *id); +/* Set active action used by AnimData from the given ID-block */ +short BKE_animdata_set_action(struct ReportList *reports, struct ID *id, struct bAction *act); + /* Free AnimData */ void BKE_free_animdata(struct ID *id); @@ -136,10 +138,10 @@ void BKE_animdata_main_cb(struct Main *main, ID_AnimData_Edit_Callback func, voi /* In general, these ones should be called to do all animation evaluation */ /* Evaluation loop for evaluating animation data */ -void BKE_animsys_evaluate_animdata(struct ID *id, struct AnimData *adt, float ctime, short recalc); +void BKE_animsys_evaluate_animdata(struct Scene *scene, struct ID *id, struct AnimData *adt, float ctime, short recalc); /* Evaluation of all ID-blocks with Animation Data blocks - Animation Data Only */ -void BKE_animsys_evaluate_all_animation(struct Main *main, float ctime); +void BKE_animsys_evaluate_all_animation(struct Main *main, struct Scene *scene, float ctime); /* ------------ Specialised API --------------- */ diff --git a/source/blender/blenkernel/BKE_armature.h b/source/blender/blenkernel/BKE_armature.h index efa87532859..7d60c00156d 100644 --- a/source/blender/blenkernel/BKE_armature.h +++ b/source/blender/blenkernel/BKE_armature.h @@ -1,6 +1,4 @@ /* - * $Id$ - * * ***** BEGIN GPL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or diff --git a/source/blender/blenkernel/BKE_blender.h b/source/blender/blenkernel/BKE_blender.h index 07f0885372a..742240d53b5 100644 --- a/source/blender/blenkernel/BKE_blender.h +++ b/source/blender/blenkernel/BKE_blender.h @@ -43,17 +43,17 @@ extern "C" { /* these lines are grep'd, watch out for our not-so-awesome regex * and keep comment above the defines. * Use STRINGIFY() rather than defining with quotes */ -#define BLENDER_VERSION 257 -#define BLENDER_SUBVERSION 1 +#define BLENDER_VERSION 259 +#define BLENDER_SUBVERSION 2 #define BLENDER_MINVERSION 250 #define BLENDER_MINSUBVERSION 0 /* used by packaging tools */ /* can be left blank, otherwise a,b,c... etc with no quotes */ -#define BLENDER_VERSION_CHAR b +#define BLENDER_VERSION_CHAR /* alpha/beta/rc/release, docs use this */ -#define BLENDER_VERSION_CYCLE beta +#define BLENDER_VERSION_CYCLE alpha struct ListBase; struct MemFile; diff --git a/source/blender/blenkernel/BKE_constraint.h b/source/blender/blenkernel/BKE_constraint.h index 7c0e7050a9f..925d1180dbd 100644 --- a/source/blender/blenkernel/BKE_constraint.h +++ b/source/blender/blenkernel/BKE_constraint.h @@ -1,6 +1,4 @@ /* - * $Id$ - * * ***** BEGIN GPL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or @@ -154,6 +152,7 @@ void constraints_clear_evalob(struct bConstraintOb *cob); void constraint_mat_convertspace(struct Object *ob, struct bPoseChannel *pchan, float mat[][4], short from, short to); void get_constraint_target_matrix(struct Scene *scene, struct bConstraint *con, int n, short ownertype, void *ownerdata, float mat[][4], float ctime); +void get_constraint_targets_for_solving(struct bConstraint *con, struct bConstraintOb *ob, struct ListBase *targets, float ctime); void solve_constraints(struct ListBase *conlist, struct bConstraintOb *cob, float ctime); #ifdef __cplusplus diff --git a/source/blender/blenkernel/BKE_curve.h b/source/blender/blenkernel/BKE_curve.h index 0491116d199..557ce417b14 100644 --- a/source/blender/blenkernel/BKE_curve.h +++ b/source/blender/blenkernel/BKE_curve.h @@ -115,5 +115,6 @@ int minmax_curve(struct Curve *cu, float min[3], float max[3]); int curve_center_median(struct Curve *cu, float cent[3]); int curve_center_bounds(struct Curve *cu, float cent[3]); void curve_translate(struct Curve *cu, float offset[3], int do_keys); +void curve_delete_material_index(struct Curve *cu, int index); #endif diff --git a/source/blender/blenkernel/BKE_depsgraph.h b/source/blender/blenkernel/BKE_depsgraph.h index 14251fb1762..f36073ba841 100644 --- a/source/blender/blenkernel/BKE_depsgraph.h +++ b/source/blender/blenkernel/BKE_depsgraph.h @@ -51,22 +51,23 @@ struct GHash; /* **** DAG relation types *** */ /* scene link to object */ -#define DAG_RL_SCENE 1 +#define DAG_RL_SCENE (1<<0) /* object link to data */ -#define DAG_RL_DATA 2 +#define DAG_RL_DATA (1<<1) /* object changes object (parent, track, constraints) */ -#define DAG_RL_OB_OB 4 +#define DAG_RL_OB_OB (1<<2) /* object changes obdata (hooks, constraints) */ -#define DAG_RL_OB_DATA 8 +#define DAG_RL_OB_DATA (1<<3) /* data changes object (vertex parent) */ -#define DAG_RL_DATA_OB 16 +#define DAG_RL_DATA_OB (1<<4) /* data changes data (deformers) */ -#define DAG_RL_DATA_DATA 32 +#define DAG_RL_DATA_DATA (1<<5) -#define DAG_NO_RELATION 64 -#define DAG_RL_ALL 63 -#define DAG_RL_ALL_BUT_DATA 61 +#define DAG_NO_RELATION (1<<6) + +#define DAG_RL_ALL_BUT_DATA (DAG_RL_SCENE|DAG_RL_OB_OB|DAG_RL_OB_DATA|DAG_RL_DATA_OB|DAG_RL_DATA_DATA) +#define DAG_RL_ALL (DAG_RL_ALL_BUT_DATA|DAG_RL_DATA) typedef void (*graph_action_func)(void * ob, void **data); diff --git a/source/blender/blenkernel/BKE_displist.h b/source/blender/blenkernel/BKE_displist.h index 68745975dae..b00db53a199 100644 --- a/source/blender/blenkernel/BKE_displist.h +++ b/source/blender/blenkernel/BKE_displist.h @@ -97,15 +97,10 @@ extern void makeDispListCurveTypes_forRender(struct Scene *scene, struct Object extern void makeDispListCurveTypes_forOrco(struct Scene *scene, struct Object *ob, struct ListBase *dispbase); extern void makeDispListMBall(struct Scene *scene, struct Object *ob); extern void makeDispListMBall_forRender(struct Scene *scene, struct Object *ob, struct ListBase *dispbase); -extern void shadeDispList(struct Scene *scene, struct Base *base); -extern void shadeMeshMCol(struct Scene *scene, struct Object *ob, struct Mesh *me); int surfindex_displist(DispList *dl, int a, int *b, int *p1, int *p2, int *p3, int *p4); -void reshadeall_displist(struct Scene *scene); void filldisplist(struct ListBase *dispbase, struct ListBase *to, int flipnormal); -void fastshade_free_render(void); - float calc_taper(struct Scene *scene, struct Object *taperobj, int cur, int tot); /* add Orco layer to the displist object which has got derived mesh and return orco */ diff --git a/source/blender/blenkernel/BKE_effect.h b/source/blender/blenkernel/BKE_effect.h index 97ac711651b..12f9383cefb 100644 --- a/source/blender/blenkernel/BKE_effect.h +++ b/source/blender/blenkernel/BKE_effect.h @@ -105,6 +105,7 @@ typedef struct EffectorCache { /* precalculated for guides */ struct GuideEffectorData *guide_data; float guide_loc[4], guide_dir[3], guide_radius; + float velocity[3]; float frame; int flag; diff --git a/source/blender/blenkernel/BKE_fcurve.h b/source/blender/blenkernel/BKE_fcurve.h index b791e29a38e..244fda33a52 100644 --- a/source/blender/blenkernel/BKE_fcurve.h +++ b/source/blender/blenkernel/BKE_fcurve.h @@ -199,7 +199,7 @@ struct FCurve *list_find_fcurve(ListBase *list, const char rna_path[], const int struct FCurve *iter_step_fcurve (struct FCurve *fcu_iter, const char rna_path[]); /* high level function to get an fcurve from C without having the rna */ -struct FCurve *id_data_find_fcurve(ID *id, void *data, struct StructRNA *type, const char *prop_name, int index); +struct FCurve *id_data_find_fcurve(ID *id, void *data, struct StructRNA *type, const char *prop_name, int index, char *driven); /* Get list of LinkData's containing pointers to the F-Curves which control the types of data indicated * e.g. numMatches = list_find_data_fcurves(matches, &act->curves, "pose.bones[", "MyFancyBone"); diff --git a/source/blender/blenkernel/BKE_global.h b/source/blender/blenkernel/BKE_global.h index d21b0428d76..0e48673f1b1 100644 --- a/source/blender/blenkernel/BKE_global.h +++ b/source/blender/blenkernel/BKE_global.h @@ -92,9 +92,6 @@ typedef struct Global { /* save the allowed windowstate of blender when using -W or -w */ int windowstate; - - /* ndof device found ? */ - int ndofdevice; } Global; /* **************** GLOBAL ********************* */ @@ -114,7 +111,7 @@ typedef struct Global { #define G_SCRIPT_OVERRIDE_PREF (1 << 14) /* when this flag is set ignore the userprefs */ /* #define G_NOFROZEN (1 << 17) also removed */ -#define G_GREASEPENCIL (1 << 17) +/* #define G_GREASEPENCIL (1 << 17) also removed */ /* #define G_AUTOMATKEYS (1 << 30) also removed */ @@ -174,5 +171,3 @@ extern Global G; #endif #endif - - diff --git a/source/blender/blenkernel/BKE_image.h b/source/blender/blenkernel/BKE_image.h index 10910493ec9..0c31083a266 100644 --- a/source/blender/blenkernel/BKE_image.h +++ b/source/blender/blenkernel/BKE_image.h @@ -60,7 +60,7 @@ int BKE_ftype_to_imtype(int ftype); int BKE_imtype_to_ftype(int imtype); int BKE_imtype_is_movie(int imtype); -struct anim *openanim(char * name, int flags); +struct anim *openanim(char * name, int flags, int streamindex); void image_de_interlace(struct Image *ima, int odd); diff --git a/source/blender/blenkernel/BKE_library.h b/source/blender/blenkernel/BKE_library.h index 871a78bbab3..0d6d41109b4 100644 --- a/source/blender/blenkernel/BKE_library.h +++ b/source/blender/blenkernel/BKE_library.h @@ -44,6 +44,8 @@ struct Main; struct Library; struct wmWindowManager; struct bContext; +struct PointerRNA; +struct PropertyRNA; void *alloc_libblock(struct ListBase *lb, short type, const char *name); void *copy_libblock(void *rt); @@ -53,6 +55,7 @@ void id_lib_extern(struct ID *id); void id_us_plus(struct ID *id); void id_us_min(struct ID *id); int id_make_local(struct ID *id, int test); +int id_single_user(struct bContext *C, struct ID *id, struct PointerRNA *ptr, struct PropertyRNA *prop); int id_copy(struct ID *id, struct ID **newid, int test); int id_unlink(struct ID *id, int test); diff --git a/source/blender/blenkernel/BKE_main.h b/source/blender/blenkernel/BKE_main.h index df6a304f0b3..c25882d1dd6 100644 --- a/source/blender/blenkernel/BKE_main.h +++ b/source/blender/blenkernel/BKE_main.h @@ -77,6 +77,7 @@ typedef struct Main { ListBase script; ListBase vfont; ListBase text; + ListBase speaker; ListBase sound; ListBase group; ListBase armature; diff --git a/source/blender/blenkernel/BKE_material.h b/source/blender/blenkernel/BKE_material.h index c445408609c..88965d12e4a 100644 --- a/source/blender/blenkernel/BKE_material.h +++ b/source/blender/blenkernel/BKE_material.h @@ -78,7 +78,7 @@ int object_remove_material_slot(struct Object *ob); /* rna api */ void material_append_id(struct ID *id, struct Material *ma); -struct Material *material_pop_id(struct ID *id, int index); +struct Material *material_pop_id(struct ID *id, int index, int remove_material_slot); /* rendering */ diff --git a/source/blender/blenkernel/BKE_modifier.h b/source/blender/blenkernel/BKE_modifier.h index 648e67cad8a..28950e4b2eb 100644 --- a/source/blender/blenkernel/BKE_modifier.h +++ b/source/blender/blenkernel/BKE_modifier.h @@ -101,6 +101,7 @@ typedef enum { typedef void (*ObjectWalkFunc)(void *userData, struct Object *ob, struct Object **obpoin); typedef void (*IDWalkFunc)(void *userData, struct Object *ob, struct ID **idpoin); +typedef void (*TexWalkFunc)(void *userData, struct Object *ob, struct ModifierData *md, const char *propname); typedef struct ModifierTypeInfo { /* The user visible name for this modifier */ @@ -284,6 +285,16 @@ typedef struct ModifierTypeInfo { */ void (*foreachIDLink)(struct ModifierData *md, struct Object *ob, IDWalkFunc walk, void *userData); + + /* Should call the given walk function for each texture that the + * modifier data stores. This is used for finding all textures in + * the context for the UI. + * + * This function is optional. If it is not present, it will be + * assumed the modifier has no textures. + */ + void (*foreachTexLink)(struct ModifierData *md, struct Object *ob, + TexWalkFunc walk, void *userData); } ModifierTypeInfo; ModifierTypeInfo *modifierType_getInfo (ModifierType type); @@ -315,6 +326,10 @@ void modifiers_foreachObjectLink(struct Object *ob, void modifiers_foreachIDLink(struct Object *ob, IDWalkFunc walk, void *userData); +void modifiers_foreachTexLink(struct Object *ob, + TexWalkFunc walk, + void *userData); + struct ModifierData *modifiers_findByType(struct Object *ob, ModifierType type); struct ModifierData *modifiers_findByName(struct Object *ob, const char *name); void modifiers_clearErrors(struct Object *ob); diff --git a/source/blender/blenkernel/BKE_nla.h b/source/blender/blenkernel/BKE_nla.h index 0206756a1ad..773c5ced1cb 100644 --- a/source/blender/blenkernel/BKE_nla.h +++ b/source/blender/blenkernel/BKE_nla.h @@ -1,6 +1,4 @@ /* - * $Id$ - * * ***** BEGIN GPL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or @@ -39,6 +37,8 @@ struct AnimData; struct NlaStrip; struct NlaTrack; struct bAction; +struct Scene; +struct Speaker; /* ----------------------------- */ /* Data Management */ @@ -54,6 +54,7 @@ void copy_nladata(ListBase *dst, ListBase *src); struct NlaTrack *add_nlatrack(struct AnimData *adt, struct NlaTrack *prev); struct NlaStrip *add_nlastrip(struct bAction *act); struct NlaStrip *add_nlastrip_to_stack(struct AnimData *adt, struct bAction *act); +struct NlaStrip *add_nla_soundstrip(struct Scene *scene, struct Speaker *spk); /* ----------------------------- */ /* API */ diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index a126f405d09..1de3c295f4d 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -37,6 +37,10 @@ * \ingroup bke */ +#include "DNA_listBase.h" + +#include "RNA_types.h" + /* not very important, but the stack solver likes to know a maximum */ #define MAX_SOCKET 64 @@ -46,62 +50,151 @@ struct bNodeLink; struct bNodeSocket; struct bNodeStack; struct bNodeTree; +struct bNodeTreeExec; struct GPUMaterial; struct GPUNode; struct GPUNodeStack; struct ID; struct ListBase; struct Main; +struct uiBlock; +struct uiLayout; struct MTex; struct PointerRNA; struct rctf; struct RenderData; struct Scene; struct Tex; -struct uiLayout; - +struct SpaceNode; +struct ARegion; +struct Object; /* ************** NODE TYPE DEFINITIONS ***** */ -typedef struct bNodeSocketType { +/** Compact definition of a node socket. + * Can be used to quickly define a list of static sockets for a node, + * which are added to each new node of that type. + * + * \deprecated New nodes should add default sockets in the initialization + * function instead. This struct is mostly kept for old nodes and should + * be removed some time. + */ +typedef struct bNodeSocketTemplate { int type, limit; - const char *name; - float val1, val2, val3, val4; /* default alloc value for inputs */ - float min, max; /* default range for inputs */ + char name[32]; + float val1, val2, val3, val4; /* default alloc value for inputs */ + float min, max; + PropertySubType subtype; /* after this line is used internal only */ - struct bNodeSocket *sock; /* used during verify_types */ + struct bNodeSocket *sock; /* used to hold verified socket */ +} bNodeSocketTemplate; + +typedef void (*NodeSocketButtonFunction)(const struct bContext *C, struct uiBlock *block, + struct bNodeTree *ntree, struct bNode *node, struct bNodeSocket *sock, + const char *name, int x, int y, int width); + +/** Defines a socket type. + * Defines the appearance and behavior of a socket in the UI. + */ +typedef struct bNodeSocketType { + int type; + char ui_name[32]; + char ui_description[128]; + int ui_icon; + char ui_color[4]; + + const char *value_structname; + int value_structsize; + + NodeSocketButtonFunction buttonfunc; } bNodeSocketType; +/** Template for creating a node. + * Stored required parameters to make a new node of a specific type. + */ +typedef struct bNodeTemplate { + int type; + + /* group tree */ + struct bNodeTree *ngroup; +} bNodeTemplate; + +/** Defines a node type. + * Initial attributes and constants for a node as well as callback functions + * implementing the node behavior. + */ typedef struct bNodeType { void *next,*prev; + short needs_free; /* set for allocated types that need to be freed */ + int type; - const char *name; /* can be allocated too */ + char name[32]; float width, minwidth, maxwidth; + float height, minheight, maxheight; short nclass, flag; - bNodeSocketType *inputs, *outputs; + /* templates for static sockets */ + bNodeSocketTemplate *inputs, *outputs; char storagename[64]; /* struct name for DNA */ - void (*execfunc)(void *data, struct bNode *, struct bNodeStack **, struct bNodeStack **); - - /* this line is set on startup of blender */ + /// Main draw function for the node. + void (*drawfunc)(const struct bContext *C, struct ARegion *ar, struct SpaceNode *snode, struct bNodeTree *ntree, struct bNode *node); + /// Updates the node geometry attributes according to internal state before actual drawing. + void (*drawupdatefunc)(const struct bContext *C, struct bNodeTree *ntree, struct bNode *node); + /// Draw the option buttons on the node. void (*uifunc)(struct uiLayout *, struct bContext *C, struct PointerRNA *ptr); + /// Additional parameters in the side panel. + void (*uifuncbut)(struct uiLayout *, struct bContext *C, struct PointerRNA *ptr); + /// Optional custom label function for the node header. const char *(*labelfunc)(struct bNode *); - - void (*initfunc)(struct bNode *); - void (*freestoragefunc)(struct bNode *); - void (*copystoragefunc)(struct bNode *, struct bNode *); + /// Optional custom resize handle polling. + int (*resize_area_func)(struct bNode *node, int x, int y); - /* for use with dynamic typedefs */ - ID *id; - void *pynode; /* holds pointer to python script */ - void *pydict; /* holds pointer to python script dictionary (scope)*/ - + /// Called when the node is updated in the editor. + void (*updatefunc)(struct bNodeTree *ntree, struct bNode *node); + /// Check and update if internal ID data has changed. + void (*verifyfunc)(struct bNodeTree *ntree, struct bNode *node, struct ID *id); + + /// Initialize a new node instance of this type after creation. + void (*initfunc)(struct bNodeTree *ntree, struct bNode *node, struct bNodeTemplate *ntemp); + /// Free the custom storage data. + void (*freestoragefunc)(struct bNode *node); + /// Make a copy of the custom storage data. + void (*copystoragefunc)(struct bNode *node, struct bNode *target); + + /// Create a template from an existing node. + struct bNodeTemplate (*templatefunc)(struct bNode *); + /** If a node can be made from the template in the given node tree. + * \example Node groups can not be created inside their own node tree. + */ + int (*validfunc)(struct bNodeTree *ntree, struct bNodeTemplate *ntemp); + + /// Initialize a node tree associated to this node type. + void (*inittreefunc)(struct bNodeTree *ntree); + /// Update a node tree associated to this node type. + void (*updatetreefunc)(struct bNodeTree *ntree); + + /* group edit callbacks for operators */ + /* XXX this is going to be changed as required by the UI */ + struct bNodeTree *(*group_edit_get)(struct bNode *node); + struct bNodeTree *(*group_edit_set)(struct bNode *node, int edit); + void (*group_edit_clear)(struct bNode *node); + + + /* **** execution callbacks **** */ + void *(*initexecfunc)(struct bNode *node); + void (*freeexecfunc)(struct bNode *node, void *nodedata); + void (*execfunc)(void *data, struct bNode *, struct bNodeStack **, struct bNodeStack **); + /* XXX this alternative exec function has been added to avoid changing all node types. + * when a final generic version of execution code is defined, this will be changed anyway + */ + void (*newexecfunc)(void *data, int thread, struct bNode *, void *nodedata, struct bNodeStack **, struct bNodeStack **); /* gpu */ int (*gpufunc)(struct GPUMaterial *mat, struct bNode *node, struct GPUNodeStack *in, struct GPUNodeStack *out); - + /* extended gpu function */ + int (*gpuextfunc)(struct GPUMaterial *mat, struct bNode *node, void *nodedata, struct GPUNodeStack *in, struct GPUNodeStack *out); } bNodeType; /* node->exec, now in use for composites (#define for break is same as ready yes) */ @@ -112,72 +205,124 @@ typedef struct bNodeType { #define NODE_FREEBUFS 8 #define NODE_SKIPPED 16 +/* sim_exec return value */ +#define NODE_EXEC_FINISHED 0 +#define NODE_EXEC_SUSPEND 1 + /* nodetype->nclass, for add-menu and themes */ -#define NODE_CLASS_INPUT 0 -#define NODE_CLASS_OUTPUT 1 -#define NODE_CLASS_OP_COLOR 3 -#define NODE_CLASS_OP_VECTOR 4 -#define NODE_CLASS_OP_FILTER 5 -#define NODE_CLASS_GROUP 6 -#define NODE_CLASS_FILE 7 -#define NODE_CLASS_CONVERTOR 8 -#define NODE_CLASS_MATTE 9 -#define NODE_CLASS_DISTORT 10 -#define NODE_CLASS_OP_DYNAMIC 11 -#define NODE_CLASS_PATTERN 12 -#define NODE_CLASS_TEXTURE 13 +#define NODE_CLASS_INPUT 0 +#define NODE_CLASS_OUTPUT 1 +#define NODE_CLASS_OP_COLOR 3 +#define NODE_CLASS_OP_VECTOR 4 +#define NODE_CLASS_OP_FILTER 5 +#define NODE_CLASS_GROUP 6 +#define NODE_CLASS_FILE 7 +#define NODE_CLASS_CONVERTOR 8 +#define NODE_CLASS_MATTE 9 +#define NODE_CLASS_DISTORT 10 +#define NODE_CLASS_OP_DYNAMIC 11 +#define NODE_CLASS_PATTERN 12 +#define NODE_CLASS_TEXTURE 13 +#define NODE_CLASS_EXECUTION 14 +#define NODE_CLASS_GETDATA 15 +#define NODE_CLASS_SETDATA 16 +#define NODE_CLASS_MATH 17 +#define NODE_CLASS_MATH_VECTOR 18 +#define NODE_CLASS_MATH_ROTATION 19 +#define NODE_CLASS_PARTICLES 25 +#define NODE_CLASS_TRANSFORM 30 +#define NODE_CLASS_COMBINE 31 +#define NODE_CLASS_LAYOUT 100 /* enum values for input/output */ #define SOCK_IN 1 #define SOCK_OUT 2 +struct bNodeTreeExec; + +typedef void (*bNodeTreeCallback)(void *calldata, struct ID *owner_id, struct bNodeTree *ntree); +typedef struct bNodeTreeType +{ + int type; /* type identifier */ + char idname[64]; /* id name for RNA identification */ + + ListBase node_types; /* type definitions */ + + /* callbacks */ + void (*free_cache)(struct bNodeTree *ntree); + void (*free_node_cache)(struct bNodeTree *ntree, struct bNode *node); + void (*foreach_nodetree)(struct Main *main, void *calldata, bNodeTreeCallback func); /* iteration over all node trees */ + + /* calls allowing threaded composite */ + void (*localize)(struct bNodeTree *localtree, struct bNodeTree *ntree); + void (*local_sync)(struct bNodeTree *localtree, struct bNodeTree *ntree); + void (*local_merge)(struct bNodeTree *localtree, struct bNodeTree *ntree); + + /* Tree update. Overrides nodetype->updatetreefunc! */ + void (*update)(struct bNodeTree *ntree); + /* Node update. Overrides nodetype->updatefunc! */ + void (*update_node)(struct bNodeTree *ntree, struct bNode *node); + + int (*validate_link)(struct bNodeTree *ntree, struct bNodeLink *link); +} bNodeTreeType; + /* ************** GENERIC API, TREES *************** */ -void ntreeVerifyTypes(struct bNodeTree *ntree); +struct bNodeTreeType *ntreeGetType(int type); +struct bNodeType *ntreeGetNodeType(struct bNodeTree *ntree); +struct bNodeSocketType *ntreeGetSocketType(int type); -struct bNodeTree *ntreeAddTree(const char *name, int type, const short is_group); +struct bNodeTree *ntreeAddTree(const char *name, int type, int nodetype); void ntreeInitTypes(struct bNodeTree *ntree); -//void ntreeMakeGroupSockets(struct bNodeTree *ntree); -void ntreeUpdateType(struct bNodeTree *ntree, struct bNodeType *ntype); void ntreeFreeTree(struct bNodeTree *ntree); struct bNodeTree *ntreeCopyTree(struct bNodeTree *ntree); void ntreeSwitchID(struct bNodeTree *ntree, struct ID *sce_from, struct ID *sce_to); void ntreeMakeLocal(struct bNodeTree *ntree); +int ntreeHasType(struct bNodeTree *ntree, int type); void ntreeSocketUseFlags(struct bNodeTree *ntree); -void ntreeSolveOrder(struct bNodeTree *ntree); +void ntreeUpdateTree(struct bNodeTree *ntree); +/* XXX Currently each tree update call does call to ntreeVerifyNodes too. + * Some day this should be replaced by a decent depsgraph automatism! + */ +void ntreeVerifyNodes(struct Main *main, struct ID *id); -void ntreeBeginExecTree(struct bNodeTree *ntree); -void ntreeExecTree(struct bNodeTree *ntree, void *callerdata, int thread); -void ntreeCompositExecTree(struct bNodeTree *ntree, struct RenderData *rd, int do_previews); -void ntreeEndExecTree(struct bNodeTree *ntree); +void ntreeGetDependencyList(struct bNodeTree *ntree, struct bNode ***deplist, int *totnodes); +/* XXX old trees handle output flags automatically based on special output node types and last active selection. + * new tree types have a per-output socket flag to indicate the final output to use explicitly. + */ +void ntreeSetOutput(struct bNodeTree *ntree); void ntreeInitPreview(struct bNodeTree *, int xsize, int ysize); void ntreeClearPreview(struct bNodeTree *ntree); void ntreeFreeCache(struct bNodeTree *ntree); - - /* calls allowing threaded composite */ + +int ntreeNodeExists(struct bNodeTree *ntree, struct bNode *testnode); +int ntreeOutputExists(struct bNode *node, struct bNodeSocket *testsock); struct bNodeTree *ntreeLocalize(struct bNodeTree *ntree); void ntreeLocalSync(struct bNodeTree *localtree, struct bNodeTree *ntree); void ntreeLocalMerge(struct bNodeTree *localtree, struct bNodeTree *ntree); /* ************** GENERIC API, NODES *************** */ -void nodeVerifyType(struct bNodeTree *ntree, struct bNode *node); +struct bNodeSocket *nodeAddSocket(struct bNodeTree *ntree, struct bNode *node, int in_out, const char *name, int type); +struct bNodeSocket *nodeInsertSocket(struct bNodeTree *ntree, struct bNode *node, int in_out, struct bNodeSocket *next_sock, const char *name, int type); +void nodeRemoveSocket(struct bNodeTree *ntree, struct bNode *node, struct bNodeSocket *sock); +void nodeRemoveAllSockets(struct bNodeTree *ntree, struct bNode *node); void nodeAddToPreview(struct bNode *, float *, int, int, int); +struct bNode *nodeAddNode(struct bNodeTree *ntree, struct bNodeTemplate *ntemp); void nodeUnlinkNode(struct bNodeTree *ntree, struct bNode *node); void nodeUniqueName(struct bNodeTree *ntree, struct bNode *node); -void nodeAddSockets(struct bNode *node, struct bNodeType *ntype); -struct bNode *nodeAddNodeType(struct bNodeTree *ntree, int type, struct bNodeTree *ngroup, struct ID *id); -void nodeRegisterType(struct ListBase *typelist, const struct bNodeType *ntype) ; -void nodeUpdateType(struct bNodeTree *ntree, struct bNode* node, struct bNodeType *ntype); + +void nodeRegisterType(struct ListBase *typelist, struct bNodeType *ntype) ; void nodeMakeDynamicType(struct bNode *node); int nodeDynamicUnlinkText(struct ID *txtid); + void nodeFreeNode(struct bNodeTree *ntree, struct bNode *node); struct bNode *nodeCopyNode(struct bNodeTree *ntree, struct bNode *node); @@ -185,6 +330,10 @@ struct bNodeLink *nodeAddLink(struct bNodeTree *ntree, struct bNode *fromnode, s void nodeRemLink(struct bNodeTree *ntree, struct bNodeLink *link); void nodeRemSocketLinks(struct bNodeTree *ntree, struct bNodeSocket *sock); +void nodeSpaceCoords(struct bNode *node, float *locx, float *locy); +void nodeAttachNode(struct bNode *node, struct bNode *parent); +void nodeDetachNode(struct bNode *node); + struct bNode *nodeFindNodebyName(struct bNodeTree *ntree, const char *name); int nodeFindNode(struct bNodeTree *ntree, struct bNodeSocket *sock, struct bNode **nodep, int *sockindex, int *in_out); @@ -201,41 +350,71 @@ void NodeTagChanged(struct bNodeTree *ntree, struct bNode *node); int NodeTagIDChanged(struct bNodeTree *ntree, struct ID *id); void ntreeClearTags(struct bNodeTree *ntree); -/* ************** Groups ****************** */ - -struct bNode *nodeMakeGroupFromSelected(struct bNodeTree *ntree); -int nodeGroupUnGroup(struct bNodeTree *ntree, struct bNode *gnode); - -void nodeGroupVerify(struct bNodeTree *ngroup); -void nodeGroupSocketUseFlags(struct bNodeTree *ngroup); - -void nodeGroupCopy(struct bNode *gnode); +void nodeFreePreview(struct bNode *node); -struct bNodeSocket *nodeGroupAddSocket(struct bNodeTree *ngroup, const char *name, int type, int in_out); -struct bNodeSocket *nodeGroupExposeSocket(struct bNodeTree *ngroup, struct bNodeSocket *sock, int in_out); -void nodeGroupExposeAllSockets(struct bNodeTree *ngroup); -void nodeGroupRemoveSocket(struct bNodeTree *ngroup, struct bNodeSocket *gsock, int in_out); +/* ************** NODE TYPE ACCESS *************** */ -/* ************** COMMON NODES *************** */ +struct bNodeTemplate nodeMakeTemplate(struct bNode *node); +int nodeValid(struct bNodeTree *ntree, struct bNodeTemplate *ntemp); +const char* nodeLabel(struct bNode *node); +struct bNodeTree *nodeGroupEditGet(struct bNode *node); +struct bNodeTree *nodeGroupEditSet(struct bNode *node, int edit); +void nodeGroupEditClear(struct bNode *node); /* Init a new node type struct with default values and callbacks */ -void node_type_base(struct bNodeType *ntype, int type, const char *name, short nclass, short flag, - struct bNodeSocketType *inputs, struct bNodeSocketType *outputs); +void node_type_base(struct bNodeType *ntype, int type, const char *name, short nclass, short flag); +void node_type_socket_templates(struct bNodeType *ntype, struct bNodeSocketTemplate *inputs, struct bNodeSocketTemplate *outputs); void node_type_size(struct bNodeType *ntype, int width, int minwidth, int maxwidth); -void node_type_init(struct bNodeType *ntype, void (*initfunc)(struct bNode *)); +void node_type_init(struct bNodeType *ntype, void (*initfunc)(struct bNodeTree *ntree, struct bNode *node, struct bNodeTemplate *ntemp)); +void node_type_valid(struct bNodeType *ntype, int (*validfunc)(struct bNodeTree *ntree, struct bNodeTemplate *ntemp)); void node_type_storage(struct bNodeType *ntype, const char *storagename, void (*freestoragefunc)(struct bNode *), void (*copystoragefunc)(struct bNode *, struct bNode *)); +void node_type_label(struct bNodeType *ntype, const char *(*labelfunc)(struct bNode *)); +void node_type_template(struct bNodeType *ntype, struct bNodeTemplate (*templatefunc)(struct bNode *)); +void node_type_update(struct bNodeType *ntype, + void (*updatefunc)(struct bNodeTree *ntree, struct bNode *node), + void (*verifyfunc)(struct bNodeTree *ntree, struct bNode *node, struct ID *id)); +void node_type_tree(struct bNodeType *ntype, + void (*inittreefunc)(struct bNodeTree *), + void (*updatetreefunc)(struct bNodeTree *)); +void node_type_group_edit(struct bNodeType *ntype, + struct bNodeTree *(*group_edit_get)(struct bNode *node), + struct bNodeTree *(*group_edit_set)(struct bNode *node, int edit), + void (*group_edit_clear)(struct bNode *node)); + void node_type_exec(struct bNodeType *ntype, void (*execfunc)(void *data, struct bNode *, struct bNodeStack **, struct bNodeStack **)); +void node_type_exec_new(struct bNodeType *ntype, + void *(*initexecfunc)(struct bNode *node), + void (*freeexecfunc)(struct bNode *node, void *nodedata), + void (*newexecfunc)(void *data, int thread, struct bNode *, void *nodedata, struct bNodeStack **, struct bNodeStack **)); void node_type_gpu(struct bNodeType *ntype, int (*gpufunc)(struct GPUMaterial *mat, struct bNode *node, struct GPUNodeStack *in, struct GPUNodeStack *out)); -void node_type_label(struct bNodeType *ntype, const char *(*labelfunc)(struct bNode *)); +void node_type_gpu_ext(struct bNodeType *ntype, int (*gpuextfunc)(struct GPUMaterial *mat, struct bNode *node, void *nodedata, struct GPUNodeStack *in, struct GPUNodeStack *out)); + +/* ************** COMMON NODES *************** */ #define NODE_GROUP 2 -#define NODE_GROUP_MENU 1000 -#define NODE_DYNAMIC_MENU 4000 +#define NODE_FORLOOP 3 +#define NODE_WHILELOOP 4 +#define NODE_FRAME 5 +#define NODE_GROUP_MENU 10000 +#define NODE_DYNAMIC_MENU 20000 + +/* look up a socket on a group node by the internal group socket */ +struct bNodeSocket *node_group_find_input(struct bNode *gnode, struct bNodeSocket *gsock); +struct bNodeSocket *node_group_find_output(struct bNode *gnode, struct bNodeSocket *gsock); + +struct bNodeSocket *node_group_add_socket(struct bNodeTree *ngroup, const char *name, int type, int in_out); +struct bNodeSocket *node_group_expose_socket(struct bNodeTree *ngroup, struct bNodeSocket *sock, int in_out); +void node_group_expose_all_sockets(struct bNodeTree *ngroup); +void node_group_remove_socket(struct bNodeTree *ngroup, struct bNodeSocket *gsock, int in_out); -void register_node_type_group(ListBase *lb); +struct bNode *node_group_make_from_selected(struct bNodeTree *ntree); +int node_group_ungroup(struct bNodeTree *ntree, struct bNode *gnode); + +/* in node_common.c */ +void register_node_type_frame(ListBase *lb); /* ************** SHADER NODES *************** */ @@ -285,11 +464,10 @@ struct ShadeResult; #define NODE_DYNAMIC_REPARSE 6 /* 64 */ #define NODE_DYNAMIC_SET 15 /* sign */ -/* the type definitions array */ -extern struct ListBase node_all_shaders; - /* API */ +struct bNodeTreeExec *ntreeShaderBeginExecTree(struct bNodeTree *ntree, int use_tree_data); +void ntreeShaderEndExecTree(struct bNodeTreeExec *exec, int use_tree_data); void ntreeShaderExecTree(struct bNodeTree *ntree, struct ShadeInput *shi, struct ShadeResult *shr); void ntreeShaderGetTexcoMode(struct bNodeTree *ntree, int osa, short *texco, int *mode); void nodeShaderSynchronizeID(struct bNode *node, int copyto); @@ -319,9 +497,10 @@ void ntreeGPUMaterialNodes(struct bNodeTree *ntree, struct GPUMaterial *mat); #define RRES_OUT_REFRACT 12 #define RRES_OUT_INDIRECT 13 #define RRES_OUT_INDEXOB 14 -#define RRES_OUT_MIST 15 -#define RRES_OUT_EMIT 16 -#define RRES_OUT_ENV 17 +#define RRES_OUT_INDEXMA 15 +#define RRES_OUT_MIST 16 +#define RRES_OUT_EMIT 17 +#define RRES_OUT_ENV 18 /* note: types are needed to restore callbacks, don't change values */ #define CMP_NODE_VIEWER 201 @@ -413,11 +592,11 @@ void ntreeGPUMaterialNodes(struct bNodeTree *ntree, struct GPUMaterial *mat); #define CMP_SCALE_RENDERPERCENT 3 -/* the type definitions array */ -extern struct ListBase node_all_composit; - /* API */ struct CompBuf; +struct bNodeTreeExec *ntreeCompositBeginExecTree(struct bNodeTree *ntree, int use_tree_data); +void ntreeCompositEndExecTree(struct bNodeTreeExec *exec, int use_tree_data); +void ntreeCompositExecTree(struct bNodeTree *ntree, struct RenderData *rd, int do_previews); void ntreeCompositTagRender(struct Scene *sce); int ntreeCompositTagAnimated(struct bNodeTree *ntree); void ntreeCompositTagGenerators(struct bNodeTree *ntree); @@ -457,23 +636,22 @@ struct TexResult; #define TEX_NODE_PROC 500 #define TEX_NODE_PROC_MAX 600 -extern struct ListBase node_all_textures; - /* API */ int ntreeTexTagAnimated(struct bNodeTree *ntree); void ntreeTexSetPreviewFlag(int); -int ntreeTexExecTree(struct bNodeTree *ntree, struct TexResult *target, float *coord, float *dxt, float *dyt, int osatex, short thread, struct Tex *tex, short which_output, int cfra, int preview, struct ShadeInput *shi, struct MTex *mtex); void ntreeTexCheckCyclics(struct bNodeTree *ntree); char* ntreeTexOutputMenu(struct bNodeTree *ntree); +struct bNodeTreeExec *ntreeTexBeginExecTree(struct bNodeTree *ntree, int use_tree_data); +void ntreeTexEndExecTree(struct bNodeTreeExec *exec, int use_tree_data); +int ntreeTexExecTree(struct bNodeTree *ntree, struct TexResult *target, float *coord, float *dxt, float *dyt, int osatex, short thread, struct Tex *tex, short which_output, int cfra, int preview, struct ShadeInput *shi, struct MTex *mtex); + -/**/ +/*************************************************/ void init_nodesystem(void); void free_nodesystem(void); -/**/ - void clear_scene_in_nodes(struct Main *bmain, struct Scene *sce); #endif diff --git a/source/blender/blenkernel/BKE_particle.h b/source/blender/blenkernel/BKE_particle.h index 4dfc53e1734..5b565223ece 100644 --- a/source/blender/blenkernel/BKE_particle.h +++ b/source/blender/blenkernel/BKE_particle.h @@ -147,7 +147,8 @@ typedef struct ParticleBillboardData struct Object *ob; float vec[3], vel[3]; float offset[2]; - float size, tilt, random, time; + float size[2]; + float tilt, random, time; int uv[3]; int lock, num; int totnum; @@ -300,6 +301,8 @@ void psys_get_pointcache_start_end(struct Scene *scene, ParticleSystem *psys, in void psys_check_boid_data(struct ParticleSystem *psys); +void psys_get_birth_coordinates(struct ParticleSimulationData *sim, struct ParticleData *pa, struct ParticleKey *state, float dtime, float cfra); + void particle_system_update(struct Scene *scene, struct Object *ob, struct ParticleSystem *psys); /* ----------- functions needed only inside particlesystem ------------ */ diff --git a/source/blender/blenkernel/BKE_sequencer.h b/source/blender/blenkernel/BKE_sequencer.h index bedd58876bc..cf68e5795b4 100644 --- a/source/blender/blenkernel/BKE_sequencer.h +++ b/source/blender/blenkernel/BKE_sequencer.h @@ -43,6 +43,7 @@ struct Scene; struct Sequence; struct Strip; struct StripElem; +struct bSound; #define MAXSEQ 32 @@ -177,6 +178,7 @@ int seq_recursive_apply(struct Sequence *seq, int (*apply_func)(struct Sequence /* maintainance functions, mostly for RNA */ // extern void seq_free_sequence(struct Scene *scene, struct Sequence *seq); +void seq_free_sequence_recurse(struct Scene *scene, struct Sequence *seq); void seq_free_strip(struct Strip *strip); void seq_free_editing(struct Scene *scene); void seq_free_clipboard(void); @@ -199,6 +201,11 @@ void update_changed_seq_and_deps(struct Scene *scene, struct Sequence *changed_s int input_have_to_preprocess( SeqRenderData context, struct Sequence * seq, float cfra); +void seq_proxy_rebuild(struct Main * bmain, + struct Scene *scene, struct Sequence * seq, + short *stop, short *do_update, float *progress); + + /* ********************************************************************** seqcache.c @@ -281,8 +288,10 @@ void free_imbuf_seq(struct Scene *scene, struct ListBase * seqbasep, int check_m struct Sequence *seq_dupli_recursive(struct Scene *scene, struct Scene *scene_to, struct Sequence * seq, int dupe_flag); int seq_swap(struct Sequence *seq_a, struct Sequence *seq_b, const char **error_str); -void seq_update_sound(struct Scene* scene, struct Sequence *seq); -void seq_update_muting(struct Scene* scene, struct Editing *ed); +void seq_update_sound_bounds_all(struct Scene *scene); +void seq_update_sound_bounds(struct Scene* scene, struct Sequence *seq); +void seq_update_muting(struct Editing *ed); +void seq_update_sound(struct Scene *scene, struct bSound *sound); void seqbase_sound_reload(struct Scene *scene, ListBase *seqbase); void seqbase_unique_name_recursive(ListBase *seqbasep, struct Sequence *seq); void seqbase_dupli_recursive(struct Scene *scene, struct Scene *scene_to, ListBase *nseqbase, ListBase *seqbase, int dupe_flag); diff --git a/source/blender/blenkernel/BKE_sound.h b/source/blender/blenkernel/BKE_sound.h index 04597fd666e..3728dd41089 100644 --- a/source/blender/blenkernel/BKE_sound.h +++ b/source/blender/blenkernel/BKE_sound.h @@ -35,17 +35,26 @@ * \author nzc */ +#define SOUND_WAVE_SAMPLES_PER_SECOND 250 + struct PackedFile; struct bSound; -struct bContext; struct ListBase; struct Main; struct Sequence; +typedef struct SoundWaveform +{ + int length; + float *data; +} SoundWaveform; + void sound_init_once(void); void sound_init(struct Main *main); +void sound_init_main(struct Main *bmain); + void sound_exit(void); void sound_force_device(int device); @@ -55,14 +64,16 @@ struct bSound* sound_new_file(struct Main *main, const char *filename); // XXX unused currently #if 0 -struct bSound* sound_new_buffer(struct bContext *C, struct bSound *source); +struct bSound* sound_new_buffer(struct Main *bmain, struct bSound *source); -struct bSound* sound_new_limiter(struct bContext *C, struct bSound *source, float start, float end); +struct bSound* sound_new_limiter(struct Main *bmain, struct bSound *source, float start, float end); #endif -void sound_delete(struct bContext *C, struct bSound* sound); +void sound_delete(struct Main *bmain, struct bSound* sound); + +void sound_cache(struct bSound* sound); -void sound_cache(struct bSound* sound, int ignore); +void sound_cache_notifying(struct Main* main, struct bSound* sound); void sound_delete_cache(struct bSound* sound); @@ -80,28 +91,50 @@ void sound_destroy_scene(struct Scene *scene); void sound_mute_scene(struct Scene *scene, int muted); +void sound_update_fps(struct Scene *scene); + +void sound_update_scene_listener(struct Scene *scene); + void* sound_scene_add_scene_sound(struct Scene *scene, struct Sequence* sequence, int startframe, int endframe, int frameskip); void* sound_add_scene_sound(struct Scene *scene, struct Sequence* sequence, int startframe, int endframe, int frameskip); void sound_remove_scene_sound(struct Scene *scene, void* handle); -void sound_mute_scene_sound(struct Scene *scene, void* handle, char mute); +void sound_mute_scene_sound(void* handle, char mute); void sound_move_scene_sound(struct Scene *scene, void* handle, int startframe, int endframe, int frameskip); +void sound_update_scene_sound(void* handle, struct bSound* sound); + +void sound_set_cfra(int cfra); + +void sound_set_scene_volume(struct Scene *scene, float volume); + +void sound_set_scene_sound_volume(void* handle, float volume, char animated); + +void sound_set_scene_sound_pitch(void* handle, float pitch, char animated); + +void sound_set_scene_sound_pan(void* handle, float pan, char animated); + +void sound_update_sequencer(struct Main* main, struct bSound* sound); + void sound_play_scene(struct Scene *scene); void sound_stop_scene(struct Scene *scene); -void sound_seek_scene(struct bContext *C); +void sound_seek_scene(struct Main *bmain, struct Scene *scene); float sound_sync_scene(struct Scene *scene); int sound_scene_playing(struct Scene *scene); -int sound_read_sound_buffer(struct bSound* sound, float* buffer, int length, float start, float end); +void sound_free_waveform(struct bSound* sound); + +void sound_read_waveform(struct bSound* sound); + +void sound_update_scene(struct Scene* scene); -int sound_get_channels(struct bSound* sound); +void* sound_get_factory(void* sound); #endif diff --git a/source/blender/blenkernel/BKE_speaker.h b/source/blender/blenkernel/BKE_speaker.h new file mode 100644 index 00000000000..111bd86fdd3 --- /dev/null +++ b/source/blender/blenkernel/BKE_speaker.h @@ -0,0 +1,43 @@ +/* + * $Id$ + * + * ***** 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) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Jörg Müller. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef BKE_SPEAKER_H +#define BKE_SPEAKER_H + +/** \file BKE_speaker.h + * \ingroup bke + * \brief General operations for speakers. + */ + +void *add_speaker(const char *name); +struct Speaker *copy_speaker(struct Speaker *spk); +void make_local_speaker(struct Speaker *spk); +void free_speaker(struct Speaker *spk); + +#endif diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt index 5078657588d..c1797427cc2 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -32,8 +32,10 @@ endif() set(INC . ../avi + ../blenfont ../blenlib ../blenloader + ../editors/include ../gpu ../ikplugin ../imbuf @@ -41,20 +43,19 @@ set(INC ../makesrna ../modifiers ../nodes - ../editors/include ../render/extern/include - ../../../intern/audaspace/intern - ../../../intern/ffmpeg - ../../../intern/bsp/extern ../blenfont + ../../../intern/bsp/extern ../../../intern/decimation/extern ../../../intern/elbeem/extern ../../../intern/guardedalloc ../../../intern/iksolver/extern ../../../intern/memutil + ../../../intern/mikktspace ../../../intern/opennl/extern ../../../intern/smoke/extern - ../../../intern/mikktspace - ../../../source/blender/windowmanager # XXX - BAD LEVEL CALL WM_api.h + + # XXX - BAD LEVEL CALL WM_api.h + ../windowmanager ) set(INC_SYS @@ -139,6 +140,7 @@ set(SRC intern/smoke.c intern/softbody.c intern/sound.c + intern/speaker.c intern/subsurf_ccg.c intern/suggestions.c intern/text.c @@ -219,6 +221,7 @@ set(SRC BKE_smoke.h BKE_softbody.h BKE_sound.h + BKE_speaker.h BKE_subsurf.h BKE_suggestions.h BKE_text.h @@ -237,13 +240,24 @@ set(SRC add_definitions(-DGLEW_STATIC) +if(WITH_AUDASPACE) + list(APPEND INC + ../../../intern/audaspace/intern + ) + add_definitions(-DWITH_AUDASPACE) +endif() + if(WITH_BULLET) - list(APPEND INC ../../../extern/bullet2/src) + list(APPEND INC + ../../../extern/bullet2/src + ) add_definitions(-DUSE_BULLET) endif() if(WITH_MOD_CLOTH_ELTOPO) - list(APPEND INC ../../../extern/eltopo) + list(APPEND INC + ../../../extern/eltopo + ) add_definitions(-DWITH_ELTOPO) endif() @@ -267,24 +281,41 @@ if(WITH_IMAGE_CINEON) add_definitions(-DWITH_CINEON) endif() +if(WITH_IMAGE_FRAMESERVER) + add_definitions(-DWITH_FRAMESERVER) +endif() + if(WITH_IMAGE_HDR) add_definitions(-DWITH_HDR) endif() if(WITH_CODEC_QUICKTIME) - list(APPEND INC ../quicktime) - list(APPEND INC_SYS ${QUICKTIME_INC}) + list(APPEND INC + ../quicktime + ) + list(APPEND INC_SYS + ${QUICKTIME_INCLUDE_DIRS} + ) add_definitions(-DWITH_QUICKTIME) endif() if(WITH_CODEC_FFMPEG) - list(APPEND INC_SYS ${FFMPEG_INC}) + list(APPEND INC + ../../../intern/ffmpeg + ) + list(APPEND INC_SYS + ${FFMPEG_INCLUDE_DIRS} + ) add_definitions(-DWITH_FFMPEG) endif() if(WITH_PYTHON) - list(APPEND INC ../python) - list(APPEND INC_SYS ${PYTHON_INCLUDE_DIRS}) + list(APPEND INC + ../python + ) + list(APPEND INC_SYS + ${PYTHON_INCLUDE_DIRS} + ) add_definitions(-DWITH_PYTHON) if(WITH_PYTHON_SECURITY) @@ -300,17 +331,25 @@ if(NOT WITH_MOD_FLUID) add_definitions(-DDISABLE_ELBEEM) endif() +if(WITH_MOD_SMOKE) + add_definitions(-DWITH_SMOKE) +endif() + if(WITH_JACK) add_definitions(-DWITH_JACK) endif() if(WITH_LZO) - list(APPEND INC_SYS ../../../extern/lzo/minilzo) + list(APPEND INC_SYS + ../../../extern/lzo/minilzo + ) add_definitions(-DWITH_LZO) endif() if(WITH_LZMA) - list(APPEND INC_SYS ../../../extern/lzma) + list(APPEND INC_SYS + ../../../extern/lzma + ) add_definitions(-DWITH_LZMA) endif() diff --git a/source/blender/blenkernel/SConscript b/source/blender/blenkernel/SConscript index b5f845acacb..5ea42ee65ae 100644 --- a/source/blender/blenkernel/SConscript +++ b/source/blender/blenkernel/SConscript @@ -21,6 +21,9 @@ incs += ' ' + env['BF_ZLIB_INC'] defs = [ 'GLEW_STATIC' ] +defs.append('WITH_SMOKE') # TODO, make optional +defs.append('WITH_FRAMESERVER') # TODO, make optional + if env['WITH_BF_PYTHON']: incs += ' ../python' incs += ' ' + env['BF_PYTHON_INC'] diff --git a/source/blender/blenkernel/depsgraph_private.h b/source/blender/blenkernel/depsgraph_private.h index 1fed115893c..ef4f320602b 100644 --- a/source/blender/blenkernel/depsgraph_private.h +++ b/source/blender/blenkernel/depsgraph_private.h @@ -69,8 +69,9 @@ typedef struct DagNode void * ob; void * first_ancestor; int ancestor_count; - unsigned int lay; // accumulated layers of its relations + itself + unsigned int lay; // accumulated layers of its relations + itself unsigned int scelay; // layers due to being in scene + unsigned int customdata_mask; // customdata mask int lasttime; // if lasttime != DagForest->time, this node was not evaluated yet for flushing int BFS_dist; // BFS distance int DFS_dist; // DFS distance diff --git a/source/blender/blenkernel/intern/BME_tools.c b/source/blender/blenkernel/intern/BME_tools.c index 7665b581d7e..99b6e7f9095 100644 --- a/source/blender/blenkernel/intern/BME_tools.c +++ b/source/blender/blenkernel/intern/BME_tools.c @@ -1002,7 +1002,7 @@ static BME_Mesh *BME_bevel_initialize(BME_Mesh *bm, int options, int UNUSED(defg } /* edge pass */ - threshold = (float)cos((angle + 0.00001) * M_PI / 180.0); + threshold = (float)cos((angle + 0.001) * M_PI / 180.0); for (e=bm->edges.first; e; e=e->next) { e->tflag1 = BME_BEVEL_ORIG; weight = 0.0; diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c index d9c98bc0200..ff7f2586767 100644 --- a/source/blender/blenkernel/intern/DerivedMesh.c +++ b/source/blender/blenkernel/intern/DerivedMesh.c @@ -637,7 +637,8 @@ static void emDM_foreachMappedFaceCenter(DerivedMesh *dm, void (*func)(void *use } /* note, material function is ignored for now. */ -static void emDM_drawMappedFaces(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index, int *drawSmooth_r), void *userData, int UNUSED(useColors), int (*setMaterial)(int, void *attribs)) +static void emDM_drawMappedFaces(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index, int *drawSmooth_r), void *userData, int UNUSED(useColors), int (*setMaterial)(int, void *attribs), + int (*compareDrawOptions)(void *userData, int cur_index, int next_index)) { EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm; EditFace *efa; @@ -645,6 +646,9 @@ static void emDM_drawMappedFaces(DerivedMesh *dm, int (*setDrawOptions)(void *us (void)setMaterial; /* unused */ + /* currently unused -- each original face is handled separately */ + (void)compareDrawOptions; + if (emdm->vertexCos) { EditVert *eve; @@ -1050,6 +1054,7 @@ static void emDM_drawMappedFacesGLSL(DerivedMesh *dm, glEnd(); } } +#undef PASSATTRIB } static void emDM_drawFacesGLSL(DerivedMesh *dm, @@ -1883,7 +1888,9 @@ static void mesh_calc_modifiers(Scene *scene, Object *ob, float (*inputVertexCos /* set the DerivedMesh to only copy needed data */ mask= (CustomDataMask)GET_INT_FROM_POINTER(curr->link); - DM_set_only_copy(dm, mask); + /* needMapping check here fixes bug [#28112], otherwise its + * possible that it wont be copied */ + DM_set_only_copy(dm, mask | (needMapping ? CD_MASK_ORIGINDEX : 0)); /* add cloth rest shape key if need */ if(mask & CD_MASK_CLOTH_ORCO) @@ -2765,6 +2772,7 @@ void DM_vertex_attributes_from_gpu(DerivedMesh *dm, GPUVertexAttribs *gattribs, attribs->tface[a].array = tfdata->layers[layer].data; attribs->tface[a].emOffset = tfdata->layers[layer].offset; attribs->tface[a].glIndex = gattribs->layer[b].glindex; + attribs->tface[a].glTexco = gattribs->layer[b].gltexco; } } else if(gattribs->layer[b].type == CD_MCOL) { @@ -2805,6 +2813,7 @@ void DM_vertex_attributes_from_gpu(DerivedMesh *dm, GPUVertexAttribs *gattribs, attribs->orco.array = vdata->layers[layer].data; attribs->orco.emOffset = vdata->layers[layer].offset; attribs->orco.glIndex = gattribs->layer[b].glindex; + attribs->orco.glTexco = gattribs->layer[b].gltexco; } } } diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c index 77f56058a4f..9c2467505cd 100644 --- a/source/blender/blenkernel/intern/action.c +++ b/source/blender/blenkernel/intern/action.c @@ -1,6 +1,4 @@ /* - * $Id$ - * * ***** BEGIN GPL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or @@ -85,66 +83,84 @@ bAction *add_empty_action(const char name[]) bAction *act; act= alloc_libblock(&G.main->action, ID_AC, name); - act->id.flag |= LIB_FAKEUSER; // XXX this is nasty for new users... maybe we don't want this anymore - act->id.us++; return act; } +/* .................................. */ + +/* temp data for make_local_action */ +typedef struct tMakeLocalActionContext { + bAction *act; /* original action */ + bAction *actn; /* new action */ + + int lib; /* some action users were libraries */ + int local; /* some action users were not libraries */ +} tMakeLocalActionContext; + +/* helper function for make_local_action() - local/lib init step */ +static void make_localact_init_cb(ID *id, AnimData *adt, void *mlac_ptr) +{ + tMakeLocalActionContext *mlac = (tMakeLocalActionContext *)mlac_ptr; + + if (adt->action == mlac->act) { + if (id->lib) + mlac->lib = 1; + else + mlac->local = 1; + } +} + +/* helper function for make_local_action() - change references */ +static void make_localact_apply_cb(ID *id, AnimData *adt, void *mlac_ptr) +{ + tMakeLocalActionContext *mlac = (tMakeLocalActionContext *)mlac_ptr; + + if (adt->action == mlac->act) { + if (id->lib==0) { + adt->action = mlac->actn; + + id_us_plus(&mlac->actn->id); + id_us_min(&mlac->act->id); + } + } +} + // does copy_fcurve... void make_local_action(bAction *act) { - // Object *ob; + tMakeLocalActionContext mlac = {act, NULL, 0, 0}; Main *bmain= G.main; - bAction *actn; - int local=0, lib=0; - if (act->id.lib==NULL) return; - if (act->id.us==1) { + if (act->id.lib==NULL) + return; + + // XXX: double-check this; it used to be just single-user check, but that was when fake-users were still default + if ((act->id.flag & LIB_FAKEUSER) && (act->id.us<=1)) { act->id.lib= NULL; act->id.flag= LIB_LOCAL; new_id(&bmain->action, (ID *)act, NULL); return; } -#if 0 // XXX old animation system - ob= G.main->object.first; - while(ob) { - if(ob->action==act) { - if(ob->id.lib) lib= 1; - else local= 1; - } - ob= ob->id.next; - } -#endif + BKE_animdata_main_cb(bmain, make_localact_init_cb, &mlac); - if(local && lib==0) { + if (mlac.local && mlac.lib==0) { act->id.lib= NULL; act->id.flag= LIB_LOCAL; //make_local_action_channels(act); new_id(&bmain->action, (ID *)act, NULL); } - else if(local && lib) { - actn= copy_action(act); - actn->id.us= 0; + else if (mlac.local && mlac.lib) { + mlac.actn= copy_action(act); + mlac.actn->id.us= 0; -#if 0 // XXX old animation system - ob= G.main->object.first; - while(ob) { - if(ob->action==act) { - - if(ob->id.lib==0) { - ob->action = actn; - actn->id.us++; - act->id.us--; - } - } - ob= ob->id.next; - } -#endif // XXX old animation system + BKE_animdata_main_cb(bmain, make_localact_apply_cb, &mlac); } } +/* .................................. */ + void free_action (bAction *act) { /* sanity check */ @@ -163,6 +179,8 @@ void free_action (bAction *act) BLI_freelistN(&act->markers); } +/* .................................. */ + bAction *copy_action (bAction *src) { bAction *dst = NULL; @@ -200,9 +218,6 @@ bAction *copy_action (bAction *src) } } - dst->id.flag |= LIB_FAKEUSER; // XXX this is nasty for new users... maybe we don't want this anymore - dst->id.us++; - return dst; } @@ -1128,7 +1143,7 @@ void copy_pose_result(bPose *to, bPose *from) /* For the calculation of the effects of an Action at the given frame on an object * This is currently only used for the Action Constraint */ -void what_does_obaction (Scene *UNUSED(scene), Object *ob, Object *workob, bPose *pose, bAction *act, char groupname[], float cframe) +void what_does_obaction (Object *ob, Object *workob, bPose *pose, bAction *act, char groupname[], float cframe) { bActionGroup *agrp= action_groups_find_named(act, groupname); @@ -1180,7 +1195,7 @@ void what_does_obaction (Scene *UNUSED(scene), Object *ob, Object *workob, bPose adt.action= act; /* execute effects of Action on to workob (or it's PoseChannels) */ - BKE_animsys_evaluate_animdata(&workob->id, &adt, cframe, ADT_RECALC_ANIM); + BKE_animsys_evaluate_animdata(NULL, &workob->id, &adt, cframe, ADT_RECALC_ANIM); } } diff --git a/source/blender/blenkernel/intern/anim.c b/source/blender/blenkernel/intern/anim.c index 1763866c000..9ca11db7fce 100644 --- a/source/blender/blenkernel/intern/anim.c +++ b/source/blender/blenkernel/intern/anim.c @@ -1,8 +1,4 @@ -/* anim.c - * - * - * $Id$ - * +/* * ***** BEGIN GPL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or @@ -171,7 +167,12 @@ bMotionPath *animviz_verify_motionpaths(Scene *scene, Object *ob, bPoseChannel * avs= &ob->avs; dst= &ob->mpath; } - + + /* avoid 0 size allocs */ + if (avs->path_sf >= avs->path_ef) { + return NULL; + } + /* if there is already a motionpath, just return that, * but provided it's settings are ok */ @@ -226,6 +227,7 @@ typedef struct MPathTarget { /* get list of motion paths to be baked for the given object * - assumes the given list is ready to be used */ +// TODO: it would be nice in future to be able to update objects dependant on these bones too? void animviz_get_object_motionpaths(Object *ob, ListBase *targets) { MPathTarget *mpt; @@ -714,12 +716,13 @@ static void group_duplilist(ListBase *lb, Scene *scene, Object *ob, int level, i /* note, if you check on layer here, render goes wrong... it still deforms verts and uses parent imat */ if(go->ob!=ob) { - /* Group Dupli Offset, should apply after everything else */ - if (group->dupli_ofs[0] || group->dupli_ofs[1] || group->dupli_ofs[2]) { + /* group dupli offset, should apply after everything else */ + if(!is_zero_v3(group->dupli_ofs)) { copy_m4_m4(tmat, go->ob->obmat); sub_v3_v3v3(tmat[3], tmat[3], group->dupli_ofs); mul_m4_m4m4(mat, tmat, ob->obmat); - } else { + } + else { mul_m4_m4m4(mat, go->ob->obmat, ob->obmat); } @@ -789,7 +792,7 @@ static void frames_duplilist(ListBase *lb, Scene *scene, Object *ob, int level, * and/or other objects which may affect this object's transforms are not updated either. * However, this has always been the way that this worked (i.e. pre 2.5), so I guess that it'll be fine! */ - BKE_animsys_evaluate_animdata(&ob->id, ob->adt, (float)scene->r.cfra, ADT_RECALC_ANIM); /* ob-eval will do drivers, so we don't need to do them */ + BKE_animsys_evaluate_animdata(scene, &ob->id, ob->adt, (float)scene->r.cfra, ADT_RECALC_ANIM); /* ob-eval will do drivers, so we don't need to do them */ where_is_object_time(scene, ob, (float)scene->r.cfra); dob= new_dupli_object(lb, ob, ob->obmat, ob->lay, scene->r.cfra, OB_DUPLIFRAMES, animated); @@ -804,7 +807,7 @@ static void frames_duplilist(ListBase *lb, Scene *scene, Object *ob, int level, */ scene->r.cfra= cfrao; - BKE_animsys_evaluate_animdata(&ob->id, ob->adt, (float)scene->r.cfra, ADT_RECALC_ANIM); /* ob-eval will do drivers, so we don't need to do them */ + BKE_animsys_evaluate_animdata(scene, &ob->id, ob->adt, (float)scene->r.cfra, ADT_RECALC_ANIM); /* ob-eval will do drivers, so we don't need to do them */ where_is_object_time(scene, ob, (float)scene->r.cfra); /* but, to make sure unkeyed object transforms are still sane, @@ -1239,6 +1242,8 @@ static void new_particle_duplilist(ListBase *lb, ID *id, Scene *scene, Object *p sim.ob= par; sim.psys= psys; sim.psmd= psys_get_modifier(par, psys); + /* make sure emitter imat is in global coordinates instead of render view coordinates */ + invert_m4_m4(par->imat, par->obmat); /* first check for loops (particle system object used as dupli object) */ if(part->ren_as == PART_DRAW_OB) { @@ -1343,6 +1348,10 @@ static void new_particle_duplilist(ListBase *lb, ID *id, Scene *scene, Object *p continue; if(part->ren_as==PART_DRAW_GR) { + /* prevent divide by zero below [#28336] */ + if(totgroup == 0) + continue; + /* for groups, pick the object based on settings */ if(part->draw&PART_DRAW_RAND_GR) b= BLI_rand() % totgroup; @@ -1390,7 +1399,17 @@ static void new_particle_duplilist(ListBase *lb, ID *id, Scene *scene, Object *p if(part->ren_as==PART_DRAW_GR && psys->part->draw & PART_DRAW_WHOLE_GR) { for(go= part->dup_group->gobject.first, b=0; go; go= go->next, b++) { - mul_m4_m4m4(tmat, oblist[b]->obmat, pamat); + + /* group dupli offset, should apply after everything else */ + if(!is_zero_v3(part->dup_group->dupli_ofs)) { + copy_m4_m4(tmat, oblist[b]->obmat); + sub_v3_v3v3(tmat[3], tmat[3], part->dup_group->dupli_ofs); + mul_m4_m4m4(tmat, tmat, pamat); + } + else { + mul_m4_m4m4(tmat, oblist[b]->obmat, pamat); + } + mul_mat3_m4_fl(tmat, size*scale); if(par_space_mat) mul_m4_m4m4(mat, tmat, par_space_mat); diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c index fdc102bf779..b690c9b4a91 100644 --- a/source/blender/blenkernel/intern/anim_sys.c +++ b/source/blender/blenkernel/intern/anim_sys.c @@ -1,6 +1,4 @@ /* - * $Id$ - * * ***** BEGIN GPL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or @@ -56,6 +54,7 @@ #include "BKE_global.h" #include "BKE_main.h" #include "BKE_library.h" +#include "BKE_report.h" #include "BKE_utildefines.h" #include "RNA_access.h" @@ -84,6 +83,7 @@ short id_type_can_have_animdata (ID *id) case ID_PA: case ID_MA: case ID_TE: case ID_NT: case ID_LA: case ID_CA: case ID_WO: + case ID_SPK: case ID_SCE: { return 1; @@ -144,6 +144,59 @@ AnimData *BKE_id_add_animdata (ID *id) return NULL; } +/* Action Setter --------------------------------------- */ + +/* Called when user tries to change the active action of an AnimData block (via RNA, Outliner, etc.) */ +short BKE_animdata_set_action (ReportList *reports, ID *id, bAction *act) +{ + AnimData *adt = BKE_animdata_from_id(id); + short ok = 0; + + /* animdata validity check */ + if (adt == NULL) { + BKE_report(reports, RPT_WARNING, "No AnimData to set action on"); + return ok; + } + + /* active action is only editable when it is not a tweaking strip + * see rna_AnimData_action_editable() in rna_animation.c + */ + if ((adt->flag & ADT_NLA_EDIT_ON) || (adt->actstrip) || (adt->tmpact)) { + /* cannot remove, otherwise things turn to custard */ + BKE_report(reports, RPT_ERROR, "Cannot change action, as it is still being edited in NLA"); + return ok; + } + + /* manage usercount for current action */ + if (adt->action) + id_us_min((ID*)adt->action); + + /* assume that AnimData's action can in fact be edited... */ + if (act) { + /* action must have same type as owner */ + if (ELEM(act->idroot, 0, GS(id->name))) { + /* can set */ + adt->action = act; + id_us_plus((ID*)adt->action); + ok = 1; + } + else { + /* cannot set */ + BKE_reportf(reports, RPT_ERROR, + "Couldn't set Action '%s' onto ID '%s', as it doesn't have suitably rooted paths for this purpose", + act->id.name+2, id->name); + //ok = 0; + } + } + else { + /* just clearing the action... */ + adt->action = NULL; + ok = 1; + } + + return ok; +} + /* Freeing -------------------------------------------- */ /* Free AnimData used by the nominated ID-block, and clear ID-block's AnimData pointer */ @@ -234,7 +287,7 @@ int BKE_copy_animdata_id (ID *id_to, ID *id_from, const short do_action) return 1; } -void BKE_copy_animdata_id_action(struct ID *id) +void BKE_copy_animdata_id_action(ID *id) { AnimData *adt= BKE_animdata_from_id(id); if (adt) { @@ -733,7 +786,10 @@ void BKE_animdata_main_cb (Main *mainptr, ID_AnimData_Edit_Callback func, void * /* particles */ ANIMDATA_IDS_CB(mainptr->particle.first); - + + /* speakers */ + ANIMDATA_IDS_CB(mainptr->speaker.first); + /* objects */ ANIMDATA_IDS_CB(mainptr->object.first); @@ -811,7 +867,10 @@ void BKE_all_animdata_fix_paths_rename (char *prefix, char *oldName, char *newNa /* particles */ RENAMEFIX_ANIM_IDS(mainptr->particle.first); - + + /* speakers */ + RENAMEFIX_ANIM_IDS(mainptr->speaker.first); + /* objects */ RENAMEFIX_ANIM_IDS(mainptr->object.first); @@ -1062,7 +1121,7 @@ static short animsys_write_rna_setting (PointerRNA *ptr, char *path, int array_i { int array_len= RNA_property_array_length(&new_ptr, prop); - if(array_len && array_index >= array_len) + if (array_len && array_index >= array_len) { if (G.f & G_DEBUG) { printf("Animato: Invalid array index. ID = '%s', '%s[%d]', array length is %d \n", @@ -1100,6 +1159,23 @@ static short animsys_write_rna_setting (PointerRNA *ptr, char *path, int array_i /* nothing can be done here... so it is unsuccessful? */ return 0; } + + /* buffer property update for later flushing */ + if (RNA_property_update_check(prop)) { + short skip_updates_hack = 0; + + /* optimisation hacks: skip property updates for those properties + * for we know that which the updates in RNA were really just for + * flushing property editing via UI/Py + */ + if (new_ptr.type == &RNA_PoseBone) { + /* bone transforms - update pose (i.e. tag depsgraph) */ + skip_updates_hack = 1; + } + + if (skip_updates_hack == 0) + RNA_property_update_cache_add(&new_ptr, prop); + } } /* successful */ @@ -1843,6 +1919,9 @@ void nlastrip_evaluate (PointerRNA *ptr, ListBase *channels, ListBase *modifiers case NLASTRIP_TYPE_META: /* meta */ nlastrip_evaluate_meta(ptr, channels, modifiers, nes); break; + + default: /* do nothing */ + break; } /* clear temp recursion safe-check */ @@ -2078,7 +2157,7 @@ static void animsys_evaluate_overrides (PointerRNA *ptr, AnimData *adt) * and that the flags for which parts of the anim-data settings need to be recalculated * have been set already by the depsgraph. Now, we use the recalc */ -void BKE_animsys_evaluate_animdata (ID *id, AnimData *adt, float ctime, short recalc) +void BKE_animsys_evaluate_animdata (Scene *scene, ID *id, AnimData *adt, float ctime, short recalc) { PointerRNA id_ptr; @@ -2130,6 +2209,14 @@ void BKE_animsys_evaluate_animdata (ID *id, AnimData *adt, float ctime, short re */ animsys_evaluate_overrides(&id_ptr, adt); + /* execute and clear all cached property update functions */ + if (scene) + { + Main *bmain = G.main; // xxx - to get passed in! + RNA_property_update_cache_flush(bmain, scene); + RNA_property_update_cache_free(); + } + /* clear recalc flag now */ adt->recalc= 0; } @@ -2141,7 +2228,7 @@ void BKE_animsys_evaluate_animdata (ID *id, AnimData *adt, float ctime, short re * 'local' (i.e. belonging in the nearest ID-block that setting is related to, not a * standard 'root') block are overridden by a larger 'user' */ -void BKE_animsys_evaluate_all_animation (Main *main, float ctime) +void BKE_animsys_evaluate_all_animation (Main *main, Scene *scene, float ctime) { ID *id; @@ -2157,7 +2244,7 @@ void BKE_animsys_evaluate_all_animation (Main *main, float ctime) for (id= first; id; id= id->next) { \ if (ID_REAL_USERS(id) > 0) { \ AnimData *adt= BKE_animdata_from_id(id); \ - BKE_animsys_evaluate_animdata(id, adt, ctime, aflag); \ + BKE_animsys_evaluate_animdata(scene, id, adt, ctime, aflag); \ } \ } /* another macro for the "embedded" nodetree cases @@ -2173,9 +2260,9 @@ void BKE_animsys_evaluate_all_animation (Main *main, float ctime) NtId_Type *ntp= (NtId_Type *)id; \ if (ntp->nodetree) { \ AnimData *adt2= BKE_animdata_from_id((ID *)ntp->nodetree); \ - BKE_animsys_evaluate_animdata((ID *)ntp->nodetree, adt2, ctime, ADT_RECALC_ANIM); \ + BKE_animsys_evaluate_animdata(scene, (ID *)ntp->nodetree, adt2, ctime, ADT_RECALC_ANIM); \ } \ - BKE_animsys_evaluate_animdata(id, adt, ctime, aflag); \ + BKE_animsys_evaluate_animdata(scene, id, adt, ctime, aflag); \ } \ } @@ -2230,6 +2317,9 @@ void BKE_animsys_evaluate_all_animation (Main *main, float ctime) /* particles */ EVAL_ANIM_IDS(main->particle.first, ADT_RECALC_ANIM); + /* lamps */ + EVAL_ANIM_IDS(main->speaker.first, ADT_RECALC_ANIM); + /* objects */ /* ADT_RECALC_ANIM doesn't need to be supplied here, since object AnimData gets * this tagged by Depsgraph on framechange. This optimisation means that objects diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c index fd25ebe266f..62ce184a2d7 100644 --- a/source/blender/blenkernel/intern/armature.c +++ b/source/blender/blenkernel/intern/armature.c @@ -1,6 +1,4 @@ /* - * $Id$ - * * ***** BEGIN GPL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or @@ -1343,8 +1341,12 @@ void vec_roll_to_mat3(float *vec, float roll, float mat[][3]) cross_v3_v3v3(axis,target,nor); /* was 0.0000000000001, caused bug [#23954], smaller values give unstable - * roll when toggling editmode */ - if (dot_v3v3(axis,axis) > 0.00001f) { + * roll when toggling editmode. + * + * was 0.00001, causes bug [#27675], with 0.00000495, + * so a value inbetween these is needed. + */ + if (dot_v3v3(axis,axis) > 0.000001f) { /* if nor is *not* a multiple of target ... */ normalize_v3(axis); diff --git a/source/blender/blenkernel/intern/blender.c b/source/blender/blenkernel/intern/blender.c index 20b44b3b899..5f33059e117 100644 --- a/source/blender/blenkernel/intern/blender.c +++ b/source/blender/blenkernel/intern/blender.c @@ -64,6 +64,7 @@ #include "BLI_dynstr.h" #include "BLI_path_util.h" #include "BLI_utildefines.h" +#include "BLI_callbacks.h" #include "IMB_imbuf.h" @@ -81,6 +82,7 @@ #include "BKE_scene.h" #include "BKE_screen.h" #include "BKE_sequencer.h" +#include "BKE_sound.h" #include "BLO_undofile.h" @@ -89,6 +91,8 @@ #include "BKE_utildefines.h" +#include "RNA_access.h" + #include "WM_api.h" // XXXXX BAD, very BAD dependency (bad level call) - remove asap, elubie Global G; @@ -96,7 +100,7 @@ UserDef U; /* ListBase = {NULL, NULL}; */ short ENDIAN_ORDER; -static char versionstr[48]= ""; +char versionstr[48]= ""; /* ********** free ********** */ @@ -110,6 +114,9 @@ void free_blender(void) BKE_spacetypes_free(); /* after free main, it uses space callbacks */ IMB_exit(); + + BLI_cb_finalize(); + seq_stripelem_cache_destruct(); free_nodesystem(); @@ -129,9 +136,9 @@ void initglobals(void) ENDIAN_ORDER= (((char*)&ENDIAN_ORDER)[0])? L_ENDIAN: B_ENDIAN; if(BLENDER_SUBVERSION) - BLI_snprintf(versionstr, sizeof(versionstr), "www.blender.org %d.%d", BLENDER_VERSION, BLENDER_SUBVERSION); + BLI_snprintf(versionstr, sizeof(versionstr), "blender.org %d.%d", BLENDER_VERSION, BLENDER_SUBVERSION); else - BLI_snprintf(versionstr, sizeof(versionstr), "www.blender.org %d", BLENDER_VERSION); + BLI_snprintf(versionstr, sizeof(versionstr), "blender.org %d", BLENDER_VERSION); #ifdef _WIN32 // FULLSCREEN G.windowstate = G_WINDOWSTATE_USERDEF; @@ -154,7 +161,6 @@ static void clear_global(void) { // extern short winqueue_break; /* screen.c */ - fastshade_free_render(); /* lamps hang otherwise */ free_main(G.main); /* free all lib data */ // free_vertexpaint(); @@ -180,7 +186,6 @@ static void clean_paths(Main *main) BLI_bpathIterator_free(bpi); for(scene= main->scene.first; scene; scene= scene->id.next) { - BLI_clean(scene->r.backbuf); BLI_clean(scene->r.pic); } } @@ -237,9 +242,14 @@ static void setup_app_data(bContext *C, BlendFileData *bfd, const char *filepath // CTX_wm_manager_set(C, NULL); clear_global(); + /* clear old property update cache, in case some old references are left dangling */ + RNA_property_update_cache_free(); + G.main= bfd->main; CTX_data_main_set(C, G.main); + + sound_init_main(G.main); if (bfd->user) { @@ -328,28 +338,45 @@ static int handle_subversion_warning(Main *main) return 1; } +static void keymap_item_free(wmKeyMapItem *kmi) +{ + if(kmi->properties) { + IDP_FreeProperty(kmi->properties); + MEM_freeN(kmi->properties); + } + if(kmi->ptr) + MEM_freeN(kmi->ptr); +} + void BKE_userdef_free(void) { wmKeyMap *km; wmKeyMapItem *kmi; + wmKeyMapDiffItem *kmdi; - for(km=U.keymaps.first; km; km=km->next) { - for(kmi=km->items.first; kmi; kmi=kmi->next) { - if(kmi->properties) { - IDP_FreeProperty(kmi->properties); - MEM_freeN(kmi->properties); + for(km=U.user_keymaps.first; km; km=km->next) { + for(kmdi=km->diff_items.first; kmdi; kmdi=kmdi->next) { + if(kmdi->add_item) { + keymap_item_free(kmdi->add_item); + MEM_freeN(kmdi->add_item); + } + if(kmdi->remove_item) { + keymap_item_free(kmdi->remove_item); + MEM_freeN(kmdi->remove_item); } - if(kmi->ptr) - MEM_freeN(kmi->ptr); } + for(kmi=km->items.first; kmi; kmi=kmi->next) + keymap_item_free(kmi); + + BLI_freelistN(&km->diff_items); BLI_freelistN(&km->items); } BLI_freelistN(&U.uistyles); BLI_freelistN(&U.uifonts); BLI_freelistN(&U.themes); - BLI_freelistN(&U.keymaps); + BLI_freelistN(&U.user_keymaps); BLI_freelistN(&U.addons); } diff --git a/source/blender/blenkernel/intern/boids.c b/source/blender/blenkernel/intern/boids.c index 9f808704eee..a0f38e675f9 100644 --- a/source/blender/blenkernel/intern/boids.c +++ b/source/blender/blenkernel/intern/boids.c @@ -937,6 +937,7 @@ void boid_brain(BoidBrainData *bbd, int p, ParticleData *pa) BoidValues val; BoidState *state = get_boid_state(boids, pa); BoidParticle *bpa = pa->boid; + ParticleSystem *psys = bbd->sim->psys; int rand; //BoidCondition *cond; @@ -959,9 +960,8 @@ void boid_brain(BoidBrainData *bbd, int p, ParticleData *pa) bbd->wanted_co[0]=bbd->wanted_co[1]=bbd->wanted_co[2]=bbd->wanted_speed=0.0f; /* create random seed for every particle & frame */ - BLI_srandom(bbd->sim->psys->seed + p); - rand = BLI_rand(); - BLI_srandom((int)bbd->cfra + rand); + rand = (int)(PSYS_FRAND(psys->seed + p) * 1000); + rand = (int)(PSYS_FRAND((int)bbd->cfra + rand) * 1000); set_boid_values(&val, bbd->part->boids, pa); diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c index a4ceb62ab55..c497cd2813a 100644 --- a/source/blender/blenkernel/intern/brush.c +++ b/source/blender/blenkernel/intern/brush.c @@ -235,8 +235,6 @@ void make_local_brush(Brush *brush) if(paint_brush(&scene->toolsettings->imapaint.paint)==brush) { if(scene->id.lib==NULL) { paint_brush_set(&scene->toolsettings->imapaint.paint, brushn); - brushn->id.us++; - brush->id.us--; } } } diff --git a/source/blender/blenkernel/intern/bvhutils.c b/source/blender/blenkernel/intern/bvhutils.c index 5520e4d1d41..c3aeb440938 100644 --- a/source/blender/blenkernel/intern/bvhutils.c +++ b/source/blender/blenkernel/intern/bvhutils.c @@ -493,7 +493,7 @@ static void mesh_edges_nearest_point(void *userdata, int index, const float *co, // NOTE: casts to "float*" here are due to co being "const float*" closest_to_line_segment_v3(nearest_tmp, (float*)co, t0, t1); - dist = len_v3v3(nearest_tmp, (float*)co); + dist = len_squared_v3v3(nearest_tmp, (float*)co); if(dist < nearest->dist) { @@ -719,7 +719,7 @@ void free_bvhtree_from_mesh(struct BVHTreeFromMesh *data) if(!data->cached) BLI_bvhtree_free(data->tree); - memset( data, 0, sizeof(data) ); + memset( data, 0, sizeof(*data) ); } } diff --git a/source/blender/blenkernel/intern/cdderivedmesh.c b/source/blender/blenkernel/intern/cdderivedmesh.c index 72ee9b55800..5eb97630e83 100644 --- a/source/blender/blenkernel/intern/cdderivedmesh.c +++ b/source/blender/blenkernel/intern/cdderivedmesh.c @@ -284,8 +284,10 @@ static void cdDM_drawVerts(DerivedMesh *dm) else { /* use OpenGL VBOs or Vertex Arrays instead for better, faster rendering */ GPU_vertex_setup(dm); if( !GPU_buffer_legacy(dm) ) { - if(dm->drawObject->nelements) glDrawArrays(GL_POINTS,0, dm->drawObject->nelements); - else glDrawArrays(GL_POINTS,0, dm->drawObject->nlooseverts); + if(dm->drawObject->tot_triangle_point) + glDrawArrays(GL_POINTS,0, dm->drawObject->tot_triangle_point); + else + glDrawArrays(GL_POINTS,0, dm->drawObject->tot_loose_point); } GPU_buffer_unbind(); } @@ -547,9 +549,10 @@ static void cdDM_drawFacesSolid(DerivedMesh *dm, GPU_normal_setup( dm ); if( !GPU_buffer_legacy(dm) ) { glShadeModel(GL_SMOOTH); - for( a = 0; a < dm->drawObject->nmaterials; a++ ) { + for( a = 0; a < dm->drawObject->totmaterial; a++ ) { if( setMaterial(dm->drawObject->materials[a].mat_nr+1, NULL) ) - glDrawArrays(GL_TRIANGLES, dm->drawObject->materials[a].start, dm->drawObject->materials[a].end-dm->drawObject->materials[a].start); + glDrawArrays(GL_TRIANGLES, dm->drawObject->materials[a].start, + dm->drawObject->materials[a].totpoint); } } GPU_buffer_unbind( ); @@ -629,13 +632,13 @@ static void cdDM_drawFacesColored(DerivedMesh *dm, int useTwoSided, unsigned cha GPU_color_setup(dm); if( !GPU_buffer_legacy(dm) ) { glShadeModel(GL_SMOOTH); - glDrawArrays(GL_TRIANGLES, 0, dm->drawObject->nelements); + glDrawArrays(GL_TRIANGLES, 0, dm->drawObject->tot_triangle_point); if( useTwoSided ) { GPU_color4_upload(dm,cp2); GPU_color_setup(dm); glCullFace(GL_FRONT); - glDrawArrays(GL_TRIANGLES, 0, dm->drawObject->nelements); + glDrawArrays(GL_TRIANGLES, 0, dm->drawObject->tot_triangle_point); glCullFace(GL_BACK); } } @@ -787,8 +790,8 @@ static void cdDM_drawFacesTex_common(DerivedMesh *dm, glShadeModel( GL_SMOOTH ); lastFlag = 0; - for(i = 0; i < dm->drawObject->nelements/3; i++) { - int actualFace = dm->drawObject->faceRemap[i]; + for(i = 0; i < dm->drawObject->tot_triangle_point/3; i++) { + int actualFace = dm->drawObject->triangle_to_mface[i]; int flag = 1; if(drawParams) { @@ -819,13 +822,13 @@ static void cdDM_drawFacesTex_common(DerivedMesh *dm, startFace = i; } } - if( startFace < dm->drawObject->nelements/3 ) { + if( startFace < dm->drawObject->tot_triangle_point/3 ) { if( lastFlag != 0 ) { /* if the flag is 0 it means the face is hidden or invisible */ if (lastFlag==1 && col) GPU_color_switch(1); else GPU_color_switch(0); - glDrawArrays(GL_TRIANGLES,startFace*3,dm->drawObject->nelements-startFace*3); + glDrawArrays(GL_TRIANGLES, startFace*3, dm->drawObject->tot_triangle_point - startFace*3); } } } @@ -840,7 +843,8 @@ static void cdDM_drawFacesTex(DerivedMesh *dm, int (*setDrawOptions)(MTFace *tfa cdDM_drawFacesTex_common(dm, setDrawOptions, NULL, NULL); } -static void cdDM_drawMappedFaces(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index, int *drawSmooth_r), void *userData, int useColors, int (*setMaterial)(int, void *attribs)) +static void cdDM_drawMappedFaces(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index, int *drawSmooth_r), void *userData, int useColors, int (*setMaterial)(int, void *attribs), + int (*compareDrawOptions)(void *userData, int cur_index, int next_index)) { CDDerivedMesh *cddm = (CDDerivedMesh*) dm; MVert *mv = cddm->mvert; @@ -935,7 +939,7 @@ static void cdDM_drawMappedFaces(DerivedMesh *dm, int (*setDrawOptions)(void *us if( useColors && mc ) GPU_color_setup(dm); if( !GPU_buffer_legacy(dm) ) { - int tottri = dm->drawObject->nelements/3; + int tottri = dm->drawObject->tot_triangle_point/3; glShadeModel(GL_SMOOTH); if(tottri == 0) { @@ -947,17 +951,18 @@ static void cdDM_drawMappedFaces(DerivedMesh *dm, int (*setDrawOptions)(void *us } else { /* we need to check if the next material changes */ - int next_actualFace= dm->drawObject->faceRemap[0]; + int next_actualFace= dm->drawObject->triangle_to_mface[0]; for( i = 0; i < tottri; i++ ) { - //int actualFace = dm->drawObject->faceRemap[i]; + //int actualFace = dm->drawObject->triangle_to_mface[i]; int actualFace = next_actualFace; MFace *mface= mf + actualFace; int drawSmooth= (mface->flag & ME_SMOOTH); int draw = 1; + int flush = 0; if(i != tottri-1) - next_actualFace= dm->drawObject->faceRemap[i+1]; + next_actualFace= dm->drawObject->triangle_to_mface[i+1]; orig= (index==NULL) ? actualFace : index[actualFace]; @@ -969,11 +974,28 @@ static void cdDM_drawMappedFaces(DerivedMesh *dm, int (*setDrawOptions)(void *us /* Goal is to draw as long of a contiguous triangle array as possible, so draw when we hit either an invisible triangle or at the end of the array */ - if(!draw || i == tottri - 1 || mf[actualFace].mat_nr != mf[next_actualFace].mat_nr) { - if(prevstart != i) - /* Add one to the length (via `draw') - if we're drawing at the end of the array */ - glDrawArrays(GL_TRIANGLES,prevstart*3, (i-prevstart+draw)*3); + + /* flush buffer if current triangle isn't drawable or it's last triangle... */ + flush= !draw || i == tottri - 1; + + /* ... or when material setting is dissferent */ + flush|= mf[actualFace].mat_nr != mf[next_actualFace].mat_nr; + + if(!flush && compareDrawOptions) { + int next_orig= (index==NULL) ? next_actualFace : index[next_actualFace]; + + /* also compare draw options and flush buffer if they're different + need for face selection highlight in edit mode */ + flush|= compareDrawOptions(userData, orig, next_orig) == 0; + } + + if(flush) { + int first= prevstart*3; + int count= (i-prevstart+(draw ? 1 : 0))*3; /* Add one to the length if we're drawing at the end of the array */ + + if(count) + glDrawArrays(GL_TRIANGLES, first, count); + prevstart = i + 1; } } @@ -990,6 +1012,50 @@ static void cdDM_drawMappedFacesTex(DerivedMesh *dm, int (*setDrawOptions)(void cdDM_drawFacesTex_common(dm, NULL, setDrawOptions, userData); } +static void cddm_draw_attrib_vertex(DMVertexAttribs *attribs, MVert *mvert, int a, int index, int vert, int smoothnormal) +{ + int b; + + /* orco texture coordinates */ + if(attribs->totorco) { + if(attribs->orco.glTexco) + glTexCoord3fv(attribs->orco.array[index]); + else + glVertexAttrib3fvARB(attribs->orco.glIndex, attribs->orco.array[index]); + } + + /* uv texture coordinates */ + for(b = 0; b < attribs->tottface; b++) { + MTFace *tf = &attribs->tface[b].array[a]; + + if(attribs->tface[b].glTexco) + glTexCoord2fv(tf->uv[vert]); + else + glVertexAttrib2fvARB(attribs->tface[b].glIndex, tf->uv[vert]); + } + + /* vertex colors */ + for(b = 0; b < attribs->totmcol; b++) { + MCol *cp = &attribs->mcol[b].array[a*4 + vert]; + GLubyte col[4]; + col[0]= cp->b; col[1]= cp->g; col[2]= cp->r; col[3]= cp->a; + glVertexAttrib4ubvARB(attribs->mcol[b].glIndex, col); + } + + /* tangent for normal mapping */ + if(attribs->tottang) { + float *tang = attribs->tang.array[a*4 + vert]; + glVertexAttrib4fvARB(attribs->tang.glIndex, tang); + } + + /* vertex normal */ + if(smoothnormal) + glNormal3sv(mvert[index].no); + + /* vertex coordinate */ + glVertex3fv(mvert[index].co); +} + static void cdDM_drawMappedFacesGLSL(DerivedMesh *dm, int (*setMaterial)(int, void *attribs), int (*setDrawOptions)(void *userData, int index), void *userData) { CDDerivedMesh *cddm = (CDDerivedMesh*) dm; @@ -1080,37 +1146,14 @@ static void cdDM_drawMappedFacesGLSL(DerivedMesh *dm, int (*setMaterial)(int, vo } } -#define PASSVERT(index, vert) { \ - if(attribs.totorco) \ - glVertexAttrib3fvARB(attribs.orco.glIndex, attribs.orco.array[index]); \ - for(b = 0; b < attribs.tottface; b++) { \ - MTFace *tf = &attribs.tface[b].array[a]; \ - glVertexAttrib2fvARB(attribs.tface[b].glIndex, tf->uv[vert]); \ - } \ - for(b = 0; b < attribs.totmcol; b++) { \ - MCol *cp = &attribs.mcol[b].array[a*4 + vert]; \ - GLubyte col[4]; \ - col[0]= cp->b; col[1]= cp->g; col[2]= cp->r; col[3]= cp->a; \ - glVertexAttrib4ubvARB(attribs.mcol[b].glIndex, col); \ - } \ - if(attribs.tottang) { \ - float *tang = attribs.tang.array[a*4 + vert]; \ - glVertexAttrib4fvARB(attribs.tang.glIndex, tang); \ - } \ - if(smoothnormal) \ - glNormal3sv(mvert[index].no); \ - glVertex3fv(mvert[index].co); \ - } + cddm_draw_attrib_vertex(&attribs, mvert, a, mface->v1, 0, smoothnormal); + cddm_draw_attrib_vertex(&attribs, mvert, a, mface->v2, 1, smoothnormal); + cddm_draw_attrib_vertex(&attribs, mvert, a, mface->v3, 2, smoothnormal); - PASSVERT(mface->v1, 0); - PASSVERT(mface->v2, 1); - PASSVERT(mface->v3, 2); if(mface->v4) - PASSVERT(mface->v4, 3) + cddm_draw_attrib_vertex(&attribs, mvert, a, mface->v4, 3, smoothnormal); else - PASSVERT(mface->v3, 2) - -#undef PASSVERT + cddm_draw_attrib_vertex(&attribs, mvert, a, mface->v3, 2, smoothnormal); } glEnd(); } @@ -1129,9 +1172,9 @@ static void cdDM_drawMappedFacesGLSL(DerivedMesh *dm, int (*setMaterial)(int, vo GPU_normal_setup(dm); if( !GPU_buffer_legacy(dm) ) { - for( i = 0; i < dm->drawObject->nelements/3; i++ ) { + for( i = 0; i < dm->drawObject->tot_triangle_point/3; i++ ) { - a = dm->drawObject->faceRemap[i]; + a = dm->drawObject->triangle_to_mface[i]; mface = mf + a; new_matnr = mface->mat_nr + 1; @@ -1153,7 +1196,7 @@ static void cdDM_drawMappedFacesGLSL(DerivedMesh *dm, int (*setMaterial)(int, vo if( numdata != 0 ) { - GPU_buffer_free(buffer, NULL); + GPU_buffer_free(buffer); buffer = NULL; } @@ -1193,7 +1236,7 @@ static void cdDM_drawMappedFacesGLSL(DerivedMesh *dm, int (*setMaterial)(int, vo } if( numdata != 0 ) { elementsize = GPU_attrib_element_size( datatypes, numdata ); - buffer = GPU_buffer_alloc( elementsize*dm->drawObject->nelements, NULL ); + buffer = GPU_buffer_alloc( elementsize*dm->drawObject->tot_triangle_point); if( buffer == NULL ) { GPU_buffer_unbind(); dm->drawObject->legacy = 1; @@ -1202,7 +1245,7 @@ static void cdDM_drawMappedFacesGLSL(DerivedMesh *dm, int (*setMaterial)(int, vo varray = GPU_buffer_lock_stream(buffer); if( varray == NULL ) { GPU_buffer_unbind(); - GPU_buffer_free(buffer, NULL); + GPU_buffer_free(buffer); dm->drawObject->legacy = 1; return; } @@ -1284,6 +1327,7 @@ static void cdDM_drawMappedFacesGLSL(DerivedMesh *dm, int (*setMaterial)(int, vo QUATCOPY((float *)&varray[elementsize*curface*3+offset+elementsize*2], tang); offset += sizeof(float)*4; } + (void)offset; } curface++; if(mface->v4) { @@ -1324,6 +1368,7 @@ static void cdDM_drawMappedFacesGLSL(DerivedMesh *dm, int (*setMaterial)(int, vo QUATCOPY((float *)&varray[elementsize*curface*3+offset+elementsize*2], tang); offset += sizeof(float)*4; } + (void)offset; } curface++; i++; @@ -1341,7 +1386,7 @@ static void cdDM_drawMappedFacesGLSL(DerivedMesh *dm, int (*setMaterial)(int, vo } GPU_buffer_unbind(); } - GPU_buffer_free( buffer, NULL ); + GPU_buffer_free(buffer); } glShadeModel(GL_FLAT); diff --git a/source/blender/blenkernel/intern/cloth.c b/source/blender/blenkernel/intern/cloth.c index ea055e90b45..3a86389dba7 100644 --- a/source/blender/blenkernel/intern/cloth.c +++ b/source/blender/blenkernel/intern/cloth.c @@ -923,7 +923,7 @@ static int cloth_from_object(Object *ob, ClothModifierData *clmd, DerivedMesh *d for(i = 0; i < dm->getNumVerts(dm); i++) { - maxdist = MAX2(maxdist, clmd->coll_parms->selfepsilon* ( cloth->verts[i].avg_spring_len*2.0)); + maxdist = MAX2(maxdist, clmd->coll_parms->selfepsilon* ( cloth->verts[i].avg_spring_len*2.0f)); } clmd->clothObject->bvhselftree = bvhselftree_build_from_cloth ( clmd, maxdist ); diff --git a/source/blender/blenkernel/intern/collision.c b/source/blender/blenkernel/intern/collision.c index e2a1b0dfb33..ed073f03270 100644 --- a/source/blender/blenkernel/intern/collision.c +++ b/source/blender/blenkernel/intern/collision.c @@ -1091,7 +1091,7 @@ static int cloth_collision_response_moving ( ClothModifierData *clmd, CollisionM VECADDMUL(cloth1->verts[collpair->ap1].impulse, pimpulse, w1*2.0); VECADDMUL(cloth1->verts[collpair->ap2].impulse, pimpulse, w2*2.0); - VECADDMUL(cloth1->verts[collpair->ap3].impulse, pimpulse, w3*2.0);; + VECADDMUL(cloth1->verts[collpair->ap3].impulse, pimpulse, w3*2.0); cloth1->verts[collpair->ap1].impulse_count++; cloth1->verts[collpair->ap2].impulse_count++; cloth1->verts[collpair->ap3].impulse_count++; @@ -1487,8 +1487,8 @@ static CollPair* cloth_collision ( ModifierData *md1, ModifierData *md2, sdis = clmd->coll_parms->distance_repel + epsilon2 + FLT_EPSILON; - /*apply a repulsion force, to help the solver along. - this is kindof crude, it only tests one vert of the triangle*/ + /* apply a repulsion force, to help the solver along. + * this is kindof crude, it only tests one vert of the triangle */ if (isect_ray_plane_v3(cloth->verts[collpair->ap1].tx, n2, collmd->current_xnew[collpair->bp1].co, collmd->current_xnew[collpair->bp2].co, collmd->current_xnew[collpair->bp3].co, &l, 0)) diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c index d3c14a9dd12..91091d3880f 100644 --- a/source/blender/blenkernel/intern/constraint.c +++ b/source/blender/blenkernel/intern/constraint.c @@ -1,6 +1,4 @@ /* - * $Id$ - * * ***** BEGIN GPL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or @@ -424,7 +422,7 @@ void constraint_mat_convertspace (Object *ob, bPoseChannel *pchan, float mat[][4 /* ------------ General Target Matrix Tools ---------- */ /* function that sets the given matrix based on given vertex group in mesh */ -static void contarget_get_mesh_mat (Scene *scene, Object *ob, const char *substring, float mat[][4]) +static void contarget_get_mesh_mat (Object *ob, const char *substring, float mat[][4]) { DerivedMesh *dm = NULL; Mesh *me= ob->data; @@ -449,16 +447,9 @@ static void contarget_get_mesh_mat (Scene *scene, Object *ob, const char *substr freeDM= 1; } else { - /* when not in EditMode, use the 'final' derived mesh - * - check if the custom data masks for derivedFinal mean that we can just use that - * (this is more effficient + sufficient for most cases) - */ - if (!(ob->lastDataMask & CD_MASK_MDEFORMVERT)) { - dm = mesh_get_derived_final(scene, ob, CD_MASK_MDEFORMVERT); - freeDM= 1; - } - else - dm = (DerivedMesh *)ob->derivedFinal; + /* when not in EditMode, use the 'final' derived mesh, depsgraph + * ensures we build with CD_MDEFORMVERT layer */ + dm = (DerivedMesh *)ob->derivedFinal; } /* only continue if there's a valid DerivedMesh */ @@ -587,7 +578,7 @@ static void contarget_get_lattice_mat (Object *ob, const char *substring, float /* generic function to get the appropriate matrix for most target cases */ /* The cases where the target can be object data have not been implemented */ -static void constraint_target_to_mat4 (Scene *scene, Object *ob, const char *substring, float mat[][4], short from, short to, float headtail) +static void constraint_target_to_mat4 (Object *ob, const char *substring, float mat[][4], short from, short to, float headtail) { /* Case OBJECT */ if (!strlen(substring)) { @@ -604,7 +595,7 @@ static void constraint_target_to_mat4 (Scene *scene, Object *ob, const char *sub * way as constraints can only really affect things on object/bone level. */ else if (ob->type == OB_MESH) { - contarget_get_mesh_mat(scene, ob, substring, mat); + contarget_get_mesh_mat(ob, substring, mat); constraint_mat_convertspace(ob, NULL, mat, from, to); } else if (ob->type == OB_LATTICE) { @@ -684,10 +675,10 @@ static bConstraintTypeInfo CTI_CONSTRNAME = { /* This function should be used for the get_target_matrix member of all * constraints that are not picky about what happens to their target matrix. */ -static void default_get_tarmat (bConstraint *con, bConstraintOb *cob, bConstraintTarget *ct, float UNUSED(ctime)) +static void default_get_tarmat (bConstraint *con, bConstraintOb *UNUSED(cob), bConstraintTarget *ct, float UNUSED(ctime)) { if (VALID_CONS_TARGET(ct)) - constraint_target_to_mat4(cob->scene, ct->tar, ct->subtarget, ct->matrix, CONSTRAINT_SPACE_WORLD, ct->space, con->headtail); + constraint_target_to_mat4(ct->tar, ct->subtarget, ct->matrix, CONSTRAINT_SPACE_WORLD, ct->space, con->headtail); else if (ct) unit_m4(ct->matrix); } @@ -1159,7 +1150,7 @@ static void kinematic_get_tarmat (bConstraint *con, bConstraintOb *cob, bConstra bKinematicConstraint *data= con->data; if (VALID_CONS_TARGET(ct)) - constraint_target_to_mat4(cob->scene, ct->tar, ct->subtarget, ct->matrix, CONSTRAINT_SPACE_WORLD, ct->space, con->headtail); + constraint_target_to_mat4(ct->tar, ct->subtarget, ct->matrix, CONSTRAINT_SPACE_WORLD, ct->space, con->headtail); else if (ct) { if (data->flag & CONSTRAINT_IK_AUTO) { Object *ob= cob->ob; @@ -2046,7 +2037,7 @@ static void pycon_get_tarmat (bConstraint *con, bConstraintOb *cob, bConstraintT /* firstly calculate the matrix the normal way, then let the py-function override * this matrix if it needs to do so */ - constraint_target_to_mat4(cob->scene, ct->tar, ct->subtarget, ct->matrix, CONSTRAINT_SPACE_WORLD, ct->space, con->headtail); + constraint_target_to_mat4(ct->tar, ct->subtarget, ct->matrix, CONSTRAINT_SPACE_WORLD, ct->space, con->headtail); /* only execute target calculation if allowed */ #ifdef WITH_PYTHON @@ -2165,7 +2156,7 @@ static void actcon_get_tarmat (bConstraint *con, bConstraintOb *cob, bConstraint unit_m4(ct->matrix); /* get the transform matrix of the target */ - constraint_target_to_mat4(cob->scene, ct->tar, ct->subtarget, tempmat, CONSTRAINT_SPACE_WORLD, ct->space, con->headtail); + constraint_target_to_mat4(ct->tar, ct->subtarget, tempmat, CONSTRAINT_SPACE_WORLD, ct->space, con->headtail); /* determine where in transform range target is */ /* data->type is mapped as follows for backwards compatability: @@ -2216,7 +2207,7 @@ static void actcon_get_tarmat (bConstraint *con, bConstraintOb *cob, bConstraint tchan->rotmode= pchan->rotmode; /* evaluate action using workob (it will only set the PoseChannel in question) */ - what_does_obaction(cob->scene, cob->ob, &workob, pose, data->act, pchan->name, t); + what_does_obaction(cob->ob, &workob, pose, data->act, pchan->name, t); /* convert animation to matrices for use here */ pchan_calc_mat(tchan); @@ -2230,7 +2221,7 @@ static void actcon_get_tarmat (bConstraint *con, bConstraintOb *cob, bConstraint /* evaluate using workob */ // FIXME: we don't have any consistent standards on limiting effects on object... - what_does_obaction(cob->scene, cob->ob, &workob, NULL, data->act, NULL, t); + what_does_obaction(cob->ob, &workob, NULL, data->act, NULL, t); object_to_mat4(&workob, ct->matrix); } else { @@ -2648,7 +2639,7 @@ static void distlimit_evaluate (bConstraint *con, bConstraintOb *cob, ListBase * /* if inside, then move to surface */ if (dist <= data->dist) { clamp_surf= 1; - sfac= data->dist / dist; + if (dist != 0.0f) sfac= data->dist / dist; } /* if soft-distance is enabled, start fading once owner is dist+softdist from the target */ else if (data->flag & LIMITDIST_USESOFT) { @@ -2661,14 +2652,14 @@ static void distlimit_evaluate (bConstraint *con, bConstraintOb *cob, ListBase * /* if outside, then move to surface */ if (dist >= data->dist) { clamp_surf= 1; - sfac= data->dist / dist; + if (dist != 0.0f) sfac= data->dist / dist; } /* if soft-distance is enabled, start fading once owner is dist-soft from the target */ else if (data->flag & LIMITDIST_USESOFT) { // FIXME: there's a problem with "jumping" when this kicks in if (dist >= (data->dist - data->soft)) { sfac = (float)( data->soft*(1.0f - expf(-(dist - data->dist)/data->soft)) + data->dist ); - sfac /= dist; + if (dist != 0.0f) sfac /= dist; clamp_surf= 1; } @@ -2677,7 +2668,7 @@ static void distlimit_evaluate (bConstraint *con, bConstraintOb *cob, ListBase * else { if (IS_EQF(dist, data->dist)==0) { clamp_surf= 1; - sfac= data->dist / dist; + if (dist != 0.0f) sfac= data->dist / dist; } } @@ -4427,6 +4418,34 @@ void get_constraint_target_matrix (struct Scene *scene, bConstraint *con, int n, unit_m4(mat); } } + +/* Get the list of targets required for solving a constraint */ +void get_constraint_targets_for_solving (bConstraint *con, bConstraintOb *cob, ListBase *targets, float ctime) +{ + bConstraintTypeInfo *cti= constraint_get_typeinfo(con); + + if (cti && cti->get_constraint_targets) { + bConstraintTarget *ct; + + /* get targets + * - constraints should use ct->matrix, not directly accessing values + * - ct->matrix members have not yet been calculated here! + */ + cti->get_constraint_targets(con, targets); + + /* set matrices + * - calculate if possible, otherwise just initialise as identity matrix + */ + if (cti->get_target_matrix) { + for (ct= targets->first; ct; ct= ct->next) + cti->get_target_matrix(con, cob, ct, ctime); + } + else { + for (ct= targets->first; ct; ct= ct->next) + unit_m4(ct->matrix); + } + } +} /* ---------- Evaluation ----------- */ @@ -4471,27 +4490,7 @@ void solve_constraints (ListBase *conlist, bConstraintOb *cob, float ctime) constraint_mat_convertspace(cob->ob, cob->pchan, cob->matrix, CONSTRAINT_SPACE_WORLD, con->ownspace); /* prepare targets for constraint solving */ - if (cti->get_constraint_targets) { - bConstraintTarget *ct; - - /* get targets - * - constraints should use ct->matrix, not directly accessing values - * - ct->matrix members have not yet been calculated here! - */ - cti->get_constraint_targets(con, &targets); - - /* set matrices - * - calculate if possible, otherwise just initialise as identity matrix - */ - if (cti->get_target_matrix) { - for (ct= targets.first; ct; ct= ct->next) - cti->get_target_matrix(con, cob, ct, ctime); - } - else { - for (ct= targets.first; ct; ct= ct->next) - unit_m4(ct->matrix); - } - } + get_constraint_targets_for_solving(con, cob, &targets, ctime); /* Solve the constraint and put result in cob->matrix */ cti->evaluate_constraint(con, cob, &targets); diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c index 704af73dd10..b1beb6c449a 100644 --- a/source/blender/blenkernel/intern/curve.c +++ b/source/blender/blenkernel/intern/curve.c @@ -580,46 +580,47 @@ void addNurbPointsBezier(Nurb *nu, int number) /* ~~~~~~~~~~~~~~~~~~~~Non Uniform Rational B Spline calculations ~~~~~~~~~~~ */ -static void calcknots(float *knots, short aantal, short order, short type) -/* knots: number of pnts NOT corrected for cyclic */ -/* type; 0: uniform, 1: endpoints, 2: bezier */ +static void calcknots(float *knots, const short pnts, const short order, const short flag) { + /* knots: number of pnts NOT corrected for cyclic */ + const int pnts_order= pnts + order; float k; - int a, t; - - t = aantal+order; - if(type==0) { + int a; - for(a=0;a<t;a++) { - knots[a]= (float)a; - } - } - else if(type==1) { + switch(flag & (CU_NURB_ENDPOINT|CU_NURB_BEZIER)) { + case CU_NURB_ENDPOINT: k= 0.0; - for(a=1;a<=t;a++) { + for(a=1; a <= pnts_order; a++) { knots[a-1]= k; - if(a>=order && a<=aantal) k+= 1.0f; + if(a >= order && a <= pnts) k+= 1.0f; } - } - else if(type==2) { - /* Warning, the order MUST be 2 or 4, if this is not enforced, the displist will be corrupt */ + break; + case CU_NURB_BEZIER: + /* Warning, the order MUST be 2 or 4, + * if this is not enforced, the displist will be corrupt */ if(order==4) { k= 0.34; - for(a=0;a<t;a++) { + for(a=0; a < pnts_order; a++) { knots[a]= floorf(k); k+= (1.0f/3.0f); } } else if(order==3) { k= 0.6f; - for(a=0;a<t;a++) { - if(a>=order && a<=aantal) k+= 0.5f; + for(a=0; a < pnts_order; a++) { + if(a >= order && a <= pnts) k+= 0.5f; knots[a]= floorf(k); } } else { printf("bez nurb curve order is not 3 or 4, should never happen\n"); } + break; + default: + for(a=0; a < pnts_order; a++) { + knots[a]= (float)a; + } + break; } } @@ -662,7 +663,7 @@ static void makeknots(Nurb *nu, short uv) calcknots(nu->knotsu, nu->pntsu, nu->orderu, 0); /* cyclic should be uniform */ makecyclicknots(nu->knotsu, nu->pntsu, nu->orderu); } else { - calcknots(nu->knotsu, nu->pntsu, nu->orderu, nu->flagu>>1); + calcknots(nu->knotsu, nu->pntsu, nu->orderu, nu->flagu); } } else nu->knotsu= NULL; @@ -675,7 +676,7 @@ static void makeknots(Nurb *nu, short uv) calcknots(nu->knotsv, nu->pntsv, nu->orderv, 0); /* cyclic should be uniform */ makecyclicknots(nu->knotsv, nu->pntsv, nu->orderv); } else { - calcknots(nu->knotsv, nu->pntsv, nu->orderv, nu->flagv>>1); + calcknots(nu->knotsv, nu->pntsv, nu->orderv, nu->flagv); } } else nu->knotsv= NULL; @@ -2431,6 +2432,7 @@ void calchandleNurb(BezTriple *bezt, BezTriple *prev, BezTriple *next, int mode) { float *p1,*p2,*p3, pt[3]; float dx1,dy1,dz1,dx,dy,dz,vx,vy,vz,len,len1,len2; + const float eps= 1e-5; if(bezt->h1==0 && bezt->h2==0) return; @@ -2471,7 +2473,7 @@ void calchandleNurb(BezTriple *bezt, BezTriple *prev, BezTriple *next, int mode) if(len2==0.0f) len2=1.0f; - if(bezt->h1==HD_AUTO || bezt->h2==HD_AUTO) { /* auto */ + if(ELEM(bezt->h1,HD_AUTO,HD_AUTO_ANIM) || ELEM(bezt->h2,HD_AUTO,HD_AUTO_ANIM)) { /* auto */ vx= dx1/len2 + dx/len1; vy= dy1/len2 + dy/len1; vz= dz1/len2 + dz/len1; @@ -2482,13 +2484,13 @@ void calchandleNurb(BezTriple *bezt, BezTriple *prev, BezTriple *next, int mode) if(len1>5.0f*len2) len1= 5.0f*len2; if(len2>5.0f*len1) len2= 5.0f*len1; - if(bezt->h1==HD_AUTO) { + if(ELEM(bezt->h1,HD_AUTO,HD_AUTO_ANIM)) { len1/=len; *(p2-3)= *p2-vx*len1; *(p2-2)= *(p2+1)-vy*len1; *(p2-1)= *(p2+2)-vz*len1; - if(mode==2 && next && prev) { // keep horizontal if extrema + if((bezt->h1==HD_AUTO_ANIM) && next && prev) { // keep horizontal if extrema float ydiff1= prev->vec[1][1] - bezt->vec[1][1]; float ydiff2= next->vec[1][1] - bezt->vec[1][1]; if( (ydiff1 <= 0.0f && ydiff2 <= 0.0f) || (ydiff1 >= 0.0f && ydiff2 >= 0.0f) ) { @@ -2510,13 +2512,13 @@ void calchandleNurb(BezTriple *bezt, BezTriple *prev, BezTriple *next, int mode) } } } - if(bezt->h2==HD_AUTO) { + if(ELEM(bezt->h2,HD_AUTO,HD_AUTO_ANIM)) { len2/=len; *(p2+3)= *p2+vx*len2; *(p2+4)= *(p2+1)+vy*len2; *(p2+5)= *(p2+2)+vz*len2; - if(mode==2 && next && prev) { // keep horizontal if extrema + if((bezt->h2==HD_AUTO_ANIM) && next && prev) { // keep horizontal if extrema float ydiff1= prev->vec[1][1] - bezt->vec[1][1]; float ydiff2= next->vec[1][1] - bezt->vec[1][1]; if( (ydiff1 <= 0.0f && ydiff2 <= 0.0f) || (ydiff1 >= 0.0f && ydiff2 >= 0.0f) ) { @@ -2587,30 +2589,38 @@ void calchandleNurb(BezTriple *bezt, BezTriple *prev, BezTriple *next, int mode) if(bezt->f1 & SELECT) { /* order of calculation */ if(bezt->h2==HD_ALIGN) { /* aligned */ - len= len2/len1; - p2[3]= p2[0]+len*(p2[0]-p2[-3]); - p2[4]= p2[1]+len*(p2[1]-p2[-2]); - p2[5]= p2[2]+len*(p2[2]-p2[-1]); + if(len1>eps) { + len= len2/len1; + p2[3]= p2[0]+len*(p2[0]-p2[-3]); + p2[4]= p2[1]+len*(p2[1]-p2[-2]); + p2[5]= p2[2]+len*(p2[2]-p2[-1]); + } } if(bezt->h1==HD_ALIGN) { - len= len1/len2; - p2[-3]= p2[0]+len*(p2[0]-p2[3]); - p2[-2]= p2[1]+len*(p2[1]-p2[4]); - p2[-1]= p2[2]+len*(p2[2]-p2[5]); + if(len2>eps) { + len= len1/len2; + p2[-3]= p2[0]+len*(p2[0]-p2[3]); + p2[-2]= p2[1]+len*(p2[1]-p2[4]); + p2[-1]= p2[2]+len*(p2[2]-p2[5]); + } } } else { if(bezt->h1==HD_ALIGN) { - len= len1/len2; - p2[-3]= p2[0]+len*(p2[0]-p2[3]); - p2[-2]= p2[1]+len*(p2[1]-p2[4]); - p2[-1]= p2[2]+len*(p2[2]-p2[5]); + if(len2>eps) { + len= len1/len2; + p2[-3]= p2[0]+len*(p2[0]-p2[3]); + p2[-2]= p2[1]+len*(p2[1]-p2[4]); + p2[-1]= p2[2]+len*(p2[2]-p2[5]); + } } if(bezt->h2==HD_ALIGN) { /* aligned */ - len= len2/len1; - p2[3]= p2[0]+len*(p2[0]-p2[-3]); - p2[4]= p2[1]+len*(p2[1]-p2[-2]); - p2[5]= p2[2]+len*(p2[2]-p2[-1]); + if(len1>eps) { + len= len2/len1; + p2[3]= p2[0]+len*(p2[0]-p2[-3]); + p2[4]= p2[1]+len*(p2[1]-p2[-2]); + p2[5]= p2[2]+len*(p2[2]-p2[-1]); + } } } } @@ -2664,15 +2674,15 @@ void testhandlesNurb(Nurb *nu) if(bezt->f1 & SELECT) flag++; if(bezt->f2 & SELECT) flag += 2; if(bezt->f3 & SELECT) flag += 4; - + if( !(flag==0 || flag==7) ) { - if(bezt->h1==HD_AUTO) { /* auto */ + if(ELEM(bezt->h1, HD_AUTO, HD_AUTO_ANIM)) { /* auto */ bezt->h1= HD_ALIGN; } - if(bezt->h2==HD_AUTO) { /* auto */ + if(ELEM(bezt->h2, HD_AUTO, HD_AUTO_ANIM)) { /* auto */ bezt->h2= HD_ALIGN; } - + if(bezt->h1==HD_VECT) { /* vector */ if(flag < 4) bezt->h1= 0; } @@ -2682,7 +2692,7 @@ void testhandlesNurb(Nurb *nu) } bezt++; } - + calchandlesNurb(nu); } @@ -3250,3 +3260,28 @@ void curve_translate(Curve *cu, float offset[3], int do_keys) } } } + +void curve_delete_material_index(Curve *cu, int index) +{ + const int curvetype= curve_type(cu); + + if(curvetype == OB_FONT) { + struct CharInfo *info= cu->strinfo; + int i; + for(i= cu->len-1; i >= 0; i--, info++) { + if (info->mat_nr && info->mat_nr>=index) { + info->mat_nr--; + } + } + } + else { + Nurb *nu; + + for (nu= cu->nurb.first; nu; nu= nu->next) { + if(nu->mat_nr && nu->mat_nr>=index) { + nu->mat_nr--; + if (curvetype == OB_CURVE) nu->charidx--; + } + } + } +} diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c index 57a7c917fa3..883f67c3061 100644 --- a/source/blender/blenkernel/intern/customdata.c +++ b/source/blender/blenkernel/intern/customdata.c @@ -466,7 +466,6 @@ static void layerInterp_mdisps(void **sources, float *UNUSED(weights), MDisps tris[2]; int vindex[4] = {0}; - S = 0; for(i = 0; i < 2; i++) for(y = 0; y < 4; y++) for(x = 0; x < 4; x++) @@ -809,42 +808,67 @@ static void layerDefault_mcol(void *data, int count) static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = { + /* 0: CD_MVERT */ {sizeof(MVert), "MVert", 1, NULL, NULL, NULL, NULL, NULL, NULL}, + /* 1: CD_MSTICKY */ {sizeof(MSticky), "MSticky", 1, NULL, NULL, NULL, layerInterp_msticky, NULL, NULL}, + /* 2: CD_MDEFORMVERT */ {sizeof(MDeformVert), "MDeformVert", 1, NULL, layerCopy_mdeformvert, layerFree_mdeformvert, layerInterp_mdeformvert, NULL, NULL}, + /* 3: CD_MEDGE */ {sizeof(MEdge), "MEdge", 1, NULL, NULL, NULL, NULL, NULL, NULL}, + /* 4: CD_MFACE */ {sizeof(MFace), "MFace", 1, NULL, NULL, NULL, NULL, NULL, NULL}, + /* 5: CD_MTFACE */ {sizeof(MTFace), "MTFace", 1, "UVTex", layerCopy_tface, NULL, layerInterp_tface, layerSwap_tface, layerDefault_tface}, + /* 6: CD_MCOL */ /* 4 MCol structs per face */ {sizeof(MCol)*4, "MCol", 4, "Col", NULL, NULL, layerInterp_mcol, layerSwap_mcol, layerDefault_mcol}, + /* 7: CD_ORIGINDEX */ {sizeof(int), "", 0, NULL, NULL, NULL, NULL, NULL, NULL}, + /* 8: CD_NORMAL */ /* 3 floats per normal vector */ {sizeof(float)*3, "", 0, NULL, NULL, NULL, NULL, NULL, NULL}, + /* 9: CD_FLAGS */ {sizeof(int), "", 0, NULL, NULL, NULL, NULL, NULL, NULL}, + /* 10: CD_PROP_FLT */ {sizeof(MFloatProperty), "MFloatProperty",1,"Float",NULL,NULL,NULL,NULL}, + /* 11: CD_PROP_INT */ {sizeof(MIntProperty), "MIntProperty",1,"Int",NULL,NULL,NULL,NULL}, + /* 12: CD_PROP_STR */ {sizeof(MStringProperty), "MStringProperty",1,"String",NULL,NULL,NULL,NULL}, + /* 13: CD_ORIGSPACE */ {sizeof(OrigSpaceFace), "OrigSpaceFace", 1, "UVTex", layerCopy_origspace_face, NULL, layerInterp_origspace_face, layerSwap_origspace_face, layerDefault_origspace_face}, + /* 14: CD_ORCO */ {sizeof(float)*3, "", 0, NULL, NULL, NULL, NULL, NULL, NULL}, + /* 15: CD_MTEXPOLY */ {sizeof(MTexPoly), "MTexPoly", 1, "Face Texture", NULL, NULL, NULL, NULL, NULL}, + /* 16: CD_MLOOPUV */ {sizeof(MLoopUV), "MLoopUV", 1, "UV coord", NULL, NULL, layerInterp_mloopuv, NULL, NULL}, + /* 17: CD_MLOOPCOL */ {sizeof(MLoopCol), "MLoopCol", 1, "Col", NULL, NULL, layerInterp_mloopcol, NULL, layerDefault_mloopcol}, + /* 18: CD_TANGENT */ {sizeof(float)*4*4, "", 0, NULL, NULL, NULL, NULL, NULL, NULL}, + /* 19: CD_MDISPS */ {sizeof(MDisps), "MDisps", 1, NULL, layerCopy_mdisps, layerFree_mdisps, layerInterp_mdisps, layerSwap_mdisps, NULL, layerRead_mdisps, layerWrite_mdisps, layerFilesize_mdisps, layerValidate_mdisps}, + /* 20: CD_WEIGHT_MCOL */ {sizeof(MCol)*4, "MCol", 4, "WeightCol", NULL, NULL, layerInterp_mcol, layerSwap_mcol, layerDefault_mcol}, - {sizeof(MCol)*4, "MCol", 4, "IDCol", NULL, NULL, layerInterp_mcol, + /* 21: CD_ID_MCOL */ + {sizeof(MCol)*4, "MCol", 4, "IDCol", NULL, NULL, layerInterp_mcol, layerSwap_mcol, layerDefault_mcol}, - {sizeof(MCol)*4, "MCol", 4, "TexturedCol", NULL, NULL, layerInterp_mcol, + /* 22: CD_TEXTURE_MCOL */ + {sizeof(MCol)*4, "MCol", 4, "TexturedCol", NULL, NULL, layerInterp_mcol, layerSwap_mcol, layerDefault_mcol}, + /* 23: CD_CLOTH_ORCO */ {sizeof(float)*3, "", 0, NULL, NULL, NULL, NULL, NULL, NULL}, + /* 24: CD_RECAST */ {sizeof(MRecast), "MRecast", 1,"Recast",NULL,NULL,NULL,NULL} }; diff --git a/source/blender/blenkernel/intern/depsgraph.c b/source/blender/blenkernel/intern/depsgraph.c index 472d7d77b80..6f27a104144 100644 --- a/source/blender/blenkernel/intern/depsgraph.c +++ b/source/blender/blenkernel/intern/depsgraph.c @@ -301,6 +301,7 @@ static void dag_add_driver_relation(AnimData *adt, DagForest *dag, DagNode *node for (fcu= adt->drivers.first; fcu; fcu= fcu->next) { ChannelDriver *driver= fcu->driver; DriverVar *dvar; + int isdata_fcu = isdata || (fcu->rna_path && strstr(fcu->rna_path, "modifiers[")); /* loop over variables to get the target relationships */ for (dvar= driver->variables.first; dvar; dvar= dvar->next) { @@ -320,14 +321,14 @@ static void dag_add_driver_relation(AnimData *adt, DagForest *dag, DagNode *node ( ((dtar->rna_path) && strstr(dtar->rna_path, "pose.bones[")) || ((dtar->flag & DTAR_FLAG_STRUCT_REF) && (dtar->pchan_name[0])) )) { - dag_add_relation(dag, node1, node, isdata?DAG_RL_DATA_DATA:DAG_RL_DATA_OB, "Driver"); + dag_add_relation(dag, node1, node, isdata_fcu?DAG_RL_DATA_DATA:DAG_RL_DATA_OB, "Driver"); } /* check if ob data */ else if (dtar->rna_path && strstr(dtar->rna_path, "data.")) - dag_add_relation(dag, node1, node, isdata?DAG_RL_DATA_DATA:DAG_RL_DATA_OB, "Driver"); + dag_add_relation(dag, node1, node, isdata_fcu?DAG_RL_DATA_DATA:DAG_RL_DATA_OB, "Driver"); /* normal */ else - dag_add_relation(dag, node1, node, isdata?DAG_RL_OB_DATA:DAG_RL_OB_OB, "Driver"); + dag_add_relation(dag, node1, node, isdata_fcu?DAG_RL_OB_DATA:DAG_RL_OB_OB, "Driver"); } } } @@ -372,6 +373,9 @@ static void build_dag_object(DagForest *dag, DagNode *scenenode, Scene *scene, O node2->first_ancestor = ob; node2->ancestor_count += 1; } + + /* also build a custom data mask for dependencies that need certain layers */ + node->customdata_mask= 0; if (ob->type == OB_ARMATURE) { if (ob->pose){ @@ -451,8 +455,12 @@ static void build_dag_object(DagForest *dag, DagNode *scenenode, Scene *scene, O case PARSKEL: dag_add_relation(dag,node2,node,DAG_RL_DATA_DATA|DAG_RL_OB_OB, "Parent"); break; - case PARVERT1: case PARVERT3: case PARBONE: + case PARVERT1: case PARVERT3: dag_add_relation(dag,node2,node,DAG_RL_DATA_OB|DAG_RL_OB_OB, "Vertex Parent"); + node2->customdata_mask |= CD_MASK_ORIGINDEX; + break; + case PARBONE: + dag_add_relation(dag,node2,node,DAG_RL_DATA_OB|DAG_RL_OB_OB, "Bone Parent"); break; default: if(ob->parent->type==OB_LATTICE) @@ -592,7 +600,7 @@ static void build_dag_object(DagForest *dag, DagNode *scenenode, Scene *scene, O if(part->ren_as == PART_DRAW_GR && part->dup_group) { for(go=part->dup_group->gobject.first; go; go=go->next) { node2 = dag_get_node(dag, go->ob); - dag_add_relation(dag, node, node2, DAG_RL_OB_OB, "Particle Group Visualisation"); + dag_add_relation(dag, node2, node, DAG_RL_OB_OB, "Particle Group Visualisation"); } } @@ -647,8 +655,11 @@ static void build_dag_object(DagForest *dag, DagNode *scenenode, Scene *scene, O if (ELEM(con->type, CONSTRAINT_TYPE_FOLLOWPATH, CONSTRAINT_TYPE_CLAMPTO)) dag_add_relation(dag, node2, node, DAG_RL_DATA_OB|DAG_RL_OB_OB, cti->name); else { - if (ELEM3(obt->type, OB_ARMATURE, OB_MESH, OB_LATTICE) && (ct->subtarget[0])) + if (ELEM3(obt->type, OB_ARMATURE, OB_MESH, OB_LATTICE) && (ct->subtarget[0])) { dag_add_relation(dag, node2, node, DAG_RL_DATA_OB|DAG_RL_OB_OB, cti->name); + if (obt->type == OB_MESH) + node2->customdata_mask |= CD_MASK_MDEFORMVERT; + } else dag_add_relation(dag, node2, node, DAG_RL_OB_OB, cti->name); } @@ -722,6 +733,9 @@ struct DagForest *build_dag(Main *bmain, Scene *sce, short mask) itA->node->color |= itA->type; } } + + /* also flush custom data mask */ + ((Object*)node->ob)->customdata_mask= node->customdata_mask; } } /* now set relations equal, so that when only one parent changes, the correct recalcs are found */ @@ -2048,6 +2062,23 @@ static short animdata_use_time(AnimData *adt) return 1; } + /* If we have drivers, more likely than not, on a frame change + * they'll need updating because their owner changed + * + * This is kindof a hack to get around a whole host of problems + * involving drivers using non-object datablock data (which the + * depsgraph currently has no way of representing let alone correctly + * dependency sort+tagging). By doing this, at least we ensure that + * some commonly attempted drivers (such as scene -> current frame; + * see "Driver updates fail" thread on Bf-committers dated July 2) + * will work correctly, and that other non-object datablocks will have + * their drivers update at least on frame change. + * + * -- Aligorith, July 4 2011 + */ + if (adt->drivers.first) + return 1; + return 0; } @@ -2364,7 +2395,7 @@ static void dag_id_flush_update(Scene *sce, ID *id) if(id) { idtype= GS(id->name); - if(ELEM7(idtype, ID_ME, ID_CU, ID_MB, ID_LA, ID_LT, ID_CA, ID_AR)) { + if(ELEM8(idtype, ID_ME, ID_CU, ID_MB, ID_LA, ID_LT, ID_CA, ID_AR, ID_SPK)) { for(obt=bmain->object.first; obt; obt= obt->id.next) { if(!(ob && obt == ob) && obt->data == id) { obt->recalc |= OB_RECALC_DATA; diff --git a/source/blender/blenkernel/intern/displist.c b/source/blender/blenkernel/intern/displist.c index 9aa794aa97e..c2ed6468643 100644 --- a/source/blender/blenkernel/intern/displist.c +++ b/source/blender/blenkernel/intern/displist.c @@ -65,9 +65,6 @@ #include "BKE_lattice.h" #include "BKE_modifier.h" -#include "RE_pipeline.h" -#include "RE_shader_ext.h" - #include "BLO_sys_types.h" // for intptr_t support #include "ED_curve.h" /* for BKE_curve_nurbs */ @@ -286,499 +283,6 @@ int surfindex_displist(DispList *dl, int a, int *b, int *p1, int *p2, int *p3, i return 1; } -/* ***************************** shade displist. note colors now are in rgb(a) order ******************** */ - -/* create default shade input... save cpu cycles with ugly global */ -/* XXXX bad code warning: local ShadeInput initialize... */ -static ShadeInput shi; -static void init_fastshade_shadeinput(Render *re) -{ - memset(&shi, 0, sizeof(ShadeInput)); - shi.lay= RE_GetScene(re)->lay; - shi.view[2]= -1.0f; - shi.passflag= SCE_PASS_COMBINED; - shi.combinedflag= -1; -} - -static Render *fastshade_get_render(Scene *UNUSED(scene)) -{ - // XXX 2.5: this crashes combined with previewrender - // due to global R so disabled for now -#if 0 - /* XXX ugly global still, but we can't do preview while rendering */ - if(G.rendering==0) { - - Render *re= RE_GetRender("_Shade View_"); - if(re==NULL) { - re= RE_NewRender("_Shade View_"); - - RE_Database_Baking(re, scene, 0, 0); /* 0= no faces */ - } - return re; - } -#endif - - return NULL; -} - -/* called on file reading */ -void fastshade_free_render(void) -{ - Render *re= RE_GetRender("_Shade View_"); - - if(re) { - RE_Database_Free(re); - RE_FreeRender(re); - } -} - - -static void fastshade_customdata(CustomData *fdata, int a, int j, Material *ma) -{ - CustomDataLayer *layer; - MTFace *mtface; - int index, needuv= ma->texco & TEXCO_UV; - char *vertcol; - - shi.totuv= 0; - shi.totcol= 0; - - for(index=0; index<fdata->totlayer; index++) { - layer= &fdata->layers[index]; - - if(needuv && layer->type == CD_MTFACE && shi.totuv < MAX_MTFACE) { - mtface= &((MTFace*)layer->data)[a]; - - shi.uv[shi.totuv].uv[0]= 2.0f*mtface->uv[j][0]-1.0f; - shi.uv[shi.totuv].uv[1]= 2.0f*mtface->uv[j][1]-1.0f; - shi.uv[shi.totuv].uv[2]= 1.0f; - - shi.uv[shi.totuv].name= layer->name; - shi.totuv++; - } - else if(layer->type == CD_MCOL && shi.totcol < MAX_MCOL) { - vertcol= (char*)&((MCol*)layer->data)[a*4 + j]; - - shi.col[shi.totcol].col[0]= ((float)vertcol[3])/255.0f; - shi.col[shi.totcol].col[1]= ((float)vertcol[2])/255.0f; - shi.col[shi.totcol].col[2]= ((float)vertcol[1])/255.0f; - - shi.col[shi.totcol].name= layer->name; - shi.totcol++; - } - } - - if(needuv && shi.totuv == 0) - VECCOPY(shi.uv[0].uv, shi.lo); - - if(shi.totcol) - VECCOPY(shi.vcol, shi.col[0].col); -} - -static void fastshade(float *co, float *nor, float *orco, Material *ma, char *col1, char *col2) -{ - ShadeResult shr; - int a; - - VECCOPY(shi.co, co); - shi.vn[0]= -nor[0]; - shi.vn[1]= -nor[1]; - shi.vn[2]= -nor[2]; - VECCOPY(shi.vno, shi.vn); - VECCOPY(shi.facenor, shi.vn); - - if(ma->texco) { - VECCOPY(shi.lo, orco); - - if(ma->texco & TEXCO_GLOB) { - VECCOPY(shi.gl, shi.lo); - } - if(ma->texco & TEXCO_WINDOW) { - VECCOPY(shi.winco, shi.lo); - } - if(ma->texco & TEXCO_STICKY) { - VECCOPY(shi.sticky, shi.lo); - } - if(ma->texco & TEXCO_OBJECT) { - VECCOPY(shi.co, shi.lo); - } - if(ma->texco & TEXCO_NORM) { - VECCOPY(shi.orn, shi.vn); - } - if(ma->texco & TEXCO_REFL) { - float inp= 2.0f * (shi.vn[2]); - shi.ref[0]= (inp*shi.vn[0]); - shi.ref[1]= (inp*shi.vn[1]); - shi.ref[2]= (-1.0f + inp*shi.vn[2]); - } - } - - shi.mat= ma; /* set each time... node shaders change it */ - RE_shade_external(NULL, &shi, &shr); - - a= 256.0f*(shr.combined[0]); - col1[0]= CLAMPIS(a, 0, 255); - a= 256.0f*(shr.combined[1]); - col1[1]= CLAMPIS(a, 0, 255); - a= 256.0f*(shr.combined[2]); - col1[2]= CLAMPIS(a, 0, 255); - - if(col2) { - shi.vn[0]= -shi.vn[0]; - shi.vn[1]= -shi.vn[1]; - shi.vn[2]= -shi.vn[2]; - - shi.mat= ma; /* set each time... node shaders change it */ - RE_shade_external(NULL, &shi, &shr); - - a= 256.0f*(shr.combined[0]); - col2[0]= CLAMPIS(a, 0, 255); - a= 256.0f*(shr.combined[1]); - col2[1]= CLAMPIS(a, 0, 255); - a= 256.0f*(shr.combined[2]); - col2[2]= CLAMPIS(a, 0, 255); - } -} - -static void init_fastshade_for_ob(Render *re, Object *ob, int *need_orco_r, float mat[4][4], float imat[3][3]) -{ - float tmat[4][4]; - float amb[3]= {0.0f, 0.0f, 0.0f}; - int a; - - /* initialize globals in render */ - RE_shade_external(re, NULL, NULL); - - /* initialize global here */ - init_fastshade_shadeinput(re); - - RE_DataBase_GetView(re, tmat); - mul_m4_m4m4(mat, ob->obmat, tmat); - - invert_m4_m4(tmat, mat); - copy_m3_m4(imat, tmat); - if(ob->transflag & OB_NEG_SCALE) mul_m3_fl(imat, -1.0); - - if (need_orco_r) *need_orco_r= 0; - for(a=0; a<ob->totcol; a++) { - Material *ma= give_current_material(ob, a+1); - if(ma) { - init_render_material(ma, 0, amb); - - if(ma->texco & TEXCO_ORCO) { - if (need_orco_r) *need_orco_r= 1; - } - } - } -} - -static void end_fastshade_for_ob(Object *ob) -{ - int a; - - for(a=0; a<ob->totcol; a++) { - Material *ma= give_current_material(ob, a+1); - if(ma) - end_render_material(ma); - } -} - - -static void mesh_create_shadedColors(Render *re, Object *ob, int onlyForMesh, unsigned int **col1_r, unsigned int **col2_r) -{ - Mesh *me= ob->data; - DerivedMesh *dm; - MVert *mvert; - MFace *mface; - unsigned int *col1, *col2; - float *orco, *vnors, *nors, imat[3][3], mat[4][4], vec[3]; - int a, i, need_orco, totface, totvert; - CustomDataMask dataMask = CD_MASK_BAREMESH | CD_MASK_MCOL - | CD_MASK_MTFACE | CD_MASK_NORMAL; - - - init_fastshade_for_ob(re, ob, &need_orco, mat, imat); - - if(need_orco) - dataMask |= CD_MASK_ORCO; - - if (onlyForMesh) - dm = mesh_get_derived_deform(RE_GetScene(re), ob, dataMask); - else - dm = mesh_get_derived_final(RE_GetScene(re), ob, dataMask); - - mvert = dm->getVertArray(dm); - mface = dm->getFaceArray(dm); - nors = dm->getFaceDataArray(dm, CD_NORMAL); - totvert = dm->getNumVerts(dm); - totface = dm->getNumFaces(dm); - orco= dm->getVertDataArray(dm, CD_ORCO); - - if (onlyForMesh) { - col1 = *col1_r; - col2 = NULL; - } else { - *col1_r = col1 = MEM_mallocN(sizeof(*col1)*totface*4, "col1"); - - if (col2_r && (me->flag & ME_TWOSIDED)) - col2 = MEM_mallocN(sizeof(*col2)*totface*4, "col2"); - else - col2 = NULL; - - if (col2_r) *col2_r = col2; - } - - /* vertexnormals */ - vnors= MEM_mallocN(totvert*3*sizeof(float), "vnors disp"); - for (a=0; a<totvert; a++) { - MVert *mv = &mvert[a]; - float *vn= &vnors[a*3]; - float xn= mv->no[0]; - float yn= mv->no[1]; - float zn= mv->no[2]; - - /* transpose ! */ - vn[0]= imat[0][0]*xn+imat[0][1]*yn+imat[0][2]*zn; - vn[1]= imat[1][0]*xn+imat[1][1]*yn+imat[1][2]*zn; - vn[2]= imat[2][0]*xn+imat[2][1]*yn+imat[2][2]*zn; - normalize_v3(vn); - } - - for (i=0; i<totface; i++) { - MFace *mf= &mface[i]; - Material *ma= give_current_material(ob, mf->mat_nr+1); - int j, vidx[4], nverts= mf->v4?4:3; - unsigned char *col1base= (unsigned char*) &col1[i*4]; - unsigned char *col2base= (unsigned char*) (col2?&col2[i*4]:NULL); - float nor[3], n1[3]; - - if(ma==NULL) ma= &defmaterial; - - vidx[0]= mf->v1; - vidx[1]= mf->v2; - vidx[2]= mf->v3; - vidx[3]= mf->v4; - - if (nors) { - VECCOPY(nor, &nors[i*3]); - } else { - if (mf->v4) - normal_quad_v3( nor,mvert[mf->v1].co, mvert[mf->v2].co, mvert[mf->v3].co, mvert[mf->v4].co); - else - normal_tri_v3( nor,mvert[mf->v1].co, mvert[mf->v2].co, mvert[mf->v3].co); - } - - n1[0]= imat[0][0]*nor[0]+imat[0][1]*nor[1]+imat[0][2]*nor[2]; - n1[1]= imat[1][0]*nor[0]+imat[1][1]*nor[1]+imat[1][2]*nor[2]; - n1[2]= imat[2][0]*nor[0]+imat[2][1]*nor[1]+imat[2][2]*nor[2]; - normalize_v3(n1); - - for (j=0; j<nverts; j++) { - MVert *mv= &mvert[vidx[j]]; - char *col1= (char*)&col1base[j*4]; - char *col2= (char*)(col2base?&col2base[j*4]:NULL); - float *vn = (mf->flag & ME_SMOOTH)?&vnors[3*vidx[j]]:n1; - - mul_v3_m4v3(vec, mat, mv->co); - - mul_v3_v3fl(vec, vn, 0.001f); - - fastshade_customdata(&dm->faceData, i, j, ma); - fastshade(vec, vn, orco?&orco[vidx[j]*3]:mv->co, ma, col1, col2); - } - } - MEM_freeN(vnors); - - dm->release(dm); - - end_fastshade_for_ob(ob); -} - -void shadeMeshMCol(Scene *scene, Object *ob, Mesh *me) -{ - Render *re= fastshade_get_render(scene); - int a; - char *cp; - unsigned int *mcol= (unsigned int*)me->mcol; - - if(re) { - mesh_create_shadedColors(re, ob, 1, &mcol, NULL); - me->mcol= (MCol*)mcol; - - /* swap bytes */ - for(cp= (char *)me->mcol, a= 4*me->totface; a>0; a--, cp+=4) { - SWAP(char, cp[0], cp[3]); - SWAP(char, cp[1], cp[2]); - } - } -} - -/* has base pointer, to check for layer */ -/* called from drawobject.c */ -void shadeDispList(Scene *scene, Base *base) -{ - Object *ob= base->object; - DispList *dl, *dlob; - Material *ma = NULL; - Render *re; - float imat[3][3], mat[4][4], vec[3]; - float *fp, *nor, n1[3]; - unsigned int *col1; - int a, need_orco; - - re= fastshade_get_render(scene); - if(re==NULL) - return; - - dl = find_displist(&ob->disp, DL_VERTCOL); - if (dl) { - BLI_remlink(&ob->disp, dl); - free_disp_elem(dl); - } - - if(ob->type==OB_MESH) { - dl= MEM_callocN(sizeof(DispList), "displistshade"); - dl->type= DL_VERTCOL; - - mesh_create_shadedColors(re, ob, 0, &dl->col1, &dl->col2); - - /* add dl to ob->disp after mesh_create_shadedColors, because it - might indirectly free ob->disp */ - BLI_addtail(&ob->disp, dl); - } - else { - - init_fastshade_for_ob(re, ob, &need_orco, mat, imat); - - if (ELEM3(ob->type, OB_CURVE, OB_SURF, OB_FONT)) { - - /* now we need the normals */ - dl= ob->disp.first; - - while(dl) { - dlob= MEM_callocN(sizeof(DispList), "displistshade"); - BLI_addtail(&ob->disp, dlob); - dlob->type= DL_VERTCOL; - dlob->parts= dl->parts; - dlob->nr= dl->nr; - - if(dl->type==DL_INDEX3) { - col1= dlob->col1= MEM_mallocN(sizeof(int)*dl->nr, "col1"); - } - else { - col1= dlob->col1= MEM_mallocN(sizeof(int)*dl->parts*dl->nr, "col1"); - } - - - ma= give_current_material(ob, dl->col+1); - if(ma==NULL) ma= &defmaterial; - - if(dl->type==DL_INDEX3) { - if(dl->nors) { - /* there's just one normal */ - n1[0]= imat[0][0]*dl->nors[0]+imat[0][1]*dl->nors[1]+imat[0][2]*dl->nors[2]; - n1[1]= imat[1][0]*dl->nors[0]+imat[1][1]*dl->nors[1]+imat[1][2]*dl->nors[2]; - n1[2]= imat[2][0]*dl->nors[0]+imat[2][1]*dl->nors[1]+imat[2][2]*dl->nors[2]; - normalize_v3(n1); - - fp= dl->verts; - - a= dl->nr; - while(a--) { - mul_v3_m4v3(vec, mat, fp); - - fastshade(vec, n1, fp, ma, (char *)col1, NULL); - - fp+= 3; col1++; - } - } - } - else if(dl->type==DL_SURF) { - if(dl->nors) { - a= dl->nr*dl->parts; - fp= dl->verts; - nor= dl->nors; - - while(a--) { - mul_v3_m4v3(vec, mat, fp); - - n1[0]= imat[0][0]*nor[0]+imat[0][1]*nor[1]+imat[0][2]*nor[2]; - n1[1]= imat[1][0]*nor[0]+imat[1][1]*nor[1]+imat[1][2]*nor[2]; - n1[2]= imat[2][0]*nor[0]+imat[2][1]*nor[1]+imat[2][2]*nor[2]; - normalize_v3(n1); - - fastshade(vec, n1, fp, ma, (char *)col1, NULL); - - fp+= 3; nor+= 3; col1++; - } - } - } - dl= dl->next; - } - } - else if(ob->type==OB_MBALL) { - /* there are normals already */ - dl= ob->disp.first; - - while(dl) { - - if(dl->type==DL_INDEX4) { - if(dl->nors) { - if(dl->col1) MEM_freeN(dl->col1); - col1= dl->col1= MEM_mallocN(sizeof(int)*dl->nr, "col1"); - - ma= give_current_material(ob, dl->col+1); - if(ma==NULL) ma= &defmaterial; - - fp= dl->verts; - nor= dl->nors; - - a= dl->nr; - while(a--) { - mul_v3_m4v3(vec, mat, fp); - - /* transpose ! */ - n1[0]= imat[0][0]*nor[0]+imat[0][1]*nor[1]+imat[0][2]*nor[2]; - n1[1]= imat[1][0]*nor[0]+imat[1][1]*nor[1]+imat[1][2]*nor[2]; - n1[2]= imat[2][0]*nor[0]+imat[2][1]*nor[1]+imat[2][2]*nor[2]; - normalize_v3(n1); - - fastshade(vec, n1, fp, ma, (char *)col1, NULL); - - fp+= 3; col1++; nor+= 3; - } - } - } - dl= dl->next; - } - } - - end_fastshade_for_ob(ob); - } -} - -/* frees render and shade part of displists */ -/* note: dont do a shade again, until a redraw happens */ -void reshadeall_displist(Scene *scene) -{ - Base *base; - Object *ob; - - fastshade_free_render(); - - for(base= scene->base.first; base; base= base->next) { - ob= base->object; - - if(ELEM5(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL)) - freedisplist(&ob->disp); - - if(base->lay & scene->lay) { - /* Metaballs have standard displist at the Object */ - if(ob->type==OB_MBALL) shadeDispList(scene, base); - } - } -} - /* ****************** make displists ********************* */ static void curve_to_displist(Curve *cu, ListBase *nubase, ListBase *dispbase, int forRender) @@ -1865,6 +1369,11 @@ void makeDispListCurveTypes(Scene *scene, Object *ob, int forOrco) Curve *cu= ob->data; ListBase *dispbase; + /* The same check for duplis as in do_makeDispListCurveTypes. + Happens when curve used for constraint/bevel was converted to mesh. + check there is still needed for render displist and orco displists. */ + if(!ELEM3(ob->type, OB_SURF, OB_CURVE, OB_FONT)) return; + freedisplist(&(ob->disp)); dispbase= &(ob->disp); freedisplist(dispbase); diff --git a/source/blender/blenkernel/intern/effect.c b/source/blender/blenkernel/intern/effect.c index ee46bef6038..4b95c44f55f 100644 --- a/source/blender/blenkernel/intern/effect.c +++ b/source/blender/blenkernel/intern/effect.c @@ -241,6 +241,16 @@ static void precalculate_effector(EffectorCache *eff) } else if(eff->psys) psys_update_particle_tree(eff->psys, eff->scene->r.cfra); + + /* Store object velocity */ + if(eff->ob) { + float old_vel[3]; + + where_is_object_time(eff->scene, eff->ob, cfra - 1.0f); + copy_v3_v3(old_vel, eff->ob->obmat[3]); + where_is_object_time(eff->scene, eff->ob, cfra); + sub_v3_v3v3(eff->velocity, eff->ob->obmat[3], old_vel); + } } static EffectorCache *new_effector_cache(Scene *scene, Object *ob, ParticleSystem *psys, PartDeflect *pd) { @@ -680,10 +690,6 @@ int get_effector_data(EffectorCache *eff, EffectorData *efd, EffectedPoint *poin Object *ob = eff->ob; Object obcopy = *ob; - /* XXX this is not thread-safe, but used from multiple threads by - particle system */ - where_is_object_time(eff->scene, ob, cfra); - /* use z-axis as normal*/ normalize_v3_v3(efd->nor, ob->obmat[2]); @@ -702,13 +708,8 @@ int get_effector_data(EffectorCache *eff, EffectorData *efd, EffectedPoint *poin VECCOPY(efd->loc, ob->obmat[3]); } - if(real_velocity) { - VECCOPY(efd->vel, ob->obmat[3]); - - where_is_object_time(eff->scene, ob, cfra - 1.0f); - - sub_v3_v3v3(efd->vel, efd->vel, ob->obmat[3]); - } + if(real_velocity) + copy_v3_v3(efd->vel, eff->velocity); *eff->ob = obcopy; diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c index d6a9d950015..3916d0ca701 100644 --- a/source/blender/blenkernel/intern/fcurve.c +++ b/source/blender/blenkernel/intern/fcurve.c @@ -1,6 +1,4 @@ /* - * $Id$ - * * ***** BEGIN GPL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or @@ -42,6 +40,7 @@ #include "MEM_guardedalloc.h" #include "DNA_anim_types.h" +#include "DNA_constraint_types.h" #include "DNA_object_types.h" #include "BLI_blenlib.h" @@ -52,6 +51,7 @@ #include "BKE_animsys.h" #include "BKE_action.h" #include "BKE_armature.h" +#include "BKE_constraint.h" #include "BKE_curve.h" #include "BKE_global.h" #include "BKE_object.h" @@ -172,7 +172,7 @@ void copy_fcurves (ListBase *dst, ListBase *src) /* ----------------- Finding F-Curves -------------------------- */ /* high level function to get an fcurve from C without having the rna */ -FCurve *id_data_find_fcurve(ID *id, void *data, StructRNA *type, const char *prop_name, int index) +FCurve *id_data_find_fcurve(ID *id, void *data, StructRNA *type, const char *prop_name, int index, char *driven) { /* anim vars */ AnimData *adt= BKE_animdata_from_id(id); @@ -182,6 +182,9 @@ FCurve *id_data_find_fcurve(ID *id, void *data, StructRNA *type, const char *pro PointerRNA ptr; PropertyRNA *prop; char *path; + + if(driven) + *driven = 0; /* only use the current action ??? */ if (ELEM(NULL, adt, adt->action)) @@ -199,11 +202,12 @@ FCurve *id_data_find_fcurve(ID *id, void *data, StructRNA *type, const char *pro fcu= list_find_fcurve(&adt->action->curves, path, index); /* if not animated, check if driven */ -#if 0 if ((fcu == NULL) && (adt->drivers.first)) { - fcu= list_find_fcurve(&adt->drivers, path, but->rnaindex); + fcu= list_find_fcurve(&adt->drivers, path, index); + if(fcu && driven) + *driven = 1; + fcu = NULL; } -#endif MEM_freeN(path); } @@ -786,13 +790,10 @@ void calchandles_fcurve (FCurve *fcu) if (bezt->vec[2][0] < bezt->vec[1][0]) bezt->vec[2][0]= bezt->vec[1][0]; /* calculate auto-handles */ - if (fcu->flag & FCURVE_AUTO_HANDLES) - calchandleNurb(bezt, prev, next, 2); /* 2==special autohandle && keep extrema horizontal */ - else - calchandleNurb(bezt, prev, next, 1); /* 1==special autohandle */ + calchandleNurb(bezt, prev, next, 1); /* 1==special autohandle */ /* for automatic ease in and out */ - if ((bezt->h1==HD_AUTO) && (bezt->h2==HD_AUTO)) { + if (ELEM(bezt->h1,HD_AUTO,HD_AUTO_ANIM) && ELEM(bezt->h2,HD_AUTO,HD_AUTO_ANIM)) { /* only do this on first or last beztriple */ if ((a == 0) || (a == fcu->totvert-1)) { /* set both handles to have same horizontal value as keyframe */ @@ -840,9 +841,9 @@ void testhandles_fcurve (FCurve *fcu) /* one or two handles selected only */ if (ELEM(flag, 0, 7)==0) { /* auto handles become aligned */ - if (bezt->h1==HD_AUTO) + if (ELEM(bezt->h1, HD_AUTO, HD_AUTO_ANIM)) bezt->h1= HD_ALIGN; - if (bezt->h2==HD_AUTO) + if (ELEM(bezt->h2, HD_AUTO, HD_AUTO_ANIM)) bezt->h2= HD_ALIGN; /* vector handles become 'free' when only one half selected */ @@ -1002,7 +1003,7 @@ static float dtar_get_prop_val (ChannelDriver *driver, DriverTarget *dtar) /* get property to read from, and get value as appropriate */ if (RNA_path_resolve_full(&id_ptr, dtar->rna_path, &ptr, &prop, &index)) { - if(RNA_property_array_check(&ptr, prop)) { + if(RNA_property_array_check(prop)) { /* array */ if (index < RNA_property_array_length(&ptr, prop)) { switch (RNA_property_type(prop)) { @@ -1151,25 +1152,50 @@ static float dvar_eval_locDiff (ChannelDriver *driver, DriverVar *dvar) /* check if object or bone */ if (pchan) { /* bone */ - if ((dtar->flag & DTAR_FLAG_LOCALSPACE) == 0) { + if (dtar->flag & DTAR_FLAG_LOCALSPACE) { + if (dtar->flag & DTAR_FLAG_LOCAL_CONSTS) { + float mat[4][4]; + + /* extract transform just like how the constraints do it! */ + copy_m4_m4(mat, pchan->pose_mat); + constraint_mat_convertspace(ob, pchan, mat, CONSTRAINT_SPACE_POSE, CONSTRAINT_SPACE_LOCAL); + + /* ... and from that, we get our transform */ + VECCOPY(tmp_loc, mat[3]); + } + else { + /* transform space (use transform values directly) */ + VECCOPY(tmp_loc, pchan->loc); + } + } + else { /* convert to worldspace */ VECCOPY(tmp_loc, pchan->pose_head); mul_m4_v3(ob->obmat, tmp_loc); } - else { - /* local (use transform values directly) */ - VECCOPY(tmp_loc, pchan->loc); - } } else { /* object */ - if ((dtar->flag & DTAR_FLAG_LOCALSPACE) == 0) { - /* worldspace */ - VECCOPY(tmp_loc, ob->obmat[3]); + if (dtar->flag & DTAR_FLAG_LOCALSPACE) { + if (dtar->flag & DTAR_FLAG_LOCAL_CONSTS) { + // XXX: this should practically be the same as transform space... + float mat[4][4]; + + /* extract transform just like how the constraints do it! */ + copy_m4_m4(mat, ob->obmat); + constraint_mat_convertspace(ob, NULL, mat, CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_LOCAL); + + /* ... and from that, we get our transform */ + VECCOPY(tmp_loc, mat[3]); + } + else { + /* transform space (use transform values directly) */ + VECCOPY(tmp_loc, ob->loc); + } } else { - /* local (use transform values directly) */ - VECCOPY(tmp_loc, ob->loc); + /* worldspace */ + VECCOPY(tmp_loc, ob->obmat[3]); } } @@ -1197,7 +1223,7 @@ static float dvar_eval_transChan (ChannelDriver *driver, DriverVar *dvar) Object *ob= (Object *)dtar_id_ensure_proxy_from(dtar->id); bPoseChannel *pchan; float mat[4][4]; - float eul[3] = {0.0f,0.0f,0.0f}; + float oldEul[3] = {0.0f,0.0f,0.0f}; short useEulers=0, rotOrder=ROT_MODE_EUL; /* check if this target has valid data */ @@ -1210,36 +1236,62 @@ static float dvar_eval_transChan (ChannelDriver *driver, DriverVar *dvar) /* try to get posechannel */ pchan= get_pose_channel(ob->pose, dtar->pchan_name); - /* check if object or bone, and get transform matrix accordingly */ + /* check if object or bone, and get transform matrix accordingly + * - "useEulers" code is used to prevent the problems associated with non-uniqueness + * of euler decomposition from matrices [#20870] + * - localspace is for [#21384], where parent results are not wanted + * but local-consts is for all the common "corrective-shapes-for-limbs" situations + */ if (pchan) { /* bone */ if (pchan->rotmode > 0) { - VECCOPY(eul, pchan->eul); + VECCOPY(oldEul, pchan->eul); rotOrder= pchan->rotmode; useEulers = 1; } if (dtar->flag & DTAR_FLAG_LOCALSPACE) { - /* specially calculate local matrix, since chan_mat is not valid - * since it stores delta transform of pose_mat so that deforms work - */ - pchan_to_mat4(pchan, mat); + if (dtar->flag & DTAR_FLAG_LOCAL_CONSTS) { + /* just like how the constraints do it! */ + copy_m4_m4(mat, pchan->pose_mat); + constraint_mat_convertspace(ob, pchan, mat, CONSTRAINT_SPACE_POSE, CONSTRAINT_SPACE_LOCAL); + } + else { + /* specially calculate local matrix, since chan_mat is not valid + * since it stores delta transform of pose_mat so that deforms work + * so it cannot be used here for "transform" space + */ + pchan_to_mat4(pchan, mat); + } } - else + else { + /* worldspace matrix */ mul_m4_m4m4(mat, pchan->pose_mat, ob->obmat); + } } else { /* object */ if (ob->rotmode > 0) { - VECCOPY(eul, ob->rot); + VECCOPY(oldEul, ob->rot); rotOrder= ob->rotmode; useEulers = 1; } - if (dtar->flag & DTAR_FLAG_LOCALSPACE) - object_to_mat4(ob, mat); - else + if (dtar->flag & DTAR_FLAG_LOCALSPACE) { + if (dtar->flag & DTAR_FLAG_LOCAL_CONSTS) { + /* just like how the constraints do it! */ + copy_m4_m4(mat, ob->obmat); + constraint_mat_convertspace(ob, NULL, mat, CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_LOCAL); + } + else { + /* transforms to matrix */ + object_to_mat4(ob, mat); + } + } + else { + /* worldspace matrix - just the good-old one */ copy_m4_m4(mat, ob->obmat); + } } /* check which transform */ @@ -1255,9 +1307,21 @@ static float dvar_eval_transChan (ChannelDriver *driver, DriverVar *dvar) return scale[dtar->transChan - DTAR_TRANSCHAN_SCALEX]; } else if (dtar->transChan >= DTAR_TRANSCHAN_ROTX) { - /* extract euler rotation (if needed), and choose the right axis */ - if ((dtar->flag & DTAR_FLAG_LOCALSPACE)==0 || (useEulers == 0)) - mat4_to_eulO(eul, rotOrder, mat); + /* extract rotation as eulers (if needed) + * - definitely if rotation order isn't eulers already + * - if eulers, then we have 2 options: + * a) decompose transform matrix as required, then try to make eulers from + * there compatible with original values + * b) [NOT USED] directly use the original values (no decomposition) + * - only an option for "transform space", if quality is really bad with a) + */ + float eul[3]; + + mat4_to_eulO(eul, rotOrder, mat); + + if (useEulers) { + compatible_eul(eul, oldEul); + } return eul[dtar->transChan - DTAR_TRANSCHAN_ROTX]; } diff --git a/source/blender/blenkernel/intern/fmodifier.c b/source/blender/blenkernel/intern/fmodifier.c index 844f25e6d21..95c0aa60991 100644 --- a/source/blender/blenkernel/intern/fmodifier.c +++ b/source/blender/blenkernel/intern/fmodifier.c @@ -1,6 +1,4 @@ /* - * $Id$ - * * ***** BEGIN GPL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or @@ -606,7 +604,7 @@ static float fcm_cycles_time (FCurve *fcu, FModifier *fcm, float UNUSED(cvalue), /* calculate the 'number' of the cycle */ cycle= ((float)side * (evaltime - ofs) / cycdx); - + /* calculate the time inside the cycle */ cyct= fmod(evaltime - ofs, cycdx); @@ -631,11 +629,11 @@ static float fcm_cycles_time (FCurve *fcu, FModifier *fcm, float UNUSED(cvalue), cycyofs = (float)ceil((evaltime - ofs) / cycdx); cycyofs *= cycdy; } - + /* special case for cycle start/end */ if(cyct == 0.0f) { evaltime = (side == 1 ? lastkey[0] : prevkey[0]); - + if((mode == FCM_EXTRAPOLATE_MIRROR) && ((int)cycle % 2)) evaltime = (side == 1 ? prevkey[0] : lastkey[0]); } @@ -1013,6 +1011,7 @@ FModifier *add_fmodifier (ListBase *modifiers, int type) fcm= MEM_callocN(sizeof(FModifier), "F-Curve Modifier"); fcm->type = type; fcm->flag = FMODIFIER_FLAG_EXPANDED; + fcm->influence = 1.0f; BLI_addtail(modifiers, fcm); /* tag modifier as "active" if no other modifiers exist in the stack yet */ @@ -1200,6 +1199,47 @@ short list_has_suitable_fmodifier (ListBase *modifiers, int mtype, short acttype /* Evaluation API --------------------------- */ +/* helper function - calculate influence of FModifier */ +static float eval_fmodifier_influence (FModifier *fcm, float evaltime) +{ + float influence; + + /* sanity check */ + if (fcm == NULL) + return 0.0f; + + /* should we use influence stored in modifier or not + * NOTE: this is really just a hack so that we don't need to version patch old files ;) + */ + if (fcm->flag & FMODIFIER_FLAG_USEINFLUENCE) + influence = fcm->influence; + else + influence = 1.0f; + + /* restricted range or full range? */ + if (fcm->flag & FMODIFIER_FLAG_RANGERESTRICT) { + if ((evaltime <= fcm->sfra) || (evaltime >= fcm->efra)) { + /* out of range */ + return 0.0f; + } + else if ((evaltime > fcm->sfra) && (evaltime < fcm->sfra + fcm->blendin)) { + /* blend in range */ + float a = fcm->sfra; + float b = fcm->sfra + fcm->blendin; + return influence * (evaltime - a) / (b - a); + } + else if ((evaltime < fcm->efra) && (evaltime > fcm->efra - fcm->blendout)) { + /* blend out range */ + float a = fcm->efra; + float b = fcm->efra - fcm->blendout; + return influence * (evaltime - a) / (b - a); + } + } + + /* just return the influence of the modifier */ + return influence; +} + /* evaluate time modifications imposed by some F-Curve Modifiers * - this step acts as an optimisation to prevent the F-Curve stack being evaluated * several times by modifiers requesting the time be modified, as the final result @@ -1230,11 +1270,24 @@ float evaluate_time_fmodifiers (ListBase *modifiers, FCurve *fcu, float cvalue, for (fcm= modifiers->last; fcm; fcm= fcm->prev) { FModifierTypeInfo *fmi= fmodifier_get_typeinfo(fcm); - /* only evaluate if there's a callback for this */ - // TODO: implement the 'influence' control feature... - if (fmi && fmi->evaluate_modifier_time) { - if ((fcm->flag & (FMODIFIER_FLAG_DISABLED|FMODIFIER_FLAG_MUTED)) == 0) - evaltime= fmi->evaluate_modifier_time(fcu, fcm, cvalue, evaltime); + if (fmi == NULL) + continue; + + /* if modifier cannot be applied on this frame (whatever scale it is on, it won't affect the results) + * hence we shouldn't bother seeing what it would do given the chance + */ + if ((fcm->flag & FMODIFIER_FLAG_RANGERESTRICT)==0 || + ((fcm->sfra <= evaltime) && (fcm->efra >= evaltime)) ) + { + /* only evaluate if there's a callback for this */ + if (fmi->evaluate_modifier_time) { + if ((fcm->flag & (FMODIFIER_FLAG_DISABLED|FMODIFIER_FLAG_MUTED)) == 0) { + float influence = eval_fmodifier_influence(fcm, evaltime); + float nval = fmi->evaluate_modifier_time(fcu, fcm, cvalue, evaltime); + + evaltime = interpf(nval, evaltime, influence); + } + } } } @@ -1257,11 +1310,22 @@ void evaluate_value_fmodifiers (ListBase *modifiers, FCurve *fcu, float *cvalue, for (fcm= modifiers->first; fcm; fcm= fcm->next) { FModifierTypeInfo *fmi= fmodifier_get_typeinfo(fcm); - /* only evaluate if there's a callback for this */ - // TODO: implement the 'influence' control feature... - if (fmi && fmi->evaluate_modifier) { - if ((fcm->flag & (FMODIFIER_FLAG_DISABLED|FMODIFIER_FLAG_MUTED)) == 0) - fmi->evaluate_modifier(fcu, fcm, cvalue, evaltime); + if (fmi == NULL) + continue; + + /* only evaluate if there's a callback for this, and if F-Modifier can be evaluated on this frame */ + if ((fcm->flag & FMODIFIER_FLAG_RANGERESTRICT)==0 || + ((fcm->sfra <= evaltime) && (fcm->efra >= evaltime)) ) + { + if (fmi->evaluate_modifier) { + if ((fcm->flag & (FMODIFIER_FLAG_DISABLED|FMODIFIER_FLAG_MUTED)) == 0) { + float influence = eval_fmodifier_influence(fcm, evaltime); + float nval = *cvalue; + + fmi->evaluate_modifier(fcu, fcm, &nval, evaltime); + *cvalue = interpf(nval, *cvalue, influence); + } + } } } } diff --git a/source/blender/blenkernel/intern/gpencil.c b/source/blender/blenkernel/intern/gpencil.c index db0c9d2735f..c2e94cc97db 100644 --- a/source/blender/blenkernel/intern/gpencil.c +++ b/source/blender/blenkernel/intern/gpencil.c @@ -1,6 +1,4 @@ /* - * $Id$ - * * ***** BEGIN GPL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or diff --git a/source/blender/blenkernel/intern/idcode.c b/source/blender/blenkernel/intern/idcode.c index 8c8a693e6e7..e84a2a04ded 100644 --- a/source/blender/blenkernel/intern/idcode.c +++ b/source/blender/blenkernel/intern/idcode.c @@ -73,7 +73,8 @@ static IDType idtypes[]= { { ID_SCE, "Scene", "scenes", IDTYPE_FLAGS_ISLINKABLE}, { ID_SCR, "Screen", "screens", 0}, { ID_SEQ, "Sequence", "sequences", 0}, /* not actually ID data */ - { ID_SO, "Sound", "sounds", IDTYPE_FLAGS_ISLINKABLE}, + { ID_SPK, "Speaker", "speakers", IDTYPE_FLAGS_ISLINKABLE}, + { ID_SO, "Sound", "sounds", IDTYPE_FLAGS_ISLINKABLE}, { ID_TE, "Texture", "textures", IDTYPE_FLAGS_ISLINKABLE}, { ID_TXT, "Text", "texts", IDTYPE_FLAGS_ISLINKABLE}, { ID_VF, "VFont", "fonts", IDTYPE_FLAGS_ISLINKABLE}, diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c index c48497c45a1..4ce5de78895 100644 --- a/source/blender/blenkernel/intern/image.c +++ b/source/blender/blenkernel/intern/image.c @@ -432,6 +432,7 @@ Image *BKE_add_image_size(unsigned int width, unsigned int height, const char *n ima->gen_x= width; ima->gen_y= height; ima->gen_type= uvtestgrid; + ima->gen_flag |= (floatbuf ? IMA_GEN_FLOAT : 0); ibuf= add_ibuf_size(width, height, name, depth, floatbuf, uvtestgrid, color); image_assign_ibuf(ima, ibuf, IMA_NO_INDEX, 0); @@ -1370,15 +1371,15 @@ void BKE_makepicstring(char *string, const char *base, int frame, int imtype, co } /* used by sequencer too */ -struct anim *openanim(char *name, int flags) +struct anim *openanim(char *name, int flags, int streamindex) { struct anim *anim; struct ImBuf *ibuf; - anim = IMB_open_anim(name, flags); + anim = IMB_open_anim(name, flags, streamindex); if (anim == NULL) return NULL; - ibuf = IMB_anim_absolute(anim, 0); + ibuf = IMB_anim_absolute(anim, 0, IMB_TC_NONE, IMB_PROXY_NONE); if (ibuf == NULL) { if(BLI_exists(name)) printf("not an anim: %s\n", name); @@ -1772,20 +1773,26 @@ static ImBuf *image_load_movie_file(Image *ima, ImageUser *iuser, int frame) else BLI_path_abs(str, G.main->name); - ima->anim = openanim(str, IB_rect); + /* FIXME: make several stream accessible in image editor, too*/ + ima->anim = openanim(str, IB_rect, 0); /* let's initialize this user */ if(ima->anim && iuser && iuser->frames==0) - iuser->frames= IMB_anim_get_duration(ima->anim); + iuser->frames= IMB_anim_get_duration(ima->anim, + IMB_TC_RECORD_RUN); } if(ima->anim) { - int dur = IMB_anim_get_duration(ima->anim); + int dur = IMB_anim_get_duration(ima->anim, + IMB_TC_RECORD_RUN); int fra= frame-1; if(fra<0) fra = 0; if(fra>(dur-1)) fra= dur-1; - ibuf = IMB_anim_absolute(ima->anim, fra); + ibuf = IMB_makeSingleUser( + IMB_anim_absolute(ima->anim, fra, + IMB_TC_RECORD_RUN, + IMB_PROXY_NONE)); if(ibuf) { image_initialize_after_load(ima, ibuf); @@ -2172,7 +2179,7 @@ ImBuf *BKE_image_acquire_ibuf(Image *ima, ImageUser *iuser, void **lock_r) /* UV testgrid or black or solid etc */ if(ima->gen_x==0) ima->gen_x= 1024; if(ima->gen_y==0) ima->gen_y= 1024; - ibuf= add_ibuf_size(ima->gen_x, ima->gen_y, ima->name, 24, 0, ima->gen_type, color); + ibuf= add_ibuf_size(ima->gen_x, ima->gen_y, ima->name, 24, (ima->gen_flag & IMA_GEN_FLOAT) != 0, ima->gen_type, color); image_assign_ibuf(ima, ibuf, IMA_NO_INDEX, 0); ima->ok= IMA_OK_LOADED; } diff --git a/source/blender/blenkernel/intern/ipo.c b/source/blender/blenkernel/intern/ipo.c index 4f921f005f4..0d3f3cc5ae4 100644 --- a/source/blender/blenkernel/intern/ipo.c +++ b/source/blender/blenkernel/intern/ipo.c @@ -1,7 +1,4 @@ -/* ipo.c - * - * $Id$ - * +/* * ***** BEGIN GPL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or @@ -518,7 +515,7 @@ static const char *material_adrcodes_to_paths (int adrcode, int *array_index) return "alpha"; case MA_REF: - return "diffuse_reflection"; + return "diffuse_intensity"; case MA_EMIT: return "emit"; @@ -527,7 +524,7 @@ static const char *material_adrcodes_to_paths (int adrcode, int *array_index) return "ambient"; case MA_SPEC: - return "specular_reflection"; + return "specular_intensity"; case MA_HARD: return "specular_hardness"; @@ -551,13 +548,13 @@ static const char *material_adrcodes_to_paths (int adrcode, int *array_index) return "raytrace_mirror.fresnel"; case MA_FRESMIRI: - return "raytrace_mirror.fresnel_fac"; + return "raytrace_mirror.fresnel_factor"; case MA_FRESTRA: return "raytrace_transparency.fresnel"; case MA_FRESTRAI: - return "raytrace_transparency.fresnel_fac"; + return "raytrace_transparency.fresnel_factor"; case MA_ADD: return "halo.add"; @@ -1157,7 +1154,6 @@ static void icu_to_fcurves (ID *id, ListBase *groups, ListBase *list, IpoCurve * if (icu->flag & IPO_ACTIVE) fcu->flag |= FCURVE_ACTIVE; if (icu->flag & IPO_MUTE) fcu->flag |= FCURVE_MUTED; if (icu->flag & IPO_PROTECT) fcu->flag |= FCURVE_PROTECTED; - if (icu->flag & IPO_AUTO_HORIZ) fcu->flag |= FCURVE_AUTO_HANDLES; /* set extrapolation */ switch (icu->extrap) { @@ -1242,6 +1238,12 @@ static void icu_to_fcurves (ID *id, ListBase *groups, ListBase *list, IpoCurve * /* 'hide' flag is now used for keytype - only 'keyframes' existed before */ dst->hide= BEZT_KEYTYPE_KEYFRAME; + /* auto-handles - per curve to per handle */ + if (icu->flag & IPO_AUTO_HORIZ) { + if (dst->h1 == HD_AUTO) dst->h1 = HD_AUTO_ANIM; + if (dst->h2 == HD_AUTO) dst->h2 = HD_AUTO_ANIM; + } + /* correct values, by checking if the flag of interest is set */ if ( ((int)(dst->vec[1][1])) & (abp->bit) ) dst->vec[0][1]= dst->vec[1][1]= dst->vec[2][1] = 1.0f; @@ -1292,6 +1294,12 @@ static void icu_to_fcurves (ID *id, ListBase *groups, ListBase *list, IpoCurve * /* 'hide' flag is now used for keytype - only 'keyframes' existed before */ dst->hide= BEZT_KEYTYPE_KEYFRAME; + + /* auto-handles - per curve to per handle */ + if (icu->flag & IPO_AUTO_HORIZ) { + if (dst->h1 == HD_AUTO) dst->h1 = HD_AUTO_ANIM; + if (dst->h2 == HD_AUTO) dst->h2 = HD_AUTO_ANIM; + } /* correct values for euler rotation curves * - they were degrees/10 diff --git a/source/blender/blenkernel/intern/key.c b/source/blender/blenkernel/intern/key.c index 4b532362cd8..2aef5b39c71 100644 --- a/source/blender/blenkernel/intern/key.c +++ b/source/blender/blenkernel/intern/key.c @@ -63,6 +63,7 @@ #include "BKE_library.h" #include "BKE_main.h" #include "BKE_object.h" +#include "BKE_deform.h" #include "RNA_access.h" @@ -473,20 +474,20 @@ static int setkeys(float fac, ListBase *lb, KeyBlock *k[], float *t, int cycl) } -static void flerp(int aantal, float *in, float *f0, float *f1, float *f2, float *f3, float *t) +static void flerp(int tot, float *in, float *f0, float *f1, float *f2, float *f3, float *t) { int a; - for(a=0; a<aantal; a++) { + for(a=0; a<tot; a++) { in[a]= t[0]*f0[a]+t[1]*f1[a]+t[2]*f2[a]+t[3]*f3[a]; } } -static void rel_flerp(int aantal, float *in, float *ref, float *out, float fac) +static void rel_flerp(int tot, float *in, float *ref, float *out, float fac) { int a; - for(a=0; a<aantal; a++) { + for(a=0; a<tot; a++) { in[a]-= fac*(ref[a]-out[a]); } } @@ -1005,7 +1006,7 @@ static float *get_weights_array(Object *ob, char *vgroup) MDeformVert *dvert= NULL; EditMesh *em= NULL; EditVert *eve; - int totvert= 0, index= 0; + int totvert= 0, defgrp_index= 0; /* no vgroup string set? */ if(vgroup[0]==0) return NULL; @@ -1028,10 +1029,10 @@ static float *get_weights_array(Object *ob, char *vgroup) if(dvert==NULL) return NULL; /* find the group (weak loop-in-loop) */ - index= defgroup_name_index(ob, vgroup); - if(index >= 0) { + defgrp_index= defgroup_name_index(ob, vgroup); + if(defgrp_index >= 0) { float *weights; - int i, j; + int i; weights= MEM_callocN(totvert*sizeof(float), "weights"); @@ -1040,23 +1041,13 @@ static float *get_weights_array(Object *ob, char *vgroup) dvert= CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT); if(dvert) { - for(j=0; j<dvert->totweight; j++) { - if(dvert->dw[j].def_nr == index) { - weights[i]= dvert->dw[j].weight; - break; - } - } + weights[i]= defvert_find_weight(dvert, defgrp_index); } } } else { for(i=0; i < totvert; i++, dvert++) { - for(j=0; j<dvert->totweight; j++) { - if(dvert->dw[j].def_nr == index) { - weights[i]= dvert->dw[j].weight; - break; - } - } + weights[i]= defvert_find_weight(dvert, defgrp_index); } } @@ -1409,7 +1400,7 @@ float *do_ob_key(Scene *scene, Object *ob) /* do shapekey local drivers */ float ctime= (float)scene->r.cfra; // XXX this needs to be checked - BKE_animsys_evaluate_animdata(&key->id, key->adt, ctime, ADT_RECALC_DRIVERS); + BKE_animsys_evaluate_animdata(scene, &key->id, key->adt, ctime, ADT_RECALC_DRIVERS); if(ob->type==OB_MESH) do_mesh_key(scene, ob, key, out, tot); else if(ob->type==OB_LATTICE) do_latt_key(scene, ob, key, out, tot); diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c index 0b07f40cad6..677a2922666 100644 --- a/source/blender/blenkernel/intern/library.c +++ b/source/blender/blenkernel/intern/library.c @@ -65,6 +65,7 @@ #include "DNA_node_types.h" #include "DNA_scene_types.h" #include "DNA_screen_types.h" +#include "DNA_speaker_types.h" #include "DNA_sound_types.h" #include "DNA_text_types.h" #include "DNA_vfont_types.h" @@ -108,6 +109,9 @@ #include "BKE_particle.h" #include "BKE_gpencil.h" #include "BKE_fcurve.h" +#include "BKE_speaker.h" + +#include "RNA_access.h" #ifdef WITH_PYTHON #include "BPY_extern.h" @@ -205,6 +209,9 @@ int id_make_local(ID *id, int test) case ID_CA: if(!test) make_local_camera((Camera*)id); return 1; + case ID_SPK: + if(!test) make_local_speaker((Speaker*)id); + return 1; case ID_IP: return 0; /* deprecated */ case ID_KE: @@ -287,6 +294,9 @@ int id_copy(ID *id, ID **newid, int test) case ID_LA: if(!test) *newid= (ID*)copy_lamp((Lamp*)id); return 1; + case ID_SPK: + if(!test) *newid= (ID*)copy_speaker((Speaker*)id); + return 1; case ID_CA: if(!test) *newid= (ID*)copy_camera((Camera*)id); return 1; @@ -368,6 +378,34 @@ int id_unlink(ID *id, int test) return 0; } +int id_single_user(bContext *C, ID *id, PointerRNA *ptr, PropertyRNA *prop) +{ + ID *newid = NULL; + PointerRNA idptr; + + if (id) { + /* if property isn't editable, we're going to have an extra block hanging around until we save */ + if (RNA_property_editable(ptr, prop)) { + if (id_copy(id, &newid, 0) && newid) { + /* copy animation actions too */ + BKE_copy_animdata_id_action(id); + /* us is 1 by convention, but RNA_property_pointer_set + will also incremement it, so set it to zero */ + newid->us= 0; + + /* assign copy */ + RNA_id_pointer_create(newid, &idptr); + RNA_property_pointer_set(ptr, prop, idptr); + RNA_property_update(C, ptr, prop); + + return 1; + } + } + } + + return 0; +} + ListBase *which_libbase(Main *mainlib, short type) { switch( type ) { @@ -409,6 +447,8 @@ ListBase *which_libbase(Main *mainlib, short type) return &(mainlib->text); case ID_SCRIPT: return &(mainlib->script); + case ID_SPK: + return &(mainlib->speaker); case ID_SO: return &(mainlib->sound); case ID_GR: @@ -493,13 +533,14 @@ int set_listbasepointers(Main *main, ListBase **lb) lb[a++]= &(main->latt); lb[a++]= &(main->lamp); lb[a++]= &(main->camera); - + lb[a++]= &(main->text); lb[a++]= &(main->sound); lb[a++]= &(main->group); lb[a++]= &(main->brush); lb[a++]= &(main->script); lb[a++]= &(main->particle); + lb[a++]= &(main->speaker); lb[a++]= &(main->world); lb[a++]= &(main->screen); @@ -585,6 +626,9 @@ static ID *alloc_libblock_notest(short type) case ID_SCRIPT: //XXX id= MEM_callocN(sizeof(Script), "script"); break; + case ID_SPK: + id= MEM_callocN(sizeof(Speaker), "speaker"); + break; case ID_SO: id= MEM_callocN(sizeof(bSound), "sound"); break; @@ -671,7 +715,7 @@ void *copy_libblock(void *rt) assert(idn != NULL); idn_len= MEM_allocN_len(idn); - if(idn_len - sizeof(ID) > 0) { + if((int)idn_len - (int)sizeof(ID) > 0) { /* signed to allow neg result */ cp= (char *)id; cpn= (char *)idn; memcpy(cpn+sizeof(ID), cp+sizeof(ID), idn_len - sizeof(ID)); @@ -788,6 +832,9 @@ void free_libblock(ListBase *lb, void *idv) case ID_SCRIPT: //XXX free_script((Script *)id); break; + case ID_SPK: + free_speaker((Speaker *)id); + break; case ID_SO: sound_free((bSound*)id); break; diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c index 334f018efc9..aab8e1abbea 100644 --- a/source/blender/blenkernel/intern/material.c +++ b/source/blender/blenkernel/intern/material.c @@ -61,7 +61,7 @@ #include "BKE_material.h" #include "BKE_mesh.h" #include "BKE_node.h" - +#include "BKE_curve.h" #include "GPU_material.h" @@ -515,6 +515,21 @@ short *give_totcolp_id(ID *id) return NULL; } +static void data_delete_material_index_id(ID *id, int index) +{ + switch(GS(id->name)) { + case ID_ME: + mesh_delete_material_index((Mesh *)id, index); + break; + case ID_CU: + curve_delete_material_index((Curve *)id, index); + break; + case ID_MB: + /* meta-elems dont have materials atm */ + break; + } +} + void material_append_id(ID *id, Material *ma) { Material ***matar; @@ -532,7 +547,7 @@ void material_append_id(ID *id, Material *ma) } } -Material *material_pop_id(ID *id, int index) +Material *material_pop_id(ID *id, int index, int remove_material_slot) { Material *ret= NULL; Material ***matar; @@ -540,27 +555,36 @@ Material *material_pop_id(ID *id, int index) short *totcol= give_totcolp_id(id); if(index >= 0 && index < (*totcol)) { ret= (*matar)[index]; - id_us_min((ID *)ret); - if(*totcol <= 1) { - *totcol= 0; - MEM_freeN(*matar); - *matar= NULL; - } - else { - Material **mat; - - if(index + 1 != (*totcol)) - memmove((*matar), (*matar) + 1, (*totcol) - (index + 1)); + id_us_min((ID *)ret); - (*totcol)--; - - mat= MEM_callocN(sizeof(void *) * (*totcol), "newmatar"); - memcpy(mat, *matar, sizeof(void *) * (*totcol)); - MEM_freeN(*matar); + if (remove_material_slot) { + if(*totcol <= 1) { + *totcol= 0; + MEM_freeN(*matar); + *matar= NULL; + } + else { + Material **mat; + if(index + 1 != (*totcol)) + memmove((*matar)+index, (*matar)+(index+1), sizeof(void *) * ((*totcol) - (index + 1))); + + (*totcol)--; + + mat= MEM_callocN(sizeof(void *) * (*totcol), "newmatar"); + memcpy(mat, *matar, sizeof(void *) * (*totcol)); + MEM_freeN(*matar); + + *matar= mat; + test_object_materials(id); + } - *matar= mat; - test_object_materials(id); + /* decrease mat_nr index */ + data_delete_material_index_id(id, index); } + + /* don't remove material slot, only clear it*/ + else + (*matar)[index]= NULL; } } @@ -867,6 +891,10 @@ static void do_init_render_material(Material *ma, int r_mode, float *amb) if(ma->strand_surfnor > 0.0f) ma->mode_l |= MA_STR_SURFDIFF; + + /* parses the geom+tex nodes */ + if(ma->nodetree && ma->use_nodes) + ntreeShaderGetTexcoMode(ma->nodetree, r_mode, &ma->texco, &ma->mode_l); } static void init_render_nodetree(bNodeTree *ntree, Material *basemat, int r_mode, float *amb) @@ -887,8 +915,6 @@ static void init_render_nodetree(bNodeTree *ntree, Material *basemat, int r_mode init_render_nodetree((bNodeTree *)node->id, basemat, r_mode, amb); } } - /* parses the geom+tex nodes */ - ntreeShaderGetTexcoMode(ntree, r_mode, &basemat->texco, &basemat->mode_l); } void init_render_material(Material *mat, int r_mode, float *amb) @@ -899,7 +925,8 @@ void init_render_material(Material *mat, int r_mode, float *amb) if(mat->nodetree && mat->use_nodes) { init_render_nodetree(mat->nodetree, mat, r_mode, amb); - ntreeBeginExecTree(mat->nodetree); /* has internal flag to detect it only does it once */ + if (!mat->nodetree->execdata) + mat->nodetree->execdata = ntreeShaderBeginExecTree(mat->nodetree, 1); } } @@ -931,8 +958,10 @@ void init_render_materials(Main *bmain, int r_mode, float *amb) /* only needed for nodes now */ void end_render_material(Material *mat) { - if(mat && mat->nodetree && mat->use_nodes) - ntreeEndExecTree(mat->nodetree); /* has internal flag to detect it only does it once */ + if(mat && mat->nodetree && mat->use_nodes) { + if (mat->nodetree->execdata) + ntreeShaderEndExecTree(mat->nodetree->execdata, 1); + } } void end_render_materials(Main *bmain) @@ -1023,8 +1052,6 @@ int object_remove_material_slot(Object *ob) { Material *mao, ***matarar; Object *obt; - Curve *cu; - Nurb *nu; short *totcolp; int a, actcol; @@ -1084,23 +1111,8 @@ int object_remove_material_slot(Object *ob) } /* check indices from mesh */ - - if(ob->type==OB_MESH) { - Mesh *me= get_mesh(ob); - mesh_delete_material_index(me, actcol-1); - freedisplist(&ob->disp); - } - else if ELEM(ob->type, OB_CURVE, OB_SURF) { - cu= ob->data; - nu= cu->nurb.first; - - while(nu) { - if(nu->mat_nr && nu->mat_nr>=actcol-1) { - nu->mat_nr--; - if (ob->type == OB_CURVE) nu->charidx--; - } - nu= nu->next; - } + if (ELEM4(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT)) { + data_delete_material_index_id((ID *)ob->data, actcol-1); freedisplist(&ob->disp); } @@ -1356,7 +1368,7 @@ void ramp_blend(int type, float *r, float *g, float *b, float fac, float *col) } /* copy/paste buffer, if we had a propper py api that would be better */ -Material matcopybuf; +static Material matcopybuf; static short matcopied= 0; void clear_matcopybuf(void) diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c index 45a60b842a7..32819226361 100644 --- a/source/blender/blenkernel/intern/mesh.c +++ b/source/blender/blenkernel/intern/mesh.c @@ -1254,10 +1254,10 @@ void mesh_to_curve(Scene *scene, Object *ob) void mesh_delete_material_index(Mesh *me, int index) { + MFace *mf; int i; - for (i=0; i<me->totface; i++) { - MFace *mf = &((MFace*) me->mface)[i]; + for (i=0, mf=me->mface; i<me->totface; i++, mf++) { if (mf->mat_nr && mf->mat_nr>=index) mf->mat_nr--; } diff --git a/source/blender/blenkernel/intern/mesh_validate.c b/source/blender/blenkernel/intern/mesh_validate.c index 34618a19ae9..70398594872 100644 --- a/source/blender/blenkernel/intern/mesh_validate.c +++ b/source/blender/blenkernel/intern/mesh_validate.c @@ -80,7 +80,7 @@ static void edge_store_from_mface_quad(EdgeUUID es[4], MFace *mf) edge_store_assign(es[3].verts, mf->v4, mf->v1); } -static void edge_store_from_mface_tri(EdgeUUID es[3], MFace *mf) +static void edge_store_from_mface_tri(EdgeUUID es[4], MFace *mf) { edge_store_assign(es[0].verts, mf->v1, mf->v2); edge_store_assign(es[1].verts, mf->v2, mf->v3); @@ -143,30 +143,30 @@ int BKE_mesh_validate_arrays(Mesh *me, MVert *UNUSED(mverts), unsigned int totve BLI_assert(!(do_fixes && me == NULL)); - PRINT("ED_mesh_validate: verts(%d), edges(%d), faces(%d)\n", totvert, totedge, totface); + PRINT("ED_mesh_validate: verts(%u), edges(%u), faces(%u)\n", totvert, totedge, totface); if(totedge == 0 && totface != 0) { - PRINT(" locical error, %d faces and 0 edges\n", totface); + PRINT(" locical error, %u faces and 0 edges\n", totface); do_edge_recalc= TRUE; } for(i=0, med= medges; i<totedge; i++, med++) { int remove= FALSE; if(med->v1 == med->v2) { - PRINT(" edge %d: has matching verts, both %d\n", i, med->v1); + PRINT(" edge %u: has matching verts, both %u\n", i, med->v1); remove= do_fixes; } if(med->v1 >= totvert) { - PRINT(" edge %d: v1 index out of range, %d\n", i, med->v1); + PRINT(" edge %u: v1 index out of range, %u\n", i, med->v1); remove= do_fixes; } if(med->v2 >= totvert) { - PRINT(" edge %d: v2 index out of range, %d\n", i, med->v2); + PRINT(" edge %u: v2 index out of range, %u\n", i, med->v2); remove= do_fixes; } if(BLI_edgehash_haskey(edge_hash, med->v1, med->v2)) { - PRINT(" edge %d: is a duplicate of, %d\n", i, GET_INT_FROM_POINTER(BLI_edgehash_lookup(edge_hash, med->v1, med->v2))); + PRINT(" edge %u: is a duplicate of, %d\n", i, GET_INT_FROM_POINTER(BLI_edgehash_lookup(edge_hash, med->v1, med->v2))); remove= do_fixes; } @@ -187,41 +187,41 @@ int BKE_mesh_validate_arrays(Mesh *me, MVert *UNUSED(mverts), unsigned int totve do { fv[fidx]= *(&(mf->v1) + fidx); if(fv[fidx] >= totvert) { - PRINT(" face %d: 'v%d' index out of range, %d\n", i, fidx + 1, fv[fidx]); + PRINT(" face %u: 'v%d' index out of range, %u\n", i, fidx + 1, fv[fidx]); remove= do_fixes; } } while (fidx--); if(remove == FALSE) { if(mf->v4) { - if(mf->v1 == mf->v2) { PRINT(" face %d: verts invalid, v1/v2 both %d\n", i, mf->v1); remove= do_fixes; } - if(mf->v1 == mf->v3) { PRINT(" face %d: verts invalid, v1/v3 both %d\n", i, mf->v1); remove= do_fixes; } - if(mf->v1 == mf->v4) { PRINT(" face %d: verts invalid, v1/v4 both %d\n", i, mf->v1); remove= do_fixes; } + if(mf->v1 == mf->v2) { PRINT(" face %u: verts invalid, v1/v2 both %u\n", i, mf->v1); remove= do_fixes; } + if(mf->v1 == mf->v3) { PRINT(" face %u: verts invalid, v1/v3 both %u\n", i, mf->v1); remove= do_fixes; } + if(mf->v1 == mf->v4) { PRINT(" face %u: verts invalid, v1/v4 both %u\n", i, mf->v1); remove= do_fixes; } - if(mf->v2 == mf->v3) { PRINT(" face %d: verts invalid, v2/v3 both %d\n", i, mf->v2); remove= do_fixes; } - if(mf->v2 == mf->v4) { PRINT(" face %d: verts invalid, v2/v4 both %d\n", i, mf->v2); remove= do_fixes; } + if(mf->v2 == mf->v3) { PRINT(" face %u: verts invalid, v2/v3 both %u\n", i, mf->v2); remove= do_fixes; } + if(mf->v2 == mf->v4) { PRINT(" face %u: verts invalid, v2/v4 both %u\n", i, mf->v2); remove= do_fixes; } - if(mf->v3 == mf->v4) { PRINT(" face %d: verts invalid, v3/v4 both %d\n", i, mf->v3); remove= do_fixes; } + if(mf->v3 == mf->v4) { PRINT(" face %u: verts invalid, v3/v4 both %u\n", i, mf->v3); remove= do_fixes; } } else { - if(mf->v1 == mf->v2) { PRINT(" faceT %d: verts invalid, v1/v2 both %d\n", i, mf->v1); remove= do_fixes; } - if(mf->v1 == mf->v3) { PRINT(" faceT %d: verts invalid, v1/v3 both %d\n", i, mf->v1); remove= do_fixes; } + if(mf->v1 == mf->v2) { PRINT(" faceT %u: verts invalid, v1/v2 both %u\n", i, mf->v1); remove= do_fixes; } + if(mf->v1 == mf->v3) { PRINT(" faceT %u: verts invalid, v1/v3 both %u\n", i, mf->v1); remove= do_fixes; } - if(mf->v2 == mf->v3) { PRINT(" faceT %d: verts invalid, v2/v3 both %d\n", i, mf->v2); remove= do_fixes; } + if(mf->v2 == mf->v3) { PRINT(" faceT %u: verts invalid, v2/v3 both %u\n", i, mf->v2); remove= do_fixes; } } if(remove == FALSE) { if(totedge) { if(mf->v4) { - if(!BLI_edgehash_haskey(edge_hash, mf->v1, mf->v2)) { PRINT(" face %d: edge v1/v2 (%d,%d) is missing egde data\n", i, mf->v1, mf->v2); do_edge_recalc= TRUE; } - if(!BLI_edgehash_haskey(edge_hash, mf->v2, mf->v3)) { PRINT(" face %d: edge v2/v3 (%d,%d) is missing egde data\n", i, mf->v2, mf->v3); do_edge_recalc= TRUE; } - if(!BLI_edgehash_haskey(edge_hash, mf->v3, mf->v4)) { PRINT(" face %d: edge v3/v4 (%d,%d) is missing egde data\n", i, mf->v3, mf->v4); do_edge_recalc= TRUE; } - if(!BLI_edgehash_haskey(edge_hash, mf->v4, mf->v1)) { PRINT(" face %d: edge v4/v1 (%d,%d) is missing egde data\n", i, mf->v4, mf->v1); do_edge_recalc= TRUE; } + if(!BLI_edgehash_haskey(edge_hash, mf->v1, mf->v2)) { PRINT(" face %u: edge v1/v2 (%u,%u) is missing egde data\n", i, mf->v1, mf->v2); do_edge_recalc= TRUE; } + if(!BLI_edgehash_haskey(edge_hash, mf->v2, mf->v3)) { PRINT(" face %u: edge v2/v3 (%u,%u) is missing egde data\n", i, mf->v2, mf->v3); do_edge_recalc= TRUE; } + if(!BLI_edgehash_haskey(edge_hash, mf->v3, mf->v4)) { PRINT(" face %u: edge v3/v4 (%u,%u) is missing egde data\n", i, mf->v3, mf->v4); do_edge_recalc= TRUE; } + if(!BLI_edgehash_haskey(edge_hash, mf->v4, mf->v1)) { PRINT(" face %u: edge v4/v1 (%u,%u) is missing egde data\n", i, mf->v4, mf->v1); do_edge_recalc= TRUE; } } else { - if(!BLI_edgehash_haskey(edge_hash, mf->v1, mf->v2)) { PRINT(" face %d: edge v1/v2 (%d,%d) is missing egde data\n", i, mf->v1, mf->v2); do_edge_recalc= TRUE; } - if(!BLI_edgehash_haskey(edge_hash, mf->v2, mf->v3)) { PRINT(" face %d: edge v2/v3 (%d,%d) is missing egde data\n", i, mf->v2, mf->v3); do_edge_recalc= TRUE; } - if(!BLI_edgehash_haskey(edge_hash, mf->v3, mf->v1)) { PRINT(" face %d: edge v3/v1 (%d,%d) is missing egde data\n", i, mf->v3, mf->v1); do_edge_recalc= TRUE; } + if(!BLI_edgehash_haskey(edge_hash, mf->v1, mf->v2)) { PRINT(" face %u: edge v1/v2 (%u,%u) is missing egde data\n", i, mf->v1, mf->v2); do_edge_recalc= TRUE; } + if(!BLI_edgehash_haskey(edge_hash, mf->v2, mf->v3)) { PRINT(" face %u: edge v2/v3 (%u,%u) is missing egde data\n", i, mf->v2, mf->v3); do_edge_recalc= TRUE; } + if(!BLI_edgehash_haskey(edge_hash, mf->v3, mf->v1)) { PRINT(" face %u: edge v3/v1 (%u,%u) is missing egde data\n", i, mf->v3, mf->v1); do_edge_recalc= TRUE; } } } @@ -261,10 +261,10 @@ int BKE_mesh_validate_arrays(Mesh *me, MVert *UNUSED(mverts), unsigned int totve if(do_verbose) { mf_prev= mfaces + sf_prev->index; if(mf->v4) { - PRINT(" face %d & %d: are duplicates (%d,%d,%d,%d) (%d,%d,%d,%d)\n", sf->index, sf_prev->index, mf->v1, mf->v2, mf->v3, mf->v4, mf_prev->v1, mf_prev->v2, mf_prev->v3, mf_prev->v4); + PRINT(" face %u & %u: are duplicates (%u,%u,%u,%u) (%u,%u,%u,%u)\n", sf->index, sf_prev->index, mf->v1, mf->v2, mf->v3, mf->v4, mf_prev->v1, mf_prev->v2, mf_prev->v3, mf_prev->v4); } else { - PRINT(" face %d & %d: are duplicates (%d,%d,%d) (%d,%d,%d)\n", sf->index, sf_prev->index, mf->v1, mf->v2, mf->v3, mf_prev->v1, mf_prev->v2, mf_prev->v3); + PRINT(" face %u & %u: are duplicates (%u,%u,%u) (%u,%u,%u)\n", sf->index, sf_prev->index, mf->v1, mf->v2, mf->v3, mf_prev->v1, mf_prev->v2, mf_prev->v3); } } diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c index 51f1cd61e7c..fe26c0ccd2d 100644 --- a/source/blender/blenkernel/intern/modifier.c +++ b/source/blender/blenkernel/intern/modifier.c @@ -195,6 +195,18 @@ void modifiers_foreachIDLink(Object *ob, IDWalkFunc walk, void *userData) } } +void modifiers_foreachTexLink(Object *ob, TexWalkFunc walk, void *userData) +{ + ModifierData *md = ob->modifiers.first; + + for (; md; md=md->next) { + ModifierTypeInfo *mti = modifierType_getInfo(md->type); + + if(mti->foreachTexLink) + mti->foreachTexLink(md, ob, walk, userData); + } +} + void modifier_copyData(ModifierData *md, ModifierData *target) { ModifierTypeInfo *mti = modifierType_getInfo(md->type); diff --git a/source/blender/blenkernel/intern/multires.c b/source/blender/blenkernel/intern/multires.c index 5802bb2b697..e621e800520 100644 --- a/source/blender/blenkernel/intern/multires.c +++ b/source/blender/blenkernel/intern/multires.c @@ -465,12 +465,13 @@ static DerivedMesh *multires_dm_create_local(Object *ob, DerivedMesh *dm, int lv return multires_dm_create_from_derived(&mmd, 1, dm, ob, 0, 0); } -static DerivedMesh *subsurf_dm_create_local(Object *ob, DerivedMesh *dm, int lvl, int simple, int optimal) +static DerivedMesh *subsurf_dm_create_local(Object *ob, DerivedMesh *dm, int lvl, int simple, int optimal, int plain_uv) { SubsurfModifierData smd= {{NULL}}; smd.levels = smd.renderLevels = lvl; - smd.flags |= eSubsurfModifierFlag_SubsurfUv; + if(!plain_uv) + smd.flags |= eSubsurfModifierFlag_SubsurfUv; if(simple) smd.subdivType = ME_SIMPLE_SUBSURF; if(optimal) @@ -591,7 +592,7 @@ void multiresModifier_base_apply(MultiresModifierData *mmd, Object *ob) /* subdivide the mesh to highest level without displacements */ cddm = CDDM_from_mesh(me, NULL); DM_set_only_copy(cddm, CD_MASK_BAREMESH); - origdm = subsurf_dm_create_local(ob, cddm, totlvl, 0, 0); + origdm = subsurf_dm_create_local(ob, cddm, totlvl, 0, 0, mmd->flags & eMultiresModifierFlag_PlainUv); cddm->release(cddm); /* calc disps */ @@ -626,7 +627,7 @@ static void multires_subdivide(MultiresModifierData *mmd, Object *ob, int totlvl /* create subsurf DM from original mesh at high level */ cddm = CDDM_from_mesh(me, NULL); DM_set_only_copy(cddm, CD_MASK_BAREMESH); - highdm = subsurf_dm_create_local(ob, cddm, totlvl, simple, 0); + highdm = subsurf_dm_create_local(ob, cddm, totlvl, simple, 0, mmd->flags & eMultiresModifierFlag_PlainUv); /* create multires DM from original mesh at low level */ lowdm = multires_dm_create_local(ob, cddm, lvl, lvl, simple); @@ -830,7 +831,7 @@ static void multiresModifier_update(DerivedMesh *dm) else cddm = CDDM_from_mesh(me, NULL); DM_set_only_copy(cddm, CD_MASK_BAREMESH); - highdm = subsurf_dm_create_local(ob, cddm, totlvl, mmd->simple, 0); + highdm = subsurf_dm_create_local(ob, cddm, totlvl, mmd->simple, 0, mmd->flags & eMultiresModifierFlag_PlainUv); /* create multires DM from original mesh and displacements */ lowdm = multires_dm_create_local(ob, cddm, lvl, totlvl, mmd->simple); @@ -884,7 +885,7 @@ static void multiresModifier_update(DerivedMesh *dm) else cddm = CDDM_from_mesh(me, NULL); DM_set_only_copy(cddm, CD_MASK_BAREMESH); - subdm = subsurf_dm_create_local(ob, cddm, mmd->totlvl, mmd->simple, 0); + subdm = subsurf_dm_create_local(ob, cddm, mmd->totlvl, mmd->simple, 0, mmd->flags & eMultiresModifierFlag_PlainUv); cddm->release(cddm); multiresModifier_disp_run(dm, me, 1, 0, subdm->getGridData(subdm), mmd->totlvl); @@ -927,7 +928,8 @@ DerivedMesh *multires_dm_create_from_derived(MultiresModifierData *mmd, int loca return dm; result = subsurf_dm_create_local(ob, dm, lvl, - mmd->simple, mmd->flags & eMultiresModifierFlag_ControlEdges); + mmd->simple, mmd->flags & eMultiresModifierFlag_ControlEdges, + mmd->flags & eMultiresModifierFlag_PlainUv); if(!local_mmd) { ccgdm = (CCGDerivedMesh*)result; @@ -1020,7 +1022,7 @@ static void old_mdisps_rotate(int S, int UNUSED(newside), int oldside, int x, in static void old_mdisps_convert(MFace *mface, MDisps *mdisp) { - int newlvl = log(sqrt(mdisp->totdisp)-1)/log(2); + int newlvl = log(sqrt(mdisp->totdisp)-1)/M_LN2; int oldlvl = newlvl+1; int oldside = multires_side_tot[oldlvl]; int newside = multires_side_tot[newlvl]; @@ -1535,6 +1537,7 @@ void multires_load_old(Object *ob, Mesh *me) me->mface[i].v2 = lvl->faces[i].v[1]; me->mface[i].v3 = lvl->faces[i].v[2]; me->mface[i].v4 = lvl->faces[i].v[3]; + me->mface[i].mat_nr = lvl->faces[i].mat_nr; } /* Add a multires modifier to the object */ @@ -1633,7 +1636,7 @@ static void multires_apply_smat(Scene *scene, Object *ob, float smat[3][3]) MEM_freeN(vertCos); /* scaled ccgDM for tangent space of object with applied scale */ - dm= subsurf_dm_create_local(ob, cddm, high_mmd.totlvl, high_mmd.simple, 0); + dm= subsurf_dm_create_local(ob, cddm, high_mmd.totlvl, high_mmd.simple, 0, mmd->flags & eMultiresModifierFlag_PlainUv); cddm->release(cddm); /*numGrids= dm->getNumGrids(dm);*/ /*UNUSED*/ diff --git a/source/blender/blenkernel/intern/nla.c b/source/blender/blenkernel/intern/nla.c index c02b5dda9ce..6ce80342dd6 100644 --- a/source/blender/blenkernel/intern/nla.c +++ b/source/blender/blenkernel/intern/nla.c @@ -1,6 +1,4 @@ /* - * $Id$ - * * ***** BEGIN GPL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or @@ -46,6 +44,8 @@ #include "DNA_anim_types.h" #include "DNA_scene_types.h" +#include "DNA_sound_types.h" +#include "DNA_speaker_types.h" #include "BKE_action.h" #include "BKE_fcurve.h" @@ -53,6 +53,9 @@ #include "BKE_global.h" #include "BKE_library.h" +#ifdef WITH_AUDASPACE +# include "AUD_C-API.h" +#endif #include "RNA_access.h" #include "nla_private.h" @@ -337,6 +340,44 @@ NlaStrip *add_nlastrip_to_stack (AnimData *adt, bAction *act) return strip; } +/* Add a NLA Strip referencing the given speaker's sound */ +NlaStrip *add_nla_soundstrip (Scene *scene, Speaker *speaker) +{ + NlaStrip *strip = MEM_callocN(sizeof(NlaStrip), "NlaSoundStrip"); + + /* if speaker has a sound, set the strip length to the length of the sound, + * otherwise default to length of 10 frames + */ +#ifdef WITH_AUDASPACE + if (speaker->sound) + { + AUD_SoundInfo info = AUD_getInfo(speaker->sound->playback_handle); + + strip->end = ceil(info.length * FPS); + } + else +#endif + { + strip->end = 10.0f; + /* quiet compiler warnings */ + (void)scene; + (void)speaker; + } + + /* general settings */ + strip->type = NLASTRIP_TYPE_SOUND; + + strip->flag = NLASTRIP_FLAG_SELECT; + strip->extendmode = NLASTRIP_EXTEND_NOTHING; /* nothing to extend... */ + + /* strip should be referenced as-is */ + strip->scale= 1.0f; + strip->repeat = 1.0f; + + /* return this strip */ + return strip; +} + /* *************************************************** */ /* NLA Evaluation <-> Editing Stuff */ @@ -813,34 +854,35 @@ void BKE_nlameta_flush_transforms (NlaStrip *mstrip) /* for each child-strip, calculate new start/end points based on this new info */ for (strip= mstrip->strips.first; strip; strip= strip->next) { if (scaleChanged) { - PointerRNA ptr; - float p1, p2, nStart, nEnd; + float p1, p2; /* compute positions of endpoints relative to old extents of strip */ p1= (strip->start - oStart) / oLen; p2= (strip->end - oStart) / oLen; - /* compute the new strip endpoints using the proportions */ - nStart= (p1 * nLen) + mstrip->start; - nEnd= (p2 * nLen) + mstrip->start; - - /* firstly, apply the new positions manually, then apply using RNA - * - first time is to make sure no truncation errors from one endpoint not being - * set yet occur - * - second time is to make sure scale is computed properly... - */ - strip->start= nStart; - strip->end= nEnd; - - RNA_pointer_create(NULL, &RNA_NlaStrip, strip, &ptr); - RNA_float_set(&ptr, "frame_start", nStart); - RNA_float_set(&ptr, "frame_end", nEnd); + /* apply new strip endpoints using the proportions, then wait for second pass to flush scale properly */ + strip->start= (p1 * nLen) + mstrip->start; + strip->end= (p2 * nLen) + mstrip->start; } else { /* just apply the changes in offset to both ends of the strip */ strip->start += offset; strip->end += offset; } + } + + /* apply a second pass over child strips, to finish up unfinished business */ + for (strip= mstrip->strips.first; strip; strip= strip->next) { + /* only if scale changed, need to perform RNA updates */ + if (scaleChanged) { + PointerRNA ptr; + + /* use RNA updates to compute scale properly */ + RNA_pointer_create(NULL, &RNA_NlaStrip, strip, &ptr); + + RNA_float_set(&ptr, "frame_start", strip->start); + RNA_float_set(&ptr, "frame_end", strip->end); + } /* finally, make sure the strip's children (if it is a meta-itself), get updated */ BKE_nlameta_flush_transforms(strip); @@ -1185,7 +1227,7 @@ void BKE_nlastrip_validate_fcurves (NlaStrip *strip) BLI_addtail(&strip->fcurves, fcu); /* set default flags */ - fcu->flag = (FCURVE_VISIBLE|FCURVE_AUTO_HANDLES|FCURVE_SELECTED); + fcu->flag = (FCURVE_VISIBLE|FCURVE_SELECTED); /* store path - make copy, and store that */ fcu->rna_path= BLI_strdupn("influence", 9); @@ -1206,7 +1248,7 @@ void BKE_nlastrip_validate_fcurves (NlaStrip *strip) BLI_addtail(&strip->fcurves, fcu); /* set default flags */ - fcu->flag = (FCURVE_VISIBLE|FCURVE_AUTO_HANDLES|FCURVE_SELECTED); + fcu->flag = (FCURVE_VISIBLE|FCURVE_SELECTED); /* store path - make copy, and store that */ fcu->rna_path= BLI_strdupn("strip_time", 10); @@ -1242,7 +1284,7 @@ void BKE_nlastrip_validate_name (AnimData *adt, NlaStrip *strip) if (strip->name[0]==0) { switch (strip->type) { case NLASTRIP_TYPE_CLIP: /* act-clip */ - sprintf(strip->name, "Act: %s", (strip->act)?(strip->act->id.name+2):("<None>")); + sprintf(strip->name, "%s", (strip->act)?(strip->act->id.name+2):("<No Action>")); break; case NLASTRIP_TYPE_TRANSITION: /* transition */ sprintf(strip->name, "Transition"); @@ -1582,7 +1624,7 @@ void BKE_nla_tweakmode_exit (AnimData *adt) /* Baking Tools ------------------------------------------- */ -static void BKE_nla_bake (Scene *scene, ID *UNUSED(id), AnimData *adt, int UNUSED(flag)) +static void UNUSED_FUNCTION(BKE_nla_bake) (Scene *scene, ID *UNUSED(id), AnimData *adt, int UNUSED(flag)) { /* verify that data is valid diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c index 3a8a2ae9c09..cd1a6e61151 100644 --- a/source/blender/blenkernel/intern/node.c +++ b/source/blender/blenkernel/intern/node.c @@ -32,8 +32,10 @@ */ -#ifdef WITH_PYTHON -#include <Python.h> +#if 0 /* pynodes commented for now */ +# ifdef WITH_PYTHON +# include <Python.h> +# endif #endif #include "MEM_guardedalloc.h" @@ -44,84 +46,107 @@ #include <limits.h> #include "DNA_anim_types.h" -#include "DNA_action_types.h" #include "DNA_node_types.h" +#include "DNA_scene_types.h" +#include "DNA_action_types.h" +#include "BLI_string.h" +#include "BLI_math.h" #include "BLI_listbase.h" - -#include "RNA_access.h" +#include "BLI_path_util.h" +#include "BLI_utildefines.h" #include "BKE_animsys.h" #include "BKE_action.h" #include "BKE_fcurve.h" +#include "BKE_global.h" +#include "BKE_image.h" +#include "BKE_library.h" +#include "BKE_main.h" #include "BKE_node.h" #include "BKE_utildefines.h" +#include "BKE_utildefines.h" -#include "PIL_time.h" - -#include "CMP_node.h" -#include "intern/CMP_util.h" /* stupid include path... */ +#include "BLI_listbase.h" -#include "SHD_node.h" -#include "TEX_node.h" -#include "intern/TEX_util.h" +#include "RNA_access.h" -#include "GPU_material.h" +#include "NOD_socket.h" +#include "NOD_composite.h" +#include "NOD_shader.h" +#include "NOD_texture.h" -static ListBase empty_list = {NULL, NULL}; -ListBase node_all_composit = {NULL, NULL}; -ListBase node_all_shaders = {NULL, NULL}; -ListBase node_all_textures = {NULL, NULL}; -/* ************** Type stuff ********** */ +bNodeTreeType *ntreeGetType(int type) +{ + static bNodeTreeType *types[NUM_NTREE_TYPES]; + static int types_init = 1; + if (types_init) { + types[NTREE_SHADER] = &ntreeType_Shader; + types[NTREE_COMPOSIT] = &ntreeType_Composite; + types[NTREE_TEXTURE] = &ntreeType_Texture; + types_init = 0; + } + + if(type >= 0 && type < NUM_NTREE_TYPES) { + return types[type]; + } + else { + return NULL; + } +} -static bNodeType *node_get_type(bNodeTree *ntree, int type, ID *id) +static bNodeType *node_get_type(bNodeTree *ntree, int type) { - bNodeType *ntype = ntree->alltypes.first; + bNodeType *ntype = ntreeGetType(ntree->type)->node_types.first; for(; ntype; ntype= ntype->next) - if(ntype->type==type && id==ntype->id ) + if(ntype->type==type) return ntype; return NULL; } -void ntreeInitTypes(bNodeTree *ntree) +bNodeType *ntreeGetNodeType(bNodeTree *ntree) { - bNode *node, *next; - - if(ntree->type==NTREE_SHADER) - ntree->alltypes= node_all_shaders; - else if(ntree->type==NTREE_COMPOSIT) - ntree->alltypes= node_all_composit; - else if(ntree->type==NTREE_TEXTURE) - ntree->alltypes= node_all_textures; + return node_get_type(ntree, ntree->nodetype); +} + +bNodeSocketType *ntreeGetSocketType(int type) +{ + static bNodeSocketType *types[NUM_SOCKET_TYPES]= {NULL}; + static int types_init = 1; + + if (types_init) { + node_socket_type_init(types); + types_init= 0; + } + + if(type < NUM_SOCKET_TYPES) { + return types[type]; + } else { - ntree->alltypes= empty_list; - printf("Error: no type definitions for nodes\n"); + return NULL; } +} + +void ntreeInitTypes(bNodeTree *ntree) +{ + bNode *node, *next; for(node= ntree->nodes.first; node; node= next) { next= node->next; + + node->typeinfo= node_get_type(ntree, node->type); + if(node->type==NODE_DYNAMIC) { - bNodeType *stype= NULL; - if(node->id==NULL) { /* empty script node */ - stype= node_get_type(ntree, node->type, NULL); - } else { /* not an empty script node */ - stype= node_get_type(ntree, node->type, node->id); - if(!stype) { - stype= node_get_type(ntree, node->type, NULL); - /* needed info if the pynode script fails now: */ - if (node->id) node->storage= ntree; - } else { - node->custom1= 0; - node->custom1= BSET(node->custom1,NODE_DYNAMIC_ADDEXIST); - } + /* needed info if the pynode script fails now: */ + node->storage= ntree; + if(node->id!=NULL) { /* not an empty script node */ + node->custom1= 0; + node->custom1= BSET(node->custom1,NODE_DYNAMIC_ADDEXIST); } - node->typeinfo= stype; - if(node->typeinfo) - node->typeinfo->initfunc(node); - } else { - node->typeinfo= node_get_type(ntree, node->type, NULL); +// if(node->typeinfo) +// node->typeinfo->initfunc(node); } if(node->typeinfo==NULL) { @@ -133,66 +158,51 @@ void ntreeInitTypes(bNodeTree *ntree) ntree->init |= NTREE_TYPE_INIT; } -/* updates node with (modified) bNodeType.. this should be done for all trees */ -void ntreeUpdateType(bNodeTree *ntree, bNodeType *ntype) +static bNodeSocket *make_socket(bNodeTree *UNUSED(ntree), int in_out, const char *name, int type) { - bNode *node; - - for(node= ntree->nodes.first; node; node= node->next) { - if(node->typeinfo== ntype) { - nodeUpdateType(ntree, node, ntype); - } - } + bNodeSocketType *stype= ntreeGetSocketType(type); + bNodeSocket *sock; + + sock= MEM_callocN(sizeof(bNodeSocket), "sock"); + + BLI_strncpy(sock->name, name, NODE_MAXSTR); + sock->limit = (in_out==SOCK_IN ? 1 : 0xFFF); + sock->type= type; + sock->storage = NULL; + + if (stype->value_structsize > 0) + sock->default_value = MEM_callocN(stype->value_structsize, "default socket value"); + + return sock; } -/* only used internal... we depend on type definitions! */ -static bNodeSocket *node_add_socket_type(ListBase *lb, bNodeSocketType *stype) +bNodeSocket *nodeAddSocket(bNodeTree *ntree, bNode *node, int in_out, const char *name, int type) { - bNodeSocket *sock= MEM_callocN(sizeof(bNodeSocket), "sock"); + bNodeSocket *sock = make_socket(ntree, in_out, name, type); + if (in_out==SOCK_IN) + BLI_addtail(&node->inputs, sock); + else if (in_out==SOCK_OUT) + BLI_addtail(&node->outputs, sock); - BLI_strncpy(sock->name, stype->name, NODE_MAXSTR); - if(stype->limit==0) sock->limit= 0xFFF; - else sock->limit= stype->limit; - sock->type= stype->type; + ntree->update |= NTREE_UPDATE_NODES; - sock->ns.vec[0]= stype->val1; - sock->ns.vec[1]= stype->val2; - sock->ns.vec[2]= stype->val3; - sock->ns.vec[3]= stype->val4; - sock->ns.min= stype->min; - sock->ns.max= stype->max; - - if(lb) - BLI_addtail(lb, sock); - return sock; } -static bNodeSocket *node_add_group_socket(ListBase *lb, bNodeSocket *gsock) +bNodeSocket *nodeInsertSocket(bNodeTree *ntree, bNode *node, int in_out, bNodeSocket *next_sock, const char *name, int type) { - bNodeSocket *sock= MEM_callocN(sizeof(bNodeSocket), "sock"); + bNodeSocket *sock = make_socket(ntree, in_out, name, type); + if (in_out==SOCK_IN) + BLI_insertlinkbefore(&node->inputs, next_sock, sock); + else if (in_out==SOCK_OUT) + BLI_insertlinkbefore(&node->outputs, next_sock, sock); - /* make a copy of the group socket */ - *sock = *gsock; - sock->link = NULL; - sock->next = sock->prev = NULL; - sock->new_sock = NULL; - sock->ns.data = NULL; + ntree->update |= NTREE_UPDATE_NODES; - sock->own_index = gsock->own_index; - sock->groupsock = gsock; - /* XXX hack: group socket input/output roles are inverted internally, - * need to change the limit value when making actual node sockets from them. - */ - sock->limit = (gsock->limit==1 ? 0xFFF : 1); - - if(lb) - BLI_addtail(lb, sock); - return sock; } -static void node_rem_socket(bNodeTree *ntree, ListBase *lb, bNodeSocket *sock) +void nodeRemoveSocket(bNodeTree *ntree, bNode *node, bNodeSocket *sock) { bNodeLink *link, *next; @@ -203,428 +213,42 @@ static void node_rem_socket(bNodeTree *ntree, ListBase *lb, bNodeSocket *sock) } } - BLI_remlink(lb, sock); - MEM_freeN(sock); -} - -static bNodeSocket *verify_socket(ListBase *lb, bNodeSocketType *stype) -{ - bNodeSocket *sock; - - for(sock= lb->first; sock; sock= sock->next) { - if(strncmp(sock->name, stype->name, NODE_MAXSTR)==0) - break; - } - if(sock) { - sock->type= stype->type; /* in future, read this from tydefs! */ - if(stype->limit==0) sock->limit= 0xFFF; - else sock->limit= stype->limit; - - sock->ns.min= stype->min; - sock->ns.max= stype->max; - - BLI_remlink(lb, sock); - - return sock; - } - else { - return node_add_socket_type(NULL, stype); - } -} - -static bNodeSocket *verify_group_socket(ListBase *lb, bNodeSocket *gsock) -{ - bNodeSocket *sock; - - for(sock= lb->first; sock; sock= sock->next) { - if(sock->own_index==gsock->own_index) - break; - } - if(sock) { - sock->groupsock = gsock; - - strcpy(sock->name, gsock->name); - sock->type= gsock->type; - - /* XXX hack: group socket input/output roles are inverted internally, - * need to change the limit value when making actual node sockets from them. - */ - sock->limit = (gsock->limit==1 ? 0xFFF : 1); - - sock->ns.min= gsock->ns.min; - sock->ns.max= gsock->ns.max; - - BLI_remlink(lb, sock); - - return sock; - } - else { - return node_add_group_socket(NULL, gsock); - } -} - -static void verify_socket_list(bNodeTree *ntree, ListBase *lb, bNodeSocketType *stype_first) -{ - bNodeSocketType *stype; + /* this is fast, this way we don't need an in_out argument */ + BLI_remlink(&node->inputs, sock); + BLI_remlink(&node->outputs, sock); - /* no inputs anymore? */ - if(stype_first==NULL) { - while(lb->first) - node_rem_socket(ntree, lb, lb->first); - } - else { - /* step by step compare */ - stype= stype_first; - while(stype->type != -1) { - stype->sock= verify_socket(lb, stype); - stype++; - } - /* leftovers are removed */ - while(lb->first) - node_rem_socket(ntree, lb, lb->first); - /* and we put back the verified sockets */ - stype= stype_first; - while(stype->type != -1) { - BLI_addtail(lb, stype->sock); - stype++; - } - } -} - -static void verify_group_socket_list(bNodeTree *ntree, ListBase *lb, ListBase *glb) -{ - bNodeSocket *gsock; - - /* step by step compare */ - for (gsock= glb->first; gsock; gsock=gsock->next) { - /* abusing new_sock pointer for verification here! only used inside this function */ - gsock->new_sock= verify_group_socket(lb, gsock); - } - /* leftovers are removed */ - while(lb->first) - node_rem_socket(ntree, lb, lb->first); - /* and we put back the verified sockets */ - for (gsock= glb->first; gsock; gsock=gsock->next) { - BLI_addtail(lb, gsock->new_sock); - gsock->new_sock = NULL; - } -} - -void nodeVerifyType(bNodeTree *ntree, bNode *node) -{ - /* node groups don't have static sock lists, but use external sockets from the tree instead */ - if (node->type==NODE_GROUP) { - bNodeTree *ngroup= (bNodeTree*)node->id; - if (ngroup) { - verify_group_socket_list(ntree, &node->inputs, &ngroup->inputs); - verify_group_socket_list(ntree, &node->outputs, &ngroup->outputs); - } - } - else { - bNodeType *ntype= node->typeinfo; - if(ntype) { - verify_socket_list(ntree, &node->inputs, ntype->inputs); - verify_socket_list(ntree, &node->outputs, ntype->outputs); - } - } -} - -void ntreeVerifyTypes(bNodeTree *ntree) -{ - bNode *node; - - /* if((ntree->init & NTREE_TYPE_INIT)==0) */ - ntreeInitTypes(ntree); - - /* check inputs and outputs, and remove or insert them */ - for(node= ntree->nodes.first; node; node= node->next) - nodeVerifyType(ntree, node); - -} - -/* ************** Group stuff ********** */ - -/* XXX group typeinfo struct is used directly in ntreeMakeOwnType, needs cleanup */ -static bNodeType ntype_group; - -/* groups display their internal tree name as label */ -static const char *group_label(bNode *node) -{ - return (node->id)? node->id->name+2: "Missing Datablock"; -} - -void register_node_type_group(ListBase *lb) -{ - node_type_base(&ntype_group, NODE_GROUP, "Group", NODE_CLASS_GROUP, NODE_OPTIONS, NULL, NULL); - node_type_size(&ntype_group, 120, 60, 200); - node_type_label(&ntype_group, group_label); + if (sock->default_value) + MEM_freeN(sock->default_value); + MEM_freeN(sock); - nodeRegisterType(lb, &ntype_group); -} - -static bNodeSocket *find_group_node_input(bNode *gnode, bNodeSocket *gsock) -{ - bNodeSocket *sock; - for (sock=gnode->inputs.first; sock; sock=sock->next) - if (sock->groupsock == gsock) - return sock; - return NULL; + ntree->update |= NTREE_UPDATE_NODES; } -static bNodeSocket *find_group_node_output(bNode *gnode, bNodeSocket *gsock) +void nodeRemoveAllSockets(bNodeTree *ntree, bNode *node) { bNodeSocket *sock; - for (sock=gnode->outputs.first; sock; sock=sock->next) - if (sock->groupsock == gsock) - return sock; - return NULL; -} - -bNode *nodeMakeGroupFromSelected(bNodeTree *ntree) -{ - bNodeLink *link, *linkn; - bNode *node, *gnode, *nextn; - bNodeTree *ngroup; - bNodeSocket *gsock; - ListBase anim_basepaths = {NULL, NULL}; - float min[2], max[2]; - int totnode=0; - - INIT_MINMAX2(min, max); - - /* is there something to group? also do some clearing */ - for(node= ntree->nodes.first; node; node= node->next) { - if(node->flag & NODE_SELECT) { - /* no groups in groups */ - if(node->type==NODE_GROUP) - return NULL; - DO_MINMAX2( (&node->locx), min, max); - totnode++; - } - node->done= 0; - } - if(totnode==0) return NULL; - - /* check if all connections are OK, no unselected node has both - inputs and outputs to a selection */ - for(link= ntree->links.first; link; link= link->next) { - if(link->fromnode && link->tonode && link->fromnode->flag & NODE_SELECT) - link->tonode->done |= 1; - if(link->fromnode && link->tonode && link->tonode->flag & NODE_SELECT) - link->fromnode->done |= 2; - } - - for(node= ntree->nodes.first; node; node= node->next) { - if((node->flag & NODE_SELECT)==0) - if(node->done==3) - break; - } - if(node) - return NULL; + bNodeLink *link, *next; - /* OK! new nodetree */ - ngroup= ntreeAddTree("NodeGroup", ntree->type, TRUE); - - /* move nodes over */ - for(node= ntree->nodes.first; node; node= nextn) { - nextn= node->next; - if(node->flag & NODE_SELECT) { - /* keep track of this node's RNA "base" path (the part of the pat identifying the node) - * if the old nodetree has animation data which potentially covers this node - */ - if (ntree->adt) { - PointerRNA ptr; - char *path; - - RNA_pointer_create(&ntree->id, &RNA_Node, node, &ptr); - path = RNA_path_from_ID_to_struct(&ptr); - - if (path) - BLI_addtail(&anim_basepaths, BLI_genericNodeN(path)); - } - - /* change node-collection membership */ - BLI_remlink(&ntree->nodes, node); - BLI_addtail(&ngroup->nodes, node); - - node->locx-= 0.5f*(min[0]+max[0]); - node->locy-= 0.5f*(min[1]+max[1]); - } - } - - /* move animation data over */ - if (ntree->adt) { - LinkData *ld, *ldn=NULL; - - BKE_animdata_separate_by_basepath(&ntree->id, &ngroup->id, &anim_basepaths); - - /* paths + their wrappers need to be freed */ - for (ld = anim_basepaths.first; ld; ld = ldn) { - ldn = ld->next; - - MEM_freeN(ld->data); - BLI_freelinkN(&anim_basepaths, ld); + for(link= ntree->links.first; link; link= next) { + next= link->next; + if(link->fromnode==node || link->tonode==node) { + nodeRemLink(ntree, link); } } - /* make group node */ - gnode= nodeAddNodeType(ntree, NODE_GROUP, ngroup, NULL); - gnode->locx= 0.5f*(min[0]+max[0]); - gnode->locy= 0.5f*(min[1]+max[1]); + for (sock=node->inputs.first; sock; sock=sock->next) + if (sock->default_value) + MEM_freeN(sock->default_value); + BLI_freelistN(&node->inputs); + for (sock=node->outputs.first; sock; sock=sock->next) + if (sock->default_value) + MEM_freeN(sock->default_value); - /* relink external sockets */ - for(link= ntree->links.first; link; link= linkn) { - linkn= link->next; - - if(link->fromnode && link->tonode && (link->fromnode->flag & link->tonode->flag & NODE_SELECT)) { - BLI_remlink(&ntree->links, link); - BLI_addtail(&ngroup->links, link); - } - else if(link->tonode && (link->tonode->flag & NODE_SELECT)) { - gsock = nodeGroupExposeSocket(ngroup, link->tosock, SOCK_IN); - link->tosock->link = nodeAddLink(ngroup, NULL, gsock, link->tonode, link->tosock); - link->tosock = node_add_group_socket(&gnode->inputs, gsock); - link->tonode = gnode; - } - else if(link->fromnode && (link->fromnode->flag & NODE_SELECT)) { - /* search for existing group node socket */ - for (gsock=ngroup->outputs.first; gsock; gsock=gsock->next) - if (gsock->link && gsock->link->fromsock==link->fromsock) - break; - if (!gsock) { - gsock = nodeGroupExposeSocket(ngroup, link->fromsock, SOCK_OUT); - gsock->link = nodeAddLink(ngroup, link->fromnode, link->fromsock, NULL, gsock); - link->fromsock = node_add_group_socket(&gnode->outputs, gsock); - } - else - link->fromsock = find_group_node_output(gnode, gsock); - link->fromnode = gnode; - } - } - - /* update node levels */ - ntreeSolveOrder(ntree); - - return gnode; -} - -/* here's a nasty little one, need to check users... */ -/* should become callbackable... */ -void nodeGroupVerify(bNodeTree *ngroup) -{ - /* group changed, so we rebuild the type definition */ -// ntreeMakeGroupSockets(ngroup); + BLI_freelistN(&node->outputs); - if(ngroup->type==NTREE_SHADER) { - Material *ma; - for(ma= G.main->mat.first; ma; ma= ma->id.next) { - if(ma->nodetree) { - bNode *node; - for(node= ma->nodetree->nodes.first; node; node= node->next) - if(node->id == (ID *)ngroup) - nodeVerifyType(ma->nodetree, node); - } - } - } - else if(ngroup->type==NTREE_COMPOSIT) { - Scene *sce; - for(sce= G.main->scene.first; sce; sce= sce->id.next) { - if(sce->nodetree) { - bNode *node; - for(node= sce->nodetree->nodes.first; node; node= node->next) - if(node->id == (ID *)ngroup) - nodeVerifyType(sce->nodetree, node); - } - } - } - else if(ngroup->type==NTREE_TEXTURE) { - Tex *tx; - for(tx= G.main->tex.first; tx; tx= tx->id.next) { - if(tx->nodetree) { - bNode *node; - for(node= tx->nodetree->nodes.first; node; node= node->next) - if(node->id == (ID *)ngroup) - nodeVerifyType(tx->nodetree, node); - } - } - } + ntree->update |= NTREE_UPDATE_NODES; } -/* also to check all users of groups. Now only used in editor for hide/unhide */ -/* should become callbackable? */ -void nodeGroupSocketUseFlags(bNodeTree *ngroup) -{ - bNode *node; - bNodeSocket *sock; - - /* clear flags */ - for(node= ngroup->nodes.first; node; node= node->next) { - for(sock= node->inputs.first; sock; sock= sock->next) - sock->flag &= ~SOCK_IN_USE; - for(sock= node->outputs.first; sock; sock= sock->next) - sock->flag &= ~SOCK_IN_USE; - } - - /* tag all thats in use */ - if(ngroup->type==NTREE_SHADER) { - Material *ma; - for(ma= G.main->mat.first; ma; ma= ma->id.next) { - if(ma->nodetree) { - for(node= ma->nodetree->nodes.first; node; node= node->next) { - if(node->id==&ngroup->id) { - for(sock= node->inputs.first; sock; sock= sock->next) - if(sock->link) - if(sock->groupsock) - sock->groupsock->flag |= SOCK_IN_USE; - for(sock= node->outputs.first; sock; sock= sock->next) - if(nodeCountSocketLinks(ma->nodetree, sock)) - if(sock->groupsock) - sock->groupsock->flag |= SOCK_IN_USE; - } - } - } - } - } - else if(ngroup->type==NTREE_COMPOSIT) { - Scene *sce; - for(sce= G.main->scene.first; sce; sce= sce->id.next) { - if(sce->nodetree) { - for(node= sce->nodetree->nodes.first; node; node= node->next) { - if(node->id==(ID *)ngroup) { - for(sock= node->inputs.first; sock; sock= sock->next) - if(sock->link) - if(sock->groupsock) - sock->groupsock->flag |= SOCK_IN_USE; - for(sock= node->outputs.first; sock; sock= sock->next) - if(nodeCountSocketLinks(sce->nodetree, sock)) - if(sock->groupsock) - sock->groupsock->flag |= SOCK_IN_USE; - } - } - } - } - } - else if(ngroup->type==NTREE_TEXTURE) { - Tex *tx; - for(tx= G.main->tex.first; tx; tx= tx->id.next) { - if(tx->nodetree) { - for(node= tx->nodetree->nodes.first; node; node= node->next) { - if(node->id==(ID *)ngroup) { - for(sock= node->inputs.first; sock; sock= sock->next) - if(sock->link) - if(sock->groupsock) - sock->groupsock->flag |= SOCK_IN_USE; - for(sock= node->outputs.first; sock; sock= sock->next) - if(nodeCountSocketLinks(tx->nodetree, sock)) - if(sock->groupsock) - sock->groupsock->flag |= SOCK_IN_USE; - } - } - } - } - } - -} /* finds a node based on its name */ bNode *nodeFindNodebyName(bNodeTree *ntree, const char *name) { @@ -667,272 +291,26 @@ int nodeFindNode(bNodeTree *ntree, bNodeSocket *sock, bNode **nodep, int *sockin return 0; } -/* returns 1 if its OK */ -int nodeGroupUnGroup(bNodeTree *ntree, bNode *gnode) -{ - bNodeLink *link, *linkn; - bNode *node, *nextn; - bNodeTree *ngroup, *wgroup; - ListBase anim_basepaths = {NULL, NULL}; - - ngroup= (bNodeTree *)gnode->id; - if(ngroup==NULL) return 0; - - /* clear new pointers, set in copytree */ - for(node= ntree->nodes.first; node; node= node->next) - node->new_node= NULL; - - /* wgroup is a temporary copy of the NodeTree we're merging in - * - all of wgroup's nodes are transferred across to their new home - * - ngroup (i.e. the source NodeTree) is left unscathed - */ - wgroup= ntreeCopyTree(ngroup); - - /* add the nodes into the ntree */ - for(node= wgroup->nodes.first; node; node= nextn) { - nextn= node->next; - - /* keep track of this node's RNA "base" path (the part of the pat identifying the node) - * if the old nodetree has animation data which potentially covers this node - */ - if (wgroup->adt) { - PointerRNA ptr; - char *path; - - RNA_pointer_create(&wgroup->id, &RNA_Node, node, &ptr); - path = RNA_path_from_ID_to_struct(&ptr); - - if (path) - BLI_addtail(&anim_basepaths, BLI_genericNodeN(path)); - } - - /* migrate node */ - BLI_remlink(&wgroup->nodes, node); - BLI_addtail(&ntree->nodes, node); - - node->locx+= gnode->locx; - node->locy+= gnode->locy; - - node->flag |= NODE_SELECT; - } - - /* restore external links to and from the gnode */ - for(link= ntree->links.first; link; link= link->next) { - if (link->fromnode==gnode) { - if (link->fromsock->groupsock) { - bNodeSocket *gsock= link->fromsock->groupsock; - if (gsock->link) { - if (gsock->link->fromnode) { - /* NB: using the new internal copies here! the groupsock pointer still maps to the old tree */ - link->fromnode = (gsock->link->fromnode ? gsock->link->fromnode->new_node : NULL); - link->fromsock = gsock->link->fromsock->new_sock; - } - else { - /* group output directly maps to group input */ - bNodeSocket *insock= find_group_node_input(gnode, gsock->link->fromsock); - if (insock->link) { - link->fromnode = insock->link->fromnode; - link->fromsock = insock->link->fromsock; - } - } - } - else { - /* constant group output: copy the stack value to the external socket. - * the link is kept here until all possible external users have been fixed. - */ - QUATCOPY(link->tosock->ns.vec, gsock->ns.vec); - } - } - } - } - /* remove internal output links, these are not used anymore */ - for(link=wgroup->links.first; link; link= linkn) { - linkn = link->next; - if (!link->tonode) - nodeRemLink(wgroup, link); - } - /* restore links from internal nodes */ - for(link= wgroup->links.first; link; link= link->next) { - /* indicates link to group input */ - if (!link->fromnode) { - /* NB: can't use find_group_node_input here, - * because gnode sockets still point to the old tree! - */ - bNodeSocket *insock; - for (insock= gnode->inputs.first; insock; insock= insock->next) - if (insock->groupsock->new_sock == link->fromsock) - break; - if (insock->link) { - link->fromnode = insock->link->fromnode; - link->fromsock = insock->link->fromsock; - } - else { - /* uses group constant input. copy the input value and remove the dead link. */ - QUATCOPY(link->tosock->ns.vec, insock->ns.vec); - nodeRemLink(wgroup, link); - } - } - } - - /* add internal links to the ntree */ - for(link= wgroup->links.first; link; link= linkn) { - linkn= link->next; - BLI_remlink(&wgroup->links, link); - BLI_addtail(&ntree->links, link); - } - - /* and copy across the animation */ - if (wgroup->adt) { - LinkData *ld, *ldn=NULL; - bAction *waction; - - /* firstly, wgroup needs to temporary dummy action that can be destroyed, as it shares copies */ - waction = wgroup->adt->action = copy_action(wgroup->adt->action); - - /* now perform the moving */ - BKE_animdata_separate_by_basepath(&wgroup->id, &ntree->id, &anim_basepaths); - - /* paths + their wrappers need to be freed */ - for (ld = anim_basepaths.first; ld; ld = ldn) { - ldn = ld->next; - - MEM_freeN(ld->data); - BLI_freelinkN(&anim_basepaths, ld); - } - - /* free temp action too */ - free_libblock(&G.main->action, waction); - } - - /* delete the group instance. this also removes old input links! */ - nodeFreeNode(ntree, gnode); - - /* free the group tree (takes care of user count) */ - free_libblock(&G.main->nodetree, wgroup); - - /* solve order goes fine, but the level tags not... doing it twice works for now. solve this once */ - /* XXX is this still necessary with new groups? it may have been caused by non-updated sock->link pointers. lukas */ - ntreeSolveOrder(ntree); - ntreeSolveOrder(ntree); - - return 1; -} - -void nodeGroupCopy(bNode *gnode) +/* ************** Add stuff ********** */ +static void node_add_sockets_from_type(bNodeTree *ntree, bNode *node, bNodeType *ntype) { + bNodeSocketTemplate *sockdef; bNodeSocket *sock; - gnode->id->us--; - gnode->id= (ID *)ntreeCopyTree((bNodeTree *)gnode->id); - - /* new_sock was set in nodeCopyNode */ - for(sock=gnode->inputs.first; sock; sock=sock->next) - if(sock->groupsock) - sock->groupsock= sock->groupsock->new_sock; - - for(sock=gnode->outputs.first; sock; sock=sock->next) - if(sock->groupsock) - sock->groupsock= sock->groupsock->new_sock; -} - -bNodeSocket *nodeGroupAddSocket(bNodeTree *ngroup, const char *name, int type, int in_out) -{ - bNodeSocket *gsock = MEM_callocN(sizeof(bNodeSocket), "bNodeSocket"); - - strncpy(gsock->name, name, sizeof(gsock->name)); - gsock->type = type; - gsock->ns.sockettype = type; - gsock->ns.min = INT_MIN; - gsock->ns.max = INT_MAX; - zero_v4(gsock->ns.vec); - gsock->ns.data = NULL; - gsock->flag = 0; - - gsock->next = gsock->prev = NULL; - gsock->new_sock = NULL; - gsock->link = NULL; - gsock->ns.data = NULL; - /* assign new unique index */ - gsock->own_index = ngroup->cur_index++; - gsock->limit = (in_out==SOCK_IN ? 0xFFF : 1); - - BLI_addtail(in_out==SOCK_IN ? &ngroup->inputs : &ngroup->outputs, gsock); - - return gsock; -} - -bNodeSocket *nodeGroupExposeSocket(bNodeTree *ngroup, bNodeSocket *sock, int in_out) -{ - bNodeSocket *gsock= nodeGroupAddSocket(ngroup, sock->name, sock->type, in_out); - /* initialize the default socket value */ - QUATCOPY(gsock->ns.vec, sock->ns.vec); - return gsock; -} - -void nodeGroupExposeAllSockets(bNodeTree *ngroup) -{ - bNode *node; - bNodeSocket *sock, *gsock; - - for (node=ngroup->nodes.first; node; node=node->next) { - for (sock=node->inputs.first; sock; sock=sock->next) { - if (!sock->link && !(sock->flag & SOCK_HIDDEN)) { - gsock = nodeGroupAddSocket(ngroup, sock->name, sock->type, SOCK_IN); - /* initialize the default socket value */ - QUATCOPY(gsock->ns.vec, sock->ns.vec); - sock->link = nodeAddLink(ngroup, NULL, gsock, node, sock); - } - } - for (sock=node->outputs.first; sock; sock=sock->next) { - if (nodeCountSocketLinks(ngroup, sock)==0 && !(sock->flag & SOCK_HIDDEN)) { - gsock = nodeGroupAddSocket(ngroup, sock->name, sock->type, SOCK_OUT); - /* initialize the default socket value */ - QUATCOPY(gsock->ns.vec, sock->ns.vec); - gsock->link = nodeAddLink(ngroup, node, sock, NULL, gsock); - } - } - } -} - -void nodeGroupRemoveSocket(bNodeTree *ngroup, bNodeSocket *gsock, int in_out) -{ - nodeRemSocketLinks(ngroup, gsock); - switch (in_out) { - case SOCK_IN: BLI_remlink(&ngroup->inputs, gsock); break; - case SOCK_OUT: BLI_remlink(&ngroup->outputs, gsock); break; - } - MEM_freeN(gsock); -} - -/* ************** Add stuff ********** */ -void nodeAddSockets(bNode *node, bNodeType *ntype) -{ - if (node->type==NODE_GROUP) { - bNodeTree *ntree= (bNodeTree*)node->id; - if (ntree) { - bNodeSocket *gsock; - for (gsock=ntree->inputs.first; gsock; gsock=gsock->next) - node_add_group_socket(&node->inputs, gsock); - for (gsock=ntree->outputs.first; gsock; gsock=gsock->next) - node_add_group_socket(&node->outputs, gsock); + if(ntype->inputs) { + sockdef= ntype->inputs; + while(sockdef->type != -1) { + sock = node_add_input_from_template(ntree, node, sockdef); + + sockdef++; } } - else { - bNodeSocketType *stype; - - if(ntype->inputs) { - stype= ntype->inputs; - while(stype->type != -1) { - node_add_socket_type(&node->inputs, stype); - stype++; - } - } - if(ntype->outputs) { - stype= ntype->outputs; - while(stype->type != -1) { - node_add_socket_type(&node->outputs, stype); - stype++; - } + if(ntype->outputs) { + sockdef= ntype->outputs; + while(sockdef->type != -1) { + sock = node_add_output_from_template(ntree, node, sockdef); + + sockdef++; } } } @@ -943,65 +321,40 @@ void nodeUniqueName(bNodeTree *ntree, bNode *node) BLI_uniquename(&ntree->nodes, node, "Node", '.', offsetof(bNode, name), sizeof(node->name)); } -bNode *nodeAddNodeType(bNodeTree *ntree, int type, bNodeTree *ngroup, ID *id) +bNode *nodeAddNode(bNodeTree *ntree, struct bNodeTemplate *ntemp) { - bNode *node= NULL; - bNodeType *ntype= NULL; - - if (ngroup && BLI_findindex(&G.main->nodetree, ngroup)==-1) { - printf("nodeAddNodeType() error: '%s' not in main->nodetree\n", ngroup->id.name); - return NULL; - } - - if(type>=NODE_DYNAMIC_MENU) { - int a=0, idx= type-NODE_DYNAMIC_MENU; - ntype= ntree->alltypes.first; - while(ntype) { - if(ntype->type==NODE_DYNAMIC) { - if(a==idx) - break; - a++; - } - ntype= ntype->next; - } - } else - ntype= node_get_type(ntree, type, id); - + bNode *node; + bNodeType *ntype; + + ntype= node_get_type(ntree, ntemp->type); if(ntype == NULL) { - printf("nodeAddNodeType() error: '%d' type invalid\n", type); + printf("nodeAddNodeType() error: '%d' type invalid\n", ntemp->type); return NULL; } - - node= MEM_callocN(sizeof(bNode), "new node"); - BLI_addtail(&ntree->nodes, node); - node->typeinfo= ntype; - if(type>=NODE_DYNAMIC_MENU) - node->custom2= type; /* for node_dynamic_init */ - - if(ngroup) - BLI_strncpy(node->name, ngroup->id.name+2, NODE_MAXSTR); - else if(type>NODE_DYNAMIC_MENU) { - BLI_strncpy(node->name, ntype->id->name+2, NODE_MAXSTR); - } - else - BLI_strncpy(node->name, ntype->name, NODE_MAXSTR); - - nodeUniqueName(ntree, node); + /* validity check */ + if (!nodeValid(ntree, ntemp)) + return NULL; + node= MEM_callocN(sizeof(bNode), "new node"); node->type= ntype->type; + node->typeinfo= ntype; node->flag= NODE_SELECT|ntype->flag; node->width= ntype->width; - node->miniwidth= 42.0f; /* small value only, allows print of first chars */ - - if(type==NODE_GROUP) - node->id= (ID *)ngroup; - - /* need init handler later? */ - /* got it-bob*/ + node->miniwidth= 42.0f; + node->height= ntype->height; + + node_add_sockets_from_type(ntree, node, ntype); + if(ntype->initfunc!=NULL) - ntype->initfunc(node); + ntype->initfunc(ntree, node, ntemp); + + /* initialize the node name with the node label */ + BLI_strncpy(node->name, nodeLabel(node), NODE_MAXSTR); + nodeUniqueName(ntree, node); + + BLI_addtail(&ntree->nodes, node); - nodeAddSockets(node, ntype); + ntree->update |= NTREE_UPDATE_NODES; return node; } @@ -1009,9 +362,9 @@ bNode *nodeAddNodeType(bNodeTree *ntree, int type, bNodeTree *ngroup, ID *id) void nodeMakeDynamicType(bNode *node) { /* find SH_DYNAMIC_NODE ntype */ - bNodeType *ntype= node_all_shaders.first; + bNodeType *ntype= ntreeGetType(NTREE_SHADER)->node_types.first; while(ntype) { - if(ntype->type==NODE_DYNAMIC && ntype->id==NULL) + if(ntype->type==NODE_DYNAMIC) break; ntype= ntype->next; } @@ -1021,17 +374,11 @@ void nodeMakeDynamicType(bNode *node) /*node->typeinfo= MEM_dupallocN(ntype);*/ bNodeType *newtype= MEM_callocN(sizeof(bNodeType), "dynamic bNodeType"); *newtype= *ntype; - newtype->name= BLI_strdup(ntype->name); + strcpy(newtype->name, ntype->name); node->typeinfo= newtype; } } -void nodeUpdateType(bNodeTree *ntree, bNode* node, bNodeType *ntype) -{ - verify_socket_list(ntree, &node->inputs, ntype->inputs); - verify_socket_list(ntree, &node->outputs, ntype->outputs); -} - /* keep socket listorder identical, for copying links */ /* ntree is the target tree */ bNode *nodeCopyNode(struct bNodeTree *ntree, struct bNode *node) @@ -1043,19 +390,23 @@ bNode *nodeCopyNode(struct bNodeTree *ntree, struct bNode *node) nodeUniqueName(ntree, nnode); BLI_addtail(&ntree->nodes, nnode); - + BLI_duplicatelist(&nnode->inputs, &node->inputs); oldsock= node->inputs.first; for(sock= nnode->inputs.first; sock; sock= sock->next, oldsock= oldsock->next) { oldsock->new_sock= sock; + sock->stack_index= 0; + + sock->default_value = (oldsock->default_value ? MEM_dupallocN(oldsock->default_value) : NULL); } BLI_duplicatelist(&nnode->outputs, &node->outputs); oldsock= node->outputs.first; for(sock= nnode->outputs.first; sock; sock= sock->next, oldsock= oldsock->next) { - sock->stack_index= 0; - sock->ns.data= NULL; oldsock->new_sock= sock; + sock->stack_index= 0; + + sock->default_value = (oldsock->default_value ? MEM_dupallocN(oldsock->default_value) : NULL); } /* don't increase node->id users, freenode doesn't decrement either */ @@ -1067,10 +418,11 @@ bNode *nodeCopyNode(struct bNodeTree *ntree, struct bNode *node) nnode->new_node= NULL; nnode->preview= NULL; + ntree->update |= NTREE_UPDATE_NODES; + return nnode; } -/* fromsock and tosock can be NULL */ /* also used via rna api, so we check for proper input output direction */ bNodeLink *nodeAddLink(bNodeTree *ntree, bNode *fromnode, bNodeSocket *fromsock, bNode *tonode, bNodeSocket *tosock) { @@ -1093,6 +445,21 @@ bNodeLink *nodeAddLink(bNodeTree *ntree, bNode *fromnode, bNodeSocket *fromsock, from= -1; /* OK but flip */ } } + else { + /* check tree sockets */ + for(sock= ntree->inputs.first; sock; sock= sock->next) + if(sock==fromsock) + break; + if(sock) + from= 1; /* OK */ + else { + for(sock= ntree->outputs.first; sock; sock= sock->next) + if(sock==fromsock) + break; + if(sock) + from= -1; /* OK but flip */ + } + } if(tonode) { for(sock= tonode->inputs.first; sock; sock= sock->next) if(sock==tosock) @@ -1107,8 +474,22 @@ bNodeLink *nodeAddLink(bNodeTree *ntree, bNode *fromnode, bNodeSocket *fromsock, to= -1; /* OK but flip */ } } + else { + /* check tree sockets */ + for(sock= ntree->outputs.first; sock; sock= sock->next) + if(sock==tosock) + break; + if(sock) + to= 1; /* OK */ + else { + for(sock= ntree->inputs.first; sock; sock= sock->next) + if(sock==tosock) + break; + if(sock) + to= -1; /* OK but flip */ + } + } - /* this allows NULL sockets to work */ if(from >= 0 && to >= 0) { link= MEM_callocN(sizeof(bNodeLink), "link"); BLI_addtail(&ntree->links, link); @@ -1126,6 +507,8 @@ bNodeLink *nodeAddLink(bNodeTree *ntree, bNode *fromnode, bNodeSocket *fromsock, link->tosock= fromsock; } + ntree->update |= NTREE_UPDATE_LINKS; + return link; } @@ -1135,6 +518,8 @@ void nodeRemLink(bNodeTree *ntree, bNodeLink *link) if(link->tosock) link->tosock->link= NULL; MEM_freeN(link); + + ntree->update |= NTREE_UPDATE_LINKS; } void nodeRemSocketLinks(bNodeTree *ntree, bNodeSocket *sock) @@ -1147,26 +532,73 @@ void nodeRemSocketLinks(bNodeTree *ntree, bNodeSocket *sock) nodeRemLink(ntree, link); } } + + ntree->update |= NTREE_UPDATE_LINKS; } +/* transforms node location to area coords */ +void nodeSpaceCoords(bNode *node, float *locx, float *locy) +{ + if (node->parent) { + nodeSpaceCoords(node->parent, locx, locy); + *locx += node->locx; + *locy += node->locy; + } + else { + *locx = node->locx; + *locy = node->locy; + } +} -bNodeTree *ntreeAddTree(const char *name, int type, const short is_group) +void nodeAttachNode(bNode *node, bNode *parent) { - bNodeTree *ntree; + float parentx, parenty; + + node->parent = parent; + /* transform to parent space */ + nodeSpaceCoords(parent, &parentx, &parenty); + node->locx -= parentx; + node->locy -= parenty; +} - if (is_group) - ntree= alloc_libblock(&G.main->nodetree, ID_NT, name); - else { +void nodeDetachNode(struct bNode *node) +{ + float parentx, parenty; + + if (node->parent) { + /* transform to "global" (area) space */ + nodeSpaceCoords(node->parent, &parentx, &parenty); + node->locx += parentx; + node->locy += parenty; + node->parent = NULL; + } +} + +bNodeTree *ntreeAddTree(const char *name, int type, int nodetype) +{ + bNodeTree *ntree; + bNodeType *ntype; + + /* trees are created as local trees if they of compositor, material or texture type, + * node groups and other tree types are created as library data. + */ + if (ELEM3(type, NTREE_COMPOSIT, NTREE_SHADER, NTREE_TEXTURE) && nodetype==0) { ntree= MEM_callocN(sizeof(bNodeTree), "new node tree"); *( (short *)ntree->id.name )= ID_NT; /* not "type", as that is ntree->type */ BLI_strncpy(ntree->id.name+2, name, sizeof(ntree->id.name)); } - + else + ntree= alloc_libblock(&G.main->nodetree, ID_NT, name); + ntree->type= type; - ntree->alltypes.first = NULL; - ntree->alltypes.last = NULL; - + ntree->nodetype = nodetype; + ntreeInitTypes(ntree); + + ntype = node_get_type(ntree, ntree->nodetype); + if (ntype && ntype->inittreefunc) + ntype->inittreefunc(ntree); + return ntree; } @@ -1197,9 +629,7 @@ bNodeTree *ntreeCopyTree(bNodeTree *ntree) id_us_plus((ID *)newtree->gpd); /* in case a running nodetree is copied */ - newtree->init &= ~(NTREE_EXEC_INIT); - newtree->threadstack= NULL; - newtree->stack= NULL; + newtree->execdata= NULL; newtree->nodes.first= newtree->nodes.last= NULL; newtree->links.first= newtree->links.last= NULL; @@ -1208,7 +638,10 @@ bNodeTree *ntreeCopyTree(bNodeTree *ntree) for(node= ntree->nodes.first; node; node= node->next) { node->new_node= NULL; nnode= nodeCopyNode(newtree, node); /* sets node->new */ - if(node==last) break; + + /* make sure we don't copy new nodes again! */ + if (node==last) + break; } /* socket definition for group usage */ @@ -1216,14 +649,15 @@ bNodeTree *ntreeCopyTree(bNodeTree *ntree) for(gsock= newtree->inputs.first, oldgsock= ntree->inputs.first; gsock; gsock=gsock->next, oldgsock=oldgsock->next) { oldgsock->new_sock= gsock; gsock->groupsock = (oldgsock->groupsock ? oldgsock->groupsock->new_sock : NULL); + gsock->default_value = (oldgsock->default_value ? MEM_dupallocN(oldgsock->default_value) : NULL); } - BLI_duplicatelist(&newtree->outputs, &ntree->outputs); for(gsock= newtree->outputs.first, oldgsock= ntree->outputs.first; gsock; gsock=gsock->next, oldgsock=oldgsock->next) { oldgsock->new_sock= gsock; gsock->groupsock = (oldgsock->groupsock ? oldgsock->groupsock->new_sock : NULL); + gsock->default_value = (oldgsock->default_value ? MEM_dupallocN(oldgsock->default_value) : NULL); } - + /* copy links */ BLI_duplicatelist(&newtree->links, &ntree->links); for(link= newtree->links.first; link; link= link->next) { @@ -1235,7 +669,13 @@ bNodeTree *ntreeCopyTree(bNodeTree *ntree) if (link->tosock) link->tosock->link = link; } - + + /* update node->parent pointers */ + for (node=newtree->nodes.first; node; node=node->next) { + if (node->parent) + node->parent = node->parent->new_node; + } + return newtree; } @@ -1254,7 +694,7 @@ void ntreeSwitchID(bNodeTree *ntree, ID *id_from, ID *id_to) /* *************** preview *********** */ /* if node->preview, then we assume the rect to exist */ -static void node_free_preview(bNode *node) +void nodeFreePreview(bNode *node) { if(node->preview) { if(node->preview->rect) @@ -1358,7 +798,6 @@ void nodeAddToPreview(bNode *node, float *col, int x, int y, int do_manage) } } - /* ************** Free stuff ********** */ /* goes over entire tree */ @@ -1393,50 +832,84 @@ void nodeUnlinkNode(bNodeTree *ntree, bNode *node) } } -static void composit_free_node_cache(bNode *node) +static void node_unlink_attached(bNodeTree *ntree, bNode *parent) { - bNodeSocket *sock; - - for(sock= node->outputs.first; sock; sock= sock->next) { - if(sock->ns.data) { - free_compbuf(sock->ns.data); - sock->ns.data= NULL; - } + bNode *node; + for (node=ntree->nodes.first; node; node=node->next) { + if (node->parent == parent) + nodeDetachNode(node); } } void nodeFreeNode(bNodeTree *ntree, bNode *node) { + bNodeTreeType *treetype= ntreeGetType(ntree->type); + bNodeSocket *sock, *nextsock; + + /* remove all references to this node */ nodeUnlinkNode(ntree, node); + node_unlink_attached(ntree, node); + BLI_remlink(&ntree->nodes, node); /* since it is called while free database, node->id is undefined */ - if(ntree->type==NTREE_COMPOSIT) - composit_free_node_cache(node); - BLI_freelistN(&node->inputs); - BLI_freelistN(&node->outputs); + if (treetype->free_node_cache) + treetype->free_node_cache(ntree, node); - node_free_preview(node); + for (sock=node->inputs.first; sock; sock = nextsock) { + nextsock = sock->next; + if (sock->default_value) + MEM_freeN(sock->default_value); + MEM_freeN(sock); + } + for (sock=node->outputs.first; sock; sock = nextsock) { + nextsock = sock->next; + if (sock->default_value) + MEM_freeN(sock->default_value); + MEM_freeN(sock); + } + + nodeFreePreview(node); if(node->typeinfo && node->typeinfo->freestoragefunc) { node->typeinfo->freestoragefunc(node); } MEM_freeN(node); + + ntree->update |= NTREE_UPDATE_NODES; } /* do not free ntree itself here, free_libblock calls this function too */ void ntreeFreeTree(bNodeTree *ntree) { bNode *node, *next; + bNodeSocket *sock; if(ntree==NULL) return; - ntreeEndExecTree(ntree); /* checks for if it is still initialized */ + /* XXX hack! node trees should not store execution graphs at all. + * This should be removed when old tree types no longer require it. + * Currently the execution data for texture nodes remains in the tree + * after execution, until the node tree is updated or freed. + */ + if (ntree->execdata) { + switch (ntree->type) { + case NTREE_COMPOSIT: + ntreeCompositEndExecTree(ntree->execdata, 1); + break; + case NTREE_SHADER: + ntreeShaderEndExecTree(ntree->execdata, 1); + break; + case NTREE_TEXTURE: + ntreeTexEndExecTree(ntree->execdata, 1); + break; + } + } BKE_free_animdata((ID *)ntree); - + id_us_min((ID *)ntree->gpd); BLI_freelistN(&ntree->links); /* do first, then unlink_node goes fast */ @@ -1446,25 +919,120 @@ void ntreeFreeTree(bNodeTree *ntree) nodeFreeNode(ntree, node); } + for (sock=ntree->inputs.first; sock; sock=sock->next) + if (sock->default_value) + MEM_freeN(sock->default_value); BLI_freelistN(&ntree->inputs); + for (sock=ntree->outputs.first; sock; sock=sock->next) + if (sock->default_value) + MEM_freeN(sock->default_value); BLI_freelistN(&ntree->outputs); } void ntreeFreeCache(bNodeTree *ntree) { - bNode *node; + bNodeTreeType *treetype; if(ntree==NULL) return; + + treetype= ntreeGetType(ntree->type); + if (treetype->free_cache) + treetype->free_cache(ntree); +} - if(ntree->type==NTREE_COMPOSIT) - for(node= ntree->nodes.first; node; node= node->next) - composit_free_node_cache(node); +void ntreeSetOutput(bNodeTree *ntree) +{ + bNode *node; + + /* find the active outputs, might become tree type dependant handler */ + for(node= ntree->nodes.first; node; node= node->next) { + if(node->typeinfo->nclass==NODE_CLASS_OUTPUT) { + bNode *tnode; + int output= 0; + + /* we need a check for which output node should be tagged like this, below an exception */ + if(node->type==CMP_NODE_OUTPUT_FILE) + continue; + + /* there is more types having output class, each one is checked */ + for(tnode= ntree->nodes.first; tnode; tnode= tnode->next) { + if(tnode->typeinfo->nclass==NODE_CLASS_OUTPUT) { + + if(ntree->type==NTREE_COMPOSIT) { + + /* same type, exception for viewer */ + if(tnode->type==node->type || + (ELEM(tnode->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER) && + ELEM(node->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER))) { + if(tnode->flag & NODE_DO_OUTPUT) { + output++; + if(output>1) + tnode->flag &= ~NODE_DO_OUTPUT; + } + } + } + else { + /* same type */ + if(tnode->type==node->type) { + if(tnode->flag & NODE_DO_OUTPUT) { + output++; + if(output>1) + tnode->flag &= ~NODE_DO_OUTPUT; + } + } + } + } + } + if(output==0) + node->flag |= NODE_DO_OUTPUT; + } + } + + /* here we could recursively set which nodes have to be done, + might be different for editor or for "real" use... */ +} + +typedef struct MakeLocalCallData { + ID *group_id; + ID *new_id; + int lib, local; +} MakeLocalCallData; + +static void ntreeMakeLocal_CheckLocal(void *calldata, ID *owner_id, bNodeTree *ntree) +{ + MakeLocalCallData *cd= (MakeLocalCallData*)calldata; + bNode *node; + + /* find if group is in tree */ + for(node= ntree->nodes.first; node; node= node->next) { + if(node->id == cd->group_id) { + if(owner_id->lib) cd->lib= 1; + else cd->local= 1; + } + } +} +static void ntreeMakeLocal_LinkNew(void *calldata, ID *owner_id, bNodeTree *ntree) +{ + MakeLocalCallData *cd= (MakeLocalCallData*)calldata; + bNode *node; + + /* find if group is in tree */ + for(node= ntree->nodes.first; node; node= node->next) { + if(node->id == cd->group_id) { + if(owner_id->lib==NULL) { + node->id= cd->new_id; + cd->new_id->us++; + cd->group_id->us--; + } + } + } } void ntreeMakeLocal(bNodeTree *ntree) { - int local=0, lib=0; + bNodeTreeType *treetype= ntreeGetType(ntree->type); + MakeLocalCallData cd; /* - only lib users: do nothing * - only local users: set flag @@ -1473,138 +1041,146 @@ void ntreeMakeLocal(bNodeTree *ntree) if(ntree->id.lib==NULL) return; if(ntree->id.us==1) { - ntree->id.lib= NULL; + ntree->id.lib= 0; ntree->id.flag= LIB_LOCAL; - new_id(NULL, (ID *)ntree, NULL); + new_id(0, (ID *)ntree, 0); return; } /* now check users of groups... again typedepending, callback... */ - if(ntree->type==NTREE_SHADER) { - Material *ma; - for(ma= G.main->mat.first; ma; ma= ma->id.next) { - if(ma->nodetree) { - bNode *node; - - /* find if group is in tree */ - for(node= ma->nodetree->nodes.first; node; node= node->next) { - if(node->id == (ID *)ntree) { - if(ma->id.lib) lib= 1; - else local= 1; - } - } - } - } - } - else if(ntree->type==NTREE_COMPOSIT) { - Scene *sce; - for(sce= G.main->scene.first; sce; sce= sce->id.next) { - if(sce->nodetree) { - bNode *node; - - /* find if group is in tree */ - for(node= sce->nodetree->nodes.first; node; node= node->next) { - if(node->id == (ID *)ntree) { - if(sce->id.lib) lib= 1; - else local= 1; - } - } - } - } - } - else if(ntree->type==NTREE_TEXTURE) { - Tex *tx; - for(tx= G.main->tex.first; tx; tx= tx->id.next) { - if(tx->nodetree) { - bNode *node; - - /* find if group is in tree */ - for(node= tx->nodetree->nodes.first; node; node= node->next) { - if(node->id == (ID *)ntree) { - if(tx->id.lib) lib= 1; - else local= 1; - } - } - } - } - } + cd.group_id = &ntree->id; + cd.new_id = NULL; + cd.local = 0; + cd.lib = 0; + + treetype->foreach_nodetree(G.main, &cd, &ntreeMakeLocal_CheckLocal); /* if all users are local, we simply make tree local */ - if(local && lib==0) { + if(cd.local && cd.lib==0) { ntree->id.lib= NULL; ntree->id.flag= LIB_LOCAL; - new_id(NULL, (ID *)ntree, NULL); + new_id(0, (ID *)ntree, 0); } - else if(local && lib) { + else if(cd.local && cd.lib) { /* this is the mixed case, we copy the tree and assign it to local users */ bNodeTree *newtree= ntreeCopyTree(ntree); newtree->id.us= 0; - if(ntree->type==NTREE_SHADER) { - Material *ma; - for(ma= G.main->mat.first; ma; ma= ma->id.next) { - if(ma->nodetree) { - bNode *node; - - /* find if group is in tree */ - for(node= ma->nodetree->nodes.first; node; node= node->next) { - if(node->id == (ID *)ntree) { - if(ma->id.lib==NULL) { - node->id= &newtree->id; - newtree->id.us++; - ntree->id.us--; - } - } - } - } - } - } - else if(ntree->type==NTREE_COMPOSIT) { - Scene *sce; - for(sce= G.main->scene.first; sce; sce= sce->id.next) { - if(sce->nodetree) { - bNode *node; - - /* find if group is in tree */ - for(node= sce->nodetree->nodes.first; node; node= node->next) { - if(node->id == (ID *)ntree) { - if(sce->id.lib==NULL) { - node->id= &newtree->id; - newtree->id.us++; - ntree->id.us--; - } - } - } - } - } - } - else if(ntree->type==NTREE_TEXTURE) { - Tex *tx; - for(tx= G.main->tex.first; tx; tx= tx->id.next) { - if(tx->nodetree) { - bNode *node; - - /* find if group is in tree */ - for(node= tx->nodetree->nodes.first; node; node= node->next) { - if(node->id == (ID *)ntree) { - if(tx->id.lib==NULL) { - node->id= &newtree->id; - newtree->id.us++; - ntree->id.us--; - } - } - } - } + + cd.new_id = &newtree->id; + treetype->foreach_nodetree(G.main, &cd, &ntreeMakeLocal_LinkNew); + } +} + +int ntreeNodeExists(bNodeTree *ntree, bNode *testnode) +{ + bNode *node= ntree->nodes.first; + for(; node; node= node->next) + if(node==testnode) + return 1; + return 0; +} + +int ntreeOutputExists(bNode *node, bNodeSocket *testsock) +{ + bNodeSocket *sock= node->outputs.first; + for(; sock; sock= sock->next) + if(sock==testsock) + return 1; + return 0; +} + +/* returns localized tree for execution in threads */ +bNodeTree *ntreeLocalize(bNodeTree *ntree) +{ + bNodeTreeType *ntreetype= ntreeGetType(ntree->type); + + bNodeTree *ltree; + bNode *node; + + bAction *action_backup= NULL, *tmpact_backup= NULL; + + /* Workaround for copying an action on each render! + * set action to NULL so animdata actions dont get copied */ + AnimData *adt= BKE_animdata_from_id(&ntree->id); + + if(adt) { + action_backup= adt->action; + tmpact_backup= adt->tmpact; + + adt->action= NULL; + adt->tmpact= NULL; + } + + /* node copy func */ + ltree= ntreeCopyTree(ntree); + + if(adt) { + AnimData *ladt= BKE_animdata_from_id(<ree->id); + + adt->action= ladt->action= action_backup; + adt->tmpact= ladt->tmpact= tmpact_backup; + + if(action_backup) action_backup->id.us++; + if(tmpact_backup) tmpact_backup->id.us++; + + } + /* end animdata uglyness */ + + /* ensures only a single output node is enabled */ + ntreeSetOutput(ntree); + + for(node= ntree->nodes.first; node; node= node->next) { + /* store new_node pointer to original */ + node->new_node->new_node= node; + } + + if (ntreetype->localize) + ntreetype->localize(ltree, ntree); + + return ltree; +} + +/* sync local composite with real tree */ +/* local tree is supposed to be running, be careful moving previews! */ +/* is called by jobs manager, outside threads, so it doesnt happen during draw */ +void ntreeLocalSync(bNodeTree *localtree, bNodeTree *ntree) +{ + bNodeTreeType *ntreetype= ntreeGetType(ntree->type); + + if (ntreetype->local_sync) + ntreetype->local_sync(localtree, ntree); +} + +/* merge local tree results back, and free local tree */ +/* we have to assume the editor already changed completely */ +void ntreeLocalMerge(bNodeTree *localtree, bNodeTree *ntree) +{ + bNodeTreeType *ntreetype= ntreeGetType(ntree->type); + bNode *lnode; + + /* move over the compbufs and previews */ + for(lnode= localtree->nodes.first; lnode; lnode= lnode->next) { + if(ntreeNodeExists(ntree, lnode->new_node)) { + if(lnode->preview && lnode->preview->rect) { + nodeFreePreview(lnode->new_node); + lnode->new_node->preview= lnode->preview; + lnode->preview= NULL; } } } -} + if (ntreetype->local_merge) + ntreetype->local_merge(localtree, ntree); + + ntreeFreeTree(localtree); + MEM_freeN(localtree); +} /* ************ find stuff *************** */ -static int ntreeHasType(bNodeTree *ntree, int type) +int ntreeHasType(bNodeTree *ntree, int type) { bNode *node; @@ -1768,7 +1344,7 @@ void ntreeSocketUseFlags(bNodeTree *ntree) /* ************** dependency stuff *********** */ /* node is guaranteed to be not checked before */ -static int node_recurs_check(bNode *node, bNode ***nsort) +static int node_get_deplist_recurs(bNode *node, bNode ***nsort) { bNode *fromnode; bNodeSocket *sock; @@ -1776,1625 +1352,361 @@ static int node_recurs_check(bNode *node, bNode ***nsort) node->done= 1; + /* check linked nodes */ for(sock= node->inputs.first; sock; sock= sock->next) { if(sock->link) { fromnode= sock->link->fromnode; if(fromnode) { if (fromnode->done==0) - fromnode->level= node_recurs_check(fromnode, nsort); + fromnode->level= node_get_deplist_recurs(fromnode, nsort); if (fromnode->level <= level) level = fromnode->level - 1; } } } - **nsort= node; - (*nsort)++; - return level; -} - - -static void ntreeSetOutput(bNodeTree *ntree) -{ - bNode *node; - - /* find the active outputs, might become tree type dependant handler */ - for(node= ntree->nodes.first; node; node= node->next) { - if(node->typeinfo->nclass==NODE_CLASS_OUTPUT) { - bNode *tnode; - int output= 0; - - /* we need a check for which output node should be tagged like this, below an exception */ - if(node->type==CMP_NODE_OUTPUT_FILE) - continue; - - /* there is more types having output class, each one is checked */ - for(tnode= ntree->nodes.first; tnode; tnode= tnode->next) { - if(tnode->typeinfo->nclass==NODE_CLASS_OUTPUT) { - - if(ntree->type==NTREE_COMPOSIT) { - - /* same type, exception for viewer */ - if(tnode->type==node->type || - (ELEM(tnode->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER) && - ELEM(node->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER))) { - if(tnode->flag & NODE_DO_OUTPUT) { - output++; - if(output>1) - tnode->flag &= ~NODE_DO_OUTPUT; - } - } - } - else { - /* same type */ - if(tnode->type==node->type) { - if(tnode->flag & NODE_DO_OUTPUT) { - output++; - if(output>1) - tnode->flag &= ~NODE_DO_OUTPUT; - } - } - } - } - } - if(output==0) - node->flag |= NODE_DO_OUTPUT; - } + /* check parent node */ + if (node->parent) { + if (node->parent->done==0) + node->parent->level= node_get_deplist_recurs(node->parent, nsort); + if (node->parent->level <= level) + level = node->parent->level - 1; } - /* here we could recursively set which nodes have to be done, - might be different for editor or for "real" use... */ + if (nsort) { + **nsort= node; + (*nsort)++; + } + + return level; } -void ntreeSolveOrder(bNodeTree *ntree) +void ntreeGetDependencyList(struct bNodeTree *ntree, struct bNode ***deplist, int *totnodes) { - bNode *node, **nodesort, **nsort; - bNodeSocket *sock; - bNodeLink *link; - int a, totnode=0; + bNode *node, **nsort; + + *totnodes=0; - /* the solve-order is called on each tree change, so we should be sure no exec can be running */ - ntreeEndExecTree(ntree); - - /* set links pointers the input sockets, to find dependencies */ /* first clear data */ for(node= ntree->nodes.first; node; node= node->next) { node->done= 0; - totnode++; - for(sock= node->inputs.first; sock; sock= sock->next) - sock->link= NULL; + (*totnodes)++; } - /* clear group socket links */ - for(sock= ntree->outputs.first; sock; sock= sock->next) - sock->link= NULL; - if(totnode==0) + if(*totnodes==0) { + *deplist = NULL; return; - - for(link= ntree->links.first; link; link= link->next) { - link->tosock->link= link; } - nsort= nodesort= MEM_callocN(totnode*sizeof(void *), "sorted node array"); + nsort= *deplist= MEM_callocN((*totnodes)*sizeof(bNode*), "sorted node array"); /* recursive check */ for(node= ntree->nodes.first; node; node= node->next) { if(node->done==0) { - node->level= node_recurs_check(node, &nsort); + node->level= node_get_deplist_recurs(node, &nsort); } } - - /* re-insert nodes in order, first a paranoia check */ - for(a=0; a<totnode; a++) { - if(nodesort[a]==NULL) - break; - } - if(a<totnode) - printf("sort error in node tree"); - else { - ntree->nodes.first= ntree->nodes.last= NULL; - for(a=0; a<totnode; a++) - BLI_addtail(&ntree->nodes, nodesort[a]); - } - - MEM_freeN(nodesort); - - ntreeSetOutput(ntree); } - -/* Should be callback! */ -/* Do not call execs here */ -void NodeTagChanged(bNodeTree *ntree, bNode *node) -{ - if(ntree->type==NTREE_COMPOSIT) { - bNodeSocket *sock; - - for(sock= node->outputs.first; sock; sock= sock->next) { - if(sock->ns.data) { - //free_compbuf(sock->ns.data); - //sock->ns.data= NULL; - } - } - node->need_exec= 1; - } -} - -int NodeTagIDChanged(bNodeTree *ntree, ID *id) -{ - int change = FALSE; - - if(ELEM(NULL, id, ntree)) - return change; - - if(ntree->type==NTREE_COMPOSIT) { - bNode *node; - - for(node= ntree->nodes.first; node; node= node->next) { - if(node->id==id) { - change= TRUE; - NodeTagChanged(ntree, node); - } - } - } - - return change; -} - - - -/* ******************* executing ************* */ - -/* for a given socket, find the actual stack entry */ -static bNodeStack *get_socket_stack(bNodeStack *stack, bNodeSocket *sock, bNodeStack **gin) -{ - switch (sock->stack_type) { - case SOCK_STACK_LOCAL: - return stack + sock->stack_index; - case SOCK_STACK_EXTERN: - return (gin ? gin[sock->stack_index] : NULL); - case SOCK_STACK_CONST: - return sock->stack_ptr; - } - return NULL; -} - -/* see notes at ntreeBeginExecTree */ -static void node_get_stack(bNode *node, bNodeStack *stack, bNodeStack **in, bNodeStack **out, bNodeStack **gin) -{ - bNodeSocket *sock; - - /* build pointer stack */ - if (in) { - for(sock= node->inputs.first; sock; sock= sock->next) { - *(in++) = get_socket_stack(stack, sock, gin); - } - } - - if (out) { - for(sock= node->outputs.first; sock; sock= sock->next) { - *(out++) = get_socket_stack(stack, sock, gin); - } - } -} - -static void node_group_execute(bNodeStack *stack, void *data, bNode *gnode, bNodeStack **in) +static void ntree_update_link_pointers(bNodeTree *ntree) { bNode *node; - bNodeTree *ntree= (bNodeTree *)gnode->id; - bNodeStack *nsin[MAX_SOCKET]; /* arbitrary... watch this */ - bNodeStack *nsout[MAX_SOCKET]; /* arbitrary... watch this */ - - if(ntree==NULL) return; + bNodeSocket *sock; + bNodeLink *link; - stack+= gnode->stack_index; - + /* first clear data */ for(node= ntree->nodes.first; node; node= node->next) { - if(node->typeinfo->execfunc) { - node_get_stack(node, stack, nsin, nsout, in); - - /* for groups, only execute outputs for edited group */ - if(node->typeinfo->nclass==NODE_CLASS_OUTPUT) { - if(node->type==CMP_NODE_OUTPUT_FILE || (gnode->flag & NODE_GROUP_EDIT)) - node->typeinfo->execfunc(data, node, nsin, nsout); - } - else - node->typeinfo->execfunc(data, node, nsin, nsout); - } - } - - /* free internal buffers */ - if (ntree->type==NTREE_COMPOSIT) { - bNodeSocket *sock; - bNodeStack *ns; - - /* clear hasoutput on all local stack data, - * only the group output will be used from now on - */ - for (node=ntree->nodes.first; node; node=node->next) { - for (sock=node->outputs.first; sock; sock=sock->next) { - if (sock->stack_type==SOCK_STACK_LOCAL) { - ns= get_socket_stack(stack, sock, in); - ns->hasoutput = 0; - } - } - } - /* use the hasoutput flag to tag external sockets */ - for (sock=ntree->outputs.first; sock; sock=sock->next) { - if (sock->stack_type==SOCK_STACK_LOCAL) { - ns= get_socket_stack(stack, sock, in); - ns->hasoutput = 1; - } - } - /* now free all stacks that are not used from outside */ - for (node=ntree->nodes.first; node; node=node->next) { - for (sock=node->outputs.first; sock; sock=sock->next) { - if (sock->stack_type==SOCK_STACK_LOCAL ) { - ns= get_socket_stack(stack, sock, in); - if (ns->hasoutput==0 && ns->data) { - free_compbuf(ns->data); - ns->data = NULL; - } - } - } - } + for(sock= node->inputs.first; sock; sock= sock->next) + sock->link= NULL; } -} + /* clear socket links */ + for(sock= ntree->outputs.first; sock; sock= sock->next) + sock->link= NULL; -static int set_stack_indexes_default(bNode *node, int index) -{ - bNodeSocket *sock; - - for (sock=node->inputs.first; sock; sock=sock->next) { - if (sock->link && sock->link->fromsock) { - sock->stack_type = sock->link->fromsock->stack_type; - sock->stack_index = sock->link->fromsock->stack_index; - sock->stack_ptr = sock->link->fromsock->stack_ptr; - } - else { - sock->stack_type = SOCK_STACK_CONST; - sock->stack_index = -1; - sock->stack_ptr = &sock->ns; - } - } - - for (sock=node->outputs.first; sock; sock=sock->next) { - sock->stack_type = SOCK_STACK_LOCAL; - sock->stack_index = index++; - sock->stack_ptr = NULL; + for(link= ntree->links.first; link; link= link->next) { + if (link->tosock) + link->tosock->link= link; } - - return index; } -static int ntree_begin_exec_tree(bNodeTree *ntree); -static int set_stack_indexes_group(bNode *node, int index) +void ntree_validate_links(bNodeTree *ntree) { - bNodeTree *ngroup= (bNodeTree*)node->id; - bNodeSocket *sock; - - if(ngroup && (ngroup->init & NTREE_TYPE_INIT)==0) - ntreeInitTypes(ngroup); - - node->stack_index = index; - if(ngroup) - index += ntree_begin_exec_tree(ngroup); - - for (sock=node->inputs.first; sock; sock=sock->next) { - if (sock->link && sock->link->fromsock) { - sock->stack_type = sock->link->fromsock->stack_type; - sock->stack_index = sock->link->fromsock->stack_index; - sock->stack_ptr = sock->link->fromsock->stack_ptr; - } - else { - sock->stack_type = SOCK_STACK_CONST; - sock->stack_index = -1; - sock->stack_ptr = &sock->ns; - } - } + bNodeTreeType *ntreetype = ntreeGetType(ntree->type); + bNodeLink *link; - /* identify group node outputs from internal group sockets */ - for(sock= node->outputs.first; sock; sock= sock->next) { - if (sock->groupsock) { - bNodeSocket *insock, *gsock = sock->groupsock; - switch (gsock->stack_type) { - case SOCK_STACK_EXTERN: - /* extern stack is resolved for this group node instance */ - insock= find_group_node_input(node, gsock->link->fromsock); - sock->stack_type = insock->stack_type; - sock->stack_index = insock->stack_index; - sock->stack_ptr = insock->stack_ptr; - break; - case SOCK_STACK_LOCAL: - sock->stack_type = SOCK_STACK_LOCAL; - /* local stack index must be offset by group node instance */ - sock->stack_index = gsock->stack_index + node->stack_index; - sock->stack_ptr = NULL; - break; - case SOCK_STACK_CONST: - sock->stack_type = SOCK_STACK_CONST; - sock->stack_index = -1; - sock->stack_ptr = gsock->stack_ptr; - break; - } - } - else { - sock->stack_type = SOCK_STACK_LOCAL; - sock->stack_index = index++; - sock->stack_ptr = NULL; + for (link = ntree->links.first; link; link = link->next) { + link->flag |= NODE_LINK_VALID; + if (link->fromnode && link->tonode && link->fromnode->level <= link->tonode->level) + link->flag &= ~NODE_LINK_VALID; + else if (ntreetype->validate_link) { + if (!ntreetype->validate_link(ntree, link)) + link->flag &= ~NODE_LINK_VALID; } } - - return index; } -/* recursively called for groups */ -/* we set all trees on own local indices, but put a total counter - in the groups, so each instance of a group has own stack */ -static int ntree_begin_exec_tree(bNodeTree *ntree) +static void ntree_verify_nodes_cb(void *calldata, struct ID *UNUSED(owner_id), struct bNodeTree *ntree) { + ID *id= (ID*)calldata; bNode *node; - bNodeSocket *gsock; - int index= 0, i; - - if((ntree->init & NTREE_TYPE_INIT)==0) - ntreeInitTypes(ntree); - - /* group inputs are numbered 0..totinputs, so external stack can easily be addressed */ - i = 0; - for(gsock=ntree->inputs.first; gsock; gsock = gsock->next) { - gsock->stack_type = SOCK_STACK_EXTERN; - gsock->stack_index = i++; - gsock->stack_ptr = NULL; - } - - /* create indices for stack, check preview */ - for(node= ntree->nodes.first; node; node= node->next) { - /* XXX can this be done by a generic one-for-all function? - * otherwise should use node-type callback. - */ - if(node->type==NODE_GROUP) - index = set_stack_indexes_group(node, index); - else - index = set_stack_indexes_default(node, index); - } - - /* group outputs */ - for(gsock=ntree->outputs.first; gsock; gsock = gsock->next) { - if (gsock->link && gsock->link->fromsock) { - gsock->stack_type = gsock->link->fromsock->stack_type; - gsock->stack_index = gsock->link->fromsock->stack_index; - gsock->stack_ptr = gsock->link->fromsock->stack_ptr; - } - else { - gsock->stack_type = SOCK_STACK_CONST; - gsock->stack_index = -1; - gsock->stack_ptr = &gsock->ns; - } - } - return index; + for (node=ntree->nodes.first; node; node=node->next) + if (node->typeinfo->verifyfunc) + node->typeinfo->verifyfunc(ntree, node, id); } -/* copy socket compbufs to stack, initialize usage of curve nodes */ -static void composit_begin_exec(bNodeTree *ntree, bNodeStack *stack) +void ntreeVerifyNodes(struct Main *main, struct ID *id) { - bNode *node; - bNodeSocket *sock; + bNodeTreeType *ntreetype; + bNodeTree *ntree; + int n; - for(node= ntree->nodes.first; node; node= node->next) { - - /* initialize needed for groups */ - node->exec= 0; - - for(sock= node->outputs.first; sock; sock= sock->next) { - bNodeStack *ns= get_socket_stack(stack, sock, NULL); - if(ns && sock->ns.data) { - ns->data= sock->ns.data; - sock->ns.data= NULL; - } - } - - /* cannot initialize them while using in threads */ - if(ELEM4(node->type, CMP_NODE_TIME, CMP_NODE_CURVE_VEC, CMP_NODE_CURVE_RGB, CMP_NODE_HUECORRECT)) { - curvemapping_initialize(node->storage); - if(node->type==CMP_NODE_CURVE_RGB) - curvemapping_premultiply(node->storage, 0); - } - if(node->type==NODE_GROUP && node->id) - composit_begin_exec((bNodeTree *)node->id, stack + node->stack_index); - - } -} - -/* copy stack compbufs to sockets */ -static void composit_end_exec(bNodeTree *ntree, bNodeStack *stack) -{ - bNode *node; - bNodeStack *ns; - - for(node= ntree->nodes.first; node; node= node->next) { - bNodeSocket *sock; - - for(sock= node->outputs.first; sock; sock= sock->next) { - ns = get_socket_stack(stack, sock, NULL); - if(ns && ns->data) { - sock->ns.data= ns->data; - ns->data= NULL; - } - } - - if(node->type==CMP_NODE_CURVE_RGB) - curvemapping_premultiply(node->storage, 1); - - if(node->type==NODE_GROUP && node->id) - composit_end_exec((bNodeTree *)node->id, stack + node->stack_index); - - node->need_exec= 0; + for (n=0; n < NUM_NTREE_TYPES; ++n) { + ntreetype= ntreeGetType(n); + if (ntreetype && ntreetype->foreach_nodetree) + ntreetype->foreach_nodetree(main, id, ntree_verify_nodes_cb); } + for (ntree=main->nodetree.first; ntree; ntree=ntree->id.next) + ntree_verify_nodes_cb(id, NULL, ntree); } -static void group_tag_used_outputs(bNode *gnode, bNodeStack *stack, bNodeStack **gin) +void ntreeUpdateTree(bNodeTree *ntree) { - bNodeTree *ntree= (bNodeTree *)gnode->id; + bNodeTreeType *ntreetype= ntreeGetType(ntree->type); bNode *node; - bNodeSocket *sock; + bNode **deplist; + int totnodes, n; - stack+= gnode->stack_index; - - for(node= ntree->nodes.first; node; node= node->next) { - if(node->typeinfo->execfunc) { - for(sock= node->inputs.first; sock; sock= sock->next) { - bNodeStack *ns = get_socket_stack(stack, sock, gin); - ns->hasoutput= 1; - } - } - - /* non-composite trees do all nodes by default */ - if (ntree->type!=NTREE_COMPOSIT) - node->need_exec = 1; - - for(sock= node->inputs.first; sock; sock= sock->next) { - bNodeStack *ns = get_socket_stack(stack, sock, gin); - if (ns) { - ns->hasoutput = 1; - - /* sock type is needed to detect rgba or value or vector types */ - if(sock->link && sock->link->fromsock) - ns->sockettype= sock->link->fromsock->type; - else - sock->ns.sockettype= sock->type; - } - - if(sock->link) { - bNodeLink *link= sock->link; - /* this is the test for a cyclic case */ - if(link->fromnode && link->tonode) { - if(link->fromnode->level >= link->tonode->level && link->tonode->level!=0xFFF); - else { - node->need_exec= 0; - } - } - } - } - - /* set stack types (for local stack entries) */ - for(sock= node->outputs.first; sock; sock= sock->next) { - bNodeStack *ns = get_socket_stack(stack, sock, gin); - if (ns) - ns->sockettype = sock->type; - } - } -} - -/* notes below are ancient! (ton) */ -/* stack indices make sure all nodes only write in allocated data, for making it thread safe */ -/* only root tree gets the stack, to enable instances to have own stack entries */ -/* per tree (and per group) unique indices are created */ -/* the index_ext we need to be able to map from groups to the group-node own stack */ - -typedef struct bNodeThreadStack { - struct bNodeThreadStack *next, *prev; - bNodeStack *stack; - int used; -} bNodeThreadStack; - -static bNodeThreadStack *ntreeGetThreadStack(bNodeTree *ntree, int thread) -{ - ListBase *lb= &ntree->threadstack[thread]; - bNodeThreadStack *nts; + ntree_update_link_pointers(ntree); - for(nts=lb->first; nts; nts=nts->next) { - if(!nts->used) { - nts->used= 1; - return nts; - } - } - nts= MEM_callocN(sizeof(bNodeThreadStack), "bNodeThreadStack"); - nts->stack= MEM_dupallocN(ntree->stack); - nts->used= 1; - BLI_addtail(lb, nts); - - return nts; -} - -static void ntreeReleaseThreadStack(bNodeThreadStack *nts) -{ - nts->used= 0; -} - -/* free texture delegates */ -static void tex_end_exec(bNodeTree *ntree) -{ - bNodeThreadStack *nts; - bNodeStack *ns; - int th, a; + /* also updates the node level! */ + ntreeGetDependencyList(ntree, &deplist, &totnodes); - if(ntree->threadstack) { - for(th=0; th<BLENDER_MAX_THREADS; th++) { - for(nts=ntree->threadstack[th].first; nts; nts=nts->next) { - for(ns= nts->stack, a=0; a<ntree->stacksize; a++, ns++) { - if(ns->data) { - MEM_freeN(ns->data); - ns->data= NULL; - } - } - } + if (deplist) { + /* update individual nodes */ + for (n=0; n < totnodes; ++n) { + node = deplist[n]; + if (ntreetype->update_node) + ntreetype->update_node(ntree, node); + else if (node->typeinfo->updatefunc) + node->typeinfo->updatefunc(ntree, node); } - } -} - -void ntreeBeginExecTree(bNodeTree *ntree) -{ - bNodeStack *nsin[MAX_SOCKET]; /* arbitrary... watch this */ - - /* let's make it sure */ - if(ntree->init & NTREE_EXEC_INIT) - return; - - /* allocate the thread stack listbase array */ - if(ntree->type!=NTREE_COMPOSIT) - ntree->threadstack= MEM_callocN(BLENDER_MAX_THREADS*sizeof(ListBase), "thread stack array"); - - /* goes recursive over all groups */ - ntree->stacksize= ntree_begin_exec_tree(ntree); - - if(ntree->stacksize) { - bNode *node; - bNodeStack *ns; - int a; - /* allocate the base stack */ - ns=ntree->stack= MEM_callocN(ntree->stacksize*sizeof(bNodeStack), "node stack"); + MEM_freeN(deplist); - /* tag inputs, the get_stack() gives own socket stackdata if not in use */ - for(a=0; a<ntree->stacksize; a++, ns++) ns->hasinput= 1; - - /* tag used outputs, so we know when we can skip operations */ - for(node= ntree->nodes.first; node; node= node->next) { - bNodeSocket *sock; - - /* non-composite trees do all nodes by default */ - if(ntree->type!=NTREE_COMPOSIT) - node->need_exec= 1; - - for(sock= node->inputs.first; sock; sock= sock->next) { - ns = get_socket_stack(ntree->stack, sock, NULL); - if (ns) { - ns->hasoutput = 1; - - /* sock type is needed to detect rgba or value or vector types */ - if(sock->link && sock->link->fromsock) - ns->sockettype= sock->link->fromsock->type; - else - sock->ns.sockettype= sock->type; - } - - if(sock->link) { - bNodeLink *link= sock->link; - /* this is the test for a cyclic case */ - if(link->fromnode && link->tonode) { - if(link->fromnode->level >= link->tonode->level && link->tonode->level!=0xFFF); - else { - node->need_exec= 0; - } - } - } - } - - /* set stack types (for local stack entries) */ - for(sock= node->outputs.first; sock; sock= sock->next) { - ns = get_socket_stack(ntree->stack, sock, NULL); - if (ns) - ns->sockettype = sock->type; - } - - if(node->type==NODE_GROUP && node->id) { - node_get_stack(node, ntree->stack, nsin, NULL, NULL); - group_tag_used_outputs(node, ntree->stack, nsin); - } - } + /* ensures only a single output node is enabled, texnode allows multiple though */ + if(ntree->type!=NTREE_TEXTURE) + ntreeSetOutput(ntree); - if(ntree->type==NTREE_COMPOSIT) - composit_begin_exec(ntree, ntree->stack); } - ntree->init |= NTREE_EXEC_INIT; -} - -void ntreeEndExecTree(bNodeTree *ntree) -{ - bNodeStack *ns; - - if(ntree->init & NTREE_EXEC_INIT) { - bNodeThreadStack *nts; - int a; - - /* another callback candidate! */ - if(ntree->type==NTREE_COMPOSIT) { - composit_end_exec(ntree, ntree->stack); - - for(ns= ntree->stack, a=0; a<ntree->stacksize; a++, ns++) { - if(ns->data) { - printf("freed leftover buffer from stack\n"); - free_compbuf(ns->data); - ns->data= NULL; - } - } - } - else if(ntree->type==NTREE_TEXTURE) - tex_end_exec(ntree); - - if(ntree->stack) { - MEM_freeN(ntree->stack); - ntree->stack= NULL; - } - - if(ntree->threadstack) { - for(a=0; a<BLENDER_MAX_THREADS; a++) { - for(nts=ntree->threadstack[a].first; nts; nts=nts->next) - if (nts->stack) MEM_freeN(nts->stack); - BLI_freelistN(&ntree->threadstack[a]); - } - - MEM_freeN(ntree->threadstack); - ntree->threadstack= NULL; - } - - ntree->init &= ~NTREE_EXEC_INIT; + /* general tree updates */ + if (ntree->update & (NTREE_UPDATE_LINKS|NTREE_UPDATE_NODES)) { + ntree_validate_links(ntree); } -} - -/* nodes are presorted, so exec is in order of list */ -void ntreeExecTree(bNodeTree *ntree, void *callerdata, int thread) -{ - bNode *node; - bNodeStack *nsin[MAX_SOCKET]; /* arbitrary... watch this */ - bNodeStack *nsout[MAX_SOCKET]; /* arbitrary... watch this */ - bNodeStack *stack; - bNodeThreadStack *nts = NULL; - - /* only when initialized */ - if((ntree->init & NTREE_EXEC_INIT)==0) - ntreeBeginExecTree(ntree); - /* composite does 1 node per thread, so no multiple stacks needed */ - if(ntree->type==NTREE_COMPOSIT) { - stack= ntree->stack; - } + /* update tree */ + if (ntreetype->update) + ntreetype->update(ntree); else { - nts= ntreeGetThreadStack(ntree, thread); - stack= nts->stack; + bNodeType *ntype= node_get_type(ntree, ntree->nodetype); + if (ntype && ntype->updatetreefunc) + ntype->updatetreefunc(ntree); } - for(node= ntree->nodes.first; node; node= node->next) { - if(node->need_exec) { - if(node->typeinfo->execfunc) { - node_get_stack(node, stack, nsin, nsout, NULL); - node->typeinfo->execfunc(callerdata, node, nsin, nsout); - } - else if(node->type==NODE_GROUP && node->id) { - node_get_stack(node, stack, nsin, NULL, NULL); - node_group_execute(stack, callerdata, node, nsin); - } - } - } - - if(nts) - ntreeReleaseThreadStack(nts); -} - - -/* ***************************** threaded version for execute composite nodes ************* */ -/* these are nodes without input, only giving values */ -/* or nodes with only value inputs */ -static int node_only_value(bNode *node) -{ - bNodeSocket *sock; - - if(ELEM3(node->type, CMP_NODE_TIME, CMP_NODE_VALUE, CMP_NODE_RGB)) - return 1; + /* XXX hack, should be done by depsgraph!! */ + ntreeVerifyNodes(G.main, &ntree->id); - /* doing this for all node types goes wrong. memory free errors */ - if(node->inputs.first && node->type==CMP_NODE_MAP_VALUE) { - int retval= 1; - for(sock= node->inputs.first; sock; sock= sock->next) { - if(sock->link && sock->link->fromnode) - retval &= node_only_value(sock->link->fromnode); - } - return retval; - } - return 0; + /* clear the update flag */ + ntree->update = 0; } - -/* not changing info, for thread callback */ -typedef struct ThreadData { - bNodeStack *stack; - RenderData *rd; -} ThreadData; - -static void *exec_composite_node(void *node_v) -{ - bNodeStack *nsin[MAX_SOCKET]; /* arbitrary... watch this */ - bNodeStack *nsout[MAX_SOCKET]; /* arbitrary... watch this */ - bNode *node= node_v; - ThreadData *thd= (ThreadData *)node->threaddata; - - node_get_stack(node, thd->stack, nsin, nsout, NULL); - - if((node->flag & NODE_MUTED) && (!node_only_value(node))) { - /* viewers we execute, for feedback to user */ - if(ELEM(node->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER)) - node->typeinfo->execfunc(thd->rd, node, nsin, nsout); - else - node_compo_pass_on(node, nsin, nsout); - } - else if(node->typeinfo->execfunc) { - node->typeinfo->execfunc(thd->rd, node, nsin, nsout); - } - else if(node->type==NODE_GROUP && node->id) { - node_group_execute(thd->stack, thd->rd, node, nsin); - } - - node->exec |= NODE_READY; - return NULL; -} - -/* return total of executable nodes, for timecursor */ -/* only compositor uses it */ -static int setExecutableNodes(bNodeTree *ntree, ThreadData *thd) -{ - bNodeStack *nsin[MAX_SOCKET]; /* arbitrary... watch this */ - bNodeStack *nsout[MAX_SOCKET]; /* arbitrary... watch this */ - bNode *node; - bNodeSocket *sock; - int totnode= 0, group_edit= 0; - - /* note; do not add a dependency sort here, the stack was created already */ - - /* if we are in group edit, viewer nodes get skipped when group has viewer */ - for(node= ntree->nodes.first; node; node= node->next) - if(node->type==NODE_GROUP && (node->flag & NODE_GROUP_EDIT)) - if(ntreeHasType((bNodeTree *)node->id, CMP_NODE_VIEWER)) - group_edit= 1; - - for(node= ntree->nodes.first; node; node= node->next) { - int a; - - node_get_stack(node, thd->stack, nsin, nsout, NULL); - - /* test the outputs */ - /* skip value-only nodes (should be in type!) */ - if(!node_only_value(node)) { - for(a=0, sock= node->outputs.first; sock; sock= sock->next, a++) { - if(nsout[a]->data==NULL && nsout[a]->hasoutput) { - node->need_exec= 1; - break; - } - } - } - - /* test the inputs */ - for(a=0, sock= node->inputs.first; sock; sock= sock->next, a++) { - /* skip viewer nodes in bg render or group edit */ - if( ELEM(node->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER) && (G.background || group_edit)) - node->need_exec= 0; - /* is sock in use? */ - else if(sock->link) { - bNodeLink *link= sock->link; - - /* this is the test for a cyclic case */ - if(link->fromnode==NULL || link->tonode==NULL); - else if(link->fromnode->level >= link->tonode->level && link->tonode->level!=0xFFF) { - if(link->fromnode->need_exec) { - node->need_exec= 1; - break; - } - } - else { - node->need_exec= 0; - printf("Node %s skipped, cyclic dependency\n", node->name); - } - } - } - - if(node->need_exec) { - - /* free output buffers */ - for(a=0, sock= node->outputs.first; sock; sock= sock->next, a++) { - if(nsout[a]->data) { - free_compbuf(nsout[a]->data); - nsout[a]->data= NULL; - } - } - totnode++; - /* printf("node needs exec %s\n", node->name); */ - - /* tag for getExecutableNode() */ - node->exec= 0; - } - else { - /* tag for getExecutableNode() */ - node->exec= NODE_READY|NODE_FINISHED|NODE_SKIPPED; - - } - } - - /* last step: set the stack values for only-value nodes */ - /* just does all now, compared to a full buffer exec this is nothing */ - if(totnode) { - for(node= ntree->nodes.first; node; node= node->next) { - if(node->need_exec==0 && node_only_value(node)) { - if(node->typeinfo->execfunc) { - node_get_stack(node, thd->stack, nsin, nsout, NULL); - node->typeinfo->execfunc(thd->rd, node, nsin, nsout); - } - } - } - } - - return totnode; -} - -/* while executing tree, free buffers from nodes that are not needed anymore */ -static void freeExecutableNode(bNodeTree *ntree) +void NodeTagChanged(bNodeTree *ntree, bNode *node) { - /* node outputs can be freed when: - - not a render result or image node - - when node outputs go to nodes all being set NODE_FINISHED - */ - bNode *node; - bNodeSocket *sock; + bNodeTreeType *ntreetype = ntreeGetType(ntree->type); - /* set exec flag for finished nodes that might need freed */ - for(node= ntree->nodes.first; node; node= node->next) { - if(node->type!=CMP_NODE_R_LAYERS) - if(node->exec & NODE_FINISHED) - node->exec |= NODE_FREEBUFS; - } - /* clear this flag for input links that are not done yet */ - for(node= ntree->nodes.first; node; node= node->next) { - if((node->exec & NODE_FINISHED)==0) { - for(sock= node->inputs.first; sock; sock= sock->next) - if(sock->link && sock->link->fromnode) - sock->link->fromnode->exec &= ~NODE_FREEBUFS; - } - } - /* now we can free buffers */ - for(node= ntree->nodes.first; node; node= node->next) { - if(node->exec & NODE_FREEBUFS) { - for(sock= node->outputs.first; sock; sock= sock->next) { - bNodeStack *ns= get_socket_stack(ntree->stack, sock, NULL); - if(ns && ns->data) { - free_compbuf(ns->data); - ns->data= NULL; - // printf("freed buf node %s \n", node->name); - } - } - } - } + if (ntreetype->update_node) + ntreetype->update_node(ntree, node); + else if (node->typeinfo->updatefunc) + node->typeinfo->updatefunc(ntree, node); } -static bNode *getExecutableNode(bNodeTree *ntree) +int NodeTagIDChanged(bNodeTree *ntree, ID *id) { + bNodeTreeType *ntreetype = ntreeGetType(ntree->type); bNode *node; - bNodeSocket *sock; - - for(node= ntree->nodes.first; node; node= node->next) { - if(node->exec==0) { - - /* input sockets should be ready */ - for(sock= node->inputs.first; sock; sock= sock->next) { - if(sock->link && sock->link->fromnode) - if((sock->link->fromnode->exec & NODE_READY)==0) - break; - } - if(sock==NULL) - return node; - } - } - return NULL; -} + int change = FALSE; -/* check if texture nodes need exec or end */ -static void ntree_composite_texnode(bNodeTree *ntree, int init) -{ - bNode *node; + if(ELEM(NULL, id, ntree)) + return change; - for(node= ntree->nodes.first; node; node= node->next) { - if(node->type==CMP_NODE_TEXTURE && node->id) { - Tex *tex= (Tex *)node->id; - if(tex->nodetree && tex->use_nodes) { - /* has internal flag to detect it only does it once */ - if(init) - ntreeBeginExecTree(tex->nodetree); - else - ntreeEndExecTree(tex->nodetree); + if (ntreetype->update_node) { + for(node= ntree->nodes.first; node; node= node->next) { + if(node->id==id) { + change = TRUE; + ntreetype->update_node(ntree, node); } } } - -} - -/* optimized tree execute test for compositing */ -void ntreeCompositExecTree(bNodeTree *ntree, RenderData *rd, int do_preview) -{ - bNode *node; - ListBase threads; - ThreadData thdata; - int totnode, curnode, rendering= 1; - - if(ntree==NULL) return; - - if(do_preview) - ntreeInitPreview(ntree, 0, 0); - - ntreeBeginExecTree(ntree); - ntree_composite_texnode(ntree, 1); - - /* prevent unlucky accidents */ - if(G.background) - rd->scemode &= ~R_COMP_CROP; - - /* setup callerdata for thread callback */ - thdata.rd= rd; - thdata.stack= ntree->stack; - - /* fixed seed, for example noise texture */ - BLI_srandom(rd->cfra); - - /* ensures only a single output node is enabled */ - ntreeSetOutput(ntree); - - /* sets need_exec tags in nodes */ - curnode = totnode= setExecutableNodes(ntree, &thdata); - - BLI_init_threads(&threads, exec_composite_node, rd->threads); - - while(rendering) { - - if(BLI_available_threads(&threads)) { - node= getExecutableNode(ntree); - if(node) { - if(ntree->progress && totnode) - ntree->progress(ntree->prh, (1.0f - curnode/(float)totnode)); - if(ntree->stats_draw) { - char str[64]; - sprintf(str, "Compositing %d %s", curnode, node->name); - ntree->stats_draw(ntree->sdh, str); - } - curnode--; - - node->threaddata = &thdata; - node->exec= NODE_PROCESSING; - BLI_insert_thread(&threads, node); - } - else - PIL_sleep_ms(50); - } - else - PIL_sleep_ms(50); - - rendering= 0; - /* test for ESC */ - if(ntree->test_break && ntree->test_break(ntree->tbh)) { - for(node= ntree->nodes.first; node; node= node->next) - node->exec |= NODE_READY; - } - - /* check for ready ones, and if we need to continue */ + else { for(node= ntree->nodes.first; node; node= node->next) { - if(node->exec & NODE_READY) { - if((node->exec & NODE_FINISHED)==0) { - BLI_remove_thread(&threads, node); /* this waits for running thread to finish btw */ - node->exec |= NODE_FINISHED; - - /* freeing unused buffers */ - if(rd->scemode & R_COMP_FREE) - freeExecutableNode(ntree); - } + if(node->id==id) { + change = TRUE; + if (node->typeinfo->updatefunc) + node->typeinfo->updatefunc(ntree, node); } - else rendering= 1; } } - BLI_end_threads(&threads); - - ntreeEndExecTree(ntree); + return change; } -/* ********** copy composite tree entirely, to allow threaded exec ******************* */ -/* ***************** do NOT execute this in a thread! ****************** */ +/* ************* node type access ********** */ -/* returns localized tree for execution in threads */ -/* local tree then owns all compbufs (for composite) */ -bNodeTree *ntreeLocalize(bNodeTree *ntree) +int nodeValid(bNodeTree *ntree, bNodeTemplate *ntemp) { - bNodeTree *ltree; - bNode *node; - bNodeSocket *sock; - - bAction *action_backup= NULL, *tmpact_backup= NULL; - - /* Workaround for copying an action on each render! - * set action to NULL so animdata actions dont get copied */ - AnimData *adt= BKE_animdata_from_id(&ntree->id); - - if(adt) { - action_backup= adt->action; - tmpact_backup= adt->tmpact; - - adt->action= NULL; - adt->tmpact= NULL; - } - - /* node copy func */ - ltree= ntreeCopyTree(ntree); - - if(adt) { - AnimData *ladt= BKE_animdata_from_id(<ree->id); - - adt->action= ladt->action= action_backup; - adt->tmpact= ladt->tmpact= tmpact_backup; - - if(action_backup) action_backup->id.us++; - if(tmpact_backup) tmpact_backup->id.us++; - - } - /* end animdata uglyness */ - - /* ensures only a single output node is enabled */ - ntreeSetOutput(ltree); - - for(node= ntree->nodes.first; node; node= node->next) { - - /* store new_node pointer to original */ - node->new_node->new_node= node; - - if(ntree->type==NTREE_COMPOSIT) { - /* ensure new user input gets handled ok, only composites (texture nodes will break, for painting since it uses no tags) */ - node->need_exec= 0; - - /* move over the compbufs */ - /* right after ntreeCopyTree() oldsock pointers are valid */ - - if(ELEM(node->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER)) { - if(node->id) { - if(node->flag & NODE_DO_OUTPUT) - node->new_node->id= (ID *)copy_image((Image *)node->id); - else - node->new_node->id= NULL; - } - } - - for(sock= node->outputs.first; sock; sock= sock->next) { - - sock->new_sock->ns.data= sock->ns.data; - compbuf_set_node(sock->new_sock->ns.data, node->new_node); - - sock->ns.data= NULL; - sock->new_sock->new_sock= sock; - } - } - } - - return ltree; -} - -static int node_exists(bNodeTree *ntree, bNode *testnode) -{ - bNode *node= ntree->nodes.first; - for(; node; node= node->next) - if(node==testnode) - return 1; - return 0; -} - -static int outsocket_exists(bNode *node, bNodeSocket *testsock) -{ - bNodeSocket *sock= node->outputs.first; - for(; sock; sock= sock->next) - if(sock==testsock) + bNodeType *ntype= node_get_type(ntree, ntemp->type); + if (ntype) { + if (ntype->validfunc) + return ntype->validfunc(ntree, ntemp); + else return 1; - return 0; -} - - -/* sync local composite with real tree */ -/* local composite is supposed to be running, be careful moving previews! */ -/* is called by jobs manager, outside threads, so it doesnt happen during draw */ -void ntreeLocalSync(bNodeTree *localtree, bNodeTree *ntree) -{ - bNode *lnode; - - if(ntree->type==NTREE_COMPOSIT) { - /* move over the compbufs and previews */ - for(lnode= localtree->nodes.first; lnode; lnode= lnode->next) { - if( (lnode->exec & NODE_READY) && !(lnode->exec & NODE_SKIPPED) ) { - if(node_exists(ntree, lnode->new_node)) { - - if(lnode->preview && lnode->preview->rect) { - node_free_preview(lnode->new_node); - lnode->new_node->preview= lnode->preview; - lnode->preview= NULL; - } - } - } - } - } - else if(ELEM(ntree->type, NTREE_SHADER, NTREE_TEXTURE)) { - /* copy over contents of previews */ - for(lnode= localtree->nodes.first; lnode; lnode= lnode->next) { - if(node_exists(ntree, lnode->new_node)) { - bNode *node= lnode->new_node; - - if(node->preview && node->preview->rect) { - if(lnode->preview && lnode->preview->rect) { - int xsize= node->preview->xsize; - int ysize= node->preview->ysize; - memcpy(node->preview->rect, lnode->preview->rect, 4*xsize + xsize*ysize*sizeof(char)*4); - } - } - } - } } + else + return 0; } -/* merge local tree results back, and free local tree */ -/* we have to assume the editor already changed completely */ -void ntreeLocalMerge(bNodeTree *localtree, bNodeTree *ntree) +const char* nodeLabel(bNode *node) { - bNode *lnode; - bNodeSocket *lsock; - - /* move over the compbufs and previews */ - for(lnode= localtree->nodes.first; lnode; lnode= lnode->next) { - if(node_exists(ntree, lnode->new_node)) { - - if(lnode->preview && lnode->preview->rect) { - node_free_preview(lnode->new_node); - lnode->new_node->preview= lnode->preview; - lnode->preview= NULL; - } - - if(ELEM(lnode->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER)) { - if(lnode->id && (lnode->flag & NODE_DO_OUTPUT)) { - /* image_merge does sanity check for pointers */ - BKE_image_merge((Image *)lnode->new_node->id, (Image *)lnode->id); - } - } - - for(lsock= lnode->outputs.first; lsock; lsock= lsock->next) { - if(outsocket_exists(lnode->new_node, lsock->new_sock)) { - lsock->new_sock->ns.data= lsock->ns.data; - compbuf_set_node(lsock->new_sock->ns.data, lnode->new_node); - lsock->ns.data= NULL; - lsock->new_sock= NULL; - } - } - } - } - ntreeFreeTree(localtree); - MEM_freeN(localtree); + if (node->label[0]!='\0') + return node->label; + else if (node->typeinfo->labelfunc) + return node->typeinfo->labelfunc(node); + else + return node->typeinfo->name; } -/* *********************************************** */ - -/* GPU material from shader nodes */ - -static void gpu_from_node_stack(ListBase *sockets, bNodeStack **ns, GPUNodeStack *gs) +struct bNodeTree *nodeGroupEditGet(struct bNode *node) { - bNodeSocket *sock; - int i; - - for (sock=sockets->first, i=0; sock; sock=sock->next, i++) { - memset(&gs[i], 0, sizeof(gs[i])); - - QUATCOPY(gs[i].vec, ns[i]->vec); - gs[i].link= ns[i]->data; - - if (sock->type == SOCK_VALUE) - gs[i].type= GPU_FLOAT; - else if (sock->type == SOCK_VECTOR) - gs[i].type= GPU_VEC3; - else if (sock->type == SOCK_RGBA) - gs[i].type= GPU_VEC4; - else - gs[i].type= GPU_NONE; - - gs[i].name = ""; - gs[i].hasinput= ns[i]->hasinput && ns[i]->data; - gs[i].hasoutput= ns[i]->hasoutput && ns[i]->data; - gs[i].sockettype= ns[i]->sockettype; - } - - gs[i].type= GPU_NONE; + if (node->typeinfo->group_edit_get) + return node->typeinfo->group_edit_get(node); + else + return NULL; } -static void data_from_gpu_stack(ListBase *sockets, bNodeStack **ns, GPUNodeStack *gs) +struct bNodeTree *nodeGroupEditSet(struct bNode *node, int edit) { - bNodeSocket *sock; - int i; - - for (sock=sockets->first, i=0; sock; sock=sock->next, i++) { - ns[i]->data= gs[i].link; - ns[i]->sockettype= gs[i].sockettype; - } + if (node->typeinfo->group_edit_set) + return node->typeinfo->group_edit_set(node, edit); + else if (node->typeinfo->group_edit_get) + return node->typeinfo->group_edit_get(node); + else + return NULL; } -static void gpu_node_group_execute(bNodeStack *stack, GPUMaterial *mat, bNode *gnode, bNodeStack **in) +void nodeGroupEditClear(struct bNode *node) { - bNode *node; - bNodeTree *ntree= (bNodeTree *)gnode->id; - bNodeStack *nsin[MAX_SOCKET]; /* arbitrary... watch this */ - bNodeStack *nsout[MAX_SOCKET]; /* arbitrary... watch this */ - GPUNodeStack gpuin[MAX_SOCKET+1], gpuout[MAX_SOCKET+1]; - int doit = 0; - - if(ntree==NULL) return; - - stack+= gnode->stack_index; - - for(node= ntree->nodes.first; node; node= node->next) { - if(node->typeinfo->gpufunc) { - node_get_stack(node, stack, nsin, nsout, in); - - doit = 0; - - /* for groups, only execute outputs for edited group */ - if(node->typeinfo->nclass==NODE_CLASS_OUTPUT) { - if(gnode->flag & NODE_GROUP_EDIT) - if(node->flag & NODE_DO_OUTPUT) - doit = 1; - } - else - doit = 1; - - if(doit) { - gpu_from_node_stack(&node->inputs, nsin, gpuin); - gpu_from_node_stack(&node->outputs, nsout, gpuout); - if(node->typeinfo->gpufunc(mat, node, gpuin, gpuout)) - data_from_gpu_stack(&node->outputs, nsout, gpuout); - } - } - } + if (node->typeinfo->group_edit_clear) + node->typeinfo->group_edit_clear(node); } -void ntreeGPUMaterialNodes(bNodeTree *ntree, GPUMaterial *mat) +struct bNodeTemplate nodeMakeTemplate(struct bNode *node) { - bNode *node; - bNodeStack *stack; - bNodeStack *nsin[MAX_SOCKET]; /* arbitrary... watch this */ - bNodeStack *nsout[MAX_SOCKET]; /* arbitrary... watch this */ - GPUNodeStack gpuin[MAX_SOCKET+1], gpuout[MAX_SOCKET+1]; - - if((ntree->init & NTREE_EXEC_INIT)==0) - ntreeBeginExecTree(ntree); - - stack= ntree->stack; - - for(node= ntree->nodes.first; node; node= node->next) { - if(node->typeinfo->gpufunc) { - node_get_stack(node, stack, nsin, nsout, NULL); - gpu_from_node_stack(&node->inputs, nsin, gpuin); - gpu_from_node_stack(&node->outputs, nsout, gpuout); - if(node->typeinfo->gpufunc(mat, node, gpuin, gpuout)) - data_from_gpu_stack(&node->outputs, nsout, gpuout); - } - else if(node->type==NODE_GROUP && node->id) { - node_get_stack(node, stack, nsin, nsout, NULL); - gpu_node_group_execute(stack, mat, node, nsin); - } + bNodeTemplate ntemp; + if (node->typeinfo->templatefunc) + return node->typeinfo->templatefunc(node); + else { + ntemp.type = node->type; + return ntemp; } - - ntreeEndExecTree(ntree); } -/* **************** call to switch lamploop for material node ************ */ - -void (*node_shader_lamp_loop)(struct ShadeInput *, struct ShadeResult *); - -void set_node_shader_lamp_loop(void (*lamp_loop_func)(ShadeInput *, ShadeResult *)) -{ - node_shader_lamp_loop= lamp_loop_func; -} - -/* clumsy checking... should do dynamic outputs once */ -static void force_hidden_passes(bNode *node, int passflag) -{ - bNodeSocket *sock; - - for(sock= node->outputs.first; sock; sock= sock->next) - sock->flag &= ~SOCK_UNAVAIL; - - sock= BLI_findlink(&node->outputs, RRES_OUT_Z); - if(!(passflag & SCE_PASS_Z)) sock->flag |= SOCK_UNAVAIL; - sock= BLI_findlink(&node->outputs, RRES_OUT_NORMAL); - if(!(passflag & SCE_PASS_NORMAL)) sock->flag |= SOCK_UNAVAIL; - sock= BLI_findlink(&node->outputs, RRES_OUT_VEC); - if(!(passflag & SCE_PASS_VECTOR)) sock->flag |= SOCK_UNAVAIL; - sock= BLI_findlink(&node->outputs, RRES_OUT_UV); - if(!(passflag & SCE_PASS_UV)) sock->flag |= SOCK_UNAVAIL; - sock= BLI_findlink(&node->outputs, RRES_OUT_RGBA); - if(!(passflag & SCE_PASS_RGBA)) sock->flag |= SOCK_UNAVAIL; - sock= BLI_findlink(&node->outputs, RRES_OUT_DIFF); - if(!(passflag & SCE_PASS_DIFFUSE)) sock->flag |= SOCK_UNAVAIL; - sock= BLI_findlink(&node->outputs, RRES_OUT_SPEC); - if(!(passflag & SCE_PASS_SPEC)) sock->flag |= SOCK_UNAVAIL; - sock= BLI_findlink(&node->outputs, RRES_OUT_SHADOW); - if(!(passflag & SCE_PASS_SHADOW)) sock->flag |= SOCK_UNAVAIL; - sock= BLI_findlink(&node->outputs, RRES_OUT_AO); - if(!(passflag & SCE_PASS_AO)) sock->flag |= SOCK_UNAVAIL; - sock= BLI_findlink(&node->outputs, RRES_OUT_REFLECT); - if(!(passflag & SCE_PASS_REFLECT)) sock->flag |= SOCK_UNAVAIL; - sock= BLI_findlink(&node->outputs, RRES_OUT_REFRACT); - if(!(passflag & SCE_PASS_REFRACT)) sock->flag |= SOCK_UNAVAIL; - sock= BLI_findlink(&node->outputs, RRES_OUT_INDIRECT); - if(!(passflag & SCE_PASS_INDIRECT)) sock->flag |= SOCK_UNAVAIL; - sock= BLI_findlink(&node->outputs, RRES_OUT_INDEXOB); - if(!(passflag & SCE_PASS_INDEXOB)) sock->flag |= SOCK_UNAVAIL; - sock= BLI_findlink(&node->outputs, RRES_OUT_MIST); - if(!(passflag & SCE_PASS_MIST)) sock->flag |= SOCK_UNAVAIL; - sock= BLI_findlink(&node->outputs, RRES_OUT_EMIT); - if(!(passflag & SCE_PASS_EMIT)) sock->flag |= SOCK_UNAVAIL; - sock= BLI_findlink(&node->outputs, RRES_OUT_ENV); - if(!(passflag & SCE_PASS_ENVIRONMENT)) sock->flag |= SOCK_UNAVAIL; - -} - -/* based on rules, force sockets hidden always */ -void ntreeCompositForceHidden(bNodeTree *ntree, Scene *curscene) +void node_type_base(bNodeType *ntype, int type, const char *name, short nclass, short flag) { - bNode *node; + memset(ntype, 0, sizeof(bNodeType)); - if(ntree==NULL) return; + ntype->type = type; + BLI_strncpy(ntype->name, name, sizeof(ntype->name)); + ntype->nclass = nclass; + ntype->flag = flag; - for(node= ntree->nodes.first; node; node= node->next) { - if( node->type==CMP_NODE_R_LAYERS) { - Scene *sce= node->id?(Scene *)node->id:curscene; - SceneRenderLayer *srl= BLI_findlink(&sce->r.layers, node->custom1); - if(srl) - force_hidden_passes(node, srl->passflag); - } - else if( node->type==CMP_NODE_IMAGE) { - Image *ima= (Image *)node->id; - if(ima) { - if(ima->rr) { - ImageUser *iuser= node->storage; - RenderLayer *rl= BLI_findlink(&ima->rr->layers, iuser->layer); - if(rl) - force_hidden_passes(node, rl->passflag); - else - force_hidden_passes(node, 0); - } - else if(ima->type!=IMA_TYPE_MULTILAYER) { /* if ->rr not yet read we keep inputs */ - force_hidden_passes(node, RRES_OUT_Z); - } - else - force_hidden_passes(node, 0); - } - else - force_hidden_passes(node, 0); - } - } - + /* default size values */ + ntype->width = 140; + ntype->minwidth = 100; + ntype->maxwidth = 320; + ntype->height = 100; + ntype->minheight = 30; + ntype->maxheight = FLT_MAX; } -/* called from render pipeline, to tag render input and output */ -/* need to do all scenes, to prevent errors when you re-render 1 scene */ -void ntreeCompositTagRender(Scene *curscene) +void node_type_socket_templates(struct bNodeType *ntype, struct bNodeSocketTemplate *inputs, struct bNodeSocketTemplate *outputs) { - Scene *sce; - - for(sce= G.main->scene.first; sce; sce= sce->id.next) { - if(sce->nodetree) { - bNode *node; - - for(node= sce->nodetree->nodes.first; node; node= node->next) { - if(node->id==(ID *)curscene || node->type==CMP_NODE_COMPOSITE) - NodeTagChanged(sce->nodetree, node); - else if(node->type==CMP_NODE_TEXTURE) /* uses scene sizex/sizey */ - NodeTagChanged(sce->nodetree, node); - } - } - } + ntype->inputs = inputs; + ntype->outputs = outputs; } -static int node_animation_properties(bNodeTree *ntree, bNode *node) +void node_type_init(struct bNodeType *ntype, void (*initfunc)(struct bNodeTree *ntree, struct bNode *node, struct bNodeTemplate *ntemp)) { - bNodeSocket *sock; - const ListBase *lb; - Link *link; - PointerRNA ptr; - PropertyRNA *prop; - - /* check to see if any of the node's properties have fcurves */ - RNA_pointer_create((ID *)ntree, &RNA_Node, node, &ptr); - lb = RNA_struct_type_properties(ptr.type); - - for (link=lb->first; link; link=link->next) { - int driven, len=1, index; - prop = (PropertyRNA *)link; - - if (RNA_property_array_check(&ptr, prop)) - len = RNA_property_array_length(&ptr, prop); - - for (index=0; index<len; index++) { - if (rna_get_fcurve(&ptr, prop, index, NULL, &driven)) { - NodeTagChanged(ntree, node); - return 1; - } - } - } - - /* now check node sockets */ - for (sock = node->inputs.first; sock; sock=sock->next) { - int driven, len=1, index; - - RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, sock, &ptr); - prop = RNA_struct_find_property(&ptr, "default_value"); - - if (RNA_property_array_check(&ptr, prop)) - len = RNA_property_array_length(&ptr, prop); - - for (index=0; index<len; index++) { - if (rna_get_fcurve(&ptr, prop, index, NULL, &driven)) { - NodeTagChanged(ntree, node); - return 1; - } - } - } - - return 0; + ntype->initfunc = initfunc; } -/* tags nodes that have animation capabilities */ -int ntreeCompositTagAnimated(bNodeTree *ntree) +void node_type_valid(struct bNodeType *ntype, int (*validfunc)(struct bNodeTree *ntree, struct bNodeTemplate *ntemp)) { - bNode *node; - int tagged= 0; - - if(ntree==NULL) return 0; - - for(node= ntree->nodes.first; node; node= node->next) { - - tagged = node_animation_properties(ntree, node); - - /* otherwise always tag these node types */ - if(node->type==CMP_NODE_IMAGE) { - Image *ima= (Image *)node->id; - if(ima && ELEM(ima->source, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE)) { - NodeTagChanged(ntree, node); - tagged= 1; - } - } - else if(node->type==CMP_NODE_TIME) { - NodeTagChanged(ntree, node); - tagged= 1; - } - /* here was tag render layer, but this is called after a render, so re-composites fail */ - else if(node->type==NODE_GROUP) { - if( ntreeCompositTagAnimated((bNodeTree *)node->id) ) { - NodeTagChanged(ntree, node); - } - } - } - - return tagged; + ntype->validfunc = validfunc; } - -/* called from image window preview */ -void ntreeCompositTagGenerators(bNodeTree *ntree) +void node_type_size(struct bNodeType *ntype, int width, int minwidth, int maxwidth) { - bNode *node; - - if(ntree==NULL) return; - - for(node= ntree->nodes.first; node; node= node->next) { - if( ELEM(node->type, CMP_NODE_R_LAYERS, CMP_NODE_IMAGE)) - NodeTagChanged(ntree, node); - } + ntype->width = width; + ntype->minwidth = minwidth; + if (maxwidth <= minwidth) + ntype->maxwidth = FLT_MAX; + else + ntype->maxwidth = maxwidth; } -/* XXX after render animation system gets a refresh, this call allows composite to end clean */ -void ntreeClearTags(bNodeTree *ntree) +void node_type_storage(bNodeType *ntype, const char *storagename, void (*freestoragefunc)(struct bNode *), void (*copystoragefunc)(struct bNode *, struct bNode *)) { - bNode *node; - - if(ntree==NULL) return; - - for(node= ntree->nodes.first; node; node= node->next) { - node->need_exec= 0; - if(node->type==NODE_GROUP) - ntreeClearTags((bNodeTree *)node->id); - } + if (storagename) + strncpy(ntype->storagename, storagename, sizeof(ntype->storagename)); + else + ntype->storagename[0] = '\0'; + ntype->copystoragefunc = copystoragefunc; + ntype->freestoragefunc = freestoragefunc; } - -int ntreeTexTagAnimated(bNodeTree *ntree) +void node_type_label(struct bNodeType *ntype, const char *(*labelfunc)(struct bNode *)) { - bNode *node; - - if(ntree==NULL) return 0; - - for(node= ntree->nodes.first; node; node= node->next) { - if(node->type==TEX_NODE_CURVE_TIME) { - NodeTagChanged(ntree, node); - return 1; - } - else if(node->type==NODE_GROUP) { - if( ntreeTexTagAnimated((bNodeTree *)node->id) ) { - return 1; - } - } - } - - return 0; + ntype->labelfunc = labelfunc; } -/* ************* node definition init ********** */ - -void node_type_base(bNodeType *ntype, int type, const char *name, short nclass, short flag, - struct bNodeSocketType *inputs, struct bNodeSocketType *outputs) +void node_type_template(struct bNodeType *ntype, struct bNodeTemplate (*templatefunc)(struct bNode *)) { - memset(ntype, 0, sizeof(bNodeType)); - - ntype->type = type; - ntype->name = name; - ntype->nclass = nclass; - ntype->flag = flag; - - ntype->inputs = inputs; - ntype->outputs = outputs; - - /* default size values */ - ntype->width = 140; - ntype->minwidth = 100; - ntype->maxwidth = 320; + ntype->templatefunc = templatefunc; } -void node_type_init(bNodeType *ntype, void (*initfunc)(struct bNode *)) +void node_type_update(struct bNodeType *ntype, + void (*updatefunc)(struct bNodeTree *ntree, struct bNode *node), + void (*verifyfunc)(struct bNodeTree *ntree, struct bNode *node, struct ID *id)) { - ntype->initfunc = initfunc; + ntype->updatefunc = updatefunc; + ntype->verifyfunc = verifyfunc; } -void node_type_size(struct bNodeType *ntype, int width, int minwidth, int maxwidth) +void node_type_tree(struct bNodeType *ntype, void (*inittreefunc)(struct bNodeTree *), void (*updatetreefunc)(struct bNodeTree *)) { - ntype->width = width; - ntype->minwidth = minwidth; - ntype->maxwidth = maxwidth; + ntype->inittreefunc = inittreefunc; + ntype->updatetreefunc = updatetreefunc; } -void node_type_storage(bNodeType *ntype, const char *storagename, void (*freestoragefunc)(struct bNode *), void (*copystoragefunc)(struct bNode *, struct bNode *)) +void node_type_group_edit(struct bNodeType *ntype, + struct bNodeTree *(*group_edit_get)(struct bNode *node), + struct bNodeTree *(*group_edit_set)(struct bNode *node, int edit), + void (*group_edit_clear)(struct bNode *node)) { - if (storagename) - strncpy(ntype->storagename, storagename, sizeof(ntype->storagename)); - else - ntype->storagename[0] = '\0'; - ntype->copystoragefunc = copystoragefunc; - ntype->freestoragefunc = freestoragefunc; + ntype->group_edit_get = group_edit_get; + ntype->group_edit_set = group_edit_set; + ntype->group_edit_clear = group_edit_clear; } void node_type_exec(struct bNodeType *ntype, void (*execfunc)(void *data, struct bNode *, struct bNodeStack **, struct bNodeStack **)) @@ -3402,42 +1714,53 @@ void node_type_exec(struct bNodeType *ntype, void (*execfunc)(void *data, struct ntype->execfunc = execfunc; } +void node_type_exec_new(struct bNodeType *ntype, + void *(*initexecfunc)(struct bNode *node), + void (*freeexecfunc)(struct bNode *node, void *nodedata), + void (*newexecfunc)(void *data, int thread, struct bNode *, void *nodedata, struct bNodeStack **, struct bNodeStack **)) +{ + ntype->initexecfunc = initexecfunc; + ntype->freeexecfunc = freeexecfunc; + ntype->newexecfunc = newexecfunc; +} + void node_type_gpu(struct bNodeType *ntype, int (*gpufunc)(struct GPUMaterial *mat, struct bNode *node, struct GPUNodeStack *in, struct GPUNodeStack *out)) { ntype->gpufunc = gpufunc; } -void node_type_label(struct bNodeType *ntype, const char *(*labelfunc)(struct bNode *)) +void node_type_gpu_ext(struct bNodeType *ntype, int (*gpuextfunc)(struct GPUMaterial *mat, struct bNode *node, void *nodedata, struct GPUNodeStack *in, struct GPUNodeStack *out)) { - ntype->labelfunc = labelfunc; + ntype->gpuextfunc = gpuextfunc; } -static bNodeType *is_nodetype_registered(ListBase *typelist, int type, ID *id) + +static bNodeType *is_nodetype_registered(ListBase *typelist, int type) { bNodeType *ntype= typelist->first; for(;ntype; ntype= ntype->next ) - if(ntype->type==type && ntype->id==id) + if(ntype->type==type) return ntype; return NULL; } -/* type can be from a static array, we make copy for duplicate types (like group) */ -void nodeRegisterType(ListBase *typelist, const bNodeType *ntype) +void nodeRegisterType(ListBase *typelist, bNodeType *ntype) { - bNodeType *found= is_nodetype_registered(typelist, ntype->type, ntype->id); + bNodeType *found= is_nodetype_registered(typelist, ntype->type); - if(found==NULL) { - bNodeType *ntypen= MEM_callocN(sizeof(bNodeType), "node type"); - *ntypen= *ntype; - BLI_addtail(typelist, ntypen); - } + if(found==NULL) + BLI_addtail(typelist, ntype); } static void registerCompositNodes(ListBase *ntypelist) { - register_node_type_group(ntypelist); + register_node_type_frame(ntypelist); + + register_node_type_cmp_group(ntypelist); +// register_node_type_cmp_forloop(ntypelist); +// register_node_type_cmp_whileloop(ntypelist); register_node_type_cmp_rlayers(ntypelist); register_node_type_cmp_image(ntypelist); @@ -3513,7 +1836,11 @@ static void registerCompositNodes(ListBase *ntypelist) static void registerShaderNodes(ListBase *ntypelist) { - register_node_type_group(ntypelist); + register_node_type_frame(ntypelist); + + register_node_type_sh_group(ntypelist); +// register_node_type_sh_forloop(ntypelist); +// register_node_type_sh_whileloop(ntypelist); register_node_type_sh_output(ntypelist); register_node_type_sh_mix_rgb(ntypelist); @@ -3542,7 +1869,11 @@ static void registerShaderNodes(ListBase *ntypelist) static void registerTextureNodes(ListBase *ntypelist) { - register_node_type_group(ntypelist); + register_node_type_frame(ntypelist); + + register_node_type_tex_group(ntypelist); +// register_node_type_tex_forloop(ntypelist); +// register_node_type_tex_whileloop(ntypelist); register_node_type_tex_math(ntypelist); register_node_type_tex_mix_rgb(ntypelist); @@ -3583,53 +1914,47 @@ static void registerTextureNodes(ListBase *ntypelist) register_node_type_tex_proc_distnoise(ntypelist); } -static void remove_dynamic_typeinfos(ListBase *list) +static void free_dynamic_typeinfo(bNodeType *ntype) { - bNodeType *ntype= list->first; - bNodeType *next= NULL; - while(ntype) { - next= ntype->next; - if(ntype->type==NODE_DYNAMIC && ntype->id!=NULL) { - BLI_remlink(list, ntype); - if(ntype->inputs) { - bNodeSocketType *sock= ntype->inputs; - while(sock->type!=-1) { - MEM_freeN((void *)sock->name); - sock++; - } - MEM_freeN(ntype->inputs); - } - if(ntype->outputs) { - bNodeSocketType *sock= ntype->outputs; - while(sock->type!=-1) { - MEM_freeN((void *)sock->name); - sock++; - } - MEM_freeN(ntype->outputs); - } - if(ntype->name) { - MEM_freeN((void *)ntype->name); - } - MEM_freeN(ntype); + if(ntype->type==NODE_DYNAMIC) { + if(ntype->inputs) { + MEM_freeN(ntype->inputs); } - ntype= next; + if(ntype->outputs) { + MEM_freeN(ntype->outputs); + } + if(ntype->name) { + MEM_freeN((void *)ntype->name); + } + } +} + +static void free_typeinfos(ListBase *list) +{ + bNodeType *ntype, *next; + for(ntype=list->first; ntype; ntype=next) { + next = ntype->next; + + if(ntype->type==NODE_DYNAMIC) + free_dynamic_typeinfo(ntype); + + if(ntype->needs_free) + MEM_freeN(ntype); } } void init_nodesystem(void) { - registerCompositNodes(&node_all_composit); - registerShaderNodes(&node_all_shaders); - registerTextureNodes(&node_all_textures); + registerCompositNodes(&ntreeGetType(NTREE_COMPOSIT)->node_types); + registerShaderNodes(&ntreeGetType(NTREE_SHADER)->node_types); + registerTextureNodes(&ntreeGetType(NTREE_TEXTURE)->node_types); } void free_nodesystem(void) { - /*remove_dynamic_typeinfos(&node_all_composit);*/ /* unused for now */ - BLI_freelistN(&node_all_composit); - remove_dynamic_typeinfos(&node_all_shaders); - BLI_freelistN(&node_all_shaders); - BLI_freelistN(&node_all_textures); + free_typeinfos(&ntreeGetType(NTREE_COMPOSIT)->node_types); + free_typeinfos(&ntreeGetType(NTREE_SHADER)->node_types); + free_typeinfos(&ntreeGetType(NTREE_TEXTURE)->node_types); } /* called from unlink_scene, when deleting a scene goes over all scenes diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index 189f2735aa8..898cec7fa55 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -54,6 +54,7 @@ #include "DNA_scene_types.h" #include "DNA_screen_types.h" #include "DNA_sequence_types.h" +#include "DNA_sound_types.h" #include "DNA_space_types.h" #include "DNA_view3d_types.h" #include "DNA_world_types.h" @@ -96,6 +97,7 @@ #include "BKE_sca.h" #include "BKE_scene.h" #include "BKE_sequencer.h" +#include "BKE_speaker.h" #include "BKE_softbody.h" #include "BKE_material.h" @@ -989,6 +991,7 @@ static void *add_obdata_from_type(int type) case OB_LAMP: return add_lamp("Lamp"); case OB_LATTICE: return add_lattice("Lattice"); case OB_ARMATURE: return add_armature("Armature"); + case OB_SPEAKER: return add_speaker("Speaker"); case OB_EMPTY: return NULL; default: printf("add_obdata_from_type: Internal error, bad type: %d\n", type); @@ -1008,6 +1011,7 @@ static const char *get_obdata_defname(int type) case OB_LAMP: return "Lamp"; case OB_LATTICE: return "Lattice"; case OB_ARMATURE: return "Armature"; + case OB_SPEAKER: return "Speaker"; case OB_EMPTY: return "Empty"; default: printf("get_obdata_defname: Internal error, bad type: %d\n", type); @@ -1051,7 +1055,7 @@ Object *add_only_object(int type, const char *name) ob->empty_drawtype= OB_PLAINAXES; ob->empty_drawsize= 1.0; - if(type==OB_CAMERA || type==OB_LAMP) { + if(type==OB_CAMERA || type==OB_LAMP || type==OB_SPEAKER) { ob->trackflag= OB_NEGZ; ob->upflag= OB_POSY; } @@ -2085,7 +2089,7 @@ void where_is_object_time(Scene *scene, Object *ob, float ctime) if(ob==NULL) return; /* execute drivers only, as animation has already been done */ - BKE_animsys_evaluate_animdata(&ob->id, ob->adt, ctime, ADT_RECALC_DRIVERS); + BKE_animsys_evaluate_animdata(scene, &ob->id, ob->adt, ctime, ADT_RECALC_DRIVERS); if(ob->parent) { Object *par= ob->parent; @@ -2624,7 +2628,7 @@ void object_handle_update(Scene *scene, Object *ob) if(adt) { /* evaluate drivers */ // XXX: for mesh types, should we push this to derivedmesh instead? - BKE_animsys_evaluate_animdata(data_id, adt, ctime, ADT_RECALC_DRIVERS); + BKE_animsys_evaluate_animdata(scene, data_id, adt, ctime, ADT_RECALC_DRIVERS); } /* includes all keys and modifiers */ @@ -2642,11 +2646,12 @@ void object_handle_update(Scene *scene, Object *ob) #else /* ensure CD_MASK_BAREMESH for now */ EditMesh *em = (ob == scene->obedit)? BKE_mesh_get_editmesh(ob->data): NULL; + unsigned int data_mask= scene->customdata_mask | ob->customdata_mask | CD_MASK_BAREMESH; if(em) { - makeDerivedMesh(scene, ob, em, scene->customdata_mask | CD_MASK_BAREMESH); /* was CD_MASK_BAREMESH */ + makeDerivedMesh(scene, ob, em, data_mask); /* was CD_MASK_BAREMESH */ BKE_mesh_end_editmesh(ob->data, em); } else - makeDerivedMesh(scene, ob, NULL, scene->customdata_mask | CD_MASK_BAREMESH); + makeDerivedMesh(scene, ob, NULL, data_mask); #endif } @@ -3134,7 +3139,7 @@ int object_is_modified(Scene *scene, Object *ob) int flag= 0; if(ob_get_key(ob)) { - flag |= eModifierMode_Render | eModifierMode_Render; + flag |= eModifierMode_Render; } else { ModifierData *md; diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c index 5be492d1108..d00eb6192da 100644 --- a/source/blender/blenkernel/intern/paint.c +++ b/source/blender/blenkernel/intern/paint.c @@ -85,8 +85,11 @@ Brush *paint_brush(Paint *p) void paint_brush_set(Paint *p, Brush *br) { - if(p) + if(p) { + id_us_min((ID *)p->brush); + id_us_plus((ID *)br); p->brush= br; + } } int paint_facesel_test(Object *ob) @@ -110,12 +113,17 @@ void paint_init(Paint *p, const char col[3]) p->flags |= PAINT_SHOW_BRUSH; } -void free_paint(Paint *UNUSED(paint)) +void free_paint(Paint *paint) { - /* nothing */ + id_us_min((ID *)paint->brush); } +/* called when copying scene settings, so even if 'src' and 'tar' are the same + * still do a id_us_plus(), rather then if we were copying betweem 2 existing + * scenes where a matching value should decrease the existing user count as + * with paint_brush_set() */ void copy_paint(Paint *src, Paint *tar) { tar->brush= src->brush; + id_us_plus((ID *)tar->brush); } diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c index f71e2e9a6e9..86c646fa257 100644 --- a/source/blender/blenkernel/intern/particle.c +++ b/source/blender/blenkernel/intern/particle.c @@ -2889,8 +2889,6 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra) if(psys_in_edit_mode(sim->scene, psys)) if(psys->renderdata==0 && (psys->edit==NULL || pset->flag & PE_DRAW_PART)==0) return; - - BLI_srandom(psys->seed); keyed = psys->flag & PSYS_KEYED; baked = psys->pointcache->mem_cache.first && psys->part->type != PART_HAIR; @@ -3163,7 +3161,7 @@ void psys_cache_edit_paths(Scene *scene, Object *ob, PTCacheEdit *edit, float cf } else { ca->vel[0] = ca->vel[1] = 0.0f; - ca->vel[1] = 1.0f; + ca->vel[2] = 1.0f; } /* selection coloring in edit mode */ @@ -3534,6 +3532,8 @@ static void default_particle_settings(ParticleSettings *part) part->path_start = 0.0f; part->path_end = 1.0f; + part->bb_size[0] = part->bb_size[1] = 1.0f; + part->keyed_loops = 1; part->color_vec_max = 1.f; @@ -4372,58 +4372,46 @@ void psys_get_dupli_path_transform(ParticleSimulationData *sim, ParticleData *pa Object *ob = sim->ob; ParticleSystem *psys = sim->psys; ParticleSystemModifierData *psmd = sim->psmd; - float loc[3], nor[3], vec[3], side[3], len, obrotmat[4][4], qmat[4][4]; - float xvec[3] = {-1.0, 0.0, 0.0}, q[4], nmat[3][3]; + float loc[3], nor[3], vec[3], side[3], len; + float xvec[3] = {-1.0, 0.0, 0.0}, nmat[3][3]; sub_v3_v3v3(vec, (cache+cache->steps)->co, cache->co); len= normalize_v3(vec); - if(psys->part->rotmode) { - if(pa == NULL) - pa= psys->particles+cpa->pa[0]; + if(pa == NULL && psys->part->childflat != PART_CHILD_FACES) + pa = psys->particles + cpa->pa[0]; - vec_to_quat( q,xvec, ob->trackflag, ob->upflag); - quat_to_mat4( obrotmat,q); - obrotmat[3][3]= 1.0f; - - quat_to_mat4( qmat,pa->state.rot); - mul_m4_m4m4(mat, obrotmat, qmat); - } - else { - if(pa == NULL && psys->part->childflat != PART_CHILD_FACES) - pa = psys->particles + cpa->pa[0]; - - if(pa) - psys_particle_on_emitter(psmd,sim->psys->part->from,pa->num,pa->num_dmcache,pa->fuv,pa->foffset,loc,nor,0,0,0,0); - else - psys_particle_on_emitter(psmd,PART_FROM_FACE,cpa->num,DMCACHE_ISCHILD,cpa->fuv,cpa->foffset,loc,nor,0,0,0,0); + if(pa) + psys_particle_on_emitter(psmd,sim->psys->part->from,pa->num,pa->num_dmcache,pa->fuv,pa->foffset,loc,nor,0,0,0,0); + else + psys_particle_on_emitter(psmd,PART_FROM_FACE,cpa->num,DMCACHE_ISCHILD,cpa->fuv,cpa->foffset,loc,nor,0,0,0,0); - copy_m3_m4(nmat, ob->imat); - transpose_m3(nmat); - mul_m3_v3(nmat, nor); - - /* make sure that we get a proper side vector */ - if(fabs(dot_v3v3(nor,vec))>0.999999) { - if(fabs(dot_v3v3(nor,xvec))>0.999999) { - nor[0] = 0.0f; - nor[1] = 1.0f; - nor[2] = 0.0f; - } - else { - nor[0] = 1.0f; - nor[1] = 0.0f; - nor[2] = 0.0f; - } + copy_m3_m4(nmat, ob->imat); + transpose_m3(nmat); + mul_m3_v3(nmat, nor); + normalize_v3(nor); + + /* make sure that we get a proper side vector */ + if(fabs(dot_v3v3(nor,vec))>0.999999) { + if(fabs(dot_v3v3(nor,xvec))>0.999999) { + nor[0] = 0.0f; + nor[1] = 1.0f; + nor[2] = 0.0f; + } + else { + nor[0] = 1.0f; + nor[1] = 0.0f; + nor[2] = 0.0f; } - cross_v3_v3v3(side, nor, vec); - normalize_v3(side); - cross_v3_v3v3(nor, vec, side); - - unit_m4(mat); - VECCOPY(mat[0], vec); - VECCOPY(mat[1], side); - VECCOPY(mat[2], nor); } + cross_v3_v3v3(side, nor, vec); + normalize_v3(side); + cross_v3_v3v3(nor, vec, side); + + unit_m4(mat); + VECCOPY(mat[0], vec); + VECCOPY(mat[1], side); + VECCOPY(mat[2], nor); *scale= len; } @@ -4505,8 +4493,8 @@ void psys_make_billboard(ParticleBillboardData *bb, float xvec[3], float yvec[3] mul_v3_fl(tvec, -sin(bb->tilt * (float)M_PI)); VECADD(yvec, yvec, tvec); - mul_v3_fl(xvec, bb->size); - mul_v3_fl(yvec, bb->size); + mul_v3_fl(xvec, bb->size[0]); + mul_v3_fl(yvec, bb->size[1]); VECADDFAC(center, bb->vec, xvec, bb->offset[0]); VECADDFAC(center, center, yvec, bb->offset[1]); diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c index fca8d470dc1..e1ea6e419d3 100644 --- a/source/blender/blenkernel/intern/particle_system.c +++ b/source/blender/blenkernel/intern/particle_system.c @@ -69,6 +69,7 @@ #include "BLI_listbase.h" #include "BLI_threads.h" #include "BLI_storage.h" /* For _LARGEFILE64_SOURCE; zlib needs this on some systems */ +#include "BLI_string.h" #include "BLI_utildefines.h" #include "BKE_main.h" @@ -104,12 +105,6 @@ #include <zlib.h> #include <string.h> -#ifdef WIN32 -#ifndef snprintf -#define snprintf _snprintf -#endif -#endif - #endif // DISABLE_ELBEEM /************************************************/ @@ -1562,8 +1557,7 @@ static void initialize_all_particles(ParticleSimulationData *sim) } } } -/* sets particle to the emitter surface with initial velocity & rotation */ -void reset_particle(ParticleSimulationData *sim, ParticleData *pa, float dtime, float cfra) +void psys_get_birth_coordinates(ParticleSimulationData *sim, ParticleData *pa, ParticleKey *state, float dtime, float cfra) { Object *ob = sim->ob; ParticleSystem *psys = sim->psys; @@ -1575,17 +1569,6 @@ void reset_particle(ParticleSimulationData *sim, ParticleData *pa, float dtime, float q_phase[4]; int p = pa - psys->particles; part=psys->part; - - /* get precise emitter matrix if particle is born */ - if(part->type!=PART_HAIR && dtime > 0.f && pa->time < cfra && pa->time >= sim->psys->cfra) { - /* we have to force RECALC_ANIM here since where_is_objec_time only does drivers */ - while(ob) { - BKE_animsys_evaluate_animdata(&ob->id, ob->adt, pa->time, ADT_RECALC_ANIM); - ob = ob->parent; - } - ob = sim->ob; - where_is_object_time(sim->scene, ob, pa->time); - } /* get birth location from object */ if(part->tanfac != 0.f) @@ -1594,7 +1577,7 @@ void reset_particle(ParticleSimulationData *sim, ParticleData *pa, float dtime, psys_particle_on_emitter(sim->psmd, part->from,pa->num, pa->num_dmcache, pa->fuv,pa->foffset,loc,nor,0,0,0,0); /* get possible textural influence */ - psys_get_texture(sim, pa, &ptex, PAMAP_IVEL|PAMAP_LIFE, cfra); + psys_get_texture(sim, pa, &ptex, PAMAP_IVEL, cfra); /* particles live in global space so */ /* let's convert: */ @@ -1654,37 +1637,27 @@ void reset_particle(ParticleSimulationData *sim, ParticleData *pa, float dtime, mat4_to_quat(rot,ob->obmat); mul_qt_qtqt(r_rot,r_rot,rot); } -#if 0 - } -#endif if(part->phystype==PART_PHYS_BOIDS && pa->boid) { - BoidParticle *bpa = pa->boid; float dvec[3], q[4], mat[3][3]; - copy_v3_v3(pa->state.co,loc); + copy_v3_v3(state->co,loc); /* boids don't get any initial velocity */ - zero_v3(pa->state.vel); + zero_v3(state->vel); /* boids store direction in ave */ if(fabsf(nor[2])==1.0f) { - sub_v3_v3v3(pa->state.ave, loc, ob->obmat[3]); - normalize_v3(pa->state.ave); + sub_v3_v3v3(state->ave, loc, ob->obmat[3]); + normalize_v3(state->ave); } else { - VECCOPY(pa->state.ave, nor); + VECCOPY(state->ave, nor); } - /* and gravity in r_ve */ - bpa->gravity[0] = bpa->gravity[1] = 0.0f; - bpa->gravity[2] = -1.0f; - if((sim->scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY) - && sim->scene->physics_settings.gravity[2]!=0.0f) - bpa->gravity[2] = sim->scene->physics_settings.gravity[2]; /* calculate rotation matrix */ - project_v3_v3v3(dvec, r_vel, pa->state.ave); - sub_v3_v3v3(mat[0], pa->state.ave, dvec); + project_v3_v3v3(dvec, r_vel, state->ave); + sub_v3_v3v3(mat[0], state->ave, dvec); normalize_v3(mat[0]); negate_v3_v3(mat[2], r_vel); normalize_v3(mat[2]); @@ -1692,12 +1665,7 @@ void reset_particle(ParticleSimulationData *sim, ParticleData *pa, float dtime, /* apply rotation */ mat3_to_quat_is_ok( q,mat); - copy_qt_qt(pa->state.rot, q); - - bpa->data.health = part->boids->health; - bpa->data.mode = eBoidMode_InAir; - bpa->data.state_id = ((BoidState*)part->boids->states.first)->id; - bpa->data.acc[0]=bpa->data.acc[1]=bpa->data.acc[2]=0.0f; + copy_qt_qt(state->rot, q); } else { /* conversion done so now we apply new: */ @@ -1710,7 +1678,7 @@ void reset_particle(ParticleSimulationData *sim, ParticleData *pa, float dtime, /* *emitter velocity */ if(dtime != 0.f && part->obfac != 0.f){ - sub_v3_v3v3(vel, loc, pa->state.co); + sub_v3_v3v3(vel, loc, state->co); mul_v3_fl(vel, part->obfac/dtime); } @@ -1747,13 +1715,13 @@ void reset_particle(ParticleSimulationData *sim, ParticleData *pa, float dtime, if(part->partfac != 0.f) madd_v3_v3fl(vel, p_vel, part->partfac); - mul_v3_v3fl(pa->state.vel, vel, ptex.ivel); + mul_v3_v3fl(state->vel, vel, ptex.ivel); /* -location from emitter */ - copy_v3_v3(pa->state.co,loc); + copy_v3_v3(state->co,loc); /* -rotation */ - unit_qt(pa->state.rot); + unit_qt(state->rot); if(part->rotmode){ /* create vector into which rotation is aligned */ @@ -1793,32 +1761,74 @@ void reset_particle(ParticleSimulationData *sim, ParticleData *pa, float dtime, axis_angle_to_quat( q_phase,x_vec, phasefac*(float)M_PI); /* combine base rotation & phase */ - mul_qt_qtqt(pa->state.rot, rot, q_phase); + mul_qt_qtqt(state->rot, rot, q_phase); } /* -angular velocity */ - zero_v3(pa->state.ave); + zero_v3(state->ave); if(part->avemode){ switch(part->avemode){ case PART_AVE_SPIN: - copy_v3_v3(pa->state.ave, vel); + copy_v3_v3(state->ave, vel); break; case PART_AVE_RAND: - copy_v3_v3(pa->state.ave, r_ave); + copy_v3_v3(state->ave, r_ave); break; } - normalize_v3(pa->state.ave); - mul_v3_fl(pa->state.ave,part->avefac); + normalize_v3(state->ave); + mul_v3_fl(state->ave, part->avefac); } } +} +/* sets particle to the emitter surface with initial velocity & rotation */ +void reset_particle(ParticleSimulationData *sim, ParticleData *pa, float dtime, float cfra) +{ + Object *ob = sim->ob; + ParticleSystem *psys = sim->psys; + ParticleSettings *part; + ParticleTexture ptex; + int p = pa - psys->particles; + part=psys->part; + + /* get precise emitter matrix if particle is born */ + if(part->type!=PART_HAIR && dtime > 0.f && pa->time < cfra && pa->time >= sim->psys->cfra) { + /* we have to force RECALC_ANIM here since where_is_objec_time only does drivers */ + while(ob) { + BKE_animsys_evaluate_animdata(sim->scene, &ob->id, ob->adt, pa->time, ADT_RECALC_ANIM); + ob = ob->parent; + } + ob = sim->ob; + where_is_object_time(sim->scene, ob, pa->time); + } + + psys_get_birth_coordinates(sim, pa, &pa->state, dtime, cfra); + + if(part->phystype==PART_PHYS_BOIDS && pa->boid) { + BoidParticle *bpa = pa->boid; + + /* and gravity in r_ve */ + bpa->gravity[0] = bpa->gravity[1] = 0.0f; + bpa->gravity[2] = -1.0f; + if((sim->scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY) + && sim->scene->physics_settings.gravity[2]!=0.0f) + bpa->gravity[2] = sim->scene->physics_settings.gravity[2]; + + bpa->data.health = part->boids->health; + bpa->data.mode = eBoidMode_InAir; + bpa->data.state_id = ((BoidState*)part->boids->states.first)->id; + bpa->data.acc[0]=bpa->data.acc[1]=bpa->data.acc[2]=0.0f; + } if(part->type == PART_HAIR){ pa->lifetime = 100.0f; } else{ + /* get possible textural influence */ + psys_get_texture(sim, pa, &ptex, PAMAP_LIFE, cfra); + pa->lifetime = part->lifetime * ptex.life; if(part->randlife != 0.0f) @@ -1904,6 +1914,7 @@ static void set_keyed_keys(ParticleSimulationData *sim) PARTICLE_P; ParticleKey *key; int totpart = psys->totpart, k, totkeys = psys->totkeyed; + int keyed_flag = 0; ksim.scene= sim->scene; @@ -1933,6 +1944,8 @@ static void set_keyed_keys(ParticleSimulationData *sim) for(k=0; k<totkeys; k++) { ksim.ob = pt->ob ? pt->ob : sim->ob; ksim.psys = BLI_findlink(&ksim.ob->particlesystem, pt->psys - 1); + keyed_flag = (ksim.psys->flag & PSYS_KEYED); + ksim.psys->flag &= ~PSYS_KEYED; LOOP_PARTICLES { key = pa->keys + k; @@ -1956,6 +1969,8 @@ static void set_keyed_keys(ParticleSimulationData *sim) if(psys->flag & PSYS_KEYED_TIMING && pt->duration!=0.0f) k++; + ksim.psys->flag |= keyed_flag; + pt = (pt->next && pt->next->flag & PTARGET_VALID)? pt->next : psys->targets.first; } @@ -3490,13 +3505,15 @@ static void do_hair_dynamics(ParticleSimulationData *sim) static void hair_step(ParticleSimulationData *sim, float cfra) { ParticleSystem *psys = sim->psys; -/* ParticleSettings *part = psys->part; */ + ParticleSettings *part = psys->part; PARTICLE_P; float disp = (float)psys_get_current_display_percentage(psys)/100.0f; - BLI_srandom(psys->seed); - LOOP_PARTICLES { + pa->size = part->size; + if(part->randsize > 0.0f) + pa->size *= 1.0f - part->randsize * PSYS_FRAND(p + 1); + if(PSYS_FRAND(p) > disp) pa->flag |= PARS_NO_DISP; else @@ -3650,7 +3667,7 @@ static void dynamics_step(ParticleSimulationData *sim, float cfra) pa->size *= 1.0f - part->randsize * PSYS_FRAND(p + 1); birthtime = pa->time; - dietime = birthtime + pa->lifetime; + dietime = pa->dietime; /* store this, so we can do multiple loops over particles */ pa->state.time = dfra; @@ -3781,8 +3798,6 @@ static void cached_step(ParticleSimulationData *sim, float cfra) PARTICLE_P; float disp, dietime; - BLI_srandom(psys->seed); - psys_update_effectors(sim); disp= (float)psys_get_current_display_percentage(psys)/100.0f; @@ -3856,7 +3871,7 @@ static void particles_fluid_step(ParticleSimulationData *sim, int UNUSED(cfra)) gzf = gzopen(filename, "rb"); if (!gzf) { - snprintf(debugStrBuffer,256,"readFsPartData::error - Unable to open file for reading '%s' \n", filename); + BLI_snprintf(debugStrBuffer, sizeof(debugStrBuffer),"readFsPartData::error - Unable to open file for reading '%s' \n", filename); // XXX bad level call elbeemDebugOut(debugStrBuffer); return; } @@ -3917,7 +3932,7 @@ static void particles_fluid_step(ParticleSimulationData *sim, int UNUSED(cfra)) gzclose( gzf ); totpart = psys->totpart = activeParts; - snprintf(debugStrBuffer,256,"readFsPartData::done - particles:%d, active:%d, file:%d, mask:%d \n", psys->totpart,activeParts,fileParts,readMask); + BLI_snprintf(debugStrBuffer,sizeof(debugStrBuffer),"readFsPartData::done - particles:%d, active:%d, file:%d, mask:%d \n", psys->totpart,activeParts,fileParts,readMask); // bad level call // XXX elbeemDebugOut(debugStrBuffer); @@ -3967,7 +3982,7 @@ static void system_step(ParticleSimulationData *sim, float cfra) BKE_ptcache_id_time(pid, sim->scene, 0.0f, &startframe, &endframe, NULL); /* clear everythin on start frame */ - if((int)cfra == startframe) { + if(cfra == startframe) { BKE_ptcache_id_reset(sim->scene, pid, PTCACHE_RESET_OUTDATED); BKE_ptcache_validate(cache, startframe); cache->flag &= ~PTCACHE_REDO_NEEDED; @@ -4034,7 +4049,6 @@ static void system_step(ParticleSimulationData *sim, float cfra) /* set particles to be not calculated TODO: can't work with pointcache */ disp= (float)psys_get_current_display_percentage(psys)/100.0f; - BLI_srandom(psys->seed); LOOP_PARTICLES { if(PSYS_FRAND(p) > disp) pa->flag |= PARS_NO_DISP; @@ -4234,7 +4248,7 @@ void particle_system_update(Scene *scene, Object *ob, ParticleSystem *psys) return; /* execute drivers only, as animation has already been done */ - BKE_animsys_evaluate_animdata(&part->id, part->adt, cfra, ADT_RECALC_DRIVERS); + BKE_animsys_evaluate_animdata(scene, &part->id, part->adt, cfra, ADT_RECALC_DRIVERS); if(psys->recalc & PSYS_RECALC_TYPE) psys_changed_type(&sim); @@ -4272,7 +4286,7 @@ void particle_system_update(Scene *scene, Object *ob, ParticleSystem *psys) for(i=0; i<=part->hair_step; i++){ hcfra=100.0f*(float)i/(float)psys->part->hair_step; if((part->flag & PART_HAIR_REGROW)==0) - BKE_animsys_evaluate_animdata(&part->id, part->adt, hcfra, ADT_RECALC_ANIM); + BKE_animsys_evaluate_animdata(scene, &part->id, part->adt, hcfra, ADT_RECALC_ANIM); system_step(&sim, hcfra); psys->cfra = hcfra; psys->recalc = 0; @@ -4350,7 +4364,7 @@ void particle_system_update(Scene *scene, Object *ob, ParticleSystem *psys) if(psys->cfra < cfra) { /* make sure emitter is left at correct time (particle emission can change this) */ while(ob) { - BKE_animsys_evaluate_animdata(&ob->id, ob->adt, cfra, ADT_RECALC_ANIM); + BKE_animsys_evaluate_animdata(scene, &ob->id, ob->adt, cfra, ADT_RECALC_ANIM); ob = ob->parent; } ob = sim.ob; diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c index 64893bb0b5b..a56010a5ccf 100644 --- a/source/blender/blenkernel/intern/pointcache.c +++ b/source/blender/blenkernel/intern/pointcache.c @@ -516,6 +516,7 @@ static int ptcache_cloth_totpoint(void *cloth_v, int UNUSED(cfra)) return clmd->clothObject ? clmd->clothObject->numverts : 0; } +#ifdef WITH_SMOKE /* Smoke functions */ static int ptcache_smoke_totpoint(void *smoke_v, int UNUSED(cfra)) { @@ -652,6 +653,11 @@ static void ptcache_smoke_read(PTCacheFile *pf, void *smoke_v) } } } +#else // WITH_SMOKE +static int ptcache_smoke_totpoint(void *UNUSED(smoke_v), int UNUSED(cfra)) { return 0; }; +static void ptcache_smoke_read(PTCacheFile *UNUSED(pf), void *UNUSED(smoke_v)) {} +static int ptcache_smoke_write(PTCacheFile *UNUSED(pf), void *UNUSED(smoke_v)) { return 0; } +#endif // WITH_SMOKE /* Creating ID's */ void BKE_ptcache_id_from_softbody(PTCacheID *pid, Object *ob, SoftBody *sb) @@ -911,14 +917,14 @@ static int ptcache_path(PTCacheID *pid, char *filename) if (i > 6) file[i-6] = '\0'; - snprintf(filename, MAX_PTCACHE_PATH, "//"PTCACHE_PATH"%s", file); /* add blend file name to pointcache dir */ + BLI_snprintf(filename, MAX_PTCACHE_PATH, "//"PTCACHE_PATH"%s", file); /* add blend file name to pointcache dir */ BLI_path_abs(filename, blendfilename); return BLI_add_slash(filename); /* new strlen() */ } /* use the temp path. this is weak but better then not using point cache at all */ /* btempdir is assumed to exist and ALWAYS has a trailing slash */ - snprintf(filename, MAX_PTCACHE_PATH, "%s"PTCACHE_PATH"%d", btempdir, abs(getpid())); + BLI_snprintf(filename, MAX_PTCACHE_PATH, "%s"PTCACHE_PATH"%d", btempdir, abs(getpid())); return BLI_add_slash(filename); /* new strlen() */ } @@ -942,7 +948,7 @@ static int ptcache_filename(PTCacheID *pid, char *filename, int cfra, short do_p idname = (pid->ob->id.name+2); /* convert chars to hex so they are always a valid filename */ while('\0' != *idname) { - snprintf(newname, MAX_PTCACHE_FILE, "%02X", (char)(*idname++)); + BLI_snprintf(newname, MAX_PTCACHE_FILE, "%02X", (char)(*idname++)); newname+=2; len += 2; } @@ -961,12 +967,12 @@ static int ptcache_filename(PTCacheID *pid, char *filename, int cfra, short do_p if(pid->cache->flag & PTCACHE_EXTERNAL) { if(pid->cache->index >= 0) - snprintf(newname, MAX_PTCACHE_FILE, "_%06d_%02d"PTCACHE_EXT, cfra, pid->stack_index); /* always 6 chars */ + BLI_snprintf(newname, MAX_PTCACHE_FILE, "_%06d_%02u"PTCACHE_EXT, cfra, pid->stack_index); /* always 6 chars */ else - snprintf(newname, MAX_PTCACHE_FILE, "_%06d"PTCACHE_EXT, cfra); /* always 6 chars */ + BLI_snprintf(newname, MAX_PTCACHE_FILE, "_%06d"PTCACHE_EXT, cfra); /* always 6 chars */ } else { - snprintf(newname, MAX_PTCACHE_FILE, "_%06d_%02d"PTCACHE_EXT, cfra, pid->stack_index); /* always 6 chars */ + BLI_snprintf(newname, MAX_PTCACHE_FILE, "_%06d_%02u"PTCACHE_EXT, cfra, pid->stack_index); /* always 6 chars */ } len += 16; } @@ -1996,7 +2002,7 @@ void BKE_ptcache_id_clear(PTCacheID *pid, int mode, unsigned int cfra) if (dir==NULL) return; - snprintf(ext, sizeof(ext), "_%02d"PTCACHE_EXT, pid->stack_index); + BLI_snprintf(ext, sizeof(ext), "_%02u"PTCACHE_EXT, pid->stack_index); while ((de = readdir(dir)) != NULL) { if (strstr(de->d_name, ext)) { /* do we have the right extension?*/ @@ -2124,7 +2130,8 @@ void BKE_ptcache_id_time(PTCacheID *pid, Scene *scene, float cfra, int *startfra { Object *ob; PointCache *cache; - float offset, time, nexttime; + /* float offset; unused for now */ + float time, nexttime; /* TODO: this has to be sorter out once bsystem_time gets redone, */ /* now caches can handle interpolating etc. too - jahka */ @@ -2152,13 +2159,18 @@ void BKE_ptcache_id_time(PTCacheID *pid, Scene *scene, float cfra, int *startfra *startframe= cache->startframe; *endframe= cache->endframe; - // XXX ipoflag is depreceated - old animation system stuff - if (/*(ob->ipoflag & OB_OFFS_PARENT) &&*/ (ob->partype & PARSLOW)==0) { + /* TODO: time handling with object offsets and simulated vs. cached + * particles isn't particularly easy, so for now what you see is what + * you get. In the future point cache could handle the whole particle + * system timing. */ +#if 0 + if ((ob->partype & PARSLOW)==0) { offset= give_timeoffset(ob); *startframe += (int)(offset+0.5f); *endframe += (int)(offset+0.5f); } +#endif } /* verify cached_frames array is up to date */ @@ -2192,7 +2204,7 @@ void BKE_ptcache_id_time(PTCacheID *pid, Scene *scene, float cfra, int *startfra if (dir==NULL) return; - snprintf(ext, sizeof(ext), "_%02d"PTCACHE_EXT, pid->stack_index); + BLI_snprintf(ext, sizeof(ext), "_%02u"PTCACHE_EXT, pid->stack_index); while ((de = readdir(dir)) != NULL) { if (strstr(de->d_name, ext)) { /* do we have the right extension?*/ @@ -2892,7 +2904,7 @@ void BKE_ptcache_disk_cache_rename(PTCacheID *pid, char *from, char *to) return; } - snprintf(ext, sizeof(ext), "_%02d"PTCACHE_EXT, pid->stack_index); + BLI_snprintf(ext, sizeof(ext), "_%02u"PTCACHE_EXT, pid->stack_index); /* put new name into cache */ strcpy(pid->cache->name, to); @@ -2948,7 +2960,7 @@ void BKE_ptcache_load_external(PTCacheID *pid) return; if(cache->index >= 0) - snprintf(ext, sizeof(ext), "_%02d"PTCACHE_EXT, cache->index); + BLI_snprintf(ext, sizeof(ext), "_%02d"PTCACHE_EXT, cache->index); else strcpy(ext, PTCACHE_EXT); diff --git a/source/blender/blenkernel/intern/report.c b/source/blender/blenkernel/intern/report.c index f84d98a31b4..4926edaeec2 100644 --- a/source/blender/blenkernel/intern/report.c +++ b/source/blender/blenkernel/intern/report.c @@ -44,12 +44,6 @@ #include <stdio.h> #include <string.h> -#ifdef _WIN32 -#ifndef vsnprintf -#define vsnprintf _vsnprintf -#endif -#endif - static const char *report_type_str(int type) { switch(type) { diff --git a/source/blender/blenkernel/intern/sca.c b/source/blender/blenkernel/intern/sca.c index ee410e75873..d529a6d94c9 100644 --- a/source/blender/blenkernel/intern/sca.c +++ b/source/blender/blenkernel/intern/sca.c @@ -431,6 +431,7 @@ void init_actuator(bActuator *act) act->data= MEM_callocN(sizeof(bCameraActuator), "camact"); ca = act->data; ca->axis = ACT_CAMERA_X; + ca->damping = 1.0/32.0; break; case ACT_EDIT_OBJECT: act->data= MEM_callocN(sizeof(bEditObjectActuator), "editobact"); diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c index 31d7d8fe08e..1454b3f0ce3 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -469,15 +469,16 @@ Scene *add_scene(const char *name) sce->r.ffcodecdata.audio_mixrate = 44100; sce->r.ffcodecdata.audio_volume = 1.0f; sce->r.ffcodecdata.audio_bitrate = 192; + sce->r.ffcodecdata.audio_channels = 2; BLI_strncpy(sce->r.engine, "BLENDER_RENDER", sizeof(sce->r.engine)); - sce->audio.distance_model = 2.0; - sce->audio.doppler_factor = 1.0; - sce->audio.speed_of_sound = 343.3; + sce->audio.distance_model = 2.0f; + sce->audio.doppler_factor = 1.0f; + sce->audio.speed_of_sound = 343.3f; + sce->audio.volume = 1.0f; - strcpy(sce->r.backbuf, "//backbuf"); - strcpy(sce->r.pic, U.renderdir); + BLI_strncpy(sce->r.pic, U.renderdir, sizeof(sce->r.pic)); BLI_init_rctf(&sce->r.safety, 0.1f, 0.9f, 0.1f, 0.9f); sce->r.osa= 8; @@ -932,7 +933,7 @@ static void scene_update_drivers(Main *UNUSED(bmain), Scene *scene) /* scene itself */ if (scene->adt && scene->adt->drivers.first) { - BKE_animsys_evaluate_animdata(&scene->id, scene->adt, ctime, ADT_RECALC_DRIVERS); + BKE_animsys_evaluate_animdata(scene, &scene->id, scene->adt, ctime, ADT_RECALC_DRIVERS); } /* world */ @@ -942,7 +943,7 @@ static void scene_update_drivers(Main *UNUSED(bmain), Scene *scene) AnimData *adt= BKE_animdata_from_id(wid); if (adt && adt->drivers.first) - BKE_animsys_evaluate_animdata(wid, adt, ctime, ADT_RECALC_DRIVERS); + BKE_animsys_evaluate_animdata(scene, wid, adt, ctime, ADT_RECALC_DRIVERS); } /* nodes */ @@ -951,7 +952,7 @@ static void scene_update_drivers(Main *UNUSED(bmain), Scene *scene) AnimData *adt= BKE_animdata_from_id(nid); if (adt && adt->drivers.first) - BKE_animsys_evaluate_animdata(nid, adt, ctime, ADT_RECALC_DRIVERS); + BKE_animsys_evaluate_animdata(scene, nid, adt, ctime, ADT_RECALC_DRIVERS); } } @@ -982,6 +983,9 @@ static void scene_update_tagged_recursive(Main *bmain, Scene *scene, Scene *scen /* scene drivers... */ scene_update_drivers(bmain, scene); + + /* update sound system animation */ + sound_update_scene(scene); } /* this is called in main loop, doing tagged updates before redraw */ @@ -1002,7 +1006,7 @@ void scene_update_tagged(Main *bmain, Scene *scene) float ctime = BKE_curframe(scene); if (adt && (adt->recalc & ADT_RECALC_ANIM)) - BKE_animsys_evaluate_animdata(&scene->id, adt, ctime, 0); + BKE_animsys_evaluate_animdata(scene, &scene->id, adt, ctime, 0); } if (scene->physics_settings.quick_cache_step) @@ -1017,6 +1021,8 @@ void scene_update_for_newframe(Main *bmain, Scene *sce, unsigned int lay) { float ctime = BKE_curframe(sce); Scene *sce_iter; + + sound_set_cfra(sce->r.cfra); /* clear animation overrides */ // XXX TODO... @@ -1037,7 +1043,7 @@ void scene_update_for_newframe(Main *bmain, Scene *sce, unsigned int lay) * can be overridden by settings from Scene, which owns the Texture through a hierarchy * such as Scene->World->MTex/Texture) can still get correctly overridden. */ - BKE_animsys_evaluate_all_animation(bmain, ctime); + BKE_animsys_evaluate_all_animation(bmain, sce, ctime); /*...done with recusrive funcs */ /* object_handle_update() on all objects, groups and sets */ diff --git a/source/blender/blenkernel/intern/seqeffects.c b/source/blender/blenkernel/intern/seqeffects.c index c19a74deff6..43747fde729 100644 --- a/source/blender/blenkernel/intern/seqeffects.c +++ b/source/blender/blenkernel/intern/seqeffects.c @@ -1582,7 +1582,7 @@ typedef struct WipeZone { static void precalc_wipe_zone(WipeZone *wipezone, WipeVars *wipe, int xo, int yo) { wipezone->flip = (wipe->angle < 0); - wipezone->angle = pow(fabsf(wipe->angle)/45.0f, log(xo)/log(2.0f)); + wipezone->angle = pow(fabsf(wipe->angle)/45.0f, log(xo)/M_LN2); wipezone->xo = xo; wipezone->yo = yo; wipezone->width = (int)(wipe->edgeWidth*((xo+yo)/2.0f)); @@ -2029,16 +2029,11 @@ static void init_transform_effect(Sequence *seq) transform->ScalexIni = 1.0f; transform->ScaleyIni = 1.0f; - transform->ScalexFin = 1.0f; - transform->ScalexFin = 1.0f; transform->xIni=0.0f; - transform->xFin=0.0f; transform->yIni=0.0f; - transform->yFin=0.0f; transform->rotIni=0.0f; - transform->rotFin=0.0f; transform->interpolation=1; transform->percent=1; @@ -2373,7 +2368,7 @@ static void RVBlurBitmap2_float ( float* map, int width,int height, /* Blancmange (bmange@airdmhor.gen.nz) */ k = -1.0f/(2.0f*(float)M_PI*blur*blur); - fval=0; + for (ix = 0;ix< halfWidth;ix++){ weight = (float)exp(k*(ix*ix)); filter[halfWidth - ix] = weight; @@ -2878,7 +2873,7 @@ static struct ImBuf * do_adjustment_impl(SeqRenderData context, Sequence * seq, { Editing * ed; ListBase * seqbasep; - struct ImBuf * i = 0; + struct ImBuf * i= NULL; ed = context.scene->ed; @@ -2913,7 +2908,7 @@ static struct ImBuf * do_adjustment( struct ImBuf *UNUSED(ibuf1), struct ImBuf *UNUSED(ibuf2), struct ImBuf *UNUSED(ibuf3)) { - struct ImBuf * i = 0; + struct ImBuf * i = NULL; struct ImBuf * out; Editing * ed; @@ -3036,7 +3031,7 @@ void sequence_effect_speed_rebuild_map(Scene *scene, Sequence * seq, int force) /* XXX - new in 2.5x. should we use the animation system this way? * The fcurve is needed because many frames need evaluating at once - campbell */ - fcu= id_data_find_fcurve(&scene->id, seq, &RNA_Sequence, "speed_factor", 0); + fcu= id_data_find_fcurve(&scene->id, seq, &RNA_Sequence, "speed_factor", 0, NULL); if (!v->frameMap || v->length != seq->len) { diff --git a/source/blender/blenkernel/intern/sequencer.c b/source/blender/blenkernel/intern/sequencer.c index b82ac69fc9e..dbb2e7860c5 100644 --- a/source/blender/blenkernel/intern/sequencer.c +++ b/source/blender/blenkernel/intern/sequencer.c @@ -73,13 +73,11 @@ #include "BKE_context.h" #include "BKE_sound.h" -#include "AUD_C-API.h" -#ifdef WIN32 -#define snprintf _snprintf +#ifdef WITH_AUDASPACE +# include "AUD_C-API.h" #endif - static ImBuf* seq_render_strip_stack( SeqRenderData context, ListBase *seqbasep, float cfra, int chanshown); @@ -215,6 +213,18 @@ void seq_free_sequence(Scene *scene, Sequence *seq) MEM_freeN(seq); } +void seq_free_sequence_recurse(Scene *scene, Sequence *seq) +{ + Sequence *iseq; + + for(iseq= seq->seqbase.first; iseq; iseq= iseq->next) { + seq_free_sequence_recurse(scene, iseq); + } + + seq_free_sequence(scene, seq); +} + + Editing *seq_give_editing(Scene *scene, int alloc) { if (scene->ed == NULL && alloc) { @@ -530,7 +540,7 @@ void calc_sequence_disp(Scene *scene, Sequence *seq) seq->handsize= (float)((seq->enddisp-seq->startdisp)/25); } - seq_update_sound(scene, seq); + seq_update_sound_bounds(scene, seq); } static void seq_update_sound_bounds_recursive(Scene *scene, Sequence *metaseq) @@ -680,13 +690,16 @@ void reload_sequence_new_file(Scene *scene, Sequence * seq, int lock_range) } case SEQ_MOVIE: if(seq->anim) IMB_free_anim(seq->anim); - seq->anim = openanim(str, IB_rect | ((seq->flag & SEQ_FILTERY) ? IB_animdeinterlace : 0)); + seq->anim = openanim(str, IB_rect | ((seq->flag & SEQ_FILTERY) ? IB_animdeinterlace : 0), seq->streamindex); if (!seq->anim) { return; } - seq->len = IMB_anim_get_duration(seq->anim); + seq->len = IMB_anim_get_duration(seq->anim, + seq->strip->proxy ? + seq->strip->proxy->tc : + IMB_TC_RECORD_RUN); seq->anim_preseek = IMB_anim_get_preseek(seq->anim); @@ -696,7 +709,9 @@ void reload_sequence_new_file(Scene *scene, Sequence * seq, int lock_range) seq->len = 0; } seq->strip->len = seq->len; + break; case SEQ_SOUND: +#ifdef WITH_AUDASPACE if(!seq->sound) return; seq->len = ceil(AUD_getInfo(seq->sound->playback_handle).length * FPS); @@ -706,6 +721,9 @@ void reload_sequence_new_file(Scene *scene, Sequence * seq, int lock_range) seq->len = 0; } seq->strip->len = seq->len; +#else + return; +#endif break; case SEQ_SCENE: { @@ -1109,7 +1127,7 @@ static int get_shown_sequences( ListBase * seqbasep, int cfra, int chanshown, Se return cnt; } - + /* ********************************************************************** proxy management @@ -1117,49 +1135,106 @@ static int get_shown_sequences( ListBase * seqbasep, int cfra, int chanshown, Se #define PROXY_MAXFILE (2*FILE_MAXDIR+FILE_MAXFILE) +static IMB_Proxy_Size seq_rendersize_to_proxysize(int size) +{ + if (size >= 100) { + return IMB_PROXY_NONE; + } + if (size >= 99) { + return IMB_PROXY_100; + } + if (size >= 75) { + return IMB_PROXY_75; + } + if (size >= 50) { + return IMB_PROXY_50; + } + return IMB_PROXY_25; +} + +static void seq_open_anim_file(Sequence * seq) +{ + char name[FILE_MAXDIR+FILE_MAXFILE]; + StripProxy * proxy; + + if(seq->anim != NULL) { + return; + } + + BLI_join_dirfile(name, sizeof(name), + seq->strip->dir, seq->strip->stripdata->name); + BLI_path_abs(name, G.main->name); + + seq->anim = openanim(name, IB_rect | + ((seq->flag & SEQ_FILTERY) ? + IB_animdeinterlace : 0), seq->streamindex); + + if (seq->anim == NULL) { + return; + } + + proxy = seq->strip->proxy; + + if (proxy == NULL) { + return; + } + + if (seq->flag & SEQ_USE_PROXY_CUSTOM_DIR) { + IMB_anim_set_index_dir(seq->anim, seq->strip->proxy->dir); + } +} + + static int seq_proxy_get_fname(SeqRenderData context, Sequence * seq, int cfra, char * name) { int frameno; - char dir[FILE_MAXDIR]; + char dir[PROXY_MAXFILE]; + int render_size = context.preview_render_size; if (!seq->strip->proxy) { return FALSE; } + /* MOVIE tracks (only exception: custom files) are now handled + internally by ImBuf module for various reasons: proper time code + support, quicker index build, using one file instead + of a full directory of jpeg files, etc. Trying to support old + and new method at once could lead to funny effects, if people + have both, a directory full of jpeg files and proxy avis, so + sorry folks, please rebuild your proxies... */ + if (seq->flag & (SEQ_USE_PROXY_CUSTOM_DIR|SEQ_USE_PROXY_CUSTOM_FILE)) { strcpy(dir, seq->strip->proxy->dir); + } else if (seq->type == SEQ_IMAGE) { + BLI_snprintf(dir, PROXY_MAXFILE, "%s/BL_proxy", seq->strip->dir); } else { - if (ELEM(seq->type, SEQ_IMAGE, SEQ_MOVIE)) { - snprintf(dir, FILE_MAXDIR, "%s/BL_proxy", seq->strip->dir); - } else { - return FALSE; - } + return FALSE; } if (seq->flag & SEQ_USE_PROXY_CUSTOM_FILE) { - BLI_join_dirfile(name, FILE_MAX, dir, seq->strip->proxy->file); /* XXX, not real length */ + BLI_join_dirfile(name, PROXY_MAXFILE, + dir, seq->strip->proxy->file); BLI_path_abs(name, G.main->name); return TRUE; } + /* dirty hack to distinguish 100% render size from PROXY_100 */ + if (render_size == 99) { + render_size = 100; + } + /* generate a separate proxy directory for each preview size */ - switch(seq->type) { - case SEQ_IMAGE: - snprintf(name, PROXY_MAXFILE, "%s/images/%d/%s_proxy", dir, + if (seq->type == SEQ_IMAGE) { + BLI_snprintf(name, PROXY_MAXFILE, "%s/images/%d/%s_proxy", dir, context.preview_render_size, give_stripelem(seq, cfra)->name); frameno = 1; - break; - case SEQ_MOVIE: - frameno = (int) give_stripelem_index(seq, cfra) + seq->anim_startofs; - snprintf(name, PROXY_MAXFILE, "%s/%s/%d/####", dir, - seq->strip->stripdata->name, context.preview_render_size); - break; - default: - frameno = (int) give_stripelem_index(seq, cfra) + seq->anim_startofs; - snprintf(name, PROXY_MAXFILE, "%s/proxy_misc/%d/####", dir, + } else { + frameno = (int) give_stripelem_index(seq, cfra) + + seq->anim_startofs; + BLI_snprintf(name, PROXY_MAXFILE, "%s/proxy_misc/%d/####", dir, context.preview_render_size); } @@ -1174,13 +1249,18 @@ static int seq_proxy_get_fname(SeqRenderData context, Sequence * seq, int cfra, static struct ImBuf * seq_proxy_fetch(SeqRenderData context, Sequence * seq, int cfra) { char name[PROXY_MAXFILE]; + IMB_Proxy_Size psize = seq_rendersize_to_proxysize( + context.preview_render_size); + int size_flags; if (!(seq->flag & SEQ_USE_PROXY)) { return NULL; } - /* rendering at 100% ? No real sense in proxy-ing, right? */ - if (context.preview_render_size == 100) { + size_flags = seq->strip->proxy->build_size_flags; + + /* only use proxies, if they are enabled (even if present!) */ + if (psize != IMB_PROXY_NONE && ((size_flags & psize) != psize)) { return NULL; } @@ -1191,13 +1271,19 @@ static struct ImBuf * seq_proxy_fetch(SeqRenderData context, Sequence * seq, int return NULL; } - seq->strip->proxy->anim = openanim(name, IB_rect); + seq->strip->proxy->anim = openanim(name, IB_rect, 0); } if (seq->strip->proxy->anim==NULL) { return NULL; } - return IMB_anim_absolute(seq->strip->proxy->anim, frameno); + seq_open_anim_file(seq); + + frameno = IMB_anim_index_get_frame_index( + seq->anim, seq->strip->proxy->tc, frameno); + + return IMB_anim_absolute(seq->strip->proxy->anim, frameno, + IMB_TC_NONE, IMB_PROXY_NONE); } if (seq_proxy_get_fname(context, seq, cfra, name) == 0) { @@ -1211,67 +1297,30 @@ static struct ImBuf * seq_proxy_fetch(SeqRenderData context, Sequence * seq, int } } -#if 0 -static void do_build_seq_ibuf(Scene *scene, Sequence * seq, TStripElem *se, int cfra, - int build_proxy_run, int preview_render_size); - -static void seq_proxy_build_frame(Scene *scene, Sequence * seq, int cfra, int preview_render_size, int seqrectx, int seqrecty) +static void seq_proxy_build_frame(SeqRenderData context, + Sequence* seq, int cfra, + int proxy_render_size) { char name[PROXY_MAXFILE]; int quality; - TStripElem * se; - int ok; int rectx, recty; + int ok; struct ImBuf * ibuf; - if (!(seq->flag & SEQ_USE_PROXY)) { + if (!seq_proxy_get_fname(context, seq, cfra, name)) { return; } - /* rendering at 100% ? No real sense in proxy-ing, right? */ - if (preview_render_size == 100) { - return; - } + ibuf = seq_render_strip(context, seq, cfra); - /* that's why it is called custom... */ - if (seq->flag & SEQ_USE_PROXY_CUSTOM_FILE) { - return; - } - - if (!seq_proxy_get_fname(scene, seq, cfra, name, preview_render_size)) { - return; - } - - se = give_tstripelem(seq, cfra); - if (!se) { - return; - } - - if(se->ibuf) { - IMB_freeImBuf(se->ibuf); - se->ibuf = 0; - } - - do_build_seq_ibuf(scene, seq, se, cfra, TRUE, preview_render_size, - seqrectx, seqrecty); - - if (!se->ibuf) { - return; - } - - rectx= (preview_render_size*scene->r.xsch)/100; - recty= (preview_render_size*scene->r.ysch)/100; - - ibuf = se->ibuf; + rectx = (proxy_render_size * context.scene->r.xsch) / 100; + recty = (proxy_render_size * context.scene->r.ysch) / 100; if (ibuf->x != rectx || ibuf->y != recty) { IMB_scalefastImBuf(ibuf, (short)rectx, (short)recty); } - /* quality is fixed, otherwise one has to generate separate - directories for every quality... - - depth = 32 is intentionally left in, otherwise ALPHA channels + /* depth = 32 is intentionally left in, otherwise ALPHA channels won't work... */ quality = seq->strip->proxy->quality; ibuf->ftype= JPG | quality; @@ -1284,69 +1333,80 @@ static void seq_proxy_build_frame(Scene *scene, Sequence * seq, int cfra, int pr } IMB_freeImBuf(ibuf); - se->ibuf = 0; } -static void seq_proxy_rebuild(Scene *scene, Sequence * seq, int seqrectx, - int seqrecty) +void seq_proxy_rebuild(struct Main * bmain, Scene *scene, Sequence * seq, + short *stop, short *do_update, float *progress) { + SeqRenderData context; int cfra; - float rsize = seq->strip->proxy->size; + int tc_flags; + int size_flags; + int quality; - waitcursor(1); + if (!seq->strip || !seq->strip->proxy) { + return; + } - G.afbreek = 0; + if (!(seq->flag & SEQ_USE_PROXY)) { + return; + } - /* flag management tries to account for strobe and - other "non-linearities", that might come in the future... - better way would be to "touch" the files, so that _really_ - no one is rebuild twice. - */ + tc_flags = seq->strip->proxy->build_tc_flags; + size_flags = seq->strip->proxy->build_size_flags; + quality = seq->strip->proxy->quality; - for (cfra = seq->startdisp; cfra < seq->enddisp; cfra++) { - TStripElem * tse = give_tstripelem(seq, cfra); + if (seq->type == SEQ_MOVIE) { + seq_open_anim_file(seq); - tse->flag &= ~STRIPELEM_PREVIEW_DONE; + if (seq->anim) { + IMB_anim_index_rebuild( + seq->anim, tc_flags, size_flags, quality, + stop, do_update, progress); + } + return; } - + if (!(seq->flag & SEQ_USE_PROXY)) { + return; + } - /* a _lot_ faster for movie files, if we read frames in - sequential order */ - if (seq->flag & SEQ_REVERSE_FRAMES) { - for (cfra = seq->enddisp-seq->endstill-1; - cfra >= seq->startdisp + seq->startstill; cfra--) { - TStripElem * tse = give_tstripelem(seq, cfra); - - if (!(tse->flag & STRIPELEM_PREVIEW_DONE)) { -//XXX set_timecursor(cfra); - seq_proxy_build_frame(scene, seq, cfra, rsize, - seqrectx, seqrecty); - tse->flag |= STRIPELEM_PREVIEW_DONE; - } - if (blender_test_break()) { - break; - } + /* that's why it is called custom... */ + if (seq->flag & SEQ_USE_PROXY_CUSTOM_FILE) { + return; + } + + /* fail safe code */ + + context = seq_new_render_data( + bmain, scene, + (scene->r.size * (float) scene->r.xsch) / 100.0f + 0.5f, + (scene->r.size * (float) scene->r.ysch) / 100.0f + 0.5f, + 100); + + for (cfra = seq->startdisp + seq->startstill; + cfra < seq->enddisp - seq->endstill; cfra++) { + if (size_flags & IMB_PROXY_25) { + seq_proxy_build_frame(context, seq, cfra, 25); } - } else { - for (cfra = seq->startdisp + seq->startstill; - cfra < seq->enddisp - seq->endstill; cfra++) { - TStripElem * tse = give_tstripelem(seq, cfra); - - if (!(tse->flag & STRIPELEM_PREVIEW_DONE)) { -//XXX set_timecursor(cfra); - seq_proxy_build_frame(scene, seq, cfra, rsize, - seqrectx, seqrecty); - tse->flag |= STRIPELEM_PREVIEW_DONE; - } - if (blender_test_break()) { - break; - } + if (size_flags & IMB_PROXY_50) { + seq_proxy_build_frame(context, seq, cfra, 50); + } + if (size_flags & IMB_PROXY_75) { + seq_proxy_build_frame(context, seq, cfra, 75); + } + if (size_flags & IMB_PROXY_100) { + seq_proxy_build_frame(context, seq, cfra, 100); } + + *progress= (float)cfra/(seq->enddisp - seq->endstill + - seq->startdisp + seq->startstill); + *do_update= 1; + + if(*stop || G.afbreek) + break; } - waitcursor(0); } -#endif /* ********************************************************************** @@ -1563,6 +1623,8 @@ static ImBuf * input_preprocess( { float mul; + ibuf = IMB_makeSingleUser(ibuf); + if((seq->flag & SEQ_FILTERY) && seq->type != SEQ_MOVIE) { IMB_filtery(ibuf); } @@ -1767,7 +1829,7 @@ static ImBuf* seq_render_effect_strip_impl( facf= fac; } else { - fcu = id_data_find_fcurve(&context.scene->id, seq, &RNA_Sequence, "effect_fader", 0); + fcu = id_data_find_fcurve(&context.scene->id, seq, &RNA_Sequence, "effect_fader", 0, NULL); if (fcu) { fac = facf = evaluate_fcurve(fcu, cfra); if( context.scene->r.mode & R_FIELDS ) { @@ -2088,17 +2150,20 @@ static ImBuf * seq_render_strip(SeqRenderData context, Sequence * seq, float cfr } case SEQ_MOVIE: { - if(seq->anim==NULL) { - BLI_join_dirfile(name, sizeof(name), seq->strip->dir, seq->strip->stripdata->name); - BLI_path_abs(name, G.main->name); - - seq->anim = openanim(name, IB_rect | - ((seq->flag & SEQ_FILTERY) ? IB_animdeinterlace : 0)); - } + seq_open_anim_file(seq); if(seq->anim) { - IMB_anim_set_preseek(seq->anim, seq->anim_preseek); - ibuf = IMB_anim_absolute(seq->anim, nr + seq->anim_startofs); + IMB_anim_set_preseek(seq->anim, + seq->anim_preseek); + + ibuf = IMB_anim_absolute( + seq->anim, nr + seq->anim_startofs, + seq->strip->proxy ? + seq->strip->proxy->tc + : IMB_TC_RECORD_RUN, + seq_rendersize_to_proxysize( + context.preview_render_size)); + /* we don't need both (speed reasons)! */ if (ibuf && ibuf->rect_float && ibuf->rect) imb_freerectImBuf(ibuf); @@ -2115,7 +2180,7 @@ static ImBuf * seq_render_strip(SeqRenderData context, Sequence * seq, float cfr ibuf = seq_render_scene_strip_impl(context, seq, nr); /* Scene strips update all animation, so we need to restore original state.*/ - BKE_animsys_evaluate_all_animation(context.bmain, cfra); + BKE_animsys_evaluate_all_animation(context.bmain, context.scene, cfra); copy_to_ibuf_still(context, seq, nr, ibuf); break; @@ -2192,7 +2257,7 @@ static ImBuf* seq_render_strip_stack( if(scene->r.cfra != cfra) { // XXX for prefetch and overlay offset!..., very bad!!! AnimData *adt= BKE_animdata_from_id(&scene->id); - BKE_animsys_evaluate_animdata(&scene->id, adt, cfra, ADT_RECALC_ANIM); + BKE_animsys_evaluate_animdata(scene, &scene->id, adt, cfra, ADT_RECALC_ANIM); } #endif @@ -3137,16 +3202,33 @@ int shuffle_seq_time(ListBase * seqbasep, Scene *evil_scene) return offset? 0:1; } -void seq_update_sound(Scene* scene, Sequence *seq) +void seq_update_sound_bounds_all(Scene *scene) { - if(seq->scene_sound) - { + Editing *ed = scene->ed; + + if(ed) { + Sequence *seq; + + for(seq = ed->seqbase.first; seq; seq = seq->next) { + if(seq->type == SEQ_META) { + seq_update_sound_bounds_recursive(scene, seq); + } + else if(ELEM(seq->type, SEQ_SOUND, SEQ_SCENE)) { + seq_update_sound_bounds(scene, seq); + } + } + } +} + +void seq_update_sound_bounds(Scene* scene, Sequence *seq) +{ + if(seq->scene_sound) { sound_move_scene_sound(scene, seq->scene_sound, seq->startdisp, seq->enddisp, seq->startofs + seq->anim_startofs); /* mute is set in seq_update_muting_recursive */ } } -static void seq_update_muting_recursive(Scene *scene, ListBase *seqbasep, Sequence *metaseq, int mute) +static void seq_update_muting_recursive(ListBase *seqbasep, Sequence *metaseq, int mute) { Sequence *seq; int seqmute; @@ -3162,26 +3244,49 @@ static void seq_update_muting_recursive(Scene *scene, ListBase *seqbasep, Sequen if(seq == metaseq) seqmute= 0; - seq_update_muting_recursive(scene, &seq->seqbase, metaseq, seqmute); + seq_update_muting_recursive(&seq->seqbase, metaseq, seqmute); } else if(ELEM(seq->type, SEQ_SOUND, SEQ_SCENE)) { if(seq->scene_sound) { - sound_mute_scene_sound(scene, seq->scene_sound, seqmute); + sound_mute_scene_sound(seq->scene_sound, seqmute); } } } } -void seq_update_muting(Scene *scene, Editing *ed) +void seq_update_muting(Editing *ed) { if(ed) { /* mute all sounds up to current metastack list */ MetaStack *ms= ed->metastack.last; if(ms) - seq_update_muting_recursive(scene, &ed->seqbase, ms->parseq, 1); + seq_update_muting_recursive(&ed->seqbase, ms->parseq, 1); else - seq_update_muting_recursive(scene, &ed->seqbase, NULL, 0); + seq_update_muting_recursive(&ed->seqbase, NULL, 0); + } +} + +static void seq_update_sound_recursive(Scene *scene, ListBase *seqbasep, bSound *sound) +{ + Sequence *seq; + + for(seq=seqbasep->first; seq; seq=seq->next) { + if(seq->type == SEQ_META) { + seq_update_sound_recursive(scene, &seq->seqbase, sound); + } + else if(seq->type == SEQ_SOUND) { + if(seq->scene_sound && sound == seq->sound) { + sound_update_scene_sound(seq->scene_sound, sound); + } + } + } +} + +void seq_update_sound(struct Scene *scene, struct bSound *sound) +{ + if(scene->ed) { + seq_update_sound_recursive(scene, &scene->ed->seqbase, sound); } } @@ -3225,9 +3330,10 @@ int seq_swap(Sequence *seq_a, Sequence *seq_b, const char **error_str) { char name[sizeof(seq_a->name)]; - if(seq_a->len != seq_b->len) + if(seq_a->len != seq_b->len) { *error_str= "Strips must be the same length"; return 0; + } /* type checking, could be more advanced but disalow sound vs non-sound copy */ if(seq_a->type != seq_b->type) { @@ -3437,7 +3543,7 @@ void seq_load_apply(Scene *scene, Sequence *seq, SeqLoadInfo *seq_load) if(seq_load->flag & SEQ_LOAD_SOUND_CACHE) { if(seq->sound) - sound_cache(seq->sound, 0); + sound_cache(seq->sound); } seq_load->tot_success++; @@ -3464,6 +3570,7 @@ Sequence *alloc_sequence(ListBase *lb, int cfra, int machine) seq->mul= 1.0; seq->blend_opacity = 100.0; seq->volume = 1.0f; + seq->pitch = 1.0f; seq->scene_sound = NULL; return seq; @@ -3493,8 +3600,10 @@ Sequence *sequencer_add_image_strip(bContext *C, ListBase *seqbasep, SeqLoadInfo return seq; } +#ifdef WITH_AUDASPACE Sequence *sequencer_add_sound_strip(bContext *C, ListBase *seqbasep, SeqLoadInfo *seq_load) { + Main *bmain= CTX_data_main(C); Scene *scene= CTX_data_scene(C); /* only for sound */ Editing *ed= seq_give_editing(scene, TRUE); bSound *sound; @@ -3516,7 +3625,7 @@ Sequence *sequencer_add_sound_strip(bContext *C, ListBase *seqbasep, SeqLoadInfo info = AUD_getInfo(sound->playback_handle); if (info.specs.channels == AUD_CHANNELS_INVALID) { - sound_delete(C, sound); + sound_delete(bmain, sound); //if(op) // BKE_report(op->reports, RPT_ERROR, "Unsupported audio format"); return NULL; @@ -3550,6 +3659,15 @@ Sequence *sequencer_add_sound_strip(bContext *C, ListBase *seqbasep, SeqLoadInfo return seq; } +#else // WITH_AUDASPACE +Sequence *sequencer_add_sound_strip(bContext *C, ListBase *seqbasep, SeqLoadInfo *seq_load) +{ + (void)C; + (void)seqbasep; + (void)seq_load; + return NULL; +} +#endif // WITH_AUDASPACE Sequence *sequencer_add_movie_strip(bContext *C, ListBase *seqbasep, SeqLoadInfo *seq_load) { @@ -3565,7 +3683,7 @@ Sequence *sequencer_add_movie_strip(bContext *C, ListBase *seqbasep, SeqLoadInfo BLI_strncpy(path, seq_load->path, sizeof(path)); BLI_path_abs(path, G.main->name); - an = openanim(path, IB_rect); + an = openanim(path, IB_rect, 0); if(an==NULL) return NULL; @@ -3581,7 +3699,7 @@ Sequence *sequencer_add_movie_strip(bContext *C, ListBase *seqbasep, SeqLoadInfo /* basic defaults */ seq->strip= strip= MEM_callocN(sizeof(Strip), "strip"); - strip->len = seq->len = IMB_anim_get_duration( an ); + strip->len = seq->len = IMB_anim_get_duration( an, IMB_TC_RECORD_RUN ); strip->us= 1; /* we only need 1 element for MOVIE strips */ diff --git a/source/blender/blenkernel/intern/smoke.c b/source/blender/blenkernel/intern/smoke.c index 4405bce3d51..6ab1574ca80 100644 --- a/source/blender/blenkernel/intern/smoke.c +++ b/source/blender/blenkernel/intern/smoke.c @@ -140,6 +140,19 @@ static void fill_scs_points(Object *ob, DerivedMesh *dm, SmokeCollSettings *scs) #define TRI_UVOFFSET (1./4.) +/* Stubs to use when smoke is disabled */ +#ifndef WITH_SMOKE +struct WTURBULENCE *smoke_turbulence_init(int *UNUSED(res), int UNUSED(amplify), int UNUSED(noisetype)) { return NULL; } +struct FLUID_3D *smoke_init(int *UNUSED(res), float *UNUSED(p0)) { return NULL; } +void smoke_free(struct FLUID_3D *UNUSED(fluid)) {} +void smoke_turbulence_free(struct WTURBULENCE *UNUSED(wt)) {} +void smoke_initWaveletBlenderRNA(struct WTURBULENCE *UNUSED(wt), float *UNUSED(strength)) {} +void smoke_initBlenderRNA(struct FLUID_3D *UNUSED(fluid), float *UNUSED(alpha), float *UNUSED(beta), float *UNUSED(dt_factor), float *UNUSED(vorticity), int *UNUSED(border_colli)) {} +long long smoke_get_mem_req(int UNUSED(xres), int UNUSED(yres), int UNUSED(zres), int UNUSED(amplify)) { return 0; } +void smokeModifier_do(SmokeModifierData *UNUSED(smd), Scene *UNUSED(scene), Object *UNUSED(ob), DerivedMesh *UNUSED(dm)) {} +#endif // WITH_SMOKE + + static int smokeModifier_init (SmokeModifierData *smd, Object *ob, Scene *scene, DerivedMesh *dm) { if((smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain && !smd->domain->fluid) @@ -805,6 +818,9 @@ void smokeModifier_copy(struct SmokeModifierData *smd, struct SmokeModifierData // forward decleration static void smoke_calc_transparency(float *result, float *input, float *p0, float *p1, int res[3], float dx, float *light, bresenham_callback cb, float correct); static float calc_voxel_transp(float *result, float *input, int res[3], int *pixel, float *tRay, float correct); + +#ifdef WITH_SMOKE + static int get_lamp(Scene *scene, float *light) { Base *base_tmp = NULL; @@ -1646,3 +1662,4 @@ static void smoke_calc_transparency(float *result, float *input, float *p0, floa } } +#endif // WITH_SMOKE diff --git a/source/blender/blenkernel/intern/softbody.c b/source/blender/blenkernel/intern/softbody.c index ff238678eeb..2960d8a41e5 100644 --- a/source/blender/blenkernel/intern/softbody.c +++ b/source/blender/blenkernel/intern/softbody.c @@ -75,6 +75,7 @@ variables on the UI for now #include "BKE_curve.h" #include "BKE_effect.h" #include "BKE_global.h" +#include "BKE_modifier.h" #include "BKE_softbody.h" #include "BKE_DerivedMesh.h" #include "BKE_pointcache.h" @@ -289,21 +290,24 @@ typedef struct ccd_Mesh { -static ccd_Mesh *ccd_mesh_make(Object *ob, DerivedMesh *dm) +static ccd_Mesh *ccd_mesh_make(Object *ob) { + CollisionModifierData *cmd; ccd_Mesh *pccd_M = NULL; ccdf_minmax *mima =NULL; MFace *mface=NULL; float v[3],hull; int i; + cmd =(CollisionModifierData *)modifiers_findByType(ob, eModifierType_Collision); + /* first some paranoia checks */ - if (!dm) return NULL; - if (!dm->getNumVerts(dm) || !dm->getNumFaces(dm)) return NULL; + if (!cmd) return NULL; + if (!cmd->numverts || !cmd->numfaces) return NULL; pccd_M = MEM_mallocN(sizeof(ccd_Mesh),"ccd_Mesh"); - pccd_M->totvert = dm->getNumVerts(dm); - pccd_M->totface = dm->getNumFaces(dm); + pccd_M->totvert = cmd->numverts; + pccd_M->totface = cmd->numfaces; pccd_M->savety = CCD_SAVETY; pccd_M->bbmin[0]=pccd_M->bbmin[1]=pccd_M->bbmin[2]=1e30f; pccd_M->bbmax[0]=pccd_M->bbmax[1]=pccd_M->bbmax[2]=-1e30f; @@ -314,12 +318,10 @@ static ccd_Mesh *ccd_mesh_make(Object *ob, DerivedMesh *dm) hull = MAX2(ob->pd->pdef_sbift,ob->pd->pdef_sboft); /* alloc and copy verts*/ - pccd_M->mvert = dm->dupVertArray(dm); - /* ah yeah, put the verices to global coords once */ - /* and determine the ortho BB on the fly */ + pccd_M->mvert = MEM_dupallocN(cmd->xnew); + /* note that xnew coords are already in global space, */ + /* determine the ortho BB */ for(i=0; i < pccd_M->totvert; i++){ - mul_m4_v3(ob->obmat, pccd_M->mvert[i].co); - /* evaluate limits */ VECCOPY(v,pccd_M->mvert[i].co); pccd_M->bbmin[0] = MIN2(pccd_M->bbmin[0],v[0]-hull); @@ -332,7 +334,7 @@ static ccd_Mesh *ccd_mesh_make(Object *ob, DerivedMesh *dm) } /* alloc and copy faces*/ - pccd_M->mface = dm->dupFaceArray(dm); + pccd_M->mface = MEM_dupallocN(cmd->mfaces); /* OBBs for idea1 */ pccd_M->mima = MEM_mallocN(sizeof(ccdf_minmax)*pccd_M->totface,"ccd_Mesh_Faces_mima"); @@ -386,19 +388,22 @@ static ccd_Mesh *ccd_mesh_make(Object *ob, DerivedMesh *dm) } return pccd_M; } -static void ccd_mesh_update(Object *ob,ccd_Mesh *pccd_M, DerivedMesh *dm) +static void ccd_mesh_update(Object *ob,ccd_Mesh *pccd_M) { - ccdf_minmax *mima =NULL; + CollisionModifierData *cmd; + ccdf_minmax *mima =NULL; MFace *mface=NULL; float v[3],hull; int i; + cmd =(CollisionModifierData *)modifiers_findByType(ob, eModifierType_Collision); + /* first some paranoia checks */ - if (!dm) return ; - if (!dm->getNumVerts(dm) || !dm->getNumFaces(dm)) return ; + if (!cmd) return ; + if (!cmd->numverts || !cmd->numfaces) return ; - if ((pccd_M->totvert != dm->getNumVerts(dm)) || - (pccd_M->totface != dm->getNumFaces(dm))) return; + if ((pccd_M->totvert != cmd->numverts) || + (pccd_M->totface != cmd->numfaces)) return; pccd_M->bbmin[0]=pccd_M->bbmin[1]=pccd_M->bbmin[2]=1e30f; pccd_M->bbmax[0]=pccd_M->bbmax[1]=pccd_M->bbmax[2]=-1e30f; @@ -411,12 +416,10 @@ static void ccd_mesh_update(Object *ob,ccd_Mesh *pccd_M, DerivedMesh *dm) if(pccd_M->mprevvert) MEM_freeN(pccd_M->mprevvert); pccd_M->mprevvert = pccd_M->mvert; /* alloc and copy verts*/ - pccd_M->mvert = dm->dupVertArray(dm); - /* ah yeah, put the verices to global coords once */ - /* and determine the ortho BB on the fly */ + pccd_M->mvert = MEM_dupallocN(cmd->xnew); + /* note that xnew coords are already in global space, */ + /* determine the ortho BB */ for(i=0; i < pccd_M->totvert; i++){ - mul_m4_v3(ob->obmat, pccd_M->mvert[i].co); - /* evaluate limits */ VECCOPY(v,pccd_M->mvert[i].co); pccd_M->bbmin[0] = MIN2(pccd_M->bbmin[0],v[0]-hull); @@ -555,21 +558,8 @@ static void ccd_build_deflector_hash(Scene *scene, Object *vertexowner, GHash *h /*+++ only with deflecting set */ if(ob->pd && ob->pd->deflect && BLI_ghash_lookup(hash, ob) == NULL) { - DerivedMesh *dm= NULL; - - if(ob->softflag & OB_SB_COLLFINAL) /* so maybe someone wants overkill to collide with subsurfed */ - dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH); - else - dm = mesh_get_derived_deform(scene, ob, CD_MASK_BAREMESH); - - if(dm){ - ccd_Mesh *ccdmesh = ccd_mesh_make(ob, dm); - BLI_ghash_insert(hash, ob, ccdmesh); - - /* we did copy & modify all we need so give 'em away again */ - dm->release(dm); - - } + ccd_Mesh *ccdmesh = ccd_mesh_make(ob); + BLI_ghash_insert(hash, ob, ccdmesh); }/*--- only with deflecting set */ }/* mesh && layer*/ @@ -595,21 +585,9 @@ static void ccd_update_deflector_hash(Scene *scene, Object *vertexowner, GHash * /*+++ only with deflecting set */ if(ob->pd && ob->pd->deflect) { - DerivedMesh *dm= NULL; - - if(ob->softflag & OB_SB_COLLFINAL) { /* so maybe someone wants overkill to collide with subsurfed */ - dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH); - } else { - dm = mesh_get_derived_deform(scene, ob, CD_MASK_BAREMESH); - } - if(dm){ - ccd_Mesh *ccdmesh = BLI_ghash_lookup(hash,ob); - if (ccdmesh) - ccd_mesh_update(ob,ccdmesh,dm); - - /* we did copy & modify all we need so give 'em away again */ - dm->release(dm); - } + ccd_Mesh *ccdmesh = BLI_ghash_lookup(hash,ob); + if (ccdmesh) + ccd_mesh_update(ob,ccdmesh); }/*--- only with deflecting set */ }/* mesh && layer*/ diff --git a/source/blender/blenkernel/intern/sound.c b/source/blender/blenkernel/intern/sound.c index e0e456a371e..ff518d69e21 100644 --- a/source/blender/blenkernel/intern/sound.c +++ b/source/blender/blenkernel/intern/sound.c @@ -13,15 +13,20 @@ #include "MEM_guardedalloc.h" #include "BLI_blenlib.h" +#include "BLI_math.h" #include "DNA_anim_types.h" +#include "DNA_object_types.h" #include "DNA_scene_types.h" #include "DNA_sequence_types.h" #include "DNA_packedFile_types.h" #include "DNA_screen_types.h" #include "DNA_sound_types.h" +#include "DNA_speaker_types.h" -#include "AUD_C-API.h" +#ifdef WITH_AUDASPACE +# include "AUD_C-API.h" +#endif #include "BKE_utildefines.h" #include "BKE_global.h" @@ -30,9 +35,76 @@ #include "BKE_context.h" #include "BKE_library.h" #include "BKE_packedFile.h" -#include "BKE_fcurve.h" #include "BKE_animsys.h" +#include "BKE_sequencer.h" +#include "BKE_scene.h" + +#ifdef WITH_AUDASPACE +// evil global ;-) +static int sound_cfra; +#endif + +struct bSound* sound_new_file(struct Main *bmain, const char *filename) +{ + bSound* sound = NULL; + + char str[FILE_MAX]; + char *path; + + int len; + + strcpy(str, filename); + + path = /*bmain ? bmain->name :*/ G.main->name; + + BLI_path_abs(str, path); + + len = strlen(filename); + while(len > 0 && filename[len-1] != '/' && filename[len-1] != '\\') + len--; + + sound = alloc_libblock(&bmain->sound, ID_SO, filename+len); + BLI_strncpy(sound->name, filename, FILE_MAX); +// XXX unused currently sound->type = SOUND_TYPE_FILE; + + sound_load(bmain, sound); + + if(!sound->playback_handle) + { + free_libblock(&bmain->sound, sound); + sound = NULL; + } + + return sound; +} + +void sound_free(struct bSound* sound) +{ + if (sound->packedfile) + { + freePackedFile(sound->packedfile); + sound->packedfile = NULL; + } + +#ifdef WITH_AUDASPACE + if(sound->handle) + { + AUD_unload(sound->handle); + sound->handle = NULL; + sound->playback_handle = NULL; + } + + if(sound->cache) + { + AUD_unload(sound->cache); + sound->cache = NULL; + } + sound_free_waveform(sound); +#endif // WITH_AUDASPACE +} + +#ifdef WITH_AUDASPACE static int force_device = -1; @@ -51,7 +123,8 @@ static void sound_sync_callback(void* data, int mode, float time) sound_play_scene(scene); else sound_stop_scene(scene); - AUD_seek(scene->sound_scene_handle, time); + if(scene->sound_scene_handle) + AUD_seek(scene->sound_scene_handle, time); } scene = scene->id.next; } @@ -110,7 +183,12 @@ void sound_init(struct Main *bmain) if(!AUD_init(device, specs, buffersize)) AUD_init(AUD_NULL_DEVICE, specs, buffersize); - + + sound_init_main(bmain); +} + +void sound_init_main(struct Main *bmain) +{ #ifdef WITH_JACK AUD_setSyncCallback(sound_sync_callback, bmain); #else @@ -123,43 +201,9 @@ void sound_exit(void) AUD_exit(); } -struct bSound* sound_new_file(struct Main *bmain, const char *filename) -{ - bSound* sound = NULL; - - char str[FILE_MAX]; - char *path; - - int len; - - strcpy(str, filename); - - path = /*bmain ? bmain->name :*/ G.main->name; - - BLI_path_abs(str, path); - - len = strlen(filename); - while(len > 0 && filename[len-1] != '/' && filename[len-1] != '\\') - len--; - - sound = alloc_libblock(&bmain->sound, ID_SO, filename+len); - BLI_strncpy(sound->name, filename, FILE_MAX); -// XXX unused currently sound->type = SOUND_TYPE_FILE; - - sound_load(bmain, sound); - - if(!sound->playback_handle) - { - free_libblock(&bmain->sound, sound); - sound = NULL; - } - - return sound; -} - // XXX unused currently #if 0 -struct bSound* sound_new_buffer(struct bContext *C, struct bSound *source) +struct bSound* sound_new_buffer(struct Main *bmain, struct bSound *source) { bSound* sound = NULL; @@ -167,23 +211,23 @@ struct bSound* sound_new_buffer(struct bContext *C, struct bSound *source) strcpy(name, "buf_"); strcpy(name + 4, source->id.name); - sound = alloc_libblock(&CTX_data_main(C)->sound, ID_SO, name); + sound = alloc_libblock(&bmain->sound, ID_SO, name); sound->child_sound = source; sound->type = SOUND_TYPE_BUFFER; - sound_load(CTX_data_main(C), sound); + sound_load(bmain, sound); if(!sound->playback_handle) { - free_libblock(&CTX_data_main(C)->sound, sound); + free_libblock(&bmain->sound, sound); sound = NULL; } return sound; } -struct bSound* sound_new_limiter(struct bContext *C, struct bSound *source, float start, float end) +struct bSound* sound_new_limiter(struct Main *bmain, struct bSound *source, float start, float end) { bSound* sound = NULL; @@ -191,18 +235,18 @@ struct bSound* sound_new_limiter(struct bContext *C, struct bSound *source, floa strcpy(name, "lim_"); strcpy(name + 4, source->id.name); - sound = alloc_libblock(&CTX_data_main(C)->sound, ID_SO, name); + sound = alloc_libblock(&bmain->sound, ID_SO, name); sound->child_sound = source; sound->start = start; sound->end = end; sound->type = SOUND_TYPE_LIMITER; - sound_load(CTX_data_main(C), sound); + sound_load(bmain, sound); if(!sound->playback_handle) { - free_libblock(&CTX_data_main(C)->sound, sound); + free_libblock(&bmain->sound, sound); sound = NULL; } @@ -210,27 +254,35 @@ struct bSound* sound_new_limiter(struct bContext *C, struct bSound *source, floa } #endif -void sound_delete(struct bContext *C, struct bSound* sound) +void sound_delete(struct Main *bmain, struct bSound* sound) { if(sound) { sound_free(sound); - free_libblock(&CTX_data_main(C)->sound, sound); + free_libblock(&bmain->sound, sound); } } -void sound_cache(struct bSound* sound, int ignore) +void sound_cache(struct bSound* sound) { - if(sound->cache && !ignore) + sound->flags |= SOUND_FLAGS_CACHING; + if(sound->cache) AUD_unload(sound->cache); sound->cache = AUD_bufferSound(sound->handle); sound->playback_handle = sound->cache; } +void sound_cache_notifying(struct Main* main, struct bSound* sound) +{ + sound_cache(sound); + sound_update_sequencer(main, sound); +} + void sound_delete_cache(struct bSound* sound) { + sound->flags &= ~SOUND_FLAGS_CACHING; if(sound->cache) { AUD_unload(sound->cache); @@ -243,6 +295,12 @@ void sound_load(struct Main *bmain, struct bSound* sound) { if(sound) { + if(sound->cache) + { + AUD_unload(sound->cache); + sound->cache = NULL; + } + if(sound->handle) { AUD_unload(sound->handle); @@ -294,68 +352,52 @@ void sound_load(struct Main *bmain, struct bSound* sound) break; } #endif + if(sound->flags & SOUND_FLAGS_MONO) + { + void* handle = AUD_monoSound(sound->handle); + AUD_unload(sound->handle); + sound->handle = handle; + } + + if(sound->flags & SOUND_FLAGS_CACHING) + { + sound->cache = AUD_bufferSound(sound->handle); + } + if(sound->cache) sound->playback_handle = sound->cache; else sound->playback_handle = sound->handle; - } -} - -void sound_free(struct bSound* sound) -{ - if (sound->packedfile) - { - freePackedFile(sound->packedfile); - sound->packedfile = NULL; - } - if(sound->handle) - { - AUD_unload(sound->handle); - sound->handle = NULL; - sound->playback_handle = NULL; + sound_update_sequencer(bmain, sound); } } -static float sound_get_volume(Scene* scene, Sequence* sequence, float time) -{ - AnimData *adt= BKE_animdata_from_id(&scene->id); - FCurve *fcu = NULL; - char buf[64]; - - /* NOTE: this manually constructed path needs to be used here to avoid problems with RNA crashes */ - sprintf(buf, "sequence_editor.sequences_all[\"%s\"].volume", sequence->name+2); - if (adt && adt->action && adt->action->curves.first) - fcu= list_find_fcurve(&adt->action->curves, buf, 0); - - if(fcu) - return evaluate_fcurve(fcu, time * (float)FPS); - else - return sequence->volume; -} - AUD_Device* sound_mixdown(struct Scene *scene, AUD_DeviceSpecs specs, int start, float volume) { - AUD_Device* mixdown = AUD_openReadDevice(specs); - - AUD_setDeviceVolume(mixdown, volume); - - AUD_playDevice(mixdown, scene->sound_scene, start / FPS); - - return mixdown; + return AUD_openMixdownDevice(specs, scene->sound_scene, volume, start / FPS); } void sound_create_scene(struct Scene *scene) { - scene->sound_scene = AUD_createSequencer(scene->audio.flag & AUDIO_MUTE, scene, (AUD_volumeFunction)&sound_get_volume); + scene->sound_scene = AUD_createSequencer(FPS, scene->audio.flag & AUDIO_MUTE); + AUD_updateSequencerData(scene->sound_scene, scene->audio.speed_of_sound, + scene->audio.doppler_factor, scene->audio.distance_model); + scene->sound_scene_handle = NULL; + scene->sound_scrub_handle = NULL; + scene->speaker_handles = NULL; } void sound_destroy_scene(struct Scene *scene) { if(scene->sound_scene_handle) AUD_stop(scene->sound_scene_handle); + if(scene->sound_scrub_handle) + AUD_stop(scene->sound_scrub_handle); if(scene->sound_scene) AUD_destroySequencer(scene->sound_scene); + if(scene->speaker_handles) + AUD_destroySet(scene->speaker_handles); } void sound_mute_scene(struct Scene *scene, int muted) @@ -364,37 +406,97 @@ void sound_mute_scene(struct Scene *scene, int muted) AUD_setSequencerMuted(scene->sound_scene, muted); } +void sound_update_fps(struct Scene *scene) +{ + if(scene->sound_scene) + AUD_setSequencerFPS(scene->sound_scene, FPS); +} + +void sound_update_scene_listener(struct Scene *scene) +{ + AUD_updateSequencerData(scene->sound_scene, scene->audio.speed_of_sound, + scene->audio.doppler_factor, scene->audio.distance_model); +} + void* sound_scene_add_scene_sound(struct Scene *scene, struct Sequence* sequence, int startframe, int endframe, int frameskip) { if(scene != sequence->scene) - return AUD_addSequencer(scene->sound_scene, &(sequence->scene->sound_scene), startframe / FPS, endframe / FPS, frameskip / FPS, sequence); + return AUD_addSequence(scene->sound_scene, sequence->scene->sound_scene, startframe / FPS, endframe / FPS, frameskip / FPS); return NULL; } void* sound_add_scene_sound(struct Scene *scene, struct Sequence* sequence, int startframe, int endframe, int frameskip) { - return AUD_addSequencer(scene->sound_scene, &(sequence->sound->playback_handle), startframe / FPS, endframe / FPS, frameskip / FPS, sequence); + void* handle = AUD_addSequence(scene->sound_scene, sequence->sound->playback_handle, startframe / FPS, endframe / FPS, frameskip / FPS); + AUD_muteSequence(handle, (sequence->flag & SEQ_MUTE) != 0); + AUD_setSequenceAnimData(handle, AUD_AP_VOLUME, CFRA, &sequence->volume, 0); + AUD_setSequenceAnimData(handle, AUD_AP_PITCH, CFRA, &sequence->pitch, 0); + AUD_setSequenceAnimData(handle, AUD_AP_PANNING, CFRA, &sequence->pan, 0); + return handle; } void sound_remove_scene_sound(struct Scene *scene, void* handle) { - AUD_removeSequencer(scene->sound_scene, handle); + AUD_removeSequence(scene->sound_scene, handle); } -void sound_mute_scene_sound(struct Scene *scene, void* handle, char mute) +void sound_mute_scene_sound(void* handle, char mute) { - AUD_muteSequencer(scene->sound_scene, handle, mute); + AUD_muteSequence(handle, mute); } void sound_move_scene_sound(struct Scene *scene, void* handle, int startframe, int endframe, int frameskip) { - AUD_moveSequencer(scene->sound_scene, handle, startframe / FPS, endframe / FPS, frameskip / FPS); + AUD_moveSequence(handle, startframe / FPS, endframe / FPS, frameskip / FPS); +} + +void sound_update_scene_sound(void* handle, struct bSound* sound) +{ + AUD_updateSequenceSound(handle, sound->playback_handle); +} + +void sound_set_cfra(int cfra) +{ + sound_cfra = cfra; +} + +void sound_set_scene_volume(struct Scene *scene, float volume) +{ + AUD_setSequencerAnimData(scene->sound_scene, AUD_AP_VOLUME, CFRA, &volume, (scene->audio.flag & AUDIO_VOLUME_ANIMATED) != 0); +} + +void sound_set_scene_sound_volume(void* handle, float volume, char animated) +{ + AUD_setSequenceAnimData(handle, AUD_AP_VOLUME, sound_cfra, &volume, animated); +} + +void sound_set_scene_sound_pitch(void* handle, float pitch, char animated) +{ + AUD_setSequenceAnimData(handle, AUD_AP_PITCH, sound_cfra, &pitch, animated); +} + +void sound_set_scene_sound_pan(void* handle, float pan, char animated) +{ + AUD_setSequenceAnimData(handle, AUD_AP_PANNING, sound_cfra, &pan, animated); +} + +void sound_update_sequencer(struct Main* main, struct bSound* sound) +{ + struct Scene* scene; + + for(scene = main->scene.first; scene; scene = scene->id.next) + seq_update_sound(scene, sound); } static void sound_start_play_scene(struct Scene *scene) { - scene->sound_scene_handle = AUD_play(scene->sound_scene, 1); - AUD_setLoop(scene->sound_scene_handle, -1); + if(scene->sound_scene_handle) + AUD_stop(scene->sound_scene_handle); + + AUD_setSequencerDeviceSpecs(scene->sound_scene); + + if((scene->sound_scene_handle = AUD_play(scene->sound_scene, 1))) + AUD_setLoop(scene->sound_scene_handle, -1); } void sound_play_scene(struct Scene *scene) @@ -402,11 +504,17 @@ void sound_play_scene(struct Scene *scene) AUD_Status status; AUD_lock(); - status = AUD_getStatus(scene->sound_scene_handle); + status = scene->sound_scene_handle ? AUD_getStatus(scene->sound_scene_handle) : AUD_STATUS_INVALID; if(status == AUD_STATUS_INVALID) sound_start_play_scene(scene); + if(!scene->sound_scene_handle) + { + AUD_unlock(); + return; + } + if(status != AUD_STATUS_PLAYING) { AUD_seek(scene->sound_scene_handle, CFRA / FPS); @@ -421,28 +529,44 @@ void sound_play_scene(struct Scene *scene) void sound_stop_scene(struct Scene *scene) { - AUD_pause(scene->sound_scene_handle); + if(scene->sound_scene_handle) + { + AUD_pause(scene->sound_scene_handle); - if(scene->audio.flag & AUDIO_SYNC) - AUD_stopPlayback(); + if(scene->audio.flag & AUDIO_SYNC) + AUD_stopPlayback(); + } } -void sound_seek_scene(struct bContext *C) +void sound_seek_scene(struct Main *bmain, struct Scene *scene) { - struct Scene *scene = CTX_data_scene(C); AUD_Status status; + bScreen *screen; + int animation_playing; AUD_lock(); - status = AUD_getStatus(scene->sound_scene_handle); + status = scene->sound_scene_handle ? AUD_getStatus(scene->sound_scene_handle) : AUD_STATUS_INVALID; if(status == AUD_STATUS_INVALID) { sound_start_play_scene(scene); + + if(!scene->sound_scene_handle) + { + AUD_unlock(); + return; + } + AUD_pause(scene->sound_scene_handle); } - if(scene->audio.flag & AUDIO_SCRUB && !CTX_wm_screen(C)->animtimer) + animation_playing = 0; + for(screen=bmain->screen.first; screen; screen=screen->id.next) + if(screen->animtimer) + animation_playing = 1; + + if(scene->audio.flag & AUDIO_SCRUB && !animation_playing) { if(scene->audio.flag & AUDIO_SYNC) { @@ -452,10 +576,14 @@ void sound_seek_scene(struct bContext *C) else AUD_seek(scene->sound_scene_handle, CFRA / FPS); AUD_resume(scene->sound_scene_handle); - if(AUD_getStatus(scene->sound_scrub_handle) != AUD_STATUS_INVALID) + if(scene->sound_scrub_handle && AUD_getStatus(scene->sound_scrub_handle) != AUD_STATUS_INVALID) AUD_seek(scene->sound_scrub_handle, 0); else + { + if(scene->sound_scrub_handle) + AUD_stop(scene->sound_scrub_handle); scene->sound_scrub_handle = AUD_pauseAfter(scene->sound_scene_handle, 1 / FPS); + } } else { @@ -473,10 +601,14 @@ void sound_seek_scene(struct bContext *C) float sound_sync_scene(struct Scene *scene) { - if(scene->audio.flag & AUDIO_SYNC) - return AUD_getSequencerPosition(scene->sound_scene_handle); - else - return AUD_getPosition(scene->sound_scene_handle); + if(scene->sound_scene_handle) + { + if(scene->audio.flag & AUDIO_SYNC) + return AUD_getSequencerPosition(scene->sound_scene_handle); + else + return AUD_getPosition(scene->sound_scene_handle); + } + return 0.0f; } int sound_scene_playing(struct Scene *scene) @@ -487,18 +619,166 @@ int sound_scene_playing(struct Scene *scene) return -1; } -int sound_read_sound_buffer(struct bSound* sound, float* buffer, int length, float start, float end) +void sound_free_waveform(struct bSound* sound) { - AUD_Sound* limiter = AUD_limitSound(sound->cache, start, end); - return AUD_readSound(limiter, buffer, length); - AUD_unload(limiter); + if(sound->waveform) + { + MEM_freeN(((SoundWaveform*)sound->waveform)->data); + MEM_freeN(sound->waveform); + } + + sound->waveform = NULL; } -int sound_get_channels(struct bSound* sound) +void sound_read_waveform(struct bSound* sound) { AUD_SoundInfo info; info = AUD_getInfo(sound->playback_handle); - return info.specs.channels; + if(info.length > 0) + { + SoundWaveform* waveform = MEM_mallocN(sizeof(SoundWaveform), "SoundWaveform"); + int length = info.length * SOUND_WAVE_SAMPLES_PER_SECOND; + + waveform->data = MEM_mallocN(length * sizeof(float) * 3, "SoundWaveform.samples"); + waveform->length = AUD_readSound(sound->playback_handle, waveform->data, length, SOUND_WAVE_SAMPLES_PER_SECOND); + + sound_free_waveform(sound); + sound->waveform = waveform; + } } + +void sound_update_scene(struct Scene* scene) +{ + Object* ob; + Base* base; + NlaTrack* track; + NlaStrip* strip; + Speaker* speaker; + Scene* sce_it; + + void* new_set = AUD_createSet(); + void* handle; + float quat[4]; + + for(SETLOOPER(scene, sce_it, base)) + { + ob = base->object; + if(ob->type == OB_SPEAKER) + { + if(ob->adt) + { + for(track = ob->adt->nla_tracks.first; track; track = track->next) + { + for(strip = track->strips.first; strip; strip = strip->next) + { + if(strip->type == NLASTRIP_TYPE_SOUND) + { + speaker = (Speaker*)ob->data; + + if(AUD_removeSet(scene->speaker_handles, strip->speaker_handle)) + { + if(speaker->sound) + AUD_moveSequence(strip->speaker_handle, strip->start / FPS, -1, 0); + else + { + AUD_removeSequence(scene->sound_scene, strip->speaker_handle); + strip->speaker_handle = NULL; + } + } + else + { + if(speaker->sound) + { + strip->speaker_handle = AUD_addSequence(scene->sound_scene, speaker->sound->playback_handle, strip->start / FPS, -1, 0); + AUD_setRelativeSequence(strip->speaker_handle, 0); + } + } + + if(strip->speaker_handle) + { + AUD_addSet(new_set, strip->speaker_handle); + AUD_updateSequenceData(strip->speaker_handle, speaker->volume_max, + speaker->volume_min, speaker->distance_max, + speaker->distance_reference, speaker->attenuation, + speaker->cone_angle_outer, speaker->cone_angle_inner, + speaker->cone_volume_outer); + + mat4_to_quat(quat, ob->obmat); + AUD_setSequenceAnimData(strip->speaker_handle, AUD_AP_LOCATION, CFRA, ob->obmat[3], 1); + AUD_setSequenceAnimData(strip->speaker_handle, AUD_AP_ORIENTATION, CFRA, quat, 1); + AUD_setSequenceAnimData(strip->speaker_handle, AUD_AP_VOLUME, CFRA, &speaker->volume, 1); + AUD_setSequenceAnimData(strip->speaker_handle, AUD_AP_PITCH, CFRA, &speaker->pitch, 1); + AUD_updateSequenceSound(strip->speaker_handle, speaker->sound->playback_handle); + AUD_muteSequence(strip->speaker_handle, ((strip->flag & NLASTRIP_FLAG_MUTED) != 0) || ((speaker->flag & SPK_MUTED) != 0)); + } + } + } + } + } + } + } + + while((handle = AUD_getSet(scene->speaker_handles))) + { + AUD_removeSequence(scene->sound_scene, handle); + } + + if(scene->camera) + { + mat4_to_quat(quat, scene->camera->obmat); + AUD_setSequencerAnimData(scene->sound_scene, AUD_AP_LOCATION, CFRA, scene->camera->obmat[3], 1); + AUD_setSequencerAnimData(scene->sound_scene, AUD_AP_ORIENTATION, CFRA, quat, 1); + } + + AUD_destroySet(scene->speaker_handles); + scene->speaker_handles = new_set; +} + +void* sound_get_factory(void* sound) +{ + return ((struct bSound*) sound)->playback_handle; +} + +#else // WITH_AUDASPACE + +#include "BLI_utildefines.h" + +int sound_define_from_str(const char *UNUSED(str)) { return -1;} +void sound_force_device(int UNUSED(device)) {} +void sound_init_once(void) {} +void sound_init(struct Main *UNUSED(bmain)) {} +void sound_exit(void) {} +void sound_cache(struct bSound* UNUSED(sound)) { } +void sound_delete_cache(struct bSound* UNUSED(sound)) {} +void sound_load(struct Main *UNUSED(bmain), struct bSound* UNUSED(sound)) {} +void sound_create_scene(struct Scene *UNUSED(scene)) {} +void sound_destroy_scene(struct Scene *UNUSED(scene)) {} +void sound_mute_scene(struct Scene *UNUSED(scene), int UNUSED(muted)) {} +void* sound_scene_add_scene_sound(struct Scene *UNUSED(scene), struct Sequence* UNUSED(sequence), int UNUSED(startframe), int UNUSED(endframe), int UNUSED(frameskip)) { return NULL; } +void* sound_add_scene_sound(struct Scene *UNUSED(scene), struct Sequence* UNUSED(sequence), int UNUSED(startframe), int UNUSED(endframe), int UNUSED(frameskip)) { return NULL; } +void sound_remove_scene_sound(struct Scene *UNUSED(scene), void* UNUSED(handle)) {} +void sound_mute_scene_sound(void* UNUSED(handle), char UNUSED(mute)) {} +void sound_move_scene_sound(struct Scene *UNUSED(scene), void* UNUSED(handle), int UNUSED(startframe), int UNUSED(endframe), int UNUSED(frameskip)) {} +static void sound_start_play_scene(struct Scene *UNUSED(scene)) {} +void sound_play_scene(struct Scene *UNUSED(scene)) {} +void sound_stop_scene(struct Scene *UNUSED(scene)) {} +void sound_seek_scene(struct Main *UNUSED(bmain), struct Scene *UNUSED(scene)) {} +float sound_sync_scene(struct Scene *UNUSED(scene)) { return 0.0f; } +int sound_scene_playing(struct Scene *UNUSED(scene)) { return -1; } +int sound_read_sound_buffer(struct bSound* UNUSED(sound), float* UNUSED(buffer), int UNUSED(length), float UNUSED(start), float UNUSED(end)) { return 0; } +void sound_read_waveform(struct bSound* sound) { (void)sound; } +void sound_init_main(struct Main *bmain) { (void)bmain; } +void sound_set_cfra(int cfra) { (void)cfra; } +void sound_update_sequencer(struct Main* main, struct bSound* sound) { (void)main; (void)sound; } +void sound_update_scene(struct Scene* scene) { (void)scene; } +void sound_update_scene_sound(void* handle, struct bSound* sound) { (void)handle; (void)sound; } +void sound_update_scene_listener(struct Scene *scene) { (void)scene; } +void sound_update_fps(struct Scene *scene) { (void)scene; } +void sound_set_scene_sound_volume(void* handle, float volume, char animated) { (void)handle; (void)volume; (void)animated; } +void sound_set_scene_sound_pan(void* handle, float pan, char animated) { (void)handle; (void)pan; (void)animated; } +void sound_set_scene_volume(struct Scene *scene, float volume) { (void)scene; (void)volume; } +void sound_set_scene_sound_pitch(void* handle, float pitch, char animated) { (void)handle; (void)pitch; (void)animated; } + +#endif // WITH_AUDASPACE diff --git a/source/blender/blenkernel/intern/speaker.c b/source/blender/blenkernel/intern/speaker.c new file mode 100644 index 00000000000..200dbd41899 --- /dev/null +++ b/source/blender/blenkernel/intern/speaker.c @@ -0,0 +1,139 @@ +/* speaker.c + * + * + * $Id$ + * + * ***** 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) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Jörg Müller. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/blenkernel/intern/speaker.c + * \ingroup bke + */ + +#include "DNA_object_types.h" +#include "DNA_sound_types.h" +#include "DNA_speaker_types.h" + +#include "BLI_math.h" + +#include "BKE_animsys.h" +#include "BKE_global.h" +#include "BKE_library.h" +#include "BKE_main.h" +#include "BKE_speaker.h" + +void *add_speaker(const char *name) +{ + Speaker *spk; + + spk= alloc_libblock(&G.main->speaker, ID_SPK, name); + + spk->attenuation = 1.0f; + spk->cone_angle_inner = 360.0f; + spk->cone_angle_outer = 360.0f; + spk->cone_volume_outer = 1.0f; + spk->distance_max = FLT_MAX; + spk->distance_reference = 1.0f; + spk->flag = 0; + spk->pitch = 1.0f; + spk->sound = NULL; + spk->volume = 1.0f; + spk->volume_max = 1.0f; + spk->volume_min = 0.0f; + + return spk; +} + +Speaker *copy_speaker(Speaker *spk) +{ + Speaker *spkn; + + spkn= copy_libblock(spk); + if(spkn->sound) + spkn->sound->id.us++; + + return spkn; +} + +void make_local_speaker(Speaker *spk) +{ + Main *bmain= G.main; + Object *ob; + int local=0, lib=0; + + /* - only lib users: do nothing + * - only local users: set flag + * - mixed: make copy + */ + + if(spk->id.lib==NULL) return; + if(spk->id.us==1) { + spk->id.lib= NULL; + spk->id.flag= LIB_LOCAL; + new_id(&bmain->speaker, (ID *)spk, NULL); + return; + } + + ob= bmain->object.first; + while(ob) { + if(ob->data==spk) { + if(ob->id.lib) lib= 1; + else local= 1; + } + ob= ob->id.next; + } + + if(local && lib==0) { + spk->id.lib= NULL; + spk->id.flag= LIB_LOCAL; + new_id(&bmain->speaker, (ID *)spk, NULL); + } + else if(local && lib) { + Speaker *spkn= copy_speaker(spk); + spkn->id.us= 0; + + ob= bmain->object.first; + while(ob) { + if(ob->data==spk) { + + if(ob->id.lib==NULL) { + ob->data= spkn; + spkn->id.us++; + spk->id.us--; + } + } + ob= ob->id.next; + } + } +} + +void free_speaker(Speaker *spk) +{ + if(spk->sound) + spk->sound->id.us--; + + BKE_free_animdata((ID *)spk); +} diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c index a66caf8879f..186a5ea1852 100644 --- a/source/blender/blenkernel/intern/subsurf_ccg.c +++ b/source/blender/blenkernel/intern/subsurf_ccg.c @@ -1176,7 +1176,8 @@ static void ccgDM_drawEdges(DerivedMesh *dm, int drawLooseEdges, int UNUSED(draw CCGSubSurf *ss = ccgdm->ss; CCGEdgeIterator *ei = ccgSubSurf_getEdgeIterator(ss); CCGFaceIterator *fi = ccgSubSurf_getFaceIterator(ss); - int i, edgeSize = ccgSubSurf_getEdgeSize(ss); + int i, j, edgeSize = ccgSubSurf_getEdgeSize(ss); + int totedge = ccgSubSurf_getNumEdges(ss); int gridSize = ccgSubSurf_getGridSize(ss); int useAging; @@ -1184,13 +1185,16 @@ static void ccgDM_drawEdges(DerivedMesh *dm, int drawLooseEdges, int UNUSED(draw ccgSubSurf_getUseAgeCounts(ss, &useAging, NULL, NULL, NULL); - for (; !ccgEdgeIterator_isStopped(ei); ccgEdgeIterator_next(ei)) { - CCGEdge *e = ccgEdgeIterator_getCurrent(ei); + for (j=0; j< totedge; j++) { + CCGEdge *e = ccgdm->edgeMap[j].edge; DMGridData *edgeData = ccgSubSurf_getEdgeDataArray(ss, e); if (!drawLooseEdges && !ccgSubSurf_getEdgeNumFaces(e)) continue; + if(ccgdm->edgeFlags && !(ccgdm->edgeFlags[j] & ME_EDGEDRAW)) + continue; + if (useAging && !(G.f&G_BACKBUFSEL)) { int ageCol = 255-ccgSubSurf_getEdgeAge(ss, e)*4; glColor3ub(0, ageCol>0?ageCol:0, 0); @@ -1775,7 +1779,8 @@ static void ccgDM_drawUVEdges(DerivedMesh *dm) } } -static void ccgDM_drawMappedFaces(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index, int *drawSmooth_r), void *userData, int useColors, int (*setMaterial)(int, void *attribs)) { +static void ccgDM_drawMappedFaces(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index, int *drawSmooth_r), void *userData, int useColors, int (*setMaterial)(int, void *attribs), + int (*compareDrawOptions)(void *userData, int cur_index, int next_index)) { CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm; CCGSubSurf *ss = ccgdm->ss; MCol *mcol= NULL; @@ -1783,6 +1788,9 @@ static void ccgDM_drawMappedFaces(DerivedMesh *dm, int (*setDrawOptions)(void *u char *faceFlags = ccgdm->faceFlags; int gridFaces = gridSize - 1, totface; + /* currently unused -- each original face is handled separately */ + (void)compareDrawOptions; + if(useColors) { mcol = dm->getFaceDataArray(dm, CD_WEIGHT_MCOL); if(!mcol) diff --git a/source/blender/blenkernel/intern/text.c b/source/blender/blenkernel/intern/text.c index da329503c9f..2c507370288 100644 --- a/source/blender/blenkernel/intern/text.c +++ b/source/blender/blenkernel/intern/text.c @@ -400,7 +400,13 @@ Text *add_text(const char *file, const char *relpath) llen++; } - if (llen!=0 || ta->nlines==0) { + /* create new line in cases: + - rest of line (if last line in file hasn't got \n terminator). + in this case content of such line would be used to fill text line buffer + - file is empty. in this case new line is needed to start editing from. + - last characted in buffer is \n. in this case new line is needed to + deal with newline at end of file. (see [#28087]) (sergey) */ + if (llen!=0 || ta->nlines==0 || buffer[len-1]=='\n') { tmp= (TextLine*) MEM_mallocN(sizeof(TextLine), "textline"); tmp->line= (char*) MEM_mallocN(llen+1, "textline_string"); tmp->format= NULL; @@ -1417,6 +1423,8 @@ void txt_insert_buf(Text *text, const char *in_buffer) } undoing= u; + + (void)count; } /******************/ diff --git a/source/blender/blenkernel/intern/texture.c b/source/blender/blenkernel/intern/texture.c index 64f3c111434..38165182d83 100644 --- a/source/blender/blenkernel/intern/texture.c +++ b/source/blender/blenkernel/intern/texture.c @@ -766,7 +766,9 @@ Tex *copy_texture(Tex *tex) if(tex->preview) texn->preview = BKE_previewimg_copy(tex->preview); if(tex->nodetree) { - ntreeEndExecTree(tex->nodetree); + if (tex->nodetree->execdata) { + ntreeTexEndExecTree(tex->nodetree->execdata, 1); + } texn->nodetree= ntreeCopyTree(tex->nodetree); } @@ -1005,7 +1007,7 @@ void autotexname(Tex *tex) Tex *give_current_object_texture(Object *ob) { - Material *ma; + Material *ma, *node_ma; Tex *tex= NULL; if(ob==NULL) return NULL; @@ -1015,6 +1017,10 @@ Tex *give_current_object_texture(Object *ob) tex= give_current_lamp_texture(ob->data); } else { ma= give_current_material(ob, ob->actcol); + + if((node_ma=give_node_material(ma))) + ma= node_ma; + tex= give_current_material_texture(ma); } @@ -1080,17 +1086,6 @@ Tex *give_current_material_texture(Material *ma) tex= (Tex *)node->id; ma= NULL; } - else { - node= nodeGetActiveID(ma->nodetree, ID_MA); - if(node) { - ma= (Material*)node->id; - if(ma) { - mtex= ma->mtex[(int)(ma->texact)]; - if(mtex) tex= mtex->tex; - } - } - } - return tex; } if(ma) { @@ -1165,11 +1160,6 @@ void set_current_material_texture(Material *ma, Tex *newtex) id_us_plus(&newtex->id); ma= NULL; } - else { - node= nodeGetActiveID(ma->nodetree, ID_MA); - if(node) - ma= (Material*)node->id; - } } if(ma) { int act= (int)ma->texact; @@ -1198,16 +1188,8 @@ int has_current_material_texture(Material *ma) if(ma && ma->use_nodes && ma->nodetree) { node= nodeGetActiveID(ma->nodetree, ID_TE); - if(node) { + if(node) return 1; - } - else { - node= nodeGetActiveID(ma->nodetree, ID_MA); - if(node) - ma= (Material*)node->id; - else - ma= NULL; - } } return (ma != NULL); @@ -1486,6 +1468,10 @@ int BKE_texture_dependsOnTime(const struct Tex *texture) // assume anything in adt means the texture is animated return 1; } + else if(texture->type == TEX_NOISE) { + // noise always varies with time + return 1; + } return 0; } diff --git a/source/blender/blenkernel/intern/unit.c b/source/blender/blenkernel/intern/unit.c index b89e576a562..72fe1c19884 100644 --- a/source/blender/blenkernel/intern/unit.c +++ b/source/blender/blenkernel/intern/unit.c @@ -34,6 +34,7 @@ #include "BKE_unit.h" #include "BLI_math.h" +#include "BLI_string.h" #include "BLI_winstuff.h" @@ -136,7 +137,7 @@ static struct bUnitDef buImperialLenDef[] = { {"yard", "yards", "yd", NULL, "Yards", UN_SC_YD, 0.0, B_UNIT_DEF_NONE}, {"foot", "feet", "'", "ft", "Feet", UN_SC_FT, 0.0, B_UNIT_DEF_NONE}, /* base unit */ {"inch", "inches", "\"", "in", "Inches", UN_SC_IN, 0.0, B_UNIT_DEF_NONE}, - {"thou", "thous", "mil", NULL, "Thous", UN_SC_MIL, 0.0, B_UNIT_DEF_NONE}, + {"thou", "thou", "thou", "mil", "Thou", UN_SC_MIL, 0.0, B_UNIT_DEF_NONE}, /* plural for thou has no 's' */ {NULL, NULL, NULL, NULL, NULL, 0.0, 0.0} }; static struct bUnitCollection buImperialLenCollecton = {buImperialLenDef, 4, 0, sizeof(buImperialLenDef)/sizeof(bUnitDef)}; @@ -344,7 +345,7 @@ static int unit_as_string(char *str, int len_max, double value, int prec, bUnitC /* Convert to a string */ { - len= snprintf(str, len_max, "%.*lf", prec, value_conv); + len= BLI_snprintf(str, len_max, "%.*lf", prec, value_conv); if(len >= len_max) len= len_max; @@ -495,7 +496,7 @@ static int unit_scale_str(char *str, int len_max, char *str_tmp, double scale_pr len_name = strlen(replace_str); len_move= (len - (found_ofs+len_name)) + 1; /* 1+ to copy the string terminator */ - len_num= snprintf(str_tmp, TEMP_STR_SIZE, "*%lg"SEP_STR, unit->scalar/scale_pref); /* # removed later */ + len_num= BLI_snprintf(str_tmp, TEMP_STR_SIZE, "*%lg"SEP_STR, unit->scalar/scale_pref); /* # removed later */ if(len_num > len_max) len_num= len_max; @@ -629,12 +630,12 @@ int bUnit_ReplaceString(char *str, int len_max, char *str_prev, double scale_pre /* add the unit prefix and re-run, use brackets incase there was an expression given */ - if(snprintf(str_tmp, sizeof(str_tmp), "(%s)%s", str, unit->name) < sizeof(str_tmp)) { + if(BLI_snprintf(str_tmp, sizeof(str_tmp), "(%s)%s", str, unit->name) < sizeof(str_tmp)) { strncpy(str, str_tmp, len_max); return bUnit_ReplaceString(str, len_max, NULL, scale_pref, system, type); } else { - /* snprintf would not fit into str_tmp, cant do much in this case + /* BLI_snprintf would not fit into str_tmp, cant do much in this case * check for this because otherwise bUnit_ReplaceString could call its self forever */ return 0; } @@ -705,7 +706,7 @@ void bUnit_ToUnitAltName(char *str, int len_max, char *orig_str, int system, int /* print the alt_name */ if(unit->name_alt) - len_name= snprintf(str, len_max, "%s", unit->name_alt); + len_name= BLI_snprintf(str, len_max, "%s", unit->name_alt); else len_name= 0; diff --git a/source/blender/blenkernel/intern/writeavi.c b/source/blender/blenkernel/intern/writeavi.c index ba7f9bdd415..769a3f9b11e 100644 --- a/source/blender/blenkernel/intern/writeavi.c +++ b/source/blender/blenkernel/intern/writeavi.c @@ -105,13 +105,18 @@ bMovieHandle *BKE_get_movie_handle(int imtype) mh.get_movie_path = filepath_ffmpeg; } #endif +#ifdef WITH_FRAMESERVER if (imtype == R_FRAMESERVER) { mh.start_movie = start_frameserver; mh.append_movie = append_frameserver; mh.end_movie = end_frameserver; mh.get_next_frame = frameserver_loop; } - +#endif + + /* incase all above are disabled */ + (void)imtype; + return &mh; } diff --git a/source/blender/blenkernel/intern/writeffmpeg.c b/source/blender/blenkernel/intern/writeffmpeg.c index c729565533f..13875ff19f7 100644 --- a/source/blender/blenkernel/intern/writeffmpeg.c +++ b/source/blender/blenkernel/intern/writeffmpeg.c @@ -39,17 +39,15 @@ #include <libswscale/swscale.h> #include <libavcodec/opt.h> -#if defined(WIN32) && (!(defined snprintf)) -#define snprintf _snprintf -#endif - #include "MEM_guardedalloc.h" #include "DNA_scene_types.h" #include "BLI_blenlib.h" -#include "AUD_C-API.h" /* must be before BKE_sound.h for define */ +#ifdef WITH_AUDASPACE +# include "AUD_C-API.h" +#endif #include "BKE_global.h" #include "BKE_idprop.h" @@ -89,7 +87,9 @@ static uint8_t* audio_output_buffer = 0; static int audio_outbuf_size = 0; static double audio_time = 0.0f; +#ifdef WITH_AUDASPACE static AUD_Device* audio_mixdown_device = 0; +#endif #define FFMPEG_AUTOSPLIT_SIZE 2000000000 @@ -103,6 +103,7 @@ static void delete_picture(AVFrame* f) } } +#ifdef WITH_AUDASPACE static int write_audio_frame(void) { AVCodecContext* c = NULL; @@ -145,6 +146,7 @@ static int write_audio_frame(void) } return 0; } +#endif // #ifdef WITH_AUDASPACE /* Allocate a temporary frame */ static AVFrame* alloc_picture(int pix_fmt, int width, int height) @@ -549,7 +551,7 @@ static AVStream* alloc_audio_stream(RenderData *rd, int codec_id, AVFormatContex c->sample_rate = rd->ffcodecdata.audio_mixrate; c->bit_rate = ffmpeg_audio_bitrate*1000; c->sample_fmt = SAMPLE_FMT_S16; - c->channels = 2; + c->channels = rd->ffcodecdata.audio_channels; codec = avcodec_find_encoder(c->codec_id); if (!codec) { //XXX error("Couldn't find a valid audio codec"); @@ -574,12 +576,11 @@ static AVStream* alloc_audio_stream(RenderData *rd, int codec_id, AVFormatContex audio_outbuf_size = c->frame_size * c->channels * sizeof(int16_t) * 4; } - audio_output_buffer = (uint8_t*)MEM_mallocN( - audio_outbuf_size, "FFMPEG audio encoder input buffer"); + audio_output_buffer = (uint8_t*)av_malloc( + audio_outbuf_size); - audio_input_buffer = (uint8_t*)MEM_mallocN( - audio_input_samples * c->channels * sizeof(int16_t), - "FFMPEG audio encoder output buffer"); + audio_input_buffer = (uint8_t*)av_malloc( + audio_input_samples * c->channels * sizeof(int16_t)); audio_time = 0.0f; @@ -647,15 +648,17 @@ static int start_ffmpeg_impl(struct RenderData *rd, int rectx, int recty, Report fmt->audio_codec = ffmpeg_audio_codec; - snprintf(of->filename, sizeof(of->filename), "%s", name); + BLI_snprintf(of->filename, sizeof(of->filename), "%s", name); /* set the codec to the user's selection */ switch(ffmpeg_type) { case FFMPEG_AVI: case FFMPEG_MOV: - case FFMPEG_OGG: case FFMPEG_MKV: fmt->video_codec = ffmpeg_codec; break; + case FFMPEG_OGG: + fmt->video_codec = CODEC_ID_THEORA; + break; case FFMPEG_DV: fmt->video_codec = CODEC_ID_DVVIDEO; break; @@ -701,7 +704,7 @@ static int start_ffmpeg_impl(struct RenderData *rd, int rectx, int recty, Report if (ffmpeg_type == FFMPEG_DV) { fmt->audio_codec = CODEC_ID_PCM_S16LE; - if (ffmpeg_audio_codec != CODEC_ID_NONE && rd->ffcodecdata.audio_mixrate != 48000) { + if (ffmpeg_audio_codec != CODEC_ID_NONE && rd->ffcodecdata.audio_mixrate != 48000 && rd->ffcodecdata.audio_channels != 2) { BKE_report(reports, RPT_ERROR, "FFMPEG only supports 48khz / stereo audio for DV!"); return 0; } @@ -851,7 +854,7 @@ int start_ffmpeg(struct Scene *scene, RenderData *rd, int rectx, int recty, Repo ffmpeg_autosplit_count = 0; success = start_ffmpeg_impl(rd, rectx, recty, reports); - +#ifdef WITH_AUDASPACE if(audio_stream) { AVCodecContext* c = audio_stream->codec; @@ -860,13 +863,18 @@ int start_ffmpeg(struct Scene *scene, RenderData *rd, int rectx, int recty, Repo specs.format = AUD_FORMAT_S16; specs.rate = rd->ffcodecdata.audio_mixrate; audio_mixdown_device = sound_mixdown(scene, specs, rd->sfra, rd->ffcodecdata.audio_volume); +#ifdef FFMPEG_CODEC_TIME_BASE + c->time_base.den = specs.rate; + c->time_base.num = 1; +#endif } - +#endif return success; } void end_ffmpeg(void); +#ifdef WITH_AUDASPACE static void write_audio_frames(double to_pts) { int finished = 0; @@ -878,6 +886,7 @@ static void write_audio_frames(double to_pts) } } } +#endif int append_ffmpeg(RenderData *rd, int frame, int *pixels, int rectx, int recty, ReportList *reports) { @@ -905,8 +914,9 @@ int append_ffmpeg(RenderData *rd, int frame, int *pixels, int rectx, int recty, } } +#ifdef WITH_AUDASPACE write_audio_frames((frame - rd->sfra) / (((double)rd->frs_sec) / rd->frs_sec_base)); - +#endif return success; } @@ -920,12 +930,14 @@ void end_ffmpeg(void) write_audio_frames(); }*/ +#ifdef WITH_AUDASPACE if(audio_mixdown_device) { AUD_closeReadDevice(audio_mixdown_device); audio_mixdown_device = 0; } - +#endif + if (video_stream && video_stream->codec) { fprintf(stderr, "Flushing delayed frames...\n"); flush_ffmpeg (); @@ -971,11 +983,11 @@ void end_ffmpeg(void) video_buffer = 0; } if (audio_output_buffer) { - MEM_freeN(audio_output_buffer); + av_free(audio_output_buffer); audio_output_buffer = 0; } if (audio_input_buffer) { - MEM_freeN(audio_input_buffer); + av_free(audio_input_buffer); audio_input_buffer = 0; } @@ -1299,6 +1311,9 @@ void ffmpeg_verify_image_type(RenderData *rd) /* Don't set preset, disturbs render resolution. * ffmpeg_set_preset(rd, FFMPEG_PRESET_DVD); */ } + if(rd->ffcodecdata.type == FFMPEG_OGG) { + rd->ffcodecdata.type = FFMPEG_MPEG2; + } audio= 1; } diff --git a/source/blender/blenkernel/intern/writeframeserver.c b/source/blender/blenkernel/intern/writeframeserver.c index 2239f6d3147..d13d15d1269 100644 --- a/source/blender/blenkernel/intern/writeframeserver.c +++ b/source/blender/blenkernel/intern/writeframeserver.c @@ -22,6 +22,7 @@ * */ +#ifdef WITH_FRAMESERVER #include <string.h> #include <stdio.h> @@ -381,3 +382,4 @@ void end_frameserver(void) shutdown_socket_system(); } +#endif /* WITH_FRAMESERVER */ |