/* This program demonstrates how to use BIOS calls for programming the */
/* Atari Portfolio in graphics mode. The program should be compiled    */
/* with Turbo C 1.5 or 2.0.                                            */
/*                                                                     */
/* Written by: Tommy Frandsen (frandsen@diku.dk) - 9/23/90.            */

#include <conio.h>
#include <stdlib.h>
#include <dos.h>

#define GRAPHIC 0x04
#define TEXT    0x07

#define PIX_OFF 0
#define PIX_ON  1

#define XDIM 240
#define YDIM 64

#define XMIN 0
#define XMAX (XDIM-1)
#define YMIN 0
#define YMAX (YDIM-1)

#define LINE_OLD 30
#define LINE_DIF  2
#define LINE_MAX 75
#define RAND_INT 10
#define RAND_THR  8 

void set_mode(int mode);
void pixel(int x, int y, int color);
void line(int x1, int y1, int x2, int y2, int color);
int  test(int x, int y);

main(int argc, char *argv[])
{
    struct {
        int x1;
        int y1;
        int x2;
        int y2;
    } old[LINE_OLD];

    int x1, y1, x2, y2;
    int x1_dir=1, y1_dir=1;
    int x2_dir=1, y2_dir=1;
    int i;

    set_mode(GRAPHIC);

    for(i=0; i<LINE_OLD; i++) 
        old[i].x1 = old[i].y1 = old[i].x2 = old[i].y2 = 0;
    i = 0;

    if(argc>1)
        srand(atoi(argv[1]));
    x1 = x2 = rand()%XDIM;
    y1 = y2 = rand()%YDIM;

    for(;;) {
        if (rand()%RAND_INT>RAND_THR) 
            x1_dir = -x1_dir;
        if (rand()%RAND_INT>RAND_THR) 
            y1_dir = -y1_dir;
        if (rand()%RAND_INT>RAND_THR) 
            x2_dir = -x2_dir;
        if (rand()%RAND_INT>RAND_THR) 
            y2_dir = -y2_dir;

        x1 += LINE_DIF*x1_dir;
        y1 += LINE_DIF*y1_dir;
        x2 += LINE_DIF*x2_dir;
        y2 += LINE_DIF*y2_dir;
        
        if (x1>XMAX) x1 = XMAX;
        if (y1>YMAX) y1 = YMAX;
        if (x2>XMAX) x2 = XMAX;
        if (y2>YMAX) y2 = YMAX;
        if (x1<XMIN) x1 = XMIN;
        if (y1<YMIN) y1 = YMIN;
        if (x2<XMIN) x2 = XMIN;
        if (y2<YMIN) y2 = YMIN;
 
       if ((long)(x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)>LINE_MAX*LINE_MAX) {
            x1 = x2 = rand()%XDIM;
            y1 = y2 = rand()%YDIM;
        }

        line(old[i].x1, old[i].y1, old[i].x2, old[i].y2, PIX_OFF);
        old[i].x1=x1;
        old[i].y1=y1;
        old[i].x2=x2;
        old[i].y2=y2;
        line(old[i].x1, old[i].y1, old[i].x2, old[i].y2, PIX_ON);
        
        i = (i+1)%LINE_OLD;

        if (kbhit())
            break;
    }

    set_mode(TEXT);
}


/* set_mode: Use this function to move between text and graphics mode. */
/*           Use set_mode(4) to set graphics mode and set_mode(7) to   */
/*           set text mode.                                            */
void set_mode(int mode)
{
    union REGS regs;

    regs.h.ah = 0;
    regs.h.al = mode;
    int86(0x10, &regs, &regs);
}


/* pixel: Sets or clears the pixel in (x,y). color=1 will set a pixel  */
/*        and color=0 will clear a pixel. 0<=x<=239 and 0<=y<=63.      */
void pixel(int x, int y, int color)
{
    union REGS regs;

    regs.h.ah = 0x0c;
    regs.h.al = color;
    regs.h.bh = 0;
    regs.x.cx = x;
    regs.x.dx = y;
    int86(0x10, &regs, &regs);
}


/* line: Draws a line between (x1,y1) and (x2,y2). color=1 will draw a */
/*       line and color=0 will clear a line. 0<=x1<=239, 0<=y1<=63,    */
/*       0<=x2<=239 and 0<=y2<=63.                                     */
void line(int x1, int y1, int x2, int y2, int color)
{
    int x, y, d, a, b;
    int dx_diag, dy_diag;
    int dx_nondiag, dy_nondiag;
    int diag_inc, nondiag_inc;
    int i, swap;

    x = x1;
    y = y1;
    a = x2-x1;
    b = y2-y1;

    if (a<0) {
        a       = -a;
        dx_diag = -1;
    } else 
        dx_diag = 1;

    if (b<0) {
        b       = -b;
        dy_diag = -1;
    } else 
        dy_diag = 1;

    if (a<b) {
        swap       = a;
        a          = b;
        b          = swap;
        dx_nondiag = 0;
        dy_nondiag = dy_diag;
    } else {
        dx_nondiag = dx_diag;
        dy_nondiag = 0;
    }

    d           = b+b-a;
    nondiag_inc = b+b;
    diag_inc    = b+b-a-a;

    for(i=0; i<=a; i++) {
        pixel(x, y, color);
        if (d<0) {
            x = x+dx_nondiag;
            y = y+dy_nondiag;
            d = d+nondiag_inc;
        } else {
            x = x+dx_diag;
            y = y+dy_diag;
            d = d+diag_inc;
        }        
    }
}


/* test: Is the pixel in (x,y) set?. Returns 1 if set, otherwise 0.    */
/*       0<=x<=239 and 0<=y<=63                                        */
int  test(int x, int y)
{
    union REGS regs;

    regs.h.ah = 0x0d;
    regs.h.bh = 0;
    regs.x.cx = x;
    regs.x.dx = y;
    int86(0x10, &regs, &regs);
    return(regs.h.al);
}
