Blender V5.0
BKE_paint_bvh_pixels.hh
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2022 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#pragma once
10
11#include "BLI_array.hh"
12#include "BLI_math_vector.hh"
13#include "BLI_rect.h"
14#include "BLI_vector.hh"
15
16#include "DNA_image_types.h"
17
18#include "BKE_image.hh"
19#include "BKE_image_wrappers.hh"
20#include "BKE_paint_bvh.hh"
21
22#include "IMB_imbuf_types.hh"
23
25
47
61
68
69 struct {
70 bool dirty : 1;
72
73 /* Dirty region of the tile in image space. */
75
77
79 {
80 flags.dirty = false;
82 }
83
84 void mark_dirty(const PackedPixelRow &pixel_row)
85 {
86 int2 start_image_coord(pixel_row.start_image_coordinate.x, pixel_row.start_image_coordinate.y);
87 BLI_rcti_do_minmax_v(&dirty_region, start_image_coord);
88 BLI_rcti_do_minmax_v(&dirty_region, start_image_coord + int2(pixel_row.num_pixels + 1, 0));
89 flags.dirty = true;
90 }
91
93 {
95 flags.dirty = false;
96 }
97};
98
105
109struct NodeData {
110 struct {
111 bool dirty : 1;
113
117
119 {
120 flags.dirty = false;
121 }
122
124 {
125 for (UDIMTilePixels &tile : tiles) {
126 if (tile.tile_number == image_tile.get_tile_number()) {
127 return &tile;
128 }
129 }
130 return nullptr;
131 }
132
134 {
135 undo_regions.clear();
136 for (UDIMTilePixels &tile : tiles) {
137 if (tile.pixel_rows.is_empty()) {
138 continue;
139 }
140
141 rcti region;
142 BLI_rcti_init_minmax(&region);
143 for (PackedPixelRow &pixel_row : tile.pixel_rows) {
145 &region, int2(pixel_row.start_image_coordinate.x, pixel_row.start_image_coordinate.y));
146 BLI_rcti_do_minmax_v(&region,
147 int2(pixel_row.start_image_coordinate.x + pixel_row.num_pixels + 1,
148 pixel_row.start_image_coordinate.y + 1));
149 }
150 undo_regions.append(UDIMTileUndo(tile.tile_number, region));
151 }
152 }
153
154 void mark_region(Image &image, const image::ImageTileWrapper &image_tile, ImBuf &image_buffer)
155 {
156 UDIMTilePixels *tile = find_tile_data(image_tile);
157 if (tile && tile->flags.dirty) {
158 if (image_buffer.planes == 8) {
159 image_buffer.planes = 32;
161 }
162 else {
164 &image, image_tile.image_tile, &image_buffer, &tile->dirty_region);
165 }
166 tile->clear_dirty();
167 }
168 }
169
171 {
172 for (UDIMTilePixels &tile : tiles) {
173 if (tile.flags.dirty) {
174 r_dirty_tiles.append_non_duplicates(tile.tile_number);
175 }
176 }
177 }
178
180 {
181 tiles.clear();
182 uv_primitives.clear();
183 }
184
185 static void free_func(void *instance)
186 {
187 NodeData *node_data = static_cast<NodeData *>(instance);
188 MEM_delete(node_data);
189 }
190};
191
192/* -------------------------------------------------------------------- */
195
206
213
224
225 CopyPixelCommand() = default;
227 : destination(group.start_destination),
228 source_1(group.start_source_1),
229 source_2(),
230 mix_factor(0.0f)
231 {
232 }
233
234 template<typename T>
236 {
237 float4 source_color_1 = tile_buffer.read_pixel(source_1);
238 float4 source_color_2 = tile_buffer.read_pixel(source_2);
239 float4 destination_color = source_color_1 * (1.0f - mix_factor) + source_color_2 * mix_factor;
240 tile_buffer.write_pixel(destination, destination_color);
241 }
242
243 void apply(const DeltaCopyPixelCommand &item)
244 {
245 destination.x += 1;
248 mix_factor = float(item.mix_factor) / 255.0f;
249 }
250
252 {
253 return DeltaCopyPixelCommand(char2(next_command.source_1 - source_1),
254 char2(next_command.source_2 - next_command.source_1),
255 uint8_t(next_command.mix_factor * 255));
256 }
257
258 bool can_be_extended(const CopyPixelCommand &command) const
259 {
260 /* Can only extend sequential pixels. */
261 if (destination.x != command.destination.x - 1 || destination.y != command.destination.y) {
262 return false;
263 }
264
265 /* Can only extend when the delta between with the previous source fits in a single byte. */
266 int2 delta_source_1 = source_1 - command.source_1;
267 if (max_ii(UNPACK2(blender::math::abs(delta_source_1))) > 127) {
268 return false;
269 }
270 return true;
271 }
272};
273
278
280
281 void copy_pixels(ImBuf &tile_buffer, IndexRange group_range) const
282 {
283 if (tile_buffer.float_buffer.data) {
284 image::ImageBufferAccessor<float4> accessor(tile_buffer);
285 copy_pixels<float4>(accessor, group_range);
286 }
287 else {
288 image::ImageBufferAccessor<int> accessor(tile_buffer);
289 copy_pixels<int>(accessor, group_range);
290 }
291 }
292
294 {
295 int decoded_size = command_deltas.size() * sizeof(CopyPixelCommand);
296 int encoded_size = groups.size() * sizeof(CopyPixelGroup) +
297 command_deltas.size() * sizeof(DeltaCopyPixelCommand);
298 printf("Tile %d compression rate: %d->%d = %d%%\n",
300 decoded_size,
301 encoded_size,
302 int(100.0 * float(encoded_size) / float(decoded_size)));
303 }
304
305 private:
306 template<typename T>
307 void copy_pixels(image::ImageBufferAccessor<T> &image_buffer, IndexRange group_range) const
308 {
309 for (const int64_t group_index : group_range) {
310 const CopyPixelGroup &group = groups[group_index];
311 CopyPixelCommand copy_command(group);
314 {
315 copy_command.apply(item);
316 copy_command.mix_source_and_write_destination<T>(image_buffer);
317 }
318 }
319 }
320};
321
324
325 std::optional<std::reference_wrapper<CopyPixelTile>> find_tile(image::TileNumber tile_number)
326 {
327 for (CopyPixelTile &tile : tiles) {
328 if (tile.tile_number == tile_number) {
329 return tile;
330 }
331 }
332 return std::nullopt;
333 }
334
335 void clear()
336 {
337 tiles.clear();
338 }
339};
340
342
346struct PBVHData {
347 /* Per UVPRimitive contains the paint data. */
349
352
354 {
355 this->vert_tris = {};
356 }
357};
358
363
365 Image &image,
366 ImageUser &image_user,
367 image::TileNumber tile_number);
368
369} // namespace blender::bke::pbvh::pixels
void BKE_image_partial_update_mark_region(Image *image, const ImageTile *image_tile, const ImBuf *image_buffer, const rcti *updated_region)
Mark a region of the image to update.
void BKE_image_partial_update_mark_full_update(Image *image)
Mark the whole image to be updated.
A BVH for high poly meshes.
MINLINE int max_ii(int a, int b)
void BLI_rcti_init_minmax(struct rcti *rect)
Definition rct.cc:474
void BLI_rcti_do_minmax_v(struct rcti *rect, const int xy[2])
Definition rct.cc:486
unsigned short ushort
#define UNPACK2(a)
long long int int64_t
void append_non_duplicates(const T &value)
nullptr float
#define printf(...)
const ccl_global KernelWorkTile * tile
#define T
NodeData & node_data_get(blender::bke::pbvh::Node &node)
void mark_image_dirty(blender::bke::pbvh::Node &node, Image &image, ImageUser &image_user)
void copy_pixels(blender::bke::pbvh::Tree &pbvh, Image &image, ImageUser &image_user, image::TileNumber tile_number)
void collect_dirty_tiles(blender::bke::pbvh::Node &node, Vector< image::TileNumber > &r_dirty_tiles)
PBVHData & data_get(blender::bke::pbvh::Tree &pbvh)
T abs(const T &a)
blender::VecBase< int8_t, 2 > char2
VecBase< float, 4 > float4
VecBase< int32_t, 2 > int2
VecBase< float, 2 > float2
VecBase< uint16_t, 2 > ushort2
ImBufFloatBuffer float_buffer
unsigned char planes
void write_pixel(const int2 coordinate, float4 new_value)
float4 read_pixel(const int2 coordinate)
void mix_source_and_write_destination(image::ImageBufferAccessor< T > &tile_buffer) const
DeltaCopyPixelCommand encode_delta(const CopyPixelCommand &next_command) const
bool can_be_extended(const CopyPixelCommand &command) const
void apply(const DeltaCopyPixelCommand &item)
Vector< DeltaCopyPixelCommand > command_deltas
void copy_pixels(ImBuf &tile_buffer, IndexRange group_range) const
std::optional< std::reference_wrapper< CopyPixelTile > > find_tile(image::TileNumber tile_number)
DeltaCopyPixelCommand(char2 delta_source_1, char2 delta_source_2, uint8_t mix_factor)
void mark_region(Image &image, const image::ImageTileWrapper &image_tile, ImBuf &image_buffer)
UDIMTilePixels * find_tile_data(const image::ImageTileWrapper &image_tile)
struct blender::bke::pbvh::pixels::NodeData::@126372137103364156366300331140353251345266233066 flags
Vector< UVPrimitivePaintInput > uv_primitives
void collect_dirty_tiles(Vector< image::TileNumber > &r_dirty_tiles)
void mark_dirty(const PackedPixelRow &pixel_row)
struct blender::bke::pbvh::pixels::UDIMTilePixels::@213142071117224155011332260101117126053322200307 flags
UDIMTileUndo(short tile_number, rcti &region)