/* * Copyright (C) 2005-2018 Team Kodi * This file is part of Kodi - https://kodi.tv * * SPDX-License-Identifier: GPL-2.0-or-later * See LICENSES/README.md for more information. */ #pragma once #ifdef __GNUC__ // under gcc, inline will only take place if optimizations are applied (-O). this will force inline even with optimizations. #define XBMC_FORCE_INLINE __attribute__((always_inline)) #else #define XBMC_FORCE_INLINE #endif #include #include #include template class CPointGen { public: typedef CPointGen this_type; CPointGen() noexcept = default; constexpr CPointGen(T a, T b) : x{a}, y{b} {} template explicit constexpr CPointGen(const CPointGen& rhs) : x{static_cast (rhs.x)}, y{static_cast (rhs.y)} {} constexpr this_type operator+(const this_type &point) const { return {x + point.x, y + point.y}; }; this_type& operator+=(const this_type &point) { x += point.x; y += point.y; return *this; }; constexpr this_type operator-(const this_type &point) const { return {x - point.x, y - point.y}; }; this_type& operator-=(const this_type &point) { x -= point.x; y -= point.y; return *this; }; constexpr this_type operator*(T factor) const { return {x * factor, y * factor}; } this_type& operator*=(T factor) { x *= factor; y *= factor; return *this; } constexpr this_type operator/(T factor) const { return {x / factor, y / factor}; } this_type& operator/=(T factor) { x /= factor; y /= factor; return *this; } T x{}, y{}; }; template constexpr bool operator==(const CPointGen &point1, const CPointGen &point2) noexcept { return (point1.x == point2.x && point1.y == point2.y); } template constexpr bool operator!=(const CPointGen &point1, const CPointGen &point2) noexcept { return !(point1 == point2); } using CPoint = CPointGen; using CPointInt = CPointGen; /** * Generic two-dimensional size representation * * Class invariant: width and height are both non-negative * Throws std::out_of_range if invariant would be violated. The class * is exception-safe. If modification would violate the invariant, the size * is not changed. */ template class CSizeGen { T m_w{}, m_h{}; void CheckSet(T width, T height) { if (width < 0) { throw std::out_of_range("Size may not have negative width"); } if (height < 0) { throw std::out_of_range("Size may not have negative height"); } m_w = width; m_h = height; } public: typedef CSizeGen this_type; CSizeGen() noexcept = default; CSizeGen(T width, T height) { CheckSet(width, height); } T Width() const { return m_w; } T Height() const { return m_h; } void SetWidth(T width) { CheckSet(width, m_h); } void SetHeight(T height) { CheckSet(m_w, height); } void Set(T width, T height) { CheckSet(width, height); } bool IsZero() const { return (m_w == static_cast (0) && m_h == static_cast (0)); } T Area() const { return m_w * m_h; } CPointGen ToPoint() const { return {m_w, m_h}; } template explicit CSizeGen(const CSizeGen& rhs) { CheckSet(static_cast (rhs.m_w), static_cast (rhs.m_h)); } this_type operator+(const this_type& size) const { return {m_w + size.m_w, m_h + size.m_h}; }; this_type& operator+=(const this_type& size) { CheckSet(m_w + size.m_w, m_h + size.m_h); return *this; }; this_type operator-(const this_type& size) const { return {m_w - size.m_w, m_h - size.m_h}; }; this_type& operator-=(const this_type& size) { CheckSet(m_w - size.m_w, m_h - size.m_h); return *this; }; this_type operator*(T factor) const { return {m_w * factor, m_h * factor}; } this_type& operator*=(T factor) { CheckSet(m_w * factor, m_h * factor); return *this; } this_type operator/(T factor) const { return {m_w / factor, m_h / factor}; } this_type& operator/=(T factor) { CheckSet(m_w / factor, m_h / factor); return *this; } }; template inline bool operator==(const CSizeGen& size1, const CSizeGen& size2) noexcept { return (size1.Width() == size2.Width() && size1.Height() == size2.Height()); } template inline bool operator!=(const CSizeGen& size1, const CSizeGen& size2) noexcept { return !(size1 == size2); } using CSize = CSizeGen; using CSizeInt = CSizeGen; template class CRectGen { public: typedef CRectGen this_type; typedef CPointGen point_type; typedef CSizeGen size_type; CRectGen() noexcept = default; constexpr CRectGen(T left, T top, T right, T bottom) : x1{left}, y1{top}, x2{right}, y2{bottom} {} constexpr CRectGen(const point_type &p1, const point_type &p2) : x1{p1.x}, y1{p1.y}, x2{p2.x}, y2{p2.y} {} constexpr CRectGen(const point_type &origin, const size_type &size) : x1{origin.x}, y1{origin.y}, x2{x1 + size.Width()}, y2{y1 + size.Height()} {} template explicit constexpr CRectGen(const CRectGen& rhs) : x1{static_cast (rhs.x1)}, y1{static_cast (rhs.y1)}, x2{static_cast (rhs.x2)}, y2{static_cast (rhs.y2)} {} void SetRect(T left, T top, T right, T bottom) { x1 = left; y1 = top; x2 = right; y2 = bottom; } constexpr bool PtInRect(const point_type &point) const { return (x1 <= point.x && point.x <= x2 && y1 <= point.y && point.y <= y2); }; this_type& operator-=(const point_type &point) XBMC_FORCE_INLINE { x1 -= point.x; y1 -= point.y; x2 -= point.x; y2 -= point.y; return *this; }; constexpr this_type operator-(const point_type &point) const { return {x1 - point.x, y1 - point.y, x2 - point.x, y2 - point.y}; } this_type& operator+=(const point_type &point) XBMC_FORCE_INLINE { x1 += point.x; y1 += point.y; x2 += point.x; y2 += point.y; return *this; }; constexpr this_type operator+(const point_type &point) const { return {x1 + point.x, y1 + point.y, x2 + point.x, y2 + point.y}; } this_type& operator-=(const size_type &size) { x2 -= size.Width(); y2 -= size.Height(); return *this; }; constexpr this_type operator-(const size_type &size) const { return {x1, y1, x2 - size.Width(), y2 - size.Height()}; } this_type& operator+=(const size_type &size) { x2 += size.Width(); y2 += size.Height(); return *this; }; constexpr this_type operator+(const size_type &size) const { return {x1, y1, x2 + size.Width(), y2 + size.Height()}; } this_type& Intersect(const this_type &rect) { x1 = clamp_range(x1, rect.x1, rect.x2); x2 = clamp_range(x2, rect.x1, rect.x2); y1 = clamp_range(y1, rect.y1, rect.y2); y2 = clamp_range(y2, rect.y1, rect.y2); return *this; }; this_type& Union(const this_type &rect) { if (IsEmpty()) *this = rect; else if (!rect.IsEmpty()) { x1 = std::min(x1,rect.x1); y1 = std::min(y1,rect.y1); x2 = std::max(x2,rect.x2); y2 = std::max(y2,rect.y2); } return *this; }; constexpr bool IsEmpty() const XBMC_FORCE_INLINE { return (x2 - x1) * (y2 - y1) == 0; }; constexpr point_type P1() const XBMC_FORCE_INLINE { return {x1, y1}; } constexpr point_type P2() const XBMC_FORCE_INLINE { return {x2, y2}; } constexpr T Width() const XBMC_FORCE_INLINE { return x2 - x1; }; constexpr T Height() const XBMC_FORCE_INLINE { return y2 - y1; }; constexpr T Area() const XBMC_FORCE_INLINE { return Width() * Height(); }; size_type ToSize() const { return {Width(), Height()}; }; std::vector SubtractRect(this_type splitterRect) { std::vector newRectanglesList; this_type intersection = splitterRect.Intersect(*this); if (!intersection.IsEmpty()) { this_type add; // add rect above intersection if not empty add = this_type(x1, y1, x2, intersection.y1); if (!add.IsEmpty()) newRectanglesList.push_back(add); // add rect below intersection if not empty add = this_type(x1, intersection.y2, x2, y2); if (!add.IsEmpty()) newRectanglesList.push_back(add); // add rect left intersection if not empty add = this_type(x1, intersection.y1, intersection.x1, intersection.y2); if (!add.IsEmpty()) newRectanglesList.push_back(add); // add rect right intersection if not empty add = this_type(intersection.x2, intersection.y1, x2, intersection.y2); if (!add.IsEmpty()) newRectanglesList.push_back(add); } else { newRectanglesList.push_back(*this); } return newRectanglesList; } std::vector SubtractRects(std::vector intersectionList) { std::vector fragmentsList; fragmentsList.push_back(*this); for (typename std::vector::iterator splitter = intersectionList.begin(); splitter != intersectionList.end(); ++splitter) { typename std::vector toAddList; for (typename std::vector::iterator fragment = fragmentsList.begin(); fragment != fragmentsList.end(); ++fragment) { std::vector newFragmentsList = fragment->SubtractRect(*splitter); toAddList.insert(toAddList.end(), newFragmentsList.begin(), newFragmentsList.end()); } fragmentsList.clear(); fragmentsList.insert(fragmentsList.end(), toAddList.begin(), toAddList.end()); } return fragmentsList; } void GetQuad(point_type (&points)[4]) { points[0] = { x1, y1 }; points[1] = { x2, y1 }; points[2] = { x2, y2 }; points[3] = { x1, y2 }; } T x1{}, y1{}, x2{}, y2{}; private: static constexpr T clamp_range(T x, T l, T h) XBMC_FORCE_INLINE { return (x > h) ? h : ((x < l) ? l : x); } }; template constexpr bool operator==(const CRectGen &rect1, const CRectGen &rect2) noexcept { return (rect1.x1 == rect2.x1 && rect1.y1 == rect2.y1 && rect1.x2 == rect2.x2 && rect1.y2 == rect2.y2); } template constexpr bool operator!=(const CRectGen &rect1, const CRectGen &rect2) noexcept { return !(rect1 == rect2); } using CRect = CRectGen; using CRectInt = CRectGen;