MERGE.C 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. // merge.c
  2. #include "bsp5.h"
  3. #define CONTINUOUS_EPSILON 0.001
  4. /*
  5. ================
  6. CheckColinear
  7. ================
  8. */
  9. void CheckColinear (face_t *f)
  10. {
  11. int i, j;
  12. vec3_t v1, v2;
  13. for (i=0 ; i<f->numpoints ;i++)
  14. {
  15. // skip the point if the vector from the previous point is the same
  16. // as the vector to the next point
  17. j = (i - 1 < 0) ? f->numpoints - 1 : i - 1;
  18. VectorSubtract (f->pts[i], f->pts[j], v1);
  19. VectorNormalize (v1);
  20. j = (i + 1 == f->numpoints) ? 0 : i + 1;
  21. VectorSubtract (f->pts[j], f->pts[i], v2);
  22. VectorNormalize (v2);
  23. if (VectorCompare (v1, v2))
  24. Error ("Colinear edge");
  25. }
  26. }
  27. /*
  28. =============
  29. TryMerge
  30. If two polygons share a common edge and the edges that meet at the
  31. common points are both inside the other polygons, merge them
  32. Returns NULL if the faces couldn't be merged, or the new face.
  33. The originals will NOT be freed.
  34. =============
  35. */
  36. face_t *TryMerge (face_t *f1, face_t *f2)
  37. {
  38. vec_t *p1, *p2, *p3, *p4, *back;
  39. face_t *newf;
  40. int i, j, k, l;
  41. vec3_t normal, delta, planenormal;
  42. vec_t dot;
  43. plane_t *plane;
  44. qboolean keep1, keep2;
  45. if (f1->numpoints == -1 || f2->numpoints == -1)
  46. return NULL;
  47. if (f1->planeside != f2->planeside)
  48. return NULL;
  49. if (f1->texturenum != f2->texturenum)
  50. return NULL;
  51. if (f1->contents[0] != f2->contents[0])
  52. return NULL;
  53. if (f1->contents[1] != f2->contents[1])
  54. return NULL;
  55. //
  56. // find a common edge
  57. //
  58. p1 = p2 = NULL; // stop compiler warning
  59. j = 0; //
  60. for (i=0 ; i<f1->numpoints ; i++)
  61. {
  62. p1 = f1->pts[i];
  63. p2 = f1->pts[(i+1)%f1->numpoints];
  64. for (j=0 ; j<f2->numpoints ; j++)
  65. {
  66. p3 = f2->pts[j];
  67. p4 = f2->pts[(j+1)%f2->numpoints];
  68. for (k=0 ; k<3 ; k++)
  69. {
  70. if (fabs(p1[k] - p4[k]) > EQUAL_EPSILON)
  71. break;
  72. if (fabs(p2[k] - p3[k]) > EQUAL_EPSILON)
  73. break;
  74. }
  75. if (k==3)
  76. break;
  77. }
  78. if (j < f2->numpoints)
  79. break;
  80. }
  81. if (i == f1->numpoints)
  82. return NULL; // no matching edges
  83. //
  84. // check slope of connected lines
  85. // if the slopes are colinear, the point can be removed
  86. //
  87. plane = &planes[f1->planenum];
  88. VectorCopy (plane->normal, planenormal);
  89. if (f1->planeside)
  90. VectorSubtract (vec3_origin, planenormal, planenormal);
  91. back = f1->pts[(i+f1->numpoints-1)%f1->numpoints];
  92. VectorSubtract (p1, back, delta);
  93. CrossProduct (planenormal, delta, normal);
  94. VectorNormalize (normal);
  95. back = f2->pts[(j+2)%f2->numpoints];
  96. VectorSubtract (back, p1, delta);
  97. dot = DotProduct (delta, normal);
  98. if (dot > CONTINUOUS_EPSILON)
  99. return NULL; // not a convex polygon
  100. keep1 = dot < -CONTINUOUS_EPSILON;
  101. back = f1->pts[(i+2)%f1->numpoints];
  102. VectorSubtract (back, p2, delta);
  103. CrossProduct (planenormal, delta, normal);
  104. VectorNormalize (normal);
  105. back = f2->pts[(j+f2->numpoints-1)%f2->numpoints];
  106. VectorSubtract (back, p2, delta);
  107. dot = DotProduct (delta, normal);
  108. if (dot > CONTINUOUS_EPSILON)
  109. return NULL; // not a convex polygon
  110. keep2 = dot < -CONTINUOUS_EPSILON;
  111. //
  112. // build the new polygon
  113. //
  114. if (f1->numpoints + f2->numpoints > MAXEDGES)
  115. {
  116. // Error ("TryMerge: too many edges!");
  117. return NULL;
  118. }
  119. newf = NewFaceFromFace (f1);
  120. // copy first polygon
  121. for (k=(i+1)%f1->numpoints ; k != i ; k=(k+1)%f1->numpoints)
  122. {
  123. if (k==(i+1)%f1->numpoints && !keep2)
  124. continue;
  125. VectorCopy (f1->pts[k], newf->pts[newf->numpoints]);
  126. newf->numpoints++;
  127. }
  128. // copy second polygon
  129. for (l= (j+1)%f2->numpoints ; l != j ; l=(l+1)%f2->numpoints)
  130. {
  131. if (l==(j+1)%f2->numpoints && !keep1)
  132. continue;
  133. VectorCopy (f2->pts[l], newf->pts[newf->numpoints]);
  134. newf->numpoints++;
  135. }
  136. return newf;
  137. }
  138. /*
  139. ===============
  140. MergeFaceToList
  141. ===============
  142. */
  143. qboolean mergedebug;
  144. face_t *MergeFaceToList (face_t *face, face_t *list)
  145. {
  146. face_t *newf, *f;
  147. for (f=list ; f ; f=f->next)
  148. {
  149. //CheckColinear (f);
  150. if (mergedebug)
  151. {
  152. Draw_ClearWindow ();
  153. Draw_DrawFace (face);
  154. Draw_DrawFace (f);
  155. Draw_SetBlack ();
  156. }
  157. newf = TryMerge (face, f);
  158. if (!newf)
  159. continue;
  160. FreeFace (face);
  161. f->numpoints = -1; // merged out
  162. return MergeFaceToList (newf, list);
  163. }
  164. // didn't merge, so add at start
  165. face->next = list;
  166. return face;
  167. }
  168. /*
  169. ===============
  170. FreeMergeListScraps
  171. ===============
  172. */
  173. face_t *FreeMergeListScraps (face_t *merged)
  174. {
  175. face_t *head, *next;
  176. head = NULL;
  177. for ( ; merged ; merged = next)
  178. {
  179. next = merged->next;
  180. if (merged->numpoints == -1)
  181. FreeFace (merged);
  182. else
  183. {
  184. merged->next = head;
  185. head = merged;
  186. }
  187. }
  188. return head;
  189. }
  190. /*
  191. ===============
  192. MergePlaneFaces
  193. ===============
  194. */
  195. void MergePlaneFaces (surface_t *plane)
  196. {
  197. face_t *f1, *next;
  198. face_t *merged;
  199. merged = NULL;
  200. for (f1 = plane->faces ; f1 ; f1 = next)
  201. {
  202. next = f1->next;
  203. merged = MergeFaceToList (f1, merged);
  204. }
  205. // chain all of the non-empty faces to the plane
  206. plane->faces = FreeMergeListScraps (merged);
  207. }
  208. /*
  209. ============
  210. MergeAll
  211. ============
  212. */
  213. void MergeAll (surface_t *surfhead)
  214. {
  215. surface_t *surf;
  216. int mergefaces;
  217. face_t *f;
  218. printf ("---- MergeAll ----\n");
  219. mergefaces = 0;
  220. for (surf = surfhead ; surf ; surf=surf->next)
  221. {
  222. MergePlaneFaces (surf);
  223. Draw_ClearWindow ();
  224. for (f=surf->faces ; f ; f=f->next)
  225. {
  226. Draw_DrawFace (f);
  227. mergefaces++;
  228. }
  229. }
  230. printf ("%i mergefaces\n", mergefaces);
  231. }