/* Copyright (C) 1999-2006 Id Software, Inc. and contributors. For a list of contributors, see the accompanying CONTRIBUTORS file. This file is part of GtkRadiant. GtkRadiant 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 2 of the License, or (at your option) any later version. GtkRadiant 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 GtkRadiant; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #if !defined(INCLUDED_WINDING_H) #define INCLUDED_WINDING_H #include "debugging/debugging.h" #include #include "math/vector.h" #include "container/array.h" enum ProjectionAxis { eProjectionAxisX = 0, eProjectionAxisY = 1, eProjectionAxisZ = 2, }; const float ProjectionAxisEpsilon = static_cast(0.0001); inline bool projectionaxis_better(float axis, float other) { return fabs(axis) > fabs(other) + ProjectionAxisEpsilon; } /// \brief Texture axis precedence: Z > X > Y inline ProjectionAxis projectionaxis_for_normal(const Vector3& normal) { return (projectionaxis_better(normal[eProjectionAxisY], normal[eProjectionAxisX])) ? (projectionaxis_better(normal[eProjectionAxisY], normal[eProjectionAxisZ])) ? eProjectionAxisY : eProjectionAxisZ : (projectionaxis_better(normal[eProjectionAxisX], normal[eProjectionAxisZ])) ? eProjectionAxisX : eProjectionAxisZ; } struct indexremap_t { indexremap_t(std::size_t _x, std::size_t _y, std::size_t _z) : x(_x), y(_y), z(_z) { } std::size_t x, y, z; }; inline indexremap_t indexremap_for_projectionaxis(const ProjectionAxis axis) { switch(axis) { case eProjectionAxisX: return indexremap_t(1, 2, 0); case eProjectionAxisY: return indexremap_t(2, 0, 1); default: return indexremap_t(0, 1, 2); } } enum PlaneClassification { ePlaneFront = 0, ePlaneBack = 1, ePlaneOn = 2, }; #define MAX_POINTS_ON_WINDING 64 const std::size_t c_brush_maxFaces = 1024; class WindingVertex { public: Vector3 vertex; Vector2 texcoord; Vector3 tangent; Vector3 bitangent; std::size_t adjacent; }; struct Winding { typedef Array container_type; std::size_t numpoints; container_type points; typedef container_type::iterator iterator; typedef container_type::const_iterator const_iterator; Winding() : numpoints(0) { } Winding(std::size_t size) : numpoints(0), points(size) { } void resize(std::size_t size) { points.resize(size); numpoints = 0; } iterator begin() { return points.begin(); } const_iterator begin() const { return points.begin(); } iterator end() { return points.begin() + numpoints; } const_iterator end() const { return points.begin() + numpoints; } WindingVertex& operator[](std::size_t index) { ASSERT_MESSAGE(index < points.size(), "winding: index out of bounds"); return points[index]; } const WindingVertex& operator[](std::size_t index) const { ASSERT_MESSAGE(index < points.size(), "winding: index out of bounds"); return points[index]; } void push_back(const WindingVertex& point) { points[numpoints] = point; ++numpoints; } void erase(iterator point) { for(iterator i = point + 1; i != end(); point = i, ++i) { *point = *i; } --numpoints; } }; typedef BasicVector3 DoubleVector3; class DoubleLine { public: DoubleVector3 origin; DoubleVector3 direction; }; class FixedWindingVertex { public: DoubleVector3 vertex; DoubleLine edge; std::size_t adjacent; FixedWindingVertex(const DoubleVector3& vertex_, const DoubleLine& edge_, std::size_t adjacent_) : vertex(vertex_), edge(edge_), adjacent(adjacent_) { } }; struct FixedWinding { typedef std::vector Points; Points points; FixedWinding() { points.reserve(MAX_POINTS_ON_WINDING); } FixedWindingVertex& front() { return points.front(); } const FixedWindingVertex& front() const { return points.front(); } FixedWindingVertex& back() { return points.back(); } const FixedWindingVertex& back() const { return points.back(); } void clear() { points.clear(); } void push_back(const FixedWindingVertex& point) { points.push_back(point); } std::size_t size() const { return points.size(); } FixedWindingVertex& operator[](std::size_t index) { //ASSERT_MESSAGE(index < MAX_POINTS_ON_WINDING, "winding: index out of bounds"); return points[index]; } const FixedWindingVertex& operator[](std::size_t index) const { //ASSERT_MESSAGE(index < MAX_POINTS_ON_WINDING, "winding: index out of bounds"); return points[index]; } }; inline void Winding_forFixedWinding(Winding& winding, const FixedWinding& fixed) { winding.resize(fixed.size()); winding.numpoints = fixed.size(); for(std::size_t i = 0; i < fixed.size(); ++i) { winding[i].vertex[0] = static_cast(fixed[i].vertex[0]); winding[i].vertex[1] = static_cast(fixed[i].vertex[1]); winding[i].vertex[2] = static_cast(fixed[i].vertex[2]); winding[i].adjacent = fixed[i].adjacent; } } inline std::size_t Winding_wrap(const Winding& winding, std::size_t i) { ASSERT_MESSAGE(winding.numpoints != 0, "Winding_wrap: empty winding"); return i % winding.numpoints; } inline std::size_t Winding_next(const Winding& winding, std::size_t i) { return Winding_wrap(winding, ++i); } class Plane3; void Winding_createInfinite(FixedWinding& w, const Plane3& plane, double infinity); const double ON_EPSILON = 1.0 / (1 << 8); /// \brief Returns true if edge (\p x, \p y) is smaller than the epsilon used to classify winding points against a plane. inline bool Edge_isDegenerate(const Vector3& x, const Vector3& y) { return vector3_length_squared(y - x) < (ON_EPSILON * ON_EPSILON); } void Winding_Clip(const FixedWinding& winding, const Plane3& plane, const Plane3& clipPlane, std::size_t adjacent, FixedWinding& clipped); struct brushsplit_t { brushsplit_t() { counts[0] = 0; counts[1] = 0; counts[2] = 0; } brushsplit_t& operator+=(const brushsplit_t& other) { counts[0] += other.counts[0]; counts[1] += other.counts[1]; counts[2] += other.counts[2]; return *this; } std::size_t counts[3]; }; brushsplit_t Winding_ClassifyPlane(const Winding& w, const Plane3& plane); bool Winding_PlanesConcave(const Winding& w1, const Winding& w2, const Plane3& plane1, const Plane3& plane2); bool Winding_TestPlane(const Winding& w, const Plane3& plane, bool flipped); std::size_t Winding_FindAdjacent(const Winding& w, std::size_t face); std::size_t Winding_Opposite(const Winding& w, const std::size_t index, const std::size_t other); std::size_t Winding_Opposite(const Winding& w, std::size_t index); void Winding_Centroid(const Winding& w, const Plane3& plane, Vector3& centroid); inline void Winding_printConnectivity(Winding& winding) { for(Winding::iterator i = winding.begin(); i != winding.end(); ++i) { std::size_t vertexIndex = std::distance(winding.begin(), i); globalOutputStream() << "vertex: " << Unsigned(vertexIndex) << " adjacent: " << Unsigned((*i).adjacent) << "\n"; } } #endif