First step to handle missing libs/datablocks when reading a file.
authorBastien Montagne <montagne29@wanadoo.fr>
Tue, 20 Oct 2015 12:44:57 +0000 (14:44 +0200)
committerBastien Montagne <montagne29@wanadoo.fr>
Tue, 20 Oct 2015 12:44:57 +0000 (14:44 +0200)
Idea is, instead of ignoring completely missing linked datablocks, to
create void placeholders for them.

That way, you can work on your file, save it, and find again your missing data once
lib becomes available again. Or you can edit missing lib's path (in Outliner),
save and reload the file, and you are done.

Also, Outliner now shows broken libraries (and placeholders) with a 'broken lib' icon.

Future plans are also to be able to relocate missing libs and reload them at runtime.

Code notes:
    - Placeholder ID is just a regular datablock of same type as expected linked one,
      with 'default' data, and a LIB_MISSING bitflag set.
    - To allow creation of such datablocks, creation of datablocks in BKE was split in two step:
        + Allocation of memory itself.
        + Setting of all internal data to default values.

See also the design task (T43351).

Reviewed by @campbellbarton, thanks a bunch!

Differential Revision: https://developer.blender.org/D1394

38 files changed:
source/blender/blenkernel/BKE_brush.h
source/blender/blenkernel/BKE_camera.h
source/blender/blenkernel/BKE_curve.h
source/blender/blenkernel/BKE_font.h
source/blender/blenkernel/BKE_lamp.h
source/blender/blenkernel/BKE_lattice.h
source/blender/blenkernel/BKE_library.h
source/blender/blenkernel/BKE_linestyle.h
source/blender/blenkernel/BKE_material.h
source/blender/blenkernel/BKE_mball.h
source/blender/blenkernel/BKE_mesh.h
source/blender/blenkernel/BKE_node.h
source/blender/blenkernel/BKE_object.h
source/blender/blenkernel/BKE_scene.h
source/blender/blenkernel/BKE_speaker.h
source/blender/blenkernel/BKE_text.h
source/blender/blenkernel/BKE_world.h
source/blender/blenkernel/intern/brush.c
source/blender/blenkernel/intern/camera.c
source/blender/blenkernel/intern/curve.c
source/blender/blenkernel/intern/font.c
source/blender/blenkernel/intern/lamp.c
source/blender/blenkernel/intern/lattice.c
source/blender/blenkernel/intern/library.c
source/blender/blenkernel/intern/linestyle.c
source/blender/blenkernel/intern/material.c
source/blender/blenkernel/intern/mball.c
source/blender/blenkernel/intern/mesh.c
source/blender/blenkernel/intern/node.c
source/blender/blenkernel/intern/object.c
source/blender/blenkernel/intern/scene.c
source/blender/blenkernel/intern/speaker.c
source/blender/blenkernel/intern/text.c
source/blender/blenkernel/intern/texture.c
source/blender/blenkernel/intern/world.c
source/blender/blenloader/intern/readfile.c
source/blender/editors/space_outliner/outliner_draw.c
source/blender/makesdna/DNA_ID.h

index aff3fb08df66734fb57a551cb483ece40d571f03..bb3ad0efb63ad8785383518a559bc0ec10429ae6 100644 (file)
@@ -40,6 +40,7 @@ void BKE_brush_system_init(void);
 void BKE_brush_system_exit(void);
 
 /* datablock functions */
+void BKE_brush_init(struct Brush *brush);
 struct Brush *BKE_brush_add(struct Main *bmain, const char *name, short ob_mode);
 struct Brush *BKE_brush_first_search(struct Main *bmain, short ob_mode);
 struct Brush *BKE_brush_copy(struct Brush *brush);
index aacb7a4066bb742037eeae33eaf6496434665e3e..118153a9163ea1edf68417ba88652bad21541193 100644 (file)
@@ -50,6 +50,7 @@ struct GPUFXSettings;
 
 /* Camera Datablock */
 
+void BKE_camera_init(struct Camera *cam);
 void *BKE_camera_add(struct Main *bmain, const char *name);
 struct Camera *BKE_camera_copy(struct Camera *cam);
 void BKE_camera_make_local(struct Camera *cam);
