netradiant-custom/radiant/winding.h
Garux df02774ff5 tweak StringOutputStream use
auto str = StringOutputStream()(bla) use form was not doing copy elision or move, but copy
2024-01-29 16:54:08 +06:00

278 lines
7.3 KiB
C++

/*
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
*/
#pragma once
#include "debugging/debugging.h"
#include <vector>
#include "math/vector.h"
#include "math/line.h"
#include "container/array.h"
enum ProjectionAxis
{
eProjectionAxisX = 0,
eProjectionAxisY = 1,
eProjectionAxisZ = 2,
};
const float ProjectionAxisEpsilon = static_cast<float>( 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, //! in front of plane ---->| *
ePlaneBack = 1, //! behind the plane -*-->|
ePlaneOn = 2,
};
#define MAX_POINTS_ON_WINDING 64
const std::size_t c_brush_maxFaces = 1024;
class WindingVertex
{
public:
DoubleVector3 vertex;
Vector2 texcoord;
Vector3 tangent;
Vector3 bitangent;
std::size_t adjacent;
};
struct Winding
{
typedef Array<WindingVertex> 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;
}
};
class FixedWindingVertex
{
public:
DoubleVector3 vertex;
DoubleRay edge;
std::size_t adjacent;
FixedWindingVertex( const DoubleVector3& vertex_, const DoubleRay& edge_, std::size_t adjacent_ )
: vertex( vertex_ ), edge( edge_ ), adjacent( adjacent_ ){
}
};
struct FixedWinding
{
typedef std::vector<FixedWindingVertex> 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] = fixed[i].vertex[0];
winding[i].vertex[1] = fixed[i].vertex[1];
winding[i].vertex[2] = 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 );
}
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 DoubleVector3& x, const DoubleVector3& 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 );
void WindingVertex_ClassifyPlane( const DoubleVector3& vertex, const Plane3& plane, brushsplit_t& split );
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: " << vertexIndex << " adjacent: " << ( *i ).adjacent << '\n';
}
}