Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrecht Van Lommel <brechtvanlommel@pandora.be>2011-11-08 17:07:16 +0400
committerBrecht Van Lommel <brechtvanlommel@pandora.be>2011-11-08 17:07:16 +0400
commit28ee0f92184af8ba6f44d08eda23ce5eb3815697 (patch)
tree6aada8d509c7470bd3bff6e52ba32e1fd54ef2ee /source/blender/editors
parent19df3147f6920a2856bccb6e4601d57288119999 (diff)
Texturing: texture and 3d view draw type changes, these should only have any
effect for a render engine using new shading nodes. In short: * No longer uses images assigned to faces in the uv layer, rather the active image texture node is what is edited/painted/drawn. * Textured draw type now shows the active image texture node, with solid lighting. * Material draw mode shows GLSL shader of a simplified material node tree, using solid lighting. * Textures for modifiers, brushes, etc, are now available from a dropdown in the texture tab in the properties editor. These do not use new shading nodes yet. http://wiki.blender.org/index.php/Dev:2.6/Source/Render/TextureWorkflow
Diffstat (limited to 'source/blender/editors')
-rw-r--r--source/blender/editors/include/ED_uvedit.h9
-rw-r--r--source/blender/editors/include/UI_interface.h2
-rw-r--r--source/blender/editors/interface/interface_templates.c11
-rw-r--r--source/blender/editors/mesh/mesh_data.c4
-rw-r--r--source/blender/editors/sculpt_paint/paint_image.c82
-rw-r--r--source/blender/editors/space_buttons/CMakeLists.txt1
-rw-r--r--source/blender/editors/space_buttons/buttons_context.c255
-rw-r--r--source/blender/editors/space_buttons/buttons_intern.h49
-rw-r--r--source/blender/editors/space_buttons/buttons_texture.c469
-rw-r--r--source/blender/editors/space_buttons/space_buttons.c7
-rw-r--r--source/blender/editors/space_image/space_image.c40
-rw-r--r--source/blender/editors/space_node/CMakeLists.txt1
-rw-r--r--source/blender/editors/space_node/SConscript2
-rw-r--r--source/blender/editors/space_node/node_edit.c13
-rw-r--r--source/blender/editors/space_node/node_templates.c9
-rw-r--r--source/blender/editors/space_view3d/drawmesh.c183
-rw-r--r--source/blender/editors/space_view3d/drawobject.c4
-rw-r--r--source/blender/editors/space_view3d/view3d_draw.c12
-rw-r--r--source/blender/editors/uvedit/uvedit_ops.c103
-rw-r--r--source/blender/editors/uvedit/uvedit_unwrap_ops.c4
20 files changed, 1098 insertions, 162 deletions
diff --git a/source/blender/editors/include/ED_uvedit.h b/source/blender/editors/include/ED_uvedit.h
index 2b4c213bc52..0666884351a 100644
--- a/source/blender/editors/include/ED_uvedit.h
+++ b/source/blender/editors/include/ED_uvedit.h
@@ -33,19 +33,26 @@
struct ARegionType;
struct EditFace;
struct Image;
+struct Main;
+struct ImageUser;
struct MTFace;
struct Object;
struct Scene;
+struct SpaceImage;
struct bContext;
+struct bNode;
struct wmKeyConfig;
/* uvedit_ops.c */
void ED_operatortypes_uvedit(void);
void ED_keymap_uvedit(struct wmKeyConfig *keyconf);
-void ED_uvedit_assign_image(struct Scene *scene, struct Object *obedit, struct Image *ima, struct Image *previma);
+void ED_uvedit_assign_image(struct Main *bmain, struct Scene *scene, struct Object *obedit, struct Image *ima, struct Image *previma);
int ED_uvedit_minmax(struct Scene *scene, struct Image *ima, struct Object *obedit, float *min, float *max);
+int ED_object_get_active_image(struct Object *ob, int mat_nr, struct Image **ima, struct ImageUser **iuser, struct bNode **node);
+void ED_object_assign_active_image(struct Main *bmain, struct Object *ob, int mat_nr, struct Image *ima);
+
int ED_uvedit_test_silent(struct Object *obedit);
int ED_uvedit_test(struct Object *obedit);
diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h
index 02b8cc9e2c6..329f4599e01 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -758,6 +758,8 @@ void uiTemplateKeymapItemProperties(uiLayout *layout, struct PointerRNA *ptr);
void uiTemplateList(uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, const char *propname, struct PointerRNA *activeptr, const char *activeprop, const char *prop_list, int rows, int maxrows, int type);
void uiTemplateNodeLink(uiLayout *layout, struct bNodeTree *ntree, struct bNode *node, struct bNodeSocket *input);
void uiTemplateNodeView(uiLayout *layout, struct bContext *C, struct bNodeTree *ntree, struct bNode *node, struct bNodeSocket *input);
+void uiTemplateTextureUser(uiLayout *layout, struct bContext *C);
+void uiTemplateTextureShow(uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA *prop);
void uiTemplateMovieClip(struct uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, const char *propname, int compact);
void uiTemplateTrack(struct uiLayout *layout, struct PointerRNA *ptr, const char *propname);
diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c
index 7c745c3cfef..a3d71674a03 100644
--- a/source/blender/editors/interface/interface_templates.c
+++ b/source/blender/editors/interface/interface_templates.c
@@ -332,7 +332,7 @@ static const char *template_id_browse_tip(StructRNA *type)
return N_("Browse ID data to be linked");
}
-static void template_ID(bContext *C, uiLayout *layout, TemplateID *template, StructRNA *type, int flag, const char *newop, const char *openop, const char *unlinkop)
+static void template_ID(bContext *C, uiLayout *layout, TemplateID *template, StructRNA *type, short idcode, int flag, const char *newop, const char *openop, const char *unlinkop)
{
uiBut *but;
uiBlock *block;
@@ -478,6 +478,9 @@ static void template_ID(bContext *C, uiLayout *layout, TemplateID *template, Str
if((idfrom && idfrom->lib) || !editable)
uiButSetFlag(but, UI_BUT_DISABLED);
}
+
+ if(idcode == ID_TE)
+ uiTemplateTextureShow(layout, C, &template->ptr, template->prop);
uiBlockEndAlign(block);
}
@@ -487,6 +490,7 @@ static void ui_template_id(uiLayout *layout, bContext *C, PointerRNA *ptr, const
TemplateID *template;
PropertyRNA *prop;
StructRNA *type;
+ short idcode;
prop= RNA_struct_find_property(ptr, propname);
@@ -507,14 +511,15 @@ static void ui_template_id(uiLayout *layout, bContext *C, PointerRNA *ptr, const
flag |= UI_ID_OPEN;
type= RNA_property_pointer_type(ptr, prop);
- template->idlb= which_libbase(CTX_data_main(C), RNA_type_to_ID_code(type));
+ idcode= RNA_type_to_ID_code(type);
+ template->idlb= which_libbase(CTX_data_main(C), idcode);
/* create UI elements for this template
* - template_ID makes a copy of the template data and assigns it to the relevant buttons
*/
if(template->idlb) {
uiLayoutRow(layout, 1);
- template_ID(C, layout, template, type, flag, newop, openop, unlinkop);
+ template_ID(C, layout, template, type, idcode, flag, newop, openop, unlinkop);
}
MEM_freeN(template);
diff --git a/source/blender/editors/mesh/mesh_data.c b/source/blender/editors/mesh/mesh_data.c
index ed890fd9b90..6e35865fb4d 100644
--- a/source/blender/editors/mesh/mesh_data.c
+++ b/source/blender/editors/mesh/mesh_data.c
@@ -51,6 +51,7 @@
#include "BKE_displist.h"
#include "BKE_image.h"
#include "BKE_library.h"
+#include "BKE_main.h"
#include "BKE_material.h"
#include "BKE_mesh.h"
#include "BKE_report.h"
@@ -331,6 +332,7 @@ void MESH_OT_uv_texture_add(wmOperatorType *ot)
static int drop_named_image_invoke(bContext *C, wmOperator *op, wmEvent *event)
{
+ Main *bmain= CTX_data_main(C);
Scene *scene= CTX_data_scene(C);
View3D *v3d= CTX_wm_view3d(C);
Base *base= ED_view3d_give_base_under_cursor(C, event->mval);
@@ -375,7 +377,7 @@ static int drop_named_image_invoke(bContext *C, wmOperator *op, wmEvent *event)
if(me->edit_mesh==NULL)
return OPERATOR_CANCELLED;
- ED_uvedit_assign_image(scene, obedit, ima, NULL);
+ ED_uvedit_assign_image(bmain, scene, obedit, ima, NULL);
if(exitmode) {
load_editMesh(scene, obedit);
diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c
index ce603ce80b6..e283927b76f 100644
--- a/source/blender/editors/sculpt_paint/paint_image.c
+++ b/source/blender/editors/sculpt_paint/paint_image.c
@@ -79,6 +79,7 @@
#include "BKE_object.h"
#include "BKE_paint.h"
#include "BKE_report.h"
+#include "BKE_scene.h"
#include "BIF_gl.h"
#include "BIF_glutil.h"
@@ -88,6 +89,7 @@
#include "ED_image.h"
#include "ED_screen.h"
#include "ED_sculpt.h"
+#include "ED_uvedit.h"
#include "ED_view3d.h"
#include "WM_api.h"
@@ -498,6 +500,40 @@ static void image_undo_free(ListBase *lb)
MEM_freeN(tile->rect);
}
+/* get active image for face depending on old/new shading system */
+
+static Image *imapaint_face_image(const ImagePaintState *s, int face_index)
+{
+ Image *ima;
+
+ if(scene_use_new_shading_nodes(s->scene)) {
+ MFace *mf = s->me->mface+face_index;
+ ED_object_get_active_image(s->ob, mf->mat_nr, &ima, NULL, NULL);
+ }
+ else {
+ MTFace *tf = s->me->mtface+face_index;
+ ima = tf->tpage;
+ }
+
+ return ima;
+}
+
+static Image *project_paint_face_image(const ProjPaintState *ps, int face_index)
+{
+ Image *ima;
+
+ if(scene_use_new_shading_nodes(ps->scene)) {
+ MFace *mf = ps->dm_mface+face_index;
+ ED_object_get_active_image(ps->ob, mf->mat_nr, &ima, NULL, NULL);
+ }
+ else {
+ MTFace *tf = ps->dm_mtface+face_index;
+ ima = tf->tpage;
+ }
+
+ return ima;
+}
+
/* fast projection bucket array lookup, use the safe version for bound checking */
static int project_bucket_offset(const ProjPaintState *ps, const float projCoSS[2])
{
@@ -670,6 +706,7 @@ static int project_paint_PickColor(const ProjPaintState *ps, float pt[2], float
int side;
int face_index;
MTFace *tf;
+ Image *ima;
ImBuf *ibuf;
int xi, yi;
@@ -687,8 +724,9 @@ static int project_paint_PickColor(const ProjPaintState *ps, float pt[2], float
else { /* QUAD */
interp_v2_v2v2v2(uv, tf->uv[0], tf->uv[2], tf->uv[3], w);
}
-
- ibuf = tf->tpage->ibufs.first; /* we must have got the imbuf before getting here */
+
+ ima = project_paint_face_image(ps, face_index);
+ ibuf = ima->ibufs.first; /* we must have got the imbuf before getting here */
if (!ibuf) return 0;
if (interp) {
@@ -1053,6 +1091,9 @@ static int check_seam(const ProjPaintState *ps, const int orig_face, const int o
/* Only need to check if 'i2_fidx' is valid because we know i1_fidx is the same vert on both faces */
if (i2_fidx != -1) {
+ Image *tpage = project_paint_face_image(ps, face_index);
+ Image *orig_tpage = project_paint_face_image(ps, orig_face);
+
/* This IS an adjacent face!, now lets check if the UVs are ok */
tf = ps->dm_mtface + face_index;
@@ -1061,7 +1102,7 @@ static int check_seam(const ProjPaintState *ps, const int orig_face, const int o
*orig_fidx = (i1_fidx < i2_fidx) ? i1_fidx : i2_fidx;
/* first test if they have the same image */
- if ( (orig_tf->tpage == tf->tpage) &&
+ if ( (orig_tpage == tpage) &&
cmp_uv(orig_tf->uv[orig_i1_fidx], tf->uv[i1_fidx]) &&
cmp_uv(orig_tf->uv[orig_i2_fidx], tf->uv[i2_fidx]) )
{
@@ -1308,9 +1349,10 @@ static float project_paint_uvpixel_mask(
if (ps->do_layer_stencil) {
/* another UV layers image is masking this one's */
ImBuf *ibuf_other;
+ Image *other_tpage = project_paint_face_image(ps, face_index);
const MTFace *tf_other = ps->dm_mtface_stencil + face_index;
- if (tf_other->tpage && (ibuf_other = BKE_image_get_ibuf(tf_other->tpage, NULL))) {
+ if (other_tpage && (ibuf_other = BKE_image_get_ibuf(other_tpage, NULL))) {
/* BKE_image_get_ibuf - TODO - this may be slow */
unsigned char rgba_ub[4];
float rgba_f[4];
@@ -1464,9 +1506,10 @@ static ProjPixel *project_paint_uvpixel_init(
if (ps->tool==PAINT_TOOL_CLONE) {
if (ps->dm_mtface_clone) {
ImBuf *ibuf_other;
+ Image *other_tpage = project_paint_face_image(ps, face_index);
const MTFace *tf_other = ps->dm_mtface_clone + face_index;
- if (tf_other->tpage && (ibuf_other = BKE_image_get_ibuf(tf_other->tpage, NULL))) {
+ if (other_tpage && (ibuf_other = BKE_image_get_ibuf(other_tpage, NULL))) {
/* BKE_image_get_ibuf - TODO - this may be slow */
if (ibuf->rect_float) {
@@ -2684,11 +2727,8 @@ static void project_bucket_init(const ProjPaintState *ps, const int thread_index
LinkNode *node;
int face_index, image_index=0;
ImBuf *ibuf = NULL;
+ Image *tpage_last = NULL, *tpage;
Image *ima = NULL;
- MTFace *tf;
-
- Image *tpage_last = NULL;
-
if (ps->image_tot==1) {
/* Simple loop, no context switching */
@@ -2706,9 +2746,9 @@ static void project_bucket_init(const ProjPaintState *ps, const int thread_index
face_index = GET_INT_FROM_POINTER(node->link);
/* Image context switching */
- tf = ps->dm_mtface+face_index;
- if (tpage_last != tf->tpage) {
- tpage_last = tf->tpage;
+ tpage = project_paint_face_image(ps, face_index);
+ if (tpage_last != tpage) {
+ tpage_last = tpage;
for (image_index=0; image_index < ps->image_tot; image_index++) {
if (ps->projImages[image_index].ima == tpage_last) {
@@ -2876,7 +2916,7 @@ static void project_paint_begin(ProjPaintState *ps)
LinkNode *node;
ProjPaintImage *projIma;
- Image *tpage_last = NULL;
+ Image *tpage_last = NULL, *tpage;
/* Face vars */
MFace *mf;
@@ -3210,7 +3250,9 @@ static void project_paint_begin(ProjPaintState *ps)
}
#endif
- if (tf->tpage && ((((Mesh *)ps->ob->data)->editflag & ME_EDIT_PAINT_MASK)==0 || mf->flag & ME_FACE_SEL)) {
+ tpage = project_paint_face_image(ps, face_index);
+
+ if (tpage && ((((Mesh *)ps->ob->data)->editflag & ME_EDIT_PAINT_MASK)==0 || mf->flag & ME_FACE_SEL)) {
float *v1coSS, *v2coSS, *v3coSS, *v4coSS=NULL;
@@ -3283,17 +3325,17 @@ static void project_paint_begin(ProjPaintState *ps)
}
}
- if (tpage_last != tf->tpage) {
+ if (tpage_last != tpage) {
- image_index = BLI_linklist_index(image_LinkList, tf->tpage);
+ image_index = BLI_linklist_index(image_LinkList, tpage);
- if (image_index==-1 && BKE_image_get_ibuf(tf->tpage, NULL)) { /* MemArena dosnt have an append func */
- BLI_linklist_append(&image_LinkList, tf->tpage);
+ if (image_index==-1 && BKE_image_get_ibuf(tpage, NULL)) { /* MemArena dosnt have an append func */
+ BLI_linklist_append(&image_LinkList, tpage);
image_index = ps->image_tot;
ps->image_tot++;
}
- tpage_last = tf->tpage;
+ tpage_last = tpage;
}
if (image_index != -1) {
@@ -4481,7 +4523,7 @@ static int imapaint_paint_stroke(ViewContext *vc, ImagePaintState *s, BrushPaint
) {
ImBuf *ibuf;
- newimage = (s->me->mtface+newfaceindex)->tpage;
+ newimage = imapaint_face_image(s, newfaceindex);
ibuf= BKE_image_get_ibuf(newimage, s->sima? &s->sima->iuser: NULL);
if(ibuf && ibuf->rect)
diff --git a/source/blender/editors/space_buttons/CMakeLists.txt b/source/blender/editors/space_buttons/CMakeLists.txt
index dbb96b68587..ee118f12062 100644
--- a/source/blender/editors/space_buttons/CMakeLists.txt
+++ b/source/blender/editors/space_buttons/CMakeLists.txt
@@ -38,6 +38,7 @@ set(SRC
buttons_context.c
buttons_header.c
buttons_ops.c
+ buttons_texture.c
space_buttons.c
buttons_intern.h
diff --git a/source/blender/editors/space_buttons/buttons_context.c b/source/blender/editors/space_buttons/buttons_context.c
index 6d6f73e98d8..e38ac7bd413 100644
--- a/source/blender/editors/space_buttons/buttons_context.c
+++ b/source/blender/editors/space_buttons/buttons_context.c
@@ -54,7 +54,6 @@
#include "BKE_screen.h"
#include "BKE_texture.h"
-
#include "RNA_access.h"
#include "ED_armature.h"
@@ -66,13 +65,6 @@
#include "buttons_intern.h" // own include
-typedef struct ButsContextPath {
- PointerRNA ptr[8];
- int len;
- int flag;
- int tex_ctx;
-} ButsContextPath;
-
static int set_pointer_type(ButsContextPath *path, bContextDataResult *result, StructRNA *type)
{
PointerRNA *ptr;
@@ -373,102 +365,141 @@ static int buttons_context_path_brush(ButsContextPath *path)
return 0;
}
-static int buttons_context_path_texture(ButsContextPath *path)
+static int buttons_context_path_texture(ButsContextPath *path, ButsContextTexture *ct)
{
- Material *ma;
- Lamp *la;
- Brush *br;
- World *wo;
- ParticleSystem *psys;
- Tex *tex;
- PointerRNA *ptr= &path->ptr[path->len-1];
- int orig_len = path->len;
+ if(ct) {
+ /* new shading system */
+ PointerRNA *ptr= &path->ptr[path->len-1];
+ ID *id;
- /* if we already have a (pinned) texture, we're done */
- if(RNA_struct_is_a(ptr->type, &RNA_Texture)) {
- return 1;
- }
- /* try brush */
- if((path->tex_ctx == SB_TEXC_BRUSH) && buttons_context_path_brush(path)) {
- br= path->ptr[path->len-1].data;
-
- if(br) {
- tex= give_current_brush_texture(br);
+ /* if we already have a (pinned) texture, we're done */
+ if(RNA_struct_is_a(ptr->type, &RNA_Texture))
+ return 1;
- RNA_id_pointer_create(&tex->id, &path->ptr[path->len]);
+ if(!ct->user)
+ return 0;
+
+ id= ct->user->id;
+
+ if(id) {
+ if(GS(id->name) == ID_BR)
+ buttons_context_path_brush(path);
+ else if(GS(id->name) == ID_MA)
+ buttons_context_path_material(path, 0);
+ else if(GS(id->name) == ID_WO)
+ buttons_context_path_world(path);
+ else if(GS(id->name) == ID_LA)
+ buttons_context_path_data(path, OB_LAMP);
+ else if(GS(id->name) == ID_PA)
+ buttons_context_path_particle(path);
+ else if(GS(id->name) == ID_OB)
+ buttons_context_path_object(path);
+ }
+
+ if(ct->texture) {
+ RNA_id_pointer_create(&ct->texture->id, &path->ptr[path->len]);
path->len++;
- return 1;
}
- }
- /* try world */
- if((path->tex_ctx == SB_TEXC_WORLD) && buttons_context_path_world(path)) {
- wo= path->ptr[path->len-1].data;
-
- if(wo && GS(wo->id.name)==ID_WO) {
- tex= give_current_world_texture(wo);
- RNA_id_pointer_create(&tex->id, &path->ptr[path->len]);
- path->len++;
+ return 1;
+ }
+ else {
+ /* old shading system */
+ Material *ma;
+ Lamp *la;
+ Brush *br;
+ World *wo;
+ ParticleSystem *psys;
+ Tex *tex;
+ PointerRNA *ptr= &path->ptr[path->len-1];
+ int orig_len = path->len;
+
+ /* if we already have a (pinned) texture, we're done */
+ if(RNA_struct_is_a(ptr->type, &RNA_Texture)) {
return 1;
}
- }
- /* try particles */
- if((path->tex_ctx == SB_TEXC_PARTICLES) && buttons_context_path_particle(path)) {
- if(path->ptr[path->len-1].type == &RNA_ParticleSettings) {
- ParticleSettings *part = path->ptr[path->len-1].data;
+ /* try brush */
+ if((path->tex_ctx == SB_TEXC_BRUSH) && buttons_context_path_brush(path)) {
+ br= path->ptr[path->len-1].data;
+
+ if(br) {
+ tex= give_current_brush_texture(br);
- tex= give_current_particle_texture(part);
- RNA_id_pointer_create(&tex->id, &path->ptr[path->len]);
- path->len++;
- return 1;
+ RNA_id_pointer_create(&tex->id, &path->ptr[path->len]);
+ path->len++;
+ return 1;
+ }
}
- else {
- psys= path->ptr[path->len-1].data;
+ /* try world */
+ if((path->tex_ctx == SB_TEXC_WORLD) && buttons_context_path_world(path)) {
+ wo= path->ptr[path->len-1].data;
- if(psys && psys->part && GS(psys->part->id.name)==ID_PA) {
- tex= give_current_particle_texture(psys->part);
+ if(wo && GS(wo->id.name)==ID_WO) {
+ tex= give_current_world_texture(wo);
RNA_id_pointer_create(&tex->id, &path->ptr[path->len]);
path->len++;
return 1;
}
}
- }
- /* try material */
- if(buttons_context_path_material(path, 1)) {
- ma= path->ptr[path->len-1].data;
+ /* try particles */
+ if((path->tex_ctx == SB_TEXC_PARTICLES) && buttons_context_path_particle(path)) {
+ if(path->ptr[path->len-1].type == &RNA_ParticleSettings) {
+ ParticleSettings *part = path->ptr[path->len-1].data;
- if(ma) {
- tex= give_current_material_texture(ma);
+ tex= give_current_particle_texture(part);
+ RNA_id_pointer_create(&tex->id, &path->ptr[path->len]);
+ path->len++;
+ return 1;
+ }
+ else {
+ psys= path->ptr[path->len-1].data;
- RNA_id_pointer_create(&tex->id, &path->ptr[path->len]);
- path->len++;
- return 1;
+ if(psys && psys->part && GS(psys->part->id.name)==ID_PA) {
+ tex= give_current_particle_texture(psys->part);
+
+ RNA_id_pointer_create(&tex->id, &path->ptr[path->len]);
+ path->len++;
+ return 1;
+ }
+ }
}
- }
- /* try lamp */
- if(buttons_context_path_data(path, OB_LAMP)) {
- la= path->ptr[path->len-1].data;
+ /* try material */
+ if(buttons_context_path_material(path, 1)) {
+ ma= path->ptr[path->len-1].data;
- if(la) {
- tex= give_current_lamp_texture(la);
+ if(ma) {
+ tex= give_current_material_texture(ma);
- RNA_id_pointer_create(&tex->id, &path->ptr[path->len]);
- path->len++;
- return 1;
+ RNA_id_pointer_create(&tex->id, &path->ptr[path->len]);
+ path->len++;
+ return 1;
+ }
}
- }
- /* try brushes again in case of no material, lamp, etc */
- path->len = orig_len;
- if(buttons_context_path_brush(path)) {
- br= path->ptr[path->len-1].data;
-
- if(br) {
- tex= give_current_brush_texture(br);
+ /* try lamp */
+ if(buttons_context_path_data(path, OB_LAMP)) {
+ la= path->ptr[path->len-1].data;
+
+ if(la) {
+ tex= give_current_lamp_texture(la);
+
+ RNA_id_pointer_create(&tex->id, &path->ptr[path->len]);
+ path->len++;
+ return 1;
+ }
+ }
+ /* try brushes again in case of no material, lamp, etc */
+ path->len = orig_len;
+ if(buttons_context_path_brush(path)) {
+ br= path->ptr[path->len-1].data;
- RNA_id_pointer_create(&tex->id, &path->ptr[path->len]);
- path->len++;
- return 1;
+ if(br) {
+ tex= give_current_brush_texture(br);
+
+ RNA_id_pointer_create(&tex->id, &path->ptr[path->len]);
+ path->len++;
+ return 1;
+ }
}
}
@@ -530,7 +561,7 @@ static int buttons_context_path(const bContext *C, ButsContextPath *path, int ma
found= buttons_context_path_material(path, 0);
break;
case BCONTEXT_TEXTURE:
- found= buttons_context_path_texture(path);
+ found= buttons_context_path_texture(path, sbuts->texuser);
break;
case BCONTEXT_BONE:
found= buttons_context_path_bone(path);
@@ -580,6 +611,8 @@ void buttons_context_compute(const bContext *C, SpaceButs *sbuts)
PointerRNA *ptr;
int a, pflag= 0, flag= 0;
+ buttons_texture_context_compute(C, sbuts);
+
if(!sbuts->path)
sbuts->path= MEM_callocN(sizeof(ButsContextPath), "ButsContextPath");
@@ -649,7 +682,8 @@ void buttons_context_compute(const bContext *C, SpaceButs *sbuts)
const char *buttons_context_dir[] = {
"world", "object", "mesh", "armature", "lattice", "curve",
"meta_ball", "lamp", "speaker", "camera", "material", "material_slot",
- "texture", "texture_slot", "bone", "edit_bone", "pose_bone", "particle_system", "particle_system_editable",
+ "texture", "texture_slot", "texture_user", "bone", "edit_bone",
+ "pose_bone", "particle_system", "particle_system_editable",
"cloth", "soft_body", "fluid", "smoke", "collision", "brush", NULL};
int buttons_context(const bContext *C, const char *member, bContextDataResult *result)
@@ -710,7 +744,17 @@ int buttons_context(const bContext *C, const char *member, bContextDataResult *r
return 1;
}
else if(CTX_data_equals(member, "texture")) {
- set_pointer_type(path, result, &RNA_Texture);
+ ButsContextTexture *ct= sbuts->texuser;
+
+ if(ct) {
+ /* new shading system */
+ CTX_data_pointer_set(result, &ct->texture->id, &RNA_Texture, ct->texture);
+ }
+ else {
+ /* old shading system */
+ set_pointer_type(path, result, &RNA_Texture);
+ }
+
return 1;
}
else if(CTX_data_equals(member, "material_slot")) {
@@ -729,23 +773,52 @@ int buttons_context(const bContext *C, const char *member, bContextDataResult *r
return 1;
}
- else if(CTX_data_equals(member, "texture_node")) {
- PointerRNA *ptr;
+ else if(CTX_data_equals(member, "texture_user")) {
+ ButsContextTexture *ct= sbuts->texuser;
- if((ptr=get_pointer_type(path, &RNA_Material))) {
- Material *ma= ptr->data;
+ if(!ct)
+ return 0; /* old shading system */
- if(ma) {
- bNode *node= give_current_material_texture_node(ma);
- CTX_data_pointer_set(result, &ma->id, &RNA_Node, node);
- }
+ if(ct->user && ct->user->ptr.data) {
+ ButsTextureUser *user= ct->user;
+ CTX_data_pointer_set(result, user->ptr.id.data, user->ptr.type, user->ptr.data);
}
return 1;
}
+ else if(CTX_data_equals(member, "texture_node")) {
+ ButsContextTexture *ct= sbuts->texuser;
+
+ if(ct) {
+ /* new shading system */
+ if(ct->user && ct->user->node)
+ CTX_data_pointer_set(result, &ct->user->ntree->id, &RNA_Node, ct->user->node);
+
+ return 1;
+ }
+ else {
+ /* old shading system */
+ PointerRNA *ptr;
+
+ if((ptr=get_pointer_type(path, &RNA_Material))) {
+ Material *ma= ptr->data;
+
+ if(ma) {
+ bNode *node= give_current_material_texture_node(ma);
+ CTX_data_pointer_set(result, &ma->id, &RNA_Node, node);
+ }
+ }
+
+ return 1;
+ }
+ }
else if(CTX_data_equals(member, "texture_slot")) {
+ ButsContextTexture *ct= sbuts->texuser;
PointerRNA *ptr;
+ if(ct)
+ return 0; /* new shading system */
+
if((ptr=get_pointer_type(path, &RNA_Material))) {
Material *ma= ptr->data;
diff --git a/source/blender/editors/space_buttons/buttons_intern.h b/source/blender/editors/space_buttons/buttons_intern.h
index 27084488163..aa692a940d8 100644
--- a/source/blender/editors/space_buttons/buttons_intern.h
+++ b/source/blender/editors/space_buttons/buttons_intern.h
@@ -31,14 +31,20 @@
#ifndef ED_BUTTONS_INTERN_H
#define ED_BUTTONS_INTERN_H
+#include "DNA_listBase.h"
+#include "RNA_types.h"
+
struct ARegion;
struct ARegionType;
+struct ID;
+struct SpaceButs;
+struct Tex;
struct bContext;
struct bContextDataResult;
-struct SpaceButs;
+struct bNode;
+struct bNodeTree;
struct uiLayout;
struct wmOperatorType;
-struct ID;
/* buts->scaflag */
#define BUTS_SENS_SEL 1
@@ -53,6 +59,42 @@ struct ID;
#define BUTS_SENS_STATE 512
#define BUTS_ACT_STATE 1024
+/* context data */
+
+typedef struct ButsContextPath {
+ PointerRNA ptr[8];
+ int len;
+ int flag;
+ int tex_ctx;
+} ButsContextPath;
+
+typedef struct ButsTextureUser {
+ struct ButsTextureUser *next, *prev;
+
+ struct ID *id;
+
+ PointerRNA ptr;
+ PropertyRNA *prop;
+
+ struct bNodeTree *ntree;
+ struct bNode *node;
+
+ const char *category;
+ int icon;
+ const char *name;
+
+ int index;
+} ButsTextureUser;
+
+typedef struct ButsContextTexture {
+ ListBase users;
+
+ struct Tex *texture;
+
+ struct ButsTextureUser *user;
+ int index;
+} ButsContextTexture;
+
/* internal exports only */
/* buttons_header.c */
@@ -67,6 +109,9 @@ struct ID *buttons_context_id_path(const struct bContext *C);
extern const char *buttons_context_dir[]; /* doc access */
+/* buttons_texture.c */
+void buttons_texture_context_compute(const struct bContext *C, struct SpaceButs *sbuts);
+
/* buttons_ops.c */
void BUTTONS_OT_file_browse(struct wmOperatorType *ot);
void BUTTONS_OT_directory_browse(struct wmOperatorType *ot);
diff --git a/source/blender/editors/space_buttons/buttons_texture.c b/source/blender/editors/space_buttons/buttons_texture.c
new file mode 100644
index 00000000000..dd9f3c57896
--- /dev/null
+++ b/source/blender/editors/space_buttons/buttons_texture.c
@@ -0,0 +1,469 @@
+/*
+ * $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) 2009 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Blender Foundation
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/space_buttons/buttons_texture.c
+ * \ingroup spbuttons
+ */
+
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_listbase.h"
+#include "BLI_string.h"
+#include "BLI_utildefines.h"
+
+#include "DNA_brush_types.h"
+#include "DNA_ID.h"
+#include "DNA_lamp_types.h"
+#include "DNA_material_types.h"
+#include "DNA_node_types.h"
+#include "DNA_object_types.h"
+#include "DNA_object_force.h"
+#include "DNA_particle_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+#include "DNA_world_types.h"
+
+#include "BKE_context.h"
+#include "BKE_material.h"
+#include "BKE_modifier.h"
+#include "BKE_node.h"
+#include "BKE_paint.h"
+#include "BKE_particle.h"
+#include "BKE_scene.h"
+
+#include "RNA_access.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "ED_node.h"
+#include "ED_screen.h"
+
+#include "../interface/interface_intern.h"
+
+#include "buttons_intern.h" // own include
+
+/************************* Texture User **************************/
+
+static void buttons_texture_user_property_add(ListBase *users, ID *id,
+ PointerRNA ptr, PropertyRNA *prop,
+ const char *category, int icon, const char *name)
+{
+ ButsTextureUser *user = MEM_callocN(sizeof(ButsTextureUser), "ButsTextureUser");
+
+ user->id= id;
+ user->ptr = ptr;
+ user->prop = prop;
+ user->category = category;
+ user->icon = icon;
+ user->name = name;
+ user->index = BLI_countlist(users);
+
+ BLI_addtail(users, user);
+}
+
+static void buttons_texture_user_node_add(ListBase *users, ID *id,
+ bNodeTree *ntree, bNode *node,
+ const char *category, int icon, const char *name)
+{
+ ButsTextureUser *user = MEM_callocN(sizeof(ButsTextureUser), "ButsTextureUser");
+
+ user->id= id;
+ user->ntree = ntree;
+ user->node = node;
+ user->category = category;
+ user->icon = icon;
+ user->name = name;
+ user->index = BLI_countlist(users);
+
+ BLI_addtail(users, user);
+}
+
+static void buttons_texture_users_find_nodetree(ListBase *users, ID *id,
+ bNodeTree *ntree, const char *category)
+{
+ bNode *node;
+
+ if(ntree) {
+ for(node=ntree->nodes.first; node; node=node->next) {
+ if(node->typeinfo->nclass == NODE_CLASS_TEXTURE) {
+ PointerRNA ptr;
+ PropertyRNA *prop;
+
+ RNA_pointer_create(&ntree->id, &RNA_Node, node, &ptr);
+ prop = RNA_struct_find_property(&ptr, "texture");
+
+ buttons_texture_user_node_add(users, id, ntree, node,
+ category, RNA_struct_ui_icon(ptr.type), node->name);
+ }
+ else if(node->type == NODE_GROUP && node->id) {
+ buttons_texture_users_find_nodetree(users, id, (bNodeTree*)node->id, category);
+ }
+ }
+ }
+}
+
+static void buttons_texture_modifier_foreach(void *userData, Object *ob, ModifierData *md, const char *propname)
+{
+ PointerRNA ptr;
+ PropertyRNA *prop;
+ ListBase *users = userData;
+
+ RNA_pointer_create(&ob->id, &RNA_Modifier, md, &ptr);
+ prop = RNA_struct_find_property(&ptr, propname);
+
+ buttons_texture_user_property_add(users, &ob->id, ptr, prop,
+ "Modifiers", RNA_struct_ui_icon(ptr.type), md->name);
+}
+
+static void buttons_texture_users_from_context(ListBase *users, const bContext *C, SpaceButs *sbuts)
+{
+ Scene *scene= NULL;
+ Object *ob= NULL;
+ Material *ma= NULL;
+ Lamp *la= NULL;
+ World *wrld= NULL;
+ Brush *brush= NULL;
+ ID *pinid = sbuts->pinid;
+
+ /* get data from context */
+ if(pinid) {
+ if(GS(pinid->name) == ID_SCE)
+ scene= (Scene*)pinid;
+ else if(GS(pinid->name) == ID_OB)
+ ob= (Object*)pinid;
+ else if(GS(pinid->name) == ID_LA)
+ la= (Lamp*)pinid;
+ else if(GS(pinid->name) == ID_WO)
+ wrld= (World*)pinid;
+ else if(GS(pinid->name) == ID_MA)
+ ma= (Material*)pinid;
+ else if(GS(pinid->name) == ID_BR)
+ brush= (Brush*)pinid;
+ }
+
+ if(!scene)
+ scene= CTX_data_scene(C);
+
+ if(!(pinid || pinid == &scene->id)) {
+ ob= (scene->basact)? scene->basact->object: NULL;
+ wrld= scene->world;
+ brush= paint_brush(paint_get_active(scene));
+ }
+
+ if(ob && ob->type == OB_LAMP && !la)
+ la= ob->data;
+ if(ob && !ma)
+ ma= give_current_material(ob, ob->actcol);
+
+ /* fill users */
+ users->first = users->last = NULL;
+
+ if(ma)
+ buttons_texture_users_find_nodetree(users, &ma->id, ma->nodetree, "Material");
+ if(la)
+ buttons_texture_users_find_nodetree(users, &la->id, la->nodetree, "Lamp");
+ if(wrld)
+ buttons_texture_users_find_nodetree(users, &wrld->id, wrld->nodetree, "World");
+
+ if(ob) {
+ ParticleSystem *psys= psys_get_current(ob);
+ MTex *mtex;
+ int a;
+
+ /* modifiers */
+ modifiers_foreachTexLink(ob, buttons_texture_modifier_foreach, users);
+
+ /* particle systems */
+ if(psys) {
+ /* todo: these slots are not in the UI */
+ for(a=0; a<MAX_MTEX; a++) {
+ mtex = psys->part->mtex[a];
+
+ if(mtex) {
+ PointerRNA ptr;
+ PropertyRNA *prop;
+
+ RNA_pointer_create(&psys->part->id, &RNA_ParticleSettingsTextureSlot, mtex, &ptr);
+ prop = RNA_struct_find_property(&ptr, "texture");
+
+ buttons_texture_user_property_add(users, &psys->part->id, ptr, prop,
+ "Particles", RNA_struct_ui_icon(&RNA_ParticleSettings), psys->name);
+ }
+ }
+ }
+
+ /* field */
+ if(ob->pd && ob->pd->forcefield == PFIELD_TEXTURE) {
+ PointerRNA ptr;
+ PropertyRNA *prop;
+
+ RNA_pointer_create(&ob->id, &RNA_FieldSettings, ob->pd, &ptr);
+ prop = RNA_struct_find_property(&ptr, "texture");
+
+ buttons_texture_user_property_add(users, &ob->id, ptr, prop,
+ "Fields", ICON_FORCE_TEXTURE, "Texture Field");
+ }
+ }
+
+ /* brush */
+ if(brush) {
+ PointerRNA ptr;
+ PropertyRNA *prop;
+
+ RNA_pointer_create(&brush->id, &RNA_BrushTextureSlot, &brush->mtex, &ptr);
+ prop= RNA_struct_find_property(&ptr, "texture");
+
+ buttons_texture_user_property_add(users, &brush->id, ptr, prop,
+ "Brush", ICON_BRUSH_DATA, brush->id.name+2);
+ }
+}
+
+void buttons_texture_context_compute(const bContext *C, SpaceButs *sbuts)
+{
+ /* gatheravailable texture users in context. runs on every draw of
+ properties editor, before the buttons are created. */
+ ButsContextTexture *ct= sbuts->texuser;
+ Scene *scene= CTX_data_scene(C);
+
+ if(!scene_use_new_shading_nodes(scene)) {
+ if(ct) {
+ MEM_freeN(ct);
+ BLI_freelistN(&ct->users);
+ sbuts->texuser= NULL;
+ }
+
+ return;
+ }
+
+ if(!ct) {
+ ct= MEM_callocN(sizeof(ButsContextTexture), "ButsContextTexture");
+ sbuts->texuser= ct;
+ }
+ else {
+ BLI_freelistN(&ct->users);
+ }
+
+ buttons_texture_users_from_context(&ct->users, C, sbuts);
+
+ /* set one user as active based on active index */
+ if(ct->index >= BLI_countlist(&ct->users))
+ ct->index= 0;
+
+ ct->user = BLI_findlink(&ct->users, ct->index);
+ ct->texture = NULL;
+
+ if(ct->user) {
+ if(ct->user->ptr.data) {
+ PointerRNA texptr;
+ Tex *tex;
+
+ /* get texture datablock pointer if it's a property */
+ texptr = RNA_property_pointer_get(&ct->user->ptr, ct->user->prop);
+ tex = (RNA_struct_is_a(texptr.type, &RNA_Texture))? texptr.data: NULL;
+
+ ct->texture = tex;
+ }
+ else if(ct->user->node && !(ct->user->node->flag & NODE_ACTIVE_TEXTURE)) {
+ ButsTextureUser *user;
+
+ /* detect change of active texture node in same node tree, in that
+ case we also automatically switch to the other node */
+ for(user=ct->users.first; user; user=user->next) {
+ if(user->ntree == ct->user->ntree && user->node != ct->user->node) {
+ if(user->node->flag & NODE_ACTIVE_TEXTURE) {
+ ct->user = user;
+ ct->index = BLI_findindex(&ct->users, user);
+ break;
+ }
+ }
+ }
+ }
+ }
+}
+
+static void template_texture_select(bContext *C, void *user_p, void *UNUSED(arg))
+{
+ /* callback when selecting a texture user in the menu */
+ SpaceButs *sbuts = CTX_wm_space_buts(C);
+ ButsContextTexture *ct= (sbuts)? sbuts->texuser: NULL;
+ ButsTextureUser *user = (ButsTextureUser*)user_p;
+ PointerRNA texptr;
+ Tex *tex;
+
+ if(!ct)
+ return;
+
+ /* set user as active */
+ if(user->node) {
+ ED_node_set_active(CTX_data_main(C), user->ntree, user->node);
+ ct->texture = NULL;
+ }
+ else {
+ texptr = RNA_property_pointer_get(&user->ptr, user->prop);
+ tex = (RNA_struct_is_a(texptr.type, &RNA_Texture))? texptr.data: NULL;
+
+ ct->texture = tex;
+ }
+
+ ct->user = user;
+ ct->index = user->index;
+}
+
+static void template_texture_user_menu(bContext *C, uiLayout *layout, void *UNUSED(arg))
+{
+ /* callback when opening texture user selection menu, to create buttons. */
+ SpaceButs *sbuts = CTX_wm_space_buts(C);
+ ButsContextTexture *ct= (sbuts)? sbuts->texuser: NULL;
+ ButsTextureUser *user;
+ uiBlock *block = uiLayoutGetBlock(layout);
+ const char *last_category = NULL;
+
+ for(user=ct->users.first; user; user=user->next) {
+ uiBut *but;
+ char name[UI_MAX_NAME_STR];
+
+ /* add label per category */
+ if(!last_category || strcmp(last_category, user->category) != 0) {
+ uiItemL(layout, user->category, ICON_NONE);
+ but= block->buttons.last;
+ but->flag= UI_TEXT_LEFT;
+ }
+
+ /* create button */
+ BLI_snprintf(name, UI_MAX_NAME_STR, " %s", user->name);
+
+ but = uiDefIconTextBut(block, BUT, 0, user->icon, name, 0, 0, UI_UNIT_X*4, UI_UNIT_Y,
+ NULL, 0.0, 0.0, 0.0, 0.0, "");
+ uiButSetNFunc(but, template_texture_select, MEM_dupallocN(user), NULL);
+
+ last_category = user->category;
+ }
+}
+
+void uiTemplateTextureUser(uiLayout *layout, bContext *C)
+{
+ /* texture user selection dropdown menu. the available users have been
+ gathered before drawing in ButsContextTexture, we merely need to
+ display the current item. */
+ SpaceButs *sbuts = CTX_wm_space_buts(C);
+ ButsContextTexture *ct= (sbuts)? sbuts->texuser: NULL;
+ uiBlock *block = uiLayoutGetBlock(layout);
+ uiBut *but;
+ ButsTextureUser *user;
+ char name[UI_MAX_NAME_STR];
+
+ if(!ct)
+ return;
+
+ /* get current user */
+ user= ct->user;
+
+ if(!user) {
+ uiItemL(layout, "No textures in context.", ICON_NONE);
+ return;
+ }
+
+ /* create button */
+ BLI_snprintf(name, UI_MAX_NAME_STR, "%s", user->name);
+
+ if(user->icon) {
+ but= uiDefIconTextMenuBut(block, template_texture_user_menu, NULL,
+ user->icon, name, 0, 0, UI_UNIT_X*4, UI_UNIT_Y, "");
+ }
+ else {
+ but= uiDefMenuBut(block, template_texture_user_menu, NULL,
+ name, 0, 0, UI_UNIT_X*4, UI_UNIT_Y, "");
+ }
+
+ /* some cosmetic tweaks */
+ but->type= MENU;
+ but->flag |= UI_TEXT_LEFT;
+ but->flag &= ~UI_ICON_SUBMENU;
+}
+
+/************************* Texture Show **************************/
+
+static void template_texture_show(bContext *C, void *data_p, void *prop_p)
+{
+ SpaceButs *sbuts = CTX_wm_space_buts(C);
+ ButsContextTexture *ct= (sbuts)? sbuts->texuser: NULL;
+ ButsTextureUser *user;
+
+ if(!ct)
+ return;
+
+ for(user=ct->users.first; user; user=user->next)
+ if(user->ptr.data == data_p && user->prop == prop_p)
+ break;
+
+ if(user) {
+ /* select texture */
+ template_texture_select(C, user, NULL);
+
+ /* change context */
+ sbuts->mainb= BCONTEXT_TEXTURE;
+ sbuts->mainbuser= sbuts->mainb;
+ sbuts->preview= 1;
+
+ /* redraw editor */
+ ED_area_tag_redraw(CTX_wm_area(C));
+ }
+}
+
+void uiTemplateTextureShow(uiLayout *layout, bContext *C, PointerRNA *ptr, PropertyRNA *prop)
+{
+ /* button to quickly show texture in texture tab */
+ SpaceButs *sbuts = CTX_wm_space_buts(C);
+ ButsContextTexture *ct= (sbuts)? sbuts->texuser: NULL;
+ ButsTextureUser *user;
+
+ /* only show button in other tabs in properties editor */
+ if(!ct || sbuts->mainb == BCONTEXT_TEXTURE)
+ return;
+
+ /* find corresponding texture user */
+ for(user=ct->users.first; user; user=user->next)
+ if(user->ptr.data == ptr->data && user->prop == prop)
+ break;
+
+ /* draw button */
+ if(user) {
+ uiBlock *block = uiLayoutGetBlock(layout);
+ uiBut *but;
+
+ but= uiDefIconBut(block, BUT, 0, ICON_BUTS, 0, 0, UI_UNIT_X, UI_UNIT_Y,
+ NULL, 0.0, 0.0, 0.0, 0.0, "Show texture in texture tab");
+ uiButSetFunc(but, template_texture_show, user->ptr.data, user->prop);
+ }
+}
+
diff --git a/source/blender/editors/space_buttons/space_buttons.c b/source/blender/editors/space_buttons/space_buttons.c
index 4c328d174e9..0c326af406f 100644
--- a/source/blender/editors/space_buttons/space_buttons.c
+++ b/source/blender/editors/space_buttons/space_buttons.c
@@ -104,6 +104,12 @@ static void buttons_free(SpaceLink *sl)
if(sbuts->path)
MEM_freeN(sbuts->path);
+
+ if(sbuts->texuser) {
+ ButsContextTexture *ct= sbuts->texuser;
+ BLI_freelistN(&ct->users);
+ MEM_freeN(ct);
+ }
}
/* spacetype; init callback */
@@ -127,6 +133,7 @@ static SpaceLink *buttons_duplicate(SpaceLink *sl)
/* clear or remove stuff from old */
sbutsn->ri= NULL;
sbutsn->path= NULL;
+ sbutsn->texuser= NULL;
return (SpaceLink *)sbutsn;
}
diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c
index 3b9876329ec..c29553a9c87 100644
--- a/source/blender/editors/space_image/space_image.c
+++ b/source/blender/editors/space_image/space_image.c
@@ -47,7 +47,10 @@
#include "BKE_colortools.h"
#include "BKE_context.h"
#include "BKE_image.h"
+#include "BKE_global.h"
+#include "BKE_main.h"
#include "BKE_mesh.h"
+#include "BKE_scene.h"
#include "BKE_screen.h"
#include "IMB_imbuf_types.h"
@@ -81,7 +84,7 @@ Image *ED_space_image(SpaceImage *sima)
/* called to assign images to UV faces */
void ED_space_image_set(bContext *C, SpaceImage *sima, Scene *scene, Object *obedit, Image *ima)
{
- ED_uvedit_assign_image(scene, obedit, ima, sima->image);
+ ED_uvedit_assign_image(CTX_data_main(C), scene, obedit, ima, sima->image);
/* change the space ima after because uvedit_face_visible uses the space ima
* to check if the face is displayed in UV-localview */
@@ -572,6 +575,7 @@ static void image_dropboxes(void)
static void image_refresh(const bContext *C, ScrArea *UNUSED(sa))
{
+ Scene *scene = CTX_data_scene(C);
SpaceImage *sima= CTX_wm_space_image(C);
Object *obedit= CTX_data_edit_object(C);
Image *ima;
@@ -586,19 +590,31 @@ static void image_refresh(const bContext *C, ScrArea *UNUSED(sa))
else if(obedit && obedit->type == OB_MESH) {
Mesh *me= (Mesh*)obedit->data;
EditMesh *em= BKE_mesh_get_editmesh(me);
- MTFace *tf;
-
- if(em && EM_texFaceCheck(em)) {
- sima->image= NULL;
-
- tf = EM_get_active_mtface(em, NULL, NULL, 1); /* partially selected face is ok */
+ int sloppy= 1; /* partially selected face is ok */
+
+ if(scene_use_new_shading_nodes(scene)) {
+ /* new shading system, get image from material */
+ EditFace *efa= EM_get_actFace(em, sloppy);
+
+ if(efa)
+ ED_object_get_active_image(obedit, efa->mat_nr, &sima->image, NULL, NULL);
+ }
+ else {
+ /* old shading system, we set texface */
+ MTFace *tf;
- if(tf) {
- /* don't need to check for pin here, see above */
- sima->image= tf->tpage;
+ if(em && EM_texFaceCheck(em)) {
+ sima->image= NULL;
+
+ tf = EM_get_active_mtface(em, NULL, NULL, sloppy);
- if(sima->flag & SI_EDITTILE);
- else sima->curtile= tf->tile;
+ if(tf) {
+ /* don't need to check for pin here, see above */
+ sima->image= tf->tpage;
+
+ if(sima->flag & SI_EDITTILE);
+ else sima->curtile= tf->tile;
+ }
}
}
diff --git a/source/blender/editors/space_node/CMakeLists.txt b/source/blender/editors/space_node/CMakeLists.txt
index 991b35585a6..f33b784c5d2 100644
--- a/source/blender/editors/space_node/CMakeLists.txt
+++ b/source/blender/editors/space_node/CMakeLists.txt
@@ -25,6 +25,7 @@ set(INC
../../blenlib
../../blenloader
../../imbuf
+ ../../gpu
../../makesdna
../../makesrna
../../nodes
diff --git a/source/blender/editors/space_node/SConscript b/source/blender/editors/space_node/SConscript
index c4309dcfca3..6b72fd066e0 100644
--- a/source/blender/editors/space_node/SConscript
+++ b/source/blender/editors/space_node/SConscript
@@ -4,7 +4,7 @@ Import ('env')
sources = env.Glob('*.c')
incs = '../include ../../blenfont ../../blenlib ../../blenkernel ../../makesdna ../../makesrna ../../imbuf'
-incs += ' ../../nodes ../../render/extern/include ../../blenloader'
+incs += ' ../../nodes ../../render/extern/include ../../blenloader ../../gpu'
incs += ' ../../windowmanager #intern/guardedalloc #extern/glew/include'
defs = []
cf = []
diff --git a/source/blender/editors/space_node/node_edit.c b/source/blender/editors/space_node/node_edit.c
index a1b705610f4..23855ff24e1 100644
--- a/source/blender/editors/space_node/node_edit.c
+++ b/source/blender/editors/space_node/node_edit.c
@@ -90,6 +90,8 @@
#include "RNA_enum_types.h"
+#include "GPU_material.h"
+
#include "node_intern.h"
static EnumPropertyItem socket_in_out_items[] = {
@@ -598,6 +600,8 @@ static int has_nodetree(bNodeTree *ntree, bNodeTree *lookup)
void ED_node_set_active(Main *bmain, bNodeTree *ntree, bNode *node)
{
+ int was_active_texture = (node->flag & NODE_ACTIVE_TEXTURE);
+
nodeSetActive(ntree, node);
if(node->type!=NODE_GROUP) {
@@ -621,6 +625,15 @@ void ED_node_set_active(Main *bmain, bNodeTree *ntree, bNode *node)
ED_node_generic_update(bmain, ntree, node);
}
+ /* if active texture changed, free glsl materials */
+ if((node->flag & NODE_ACTIVE_TEXTURE) && !was_active_texture) {
+ Material *ma;
+
+ for(ma=bmain->mat.first; ma; ma=ma->id.next)
+ if(ma->nodetree && ma->use_nodes && has_nodetree(ma->nodetree, ntree))
+ GPU_material_free(ma);
+ }
+
WM_main_add_notifier(NC_MATERIAL|ND_NODES, node->id);
}
else if(ntree->type==NTREE_COMPOSIT) {
diff --git a/source/blender/editors/space_node/node_templates.c b/source/blender/editors/space_node/node_templates.c
index 806a6f98828..5aa15cc68d6 100644
--- a/source/blender/editors/space_node/node_templates.c
+++ b/source/blender/editors/space_node/node_templates.c
@@ -215,6 +215,11 @@ static void node_socket_add_replace(Main *bmain, bNodeTree *ntree, bNode *node_t
}
}
+ /* also preserve mapping for texture nodes */
+ if(node_from->typeinfo->nclass == NODE_CLASS_TEXTURE &&
+ node_prev->typeinfo->nclass == NODE_CLASS_TEXTURE)
+ memcpy(node_from->storage, node_prev->storage, sizeof(NodeTexBase));
+
/* remove node */
node_remove_linked(ntree, node_prev);
}
@@ -503,6 +508,10 @@ void uiTemplateNodeLink(uiLayout *layout, bNodeTree *ntree, bNode *node, bNodeSo
but->flag |= UI_TEXT_LEFT|UI_BUT_NODE_LINK;
but->poin= (char*)but;
but->func_argN = arg;
+
+ if(sock->link && sock->link->fromnode)
+ if(sock->link->fromnode->flag & NODE_ACTIVE_TEXTURE)
+ but->flag |= UI_BUT_NODE_ACTIVE;
}
/**************************** Node Tree Layout *******************************/
diff --git a/source/blender/editors/space_view3d/drawmesh.c b/source/blender/editors/space_view3d/drawmesh.c
index 670943afdd3..e23824a2210 100644
--- a/source/blender/editors/space_view3d/drawmesh.c
+++ b/source/blender/editors/space_view3d/drawmesh.c
@@ -40,11 +40,12 @@
#include "DNA_material_types.h"
#include "DNA_meshdata_types.h"
+#include "DNA_node_types.h"
+#include "DNA_object_types.h"
#include "DNA_property_types.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "DNA_view3d_types.h"
-#include "DNA_object_types.h"
#include "BKE_DerivedMesh.h"
#include "BKE_effect.h"
@@ -52,6 +53,7 @@
#include "BKE_material.h"
#include "BKE_paint.h"
#include "BKE_property.h"
+#include "BKE_scene.h"
#include "BIF_gl.h"
#include "BIF_glutil.h"
@@ -64,6 +66,7 @@
#include "GPU_material.h"
#include "ED_mesh.h"
+#include "ED_uvedit.h"
#include "view3d_intern.h" // own include
@@ -619,7 +622,7 @@ static void draw_mesh_text(Scene *scene, Object *ob, int glsl)
ddm->release(ddm);
}
-void draw_mesh_textured(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object *ob, DerivedMesh *dm, int faceselect)
+void draw_mesh_textured_old(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object *ob, DerivedMesh *dm, int faceselect)
{
Mesh *me= ob->data;
@@ -676,3 +679,179 @@ void draw_mesh_textured(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object *o
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
+/************************** NEW SHADING NODES ********************************/
+
+typedef struct TexMatCallback {
+ Scene *scene;
+ Object *ob;
+ Mesh *me;
+ DerivedMesh *dm;
+} TexMatCallback;
+
+static void tex_mat_set_material_cb(void *UNUSED(userData), int mat_nr, void *attribs)
+{
+ /* all we have to do here is simply enable the GLSL material, but note
+ that the GLSL code will give different result depending on the drawtype,
+ in texture draw mode it will output the active texture node, in material
+ draw mode it will show the full material. */
+ GPU_enable_material(mat_nr, attribs);
+}
+
+static void tex_mat_set_texture_cb(void *userData, int mat_nr, void *attribs)
+{
+ /* texture draw mode without GLSL */
+ TexMatCallback *data= (TexMatCallback*)userData;
+ GPUVertexAttribs *gattribs = attribs;
+ Image *ima;
+ ImageUser *iuser;
+ bNode *node;
+ int texture_set= 0;
+
+ /* draw image texture if we find one */
+ if(ED_object_get_active_image(data->ob, mat_nr, &ima, &iuser, &node)) {
+ /* get openl texture */
+ int mipmap= 1;
+ int bindcode= (ima)? GPU_verify_image(ima, iuser, 0, 0, mipmap): 0;
+ float zero[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+
+ if(bindcode) {
+ NodeTexBase *texbase= node->storage;
+
+ /* disable existing material */
+ GPU_disable_material();
+ glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, zero);
+ glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, zero);
+ glMateriali(GL_FRONT_AND_BACK, GL_SHININESS, 0);
+
+ /* bind texture */
+ glEnable(GL_COLOR_MATERIAL);
+ glEnable(GL_TEXTURE_2D);
+
+ glBindTexture(GL_TEXTURE_2D, ima->bindcode);
+ glColor3f(1.0f, 1.0f, 1.0f);
+
+ glMatrixMode(GL_TEXTURE);
+ glLoadMatrixf(texbase->tex_mapping.mat);
+ glMatrixMode(GL_MODELVIEW);
+
+ /* use active UV texture layer */
+ memset(gattribs, 0, sizeof(*gattribs));
+
+ gattribs->layer[0].type= CD_MTFACE;
+ gattribs->layer[0].name[0]= '\0';
+ gattribs->layer[0].gltexco= 1;
+ gattribs->totlayer= 1;
+
+ texture_set= 1;
+ }
+ }
+
+ if(!texture_set) {
+ glMatrixMode(GL_TEXTURE);
+ glLoadIdentity();
+ glMatrixMode(GL_MODELVIEW);
+
+ /* disable texture */
+ glDisable(GL_TEXTURE_2D);
+ glDisable(GL_COLOR_MATERIAL);
+
+ /* draw single color */
+ GPU_enable_material(mat_nr, attribs);
+ }
+}
+
+static int tex_mat_set_face_mesh_cb(void *userData, int index)
+{
+ /* faceselect mode face hiding */
+ TexMatCallback *data= (TexMatCallback*)userData;
+ Mesh *me = (Mesh*)data->me;
+ MFace *mface = &me->mface[index];
+
+ return !(mface->flag & ME_HIDE);
+}
+
+static int tex_mat_set_face_editmesh_cb(void *UNUSED(userData), int index)
+{
+ /* editmode face hiding */
+ EditFace *efa= EM_get_face_for_index(index);
+
+ return !(efa->h);
+}
+
+void draw_mesh_textured(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object *ob, DerivedMesh *dm, int faceselect)
+{
+ if(!scene_use_new_shading_nodes(scene)) {
+ draw_mesh_textured_old(scene, v3d, rv3d, ob, dm, faceselect);
+ return;
+ }
+
+ /* set opengl state for negative scale & color */
+ if(ob->transflag & OB_NEG_SCALE) glFrontFace(GL_CW);
+ else glFrontFace(GL_CCW);
+
+ glEnable(GL_LIGHTING);
+
+ if(ob->mode & OB_MODE_WEIGHT_PAINT) {
+ /* weight paint mode exception */
+ int useColors= 1;
+
+ dm->drawMappedFaces(dm, wpaint__setSolidDrawOptions,
+ ob->data, useColors, GPU_enable_material, NULL);
+ }
+ else {
+ Mesh *me= ob->data;
+ TexMatCallback data = {scene, ob, me, dm};
+ int (*set_face_cb)(void*, int);
+ int glsl;
+
+ /* face hiding callback depending on mode */
+ if(ob == scene->obedit)
+ set_face_cb= tex_mat_set_face_editmesh_cb;
+ else if(faceselect)
+ set_face_cb= tex_mat_set_face_mesh_cb;
+ else
+ set_face_cb= NULL;
+
+ /* test if we can use glsl */
+ glsl= (v3d->drawtype == OB_MATERIAL) && GPU_glsl_support();
+
+ GPU_begin_object_materials(v3d, rv3d, scene, ob, glsl, NULL);
+
+ if(glsl) {
+ /* draw glsl */
+ dm->drawMappedFacesMat(dm,
+ tex_mat_set_material_cb,
+ set_face_cb, &data);
+ }
+ else {
+ float zero[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+
+ /* draw textured */
+ glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, zero);
+ glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, zero);
+ glMateriali(GL_FRONT_AND_BACK, GL_SHININESS, 0);
+
+ dm->drawMappedFacesMat(dm,
+ tex_mat_set_texture_cb,
+ set_face_cb, &data);
+ }
+
+ GPU_end_object_materials();
+ }
+
+ /* reset opengl state */
+ glDisable(GL_COLOR_MATERIAL);
+ glDisable(GL_TEXTURE_2D);
+ glDisable(GL_LIGHTING);
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glFrontFace(GL_CCW);
+
+ glMatrixMode(GL_TEXTURE);
+ glLoadIdentity();
+ glMatrixMode(GL_MODELVIEW);
+
+ /* faceselect mode drawing over textured mesh */
+ if(!(ob == scene->obedit) && faceselect)
+ draw_mesh_face_select(rv3d, ob->data, dm);
+}
+
diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c
index f2bd4b51d94..8e592ad9f68 100644
--- a/source/blender/editors/space_view3d/drawobject.c
+++ b/source/blender/editors/space_view3d/drawobject.c
@@ -108,7 +108,7 @@
/* this condition has been made more complex since editmode can draw textures */
#define CHECK_OB_DRAWTEXTURE(vd, dt) \
- ((vd->drawtype==OB_TEXTURE && dt>OB_SOLID) || \
+ ((ELEM(vd->drawtype, OB_TEXTURE, OB_MATERIAL) && dt>OB_SOLID) || \
(vd->drawtype==OB_SOLID && vd->flag2 & V3D_SOLID_TEX))
static void draw_bounding_volume(Scene *scene, Object *ob, char type);
@@ -252,6 +252,8 @@ int draw_glsl_material(Scene *scene, Object *ob, View3D *v3d, int dt)
return 0;
if(ob==OBACT && (ob && ob->mode & OB_MODE_WEIGHT_PAINT))
return 0;
+ if(scene_use_new_shading_nodes(scene))
+ return 0;
return (scene->gm.matmode == GAME_MAT_GLSL) && (dt > OB_SOLID);
}
diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c
index 51bbf591bb3..8e20f331698 100644
--- a/source/blender/editors/space_view3d/view3d_draw.c
+++ b/source/blender/editors/space_view3d/view3d_draw.c
@@ -2229,11 +2229,17 @@ CustomDataMask ED_view3d_datamask(Scene *scene, View3D *v3d)
{
CustomDataMask mask= 0;
- if((v3d->drawtype == OB_TEXTURE) || ((v3d->drawtype == OB_SOLID) && (v3d->flag2 & V3D_SOLID_TEX))) {
+ if(ELEM(v3d->drawtype, OB_TEXTURE, OB_MATERIAL) || ((v3d->drawtype == OB_SOLID) && (v3d->flag2 & V3D_SOLID_TEX))) {
mask |= CD_MASK_MTFACE | CD_MASK_MCOL;
- if(scene->gm.matmode == GAME_MAT_GLSL)
- mask |= CD_MASK_ORCO;
+ if(scene_use_new_shading_nodes(scene)) {
+ if(v3d->drawtype == OB_MATERIAL)
+ mask |= CD_MASK_ORCO;
+ }
+ else {
+ if(scene->gm.matmode == GAME_MAT_GLSL)
+ mask |= CD_MASK_ORCO;
+ }
}
return mask;
diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c
index 62b875c82de..173ab809b53 100644
--- a/source/blender/editors/uvedit/uvedit_ops.c
+++ b/source/blender/editors/uvedit/uvedit_ops.c
@@ -37,7 +37,9 @@
#include "MEM_guardedalloc.h"
#include "DNA_object_types.h"
+#include "DNA_material_types.h"
#include "DNA_meshdata_types.h"
+#include "DNA_node_types.h"
#include "DNA_scene_types.h"
#include "BLI_math.h"
@@ -50,11 +52,16 @@
#include "BKE_depsgraph.h"
#include "BKE_image.h"
#include "BKE_library.h"
+#include "BKE_main.h"
+#include "BKE_material.h"
#include "BKE_mesh.h"
+#include "BKE_node.h"
#include "BKE_report.h"
+#include "BKE_scene.h"
#include "ED_image.h"
#include "ED_mesh.h"
+#include "ED_node.h"
#include "ED_uvedit.h"
#include "ED_object.h"
#include "ED_screen.h"
@@ -87,9 +94,46 @@ int ED_uvedit_test(Object *obedit)
return ret;
}
+/**************************** object active image *****************************/
+
+static int is_image_texture_node(bNode *node)
+{
+ return ELEM(node->type, SH_NODE_TEX_IMAGE, SH_NODE_TEX_ENVIRONMENT);
+}
+
+int ED_object_get_active_image(Object *ob, int mat_nr, Image **ima, ImageUser **iuser, bNode **node_r)
+{
+ Material *ma= give_current_material(ob, mat_nr);
+ bNode *node= (ma && ma->use_nodes)? nodeGetActiveTexture(ma->nodetree): NULL;
+
+ if(node && is_image_texture_node(node)) {
+ if(ima) *ima= (Image*)node->id;
+ if(iuser) *iuser= NULL;
+ if(node_r) *node_r= node;
+ return TRUE;
+ }
+
+ if(ima) *ima= NULL;
+ if(iuser) *iuser= NULL;
+ if(node_r) *node_r= node;
+
+ return FALSE;
+}
+
+void ED_object_assign_active_image(Main *bmain, Object *ob, int mat_nr, Image *ima)
+{
+ Material *ma= give_current_material(ob, mat_nr);
+ bNode *node= (ma && ma->use_nodes)? nodeGetActiveTexture(ma->nodetree): NULL;
+
+ if(node && is_image_texture_node(node)) {
+ node->id= &ima->id;
+ ED_node_generic_update(bmain, ma->nodetree, node);
+ }
+}
+
/************************* assign image ************************/
-void ED_uvedit_assign_image(Scene *scene, Object *obedit, Image *ima, Image *previma)
+void ED_uvedit_assign_image(Main *bmain, Scene *scene, Object *obedit, Image *ima, Image *previma)
{
EditMesh *em;
EditFace *efa;
@@ -109,35 +153,46 @@ void ED_uvedit_assign_image(Scene *scene, Object *obedit, Image *ima, Image *pre
BKE_mesh_end_editmesh(obedit->data, em);
return;
}
-
- /* ensure we have a uv layer */
- if(!CustomData_has_layer(&em->fdata, CD_MTFACE)) {
- EM_add_data_layer(em, &em->fdata, CD_MTFACE, NULL);
- update= 1;
+
+ if(scene_use_new_shading_nodes(scene)) {
+ /* new shading system, assign image in material */
+ int sloppy= 1;
+ EditFace *efa= EM_get_actFace(em, sloppy);
+
+ if(efa)
+ ED_object_assign_active_image(bmain, obedit, efa->mat_nr, ima);
}
+ else {
+ /* old shading system, assign image to selected faces */
+
+ /* ensure we have a uv layer */
+ if(!CustomData_has_layer(&em->fdata, CD_MTFACE)) {
+ EM_add_data_layer(em, &em->fdata, CD_MTFACE, NULL);
+ update= 1;
+ }
- /* now assign to all visible faces */
- for(efa= em->faces.first; efa; efa= efa->next) {
- tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+ /* now assign to all visible faces */
+ for(efa= em->faces.first; efa; efa= efa->next) {
+ tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
- if(uvedit_face_visible(scene, previma, efa, tf)) {
- if(ima) {
- tf->tpage= ima;
-
- if(ima->id.us==0) id_us_plus(&ima->id);
- else id_lib_extern(&ima->id);
- }
- else {
- tf->tpage= NULL;
- }
+ if(uvedit_face_visible(scene, previma, efa, tf)) {
+ if(ima) {
+ tf->tpage= ima;
+
+ if(ima->id.us==0) id_us_plus(&ima->id);
+ else id_lib_extern(&ima->id);
+ }
+ else
+ tf->tpage= NULL;
- update = 1;
+ update = 1;
+ }
}
- }
- /* and update depdency graph */
- if(update)
- DAG_id_tag_update(obedit->data, 0);
+ /* and update depdency graph */
+ if(update)
+ DAG_id_tag_update(obedit->data, 0);
+ }
BKE_mesh_end_editmesh(obedit->data, em);
}
diff --git a/source/blender/editors/uvedit/uvedit_unwrap_ops.c b/source/blender/editors/uvedit/uvedit_unwrap_ops.c
index 29a9ae84cd5..11cd50a7d4e 100644
--- a/source/blender/editors/uvedit/uvedit_unwrap_ops.c
+++ b/source/blender/editors/uvedit/uvedit_unwrap_ops.c
@@ -51,6 +51,7 @@
#include "BKE_customdata.h"
#include "BKE_depsgraph.h"
#include "BKE_image.h"
+#include "BKE_main.h"
#include "BKE_mesh.h"
#include "PIL_time.h"
@@ -73,6 +74,7 @@
static int ED_uvedit_ensure_uvs(bContext *C, Scene *scene, Object *obedit)
{
+ Main *bmain= CTX_data_main(C);
EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
EditFace *efa;
MTFace *tf;
@@ -118,7 +120,7 @@ static int ED_uvedit_ensure_uvs(bContext *C, Scene *scene, Object *obedit)
}
if(ima)
- ED_uvedit_assign_image(scene, obedit, ima, NULL);
+ ED_uvedit_assign_image(bmain, scene, obedit, ima, NULL);
/* select new UV's */
for(efa=em->faces.first; efa; efa=efa->next) {