[comp.sys.atari.st] put pixel routine wanted

rosenkra@hall.cray.com (Bill Rosenkranz) (09/13/89)

---
someone wanted some non-GEM put pixel routine. here are some line-A calls
for C (written for alcyon/madmac, should work with sozobon)...

i wrote these a long time ago but they should be ok and be pretty fast.
if u really need speed, write in asm and inline these calls...

-bill
rosenkra@boston.cray.com

#! /bin/sh
: This is a shar archive.  Extract with sh, not csh.
echo x - Readme
cat > Readme << '19165!Funky!Stuff!'
the linea functions here are callable from c. so far the basic ones are
written (init, get/put pixel, line, blit).

the test programs exercise the functions as follows:

	tst1.ttp	put random pixels (linea1) and lines (linea3)
	tst2.ttp	bit blit an image around the screen

they seem to work fine but i don't yet know all the side effects (i.e. which
regs get clobbered). tst2 never does an init (linea0).

the linea0 function could be expanded to pass all the pointers back thru
args. right now it just returns ptr to the linea structure. the init also
gives a ptr to the font header list as well as ptrs to the actual linea
functions though to use them directly, you must be in supervisor mode.

the line drawing demo is very fast.

so far, there is no need to be in supervisor mode to do these things.

the file "linea.h" is not needed. it does, however, present a list of all
the things in the line A structure in memory.
19165!Funky!Stuff!
echo x - Makefile
cat > Makefile << '19165!Funky!Stuff!'
CFLAGS	= -new

T1_OBJS	= tst1.o linea0.o linea1.o linea3.o
T2_OBJS	= tst2.o linea7.o

all:		tst1 tst2
tst1:		tst1.ttp
tst2:		tst2.ttp

tst1.ttp:	$(T1_OBJS)
		$(CC) -new -s -o tst1.ttp $(T1_OBJS)
		@echo tst1.ttp (point and line tests) made
		@echo execute with:   tst1 500


tst2.ttp:	$(T2_OBJS)
		$(CC) -new -s -o tst2.ttp $(T2_OBJS)
		@echo tst2.ttp (bit blit test) made
		@echo execute with:   tst2

tst1.o:		tst1.c
tst2.o:		tst2.c
linea0.o:	linea0.s
linea1.o:	linea1.s
linea3.o:	linea3.s
linea7.o:	linea7.s

19165!Funky!Stuff!
echo x - linea0.s
cat > linea0.s << '19165!Funky!Stuff!'
*
*	linea0 - return long pointer to struct
*
*	synopsis:
*
*	ptr = (struct line_a *) linea0 ();
*

Init=$A000

	.globl	_linea0

	.text

_linea0:
	link	a6,#0			* stack frame
	movem.l	a0-a2,-(a7)		* save regs we clobber (except d0)

	dc.w	Init

* pointer to struct now in d0 and a0. a1 -> array of font headers, a2 -> array
* of linea functions

	movem.l	(a7)+,a0-a2		* restore regs
	unlk	a6			* fix stack frame

	rts				* d0 is pointer

	.end

19165!Funky!Stuff!
echo x - linea1.s
cat > linea1.s << '19165!Funky!Stuff!'
*
*	linea1 - put pixel
*
*	synopsis:
*
*	void linea1 (struct line_a *ptr, x, y, color);
*

* linea struct offsets:

INTIN=8
PTSIN=12

* args: (wrt stack frame ptr a6)

ptr=8
x=12
y=14
color=16


	.globl	_linea1

	.text

_linea1:
	link	a6,#0
*	movem.l	a0,-(a7)

	move.l	ptr(a6),a0		* linea struct ptr
	move.l	INTIN(a0),a1
	move.l	PTSIN(a0),a2
	move.w	color(a6),(a1)		* put color in intin table
	move.l	x(a6),(a2)		* put coord in ptsin table

	dc.w	$A001			* draw pixel

*	movem.l	(a7)+,a0
	unlk	a6

	rts


	.end

