[comp.sys.handhelds] Atari Portfolio Graphics

frandsen@rimfaxe.diku.dk (Tommy Frandsen) (09/28/90)

To Portfolio Users...

There has been som interest in programming graphics applications for the
Portfolio. As you may know the Portfolio supports 240*64 pixel graphics, but
the built-in software dosen't use this capability. Below I have included
a program, that demonstrates how to program graphics on the Portfolio.

The graphics mode on the Portfolio works very well. You can activate the 
built-in applications also when in graphics mode (it automaticly switch 
bewtween graphics and text and back again) and you can turn it on/off and
retain graphics mode. But it isn't possible to output text while in
graphics mode and PrtScr dosen't work (two intereseting programming projects).

The program draws nice random figures on the screen. The program is rather 
compact, so it dosen't take up much memory (about 2.7K) either on the disk
or in memory (you can call the built-in applications while the program is
active). To activate the program just type 'pix' at the DOS prompt. If you
want to see another sequence of figures, just follow 'pix' with a seed for
the random number generator, fx. 'pix 123'. The program continues to run 
until a key is pressed. It also disactivates the automatic power off (not
by intention), so it may drain your batteries if you forget to stop it 
(or you could power off manually, in witch case the program will continue 
to run, when you turn on the Portfolio again). 

I have also included the Turbo C source for the program. You are welcomed
to include any part of the program in your own programs. If you write a
good program, it would be nice to hear about it in this newsgroup.

The only way to use the graphics mode is with BIOS function calls. Since the 
Portfolio is BIOS-compatible, you can find the relevant BIOS functions in any 
book about BIOS programming (I can recommend DOS Programmers Reference from 
QUE, this book also discusses how to call BIOS functions from high level 
languages such as C or Pascal). But you don't need to know anything about
BIOS-programming to use the C-functions I have provided.

Please write to me, if you have problems with the program. I would also be 
glad to hear from others, who has experiences with programming the Portfolio 
at the BIOS level (is there a way to setup the Portfolio thru BIOS calls, fx.
to switch sound on/off).

frandsen@diku.dk


/* 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;
v    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);
}


Below is an uuencoded version of the executable. To decode it
place it in a file and use the command 'uudecode file-name'.

--- cut here ---
begin 666 pix.exe
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
<  '& 08" "T0 ([8CL QV_J.UHOG^R[_+P ! ,+K
 
end