diff options
author | Matt Ebb <matt@mke3.net> | 2010-01-20 07:19:55 +0300 |
---|---|---|
committer | Matt Ebb <matt@mke3.net> | 2010-01-20 07:19:55 +0300 |
commit | 1d3186cbcf9e3e463e4e6362ac76862b801cf7ba (patch) | |
tree | 450dc8b914efeb8829f815dbba1f9aabd7449a0f /source | |
parent | 8bcf66e1d16ece55f8736797f7d4180a456060ff (diff) |
Durian request: Added 'Color Balance' node to compositor. uses Lift/Gamma/Gain
similar to sequence editor.
--> http://mke3.net/blender/devel/2.5/color_balance_node.jpg
Also added 0 key (zero key) shortcut when mouse is over a button, to reset it to its default value.
Same as the RMB menu ->Reset to Default, except for color wheels, it only resets the hue/sat/value
components that that widget affects.
Peter/Xavier: The existing color balance code can generate NaNs (fractional power of a negative),
which causes havoc along the image pipeline. I added a check in the node code to prevent this.
Still plenty of potential for lots of better colour correction tools in the compositor, just needs time...
Diffstat (limited to 'source')
-rw-r--r-- | source/blender/blenkernel/BKE_node.h | 1 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/node.c | 1 | ||||
-rw-r--r-- | source/blender/blenlib/BLI_math_color.h | 4 | ||||
-rw-r--r-- | source/blender/blenlib/intern/math_color.c | 14 | ||||
-rw-r--r-- | source/blender/editors/interface/interface.c | 11 | ||||
-rw-r--r-- | source/blender/editors/interface/interface_handlers.c | 59 | ||||
-rw-r--r-- | source/blender/editors/interface/interface_intern.h | 2 | ||||
-rw-r--r-- | source/blender/editors/space_image/space_image.c | 445 | ||||
-rw-r--r-- | source/blender/editors/space_node/drawnode.c | 27 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_node_types.h | 12 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_nodetree.c | 51 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_nodetree_types.h | 1 | ||||
-rw-r--r-- | source/blender/nodes/CMP_node.h | 1 | ||||
-rw-r--r-- | source/blender/nodes/intern/node_util.h | 11 |
14 files changed, 418 insertions, 222 deletions
diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index 8da732af2dd..fe20c4d8158 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -354,6 +354,7 @@ void ntreeGPUMaterialNodes(struct bNodeTree *ntree, struct GPUMaterial *mat); #define CMP_NODE_DIST_MATTE 257 #define CMP_NODE_VIEW_LEVELS 258 #define CMP_NODE_COLOR_MATTE 259 +#define CMP_NODE_COLORBALANCE 260 #define CMP_NODE_GLARE 301 #define CMP_NODE_TONEMAP 302 diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c index b7991d0c589..874529d9965 100644 --- a/source/blender/blenkernel/intern/node.c +++ b/source/blender/blenkernel/intern/node.c @@ -2983,6 +2983,7 @@ static void registerCompositNodes(ListBase *ntypelist) nodeRegisterType(ntypelist, &cmp_node_invert); nodeRegisterType(ntypelist, &cmp_node_alphaover); nodeRegisterType(ntypelist, &cmp_node_zcombine); + nodeRegisterType(ntypelist, &cmp_node_colorbalance); nodeRegisterType(ntypelist, &cmp_node_normal); nodeRegisterType(ntypelist, &cmp_node_curve_vec); diff --git a/source/blender/blenlib/BLI_math_color.h b/source/blender/blenlib/BLI_math_color.h index 2123765643e..41cce59c2b9 100644 --- a/source/blender/blenlib/BLI_math_color.h +++ b/source/blender/blenlib/BLI_math_color.h @@ -73,6 +73,10 @@ void linearrgb_to_srgb_v3_v3(float *col_to, float *col_from); int constrain_rgb(float *r, float *g, float *b); void minmax_rgb(short c[3]); + +/***************** lift/gamma/gain / ASC-CDL conversion *****************/ + +void lift_gamma_gain_to_asc_cdl(float *lift, float *gamma, float *gain, float *offset, float *slope, float *power); void rgb_byte_to_float(char *in, float *out); void rgb_float_to_byte(float *in, char *out); diff --git a/source/blender/blenlib/intern/math_color.c b/source/blender/blenlib/intern/math_color.c index a4bd11a4bc8..044f1ca743e 100644 --- a/source/blender/blenlib/intern/math_color.c +++ b/source/blender/blenlib/intern/math_color.c @@ -386,3 +386,17 @@ int constrain_rgb(float *r, float *g, float *b) return 0; /* Color within RGB gamut */ } +/* ********************************* lift/gamma/gain / ASC-CDL conversion ********************************* */ + +void lift_gamma_gain_to_asc_cdl(float *lift, float *gamma, float *gain, float *offset, float *slope, float *power) +{ + int c; + for(c=0; c<3; c++) { + offset[c]= lift[c]*gain[c]; + slope[c]= gain[c]*(1.0f-lift[c]); + if(gamma[c] == 0) + power[c]= FLT_MAX; + else + power[c]= 1.0f/gamma[c]; + } +} diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c index 48fd23ad0e7..8b59ff604b9 100644 --- a/source/blender/editors/interface/interface.c +++ b/source/blender/editors/interface/interface.c @@ -1626,6 +1626,17 @@ int ui_set_but_string(bContext *C, uiBut *but, const char *str) return 0; } +void ui_set_but_default(bContext *C, uiBut *but) +{ + /* if there is a valid property that is editable... */ + if (but->rnapoin.data && but->rnaprop && RNA_property_editable(&but->rnapoin, but->rnaprop)) { + if(RNA_property_reset(&but->rnapoin, but->rnaprop, -1)) { + /* perform updates required for this property */ + RNA_property_update(C, &but->rnapoin, but->rnaprop); + } + } +} + static double soft_range_round_up(double value, double max) { /* round up to .., 0.1, 0.2, 0.5, 1, 2, 5, 10, 20, 50, .. */ diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index 6873c64a188..37d5191691a 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -2781,6 +2781,34 @@ static int ui_do_but_HSVCUBE(bContext *C, uiBlock *block, uiBut *but, uiHandleBu return WM_UI_HANDLER_BREAK; } + else if (event->type == ZEROKEY && event->val == KM_PRESS) { + if (but->a1==9){ + float rgb[3], hsv[3], def_hsv[3]; + float *def; + int len; + + /* reset only value */ + + len= RNA_property_array_length(&but->rnapoin, but->rnaprop); + if (len >= 3) { + def= MEM_callocN(sizeof(float)*len, "reset_defaults - float"); + + RNA_property_float_get_default_array(&but->rnapoin, but->rnaprop, def); + rgb_to_hsv(def[0], def[1], def[2], def_hsv, def_hsv+1, def_hsv+2); + + ui_get_but_vectorf(but, rgb); + rgb_to_hsv(rgb[0], rgb[1], rgb[2], hsv, hsv+1, hsv+2); + + hsv_to_rgb(hsv[0], hsv[1], def_hsv[2], rgb, rgb+1, rgb+2); + ui_set_but_vectorf(but, rgb); + + RNA_property_update(C, &but->rnapoin, but->rnaprop); + + MEM_freeN(def); + } + return WM_UI_HANDLER_BREAK; + } + } } else if(data->state == BUTTON_STATE_NUM_EDITING) { if(event->type == ESCKEY) { @@ -2849,6 +2877,32 @@ static int ui_do_but_HSVCIRCLE(bContext *C, uiBlock *block, uiBut *but, uiHandle return WM_UI_HANDLER_BREAK; } + else if (event->type == ZEROKEY && event->val == KM_PRESS) { + float rgb[3], hsv[3], def_hsv[3]; + float *def; + int len; + + /* reset only saturation */ + + len= RNA_property_array_length(&but->rnapoin, but->rnaprop); + if (len >= 3) { + def= MEM_callocN(sizeof(float)*len, "reset_defaults - float"); + + RNA_property_float_get_default_array(&but->rnapoin, but->rnaprop, def); + rgb_to_hsv(def[0], def[1], def[2], def_hsv, def_hsv+1, def_hsv+2); + + ui_get_but_vectorf(but, rgb); + rgb_to_hsv(rgb[0], rgb[1], rgb[2], hsv, hsv+1, hsv+2); + + hsv_to_rgb(hsv[0], def_hsv[1], hsv[2], rgb, rgb+1, rgb+2); + ui_set_but_vectorf(but, rgb); + + RNA_property_update(C, &but->rnapoin, but->rnaprop); + + MEM_freeN(def); + } + return WM_UI_HANDLER_BREAK; + } } else if(data->state == BUTTON_STATE_NUM_EDITING) { if(event->type == ESCKEY) { @@ -3724,6 +3778,11 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, wmEvent *event) return WM_UI_HANDLER_BREAK; } + /* reset to default */ + else if(event->type == ZEROKEY && event->val == KM_PRESS) { + if (!(ELEM(but->type, HSVCIRCLE, HSVCUBE))) + ui_set_but_default(C, but); + } /* handle menu */ else if(event->type == RIGHTMOUSE && event->val == KM_PRESS) { /* RMB has two options now */ diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h index 089ad85a5a1..1851255fd3b 100644 --- a/source/blender/editors/interface/interface_intern.h +++ b/source/blender/editors/interface/interface_intern.h @@ -345,6 +345,8 @@ extern void ui_get_but_string(uiBut *but, char *str, int maxlen); extern int ui_set_but_string(struct bContext *C, uiBut *but, const char *str); extern int ui_get_but_string_max_length(uiBut *but); +extern void ui_set_but_default(struct bContext *C, uiBut *but); + extern void ui_set_but_soft_range(uiBut *but, double value); extern void ui_check_but(uiBut *but); diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c index 0a3367b0427..34737c62450 100644 --- a/source/blender/editors/space_image/space_image.c +++ b/source/blender/editors/space_image/space_image.c @@ -75,6 +75,228 @@ #include "image_intern.h" +/**************************** common state *****************************/ + +/* note; image_panel_properties() uses pointer to sima->image directly */ +Image *ED_space_image(SpaceImage *sima) +{ + return sima->image; +} + +/* called to assign images to UV faces */ +void ED_space_image_set(bContext *C, SpaceImage *sima, Scene *scene, Object *obedit, Image *ima) +{ + ED_uvedit_assign_image(scene, obedit, ima, sima->image); + + /* change the space ima after because uvedit_face_visible uses the space ima + * to check if the face is displayed in UV-localview */ + sima->image= ima; + + if(ima == NULL || ima->type==IMA_TYPE_R_RESULT || ima->type==IMA_TYPE_COMPOSITE) + sima->flag &= ~SI_DRAWTOOL; + + if(sima->image) + BKE_image_signal(sima->image, &sima->iuser, IMA_SIGNAL_USER_NEW_IMAGE); + + if(sima->image && sima->image->id.us==0) + sima->image->id.us= 1; + + if(C) { + if(obedit) + WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); + + ED_area_tag_redraw(CTX_wm_area(C)); + } +} + +ImBuf *ED_space_image_acquire_buffer(SpaceImage *sima, void **lock_r) +{ + ImBuf *ibuf; + + if(sima && sima->image) { +#if 0 + if(sima->image->type==IMA_TYPE_R_RESULT && BIF_show_render_spare()) + return BIF_render_spare_imbuf(); + else +#endif + ibuf= BKE_image_acquire_ibuf(sima->image, &sima->iuser, lock_r); + + if(ibuf && (ibuf->rect || ibuf->rect_float)) + return ibuf; + } + + return NULL; +} + +void ED_space_image_release_buffer(SpaceImage *sima, void *lock) +{ + if(sima && sima->image) + BKE_image_release_ibuf(sima->image, lock); +} + +int ED_space_image_has_buffer(SpaceImage *sima) +{ + ImBuf *ibuf; + void *lock; + int has_buffer; + + ibuf= ED_space_image_acquire_buffer(sima, &lock); + has_buffer= (ibuf != NULL); + ED_space_image_release_buffer(sima, lock); + + return has_buffer; +} + +void ED_image_size(Image *ima, int *width, int *height) +{ + ImBuf *ibuf= NULL; + void *lock; + + if(ima) + ibuf= BKE_image_acquire_ibuf(ima, NULL, &lock); + + if(ibuf && ibuf->x > 0 && ibuf->y > 0) { + *width= ibuf->x; + *height= ibuf->y; + } + else { + *width= 256; + *height= 256; + } + + if(ima) + BKE_image_release_ibuf(ima, lock); +} + +void ED_space_image_size(SpaceImage *sima, int *width, int *height) +{ + Scene *scene= sima->iuser.scene; + ImBuf *ibuf; + void *lock; + + ibuf= ED_space_image_acquire_buffer(sima, &lock); + + if(ibuf && ibuf->x > 0 && ibuf->y > 0) { + *width= ibuf->x; + *height= ibuf->y; + } + else if(sima->image && sima->image->type==IMA_TYPE_R_RESULT && scene) { + /* not very important, just nice */ + *width= (scene->r.xsch*scene->r.size)/100; + *height= (scene->r.ysch*scene->r.size)/100; + } + /* I know a bit weak... but preview uses not actual image size */ + // XXX else if(image_preview_active(sima, width, height)); + else { + *width= 256; + *height= 256; + } + + ED_space_image_release_buffer(sima, lock); +} + +void ED_image_aspect(Image *ima, float *aspx, float *aspy) +{ + *aspx= *aspy= 1.0; + + if((ima == NULL) || (ima->type == IMA_TYPE_R_RESULT) || (ima->type == IMA_TYPE_COMPOSITE) || + (ima->aspx==0.0 || ima->aspy==0.0)) + return; + + /* x is always 1 */ + *aspy = ima->aspy/ima->aspx; +} + +void ED_space_image_aspect(SpaceImage *sima, float *aspx, float *aspy) +{ + ED_image_aspect(ED_space_image(sima), aspx, aspy); +} + +void ED_space_image_zoom(SpaceImage *sima, ARegion *ar, float *zoomx, float *zoomy) +{ + int width, height; + + ED_space_image_size(sima, &width, &height); + + *zoomx= (float)(ar->winrct.xmax - ar->winrct.xmin)/(float)((ar->v2d.cur.xmax - ar->v2d.cur.xmin)*width); + *zoomy= (float)(ar->winrct.ymax - ar->winrct.ymin)/(float)((ar->v2d.cur.ymax - ar->v2d.cur.ymin)*height); +} + +void ED_space_image_uv_aspect(SpaceImage *sima, float *aspx, float *aspy) +{ + int w, h; + + ED_space_image_aspect(sima, aspx, aspy); + ED_space_image_size(sima, &w, &h); + + *aspx *= (float)w/256.0f; + *aspy *= (float)h/256.0f; +} + +void ED_image_uv_aspect(Image *ima, float *aspx, float *aspy) +{ + int w, h; + + ED_image_aspect(ima, aspx, aspy); + ED_image_size(ima, &w, &h); + + *aspx *= (float)w; + *aspy *= (float)h; +} + +int ED_space_image_show_render(SpaceImage *sima) +{ + return (sima->image && ELEM(sima->image->type, IMA_TYPE_R_RESULT, IMA_TYPE_COMPOSITE)); +} + +int ED_space_image_show_paint(SpaceImage *sima) +{ + if(ED_space_image_show_render(sima)) + return 0; + + return (sima->flag & SI_DRAWTOOL); +} + +int ED_space_image_show_uvedit(SpaceImage *sima, Object *obedit) +{ + if(ED_space_image_show_render(sima)) + return 0; + if(ED_space_image_show_paint(sima)) + return 0; + + if(obedit && obedit->type == OB_MESH) { + EditMesh *em = BKE_mesh_get_editmesh(obedit->data); + int ret; + + ret = EM_texFaceCheck(em); + + BKE_mesh_end_editmesh(obedit->data, em); + return ret; + } + + return 0; +} + +int ED_space_image_show_uvshadow(SpaceImage *sima, Object *obedit) +{ + if(ED_space_image_show_render(sima)) + return 0; + + if(ED_space_image_show_paint(sima)) + if(obedit && obedit->type == OB_MESH) { + EditMesh *em = BKE_mesh_get_editmesh(obedit->data); + int ret; + + ret = EM_texFaceCheck(em); + + BKE_mesh_end_editmesh(obedit->data, em); + return ret; + } + + return 0; +} + + static void image_histogram_tag_refresh(ScrArea *sa) { @@ -343,6 +565,8 @@ static void image_listener(ScrArea *sa, wmNotifier *wmn) case ND_MODE: case ND_RENDER_RESULT: case ND_COMPO_RESULT: + if (ED_space_image_show_render(sima)) + image_histogram_tag_refresh(sa); ED_area_tag_refresh(sa); ED_area_tag_redraw(sa); break; @@ -650,224 +874,3 @@ void ED_spacetype_image(void) BKE_spacetype_register(st); } -/**************************** common state *****************************/ - -/* note; image_panel_properties() uses pointer to sima->image directly */ -Image *ED_space_image(SpaceImage *sima) -{ - return sima->image; -} - -/* called to assign images to UV faces */ -void ED_space_image_set(bContext *C, SpaceImage *sima, Scene *scene, Object *obedit, Image *ima) -{ - ED_uvedit_assign_image(scene, obedit, ima, sima->image); - - /* change the space ima after because uvedit_face_visible uses the space ima - * to check if the face is displayed in UV-localview */ - sima->image= ima; - - if(ima == NULL || ima->type==IMA_TYPE_R_RESULT || ima->type==IMA_TYPE_COMPOSITE) - sima->flag &= ~SI_DRAWTOOL; - - if(sima->image) - BKE_image_signal(sima->image, &sima->iuser, IMA_SIGNAL_USER_NEW_IMAGE); - - if(sima->image && sima->image->id.us==0) - sima->image->id.us= 1; - - if(C) { - if(obedit) - WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); - - ED_area_tag_redraw(CTX_wm_area(C)); - } -} - -ImBuf *ED_space_image_acquire_buffer(SpaceImage *sima, void **lock_r) -{ - ImBuf *ibuf; - - if(sima && sima->image) { -#if 0 - if(sima->image->type==IMA_TYPE_R_RESULT && BIF_show_render_spare()) - return BIF_render_spare_imbuf(); - else -#endif - ibuf= BKE_image_acquire_ibuf(sima->image, &sima->iuser, lock_r); - - if(ibuf && (ibuf->rect || ibuf->rect_float)) - return ibuf; - } - - return NULL; -} - -void ED_space_image_release_buffer(SpaceImage *sima, void *lock) -{ - if(sima && sima->image) - BKE_image_release_ibuf(sima->image, lock); -} - -int ED_space_image_has_buffer(SpaceImage *sima) -{ - ImBuf *ibuf; - void *lock; - int has_buffer; - - ibuf= ED_space_image_acquire_buffer(sima, &lock); - has_buffer= (ibuf != NULL); - ED_space_image_release_buffer(sima, lock); - - return has_buffer; -} - -void ED_image_size(Image *ima, int *width, int *height) -{ - ImBuf *ibuf= NULL; - void *lock; - - if(ima) - ibuf= BKE_image_acquire_ibuf(ima, NULL, &lock); - - if(ibuf && ibuf->x > 0 && ibuf->y > 0) { - *width= ibuf->x; - *height= ibuf->y; - } - else { - *width= 256; - *height= 256; - } - - if(ima) - BKE_image_release_ibuf(ima, lock); -} - -void ED_space_image_size(SpaceImage *sima, int *width, int *height) -{ - Scene *scene= sima->iuser.scene; - ImBuf *ibuf; - void *lock; - - ibuf= ED_space_image_acquire_buffer(sima, &lock); - - if(ibuf && ibuf->x > 0 && ibuf->y > 0) { - *width= ibuf->x; - *height= ibuf->y; - } - else if(sima->image && sima->image->type==IMA_TYPE_R_RESULT && scene) { - /* not very important, just nice */ - *width= (scene->r.xsch*scene->r.size)/100; - *height= (scene->r.ysch*scene->r.size)/100; - } - /* I know a bit weak... but preview uses not actual image size */ - // XXX else if(image_preview_active(sima, width, height)); - else { - *width= 256; - *height= 256; - } - - ED_space_image_release_buffer(sima, lock); -} - -void ED_image_aspect(Image *ima, float *aspx, float *aspy) -{ - *aspx= *aspy= 1.0; - - if((ima == NULL) || (ima->type == IMA_TYPE_R_RESULT) || (ima->type == IMA_TYPE_COMPOSITE) || - (ima->aspx==0.0 || ima->aspy==0.0)) - return; - - /* x is always 1 */ - *aspy = ima->aspy/ima->aspx; -} - -void ED_space_image_aspect(SpaceImage *sima, float *aspx, float *aspy) -{ - ED_image_aspect(ED_space_image(sima), aspx, aspy); -} - -void ED_space_image_zoom(SpaceImage *sima, ARegion *ar, float *zoomx, float *zoomy) -{ - int width, height; - - ED_space_image_size(sima, &width, &height); - - *zoomx= (float)(ar->winrct.xmax - ar->winrct.xmin)/(float)((ar->v2d.cur.xmax - ar->v2d.cur.xmin)*width); - *zoomy= (float)(ar->winrct.ymax - ar->winrct.ymin)/(float)((ar->v2d.cur.ymax - ar->v2d.cur.ymin)*height); -} - -void ED_space_image_uv_aspect(SpaceImage *sima, float *aspx, float *aspy) -{ - int w, h; - - ED_space_image_aspect(sima, aspx, aspy); - ED_space_image_size(sima, &w, &h); - - *aspx *= (float)w/256.0f; - *aspy *= (float)h/256.0f; -} - -void ED_image_uv_aspect(Image *ima, float *aspx, float *aspy) -{ - int w, h; - - ED_image_aspect(ima, aspx, aspy); - ED_image_size(ima, &w, &h); - - *aspx *= (float)w; - *aspy *= (float)h; -} - -int ED_space_image_show_render(SpaceImage *sima) -{ - return (sima->image && ELEM(sima->image->type, IMA_TYPE_R_RESULT, IMA_TYPE_COMPOSITE)); -} - -int ED_space_image_show_paint(SpaceImage *sima) -{ - if(ED_space_image_show_render(sima)) - return 0; - - return (sima->flag & SI_DRAWTOOL); -} - -int ED_space_image_show_uvedit(SpaceImage *sima, Object *obedit) -{ - if(ED_space_image_show_render(sima)) - return 0; - if(ED_space_image_show_paint(sima)) - return 0; - - if(obedit && obedit->type == OB_MESH) { - EditMesh *em = BKE_mesh_get_editmesh(obedit->data); - int ret; - - ret = EM_texFaceCheck(em); - - BKE_mesh_end_editmesh(obedit->data, em); - return ret; - } - - return 0; -} - -int ED_space_image_show_uvshadow(SpaceImage *sima, Object *obedit) -{ - if(ED_space_image_show_render(sima)) - return 0; - - if(ED_space_image_show_paint(sima)) - if(obedit && obedit->type == OB_MESH) { - EditMesh *em = BKE_mesh_get_editmesh(obedit->data); - int ret; - - ret = EM_texFaceCheck(em); - - BKE_mesh_end_editmesh(obedit->data, em); - return ret; - } - - return 0; -} - diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c index 5c5e316663c..3323183cb54 100644 --- a/source/blender/editors/space_node/drawnode.c +++ b/source/blender/editors/space_node/drawnode.c @@ -913,6 +913,28 @@ static void node_composit_buts_view_levels(uiLayout *layout, bContext *C, Pointe uiItemR(layout, NULL, 0, ptr, "channel", UI_ITEM_R_EXPAND); } +static void node_composit_buts_colorbalance(uiLayout *layout, bContext *C, PointerRNA *ptr) +{ + uiLayout *split, *col, *row; + + split = uiLayoutSplit(layout, 0, 0); + col = uiLayoutColumn(split, 0); + uiTemplateColorWheel(col, ptr, "lift", 1); + row = uiLayoutRow(col, 0); + uiItemR(row, NULL, 0, ptr, "lift", 0); + + col = uiLayoutColumn(split, 0); + uiTemplateColorWheel(col, ptr, "gamma", 1); + row = uiLayoutRow(col, 0); + uiItemR(row, NULL, 0, ptr, "gamma", 0); + + col = uiLayoutColumn(split, 0); + uiTemplateColorWheel(col, ptr, "gain", 1); + row = uiLayoutRow(col, 0); + uiItemR(row, NULL, 0, ptr, "gain", 0); + +} + /* only once called */ static void node_composit_set_butfunc(bNodeType *ntype) { @@ -1042,9 +1064,12 @@ static void node_composit_set_butfunc(bNodeType *ntype) case CMP_NODE_PREMULKEY: ntype->uifunc= node_composit_buts_premulkey; break; - case CMP_NODE_VIEW_LEVELS: + case CMP_NODE_VIEW_LEVELS: ntype->uifunc=node_composit_buts_view_levels; break; + case CMP_NODE_COLORBALANCE: + ntype->uifunc=node_composit_buts_colorbalance; + break; default: ntype->uifunc= NULL; } diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index 9b433c5bf8c..71b607247d3 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -300,6 +300,18 @@ typedef struct NodeLensDist { short jit, proj, fit, pad; } NodeLensDist; +typedef struct NodeColorBalance { + /* for processing */ + float slope[3]; + float offset[3]; + float power[3]; + + /* for ui representation */ + float lift[3]; + float gamma[3]; + float gain[3]; +} NodeColorBalance; + /* TEX_output */ typedef struct TexNodeOutput { char name[32]; diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index 2105e10bbd1..d151e911a9c 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -42,6 +42,8 @@ #include "BKE_image.h" #include "BKE_texture.h" +#include "BLI_math.h" + #include "WM_types.h" #include "MEM_guardedalloc.h" @@ -298,6 +300,23 @@ static void rna_Node_image_layer_update(Main *bmain, Scene *scene, PointerRNA *p rna_Node_update(bmain, scene, ptr); } +static void rna_Node_colorbalance_update(Main *bmain, Scene *scene, PointerRNA *ptr) +{ + bNode *node= (bNode*)ptr->data; + NodeColorBalance *ncb = node->storage; + float lift[3], gamma[3], gain[3]; + float n_one[3] = {-1.f, -1.f, -1.f}; + + mul_v3_v3fl(lift, ncb->lift, 2.f); + add_v3_v3(lift, n_one); + mul_v3_v3fl(gamma, ncb->gamma, 2.f); + mul_v3_v3fl(gain, ncb->gain, 2.f); + + lift_gamma_gain_to_asc_cdl(lift, gamma, gain, ncb->offset, ncb->slope, ncb->power); + + rna_Node_update(bmain, scene, ptr); +} + static EnumPropertyItem *renderresult_layers_add_enum(RenderLayer *rl) { EnumPropertyItem *item= NULL; @@ -1854,6 +1873,38 @@ static void def_cmp_lensdist(StructRNA *srna) RNA_def_property_ui_text(prop, "Fit", "For positive distortion factor only: scale image such that black areas are not visible"); RNA_def_property_update(prop, NC_NODE|NA_EDITED, "rna_Node_update"); } + +static void def_cmp_colorbalance(StructRNA *srna) +{ + PropertyRNA *prop; + static float default_col[3] = {0.5f, 0.5f, 0.5f}; + + RNA_def_struct_sdna_from(srna, "NodeColorBalance", "storage"); + + prop = RNA_def_property(srna, "lift", PROP_FLOAT, PROP_COLOR_GAMMA); + RNA_def_property_float_sdna(prop, NULL, "lift"); + RNA_def_property_array(prop, 3); + RNA_def_property_float_array_default(prop, default_col); + RNA_def_property_ui_range(prop, 0, 1, 0.1, 3); + RNA_def_property_ui_text(prop, "Lift", "Correction for Shadows"); + RNA_def_property_update(prop, NC_NODE|NA_EDITED, "rna_Node_colorbalance_update"); + + prop = RNA_def_property(srna, "gamma", PROP_FLOAT, PROP_COLOR_GAMMA); + RNA_def_property_float_sdna(prop, NULL, "gamma"); + RNA_def_property_array(prop, 3); + RNA_def_property_float_array_default(prop, default_col); + RNA_def_property_ui_range(prop, 0, 1, 0.1, 3); + RNA_def_property_ui_text(prop, "Gamma", "Correction for Midtones"); + RNA_def_property_update(prop, NC_NODE|NA_EDITED, "rna_Node_colorbalance_update"); + + prop = RNA_def_property(srna, "gain", PROP_FLOAT, PROP_COLOR_GAMMA); + RNA_def_property_float_sdna(prop, NULL, "gain"); + RNA_def_property_array(prop, 3); + RNA_def_property_float_array_default(prop, default_col); + RNA_def_property_ui_range(prop, 0, 1, 0.1, 3); + RNA_def_property_ui_text(prop, "Gain", "Correction for Highlights"); + RNA_def_property_update(prop, NC_NODE|NA_EDITED, "rna_Node_colorbalance_update"); +} diff --git a/source/blender/makesrna/intern/rna_nodetree_types.h b/source/blender/makesrna/intern/rna_nodetree_types.h index d9a1db996de..936832221f9 100644 --- a/source/blender/makesrna/intern/rna_nodetree_types.h +++ b/source/blender/makesrna/intern/rna_nodetree_types.h @@ -107,6 +107,7 @@ DefNode( CompositorNode, CMP_NODE_LENSDIST, def_cmp_lensdist, "LENSD DefNode( CompositorNode, CMP_NODE_VIEW_LEVELS, def_cmp_levels, "LEVELS", Levels, "Levels", "" ) DefNode( CompositorNode, CMP_NODE_COLOR_MATTE, def_cmp_color_matte, "COLOR_MATTE", ColorMatte, "Color Matte", "" ) DefNode( CompositorNode, CMP_NODE_DIST_MATTE, def_cmp_distance_matte, "DISTANCE_MATTE", DistanceMatte, "Distance Matte", "" ) +DefNode( CompositorNode, CMP_NODE_COLORBALANCE, def_cmp_colorbalance, "COLORBALANCE", ColorBalance, "Color Balance", "" ) DefNode( TextureNode, TEX_NODE_OUTPUT, def_tex_output, "OUTPUT", Output, "Output", "" ) DefNode( TextureNode, TEX_NODE_CHECKER, 0, "CHECKER", Checker, "Checker", "" ) diff --git a/source/blender/nodes/CMP_node.h b/source/blender/nodes/CMP_node.h index 041bf1c8361..8c3f4f4a847 100644 --- a/source/blender/nodes/CMP_node.h +++ b/source/blender/nodes/CMP_node.h @@ -59,6 +59,7 @@ extern bNodeType cmp_node_gamma; extern bNodeType cmp_node_invert; extern bNodeType cmp_node_alphaover; extern bNodeType cmp_node_zcombine; +extern bNodeType cmp_node_colorbalance; extern bNodeType cmp_node_normal; extern bNodeType cmp_node_curve_vec; diff --git a/source/blender/nodes/intern/node_util.h b/source/blender/nodes/intern/node_util.h index 5c8ed19a8d1..6cfcd03fdc8 100644 --- a/source/blender/nodes/intern/node_util.h +++ b/source/blender/nodes/intern/node_util.h @@ -40,3 +40,14 @@ extern void node_copy_standard_storage(struct bNode *orig_node, struct bNode *ne #endif +// this is needed for inlining behaviour +#if defined _WIN32 +# define DO_INLINE __inline +#elif defined (__sgi) +# define DO_INLINE +#elif defined (__sun) || defined (__sun__) +# define DO_INLINE +#else +# define DO_INLINE static inline +#endif + |