19165!Funky!Stuff!
echo x - linea2.s
cat > linea2.s << '19165!Funky!Stuff!'
*
*	linea2 - get pixel
*
*	synopsis:
*
*	int linea1 (struct line_a *ptr, x, y);
*

* linea struct offsets:

PTSIN=12

* args: (wrt stack frame ptr a6)

ptr=8
x=12
y=14


	.globl	_linea2

	.text

_linea2:
	link	a6,#0
	movem.l	a0-a1,-(a7)

	move.l	ptr(a6),a0		* linea struct ptr
	move.l	PTSIN(a0),a1
	move.l	x(a6),(a1)		* put coord in ptsin table

	dc.w	$A002			* get pixel. returns d0.w

	movem.l	(a7)+,a0-a1
	unlk	a6

	rts


	.end

19165!Funky!Stuff!
echo x - linea3.s
cat > linea3.s << '19165!Funky!Stuff!'
*
*	linea3 - draw line
*
*	synopsis:
*
*	void linea3 (struct line_a *ptr, x1, y1, x2, y2, mode, mask, opt);
*
*	uses line A to draw a line from x1,y1 to x2,y2.
*

* linea struct offsets:

CBIT0=24
CBIT1=26
CBIT2=28
CBIT3=30
LSTLIN=32
LNMASK=34
WMODE=36
X1=38
Y1=40
X2=42
Y2=44


* args:  (wrt stack frame ptr a6)

ptr=8
x_1=12
y_1=14
x_2=16
y_2=18
mode=20
mask=22
opt=24

	.globl	_linea3

	.text

_linea3:
	link	a6,#0

	move.l	ptr(a6),a0		* line A init (a0 -> structure)

	move.w	#1,CBIT0(a0)		* plane 0 (all)
	move.w	#1,CBIT1(a0)		* plane 1 (color only)
	move.w	#1,CBIT2(a0)		* plane 2 (lo res only)
	move.w	#1,CBIT3(a0)		* plane 3 (lo res only)
	move.w	opt(a6),LSTLIN(a0)	* draw last pixel of line?
	move.w	mask(a6),LNMASK(a0)	* line mask (solid=FFFF)
	move.w	mode(a6),WMODE(a0)	* write mode (replace=0)
	move.l	x_1(a6),X1(a0)		* coord of points
	move.l	x_2(a6),X2(a0)

	dc.w	$A003			* draw line

	unlk	a6

	rts

	.end

19165!Funky!Stuff!
echo x - linea7.s
cat > linea7.s << '19165!Funky!Stuff!'
*
*	linea7 - bit blit
*
*	synopsis:
*
*	void linea7 (long blit_parm_block);
*

pblock=8


	.globl	_linea7

	.text

_linea7:
	link	a5,#0			* set up a stack frame with a5
	movem.l	a6,-(a7)		* save a6 since it is used

	move.l	pblock(a5),a6		* copy arg to a6 (-> blit parm block)

	dc.w	$A007			* do it...

	movem.l	(a7)+,a6		* restore a6
	unlk	a5

	rts				* returns nothing

	.end
19165!Funky!Stuff!
echo x - tst1.c
cat > tst1.c << '19165!Funky!Stuff!'
/*#define DEBUG*/

#ifdef DEBUG
#include <stdio.h>
#endif
#include <osbind.h>

#ifndef void
#define void	int
#endif

long	linea0 ();
void	linea1 ();
long	atol ();
int	rand ();
int	rand_range ();
long	lrand_range ();
long	lrand ();


