Blender V5.0
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
8
9#include <algorithm>
10#include <cfloat>
11#include <cmath>
12#include <cstring>
13
14#include "DNA_scene_types.h"
15#include "DNA_userdef_types.h"
16
17#include "BLI_math_base.h"
18#include "BLI_rect.h"
19#include "BLI_string_utf8.h"
20#include "BLI_timecode.h"
21#include "BLI_utildefines.h"
22#include "BLI_vector.hh"
23
24#include "GPU_immediate.hh"
25#include "GPU_matrix.hh"
26#include "GPU_state.hh"
27
28#include "WM_api.hh"
29
30#include "BLF_api.hh"
31
32#include "UI_resources.hh"
33#include "UI_view2d.hh"
34
35/* Compute display grid resolution
36 ********************************************************/
37
38#define MIN_MAJOR_LINE_DISTANCE (U.v2d_min_gridsize * UI_SCALE_FAC)
39
40/* This number defines the smalles scale unit that will be displayed. For example 100 will give
41 * 1/100 -> 0.01 as the smallest step. This is only relevant for editors that do display subframe
42 * information, for example the Graph Editor. */
43constexpr int subframe_range = 100;
44
45/* This esentially performs a special prime factor decomposition where it can only use 2, 3 and 5
46 * as prime factors. Divisions that result in 2 are preferred. */
47static int get_divisor(const int distance)
48{
49 const int divisors[3] = {2, 3, 5};
50 constexpr uint8_t num_divisors = ARRAY_SIZE(divisors);
51 bool divides_no_remainder[num_divisors];
52
53 for (int i = 0; i < num_divisors; i++) {
54 const int divisor = divisors[i];
55 const int result = distance / divisor;
56 /* If the division was without loss due to integer cast and the result is 2, return
57 * that. Animating on 2s is a very useful thing for animators so the lines should be shown with
58 * that distance. */
59 const bool has_no_remainder = result * divisor == distance;
60 if (has_no_remainder && result == 2) {
61 return divisor;
62 }
63 divides_no_remainder[i] = has_no_remainder;
64 }
65
66 /* If no division results in a 2, take the first to divide cleanly. */
67 for (int i = 0; i < num_divisors; i++) {
68 if (divides_no_remainder[i]) {
69 return divisors[i];
70 }
71 }
72
73 /* In case none of the above if is true, the divisor will be the full distance meaning the next
74 * step down from that number is 1. */
75 return distance;
76}
77
85static int calculate_grid_step(const int base, const float pixel_width, const float view_width)
86{
87 if (IS_EQF(view_width, 0.0f) || base == 0) {
88 return 1;
89 }
90 const float pixels_per_view_unit = pixel_width / view_width;
91 int distance = base;
92 if (pixels_per_view_unit * distance > MIN_MAJOR_LINE_DISTANCE) {
93 /* Shrink the distance. */
94 while (distance > 1) {
95 const int divisor = get_divisor(distance);
96 const int result = (distance / divisor);
97 if (pixels_per_view_unit * result < MIN_MAJOR_LINE_DISTANCE) {
98 /* If the distance would fall below the threshold, stop dividing. */
99 break;
100 }
102 }
103 }
104 else {
105 /* Grow the distance, doubling every time. */
106 while (pixels_per_view_unit * distance < MIN_MAJOR_LINE_DISTANCE) {
107 distance *= 2;
108 }
109 }
110 BLI_assert(distance != 0);
111 return distance;
112}
113
114/* Mostly the same as `calculate_grid_step, except in can divide into the 0-1 range. */
115static float calculate_grid_step_subframes(const int base,
116 const float pixel_width,
117 const float view_width)
118{
119 float distance = calculate_grid_step(base, pixel_width, view_width);
120 if (distance > 1) {
121 return distance;
122 }
123
124 /* Using `calculate_grid_step` to break down subframe_range simulating a larger view. */
125 distance = calculate_grid_step(subframe_range, pixel_width, view_width * subframe_range);
126 return distance / subframe_range;
127}
128
129/* Draw parallel lines
130 ************************************/
131
133 float offset;
134 float distance;
135};
136
138 float region_start,
139 float region_end,
140 float *r_first,
141 uint *r_steps)
142{
143 if (region_start >= region_end) {
144 *r_first = 0;
145 *r_steps = 0;
146 return;
147 }
148
149 BLI_assert(lines->distance > 0);
150 BLI_assert(region_start <= region_end);
151
152 *r_first = ceilf((region_start - lines->offset) / lines->distance) * lines->distance +
153 lines->offset;
154
155 if (region_start <= *r_first && region_end >= *r_first) {
156 *r_steps = std::max(0.0f, floorf((region_end - *r_first) / lines->distance)) + 1;
157 }
158 else {
159 *r_steps = 0;
160 }
161}
162
166static void draw_parallel_lines(const ParallelLinesSet *lines,
167 const rctf *rect,
168 const rcti *rect_mask,
169 const uchar color[3],
170 char direction)
171{
172 float first;
173 uint steps, steps_max;
174
175 if (direction == 'v') {
176 get_parallel_lines_draw_steps(lines, rect->xmin, rect->xmax, &first, &steps);
177 steps_max = BLI_rcti_size_x(rect_mask);
178 }
179 else {
180 BLI_assert(direction == 'h');
181 get_parallel_lines_draw_steps(lines, rect->ymin, rect->ymax, &first, &steps);
182 steps_max = BLI_rcti_size_y(rect_mask);
183 }
184
185 if (steps == 0) {
186 return;
187 }
188
189 if (UNLIKELY(steps >= steps_max)) {
190 /* Note that we could draw a solid color,
191 * however this flickers because of numeric instability when zoomed out. */
192 return;
193 }
194
197 format, "pos", blender::gpu::VertAttrType::SFLOAT_32_32);
198
199 if (U.pixelsize > 1.0f) {
200 float viewport[4];
201 GPU_viewport_size_get_f(viewport);
202
204 immUniform2fv("viewportSize", &viewport[2]);
205 /* -1.0f offset here is because the line is too fat due to the builtin anti-aliasing.
206 * TODO: make a variant or a uniform to toggle it off. */
207 immUniform1f("lineWidth", U.pixelsize - 1.0f);
208 }
209 else {
211 }
212 immUniformColor3ubv(color);
213 immBegin(GPU_PRIM_LINES, steps * 2);
214
215 if (direction == 'v') {
216 for (uint i = 0; i < steps; i++) {
217 const float xpos = first + i * lines->distance;
218 immVertex2f(pos, xpos, rect->ymin);
219 immVertex2f(pos, xpos, rect->ymax);
220 }
221 }
222 else {
223 for (uint i = 0; i < steps; i++) {
224 const float ypos = first + i * lines->distance;
225 immVertex2f(pos, rect->xmin, ypos);
226 immVertex2f(pos, rect->xmax, ypos);
227 }
228 }
229
230 immEnd();
232}
233
234static void view2d_draw_lines_internal(const View2D *v2d,
235 const ParallelLinesSet *lines,
236 const uchar color[3],
237 char direction)
238{
241 draw_parallel_lines(lines, &v2d->cur, &v2d->mask, color, direction);
243}
244
245static void view2d_draw_lines(const View2D *v2d,
246 const float major_distance,
247 const bool display_minor_lines,
248 const char direction)
249{
250 if (display_minor_lines) {
251 uchar minor_color[3];
252 UI_GetThemeColorShade3ubv(TH_GRID, 16, minor_color);
253 ParallelLinesSet minor_lines;
254 int distance_int;
255 if (major_distance > 1) {
256 distance_int = round_fl_to_int(major_distance);
257 }
258 else {
259 /* By multiplying by the subframe range, the smallest distance in which minor lines are drawn
260 * is the same as the smallest distance between major lines. We can just do this
261 * multiplication because from the result, the next divisor is found and applied to the
262 * major distance. The returned divisor may be 1. */
263 distance_int = round_fl_to_int(major_distance * subframe_range);
264 }
265 const int divisor = get_divisor(distance_int);
266 minor_lines.distance = major_distance / divisor;
267 minor_lines.offset = 0;
268 const int pixel_width = BLI_rcti_size_x(&v2d->mask) + 1;
269 const float view_width = BLI_rctf_size_x(&v2d->cur);
270
271 if ((pixel_width / view_width) * (major_distance / divisor) > MIN_MAJOR_LINE_DISTANCE / 5) {
272 view2d_draw_lines_internal(v2d, &minor_lines, minor_color, direction);
273 }
274 }
275
276 {
277 uchar major_color[3];
278 UI_GetThemeColor3ubv(TH_GRID, major_color);
279 ParallelLinesSet major_lines;
280 major_lines.distance = major_distance;
281 major_lines.offset = 0;
282 view2d_draw_lines_internal(v2d, &major_lines, major_color, direction);
283 }
284}
285
286/* Scale indicator text drawing
287 **************************************************/
288
290 void (*)(void *user_data, float v2d_pos, float v2d_step, char *r_str, uint str_maxncpy);
291
293 const View2D *v2d,
294 float distance,
295 const rcti *rect,
297 void *to_string_data,
298 int colorid)
299{
300 if (UI_view2d_scale_get_x(v2d) <= 0.0f) {
301 return;
302 }
303
304 float start;
305 uint steps;
306 {
307 ParallelLinesSet lines;
308 lines.distance = distance;
309 lines.offset = 0;
313 &start,
314 &steps);
315 const uint steps_max = BLI_rcti_size_x(&v2d->mask) + 1;
316 if (UNLIKELY(steps >= steps_max)) {
317 return;
318 }
319 }
320
323
324 const int font_id = BLF_set_default();
325 UI_FontThemeColor(font_id, colorid);
326
328
329 const float ypos = rect->ymin + 4 * UI_SCALE_FAC;
330 const float xmin = rect->xmin;
331 const float xmax = rect->xmax;
332
333 char text[32];
334
335 /* Calculate max_label_count and draw_frequency based on largest visible label. */
336 int draw_frequency;
337 {
338 to_string(to_string_data, start, 0, text, sizeof(text));
339 const float left_text_width = BLF_width(font_id, text, strlen(text));
340 to_string(to_string_data, start + steps * distance, 0, text, sizeof(text));
341 const float right_text_width = BLF_width(font_id, text, strlen(text));
342 const float max_text_width = max_ff(left_text_width, right_text_width);
343 const float max_label_count = (BLI_rcti_size_x(&v2d->mask) + 1) / (max_text_width + 6.0f);
344 draw_frequency = ceil(float(steps) / max_label_count);
345 }
346
347 if (draw_frequency != 0) {
348 const int start_index = abs(int(start / distance)) % draw_frequency;
349 for (uint i = start_index; i < steps; i += draw_frequency) {
350 const float xpos_view = start + i * distance;
351 const float xpos_region = UI_view2d_view_to_region_x(v2d, xpos_view);
352 to_string(to_string_data, xpos_view, distance, text, sizeof(text));
353 const float text_width = BLF_width(font_id, text, strlen(text));
354
355 if (xpos_region - text_width / 2.0f >= xmin && xpos_region + text_width / 2.0f <= xmax) {
357 xpos_region - std::trunc(text_width / 2.0f), ypos, 0.0f, text, sizeof(text));
358 }
359 }
360 }
361
364}
365
366static void draw_vertical_scale_indicators(const ARegion *region,
367 const View2D *v2d,
368 float distance,
369 float display_offset,
370 const rcti *rect,
372 void *to_string_data,
373 int colorid)
374{
375 if (UI_view2d_scale_get_y(v2d) <= 0.0f) {
376 return;
377 }
378
379 float start;
380 uint steps;
381 {
382 ParallelLinesSet lines;
383 lines.distance = distance;
384 lines.offset = 0;
388 &start,
389 &steps);
390 const uint steps_max = BLI_rcti_size_y(&v2d->mask) + 1;
391 if (UNLIKELY(steps >= steps_max)) {
392 return;
393 }
394 }
395
398
399 const int font_id = BLF_set_default();
400 UI_FontThemeColor(font_id, colorid);
401
403
404 BLF_enable(font_id, BLF_SHADOW);
405 float shadow_color[4];
406 UI_GetThemeColor4fv(TH_BACK, shadow_color);
407 BLF_shadow_offset(font_id, 0, 0);
408 BLF_shadow(font_id, FontShadowType::Outline, shadow_color);
409
410 const float x_offset = 8.0f;
411 const float xpos = (rect->xmin + x_offset) * UI_SCALE_FAC;
412 const float ymin = rect->ymin;
413 const float ymax = rect->ymax;
414 const float y_offset = (BLF_height(font_id, "0", 1) / 2.0f) - U.pixelsize;
415
416 for (uint i = 0; i < steps; i++) {
417 const float ypos_view = start + i * distance;
418 const float ypos_region = UI_view2d_view_to_region_y(v2d, ypos_view + display_offset);
419 char text[32];
420 to_string(to_string_data, ypos_view, distance, text, sizeof(text));
421
422 if (ypos_region - y_offset >= ymin && ypos_region + y_offset <= ymax) {
423 BLF_draw_default(xpos, ypos_region - y_offset, 0.0f, text, sizeof(text));
424 }
425 }
426
427 BLF_disable(font_id, BLF_SHADOW);
428
430
432}
433
435 void * /*user_data*/, float v2d_pos, float /*v2d_step*/, char *r_str, uint str_maxncpy)
436{
437 BLI_snprintf_utf8(r_str, str_maxncpy, "%d", int(v2d_pos));
438}
439
441 void *user_data, float v2d_pos, float v2d_step, char *r_str, uint str_maxncpy)
442{
443 const Scene *scene = (const Scene *)user_data;
444
445 int brevity_level = -1;
446 if (U.timecode_style == USER_TIMECODE_MINIMAL && v2d_step >= scene->frames_per_second()) {
447 brevity_level = 1;
448 }
449
451 str_maxncpy,
452 brevity_level,
453 v2d_pos / float(scene->frames_per_second()),
454 scene->frames_per_second(),
455 U.timecode_style);
456}
457
459 void * /*user_data*/, float v2d_pos, float v2d_step, char *r_str, uint str_maxncpy)
460{
461 if (v2d_step >= 1.0f * UI_SCALE_FAC) {
462 BLI_snprintf_utf8(r_str, str_maxncpy, "%d", int(v2d_pos));
463 }
464 else if (v2d_step >= 0.5f * UI_SCALE_FAC) {
465 BLI_snprintf_utf8(r_str, str_maxncpy, "%.1f", v2d_pos);
466 }
467 else if (v2d_step >= 0.01f * UI_SCALE_FAC) {
468 BLI_snprintf_utf8(r_str, str_maxncpy, "%.2f", v2d_pos);
469 }
470 else {
471 BLI_snprintf_utf8(r_str, str_maxncpy, "%.3f", v2d_pos);
472 }
473}
474
475/* Grid Resolution API
476 **************************************************/
477
479{
480 const int fps = round_db_to_int(scene->frames_per_second());
482 fps, BLI_rcti_size_x(&v2d->mask) + 1, BLI_rctf_size_x(&v2d->cur));
483}
484
485float UI_view2d_grid_resolution_y__values(const View2D *v2d, const int base)
486{
488 base, BLI_rcti_size_y(&v2d->mask) + 1, BLI_rctf_size_y(&v2d->cur));
489}
490
491/* Line Drawing API
492 **************************************************/
493
495 const int base,
496 bool display_minor_lines)
497{
498 const float major_line_distance = calculate_grid_step(
499 base, BLI_rcti_size_x(&v2d->mask) + 1, BLI_rctf_size_x(&v2d->cur));
501 v2d, major_line_distance, display_minor_lines && (major_line_distance > 1), 'v');
502}
503
504void UI_view2d_draw_lines_x__values(const View2D *v2d, const int base)
505{
506 const float major_line_distance = calculate_grid_step_subframes(
507 base, BLI_rcti_size_x(&v2d->mask) + 1, BLI_rctf_size_x(&v2d->cur));
508 view2d_draw_lines(v2d, major_line_distance, true, 'v');
509}
510
511void UI_view2d_draw_lines_y__values(const View2D *v2d, const int base)
512{
513 const float major_line_distance = calculate_grid_step_subframes(
514 base, BLI_rcti_size_y(&v2d->mask) + 1, BLI_rctf_size_y(&v2d->cur));
515 view2d_draw_lines(v2d, major_line_distance, true, 'h');
516}
517
519 const int base,
520 bool display_minor_lines)
521{
522 const float major_line_distance = calculate_grid_step(
523 base, BLI_rcti_size_x(&v2d->mask) + 1, BLI_rctf_size_x(&v2d->cur));
525 v2d, major_line_distance, display_minor_lines && (major_line_distance > 1), 'v');
526}
527
529 const Scene *scene,
530 bool display_seconds,
531 bool display_minor_lines)
532{
533 /* Rounding fractional framerates for drawing. */
534 const int fps = round_db_to_int(scene->frames_per_second());
535 if (display_seconds) {
536 UI_view2d_draw_lines_x__discrete_time(v2d, fps, display_minor_lines);
537 }
538 else {
539 UI_view2d_draw_lines_x__discrete_values(v2d, fps, display_minor_lines);
540 }
541}
542
544 const Scene *scene,
545 bool display_seconds)
546{
547 const int fps = round_db_to_int(scene->frames_per_second());
548 if (display_seconds) {
550 }
551 else {
553 }
554}
555
556/* Scale indicator text drawing API
557 **************************************************/
558
560 const ARegion *region, const View2D *v2d, const rcti *rect, int colorid, const int base)
561{
563 base, BLI_rcti_size_y(&v2d->mask) + 1, BLI_rctf_size_y(&v2d->cur));
565 region, v2d, step, 0.0f, rect, view_to_string__value, nullptr, colorid);
566}
567
569 const View2D *v2d,
570 const rcti *rect,
571 const Scene *scene,
572 bool display_seconds,
573 int colorid,
574 const int base)
575{
576 const float step = calculate_grid_step(
577 base, BLI_rcti_size_x(&v2d->mask) + 1, BLI_rctf_size_x(&v2d->cur));
578 if (display_seconds) {
580 region, v2d, step, rect, view_to_string__time, (void *)scene, colorid);
581 }
582 else {
584 region, v2d, step, rect, view_to_string__frame_number, nullptr, colorid);
585 }
586}
587
589 const View2D *v2d,
590 const rcti *rect,
591 const Scene *scene,
592 bool display_seconds,
593 int colorid,
594 const int base)
595{
596 if (display_seconds) {
597 const float step = calculate_grid_step(
598 base, BLI_rcti_size_x(&v2d->mask) + 1, BLI_rctf_size_x(&v2d->cur));
600 region, v2d, step, rect, view_to_string__time, (void *)scene, colorid);
601 }
602 else {
604 base, BLI_rcti_size_x(&v2d->mask) + 1, BLI_rctf_size_x(&v2d->cur));
606 region, v2d, step, rect, view_to_string__value, nullptr, colorid);
607 }
608}
int BLF_set_default()
void BLF_enable(int fontid, FontFlags flag)
Definition blf.cc:320
void BLF_shadow(int fontid, FontShadowType type, const float rgba[4]=nullptr)
Definition blf.cc:934
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:837
void BLF_shadow_offset(int fontid, int x, int y)
Definition blf.cc:946
void BLF_batch_draw_begin()
Definition blf.cc:534
void BLF_batch_draw_end()
Definition blf.cc:547
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:802
void BLF_disable(int fontid, FontFlags flag)
Definition blf.cc:329
void BLF_draw_default(float x, float y, float z, const char *str, size_t str_len) ATTR_NONNULL()
@ BLF_SHADOW
Definition BLF_enums.hh:35
#define BLI_assert(a)
Definition BLI_assert.h:46
MINLINE int round_fl_to_int(float a)
MINLINE float max_ff(float a, float b)
MINLINE int round_db_to_int(double a)
BLI_INLINE int BLI_rcti_size_y(const struct rcti *rct)
Definition BLI_rect.h:198
BLI_INLINE int BLI_rcti_size_x(const struct rcti *rct)
Definition BLI_rect.h:194
BLI_INLINE float BLI_rctf_size_x(const struct rctf *rct)
Definition BLI_rect.h:202
BLI_INLINE float BLI_rctf_size_y(const struct rctf *rct)
Definition BLI_rect.h:206
size_t size_t size_t BLI_snprintf_utf8(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.cc:22
#define ARRAY_SIZE(arr)
#define UNLIKELY(x)
#define IS_EQF(a, b)
#define UI_SCALE_FAC
@ USER_TIMECODE_MINIMAL
void immEnd()
void immUniform2fv(const char *name, const float data[2])
void immUnbindProgram()
void immBindBuiltinProgram(GPUBuiltinShader shader_id)
void immVertex2f(uint attr_id, float x, float y)
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:273
uint GPU_vertformat_attr_add(GPUVertFormat *format, blender::StringRef name, blender::gpu::VertAttrType type)
@ 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:1662
float UI_view2d_view_to_region_y(const View2D *v2d, float y)
Definition view2d.cc:1696
void UI_view2d_view_ortho(const View2D *v2d)
Definition view2d.cc:1095
float UI_view2d_scale_get_y(const View2D *v2d)
Definition view2d.cc:1925
float UI_view2d_region_to_view_x(const View2D *v2d, float x)
Definition view2d.cc:1657
float UI_view2d_view_to_region_x(const View2D *v2d, float x)
Definition view2d.cc:1691
float UI_view2d_scale_get_x(const View2D *v2d)
Definition view2d.cc:1921
#define U
static const char * to_string(const Interpolation &interp)
Definition gl_shader.cc:103
uint pos
#define abs
#define ceil
VecBase< float, D > step(VecOp< float, D >, VecOp< float, D >) RET
float distance(VecOp< float, D >, VecOp< float, D >) RET
format
#define floorf
#define ceilf
float xmax
float xmin
float ymax
float ymin
int ymin
int ymax
int xmin
int xmax
i
Definition text_draw.cc:230
void UI_view2d_draw_lines_x__values(const View2D *v2d, const int base)
float UI_view2d_grid_resolution_x__frames_or_seconds(const View2D *v2d, const Scene *scene)
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)
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, const int base)
#define MIN_MAJOR_LINE_DISTANCE
void UI_view2d_draw_lines_x__discrete_values(const View2D *v2d, const int base, bool display_minor_lines)
void UI_view2d_draw_lines_y__values(const View2D *v2d, const int base)
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 int get_divisor(const int distance)
void(*)(void *user_data, float v2d_pos, float v2d_step, char *r_str, uint str_maxncpy) PositionToString
static void view_to_string__time(void *user_data, float v2d_pos, float v2d_step, char *r_str, uint str_maxncpy)
static int calculate_grid_step(const int base, const float pixel_width, const float view_width)
void UI_view2d_draw_scale_y__values(const ARegion *region, const View2D *v2d, const rcti *rect, int colorid, const int base)
void UI_view2d_draw_lines_x__discrete_frames_or_seconds(const View2D *v2d, const Scene *scene, bool display_seconds, bool display_minor_lines)
static void view2d_draw_lines(const View2D *v2d, const float major_distance, const bool display_minor_lines, const char direction)
float UI_view2d_grid_resolution_y__values(const View2D *v2d, const int base)
static void view2d_draw_lines_internal(const View2D *v2d, const ParallelLinesSet *lines, const uchar color[3], char direction)
void UI_view2d_draw_lines_x__discrete_time(const View2D *v2d, const int base, bool display_minor_lines)
static float calculate_grid_step_subframes(const int base, const float pixel_width, const float view_width)
constexpr int subframe_range
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)
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, const int base)
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)