index a03dd2871467d0d617971c215bb67f9e8e4dcb4d..061270b8b4127aaaa150f6da3b779604d05d0d73 100644 (file)
@@ -69,6 +69,7 @@ typedef struct CurveCache {
 void BKE_curve_unlink(struct Curve *cu);
 void BKE_curve_free(struct Curve *cu);
 void BKE_curve_editfont_free(struct Curve *cu);
+void BKE_curve_init(struct Curve *cu);
 struct Curve *BKE_curve_add(struct Main *bmain, const char *name, int type);
 struct Curve *BKE_curve_copy(struct Curve *cu);
 void BKE_curve_make_local(struct Curve *cu);
index f20c166aa6dfdf7be4f49fbacd4f4d26051b2f58..5dcc6f8d981a046b722b4d4bd764a3d60a3758ca 100644 (file)
@@ -79,6 +79,7 @@ void BKE_vfont_builtin_register(void *mem, int size);
 
 void BKE_vfont_free_data(struct VFont *vfont);
 void BKE_vfont_free(struct VFont *sc); 
+void BKE_vfont_init(struct VFont *vfont);
 struct VFont *BKE_vfont_builtin_get(void);
 struct VFont *BKE_vfont_load(struct Main *bmain, const char *filepath);
 struct VFont *BKE_vfont_load_exists_ex(struct Main *bmain, const char *filepath, bool *r_exists);
index fb2c4da91ea344c873d7bc48cfc4d9b6879a62b6..d830c19651fd5e8dc100b512a0db68a07b2fb84b 100644 (file)
@@ -42,6 +42,7 @@ struct Lamp;
 struct Main;
 struct Scene;
 
+void BKE_lamp_init(struct Lamp *la);
 struct Lamp *BKE_lamp_add(struct Main *bmain, const char *name) ATTR_WARN_UNUSED_RESULT;
 struct Lamp *BKE_lamp_copy(struct Lamp *la) ATTR_WARN_UNUSED_RESULT;
 struct Lamp *localize_lamp(struct Lamp *la) ATTR_WARN_UNUSED_RESULT;
index 677d8e342290c955d05070cc00db652bc77b8a66..828a40de1c9f7c1f29c6b4b9eb1fb10dff9f8a6a 100644 (file)
@@ -45,6 +45,7 @@ struct BPoint;
 struct MDeformVert;
 
 void BKE_lattice_resize(struct Lattice *lt, int u, int v, int w, struct Object *ltOb);
+void BKE_lattice_init(struct Lattice *lt);
 struct Lattice *BKE_lattice_add(struct Main *bmain, const char *name);
 struct Lattice *BKE_lattice_copy(struct Lattice *lt);
 void BKE_lattice_free(struct Lattice *lt);
index 4fab910b7eebd05977a41071970392b827ca2783..f46ae5617ac1b1872a8b1465d74dc5eec9627128 100644 (file)
@@ -49,7 +49,9 @@ struct bContext;
 struct PointerRNA;
 struct PropertyRNA;
 
+void *BKE_libblock_alloc_notest(short type);
 void *BKE_libblock_alloc(struct Main *bmain, short type, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+void  BKE_libblock_init_empty(struct ID *id);
 void *BKE_libblock_copy_ex(struct Main *bmain, struct ID *id) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
 void *BKE_libblock_copy_nolib(struct ID *id, const bool do_action) ATTR_NONNULL();
 void *BKE_libblock_copy(struct ID *id) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
index e77b4f5e8fe5fb8104fee57b5e6f4ec1d32ff3fe..e3eead4102c801251a8944dda6c30a9985e0cfad 100644 (file)
@@ -49,6 +49,7 @@ struct Object;
 struct ColorBand;
 struct bContext;
 
+void BKE_linestyle_init(struct FreestyleLineStyle *linestyle);
 FreestyleLineStyle *BKE_linestyle_new(struct Main *bmain, const char *name);
 void                BKE_linestyle_free(FreestyleLineStyle *linestyle);
 FreestyleLineStyle *BKE_linestyle_copy(struct Main *bmain, FreestyleLineStyle *linestyle);
index a3c61f44ff2acb2cf2a69c0ad3b5b9941646a026..d32d679e7edfc69adcbd31cb62c057feda8dbd7d 100644 (file)
@@ -49,7 +49,7 @@ void BKE_material_free(struct Material *sc);
 void BKE_material_free_ex(struct Material *ma, bool do_id_user);
 void test_object_materials(struct Main *bmain, struct ID *id);
 void BKE_material_resize_object(struct Object *ob, const short totcol, bool do_id_user);
-void init_material(struct Material *ma);
+void BKE_material_init(struct Material *ma);
 void BKE_material_remap_object(struct Object *ob, const unsigned int *remap);
 struct Material *BKE_material_add(struct Main *bmain, const char *name);
 struct Material *BKE_material_copy(struct Material *ma);
index 62cd50099fd0d50a36b518ebc65dd8e9e831d2e8..0574b88bef3bedbe9f0268066da247ad505d4dfd 100644 (file)
@@ -40,6 +40,7 @@ struct MetaElem;
 
 void BKE_mball_unlink(struct MetaBall *mb);
 void BKE_mball_free(struct MetaBall *mb);
+void BKE_mball_init(struct MetaBall *mb);
 struct MetaBall *BKE_mball_add(struct Main *bmain, const char *name);
 struct MetaBall *BKE_mball_copy(struct MetaBall *mb);
 
index 5bd8931ee2efebefba29db107a399f63a2bb1fad..f35613f8bf7c84fae05bcb79d5af3cf76f8a2380 100644 (file)
@@ -82,6 +82,7 @@ int BKE_mesh_edge_other_vert(const struct MEdge *e, int v);
 
 void BKE_mesh_unlink(struct Mesh *me);
 void BKE_mesh_free(struct Mesh *me, int unlink);
+void BKE_mesh_init(struct Mesh *me);
 struct Mesh *BKE_mesh_add(struct Main *bmain, const char *name);
 struct Mesh *BKE_mesh_copy_ex(struct Main *bmain, struct Mesh *me);
 struct Mesh *BKE_mesh_copy(struct Mesh *me);
index b97bf203a7c625262e1b21c46e81b5203885bcd2..88e54d0ff2ce80cfeec19b4223cae57d1d9aba75 100644 (file)
@@ -337,6 +337,7 @@ struct GHashIterator *ntreeTypeGetIterator(void);
 
 void ntreeSetTypes(const struct bContext *C, struct bNodeTree *ntree);
 
+void ntreeInitDefault(struct bNodeTree *ntree);
 struct bNodeTree *ntreeAddTree(struct Main *bmain, const char *name, const char *idname);
 
 /* copy/free funcs, need to manage ID users */
index f3a1be24af68f5559d35b37b93a023dd895c1025..45d14a35539d0c5fac0b8dae674e3e142b67a492 100644 (file)
@@ -85,6 +85,7 @@ bool BKE_object_is_in_editmode(struct Object *ob);
 bool BKE_object_is_in_editmode_vgroup(struct Object *ob);
 bool BKE_object_is_in_wpaint_select_vert(struct Object *ob);
 
+void BKE_object_init(struct Object *ob);
 struct Object *BKE_object_add_only_object(
         struct Main *bmain,
         int type, const char *name)
index 027bdbbbe58aa1af21b26110aae6919fb0c62440..aa698317e33dbdf8dc8b9debd970b45a37ca62df 100644 (file)
@@ -67,6 +67,7 @@ void free_avicodecdata(struct AviCodecData *acd);
 void free_qtcodecdata(struct QuicktimeCodecData *acd);
 
 void BKE_scene_free(struct Scene *sce);
+void BKE_scene_init(struct Scene *sce);
 struct Scene *BKE_scene_add(struct Main *bmain, const char *name);
 
 /* base functions */
index 5d93b9844ab8f71223fd448bd345268a911c2518..5f30df1d6e31a8f514c3122658a6191e2bd0d308 100644 (file)
@@ -29,7 +29,9 @@
  */
 
 struct Main;
+struct Speaker;
 
+void BKE_speaker_init(struct Speaker *spk);
 void *BKE_speaker_add(struct Main *bmain, const char *name);
 struct Speaker *BKE_speaker_copy(struct Speaker *spk);
 void BKE_speaker_make_local(struct Speaker *spk);
index a5a59d14c92e26bd22c488d9efb942a12a63893d..50e4fa4c41d1c51d96d8bfe99b5f82fa409f08e4 100644 (file)
@@ -44,6 +44,7 @@ struct TextLine;
 void                   BKE_text_free           (struct Text *text);
 void                   txt_set_undostate       (int u);
 int                    txt_get_undostate       (void);
+void            BKE_text_init(struct Text *ta);
 struct Text    *BKE_text_add   (struct Main *bmain, const char *name);
 int                            txt_extended_ascii_as_utf8(char **str);
 bool            BKE_text_reload(struct Text *text);
index 7f4ba6c615ee4f2fcbc759382d15f4c577db156f..8d7ab2309198d3de8dfc722b4fbe46b4500034fb 100644 (file)
@@ -38,6 +38,7 @@ struct World;
 
 void BKE_world_free(struct World *sc);
 void BKE_world_free_ex(struct World *sc, bool do_id_user);
+void BKE_world_init(struct World *wrld);
 struct World *add_world(struct Main *bmian, const char *name);
 struct World *BKE_world_copy(struct World *wrld);
 struct World *localize_world(struct World *wrld);
index e0ffd83080493c33ebf933d103e34b8fcf04ee35..c2a66adbf929aa55150d349fd827151893374bd7 100644 (file)
@@ -131,11 +131,9 @@ static void brush_defaults(Brush *brush)
 
 /* Datablock add/copy/free/make_local */
 
-Brush *BKE_brush_add(Main *bmain, const char *name, short ob_mode)
+void BKE_brush_init(Brush *brush)
 {
-       Brush *brush;
-
-       brush = BKE_libblock_alloc(bmain, ID_BR, name);
+       BLI_assert(MEMCMP_STRUCT_OFS_IS_ZERO(brush, id));
 
        /* enable fake user by default */
        brush->id.flag |= LIB_FAKEUSER;
@@ -143,10 +141,20 @@ Brush *BKE_brush_add(Main *bmain, const char *name, short ob_mode)
        brush_defaults(brush);
 
        brush->sculpt_tool = SCULPT_TOOL_DRAW; /* sculpting defaults to the draw tool for new brushes */
-       brush->ob_mode = ob_mode;
 
        /* the default alpha falloff curve */
        BKE_brush_curve_preset(brush, CURVE_PRESET_SMOOTH);
+}
+
+Brush *BKE_brush_add(Main *bmain, const char *name, short ob_mode)
+{
+       Brush *brush;
+
+       brush = BKE_libblock_alloc(bmain, ID_BR, name);
+
+       BKE_brush_init(brush);
+
+       brush->ob_mode = ob_mode;
 
        return brush;
 }
index 7e043df2808f747bd85f09dac5b624b6ceceeff7..46b74c5896546d838d55e4179d54f5c7eb861974 100644 (file)
 
 /****************************** Camera Datablock *****************************/
 
-void *BKE_camera_add(Main *bmain, const char *name)
+void BKE_camera_init(Camera *cam)
 {
-       Camera *cam;
-       
-       cam =  BKE_libblock_alloc(bmain, ID_CA, name);
+       BLI_assert(MEMCMP_STRUCT_OFS_IS_ZERO(cam, id));
 
        cam->lens = 35.0f;
        cam->sensor_x = DEFAULT_SENSOR_WIDTH;
@@ -78,6 +76,15 @@ void *BKE_camera_add(Main *bmain, const char *name)
        /* stereoscopy 3d */
        cam->stereo.interocular_distance = 0.065f;
        cam->stereo.convergence_distance = 30.f * 0.065f;
+}
+
+void *BKE_camera_add(Main *bmain, const char *name)
+{
+       Camera *cam;
+
+       cam =  BKE_libblock_alloc(bmain, ID_CA, name);
+
+       BKE_camera_init(cam);
 
        return cam;
 }
index 8d7d62be7e4e4d3ef50dafac53c8573e02cf6fb6..3e0bdbe31af1a0936cfda428af78005630c22987 100644 (file)
@@ -161,15 +161,14 @@ void BKE_curve_free(Curve *cu)
                MEM_freeN(cu->tb);
 }
 
-Curve *BKE_curve_add(Main *bmain, const char *name, int type)
+void BKE_curve_init(Curve *cu)
 {
-       Curve *cu;
+       /* BLI_assert(MEMCMP_STRUCT_OFS_IS_ZERO(cu, id)); */  /* cu->type is already initialized... */
 
-       cu = BKE_libblock_alloc(bmain, ID_CU, name);
        copy_v3_fl(cu->size, 1.0f);
        cu->flag = CU_FRONT | CU_BACK | CU_DEFORM_BOUNDS_OFF | CU_PATH_RADIUS;
        cu->pathlen = 100;
-       cu->resolu = cu->resolv = (type == OB_SURF) ? 4 : 12;
+       cu->resolu = cu->resolv = (cu->type == OB_SURF) ? 4 : 12;
        cu->width = 1.0;
        cu->wordspace = 1.0;
        cu->spacing = cu->linedist = 1.0;
@@ -179,7 +178,6 @@ Curve *BKE_curve_add(Main *bmain, const char *name, int type)
        cu->smallcaps_scale = 0.75f;
        /* XXX: this one seems to be the best one in most cases, at least for curve deform... */
        cu->twist_mode = CU_TWIST_MINIMUM;
-       cu->type = type;
        cu->bevfac1 = 0.0f;
        cu->bevfac2 = 1.0f;
        cu->bevfac1_mapping = CU_BEVFAC_MAP_RESOLU;
@@ -187,7 +185,7 @@ Curve *BKE_curve_add(Main *bmain, const char *name, int type)
 
        cu->bb = BKE_boundbox_alloc_unit();
 
-       if (type == OB_FONT) {
+       if (cu->type == OB_FONT) {
                cu->vfont = cu->vfontb = cu->vfonti = cu->vfontbi = BKE_vfont_builtin_get();
                cu->vfont->id.us += 4;
                cu->str = MEM_mallocN(12, "str");
@@ -198,6 +196,16 @@ Curve *BKE_curve_add(Main *bmain, const char *name, int type)
                cu->tb = MEM_callocN(MAXTEXTBOX * sizeof(TextBox), "textbox");
                cu->tb[0].w = cu->tb[0].h = 0.0;
        }
+}
+
+Curve *BKE_curve_add(Main *bmain, const char *name, int type)
+{
+       Curve *cu;
+
+       cu = BKE_libblock_alloc(bmain, ID_CU, name);
+       cu->type = type;
+
+       BKE_curve_init(cu);
 
        return cu;
 }
index e3ebb7f908ce96a54100044031baff4d93abe598..b12e16d95024cb7386d3a8c6ef8afe2283996920 100644 (file)
@@ -203,6 +203,26 @@ static VFontData *vfont_get_data(Main *bmain, VFont *vfont)
        return vfont->data;
 }
 
+/* Bad naming actually in this case... */
+void BKE_vfont_init(VFont *vfont)
+{
+       PackedFile *pf = get_builtin_packedfile();
+
+       if (pf) {
+               VFontData *vfd;
+
+               vfd = BLI_vfontdata_from_freetypefont(pf);
+               if (vfd) {
+                       vfont->data = vfd;
+
+                       BLI_strncpy(vfont->name, FO_BUILTIN_NAME, sizeof(vfont->name));
+               }
+
+               /* Free the packed file */
+               freePackedFile(pf);
+       }
+}
+
 VFont *BKE_vfont_load(Main *bmain, const char *filepath)
 {
        char filename[FILE_MAXFILE];
index 44e35c645debc5307ac37a69cbba953d2b035a13..8e350896eb885156d9ad66d2e8203179cf72a8f9 100644 (file)
 #include "BKE_main.h"
 #include "BKE_node.h"
 
-Lamp *BKE_lamp_add(Main *bmain, const char *name)
+void BKE_lamp_init(Lamp *la)
 {
-       Lamp *la;
-       
-       la =  BKE_libblock_alloc(bmain, ID_LA, name);
-       
+       BLI_assert(MEMCMP_STRUCT_OFS_IS_ZERO(la, id));
+
        la->r = la->g = la->b = la->k = 1.0f;
        la->haint = la->energy = 1.0f;
        la->dist = 25.0f;
@@ -100,6 +98,16 @@ Lamp *BKE_lamp_add(Main *bmain, const char *name)
        la->shadow_frustum_size = 10.0f;
        
        curvemapping_initialize(la->curfalloff);
+}
+
+Lamp *BKE_lamp_add(Main *bmain, const char *name)
+{
+       Lamp *la;
+
+       la =  BKE_libblock_alloc(bmain, ID_LA, name);
+
+       BKE_lamp_init(la);
+
        return la;
 }
 
index 009e1d20328650e2d81f2741322595b76bdf3ad1..0e5228a6db46399e3df2b01e1eb51ee4633f8050 100644 (file)
@@ -251,12 +251,10 @@ void BKE_lattice_resize(Lattice *lt, int uNew, int vNew, int wNew, Object *ltOb)
        MEM_freeN(vertexCos);
 }
 
-Lattice *BKE_lattice_add(Main *bmain, const char *name)
+void BKE_lattice_init(Lattice *lt)
 {
-       Lattice *lt;
-       
-       lt = BKE_libblock_alloc(bmain, ID_LT, name);
-       
+       BLI_assert(MEMCMP_STRUCT_OFS_IS_ZERO(lt, id));
+
        lt->flag = LT_GRID;
        
        lt->typeu = lt->typev = lt->typew = KEY_BSPLINE;
@@ -264,7 +262,16 @@ Lattice *BKE_lattice_add(Main *bmain, const char *name)
        lt->def = MEM_callocN(sizeof(BPoint), "lattvert"); /* temporary */
        BKE_lattice_resize(lt, 2, 2, 2, NULL);  /* creates a uniform lattice */
        lt->actbp = LT_ACTBP_NONE;
-               
+}
+
+Lattice *BKE_lattice_add(Main *bmain, const char *name)
+{
+       Lattice *lt;
+
+       lt = BKE_libblock_alloc(bmain, ID_LT, name);
+
+       BKE_lattice_init(lt);
+
        return lt;
 }
 
index d6b2a3cea29ac6562bfed831cee3b61d289b63e6..f8f928254792b911682e56671760a0016951ca0b 100644 (file)
@@ -59,6 +59,7 @@
 #include "DNA_movieclip_types.h"
 #include "DNA_mask_types.h"
 #include "DNA_node_types.h"
+#include "DNA_object_types.h"
 #include "DNA_scene_types.h"
 #include "DNA_screen_types.h"
 #include "DNA_speaker_types.h"
@@ -648,7 +649,7 @@ int set_listbasepointers(Main *main, ListBase **lb)
  * Allocates and returns memory of the right size for the specified block type,
  * initialized to zero.
  */
-static ID *alloc_libblock_notest(short type)
+void *BKE_libblock_alloc_notest(short type)
 {
        ID *id = NULL;
        
@@ -770,7 +771,7 @@ void *BKE_libblock_alloc(Main *bmain, short type, const char *name)
        ID *id = NULL;
        ListBase *lb = which_libbase(bmain, type);
        
-       id = alloc_libblock_notest(type);
+       id = BKE_libblock_alloc_notest(type);
        if (id) {
                BKE_main_lock(bmain);
                BLI_addtail(lb, id);
@@ -785,6 +786,121 @@ void *BKE_libblock_alloc(Main *bmain, short type, const char *name)
        return id;
 }
 
+/**
+ * Initialize an ID of given type, such that it has valid 'empty' data.
+ * ID is assumed to be just calloc'ed.
+ */
+void BKE_libblock_init_empty(ID *id)
+{
+       /* Note that only ID types that are not valid when filled of zero should have a callback here. */
+       switch (GS(id->name)) {
+               case ID_SCE:
+                       BKE_scene_init((Scene *)id);
+                       break;
+               case ID_LI:
+                       /* Nothing to do. */
+                       break;
+               case ID_OB:
+               {
+                       Object *ob = (Object *)id;
+                       ob->type = OB_EMPTY;
+                       BKE_object_init(ob);
+                       break;
+               }
+               case ID_ME:
+                       BKE_mesh_init((Mesh *)id);
+                       break;
+               case ID_CU:
+                       BKE_curve_init((Curve *)id);
+                       break;
+               case ID_MB:
+                       BKE_mball_init((MetaBall *)id);
+                       break;
+               case ID_MA:
+                       BKE_material_init((Material *)id);
+                       break;
+               case ID_TE:
+                       BKE_texture_default((Tex *)id);
+                       break;
+               case ID_IM:
+                       /* Image is a bit complicated, for now assume NULLified im is OK. */
+                       break;
+               case ID_LT:
+                       BKE_lattice_init((Lattice *)id);
+                       break;
+               case ID_LA:
+                       BKE_lamp_init((Lamp *)id);
+                       break;
+               case ID_SPK:
+                       BKE_speaker_init((Speaker *)id);
+                       break;
+               case ID_CA:
+                       BKE_camera_init((Camera *)id);
+                       break;
+               case ID_IP:
+                       /* Should not be needed - animation from lib pre-2.5 is broken anyway. */
+                       BLI_assert(0);
+                       break;
+               case ID_KE:
+                       /* Shapekeys are a complex topic too - they depend on their 'user' data type...
+                        * They are not linkable, though, so it should never reach here anyway. */
+                       BLI_assert(0);
+                       break;
+               case ID_WO:
+                       BKE_world_init((World *)id);
+                       break;
+               case ID_SCR:
+                       /* Nothing to do. */
+                       break;
+               case ID_VF:
+                       BKE_vfont_init((VFont *)id);
+                       break;
+               case ID_TXT:
+                       BKE_text_init((Text *)id);
+                       break;
+               case ID_SCRIPT:
+                       BLI_assert(0);
+                       break;
+               case ID_SO:
+                       /* Another fuzzy case, think NULLified content is OK here... */
+                       break;
+               case ID_GR:
+                       /* Nothing to do. */
+                       break;
+               case ID_AR:
+                       /* Nothing to do. */
+                       break;
+               case ID_AC:
+                       /* Nothing to do. */
+                       break;
+               case ID_NT:
+                       ntreeInitDefault((bNodeTree *)id);
+                       break;
+               case ID_BR:
+                       BKE_brush_init((Brush *)id);
+                       break;
+               case ID_PA:
+                       /* Nothing to do. */
+                       break;
+               case ID_PC:
+                       /* Nothing to do. */
+                       break;
+               case ID_WM:
+                       /* We should never reach this. */
+                       BLI_assert(0);
+                       break;
+               case ID_GD:
+                       /* Nothing to do. */
+                       break;
+               case ID_MSK:
+                       /* Nothing to do. */
+                       break;
+               case ID_LS:
+                       BKE_linestyle_init((FreestyleLineStyle *)id);
+                       break;
+       }
+}
+
 /* by spec, animdata is first item after ID */
 /* and, trust that BKE_animdata_from_id() will only find AnimData for valid ID-types */
 static void id_copy_animdata(ID *id, const bool do_action)
@@ -838,7 +954,7 @@ void *BKE_libblock_copy_nolib(ID *id, const bool do_action)
        ID *idn;
        size_t idn_len;
 
-       idn = alloc_libblock_notest(GS(id->name));
+       idn = BKE_libblock_alloc_notest(GS(id->name));
        assert(idn != NULL);
 
        BLI_strncpy(idn->name, id->name, sizeof(idn->name));
@@ -1720,7 +1836,7 @@ void rename_id(ID *id, const char *name)
  */
 void name_uiprefix_id(char *name, const ID *id)
 {
-       name[0] = id->lib ? 'L' : ' ';
+       name[0] = id->lib ? (ID_MISSING(id) ? 'M' : 'L') : ' ';
        name[1] = (id->flag & LIB_FAKEUSER) ? 'F' : ((id->us == 0) ? '0' : ' ');
        name[2] = ' ';
 
index ac2c4e35dce1d1763846df71c1b7b52e34e9bfd5..93d2b549feeb2604852a80442d5f994d29fb96f6 100644 (file)
@@ -80,8 +80,10 @@ static const char *modifier_name[LS_MODIFIER_NUM] = {
        "3D Curvature",
 };
 
-static void default_linestyle_settings(FreestyleLineStyle *linestyle)
+void BKE_linestyle_init(FreestyleLineStyle *linestyle)
 {
+       BLI_assert(MEMCMP_STRUCT_OFS_IS_ZERO(linestyle, id));
+
        linestyle->panel = LS_PANEL_STROKES;
        linestyle->r = linestyle->g = linestyle->b = 0.0f;
        linestyle->alpha = 1.0f;
@@ -118,7 +120,7 @@ FreestyleLineStyle *BKE_linestyle_new(struct Main *bmain, const char *name)
 
        linestyle = (FreestyleLineStyle *)BKE_libblock_alloc(bmain, ID_LS, name);
 
-       default_linestyle_settings(linestyle);
+       BKE_linestyle_init(linestyle);
 
        return linestyle;
 }
index 3e7e98b4a1d03fa4822fdd1adcc7489ff514b28c..a69b5fd87b536896a54207a8006425156242d21f 100644 (file)
@@ -78,7 +78,7 @@ Material defmaterial;
 /* called on startup, creator.c */
 void init_def_material(void)
 {
-       init_material(&defmaterial);
+       BKE_material_init(&defmaterial);
 }
 
 /* not material itself */
@@ -122,8 +122,10 @@ void BKE_material_free_ex(Material *ma, bool do_id_user)
                GPU_material_free(&ma->gpumaterial);
 }
 
-void init_material(Material *ma)
+void BKE_material_init(Material *ma)
 {
+       BLI_assert(MEMCMP_STRUCT_OFS_IS_ZERO(ma, id));
+
        ma->r = ma->g = ma->b = ma->ref = 0.8;
        ma->specr = ma->specg = ma->specb = 1.0;
        ma->mirr = ma->mirg = ma->mirb = 1.0;
@@ -221,7 +223,7 @@ Material *BKE_material_add(Main *bmain, const char *name)
 
        ma = BKE_libblock_alloc(bmain, ID_MA, name);
        
-       init_material(ma);
+       BKE_material_init(ma);
        
        return ma;
 }
index c09cd1aabdcf51a85c41228276efe44bba2a6261..bd9fd33158467ea56099e550699e8a286f2f2422 100644 (file)
@@ -91,19 +91,26 @@ void BKE_mball_free(MetaBall *mb)
        if (mb->disp.first) BKE_displist_free(&mb->disp);
 }
 
-MetaBall *BKE_mball_add(Main *bmain, const char *name)
+void BKE_mball_init(MetaBall *mb)
 {
-       MetaBall *mb;
-       
-       mb = BKE_libblock_alloc(bmain, ID_MB, name);
-       
+       BLI_assert(MEMCMP_STRUCT_OFS_IS_ZERO(mb, id));
+
        mb->size[0] = mb->size[1] = mb->size[2] = 1.0;
        mb->texflag = MB_AUTOSPACE;
        
        mb->wiresize = 0.4f;
        mb->rendersize = 0.2f;
        mb->thresh = 0.6f;
-       
+}
+
+MetaBall *BKE_mball_add(Main *bmain, const char *name)
+{
+       MetaBall *mb;
+
+       mb = BKE_libblock_alloc(bmain, ID_MB, name);
+
+       BKE_mball_init(mb);
+
        return mb;
 }
 
index b948ed56c567d84064dd7a6219ef5019468ff244..318040db2be382f0b2629f741bea04ae4b5f928b 100644 (file)
@@ -490,12 +490,10 @@ static void mesh_tessface_clear_intern(Mesh *mesh, int free_customdata)
        mesh->totface = 0;
 }
 
