Merging trunk up to r39145.
[blender-staging.git] / source / blender / makesrna / intern / rna_access.c
index f1056c86a4cb1d0c9380bccdb1a5b3f405497611..ac3508b9b4a389e921036df6bf756961151605b9 100644 (file)
@@ -85,7 +85,9 @@ void RNA_init(void)
 void RNA_exit(void)
 {
        StructRNA *srna;
-
+       
+       RNA_property_update_cache_free();
+       
        for(srna=BLENDER_RNA.structs.first; srna; srna=srna->cont.next) {
                if(srna->cont.prophash) {
                        BLI_ghash_free(srna->cont.prophash, NULL, NULL);
@@ -1391,6 +1393,112 @@ void RNA_property_update_main(Main *bmain, Scene *scene, PointerRNA *ptr, Proper
        rna_property_update(NULL, bmain, scene, ptr, prop);
 }
 
+
+/* RNA Updates Cache ------------------------ */
+/* Overview of RNA Update cache system:
+ *
+ * RNA Update calls need to be cached in order to maintain reasonable performance
+ * of the animation system (i.e. maintaining a somewhat interactive framerate)
+ * while still allowing updates to be called (necessary in particular for modifier
+ * property updates to actually work).
+ *
+ * The cache is structured with a dual-layer structure
+ * - L1 = PointerRNA used as key; id.data is used (it should always be defined,
+ *              and most updates end up using just that anyways)
+ * - L2 = Update functions to be called on those PointerRNA's
+ */
+
+/* cache element */
+typedef struct tRnaUpdateCacheElem {
+       struct tRnaUpdateCacheElem *next, *prev;
+       
+       PointerRNA ptr;         /* L1 key - id as primary, data secondary/ignored? */
+       ListBase L2Funcs;       /* L2 functions (LinkData<RnaUpdateFuncRef>) */
+} tRnaUpdateCacheElem;
+
+/* cache global (tRnaUpdateCacheElem's) - only accessible using these API calls */
+static ListBase rna_updates_cache = {NULL, NULL};
+
+/* ........................... */
+
+void RNA_property_update_cache_add(PointerRNA *ptr, PropertyRNA *prop)
+{
+       tRnaUpdateCacheElem *uce = NULL;
+       UpdateFunc fn = NULL;
+       LinkData *ld;
+       short is_rna = (prop->magic == RNA_MAGIC);
+       
+       /* sanity check */
+       if (ELEM(NULL, ptr, prop))
+               return;
+               
+       prop= rna_ensure_property(prop);
+       
+       /* we can only handle update calls with no context args for now (makes animsys updates easier) */
+       if ((is_rna == 0) || (prop->update == NULL) || (prop->flag & PROP_CONTEXT_UPDATE))
+               return;
+       fn = prop->update;
+               
+       /* find cache element for which key matches... */
+       for (uce = rna_updates_cache.first; uce; uce = uce->next) {
+               /* just match by id only for now, since most update calls that we'll encounter only really care about this */
+               // TODO: later, the cache might need to have some nesting on L1 to cope better with these problems + some tagging to indicate we need this
+               if (uce->ptr.id.data == ptr->id.data)
+                       break;
+       }
+       if (uce == NULL) {
+               /* create new instance */
+               uce = MEM_callocN(sizeof(tRnaUpdateCacheElem), "tRnaUpdateCacheElem");
+               BLI_addtail(&rna_updates_cache, uce);
+               
+               /* copy pointer */
+               RNA_pointer_create(ptr->id.data, ptr->type, ptr->data, &uce->ptr);
+       }
+       
+       /* check on the update func */
+       for (ld = uce->L2Funcs.first; ld; ld = ld->next) {
+               /* stop on match - function already cached */
+               if (fn == ld->data)
+                       return;
+       }
+       /* else... if still here, we need to add it */
+       BLI_addtail(&uce->L2Funcs, BLI_genericNodeN(fn));
+}
+
+void RNA_property_update_cache_flush(Main *bmain, Scene *scene)
+{
+       tRnaUpdateCacheElem *uce;
+       
+       // TODO: should we check that bmain and scene are valid? The above stuff doesn't!
+       
+       /* execute the cached updates */
+       for (uce = rna_updates_cache.first; uce; uce = uce->next) {
+               LinkData *ld;
+               
+               for (ld = uce->L2Funcs.first; ld; ld = ld->next) {
+                       UpdateFunc fn = (UpdateFunc)ld->data;
+                       fn(bmain, scene, &uce->ptr);
+               }
+       }
+}
+
+void RNA_property_update_cache_free(void)
+{
+       tRnaUpdateCacheElem *uce, *ucn;
+       
+       for (uce = rna_updates_cache.first; uce; uce = ucn) {
+               ucn = uce->next;
+               
+               /* free L2 cache */
+               BLI_freelistN(&uce->L2Funcs);
+               
+               /* remove self */
+               BLI_freelinkN(&rna_updates_cache, uce);
+       }
+}
+
+/* ---------------------------------------------------------------------- */
+
 /* Property Data */
 
 int RNA_property_boolean_get(PointerRNA *ptr, PropertyRNA *prop)
@@ -3192,7 +3300,7 @@ static char *rna_path_token(const char **path, char *fixedbuf, int fixedlen, int
                /* 2 kinds of lookups now, quoted or unquoted */
                quote= *p;
 
-               if(quote != '"')
+               if(quote != '"') /* " - this comment is hack for Aligorith's text editor's sanity */
                        quote= 0;
 
                if(quote==0) {