Blender V5.0
image_drawing_mode.hh
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2021 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#pragma once
10
11#include "IMB_imbuf_types.hh"
12#include "IMB_interp.hh"
13
16
17#include "image_batches.hh"
18#include "image_private.hh"
19
21
22namespace blender::image_engine {
23class Instance;
24
25constexpr float EPSILON_UV_BOUNDS = 0.00001f;
26
28 protected:
30
31 protected:
33
34 public:
38 virtual void ensure_texture_infos() = 0;
39
43 virtual void update_bounds(const ARegion *region) = 0;
44
46};
47
53 public:
55 void ensure_texture_infos() override
56 {
57 instance_data->texture_infos.resize(1);
58 }
59
60 void update_bounds(const ARegion *region) override
61 {
62 float4x4 mat = math::invert(float4x4(instance_data->ss_to_texture));
63 float2 region_uv_min = math::transform_point(mat, float3(0.0f, 0.0f, 0.0f)).xy();
64 float2 region_uv_max = math::transform_point(mat, float3(1.0f, 1.0f, 0.0f)).xy();
65
66 TextureInfo &texture_info = instance_data->texture_infos[0];
67 texture_info.tile_id = int2(0);
68 texture_info.need_full_update = false;
69 rctf new_clipping_uv_bounds;
70 BLI_rctf_init(&new_clipping_uv_bounds,
71 region_uv_min.x,
72 region_uv_max.x,
73 region_uv_min.y,
74 region_uv_max.y);
75
76 if (memcmp(&new_clipping_uv_bounds, &texture_info.clipping_uv_bounds, sizeof(rctf))) {
77 texture_info.clipping_uv_bounds = new_clipping_uv_bounds;
78 texture_info.need_full_update = true;
79 }
80
81 rcti new_clipping_bounds;
82 BLI_rcti_init(&new_clipping_bounds, 0, region->winx, 0, region->winy);
83 if (memcmp(&new_clipping_bounds, &texture_info.clipping_bounds, sizeof(rcti))) {
84 texture_info.clipping_bounds = new_clipping_bounds;
85 texture_info.need_full_update = true;
86 }
87 }
88
90 {
91 TextureInfo &texture_info = instance_data->texture_infos[0];
92 int2 texture_size = int2(BLI_rcti_size_x(&texture_info.clipping_bounds),
93 BLI_rcti_size_y(&texture_info.clipping_bounds));
94 texture_info.ensure_gpu_texture(texture_size);
95 }
96};
97
104template<size_t Divisions> class ScreenTileTextures : public BaseTextureMethod {
105 public:
106 static const size_t TexturesPerDimension = Divisions + 1;
109
110 private:
114 struct TextureInfoBounds {
115 TextureInfo *info = nullptr;
116 rctf uv_bounds;
117 /* Offset of this tile to be drawn on the screen (number of tiles from bottom left corner). */
118 int2 tile_id;
119 };
120
121 public:
123
127 void ensure_texture_infos() override
128 {
129 instance_data->texture_infos.resize(TexturesRequired);
130 }
131
135 void update_bounds(const ARegion *region) override
136 {
137 /* determine uv_area of the region. */
138 Vector<TextureInfo *> unassigned_textures;
139 float4x4 mat = math::invert(float4x4(instance_data->ss_to_texture));
140 float2 region_uv_min = math::transform_point(mat, float3(0.0f, 0.0f, 0.0f)).xy();
141 float2 region_uv_max = math::transform_point(mat, float3(1.0f, 1.0f, 0.0f)).xy();
142 float2 region_uv_span = region_uv_max - region_uv_min;
143
144 /* Calculate uv coordinates of each vert in the grid of textures. */
145
146 /* Construct the uv bounds of the 4 textures that are needed to fill the region. */
147 Vector<TextureInfoBounds> info_bounds = create_uv_bounds(region_uv_span, region_uv_min);
148 assign_texture_infos_by_uv_bounds(info_bounds, unassigned_textures);
149 assign_unused_texture_infos(info_bounds, unassigned_textures);
150
151 /* Calculate the region bounds from the uv bounds. */
152 rctf region_uv_bounds;
154 &region_uv_bounds, region_uv_min.x, region_uv_max.x, region_uv_min.y, region_uv_max.y);
155 update_region_bounds_from_uv_bounds(region_uv_bounds, int2(region->winx, region->winy));
156 }
157
162 {
163 float2 viewport_size = DRW_context_get()->viewport_size_get();
164 int2 texture_size(ceil(viewport_size.x / Divisions), ceil(viewport_size.y / Divisions));
165 return texture_size;
166 }
167
169 {
170 int2 texture_size = gpu_texture_size();
171 for (TextureInfo &info : instance_data->texture_infos) {
172 info.ensure_gpu_texture(texture_size);
173 }
174 }
175
176 private:
177 Vector<TextureInfoBounds> create_uv_bounds(float2 region_uv_span, float2 region_uv_min)
178 {
180 float2 region_tile_uv_span = region_uv_span / float2(float(Divisions));
181 float2 onscreen_multiple = (blender::math::floor(region_uv_min / region_tile_uv_span) +
182 float2(1.0f)) *
183 region_tile_uv_span;
184 for (int y = 0; y < VerticesPerDimension; y++) {
185 for (int x = 0; x < VerticesPerDimension; x++) {
186 uv_coords[x][y] = region_tile_uv_span * float2(float(x - 1), float(y - 1)) +
187 onscreen_multiple;
188 }
189 }
190
191 Vector<TextureInfoBounds> info_bounds;
192 for (int x = 0; x < TexturesPerDimension; x++) {
193 for (int y = 0; y < TexturesPerDimension; y++) {
194 TextureInfoBounds texture_info_bounds;
195 texture_info_bounds.tile_id = int2(x, y);
196 BLI_rctf_init(&texture_info_bounds.uv_bounds,
197 uv_coords[x][y].x,
198 uv_coords[x + 1][y + 1].x,
199 uv_coords[x][y].y,
200 uv_coords[x + 1][y + 1].y);
201 info_bounds.append(texture_info_bounds);
202 }
203 }
204 return info_bounds;
205 }
206
207 void assign_texture_infos_by_uv_bounds(Vector<TextureInfoBounds> &info_bounds,
208 Vector<TextureInfo *> &r_unassigned_textures)
209 {
210 for (TextureInfo &info : instance_data->texture_infos) {
211 bool assigned = false;
212 for (TextureInfoBounds &info_bound : info_bounds) {
213 if (info_bound.info == nullptr &&
214 BLI_rctf_compare(&info_bound.uv_bounds, &info.clipping_uv_bounds, 0.001))
215 {
216 info_bound.info = &info;
217 info.tile_id = info_bound.tile_id;
218 assigned = true;
219 break;
220 }
221 }
222 if (!assigned) {
223 r_unassigned_textures.append(&info);
224 }
225 }
226 }
227
228 void assign_unused_texture_infos(Vector<TextureInfoBounds> &info_bounds,
229 Vector<TextureInfo *> &unassigned_textures)
230 {
231 for (TextureInfoBounds &info_bound : info_bounds) {
232 if (info_bound.info == nullptr) {
233 info_bound.info = unassigned_textures.pop_last();
234 info_bound.info->tile_id = info_bound.tile_id;
235 info_bound.info->need_full_update = true;
236 info_bound.info->clipping_uv_bounds = info_bound.uv_bounds;
237 }
238 }
239 }
240
241 void update_region_bounds_from_uv_bounds(const rctf &region_uv_bounds, const int2 region_size)
242 {
243 rctf region_bounds;
244 BLI_rctf_init(&region_bounds, 0.0, region_size.x, 0.0, region_size.y);
245 float4x4 uv_to_screen;
246 BLI_rctf_transform_calc_m4_pivot_min(&region_uv_bounds, &region_bounds, uv_to_screen.ptr());
247 int2 tile_origin(0);
248 for (const TextureInfo &info : instance_data->texture_infos) {
249 if (info.tile_id == int2(0)) {
250 tile_origin = int2(math::transform_point(
251 uv_to_screen,
252 float3(info.clipping_uv_bounds.xmin, info.clipping_uv_bounds.ymin, 0.0)));
253 break;
254 }
255 }
256
257 const int2 texture_size = gpu_texture_size();
258 for (TextureInfo &info : instance_data->texture_infos) {
259 int2 bottom_left = tile_origin + texture_size * info.tile_id;
260 int2 top_right = bottom_left + texture_size;
261 BLI_rcti_init(&info.clipping_bounds, bottom_left.x, top_right.x, bottom_left.y, top_right.y);
262 }
263 }
264};
265
266using namespace blender::bke::image::partial_update;
267using namespace blender::bke::image;
268
270 private:
271 Instance &instance_;
272
273 public:
274 ScreenSpaceDrawingMode(Instance &instance) : instance_(instance) {}
275
276 private:
277 void add_shgroups() const;
278
284 void add_depth_shgroups(::Image *image, ::ImageUser *image_user) const;
285
292 void update_textures(::Image *image, ::ImageUser *image_user) const;
293
297 void do_partial_update_float_buffer(
300 void do_full_update_for_dirty_textures(const ::ImageUser *image_user) const;
301 void do_full_update_gpu_texture(TextureInfo &info, const ::ImageUser *image_user) const;
306 void do_full_update_texture_slot(const TextureInfo &texture_info,
307 ImBuf &texture_buffer,
308 ImBuf &tile_buffer,
309 const ImageTileWrapper &image_tile) const;
310
311 public:
312 void begin_sync() const override;
313 void image_sync(::Image *image, ::ImageUser *iuser) const override;
314 void draw_finish() const override;
315 void draw_viewport() const override;
316};
317
318} // namespace blender::image_engine
BLI_INLINE int BLI_rcti_size_y(const struct rcti *rct)
Definition BLI_rect.h:198
void BLI_rcti_init(struct rcti *rect, int xmin, int xmax, int ymin, int ymax)
Definition rct.cc:414
void BLI_rctf_transform_calc_m4_pivot_min(const rctf *dst, const rctf *src, float matrix[4][4])
Definition rct.cc:551
void BLI_rctf_init(struct rctf *rect, float xmin, float xmax, float ymin, float ymax)
Definition rct.cc:404
BLI_INLINE int BLI_rcti_size_x(const struct rcti *rct)
Definition BLI_rect.h:194
bool BLI_rctf_compare(const struct rctf *rect_a, const struct rctf *rect_b, float limit)
struct rctf rctf
T pop_last()
void append(const T &value)
A running instance of the engine.
virtual void update_bounds(const ARegion *region)=0
Update the uv and region bounds of all texture_infos of instance_data.
virtual void ensure_texture_infos()=0
Ensure enough texture infos are allocated in instance_data.
void update_bounds(const ARegion *region) override
Update the uv and region bounds of all texture_infos of instance_data.
void ensure_texture_infos() override
Ensure enough texture infos are allocated in instance_data.
void image_sync(::Image *image, ::ImageUser *iuser) const override
void ensure_texture_infos() override
Ensure enough texture infos are allocated in instance_data.
void update_bounds(const ARegion *region) override
Update the uv and region bounds of all texture_infos of instance_data.
const DRWContext * DRW_context_get()
#define ceil
constexpr float EPSILON_UV_BOUNDS
T floor(const T &a)
CartesianBasis invert(const CartesianBasis &basis)
T ceil(const T &a)
VecBase< T, 3 > transform_point(const CartesianBasis &basis, const VecBase< T, 3 > &v)
MatBase< float, 4, 4 > float4x4
VecBase< int32_t, 2 > int2
VecBase< float, 2 > float2
VecBase< float, 3 > float3
blender::float2 viewport_size_get() const
const c_style_mat & ptr() const
VecBase< T, 2 > xy() const
rctf clipping_uv_bounds
uv area of the texture in screen space.
rcti clipping_bounds
area of the texture in screen space.
void ensure_gpu_texture(int2 texture_size)
bool need_full_update
does this texture need a full update.