patch [#21740] Image support for Empty Objects
authorCampbell Barton <ideasman42@gmail.com>
Mon, 9 May 2011 16:31:54 +0000 (16:31 +0000)
committerCampbell Barton <ideasman42@gmail.com>
Mon, 9 May 2011 16:31:54 +0000 (16:31 +0000)
from Andy Braham (andybraham)

This adds support for empties to reference images and draw in the 3D view.

Modifications from the original patch.
- use an empty draw 'image' type
- use image aspect ratio for non-square-pixels
- when the image is not found, still draw the frame.

release/scripts/startup/bl_ui/properties_data_empty.py
source/blender/editors/space_view3d/drawobject.c
source/blender/makesdna/DNA_object_types.h
source/blender/makesrna/intern/rna_object.c
source/blender/makesrna/intern/rna_ui_api.c

index e46cd1270adb2fa9c014672ee93a2fb197d8753d..80f83e7fabefa4b75fa8540bda59a1d23e6f94df 100644 (file)
@@ -39,6 +39,17 @@ class DATA_PT_empty(DataButtonsPanel, bpy.types.Panel):
         ob = context.object
 
         layout.prop(ob, "empty_draw_type", text="Display")
+
+        if ob.empty_draw_type == 'IMAGE':
+            # layout.template_image(ob, "data", None)
+            layout.template_ID(ob, "data", open="image.open", unlink="image.unlink")
+
+            row = layout.row(align = True)
+            row.prop(ob, "color", text="Transparency", index=3, slider=True)
+            row = layout.row(align = True)
+            row.prop(ob, "empty_image_offset", text="Offset X", index=0)
+            row.prop(ob, "empty_image_offset", text="Offset Y", index=1)
+
         layout.prop(ob, "empty_draw_size", text="Size")
 
 if __name__ == "__main__":  # only for live edit.
index a3a139181d5bfa680e62fa5ad79f7e8c0f9669a7..ba30aecc9ab8bce1aae0684b3bd4a5b9a5f6da01 100644 (file)
@@ -46,6 +46,7 @@
 #include "DNA_scene_types.h"
 #include "DNA_smoke_types.h"
 #include "DNA_world_types.h"
+#include "DNA_armature_types.h"
 
 #include "BLI_blenlib.h"
 #include "BLI_math.h"
@@ -76,6 +77,9 @@
 
 #include "smoke_API.h"
 
+#include "IMB_imbuf.h"
+#include "IMB_imbuf_types.h"
+
 #include "BIF_gl.h"
 #include "BIF_glutil.h"
 
@@ -515,6 +519,96 @@ void drawaxes(float size, char drawtype)
        }
 }
 