-Mesh *BKE_mesh_add(Main *bmain, const char *name)
+void BKE_mesh_init(Mesh *me)
 {
-       Mesh *me;
-       
-       me = BKE_libblock_alloc(bmain, ID_ME, name);
-       
+       BLI_assert(MEMCMP_STRUCT_OFS_IS_ZERO(me, id));
+
        me->size[0] = me->size[1] = me->size[2] = 1.0;
        me->smoothresh = 30;
        me->texflag = ME_AUTOSPACE;
@@ -511,6 +509,15 @@ Mesh *BKE_mesh_add(Main *bmain, const char *name)
        CustomData_reset(&me->fdata);
        CustomData_reset(&me->pdata);
        CustomData_reset(&me->ldata);
+}
+
+Mesh *BKE_mesh_add(Main *bmain, const char *name)
+{
+       Mesh *me;
+
+       me = BKE_libblock_alloc(bmain, ID_ME, name);
+
+       BKE_mesh_init(me);
 
        return me;
 }
index c656931d18b0779d46c61406602f76d5f78f4c2d..d3460dcb4816eae77b2e6972a55adda5254200df 100644 (file)
@@ -1151,6 +1151,11 @@ void nodeDetachNode(struct bNode *node)
        }
 }
 
+void ntreeInitDefault(bNodeTree *ntree)
+{
+       ntree_set_typeinfo(ntree, NULL);
+}
+
 bNodeTree *ntreeAddTree(Main *bmain, const char *name, const char *idname)
 {
        bNodeTree *ntree;
index e5f826f670d44beddbcc4ca25d0f538701574f7b..ffb614fdf1144f34ccaa73aa5a266a72b2dd4a27 100644 (file)
@@ -972,19 +972,10 @@ void *BKE_object_obdata_add_from_type(Main *bmain, int type, const char *name)
        }
 }
 
