Wed, 25 May 2022 20:36:34 +0300
Fix pick() picking from weird places on the screen with high DPI scaling
glReadPixels reads data from the frame buffer, which contains data after
high DPI scaling, so any reads to that need to take this scaling into account
3 | 1 | /* |
2 | * LDForge: LDraw parts authoring CAD | |
24 | 3 | * Copyright (C) 2013 - 2020 Teemu Piippo |
3 | 4 | * |
5 | * This program is free software: you can redistribute it and/or modify | |
6 | * it under the terms of the GNU General Public License as published by | |
7 | * the Free Software Foundation, either version 3 of the License, or | |
8 | * (at your option) any later version. | |
9 | * | |
10 | * This program is distributed in the hope that it will be useful, | |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | * GNU General Public License for more details. | |
14 | * | |
15 | * You should have received a copy of the GNU General Public License | |
16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | |
17 | */ | |
18 | ||
19 | #pragma once | |
8
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
7
diff
changeset
|
20 | #include <algorithm> |
3 | 21 | #include <cstdio> |
22 | #include <cstdlib> | |
8
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
7
diff
changeset
|
23 | #include <cstring> |
3 | 24 | #include <cmath> |
53 | 25 | #include <optional> |
96 | 26 | #include <type_traits> |
3 | 27 | #include <QMatrix4x4> |
28 | #include <QObject> | |
29 | #include <QPointF> | |
30 | #include <QSet> | |
31 | #include <QString> | |
32 | #include <QStringList> | |
33 | #include <QVariant> | |
34 | #include <QVector> | |
35 | #include <QVector3D> | |
33
4c41bfe2ec6e
replaced matrix and vertex classes with glm
Teemu Piippo <teemu@hecknology.net>
parents:
26
diff
changeset
|
36 | #include <glm/glm.hpp> |
3 | 37 | |
38 | using GLRotationMatrix = QMatrix4x4; | |
39 | ||
40 | enum Axis | |
41 | { | |
21 | 42 | X = 0, |
43 | Y = 1, | |
44 | Z = 2 | |
3 | 45 | }; |
46 | ||
26 | 47 | enum Result |
48 | { | |
49 | Success = 0, | |
50 | PartialSuccess, | |
51 | Failure | |
52 | }; | |
53 | ||
54 | constexpr bool failed(Result r) | |
55 | { | |
56 | return r == Failure; | |
57 | } | |
58 | ||
3 | 59 | enum Winding |
60 | { | |
61 | NoWinding, | |
8
44679e468ba9
major update with many things
Teemu Piippo <teemu@hecknology.net>
parents:
7
diff
changeset
|
62 | Anticlockwise, |
3 | 63 | Clockwise, |
64 | }; | |
65 | ||
66 | /* | |
67 | * Special operator definition that implements the XOR operator for windings. | |
68 | * However, if either winding is NoWinding, then this function returns NoWinding. | |
69 | */ | |
70 | inline Winding operator^(Winding one, Winding other) | |
71 | { | |
72 | if (one == NoWinding or other == NoWinding) | |
73 | return NoWinding; | |
74 | else | |
75 | return static_cast<Winding>(static_cast<int>(one) ^ static_cast<int>(other)); | |
76 | } | |
77 | ||
78 | inline Winding& operator^=(Winding& one, Winding other) | |
79 | { | |
80 | one = one ^ other; | |
81 | return one; | |
82 | } | |
21 | 83 | |
84 | template<typename T, int N> | |
90
e234edb5e613
remove dependency on glut, fixes
Teemu Piippo <teemu@hecknology.net>
parents:
70
diff
changeset
|
85 | constexpr int countof(T const (&)[N]) |
21 | 86 | { |
87 | return N; | |
88 | } | |
33
4c41bfe2ec6e
replaced matrix and vertex classes with glm
Teemu Piippo <teemu@hecknology.net>
parents:
26
diff
changeset
|
89 | |
51 | 90 | /** |
91 | * @brief casts @c x to a suitable unsigned integer | |
92 | */ | |
93 | template<typename T> | |
94 | constexpr auto unsigned_cast(T x) | |
95 | -> std::enable_if_t<std::is_integral_v<T>, std::make_unsigned_t<T>> | |
96 | { | |
97 | return static_cast<std::make_unsigned_t<T>>(x); | |
98 | } | |
99 | ||
100 | /** | |
101 | * @brief casts @c x to a suitable signed integer | |
102 | */ | |
103 | template<typename T> | |
104 | constexpr auto signed_cast(T x) | |
105 | -> std::enable_if_t<std::is_integral_v<T>, std::make_signed_t<T>> | |
106 | { | |
107 | return static_cast<std::make_signed_t<T>>(x); | |
108 | } | |
109 | ||
53 | 110 | |
111 | /** | |
55 | 112 | * @brief casts floating point values to float, converting non-floating point values causes an error |
113 | * @param[in] x floating point value to cast | |
53 | 114 | * @returns float |
115 | */ | |
116 | template<typename T> | |
55 | 117 | auto toFloat(T x) -> std::enable_if_t<std::is_floating_point_v<T>, float> |
53 | 118 | { |
119 | return static_cast<float>(x); | |
120 | } | |
121 | ||
122 | /** | |
55 | 123 | * @brief casts floating point values to double, converting non-floating point values causes an error |
124 | * @param[in] x floating point value to cast | |
53 | 125 | * @returns double |
126 | */ | |
127 | template<typename T> | |
55 | 128 | auto toDouble(T x) -> std::enable_if_t<std::is_floating_point_v<T>, double> |
53 | 129 | { |
130 | return static_cast<double>(x); | |
131 | } | |
55 | 132 | |
81
62373840e33a
object editor widgets start to form up
Teemu Piippo <teemu@hecknology.net>
parents:
70
diff
changeset
|
133 | /** |
62373840e33a
object editor widgets start to form up
Teemu Piippo <teemu@hecknology.net>
parents:
70
diff
changeset
|
134 | * @brief casts floating point values to qreal, converting non-floating point values causes an error |
62373840e33a
object editor widgets start to form up
Teemu Piippo <teemu@hecknology.net>
parents:
70
diff
changeset
|
135 | * @param[in] x floating point value to cast |
62373840e33a
object editor widgets start to form up
Teemu Piippo <teemu@hecknology.net>
parents:
70
diff
changeset
|
136 | * @returns qreal |
62373840e33a
object editor widgets start to form up
Teemu Piippo <teemu@hecknology.net>
parents:
70
diff
changeset
|
137 | */ |
62373840e33a
object editor widgets start to form up
Teemu Piippo <teemu@hecknology.net>
parents:
70
diff
changeset
|
138 | template<typename T> |
62373840e33a
object editor widgets start to form up
Teemu Piippo <teemu@hecknology.net>
parents:
70
diff
changeset
|
139 | auto toQreal(T x) -> std::enable_if_t<std::is_floating_point_v<T>, qreal> |
62373840e33a
object editor widgets start to form up
Teemu Piippo <teemu@hecknology.net>
parents:
70
diff
changeset
|
140 | { |
62373840e33a
object editor widgets start to form up
Teemu Piippo <teemu@hecknology.net>
parents:
70
diff
changeset
|
141 | return static_cast<qreal>(x); |
62373840e33a
object editor widgets start to form up
Teemu Piippo <teemu@hecknology.net>
parents:
70
diff
changeset
|
142 | } |
62373840e33a
object editor widgets start to form up
Teemu Piippo <teemu@hecknology.net>
parents:
70
diff
changeset
|
143 | |
55 | 144 | template<int N, typename T, glm::qualifier Q> |
145 | inline QPoint toQPoint(const glm::vec<N, T, Q>& vec) | |
146 | { | |
147 | return {static_cast<int>(vec.x), static_cast<int>(vec.y)}; | |
148 | } | |
149 | ||
150 | template<int N, typename T, glm::qualifier Q> | |
151 | inline QPointF toQPointF(const glm::vec<N, T, Q>& vec) | |
152 | { | |
153 | return {toDouble(vec.x), toDouble(vec.y)}; | |
154 | } | |
155 | ||
156 | inline glm::vec2 toVec2(const QPoint& point) | |
157 | { | |
158 | return {point.x(), point.y()}; | |
159 | } | |
160 | ||
161 | inline glm::vec2 toVec2(const QPointF& point) | |
162 | { | |
163 | return {point.x(), point.y()}; | |
164 | } | |
165 | ||
96 | 166 | /* |
167 | * coalesce(arg1, arg2, ..., argn) | |
168 | * Returns the first of the given arguments that evaluates to true. | |
169 | */ | |
170 | template<typename T> | |
171 | T coalesce(T&& arg) | |
172 | { | |
173 | // recursion base: 1 argument | |
174 | return arg; | |
175 | } | |
176 | ||
177 | template<typename T, typename... Rest> | |
178 | std::common_type_t<T, Rest...> coalesce(T&& arg, Rest&&... rest) | |
179 | { | |
180 | // general case: n arguments | |
181 | return arg ? arg : coalesce(rest...); | |
182 | } | |
183 | ||
148 | 184 | /** |
185 | * @brief Finds an element in a map and possibly returns a reference to it if find | |
186 | * @param map | |
187 | * @param key | |
188 | * @returns the value or nullptr if not found | |
189 | */ | |
190 | template<typename T, typename R, typename K> | |
191 | const R* findInMap(const std::map<T, R>& map, K&& key) | |
192 | { | |
193 | auto pair = map.find(key); | |
194 | if (pair != map.end()) | |
195 | { | |
196 | return &pair->second; | |
197 | } | |
198 | else | |
199 | { | |
200 | return nullptr; | |
201 | } | |
202 | } | |
203 | ||
204 | /** | |
205 | * @brief Finds an element in a map and possibly returns a reference to it if find | |
206 | * @param map | |
207 | * @param key | |
208 | * @returns the value or no value if not found | |
209 | */ | |
210 | template<typename T, typename R, typename K> | |
211 | R* findInMap(std::map<T, R>& map, K&& key) | |
212 | { | |
213 | auto pair = map.find(key); | |
214 | if (pair != map.end()) | |
215 | { | |
216 | return &pair->second; | |
217 | } | |
218 | else | |
219 | { | |
220 | return nullptr; | |
221 | } | |
222 | } | |
223 | ||
191
d355d4c52d51
made editing tools not a polymorphic class tree
Teemu Piippo <teemu@hecknology.net>
parents:
148
diff
changeset
|
224 | template<typename T = float> |
d355d4c52d51
made editing tools not a polymorphic class tree
Teemu Piippo <teemu@hecknology.net>
parents:
148
diff
changeset
|
225 | constexpr std::enable_if_t<std::is_floating_point_v<T>, T> pi = static_cast<T>(M_PIl); |
196 | 226 | constexpr double infinity = std::numeric_limits<double>::infinity(); |
227 | ||
70 | 228 | |
33
4c41bfe2ec6e
replaced matrix and vertex classes with glm
Teemu Piippo <teemu@hecknology.net>
parents:
26
diff
changeset
|
229 | Q_DECLARE_METATYPE(glm::vec3) |
4c41bfe2ec6e
replaced matrix and vertex classes with glm
Teemu Piippo <teemu@hecknology.net>
parents:
26
diff
changeset
|
230 | Q_DECLARE_METATYPE(glm::mat4) |