+
+/* Function to draw an Image on a empty Object */
+static void draw_empty_image(Object *ob)
+{
+       Image *ima = (Image*)ob->data;
+       ImBuf *ibuf = ima ? BKE_image_get_ibuf(ima, NULL) : NULL;
+
+       float scale, ofs_x, ofs_y, sca_x, sca_y;
+       int ima_x, ima_y;
+
+       if(ibuf && (ibuf->rect == NULL) && (ibuf->rect_float != NULL)) {
+               IMB_rect_from_float(ibuf);
+       }
+
+       /* Get the buffer dimensions so we can fallback to fake ones */
+       if(ibuf && ibuf->rect) {
+               ima_x= ibuf->x;
+               ima_y= ibuf->y;
+       }
+       else {
+               ima_x= 1;
+               ima_y= 1;
+       }
+
+       /* Get the image aspect even if the buffer is invalid */
+       if(ima) {
+               if(ima->aspx > ima->aspy) {
+                       sca_x= 1.0f;
+                       sca_y= ima->aspy / ima->aspx;
+               }
+               else if(ima->aspx < ima->aspy) {
+                       sca_x= ima->aspx / ima->aspy;
+                       sca_y= 1.0f;
+               }
+               else {
+                       sca_x= 1.0f;
+                       sca_y= 1.0f;
+               }
+       }
+       else {
+               sca_x= 1.0f;
+               sca_y= 1.0f;
+       }
+
+       /* Calculate the scale center based on objects origin */
+       ofs_x= ob->ima_ofs[0] * ima_x;
+       ofs_y= ob->ima_ofs[1] * ima_y;
+
+       glMatrixMode(GL_MODELVIEW);
+       glPushMatrix();
+
+       /* Make sure we are drawing at the origin */
+       glTranslatef(0.0f,  0.0f,  0.0f);
+
+       /* Calculate Image scale */
+       scale= (ob->empty_drawsize / (float)MAX2(ima_x * sca_x, ima_y * sca_y));
+
+       /* Set the object scale */
+       glScalef(scale * sca_x, scale * sca_y, 1.0f);
+
+       if(ibuf && ibuf->rect) {
+               /* Setup GL params */
+               glEnable(GL_BLEND);
+               glBlendFunc(GL_SRC_ALPHA,  GL_ONE_MINUS_SRC_ALPHA);
+
+               /* Use the object color and alpha */
+               glColor4fv(ob->col);
+
+               /* Draw the Image on the screen */
+               glaDrawPixelsTex(ofs_x, ofs_y, ima_x, ima_y, GL_UNSIGNED_BYTE, ibuf->rect);
+               glPixelTransferf(GL_ALPHA_SCALE, 1.0f);
+
+               glDisable(GL_BLEND);
+       }
+
+       UI_ThemeColor((ob->flag & SELECT) ? TH_SELECT : TH_WIRE);
+
+       /* Calculate the outline vertex positions */
+       glBegin(GL_LINE_LOOP);
+       glVertex2f(ofs_x, ofs_y);
+       glVertex2f(ofs_x + ima_x, ofs_y);
+       glVertex2f(ofs_x + ima_x, ofs_y + ima_y);
+       glVertex2f(ofs_x, ofs_y + ima_y);
+       glEnd();
+
+       /* Reset GL settings */
+       glMatrixMode(GL_MODELVIEW);
+       glPopMatrix();
+}
+
 void drawcircball(int mode, const float cent[3], float rad, float tmat[][4])
 {
        float vec[3], vx[3], vy[3];
@@ -5954,8 +6048,14 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, int flag)
                        break;
                }
                case OB_EMPTY:
-                       if((v3d->flag2 & V3D_RENDER_OVERRIDE)==0)
-                               drawaxes(ob->empty_drawsize, ob->empty_drawtype);
+                       if((v3d->flag2 & V3D_RENDER_OVERRIDE)==0) {
+                               if (ob->empty_drawtype == OB_EMPTY_IMAGE) {
+                                       draw_empty_image(ob);
+                               }
+                               else {
+                                       drawaxes(ob->empty_drawsize, ob->empty_drawtype);
+                               }
+                       }
                        break;
                case OB_LAMP:
                        if((v3d->flag2 & V3D_RENDER_OVERRIDE)==0) {
@@ -6564,7 +6664,12 @@ void draw_object_instance(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object
                        draw_object_mesh_instance(scene, v3d, rv3d, ob, dt, outline);
                        break;
                case OB_EMPTY:
-                       drawaxes(ob->empty_drawsize, ob->empty_drawtype);
+                       if (ob->empty_drawtype == OB_EMPTY_IMAGE) {
+                               draw_empty_image(ob);
+                       }
+                       else {
+                               drawaxes(ob->empty_drawsize, ob->empty_drawtype);
+                       }
                        break;
        }
 }
index c97a1d8fef5addbae5f8c01ae6cc61310b2c53a2..54a885a08605525fa2e21a94586422a6545ba703 100644 (file)
@@ -259,6 +259,9 @@ typedef struct Object {
        ListBase gpulamp;               /* runtime, for lamps only */
        ListBase pc_ids;
        ListBase *duplilist;    /* for temporary dupli list storage, only for use by RNA API */
+
+       float ima_ofs[2];               /* offset for image empties */
+       char pad3[8];
 } Object;
 
 /* Warning, this is not used anymore because hooks are now modifiers */
@@ -399,6 +402,7 @@ extern Object workob;
 #define OB_CUBE                        5
 #define OB_EMPTY_SPHERE        6
 #define OB_EMPTY_CONE  7
+#define OB_EMPTY_IMAGE 8
 
 /* boundtype */
 #define OB_BOUND_BOX           0
index 11e7dd81cb6335ba007679d9b4fd849960e0c65e..d5d7f2917b96bcb7c22f4bb173517fc72fefaf67 100644 (file)
@@ -307,22 +307,26 @@ static void rna_Base_layer_update(Main *bmain, Scene *scene, PointerRNA *ptr)
        WM_main_add_notifier(NC_SCENE|ND_LAYER_CONTENT, scene);
 }
 
