diff options
| author | assiduous <assiduous@diligentgraphics.com> | 2020-06-06 22:48:13 +0000 |
|---|---|---|
| committer | assiduous <assiduous@diligentgraphics.com> | 2020-06-06 22:48:13 +0000 |
| commit | 496cd326b4336954932fc1c5bd3491fe920f2e1b (patch) | |
| tree | 04dd4a33f87615fd75c6a92d534d1aff2a395312 /Common/interface | |
| parent | MathLib: added IsPointInsideTriangle function (diff) | |
| download | DiligentCore-496cd326b4336954932fc1c5bd3491fe920f2e1b.tar.gz DiligentCore-496cd326b4336954932fc1c5bd3491fe920f2e1b.zip | |
MathLib: added RasterizeTriangle function
Diffstat (limited to 'Common/interface')
| -rw-r--r-- | Common/interface/AdvancedMath.hpp | 115 |
1 files changed, 115 insertions, 0 deletions
diff --git a/Common/interface/AdvancedMath.hpp b/Common/interface/AdvancedMath.hpp index 279ed153..d450ec1b 100644 --- a/Common/interface/AdvancedMath.hpp +++ b/Common/interface/AdvancedMath.hpp @@ -750,6 +750,121 @@ bool IsPointInsideTriangle(const Vector2<T>& V0, return IsPointInsideTriangle<T, T>(V0, V1, V2, Point, AllowEdges); } + +/// Rasterizes a triangle and calls the callback function for every sample covered. + +/// The samples are assumed to be located at integer coordinates. Samples located on +/// edges are always enumerated. Samples are enumerated row by row, bottom to top, +/// left to right. For example, for triangle (1, 1)-(1, 3)-(3, 1), +/// the following locations will be enumerated: +/// (1, 1), (2, 1), (3, 1), (1, 2), (2, 2), (1, 3). +/// +/// 3 * *. * * +/// | '. +/// 2 * * *. * +/// | '. +/// 1 * *---*---* +/// +/// 0 * * * * +/// 0 1 2 3 +/// +/// \tparam [in] T - Vertex component type. +/// \tparam TCallback - Type of the callback function. +/// +/// \param [in] V0 - First triangle vertex. +/// \param [in] V1 - Second triangle vertex. +/// \param [in] V2 - Third triangle vertex. +/// \param [in] Callback - Callback function that will be caled with the argument of type int2 +/// for every sample covered. +template <typename T, + class TCallback> +void RasterizeTriangle(Vector2<T> V0, + Vector2<T> V1, + Vector2<T> V2, + TCallback Callback) +{ + if (V1.y < V0.y) + std::swap(V1, V0); + if (V2.y < V0.y) + std::swap(V2, V0); + if (V2.y < V1.y) + std::swap(V2, V1); + + VERIFY_EXPR(V0.y <= V1.y && V1.y <= V2.y); + + const int iStartRow = static_cast<int>(FastCeil(V0.y)); + const int iEndRow = static_cast<int>(FastFloor(V2.y)); + + if (iStartRow == iEndRow) + { + auto iStartCol = static_cast<int>(FastCeil(min3(V0.x, V1.x, V2.x))); + auto iEndCol = static_cast<int>(FastFloor(max3(V0.x, V1.x, V2.x))); + for (int iCol = iStartCol; iCol <= iEndCol; ++iCol) + { + Callback(int2{iCol, iStartRow}); + } + return; + } + + auto LerpCol = [](T StartCol, T EndCol, T StartRow, T EndRow, int CurrRow) // + { + return StartCol + + ((EndCol - StartCol) * (static_cast<T>(CurrRow) - StartRow)) / (EndRow - StartRow); + }; + + for (int iRow = iStartRow; iRow <= iEndRow; ++iRow) + { + auto dStartCol = LerpCol(V0.x, V2.x, V0.y, V2.y, iRow); + + T dEndCol; + if (static_cast<T>(iRow) < V1.y) + { + // V2. + // V2-------V1 \' . + // | .' <- \ ' . V1 + // | .' <- \ / <- + // | .' <- \ / <- + // .' <- \/ <- + // V0 <- V0 <- + dEndCol = LerpCol(V0.x, V1.x, V0.y, V1.y, iRow); + } + else + { + if (V1.y < V2.y) + { + // V2. <- + // V2 <- \' . <- + // |'. <- \ ' . V1 <- + // | '. <- \ / + // | '. <- \ / + // | '. <- \/ + // V0-------V1 <- V0 + dEndCol = LerpCol(V1.x, V2.x, V1.y, V2.y, iRow); + } + else + { + // V2-------V1 <- + // | .' + // | .' + // | .' + // .' + // V0 + dEndCol = V1.x; + } + } + if (dStartCol > dEndCol) + std::swap(dStartCol, dEndCol); + + int iStartCol = static_cast<int>(FastCeil(dStartCol)); + int iEndCol = static_cast<int>(FastFloor(dEndCol)); + + for (int iCol = iStartCol; iCol <= iEndCol; ++iCol) + { + Callback(int2{iCol, iRow}); + } + } +} + } // namespace Diligent namespace std |
