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...
This commit is contained in:
Matt Ebb 2010-01-20 04:19:55 +00:00
parent 8bcf66e1d1
commit 1d3186cbcf
14 changed files with 418 additions and 222 deletions

@ -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

@ -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);

@ -74,6 +74,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);

@ -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];
}
}

@ -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, .. */

@ -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 */

@ -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);

@ -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;
}

@ -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;
}

@ -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];

@ -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;
@ -1855,6 +1874,38 @@ static void def_cmp_lensdist(StructRNA *srna)
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");
}
/* -- Texture Nodes --------------------------------------------------------- */

@ -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", "" )

@ -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;

@ -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