|
|
//========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#include "stdafx.h"
#include <stdio.h>
#include <math.h>
#include "hammer.h"
#include "MapEntity.h"
#include "MapDefs.h"
#include "MapFace.h"
#include "hammer_mathlib.h"
#include "history.h"
#include "Error3d.h"
#include "BrushOps.h"
#include "GlobalFunctions.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
#pragma warning( disable : 4244 ) // Disable warning messages
#define SIDE_FRONT 0
#define SIDE_BACK 1
#define SIDE_ON 2
#define BOGUS_RANGE ( MAX_COORD_INTEGER * 4 )
float lightaxis[3] = {1, 0.6f, 0.75f};
const int MAX_POINTS_ON_WINDING = 128;
void Error(char* fmt, ...) { char str[300]; sprintf(str, fmt, (&fmt)+1); Msg(mwError, str); }
/*
=============================================================================
TURN PLANES INTO GROUPS OF FACES
============================================================================= */
/*
================== NewWinding ================== */ winding_t *NewWinding (int points) { winding_t *w;
if (points > MAX_POINTS_ON_WINDING) Error ("NewWinding: %i points", points);
w = (winding_t *)malloc(sizeof(*w)); w->numpoints = 0; // None are occupied yet even though allocated.
w->p = (Vector *)calloc( points, sizeof(Vector) );
return w; }
void FreeWinding (winding_t *w) { if (*(unsigned *)w == 0xdeaddead) Error ("FreeWinding: freed a freed winding"); *(unsigned *)w = 0xdeaddead;
if (w->p) { free (w->p); w->p = NULL; } free (w); }
size_t WindingSize(int points) { return (size_t)(&((winding_t *)0)->p[points]); }
//-----------------------------------------------------------------------------
// Purpose: Removes points that are withing a given distance from each other
// from the winding.
// Input : pWinding - The winding to remove duplicates from.
// fMinDist - The minimum distance two points must be from one another
// to be considered different. If this is zero, the points must be
// identical to be considered duplicates.
//-----------------------------------------------------------------------------
void RemoveDuplicateWindingPoints(winding_t *pWinding, float fMinDist) { for (int i = 0; i < pWinding->numpoints; i++) { for (int j = i + 1; j < pWinding->numpoints; j++) { Vector edge; VectorSubtract(pWinding->p[i], pWinding->p[j], edge);
if (VectorLength(edge) < fMinDist) { if (j + 1 < pWinding->numpoints) { memmove(&pWinding->p[j], &pWinding->p[j + 1], (pWinding->numpoints - (j + 1)) * sizeof(pWinding->p[0])); }
pWinding->numpoints--; } } } }
/*
================== CopyWinding ================== */ winding_t *CopyWinding (winding_t *w) { int size; winding_t *c;
c = NewWinding (w->numpoints); c->numpoints = w->numpoints; size = w->numpoints*sizeof(w->p[0]); memcpy (c->p, w->p, size); return c; }
/*
================== ClipWinding
Clips the winding to the plane, returning the new winding on the positive side Frees the input winding. ================== */ // YWB ADDED SPLIT EPS to match qcsg splitting
#define SPLIT_EPSILON 0.01
winding_t *ClipWinding (winding_t *in, PLANE *split) { float dists[MAX_POINTS_ON_WINDING]; int sides[MAX_POINTS_ON_WINDING]; int counts[3]; float dot; int i, j; Vector *p1, *p2, *mid; winding_t *neww; int maxpts;
counts[0] = counts[1] = counts[2] = 0;
// determine sides for each point
for (i=0 ; i<in->numpoints ; i++) { dot = DotProduct (in->p[i], split->normal); dot -= split->dist; dists[i] = dot; if (dot > SPLIT_EPSILON) sides[i] = SIDE_FRONT; else if (dot < -SPLIT_EPSILON) sides[i] = SIDE_BACK; else { sides[i] = SIDE_ON; } counts[sides[i]]++; } sides[i] = sides[0]; dists[i] = dists[0];
if (!counts[0] && !counts[1]) return in;
if (!counts[0]) { free (in); return NULL; } if (!counts[1]) return in;
maxpts = in->numpoints+4; // can't use counts[0]+2 because
// of fp grouping errors
neww = NewWinding (maxpts);
for (i=0 ; i<in->numpoints ; i++) { p1 = &in->p[i];
mid = &neww->p[neww->numpoints];
if (sides[i] == SIDE_FRONT || sides[i] == SIDE_ON) { *mid = *p1; neww->numpoints++; if (sides[i] == SIDE_ON) continue; mid = &neww->p[neww->numpoints]; }
if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i]) continue;
// generate a split point
if (i == in->numpoints - 1) p2 = &in->p[0]; else p2 = p1 + 1;
neww->numpoints++;
dot = dists[i] / (dists[i]-dists[i+1]); for (j=0 ; j<3 ; j++) { // avoid round off error when possible
if (split->normal[j] == 1) mid[0][j] = split->dist; else if (split->normal[j] == -1) mid[0][j] = -split->dist; mid[0][j] = p1[0][j] + dot*(p2[0][j]-p1[0][j]); } // mid[3] = p1[3] + dot*(p2[3]-p1[3]);
// mid[4] = p1[4] + dot*(p2[4]-p1[4]);
}
if (neww->numpoints > maxpts) Error ("ClipWinding: points exceeded estimate");
// free the original winding
FreeWinding (in);
return neww; }
//-----------------------------------------------------------------------------
// Purpose: Creates a huge quadrilateral winding given a plane.
// Input : pPlane - Plane normal and distance to use when creating the winding.
// Output : Returns a winding with 4 points.
//-----------------------------------------------------------------------------
// dvs: read through this and clean it up
winding_t *CreateWindingFromPlane(PLANE *pPlane) { int i, x; float max, v; Vector org, vright, vup; winding_t *w; // find the major axis
max = -BOGUS_RANGE; x = -1; for (i=0 ; i<3; i++) { v = fabs(pPlane->normal[i]); if (v > max) { x = i; max = v; } } if (x==-1) Error ("BasePolyForPlane: no axis found");
vup = vec3_origin; switch (x) { case 0: case 1: vup[2] = 1; break; case 2: vup[0] = 1; break; }
v = DotProduct (vup, pPlane->normal); VectorMA (vup, -v, pPlane->normal, vup); VectorNormalize (vup);
org = pPlane->normal * pPlane->dist;
CrossProduct (vup, pPlane->normal, vright);
vup = vup * MAX_TRACE_LENGTH; vright = vright * MAX_TRACE_LENGTH;
// project a really big axis aligned box onto the plane
w = NewWinding (4); w->numpoints = 4;
VectorSubtract (org, vright, w->p[0]); VectorAdd (w->p[0], vup, w->p[0]);
VectorAdd (org, vright, w->p[1]); VectorAdd (w->p[1], vup, w->p[1]);
VectorAdd (org, vright, w->p[2]); VectorSubtract (w->p[2], vup, w->p[2]);
VectorSubtract (org, vright, w->p[3]); VectorSubtract (w->p[3], vup, w->p[3]);
return w; }
static CArray<error3d, error3d&> Errors; static int nErrors;
void Add3dError(DWORD dwObjectID, LPCTSTR pszReason, PVOID pInfo) { error3d err; err.dwObjectID = dwObjectID; err.pszReason = pszReason; err.pInfo = pInfo; Errors.Add(err); ++nErrors; }
int Get3dErrorCount() { return nErrors; }
error3d * Enum3dErrors(BOOL bStart) { static int iCurrent = 0;
if(bStart) iCurrent = 0;
if(iCurrent == nErrors) return NULL;
return & Errors.GetData()[iCurrent++]; }
|