rev |
line source |
nuclear@9
|
1 #include "lines.h"
|
nuclear@9
|
2
|
nuclear@9
|
3 enum {
|
nuclear@9
|
4 IN = 0,
|
nuclear@9
|
5 LEFT = 1,
|
nuclear@9
|
6 RIGHT = 2,
|
nuclear@9
|
7 TOP = 4,
|
nuclear@9
|
8 BOTTOM = 8
|
nuclear@9
|
9 };
|
nuclear@9
|
10
|
nuclear@9
|
11 static int outcode(int x, int y, int minx, int miny, int maxx, int maxy)
|
nuclear@9
|
12 {
|
nuclear@9
|
13 int code = 0;
|
nuclear@9
|
14
|
nuclear@9
|
15 if(x < minx) {
|
nuclear@9
|
16 code |= LEFT;
|
nuclear@9
|
17 } else if(x > maxx) {
|
nuclear@9
|
18 code |= RIGHT;
|
nuclear@9
|
19 }
|
nuclear@9
|
20 if(y < miny) {
|
nuclear@9
|
21 code |= TOP;
|
nuclear@9
|
22 } else if(y > maxy) {
|
nuclear@9
|
23 code |= BOTTOM;
|
nuclear@9
|
24 }
|
nuclear@9
|
25 return code;
|
nuclear@9
|
26 }
|
nuclear@9
|
27
|
nuclear@9
|
28 #define FIXMUL(a, b) (((a) * (b)) >> 8)
|
nuclear@9
|
29 #define FIXDIV(a, b) (((a) << 8) / (b))
|
nuclear@9
|
30
|
nuclear@9
|
31 #define LERP(a, b, t) ((a) + FIXMUL((b) - (a), (t)))
|
nuclear@9
|
32
|
nuclear@9
|
33 int clip_line2d(int *x0, int *y0, int *x1, int *y1, const int *vp)
|
nuclear@9
|
34 {
|
nuclear@9
|
35 int oc_out;
|
nuclear@9
|
36 int minx = vp[0];
|
nuclear@9
|
37 int miny = vp[1];
|
nuclear@9
|
38 int maxx = vp[0] + vp[2] - 1;
|
nuclear@9
|
39 int maxy = vp[1] + vp[3] - 1;
|
nuclear@9
|
40
|
nuclear@9
|
41 int oc0 = outcode(*x0, *y0, minx, miny, maxx, maxy);
|
nuclear@9
|
42 int oc1 = outcode(*x1, *y1, minx, miny, maxx, maxy);
|
nuclear@9
|
43
|
nuclear@9
|
44 int32_t fx0, fy0, fx1, fy1, fminx, fminy, fmaxx, fmaxy;
|
nuclear@9
|
45
|
nuclear@9
|
46 if(!(oc0 | oc1)) return 1; /* both points are inside */
|
nuclear@9
|
47
|
nuclear@9
|
48 fx0 = *x0 << 8;
|
nuclear@9
|
49 fy0 = *y0 << 8;
|
nuclear@9
|
50 fx1 = *x1 << 8;
|
nuclear@9
|
51 fy1 = *y1 << 8;
|
nuclear@9
|
52 fminx = minx << 8;
|
nuclear@9
|
53 fminy = miny << 8;
|
nuclear@9
|
54 fmaxx = maxx << 8;
|
nuclear@9
|
55 fmaxy = maxy << 8;
|
nuclear@9
|
56
|
nuclear@9
|
57 for(;;) {
|
nuclear@9
|
58 int32_t x, y, t;
|
nuclear@9
|
59
|
nuclear@9
|
60 if(oc0 & oc1) return 0; /* both have points with the same outbit, not visible */
|
nuclear@9
|
61 if(!(oc0 | oc1)) break; /* both points are inside */
|
nuclear@9
|
62
|
nuclear@9
|
63 oc_out = oc0 ? oc0 : oc1;
|
nuclear@9
|
64
|
nuclear@9
|
65 if(oc_out & TOP) {
|
nuclear@9
|
66 t = FIXDIV(fminy - fy0, fy1 - fy0);
|
nuclear@9
|
67 x = LERP(fx0, fx1, t);
|
nuclear@9
|
68 y = fminy;
|
nuclear@9
|
69 } else if(oc_out & BOTTOM) {
|
nuclear@9
|
70 t = FIXDIV(fmaxy - fy0, fy1 - fy0);
|
nuclear@9
|
71 x = LERP(fx0, fx1, t);
|
nuclear@9
|
72 y = fmaxy;
|
nuclear@9
|
73 } else if(oc_out & LEFT) {
|
nuclear@9
|
74 t = FIXDIV(fminx - fx0, fx1 - fx0);
|
nuclear@9
|
75 x = fminx;
|
nuclear@9
|
76 y = LERP(fy0, fy1, t);
|
nuclear@9
|
77 } else if(oc_out & RIGHT) {
|
nuclear@9
|
78 t = FIXDIV(fmaxx - fx0, fx1 - fx0);
|
nuclear@9
|
79 x = fmaxx;
|
nuclear@9
|
80 y = LERP(fy0, fy1, t);
|
nuclear@9
|
81 }
|
nuclear@9
|
82
|
nuclear@9
|
83 if(oc_out == oc0) {
|
nuclear@9
|
84 fx0 = x;
|
nuclear@9
|
85 fy0 = y;
|
nuclear@9
|
86 oc0 = outcode(fx0 >> 8, fy0 >> 8, minx, miny, maxx, maxy);
|
nuclear@9
|
87 } else {
|
nuclear@9
|
88 fx1 = x;
|
nuclear@9
|
89 fy1 = y;
|
nuclear@9
|
90 oc1 = outcode(fx1 >> 8, fy1 >> 8, minx, miny, maxx, maxy);
|
nuclear@9
|
91 }
|
nuclear@9
|
92 }
|
nuclear@9
|
93
|
nuclear@9
|
94 *x0 = fx0 >> 8;
|
nuclear@9
|
95 *y0 = fy0 >> 8;
|
nuclear@9
|
96 *x1 = fx1 >> 8;
|
nuclear@9
|
97 *y1 = fy1 >> 8;
|
nuclear@9
|
98 return 1;
|
nuclear@9
|
99 }
|
nuclear@9
|
100
|
nuclear@9
|
101 void draw_line(uint32_t *fb, int fbwidth, uint32_t col, int x0, int y0, int x1, int y1)
|
nuclear@9
|
102 {
|
nuclear@9
|
103 int i, dx, dy, x_inc, y_inc, error;
|
nuclear@9
|
104
|
nuclear@9
|
105 fb += y0 * fbwidth + x0;
|
nuclear@9
|
106
|
nuclear@9
|
107 dx = x1 - x0;
|
nuclear@9
|
108 dy = y1 - y0;
|
nuclear@9
|
109
|
nuclear@9
|
110 if(dx >= 0) {
|
nuclear@9
|
111 x_inc = 1;
|
nuclear@9
|
112 } else {
|
nuclear@9
|
113 x_inc = -1;
|
nuclear@9
|
114 dx = -dx;
|
nuclear@9
|
115 }
|
nuclear@9
|
116 if(dy >= 0) {
|
nuclear@9
|
117 y_inc = fbwidth;
|
nuclear@9
|
118 } else {
|
nuclear@9
|
119 y_inc = -fbwidth;
|
nuclear@9
|
120 dy = -dy;
|
nuclear@9
|
121 }
|
nuclear@9
|
122
|
nuclear@9
|
123 if(dx > dy) {
|
nuclear@9
|
124 error = dy * 2 - dx;
|
nuclear@9
|
125 for(i=0; i<=dx; i++) {
|
nuclear@9
|
126 *fb = col;
|
nuclear@9
|
127 if(error >= 0) {
|
nuclear@9
|
128 error -= dx * 2;
|
nuclear@9
|
129 fb += y_inc;
|
nuclear@9
|
130 }
|
nuclear@9
|
131 error += dy * 2;
|
nuclear@9
|
132 fb += x_inc;
|
nuclear@9
|
133 }
|
nuclear@9
|
134 } else {
|
nuclear@9
|
135 error = dx * 2 - dy;
|
nuclear@9
|
136 for(i=0; i<=dy; i++) {
|
nuclear@9
|
137 *fb = col;
|
nuclear@9
|
138 if(error >= 0) {
|
nuclear@9
|
139 error -= dy * 2;
|
nuclear@9
|
140 fb += x_inc;
|
nuclear@9
|
141 }
|
nuclear@9
|
142 error += dx * 2;
|
nuclear@9
|
143 fb += y_inc;
|
nuclear@9
|
144 }
|
nuclear@9
|
145 }
|
nuclear@9
|
146 }
|