main(argc, argv)
int	argc;
char   *argv[];
{
	long	ii;
	int	x1, y1, x2, y2;
	int	x, y;
	int	mode = 2;		/* 0=replace,2=XOR */
	int	opt = 0;
	int	mask = 0xFFFF;
	int	color = 1;
	long	ptr;
	long	num = 1000L;

	argc--, argv++;
	if (argc > 0)
		num = atol (*argv);

	ptr = linea0 ();

#ifdef DEBUG
	fprintf (stderr, "linea0 ptr: 0x%08lx\n\n\n", ptr);
	fprintf (stderr, "planes:     %d\n", *(int *)(ptr));
	fprintf (stderr, "v_rez_vt:   %d\n", *(int *)(ptr-4));
	fprintf (stderr, "v_rez_hz:   %d\n", *(int *)(ptr-12));
#endif
	Cconws ("any key to start pixel test (linea1):\n\r");
	Cconin ();
	Cconws ("\33E");

	for (ii = 0; ii < num; ii++)
	{
		x = rand_range (100, 500);
		y = rand_range (100, 300);

		linea1 (ptr, x, y, color);
	}

	Cconws ("pixel test done...any key to start line test (linea3):\n\r");
	Cconin ();
	Cconws ("\33E");

	for (ii = 0; ii < num; ii++)
	{
		x1 = rand_range (100, 500);
		x2 = rand_range (100, 500);
		y1 = rand_range (100, 300);
		y2 = rand_range (100, 300);

		linea3 (ptr, x1, y1, x2, y2, mode, mask, opt);
	}

	exit (0);
}
	

/*------------------------------*/
/*	rand_range		*/
/*------------------------------*/
int	rand_range (lo, hi)
int	lo, hi;
{

/*
 *	return random int in the range specified (0-7fff): lo <= val < hi
 */

	return (((int) rand () % (hi - lo)) + lo);
}


/*------------------------------*/
/*	lrand_range		*/
/*------------------------------*/
long	lrand_range (lo, hi)
long	lo, hi;
{

/*
 *	return random long in the range specified (0-7fffffff): lo <= val < hi
 *
 *	note: alcyon may have a problem with % for longs...
 */

	extern long	lrand ();

	return (((long) lrand () % (hi - lo)) + lo);
}



/*------------------------------*/
/*	lrand			*/
/*------------------------------*/
long	lrand ()
{

/*
 *	return random long.
 *
 *	fills each word with a random int. also could interleave the ints.
 */

	union
	{
		long	lval;
		int	ival[2];

	}	uuu;

	uuu.ival[0] = rand ();
	uuu.ival[1] = rand ();

	return ((long) uuu.lval);
}
19165!Funky!Stuff!
echo x - tst2.c
cat > tst2.c << '19165!Funky!Stuff!'
/*
 *	demo the linea bit blit ($A007)
 */

#include <portab.h>
#include <osbind.h>
#include <gem\blit.h>

extern void	linea7 ();
extern long	atol ();

long		tfac;				/* for speed control */

BBPB		pblock;				/* for transfer to screen */
BBPB		pblock2;			/* for transfer from screen */

int		save_space[60];			/* place to save screen rect*/
int		bug[60] =			/* our thingie to blit... */
{
		0x0000,0x0000,0x0030,
		0x0000,0x0000,0x0066,
		0x0000,0x0000,0x006c,
		0x0000,0x0000,0x00ce,
		0x0000,0x0000,0x00cc,
		0x0000,0x0000,0x0198,
		0x0000,0x0000,0x03b0,
		0x0000,0x0000,0x0770,
		0x0000,0x0000,0x0760,
		0x0000,0x0000,0x0ee0,
		0x0000,0x0000,0x7fc0,
		0x0000,0x0003,0xffc0,
		0x0000,0x003f,0xffc0,
		0x0000,0x00ff,0xffe0,
		0x0000,0x1fff,0xfff0,
		0x01ff,0xffff,0xfef0,
		0x0fff,0xffff,0xff70,
		0x1fff,0xffff,0xff80,
		0xffff,0xffff,0xffe0,
		0xffff,0xffff,0xffc0
};
int		unbug[60] =			/* not really needed... */
{
		0,0,0, 0,0,0, 0,0,0, 0,0,0, 0,0,0, 0,0,0, 0,0,0, 0,0,0,
		0,0,0, 0,0,0, 0,0,0, 0,0,0, 0,0,0, 0,0,0, 0,0,0, 0,0,0,
		0,0,0, 0,0,0, 0,0,0, 0,0,0
};

