File indexing completed on 2024-05-19 05:32:19

0001 /*
0002     SPDX-FileCopyrightText: 2006 Lubos Lunak <l.lunak@kde.org>
0003     SPDX-FileCopyrightText: 2022 Arjen Hiemstra <ahiemstra@heimr.nl>
0004 
0005     SPDX-License-Identifier: GPL-2.0-or-later
0006 */
0007 
0008 #pragma once
0009 
0010 #include "opengl/glvertexbuffer.h"
0011 
0012 namespace KWin
0013 {
0014 
0015 /**
0016  * @short Vertex class
0017  *
0018  * A vertex is one position in a window. WindowQuad consists of four WindowVertex objects
0019  * and represents one part of a window.
0020  */
0021 class KWIN_EXPORT WindowVertex
0022 {
0023 public:
0024     WindowVertex();
0025     WindowVertex(const QPointF &position, const QPointF &textureCoordinate);
0026     WindowVertex(double x, double y, double tx, double ty);
0027 
0028     double x() const
0029     {
0030         return px;
0031     }
0032     double y() const
0033     {
0034         return py;
0035     }
0036     double u() const
0037     {
0038         return tx;
0039     }
0040     double v() const
0041     {
0042         return ty;
0043     }
0044     void move(double x, double y);
0045     void setX(double x);
0046     void setY(double y);
0047 
0048 private:
0049     friend class WindowQuad;
0050     friend class WindowQuadList;
0051     double px, py; // position
0052     double tx, ty; // texture coords
0053 };
0054 
0055 /**
0056  * @short Class representing one area of a window.
0057  *
0058  * WindowQuads consists of four WindowVertex objects and represents one part of a window.
0059  */
0060 // NOTE: This class expects the (original) vertices to be in the clockwise order starting from topleft.
0061 class KWIN_EXPORT WindowQuad
0062 {
0063 public:
0064     WindowQuad();
0065     WindowQuad makeSubQuad(double x1, double y1, double x2, double y2) const;
0066     WindowVertex &operator[](int index);
0067     const WindowVertex &operator[](int index) const;
0068     double left() const;
0069     double right() const;
0070     double top() const;
0071     double bottom() const;
0072     QRectF bounds() const;
0073 
0074 private:
0075     friend class WindowQuadList;
0076     WindowVertex verts[4];
0077 };
0078 
0079 class KWIN_EXPORT WindowQuadList
0080     : public QList<WindowQuad>
0081 {
0082 public:
0083     WindowQuadList splitAtX(double x) const;
0084     WindowQuadList splitAtY(double y) const;
0085     WindowQuadList makeGrid(int maxquadsize) const;
0086     WindowQuadList makeRegularGrid(int xSubdivisions, int ySubdivisions) const;
0087 };
0088 
0089 /**
0090  * A helper class for render geometry in device coordinates.
0091  *
0092  * This mostly represents a vector of vertices, with some convenience methods
0093  * for easily converting from WindowQuad and related classes to lists of
0094  * GLVertex2D. This class assumes rendering happens as unindexed triangles.
0095  */
0096 class KWIN_EXPORT RenderGeometry : public QList<GLVertex2D>
0097 {
0098 public:
0099     /**
0100      * In what way should vertices snap to integer device coordinates?
0101      *
0102      * Vertices are converted to device coordinates before being sent to the
0103      * rendering system. Depending on scaling factors, this may lead to device
0104      * coordinates with fractional parts. For some cases, this may not be ideal
0105      * as fractional coordinates need to be interpolated and can lead to
0106      * "blurry" rendering. To avoid that, we can snap the vertices to integer
0107      * device coordinates when they are added.
0108      */
0109     enum class VertexSnappingMode {
0110         None, //< No rounding, device coordinates containing fractional parts
0111               //  are passed directly to the rendering system.
0112         Round, //< Perform a simple rounding, device coordinates will not have
0113                //  any fractional parts.
0114     };
0115 
0116     /**
0117      * The vertex snapping mode to use for this geometry.
0118      *
0119      * By default, this is VertexSnappingMode::Round.
0120      */
0121     inline VertexSnappingMode vertexSnappingMode() const
0122     {
0123         return m_vertexSnappingMode;
0124     }
0125     /**
0126      * Set the vertex snapping mode to use for this geometry.
0127      *
0128      * Note that this doesn't change vertices retroactively, so you should set
0129      * this before adding any vertices, or clear and rebuild the geometry after
0130      * setting it.
0131      *
0132      * @param mode The new rounding mode.
0133      */
0134     void setVertexSnappingMode(VertexSnappingMode mode)
0135     {
0136         m_vertexSnappingMode = mode;
0137     }
0138     /**
0139      * Copy geometry data into another buffer.
0140      *
0141      * This is primarily intended for copying into a vertex buffer for rendering.
0142      *
0143      * @param destination The destination buffer. This needs to be at least large
0144      *                    enough to contain all elements.
0145      */
0146     void copy(std::span<GLVertex2D> destination);
0147     /**
0148      * Append a WindowVertex as a geometry vertex.
0149      *
0150      * WindowVertex is assumed to be in logical coordinates. It will be converted
0151      * to device coordinates using the specified device scale and then rounded
0152      * so it fits correctly on the device pixel grid.
0153      *
0154      * @param windowVertex The WindowVertex instance to append.
0155      * @param deviceScale The scaling factor to use to go from logical to device
0156      *                    coordinates.
0157      */
0158     void appendWindowVertex(const WindowVertex &windowVertex, qreal deviceScale);
0159     /**
0160      * Append a WindowQuad as two triangles.
0161      *
0162      * This will append the corners of the specified WindowQuad in the right
0163      * order so they make two triangles that can be rendered by OpenGL. The
0164      * corners are converted to device coordinates and rounded, just like
0165      * `appendWindowVertex()` does.
0166      *
0167      * @param quad The WindowQuad instance to append.
0168      * @param deviceScale The scaling factor to use to go from logical to device
0169      *                    coordinates.
0170      */
0171     void appendWindowQuad(const WindowQuad &quad, qreal deviceScale);
0172     /**
0173      * Append a sub-quad of a WindowQuad as two triangles.
0174      *
0175      * This will append the sub-quad specified by `intersection` as two
0176      * triangles. The quad is expected to be in logical coordinates, while the
0177      * intersection is expected to be in device coordinates. The texture
0178      * coordinates of the resulting vertices are based upon those of the quad,
0179      * using bilinear interpolation for interpolating how much of the original
0180      * texture coordinates to use.
0181      *
0182      * @param quad The WindowQuad instance to use a sub-quad of.
0183      * @param subquad The sub-quad to append.
0184      * @param deviceScale The scaling factor used to convert from logical to
0185      *                    device coordinates.
0186      */
0187     void appendSubQuad(const WindowQuad &quad, const QRectF &subquad, qreal deviceScale);
0188     /**
0189      * Modify this geometry's texture coordinates based on a matrix.
0190      *
0191      * This is primarily intended to convert from non-normalised to normalised
0192      * texture coordinates.
0193      *
0194      * @param textureMatrix The texture matrix to use for modifying the
0195      *                      texture coordinates. Note that only the 2D scale and
0196      *                      translation are used.
0197      */
0198     void postProcessTextureCoordinates(const QMatrix4x4 &textureMatrix);
0199 
0200 private:
0201     VertexSnappingMode m_vertexSnappingMode = VertexSnappingMode::Round;
0202 };
0203 
0204 inline WindowVertex::WindowVertex()
0205     : px(0)
0206     , py(0)
0207     , tx(0)
0208     , ty(0)
0209 {
0210 }
0211 
0212 inline WindowVertex::WindowVertex(double _x, double _y, double _tx, double _ty)
0213     : px(_x)
0214     , py(_y)
0215     , tx(_tx)
0216     , ty(_ty)
0217 {
0218 }
0219 
0220 inline WindowVertex::WindowVertex(const QPointF &position, const QPointF &texturePosition)
0221     : px(position.x())
0222     , py(position.y())
0223     , tx(texturePosition.x())
0224     , ty(texturePosition.y())
0225 {
0226 }
0227 
0228 inline void WindowVertex::move(double x, double y)
0229 {
0230     px = x;
0231     py = y;
0232 }
0233 
0234 inline void WindowVertex::setX(double x)
0235 {
0236     px = x;
0237 }
0238 
0239 inline void WindowVertex::setY(double y)
0240 {
0241     py = y;
0242 }
0243 
0244 inline WindowQuad::WindowQuad()
0245 {
0246 }
0247 
0248 inline WindowVertex &WindowQuad::operator[](int index)
0249 {
0250     Q_ASSERT(index >= 0 && index < 4);
0251     return verts[index];
0252 }
0253 
0254 inline const WindowVertex &WindowQuad::operator[](int index) const
0255 {
0256     Q_ASSERT(index >= 0 && index < 4);
0257     return verts[index];
0258 }
0259 
0260 inline double WindowQuad::left() const
0261 {
0262     return std::min(verts[0].px, std::min(verts[1].px, std::min(verts[2].px, verts[3].px)));
0263 }
0264 
0265 inline double WindowQuad::right() const
0266 {
0267     return std::max(verts[0].px, std::max(verts[1].px, std::max(verts[2].px, verts[3].px)));
0268 }
0269 
0270 inline double WindowQuad::top() const
0271 {
0272     return std::min(verts[0].py, std::min(verts[1].py, std::min(verts[2].py, verts[3].py)));
0273 }
0274 
0275 inline double WindowQuad::bottom() const
0276 {
0277     return std::max(verts[0].py, std::max(verts[1].py, std::max(verts[2].py, verts[3].py)));
0278 }
0279 
0280 inline QRectF WindowQuad::bounds() const
0281 {
0282     return QRectF(QPointF(left(), top()), QPointF(right(), bottom()));
0283 }
0284 
0285 } // namespace KWin