diff options
-rw-r--r-- | source/blender/blenkernel/BKE_brush.h | 4 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/brush.c | 33 | ||||
-rw-r--r-- | source/blender/blenlib/BLI_math_vector.h | 2 | ||||
-rw-r--r-- | source/blender/blenlib/BLI_utildefines.h | 6 | ||||
-rw-r--r-- | source/blender/blenlib/intern/math_vector_inline.c | 15 | ||||
-rw-r--r-- | source/blender/editors/sculpt_paint/paint_image.c | 31 | ||||
-rw-r--r-- | source/blender/gpu/intern/gpu_draw.c | 22 | ||||
-rw-r--r-- | source/blender/imbuf/IMB_imbuf.h | 5 | ||||
-rw-r--r-- | source/blender/imbuf/intern/divers.c | 129 |
9 files changed, 218 insertions, 29 deletions
diff --git a/source/blender/blenkernel/BKE_brush.h b/source/blender/blenkernel/BKE_brush.h index ad736cd07bf..ebb9714cd1b 100644 --- a/source/blender/blenkernel/BKE_brush.h +++ b/source/blender/blenkernel/BKE_brush.h @@ -71,7 +71,7 @@ float brush_curve_strength(struct Brush *br, float p, const float len); /* used /* sampling */ void brush_sample_tex(struct Brush *brush, float *xy, float *rgba, const int thread); void brush_imbuf_new(struct Brush *brush, short flt, short texfalloff, int size, - struct ImBuf **imbuf); + struct ImBuf **imbuf, int use_color_correction); /* painting */ struct BrushPainter; @@ -82,7 +82,7 @@ BrushPainter *brush_painter_new(struct Brush *brush); void brush_painter_require_imbuf(BrushPainter *painter, short flt, short texonly, int size); int brush_painter_paint(BrushPainter *painter, BrushFunc func, float *pos, - double time, float pressure, void *user); + double time, float pressure, void *user, int use_color_correction); void brush_painter_break_stroke(BrushPainter *painter); void brush_painter_free(BrushPainter *painter); diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c index 25b60fef6dd..a4ceb62ab55 100644 --- a/source/blender/blenkernel/intern/brush.c +++ b/source/blender/blenkernel/intern/brush.c @@ -521,7 +521,7 @@ void brush_sample_tex(Brush *brush, float *xy, float *rgba, const int thread) } -void brush_imbuf_new(Brush *brush, short flt, short texfall, int bufsize, ImBuf **outbuf) +void brush_imbuf_new(Brush *brush, short flt, short texfall, int bufsize, ImBuf **outbuf, int use_color_correction) { ImBuf *ibuf; float xy[2], dist, rgba[4], *dstf; @@ -529,7 +529,8 @@ void brush_imbuf_new(Brush *brush, short flt, short texfall, int bufsize, ImBuf const int radius= brush_size(brush); char *dst, crgb[3]; const float alpha= brush_alpha(brush); - + float brush_rgb[3]; + imbflag= (flt)? IB_rectfloat: IB_rect; xoff = -bufsize/2.0f + 0.5f; yoff = -bufsize/2.0f + 0.5f; @@ -541,6 +542,11 @@ void brush_imbuf_new(Brush *brush, short flt, short texfall, int bufsize, ImBuf ibuf= IMB_allocImBuf(bufsize, bufsize, 32, imbflag); if (flt) { + copy_v3_v3(brush_rgb, brush->rgb); + if(use_color_correction){ + srgb_to_linearrgb_v3_v3(brush_rgb, brush_rgb); + } + for (y=0; y < ibuf->y; y++) { dstf = ibuf->rect_float + y*rowbytes; @@ -551,7 +557,7 @@ void brush_imbuf_new(Brush *brush, short flt, short texfall, int bufsize, ImBuf if (texfall == 0) { dist = sqrt(xy[0]*xy[0] + xy[1]*xy[1]); - VECCOPY(dstf, brush->rgb); + VECCOPY(dstf, brush_rgb); dstf[3]= alpha*brush_curve_strength_clamp(brush, dist, radius); } else if (texfall == 1) { @@ -561,10 +567,7 @@ void brush_imbuf_new(Brush *brush, short flt, short texfall, int bufsize, ImBuf dist = sqrt(xy[0]*xy[0] + xy[1]*xy[1]); brush_sample_tex(brush, xy, rgba, 0); - - dstf[0] = rgba[0]*brush->rgb[0]; - dstf[1] = rgba[1]*brush->rgb[1]; - dstf[2] = rgba[2]*brush->rgb[2]; + mul_v3_v3v3(dstf, rgba, brush_rgb); dstf[3] = rgba[3]*alpha*brush_curve_strength_clamp(brush, dist, radius); } } @@ -862,7 +865,7 @@ static void brush_painter_fixed_tex_partial_update(BrushPainter *painter, float brush_painter_do_partial(painter, NULL, x1, y2, x2, ibuf->y, 0, 0, pos); } -static void brush_painter_refresh_cache(BrushPainter *painter, float *pos) +static void brush_painter_refresh_cache(BrushPainter *painter, float *pos, int use_color_correction) { Brush *brush= painter->brush; BrushPainterCache *cache= &painter->cache; @@ -889,11 +892,11 @@ static void brush_painter_refresh_cache(BrushPainter *painter, float *pos) size= (cache->size)? cache->size: diameter; if (brush->flag & BRUSH_FIXED_TEX) { - brush_imbuf_new(brush, flt, 3, size, &cache->maskibuf); + brush_imbuf_new(brush, flt, 3, size, &cache->maskibuf, use_color_correction); brush_painter_fixed_tex_partial_update(painter, pos); } else - brush_imbuf_new(brush, flt, 2, size, &cache->ibuf); + brush_imbuf_new(brush, flt, 2, size, &cache->ibuf, use_color_correction); cache->lastsize= diameter; cache->lastalpha= alpha; @@ -952,7 +955,7 @@ void brush_jitter_pos(Brush *brush, float *pos, float *jitterpos) } } -int brush_painter_paint(BrushPainter *painter, BrushFunc func, float *pos, double time, float pressure, void *user) +int brush_painter_paint(BrushPainter *painter, BrushFunc func, float *pos, double time, float pressure, void *user, int use_color_correction) { Brush *brush= painter->brush; int totpaintops= 0; @@ -970,7 +973,7 @@ int brush_painter_paint(BrushPainter *painter, BrushFunc func, float *pos, doubl brush_apply_pressure(painter, brush, pressure); if (painter->cache.enabled) - brush_painter_refresh_cache(painter, pos); + brush_painter_refresh_cache(painter, pos, use_color_correction); totpaintops += func(user, painter->cache.ibuf, pos, pos); painter->lasttime= time; @@ -1043,7 +1046,7 @@ int brush_painter_paint(BrushPainter *painter, BrushFunc func, float *pos, doubl brush_jitter_pos(brush, paintpos, finalpos); if (painter->cache.enabled) - brush_painter_refresh_cache(painter, finalpos); + brush_painter_refresh_cache(painter, finalpos, use_color_correction); totpaintops += func(user, painter->cache.ibuf, painter->lastpaintpos, finalpos); @@ -1057,7 +1060,7 @@ int brush_painter_paint(BrushPainter *painter, BrushFunc func, float *pos, doubl brush_jitter_pos(brush, pos, finalpos); if (painter->cache.enabled) - brush_painter_refresh_cache(painter, finalpos); + brush_painter_refresh_cache(painter, finalpos, use_color_correction); totpaintops += func(user, painter->cache.ibuf, pos, finalpos); @@ -1085,7 +1088,7 @@ int brush_painter_paint(BrushPainter *painter, BrushFunc func, float *pos, doubl brush_jitter_pos(brush, pos, finalpos); if (painter->cache.enabled) - brush_painter_refresh_cache(painter, finalpos); + brush_painter_refresh_cache(painter, finalpos, use_color_correction); totpaintops += func(user, painter->cache.ibuf, painter->lastmousepos, finalpos); diff --git a/source/blender/blenlib/BLI_math_vector.h b/source/blender/blenlib/BLI_math_vector.h index 5f26bff0ad9..decfa22c3e6 100644 --- a/source/blender/blenlib/BLI_math_vector.h +++ b/source/blender/blenlib/BLI_math_vector.h @@ -58,6 +58,8 @@ MINLINE void swap_v4_v4(float a[4], float b[4]); /********************************* Arithmetic ********************************/ +MINLINE void add_v3_fl(float r[3], float f); +MINLINE void add_v4_fl(float r[4], float f); MINLINE void add_v2_v2(float r[2], const float a[2]); MINLINE void add_v2_v2v2(float r[2], const float a[2], const float b[2]); MINLINE void add_v3_v3(float r[3], const float a[3]); diff --git a/source/blender/blenlib/BLI_utildefines.h b/source/blender/blenlib/BLI_utildefines.h index a376d048412..9af55601ff7 100644 --- a/source/blender/blenlib/BLI_utildefines.h +++ b/source/blender/blenlib/BLI_utildefines.h @@ -103,6 +103,12 @@ #define FTOCHAR(val) ((val)<=0.0f)? 0 : (((val)>(1.0f-0.5f/255.0f))? 255 : (char)((255.0f*(val))+0.5f)) #define FTOUSHORT(val) ((val >= 1.0f-0.5f/65535)? 65535: (val <= 0.0f)? 0: (unsigned short)(val*65535.0f + 0.5f)) +#define F3TOCHAR3(v2,v1) (v1)[0]=FTOCHAR((v2[0])); (v1)[1]=FTOCHAR((v2[1])); (v1)[2]=FTOCHAR((v2[2])) +#define F3TOCHAR4(v2,v1) { (v1)[0]=FTOCHAR((v2[0])); (v1)[1]=FTOCHAR((v2[1])); (v1)[2]=FTOCHAR((v2[2])); \ + (v1)[3]=FTOCHAR((v2[3])); (v1)[3] = 255; } +#define F4TOCHAR4(v2,v1) { (v1)[0]=FTOCHAR((v2[0])); (v1)[1]=FTOCHAR((v2[1])); (v1)[2]=FTOCHAR((v2[2])); \ + (v1)[3]=FTOCHAR((v2[3])); (v1)[3]=FTOCHAR((v2[3])); } + #define VECCOPY(v1,v2) {*(v1)= *(v2); *(v1+1)= *(v2+1); *(v1+2)= *(v2+2);} #define VECCOPY2D(v1,v2) {*(v1)= *(v2); *(v1+1)= *(v2+1);} diff --git a/source/blender/blenlib/intern/math_vector_inline.c b/source/blender/blenlib/intern/math_vector_inline.c index 9f6a8afe2d5..e2b7c770356 100644 --- a/source/blender/blenlib/intern/math_vector_inline.c +++ b/source/blender/blenlib/intern/math_vector_inline.c @@ -102,6 +102,21 @@ MINLINE void swap_v4_v4(float a[4], float b[4]) /********************************* Arithmetic ********************************/ +MINLINE void add_v3_fl(float r[3], float f) +{ + r[0] += f; + r[1] += f; + r[2] += f; +} + +MINLINE void add_v4_fl(float r[4], float f) +{ + r[0] += f; + r[1] += f; + r[2] += f; + r[3] += f; +} + MINLINE void add_v2_v2(float *r, const float *a) { r[0] += a[0]; diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c index d7e8d3be66f..83ba35a2e5c 100644 --- a/source/blender/editors/sculpt_paint/paint_image.c +++ b/source/blender/editors/sculpt_paint/paint_image.c @@ -3692,14 +3692,26 @@ static void do_projectpaint_draw(ProjPaintState *ps, ProjPixel *projPixel, float } } -static void do_projectpaint_draw_f(ProjPaintState *ps, ProjPixel *projPixel, float *rgba, float alpha, float mask) { +static void do_projectpaint_draw_f(ProjPaintState *ps, ProjPixel *projPixel, float *rgba, float alpha, float mask, int use_color_correction) { if (ps->is_texbrush) { - rgba[0] *= ps->brush->rgb[0]; - rgba[1] *= ps->brush->rgb[1]; - rgba[2] *= ps->brush->rgb[2]; + /* rgba already holds a texture result here from higher level function */ + float rgba_br[3]; + if(use_color_correction){ + srgb_to_linearrgb_v3_v3(rgba_br, ps->brush->rgb); + mul_v3_v3(rgba, rgba_br); + } + else{ + mul_v3_v3(rgba, ps->brush->rgb); + } } else { - VECCOPY(rgba, ps->brush->rgb); + if(use_color_correction){ + srgb_to_linearrgb_v3_v3(rgba, rgba); + } + else { + VECCOPY(rgba, ps->brush->rgb); + } + rgba[3] = 1.0; } if (ps->is_airbrush==0 && mask < 1.0f) { @@ -3736,6 +3748,7 @@ static void *do_projectpaint_thread(void *ph_v) float falloff; int bucket_index; int is_floatbuf = 0; + int use_color_correction = 0; const short tool = ps->tool; rctf bucket_bounds; @@ -3841,6 +3854,7 @@ static void *do_projectpaint_thread(void *ph_v) last_projIma->touch = 1; is_floatbuf = last_projIma->ibuf->rect_float ? 1 : 0; + use_color_correction = (last_projIma->ibuf->profile == IB_PROFILE_LINEAR_RGB) ? 1 : 0; } last_partial_redraw_cell = last_projIma->partRedrawRect + projPixel->bb_cell_index; @@ -3871,7 +3885,7 @@ static void *do_projectpaint_thread(void *ph_v) else do_projectpaint_smear(ps, projPixel, alpha, mask, smearArena, &smearPixels, co); break; default: - if (is_floatbuf) do_projectpaint_draw_f(ps, projPixel, rgba, alpha, mask); + if (is_floatbuf) do_projectpaint_draw_f(ps, projPixel, rgba, alpha, mask, use_color_correction); else do_projectpaint_draw(ps, projPixel, rgba, alpha, mask); break; } @@ -3987,7 +4001,7 @@ static int project_paint_sub_stroke(ProjPaintState *ps, BrushPainter *painter, c // we may want to use this later // brush_painter_require_imbuf(painter, ((ibuf->rect_float)? 1: 0), 0, 0); - if (brush_painter_paint(painter, project_paint_op, pos, time, pressure, ps)) { + if (brush_painter_paint(painter, project_paint_op, pos, time, pressure, ps, 0)) { return 1; } else return 0; @@ -4058,7 +4072,6 @@ static void imapaint_dirty_region(Image *ima, ImBuf *ibuf, int x, int y, int w, static void imapaint_image_update(SpaceImage *sima, Image *image, ImBuf *ibuf, short texpaint) { if(ibuf->rect_float) - /* TODO - should just update a portion from imapaintpartial! */ ibuf->userflags |= IB_RECT_INVALID; /* force recreate of char rect */ if(ibuf->mipmap[0]) @@ -4409,7 +4422,7 @@ static int imapaint_paint_sub_stroke(ImagePaintState *s, BrushPainter *painter, brush_painter_require_imbuf(painter, ((ibuf->rect_float)? 1: 0), 0, 0); - if (brush_painter_paint(painter, imapaint_paint_op, pos, time, pressure, s)) { + if (brush_painter_paint(painter, imapaint_paint_op, pos, time, pressure, s, ibuf->profile == IB_PROFILE_LINEAR_RGB)) { if (update) imapaint_image_update(s->sima, image, ibuf, texpaint); return 1; diff --git a/source/blender/gpu/intern/gpu_draw.c b/source/blender/gpu/intern/gpu_draw.c index 0e7df43bd34..7dfbc52819e 100644 --- a/source/blender/gpu/intern/gpu_draw.c +++ b/source/blender/gpu/intern/gpu_draw.c @@ -687,9 +687,25 @@ void GPU_paint_update_image(Image *ima, int x, int y, int w, int h, int mipmap) glGetIntegerv(GL_UNPACK_SKIP_PIXELS, &skip_pixels); glGetIntegerv(GL_UNPACK_SKIP_ROWS, &skip_rows); - if ((ibuf->rect==NULL) && ibuf->rect_float) - IMB_rect_from_float(ibuf); - + if (ibuf->rect_float){ + /*This case needs a whole new buffer*/ + if(ibuf->rect==NULL) { + IMB_rect_from_float(ibuf); + } + else { + /* Do partial drawing. 'buffer' holds only the changed part. Needed for color corrected result */ + float *buffer = (float *)MEM_mallocN(w*h*sizeof(float)*4, "temp_texpaint_float_buf"); + IMB_partial_rect_from_float(ibuf, buffer, x, y, w, h); + glBindTexture(GL_TEXTURE_2D, ima->bindcode); + glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h, GL_RGBA, + GL_FLOAT, buffer); + MEM_freeN(buffer); + if(ima->tpageflag & IMA_MIPMAP_COMPLETE) + ima->tpageflag &= ~IMA_MIPMAP_COMPLETE; + return; + } + } + glBindTexture(GL_TEXTURE_2D, ima->bindcode); glPixelStorei(GL_UNPACK_ROW_LENGTH, ibuf->x); diff --git a/source/blender/imbuf/IMB_imbuf.h b/source/blender/imbuf/IMB_imbuf.h index 1eefc58d4de..5d61452e149 100644 --- a/source/blender/imbuf/IMB_imbuf.h +++ b/source/blender/imbuf/IMB_imbuf.h @@ -327,7 +327,12 @@ int imb_get_anim_type(const char *name); */ void IMB_de_interlace(struct ImBuf *ibuf); void IMB_interlace(struct ImBuf *ibuf); + +/* create char buffer, color corrected if necessary, for ImBufs that lack one */ void IMB_rect_from_float(struct ImBuf *ibuf); +/* create char buffer for part of the image, color corrected if necessary, + Changed part will be stored in buffer. This is expected to be used for texture painting updates */ +void IMB_partial_rect_from_float(struct ImBuf *ibuf, float *buffer, int x, int y, int w, int h); void IMB_float_from_rect(struct ImBuf *ibuf); void IMB_float_from_rect_simple(struct ImBuf *ibuf); /* no profile conversion */ /* note, check that the conversion exists, only some are supported */ diff --git a/source/blender/imbuf/intern/divers.c b/source/blender/imbuf/intern/divers.c index 6b35d7df397..90ee2692cf0 100644 --- a/source/blender/imbuf/intern/divers.c +++ b/source/blender/imbuf/intern/divers.c @@ -197,6 +197,135 @@ void IMB_rect_from_float(struct ImBuf *ibuf) ibuf->userflags &= ~IB_RECT_INVALID; } + + +/* converts from linear float to sRGB byte for part of the texture, buffer will hold the changed part */ +void IMB_partial_rect_from_float(struct ImBuf *ibuf,float *buffer, int x, int y, int w, int h) +{ + /* indices to source and destination image pixels */ + float *srcFloatPxl; + unsigned char *dstBytePxl; + /* buffer index will fill buffer */ + float *bufferIndex; + + /* convenience pointers to start of image buffers */ + float *init_srcFloatPxl = (float *)ibuf->rect_float; + unsigned char *init_dstBytePxl = (unsigned char *) ibuf->rect; + + /* Dithering factor */ + float dither= ibuf->dither / 255.0f; + /* respective attributes of image */ + short profile= ibuf->profile; + int channels= ibuf->channels; + + int i, j; + + /* + if called -only- from GPU_paint_update_image this test will never fail + but leaving it here for better or worse + */ + if(init_srcFloatPxl==NULL || (buffer == NULL)){ + return; + } + if(init_dstBytePxl==NULL) { + imb_addrectImBuf(ibuf); + init_dstBytePxl = (unsigned char *) ibuf->rect; + } + if(channels==1) { + for (j = 0; j < h; j++){ + bufferIndex = buffer + w*j*4; + dstBytePxl = init_dstBytePxl + (ibuf->x*(y + j) + x)*4; + srcFloatPxl = init_srcFloatPxl + (ibuf->x*(y + j) + x); + for(i = 0; i < w; i++, dstBytePxl+=4, srcFloatPxl++, bufferIndex+=4) { + dstBytePxl[1]= dstBytePxl[2]= dstBytePxl[3]= dstBytePxl[0] = FTOCHAR(srcFloatPxl[0]); + bufferIndex[0] = bufferIndex[1] = bufferIndex[2] = bufferIndex[3] = srcFloatPxl[0]; + } + } + } + else if (profile == IB_PROFILE_LINEAR_RGB) { + if(channels == 3) { + for (j = 0; j < h; j++){ + bufferIndex = buffer + w*j*4; + dstBytePxl = init_dstBytePxl + (ibuf->x*(y + j) + x)*4; + srcFloatPxl = init_srcFloatPxl + (ibuf->x*(y + j) + x)*3; + for(i = 0; i < w; i++, dstBytePxl+=4, srcFloatPxl+=3, bufferIndex += 4) { + linearrgb_to_srgb_v3_v3(bufferIndex, srcFloatPxl); + F3TOCHAR4(bufferIndex, dstBytePxl); + bufferIndex[3]= 1.0; + } + } + } + else if (channels == 4) { + if (dither != 0.f) { + for (j = 0; j < h; j++){ + bufferIndex = buffer + w*j*4; + dstBytePxl = init_dstBytePxl + (ibuf->x*(y + j) + x)*4; + srcFloatPxl = init_srcFloatPxl + (ibuf->x*(y + j) + x)*4; + for(i = 0; i < w; i++, dstBytePxl+=4, srcFloatPxl+=4, bufferIndex+=4) { + const float d = (BLI_frand()-0.5f)*dither; + linearrgb_to_srgb_v3_v3(bufferIndex, srcFloatPxl); + bufferIndex[3] = srcFloatPxl[3]; + add_v4_fl(bufferIndex, d); + F4TOCHAR4(bufferIndex, dstBytePxl); + } + } + } else { + for (j = 0; j < h; j++){ + bufferIndex = buffer + w*j*4; + dstBytePxl = init_dstBytePxl + (ibuf->x*(y + j) + x)*4; + srcFloatPxl = init_srcFloatPxl + (ibuf->x*(y + j) + x)*4; + for(i = 0; i < w; i++, dstBytePxl+=4, srcFloatPxl+=4, bufferIndex+=4) { + linearrgb_to_srgb_v3_v3(bufferIndex, srcFloatPxl); + bufferIndex[3]= srcFloatPxl[3]; + F4TOCHAR4(bufferIndex, dstBytePxl); + } + } + } + } + } + else if(ELEM(profile, IB_PROFILE_NONE, IB_PROFILE_SRGB)) { + if(channels==3) { + for (j = 0; j < h; j++){ + bufferIndex = buffer + w*j*4; + dstBytePxl = init_dstBytePxl + (ibuf->x*(y + j) + x)*4; + srcFloatPxl = init_srcFloatPxl + (ibuf->x*(y + j) + x)*3; + for(i = 0; i < w; i++, dstBytePxl+=4, srcFloatPxl+=3, bufferIndex+=4) { + copy_v3_v3(bufferIndex, srcFloatPxl); + F3TOCHAR4(bufferIndex, dstBytePxl); + bufferIndex[3] = 1.0; + } + } + } + else { + if (dither != 0.f) { + for (j = 0; j < h; j++){ + bufferIndex = buffer + w*j*4; + dstBytePxl = init_dstBytePxl + (ibuf->x*(y + j) + x)*4; + srcFloatPxl = init_srcFloatPxl + (ibuf->x*(y + j) + x)*4; + for(i = 0; i < w; i++, dstBytePxl+=4, srcFloatPxl+=4, bufferIndex+=4) { + const float d = (BLI_frand()-0.5f)*dither; + copy_v4_v4(bufferIndex, srcFloatPxl); + add_v4_fl(bufferIndex,d); + F4TOCHAR4(bufferIndex, dstBytePxl); + } + } + } else { + for (j = 0; j < h; j++){ + bufferIndex = buffer + w*j*4; + dstBytePxl = init_dstBytePxl + (ibuf->x*(y + j) + x)*4; + srcFloatPxl = init_srcFloatPxl + (ibuf->x*(y + j) + x)*4; + for(i = 0; i < w; i++, dstBytePxl+=4, srcFloatPxl+=4, bufferIndex+=4) { + copy_v4_v4(bufferIndex, srcFloatPxl); + F4TOCHAR4(bufferIndex, dstBytePxl); + } + } + } + } + } + /* ensure user flag is reset */ + ibuf->userflags &= ~IB_RECT_INVALID; +} + static void imb_float_from_rect_nonlinear(struct ImBuf *ibuf, float *fbuf) { float *tof = fbuf; |