Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

353 lines
7.0 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "stdafx.h"
  8. #include <stdio.h>
  9. #include <math.h>
  10. #include "hammer.h"
  11. #include "MapEntity.h"
  12. #include "MapDefs.h"
  13. #include "MapFace.h"
  14. #include "hammer_mathlib.h"
  15. #include "history.h"
  16. #include "Error3d.h"
  17. #include "BrushOps.h"
  18. #include "GlobalFunctions.h"
  19. // memdbgon must be the last include file in a .cpp file!!!
  20. #include "tier0/memdbgon.h"
  21. #pragma warning( disable : 4244 ) // Disable warning messages
  22. #define SIDE_FRONT 0
  23. #define SIDE_BACK 1
  24. #define SIDE_ON 2
  25. #define BOGUS_RANGE ( MAX_COORD_INTEGER * 4 )
  26. float lightaxis[3] = {1, 0.6f, 0.75f};
  27. const int MAX_POINTS_ON_WINDING = 128;
  28. void Error(char* fmt, ...)
  29. {
  30. char str[300];
  31. sprintf(str, fmt, (&fmt)+1);
  32. Msg(mwError, str);
  33. }
  34. /*
  35. =============================================================================
  36. TURN PLANES INTO GROUPS OF FACES
  37. =============================================================================
  38. */
  39. /*
  40. ==================
  41. NewWinding
  42. ==================
  43. */
  44. winding_t *NewWinding (int points)
  45. {
  46. winding_t *w;
  47. if (points > MAX_POINTS_ON_WINDING)
  48. Error ("NewWinding: %i points", points);
  49. w = (winding_t *)malloc(sizeof(*w));
  50. w->numpoints = 0; // None are occupied yet even though allocated.
  51. w->p = (Vector *)calloc( points, sizeof(Vector) );
  52. return w;
  53. }
  54. void FreeWinding (winding_t *w)
  55. {
  56. if (*(unsigned *)w == 0xdeaddead)
  57. Error ("FreeWinding: freed a freed winding");
  58. *(unsigned *)w = 0xdeaddead;
  59. if (w->p)
  60. {
  61. free (w->p);
  62. w->p = NULL;
  63. }
  64. free (w);
  65. }
  66. size_t WindingSize(int points)
  67. {
  68. return (size_t)(&((winding_t *)0)->p[points]);
  69. }
  70. //-----------------------------------------------------------------------------
  71. // Purpose: Removes points that are withing a given distance from each other
  72. // from the winding.
  73. // Input : pWinding - The winding to remove duplicates from.
  74. // fMinDist - The minimum distance two points must be from one another
  75. // to be considered different. If this is zero, the points must be
  76. // identical to be considered duplicates.
  77. //-----------------------------------------------------------------------------
  78. void RemoveDuplicateWindingPoints(winding_t *pWinding, float fMinDist)
  79. {
  80. for (int i = 0; i < pWinding->numpoints; i++)
  81. {
  82. for (int j = i + 1; j < pWinding->numpoints; j++)
  83. {
  84. Vector edge;
  85. VectorSubtract(pWinding->p[i], pWinding->p[j], edge);
  86. if (VectorLength(edge) < fMinDist)
  87. {
  88. if (j + 1 < pWinding->numpoints)
  89. {
  90. memmove(&pWinding->p[j], &pWinding->p[j + 1], (pWinding->numpoints - (j + 1)) * sizeof(pWinding->p[0]));
  91. }
  92. pWinding->numpoints--;
  93. }
  94. }
  95. }
  96. }
  97. /*
  98. ==================
  99. CopyWinding
  100. ==================
  101. */
  102. winding_t *CopyWinding (winding_t *w)
  103. {
  104. int size;
  105. winding_t *c;
  106. c = NewWinding (w->numpoints);
  107. c->numpoints = w->numpoints;
  108. size = w->numpoints*sizeof(w->p[0]);
  109. memcpy (c->p, w->p, size);
  110. return c;
  111. }
  112. /*
  113. ==================
  114. ClipWinding
  115. Clips the winding to the plane, returning the new winding on the positive side
  116. Frees the input winding.
  117. ==================
  118. */
  119. // YWB ADDED SPLIT EPS to match qcsg splitting
  120. #define SPLIT_EPSILON 0.01
  121. winding_t *ClipWinding (winding_t *in, PLANE *split)
  122. {
  123. float dists[MAX_POINTS_ON_WINDING];
  124. int sides[MAX_POINTS_ON_WINDING];
  125. int counts[3];
  126. float dot;
  127. int i, j;
  128. Vector *p1, *p2, *mid;
  129. winding_t *neww;
  130. int maxpts;
  131. counts[0] = counts[1] = counts[2] = 0;
  132. // determine sides for each point
  133. for (i=0 ; i<in->numpoints ; i++)
  134. {
  135. dot = DotProduct (in->p[i], split->normal);
  136. dot -= split->dist;
  137. dists[i] = dot;
  138. if (dot > SPLIT_EPSILON)
  139. sides[i] = SIDE_FRONT;
  140. else if (dot < -SPLIT_EPSILON)
  141. sides[i] = SIDE_BACK;
  142. else
  143. {
  144. sides[i] = SIDE_ON;
  145. }
  146. counts[sides[i]]++;
  147. }
  148. sides[i] = sides[0];
  149. dists[i] = dists[0];
  150. if (!counts[0] && !counts[1])
  151. return in;
  152. if (!counts[0])
  153. {
  154. free (in);
  155. return NULL;
  156. }
  157. if (!counts[1])
  158. return in;
  159. maxpts = in->numpoints+4; // can't use counts[0]+2 because
  160. // of fp grouping errors
  161. neww = NewWinding (maxpts);
  162. for (i=0 ; i<in->numpoints ; i++)
  163. {
  164. p1 = &in->p[i];
  165. mid = &neww->p[neww->numpoints];
  166. if (sides[i] == SIDE_FRONT || sides[i] == SIDE_ON)
  167. {
  168. *mid = *p1;
  169. neww->numpoints++;
  170. if (sides[i] == SIDE_ON)
  171. continue;
  172. mid = &neww->p[neww->numpoints];
  173. }
  174. if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
  175. continue;
  176. // generate a split point
  177. if (i == in->numpoints - 1)
  178. p2 = &in->p[0];
  179. else
  180. p2 = p1 + 1;
  181. neww->numpoints++;
  182. dot = dists[i] / (dists[i]-dists[i+1]);
  183. for (j=0 ; j<3 ; j++)
  184. { // avoid round off error when possible
  185. if (split->normal[j] == 1)
  186. mid[0][j] = split->dist;
  187. else if (split->normal[j] == -1)
  188. mid[0][j] = -split->dist;
  189. mid[0][j] = p1[0][j] + dot*(p2[0][j]-p1[0][j]);
  190. }
  191. // mid[3] = p1[3] + dot*(p2[3]-p1[3]);
  192. // mid[4] = p1[4] + dot*(p2[4]-p1[4]);
  193. }
  194. if (neww->numpoints > maxpts)
  195. Error ("ClipWinding: points exceeded estimate");
  196. // free the original winding
  197. FreeWinding (in);
  198. return neww;
  199. }
  200. //-----------------------------------------------------------------------------
  201. // Purpose: Creates a huge quadrilateral winding given a plane.
  202. // Input : pPlane - Plane normal and distance to use when creating the winding.
  203. // Output : Returns a winding with 4 points.
  204. //-----------------------------------------------------------------------------
  205. // dvs: read through this and clean it up
  206. winding_t *CreateWindingFromPlane(PLANE *pPlane)
  207. {
  208. int i, x;
  209. float max, v;
  210. Vector org, vright, vup;
  211. winding_t *w;
  212. // find the major axis
  213. max = -BOGUS_RANGE;
  214. x = -1;
  215. for (i=0 ; i<3; i++)
  216. {
  217. v = fabs(pPlane->normal[i]);
  218. if (v > max)
  219. {
  220. x = i;
  221. max = v;
  222. }
  223. }
  224. if (x==-1)
  225. Error ("BasePolyForPlane: no axis found");
  226. vup = vec3_origin;
  227. switch (x)
  228. {
  229. case 0:
  230. case 1:
  231. vup[2] = 1;
  232. break;
  233. case 2:
  234. vup[0] = 1;
  235. break;
  236. }
  237. v = DotProduct (vup, pPlane->normal);
  238. VectorMA (vup, -v, pPlane->normal, vup);
  239. VectorNormalize (vup);
  240. org = pPlane->normal * pPlane->dist;
  241. CrossProduct (vup, pPlane->normal, vright);
  242. vup = vup * MAX_TRACE_LENGTH;
  243. vright = vright * MAX_TRACE_LENGTH;
  244. // project a really big axis aligned box onto the plane
  245. w = NewWinding (4);
  246. w->numpoints = 4;
  247. VectorSubtract (org, vright, w->p[0]);
  248. VectorAdd (w->p[0], vup, w->p[0]);
  249. VectorAdd (org, vright, w->p[1]);
  250. VectorAdd (w->p[1], vup, w->p[1]);
  251. VectorAdd (org, vright, w->p[2]);
  252. VectorSubtract (w->p[2], vup, w->p[2]);
  253. VectorSubtract (org, vright, w->p[3]);
  254. VectorSubtract (w->p[3], vup, w->p[3]);
  255. return w;
  256. }
  257. static CArray<error3d, error3d&> Errors;
  258. static int nErrors;
  259. void Add3dError(DWORD dwObjectID, LPCTSTR pszReason, PVOID pInfo)
  260. {
  261. error3d err;
  262. err.dwObjectID = dwObjectID;
  263. err.pszReason = pszReason;
  264. err.pInfo = pInfo;
  265. Errors.Add(err);
  266. ++nErrors;
  267. }
  268. int Get3dErrorCount()
  269. {
  270. return nErrors;
  271. }
  272. error3d * Enum3dErrors(BOOL bStart)
  273. {
  274. static int iCurrent = 0;
  275. if(bStart)
  276. iCurrent = 0;
  277. if(iCurrent == nErrors)
  278. return NULL;
  279. return & Errors.GetData()[iCurrent++];
  280. }