-/* more general add: creates minimum required data, but without vertices etc. */
-Object *BKE_object_add_only_object(Main *bmain, int type, const char *name)
+void BKE_object_init(Object *ob)
 {
-       Object *ob;
+       /* BLI_assert(MEMCMP_STRUCT_OFS_IS_ZERO(ob, id)); */  /* ob->type is already initialized... */
 
-       if (!name)
-               name = get_obdata_defname(type);
-
-       ob = BKE_libblock_alloc(bmain, ID_OB, name);
-
-       /* default object vars */
-       ob->type = type;
-       
        ob->col[0] = ob->col[1] = ob->col[2] = 1.0;
        ob->col[3] = 1.0;
        
@@ -1012,7 +1003,7 @@ Object *BKE_object_add_only_object(Main *bmain, int type, const char *name)
        ob->empty_drawtype = OB_PLAINAXES;
        ob->empty_drawsize = 1.0;
 
-       if (ELEM(type, OB_LAMP, OB_CAMERA, OB_SPEAKER)) {
+       if (ELEM(ob->type, OB_LAMP, OB_CAMERA, OB_SPEAKER)) {
                ob->trackflag = OB_NEGZ;
                ob->upflag = OB_POSY;
        }
@@ -1053,6 +1044,22 @@ Object *BKE_object_add_only_object(Main *bmain, int type, const char *name)
        
        /* Animation Visualization defaults */
        animviz_settings_init(&ob->avs);
+}
+
+/* more general add: creates minimum required data, but without vertices etc. */
+Object *BKE_object_add_only_object(Main *bmain, int type, const char *name)
+{
+       Object *ob;
+
+       if (!name)
+               name = get_obdata_defname(type);
+
+       ob = BKE_libblock_alloc(bmain, ID_OB, name);
+
+       /* default object vars */
+       ob->type = type;
+
+       BKE_object_init(ob);
 
        return ob;
 }
index 1ccc213006ad74b4dc106badbce7f72a21392f6c..cc656775c1457daacc43911dc95a93655ec5b00c 100644 (file)
@@ -464,15 +464,15 @@ void BKE_scene_free(Scene *sce)
        BKE_previewimg_free(&sce->preview);
 }
 