main (argc, argv)
int	argc;
char   *argv[];
{
	register int	x,
			y;
	register int	xdirection,
			ydirection;
	register int	inc;
	int		i;
	int		xmin,
			xmax,
			ymin,
			ymax;
	long		screen;
	long		old_phys;
	long		old_log;
	

	/*
	 *   check arg...(time delay)
	 */
	argc--, argv++;
	tfac = 1000L;
	if (argc > 0)
		tfac = atol (*argv);


	/*
	 *   erase screen
	 */
/*	Cconws ("\33E");*/
	Cconws ("up/down arrow controls speed. any other key quits...any key to start: \n\r");
	Cconin ();

	/*
	 *   get old phys/logbase and reset screen
	 */
	old_phys = Physbase ();
	old_log  = Logbase ();
	screen   = old_phys;
/*	Setscreen (screen, screen, -1);*/


	/*
	 *   fill in blit param blocks. first one is used for sprite->screen
	 *   second one used for screen->buf. the op_tab stuff is critical.
	 */
	pblock.bb_b_wd 		= 48;		/* pixels/line */
	pblock.bb_b_ht 		= 20;		/* lines */
	pblock.bb_plane_ct	= 1;		/* num conseq planes to blit */
	pblock.bb_fg_col	= 1;
/*!!!*/	pblock.bb_bg_col	= 0;		/* was 0 */
	pblock.bb_op_tab.fg0bg0	= 4;		/* replace */
	pblock.bb_op_tab.fg0bg1	= 4;
	pblock.bb_op_tab.fg1bg0	= 7;
	pblock.bb_op_tab.fg1bg1	= 7;

	pblock.bb_s.bl_xmin	= 0;		/* src always 0,0 */
	pblock.bb_s.bl_ymin	= 0;
	pblock.bb_s.bl_form	= (char *) bug;
	pblock.bb_s.bl_nxwd	= HI_NXWD;
	pblock.bb_s.bl_nxln	= 6;		/* byte offset (48/8) */
	pblock.bb_s.bl_nxpl	= NXPL;		/* always 2 */

	pblock.bb_d.bl_xmin	= 0x00FF;	/* initial dest x,y */
	pblock.bb_d.bl_ymin	= 0x0064;
	pblock.bb_d.bl_form	= (char *) screen;
	pblock.bb_d.bl_nxwd	= HI_NXWD;
	pblock.bb_d.bl_nxln	= HI_NXLN;	/* 80*8 pix/lines */
	pblock.bb_d.bl_nxpl	= NXPL;		/* always 2 */

	pblock.bb_p_addr	= 0L;		/* no "pattern"... */
	pblock.bb_p_nxln	= 0;
	pblock.bb_p_nxpl	= 0;
	pblock.bb_p_mask	= 0;
	for (i = 0; i < 24; i++)
		pblock.bb_fill[i] = 0;

	pblock2.bb_b_wd 	= pblock.bb_b_wd;
	pblock2.bb_b_ht 	= pblock.bb_b_ht;
	pblock2.bb_plane_ct	= 1;
	pblock2.bb_fg_col	= 1;
	pblock2.bb_bg_col	= 0;
	pblock2.bb_op_tab.fg0bg0= 3;
	pblock2.bb_op_tab.fg0bg1= 3;
	pblock2.bb_op_tab.fg1bg0= 3;
	pblock2.bb_op_tab.fg1bg1= 3;

	pblock2.bb_s.bl_xmin	= pblock.bb_d.bl_xmin;
	pblock2.bb_s.bl_ymin	= pblock.bb_d.bl_ymin;
	pblock2.bb_s.bl_form	= pblock.bb_d.bl_form;
	pblock2.bb_s.bl_nxwd	= pblock.bb_d.bl_nxwd;
	pblock2.bb_s.bl_nxln	= pblock.bb_d.bl_nxln;
	pblock2.bb_s.bl_nxpl	= pblock.bb_d.bl_nxpl;

	pblock2.bb_d.bl_xmin	= pblock.bb_s.bl_xmin;
	pblock2.bb_d.bl_ymin	= pblock.bb_s.bl_ymin;
	pblock2.bb_d.bl_form	= pblock.bb_s.bl_form;
	pblock2.bb_d.bl_nxwd	= pblock.bb_s.bl_nxwd;
	pblock2.bb_d.bl_nxln	= pblock.bb_s.bl_nxln;
	pblock2.bb_d.bl_nxpl	= pblock.bb_s.bl_nxpl;

	pblock2.bb_p_addr	= 0L;
	pblock2.bb_p_nxln	= 0;
	pblock2.bb_p_nxpl	= 0;
	pblock2.bb_p_mask	= 0;
	for (i = 0; i < 24; i++)
		pblock2.bb_fill[i] = 0;

	/*
	 *   for direction changes...
	 */
	xdirection = -1;
	ydirection = -1;
	xmin = 0;				/* limits */
	xmax = 640-48;
	ymin = 0;
	ymax = 400-14;
	inc = 2;				/* movement each cycle (pix)*/

	/*
	 *   do it until a non-arrow key is pressed
	 */
	while (1)
	{
		/*
		 *   save old background. use block 2
		 */
		pblock2.bb_s.bl_form = (char *) screen;
		pblock2.bb_d.bl_form = (char *) save_space;
		linea7 (&pblock2);

		/*
		 *   draw block (vsync is bad...)
		 */
		pblock.bb_op_tab.fg0bg0	= 4;		/* !s & d */
		pblock.bb_op_tab.fg0bg1	= 4;
		pblock.bb_op_tab.fg1bg0	= 7;		/* s | d */
		pblock.bb_op_tab.fg1bg1	= 7;
		pblock.bb_d.bl_form = (char *) screen;
		pblock.bb_s.bl_form = (char *) bug;
		linea7 (&pblock);


		/*
		 *   delay controls speed
		 */
		time_delay (tfac);


		/*
		 *   calc new position during the delay
		 */
		x = pblock.bb_d.bl_xmin + (xdirection * inc);
		if (x < xmin)
		{
			x = xmin + inc;
			xdirection *= -1;
		}
		if (x > xmax)
		{
			x = xmax - inc;
			xdirection *= -1;
		}
		y = pblock.bb_d.bl_ymin + (ydirection * inc);
		if (y < ymin)
		{
			y = ymin + inc;
			ydirection *= -1;
		}
		if (y > ymax)
		{
			y = ymax - inc;
			ydirection *= -1;
		}


		/*
		 *   get user key input. right now just track up/down
		 *   arrows for speed control. any other char quits.
		 */
		if (user_break ())
			break;


		/*
		 *   now undraw (could actually blit old background back)
		 */
		pblock.bb_op_tab.fg0bg0	= 3;		/* replace */
		pblock.bb_op_tab.fg0bg1	= 3;
		pblock.bb_op_tab.fg1bg0	= 3;
		pblock.bb_op_tab.fg1bg1	= 3;
/*		pblock.bb_s.bl_form = (char *) unbug;*/
		pblock.bb_s.bl_form = (char *) save_space;
		pblock.bb_d.bl_form = (char *) screen;
		linea7 (&pblock);
/*		Vsync ();*/
		/* vsync here makes it smoother, but it is much slower */


		/*
		 *   set new coords
		 */
		pblock.bb_d.bl_xmin  = x;
		pblock2.bb_s.bl_xmin = x;
		pblock.bb_d.bl_ymin  = y;
		pblock2.bb_s.bl_ymin = y;
	}

	/*
	 *   reset screen
	 */
/*	Setscreen (old_log, old_phys, -1);*/

	exit (0);
}



time_delay (n)
long	n;
{
	long	i;

	for (i = 0; i < n; i++)
		;
}



int	user_break ()
{
	long	inkey;

	if (Bconstat (2))
	{
		/*
		 *   ret 2 bytes in low byte of each word (not like
		 *   evnt_keybd)
		 */
		inkey = Bconin (2);
		if (inkey == 0x00480000L)	/* up arrow -> faster */
			tfac -= 55;
		else if (inkey == 0x00500000L)	/* down arrow -> slower */
			tfac += 55;
		else
			return (1);
	}
	return (0);
}
19165!Funky!Stuff!