Blender V4.3
view2d_draw.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2008 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#include <algorithm>
10#include <cfloat>
11#include <climits>
12#include <cmath>
13#include <cstring>
14
15#include "MEM_guardedalloc.h"
16
17#include "DNA_scene_types.h"
18#include "DNA_userdef_types.h"
19
20#include "BLI_rect.h"
21#include "BLI_string.h"
22#include "BLI_timecode.h"
23#include "BLI_utildefines.h"
24#include "BLI_vector.hh"
25
26#include "GPU_immediate.hh"
27#include "GPU_matrix.hh"
28#include "GPU_state.hh"
29
30#include "WM_api.hh"
31
32#include "BLF_api.hh"
33
34#include "UI_interface.hh"
35#include "UI_view2d.hh"
36
37/* Compute display grid resolution
38 ********************************************************/
39
40#define MIN_MAJOR_LINE_DISTANCE (U.v2d_min_gridsize * UI_SCALE_FAC)
41
42static float select_major_distance(const float *possible_distances,
43 uint amount,
44 float pixel_width,
45 float view_width)
46{
47 BLI_assert(amount >= 1);
48
49 if (IS_EQF(view_width, 0.0f)) {
50 return possible_distances[0];
51 }
52
53 const float pixels_per_view_unit = pixel_width / view_width;
54
55 for (uint i = 0; i < amount; i++) {
56 const float distance = possible_distances[i];
57 if (pixels_per_view_unit * distance >= MIN_MAJOR_LINE_DISTANCE) {
58 return distance;
59 }
60 }
61 return possible_distances[amount - 1];
62}
63
64static const float discrete_value_scales[] = {
65 1, 2, 5, 10, 20, 50, 100, 200, 500, 1000, 2000, 5000, 10000, 20000, 50000, 100000};
66
67static const float continuous_value_scales[] = {0.01, 0.02, 0.05, 0.1, 0.2, 0.5, 1, 2,
68 5, 10, 20, 50, 100, 200, 500, 1000,
69 2000, 5000, 10000, 20000, 50000, 100000};
70
78
86
94
95static float view2d_major_step_x__time(const View2D *v2d, const Scene *scene)
96{
97 const double fps = FPS;
98
99 blender::Vector<float, 32> possible_distances;
100
101 for (int step = 1; step < fps; step *= 2) {
102 possible_distances.append(step);
103 }
104
105 for (int i = 0; i <= 5; i++) {
106 uint fac = pow(60, i);
107 possible_distances.append(fac * fps);
108 possible_distances.append(fac * 2 * fps);
109 possible_distances.append(fac * 5 * fps);
110 possible_distances.append(fac * 10 * fps);
111 possible_distances.append(fac * 30 * fps);
112 possible_distances.append(fac * 60 * fps);
113 }
114
115 float distance = select_major_distance(possible_distances.data(),
116 possible_distances.size(),
117 BLI_rcti_size_x(&v2d->mask),
118 BLI_rctf_size_x(&v2d->cur));
119
120 return distance;
121}
122
123/* Draw parallel lines
124 ************************************/
125
127 float offset;
128 float distance;
129};
130
132 float region_start,
133 float region_end,
134 float *r_first,
135 uint *r_steps)
136{
137 if (region_start >= region_end) {
138 *r_first = 0;
139 *r_steps = 0;
140 return;
141 }
142
143 BLI_assert(lines->distance > 0);
144 BLI_assert(region_start <= region_end);
145
146 *r_first = ceilf((region_start - lines->offset) / lines->distance) * lines->distance +
147 lines->offset;
148
149 if (region_start <= *r_first && region_end >= *r_first) {
150 *r_steps = std::max(0.0f, floorf((region_end - *r_first) / lines->distance)) + 1;
151 }
152 else {
153 *r_steps = 0;
154 }
155}
156
160static void draw_parallel_lines(const ParallelLinesSet *lines,
161 const rctf *rect,
162 const rcti *rect_mask,
163 const uchar color[3],
164 char direction)
165{
166 float first;
167 uint steps, steps_max;
168
169 if (direction == 'v') {
170 get_parallel_lines_draw_steps(lines, rect->xmin, rect->xmax, &first, &steps);
171 steps_max = BLI_rcti_size_x(rect_mask);
172 }
173 else {
174 BLI_assert(direction == 'h');
175 get_parallel_lines_draw_steps(lines, rect->ymin, rect->ymax, &first, &steps);
176 steps_max = BLI_rcti_size_y(rect_mask);
177 }
178
179 if (steps == 0) {
180 return;
181 }
182
183 if (UNLIKELY(steps >= steps_max)) {
184 /* Note that we could draw a solid color,
185 * however this flickers because of numeric instability when zoomed out. */
186 return;
187 }
188
191
192 if (U.pixelsize > 1.0f) {
193 float viewport[4];
194 GPU_viewport_size_get_f(viewport);
195
197 immUniform2fv("viewportSize", &viewport[2]);
198 /* -1.0f offset here is because the line is too fat due to the builtin anti-aliasing.
199 * TODO: make a variant or a uniform to toggle it off. */
200 immUniform1f("lineWidth", U.pixelsize - 1.0f);
201 }
202 else {
204 }
205 immUniformColor3ubv(color);
207
208 if (direction == 'v') {
209 for (uint i = 0; i < steps; i++) {
210 const float xpos = first + i * lines->distance;
211 immVertex2f(pos, xpos, rect->ymin);
212 immVertex2f(pos, xpos, rect->ymax);
213 }
214 }
215 else {
216 for (uint i = 0; i < steps; i++) {
217 const float ypos = first + i * lines->distance;
218 immVertex2f(pos, rect->xmin, ypos);
219 immVertex2f(pos, rect->xmax, ypos);
220 }
221 }
222
223 immEnd();
225}
226
227static void view2d_draw_lines_internal(const View2D *v2d,
228 const ParallelLinesSet *lines,
229 const uchar color[3],
230 char direction)
231{
234 draw_parallel_lines(lines, &v2d->cur, &v2d->mask, color, direction);
236}
237
238static void view2d_draw_lines(const View2D *v2d,
239 float major_distance,
240 bool display_minor_lines,
241 char direction)
242{
243 {
244 uchar major_color[3];
245 UI_GetThemeColor3ubv(TH_GRID, major_color);
246 ParallelLinesSet major_lines;
247 major_lines.distance = major_distance;
248 major_lines.offset = 0;
249 view2d_draw_lines_internal(v2d, &major_lines, major_color, direction);
250 }
251
252 if (display_minor_lines) {
253 uchar minor_color[3];
254 UI_GetThemeColorShade3ubv(TH_GRID, 16, minor_color);
255 ParallelLinesSet minor_lines;
256 minor_lines.distance = major_distance;
257 minor_lines.offset = major_distance / 2.0f;
258 view2d_draw_lines_internal(v2d, &minor_lines, minor_color, direction);
259 }
260}
261
262/* Scale indicator text drawing
263 **************************************************/
264
266 void (*)(void *user_data, float v2d_pos, float v2d_step, char *r_str, uint str_maxncpy);
267
269 const View2D *v2d,
270 float distance,
271 const rcti *rect,
272 PositionToString to_string,
273 void *to_string_data,
274 int colorid)
275{
276 if (UI_view2d_scale_get_x(v2d) <= 0.0f) {
277 return;
278 }
279
280 float start;
281 uint steps;
282 {
283 ParallelLinesSet lines;
284 lines.distance = distance;
285 lines.offset = 0;
289 &start,
290 &steps);
291 const uint steps_max = BLI_rcti_size_x(&v2d->mask);
292 if (UNLIKELY(steps >= steps_max)) {
293 return;
294 }
295 }
296
299
300 const int font_id = BLF_default();
301 UI_FontThemeColor(font_id, colorid);
302
304
305 const float ypos = rect->ymin + 4 * UI_SCALE_FAC;
306 const float xmin = rect->xmin;
307 const float xmax = rect->xmax;
308
309 char text[32];
310
311 /* Calculate max_label_count and draw_frequency based on largest visible label. */
312 int draw_frequency;
313 {
314 to_string(to_string_data, start, 0, text, sizeof(text));
315 const float left_text_width = BLF_width(font_id, text, strlen(text));
316 to_string(to_string_data, start + steps * distance, 0, text, sizeof(text));
317 const float right_text_width = BLF_width(font_id, text, strlen(text));
318 const float max_text_width = max_ff(left_text_width, right_text_width);
319 const float max_label_count = BLI_rcti_size_x(&v2d->mask) / (max_text_width + 10.0f);
320 draw_frequency = ceil(float(steps) / max_label_count);
321 }
322
323 if (draw_frequency != 0) {
324 const int start_index = abs(int(start / distance)) % draw_frequency;
325 for (uint i = start_index; i < steps; i += draw_frequency) {
326 const float xpos_view = start + i * distance;
327 const float xpos_region = UI_view2d_view_to_region_x(v2d, xpos_view);
328 to_string(to_string_data, xpos_view, distance, text, sizeof(text));
329 const float text_width = BLF_width(font_id, text, strlen(text));
330
331 if (xpos_region - text_width / 2.0f >= xmin && xpos_region + text_width / 2.0f <= xmax) {
332 BLF_draw_default(xpos_region - text_width / 2.0f, ypos, 0.0f, text, sizeof(text));
333 }
334 }
335 }
336
339}
340
341static void draw_vertical_scale_indicators(const ARegion *region,
342 const View2D *v2d,
343 float distance,
344 float display_offset,
345 const rcti *rect,
346 PositionToString to_string,
347 void *to_string_data,
348 int colorid)
349{
350 if (UI_view2d_scale_get_y(v2d) <= 0.0f) {
351 return;
352 }
353
354 float start;
355 uint steps;
356 {
357 ParallelLinesSet lines;
358 lines.distance = distance;
359 lines.offset = 0;
363 &start,
364 &steps);
365 const uint steps_max = BLI_rcti_size_y(&v2d->mask);
366 if (UNLIKELY(steps >= steps_max)) {
367 return;
368 }
369 }
370
373
374 const int font_id = BLF_default();
375 UI_FontThemeColor(font_id, colorid);
376
378
379 BLF_enable(font_id, BLF_SHADOW);
380 float shadow_color[4];
381 UI_GetThemeColor4fv(TH_BACK, shadow_color);
382 BLF_shadow_offset(font_id, 0, 0);
383 BLF_shadow(font_id, FontShadowType::Outline, shadow_color);
384
385 const float x_offset = 8.0f;
386 const float xpos = (rect->xmin + x_offset) * UI_SCALE_FAC;
387 const float ymin = rect->ymin;
388 const float ymax = rect->ymax;
389 const float y_offset = (BLF_height(font_id, "0", 1) / 2.0f) - U.pixelsize;
390
391 for (uint i = 0; i < steps; i++) {
392 const float ypos_view = start + i * distance;
393 const float ypos_region = UI_view2d_view_to_region_y(v2d, ypos_view + display_offset);
394 char text[32];
395 to_string(to_string_data, ypos_view, distance, text, sizeof(text));
396
397 if (ypos_region - y_offset >= ymin && ypos_region + y_offset <= ymax) {
398 BLF_draw_default(xpos, ypos_region - y_offset, 0.0f, text, sizeof(text));
399 }
400 }
401
402 BLF_disable(font_id, BLF_SHADOW);
403
405
407}
408
410 void * /*user_data*/, float v2d_pos, float /*v2d_step*/, char *r_str, uint str_maxncpy)
411{
412 BLI_snprintf(r_str, str_maxncpy, "%d", int(v2d_pos));
413}
414
416 void *user_data, float v2d_pos, float v2d_step, char *r_str, uint str_maxncpy)
417{
418 const Scene *scene = (const Scene *)user_data;
419
420 int brevity_level = -1;
421 if (U.timecode_style == USER_TIMECODE_MINIMAL && v2d_step >= FPS) {
422 brevity_level = 1;
423 }
424
426 r_str, str_maxncpy, brevity_level, v2d_pos / float(FPS), FPS, U.timecode_style);
427}
428
430 void * /*user_data*/, float v2d_pos, float v2d_step, char *r_str, uint str_maxncpy)
431{
432 if (v2d_step >= 1.0f) {
433 BLI_snprintf(r_str, str_maxncpy, "%d", int(v2d_pos));
434 }
435 else if (v2d_step >= 0.1f) {
436 BLI_snprintf(r_str, str_maxncpy, "%.1f", v2d_pos);
437 }
438 else if (v2d_step >= 0.01f) {
439 BLI_snprintf(r_str, str_maxncpy, "%.2f", v2d_pos);
440 }
441 else {
442 BLI_snprintf(r_str, str_maxncpy, "%.3f", v2d_pos);
443 }
444}
445
446/* Grid Resolution API
447 **************************************************/
448
450 const Scene *scene,
451 bool display_seconds)
452{
453 if (display_seconds) {
454 return view2d_major_step_x__time(v2d, scene);
455 }
457}
458
463
464/* Line Drawing API
465 **************************************************/
466
467void UI_view2d_draw_lines_x__discrete_values(const View2D *v2d, bool display_minor_lines)
468{
469 const uint major_line_distance = view2d_major_step_x__discrete(v2d);
471 v2d, major_line_distance, display_minor_lines && (major_line_distance > 1), 'v');
472}
473
475{
476 const float major_line_distance = view2d_major_step_x__continuous(v2d);
477 view2d_draw_lines(v2d, major_line_distance, true, 'v');
478}
479
481{
482 const float major_line_distance = view2d_major_step_y__continuous(v2d);
483 view2d_draw_lines(v2d, major_line_distance, true, 'h');
484}
485
487 const Scene *scene,
488 bool display_minor_lines)
489{
490 const float major_line_distance = view2d_major_step_x__time(v2d, scene);
492 v2d, major_line_distance, display_minor_lines && (major_line_distance > 1), 'v');
493}
494
496 const Scene *scene,
497 bool display_seconds,
498 bool display_minor_lines)
499{
500 if (display_seconds) {
501 UI_view2d_draw_lines_x__discrete_time(v2d, scene, display_minor_lines);
502 }
503 else {
504 UI_view2d_draw_lines_x__discrete_values(v2d, display_minor_lines);
505 }
506}
507
509 const Scene *scene,
510 bool display_seconds)
511{
512 if (display_seconds) {
514 }
515 else {
517 }
518}
519
520/* Scale indicator text drawing API
521 **************************************************/
522
524 const View2D *v2d,
525 const rcti *rect,
526 int colorid)
527{
528 const float number_step = view2d_major_step_x__discrete(v2d);
530 region, v2d, number_step, rect, view_to_string__frame_number, nullptr, colorid);
531}
532
534 const ARegion *region, const View2D *v2d, const rcti *rect, const Scene *scene, int colorid)
535{
536 const float step = view2d_major_step_x__time(v2d, scene);
538 region, v2d, step, rect, view_to_string__time, (void *)scene, colorid);
539}
540
541static void UI_view2d_draw_scale_x__values(const ARegion *region,
542 const View2D *v2d,
543 const rcti *rect,
544 int colorid)
545{
546 const float step = view2d_major_step_x__continuous(v2d);
548 region, v2d, step, rect, view_to_string__value, nullptr, colorid);
549}
550
552 const View2D *v2d,
553 const rcti *rect,
554 int colorid)
555{
556 const float step = view2d_major_step_y__continuous(v2d);
558 region, v2d, step, 0.0f, rect, view_to_string__value, nullptr, colorid);
559}
560
562 const View2D *v2d,
563 const rcti *rect,
564 int colorid)
565{
567 region, v2d, 1.0f, 0.5f, rect, view_to_string__value, nullptr, colorid);
568}
569
571 const View2D *v2d,
572 const rcti *rect,
573 const Scene *scene,
574 bool display_seconds,
575 int colorid)
576{
577 if (display_seconds) {
578 UI_view2d_draw_scale_x__discrete_time(region, v2d, rect, scene, colorid);
579 }
580 else {
581 UI_view2d_draw_scale_x__discrete_values(region, v2d, rect, colorid);
582 }
583}
584
586 const View2D *v2d,
587 const rcti *rect,
588 const Scene *scene,
589 bool display_seconds,
590 int colorid)
591{
592 if (display_seconds) {
593 UI_view2d_draw_scale_x__discrete_time(region, v2d, rect, scene, colorid);
594 }
595 else {
596 UI_view2d_draw_scale_x__values(region, v2d, rect, colorid);
597 }
598}
void BLF_shadow(int fontid, FontShadowType type, const float rgba[4]=nullptr)
Definition blf.cc:902
float BLF_height(int fontid, const char *str, size_t str_len, ResultBLF *r_info=nullptr) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(2)
Definition blf.cc:815
void BLF_shadow_offset(int fontid, int x, int y)
Definition blf.cc:914
void BLF_batch_draw_begin()
Definition blf.cc:517
void BLF_disable(int fontid, int option)
Definition blf.cc:321
int BLF_default()
void BLF_batch_draw_end()
Definition blf.cc:530
void BLF_enable(int fontid, int option)
Definition blf.cc:312
float BLF_width(int fontid, const char *str, size_t str_len, ResultBLF *r_info=nullptr) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(2)
Definition blf.cc:791
@ BLF_SHADOW
Definition BLF_api.hh:363
void BLF_draw_default(float x, float y, float z, const char *str, size_t str_len) ATTR_NONNULL()
#define BLI_assert(a)
Definition BLI_assert.h:50
MINLINE float max_ff(float a, float b)
BLI_INLINE int BLI_rcti_size_y(const struct rcti *rct)
Definition BLI_rect.h:193
BLI_INLINE int BLI_rcti_size_x(const struct rcti *rct)
Definition BLI_rect.h:189
BLI_INLINE float BLI_rctf_size_x(const struct rctf *rct)
Definition BLI_rect.h:197
BLI_INLINE float BLI_rctf_size_y(const struct rctf *rct)
Definition BLI_rect.h:201
size_t BLI_snprintf(char *__restrict dst, size_t dst_maxncpy, const char *__restrict format,...) ATTR_NONNULL(1
unsigned char uchar
unsigned int uint
size_t BLI_timecode_string_from_time(char *str, size_t maxncpy, int brevity_level, float time_seconds, double fps, short timecode_style) ATTR_NONNULL()
Definition timecode.c:23
#define ARRAY_SIZE(arr)
#define UNLIKELY(x)
#define IS_EQF(a, b)
#define FPS
#define UI_SCALE_FAC
@ USER_TIMECODE_MINIMAL
void immEnd()
void immUniform2fv(const char *name, const float data[2])
void immUnbindProgram()
void immVertex2f(uint attr_id, float x, float y)
void immBindBuiltinProgram(eGPUBuiltinShader shader_id)
void immUniformColor3ubv(const unsigned char rgb[3])
void immUniform1f(const char *name, float x)
GPUVertFormat * immVertexFormat()
void immBegin(GPUPrimType, uint vertex_len)
void GPU_matrix_push_projection()
void GPU_matrix_pop_projection()
@ GPU_PRIM_LINES
@ GPU_SHADER_3D_POLYLINE_UNIFORM_COLOR
@ GPU_SHADER_3D_UNIFORM_COLOR
void GPU_viewport_size_get_f(float coords[4])
Definition gpu_state.cc:262
@ GPU_FETCH_FLOAT
uint GPU_vertformat_attr_add(GPUVertFormat *, const char *name, GPUVertCompType, uint comp_len, GPUVertFetchMode)
@ GPU_COMP_F32
Read Guarded memory(de)allocation.
@ TH_GRID
@ TH_BACK
void UI_GetThemeColor3ubv(int colorid, unsigned char col[3])
void UI_GetThemeColor4fv(int colorid, float col[4])
void UI_FontThemeColor(int fontid, int colorid)
void UI_GetThemeColorShade3ubv(int colorid, int offset, unsigned char col[3])
float UI_view2d_region_to_view_y(const View2D *v2d, float y)
Definition view2d.cc:1657
float UI_view2d_view_to_region_y(const View2D *v2d, float y)
Definition view2d.cc:1691
void UI_view2d_view_ortho(const View2D *v2d)
Definition view2d.cc:1091
float UI_view2d_scale_get_y(const View2D *v2d)
Definition view2d.cc:1920
float UI_view2d_region_to_view_x(const View2D *v2d, float x)
Definition view2d.cc:1652
float UI_view2d_view_to_region_x(const View2D *v2d, float x)
Definition view2d.cc:1686
float UI_view2d_scale_get_x(const View2D *v2d)
Definition view2d.cc:1916
unsigned int U
Definition btGjkEpa3.h:78
int64_t size() const
void append(const T &value)
pow(value.r - subtrahend, 2.0)") .do_static_compilation(true)
#define ceilf(x)
#define floorf(x)
static const char * to_string(const Interpolation &interp)
Definition gl_shader.cc:82
format
ccl_device_inline float3 ceil(const float3 a)
float distance(float a, float b)
static const int steps
float xmax
float xmin
float ymax
float ymin
int ymin
int ymax
int xmin
int xmax
ccl_device_inline int abs(int x)
Definition util/math.h:120
static void draw_vertical_scale_indicators(const ARegion *region, const View2D *v2d, float distance, float display_offset, const rcti *rect, PositionToString to_string, void *to_string_data, int colorid)
static void draw_horizontal_scale_indicators(const ARegion *region, const View2D *v2d, float distance, const rcti *rect, PositionToString to_string, void *to_string_data, int colorid)
float UI_view2d_grid_resolution_x__frames_or_seconds(const View2D *v2d, const Scene *scene, bool display_seconds)
void UI_view2d_draw_scale_x__discrete_frames_or_seconds(const ARegion *region, const View2D *v2d, const rcti *rect, const Scene *scene, bool display_seconds, int colorid)
void UI_view2d_draw_lines_x__values(const View2D *v2d)
static float select_major_distance(const float *possible_distances, uint amount, float pixel_width, float view_width)
void(*)(void *user_data, float v2d_pos, float v2d_step, char *r_str, uint str_maxncpy) PositionToString
static void UI_view2d_draw_scale_x__values(const ARegion *region, const View2D *v2d, const rcti *rect, int colorid)
#define MIN_MAJOR_LINE_DISTANCE
static void view_to_string__frame_number(void *, float v2d_pos, float, char *r_str, uint str_maxncpy)
void UI_view2d_draw_lines_x__frames_or_seconds(const View2D *v2d, const Scene *scene, bool display_seconds)
static float view2d_major_step_x__continuous(const View2D *v2d)
static void view2d_draw_lines(const View2D *v2d, float major_distance, bool display_minor_lines, char direction)
void UI_view2d_draw_scale_x__frames_or_seconds(const ARegion *region, const View2D *v2d, const rcti *rect, const Scene *scene, bool display_seconds, int colorid)
static void view_to_string__time(void *user_data, float v2d_pos, float v2d_step, char *r_str, uint str_maxncpy)
void UI_view2d_draw_lines_y__values(const View2D *v2d)
static const float discrete_value_scales[]
static float view2d_major_step_x__time(const View2D *v2d, const Scene *scene)
void UI_view2d_draw_lines_x__discrete_frames_or_seconds(const View2D *v2d, const Scene *scene, bool display_seconds, bool display_minor_lines)
void UI_view2d_draw_lines_x__discrete_values(const View2D *v2d, bool display_minor_lines)
void UI_view2d_draw_lines_x__discrete_time(const View2D *v2d, const Scene *scene, bool display_minor_lines)
float UI_view2d_grid_resolution_y__values(const View2D *v2d)
static void UI_view2d_draw_scale_x__discrete_time(const ARegion *region, const View2D *v2d, const rcti *rect, const Scene *scene, int colorid)
void UI_view2d_draw_scale_y__values(const ARegion *region, const View2D *v2d, const rcti *rect, int colorid)
static void view2d_draw_lines_internal(const View2D *v2d, const ParallelLinesSet *lines, const uchar color[3], char direction)
void UI_view2d_draw_scale_y__block(const ARegion *region, const View2D *v2d, const rcti *rect, int colorid)
static void UI_view2d_draw_scale_x__discrete_values(const ARegion *region, const View2D *v2d, const rcti *rect, int colorid)
static float view2d_major_step_y__continuous(const View2D *v2d)
static uint view2d_major_step_x__discrete(const View2D *v2d)
static void view_to_string__value(void *, float v2d_pos, float v2d_step, char *r_str, uint str_maxncpy)
static void draw_parallel_lines(const ParallelLinesSet *lines, const rctf *rect, const rcti *rect_mask, const uchar color[3], char direction)
static const float continuous_value_scales[]
static void get_parallel_lines_draw_steps(const ParallelLinesSet *lines, float region_start, float region_end, float *r_first, uint *r_steps)
void wmOrtho2_region_pixelspace(const ARegion *region)