/* 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