Changeset View
Changeset View
Standalone View
Standalone View
source/blender/editors/sculpt_paint/paint_image_2d.c
| Show First 20 Lines • Show All 184 Lines • ▼ Show 20 Lines | static void brush_painter_cache_2d_free(BrushPainterCache *cache) | ||||
| if (cache->tex_mask) { | if (cache->tex_mask) { | ||||
| MEM_freeN(cache->tex_mask); | MEM_freeN(cache->tex_mask); | ||||
| } | } | ||||
| if (cache->tex_mask_old) { | if (cache->tex_mask_old) { | ||||
| MEM_freeN(cache->tex_mask_old); | MEM_freeN(cache->tex_mask_old); | ||||
| } | } | ||||
| } | } | ||||
| static void brush_imbuf_tex_co(rctf *mapping, int x, int y, float texco[3]) | static void brush_imbuf_tex_co(const rctf *mapping, int x, int y, float texco[3]) | ||||
| { | { | ||||
| texco[0] = mapping->xmin + x * mapping->xmax; | texco[0] = mapping->xmin + x * mapping->xmax; | ||||
| texco[1] = mapping->ymin + y * mapping->ymax; | texco[1] = mapping->ymin + y * mapping->ymax; | ||||
| texco[2] = 0.0f; | texco[2] = 0.0f; | ||||
| } | } | ||||
| /* create a mask with the mask texture */ | static void brush_painter_tex_mask_fill(const BrushPainter *painter, | ||||
| static ushort *brush_painter_mask_ibuf_new(BrushPainter *painter, const int size) | float *mask, | ||||
| const int x1, | |||||
| const int y1, | |||||
| const int x2, | |||||
| const int y2) | |||||
| { | { | ||||
| Scene *scene = painter->scene; | const Scene *scene = painter->scene; | ||||
| Brush *brush = painter->brush; | const Brush *brush = painter->brush; | ||||
| rctf mask_mapping = painter->mask_mapping; | const int thread = 0; | ||||
| const rctf mask_mapping = painter->mask_mapping; | |||||
| struct ImagePool *pool = painter->pool; | struct ImagePool *pool = painter->pool; | ||||
| float texco[3]; | const int w = (x2 - x1); | ||||
| ushort *mask, *m; | const int h = (y2 - y1); | ||||
| int x, y, thread = 0; | |||||
| mask = MEM_mallocN(sizeof(ushort) * size * size, "brush_painter_mask"); | float(*texco)[3] = MEM_mallocN(sizeof(float) * 3 * w * h, "brush mask texco"); | ||||
| m = mask; | |||||
| for (y = 0; y < size; y++) { | for (int y = 0; y < h; y++) { | ||||
| for (x = 0; x < size; x++, m++) { | for (int x = 0; x < w; x++) { | ||||
| float res; | brush_imbuf_tex_co(&mask_mapping, x1 + x, y1 + y, texco[y * w + x]); | ||||
| brush_imbuf_tex_co(&mask_mapping, x, y, texco); | |||||
| res = BKE_brush_sample_masktex(scene, brush, texco, thread, pool); | |||||
| *m = (ushort)(65535.0f * res); | |||||
| } | } | ||||
| } | } | ||||
| return mask; | BKE_brush_sample_tex_mask(scene, brush, w * h, texco, mask, thread, pool); | ||||
| MEM_freeN(texco); | |||||
| } | } | ||||
| /* update rectangular section of the brush image */ | static void brush_painter_tex_mask_fill_strided(const BrushPainter *painter, | ||||
| static void brush_painter_mask_imbuf_update(BrushPainter *painter, | ushort *umask, | ||||
| ImagePaintTile *tile, | const int x1, | ||||
| const ushort *tex_mask_old, | const int y1, | ||||
| int origx, | const int x2, | ||||
| int origy, | const int y2, | ||||
| int w, | const int stride) | ||||
| int h, | |||||
| int xt, | |||||
| int yt, | |||||
| const int diameter) | |||||
| { | { | ||||
| Scene *scene = painter->scene; | const int w = (x2 - x1); | ||||
| Brush *brush = painter->brush; | const int h = (y2 - y1); | ||||
| BrushPainterCache *cache = &tile->cache; | |||||
| rctf tex_mapping = painter->mask_mapping; | float *mask = MEM_mallocN(sizeof(float) * w * h, "brush mask"); | ||||
| struct ImagePool *pool = painter->pool; | brush_painter_tex_mask_fill(painter, mask, x1, y1, x2, y2); | ||||
| ushort res; | |||||
| for (int y = 0; y < h; y++) { | |||||
| for (int x = 0; x < w; x++) { | |||||
| umask[(y + y1) * stride + (x + x1)] = (ushort)(65535.0f * mask[y * w + x]); | |||||
| } | |||||
| } | |||||
| bool use_texture_old = (tex_mask_old != NULL); | MEM_freeN(mask); | ||||
| } | |||||
| int x, y, thread = 0; | static void brush_painter_tex_rgba_fill(const BrushPainter *painter, | ||||
| float (*rgba)[4], | |||||
| const int x1, | |||||
| const int y1, | |||||
| const int x2, | |||||
| const int y2) | |||||
| { | |||||
| const Scene *scene = painter->scene; | |||||
| const Brush *brush = painter->brush; | |||||
| const int thread = 0; | |||||
| const rctf tex_mapping = painter->tex_mapping; | |||||
| struct ImagePool *pool = painter->pool; | |||||
| ushort *tex_mask = cache->tex_mask; | const int w = (x2 - x1); | ||||
| ushort *tex_mask_cur = cache->tex_mask_old; | const int h = (y2 - y1); | ||||
| /* fill pixels */ | float(*texco)[3] = MEM_mallocN(sizeof(float) * 3 * w * h, "brush mask texco"); | ||||
| for (y = origy; y < h; y++) { | |||||
| for (x = origx; x < w; x++) { | |||||
| /* sample texture */ | |||||
| float texco[3]; | |||||
| /* handle byte pixel */ | for (int y = 0; y < h; y++) { | ||||
| ushort *b = tex_mask + (y * diameter + x); | for (int x = 0; x < w; x++) { | ||||
| ushort *t = tex_mask_cur + (y * diameter + x); | brush_imbuf_tex_co(&tex_mapping, x1 + x, y1 + y, texco[y * w + x]); | ||||
| } | |||||
| } | |||||
| if (!use_texture_old) { | BKE_brush_sample_tex_rgba(scene, brush, w * h, texco, rgba, thread, pool); | ||||
| brush_imbuf_tex_co(&tex_mapping, x, y, texco); | |||||
| res = (ushort)(65535.0f * BKE_brush_sample_masktex(scene, brush, texco, thread, pool)); | |||||
| } | } | ||||
| /* read from old texture buffer */ | /* create a mask with the mask texture */ | ||||
| if (use_texture_old) { | static ushort *brush_painter_mask_ibuf_new(const BrushPainter *painter, const int size) | ||||
| res = *(tex_mask_old + ((y - origy + yt) * cache->tex_mask_old_w + (x - origx + xt))); | { | ||||
| ushort *umask = MEM_mallocN(sizeof(umask) * size * size, "brush ushort mask"); | |||||
| brush_painter_tex_mask_fill_strided(painter, umask, 0, 0, size, size, size); | |||||
| return umask; | |||||
| } | } | ||||
| /* write to new texture mask */ | /* update rectangular section of the brush image */ | ||||
| *t = res; | static void brush_painter_mask_imbuf_update(const BrushPainter *painter, | ||||
| /* write to mask image buffer */ | ImagePaintTile *tile, | ||||
| *b = res; | const ushort *tex_mask_old, | ||||
| const int x1, | |||||
| const int y1, | |||||
| const int x2, | |||||
| const int y2, | |||||
| const int xt, | |||||
| const int yt, | |||||
| const int stride) | |||||
| { | |||||
| BrushPainterCache *cache = &tile->cache; | |||||
| ushort *tex_mask = cache->tex_mask; | |||||
| ushort *tex_mask_cur = cache->tex_mask_old; | |||||
| if (tex_mask_old != NULL) { | |||||
| /* Read from old texture buffer. */ | |||||
| for (int y = y1; y < y2; y++) { | |||||
| for (int x = x1; x < x2; x++) { | |||||
| ushort res = *(tex_mask_old + ((y - y1 + yt) * cache->tex_mask_old_w + (x - x1 + xt))); | |||||
| /* Write to new texture mask and mask image buffer. */ | |||||
| tex_mask[y * stride + x] = res; | |||||
| tex_mask_cur[y * stride + x] = res; | |||||
| } | |||||
| } | |||||
| } | |||||
| else { | |||||
| /* Evaluate mask texture, copy to both buffers. */ | |||||
| brush_painter_tex_mask_fill_strided(painter, tex_mask, x1, y1, x2, y2, stride); | |||||
| for (int y = y1; y < y2; y++) { | |||||
| for (int x = x1; x < x2; x++) { | |||||
| tex_mask_cur[y * stride + x] = tex_mask[y * stride + x]; | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /** | /** | ||||
| * Update the brush mask image by trying to reuse the cached texture result. | * Update the brush mask image by trying to reuse the cached texture result. | ||||
| * This can be considerably faster for brushes that change size due to pressure or | * This can be considerably faster for brushes that change size due to pressure or | ||||
| * textures that stick to the surface where only part of the pixels are new | * textures that stick to the surface where only part of the pixels are new | ||||
| ▲ Show 20 Lines • Show All 80 Lines • ▼ Show 20 Lines | |||||
| { | { | ||||
| Scene *scene = painter->scene; | Scene *scene = painter->scene; | ||||
| Brush *brush = painter->brush; | Brush *brush = painter->brush; | ||||
| BrushPainterCache *cache = &tile->cache; | BrushPainterCache *cache = &tile->cache; | ||||
| const char *display_device = scene->display_settings.display_device; | const char *display_device = scene->display_settings.display_device; | ||||
| struct ColorManagedDisplay *display = IMB_colormanagement_display_get_named(display_device); | struct ColorManagedDisplay *display = IMB_colormanagement_display_get_named(display_device); | ||||
| rctf tex_mapping = painter->tex_mapping; | |||||
| struct ImagePool *pool = painter->pool; | |||||
| bool use_color_correction = cache->use_color_correction; | bool use_color_correction = cache->use_color_correction; | ||||
| bool use_float = cache->use_float; | bool use_float = cache->use_float; | ||||
| bool is_texbrush = cache->is_texbrush; | bool is_texbrush = cache->is_texbrush; | ||||
| int x, y, thread = 0; | |||||
| float brush_rgb[3]; | float brush_rgb[3]; | ||||
| /* allocate image buffer */ | /* allocate image buffer */ | ||||
| ImBuf *ibuf = IMB_allocImBuf(size, size, 32, (use_float) ? IB_rectfloat : IB_rect); | ImBuf *ibuf = IMB_allocImBuf(size, size, 32, (use_float) ? IB_rectfloat : IB_rect); | ||||
| /* get brush color */ | /* get brush color */ | ||||
| if (brush->imagepaint_tool == PAINT_TOOL_DRAW) { | if (brush->imagepaint_tool == PAINT_TOOL_DRAW) { | ||||
| paint_brush_color_get( | paint_brush_color_get( | ||||
| scene, brush, use_color_correction, cache->invert, distance, pressure, brush_rgb, display); | scene, brush, use_color_correction, cache->invert, distance, pressure, brush_rgb, display); | ||||
| } | } | ||||
| else { | else { | ||||
| brush_rgb[0] = 1.0f; | brush_rgb[0] = 1.0f; | ||||
| brush_rgb[1] = 1.0f; | brush_rgb[1] = 1.0f; | ||||
| brush_rgb[2] = 1.0f; | brush_rgb[2] = 1.0f; | ||||
| } | } | ||||
| float(*tex_rgba)[4] = NULL; | |||||
| if (is_texbrush) { | |||||
| tex_rgba = MEM_mallocN(sizeof(float) * 4 * size * size, "brush tex rgba"); | |||||
| brush_painter_tex_rgba_fill(painter, tex_rgba, 0, 0, size, size); | |||||
| } | |||||
| /* fill image buffer */ | /* fill image buffer */ | ||||
| for (y = 0; y < size; y++) { | for (int y = 0; y < size; y++) { | ||||
| for (x = 0; x < size; x++) { | for (int x = 0; x < size; x++) { | ||||
| /* sample texture and multiply with brush color */ | /* sample texture and multiply with brush color */ | ||||
| float texco[3], rgba[4]; | float rgba[4]; | ||||
| if (is_texbrush) { | if (is_texbrush) { | ||||
| brush_imbuf_tex_co(&tex_mapping, x, y, texco); | copy_v4_v4(rgba, tex_rgba[y * size + x]); | ||||
| BKE_brush_sample_tex_3d(scene, brush, texco, rgba, thread, pool); | |||||
| /* TODO(sergey): Support texture paint color space. */ | /* TODO(sergey): Support texture paint color space. */ | ||||
| if (!use_float) { | if (!use_float) { | ||||
| IMB_colormanagement_scene_linear_to_display_v3(rgba, display); | IMB_colormanagement_scene_linear_to_display_v3(rgba, display); | ||||
| } | } | ||||
| mul_v3_v3(rgba, brush_rgb); | mul_v3_v3(rgba, brush_rgb); | ||||
| } | } | ||||
| else { | else { | ||||
| copy_v3_v3(rgba, brush_rgb); | copy_v3_v3(rgba, brush_rgb); | ||||
| Show All 11 Lines | for (int x = 0; x < size; x++) { | ||||
| uchar *dst = (uchar *)ibuf->rect + (y * size + x) * 4; | uchar *dst = (uchar *)ibuf->rect + (y * size + x) * 4; | ||||
| rgb_float_to_uchar(dst, rgba); | rgb_float_to_uchar(dst, rgba); | ||||
| dst[3] = unit_float_to_uchar_clamp(rgba[3]); | dst[3] = unit_float_to_uchar_clamp(rgba[3]); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| MEM_SAFE_FREE(tex_rgba); | |||||
| return ibuf; | return ibuf; | ||||
| } | } | ||||
| /* update rectangular section of the brush image */ | /* update rectangular section of the brush image */ | ||||
| static void brush_painter_imbuf_update(BrushPainter *painter, | static void brush_painter_imbuf_update(BrushPainter *painter, | ||||
| ImagePaintTile *tile, | ImagePaintTile *tile, | ||||
| ImBuf *oldtexibuf, | ImBuf *oldtexibuf, | ||||
| int origx, | const int x1, | ||||
| int origy, | const int y1, | ||||
| int w, | const int x2, | ||||
| int h, | const int y2, | ||||
| int xt, | const int xt, | ||||
| int yt) | const int yt) | ||||
| { | { | ||||
| Scene *scene = painter->scene; | Scene *scene = painter->scene; | ||||
| Brush *brush = painter->brush; | Brush *brush = painter->brush; | ||||
| BrushPainterCache *cache = &tile->cache; | BrushPainterCache *cache = &tile->cache; | ||||
| const char *display_device = scene->display_settings.display_device; | const char *display_device = scene->display_settings.display_device; | ||||
| struct ColorManagedDisplay *display = IMB_colormanagement_display_get_named(display_device); | struct ColorManagedDisplay *display = IMB_colormanagement_display_get_named(display_device); | ||||
| rctf tex_mapping = painter->tex_mapping; | |||||
| struct ImagePool *pool = painter->pool; | |||||
| bool use_color_correction = cache->use_color_correction; | bool use_color_correction = cache->use_color_correction; | ||||
| bool use_float = cache->use_float; | bool use_float = cache->use_float; | ||||
| bool is_texbrush = cache->is_texbrush; | bool is_texbrush = cache->is_texbrush; | ||||
| bool use_texture_old = (oldtexibuf != NULL); | bool use_texture_old = (oldtexibuf != NULL); | ||||
| int x, y, thread = 0; | |||||
| float brush_rgb[3]; | float brush_rgb[3]; | ||||
| ImBuf *ibuf = cache->ibuf; | ImBuf *ibuf = cache->ibuf; | ||||
| ImBuf *texibuf = cache->texibuf; | ImBuf *texibuf = cache->texibuf; | ||||
| /* get brush color */ | /* get brush color */ | ||||
| if (brush->imagepaint_tool == PAINT_TOOL_DRAW) { | if (brush->imagepaint_tool == PAINT_TOOL_DRAW) { | ||||
| paint_brush_color_get( | paint_brush_color_get( | ||||
| scene, brush, use_color_correction, cache->invert, 0.0f, 1.0f, brush_rgb, display); | scene, brush, use_color_correction, cache->invert, 0.0f, 1.0f, brush_rgb, display); | ||||
| } | } | ||||
| else { | else { | ||||
| brush_rgb[0] = 1.0f; | brush_rgb[0] = 1.0f; | ||||
| brush_rgb[1] = 1.0f; | brush_rgb[1] = 1.0f; | ||||
| brush_rgb[2] = 1.0f; | brush_rgb[2] = 1.0f; | ||||
| } | } | ||||
| float(*tex_rgba)[4] = NULL; | |||||
| if (is_texbrush) { | |||||
| tex_rgba = MEM_mallocN(sizeof(float) * 4 * (x2 - x1) * (y2 - y1), "brush tex rgba"); | |||||
| brush_painter_tex_rgba_fill(painter, tex_rgba, x1, y1, x2, y2); | |||||
| } | |||||
| /* fill pixels */ | /* fill pixels */ | ||||
| for (y = origy; y < h; y++) { | for (int y = y1; y < y2; y++) { | ||||
| for (x = origx; x < w; x++) { | for (int x = x1; x < x2; x++) { | ||||
| /* sample texture and multiply with brush color */ | /* sample texture and multiply with brush color */ | ||||
| float texco[3], rgba[4]; | float rgba[4]; | ||||
| if (!use_texture_old) { | if (!use_texture_old) { | ||||
| if (is_texbrush) { | if (is_texbrush) { | ||||
| brush_imbuf_tex_co(&tex_mapping, x, y, texco); | copy_v4_v4(rgba, tex_rgba[(y - y1) * (x2 - x1) + (x - x1)]); | ||||
| BKE_brush_sample_tex_3d(scene, brush, texco, rgba, thread, pool); | |||||
| /* TODO(sergey): Support texture paint color space. */ | /* TODO(sergey): Support texture paint color space. */ | ||||
| if (!use_float) { | if (!use_float) { | ||||
| IMB_colormanagement_scene_linear_to_display_v3(rgba, display); | IMB_colormanagement_scene_linear_to_display_v3(rgba, display); | ||||
| } | } | ||||
| mul_v3_v3(rgba, brush_rgb); | mul_v3_v3(rgba, brush_rgb); | ||||
| } | } | ||||
| else { | else { | ||||
| copy_v3_v3(rgba, brush_rgb); | copy_v3_v3(rgba, brush_rgb); | ||||
| rgba[3] = 1.0f; | rgba[3] = 1.0f; | ||||
| } | } | ||||
| } | } | ||||
| if (use_float) { | if (use_float) { | ||||
| /* handle float pixel */ | /* handle float pixel */ | ||||
| float *bf = ibuf->rect_float + (y * ibuf->x + x) * 4; | float *bf = ibuf->rect_float + (y * ibuf->x + x) * 4; | ||||
| float *tf = texibuf->rect_float + (y * texibuf->x + x) * 4; | float *tf = texibuf->rect_float + (y * texibuf->x + x) * 4; | ||||
| /* read from old texture buffer */ | /* read from old texture buffer */ | ||||
| if (use_texture_old) { | if (use_texture_old) { | ||||
| const float *otf = oldtexibuf->rect_float + | const float *otf = oldtexibuf->rect_float + | ||||
| ((y - origy + yt) * oldtexibuf->x + (x - origx + xt)) * 4; | ((y - y1 + yt) * oldtexibuf->x + (x - x1 + xt)) * 4; | ||||
| copy_v4_v4(rgba, otf); | copy_v4_v4(rgba, otf); | ||||
| } | } | ||||
| /* write to new texture buffer */ | /* write to new texture buffer */ | ||||
| copy_v4_v4(tf, rgba); | copy_v4_v4(tf, rgba); | ||||
| /* output premultiplied float image, mf was already premultiplied */ | /* output premultiplied float image, mf was already premultiplied */ | ||||
| mul_v3_v3fl(bf, rgba, rgba[3]); | mul_v3_v3fl(bf, rgba, rgba[3]); | ||||
| bf[3] = rgba[3]; | bf[3] = rgba[3]; | ||||
| } | } | ||||
| else { | else { | ||||
| uchar crgba[4]; | uchar crgba[4]; | ||||
| /* handle byte pixel */ | /* handle byte pixel */ | ||||
| uchar *b = (uchar *)ibuf->rect + (y * ibuf->x + x) * 4; | uchar *b = (uchar *)ibuf->rect + (y * ibuf->x + x) * 4; | ||||
| uchar *t = (uchar *)texibuf->rect + (y * texibuf->x + x) * 4; | uchar *t = (uchar *)texibuf->rect + (y * texibuf->x + x) * 4; | ||||
| /* read from old texture buffer */ | /* read from old texture buffer */ | ||||
| if (use_texture_old) { | if (use_texture_old) { | ||||
| uchar *ot = (uchar *)oldtexibuf->rect + | uchar *ot = (uchar *)oldtexibuf->rect + | ||||
| ((y - origy + yt) * oldtexibuf->x + (x - origx + xt)) * 4; | ((y - y1 + yt) * oldtexibuf->x + (x - x1 + xt)) * 4; | ||||
| crgba[0] = ot[0]; | crgba[0] = ot[0]; | ||||
| crgba[1] = ot[1]; | crgba[1] = ot[1]; | ||||
| crgba[2] = ot[2]; | crgba[2] = ot[2]; | ||||
| crgba[3] = ot[3]; | crgba[3] = ot[3]; | ||||
| } | } | ||||
| else { | else { | ||||
| rgba_float_to_uchar(crgba, rgba); | rgba_float_to_uchar(crgba, rgba); | ||||
| } | } | ||||
| /* write to new texture buffer */ | /* write to new texture buffer */ | ||||
| t[0] = crgba[0]; | t[0] = crgba[0]; | ||||
| t[1] = crgba[1]; | t[1] = crgba[1]; | ||||
| t[2] = crgba[2]; | t[2] = crgba[2]; | ||||
| t[3] = crgba[3]; | t[3] = crgba[3]; | ||||
| /* write to brush image buffer */ | /* write to brush image buffer */ | ||||
| b[0] = crgba[0]; | b[0] = crgba[0]; | ||||
| b[1] = crgba[1]; | b[1] = crgba[1]; | ||||
| b[2] = crgba[2]; | b[2] = crgba[2]; | ||||
| b[3] = crgba[3]; | b[3] = crgba[3]; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| MEM_SAFE_FREE(tex_rgba); | |||||
| } | } | ||||
| /* update the brush image by trying to reuse the cached texture result. this | /* update the brush image by trying to reuse the cached texture result. this | ||||
| * can be considerably faster for brushes that change size due to pressure or | * can be considerably faster for brushes that change size due to pressure or | ||||
| * textures that stick to the surface where only part of the pixels are new */ | * textures that stick to the surface where only part of the pixels are new */ | ||||
| static void brush_painter_imbuf_partial_update(BrushPainter *painter, | static void brush_painter_imbuf_partial_update(BrushPainter *painter, | ||||
| ImagePaintTile *tile, | ImagePaintTile *tile, | ||||
| const float pos[2], | const float pos[2], | ||||
| ▲ Show 20 Lines • Show All 1,539 Lines • Show Last 20 Lines | |||||