4 * ***** BEGIN GPL LICENSE BLOCK *****
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 * The Original Code is Copyright (C) 2005 Blender Foundation.
21 * All rights reserved.
23 * The Original Code is: all of this file.
25 * Contributor(s): none yet.
27 * ***** END GPL LICENSE BLOCK *****
34 #include "BLI_blenlib.h"
35 #include "BLI_arithb.h"
37 #include "DNA_action_types.h"
38 #include "DNA_ipo_types.h"
40 #include "DNA_material_types.h"
41 #include "DNA_node_types.h"
42 #include "DNA_object_types.h"
43 #include "DNA_scene_types.h"
44 #include "DNA_space_types.h"
45 #include "DNA_screen_types.h"
46 #include "DNA_texture_types.h"
47 #include "DNA_userdef_types.h"
49 #include "BKE_global.h"
50 #include "BKE_image.h"
51 #include "BKE_library.h"
53 #include "BKE_material.h"
55 #include "BKE_object.h"
56 #include "BKE_texture.h"
57 #include "BKE_utildefines.h"
60 #include "BIF_glutil.h"
61 #include "BIF_interface.h"
62 #include "BIF_interface_icons.h"
63 #include "BIF_language.h"
64 #include "BIF_mywindow.h"
65 #include "BIF_previewrender.h"
66 #include "BIF_resources.h"
67 #include "BIF_screen.h"
68 #include "BIF_space.h"
70 #include "BSE_drawipo.h"
76 #include "MEM_guardedalloc.h"
78 #include "RE_pipeline.h"
82 #include "interface.h" /* urm... for rasterpos_safe, roundbox */
87 static void snode_drawstring(SpaceNode *snode, char *str, int okwidth)
89 char drawstr[NODE_MAXSTR];
92 if(str[0]==0 || okwidth<4) return;
94 BLI_strncpy(drawstr, str, NODE_MAXSTR);
95 width= snode->aspect*BIF_GetStringWidth(snode->curfont, drawstr, 0);
98 int len= strlen(drawstr)-1;
100 while(width > okwidth && len>=0) {
103 width= snode->aspect*BIF_GetStringWidth(snode->curfont, drawstr, 0);
108 BIF_DrawString(snode->curfont, drawstr, 0);
112 /* ************** Socket callbacks *********** */
114 /* NOTE: this is a block-menu, needs 0 events, otherwise the menu closes */
115 static uiBlock *socket_vector_menu(void *butpoin_v)
117 float *butpoin= butpoin_v;
120 block= uiNewBlock(&curarea->uiblocks, "socket menu", UI_EMBOSS, UI_HELV, curarea->win);
122 /* use this for a fake extra empy space around the buttons */
123 uiDefBut(block, LABEL, 0, "", -4, -4, 188, 68, NULL, 0, 0, 0, 0, "");
125 uiBlockBeginAlign(block);
126 uiDefButF(block, NUMSLI, 0, "X ", 0,40,180,20, butpoin, -1.0, 1.0, 10, 0, "");
127 uiDefButF(block, NUMSLI, 0, "Y ", 0,20,180,20, butpoin+1, -1.0, 1.0, 10, 0, "");
128 uiDefButF(block, NUMSLI, 0, "Z ", 0,0,180,20, butpoin+2, -1.0, 1.0, 10, 0, "");
130 uiBlockSetDirection(block, UI_TOP);
132 allqueue(REDRAWNODE, 0);
137 static void node_sync_cb(void *snode_v, void *node_v)
139 SpaceNode *snode= snode_v;
141 if(snode->treetype==NTREE_SHADER) {
142 nodeShaderSynchronizeID(node_v, 1);
143 allqueue(REDRAWBUTSSHADING, 0);
147 /* ****************** GENERAL CALLBACKS FOR NODES ***************** */
149 static void node_ID_title_cb(void *node_v, void *unused_v)
154 test_idbutton(node->id->name+2); /* library.c, verifies unique name */
155 BLI_strncpy(node->name, node->id->name+2, 21);
157 allqueue(REDRAWBUTSSHADING, 0);
158 allqueue(REDRAWNODE, 0);
159 allqueue(REDRAWOOPS, 0);
164 static void node_but_title_cb(void *node_v, void *but_v)
168 BLI_strncpy(node->name, bt->drawstr, NODE_MAXSTR);
170 allqueue(REDRAWNODE, 0);
174 /* ****************** BUTTON CALLBACKS FOR ALL TREES ***************** */
176 static int node_buts_group(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr)
178 if(block && node->id) {
182 uiBlockBeginAlign(block);
185 width= (short)(butr->xmax-butr->xmin - (node->id->us>1?19.0f:0.0f));
186 bt= uiDefBut(block, TEX, B_NOP, "NT:",
187 butr->xmin, butr->ymin, width, 19,
188 node->id->name+2, 0.0, 19.0, 0, 0, "NodeTree name");
189 uiButSetFunc(bt, node_ID_title_cb, node, NULL);
194 sprintf(str1, "%d", node->id->us);
195 bt= uiDefBut(block, BUT, B_NOP, str1,
196 butr->xmax-19, butr->ymin, 19, 19,
197 NULL, 0, 0, 0, 0, "Displays number of users. Click to make a single-user copy.");
198 //uiButSetFunc(bt, node_mat_alone_cb, node, NULL);
201 uiBlockEndAlign(block);
206 static int node_buts_value(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr)
209 bNodeSocket *sock= node->outputs.first; /* first socket stores value */
211 uiDefButF(block, NUM, B_NODE_EXEC, "",
212 butr->xmin, butr->ymin, butr->xmax-butr->xmin, 20,
213 sock->ns.vec, 0.0f, 1.0f, 10, 2, "");
219 static int node_buts_rgb(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr)
222 bNodeSocket *sock= node->outputs.first; /* first socket stores value */
224 /* enforce square box drawing */
225 uiBlockSetEmboss(block, UI_EMBOSSP);
227 uiDefButF(block, HSVCUBE, B_NODE_EXEC, "",
228 butr->xmin, butr->ymin, butr->xmax-butr->xmin, 12,
229 sock->ns.vec, 0.0f, 1.0f, 3, 0, "");
230 uiDefButF(block, HSVCUBE, B_NODE_EXEC, "",
231 butr->xmin, butr->ymin+15, butr->xmax-butr->xmin, butr->ymax-butr->ymin -15 -15,
232 sock->ns.vec, 0.0f, 1.0f, 2, 0, "");
233 uiDefButF(block, COL, B_NOP, "",
234 butr->xmin, butr->ymax-12, butr->xmax-butr->xmin, 12,
235 sock->ns.vec, 0.0, 0.0, -1, 0, "");
236 /* the -1 above prevents col button to popup a color picker */
238 uiBlockSetEmboss(block, UI_EMBOSS);
241 return 30 + (int)(node->width-NODE_DY);
244 static int node_buts_mix_rgb(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr)
250 bt=uiDefButS(block, MENU, B_NODE_EXEC, "Mix %x0|Add %x1|Subtract %x3|Multiply %x2|Screen %x4|Divide %x5|Difference %x6|Darken %x7|Lighten %x8",
251 butr->xmin, butr->ymin, butr->xmax-butr->xmin, 20,
252 &node->custom1, 0, 0, 0, 0, "");
253 uiButSetFunc(bt, node_but_title_cb, node, bt);
258 static int node_buts_valtorgb(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr)
262 draw_colorband_buts_small(block, node->storage, butr, B_NODE_EXEC);
268 static int node_buts_curvevec(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr)
271 curvemap_buttons(block, node->storage, 'v', B_NODE_EXEC, B_REDR, butr);
273 return (int)(node->width-NODE_DY);
276 static int node_buts_curvecol(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr)
279 curvemap_buttons(block, node->storage, 'c', B_NODE_EXEC, B_REDR, butr);
281 return (int)(node->width-NODE_DY);
284 static int node_buts_normal(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr)
287 bNodeSocket *sock= node->outputs.first; /* first socket stores normal */
289 uiDefButF(block, BUT_NORMAL, B_NODE_EXEC, "",
290 butr->xmin, butr->ymin, butr->xmax-butr->xmin, butr->ymax-butr->ymin,
291 sock->ns.vec, 0.0f, 1.0f, 0, 0, "");
294 return (int)(node->width-NODE_DY);
299 /* ****************** BUTTON CALLBACKS FOR SHADER NODES ***************** */
302 static void node_mat_alone_cb(void *node_v, void *unused)
306 node->id= (ID *)copy_material((Material *)node->id);
308 BIF_undo_push("Single user material");
309 allqueue(REDRAWBUTSSHADING, 0);
310 allqueue(REDRAWNODE, 0);
311 allqueue(REDRAWOOPS, 0);
314 static void node_browse_mat_cb(void *ntree_v, void *node_v)
316 bNodeTree *ntree= ntree_v;
319 if(node->menunr<1) return;
321 if(node->menunr==32767) { /* code for Add New */
323 /* make copy, but make sure it doesnt have the node tag nor nodes */
324 Material *ma= (Material *)node->id;
326 ma= copy_material(ma);
329 ntreeFreeTree(ma->nodetree);
330 MEM_freeN(ma->nodetree);
335 else node->id= (ID *)add_material("MatNode");
338 if(node->id) node->id->us--;
339 node->id= BLI_findlink(&G.main->mat, node->menunr-1);
340 id_us_plus(node->id);
342 BLI_strncpy(node->name, node->id->name+2, 21);
344 nodeSetActive(ntree, node);
346 allqueue(REDRAWBUTSSHADING, 0);
347 allqueue(REDRAWNODE, 0);
348 BIF_preview_changed(ID_MA);
353 static void node_new_mat_cb(void *ntree_v, void *node_v)
355 bNodeTree *ntree= ntree_v;
358 node->id= (ID *)add_material("MatNode");
359 BLI_strncpy(node->name, node->id->name+2, 21);
361 nodeSetActive(ntree, node);
363 allqueue(REDRAWBUTSSHADING, 0);
364 allqueue(REDRAWNODE, 0);
365 BIF_preview_changed(ID_MA);
369 static void node_texmap_cb(void *texmap_v, void *unused_v)
371 init_mapping(texmap_v);
374 static int node_shader_buts_material(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr)
378 short dx= (short)((butr->xmax-butr->xmin)/3.0f), has_us= (node->id && node->id->us>1);
379 short dy= (short)butr->ymin;
382 /* WATCH IT: we use this callback in material buttons, but then only want first row */
383 if(butr->ymax-butr->ymin > 21.0f) dy+= 19;
385 uiBlockBeginAlign(block);
386 if(node->id==NULL) uiBlockSetCol(block, TH_REDALERT);
387 else if(has_us) uiBlockSetCol(block, TH_BUT_SETTING1);
388 else uiBlockSetCol(block, TH_BUT_SETTING2);
391 IDnames_to_pupstring(&strp, NULL, "ADD NEW %x32767", &(G.main->mat), NULL, NULL);
393 bt= uiDefButS(block, MENU, B_NOP, strp,
394 butr->xmin, dy, 19, 19,
395 &node->menunr, 0, 0, 0, 0, "Browses existing choices or adds NEW");
396 uiButSetFunc(bt, node_browse_mat_cb, ntree, node);
397 if(strp) MEM_freeN(strp);
401 bt= uiDefBut(block, BUT, B_NOP, "Add New",
402 butr->xmin+19, dy, (short)(butr->xmax-butr->xmin-19.0f), 19,
403 NULL, 0.0, 0.0, 0, 0, "Add new Material");
404 uiButSetFunc(bt, node_new_mat_cb, ntree, node);
405 uiBlockSetCol(block, TH_AUTO);
409 short width= (short)(butr->xmax-butr->xmin-19.0f - (has_us?19.0f:0.0f));
410 bt= uiDefBut(block, TEX, B_NOP, "MA:",
411 butr->xmin+19, dy, width, 19,
412 node->id->name+2, 0.0, 19.0, 0, 0, "Material name");
413 uiButSetFunc(bt, node_ID_title_cb, node, NULL);
418 sprintf(str1, "%d", node->id->us);
419 bt= uiDefBut(block, BUT, B_NOP, str1,
420 butr->xmax-19, dy, 19, 19,
421 NULL, 0, 0, 0, 0, "Displays number of users. Click to make a single-user copy.");
422 uiButSetFunc(bt, node_mat_alone_cb, node, NULL);
425 /* WATCH IT: we use this callback in material buttons, but then only want first row */
426 if(butr->ymax-butr->ymin > 21.0f) {
428 uiBlockSetCol(block, TH_AUTO);
429 uiDefButBitS(block, TOG, SH_NODE_MAT_DIFF, B_NODE_EXEC, "Diff",
430 butr->xmin, butr->ymin, dx, 19,
431 &node->custom1, 0, 0, 0, 0, "Material Node outputs Diffuse");
432 uiDefButBitS(block, TOG, SH_NODE_MAT_SPEC, B_NODE_EXEC, "Spec",
433 butr->xmin+dx, butr->ymin, dx, 19,
434 &node->custom1, 0, 0, 0, 0, "Material Node outputs Specular");
435 uiDefButBitS(block, TOG, SH_NODE_MAT_NEG, B_NODE_EXEC, "Neg Normal",
436 butr->xmax-dx, butr->ymin, dx, 19,
437 &node->custom1, 0, 0, 0, 0, "Material Node uses inverted Normal");
440 uiBlockEndAlign(block);
445 static int node_shader_buts_texture(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr)
450 bt= uiDefIDPoinBut(block, test_texpoin_but, ID_TE, B_NODE_EXEC, "",
451 butr->xmin, butr->ymin, butr->xmax-butr->xmin, 19,
453 uiButSetFunc(bt, node_ID_title_cb, node, NULL);
460 static int node_shader_buts_mapping(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr)
463 TexMapping *texmap= node->storage;
464 short dx= (short)((butr->xmax-butr->xmin)/7.0f);
465 short dy= (short)(butr->ymax-19);
467 uiBlockSetFunc(block, node_texmap_cb, texmap, NULL); /* all buttons get this */
469 uiBlockBeginAlign(block);
470 uiDefButF(block, NUM, B_NODE_EXEC, "", butr->xmin+dx, dy, 2*dx, 19, texmap->loc, -1000.0f, 1000.0f, 10, 2, "");
471 uiDefButF(block, NUM, B_NODE_EXEC, "", butr->xmin+3*dx, dy, 2*dx, 19, texmap->loc+1, -1000.0f, 1000.0f, 10, 2, "");
472 uiDefButF(block, NUM, B_NODE_EXEC, "", butr->xmin+5*dx, dy, 2*dx, 19, texmap->loc+2, -1000.0f, 1000.0f, 10, 2, "");
474 uiDefButF(block, NUM, B_NODE_EXEC, "", butr->xmin+dx, dy, 2*dx, 19, texmap->rot, -1000.0f, 1000.0f, 1000, 1, "");
475 uiDefButF(block, NUM, B_NODE_EXEC, "", butr->xmin+3*dx, dy, 2*dx, 19, texmap->rot+1, -1000.0f, 1000.0f, 1000, 1, "");
476 uiDefButF(block, NUM, B_NODE_EXEC, "", butr->xmin+5*dx, dy, 2*dx, 19, texmap->rot+2, -1000.0f, 1000.0f, 1000, 1, "");
478 uiDefButF(block, NUM, B_NODE_EXEC, "", butr->xmin+dx, dy, 2*dx, 19, texmap->size, -1000.0f, 1000.0f, 10, 2, "");
479 uiDefButF(block, NUM, B_NODE_EXEC, "", butr->xmin+3*dx, dy, 2*dx, 19, texmap->size+1, -1000.0f, 1000.0f, 10, 2, "");
480 uiDefButF(block, NUM, B_NODE_EXEC, "", butr->xmin+5*dx, dy, 2*dx, 19, texmap->size+2, -1000.0f, 1000.0f, 10, 2, "");
482 uiBlockBeginAlign(block);
483 uiDefButF(block, NUM, B_NODE_EXEC, "", butr->xmin+dx, dy, 2*dx, 19, texmap->min, -10.0f, 10.0f, 100, 2, "");
484 uiDefButF(block, NUM, B_NODE_EXEC, "", butr->xmin+3*dx, dy, 2*dx, 19, texmap->min+1, -10.0f, 10.0f, 100, 2, "");
485 uiDefButF(block, NUM, B_NODE_EXEC, "", butr->xmin+5*dx, dy, 2*dx, 19, texmap->min+2, -10.0f, 10.0f, 100, 2, "");
487 uiDefButF(block, NUM, B_NODE_EXEC, "", butr->xmin+dx, dy, 2*dx, 19, texmap->max, -10.0f, 10.0f, 10, 2, "");
488 uiDefButF(block, NUM, B_NODE_EXEC, "", butr->xmin+3*dx, dy, 2*dx, 19, texmap->max+1, -10.0f, 10.0f, 10, 2, "");
489 uiDefButF(block, NUM, B_NODE_EXEC, "", butr->xmin+5*dx, dy, 2*dx, 19, texmap->max+2, -10.0f, 10.0f, 10, 2, "");
490 uiBlockEndAlign(block);
494 dy= (short)(butr->ymax-19);
495 uiDefBut(block, LABEL, B_NOP, "Loc", butr->xmin, dy, dx, 19, NULL, 0.0f, 0.0f, 0, 0, "");
497 uiDefBut(block, LABEL, B_NOP, "Rot", butr->xmin, dy, dx, 19, NULL, 0.0f, 0.0f, 0, 0, "");
499 uiDefBut(block, LABEL, B_NOP, "Size", butr->xmin, dy, dx, 19, NULL, 0.0f, 0.0f, 0, 0, "");
501 uiDefButBitI(block, TOG, TEXMAP_CLIP_MIN, B_NODE_EXEC, "Min", butr->xmin, dy, dx-4, 19, &texmap->flag, 0.0f, 0.0f, 0, 0, "");
503 uiDefButBitI(block, TOG, TEXMAP_CLIP_MAX, B_NODE_EXEC, "Max", butr->xmin, dy, dx-4, 19, &texmap->flag, 0.0f, 0.0f, 0, 0, "");
510 /* only once called */
511 static void node_shader_set_butfunc(bNodeType *ntype)
513 switch(ntype->type) {
514 case NODE_GROUP: /* note, generic type, but put here because we call this function anyway */
515 ntype->butfunc= node_buts_group;
517 case SH_NODE_MATERIAL:
518 ntype->butfunc= node_shader_buts_material;
520 case SH_NODE_TEXTURE:
521 ntype->butfunc= node_shader_buts_texture;
524 ntype->butfunc= node_buts_normal;
526 case SH_NODE_CURVE_VEC:
527 ntype->butfunc= node_buts_curvevec;
529 case SH_NODE_CURVE_RGB:
530 ntype->butfunc= node_buts_curvecol;
532 case SH_NODE_MAPPING:
533 ntype->butfunc= node_shader_buts_mapping;
536 ntype->butfunc= node_buts_value;
539 ntype->butfunc= node_buts_rgb;
541 case SH_NODE_MIX_RGB:
542 ntype->butfunc= node_buts_mix_rgb;
544 case SH_NODE_VALTORGB:
545 ntype->butfunc= node_buts_valtorgb;
548 ntype->butfunc= NULL;
552 /* ****************** BUTTON CALLBACKS FOR COMPOSIT NODES ***************** */
556 static void node_browse_image_cb(void *ntree_v, void *node_v)
558 bNodeTree *ntree= ntree_v;
561 nodeSetActive(ntree, node);
563 if(node->menunr<1) return;
564 if(node->menunr==32767) { /* code for Load New */
565 addqueue(curarea->win, UI_BUT_EVENT, B_NODE_LOADIMAGE);
568 if(node->id) node->id->us--;
569 node->id= BLI_findlink(&G.main->image, node->menunr-1);
570 id_us_plus(node->id);
572 BLI_strncpy(node->name, node->id->name+2, 21);
574 addqueue(curarea->win, RENDERPREVIEW, 1);
579 static void node_active_cb(void *ntree_v, void *node_v)
581 nodeSetActive(ntree_v, node_v);
583 static void node_image_anim_cb(void *node_v, void *unused)
589 MEM_freeN(node->storage);
593 nia= node->storage= MEM_callocN(sizeof(NodeImageAnim), "node image anim");
594 nia->sfra= nia->nr= 1;
596 allqueue(REDRAWNODE, 1);
599 static int node_composit_buts_image(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr)
603 short dy= (short)butr->ymax-19;
606 uiBlockBeginAlign(block);
607 uiBlockSetCol(block, TH_BUT_SETTING2);
610 IDnames_to_pupstring(&strp, NULL, "LOAD NEW %x32767", &(G.main->image), NULL, NULL);
612 bt= uiDefButS(block, MENU, B_NOP, strp,
613 butr->xmin, dy, 19, 19,
614 &node->menunr, 0, 0, 0, 0, "Browses existing choices");
615 uiButSetFunc(bt, node_browse_image_cb, ntree, node);
616 if(strp) MEM_freeN(strp);
620 bt= uiDefBut(block, BUT, B_NODE_LOADIMAGE, "Load New",
621 butr->xmin+19, dy, (short)(butr->xmax-butr->xmin-19.0f), 19,
622 NULL, 0.0, 0.0, 0, 0, "Add new Image");
623 uiButSetFunc(bt, node_active_cb, ntree, node);
624 uiBlockSetCol(block, TH_AUTO);
628 short width= (short)(butr->xmax-butr->xmin-38.0f);
629 bt= uiDefBut(block, TEX, B_NOP, "IMA:",
630 butr->xmin+19, dy, width, 19,
631 node->id->name+2, 0.0, 19.0, 0, 0, "Image name");
632 uiButSetFunc(bt, node_ID_title_cb, node, NULL);
633 bt= uiDefIconBut(block, BUT, B_NOP, ICON_SEQUENCE,
634 butr->xmax-19, dy, 19, 19,
635 node->id->name+2, 0.0, 19.0, 0, 0, "Enable/Disable Image animation");
636 uiButSetFunc(bt, node_image_anim_cb, node, NULL);
639 NodeImageAnim *nia= node->storage;
640 short width= (short)(butr->xmax-butr->xmin)/2;
643 uiDefButS(block, NUM, B_NODE_EXEC, "Frs:",
644 butr->xmin, dy, width, 19,
645 &nia->frames, 0.0, 10000.0, 0, 0, "Amount of images used in animation");
646 uiDefButS(block, NUM, B_NODE_EXEC, "SFra:",
647 butr->xmin+width, dy, width, 19,
648 &nia->sfra, 1.0, 1000.0, 0, 0, "Start frame of animation");
650 uiDefButS(block, NUM, B_NODE_EXEC, "First:",
651 butr->xmin, dy, width, 19,
652 &nia->nr, 0.0, 10000.0, 0, 0, "Number in image name, used as first in animation");
653 uiDefButC(block, TOG, B_NODE_EXEC, "Cycl",
654 butr->xmin+width, dy, width, 19,
655 &nia->cyclic, 0.0, 0.0, 0, 0, "Make animation go cyclic");
666 static char *scene_layer_menu(void)
668 SceneRenderLayer *srl;
669 int len= 32 + 32*BLI_countlist(&G.scene->r.layers);
671 char *str= MEM_callocN(len, "menu layers");
673 strcpy(str, "Active Layer %t");
675 for(nr=0, srl= G.scene->r.layers.first; srl; srl= srl->next, nr++) {
676 a+= sprintf(str+a, "|%s %%x%d", srl->name, nr);
683 static int node_composit_buts_renderresult(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr)
689 strp= scene_layer_menu();
690 bt= uiDefButS(block, MENU, B_NODE_EXEC, strp,
691 butr->xmin, butr->ymin, (butr->xmax-butr->xmin), 19,
692 &node->custom1, 0, 0, 0, 0, "Choose Render Layer");
693 uiButSetFunc(bt, node_but_title_cb, node, bt);
699 static int node_composit_buts_blur(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr)
704 uiBlockBeginAlign(block);
705 bt=uiDefButS(block, NUM, B_NODE_EXEC, "X:",
706 butr->xmin, butr->ymin, (butr->xmax-butr->xmin)/2, 19,
707 &node->custom1, 0, 256, 0, 0, "");
708 bt=uiDefButS(block, NUM, B_NODE_EXEC, "Y:",
709 butr->xmin+(butr->xmax-butr->xmin)/2, butr->ymin, (butr->xmax-butr->xmin)/2, 19,
710 &node->custom2, 0, 256, 0, 0, "");
715 static int node_composit_buts_filter(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr)
721 bt=uiDefButS(block, MENU, B_NODE_EXEC, "Soften %x0|Sharpen %x1|Laplace %x2|Sobel %x3|Prewitt %x4|Kirsch %x5|Shadow %x6",
722 butr->xmin, butr->ymin, butr->xmax-butr->xmin, 20,
723 &node->custom1, 0, 0, 0, 0, "");
724 uiButSetFunc(bt, node_but_title_cb, node, bt);
729 static int node_composit_buts_map_value(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr)
732 TexMapping *texmap= node->storage;
733 short xstart= (short)butr->xmin;
734 short dy= (short)(butr->ymax-19.0f);
735 short dx= (short)(butr->xmax-butr->xmin)/2;
737 uiBlockBeginAlign(block);
738 uiDefButF(block, NUM, B_NODE_EXEC, "Offs:", xstart, dy, 2*dx, 19, texmap->loc, -1000.0f, 1000.0f, 10, 2, "");
740 uiDefButF(block, NUM, B_NODE_EXEC, "Size:", xstart, dy, 2*dx, 19, texmap->size, -1000.0f, 1000.0f, 10, 3, "");
742 uiBlockBeginAlign(block);
743 uiDefButBitI(block, TOG, TEXMAP_CLIP_MIN, B_NODE_EXEC, "Min", xstart, dy, dx, 19, &texmap->flag, 0.0f, 0.0f, 0, 0, "");
744 uiDefButF(block, NUM, B_NODE_EXEC, "", xstart+dx, dy, dx, 19, texmap->min, -1000.0f, 1000.0f, 10, 2, "");
746 uiDefButBitI(block, TOG, TEXMAP_CLIP_MIN, B_NODE_EXEC, "Max", xstart, dy, dx, 19, &texmap->flag, 0.0f, 0.0f, 0, 0, "");
747 uiDefButF(block, NUM, B_NODE_EXEC, "", xstart+dx, dy, dx, 19, texmap->min, -1000.0f, 1000.0f, 10, 2, "");
753 /* only once called */
754 static void node_composit_set_butfunc(bNodeType *ntype)
756 switch(ntype->type) {
757 case NODE_GROUP: /* note, generic type, but put here because we call this function anyway */
758 ntype->butfunc= node_buts_group;
761 ntype->butfunc= node_composit_buts_image;
763 case CMP_NODE_R_RESULT:
764 ntype->butfunc= node_composit_buts_renderresult;
766 case CMP_NODE_NORMAL:
767 ntype->butfunc= node_buts_normal;
769 case CMP_NODE_CURVE_VEC:
770 ntype->butfunc= node_buts_curvevec;
772 case CMP_NODE_CURVE_RGB:
773 ntype->butfunc= node_buts_curvecol;
776 ntype->butfunc= node_buts_value;
779 ntype->butfunc= node_buts_rgb;
781 case CMP_NODE_MIX_RGB:
782 ntype->butfunc= node_buts_mix_rgb;
784 case CMP_NODE_VALTORGB:
785 ntype->butfunc= node_buts_valtorgb;
788 ntype->butfunc= node_composit_buts_blur;
790 case CMP_NODE_FILTER:
791 ntype->butfunc= node_composit_buts_filter;
793 case CMP_NODE_MAP_VALUE:
794 ntype->butfunc= node_composit_buts_map_value;
797 ntype->butfunc= NULL;
802 /* ******* init draw callbacks for all tree types, only called in usiblender.c, once ************* */
804 void init_node_butfuncs(void)
806 bNodeType **typedefs;
809 typedefs= node_all_shaders; /* BKE_node.h */
811 node_shader_set_butfunc(*typedefs);
815 typedefs= node_all_composit; /* BKE_node.h */
817 node_composit_set_butfunc(*typedefs);
822 /* ************** Generic drawing ************** */
824 static void draw_nodespace_grid(SpaceNode *snode)
826 float start, step= 25.0f;
828 BIF_ThemeColorShade(TH_BACK, -10);
830 start= snode->v2d.cur.xmin -fmod(snode->v2d.cur.xmin, step);
833 for(; start<snode->v2d.cur.xmax; start+=step) {
834 glVertex2f(start, snode->v2d.cur.ymin);
835 glVertex2f(start, snode->v2d.cur.ymax);
838 start= snode->v2d.cur.ymin -fmod(snode->v2d.cur.ymin, step);
839 for(; start<snode->v2d.cur.ymax; start+=step) {
840 glVertex2f(snode->v2d.cur.xmin, start);
841 glVertex2f(snode->v2d.cur.xmax, start);
845 BIF_ThemeColorShade(TH_BACK, -18);
846 glVertex2f(0.0f, snode->v2d.cur.ymin);
847 glVertex2f(0.0f, snode->v2d.cur.ymax);
848 glVertex2f(snode->v2d.cur.xmin, 0.0f);
849 glVertex2f(snode->v2d.cur.xmax, 0.0f);
855 static void nodeshadow(rctf *rct, float radius, float aspect, int select)
863 if(radius > (rct->ymax-rct->ymin-10.0f)/2.0f)
864 rad= (rct->ymax-rct->ymin-10.0f)/2.0f;
868 if(select) a= 10.0f*aspect; else a= 7.0f*aspect;
869 for(; a>0.0f; a-=aspect) {
870 /* alpha ranges from 2 to 20 or so */
871 glColor4ub(0, 0, 0, alpha);
874 gl_round_box(GL_POLYGON, rct->xmin - a, rct->ymin - a, rct->xmax + a, rct->ymax-10.0f + a, rad+a);
877 /* outline emphasis */
878 glEnable( GL_LINE_SMOOTH );
879 glColor4ub(0, 0, 0, 100);
880 gl_round_box(GL_LINE_LOOP, rct->xmin-0.5f, rct->ymin-0.5f, rct->xmax+0.5f, rct->ymax+0.5f, radius);
881 glDisable( GL_LINE_SMOOTH );
886 /* nice AA filled circle */
887 static void socket_circle_draw(float x, float y, float size, int type, int select)
889 /* 16 values of sin function */
890 static float si[16] = {
891 0.00000000, 0.39435585,0.72479278,0.93775213,
892 0.99871650,0.89780453,0.65137248,0.29936312,
893 -0.10116832,-0.48530196,-0.79077573,-0.96807711,
894 -0.98846832,-0.84864425,-0.57126821,-0.20129852
896 /* 16 values of cos function */
897 static float co[16] ={
898 1.00000000,0.91895781,0.68896691,0.34730525,
899 -0.05064916,-0.44039415,-0.75875812,-0.95413925,
900 -0.99486932,-0.87434661,-0.61210598,-0.25065253,
901 0.15142777,0.52896401,0.82076344,0.97952994,
908 else if(type==SOCK_VALUE)
909 glColor3ub(160, 160, 160);
910 else if(type==SOCK_VECTOR)
911 glColor3ub(100, 100, 200);
912 else if(type==SOCK_RGBA)
913 glColor3ub(200, 200, 40);
915 glColor3ub(100, 200, 100);
919 glColor3ub(200, 200, 200);
920 else if(type==SOCK_VECTOR)
921 glColor3ub(140, 140, 240);
922 else if(type==SOCK_RGBA)
923 glColor3ub(240, 240, 100);
925 glColor3ub(140, 240, 140);
930 glVertex2f(x+size*si[a], y+size*co[a]);
933 glColor4ub(0, 0, 0, 150);
935 glEnable( GL_LINE_SMOOTH );
936 glBegin(GL_LINE_LOOP);
938 glVertex2f(x+size*si[a], y+size*co[a]);
940 glDisable( GL_LINE_SMOOTH );
945 static void node_draw_preview(bNodePreview *preview, rctf *prv)
947 float scale= (prv->xmax-prv->xmin)/((float)preview->xsize);
948 float centx= prv->xmin + 0.5*(prv->xmax-prv->xmin);
949 float centy= prv->ymin + 0.5*(prv->ymax-prv->ymin);
951 /* draw standard bacdrop to show alpha */
952 glBegin(GL_TRIANGLES);
953 glColor3f(0.625f, 0.625f, 0.625f);
954 glVertex2f(prv->xmin, prv->ymin);
955 glVertex2f(prv->xmax, prv->ymin);
956 glVertex2f(centx, centy);
957 glVertex2f(prv->xmin, prv->ymax);
958 glVertex2f(prv->xmax, prv->ymax);
959 glVertex2f(centx, centy);
961 glColor3f(0.25f, 0.25f, 0.25f);
962 glVertex2f(prv->xmin, prv->ymin);
963 glVertex2f(prv->xmin, prv->ymax);
964 glVertex2f(centx, centy);
965 glVertex2f(prv->xmax, prv->ymin);
966 glVertex2f(prv->xmax, prv->ymax);
967 glVertex2f(centx, centy);
970 glPixelZoom(scale, scale);
973 glaDrawPixelsTex(prv->xmin, prv->ymin, preview->xsize, preview->ysize, GL_FLOAT, preview->rect);
976 glPixelZoom(1.0f, 1.0f);
980 /* based on settings in node, sets drawing rect info. each redraw! */
981 static void node_update_hidden(bNode *node)
984 float rad, drad, hiddenrad= HIDDEN_RAD;
985 int totin=0, totout=0, tot;
987 /* calculate minimal radius */
988 for(nsock= node->inputs.first; nsock; nsock= nsock->next)
989 if(!(nsock->flag & SOCK_HIDDEN))
991 for(nsock= node->outputs.first; nsock; nsock= nsock->next)
992 if(!(nsock->flag & SOCK_HIDDEN))
995 tot= MAX2(totin, totout);
997 hiddenrad += 5.0*(float)(tot-4);
1000 node->totr.xmin= node->locx;
1001 node->totr.xmax= node->locx + 3*hiddenrad + node->miniwidth;
1002 node->totr.ymax= node->locy + (hiddenrad - 0.5f*NODE_DY);
1003 node->totr.ymin= node->totr.ymax - 2*hiddenrad;
1005 /* output sockets */
1006 rad=drad= M_PI/(1.0f + (float)totout);
1008 for(nsock= node->outputs.first; nsock; nsock= nsock->next) {
1009 if(!(nsock->flag & SOCK_HIDDEN)) {
1010 nsock->locx= node->totr.xmax - hiddenrad + sin(rad)*hiddenrad;
1011 nsock->locy= node->totr.ymin + hiddenrad + cos(rad)*hiddenrad;
1017 rad=drad= - M_PI/(1.0f + (float)totin);
1019 for(nsock= node->inputs.first; nsock; nsock= nsock->next) {
1020 if(!(nsock->flag & SOCK_HIDDEN)) {
1021 nsock->locx= node->totr.xmin + hiddenrad + sin(rad)*hiddenrad;
1022 nsock->locy= node->totr.ymin + hiddenrad + cos(rad)*hiddenrad;
1028 /* based on settings in node, sets drawing rect info. each redraw! */
1029 static void node_update(bNode *node)
1032 float dy= node->locy;
1037 /* little bit space in top */
1038 if(node->outputs.first)
1041 /* output sockets */
1042 for(nsock= node->outputs.first; nsock; nsock= nsock->next) {
1043 if(!(nsock->flag & SOCK_HIDDEN)) {
1044 nsock->locx= node->locx + node->width;
1045 nsock->locy= dy - NODE_DYS;
1050 node->prvr.xmin= node->butr.xmin= node->locx + NODE_DYS;
1051 node->prvr.xmax= node->butr.xmax= node->locx + node->width- NODE_DYS;
1054 if(node->flag & NODE_PREVIEW) {
1055 /* only recalculate size when there's a preview actually, otherwise we use stored result */
1056 if(node->preview && node->preview->rect) {
1059 if(node->preview && node->preview->xsize && node->preview->ysize)
1060 aspect= (float)node->preview->ysize/(float)node->preview->xsize;
1063 node->prvr.ymax= dy;
1064 node->prvr.ymin= dy - aspect*(node->width-NODE_DY);
1065 dy= node->prvr.ymin - NODE_DYS/2;
1068 float oldh= node->prvr.ymax - node->prvr.ymin;
1070 oldh= node->width-NODE_DY;
1072 node->prvr.ymax= dy;
1073 node->prvr.ymin= dy - oldh;
1074 dy= node->prvr.ymin - NODE_DYS/2;
1079 if((node->flag & NODE_OPTIONS) && node->typeinfo->butfunc) {
1081 node->butr.ymax= dy;
1082 node->butr.ymin= dy - (float)node->typeinfo->butfunc(NULL, NULL, node, NULL);
1083 dy= node->butr.ymin - NODE_DYS/2;
1087 for(nsock= node->inputs.first; nsock; nsock= nsock->next) {
1088 if(!(nsock->flag & SOCK_HIDDEN)) {
1089 nsock->locx= node->locx;
1090 nsock->locy= dy - NODE_DYS;
1095 /* little bit space in end */
1096 if(node->inputs.first || (node->flag & (NODE_OPTIONS|NODE_PREVIEW))==0 )
1099 node->totr.xmin= node->locx;
1100 node->totr.xmax= node->locx + node->width;
1101 node->totr.ymax= node->locy;
1102 node->totr.ymin= dy;
1105 /* based on settings in node, sets drawing rect info. each redraw! */
1106 /* note: this assumes only 1 group at a time is drawn (linked data) */
1107 /* in node->totr the entire boundbox for the group is stored */
1108 static void node_update_group(bNode *gnode)
1110 bNodeTree *ngroup= (bNodeTree *)gnode->id;
1113 rctf *rect= &gnode->totr;
1116 /* center them, is a bit of abuse of locx and locy though */
1117 for(node= ngroup->nodes.first; node; node= node->next) {
1118 node->locx+= gnode->locx;
1119 node->locy+= gnode->locy;
1120 if(node->flag & NODE_HIDDEN)
1121 node_update_hidden(node);
1124 node->locx-= gnode->locx;
1125 node->locy-= gnode->locy;
1128 for(node= ngroup->nodes.first; node; node= node->next) {
1134 BLI_union_rctf(rect, &node->totr);
1136 if(counter==1) return; /* should be prevented? */
1138 rect->xmin-= NODE_DY;
1139 rect->ymin-= NODE_DY;
1140 rect->xmax+= NODE_DY;
1141 rect->ymax+= NODE_DY;
1143 /* output sockets */
1144 for(nsock= gnode->outputs.first; nsock; nsock= nsock->next) {
1145 nsock->locx= rect->xmax;
1146 nsock->locy= nsock->tosock->locy;
1150 for(nsock= gnode->inputs.first; nsock; nsock= nsock->next) {
1151 nsock->locx= rect->xmin;
1152 nsock->locy= nsock->tosock->locy;
1156 static void node_scaling_widget(int color_id, float aspect, float xmin, float ymin, float xmax, float ymax)
1161 dx= 0.5f*(xmax-xmin);
1162 dy= 0.5f*(ymax-ymin);
1164 BIF_ThemeColorShade(color_id, +30);
1165 fdrawline(xmin, ymin, xmax, ymax);
1166 fdrawline(xmin+dx, ymin, xmax, ymax-dy);
1168 BIF_ThemeColorShade(color_id, -10);
1169 fdrawline(xmin, ymin+aspect, xmax, ymax+aspect);
1170 fdrawline(xmin+dx, ymin+aspect, xmax, ymax-dy+aspect);
1173 static int node_get_colorid(bNode *node)
1175 if(node->typeinfo->nclass==NODE_CLASS_INPUT)
1176 return TH_NODE_IN_OUT;
1177 if(node->typeinfo->nclass==NODE_CLASS_OUTPUT) {
1178 if(node->flag & NODE_DO_OUTPUT)
1179 return TH_NODE_IN_OUT;
1183 if(node->typeinfo->nclass==NODE_CLASS_GENERATOR)
1184 return TH_NODE_GENERATOR;
1185 if(node->typeinfo->nclass==NODE_CLASS_OPERATOR)
1186 return TH_NODE_OPERATOR;
1187 if(node->typeinfo->nclass==NODE_CLASS_GROUP)
1188 return TH_NODE_GROUP;
1192 static void node_draw_basis(ScrArea *sa, SpaceNode *snode, bNode *node)
1196 rctf *rct= &node->totr;
1197 float slen, iconofs;
1198 int ofs, color_id= node_get_colorid(node);
1200 uiSetRoundBox(15-4);
1201 nodeshadow(rct, BASIS_RAD, snode->aspect, node->flag & SELECT);
1204 if(color_id==TH_NODE)
1205 BIF_ThemeColorShade(color_id, -20);
1207 BIF_ThemeColor(color_id);
1210 uiRoundBox(rct->xmin, rct->ymax-NODE_DY, rct->xmax, rct->ymax, BASIS_RAD);
1212 /* show/hide icons, note this sequence is copied in editnode.c */
1215 if(node->typeinfo->flag & NODE_PREVIEW) {
1218 if(node->flag & (NODE_ACTIVE_ID|NODE_DO_OUTPUT))
1219 icon_id= ICON_MATERIAL;
1221 icon_id= ICON_MATERIAL_DEHLT;
1224 BIF_icon_set_aspect(icon_id, snode->aspect);
1225 BIF_icon_draw_blended(iconofs, rct->ymax-NODE_DY+2, icon_id, 0, -60);
1226 glDisable(GL_BLEND);
1228 if(node->type == NODE_GROUP) {
1231 BIF_icon_set_aspect(ICON_NODE, snode->aspect);
1232 BIF_icon_draw_blended(iconofs, rct->ymax-NODE_DY+2, ICON_NODE, 0, -60);
1233 glDisable(GL_BLEND);
1235 if(node->typeinfo->flag & NODE_OPTIONS) {
1238 BIF_icon_set_aspect(ICON_BUTS, snode->aspect);
1239 BIF_icon_draw_blended(iconofs, rct->ymax-NODE_DY+2, ICON_BUTS, 0, -60);
1240 glDisable(GL_BLEND);
1242 if(node->outputs.first) {
1244 /* socket selector */
1246 if(node_has_hidden_sockets(node))
1251 BIF_icon_set_aspect(ICON_PLUS, snode->aspect);
1252 BIF_icon_draw_blended(iconofs, rct->ymax-NODE_DY+2, ICON_PLUS, 0, shade);
1253 glDisable(GL_BLEND);
1257 if(node->flag & SELECT)
1258 BIF_ThemeColor(TH_TEXT_HI);
1260 BIF_ThemeColorBlendShade(TH_TEXT, color_id, 0.4, 10);
1262 /* open/close entirely? */
1263 ui_draw_tria_icon(rct->xmin+8.0f, rct->ymax-NODE_DY+4.0f, snode->aspect, 'v');
1265 if(node->flag & SELECT)
1266 BIF_ThemeColor(TH_TEXT_HI);
1268 BIF_ThemeColor(TH_TEXT);
1270 ui_rasterpos_safe(rct->xmin+19.0f, rct->ymax-NODE_DY+5.0f, snode->aspect);
1271 snode_drawstring(snode, node->name, (int)(iconofs - rct->xmin-18.0f));
1274 BIF_ThemeColor(TH_NODE);
1276 uiRoundBox(rct->xmin, rct->ymin, rct->xmax, rct->ymax-NODE_DY, BASIS_RAD);
1278 /* scaling indicator */
1279 node_scaling_widget(TH_NODE, snode->aspect, rct->xmax-BASIS_RAD*snode->aspect, rct->ymin, rct->xmax, rct->ymin+BASIS_RAD*snode->aspect);
1281 /* outline active emphasis */
1282 if(node->flag & NODE_ACTIVE) {
1284 glColor4ub(200, 200, 200, 140);
1285 uiSetRoundBox(15-4);
1286 gl_round_box(GL_LINE_LOOP, rct->xmin, rct->ymin, rct->xmax, rct->ymax, BASIS_RAD);
1287 glDisable(GL_BLEND);
1290 /* we make buttons for input sockets, if... */
1291 if(node->flag & NODE_OPTIONS) {
1292 if(node->inputs.first || node->typeinfo->butfunc) {
1293 uiBlock *block= uiNewBlock(NULL, "node buttons", UI_EMBOSS, UI_HELV, sa->win);
1294 BLI_addtail(&sa->uiblocks, block);
1295 uiBlockSetFlag(block, UI_BLOCK_NO_HILITE);
1297 uiSetButLock(snode->id->lib!=NULL, "Can't edit library data");
1302 /* hurmf... another candidate for callback, have to see how this works first */
1303 if(node->id && node->block && snode->treetype==NTREE_SHADER)
1304 nodeShaderSynchronizeID(node, 0);
1306 /* socket inputs, buttons */
1307 for(sock= node->inputs.first; sock; sock= sock->next) {
1308 if(!(sock->flag & SOCK_HIDDEN)) {
1309 socket_circle_draw(sock->locx, sock->locy, NODE_SOCKSIZE, sock->type, sock->flag & SELECT);
1311 if(node->block && sock->link==NULL) {
1312 float *butpoin= sock->ns.vec;
1314 if(node->type==NODE_GROUP && sock->tosock)
1315 butpoin= sock->tosock->ns.vec;
1317 if(sock->type==SOCK_VALUE) {
1318 bt= uiDefButF(node->block, NUM, B_NODE_EXEC, sock->name,
1319 (short)sock->locx+NODE_DYS, (short)(sock->locy)-9, (short)node->width-NODE_DY, 17,
1320 butpoin, 0.0f, 1.0f, 10, 2, "");
1321 uiButSetFunc(bt, node_sync_cb, snode, node);
1323 else if(sock->type==SOCK_VECTOR) {
1324 uiDefBlockBut(node->block, socket_vector_menu, butpoin, sock->name,
1325 (short)sock->locx+NODE_DYS, (short)sock->locy-9, (short)node->width-NODE_DY, 17,
1328 else if(node->block && sock->type==SOCK_RGBA) {
1329 short labelw= node->width-NODE_DY-40, width;
1331 if(labelw>0) width= 40; else width= node->width-NODE_DY;
1333 bt= uiDefButF(node->block, COL, B_NODE_EXEC, "",
1334 (short)(sock->locx+NODE_DYS), (short)sock->locy-8, width, 15,
1335 butpoin, 0, 0, 0, 0, "");
1336 uiButSetFunc(bt, node_sync_cb, snode, node);
1338 if(labelw>0) uiDefBut(node->block, LABEL, 0, sock->name,
1339 (short)(sock->locx+NODE_DYS) + 40, (short)sock->locy-8, labelw, 15,
1340 NULL, 0, 0, 0, 0, "");
1344 BIF_ThemeColor(TH_TEXT);
1345 ui_rasterpos_safe(sock->locx+8.0f, sock->locy-5.0f, snode->aspect);
1346 BIF_DrawString(snode->curfont, sock->name, 0);
1351 /* socket outputs */
1352 for(sock= node->outputs.first; sock; sock= sock->next) {
1353 if(!(sock->flag & SOCK_HIDDEN)) {
1354 socket_circle_draw(sock->locx, sock->locy, NODE_SOCKSIZE, sock->type, sock->flag & SELECT);
1356 BIF_ThemeColor(TH_TEXT);
1358 slen= snode->aspect*BIF_GetStringWidth(snode->curfont, sock->name, 0);
1359 while(slen > node->width) {
1361 slen= snode->aspect*BIF_GetStringWidth(snode->curfont, sock->name+ofs, 0);
1363 ui_rasterpos_safe(sock->locx-8.0f-slen, sock->locy-5.0f, snode->aspect);
1364 BIF_DrawString(snode->curfont, sock->name+ofs, 0);
1369 if(node->flag & NODE_PREVIEW)
1370 if(node->preview && node->preview->rect)
1371 node_draw_preview(node->preview, &node->prvr);
1374 if(node->flag & NODE_OPTIONS) {
1375 if(node->typeinfo->butfunc) {
1376 node->typeinfo->butfunc(node->block, snode->nodetree, node, &node->butr);
1378 uiDrawBlock(node->block);
1383 void node_draw_hidden(SpaceNode *snode, bNode *node)
1386 rctf *rct= &node->totr;
1387 float dx, centy= 0.5f*(rct->ymax+rct->ymin);
1388 float hiddenrad= 0.5f*(rct->ymax-rct->ymin);
1389 int color_id= node_get_colorid(node);
1393 nodeshadow(rct, hiddenrad, snode->aspect, node->flag & SELECT);
1396 BIF_ThemeColor(color_id);
1397 uiRoundBox(rct->xmin, rct->ymin, rct->xmax, rct->ymax, hiddenrad);
1399 /* outline active emphasis */
1400 if(node->flag & NODE_ACTIVE) {
1402 glColor4ub(200, 200, 200, 140);
1403 gl_round_box(GL_LINE_LOOP, rct->xmin, rct->ymin, rct->xmax, rct->ymax, hiddenrad);
1404 glDisable(GL_BLEND);
1408 if(node->flag & SELECT)
1409 BIF_ThemeColor(TH_TEXT_HI);
1411 BIF_ThemeColorBlendShade(TH_TEXT, color_id, 0.4, 10);
1413 /* open entirely icon */
1414 ui_draw_tria_icon(rct->xmin+9.0f, centy-6.0f, snode->aspect, 'h');
1416 if(node->flag & SELECT)
1417 BIF_ThemeColor(TH_TEXT_HI);
1419 BIF_ThemeColor(TH_TEXT);
1421 if(node->miniwidth>0.0f) {
1422 ui_rasterpos_safe(rct->xmin+21.0f, centy-4.0f, snode->aspect);
1423 snode_drawstring(snode, node->name, (int)(rct->xmax - rct->xmin-18.0f -12.0f));
1426 /* scale widget thing */
1427 BIF_ThemeColorShade(color_id, -10);
1429 fdrawline(rct->xmax-dx, centy-4.0f, rct->xmax-dx, centy+4.0f);
1430 fdrawline(rct->xmax-dx-3.0f*snode->aspect, centy-4.0f, rct->xmax-dx-3.0f*snode->aspect, centy+4.0f);
1432 BIF_ThemeColorShade(color_id, +30);
1434 fdrawline(rct->xmax-dx, centy-4.0f, rct->xmax-dx, centy+4.0f);
1435 fdrawline(rct->xmax-dx-3.0f*snode->aspect, centy-4.0f, rct->xmax-dx-3.0f*snode->aspect, centy+4.0f);
1438 for(sock= node->inputs.first; sock; sock= sock->next) {
1439 if(!(sock->flag & SOCK_HIDDEN))
1440 socket_circle_draw(sock->locx, sock->locy, NODE_SOCKSIZE, sock->type, sock->flag & SELECT);
1443 for(sock= node->outputs.first; sock; sock= sock->next) {
1444 if(!(sock->flag & SOCK_HIDDEN))
1445 socket_circle_draw(sock->locx, sock->locy, NODE_SOCKSIZE, sock->type, sock->flag & SELECT);
1449 /* note; this is used for fake links in groups too */
1450 void node_draw_link(SpaceNode *snode, bNodeLink *link)
1453 float dist, spline_step, mx=0.0f, my=0.0f;
1454 int curve_res, do_shaded= 1, th_col1= TH_WIRE, th_col2= TH_WIRE;
1456 if(link->fromnode==NULL && link->tonode==NULL)
1459 /* this is dragging link */
1460 if(link->fromnode==NULL || link->tonode==NULL) {
1462 getmouseco_areawin(mval);
1463 areamouseco_to_ipoco(G.v2d, mval, &mx, &my);
1464 BIF_ThemeColor(TH_WIRE);
1468 /* a bit ugly... but thats how we detect the internal group links */
1469 if(link->fromnode==link->tonode) {
1470 BIF_ThemeColorBlend(TH_BACK, TH_WIRE, 0.25f);
1475 if(link->fromnode->level >= link->tonode->level && link->tonode->level!=0xFFF) {
1476 if(link->fromnode->flag & SELECT)
1477 th_col1= TH_EDGE_SELECT;
1478 if(link->tonode->flag & SELECT)
1479 th_col2= TH_EDGE_SELECT;
1482 BIF_ThemeColor(TH_REDALERT);
1488 vec[0][2]= vec[1][2]= vec[2][2]= vec[3][2]= 0.0; /* only 2d spline, set the Z to 0*/
1490 /* in v0 and v3 we put begin/end points */
1491 if(link->fromnode) {
1492 vec[0][0]= link->fromsock->locx;
1493 vec[0][1]= link->fromsock->locy;
1500 vec[3][0]= link->tosock->locx;
1501 vec[3][1]= link->tosock->locy;
1508 dist= 0.5f*ABS(vec[0][0] - vec[3][0]);
1510 /* check direction later, for top sockets */
1511 vec[1][0]= vec[0][0]+dist;
1512 vec[1][1]= vec[0][1];
1514 vec[2][0]= vec[3][0]-dist;
1515 vec[2][1]= vec[3][1];
1517 if( MIN4(vec[0][0], vec[1][0], vec[2][0], vec[3][0]) > G.v2d->cur.xmax); /* clipped */
1518 else if ( MAX4(vec[0][0], vec[1][0], vec[2][0], vec[3][0]) < G.v2d->cur.xmin); /* clipped */
1522 /* we can reuse the dist variable here to increment the GL curve eval amount*/
1523 dist = 1.0f/curve_res;
1526 glMap1f(GL_MAP1_VERTEX_3, 0.0, 1.0, 3, 4, vec[0]);
1527 glBegin(GL_LINE_STRIP);
1528 while (spline_step < 1.000001f) {
1530 BIF_ThemeColorBlend(th_col1, th_col2, spline_step);
1531 glEvalCoord1f(spline_step);
1532 spline_step += dist;
1538 static void node_draw_nodetree(ScrArea *sa, SpaceNode *snode, bNodeTree *ntree)
1543 if(ntree==NULL) return; /* groups... */
1547 glEnable( GL_LINE_SMOOTH );
1548 for(link= ntree->links.first; link; link= link->next)
1549 node_draw_link(snode, link);
1550 glDisable(GL_BLEND);
1551 glDisable( GL_LINE_SMOOTH );
1553 /* not selected first */
1554 for(node= ntree->nodes.first; node; node= node->next) {
1555 node->block= NULL; /* were freed */
1556 if(!(node->flag & SELECT)) {
1557 if(node->flag & NODE_GROUP_EDIT);
1558 else if(node->flag & NODE_HIDDEN)
1559 node_draw_hidden(snode, node);
1561 node_draw_basis(sa, snode, node);
1566 for(node= ntree->nodes.first; node; node= node->next) {
1567 if(node->flag & SELECT) {
1568 if(node->flag & NODE_GROUP_EDIT);
1569 else if(node->flag & NODE_HIDDEN)
1570 node_draw_hidden(snode, node);
1572 node_draw_basis(sa, snode, node);
1577 /* fake links from groupnode to internal nodes */
1578 static void node_draw_group_links(SpaceNode *snode, bNode *gnode)
1584 glEnable( GL_LINE_SMOOTH );
1586 fakelink.tonode= fakelink.fromnode= gnode;
1588 for(sock= gnode->inputs.first; sock; sock= sock->next) {
1589 if(!(sock->flag & SOCK_HIDDEN)) {
1591 fakelink.fromsock= sock;
1592 fakelink.tosock= sock->tosock;
1593 node_draw_link(snode, &fakelink);
1598 for(sock= gnode->outputs.first; sock; sock= sock->next) {
1599 if(!(sock->flag & SOCK_HIDDEN)) {
1601 fakelink.tosock= sock;
1602 fakelink.fromsock= sock->tosock;
1603 node_draw_link(snode, &fakelink);
1608 glDisable(GL_BLEND);
1609 glDisable( GL_LINE_SMOOTH );
1612 /* groups are, on creation, centered around 0,0 */
1613 static void node_draw_group(ScrArea *sa, SpaceNode *snode, bNode *gnode)
1615 bNodeTree *ngroup= (bNodeTree *)gnode->id;
1617 rctf rect= gnode->totr;
1619 /* backdrop header */
1622 BIF_ThemeColorShadeAlpha(TH_NODE_GROUP, 0, -70);
1623 gl_round_box(GL_POLYGON, rect.xmin, rect.ymax, rect.xmax, rect.ymax+NODE_DY, BASIS_RAD);
1626 BIF_ThemeColorShadeAlpha(TH_BACK, -8, -70);
1628 gl_round_box(GL_POLYGON, rect.xmin, rect.ymin, rect.xmax, rect.ymax, BASIS_RAD);
1630 /* selection outline */
1632 glColor4ub(200, 200, 200, 140);
1633 glEnable( GL_LINE_SMOOTH );
1634 gl_round_box(GL_LINE_LOOP, rect.xmin, rect.ymin, rect.xmax, rect.ymax+NODE_DY, BASIS_RAD);
1635 glDisable( GL_LINE_SMOOTH );
1636 glDisable(GL_BLEND);
1638 /* backdrop title */
1639 BIF_ThemeColor(TH_TEXT_HI);
1640 ui_rasterpos_safe(rect.xmin+8.0f, rect.ymax+5.0f, snode->aspect);
1641 BIF_DrawString(snode->curfont, ngroup->id.name+2, 0);
1643 /* links from groupsockets to the internal nodes */
1644 node_draw_group_links(snode, gnode);
1647 for(sock= gnode->inputs.first; sock; sock= sock->next)
1648 if(!(sock->flag & SOCK_HIDDEN))
1649 socket_circle_draw(sock->locx, sock->locy, NODE_SOCKSIZE, sock->type, sock->flag & SELECT);
1650 for(sock= gnode->outputs.first; sock; sock= sock->next)
1651 if(!(sock->flag & SOCK_HIDDEN))
1652 socket_circle_draw(sock->locx, sock->locy, NODE_SOCKSIZE, sock->type, sock->flag & SELECT);
1654 /* and finally the whole tree */
1655 node_draw_nodetree(sa, snode, ngroup);
1659 void drawnodespace(ScrArea *sa, void *spacedata)
1661 SpaceNode *snode= sa->spacedata.first;
1664 BIF_GetThemeColor3fv(TH_BACK, col);
1665 glClearColor(col[0], col[1], col[2], 0.0);
1666 glClear(GL_COLOR_BUFFER_BIT);
1668 calc_scrollrcts(sa, &(snode->v2d), sa->winx, sa->winy);
1670 myortho2(snode->v2d.cur.xmin, snode->v2d.cur.xmax, snode->v2d.cur.ymin, snode->v2d.cur.ymax);
1671 bwin_clear_viewmat(sa->win); /* clear buttons view */
1674 /* always free, blocks here have no unique identifier (1 block per node) */
1675 uiFreeBlocksWin(&sa->uiblocks, sa->win);
1678 glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
1679 glEnable(GL_MAP1_VERTEX_3);
1681 /* aspect+font, set each time */
1682 snode->aspect= (snode->v2d.cur.xmax - snode->v2d.cur.xmin)/((float)sa->winx);
1683 snode->curfont= uiSetCurFont_ext(snode->aspect);
1686 draw_nodespace_grid(snode);
1689 snode_set_context(snode);
1691 if(snode->nodetree) {
1694 /* for now, we set drawing coordinates on each redraw */
1695 for(node= snode->nodetree->nodes.first; node; node= node->next) {
1696 if(node->flag & NODE_GROUP_EDIT)
1697 node_update_group(node);
1698 else if(node->flag & NODE_HIDDEN)
1699 node_update_hidden(node);
1704 node_draw_nodetree(sa, snode, snode->nodetree);
1707 for(node= snode->nodetree->nodes.first; node; node= node->next) {
1708 if(node->flag & NODE_GROUP_EDIT)
1709 node_draw_group(sa, snode, node);
1713 /* restore viewport (not needed yet) */
1716 /* ortho at pixel level curarea */
1717 myortho2(-0.375, sa->winx-0.375, -0.375, sa->winy-0.375);
1719 draw_area_emboss(sa);
1720 curarea->win_swap= WIN_BACK_OK;
1722 /* in the end, this is a delayed previewrender test, to allow buttons to be first */
1723 if(snode->flag & SNODE_DO_PREVIEW) {
1724 addafterqueue(sa->win, RENDERPREVIEW, 1);
1725 snode->flag &= ~SNODE_DO_PREVIEW;