-Scene *BKE_scene_add(Main *bmain, const char *name)
+void BKE_scene_init(Scene *sce)
 {
-       Scene *sce;
        ParticleEditSettings *pset;
        int a;
        const char *colorspace_name;
        SceneRenderView *srv;
 
-       sce = BKE_libblock_alloc(bmain, ID_SCE, name);
+       BLI_assert(MEMCMP_STRUCT_OFS_IS_ZERO(sce, id));
+
        sce->lay = sce->layact = 1;
        
        sce->r.mode = R_GAMMA | R_OSA | R_SHADOW | R_SSS | R_ENVMAP | R_RAYTRACE;
@@ -743,6 +743,15 @@ Scene *BKE_scene_add(Main *bmain, const char *name)
        copy_v2_fl2(sce->safe_areas.action_center, 15.0f / 100.0f, 5.0f / 100.0f);
 
        sce->preview = NULL;
+}
+
+Scene *BKE_scene_add(Main *bmain, const char *name)
+{
+       Scene *sce;
+
+       sce = BKE_libblock_alloc(bmain, ID_SCE, name);
+
+       BKE_scene_init(sce);
 
        return sce;
 }
index 7a800555144294300828dfadbd457e7d4484fec8..30296c7813c0f1d963349cff9af44f375de4bf4a 100644 (file)
 #include "BKE_main.h"
 #include "BKE_speaker.h"
 
