/* * Copyright (C) 2020 Christopher J. Howard * * This file is part of Antkeeper source code. * * Antkeeper source code is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Antkeeper source code is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Antkeeper source code. If not, see . */ #ifndef ANTKEEPER_VIEW_FRUSTUM_HPP #define ANTKEEPER_VIEW_FRUSTUM_HPP #include "convex-hull.hpp" #include #include using vmq::vector; using vmq::matrix; using namespace vmq::operators; template class view_frustum { public: /** * Creates a view frustum from a view-projection matrix. * * @param view_projection View-projection matrix. */ view_frustum(const matrix& view_projection); /// Creates an uninitialized view frustum. view_frustum(); /** * Recalculates the view frustum from a view-projection matrix. * * @param view_projection View-projection matrix. */ void set_matrix(const matrix& view_projection); /// Returns a convex hull which describes the bounds of the view frustum. const convex_hull& get_bounds() const; /// Returns the left clipping plane. const plane& get_left() const; /// Returns the right clipping plane. const plane& get_right() const; /// Returns the bottom clipping plane. const plane& get_bottom() const; /// Returns the top clipping plane. const plane& get_top() const; /// Returns the near clipping plane. const plane& get_near() const; /// Returns the far clipping plane. const plane& get_far() const; /** * Returns an array containing the corners of the view frustum bounds. * * @return Array containing the corners of the view frustum bounds. Corners are stored in the following order: NTL, NTR, NBL, NBR, FTL, FTR, FBL, FBR; where N is near, F is far, T is top, B is bottom, L is left, and R is right, therefore NTL refers to the corner shared between the near, top, and left clipping planes. */ const std::array, 8>& get_corners() const; private: void recalculate_planes(const matrix& view_projection); void recalculate_corners(); convex_hull bounds; std::array, 8> corners; }; template view_frustum::view_frustum(const matrix& view_projection): bounds(6) { set_matrix(view_projection); } template view_frustum::view_frustum(): view_frustum(vmq::identity4x4) {} template void view_frustum::set_matrix(const matrix& view_projection) { recalculate_planes(view_projection); recalculate_corners(); } template inline const convex_hull& view_frustum::get_bounds() const { return bounds; } template inline const plane& view_frustum::get_left() const { return bounds.planes[0]; } template inline const plane& view_frustum::get_right() const { return bounds.planes[1]; } template inline const plane& view_frustum::get_bottom() const { return bounds.planes[2]; } template inline const plane& view_frustum::get_top() const { return bounds.planes[3]; } template inline const plane& view_frustum::get_near() const { return bounds.planes[4]; } template inline const plane& view_frustum::get_far() const { return bounds.planes[5]; } template inline const std::array, 8>& view_frustum::get_corners() const { return corners; } template void view_frustum::recalculate_planes(const matrix& view_projection) { matrix transpose = vmq::transpose(view_projection); bounds.planes[0] = plane(transpose[3] + transpose[0]); bounds.planes[1] = plane(transpose[3] - transpose[0]); bounds.planes[2] = plane(transpose[3] + transpose[1]); bounds.planes[3] = plane(transpose[3] - transpose[1]); bounds.planes[4] = plane(transpose[3] + transpose[2]); bounds.planes[5] = plane(transpose[3] - transpose[2]); } template void view_frustum::recalculate_corners() { corners[0] = intersection(get_near(), get_top(), get_left()); corners[1] = intersection(get_near(), get_top(), get_right()); corners[2] = intersection(get_near(), get_bottom(), get_left()); corners[3] = intersection(get_near(), get_bottom(), get_right()); corners[4] = intersection(get_far(), get_top(), get_left()); corners[5] = intersection(get_far(), get_top(), get_right()); corners[6] = intersection(get_far(), get_bottom(), get_left()); corners[7] = intersection(get_far(), get_bottom(), get_right()); } #endif // ANTKEEPER_VIEW_FRUSTUM_HPP