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:
authorTon Roosendaal <ton@blender.org>2006-01-08 14:41:06 +0300
committerTon Roosendaal <ton@blender.org>2006-01-08 14:41:06 +0300
commit104ab9b103ab30ca87ccb9e739a58863fc29d3bf (patch)
tree4f26f35a13cc5f92d485f72f2c9116d202f2f9cd /source/blender/blenkernel
parent32e21f4524cd3c428b5b8492089530471a7f0867 (diff)
Orange:
- New UI element: the "Curve Button". For mapping ranges (like 0 - 1) to another range, the curve button can be used for proportional falloff, bone influences, painting density, etc. Most evident use is of course to map RGB color with curves. To be able to use it, you have to allocate a CurveMapping struct and pass this on to the button. The CurveMapping API is in the new C file blenkernel/intern/colortools.c It's as simple as calling: curvemap= curvemapping_add(3, 0, 0, 1, 1) Which will create 3 curves, and sets a default 0-1 range. The current code only supports up to 4 curves maximum per mapping struct. The CurveMap button in Blender than handles allmost all editing. Evaluating a single channel: float newvalue= curvemapping_evaluateF(curvemap, 0, oldval); Where the second argument is the channel index, here 0-1-2 are possible. Or mapping a vector: curvemapping_evaluate3F(curvemap, newvec, oldvec); Optimized versions for byte or short mapping is possible too, not done yet. In butspace.c I've added a template wrapper for buttons around the curve, to reveil settings or show tools; check this screenie: http://www.blender.org/bf/curves.jpg - Buttons R, G, B: select channel - icons + and -: zoom in, out - icon 'wrench': menu with tools, like clear curve, set handle type - icon 'clipping': menu with clip values, and to dis/enable clipping - icon 'x': delete selection In the curve button itself, only LMB clicks are handled (like all UI elements in Blender). - click on point: select - shift+click on point: swap select - click on point + drag: select point (if not selected) and move it - click outside point + drag: translate view - CTRL+click: add new point - hold SHIFT while dragging to snap to grid (Yes I know... either one of these can be Blender compliant, not both!) - if you drag a point exactly on top of another, it merges them Other fixes: - Icons now draw using "Safe RasterPos", so they align with pixel boundary. the old code made ints from the raster pos coordinate, which doesn't work well for zoom in/out situations - bug in Node editing: buttons could not get freed, causing in memory error prints at end of a Blender session. That one was a very simple, but nasty error causing me all evening last night to find! (Hint; check diff of editnode.c, where uiDoButtons is called) Last note: this adds 3 new files in our tree, I did scons, but not MSVC!
Diffstat (limited to 'source/blender/blenkernel')
-rw-r--r--source/blender/blenkernel/BKE_colortools.h50
-rw-r--r--source/blender/blenkernel/BKE_node.h2
-rw-r--r--source/blender/blenkernel/SConscript1
-rw-r--r--source/blender/blenkernel/intern/colortools.c469
-rw-r--r--source/blender/blenkernel/intern/node.c44
-rw-r--r--source/blender/blenkernel/intern/node_shaders.c62
6 files changed, 616 insertions, 12 deletions
diff --git a/source/blender/blenkernel/BKE_colortools.h b/source/blender/blenkernel/BKE_colortools.h
new file mode 100644
index 00000000000..7521a935118
--- /dev/null
+++ b/source/blender/blenkernel/BKE_colortools.h
@@ -0,0 +1,50 @@
+/**
+ * $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) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef BKE_COLORTOOLS_H
+#define BKE_COLORTOOLS_H
+
+struct CurveMapping;
+struct CurveMap;
+struct rctf;
+
+struct CurveMapping *curvemapping_add(int tot, float minx, float miny, float maxx, float maxy);
+void curvemapping_free(struct CurveMapping *cumap);
+struct CurveMapping *curvemapping_copy(struct CurveMapping *cumap);
+
+void curvemap_remove(struct CurveMap *cuma, int flag);
+void curvemap_insert(struct CurveMap *cuma, float x, float y);
+void curvemap_reset(struct CurveMap *cuma, struct rctf *clipr);
+void curvemap_sethandle(struct CurveMap *cuma, int type);
+
+void curvemapping_changed(struct CurveMapping *cumap, int rem_doubles);
+float curvemapping_evaluateF(struct CurveMapping *cumap, int cur, float value);
+void curvemapping_evaluate3F(struct CurveMapping *cumap, float *vecout, const float *vecin);
+
+#endif
+
diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h
index 7253a0cc95a..7c887e2db63 100644
--- a/source/blender/blenkernel/BKE_node.h
+++ b/source/blender/blenkernel/BKE_node.h
@@ -159,6 +159,8 @@ struct ShadeResult;
#define SH_NODE_NORMAL 107
#define SH_NODE_GEOMETRY 108
#define SH_NODE_MAPPING 109
+#define SH_NODE_CURVE_VEC 110
+#define SH_NODE_CURVE_RGB 111
/* custom defines: options for Material node */
#define SH_NODE_MAT_DIFF 1
diff --git a/source/blender/blenkernel/SConscript b/source/blender/blenkernel/SConscript
index 7d1b45f69f1..acbb15a4ecd 100644
--- a/source/blender/blenkernel/SConscript
+++ b/source/blender/blenkernel/SConscript
@@ -46,6 +46,7 @@ source_files = ['intern/constraint.c',
'intern/softbody.c',
'intern/node.c',
'intern/node_shaders.c',
+ 'intern/colortools.c',
'intern/texture.c']
blenkernel_env.Append (CPPPATH = ['.',
diff --git a/source/blender/blenkernel/intern/colortools.c b/source/blender/blenkernel/intern/colortools.c
new file mode 100644
index 00000000000..0ce9bfc9ee9
--- /dev/null
+++ b/source/blender/blenkernel/intern/colortools.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., 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/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <string.h>
+#include <math.h>
+#include <stdlib.h>
+#include <float.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_color_types.h"
+#include "DNA_curve_types.h"
+#include "DNA_texture_types.h"
+
+#include "BKE_colortools.h"
+#include "BKE_curve.h"
+#include "BKE_global.h"
+#include "BKE_ipo.h"
+#include "BKE_main.h"
+#include "BKE_utildefines.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+
+
+/* ********************************* color curve ********************* */
+
+/* ***************** operations on full struct ************* */
+
+CurveMapping *curvemapping_add(int tot, float minx, float miny, float maxx, float maxy)
+{
+ CurveMapping *cumap;
+ int a;
+
+ cumap= MEM_callocN(sizeof(CurveMapping), "new curvemap");
+ cumap->flag= CUMA_DO_CLIP;
+
+ BLI_init_rctf(&cumap->curr, minx, maxx, miny, maxy);
+ cumap->clipr= cumap->curr;
+
+ for(a=0; a<tot; a++) {
+ cumap->cm[a].totpoint= 2;
+ cumap->cm[a].curve= MEM_callocN(2*sizeof(CurveMapPoint), "curve points");
+
+ cumap->cm[a].curve[0].x= minx;
+ cumap->cm[a].curve[0].y= miny;
+ cumap->cm[a].curve[1].x= maxx;
+ cumap->cm[a].curve[1].y= maxy;
+ }
+ return cumap;
+}
+
+void curvemapping_free(CurveMapping *cumap)
+{
+ int a;
+
+ if(cumap) {
+ for(a=0; a<CM_TOT; a++) {
+ if(cumap->cm[a].curve) MEM_freeN(cumap->cm[a].curve);
+ if(cumap->cm[a].table) MEM_freeN(cumap->cm[a].table);
+ }
+ MEM_freeN(cumap);
+ }
+}
+
+CurveMapping *curvemapping_copy(CurveMapping *cumap)
+{
+ int a;
+
+ if(cumap) {
+ CurveMapping *cumapn= MEM_dupallocN(cumap);
+ for(a=0; a<CM_TOT; a++) {
+ if(cumap->cm[a].curve)
+ cumapn->cm[a].curve= MEM_dupallocN(cumap->cm[a].curve);
+ if(cumap->cm[a].table)
+ cumapn->cm[a].table= MEM_dupallocN(cumap->cm[a].table);
+ }
+ return cumapn;
+ }
+ return NULL;
+}
+
+/* ***************** operations on single curve ************* */
+/* ********** NOTE: requires curvemapping_changed() call after ******** */
+
+/* removes with flag set */
+void curvemap_remove(CurveMap *cuma, int flag)
+{
+ CurveMapPoint *cmp= MEM_mallocN((cuma->totpoint)*sizeof(CurveMapPoint), "curve points");
+ int a, b, removed=0;
+
+ /* well, lets keep the two outer points! */
+ cmp[0]= cuma->curve[0];
+ for(a=1, b=1; a<cuma->totpoint-1; a++) {
+ if(!(cuma->curve[a].flag & flag)) {
+ cmp[b]= cuma->curve[a];
+ b++;
+ }
+ else removed++;
+ }
+ cmp[b]= cuma->curve[a];
+
+ MEM_freeN(cuma->curve);
+ cuma->curve= cmp;
+ cuma->totpoint -= removed;
+}
+
+void curvemap_insert(CurveMap *cuma, float x, float y)
+{
+ CurveMapPoint *cmp= MEM_callocN((cuma->totpoint+1)*sizeof(CurveMapPoint), "curve points");
+ int a;
+
+ memcpy(cmp, cuma->curve, (cuma->totpoint)*sizeof(CurveMapPoint));
+ MEM_freeN(cuma->curve);
+ cuma->curve= cmp;
+
+ cuma->curve[cuma->totpoint].x= x;
+ cuma->curve[cuma->totpoint].y= y;
+ cuma->curve[cuma->totpoint].flag = CUMA_SELECT;
+ for(a=0; a<cuma->totpoint; a++, cmp++)
+ cmp->flag= 0;
+ cuma->totpoint++;
+}
+
+void curvemap_reset(CurveMap *cuma, rctf *clipr)
+{
+ cuma->totpoint= 2;
+
+ cuma->curve[0].x= clipr->xmin;
+ cuma->curve[0].y= clipr->ymin;
+ cuma->curve[0].flag= 0;
+ cuma->curve[1].x= clipr->xmax;
+ cuma->curve[1].y= clipr->ymax;
+ cuma->curve[1].flag= 0;
+}
+
+/* if type==1: vector, else auto */
+void curvemap_sethandle(CurveMap *cuma, int type)
+{
+ int a;
+
+ for(a=0; a<cuma->totpoint; a++) {
+ if(cuma->curve[a].flag & CUMA_SELECT) {
+ if(type) cuma->curve[a].flag |= CUMA_VECTOR;
+ else cuma->curve[a].flag &= ~CUMA_VECTOR;
+ }
+ }
+}
+
+/* *********************** Making the tables and display ************** */
+
+/* reduced copy of garbled calchandleNurb() code in curve.c */
+static void calchandle_curvemap(BezTriple *bezt, BezTriple *prev, BezTriple *next, int mode)
+{
+ float *p1,*p2,*p3,pt[3];
+ float dx1,dy1, dx,dy, vx,vy, len,len1,len2;
+
+ if(bezt->h1==0 && bezt->h2==0) return;
+
+ p2= bezt->vec[1];
+
+ if(prev==NULL) {
+ p3= next->vec[1];
+ pt[0]= 2*p2[0]- p3[0];
+ pt[1]= 2*p2[1]- p3[1];
+ p1= pt;
+ }
+ else p1= prev->vec[1];
+
+ if(next==NULL) {
+ p1= prev->vec[1];
+ pt[0]= 2*p2[0]- p1[0];
+ pt[1]= 2*p2[1]- p1[1];
+ p3= pt;
+ }
+ else p3= next->vec[1];
+
+ dx= p2[0]- p1[0];
+ dy= p2[1]- p1[1];
+
+ len1= (float)sqrt(dx*dx+dy*dy);
+
+ dx1= p3[0]- p2[0];
+ dy1= p3[1]- p2[1];
+
+ len2= (float)sqrt(dx1*dx1+dy1*dy1);
+
+ if(len1==0.0f) len1=1.0f;
+ if(len2==0.0f) len2=1.0f;
+
+ if(bezt->h1==HD_AUTO || bezt->h2==HD_AUTO) { /* auto */
+ vx= dx1/len2 + dx/len1;
+ vy= dy1/len2 + dy/len1;
+
+ len= 2.5614f*(float)sqrt(vx*vx + vy*vy);
+ if(len!=0.0f) {
+
+ if(bezt->h1==HD_AUTO) {
+ len1/=len;
+ *(p2-3)= *p2-vx*len1;
+ *(p2-2)= *(p2+1)-vy*len1;
+ }
+ if(bezt->h2==HD_AUTO) {
+ len2/=len;
+ *(p2+3)= *p2+vx*len2;
+ *(p2+4)= *(p2+1)+vy*len2;
+ }
+ }
+ }
+
+ if(bezt->h1==HD_VECT) { /* vector */
+ dx/=3.0;
+ dy/=3.0;
+ *(p2-3)= *p2-dx;
+ *(p2-2)= *(p2+1)-dy;
+ }
+ if(bezt->h2==HD_VECT) {
+ dx1/=3.0;
+ dy1/=3.0;
+ *(p2+3)= *p2+dx1;
+ *(p2+4)= *(p2+1)+dy1;
+ }
+}
+
+
+static void curvemap_make_table(CurveMap *cuma, rctf *clipr)
+{
+ CurveMapPoint *cmp= cuma->curve;
+ BezTriple *bezt;
+ float *fp, *allpoints, curf, range;
+ int a, totpoint;
+
+ if(cuma->curve==NULL) return;
+
+ /* default rect also is table range */
+ cuma->mintable= clipr->xmin;
+ cuma->maxtable= clipr->xmax;
+
+ /* hrmf... we now rely on blender ipo beziers, these are more advanced */
+ bezt= MEM_callocN(cuma->totpoint*sizeof(BezTriple), "beztarr");
+
+ for(a=0; a<cuma->totpoint; a++) {
+ cuma->mintable= MIN2(cuma->mintable, cmp[a].x);
+ cuma->maxtable= MAX2(cuma->maxtable, cmp[a].x);
+ bezt[a].vec[1][0]= cmp[a].x;
+ bezt[a].vec[1][1]= cmp[a].y;
+ if(cmp[a].flag & CUMA_VECTOR)
+ bezt[a].h1= bezt[a].h2= HD_VECT;
+ else
+ bezt[a].h1= bezt[a].h2= HD_AUTO;
+ }
+
+ for(a=0; a<cuma->totpoint; a++) {
+ if(a==0)
+ calchandle_curvemap(bezt, NULL, bezt+1, 0);
+ else if(a==cuma->totpoint-1)
+ calchandle_curvemap(bezt+a, bezt+a-1, NULL, 0);
+ else
+ calchandle_curvemap(bezt+a, bezt+a-1, bezt+a+1, 0);
+ }
+
+ /* first and last handle need correction, instead of pointing to center of next/prev,
+ we let it point to the closest handle */
+ if(cuma->totpoint>2) {
+ float hlen, nlen, vec[3];
+
+ if(bezt[0].h2==HD_AUTO) {
+
+ hlen= VecLenf(bezt[0].vec[1], bezt[0].vec[2]); /* original handle length */
+ /* clip handle point */
+ VECCOPY(vec, bezt[1].vec[0]);
+ if(vec[0] < bezt[0].vec[1][0])
+ vec[0]= bezt[0].vec[1][0];
+
+ VecSubf(vec, vec, bezt[0].vec[1]);
+ nlen= VecLength(vec);
+ if(nlen>FLT_EPSILON) {
+ VecMulf(vec, hlen/nlen);
+ VecAddf(bezt[0].vec[2], vec, bezt[0].vec[1]);
+ }
+ }
+ a= cuma->totpoint-1;
+ if(bezt[a].h2==HD_AUTO) {
+
+ hlen= VecLenf(bezt[a].vec[1], bezt[a].vec[0]); /* original handle length */
+ /* clip handle point */
+ VECCOPY(vec, bezt[a-1].vec[2]);
+ if(vec[0] > bezt[a].vec[1][0])
+ vec[0]= bezt[a].vec[1][0];
+
+ VecSubf(vec, vec, bezt[a].vec[1]);
+ nlen= VecLength(vec);
+ if(nlen>FLT_EPSILON) {
+ VecMulf(vec, hlen/nlen);
+ VecAddf(bezt[a].vec[0], vec, bezt[a].vec[1]);
+ }
+ }
+ }
+ /* make the bezier curve */
+ if(cuma->table)
+ MEM_freeN(cuma->table);
+ totpoint= (cuma->totpoint-1)*CM_RESOL;
+ fp= allpoints= MEM_mallocN(totpoint*2*sizeof(float), "table");
+
+ for(a=0; a<cuma->totpoint-1; a++, fp += 2*CM_RESOL) {
+ correct_bezpart(bezt[a].vec[1], bezt[a].vec[2], bezt[a+1].vec[0], bezt[a+1].vec[1]);
+ forward_diff_bezier(bezt[a].vec[1][0], bezt[a].vec[2][0], bezt[a+1].vec[0][0], bezt[a+1].vec[1][0], fp, CM_RESOL-1, 2);
+ forward_diff_bezier(bezt[a].vec[1][1], bezt[a].vec[2][1], bezt[a+1].vec[0][1], bezt[a+1].vec[1][1], fp+1, CM_RESOL-1, 2);
+ }
+
+ MEM_freeN(bezt);
+
+ range= CM_TABLEDIV*(cuma->maxtable - cuma->mintable);
+ cuma->range= 1.0f/range;
+
+ /* now make a table with CM_TABLE equal x distances */
+ fp= allpoints;
+ cmp= MEM_callocN((CM_TABLE+1)*sizeof(CurveMapPoint), "dist table");
+ cmp[0].x= cuma->mintable;
+ cmp[0].y= allpoints[1];
+
+ for(a=1; a<CM_TABLE; a++) {
+ curf= cuma->mintable + range*(float)a;
+ cmp[a].x= curf;
+
+ /* get the first x coordinate larger than curf */
+ while(curf >= fp[0] && fp!=allpoints-2) {
+ fp+=2;
+ }
+ if(fp==allpoints-2)
+ cmp[a].y= fp[1];
+ else {
+ float fac1= fp[0] - fp[-2];
+ float fac2= fp[0] - curf;
+ if(fac1 > FLT_EPSILON)
+ fac1= fac2/fac1;
+ else
+ fac1= 0.0f;
+ cmp[a].y= fac1*fp[-1] + (1.0f-fac1)*fp[1];
+ }
+ }
+ cmp[CM_TABLE].x= cuma->maxtable;
+ cmp[CM_TABLE].y= allpoints[2*totpoint-1];
+
+ MEM_freeN(allpoints);
+ cuma->table= cmp;
+}
+
+
+static int sort_curvepoints(const void *a1, const void *a2)
+{
+ const struct CurveMapPoint *x1=a1, *x2=a2;
+
+ if( x1->x > x2->x ) return 1;
+ else if( x1->x < x2->x) return -1;
+ return 0;
+}
+
+/* ************************ more CurveMapping calls *************** */
+
+/* note; only does current curvemap! */
+void curvemapping_changed(CurveMapping *cumap, int rem_doubles)
+{
+ CurveMap *cuma= cumap->cm+cumap->cur;
+ CurveMapPoint *cmp= cuma->curve;
+ rctf *clipr= &cumap->clipr;
+ float thresh= 0.01f*(clipr->xmax - clipr->xmin);
+ float dx, dy;
+ int a;
+
+ /* clamp with clip */
+ if(cumap->flag & CUMA_DO_CLIP) {
+ for(a=0; a<cuma->totpoint; a++) {
+ if(cmp[a].x < clipr->xmin)
+ cmp[a].x= clipr->xmin;
+ else if(cmp[a].x > clipr->xmax)
+ cmp[a].x= clipr->xmax;
+ if(cmp[a].y < clipr->ymin)
+ cmp[a].y= clipr->ymin;
+ else if(cmp[a].y > clipr->ymax)
+ cmp[a].y= clipr->ymax;
+ }
+ }
+
+ qsort(cmp, cuma->totpoint, sizeof(CurveMapPoint), sort_curvepoints);
+
+ /* remove doubles, threshold set on 1% of default range */
+ if(rem_doubles && cuma->totpoint>2) {
+ for(a=0; a<cuma->totpoint-1; a++) {
+ dx= cmp[a].x - cmp[a+1].x;
+ dy= cmp[a].y - cmp[a+1].y;
+ if( sqrt(dx*dx + dy*dy) < thresh ) {
+ if(a==0) {
+ cmp[a+1].flag|= 2;
+ if(cmp[a+1].flag & CUMA_SELECT)
+ cmp[a].flag |= CUMA_SELECT;
+ }
+ else {
+ cmp[a].flag|= 2;
+ if(cmp[a].flag & CUMA_SELECT)
+ cmp[a+1].flag |= CUMA_SELECT;
+ }
+ break; /* we assume 1 deletion per edit is ok */
+ }
+ }
+ if(a != cuma->totpoint-1)
+ curvemap_remove(cuma, 2);
+ }
+ curvemap_make_table(cuma, clipr);
+}
+
+/* works with curve 'cur' */
+float curvemapping_evaluateF(CurveMapping *cumap, int cur, float value)
+{
+ CurveMap *cuma= cumap->cm+cur;
+ float fi;
+ int i;
+
+ /* allocate or bail out */
+ if(cuma->table==NULL) {
+ curvemap_make_table(cuma, &cumap->clipr);
+ if(cuma->table==NULL)
+ return value;
+ }
+
+ /* index in table */
+ fi= (value-cuma->mintable)*cuma->range;
+ i= (int)fi;
+ if(i<0) return cuma->table[0].y;
+ if(i>=CM_TABLE) return cuma->table[CM_TABLE].y;
+
+ fi= fi-(float)i;
+ return (1.0f-fi)*cuma->table[i].y + (fi)*cuma->table[i+1].y;
+}
+
+void curvemapping_evaluate3F(CurveMapping *cumap, float *vecout, const float *vecin)
+{
+ vecout[0]= curvemapping_evaluateF(cumap, 0, vecin[0]);
+ vecout[1]= curvemapping_evaluateF(cumap, 1, vecin[1]);
+ vecout[2]= curvemapping_evaluateF(cumap, 2, vecin[2]);
+}
+
+
diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c
index 7aec48edd83..da18725c2dd 100644
--- a/source/blender/blenkernel/intern/node.c
+++ b/source/blender/blenkernel/intern/node.c
@@ -35,6 +35,7 @@
#include "DNA_material_types.h"
#include "BKE_blender.h"
+#include "BKE_colortools.h"
#include "BKE_global.h"
#include "BKE_library.h"
#include "BKE_main.h"
@@ -696,6 +697,10 @@ bNode *nodeAddNodeType(bNodeTree *ntree, int type, bNodeTree *ngroup)
node->storage= add_colorband(1);
else if(type==SH_NODE_MAPPING)
node->storage= add_mapping();
+ else if(type==SH_NODE_CURVE_VEC)
+ node->storage= curvemapping_add(3, -1.0f, -1.0f, 1.0f, 1.0f);
+ else if(type==SH_NODE_CURVE_RGB)
+ node->storage= curvemapping_add(4, 0.0f, 0.0f, 1.0f, 1.0f);
}
return node;
@@ -722,8 +727,17 @@ bNode *nodeCopyNode(struct bNodeTree *ntree, struct bNode *node)
if(nnode->id)
nnode->id->us++;
- if(nnode->storage)
- nnode->storage= MEM_dupallocN(nnode->storage);
+ if(nnode->storage) {
+ /* another candidate for handlerizing! */
+ if(ntree->type==NTREE_SHADER) {
+ if(node->type==SH_NODE_CURVE_VEC || node->type==SH_NODE_CURVE_RGB)
+ nnode->storage= curvemapping_copy(node->storage);
+ else
+ nnode->storage= MEM_dupallocN(nnode->storage);
+ }
+ else
+ nnode->storage= MEM_dupallocN(nnode->storage);
+ }
node->new= nnode;
nnode->new= NULL;
@@ -796,10 +810,9 @@ static void node_unlink_node(bNodeTree *ntree, bNode *node)
void nodeFreeNode(bNodeTree *ntree, bNode *node)
{
- if(ntree) {
- node_unlink_node(ntree, node);
- BLI_remlink(&ntree->nodes, node);
- }
+ node_unlink_node(ntree, node);
+ BLI_remlink(&ntree->nodes, node);
+
if(node->id)
node->id->us--;
@@ -811,9 +824,17 @@ void nodeFreeNode(bNodeTree *ntree, bNode *node)
MEM_freeN(node->preview->rect);
MEM_freeN(node->preview);
}
- if(node->storage)
- MEM_freeN(node->storage);
-
+ if(node->storage) {
+ /* could be handlerized at some point, now only 1 exception still */
+ if(ntree->type==NTREE_SHADER) {
+ if(node->type==SH_NODE_CURVE_VEC || node->type==SH_NODE_CURVE_RGB)
+ curvemapping_free(node->storage);
+ else
+ MEM_freeN(node->storage);
+ }
+ else
+ MEM_freeN(node->storage);
+ }
MEM_freeN(node);
}
@@ -822,11 +843,12 @@ void ntreeFreeTree(bNodeTree *ntree)
{
bNode *node, *next;
+ BLI_freelistN(&ntree->links); /* do first, then unlink_node goes fast */
+
for(node= ntree->nodes.first; node; node= next) {
next= node->next;
- nodeFreeNode(NULL, node); /* NULL -> no unlinking needed */
+ nodeFreeNode(ntree, node);
}
- BLI_freelistN(&ntree->links);
if(ntree->owntype) {
if(ntree->owntype->inputs)
diff --git a/source/blender/blenkernel/intern/node_shaders.c b/source/blender/blenkernel/intern/node_shaders.c
index 6bc3045c139..b1dfdf0f5b4 100644
--- a/source/blender/blenkernel/intern/node_shaders.c
+++ b/source/blender/blenkernel/intern/node_shaders.c
@@ -36,6 +36,7 @@
#include "DNA_texture_types.h"
#include "BKE_blender.h"
+#include "BKE_colortools.h"
#include "BKE_node.h"
#include "BKE_texture.h"
#include "BKE_utildefines.h"
@@ -240,8 +241,10 @@ static void node_shader_exec_material(void *data, bNode *node, bNodeStack **in,
shi->mat->ref= in[MAT_IN_REFL]->vec[0];
/* retrieve normal */
- if(in[MAT_IN_NORMAL]->hasinput)
+ if(in[MAT_IN_NORMAL]->hasinput) {
nor= in[MAT_IN_NORMAL]->vec;
+ Normalise(nor);
+ }
else
nor= shi->vno;
@@ -476,6 +479,61 @@ static bNodeType sh_node_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, "" }
+};
+
+/* generates normal, does dot product */
+static void node_shader_exec_curve(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ /* stack order input: vec */
+ /* stack order output: vec */
+
+ curvemapping_evaluate3F(node->storage, out[0]->vec, in[0]->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_OPERATOR, NODE_OPTIONS,
+ /* input sock */ sh_node_curve_vec_in,
+ /* output sock */ sh_node_curve_vec_out,
+ /* storage */ "CurveMapping",
+ /* execfunc */ node_shader_exec_curve
+
+};
+
+/* **************** 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 bNodeType sh_node_curve_rgb= {
+ /* type code */ SH_NODE_CURVE_RGB,
+ /* name */ "RGB Curves",
+ /* width+range */ 200, 140, 320,
+ /* class+opts */ NODE_CLASS_OPERATOR, NODE_OPTIONS,
+ /* input sock */ sh_node_curve_rgb_in,
+ /* output sock */ sh_node_curve_rgb_out,
+ /* storage */ "CurveMapping",
+ /* execfunc */ node_shader_exec_curve
+
+};
+
/* **************** VALUE ******************** */
static bNodeSocketType sh_node_value_out[]= {
{ SOCK_VALUE, 0, "Value", 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
@@ -647,6 +705,8 @@ bNodeType *node_all_shaders[]= {
&sh_node_normal,
&sh_node_geom,
&sh_node_mapping,
+ &sh_node_curve_vec,
+ &sh_node_curve_rgb,
NULL
};