]> de.git.xonotic.org Git - voretournament/voretournament.git/blobdiff - misc/mediasource/netradiant-src/contrib/bobtoolz/DWinding.cpp
Move the netradiant and fteqcc sources
[voretournament/voretournament.git] / misc / mediasource / netradiant-src / contrib / bobtoolz / DWinding.cpp
diff --git a/misc/mediasource/netradiant-src/contrib/bobtoolz/DWinding.cpp b/misc/mediasource/netradiant-src/contrib/bobtoolz/DWinding.cpp
new file mode 100644 (file)
index 0000000..2068f3f
--- /dev/null
@@ -0,0 +1,485 @@
+/*
+BobToolz plugin for GtkRadiant
+Copyright (C) 2001 Gordon Biggans
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library 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
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+// DWinding.cpp: implementation of the DWinding class.
+//
+//////////////////////////////////////////////////////////////////////
+
+#include "DWinding.h"
+
+#include <list>
+
+#include "DPoint.h"
+#include "DPlane.h"
+
+//////////////////////////////////////////////////////////////////////
+// Construction/Destruction
+//////////////////////////////////////////////////////////////////////
+
+DWinding::DWinding()
+{
+       numpoints = 0;
+       p = NULL;
+}
+
+DWinding::~DWinding()
+{
+       if(p)
+               delete[] p;
+}
+
+//////////////////////////////////////////////////////////////////////
+// Implementation
+//////////////////////////////////////////////////////////////////////
+
+#define        BOGUS_RANGE     4096
+
+void DWinding::AllocWinding(int points)
+{
+       numpoints = points;
+       if(p)
+               delete[] p;
+       p = new vec3_t[points];
+}
+
+vec_t DWinding::WindingArea()
+{
+       vec3_t  d1, d2, cross;
+       vec_t   total;
+
+       total = 0;
+       for (int i = 2; i < numpoints ; i++)
+       {
+               VectorSubtract (p[i-1], p[0], d1);
+               VectorSubtract (p[i], p[0], d2);
+
+               CrossProduct (d1, d2, cross);
+
+               total += 0.5f * VectorLength ( cross );
+       }
+
+       return total;
+}
+
+void DWinding::RemoveColinearPoints()
+{
+       vec3_t  p2[MAX_POINTS_ON_WINDING];
+
+       int nump = 0;
+       for (int i = 0; i < numpoints; i++)
+       {
+               int j = (i+1)%numpoints;
+               int k = (i+numpoints-1)%numpoints;
+
+               vec3_t  v1, v2;
+               VectorSubtract (p[j], p[i], v1);
+               VectorSubtract (p[i], p[k], v2);
+               VectorNormalize(v1, v1);
+               VectorNormalize(v2, v2);
+
+               if (DotProduct(v1, v2) < 0.999)
+               {
+                       VectorCopy (p[i], p2[nump]);
+                       nump++;
+               }
+       }
+
+       if (nump == numpoints)
+               return;
+
+       AllocWinding(nump);
+       memcpy (p, p2, nump*sizeof(vec3_t));
+}
+
+DPlane* DWinding::WindingPlane()
+{
+       DPlane* newPlane = new DPlane(p[0], p[1], p[2], NULL);
+       return newPlane;
+}
+
+void DWinding::WindingBounds(vec3_t mins, vec3_t maxs)
+{
+       if(numpoints == 0)
+               return;
+
+       VectorCopy(mins, p[0]);
+       VectorCopy(maxs, p[0]);
+
+       for (int i = 1; i < numpoints ;i++)
+       {
+               for (int j = 0; j < 3; j++)
+               {
+                       vec_t v = p[i][j];
+                       if (v < mins[j])
+                               mins[j] = v;
+                       if (v > maxs[j])
+                               maxs[j] = v;
+               }
+       }
+}
+
+void DWinding::WindingCentre(vec3_t centre)
+{
+       VectorCopy (vec3_origin, centre);
+       for (int i = 0; i < numpoints; i++)
+               VectorAdd (p[i], centre, centre);
+
+       float scale = 1.0f/numpoints;
+       VectorScale (centre, scale, centre);
+}
+
+
+DWinding* DWinding::CopyWinding()
+{
+       DWinding* c = new DWinding;
+       c->AllocWinding(numpoints);
+       memcpy (c->p, p, numpoints*sizeof(vec3_t));
+       return c;
+}
+
+
+int DWinding::WindingOnPlaneSide(vec3_t normal, vec_t dist)
+{
+       bool front = false;
+       bool back = false;
+
+       for (int i = 0; i < numpoints; i++)
+       {
+               vec_t d = DotProduct (p[i], normal) - dist;
+               if (d < -ON_EPSILON)
+               {
+                       if (front)
+                               return SIDE_CROSS;
+                       back = true;
+                       continue;
+               }
+               if (d > ON_EPSILON)
+               {
+                       if (back)
+                               return SIDE_CROSS;
+                       front = true;
+                       continue;
+               }
+       }
+
+       if (back)
+               return SIDE_BACK;
+       if (front)
+               return SIDE_FRONT;
+       return SIDE_ON;
+}
+
+void DWinding::CheckWinding()
+{
+       vec_t   *p1, *p2;
+       vec_t   edgedist;
+       vec3_t  dir, edgenormal;
+
+       if (numpoints < 3)
+               globalOutputStream() << "CheckWinding: " << numpoints << " points\n";
+       
+       vec_t area = WindingArea();
+       if (area < 1)
+               globalOutputStream() << "CheckWinding: " << area << " area\n";
+
+       DPlane* wPlane = WindingPlane ();
+       int i;
+       for (i = 0; i < numpoints; i++)
+       {
+               p1 = p[i];
+
+               int j;
+               for (j = 0; j < 3; j++)
+                       if (p1[j] > BOGUS_RANGE || p1[j] < -BOGUS_RANGE)
+                               globalOutputStream() << "CheckFace: BOGUS_RANGE: " << p1[j] << "\n";
+
+               j = i + 1 == numpoints ? 0 : i + 1;
+               
+               // check the point is on the face plane
+               vec_t d = DotProduct (p1, wPlane->normal) - wPlane->_d;
+               if (d < -ON_EPSILON || d > ON_EPSILON)
+                       globalOutputStream() << "CheckWinding: point off plane\n";
+       
+               // check the edge isnt degenerate
+               p2 = p[j];
+               VectorSubtract (p2, p1, dir);
+               
+               if (VectorLength (dir) < ON_EPSILON)
+                       globalOutputStream() << "CheckWinding: degenerate edge\n";
+                       
+               CrossProduct (wPlane->normal, dir, edgenormal);
+               VectorNormalize (edgenormal, edgenormal);
+               edgedist = DotProduct (p1, edgenormal);
+               
+               // all other points must be on front side
+               for (j = 0 ; j < numpoints ; j++)
+               {
+                       if (j == i)
+                               continue;
+
+                       d = DotProduct (p[j], edgenormal);
+                       if (d > (edgedist + ON_EPSILON))
+                               globalOutputStream() << "CheckWinding: non-convex\n";
+               }
+       }
+
+       delete wPlane;
+}
+
+DWinding* DWinding::ReverseWinding()
+{
+       DWinding* c = new DWinding;
+       c->AllocWinding(numpoints);
+
+       for (int i = 0; i < numpoints ; i++)
+               VectorCopy (p[numpoints-1-i], c->p[i]);
+
+       return c;
+}
+
+bool DWinding::ChopWindingInPlace(DPlane* chopPlane, vec_t epsilon)
+{
+       vec_t   dists[MAX_POINTS_ON_WINDING+4];
+       int             sides[MAX_POINTS_ON_WINDING+4];
+       int             counts[3];
+       vec_t   *p1, *p2;
+       vec3_t  mid;
+
+       counts[0] = counts[1] = counts[2] = 0;
+
+// determine sides for each point
+       int i;
+       for (i = 0; i < numpoints; i++)
+       {
+               vec_t dot = DotProduct (p[i], chopPlane->normal);
+               dot -= chopPlane->_d;
+               dists[i] = dot;
+               
+               if (dot > epsilon)
+                       sides[i] = SIDE_FRONT;
+               else if (dot < -epsilon)
+                       sides[i] = SIDE_BACK;
+               else
+                       sides[i] = SIDE_ON;
+
+               counts[sides[i]]++;
+       }
+       sides[i] = sides[0];
+       dists[i] = dists[0];
+       
+       if (!counts[0])
+       {
+               delete this;
+               return false;
+       }
+
+       if (!counts[1])
+               return true;
+
+       int maxpts = numpoints+4;       // cant use counts[0]+2 because
+                                                               // of fp grouping errors
+
+       DWinding* f = new DWinding;
+       f->AllocWinding(maxpts);
+       f->numpoints = 0;
+               
+       for (i = 0; i < numpoints; i++)
+       {
+               p1 = p[i];
+               
+               if (sides[i] == SIDE_ON)
+               {
+                       VectorCopy (p1, f->p[f->numpoints]);
+                       f->numpoints++;
+                       continue;
+               }
+       
+               if (sides[i] == SIDE_FRONT)
+               {
+                       VectorCopy (p1, f->p[f->numpoints]);
+                       f->numpoints++;
+               }
+
+               if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
+                       continue;
+                       
+       // generate a split point
+               p2 = p[(i+1)%numpoints];
+               
+               vec_t dot = dists[i] / (dists[i]-dists[i+1]);
+               for (int j = 0; j < 3; j++)
+               {
+                       if (chopPlane->normal[j] == 1)
+                               mid[j] = chopPlane->_d;
+                       else if (chopPlane->normal[j] == -1)
+                               mid[j] = -chopPlane->_d;
+                       else
+                               mid[j] = p1[j] + dot*(p2[j]-p1[j]);
+               }
+                       
+               VectorCopy (mid, f->p[f->numpoints]);
+               f->numpoints++;
+       }
+       
+       if (f->numpoints > maxpts)
+               globalOutputStream() << "ClipWinding: points exceeded estimate\n";
+       if (f->numpoints > MAX_POINTS_ON_WINDING)
+               globalOutputStream() << "ClipWinding: MAX_POINTS_ON_WINDING\n";
+
+       delete[] p;
+       p = f->p;
+       f->p = NULL;
+       delete f;
+       return true;
+}
+
+void DWinding::ClipWindingEpsilon(DPlane* chopPlane, vec_t epsilon, DWinding **front, DWinding **back)
+{
+       vec_t   dists[MAX_POINTS_ON_WINDING+4];
+       int             sides[MAX_POINTS_ON_WINDING+4];
+       int             counts[3];
+       vec_t   *p1, *p2;
+       vec3_t  mid;
+       
+       counts[0] = counts[1] = counts[2] = 0;
+
+// determine sides for each point
+       int i;
+       for (i = 0; i < numpoints; i++)
+       {
+               vec_t dot = -chopPlane->DistanceToPoint(p[i]);
+               dists[i] = dot;
+               
+               if (dot > epsilon)
+                       sides[i] = SIDE_FRONT;
+               else if (dot < -epsilon)
+                       sides[i] = SIDE_BACK;
+               else
+                       sides[i] = SIDE_ON;
+
+               counts[sides[i]]++;
+       }
+       sides[i] = sides[0];
+       dists[i] = dists[0];
+       
+       *front = *back = NULL;
+
+       if (!counts[0])
+       {
+               *back = CopyWinding();
+               return;
+       }
+       if (!counts[1])
+       {
+               *front = CopyWinding();
+               return;
+       }
+
+       int maxpts = numpoints+4;       // cant use counts[0]+2 because
+                                                               // of fp grouping errors
+
+       DWinding* f = new DWinding;
+       DWinding* b = new DWinding;
+
+       f->AllocWinding(maxpts);
+       f->numpoints = 0;
+
+       b->AllocWinding(maxpts);
+       b->numpoints = 0;
+               
+       *front = f;
+       *back = b;
+
+       for (i = 0; i < numpoints ; i++)
+       {
+               p1 = p[i];
+               
+               if (sides[i] == SIDE_ON)
+               {
+                       VectorCopy (p1, f->p[f->numpoints]);
+                       f->numpoints++;
+                       VectorCopy (p1, b->p[b->numpoints]);
+                       b->numpoints++;
+                       continue;
+               }
+       
+               if (sides[i] == SIDE_FRONT)
+               {
+                       VectorCopy (p1, f->p[f->numpoints]);
+                       f->numpoints++;
+               }
+               if (sides[i] == SIDE_BACK)
+               {
+                       VectorCopy (p1, b->p[b->numpoints]);
+                       b->numpoints++;
+               }
+
+               if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
+                       continue;
+                       
+       // generate a split point
+               p2 = p[(i+1)%numpoints];
+               
+               vec_t dot = dists[i] / (dists[i]-dists[i+1]);
+               for (int j = 0; j < 3; j++)
+               {
+                       if (chopPlane->normal[j] == 1)
+                               mid[j] = chopPlane->_d;
+                       else if (chopPlane->normal[j] == -1)
+                               mid[j] = -chopPlane->_d;
+                       else
+                               mid[j] = p1[j] + dot*(p2[j]-p1[j]);
+               }
+                       
+               VectorCopy (mid, f->p[f->numpoints]);
+               f->numpoints++;
+               VectorCopy (mid, b->p[b->numpoints]);
+               b->numpoints++;
+       }
+       
+       if (f->numpoints > maxpts || b->numpoints > maxpts)
+               globalOutputStream() << "ClipWinding: points exceeded estimate\n";
+       if (f->numpoints > MAX_POINTS_ON_WINDING || b->numpoints > MAX_POINTS_ON_WINDING)
+               globalOutputStream() << "ClipWinding: MAX_POINTS_ON_WINDING\n";
+}
+
+bool DWinding::ChopWinding(DPlane* chopPlane)
+{
+       DWinding *f, *b;
+
+       ClipWindingEpsilon (chopPlane, (float)ON_EPSILON, &f, &b);
+
+       if (b)
+               delete (b);
+
+
+       if(!f)
+       {
+               delete this;
+               return false;
+       }
+
+       delete[] p;
+       p = f->p;
+       f->p = NULL;
+       numpoints = f->numpoints;
+       delete f;
+
+       return true;
+}