288 lines
8.7 KiB
C
288 lines
8.7 KiB
C
/**
|
|
* $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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
*
|
|
* The Original Code is Copyright (C) 2005 Blender Foundation.
|
|
* All rights reserved.
|
|
*
|
|
* The Original Code is: all of this file.
|
|
*
|
|
* Contributor(s): none yet.
|
|
*
|
|
* ***** END GPL LICENSE BLOCK *****
|
|
*/
|
|
|
|
#include "../SHD_util.h"
|
|
|
|
/* **************** MATERIAL ******************** */
|
|
|
|
static bNodeSocketType sh_node_material_in[]= {
|
|
{ SOCK_RGBA, 1, "Color", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
|
|
{ SOCK_RGBA, 1, "Spec", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
|
|
{ SOCK_VALUE, 1, "Refl", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
|
|
{ SOCK_VECTOR, 1, "Normal", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f},
|
|
{ -1, 0, "" }
|
|
};
|
|
|
|
/* output socket defines */
|
|
#define MAT_OUT_COLOR 0
|
|
#define MAT_OUT_ALPHA 1
|
|
#define MAT_OUT_NORMAL 2
|
|
|
|
static bNodeSocketType sh_node_material_out[]= {
|
|
{ SOCK_RGBA, 0, "Color", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
|
|
{ SOCK_VALUE, 0, "Alpha", 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
|
|
{ SOCK_VECTOR, 0, "Normal", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f},
|
|
{ -1, 0, "" }
|
|
};
|
|
|
|
static void node_shader_exec_material(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
|
|
{
|
|
if(data && node->id) {
|
|
ShadeResult shrnode;
|
|
ShadeInput *shi;
|
|
ShaderCallData *shcd= data;
|
|
float col[4];
|
|
|
|
shi= shcd->shi;
|
|
shi->mat= (Material *)node->id;
|
|
|
|
/* copy all relevant material vars, note, keep this synced with render_types.h */
|
|
memcpy(&shi->r, &shi->mat->r, 23*sizeof(float));
|
|
shi->har= shi->mat->har;
|
|
|
|
/* write values */
|
|
if(in[MAT_IN_COLOR]->hasinput)
|
|
nodestack_get_vec(&shi->r, SOCK_VECTOR, in[MAT_IN_COLOR]);
|
|
|
|
if(in[MAT_IN_SPEC]->hasinput)
|
|
nodestack_get_vec(&shi->specr, SOCK_VECTOR, in[MAT_IN_SPEC]);
|
|
|
|
if(in[MAT_IN_REFL]->hasinput)
|
|
nodestack_get_vec(&shi->refl, SOCK_VALUE, in[MAT_IN_REFL]);
|
|
|
|
/* retrieve normal */
|
|
if(in[MAT_IN_NORMAL]->hasinput) {
|
|
nodestack_get_vec(shi->vn, SOCK_VECTOR, in[MAT_IN_NORMAL]);
|
|
Normalise(shi->vn);
|
|
}
|
|
else
|
|
VECCOPY(shi->vn, shi->vno);
|
|
|
|
/* custom option to flip normal */
|
|
if(node->custom1 & SH_NODE_MAT_NEG) {
|
|
shi->vn[0]= -shi->vn[0];
|
|
shi->vn[1]= -shi->vn[1];
|
|
shi->vn[2]= -shi->vn[2];
|
|
}
|
|
|
|
node_shader_lamp_loop(shi, &shrnode); /* clears shrnode */
|
|
|
|
/* write to outputs */
|
|
if(node->custom1 & SH_NODE_MAT_DIFF) {
|
|
VECCOPY(col, shrnode.combined);
|
|
if(!(node->custom1 & SH_NODE_MAT_SPEC)) {
|
|
VecSubf(col, col, shrnode.spec);
|
|
}
|
|
}
|
|
else if(node->custom1 & SH_NODE_MAT_SPEC) {
|
|
VECCOPY(col, shrnode.spec);
|
|
}
|
|
else
|
|
col[0]= col[1]= col[2]= 0.0f;
|
|
|
|
col[3]= shrnode.alpha;
|
|
|
|
if(shi->do_preview)
|
|
nodeAddToPreview(node, col, shi->xs, shi->ys);
|
|
|
|
VECCOPY(out[MAT_OUT_COLOR]->vec, col);
|
|
out[MAT_OUT_ALPHA]->vec[0]= shrnode.alpha;
|
|
|
|
if(node->custom1 & SH_NODE_MAT_NEG) {
|
|
shi->vn[0]= -shi->vn[0];
|
|
shi->vn[1]= -shi->vn[1];
|
|
shi->vn[2]= -shi->vn[2];
|
|
}
|
|
|
|
VECCOPY(out[MAT_OUT_NORMAL]->vec, shi->vn);
|
|
|
|
/* copy passes, now just active node */
|
|
if(node->flag & NODE_ACTIVE_ID)
|
|
*(shcd->shr)= shrnode;
|
|
}
|
|
}
|
|
|
|
static void node_mat_alone_cb(void *node_v, void *unused)
|
|
{
|
|
bNode *node= node_v;
|
|
|
|
node->id= (ID *)copy_material((Material *)node->id);
|
|
|
|
BIF_undo_push("Single user material");
|
|
allqueue(REDRAWBUTSSHADING, 0);
|
|
allqueue(REDRAWNODE, 0);
|
|
allqueue(REDRAWOOPS, 0);
|
|
}
|
|
|
|
static void node_browse_mat_cb(void *ntree_v, void *node_v)
|
|
{
|
|
bNodeTree *ntree= ntree_v;
|
|
bNode *node= node_v;
|
|
|
|
if(node->menunr<1) return;
|
|
|
|
if(node->menunr==32767) { /* code for Add New */
|
|
if(node->id) {
|
|
/* make copy, but make sure it doesnt have the node tag nor nodes */
|
|
Material *ma= (Material *)node->id;
|
|
ma->id.us--;
|
|
ma= copy_material(ma);
|
|
ma->use_nodes= 0;
|
|
if(ma->nodetree) {
|
|
ntreeFreeTree(ma->nodetree);
|
|
MEM_freeN(ma->nodetree);
|
|
}
|
|
ma->nodetree= NULL;
|
|
node->id= (ID *)ma;
|
|
}
|
|
else node->id= (ID *)add_material("MatNode");
|
|
}
|
|
else {
|
|
if(node->id) node->id->us--;
|
|
node->id= BLI_findlink(&G.main->mat, node->menunr-1);
|
|
id_us_plus(node->id);
|
|
}
|
|
BLI_strncpy(node->name, node->id->name+2, 21);
|
|
|
|
nodeSetActive(ntree, node);
|
|
|
|
allqueue(REDRAWBUTSSHADING, 0);
|
|
allqueue(REDRAWNODE, 0);
|
|
BIF_preview_changed(ID_MA);
|
|
|
|
node->menunr= 0;
|
|
}
|
|
|
|
static void node_new_mat_cb(void *ntree_v, void *node_v)
|
|
{
|
|
bNodeTree *ntree= ntree_v;
|
|
bNode *node= node_v;
|
|
|
|
node->id= (ID *)add_material("MatNode");
|
|
BLI_strncpy(node->name, node->id->name+2, 21);
|
|
|
|
nodeSetActive(ntree, node);
|
|
|
|
allqueue(REDRAWBUTSSHADING, 0);
|
|
allqueue(REDRAWNODE, 0);
|
|
BIF_preview_changed(ID_MA);
|
|
|
|
}
|
|
static int node_shader_buts_material(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr)
|
|
{
|
|
if(block) {
|
|
uiBut *bt;
|
|
short dx= (short)((butr->xmax-butr->xmin)/3.0f), has_us= (node->id && node->id->us>1);
|
|
short dy= (short)butr->ymin;
|
|
char *strp;
|
|
|
|
/* WATCH IT: we use this callback in material buttons, but then only want first row */
|
|
if(butr->ymax-butr->ymin > 21.0f) dy+= 19;
|
|
|
|
uiBlockBeginAlign(block);
|
|
if(node->id==NULL) uiBlockSetCol(block, TH_REDALERT);
|
|
else if(has_us) uiBlockSetCol(block, TH_BUT_SETTING1);
|
|
else uiBlockSetCol(block, TH_BUT_SETTING2);
|
|
|
|
/* browse button */
|
|
IDnames_to_pupstring(&strp, NULL, "ADD NEW %x32767", &(G.main->mat), NULL, NULL);
|
|
node->menunr= 0;
|
|
bt= uiDefButS(block, MENU, B_NOP, strp,
|
|
butr->xmin, dy, 19, 19,
|
|
&node->menunr, 0, 0, 0, 0, "Browses existing choices or adds NEW");
|
|
uiButSetFunc(bt, node_browse_mat_cb, ntree, node);
|
|
if(strp) MEM_freeN(strp);
|
|
|
|
/* Add New button */
|
|
if(node->id==NULL) {
|
|
bt= uiDefBut(block, BUT, B_NOP, "Add New",
|
|
butr->xmin+19, dy, (short)(butr->xmax-butr->xmin-19.0f), 19,
|
|
NULL, 0.0, 0.0, 0, 0, "Add new Material");
|
|
uiButSetFunc(bt, node_new_mat_cb, ntree, node);
|
|
uiBlockSetCol(block, TH_AUTO);
|
|
}
|
|
else {
|
|
/* name button */
|
|
short width= (short)(butr->xmax-butr->xmin-19.0f - (has_us?19.0f:0.0f));
|
|
bt= uiDefBut(block, TEX, B_NOP, "MA:",
|
|
butr->xmin+19, dy, width, 19,
|
|
node->id->name+2, 0.0, 19.0, 0, 0, "Material name");
|
|
uiButSetFunc(bt, node_ID_title_cb, node, NULL);
|
|
|
|
/* user amount */
|
|
if(has_us) {
|
|
char str1[32];
|
|
sprintf(str1, "%d", node->id->us);
|
|
bt= uiDefBut(block, BUT, B_NOP, str1,
|
|
butr->xmax-19, dy, 19, 19,
|
|
NULL, 0, 0, 0, 0, "Displays number of users. Click to make a single-user copy.");
|
|
uiButSetFunc(bt, node_mat_alone_cb, node, NULL);
|
|
}
|
|
|
|
/* WATCH IT: we use this callback in material buttons, but then only want first row */
|
|
if(butr->ymax-butr->ymin > 21.0f) {
|
|
/* node options */
|
|
uiBlockSetCol(block, TH_AUTO);
|
|
uiDefButBitS(block, TOG, SH_NODE_MAT_DIFF, B_NODE_EXEC+node->nr, "Diff",
|
|
butr->xmin, butr->ymin, dx, 19,
|
|
&node->custom1, 0, 0, 0, 0, "Material Node outputs Diffuse");
|
|
uiDefButBitS(block, TOG, SH_NODE_MAT_SPEC, B_NODE_EXEC+node->nr, "Spec",
|
|
butr->xmin+dx, butr->ymin, dx, 19,
|
|
&node->custom1, 0, 0, 0, 0, "Material Node outputs Specular");
|
|
uiDefButBitS(block, TOG, SH_NODE_MAT_NEG, B_NODE_EXEC+node->nr, "Neg Normal",
|
|
butr->xmax-dx, butr->ymin, dx, 19,
|
|
&node->custom1, 0, 0, 0, 0, "Material Node uses inverted Normal");
|
|
}
|
|
}
|
|
uiBlockEndAlign(block);
|
|
}
|
|
return 38;
|
|
}
|
|
|
|
static void node_shader_init_material(bNode* node)
|
|
{
|
|
node->custom1= SH_NODE_MAT_DIFF|SH_NODE_MAT_SPEC;
|
|
}
|
|
|
|
|
|
bNodeType sh_node_material= {
|
|
/* type code */ SH_NODE_MATERIAL,
|
|
/* name */ "Material",
|
|
/* width+range */ 120, 80, 240,
|
|
/* class+opts */ NODE_CLASS_INPUT, NODE_OPTIONS|NODE_PREVIEW,
|
|
/* input sock */ sh_node_material_in,
|
|
/* output sock */ sh_node_material_out,
|
|
/* storage */ "",
|
|
/* execfunc */ node_shader_exec_material,
|
|
/* butfunc */ node_shader_buts_material,
|
|
/* initfunc */ node_shader_init_material
|
|
|
|
};
|
|
|