added summerhack
[summerhack] / tools / curve_draw / gfx.cc
1 #include "gfx.h"
2
3 #define RGB(r, g, b)    (((r) << 16) & 0xff0000) | (((g) << 8) & 0x00ff00) | ((b) & 0xff)
4
5 static int clip_line(int *x1, int *y1, int *x2, int *y2);
6
7
8 extern int xsz, ysz;
9         
10
11 void draw_point(int x, int y, unsigned int col, unsigned int *ptr, int xsz) {
12         const int sz = 9;
13         const int pt_img[sz][sz] = {
14                 {0,0,0,0,1,0,0,0,0},
15                 {0,0,1,1,1,1,1,0,0},
16                 {0,1,2,2,1,1,1,3,0},
17                 {0,1,2,1,1,1,1,3,0},
18                 {1,1,1,1,1,1,1,3,3},
19                 {0,1,1,1,1,1,3,3,0},
20                 {0,1,1,1,1,3,3,3,0},
21                 {0,0,3,3,3,3,3,0,0},
22                 {0,0,0,0,3,0,0,0,0}
23         };
24
25         if(x < sz/2 || x >= xsz - sz/2 || y < sz/2 || y >= ysz - sz/2) {
26                 return;
27         }
28
29         int base_r = (col & 0xff0000) >> 16;
30         int base_g = (col & 0x00ff00) >> 8;
31         int base_b = (col & 0x0000ff);
32
33         unsigned int dark = RGB(base_r - base_r/4, base_g - base_g/4, base_b - base_b/4);;
34         
35         unsigned int ctable[] = {0, col, 0xffffff, dark};
36         ptr += (y - sz / 2) * xsz + (x - sz / 2);
37
38         for(int i=0; i<sz; i++) {
39                 for(int j=0; j<sz; j++) {
40                         if(pt_img[i][j]) {
41                                 *(ptr + j) = ctable[pt_img[i][j]];
42                         }
43                 }
44                 ptr += xsz;
45         }
46 }
47
48 void draw_line(int x1, int y1, int x2, int y2, unsigned int col, unsigned int *ptr, int xsz) {
49         int dx, dy, dx2, dy2;
50         int x_inc, y_inc;
51         int error;
52         int i;
53
54         if(!clip_line(&x1, &y1, &x2, &y2)) return;
55
56         ptr += y1 * xsz + x1;
57         dx = x2 - x1;
58         dy = y2 - y1;
59         
60         if(dx >= 0) {
61                 x_inc = 1;
62         } else {
63                 x_inc = -1;
64                 dx = -dx;
65         }
66         
67         if(dy >= 0) {
68                 y_inc = xsz;
69         } else {
70                 y_inc = -xsz;
71                 dy = -dy;
72         }
73         
74         dx2 = dx << 1;
75         dy2 = dy << 1;
76
77         if(dx > dy) {
78                 error = dy2 - dx;
79                 for(i=0; i<=dx; i++) {
80                         *ptr = col;
81                         if(error >= 0) {
82                                 error -= dx2;
83                                 ptr += y_inc;
84                         }
85                         error += dy2;
86                         ptr += x_inc;
87                 }
88         } else {
89                 error = dx2 - dy;
90                 for(i=0;i<=dy;i++) {
91                         *ptr = col;
92                         if(error >= 0) {
93                                 error -= dy2;
94                                 ptr += x_inc;
95                         }
96                         error += dx2;
97                         ptr += y_inc;
98                 }
99         }
100 }
101
102 enum {
103         CLIP_C          = 0x0000,
104         CLIP_N          = 0x0008,
105         CLIP_S          = 0x0004,
106         CLIP_E          = 0x0002,
107         CLIP_W          = 0x0001,
108         CLIP_NE         = 0x000a,
109         CLIP_SE         = 0x0006,
110         CLIP_NW         = 0x0009,
111         CLIP_SW         = 0x0005
112 };
113
114 #define MIN_CLIP_X      0
115 #define MIN_CLIP_Y      0
116 #define MAX_CLIP_X      (xsz - 1)
117 #define MAX_CLIP_Y      (ysz - 1)
118
119 static int clip_line(int *x1, int *y1, int *x2, int *y2) {
120         int xc1 = *x1;
121         int yc1 = *y1;
122         int xc2 = *x2;
123         int yc2 = *y2;
124         int p1_code = 0;
125         int p2_code = 0;
126
127         // determine codes for p1 and p2
128         if(*y1 < MIN_CLIP_Y) {
129                 p1_code |= CLIP_N;
130         } else {
131                 if(*y1 > MAX_CLIP_Y) {
132                         p1_code |= CLIP_S;
133                 } else {
134                         if(*x1 < MIN_CLIP_X) {
135                                 p1_code |= CLIP_W;
136                         } else {
137                                 if(*x1 > MAX_CLIP_X) p1_code |= CLIP_E;
138                         }
139                 }
140         }
141
142         if(*y2 < MIN_CLIP_Y) {
143                 p2_code |= CLIP_N;
144         } else {
145                 if(*y2 > MAX_CLIP_Y) {
146                         p2_code |= CLIP_S;
147                 } else {
148                         if(*x2 < MIN_CLIP_X) {
149                                 p2_code |= CLIP_W;
150                         } else {
151                                 if(*x2 > MAX_CLIP_X) p2_code |= CLIP_E;
152                         }
153                 }
154         }
155
156         if((p1_code & p2_code)) return 0; // trivial rejection
157         if(p1_code == 0 && p2_code == 0) return 1; // test if totally visible
158
159         // find clip point for p1
160         switch(p1_code) {
161                 case CLIP_C: break;
162                 
163                 case CLIP_N:
164                         yc1 = MIN_CLIP_Y;
165                         xc1 = *x1 + 0.5 + (MIN_CLIP_Y - *y1) * (*x2 - *x1) / (*y2 - *y1);
166                         break;
167
168                 case CLIP_S:
169                         yc1 = MAX_CLIP_Y;
170                         xc1 = *x1 + 0.5 + (MAX_CLIP_Y - *y1) * (*x2 - *x1) / (*y2 - *y1);
171                         break;
172
173                 case CLIP_W:
174                         xc1 = MIN_CLIP_X;
175                         yc1 = *y1 + 0.5 + (MIN_CLIP_X - *x1) * (*y2 - *y1) / (*x2 - *x1);
176                         break;
177
178                 case CLIP_E:
179                         xc1 = MAX_CLIP_X;
180                         yc1 = *y1 + 0.5 + (MAX_CLIP_X - *x1) * (*y2 - *y1) / (*x2 - *x1);
181                         break;
182
183                 case CLIP_NE:
184                         yc1 = MIN_CLIP_Y;
185                         xc1 = *x1 + 0.5 + (MIN_CLIP_Y - *y1) * (*x2 - *x1) / (*y2 - *y1);
186                         if(xc1 < MIN_CLIP_X || xc1 > MAX_CLIP_X) {
187                                 xc1 = MAX_CLIP_X;
188                                 yc1 = *y1 + 0.5 + (MAX_CLIP_X - *x1) * (*y2 - *y1) / (*x2 - *x1);
189                         }
190                         break;
191
192                 case CLIP_SE:
193                         yc1 = MAX_CLIP_Y;
194                         xc1 = *x1 + 0.5 + (MAX_CLIP_Y - *y1) * (*x2 - *x1) / (*y2 - *y1);
195                         if(xc1 < MIN_CLIP_X || xc1 > MAX_CLIP_X) {
196                                 xc1 = MAX_CLIP_X;
197                                 yc1 = *y1 + 0.5 + (MAX_CLIP_X - *x1) * (*y2 - *y1) / (*x2 - *x1);
198                         }
199                         break;
200
201                 case CLIP_NW:
202                         yc1 = MIN_CLIP_Y;
203                         xc1 = *x1 + 0.5 + (MIN_CLIP_Y - *y1) * (*x2 - *x1) / (*y2 - *y1);
204                         if(xc1 < MIN_CLIP_X || xc1 > MAX_CLIP_X) {
205                                 xc1 = MIN_CLIP_X;
206                                 yc1 = *y1 + 0.5 + (MIN_CLIP_X - *x1) * (*y2 - *y1) / (*x2 - *x1);
207                         }
208                         break;
209
210                 case CLIP_SW:
211                         yc1 = MAX_CLIP_Y;
212                         xc1 = *x1 + 0.5 + (MAX_CLIP_Y - *y1) * (*x2 - *x1) / (*y2 - *y1);
213                         if(xc1 < MIN_CLIP_X || xc1 > MAX_CLIP_X) {
214                                 xc1 = MIN_CLIP_X;
215                                 yc1 = *y1 + 0.5 + (MIN_CLIP_X - *x1) * (*y2 - *y1) / (*x2 - *x1);
216                         }
217                         break;
218
219                 default: break;
220         }
221
222         // find clip point for p2
223         switch(p2_code) {
224                 case CLIP_C: break;
225                 
226                 case CLIP_N:
227                         yc2 = MIN_CLIP_Y;
228                         xc2 = *x2 + 0.5 + (MIN_CLIP_Y - *y2) * (*x1 - *x2) / (*y1 - *y2);
229                         break;
230
231                 case CLIP_S:
232                         yc2 = MAX_CLIP_Y;
233                         xc2 = *x2 + 0.5 + (MAX_CLIP_Y - *y2) * (*x1 - *x2) / (*y1 - *y2);
234                         break;
235
236                 case CLIP_W:
237                         xc2 = MIN_CLIP_X;
238                         yc2 = *y2 + 0.5 + (MIN_CLIP_X - *x2) * (*y1 - *y2) / (*x1 - *x2);
239                         break;
240
241                 case CLIP_E:
242                         xc2 = MAX_CLIP_X;
243                         yc2 = *y1 + 0.5 + (MAX_CLIP_X - *x2) * (*y1 - *y2) / (*x1 - *x2);
244                         break;
245
246                 case CLIP_NE:
247                         yc2 = MIN_CLIP_Y;
248                         xc2 = *x2 + 0.5 + (MIN_CLIP_Y - *y2) * (*x1 - *x2) / (*y1 - *y2);
249                         if(xc2 < MIN_CLIP_X || xc2 > MAX_CLIP_X) {
250                                 xc2 = MAX_CLIP_X;
251                                 yc2 = *y2 + 0.5 + (MAX_CLIP_X - *x2) * (*y1 - *y2) / (*x1 - *x2);
252                         }
253                         break;
254
255                 case CLIP_SE:
256                         yc2 = MAX_CLIP_Y;
257                         xc2 = *x2 + 0.5 + (MAX_CLIP_Y - *y2) * (*x1 - *x2) / (*y1 - *y2);
258                         if(xc2 < MIN_CLIP_X || xc2 > MAX_CLIP_X) {
259                                 xc2 = MAX_CLIP_X;
260                                 yc2 = *y2 + 0.5 + (MAX_CLIP_X - *x2) * (*y1 - *y2) / (*x1 - *x2);
261                         }
262                         break;
263
264                 case CLIP_NW:
265                         yc2 = MIN_CLIP_Y;
266                         xc2 = *x2 + 0.5 + (MIN_CLIP_Y - *y2) * (*x1 - *x2) / (*y1 - *y2);
267                         if(xc2 < MIN_CLIP_X || xc2 > MAX_CLIP_X) {
268                                 xc2 = MIN_CLIP_X;
269                                 yc2 = *y2 + 0.5 + (MIN_CLIP_X - *x2) * (*y1 - *y2) / (*x1 - *x2);
270                         }
271                         break;
272
273                 case CLIP_SW:
274                         yc2 = MAX_CLIP_Y;
275                         xc2 = *x2 + 0.5 + (MAX_CLIP_Y - *y2) * (*x1 - *x2) / (*y1 - *y2);
276                         if(xc2 < MIN_CLIP_X || xc2 > MAX_CLIP_X) {
277                                 xc2 = MIN_CLIP_X;
278                                 yc2 = *y2 + 0.5 + (MIN_CLIP_X - *x2) * (*y1 - *y2) / (*x1 - *x2);
279                         }
280                         break;
281
282                 default: break;
283         }
284
285         // bounds check
286         if(     (xc1 < MIN_CLIP_X) || (xc1 > MAX_CLIP_X) ||
287                 (yc1 < MIN_CLIP_Y) || (yc1 > MAX_CLIP_Y) ||
288                 (xc2 < MIN_CLIP_X) || (xc2 > MAX_CLIP_X) ||
289                 (yc2 < MIN_CLIP_Y) || (yc2 > MAX_CLIP_X)  ) return 0;
290
291         *x1 = xc1;
292         *y1 = yc1;
293         *x2 = xc2;
294         *y2 = yc2;
295
296         return 1;
297 }
298
299