clip.c 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. #include <string.h>
  2. #include <stdint.h>
  3. #include <stddef.h>
  4. #include "sr.h"
  5. #include "clip.h"
  6. /**
  7. * sr_clip.c
  8. * --------
  9. * defines functions to clip a polygon of vectors (x, y, z, w) in
  10. * homogeneous space
  11. *
  12. */
  13. /*********************************************************************
  14. * *
  15. * private definitions *
  16. * *
  17. *********************************************************************/
  18. /********
  19. * swap *
  20. ********/
  21. /* swaps what the pointers point to */
  22. static void
  23. swap(float** a, float** b)
  24. {
  25. void* tmp = *a;
  26. *a = *b;
  27. *b = tmp;
  28. }
  29. /********
  30. * lerp *
  31. ********/
  32. /* interpolates a point some length up an edge */
  33. static void
  34. lerp(float* dest, float* from, float* to, float a, int n_attr)
  35. {
  36. for (int i = 0; i < n_attr; i++) {
  37. dest[i] = from[i] + (to[i] - from[i]) * a;
  38. }
  39. }
  40. /****************
  41. * clip_routine *
  42. ****************/
  43. /**
  44. * a variant of cohen-sutherland for one plane
  45. * as determined by an axis and a sign to indicate direction
  46. */
  47. static void
  48. clip_routine(float* dest, float* src,
  49. int* n_pts, int n_attr,
  50. int axis, int sign)
  51. {
  52. float* tmp = dest; /* walk along dest with this pointer */
  53. float* prev = src + (*n_pts - 1) * n_attr; /* last pt */
  54. int prev_inside = prev[axis] * sign <= prev[3];
  55. for (int i = 0; i < *n_pts; i++) {
  56. float* cur = src + i * n_attr;
  57. int cur_inside = cur[axis] * sign <= cur[3];
  58. /* intersection */
  59. if (cur_inside ^ prev_inside) {
  60. float a = (prev[3] - prev[axis] * sign) /
  61. ((prev[3] - prev[axis] * sign) -
  62. (cur[3] - cur[axis] * sign));
  63. lerp(tmp, prev, cur, a, n_attr);
  64. tmp += n_attr;
  65. }
  66. /* point inside */
  67. if (cur_inside) {
  68. memcpy(tmp, cur, n_attr * sizeof(float));
  69. tmp += n_attr;
  70. }
  71. prev = cur;
  72. prev_inside = cur_inside;
  73. }
  74. *n_pts = (tmp - dest) / n_attr; /* new number of points after clip */
  75. }
  76. /*********************************************************************
  77. * *
  78. * public definitions *
  79. * *
  80. *********************************************************************/
  81. /*************
  82. * clip_poly *
  83. *************/
  84. /**
  85. * matches a one-hot clip flag to its clip routine
  86. * updates source points to the clipped ones in place
  87. */
  88. void
  89. clip_poly(float* src, int* n_pts,
  90. int n_attr, uint8_t clip_flags)
  91. {
  92. float dest[16 * SR_MAX_ATTRIBUTE_COUNT];
  93. float tmp[16 * SR_MAX_ATTRIBUTE_COUNT];
  94. memcpy(tmp, src, *n_pts * n_attr * sizeof(float));
  95. float* tmp_src = (float*)tmp;
  96. float* tmp_dest = (float*)dest;
  97. if (clip_flags & SR_CLIP_LEFT_PLANE) { /* left */
  98. clip_routine(tmp_dest, tmp_src, n_pts, n_attr, 0, -1);
  99. swap(&tmp_src, &tmp_dest);
  100. }
  101. if (clip_flags & (SR_CLIP_BOTTOM_PLANE)) { /* bottom */
  102. clip_routine(tmp_dest, tmp_src, n_pts, n_attr, 1, -1);
  103. swap(&tmp_src, &tmp_dest);
  104. }
  105. if (clip_flags & SR_CLIP_NEAR_PLANE) { /* near */
  106. clip_routine(tmp_dest, tmp_src, n_pts, n_attr, 2, -1);
  107. swap(&tmp_src, &tmp_dest);
  108. }
  109. if (clip_flags & SR_CLIP_RIGHT_PLANE) { /* right */
  110. clip_routine(tmp_dest, tmp_src, n_pts, n_attr, 0, 1);
  111. swap(&tmp_src, &tmp_dest);
  112. }
  113. if (clip_flags & SR_CLIP_TOP_PLANE) { /* top */
  114. clip_routine(tmp_dest, tmp_src, n_pts, n_attr, 1, 1);
  115. swap(&tmp_src, &tmp_dest);
  116. }
  117. memcpy(src, tmp_src, *n_pts * n_attr * sizeof(float));
  118. }
  119. /*************
  120. * clip_test *
  121. *************/
  122. /* assigns proper clip flags to a point */
  123. void
  124. clip_test(float* pt, uint8_t* flags)
  125. {
  126. uint8_t left = (pt[3] + pt[0] < 0) << 0;
  127. uint8_t bottom = (pt[3] + pt[1] < 0) << 1;
  128. uint8_t near = (pt[3] + pt[2] < 0) << 2;
  129. uint8_t right = (pt[3] - pt[0] < 0) << 3;
  130. uint8_t top = (pt[3] - pt[1] < 0) << 4;
  131. *flags = left | bottom | near | right | top;
  132. }