KWin
Loading...
Searching...
No Matches
itemgeometry.cpp
Go to the documentation of this file.
1/*
2 SPDX-FileCopyrightText: 2006 Lubos Lunak <l.lunak@kde.org>
3 SPDX-FileCopyrightText: 2022 Arjen Hiemstra <ahiemstra@heimr.nl>
4
5 SPDX-License-Identifier: GPL-2.0-or-later
6*/
7
9#include "effect/globals.h"
10
11#include <QMatrix4x4>
12
13namespace KWin
14{
15
16WindowQuad WindowQuad::makeSubQuad(double x1, double y1, double x2, double y2) const
17{
18 Q_ASSERT(x1 < x2 && y1 < y2 && x1 >= left() && x2 <= right() && y1 >= top() && y2 <= bottom());
19 WindowQuad ret(*this);
20 // vertices are clockwise starting from topleft
21 ret.verts[0].px = x1;
22 ret.verts[3].px = x1;
23 ret.verts[1].px = x2;
24 ret.verts[2].px = x2;
25 ret.verts[0].py = y1;
26 ret.verts[1].py = y1;
27 ret.verts[2].py = y2;
28 ret.verts[3].py = y2;
29
30 const double xOrigin = left();
31 const double yOrigin = top();
32
33 const double widthReciprocal = 1 / (right() - xOrigin);
34 const double heightReciprocal = 1 / (bottom() - yOrigin);
35
36 for (int i = 0; i < 4; ++i) {
37 const double w1 = (ret.verts[i].px - xOrigin) * widthReciprocal;
38 const double w2 = (ret.verts[i].py - yOrigin) * heightReciprocal;
39
40 // Use bilinear interpolation to compute the texture coords.
41 ret.verts[i].tx = (1 - w1) * (1 - w2) * verts[0].tx + w1 * (1 - w2) * verts[1].tx + w1 * w2 * verts[2].tx + (1 - w1) * w2 * verts[3].tx;
42 ret.verts[i].ty = (1 - w1) * (1 - w2) * verts[0].ty + w1 * (1 - w2) * verts[1].ty + w1 * w2 * verts[2].ty + (1 - w1) * w2 * verts[3].ty;
43 }
44
45 return ret;
46}
47
49{
51 ret.reserve(count());
52 for (const WindowQuad &quad : *this) {
53 bool wholeleft = true;
54 bool wholeright = true;
55 for (int i = 0; i < 4; ++i) {
56 if (quad[i].x() < x) {
57 wholeright = false;
58 }
59 if (quad[i].x() > x) {
60 wholeleft = false;
61 }
62 }
63 if (wholeleft || wholeright) { // is whole in one split part
64 ret.append(quad);
65 continue;
66 }
67 if (quad.top() == quad.bottom() || quad.left() == quad.right()) { // quad has no size
68 ret.append(quad);
69 continue;
70 }
71 ret.append(quad.makeSubQuad(quad.left(), quad.top(), x, quad.bottom()));
72 ret.append(quad.makeSubQuad(x, quad.top(), quad.right(), quad.bottom()));
73 }
74 return ret;
75}
76
78{
80 ret.reserve(count());
81 for (const WindowQuad &quad : *this) {
82 bool wholetop = true;
83 bool wholebottom = true;
84 for (int i = 0; i < 4; ++i) {
85 if (quad[i].y() < y) {
86 wholebottom = false;
87 }
88 if (quad[i].y() > y) {
89 wholetop = false;
90 }
91 }
92 if (wholetop || wholebottom) { // is whole in one split part
93 ret.append(quad);
94 continue;
95 }
96 if (quad.top() == quad.bottom() || quad.left() == quad.right()) { // quad has no size
97 ret.append(quad);
98 continue;
99 }
100 ret.append(quad.makeSubQuad(quad.left(), quad.top(), quad.right(), y));
101 ret.append(quad.makeSubQuad(quad.left(), y, quad.right(), quad.bottom()));
102 }
103 return ret;
104}
105
107{
108 if (empty()) {
109 return *this;
110 }
111
112 // Find the bounding rectangle
113 double left = first().left();
114 double right = first().right();
115 double top = first().top();
116 double bottom = first().bottom();
117
118 for (const WindowQuad &quad : std::as_const(*this)) {
119 left = std::min(left, quad.left());
120 right = std::max(right, quad.right());
121 top = std::min(top, quad.top());
122 bottom = std::max(bottom, quad.bottom());
123 }
124
125 WindowQuadList ret;
126
127 for (const WindowQuad &quad : std::as_const(*this)) {
128 const double quadLeft = quad.left();
129 const double quadRight = quad.right();
130 const double quadTop = quad.top();
131 const double quadBottom = quad.bottom();
132
133 // sanity check, see BUG 390953
134 if (quadLeft == quadRight || quadTop == quadBottom) {
135 ret.append(quad);
136 continue;
137 }
138
139 // Compute the top-left corner of the first intersecting grid cell
140 const double xBegin = left + qFloor((quadLeft - left) / maxQuadSize) * maxQuadSize;
141 const double yBegin = top + qFloor((quadTop - top) / maxQuadSize) * maxQuadSize;
142
143 // Loop over all intersecting cells and add sub-quads
144 for (double y = yBegin; y < quadBottom; y += maxQuadSize) {
145 const double y0 = std::max(y, quadTop);
146 const double y1 = std::min(quadBottom, y + maxQuadSize);
147
148 for (double x = xBegin; x < quadRight; x += maxQuadSize) {
149 const double x0 = std::max(x, quadLeft);
150 const double x1 = std::min(quadRight, x + maxQuadSize);
151
152 ret.append(quad.makeSubQuad(x0, y0, x1, y1));
153 }
154 }
155 }
156
157 return ret;
158}
159
160WindowQuadList WindowQuadList::makeRegularGrid(int xSubdivisions, int ySubdivisions) const
161{
162 if (empty()) {
163 return *this;
164 }
165
166 // Find the bounding rectangle
167 double left = first().left();
168 double right = first().right();
169 double top = first().top();
170 double bottom = first().bottom();
171
172 for (const WindowQuad &quad : *this) {
173 left = std::min(left, quad.left());
174 right = std::max(right, quad.right());
175 top = std::min(top, quad.top());
176 bottom = std::max(bottom, quad.bottom());
177 }
178
179 double xIncrement = (right - left) / xSubdivisions;
180 double yIncrement = (bottom - top) / ySubdivisions;
181
182 WindowQuadList ret;
183
184 for (const WindowQuad &quad : *this) {
185 const double quadLeft = quad.left();
186 const double quadRight = quad.right();
187 const double quadTop = quad.top();
188 const double quadBottom = quad.bottom();
189
190 // sanity check, see BUG 390953
191 if (quadLeft == quadRight || quadTop == quadBottom) {
192 ret.append(quad);
193 continue;
194 }
195
196 // Compute the top-left corner of the first intersecting grid cell
197 const double xBegin = left + qFloor((quadLeft - left) / xIncrement) * xIncrement;
198 const double yBegin = top + qFloor((quadTop - top) / yIncrement) * yIncrement;
199
200 // Loop over all intersecting cells and add sub-quads
201 for (double y = yBegin; y < quadBottom; y += yIncrement) {
202 const double y0 = std::max(y, quadTop);
203 const double y1 = std::min(quadBottom, y + yIncrement);
204
205 for (double x = xBegin; x < quadRight; x += xIncrement) {
206 const double x0 = std::max(x, quadLeft);
207 const double x1 = std::min(quadRight, x + xIncrement);
208
209 ret.append(quad.makeSubQuad(x0, y0, x1, y1));
210 }
211 }
212 }
213
214 return ret;
215}
216
217void RenderGeometry::copy(std::span<GLVertex2D> destination)
218{
219 Q_ASSERT(int(destination.size()) >= size());
220 std::copy(cbegin(), cend(), destination.begin());
221}
222
223void RenderGeometry::appendWindowVertex(const WindowVertex &windowVertex, qreal deviceScale)
224{
225 GLVertex2D glVertex;
226 switch (m_vertexSnappingMode) {
228 glVertex.position = QVector2D(windowVertex.x(), windowVertex.y()) * deviceScale;
229 break;
231 glVertex.position = roundVector(QVector2D(windowVertex.x(), windowVertex.y()) * deviceScale);
232 break;
233 }
234 glVertex.texcoord = QVector2D(windowVertex.u(), windowVertex.v());
235 append(glVertex);
236}
237
238void RenderGeometry::appendWindowQuad(const WindowQuad &quad, qreal deviceScale)
239{
240 // Geometry assumes we're rendering triangles, so add the quad's
241 // vertices as two triangles. Vertex order is top-left, bottom-left,
242 // top-right followed by top-right, bottom-left, bottom-right.
243 appendWindowVertex(quad[0], deviceScale);
244 appendWindowVertex(quad[3], deviceScale);
245 appendWindowVertex(quad[1], deviceScale);
246
247 appendWindowVertex(quad[1], deviceScale);
248 appendWindowVertex(quad[3], deviceScale);
249 appendWindowVertex(quad[2], deviceScale);
250}
251
252void RenderGeometry::appendSubQuad(const WindowQuad &quad, const QRectF &subquad, qreal deviceScale)
253{
254 std::array<GLVertex2D, 4> vertices;
255 vertices[0].position = QVector2D(subquad.topLeft());
256 vertices[1].position = QVector2D(subquad.topRight());
257 vertices[2].position = QVector2D(subquad.bottomRight());
258 vertices[3].position = QVector2D(subquad.bottomLeft());
259
260 const auto deviceQuad = QRectF{QPointF(std::round(quad.left() * deviceScale), std::round(quad.top() * deviceScale)),
261 QPointF(std::round(quad.right() * deviceScale), std::round(quad.bottom() * deviceScale))};
262
263 const QPointF origin = deviceQuad.topLeft();
264 const QSizeF size = deviceQuad.size();
265
266#pragma GCC unroll 4
267 for (int i = 0; i < 4; ++i) {
268 const double weight1 = (vertices[i].position.x() - origin.x()) / size.width();
269 const double weight2 = (vertices[i].position.y() - origin.y()) / size.height();
270 const double oneMinW1 = 1.0 - weight1;
271 const double oneMinW2 = 1.0 - weight2;
272
273 const float u = oneMinW1 * oneMinW2 * quad[0].u() + weight1 * oneMinW2 * quad[1].u()
274 + weight1 * weight2 * quad[2].u() + oneMinW1 * weight2 * quad[3].u();
275 const float v = oneMinW1 * oneMinW2 * quad[0].v() + weight1 * oneMinW2 * quad[1].v()
276 + weight1 * weight2 * quad[2].v() + oneMinW1 * weight2 * quad[3].v();
277 vertices[i].texcoord = QVector2D(u, v);
278 }
279
280 append(vertices[0]);
281 append(vertices[3]);
282 append(vertices[1]);
283
284 append(vertices[1]);
285 append(vertices[3]);
286 append(vertices[2]);
287}
288
289void RenderGeometry::postProcessTextureCoordinates(const QMatrix4x4 &textureMatrix)
290{
291 if (!textureMatrix.isIdentity()) {
292 const QVector2D coeff(textureMatrix(0, 0), textureMatrix(1, 1));
293 const QVector2D offset(textureMatrix(0, 3), textureMatrix(1, 3));
294
295 for (auto &vertex : (*this)) {
296 vertex.texcoord = vertex.texcoord * coeff + offset;
297 }
298 }
299}
300
301} // namespace KWin
void postProcessTextureCoordinates(const QMatrix4x4 &textureMatrix)
void appendWindowQuad(const WindowQuad &quad, qreal deviceScale)
void copy(std::span< GLVertex2D > destination)
void appendSubQuad(const WindowQuad &quad, const QRectF &subquad, qreal deviceScale)
void appendWindowVertex(const WindowVertex &windowVertex, qreal deviceScale)
Class representing one area of a window.
double left() const
double bottom() const
double right() const
WindowQuad makeSubQuad(double x1, double y1, double x2, double y2) const
double top() const
WindowQuadList makeGrid(int maxquadsize) const
WindowQuadList splitAtY(double y) const
WindowQuadList splitAtX(double x) const
WindowQuadList makeRegularGrid(int xSubdivisions, int ySubdivisions) const
Vertex class.
double x() const
double u() const
double v() const
double y() const
KWIN_EXPORT QVector2D roundVector(const QVector2D &input)
Definition globals.h:251