-void *BKE_speaker_add(Main *bmain, const char *name)
+void BKE_speaker_init(Speaker *spk)
 {
-       Speaker *spk;
-
-       spk =  BKE_libblock_alloc(bmain, ID_SPK, name);
+       BLI_assert(MEMCMP_STRUCT_OFS_IS_ZERO(spk, id));
 
        spk->attenuation = 1.0f;
        spk->cone_angle_inner = 360.0f;
@@ -55,6 +53,15 @@ void *BKE_speaker_add(Main *bmain, const char *name)
        spk->volume = 1.0f;
        spk->volume_max = 1.0f;
        spk->volume_min = 0.0f;
+}
+
+void *BKE_speaker_add(Main *bmain, const char *name)
+{
+       Speaker *spk;
+
+       spk =  BKE_libblock_alloc(bmain, ID_SPK, name);
+
+       BKE_speaker_init(spk);
 
        return spk;
 }
index 77d6043d6f35015c064a60c528262621e71d36bf..6e41ed3f9a6730c7f982f316e827683d63aad11b 100644 (file)
@@ -171,14 +171,12 @@ void BKE_text_free(Text *text)
 #endif
 }
 
-Text *BKE_text_add(Main *bmain, const char *name) 
+void BKE_text_init(Text *ta)
 {
-       Text *ta;
        TextLine *tmp;
-       
-       ta = BKE_libblock_alloc(bmain, ID_TXT, name);
-       ta->id.us = 1;
-       
+
+       BLI_assert(MEMCMP_STRUCT_OFS_IS_ZERO(ta, id));
+
        ta->name = NULL;
 
        init_undo_text(ta);
@@ -206,6 +204,15 @@ Text *BKE_text_add(Main *bmain, const char *name)
        ta->curc = 0;
        ta->sell = ta->lines.first;
        ta->selc = 0;
+}
+
+Text *BKE_text_add(Main *bmain, const char *name)
+{
+       Text *ta;
+
+       ta = BKE_libblock_alloc(bmain, ID_TXT, name);
+
+       BKE_text_init(ta);
 
        return ta;
 }
