mirror of
https://github.com/UberGames/GtkRadiant.git
synced 2024-11-30 07:31:30 +00:00
323 lines
7.4 KiB
C
323 lines
7.4 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
|
||
|
*/
|
||
|
|
||
|
#if !defined(INCLUDED_WINDING_H)
|
||
|
#define INCLUDED_WINDING_H
|
||
|
|
||
|
#include "debugging/debugging.h"
|
||
|
|
||
|
#include <vector>
|
||
|
|
||
|
#include "math/vector.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,
|
||
|
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<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;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
typedef BasicVector3<double> 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<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] = static_cast<float>(fixed[i].vertex[0]);
|
||
|
winding[i].vertex[1] = static_cast<float>(fixed[i].vertex[1]);
|
||
|
winding[i].vertex[2] = static_cast<float>(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
|