1 | // Aseprite Render Library |
2 | // Copyright (c) 2020-2022 Igara Studio S.A. |
3 | // Copyright (c) 2001-2016 David Capello |
4 | // |
5 | // This file is released under the terms of the MIT license. |
6 | // Read LICENSE.txt for more information. |
7 | |
8 | #ifdef HAVE_CONFIG_H |
9 | #include "config.h" |
10 | #endif |
11 | |
12 | #include "base/debug.h" |
13 | #include "render/zoom.h" |
14 | |
15 | #include <algorithm> |
16 | |
17 | namespace render { |
18 | |
19 | static int scales[][2] = { |
20 | { 1, 64 }, |
21 | { 1, 48 }, |
22 | { 1, 32 }, |
23 | { 1, 24 }, |
24 | { 1, 16 }, |
25 | { 1, 12 }, |
26 | { 1, 8 }, |
27 | { 1, 6 }, |
28 | { 1, 5 }, |
29 | { 1, 4 }, |
30 | { 1, 3 }, |
31 | { 1, 2 }, |
32 | { 1, 1 }, // 100% |
33 | { 2, 1 }, |
34 | { 3, 1 }, |
35 | { 4, 1 }, |
36 | { 5, 1 }, |
37 | { 6, 1 }, |
38 | { 8, 1 }, |
39 | { 12, 1 }, |
40 | { 16, 1 }, |
41 | { 24, 1 }, |
42 | { 32, 1 }, |
43 | { 48, 1 }, |
44 | { 64, 1 }, |
45 | }; |
46 | |
47 | static int scales_size = sizeof(scales) / sizeof(scales[0]); |
48 | |
49 | Zoom::Zoom(int num, int den) |
50 | : m_num(num) |
51 | , m_den(den) |
52 | { |
53 | ASSERT(m_num > 0); |
54 | ASSERT(m_den > 0); |
55 | m_internalScale = scale(); |
56 | } |
57 | |
58 | bool Zoom::in() |
59 | { |
60 | int i = linearScale(); |
61 | if (i < scales_size-1) { |
62 | ++i; |
63 | m_num = scales[i][0]; |
64 | m_den = scales[i][1]; |
65 | m_internalScale = scale(); |
66 | return true; |
67 | } |
68 | else |
69 | return false; |
70 | } |
71 | |
72 | bool Zoom::out() |
73 | { |
74 | int i = linearScale(); |
75 | if (i > 0) { |
76 | --i; |
77 | m_num = scales[i][0]; |
78 | m_den = scales[i][1]; |
79 | m_internalScale = scale(); |
80 | return true; |
81 | } |
82 | else |
83 | return false; |
84 | } |
85 | |
86 | int Zoom::linearScale() const |
87 | { |
88 | for (int i=0; i<scales_size; ++i) { |
89 | // Exact match |
90 | if (scales[i][0] == m_num && |
91 | scales[i][1] == m_den) { |
92 | return i; |
93 | } |
94 | } |
95 | return findClosestLinearScale(scale()); |
96 | } |
97 | |
98 | // static |
99 | Zoom Zoom::fromScale(double scale) |
100 | { |
101 | Zoom zoom = fromLinearScale(findClosestLinearScale(scale)); |
102 | zoom.m_internalScale = scale; |
103 | return zoom; |
104 | } |
105 | |
106 | // static |
107 | Zoom Zoom::fromLinearScale(int i) |
108 | { |
109 | i = std::clamp(i, 0, scales_size-1); |
110 | return Zoom(scales[i][0], scales[i][1]); |
111 | } |
112 | |
113 | // static |
114 | int Zoom::findClosestLinearScale(double scale) |
115 | { |
116 | for (int i=1; i<scales_size-1; ++i) { |
117 | double min = double(scales[i-1][0]) / double(scales[i-1][1]); |
118 | double mid = double(scales[i ][0]) / double(scales[i ][1]); |
119 | double max = double(scales[i+1][0]) / double(scales[i+1][1]); |
120 | |
121 | if (scale >= (min+mid)/2.0 && |
122 | scale <= (mid+max)/2.0) |
123 | return i; |
124 | } |
125 | if (scale < 1.0) |
126 | return 0; |
127 | else |
128 | return scales_size-1; |
129 | } |
130 | |
131 | int Zoom::linearValues() |
132 | { |
133 | return scales_size; |
134 | } |
135 | |
136 | } // namespace render |
137 | |