-static int rna_Object_data_editable(PointerRNA *ptr)
-{
-       Object *ob= (Object*)ptr->data;
-
-       return (ob->type == OB_EMPTY)? 0: PROP_EDITABLE;
-}
-
 static void rna_Object_data_set(PointerRNA *ptr, PointerRNA value)
 {
        Object *ob= (Object*)ptr->data;
        ID *id= value.data;
 
-       if(ob->type == OB_EMPTY || id == NULL || ob->mode & OB_MODE_EDIT)
+       if (id == NULL || ob->mode & OB_MODE_EDIT)
                return;
-       
-       if(ob->type == OB_MESH) {
+
+       if (ob->type == OB_EMPTY) {
+               if(ob->data) {
+                       id_us_min((ID*)ob->data);
+                       ob->data = NULL;
+               }
+
+               if (id && GS(id->name) == ID_IM) {
+                       id_us_plus(id);
+                       ob->data = id;
+               }
+       }
+       else if(ob->type == OB_MESH) {
                set_mesh(ob, (Mesh*)id);
        }
        else {
@@ -346,6 +350,7 @@ static StructRNA *rna_Object_data_typef(PointerRNA *ptr)
        Object *ob= (Object*)ptr->data;
 
        switch(ob->type) {
+               case OB_EMPTY: return &RNA_Image;
                case OB_MESH: return &RNA_Mesh;
                case OB_CURVE: return &RNA_Curve;
                case OB_SURF: return &RNA_Curve;
@@ -1691,6 +1696,7 @@ static void rna_def_object(BlenderRNA *brna)
                {OB_CUBE, "CUBE", 0, "Cube", ""},
                {OB_EMPTY_SPHERE, "SPHERE", 0, "Sphere", ""},
                {OB_EMPTY_CONE, "CONE", 0, "Cone", ""},
+               {OB_EMPTY_IMAGE, "IMAGE", 0, "Image", ""},
                {0, NULL, 0, NULL, NULL}};
        
        static EnumPropertyItem track_items[] = {
@@ -1758,7 +1764,6 @@ static void rna_def_object(BlenderRNA *brna)
        prop= RNA_def_property(srna, "data", PROP_POINTER, PROP_NONE);
        RNA_def_property_struct_type(prop, "ID");
        RNA_def_property_pointer_funcs(prop, NULL, "rna_Object_data_set", "rna_Object_data_typef", NULL);
-       RNA_def_property_editable_func(prop, "rna_Object_data_editable");
        RNA_def_property_flag(prop, PROP_EDITABLE|PROP_NEVER_UNLINK);
        RNA_def_property_ui_text(prop, "Data", "Object data");
        RNA_def_property_update(prop, 0, "rna_Object_internal_update_data");
@@ -2043,6 +2048,12 @@ static void rna_def_object(BlenderRNA *brna)
        RNA_def_property_ui_text(prop, "Empty Display Size", "Size of display for empties in the viewport");
        RNA_def_property_update(prop, NC_OBJECT|ND_DRAW, NULL);
 
+       prop= RNA_def_property(srna, "empty_image_offset", PROP_FLOAT, PROP_DISTANCE);
+       RNA_def_property_float_sdna(prop, NULL, "ima_ofs");
+       RNA_def_property_ui_text(prop, "Origin Offset", "Origin offset distance");
+       RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 0.1f, 2);
+       RNA_def_property_update(prop, NC_OBJECT|ND_DRAW, NULL);
+
        /* render */
        prop= RNA_def_property(srna, "pass_index", PROP_INT, PROP_UNSIGNED);
        RNA_def_property_int_sdna(prop, NULL, "index");
index ae308b9423f4ac253bd1f9bbd6bc352017dbbdbb..d4ac98802905fe104d89aff712cc7c4da5249fbd 100644 (file)
@@ -389,7 +389,7 @@ void RNA_api_ui_layout(StructRNA *srna)
        RNA_def_function_flag(func, FUNC_USE_CONTEXT);
        api_ui_item_rna_common(func);
        parm= RNA_def_pointer(func, "image_user", "ImageUser", "", "");
-       RNA_def_property_flag(parm, PROP_REQUIRED|PROP_RNAPTR);
+       RNA_def_property_flag(parm, PROP_REQUIRED|PROP_RNAPTR|PROP_NEVER_NULL);
        RNA_def_boolean(func, "compact", 0, "", "Use more compact layout.");
 
        func= RNA_def_function(srna, "template_list", "uiTemplateList");