]> git.ozlabs.org Git - ponghero.git/blob - prpong.c
Mostly works now.
[ponghero.git] / prpong.c
1 #define _GNU_SOURCE
2 #include <math.h>
3 #include <err.h>
4 #include <stdlib.h>
5 #include <stdio.h>
6 #include <stdbool.h>
7 #include <sys/time.h>
8 #include <time.h>
9 #include <limits.h>
10 #include "stdrusty.h"
11 #include "list/list.h"
12 #include <SDL/SDL.h>
13 #include <cwiid.h>
14
15 #define MAX_X CWIID_IR_X_MAX
16 #define MAX_Y CWIID_IR_Y_MAX
17
18 /* Obtained from http://tog.acm.org/GraphicsGems/gemsiii/insectc.c */
19 /* Faster Line Segment Intersection   */
20 /* Franklin Antonio                   */
21
22 /* The use of some short working variables allows this code to run   */
23 /* faster on 16-bit computers, but is not essential.  It should not  */
24 /* affect operation on 32-bit computers.  The short working variables*/
25 /* to not restrict the range of valid input values, as these were    */
26 /* constrained in any case, due to algorithm restrictions.           */
27 static bool lines_intersect(double x1, double y1,
28                             double x2, double y2,
29                             double x3, double y3,
30                             double x4, double y4,
31                             double *x, double *y) 
32 {
33
34         double Ax,Bx,Cx,Ay,By,Cy,d,e,f,num;
35         double x1lo,x1hi,y1lo,y1hi;
36
37         Ax = x2-x1;
38         Bx = x3-x4;
39
40         if(Ax<0) {                                              /* X bound box test*/
41                 x1lo=x2; x1hi=x1;
42         } else {
43                 x1hi=x2; x1lo=x1;
44         }
45         if(Bx>0) {
46                 if(x1hi < x4 || x3 < x1lo) return false;
47         } else {
48                 if(x1hi < x3 || x4 < x1lo) return false;
49         }
50
51         Ay = y2-y1;
52         By = y3-y4;
53
54         if(Ay<0) {                                              /* Y bound box test*/
55                 y1lo=y2; y1hi=y1;
56         } else {
57                 y1hi=y2; y1lo=y1;
58         }
59         if(By>0) {
60                 if(y1hi < y4 || y3 < y1lo) return false;
61         } else {
62                 if(y1hi < y3 || y4 < y1lo) return false;
63         }
64
65
66         Cx = x1-x3;
67         Cy = y1-y3;
68         d = By*Cx - Bx*Cy;                                      /* alpha numerator*/
69         f = Ay*Bx - Ax*By;                                      /* both denominator*/
70         if(f>0) {                                               /* alpha tests*/
71                 if(d<0 || d>f) return false;
72         } else {
73                 if(d>0 || d<f) return false;
74         }
75
76         e = Ax*Cy - Ay*Cx;                                      /* beta numerator*/
77         if(f>0) {                                               /* beta tests*/
78                 if(e<0 || e>f) return false;
79         } else {
80                 if(e>0 || e<f) return false;
81         }
82
83 /*compute intersection coordinates*/
84
85         if(f==0) return false;
86         num = d*Ax;                                             /* numerator */
87         *x = x1 + num / f;                              /* intersection x */
88
89         num = d*Ay;
90         *y = y1 + num / f;                              /* intersection y */
91
92         return true;
93 }
94
95 // A set of very useful macros that you will find in most
96 // code that I write whether I use them in a program or
97 // not.
98
99 #define abs(a) (((a)<0) ? -(a) : (a))
100 #define sign(a) (((a)<0) ? -1 : (a)>0 ? 1 : 0)
101
102 // The following code implements a Bresenham line drawing
103 // algorithm. There are 4 separate routines each optimized
104 // for one of the four pixel depths supported by SDL. SDL
105 // support many pixel formats, but it only support 8, 16,
106 // 24, and 32 bit pixels.
107
108 //----------------------------------------------------------
109
110 // Draw lines in 8 bit surfaces.
111
112 static void line8(SDL_Surface *s, 
113                   int x1, int y1, 
114                   int x2, int y2, 
115                   Uint32 color)
116 {
117   int d;
118   int x;
119   int y;
120   int ax;
121   int ay;
122   int sx;
123   int sy;
124   int dx;
125   int dy;
126
127   Uint8 *lineAddr;
128   Sint32 yOffset;
129
130   dx = x2 - x1;  
131   ax = abs(dx) << 1;  
132   sx = sign(dx);
133
134   dy = y2 - y1;  
135   ay = abs(dy) << 1;  
136   sy = sign(dy);
137   yOffset = sy * s->pitch;
138
139   x = x1;
140   y = y1;
141
142   lineAddr = ((Uint8 *)(s->pixels)) + (y * s->pitch);
143   if (ax>ay)
144   {                      /* x dominant */
145     d = ay - (ax >> 1);
146     for (;;)
147     {
148       if (y >= 0 && y < MAX_Y && x >= 0 && x < MAX_X)
149         *(lineAddr + x) = (Uint8)color;
150
151       if (x == x2)
152       {
153         return;
154       }
155       if (d>=0)
156       {
157         y += sy;
158         lineAddr += yOffset;
159         d -= ax;
160       }
161       x += sx;
162       d += ay;
163     }
164   }
165   else
166   {                      /* y dominant */
167     d = ax - (ay >> 1);
168     for (;;)
169     {
170       if (y >= 0 && y < MAX_Y && x >= 0 && x < MAX_X)
171         *(lineAddr + x) = (Uint8)color;
172
173       if (y == y2)
174       {
175         return;
176       }
177       if (d>=0) 
178       {
179         x += sx;
180         d -= ay;
181       }
182       y += sy;
183       lineAddr += yOffset;
184       d += ax;
185     }
186   }
187 }
188
189 //----------------------------------------------------------
190
191 // Draw lines in 16 bit surfaces. Note that this code will
192 // also work on 15 bit surfaces.
193
194 static void line16(SDL_Surface *s, 
195                    int x1, int y1, 
196                    int x2, int y2, 
197                    Uint32 color)
198 {
199   int d;
200   int x;
201   int y;
202   int ax;
203   int ay;
204   int sx;
205   int sy;
206   int dx;
207   int dy;
208
209   Uint8 *lineAddr;
210   Sint32 yOffset;
211
212   dx = x2 - x1;  
213   ax = abs(dx) << 1;  
214   sx = sign(dx);
215
216   dy = y2 - y1;  
217   ay = abs(dy) << 1;  
218   sy = sign(dy);
219   yOffset = sy * s->pitch;
220
221   x = x1;
222   y = y1;
223
224   lineAddr = ((Uint8 *)s->pixels) + (y * s->pitch);
225   if (ax>ay)
226   {                      /* x dominant */
227     d = ay - (ax >> 1);
228     for (;;)
229     {
230       if (y >= 0 && y < MAX_Y && x >= 0 && x < MAX_X)
231         *((Uint16 *)(lineAddr + (x << 1))) = (Uint16)color;
232
233       if (x == x2)
234       {
235         return;
236       }
237       if (d>=0)
238       {
239         y += sy;
240         lineAddr += yOffset;
241         d -= ax;
242       }
243       x += sx;
244       d += ay;
245     }
246   }
247   else
248   {                      /* y dominant */
249     d = ax - (ay >> 1);
250     for (;;)
251     {
252       if (y >= 0 && y < MAX_Y && x >= 0 && x < MAX_X)
253         *((Uint16 *)(lineAddr + (x << 1))) = (Uint16)color;
254
255       if (y == y2)
256       {
257         return;
258       }
259       if (d>=0) 
260       {
261         x += sx;
262         d -= ay;
263       }
264       y += sy;
265       lineAddr += yOffset;
266       d += ax;
267     }
268   }
269 }
270
271 //----------------------------------------------------------
272
273 // Draw lines in 24 bit surfaces. 24 bit surfaces require
274 // special handling because the pixels don't fall on even
275 // address boundaries. Instead of being able to store a
276 // single byte, word, or long you have to store 3
277 // individual bytes. As a result 24 bit graphics is slower
278 // than the other pixel sizes.
279
280 static void line24(SDL_Surface *s, 
281                    int x1, int y1, 
282                    int x2, int y2, 
283                    Uint32 color)
284 {
285   int d;
286   int x;
287   int y;
288   int ax;
289   int ay;
290   int sx;
291   int sy;
292   int dx;
293   int dy;
294
295   Uint8 *lineAddr;
296   Sint32 yOffset;
297
298 #if (SDL_BYTEORDER == SDL_BIG_ENDIAN)
299   color <<= 8;
300 #endif
301
302   dx = x2 - x1;  
303   ax = abs(dx) << 1;  
304   sx = sign(dx);
305
306   dy = y2 - y1;  
307   ay = abs(dy) << 1;  
308   sy = sign(dy);
309   yOffset = sy * s->pitch;
310
311   x = x1;
312   y = y1;
313
314   lineAddr = ((Uint8 *)(s->pixels)) + (y * s->pitch);
315   if (ax>ay)
316   {                      /* x dominant */
317     d = ay - (ax >> 1);
318     for (;;)
319     {
320       Uint8 *p = (lineAddr + (x * 3));
321       if (y >= 0 && y < MAX_Y && x >= 0 && x < MAX_X)
322         memcpy(p, &color, 3);
323
324       if (x == x2)
325       {
326         return;
327       }
328       if (d>=0)
329       {
330         y += sy;
331         lineAddr += yOffset;
332         d -= ax;
333       }
334       x += sx;
335       d += ay;
336     }
337   }
338   else
339   {                      /* y dominant */
340     d = ax - (ay >> 1);
341     for (;;)
342     {
343       Uint8 *p = (lineAddr + (x * 3));
344       if (y >= 0 && y < MAX_Y && x >= 0 && x < MAX_X)
345         memcpy(p, &color, 3);
346
347       if (y == y2)
348       {
349         return;
350       }
351       if (d>=0) 
352       {
353         x += sx;
354         d -= ay;
355       }
356       y += sy;
357       lineAddr += yOffset;
358       d += ax;
359     }
360   }
361 }
362
363 //----------------------------------------------------------
364
365 // Draw lines in 32 bit surfaces. Note that this routine
366 // ignores alpha values. It writes them into the surface
367 // if they are included in the pixel, but does nothing
368 // else with them.
369
370 static void line32(SDL_Surface *s, 
371                    int x1, int y1, 
372                    int x2, int y2, 
373                    Uint32 color)
374 {
375   int d;
376   int x;
377   int y;
378   int ax;
379   int ay;
380   int sx;
381   int sy;
382   int dx;
383   int dy;
384
385   Uint8 *lineAddr;
386   Sint32 yOffset;
387
388   dx = x2 - x1;  
389   ax = abs(dx) << 1;  
390   sx = sign(dx);
391
392   dy = y2 - y1;  
393   ay = abs(dy) << 1;  
394   sy = sign(dy);
395   yOffset = sy * s->pitch;
396
397   x = x1;
398   y = y1;
399
400   lineAddr = ((Uint8 *)(s->pixels)) + (y * s->pitch);
401   if (ax>ay)
402   {                      /* x dominant */
403     d = ay - (ax >> 1);
404     for (;;)
405     {
406       if (y >= 0 && y < MAX_Y && x >= 0 && x < MAX_X)
407         *((Uint32 *)(lineAddr + (x << 2))) = (Uint32)color;
408
409       if (x == x2)
410       {
411         return;
412       }
413       if (d>=0)
414       {
415         y += sy;
416         lineAddr += yOffset;
417         d -= ax;
418       }
419       x += sx;
420       d += ay;
421     }
422   }
423   else
424   {                      /* y dominant */
425     d = ax - (ay >> 1);
426     for (;;)
427     {
428       if (y >= 0 && y < MAX_Y && x >= 0 && x < MAX_X)
429         *((Uint32 *)(lineAddr + (x << 2))) = (Uint32)color;
430
431       if (y == y2)
432       {
433         return;
434       }
435       if (d>=0) 
436       {
437         x += sx;
438         d -= ay;
439       }
440       y += sy;
441       lineAddr += yOffset;
442       d += ax;
443     }
444   }
445 }
446
447 //----------------------------------------------------------
448
449 // Examine the depth of a surface and select a line
450 // drawing routine optimized for the bytes/pixel of the
451 // surface.
452
453 static void line(SDL_Surface *s, 
454                  int x1, int y1, 
455                  int x2, int y2, 
456                  Uint32 color)
457 {
458   switch (s->format->BytesPerPixel)
459   {
460   case 1:
461     line8(s, x1, y1, x2, y2, color);
462     break;
463   case 2:
464     line16(s, x1, y1, x2, y2, color);
465     break;
466   case 3:
467     line24(s, x1, y1, x2, y2, color);
468     break;
469   case 4:
470     line32(s, x1, y1, x2, y2, color);
471     break;
472   }
473 }
474
475 #if 1
476 struct coord
477 {
478         double x;
479         double y;
480 };
481
482 struct ball
483 {
484         struct coord pos;
485         struct coord move;
486 };
487
488 struct line_segment
489 {
490         struct coord start, end;
491         struct list_node list;
492         bool ignore;
493         struct timeval expires;
494 };
495
496 static void thick_line(SDL_Surface *s, const struct line_segment *l,
497                        unsigned color)
498 {
499         struct line_segment adj;
500         int x, y, minx = MAX_X, miny = MAX_Y, maxx = 0, maxy = 0;
501
502         SDL_LockSurface(s);
503
504         /* Cheap hack */
505         for (x = -1; x < 2; x++) {
506                 for (y = -1; y < 2; y++) {
507                         adj.start.x = l->start.x + x;
508                         adj.end.x = l->end.x + x;
509                         adj.start.y = l->start.y + y;
510                         adj.end.y = l->end.y + y;
511
512                         if (adj.start.x < minx)
513                                 minx = adj.start.x;
514                         if (adj.start.x > maxx)
515                                 maxx = adj.start.x;
516                         if (adj.start.y < miny)
517                                 miny = adj.start.y;
518                         if (adj.start.y > maxy)
519                                 maxy = adj.start.y;
520                         if (adj.end.x < minx)
521                                 minx = adj.end.x;
522                         if (adj.end.x > maxx)
523                                 maxx = adj.end.x;
524                         if (adj.end.y < miny)
525                                 miny = adj.end.y;
526                         if (adj.end.y > maxy)
527                                 maxy = adj.end.y;
528
529                         line(s, adj.start.x, adj.start.y, adj.end.x, adj.end.y,
530                              color);
531                 }
532         }
533
534         if (minx < 0)
535                 minx = 0;
536         if (miny < 0)
537                 miny = 0;
538         if (maxx >= MAX_X)
539                 maxx = MAX_X-1;
540         if (maxy >= MAX_Y)
541                 maxy = MAX_Y-1;
542         SDL_UpdateRect(s, minx, miny, maxx-minx, maxy-miny);
543         SDL_UnlockSurface(s);
544 }
545
546 static bool intersect(const struct coord *c1, const struct coord *c2,
547                       const struct line_segment *seg, struct coord *intersect)
548 {
549         return lines_intersect(c1->x, c1->y, c2->x, c2->y,
550                                seg->start.x, seg->start.y,
551                                seg->end.x, seg->end.y,
552                                &intersect->x, &intersect->y);
553 }
554
555 static double dist(const struct coord *c1, const struct coord *c2)
556 {
557         float x = (c1->x - c2->x), y = (c1->y - c2->y);
558         return sqrt(x * x + y * y);
559 }
560
561 static unsigned rad_to_deg(double rad)
562 {
563         return ((unsigned)(rad / M_PI * 180) + 360) % 360;
564 }
565
566 static void bounce(struct ball *ball, const struct line_segment *line,
567                    struct coord *remainder)
568 {
569         double len, speed, lang, iang, oang;
570         struct coord isect, new;
571
572         new.x = ball->pos.x + ball->move.x;
573         new.y = ball->pos.y + ball->move.y;
574
575         /* How far were we supposed to move ball? */
576         len = sqrt(remainder->x * remainder->x + remainder->y * remainder->y);
577
578         /* How far is it to intersection? */
579         intersect(&ball->pos, &new, line, &isect);
580         len -= dist(&ball->pos, &isect);
581
582         /* Move ball to intersection. */
583         ball->pos = isect;
584         printf("ball is now at %f,%f\n", ball->pos.x, ball->pos.y);
585
586         /* Outgoing angle = 2 * line angle - incident angle. */
587         lang = atan2(line->end.x - line->start.x, line->end.y - line->start.y);
588         iang = atan2(ball->move.x, ball->move.y);
589         oang = 2 * lang - iang, 2*M_PI;
590         printf("lang = %u, iang = %u, oang=%u\n", 
591                rad_to_deg(lang),
592                rad_to_deg(iang),
593                rad_to_deg(oang));
594
595         /* Set new direction for ball, at same speed */
596         speed = sqrt(ball->move.x * ball->move.x + ball->move.y * ball->move.y);
597         speed *= 1.01;
598         ball->move.x = sin(oang) * speed;
599         ball->move.y = cos(oang) * speed;
600
601         /* Set remainder. */
602         remainder->x = sin(oang) * len;
603         remainder->y = cos(oang) * len;
604         printf("len = %f, remainder = %f,%f\n", len, remainder->x, remainder->y);
605 }
606
607 static struct line_segment border[] = {
608         { { 0, 0, }, { MAX_X-1, 0 } },
609         { { MAX_X-1, 0, }, { MAX_X-1, MAX_Y-1 } },
610         { { MAX_X-1, MAX_Y-1, }, { 0, MAX_Y-1 } },
611         { { 0, MAX_Y-1, }, { 0, 0 } },
612 };
613
614 static inline float deg_to_rad(float degrees)
615 {
616         return degrees * M_PI / 180;
617 }
618
619 static SDL_Surface *sub_surface(SDL_Surface *screen, int w, int h)
620 {
621         return SDL_CreateRGBSurface(SDL_SWSURFACE, w, h,
622                                     screen->format->BitsPerPixel,
623                                     screen->format->Rmask,
624                                     screen->format->Gmask,
625                                     screen->format->Bmask,
626                                     screen->format->Amask);
627 }
628
629 static SDL_Surface *ball_surface(SDL_Surface *screen)
630 {
631         SDL_Surface *ball;
632
633         /* Just like the screen surface. */
634         ball = sub_surface(screen, 5, 5);
635
636         /* Lock the surface */
637         SDL_LockSurface(ball);
638
639         /* Black, white corners. */
640         memset(ball->pixels, 0x00, ball->pitch * 5);
641         line(ball, 0, 0, 0, 0, 0xFFFFFFFF);
642         line(ball, 4, 0, 4, 0, 0xFFFFFFFF);
643         line(ball, 0, 4, 0, 4, 0xFFFFFFFF);
644         line(ball, 4, 4, 4, 4, 0xFFFFFFFF);
645         SDL_UnlockSurface(ball);
646
647         return ball;
648 }
649
650 static void clear_ignore(struct list_head *lines)
651 {
652         struct line_segment *i;
653         printf("Unignoring...\n");
654         list_for_each(lines, i, list)
655                 i->ignore = false;
656 }
657
658 int main(int argc, char *argv[])
659 {
660         struct ball ball;
661         SDL_Surface *screen, *ballsur, *savesur = NULL;
662         Uint8  video_bpp;
663         Uint32 videoflags;
664         unsigned int i;
665         SDL_Rect rect;
666         bool creating_lines = false;
667         struct timeval line_life = { 5, 0 };
668         LIST_HEAD(lines);
669
670         if (argc != 5)
671                 errx(1, "Usage: %s ballx bally ballangle ballspeed\n"
672                      "   Where ballangle is 0 for north, 90 for east, etc\n",
673                         argv[0]);
674
675         ball.pos.x = atol(argv[1]);
676         ball.pos.y = atol(argv[2]);
677         ball.move.x = sin(deg_to_rad(atof(argv[3]))) * atol(argv[4]);
678         ball.move.y = cos(deg_to_rad(atof(argv[3]))) * atol(argv[4]);
679         printf("ball move = %f,%f\n", ball.move.x, ball.move.y);
680
681         /* Initialize SDL */
682         if ( SDL_Init(SDL_INIT_VIDEO) < 0 ) {
683                 fprintf(stderr, "Couldn't initialize SDL: %s\n",SDL_GetError());
684                 return(1);
685         }
686
687         video_bpp = 0;
688         videoflags = SDL_SWSURFACE;
689
690         /* Set 640x480 video mode */
691         if ( (screen=SDL_SetVideoMode(MAX_X,MAX_Y,video_bpp,videoflags)) == NULL ) {
692                 errx(1, "Couldn't set %dx%dx%d video mode: %s",
693                      MAX_X, MAX_Y,video_bpp, SDL_GetError());
694         }
695
696         /* Set the surface pixels and refresh! */
697         if ( SDL_LockSurface(screen) < 0 ) {
698                 errx(1, "Couldn't lock the display surface: %s",
699                      SDL_GetError());
700         }
701         /* White. */
702         memset(screen->pixels, 0xFF, screen->pitch * screen->h);
703
704         SDL_UnlockSurface(screen);
705         SDL_UpdateRect(screen, 0, 0, 0, 0);
706
707         /* Draw borders, put them in list. */
708         for (i = 0; i < ARRAY_SIZE(border); i++) {
709                 border[i].ignore = false;
710                 border[i].expires.tv_sec = LONG_MAX;
711                 border[i].expires.tv_usec = 0;
712                 list_add(&lines, &border[i].list);
713                 thick_line(screen, &border[i], 0);
714         }
715
716         ballsur = ball_surface(screen);
717
718         for (;;) {
719                 struct coord new, isect, move = ball.move;
720                 struct line_segment *best_l, *l, *next;
721                 double best_d;
722                 SDL_Event event;
723                 struct timeval now;
724
725                 gettimeofday(&now, NULL);
726
727                 /* Expire lines */
728                 list_for_each_safe(&lines, l, next, list) {
729                         if (timercmp(&l->expires, &now, <)) {
730                                 list_del(&l->list);
731                                 /* FIXME: Undraw properly. */
732                                 thick_line(screen, l, 0xFFFFFFFF);
733                                 free(l);
734                         }
735                 }
736
737         again:
738                 best_d = MAX_X + MAX_Y;
739                 best_l = NULL;
740                 new.x = ball.pos.x + move.x;
741                 new.y = ball.pos.y + move.y;
742
743                 list_for_each(&lines, l, list) {
744                         if (!l->ignore && intersect(&ball.pos, &new, l, &isect)) {
745                                 double d;
746                                 d = dist(&ball.pos, &isect);
747                                 if (d < best_d) {
748                                         best_l = l;
749                                         best_d = d;
750                                 }
751                         }
752                 }
753
754                 if (best_l) {
755                         printf("Ball bouncing off (%f,%f %f,%f)!\n",
756                                best_l->start.x, best_l->start.y,
757                                best_l->end.x, best_l->end.y);
758                         bounce(&ball, best_l, &move);
759
760                         /* If we moved, stop ignoring lines. */
761                         if (move.x > 0.001 || move.y > 0.001)
762                                 clear_ignore(&lines);
763
764                         /* Don't hit the same line twice. */
765                         printf("Ignoring that line\n");
766                         best_l->ignore = true;
767                         goto again;
768                 }
769
770                 if (move.x > 0.001 || move.y > 0.001) {
771                         clear_ignore(&lines);
772                         printf("Moving by %f,%f to %f,%f\n", move.x, move.y, new.x, new.y);
773                 }
774
775                 /* Restore what was there before ball. */
776                 if (savesur) {
777                         SDL_BlitSurface(savesur, NULL, screen, &rect);
778                         SDL_UpdateRect(screen, rect.x, rect.y, rect.w, rect.h);
779                 } else {
780                         savesur = sub_surface(screen, ballsur->w, ballsur->h);
781                 }
782
783                 /* Save away image under new ball. */
784                 rect.w = ballsur->w;
785                 rect.h = ballsur->h;
786                 rect.x = new.x - ballsur->w/2;
787                 rect.y = new.y - ballsur->h/2;
788                 SDL_BlitSurface(screen, &rect, savesur, NULL);
789
790                 /* Draw new ball */
791                 SDL_BlitSurface(ballsur, NULL, screen, &rect);
792                 SDL_UpdateRect(screen, rect.x, rect.y, rect.w, rect.h);
793                 /* That SDL_BlitSurface can crop rect. */
794                 rect.x = new.x - ballsur->w/2;
795                 rect.y = new.y - ballsur->h/2;
796                 ball.pos = new;
797                 SDL_Delay(25);
798
799                 while (SDL_PollEvent(&event)) {
800                         if (event.type == SDL_QUIT) {
801                                 SDL_Quit();
802                                 return 0;
803                         }
804                         if (event.type == SDL_MOUSEBUTTONDOWN)
805                                 creating_lines = true;
806                         else if (event.type == SDL_MOUSEBUTTONUP)
807                                 creating_lines = false;
808
809                         if (creating_lines && event.type == SDL_MOUSEMOTION) {
810                                 struct line_segment *n = malloc(sizeof(*n));
811                                 n->start.x = event.motion.x - event.motion.xrel;
812                                 n->start.y = event.motion.y - event.motion.yrel;
813                                 n->end.x = event.motion.x;
814                                 n->end.y = event.motion.y;
815                                 n->ignore = false;
816                                 timeradd(&now, &line_life, &n->expires);
817                                 list_add_tail(&lines, &n->list);
818                                 thick_line(screen, n, 0);
819                         }
820                 }
821         }
822 }
823 #endif