fill.c 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. /*
  2. * fill -- polygon tiler
  3. * Updating the edgelist from scanline to scanline could be quicker if no
  4. * edges cross: we can just merge the incoming edges. If the scan-line
  5. * filling routine were a parameter, we could do textured
  6. * polygons, polyblt, and other such stuff.
  7. */
  8. #include "mplot.h"
  9. typedef enum{
  10. Odd=1,
  11. Nonzero=~0
  12. }Windrule;
  13. typedef struct edge Edge;
  14. struct edge{
  15. Point p; /* point of crossing current scan-line */
  16. int maxy; /* scan line at which to discard edge */
  17. int dx; /* x increment if x fraction<1 */
  18. int dx1; /* x increment if x fraction>=1 */
  19. int x; /* x fraction, scaled by den */
  20. int num; /* x fraction increment for unit y change, scaled by den */
  21. int den; /* x fraction increment for unit x change, scaled by num */
  22. int dwind; /* increment of winding number on passing this edge */
  23. Edge *next; /* next edge on current scanline */
  24. Edge *prev; /* previous edge on current scanline */
  25. };
  26. static void insert(Edge *ep, Edge **yp){
  27. while(*yp && (*yp)->p.x<ep->p.x) yp=&(*yp)->next;
  28. ep->next=*yp;
  29. *yp=ep;
  30. if(ep->next){
  31. ep->prev=ep->next->prev;
  32. ep->next->prev=ep;
  33. if(ep->prev)
  34. ep->prev->next=ep;
  35. }
  36. else
  37. ep->prev=0;
  38. }
  39. static void polygon(int cnt[], double *pts[], Windrule w, int v){
  40. Edge *edges, *ep, *nextep, **ylist, **eylist, **yp;
  41. Point p, q, p0, p1, p10;
  42. int i, dy, nbig, y, left, right, wind, nwind, nvert;
  43. int *cntp;
  44. double **ptsp, *xp;
  45. nvert=0;
  46. for(cntp=cnt;*cntp;cntp++) nvert+=*cntp;
  47. edges=(Edge *)malloc(nvert*sizeof(Edge));
  48. if(edges==0){
  49. NoSpace:
  50. fprintf(stderr, "polygon: no space\n");
  51. exits("malloc failed");
  52. }
  53. ylist=(Edge **)malloc(Dy(screen->r)*sizeof(Edge *));
  54. if(ylist==0) goto NoSpace;
  55. eylist=ylist+Dy(screen->r);
  56. for(yp=ylist;yp!=eylist;yp++) *yp=0;
  57. ep=edges;
  58. for(cntp=cnt,ptsp=pts;*cntp;cntp++,ptsp++){
  59. p.x=SCX((*ptsp)[*cntp*2-2]);
  60. p.y=SCY((*ptsp)[*cntp*2-1]);
  61. nvert=*cntp;
  62. for(xp=*ptsp,i=0;i!=nvert;xp+=2,i++){
  63. q=p;
  64. p.x=SCX(xp[0]);
  65. p.y=SCY(xp[1]);
  66. if(p.y==q.y) continue;
  67. if(p.y<q.y){
  68. p0=p;
  69. p1=q;
  70. ep->dwind=1;
  71. }
  72. else{
  73. p0=q;
  74. p1=p;
  75. ep->dwind=-1;
  76. }
  77. if(p1.y<=screen->r.min.y) continue;
  78. if(p0.y>=screen->r.max.y) continue;
  79. ep->p=p0;
  80. if(p1.y>screen->r.max.y)
  81. ep->maxy=screen->r.max.y;
  82. else
  83. ep->maxy=p1.y;
  84. p10=subpt(p1, p0);
  85. if(p10.x>=0){
  86. ep->dx=p10.x/p10.y;
  87. ep->dx1=ep->dx+1;
  88. }
  89. else{
  90. p10.x=-p10.x;
  91. ep->dx=-(p10.x/p10.y); /* this nonsense rounds toward zero */
  92. ep->dx1=ep->dx-1;
  93. }
  94. ep->x=0;
  95. ep->num=p10.x%p10.y;
  96. ep->den=p10.y;
  97. if(ep->p.y<screen->r.min.y){
  98. dy=screen->r.min.y-ep->p.y;
  99. ep->x+=dy*ep->num;
  100. nbig=ep->x/ep->den;
  101. ep->p.x+=ep->dx1*nbig+ep->dx*(dy-nbig);
  102. ep->x%=ep->den;
  103. ep->p.y=screen->r.min.y;
  104. }
  105. insert(ep, ylist+(ep->p.y-screen->r.min.y));
  106. ep++;
  107. }
  108. }
  109. left = 0;
  110. for(yp=ylist,y=screen->r.min.y;yp!=eylist;yp++,y++){
  111. wind=0;
  112. for(ep=*yp;ep;ep=nextep){
  113. nwind=wind+ep->dwind;
  114. if(nwind&w){ /* inside */
  115. if(!(wind&w)){
  116. left=ep->p.x;
  117. if(left<screen->r.min.x) left=screen->r.min.x;
  118. }
  119. }
  120. else if(wind&w){
  121. right=ep->p.x;
  122. if(right>=screen->r.max.x) right=screen->r.max.x;
  123. #define BART_BUG_FIXED /* what goes on here?? -rob */
  124. #ifdef BART_BUG_FIXED
  125. if(right>left)
  126. line(screen, Pt(left, y), Pt(right, y), Endsquare, Endsquare, 0, getcolor(v), ZP);
  127. #else
  128. if(right>left){
  129. switch(v){
  130. default:
  131. segment(&screen, Pt(left, y), Pt(right, y),
  132. ~0, D&~S);
  133. segment(&screen, Pt(left, y), Pt(right, y),
  134. v, f);
  135. break;
  136. case 0:
  137. segment(&screen, Pt(left, y), Pt(right, y),
  138. ~0, D&~S);
  139. break;
  140. case 3:
  141. segment(&screen, Pt(left, y), Pt(right, y),
  142. v, f);
  143. break;
  144. }
  145. }
  146. #endif
  147. }
  148. wind=nwind;
  149. nextep=ep->next;
  150. if(++ep->p.y!=ep->maxy){
  151. ep->x+=ep->num;
  152. if(ep->x>=ep->den){
  153. ep->x-=ep->den;
  154. ep->p.x+=ep->dx1;
  155. }
  156. else
  157. ep->p.x+=ep->dx;
  158. insert(ep, yp+1);
  159. }
  160. }
  161. }
  162. free((char *)edges);
  163. free((char *)ylist);
  164. }
  165. void fill(int num[], double *ff[]){
  166. polygon(num, ff, Odd, e1->foregr);
  167. }