pipe.c 5.7 KB

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