pipe.c 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. #include <stdlib.h>
  2. #include <string.h>
  3. #include "sr.h"
  4. #include "sr_priv.h"
  5. /**
  6. * sr_pipe.c
  7. * --------
  8. * implementation of the internal graphics pipeline,
  9. * resembling roughly how its done in hardware
  10. *
  11. */
  12. /*********************************************************************
  13. * *
  14. * private definitions *
  15. * *
  16. *********************************************************************/
  17. /*****************
  18. * winding_order *
  19. *****************/
  20. /* false for triangles against the winding order */
  21. static int
  22. winding_order(int winding, float* v0, float* v1, float* v2)
  23. {
  24. float e01 = (v1[0] - v0[0]) * (v1[1] + v0[1]);
  25. float e12 = (v2[0] - v1[0]) * (v2[1] + v1[1]);
  26. float e20 = (v0[0] - v2[0]) * (v0[1] + v2[1]);
  27. return (e01 + e12 + e20) * winding > 0; /* same sign */
  28. }
  29. /*************
  30. * draw_prim *
  31. *************/
  32. /* matches the correct drawing routine with the primitive type */
  33. static void
  34. draw_prim(struct raster_context* rast, float* pts,
  35. int n_pts, enum sr_primitive prim_type)
  36. {
  37. switch (prim_type) {
  38. case SR_POINT_LIST: /* point list */
  39. for (int i = 0; i < n_pts; i++) {
  40. draw_pt(rast, pts + i * rast->n_attr);
  41. }
  42. break;
  43. case SR_LINE_LIST:
  44. case SR_LINE_STRIP: /* line list */
  45. for (int i = 1; i < n_pts; i++) {
  46. /* draw_ln(rast, tmp_p, tmp_p + i * n_attr_out); */
  47. }
  48. break;
  49. case SR_TRIANGLE_LIST:
  50. case SR_TRIANGLE_STRIP: /* triangle fan */
  51. {
  52. float* v0 = pts;
  53. float* v1 = pts + 1 * rast->n_attr;
  54. for (int i = 2; i < n_pts; i++) {
  55. float* v2 = pts + i * rast->n_attr;
  56. if (winding_order(rast->winding, v0, v1, v2))
  57. draw_tr(rast, v0, v1, v2);
  58. v1 = v2;
  59. }
  60. }
  61. break;
  62. }
  63. }
  64. /**************
  65. * split_prim *
  66. **************/
  67. /* fills relevant traversal data about a primitive type */
  68. static void
  69. split_prim(enum sr_primitive prim_type, int* prim_size)
  70. {
  71. switch (prim_type) {
  72. case SR_POINT_LIST:
  73. *prim_size = 1;
  74. break;
  75. case SR_LINE_LIST:
  76. case SR_LINE_STRIP:
  77. *prim_size = 2;
  78. break;
  79. case SR_TRIANGLE_LIST:
  80. case SR_TRIANGLE_STRIP:
  81. *prim_size = 3;
  82. break;
  83. }
  84. }
  85. /****************
  86. * screen_space *
  87. ****************/
  88. /* moves coordinates from clip space to screen space */
  89. static void
  90. screen_space(struct sr_framebuffer* fbuf, float* pt)
  91. {
  92. /* to ndc space */
  93. pt[3] = 1 / pt[3];
  94. pt[0] *= pt[3];
  95. pt[1] *= pt[3];
  96. pt[2] *= pt[3]; /* should equal 1 now */
  97. /* to screen space */
  98. pt[0] = (fbuf->width / 2) * (pt[0] + 1);
  99. pt[1] = (fbuf->height / 2) * (1 - pt[1]);
  100. pt[2] = (pt[2] + 1) / 2;
  101. }
  102. /*********************************************************************
  103. * *
  104. * public definition *
  105. * *
  106. *********************************************************************/
  107. /*************
  108. * sr_render *
  109. *************/
  110. /**
  111. * entry point of the sr pipeline,
  112. * refines indexed vertex data to be sent to rasterizer
  113. */
  114. void
  115. sr_render(struct sr_pipeline* pipe, int* indices,
  116. int n_indices, enum sr_primitive prim_type)
  117. {
  118. /* setup variables */
  119. struct raster rast = {
  120. .fbuf = pipe->fbuf,
  121. .uniform = pipe->uniform,
  122. .fs = pipe->fs,
  123. .n_attr = pipe->n_attr_out,
  124. .winding = pipe->winding
  125. };
  126. int prim_size, n_prims;
  127. float* pts_out;
  128. float tmp[16 * SR_MAX_ATTRIBUTE_COUNT]; /* holds current face */;
  129. uint8_t* clip_flags;
  130. prim_size = 0;
  131. split_prim(prim_type, &prim_size);
  132. n_prims = n_indices / prim_size;
  133. /* vertex processing */
  134. pts_out = malloc(pipe->n_pts * pipe->n_attr_out * sizeof(float));
  135. clip_flags = malloc(pipe->n_pts * sizeof(uint8_t));
  136. for (int i = 0; i < pipe->n_pts; i++) { /* per point */
  137. /* vertex shader pass */
  138. pipe->vs(pts_out + i * pipe->n_attr_out,
  139. pipe->pts_in + i * pipe->n_attr_in,
  140. pipe->uniform);
  141. /* grab clip flags while vertex is still hot */
  142. clip_test(pts_out + i * pipe->n_attr_out, clip_flags + i);
  143. }
  144. for (int i = 0; i < n_prims * prim_size; i += prim_size) {
  145. /* primitive assembly */
  146. uint8_t clip_and, clip_or;
  147. clip_and = 0;
  148. clip_or = 0;
  149. for (int j = 0; j < prim_size; j++) {
  150. /* fill buffer with primitive data */
  151. memcpy(tmp + j * pipe->n_attr_out,
  152. pts_out + indices[i + j] * pipe->n_attr_out,
  153. pipe->n_attr_out * sizeof(float));
  154. /* accumulate point clip flags */
  155. clip_and &= clip_flags[indices[i + j]];
  156. clip_or |= clip_flags[indices[i + j]];
  157. }
  158. /* clipping */
  159. if (clip_and != 0) /* outside frustum */
  160. continue;
  161. int clipped_prim_size = prim_size;
  162. if (clip_or != 0) /* if intersect frustum */
  163. clip_poly(tmp, &clipped_prim_size, pipe->n_attr_out, clip_or);
  164. /* perspective divide */
  165. for (int j = 0; j < clipped_prim_size; j++)
  166. screen_space(pipe->fbuf, tmp + j * pipe->n_attr_out);
  167. draw_prim(&rast, tmp, clipped_prim_size, prim_type);
  168. }
  169. free(pts_out);
  170. free(clip_flags);
  171. }