index 88a412d5e95d8f40bb4588f1bc2b64eeafc5c8ec..463ca250ad51bcfabd92a6655ae5588dc8edb92c 100644 (file)
@@ -580,6 +580,8 @@ void BKE_texture_free(Tex *tex)
 
 void BKE_texture_default(Tex *tex)
 {
+       /* BLI_assert(MEMCMP_STRUCT_OFS_IS_ZERO(tex, id)); */  /* Not here, can be called with some pointers set. :/ */
+
        tex->type = TEX_IMAGE;
        tex->ima = NULL;
        tex->stype = 0;
index e4736b1f54c5fe1bc09a43502fff943df12ba142..88c98b6d9d83ff03ae985f01701736985f98f395 100644 (file)
@@ -31,6 +31,7 @@
 
 
 #include <string.h>
+#include <stdlib.h>
 #include <math.h>
 #include "MEM_guardedalloc.h"
 
@@ -83,12 +84,10 @@ void BKE_world_free(World *wrld)
        BKE_world_free_ex(wrld, true);
 }
 
-World *add_world(Main *bmain, const char *name)
+void BKE_world_init(World *wrld)
 {
-       World *wrld;
+       BLI_assert(MEMCMP_STRUCT_OFS_IS_ZERO(wrld, id));
 
-       wrld = BKE_libblock_alloc(bmain, ID_WO, name);
-       
        wrld->horr = 0.05f;
        wrld->horg = 0.05f;
        wrld->horb = 0.05f;
@@ -113,6 +112,15 @@ World *add_world(Main *bmain, const char *name)
        wrld->preview = NULL;
        wrld->miststa = 5.0f;
        wrld->mistdist = 25.0f;
+}
+
+World *add_world(Main *bmain, const char *name)
+{
+       World *wrld;
+
+       wrld = BKE_libblock_alloc(bmain, ID_WO, name);
+
+       BKE_world_init(wrld);
 
        return wrld;
 }
index 2e7969637a31b27b2dadefdc14a8a5320af7b1ba..6545a3b0e6734642248f5cd67834208e07e8afb3 100644 (file)
@@ -7937,7 +7937,7 @@ static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, int flag, ID
        if (id->flag & LIB_FAKEUSER) id->us= 1;
        else id->us = 0;
        id->icon_id = 0;
-       id->flag &= ~(LIB_ID_RECALC|LIB_ID_RECALC_DATA|LIB_DOIT);
+       id->flag &= ~(LIB_ID_RECALC | LIB_ID_RECALC_DATA | LIB_DOIT | LIB_MISSING);
        
        /* this case cannot be direct_linked: it's just the ID part */
        if (bhead->code == ID_ID) {
@@ -9615,6 +9615,25 @@ static void give_base_to_groups(
        }
 }
 
+static ID *create_placeholder(Main *mainvar, const char *idname, const short flag)
+{
+       const short idcode = GS(idname);
+       ListBase *lb = which_libbase(mainvar, idcode);
+       ID *ph_id = BKE_libblock_alloc_notest(idcode);
+
+       memcpy(ph_id->name, idname, sizeof(ph_id->name));
+       BKE_libblock_init_empty(ph_id);
+       ph_id->lib = mainvar->curlib;
+       ph_id->flag = flag | LIB_MISSING;
+       ph_id->us = (flag & LIB_FAKEUSER) ? 1 : 0;
+       ph_id->icon_id = 0;
+
+       BLI_addtail(lb, ph_id);
+       id_sort_by_name(lb, ph_id);
+
+       return ph_id;
+}
+
 /* returns true if the item was found
  * but it may already have already been appended/linked */
 static ID *link_named_part(Main *mainl, FileData *fd, const short idcode, const char *name)
@@ -9758,16 +9777,35 @@ ID *BLO_library_link_named_part_ex(
        return link_named_part_ex(mainl, fd, idcode, name, flag, scene, v3d);
 }
 
-static void link_id_part(FileData *fd, Main *mainvar, ID *id, ID **r_id)
+static void link_id_part(ReportList *reports, FileData *fd, Main *mainvar, ID *id, ID **r_id)
 {
-       BHead *bhead = find_bhead_from_idname(fd, id->name);
+       BHead *bhead = NULL;
+
+       if (fd) {
+               bhead = find_bhead_from_idname(fd, id->name);
+       }
+
+       id->flag &= ~LIB_READ;
 
        if (bhead) {
-               id->flag &= ~LIB_READ;
                id->flag |= LIB_NEED_EXPAND;
                // printf("read lib block %s\n", id->name);
                read_libblock(fd, mainvar, bhead, id->flag, r_id);
        }
+       else {
+               blo_reportf_wrap(
+                       reports, RPT_WARNING,
+                       TIP_("LIB ERROR: %s: '%s' missing from '%s', parent '%s'"),
+                       BKE_idcode_to_name(GS(id->name)),
+                       id->name + 2,
+                       mainvar->curlib->filepath,
+                       library_parent_filepath(mainvar->curlib));
+
+               /* Generate a placeholder for this ID (simplified version of read_libblock actually...). */
+               if (r_id) {
+                       *r_id = create_placeholder(mainvar, id->name, id->flag);
+               }
+       }
 }
 
 /* common routine to append/link something from a library */
