Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJacques Lucke <mail@jlucke.com>2019-05-02 13:00:12 +0300
committerJacques Lucke <mail@jlucke.com>2019-05-02 13:00:12 +0300
commit667af6cf411918ba181afc1a7d6bcb474f9fadb8 (patch)
treed9d8831caff733df9293db42d87fbc9733ba1415 /source/blender/editors/interface/view2d_draw.c
parent5b14b5654231a50874fd9103d2adb306f62aec8d (diff)
Refactor grid and scale indicator text drawing
This affects the timeline, dopesheet, graph editor, sequencer, clip editor and nla editor. Removed structs and enums: `V2D_ARG_DUMMY`, `eView2D_Units`, `eView2D_Clamp`, `eView2D_Gridlines`, `View2DGrid`. A main goal of this refactor is to get rid of the very generic `View2DGrid` struct. The drawing code became very complex because there were many different combinations of settings. This refactor implements a different approach. Instead of one very generic API, there are many slighly different functions that do exactly, what we need in the different editors. Only very little code is duplicated, because the API functions compose some shared low level code. This structure makes the code much easier to debug and change, because every function has much fewer responsibilities. Additionally, this refactor fixes some long standing bugs. E.g. when `Show Seconds` is enabled, you zoom in and pan the view. Or that the step size between displayed frame numbers was always `>= 2`, no matter how close you zoom in. Reviewers: brecht Differential Revision: https://developer.blender.org/D4776
Diffstat (limited to 'source/blender/editors/interface/view2d_draw.c')
-rw-r--r--source/blender/editors/interface/view2d_draw.c526
1 files changed, 526 insertions, 0 deletions
diff --git a/source/blender/editors/interface/view2d_draw.c b/source/blender/editors/interface/view2d_draw.c
new file mode 100644
index 00000000000..91128e49a60
--- /dev/null
+++ b/source/blender/editors/interface/view2d_draw.c
@@ -0,0 +1,526 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2008 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edinterface
+ */
+
+#include <float.h>
+#include <limits.h>
+#include <math.h>
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_scene_types.h"
+#include "DNA_userdef_types.h"
+
+#include "BLI_array.h"
+#include "BLI_utildefines.h"
+#include "BLI_rect.h"
+#include "BLI_math.h"
+#include "BLI_timecode.h"
+#include "BLI_string.h"
+
+#include "GPU_immediate.h"
+#include "GPU_matrix.h"
+
+#include "WM_api.h"
+
+#include "BLF_api.h"
+
+#include "UI_interface.h"
+#include "UI_view2d.h"
+
+#include "interface_intern.h"
+
+/* Compute display grid resolution
+ ********************************************************/
+
+#define MIN_MAJOR_LINE_DISTANCE (UI_DPI_FAC * 50)
+
+static float select_major_distance(const float *possible_distances,
+ uint amount,
+ float pixel_width,
+ float view_width)
+{
+ BLI_assert(amount >= 1);
+
+ if (IS_EQF(view_width, 0.0f)) {
+ return possible_distances[0];
+ }
+
+ float pixels_per_view_unit = pixel_width / view_width;
+
+ for (uint i = 0; i < amount; i++) {
+ float distance = possible_distances[i];
+ if (pixels_per_view_unit * distance >= MIN_MAJOR_LINE_DISTANCE) {
+ return distance;
+ }
+ }
+ return possible_distances[amount - 1];
+}
+
+static const float discrete_value_scales[] = {
+ 1, 2, 5, 10, 20, 50, 100, 200, 500, 1000, 2000, 5000, 10000, 20000, 50000, 100000};
+
+static const float continuous_value_scales[] = {0.01, 0.02, 0.05, 0.1, 0.2, 0.5, 1, 2,
+ 5, 10, 20, 50, 100, 200, 500, 1000,
+ 2000, 5000, 10000, 20000, 50000, 100000};
+
+static uint view2d_major_step_x__discrete(const View2D *v2d)
+{
+ return select_major_distance(discrete_value_scales,
+ ARRAY_SIZE(discrete_value_scales),
+ BLI_rcti_size_x(&v2d->mask),
+ BLI_rctf_size_x(&v2d->cur));
+}
+
+static float view2d_major_step_x__continuous(const View2D *v2d)
+{
+ return select_major_distance(continuous_value_scales,
+ ARRAY_SIZE(continuous_value_scales),
+ BLI_rcti_size_x(&v2d->mask),
+ BLI_rctf_size_x(&v2d->cur));
+}
+
+static float view2d_major_step_y__continuous(const View2D *v2d)
+{
+ return select_major_distance(continuous_value_scales,
+ ARRAY_SIZE(continuous_value_scales),
+ BLI_rcti_size_y(&v2d->mask),
+ BLI_rctf_size_y(&v2d->cur));
+}
+
+static float view2d_major_step_x__time(const View2D *v2d, const Scene *scene)
+{
+ double fps = FPS;
+
+ float *possible_distances = NULL;
+ BLI_array_staticdeclare(possible_distances, 32);
+
+ for (uint step = 1; step < fps; step *= 2) {
+ BLI_array_append(possible_distances, step);
+ }
+ BLI_array_append(possible_distances, fps);
+ BLI_array_append(possible_distances, 2 * fps);
+ BLI_array_append(possible_distances, 5 * fps);
+ BLI_array_append(possible_distances, 10 * fps);
+ BLI_array_append(possible_distances, 30 * fps);
+ BLI_array_append(possible_distances, 60 * fps);
+ BLI_array_append(possible_distances, 2 * 60 * fps);
+ BLI_array_append(possible_distances, 5 * 60 * fps);
+ BLI_array_append(possible_distances, 10 * 60 * fps);
+ BLI_array_append(possible_distances, 30 * 60 * fps);
+ BLI_array_append(possible_distances, 60 * 60 * fps);
+
+ float distance = select_major_distance(possible_distances,
+ BLI_array_len(possible_distances),
+ BLI_rcti_size_x(&v2d->mask),
+ BLI_rctf_size_x(&v2d->cur));
+
+ BLI_array_free(possible_distances);
+ return distance;
+}
+
+/* Draw parallel lines
+ ************************************/
+
+typedef struct ParallelLinesSet {
+ float offset;
+ float distance;
+} ParallelLinesSet;
+
+static void get_parallel_lines_draw_steps(const ParallelLinesSet *lines,
+ float region_start,
+ float region_end,
+ float *r_first,
+ uint *r_steps)
+{
+ BLI_assert(lines->distance > 0);
+ BLI_assert(region_start <= region_end);
+
+ *r_first = ceilf((region_start - lines->offset) / lines->distance) * lines->distance +
+ lines->offset;
+
+ if (region_start <= *r_first && region_end >= *r_first) {
+ *r_steps = MAX2(0, floorf((region_end - *r_first) / lines->distance)) + 1;
+ }
+ else {
+ *r_steps = 0;
+ }
+}
+
+static void draw_parallel_lines(const ParallelLinesSet *lines,
+ const rctf *rect,
+ const uchar *color,
+ char direction)
+{
+ float first;
+ uint steps;
+
+ if (direction == 'v') {
+ get_parallel_lines_draw_steps(lines, rect->xmin, rect->xmax, &first, &steps);
+ }
+ else {
+ BLI_assert(direction == 'h');
+ get_parallel_lines_draw_steps(lines, rect->ymin, rect->ymax, &first, &steps);
+ }
+
+ if (steps == 0) {
+ return;
+ }
+
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformColor3ubv(color);
+ immBegin(GPU_PRIM_LINES, steps * 2);
+
+ if (direction == 'v') {
+ for (uint i = 0; i < steps; i++) {
+ float xpos = first + i * lines->distance;
+ immVertex2f(pos, xpos, rect->ymin);
+ immVertex2f(pos, xpos, rect->ymax);
+ }
+ }
+ else {
+ for (uint i = 0; i < steps; i++) {
+ float ypos = first + i * lines->distance;
+ immVertex2f(pos, rect->xmin, ypos);
+ immVertex2f(pos, rect->xmax, ypos);
+ }
+ }
+
+ immEnd();
+ immUnbindProgram();
+}
+
+static void view2d_draw_lines_internal(const View2D *v2d,
+ const ParallelLinesSet *lines,
+ const uchar *color,
+ char direction)
+{
+ GPU_matrix_push_projection();
+ UI_view2d_view_ortho(v2d);
+ draw_parallel_lines(lines, &v2d->cur, color, direction);
+ GPU_matrix_pop_projection();
+}
+
+static void view2d_draw_lines(const View2D *v2d,
+ float major_distance,
+ bool display_minor_lines,
+ char direction)
+{
+ uchar major_color[3];
+ uchar minor_color[3];
+ UI_GetThemeColor3ubv(TH_GRID, major_color);
+ UI_GetThemeColorShade3ubv(TH_GRID, 16, minor_color);
+
+ ParallelLinesSet major_lines;
+ major_lines.distance = major_distance;
+ major_lines.offset = 0;
+ view2d_draw_lines_internal(v2d, &major_lines, major_color, direction);
+
+ if (display_minor_lines) {
+ ParallelLinesSet minor_lines;
+ minor_lines.distance = major_distance;
+ minor_lines.offset = major_distance / 2.0f;
+ view2d_draw_lines_internal(v2d, &minor_lines, minor_color, direction);
+ }
+}
+
+/* Scale indicator text drawing
+ **************************************************/
+
+typedef void (*PositionToString)(
+ void *user_data, float v2d_pos, float v2d_step, uint max_len, char *r_str);
+
+static void draw_horizontal_scale_indicators(const ARegion *ar,
+ const View2D *v2d,
+ float distance,
+ const rcti *rect,
+ PositionToString to_string,
+ void *to_string_data)
+{
+ GPU_matrix_push_projection();
+ wmOrtho2_region_pixelspace(ar);
+
+ float start;
+ uint steps;
+ {
+ ParallelLinesSet lines;
+ lines.distance = distance;
+ lines.offset = 0;
+ get_parallel_lines_draw_steps(&lines,
+ UI_view2d_region_to_view_x(v2d, rect->xmin),
+ UI_view2d_region_to_view_x(v2d, rect->xmax),
+ &start,
+ &steps);
+ }
+
+ const int font_id = BLF_default();
+ UI_FontThemeColor(font_id, TH_TEXT);
+
+ BLF_batch_draw_begin();
+
+ float ypos = rect->ymin + 4 * UI_DPI_FAC;
+ float xmin = rect->xmin;
+ float xmax = rect->xmax;
+
+ for (uint i = 0; i < steps; i++) {
+ float xpos_view = start + i * distance;
+ float xpos_region = UI_view2d_view_to_region_x(v2d, xpos_view);
+ char text[32];
+ to_string(to_string_data, xpos_view, distance, sizeof(text), text);
+ float text_width = BLF_width(font_id, text, strlen(text));
+
+ if (xpos_region - text_width / 2.0f >= xmin && xpos_region + text_width / 2.0f <= xmax) {
+ BLF_draw_default_ascii(xpos_region - text_width / 2.0f, ypos, 0.0f, text, sizeof(text));
+ }
+ }
+
+ BLF_batch_draw_end();
+
+ GPU_matrix_pop_projection();
+}
+
+static void draw_vertical_scale_indicators(const ARegion *ar,
+ const View2D *v2d,
+ float distance,
+ float display_offset,
+ const rcti *rect,
+ PositionToString to_string,
+ void *to_string_data)
+{
+ GPU_matrix_push_projection();
+ wmOrtho2_region_pixelspace(ar);
+
+ float start;
+ uint steps;
+ {
+ ParallelLinesSet lines;
+ lines.distance = distance;
+ lines.offset = 0;
+ get_parallel_lines_draw_steps(&lines,
+ UI_view2d_region_to_view_y(v2d, rect->ymin),
+ UI_view2d_region_to_view_y(v2d, rect->ymax),
+ &start,
+ &steps);
+ }
+
+ const int font_id = BLF_default();
+ UI_FontThemeColor(font_id, TH_TEXT);
+
+ BLF_enable(font_id, BLF_ROTATION);
+ BLF_rotation(font_id, M_PI_2);
+
+ BLF_batch_draw_begin();
+
+ float xpos = rect->xmax - 2.0f * UI_DPI_FAC;
+ float ymin = rect->ymin;
+ float ymax = rect->ymax;
+
+ for (uint i = 0; i < steps; i++) {
+ float ypos_view = start + i * distance;
+ float ypos_region = UI_view2d_view_to_region_y(v2d, ypos_view + display_offset);
+ char text[32];
+ to_string(to_string_data, ypos_view, distance, sizeof(text), text);
+ float text_width = BLF_width(font_id, text, strlen(text));
+
+ if (ypos_region - text_width / 2.0f >= ymin && ypos_region + text_width / 2.0f <= ymax) {
+ BLF_draw_default_ascii(xpos, ypos_region - text_width / 2.0f, 0.0f, text, sizeof(text));
+ }
+ }
+
+ BLF_batch_draw_end();
+ BLF_disable(font_id, BLF_ROTATION);
+
+ GPU_matrix_pop_projection();
+}
+
+static void view_to_string__frame_number(
+ void *UNUSED(user_data), float v2d_pos, float UNUSED(v2d_step), uint max_len, char *r_str)
+{
+ BLI_snprintf(r_str, max_len, "%d", (int)v2d_pos);
+}
+
+static void view_to_string__time(
+ void *user_data, float v2d_pos, float UNUSED(v2d_step), uint max_len, char *r_str)
+{
+ const Scene *scene = (const Scene *)user_data;
+
+ int brevity_level = 0;
+ BLI_timecode_string_from_time(
+ r_str, max_len, brevity_level, v2d_pos / (float)FPS, FPS, U.timecode_style);
+}
+
+static void view_to_string__value(
+ void *UNUSED(user_data), float v2d_pos, float v2d_step, uint max_len, char *r_str)
+{
+ if (v2d_step >= 1.0f) {
+ BLI_snprintf(r_str, max_len, "%d", (int)v2d_pos);
+ }
+ else if (v2d_step >= 0.1f) {
+ BLI_snprintf(r_str, max_len, "%.1f", v2d_pos);
+ }
+ else if (v2d_step >= 0.01f) {
+ BLI_snprintf(r_str, max_len, "%.2f", v2d_pos);
+ }
+ else {
+ BLI_snprintf(r_str, max_len, "%.3f", v2d_pos);
+ }
+}
+
+/* Grid Resolution API
+ **************************************************/
+
+float UI_view2d_grid_resolution_x__frames_or_seconds(const struct View2D *v2d,
+ const struct Scene *scene,
+ bool display_seconds)
+{
+ if (display_seconds) {
+ return view2d_major_step_x__time(v2d, scene);
+ }
+ else {
+ return view2d_major_step_x__continuous(v2d);
+ }
+}
+
+float UI_view2d_grid_resolution_y__values(const struct View2D *v2d)
+{
+ return view2d_major_step_y__continuous(v2d);
+}
+
+/* Line Drawing API
+ **************************************************/
+
+void UI_view2d_draw_lines_x__discrete_values(const View2D *v2d)
+{
+ uint major_line_distance = view2d_major_step_x__discrete(v2d);
+ view2d_draw_lines(v2d, major_line_distance, major_line_distance > 1, 'v');
+}
+
+void UI_view2d_draw_lines_x__values(const View2D *v2d)
+{
+ float major_line_distance = view2d_major_step_x__continuous(v2d);
+ view2d_draw_lines(v2d, major_line_distance, true, 'v');
+}
+
+void UI_view2d_draw_lines_y__values(const View2D *v2d)
+{
+ float major_line_distance = view2d_major_step_y__continuous(v2d);
+ view2d_draw_lines(v2d, major_line_distance, true, 'h');
+}
+
+void UI_view2d_draw_lines_x__discrete_time(const View2D *v2d, const Scene *scene)
+{
+ float major_line_distance = view2d_major_step_x__time(v2d, scene);
+ view2d_draw_lines(v2d, major_line_distance, major_line_distance > 1, 'v');
+}
+
+void UI_view2d_draw_lines_x__discrete_frames_or_seconds(const View2D *v2d,
+ const Scene *scene,
+ bool display_seconds)
+{
+ if (display_seconds) {
+ UI_view2d_draw_lines_x__discrete_time(v2d, scene);
+ }
+ else {
+ UI_view2d_draw_lines_x__discrete_values(v2d);
+ }
+}
+
+void UI_view2d_draw_lines_x__frames_or_seconds(const View2D *v2d,
+ const Scene *scene,
+ bool display_seconds)
+{
+ if (display_seconds) {
+ UI_view2d_draw_lines_x__discrete_time(v2d, scene);
+ }
+ else {
+ UI_view2d_draw_lines_x__values(v2d);
+ }
+}
+
+/* Scale indicator text drawing API
+ **************************************************/
+
+void UI_view2d_draw_scale_x__discrete_values(const ARegion *ar,
+ const View2D *v2d,
+ const rcti *rect)
+{
+ float number_step = view2d_major_step_x__discrete(v2d);
+ draw_horizontal_scale_indicators(ar, v2d, number_step, rect, view_to_string__frame_number, NULL);
+}
+
+void UI_view2d_draw_scale_x__discrete_time(const ARegion *ar,
+ const View2D *v2d,
+ const rcti *rect,
+ const Scene *scene)
+{
+ float step = view2d_major_step_x__time(v2d, scene);
+ draw_horizontal_scale_indicators(ar, v2d, step, rect, view_to_string__time, (void *)scene);
+}
+
+void UI_view2d_draw_scale_x__values(const ARegion *ar, const View2D *v2d, const rcti *rect)
+{
+ float step = view2d_major_step_x__continuous(v2d);
+ draw_horizontal_scale_indicators(ar, v2d, step, rect, view_to_string__value, NULL);
+}
+
+void UI_view2d_draw_scale_y__values(const ARegion *ar, const View2D *v2d, const rcti *rect)
+{
+ float step = view2d_major_step_y__continuous(v2d);
+ draw_vertical_scale_indicators(ar, v2d, step, 0.0f, rect, view_to_string__value, NULL);
+}
+
+void UI_view2d_draw_scale_y__block(const ARegion *ar, const View2D *v2d, const rcti *rect)
+{
+ draw_vertical_scale_indicators(ar, v2d, 1.0f, 0.5f, rect, view_to_string__value, NULL);
+}
+
+void UI_view2d_draw_scale_x__discrete_frames_or_seconds(const struct ARegion *ar,
+ const struct View2D *v2d,
+ const struct rcti *rect,
+ const struct Scene *scene,
+ bool display_seconds)
+{
+ if (display_seconds) {
+ UI_view2d_draw_scale_x__discrete_time(ar, v2d, rect, scene);
+ }
+ else {
+ UI_view2d_draw_scale_x__discrete_values(ar, v2d, rect);
+ }
+}
+
+void UI_view2d_draw_scale_x__frames_or_seconds(const struct ARegion *ar,
+ const struct View2D *v2d,
+ const struct rcti *rect,
+ const struct Scene *scene,
+ bool display_seconds)
+{
+ if (display_seconds) {
+ UI_view2d_draw_scale_x__discrete_time(ar, v2d, rect, scene);
+ }
+ else {
+ UI_view2d_draw_scale_x__values(ar, v2d, rect);
+ }
+}