Added support for multiple UVs in the render engine. This also involved changing the way faces are stored, to allow data to be added optionally per 256 faces, same as the existing system for vertices. A UV layer can be specified in the Map Input panel and the Geometry node by name. Leaving this field blank will default to the active UV layer. Also added sharing of face selection and hiding between UV layers, and at the same time improved syncing with editmode selection and hiding. Still to do: - Multi UV support for fastshade. - Multires and NMesh preservation of multiple UV sets.
1198 lines
33 KiB
C
1198 lines
33 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 <stdlib.h>
|
|
#include <string.h>
|
|
#include <math.h>
|
|
|
|
#include "DNA_ID.h"
|
|
#include "DNA_material_types.h"
|
|
#include "DNA_node_types.h"
|
|
#include "DNA_scene_types.h"
|
|
#include "DNA_texture_types.h"
|
|
|
|
#include "BKE_blender.h"
|
|
#include "BKE_colortools.h"
|
|
#include "BKE_node.h"
|
|
#include "BKE_material.h"
|
|
#include "BKE_texture.h"
|
|
#include "BKE_utildefines.h"
|
|
|
|
#include "BLI_arithb.h"
|
|
#include "BLI_blenlib.h"
|
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
#include "RE_shader_ext.h" /* <- ShadeInput Shaderesult TexResult */
|
|
|
|
|
|
/* ********* exec data struct, remains internal *********** */
|
|
|
|
typedef struct ShaderCallData {
|
|
ShadeInput *shi; /* from render pipe */
|
|
ShadeResult *shr; /* from render pipe */
|
|
} ShaderCallData;
|
|
|
|
|
|
/* **************** call to switch lamploop for material node ************ */
|
|
|
|
static void (*node_shader_lamp_loop)(ShadeInput *, ShadeResult *);
|
|
|
|
void set_node_shader_lamp_loop(void (*lamp_loop_func)(ShadeInput *, ShadeResult *))
|
|
{
|
|
node_shader_lamp_loop= lamp_loop_func;
|
|
}
|
|
|
|
/* ****** */
|
|
|
|
static void nodestack_get_vec(float *in, short type_in, bNodeStack *ns)
|
|
{
|
|
float *from= ns->vec;
|
|
|
|
if(type_in==SOCK_VALUE) {
|
|
if(ns->sockettype==SOCK_VALUE)
|
|
*in= *from;
|
|
else
|
|
*in= 0.333333f*(from[0]+from[1]+from[2]);
|
|
}
|
|
else if(type_in==SOCK_VECTOR) {
|
|
if(ns->sockettype==SOCK_VALUE) {
|
|
in[0]= from[0];
|
|
in[1]= from[0];
|
|
in[2]= from[0];
|
|
}
|
|
else {
|
|
VECCOPY(in, from);
|
|
}
|
|
}
|
|
else { /* type_in==SOCK_RGBA */
|
|
if(ns->sockettype==SOCK_RGBA) {
|
|
QUATCOPY(in, from);
|
|
}
|
|
else if(ns->sockettype==SOCK_VALUE) {
|
|
in[0]= from[0];
|
|
in[1]= from[0];
|
|
in[2]= from[0];
|
|
in[3]= 1.0f;
|
|
}
|
|
else {
|
|
VECCOPY(in, from);
|
|
in[3]= 1.0f;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* ******************************************************** */
|
|
/* ********* Shader Node type definitions ***************** */
|
|
/* ******************************************************** */
|
|
|
|
/* SocketType syntax:
|
|
socket type, max connections (0 is no limit), name, 4 values for default, 2 values for range */
|
|
|
|
/* Verification rule: If name changes, a saved socket and its links will be removed! Type changes are OK */
|
|
|
|
/* **************** OUTPUT ******************** */
|
|
static bNodeSocketType sh_node_output_in[]= {
|
|
{ SOCK_RGBA, 1, "Color", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
|
|
{ SOCK_VALUE, 1, "Alpha", 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
|
|
{ -1, 0, "" }
|
|
};
|
|
|
|
static void node_shader_exec_output(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
|
|
{
|
|
if(data) {
|
|
ShadeInput *shi= ((ShaderCallData *)data)->shi;
|
|
float col[4];
|
|
|
|
/* stack order input sockets: col, alpha, normal */
|
|
nodestack_get_vec(col, SOCK_VECTOR, in[0]);
|
|
nodestack_get_vec(col+3, SOCK_VALUE, in[1]);
|
|
|
|
if(shi->do_preview) {
|
|
nodeAddToPreview(node, col, shi->xs, shi->ys);
|
|
node->lasty= shi->ys;
|
|
}
|
|
|
|
if(node->flag & NODE_DO_OUTPUT) {
|
|
ShadeResult *shr= ((ShaderCallData *)data)->shr;
|
|
|
|
QUATCOPY(shr->combined, col);
|
|
shr->alpha= col[3];
|
|
|
|
// VECCOPY(shr->nor, in[3]->vec);
|
|
}
|
|
}
|
|
}
|
|
|
|
static bNodeType sh_node_output= {
|
|
/* type code */ SH_NODE_OUTPUT,
|
|
/* name */ "Output",
|
|
/* width+range */ 80, 60, 200,
|
|
/* class+opts */ NODE_CLASS_OUTPUT, NODE_PREVIEW,
|
|
/* input sock */ sh_node_output_in,
|
|
/* output sock */ NULL,
|
|
/* storage */ "",
|
|
/* execfunc */ node_shader_exec_output
|
|
|
|
};
|
|
|
|
/* **************** GEOMETRY ******************** */
|
|
|
|
/* output socket defines */
|
|
#define GEOM_OUT_GLOB 0
|
|
#define GEOM_OUT_LOCAL 1
|
|
#define GEOM_OUT_VIEW 2
|
|
#define GEOM_OUT_ORCO 3
|
|
#define GEOM_OUT_UV 4
|
|
#define GEOM_OUT_NORMAL 5
|
|
|
|
/* output socket type definition */
|
|
static bNodeSocketType sh_node_geom_out[]= {
|
|
{ SOCK_VECTOR, 0, "Global", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f}, /* btw; uses no limit */
|
|
{ SOCK_VECTOR, 0, "Local", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f},
|
|
{ SOCK_VECTOR, 0, "View", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f},
|
|
{ SOCK_VECTOR, 0, "Orco", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f},
|
|
{ SOCK_VECTOR, 0, "UV", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f},
|
|
{ SOCK_VECTOR, 0, "Normal", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f},
|
|
{ -1, 0, "" }
|
|
};
|
|
|
|
/* node execute callback */
|
|
static void node_shader_exec_geom(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
|
|
{
|
|
if(data) {
|
|
ShadeInput *shi= ((ShaderCallData *)data)->shi;
|
|
ShadeInputUV *suv= &shi->uv[0];
|
|
NodeGeometry *ngeo= (NodeGeometry*)node->storage;
|
|
int i;
|
|
|
|
if(ngeo->uvname[0]) {
|
|
for(i = 0; i < shi->totuv; i++) {
|
|
if(strcmp(shi->uv[i].name, ngeo->uvname)==0) {
|
|
suv= &shi->uv[i];
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* out: global, local, view, orco, uv, normal */
|
|
VECCOPY(out[GEOM_OUT_GLOB]->vec, shi->gl);
|
|
VECCOPY(out[GEOM_OUT_LOCAL]->vec, shi->co);
|
|
VECCOPY(out[GEOM_OUT_VIEW]->vec, shi->view);
|
|
VECCOPY(out[GEOM_OUT_ORCO]->vec, shi->lo);
|
|
VECCOPY(out[GEOM_OUT_UV]->vec, suv->uv);
|
|
VECCOPY(out[GEOM_OUT_NORMAL]->vec, shi->vno);
|
|
|
|
if(shi->osatex) {
|
|
out[GEOM_OUT_GLOB]->data= shi->dxgl;
|
|
out[GEOM_OUT_GLOB]->datatype= NS_OSA_VECTORS;
|
|
out[GEOM_OUT_LOCAL]->data= shi->dxco;
|
|
out[GEOM_OUT_LOCAL]->datatype= NS_OSA_VECTORS;
|
|
out[GEOM_OUT_VIEW]->data= &shi->dxview;
|
|
out[GEOM_OUT_VIEW]->datatype= NS_OSA_VALUES;
|
|
out[GEOM_OUT_ORCO]->data= shi->dxlo;
|
|
out[GEOM_OUT_ORCO]->datatype= NS_OSA_VECTORS;
|
|
out[GEOM_OUT_UV]->data= suv->dxuv;
|
|
out[GEOM_OUT_UV]->datatype= NS_OSA_VECTORS;
|
|
out[GEOM_OUT_NORMAL]->data= shi->dxno;
|
|
out[GEOM_OUT_NORMAL]->datatype= NS_OSA_VECTORS;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* node type definition */
|
|
static bNodeType sh_node_geom= {
|
|
/* type code */ SH_NODE_GEOMETRY,
|
|
/* name */ "Geometry",
|
|
/* width+range */ 120, 80, 160,
|
|
/* class+opts */ NODE_CLASS_INPUT, NODE_OPTIONS,
|
|
/* input sock */ NULL,
|
|
/* output sock */ sh_node_geom_out,
|
|
/* storage */ "NodeGeometry",
|
|
/* execfunc */ node_shader_exec_geom
|
|
|
|
};
|
|
|
|
/* **************** MATERIAL ******************** */
|
|
|
|
/* input socket defines */
|
|
#define MAT_IN_COLOR 0
|
|
#define MAT_IN_SPEC 1
|
|
#define MAT_IN_REFL 2
|
|
#define MAT_IN_NORMAL 3
|
|
|
|
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 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
|
|
|
|
};
|
|
|
|
/* **************** TEXTURE ******************** */
|
|
static bNodeSocketType sh_node_texture_in[]= {
|
|
{ SOCK_VECTOR, 1, "Vector", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f}, /* no limit */
|
|
{ -1, 0, "" }
|
|
};
|
|
static bNodeSocketType sh_node_texture_out[]= {
|
|
{ SOCK_VALUE, 0, "Value", 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
|
|
{ SOCK_RGBA , 0, "Color", 1.0f, 1.0f, 1.0f, 1.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_texture(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
|
|
{
|
|
if(data && node->id) {
|
|
ShadeInput *shi= ((ShaderCallData *)data)->shi;
|
|
TexResult texres;
|
|
float vec[3], nor[3]={0.0f, 0.0f, 0.0f};
|
|
int retval;
|
|
|
|
/* out: value, color, normal */
|
|
|
|
/* we should find out if a normal as output is needed, for now we do all */
|
|
texres.nor= nor;
|
|
|
|
if(in[0]->hasinput) {
|
|
nodestack_get_vec(vec, SOCK_VECTOR, in[0]);
|
|
|
|
if(in[0]->datatype==NS_OSA_VECTORS) {
|
|
float *fp= in[0]->data;
|
|
retval= multitex_ext((Tex *)node->id, vec, fp, fp+3, shi->osatex, &texres);
|
|
}
|
|
else if(in[0]->datatype==NS_OSA_VALUES) {
|
|
float *fp= in[0]->data;
|
|
float dxt[3], dyt[3];
|
|
|
|
dxt[0]= fp[0]; dxt[1]= dxt[2]= 0.0f;
|
|
dyt[0]= fp[1]; dyt[1]= dyt[2]= 0.0f;
|
|
retval= multitex_ext((Tex *)node->id, vec, dxt, dyt, shi->osatex, &texres);
|
|
}
|
|
else
|
|
retval= multitex_ext((Tex *)node->id, vec, NULL, NULL, 0, &texres);
|
|
}
|
|
else { /* only for previewrender, so we see stuff */
|
|
VECCOPY(vec, shi->lo);
|
|
retval= multitex_ext((Tex *)node->id, vec, NULL, NULL, 0, &texres);
|
|
}
|
|
|
|
/* stupid exception */
|
|
if( ((Tex *)node->id)->type==TEX_STUCCI) {
|
|
texres.tin= 0.5f + 0.7f*texres.nor[0];
|
|
CLAMP(texres.tin, 0.0f, 1.0f);
|
|
}
|
|
|
|
/* intensity and color need some handling */
|
|
if(texres.talpha)
|
|
out[0]->vec[0]= texres.ta;
|
|
else
|
|
out[0]->vec[0]= texres.tin;
|
|
|
|
if((retval & TEX_RGB)==0) {
|
|
out[1]->vec[0]= out[0]->vec[0];
|
|
out[1]->vec[1]= out[0]->vec[0];
|
|
out[1]->vec[2]= out[0]->vec[0];
|
|
out[1]->vec[3]= 1.0f;
|
|
}
|
|
else {
|
|
out[1]->vec[0]= texres.tr;
|
|
out[1]->vec[1]= texres.tg;
|
|
out[1]->vec[2]= texres.tb;
|
|
out[1]->vec[3]= 1.0f;
|
|
}
|
|
|
|
VECCOPY(out[2]->vec, nor);
|
|
|
|
if(shi->do_preview)
|
|
nodeAddToPreview(node, out[1]->vec, shi->xs, shi->ys);
|
|
|
|
}
|
|
}
|
|
|
|
static bNodeType sh_node_texture= {
|
|
/* type code */ SH_NODE_TEXTURE,
|
|
/* name */ "Texture",
|
|
/* width+range */ 120, 80, 240,
|
|
/* class+opts */ NODE_CLASS_INPUT, NODE_OPTIONS|NODE_PREVIEW,
|
|
/* input sock */ sh_node_texture_in,
|
|
/* output sock */ sh_node_texture_out,
|
|
/* storage */ "",
|
|
/* execfunc */ node_shader_exec_texture
|
|
|
|
};
|
|
|
|
/* **************** MAPPING ******************** */
|
|
static bNodeSocketType sh_node_mapping_in[]= {
|
|
{ SOCK_VECTOR, 1, "Vector", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f},
|
|
{ -1, 0, "" }
|
|
};
|
|
|
|
static bNodeSocketType sh_node_mapping_out[]= {
|
|
{ SOCK_VECTOR, 0, "Vector", 0.0f, 0.0f, 1.0f, 1.0f, -1.0f, 1.0f},
|
|
{ -1, 0, "" }
|
|
};
|
|
|
|
/* do the regular mapping options for blender textures */
|
|
static void node_shader_exec_mapping(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
|
|
{
|
|
TexMapping *texmap= node->storage;
|
|
float *vec= out[0]->vec;
|
|
|
|
/* stack order input: vector */
|
|
/* stack order output: vector */
|
|
nodestack_get_vec(vec, SOCK_VECTOR, in[0]);
|
|
Mat4MulVecfl(texmap->mat, vec);
|
|
|
|
if(texmap->flag & TEXMAP_CLIP_MIN) {
|
|
if(vec[0]<texmap->min[0]) vec[0]= texmap->min[0];
|
|
if(vec[1]<texmap->min[1]) vec[1]= texmap->min[1];
|
|
if(vec[2]<texmap->min[2]) vec[2]= texmap->min[2];
|
|
}
|
|
if(texmap->flag & TEXMAP_CLIP_MAX) {
|
|
if(vec[0]>texmap->max[0]) vec[0]= texmap->max[0];
|
|
if(vec[1]>texmap->max[1]) vec[1]= texmap->max[1];
|
|
if(vec[2]>texmap->max[2]) vec[2]= texmap->max[2];
|
|
}
|
|
}
|
|
|
|
static bNodeType sh_node_mapping= {
|
|
/* type code */ SH_NODE_MAPPING,
|
|
/* name */ "Mapping",
|
|
/* width+range */ 240, 160, 320,
|
|
/* class+opts */ NODE_CLASS_OP_VECTOR, NODE_OPTIONS,
|
|
/* input sock */ sh_node_mapping_in,
|
|
/* output sock */ sh_node_mapping_out,
|
|
/* storage */ "TexMapping",
|
|
/* execfunc */ node_shader_exec_mapping
|
|
|
|
};
|
|
|
|
/* **************** CAMERA INFO ******************** */
|
|
static bNodeSocketType sh_node_camera_out[]= {
|
|
{ SOCK_VECTOR, 0, "View Vector", 1.0f, 0.0f, 0.0f, 0.0f, -1.0f, 1.0f}, /* None of these actually */
|
|
{ SOCK_VALUE, 0, "View Z Depth", 0.f, 0.0f, 0.0f, 0.0f, 0.0f, 99999999999.0f}, /* have any limits on their */
|
|
{ SOCK_VALUE, 0, "View Distance", 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 99999999999.0f}, /* values. */
|
|
{ -1, 0, "" }
|
|
};
|
|
|
|
|
|
static void node_shader_exec_camera(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
|
|
{
|
|
if(data) {
|
|
ShadeInput *shi= ((ShaderCallData *)data)->shi; /* Data we need for shading. */
|
|
|
|
VECCOPY(out[0]->vec, shi->co); /* get view vector */
|
|
out[1]->vec[0]= fabs(shi->co[2]); /* get view z-depth */
|
|
out[2]->vec[0]= Normalise(out[0]->vec); /* get view distance */
|
|
}
|
|
}
|
|
|
|
static bNodeType sh_node_camera= {
|
|
/* type code */ SH_NODE_CAMERA,
|
|
/* name */ "Camera Data",
|
|
/* width+range */ 95, 95, 120,
|
|
/* class+opts */ NODE_CLASS_INPUT, 0,
|
|
/* input sock */ NULL,
|
|
/* output sock */ sh_node_camera_out,
|
|
/* storage */ "node_camera",
|
|
/* execfunc */ node_shader_exec_camera
|
|
};
|
|
|
|
/* **************** SCALAR MATH ******************** */
|
|
static bNodeSocketType sh_node_math_in[]= {
|
|
{ SOCK_VALUE, 1, "Value", 0.5f, 0.5f, 0.5f, 1.0f, -100.0f, 100.0f},
|
|
{ SOCK_VALUE, 1, "Value", 0.5f, 0.5f, 0.5f, 1.0f, -100.0f, 100.0f},
|
|
{ -1, 0, "" }
|
|
};
|
|
|
|
static bNodeSocketType sh_node_math_out[]= {
|
|
{ SOCK_VALUE, 0, "Value", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
|
|
{ -1, 0, "" }
|
|
};
|
|
|
|
static void node_shader_exec_math(void *data, bNode *node, bNodeStack **in,
|
|
bNodeStack **out)
|
|
{
|
|
switch(node->custom1){
|
|
|
|
case 0: /* Add */
|
|
out[0]->vec[0]= in[0]->vec[0] + in[1]->vec[0];
|
|
break;
|
|
case 1: /* Subtract */
|
|
out[0]->vec[0]= in[0]->vec[0] - in[1]->vec[0];
|
|
break;
|
|
case 2: /* Multiply */
|
|
out[0]->vec[0]= in[0]->vec[0] * in[1]->vec[0];
|
|
break;
|
|
case 3: /* Divide */
|
|
{
|
|
if(in[1]->vec[0]==0) /* We don't want to divide by zero. */
|
|
out[0]->vec[0]= 0.0;
|
|
else
|
|
out[0]->vec[0]= in[0]->vec[0] / in[1]->vec[0];
|
|
}
|
|
break;
|
|
case 4: /* Sine */
|
|
{
|
|
if(in[0]->hasinput || !in[1]->hasinput) /* This one only takes one input, so we've got to choose. */
|
|
out[0]->vec[0]= sin(in[0]->vec[0]);
|
|
else
|
|
out[0]->vec[0]= sin(in[1]->vec[0]);
|
|
}
|
|
break;
|
|
case 5: /* Cosine */
|
|
{
|
|
if(in[0]->hasinput || !in[1]->hasinput) /* This one only takes one input, so we've got to choose. */
|
|
out[0]->vec[0]= cos(in[0]->vec[0]);
|
|
else
|
|
out[0]->vec[0]= cos(in[1]->vec[0]);
|
|
}
|
|
break;
|
|
case 6: /* Tangent */
|
|
{
|
|
if(in[0]->hasinput || !in[1]->hasinput) /* This one only takes one input, so we've got to choose. */
|
|
out[0]->vec[0]= tan(in[0]->vec[0]);
|
|
else
|
|
out[0]->vec[0]= tan(in[1]->vec[0]);
|
|
}
|
|
break;
|
|
case 7: /* Arc-Sine */
|
|
{
|
|
if(in[0]->hasinput || !in[1]->hasinput) { /* This one only takes one input, so we've got to choose. */
|
|
/* Can't do the impossible... */
|
|
if( in[0]->vec[0] <= 1 && in[0]->vec[0] >= -1 )
|
|
out[0]->vec[0]= asin(in[0]->vec[0]);
|
|
else
|
|
out[0]->vec[0]= 0.0;
|
|
}
|
|
else {
|
|
/* Can't do the impossible... */
|
|
if( in[1]->vec[0] <= 1 && in[1]->vec[0] >= -1 )
|
|
out[0]->vec[0]= asin(in[1]->vec[0]);
|
|
else
|
|
out[0]->vec[0]= 0.0;
|
|
}
|
|
}
|
|
break;
|
|
case 8: /* Arc-Cosine */
|
|
{
|
|
if(in[0]->hasinput || !in[1]->hasinput) { /* This one only takes one input, so we've got to choose. */
|
|
/* Can't do the impossible... */
|
|
if( in[0]->vec[0] <= 1 && in[0]->vec[0] >= -1 )
|
|
out[0]->vec[0]= acos(in[0]->vec[0]);
|
|
else
|
|
out[0]->vec[0]= 0.0;
|
|
}
|
|
else {
|
|
/* Can't do the impossible... */
|
|
if( in[1]->vec[0] <= 1 && in[1]->vec[0] >= -1 )
|
|
out[0]->vec[0]= acos(in[1]->vec[0]);
|
|
else
|
|
out[0]->vec[0]= 0.0;
|
|
}
|
|
}
|
|
break;
|
|
case 9: /* Arc-Tangent */
|
|
{
|
|
if(in[0]->hasinput || !in[1]->hasinput) /* This one only takes one input, so we've got to choose. */
|
|
out[0]->vec[0]= atan(in[0]->vec[0]);
|
|
else
|
|
out[0]->vec[0]= atan(in[1]->vec[0]);
|
|
}
|
|
break;
|
|
case 10: /* Power */
|
|
{
|
|
/* Don't want any imaginary numbers... */
|
|
if( in[0]->vec[0] >= 0 )
|
|
out[0]->vec[0]= pow(in[0]->vec[0], in[1]->vec[0]);
|
|
else
|
|
out[0]->vec[0]= 0.0;
|
|
}
|
|
break;
|
|
case 11: /* Logarithm */
|
|
{
|
|
/* Don't want any imaginary numbers... */
|
|
if( in[0]->vec[0] > 0 && in[1]->vec[0] > 0 )
|
|
out[0]->vec[0]= log(in[0]->vec[0]) / log(in[1]->vec[0]);
|
|
else
|
|
out[0]->vec[0]= 0.0;
|
|
}
|
|
break;
|
|
case 12: /* Minimum */
|
|
{
|
|
if( in[0]->vec[0] < in[1]->vec[0] )
|
|
out[0]->vec[0]= in[1]->vec[0];
|
|
else
|
|
out[0]->vec[0]= in[0]->vec[0];
|
|
}
|
|
break;
|
|
case 13: /* Maximum */
|
|
{
|
|
if( in[0]->vec[0] > in[1]->vec[0] )
|
|
out[0]->vec[0]= in[1]->vec[0];
|
|
else
|
|
out[0]->vec[0]= in[0]->vec[0];
|
|
}
|
|
break;
|
|
case 14: /* Round */
|
|
{
|
|
if(in[0]->hasinput || !in[1]->hasinput) /* This one only takes one input, so we've got to choose. */
|
|
out[0]->vec[0]= (int)(in[0]->vec[0] + 0.5f);
|
|
else
|
|
out[0]->vec[0]= (int)(in[1]->vec[0] + 0.5f);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
static bNodeType sh_node_math= {
|
|
/* type code */ SH_NODE_MATH,
|
|
/* name */ "Math",
|
|
/* width+range */ 120, 110, 160,
|
|
/* class+opts */ NODE_CLASS_CONVERTOR, NODE_OPTIONS,
|
|
/* input sock */ sh_node_math_in,
|
|
/* output sock */ sh_node_math_out,
|
|
/* storage */ "node_math",
|
|
/* execfunc */ node_shader_exec_math
|
|
};
|
|
|
|
/* **************** VALUE SQUEEZE ******************** */
|
|
static bNodeSocketType sh_node_squeeze_in[]= {
|
|
{ SOCK_VALUE, 1, "Value", 0.0f, 0.0f, 0.0f, 0.0f, -100.0f, 100.0f},
|
|
{ SOCK_VALUE, 1, "Width", 1.0f, 0.0f, 0.0f, 0.0f, -100.0f, 100.0f},
|
|
{ SOCK_VALUE, 1, "Center", 0.0f, 0.0f, 0.0f, 0.0f, -100.0f, 100.0f},
|
|
{ -1, 0, "" }
|
|
};
|
|
|
|
static bNodeSocketType sh_node_squeeze_out[]= {
|
|
{ SOCK_VALUE, 0, "Value", 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
|
|
{ -1, 0, "" }
|
|
};
|
|
|
|
static void node_shader_exec_squeeze(void *data, bNode *node, bNodeStack **in,
|
|
bNodeStack **out)
|
|
{
|
|
float vec[3];
|
|
|
|
nodestack_get_vec(vec, SOCK_VALUE, in[0]);
|
|
nodestack_get_vec(vec+1, SOCK_VALUE, in[1]);
|
|
nodestack_get_vec(vec+2, SOCK_VALUE, in[2]);
|
|
|
|
out[0]->vec[0] = 1.0f / (1.0f + pow(2.71828183,-((vec[0]-vec[2])*vec[1]))) ;
|
|
}
|
|
|
|
static bNodeType sh_node_squeeze= {
|
|
/* type code */ SH_NODE_SQUEEZE,
|
|
/* name */ "Squeeze Value",
|
|
/* width+range */ 120, 110, 160,
|
|
/* class+opts */ NODE_CLASS_CONVERTOR, NODE_OPTIONS,
|
|
/* input sock */ sh_node_squeeze_in,
|
|
/* output sock */ sh_node_squeeze_out,
|
|
/* storage */ "node_squeeze",
|
|
/* execfunc */ node_shader_exec_squeeze
|
|
};
|
|
|
|
|
|
|
|
/* **************** VECTOR MATH ******************** */
|
|
static bNodeSocketType sh_node_vect_math_in[]= {
|
|
{ SOCK_VECTOR, 1, "Vector", 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 1.0f},
|
|
{ SOCK_VECTOR, 1, "Vector", 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 1.0f},
|
|
{ -1, 0, "" }
|
|
};
|
|
|
|
static bNodeSocketType sh_node_vect_math_out[]= {
|
|
{ SOCK_VECTOR, 0, "Vector", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
|
|
{ SOCK_VALUE, 0, "Value", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
|
|
{ -1, 0, "" }
|
|
};
|
|
|
|
static void node_shader_exec_vect_math(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
|
|
{
|
|
float vec1[3], vec2[3];
|
|
|
|
nodestack_get_vec(vec1, SOCK_VECTOR, in[0]);
|
|
nodestack_get_vec(vec2, SOCK_VECTOR, in[1]);
|
|
|
|
if(node->custom1 == 0) { /* Add */
|
|
out[0]->vec[0]= vec1[0] + vec2[0];
|
|
out[0]->vec[1]= vec1[1] + vec2[1];
|
|
out[0]->vec[2]= vec1[2] + vec2[2];
|
|
|
|
out[1]->vec[0]= (fabs(out[0]->vec[0]) + fabs(out[0]->vec[0]) + fabs(out[0]->vec[0])) / 3;
|
|
}
|
|
else if(node->custom1 == 1) { /* Subtract */
|
|
out[0]->vec[0]= vec1[0] - vec2[0];
|
|
out[0]->vec[1]= vec1[1] - vec2[1];
|
|
out[0]->vec[2]= vec1[2] - vec2[2];
|
|
|
|
out[1]->vec[0]= (fabs(out[0]->vec[0]) + fabs(out[0]->vec[0]) + fabs(out[0]->vec[0])) / 3;
|
|
}
|
|
else if(node->custom1 == 2) { /* Average */
|
|
out[0]->vec[0]= vec1[0] + vec2[0];
|
|
out[0]->vec[1]= vec1[1] + vec2[1];
|
|
out[0]->vec[2]= vec1[2] + vec2[2];
|
|
|
|
out[1]->vec[0] = Normalise( out[0]->vec );
|
|
}
|
|
else if(node->custom1 == 3) { /* Dot product */
|
|
out[1]->vec[0]= (vec1[0] * vec2[0]) + (vec1[1] * vec2[1]) + (vec1[2] * vec2[2]);
|
|
}
|
|
else if(node->custom1 == 4) { /* Cross product */
|
|
out[0]->vec[0]= (vec1[1] * vec2[2]) - (vec1[2] * vec2[1]);
|
|
out[0]->vec[1]= (vec1[2] * vec2[0]) - (vec1[0] * vec2[2]);
|
|
out[0]->vec[2]= (vec1[0] * vec2[1]) - (vec1[1] * vec2[0]);
|
|
|
|
out[1]->vec[0] = Normalise( out[0]->vec );
|
|
}
|
|
else if(node->custom1 == 5) { /* Normalize */
|
|
if(in[0]->hasinput || !in[1]->hasinput) { /* This one only takes one input, so we've got to choose. */
|
|
out[0]->vec[0]= vec1[0];
|
|
out[0]->vec[1]= vec1[1];
|
|
out[0]->vec[2]= vec1[2];
|
|
}
|
|
else {
|
|
out[0]->vec[0]= vec2[0];
|
|
out[0]->vec[1]= vec2[1];
|
|
out[0]->vec[2]= vec2[2];
|
|
}
|
|
|
|
out[1]->vec[0] = Normalise( out[0]->vec );
|
|
}
|
|
|
|
}
|
|
|
|
static bNodeType sh_node_vect_math= {
|
|
/* type code */ SH_NODE_VECT_MATH,
|
|
/* name */ "Vector Math",
|
|
/* width+range */ 80, 75, 140,
|
|
/* class+opts */ NODE_CLASS_CONVERTOR, NODE_OPTIONS,
|
|
/* input sock */ sh_node_vect_math_in,
|
|
/* output sock */ sh_node_vect_math_out,
|
|
/* storage */ "node_vect_math",
|
|
/* execfunc */ node_shader_exec_vect_math
|
|
};
|
|
|
|
/* **************** NORMAL ******************** */
|
|
static bNodeSocketType sh_node_normal_in[]= {
|
|
{ SOCK_VECTOR, 1, "Normal", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f},
|
|
{ -1, 0, "" }
|
|
};
|
|
|
|
static bNodeSocketType sh_node_normal_out[]= {
|
|
{ SOCK_VECTOR, 0, "Normal", 0.0f, 0.0f, 1.0f, 1.0f, -1.0f, 1.0f},
|
|
{ SOCK_VALUE, 0, "Dot", 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
|
|
{ -1, 0, "" }
|
|
};
|
|
|
|
/* generates normal, does dot product */
|
|
static void node_shader_exec_normal(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
|
|
{
|
|
bNodeSocket *sock= node->outputs.first;
|
|
float vec[3];
|
|
|
|
/* stack order input: normal */
|
|
/* stack order output: normal, value */
|
|
|
|
nodestack_get_vec(vec, SOCK_VECTOR, in[0]);
|
|
|
|
VECCOPY(out[0]->vec, sock->ns.vec);
|
|
/* render normals point inside... the widget points outside */
|
|
out[1]->vec[0]= -INPR(out[0]->vec, vec);
|
|
}
|
|
|
|
static bNodeType sh_node_normal= {
|
|
/* type code */ SH_NODE_NORMAL,
|
|
/* name */ "Normal",
|
|
/* width+range */ 100, 60, 200,
|
|
/* class+opts */ NODE_CLASS_OP_VECTOR, NODE_OPTIONS,
|
|
/* input sock */ sh_node_normal_in,
|
|
/* output sock */ sh_node_normal_out,
|
|
/* storage */ "",
|
|
/* execfunc */ node_shader_exec_normal
|
|
|
|
};
|
|
|
|
/* **************** CURVE VEC ******************** */
|
|
static bNodeSocketType sh_node_curve_vec_in[]= {
|
|
{ SOCK_VECTOR, 1, "Vector", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f},
|
|
{ -1, 0, "" }
|
|
};
|
|
|
|
static bNodeSocketType sh_node_curve_vec_out[]= {
|
|
{ SOCK_VECTOR, 0, "Vector", 0.0f, 0.0f, 1.0f, 1.0f, -1.0f, 1.0f},
|
|
{ -1, 0, "" }
|
|
};
|
|
|
|
static void node_shader_exec_curve_vec(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
|
|
{
|
|
float vec[3];
|
|
|
|
/* stack order input: vec */
|
|
/* stack order output: vec */
|
|
nodestack_get_vec(vec, SOCK_VECTOR, in[0]);
|
|
curvemapping_evaluate3F(node->storage, out[0]->vec, vec);
|
|
}
|
|
|
|
static bNodeType sh_node_curve_vec= {
|
|
/* type code */ SH_NODE_CURVE_VEC,
|
|
/* name */ "Vector Curves",
|
|
/* width+range */ 200, 140, 320,
|
|
/* class+opts */ NODE_CLASS_OP_VECTOR, NODE_OPTIONS,
|
|
/* input sock */ sh_node_curve_vec_in,
|
|
/* output sock */ sh_node_curve_vec_out,
|
|
/* storage */ "CurveMapping",
|
|
/* execfunc */ node_shader_exec_curve_vec
|
|
|
|
};
|
|
|
|
/* **************** CURVE RGB ******************** */
|
|
static bNodeSocketType sh_node_curve_rgb_in[]= {
|
|
{ SOCK_RGBA, 1, "Color", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f},
|
|
{ -1, 0, "" }
|
|
};
|
|
|
|
static bNodeSocketType sh_node_curve_rgb_out[]= {
|
|
{ SOCK_RGBA, 0, "Color", 0.0f, 0.0f, 1.0f, 1.0f, -1.0f, 1.0f},
|
|
{ -1, 0, "" }
|
|
};
|
|
|
|
static void node_shader_exec_curve_rgb(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
|
|
{
|
|
float vec[3];
|
|
|
|
/* stack order input: vec */
|
|
/* stack order output: vec */
|
|
nodestack_get_vec(vec, SOCK_VECTOR, in[0]);
|
|
curvemapping_evaluateRGBF(node->storage, out[0]->vec, vec);
|
|
}
|
|
|
|
static bNodeType sh_node_curve_rgb= {
|
|
/* type code */ SH_NODE_CURVE_RGB,
|
|
/* name */ "RGB Curves",
|
|
/* width+range */ 200, 140, 320,
|
|
/* class+opts */ NODE_CLASS_OP_COLOR, NODE_OPTIONS,
|
|
/* input sock */ sh_node_curve_rgb_in,
|
|
/* output sock */ sh_node_curve_rgb_out,
|
|
/* storage */ "CurveMapping",
|
|
/* execfunc */ node_shader_exec_curve_rgb
|
|
|
|
};
|
|
|
|
/* **************** VALUE ******************** */
|
|
static bNodeSocketType sh_node_value_out[]= {
|
|
{ SOCK_VALUE, 0, "Value", 0.5f, 0.0f, 0.0f, 0.0f, -100.0f, 100.0f},
|
|
{ -1, 0, "" }
|
|
};
|
|
|
|
static void node_shader_exec_value(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
|
|
{
|
|
bNodeSocket *sock= node->outputs.first;
|
|
|
|
out[0]->vec[0]= sock->ns.vec[0];
|
|
}
|
|
|
|
static bNodeType sh_node_value= {
|
|
/* type code */ SH_NODE_VALUE,
|
|
/* name */ "Value",
|
|
/* width+range */ 80, 50, 120,
|
|
/* class+opts */ NODE_CLASS_INPUT, NODE_OPTIONS,
|
|
/* input sock */ NULL,
|
|
/* output sock */ sh_node_value_out,
|
|
/* storage */ "",
|
|
/* execfunc */ node_shader_exec_value
|
|
|
|
};
|
|
|
|
/* **************** RGB ******************** */
|
|
static bNodeSocketType sh_node_rgb_out[]= {
|
|
{ SOCK_RGBA, 0, "Color", 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 1.0f},
|
|
{ -1, 0, "" }
|
|
};
|
|
|
|
static void node_shader_exec_rgb(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
|
|
{
|
|
bNodeSocket *sock= node->outputs.first;
|
|
|
|
VECCOPY(out[0]->vec, sock->ns.vec);
|
|
}
|
|
|
|
static bNodeType sh_node_rgb= {
|
|
/* type code */ SH_NODE_RGB,
|
|
/* name */ "RGB",
|
|
/* width+range */ 100, 60, 140,
|
|
/* class+opts */ NODE_CLASS_INPUT, NODE_OPTIONS,
|
|
/* input sock */ NULL,
|
|
/* output sock */ sh_node_rgb_out,
|
|
/* storage */ "",
|
|
/* execfunc */ node_shader_exec_rgb
|
|
|
|
};
|
|
|
|
/* **************** MIX RGB ******************** */
|
|
static bNodeSocketType sh_node_mix_rgb_in[]= {
|
|
{ SOCK_VALUE, 1, "Fac", 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
|
|
{ SOCK_RGBA, 1, "Color1", 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 1.0f},
|
|
{ SOCK_RGBA, 1, "Color2", 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 1.0f},
|
|
{ -1, 0, "" }
|
|
};
|
|
static bNodeSocketType sh_node_mix_rgb_out[]= {
|
|
{ SOCK_RGBA, 0, "Color", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
|
|
{ -1, 0, "" }
|
|
};
|
|
|
|
static void node_shader_exec_mix_rgb(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
|
|
{
|
|
/* stack order in: fac, col1, col2 */
|
|
/* stack order out: col */
|
|
float col[3];
|
|
float fac;
|
|
float vec[3];
|
|
|
|
nodestack_get_vec(&fac, SOCK_VALUE, in[0]);
|
|
CLAMP(fac, 0.0f, 1.0f);
|
|
|
|
nodestack_get_vec(col, SOCK_VECTOR, in[1]);
|
|
nodestack_get_vec(vec, SOCK_VECTOR, in[2]);
|
|
|
|
ramp_blend(node->custom1, col, col+1, col+2, fac, vec);
|
|
VECCOPY(out[0]->vec, col);
|
|
}
|
|
|
|
static bNodeType sh_node_mix_rgb= {
|
|
/* type code */ SH_NODE_MIX_RGB,
|
|
/* name */ "Mix",
|
|
/* width+range */ 100, 60, 150,
|
|
/* class+opts */ NODE_CLASS_OP_COLOR, NODE_OPTIONS,
|
|
/* input sock */ sh_node_mix_rgb_in,
|
|
/* output sock */ sh_node_mix_rgb_out,
|
|
/* storage */ "",
|
|
/* execfunc */ node_shader_exec_mix_rgb
|
|
|
|
};
|
|
|
|
|
|
/* **************** VALTORGB ******************** */
|
|
static bNodeSocketType sh_node_valtorgb_in[]= {
|
|
{ SOCK_VALUE, 1, "Fac", 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
|
|
{ -1, 0, "" }
|
|
};
|
|
static bNodeSocketType sh_node_valtorgb_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},
|
|
{ -1, 0, "" }
|
|
};
|
|
|
|
static void node_shader_exec_valtorgb(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
|
|
{
|
|
/* stack order in: fac */
|
|
/* stack order out: col, alpha */
|
|
|
|
if(node->storage) {
|
|
float fac;
|
|
nodestack_get_vec(&fac, SOCK_VALUE, in[0]);
|
|
|
|
do_colorband(node->storage, fac, out[0]->vec);
|
|
out[1]->vec[0]= out[0]->vec[3];
|
|
}
|
|
}
|
|
|
|
static bNodeType sh_node_valtorgb= {
|
|
/* type code */ SH_NODE_VALTORGB,
|
|
/* name */ "ColorRamp",
|
|
/* width+range */ 240, 200, 300,
|
|
/* class+opts */ NODE_CLASS_CONVERTOR, NODE_OPTIONS,
|
|
/* input sock */ sh_node_valtorgb_in,
|
|
/* output sock */ sh_node_valtorgb_out,
|
|
/* storage */ "ColorBand",
|
|
/* execfunc */ node_shader_exec_valtorgb
|
|
|
|
};
|
|
|
|
|
|
/* **************** RGBTOBW ******************** */
|
|
static bNodeSocketType sh_node_rgbtobw_in[]= {
|
|
{ SOCK_RGBA, 1, "Color", 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 1.0f},
|
|
{ -1, 0, "" }
|
|
};
|
|
static bNodeSocketType sh_node_rgbtobw_out[]= {
|
|
{ SOCK_VALUE, 0, "Val", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
|
|
{ -1, 0, "" }
|
|
};
|
|
|
|
|
|
static void node_shader_exec_rgbtobw(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
|
|
{
|
|
/* stack order out: bw */
|
|
/* stack order in: col */
|
|
|
|
out[0]->vec[0]= in[0]->vec[0]*0.35f + in[0]->vec[1]*0.45f + in[0]->vec[2]*0.2f;
|
|
}
|
|
|
|
static bNodeType sh_node_rgbtobw= {
|
|
/* type code */ SH_NODE_RGBTOBW,
|
|
/* name */ "RGB to BW",
|
|
/* width+range */ 80, 40, 120,
|
|
/* class+opts */ NODE_CLASS_CONVERTOR, 0,
|
|
/* input sock */ sh_node_rgbtobw_in,
|
|
/* output sock */ sh_node_rgbtobw_out,
|
|
/* storage */ "",
|
|
/* execfunc */ node_shader_exec_rgbtobw
|
|
|
|
};
|
|
|
|
|
|
/* ****************** types array for all shaders ****************** */
|
|
|
|
bNodeType *node_all_shaders[]= {
|
|
&node_group_typeinfo,
|
|
&sh_node_output,
|
|
&sh_node_material,
|
|
&sh_node_camera,
|
|
&sh_node_value,
|
|
&sh_node_rgb,
|
|
&sh_node_mix_rgb,
|
|
&sh_node_valtorgb,
|
|
&sh_node_rgbtobw,
|
|
&sh_node_texture,
|
|
&sh_node_normal,
|
|
&sh_node_geom,
|
|
&sh_node_mapping,
|
|
&sh_node_curve_vec,
|
|
&sh_node_curve_rgb,
|
|
&sh_node_math,
|
|
&sh_node_vect_math,
|
|
&sh_node_squeeze,
|
|
NULL
|
|
};
|
|
|
|
/* ******************* execute and parse ************ */
|
|
|
|
void ntreeShaderExecTree(bNodeTree *ntree, ShadeInput *shi, ShadeResult *shr)
|
|
{
|
|
ShaderCallData scd;
|
|
|
|
/* convert caller data to struct */
|
|
scd.shi= shi;
|
|
scd.shr= shr;
|
|
/* each material node has own local shaderesult, with optional copying */
|
|
memset(shr, 0, sizeof(ShadeResult));
|
|
|
|
ntreeExecTree(ntree, &scd, shi->thread); /* threads */
|
|
|
|
/* better not allow negative for now */
|
|
if(shr->combined[0]<0.0f) shr->combined[0]= 0.0f;
|
|
if(shr->combined[1]<0.0f) shr->combined[1]= 0.0f;
|
|
if(shr->combined[2]<0.0f) shr->combined[2]= 0.0f;
|
|
|
|
}
|
|
|
|
/* go over all used Geometry and Texture nodes, and return a texco flag */
|
|
/* no group inside needed, this function is called for groups too */
|
|
int ntreeShaderGetTexco(bNodeTree *ntree, int r_mode)
|
|
{
|
|
bNode *node;
|
|
bNodeSocket *sock;
|
|
int texco= 0, a;
|
|
|
|
ntreeSocketUseFlags(ntree);
|
|
|
|
for(node= ntree->nodes.first; node; node= node->next) {
|
|
if(node->type==SH_NODE_TEXTURE) {
|
|
if((r_mode & R_OSA) && node->id) {
|
|
Tex *tex= (Tex *)node->id;
|
|
if ELEM3(tex->type, TEX_IMAGE, TEX_PLUGIN, TEX_ENVMAP)
|
|
texco |= TEXCO_OSA|NEED_UV;
|
|
}
|
|
}
|
|
else if(node->type==SH_NODE_GEOMETRY) {
|
|
/* note; sockets always exist for the given type! */
|
|
for(a=0, sock= node->outputs.first; sock; sock= sock->next, a++) {
|
|
if(sock->flag & SOCK_IN_USE) {
|
|
switch(a) {
|
|
case GEOM_OUT_GLOB:
|
|
texco |= TEXCO_GLOB|NEED_UV; break;
|
|
case GEOM_OUT_VIEW:
|
|
texco |= TEXCO_VIEW|NEED_UV; break;
|
|
case GEOM_OUT_ORCO:
|
|
texco |= TEXCO_ORCO|NEED_UV; break;
|
|
case GEOM_OUT_UV:
|
|
texco |= TEXCO_UV|NEED_UV; break;
|
|
case GEOM_OUT_NORMAL:
|
|
texco |= TEXCO_NORM|NEED_UV; break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return texco;
|
|
}
|
|
|
|
/* nodes that use ID data get synced with local data */
|
|
void nodeShaderSynchronizeID(bNode *node, int copyto)
|
|
{
|
|
if(node->id==NULL) return;
|
|
|
|
if(node->type==SH_NODE_MATERIAL) {
|
|
bNodeSocket *sock;
|
|
Material *ma= (Material *)node->id;
|
|
int a;
|
|
|
|
/* hrmf, case in loop isnt super fast, but we dont edit 100s of material at same time either! */
|
|
for(a=0, sock= node->inputs.first; sock; sock= sock->next, a++) {
|
|
if(!(sock->flag & SOCK_HIDDEN)) {
|
|
if(copyto) {
|
|
switch(a) {
|
|
case MAT_IN_COLOR:
|
|
VECCOPY(&ma->r, sock->ns.vec); break;
|
|
case MAT_IN_SPEC:
|
|
VECCOPY(&ma->specr, sock->ns.vec); break;
|
|
case MAT_IN_REFL:
|
|
ma->ref= sock->ns.vec[0]; break;
|
|
}
|
|
}
|
|
else {
|
|
switch(a) {
|
|
case MAT_IN_COLOR:
|
|
VECCOPY(sock->ns.vec, &ma->r); break;
|
|
case MAT_IN_SPEC:
|
|
VECCOPY(sock->ns.vec, &ma->specr); break;
|
|
case MAT_IN_REFL:
|
|
sock->ns.vec[0]= ma->ref; break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|