@@ -10012,6 +10050,7 @@ static void read_libraries(FileData *basefd, ListBase *mainlist)
                                        }
                                        else {
                                                mainptr->curlib->filedata = NULL;
+                                               mainptr->curlib->id.flag |= LIB_MISSING;
                                        }
                                        
                                        if (fd == NULL) {
@@ -10021,37 +10060,29 @@ static void read_libraries(FileData *basefd, ListBase *mainlist)
                                }
                                if (fd) {
                                        do_it = true;
-                                       a = set_listbasepointers(mainptr, lbarray);
-                                       while (a--) {
-                                               ID *id = lbarray[a]->first;
-                                               
-                                               while (id) {
-                                                       ID *idn = id->next;
-                                                       if (id->flag & LIB_READ) {
-                                                               ID *realid = NULL;
-                                                               BLI_remlink(lbarray[a], id);
-                                                               
-                                                               link_id_part(fd, mainptr, id, &realid);
-                                                               if (!realid) {
-                                                                       blo_reportf_wrap(
-                                                                               fd->reports, RPT_WARNING,
-                                                                               TIP_("LIB ERROR: %s: '%s' missing from '%s', parent '%s'"),
-                                                                               BKE_idcode_to_name(GS(id->name)),
-                                                                               id->name + 2,
-                                                                               mainptr->curlib->filepath,
-                                                                               library_parent_filepath(mainptr->curlib));
-                                                               }
-                                                               
-                                                               change_idid_adr(mainlist, basefd, id, realid);
-                                                               
-                                                               MEM_freeN(id);
-                                                       }
-                                                       id = idn;
+                               }
+                               a = set_listbasepointers(mainptr, lbarray);
+                               while (a--) {
+                                       ID *id = lbarray[a]->first;
+
+                                       while (id) {
+                                               ID *idn = id->next;
+                                               if (id->flag & LIB_READ) {
+                                                       ID *realid = NULL;
+                                                       BLI_remlink(lbarray[a], id);
+
+                                                       link_id_part(basefd->reports, fd, mainptr, id, &realid);
+
+                                                       BLI_assert(realid != NULL);
+
+                                                       change_idid_adr(mainlist, basefd, id, realid);
+
+                                                       MEM_freeN(id);
                                                }
+                                               id = idn;
                                        }
-                                       
-                                       BLO_expand_main(fd, mainptr);
                                }
+                               BLO_expand_main(fd, mainptr);
                        }
                        
                        mainptr = mainptr->next;
@@ -10059,6 +10090,7 @@ static void read_libraries(FileData *basefd, ListBase *mainlist)
        }
        
        /* test if there are unread libblocks */
+       /* XXX This code block is kept for 2.77, until we are sure it never gets reached anymore. Can be removed later. */
        for (mainptr = mainl->next; mainptr; mainptr = mainptr->next) {
                a = set_listbasepointers(mainptr, lbarray);
                while (a--) {
@@ -10067,10 +10099,12 @@ static void read_libraries(FileData *basefd, ListBase *mainlist)
                        for (id = lbarray[a]->first; id; id = idn) {
                                idn = id->next;
                                if (id->flag & LIB_READ) {
+                                       BLI_assert(0);
                                        BLI_remlink(lbarray[a], id);
                                        blo_reportf_wrap(
                                                basefd->reports, RPT_WARNING,
-                                               TIP_("LIB ERROR: %s: '%s' unread lib block missing from '%s', parent '%s'"),
+                                               TIP_("LIB ERROR: %s: '%s' unread lib block missing from '%s', parent '%s' - "
+                                                    "Please file a bug report if you see this message"),
                                                BKE_idcode_to_name(GS(id->name)),
                                                id->name + 2,
                                                mainptr->curlib->filepath,
index ac9e2e36dedb89532125c08103b69c12bef305c3..665ae88d83390a7fe513a71630525d367da5272a 100644 (file)
@@ -1318,7 +1318,16 @@ static void tselem_draw_icon(uiBlock *block, int xmax, float x, float y, TreeSto
                        case ID_GR:
                                tselem_draw_icon_uibut(&arg, ICON_GROUP); break;
                        case ID_LI:
-                               tselem_draw_icon_uibut(&arg, ICON_LIBRARY_DATA_DIRECT); break;
+                               if (tselem->id->flag & LIB_MISSING) {
+                                       tselem_draw_icon_uibut(&arg, ICON_LIBRARY_DATA_BROKEN);
+                               }
+                               else if (((Library *)tselem->id)->parent) {
+                                       tselem_draw_icon_uibut(&arg, ICON_LIBRARY_DATA_INDIRECT);
+                               }
+                               else {
+                                       tselem_draw_icon_uibut(&arg, ICON_LIBRARY_DATA_DIRECT);
+                               }
+                               break;
                        case ID_LS:
                                tselem_draw_icon_uibut(&arg, ICON_LINE_DATA); break;
                        case ID_GD:
@@ -1553,10 +1562,15 @@ static void outliner_draw_tree_element(
                
                if (tselem->type == 0 && tselem->id->lib) {
                        glPixelTransferf(GL_ALPHA_SCALE, 0.5f);
-                       if (tselem->id->flag & LIB_INDIRECT)
+                       if (tselem->id->flag & LIB_MISSING) {
+                               UI_icon_draw((float)startx + offsx, (float)*starty + 2 * ufac, ICON_LIBRARY_DATA_BROKEN);
+                       }
+                       else if (tselem->id->flag & LIB_INDIRECT) {
                                UI_icon_draw((float)startx + offsx, (float)*starty + 2 * ufac, ICON_LIBRARY_DATA_INDIRECT);
-                       else
+                       }
+                       else {
                                UI_icon_draw((float)startx + offsx, (float)*starty + 2 * ufac, ICON_LIBRARY_DATA_DIRECT);
+                       }
                        glPixelTransferf(GL_ALPHA_SCALE, 1.0f);
                        offsx += UI_UNIT_X;
                }
index 342245fa393965462cd5297079f8294740ac1b7d..c2901b8b9a5b5f5e21332354e9ba00121ea84ffe 100644 (file)
@@ -261,6 +261,8 @@ typedef struct PreviewImage {
 
 #define ID_BLEND_PATH(_bmain, _id) ((_id)->lib ? (_id)->lib->filepath : (_bmain)->name)
 
+#define ID_MISSING(_id) (((_id)->flag & LIB_MISSING) != 0)
+
 #ifdef GS
 #  undef GS
 #endif
@@ -280,6 +282,8 @@ enum {
        LIB_TESTIND         = (LIB_NEED_EXPAND | LIB_INDIRECT),
        LIB_READ            = 1 << 4,
        LIB_NEED_LINK       = 1 << 5,
+       /* tag datablock as a place-holder (because the real one could not be linked from its library e.g.). */
+       LIB_MISSING         = 1 << 6,
 
        LIB_NEW             = 1 << 8,
        LIB_FAKEUSER        = 1 << 9,