Index: [thread] [date] [subject] [author]
  From: Martin Eli Erhardsen <mee@daimi.aau.dk>
  To  : ggi-develop@eskimo.com
  Date: Wed, 08 Jul 1998 21:15:47 +0200

Fast lines

Why are the linear targets using the sliced runlength bresenham
linedrawing algoritm, when a straight bresenham linedraw is
faster and much simpler.

I think that a fixedpoint linedrawing algoritm could be
a good idea too, but it requires an extra division compared
with bresenham, and the decision variable must be
tvice as wide for the same precision.

I have attached the program, which I used to take the 
following measurements on a MIPS R10000

~/prgs/lines> hinv
1 175 MHZ IP30 Processor
CPU: MIPS R10000 Processor Chip Revision: 2.7
FPU: MIPS R10010 Floating Point Chip Revision: 0.0
Main memory size: 128 Mbytes
Instruction cache size: 32 Kbytes
Data cache size: 32 Kbytes
Secondary unified instruction/data cache size: 1 Mbyte
Integral SCSI controller 0: Version QL1040B (rev. 2)
  Disk drive: unit 1 on SCSI controller 0
Integral SCSI controller 1: Version QL1040B (rev. 2)
  CDROM: unit 4 on SCSI controller 1
IOC3 serial port: tty1
IOC3 serial port: tty2
IOC3 parallel port: plp1
Graphics board: SI
Integral Fast Ethernet: ef0, version 1
Iris Audio Processor: version RAD revision 12.0, number 1
~/prgs/lines> cc -O2 -n32 -mips4 -r10000 speed.c -o speed
~/prgs/lines> ./speed
BasicConsistency
ColorWrap
Info:Color wraps at 256
HLine
VLine
sliced
Line   1: 9803921.568627 1.020000 0.000000
XMajorLine  10: 1098901.098901 8.970000 0.130000
YmajorLine  10: 1102535.832415 8.980000 0.090000
XMajorLine 100: 200400.801603 4.940000 0.050000
YmajorLine 100: 199600.798403 4.950000 0.060000
bres1
LineTest Skipped
Line   1: 5988023.952096 1.660000 0.010000
XMajorLine  10: 990099.009901 1.010000 0.000000
YmajorLine  10: 976562.500000 10.120000 0.120000
XMajorLine 100: 128700.128700 7.710000 0.060000
YmajorLine 100: 128700.128700 7.720000 0.050000
bres2
Line   1: 6944444.444444 1.440000 0.000000
XMajorLine  10: 2314814.814815 4.310000 0.010000
YmajorLine  10: 2083333.333333 4.770000 0.030000
XMajorLine 100: 374531.835206 2.650000 0.020000
YmajorLine 100: 309597.523220 3.220000 0.010000
bres3
Line   1: 6944444.444444 1.430000 0.010000
XMajorLine  10: 1445086.705202 6.860000 0.060000
YmajorLine  10: 1600000.000000 6.210000 0.040000
XMajorLine 100: 188323.917137 5.280000 0.030000
YmajorLine 100: 228310.502283 4.340000 0.040000
fixedpoint1
Line   1: 5102040.816327 1.900000 0.060000
XMajorLine  10: 2105263.157895 4.720000 0.030000
YmajorLine  10: 2222222.222222 4.480000 0.020000
XMajorLine 100: 392156.862745 2.530000 0.020000
YmajorLine 100: 492610.837438 2.020000 0.010000
fixedpoint2
Line   1: 6666666.666667 1.480000 0.020000
XMajorLine  10: 1464128.843338 6.740000 0.090000
YmajorLine  10: 1398601.398601 7.070000 0.080000
XMajorLine 100: 409836.065574 2.430000 0.010000
YmajorLine 100: 458715.596330 2.170000 0.010000
~/prgs/lines>
/*
 * This is a GGI speed- and consistency-test application.
 * Policy : Speed-Tests send their output to stdout,
 *          Consistency-Tests report to stderr.
 */

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include <sys/times.h>

#ifdef _POSIX_PRIORITY_SCHEDULING
#  include <sched.h>
#else
#  define sched_yield() ;
#endif

unsigned char Buffer[128][128];
unsigned int COL;
#define ggiSetGCForeground(vis,c) COL=c
#define ggiDrawPixel(vis,x,y) Buffer[y][x]=COL
#define GGIdrawpixel(vis,x,y) Buffer[y][x]=COL
#define ggiPutPixel(vis,x,y,c) Buffer[y][x]=c
#define ggiGetPixel(vis,x,y,p) *p=Buffer[y][x]
#define ggiFillscreen(vis) memset(Buffer,COL,128*128)
#define ggiDrawHLine(vis,x,y,l) memset(&Buffer[y][x],COL,l)
#define ggiDrawVLine(vis,x,y,l) {int i;for(i=0;i<l;i++) Buffer[y+i][x]=COL;} 
int (*ggiDrawLine)(int *vis,int x1,int y1,int x2,int y2);
#define VIS_FB_LINEAR(vis) Buffer
#define VIS_FB_WIDTH(vis) 128
#define VIS_GC_FGCOLOR(vis) COL
#define LIBGGI_FB_LINEAR(vis) Buffer
#define LIBGGI_FB_WIDTH(vis) 128
#define LIBGGI_GC_FGCOLOR(vis) COL



struct {
	int *vis;
	int vx,vy;
	} mode;

typedef unsigned int ggi_uint;
typedef int ggi_visual;
typedef unsigned char uchar;
#define EOK 0

/**********************************************************************/

/* This is a general clipping linedrawer using a sliced run-length
   bresenham algorithm. It is modified to calculate the first and last
   run-lengths when they are clipped to get pixel-perfect rasterization.

   If you wan't to use this you have to define FBTYPE to the right frame-
   buffer type and then include this file.
   */

typedef unsigned char FBTYPE;

int sliced(ggi_visual *vis,int orig_x1,int orig_y1,int orig_x2,int orig_y2)
{
  int orig_dx,orig_dy,sx,sy;
  int dx,dy;
  int i;
  int w;
  int x1,y1,x2,y2;
  int clip_first=0,clip_last=0;
  FBTYPE *fb,color;

  color = LIBGGI_GC_FGCOLOR(vis);
  
  x1 = orig_x1;
  y1 = orig_y1;
  x2 = orig_x2;
  y2 = orig_y2;

  /* clip x1,y1 and x2,y2. Set clip_first and clip_last if clipped */
  /*  if (!clip2d(vis, &x1,&y1,&x2,&y2,&clip_first,&clip_last))
      return 0; */ /* Clipped */
  
  dy = y2 - y1;
  orig_dy = orig_y2 - orig_y1;
  sy=1;
  if (orig_dy<0) {
    orig_dy = -orig_dy;
    dy = -dy;
    sy = -1;
  }

  dx = x2-x1;
  orig_dx = orig_x2 - orig_x1;
  sx=1;
  if (orig_dx<0) {
    sx=-1;
    orig_dx = -orig_dx;
    dx = -dx;
  }

  w = LIBGGI_FB_WIDTH(vis);
  
  fb = ((FBTYPE *)LIBGGI_FB_LINEAR(vis)) + y1*w+x1;
  
  if (dx==0) {
    if (sy<0)
      w=-w;
   
    for (i=dy;i>=0; i--) {
      *fb = color;
      fb += w;
    }
    return 0;
  }

  if (dy==0) {
    for (i=dx;i>=0; i--) {
      *fb = color;
      fb += sx;
    }
    return 0;
  }

  if (orig_dx==orig_dy) {
    if (sy<0)
      w=-w;
    w += sx;
    for (i=dx;i>=0; i--) {
      *fb = color;
      fb += w;
    }
    return 0;
  }

  if (orig_dx >= orig_dy) { /* x major */
    int runlen,adjup,adjdown,e,len;
    int firstlen,lastlen;

    runlen = orig_dx/orig_dy;
    adjup = orig_dx%orig_dy;
    lastlen = firstlen = (runlen>>1) + 1;
    if (clip_first) { /* clipped, Adjust firstlen */
      int clip_dx = abs(x1 - orig_x1);
      int clip_dy = abs(y1 - orig_y1);
      int d = (2*clip_dy+1)*orig_dx; 
      firstlen = d/(2*orig_dy) - clip_dx + 1;
      e = d%(2*orig_dy);
      if ((e==0) && (sy>0)) { /* Special case, arbitrary choise. Select lower pixel.(?) */
	firstlen--;
	e += 2*orig_dy;
      }
      e -= (orig_dy*2);
    } else { /* Not clipped, calculate start error term */
      e = adjup - (orig_dy<<1); /* initial errorterm == half a step */
      if ((runlen&1) != 0) {
	e += orig_dy;
      }
    }
    if (clip_last) { /* Last endpoint clipped */
      int clip_dx = abs(x2 - orig_x2);
      int clip_dy = abs(y2 - orig_y2);
      int d = (1+2*clip_dy)*orig_dx; 
      lastlen = d/(2*orig_dy) - clip_dx + 1;
      if ((sy<0)  && ((d%(2*orig_dy))==0) ) /* special arbitrary case */
	lastlen--; 
    }
    adjup <<= 1;
    adjdown = orig_dy<<1;

    if (sy>0) {  /* line goes down */
      if ((adjup==0) && ((runlen&1)==0) && (!clip_first)) {
	firstlen--;
      }
      if (sx>0) { /* line goes right */
	for (;firstlen>0; firstlen--) {
	  *fb = color;
	  fb++;
	}
	fb += w;
	for (i=dy-1; i>0; i--) {
	  len = runlen;
	  e += adjup;
	  if (e>0) {
	    len++;
	    e -= adjdown;
	  }
	  for (;len>0; len--) {
	    *fb = color;
	    fb++;
	  }
	  fb += w;
	}
	for (;lastlen>0; lastlen--) {
	  *fb = color;
	  fb++;
	}
	return 0;
      } else { /* line goes left */
	for (;firstlen>0; firstlen--) {
	  *fb = color;
	  fb--;
	}
	fb += w;
	for (i=dy-1; i>0; i--) {
	  len = runlen;
	  e += adjup;
	  if (e>0) {
	    len++;
	    e -= adjdown;
	  }
	  for (;len>0; len--) {
	    *fb = color;
	    fb--;
	  }
	  fb += w;
	} 
	for (;lastlen>0; lastlen--) {
	  *fb = color;
	  fb--;
	}
	return 0;
      }
    } else { /* line goes up */
      if ((adjup==0) && ((runlen&1)==0) && (!clip_last)) { 
	lastlen--;
      }
      if (sx>0) { /* line goes right */
	for (;firstlen>0; firstlen--) {
	  *fb = color;
	  fb++;
	}
	fb -= w;
	for (i=dy-1; i>0; i--) {
	  len = runlen;
	  e += adjup;
	  if (e>=0) {
	    len++;
	    e -= adjdown;
	  }
	  for (;len>0; len--) {
	    *fb = color;
	    fb++;
	  }
	  fb -= w;
	}
	for (;lastlen>0; lastlen--) {
	  *fb = color;
	  fb++;
	}
	return 0;
      } else { /* line goes left */
	for (;firstlen>0; firstlen--) {
	  *fb = color;
	  fb--;
	}
	fb -= w;
	for (i=dy-1; i>0; i--) {
	  len = runlen;
	  e += adjup;
	  if (e>=0) {
	    len++;
	    e -= adjdown;
	  }
	  for (;len>0; len--) {
	    *fb = color;
	    fb--;
	  }
	  fb -= w;
	} 
	for (;lastlen>0; lastlen--) {
	  *fb = color;
	  fb--;
	}
	return 0;
      }
    }
  } else { /* y major */
    int runlen,adjup,adjdown,e,len;
    int firstlen,lastlen;

    runlen = orig_dy/orig_dx;
    adjup = orig_dy%orig_dx;
    
    lastlen = firstlen = (runlen>>1) + 1;
    if (clip_first) { /* clipped, Adjust firstlen */
      int clip_dx = abs(x1 - orig_x1);
      int clip_dy = abs(y1 - orig_y1);
      int d = (2*clip_dx+1)*orig_dy;
      firstlen = d/(2*orig_dx) - clip_dy + 1;
      e = d%(2*orig_dx);
      if ((e==0) && (sx>0)) { /* Special case, arbitrary choise. Select lower pixel.(?) */
	firstlen--;
	e += 2*orig_dx;
      }
      e -= (orig_dx*2);
    } else { /* Not clipped, calculate start error term */
      e = adjup - (orig_dx<<1); /* initial errorterm == half a step */
      if ((runlen&1) != 0) {
	e += orig_dx;
      }
    }
    if (clip_last) { /* Last endpoint clipped */
      int clip_dx = abs(x2 - orig_x2);
      int clip_dy = abs(y2 - orig_y2);
      int d = (1+2*clip_dx)*orig_dy; 
      lastlen = d/(2*orig_dx) - clip_dy + 1;
      if ((sx<0)  && ((d%(2*orig_dx))==0) ) /* special arbitrary case */
	lastlen--;
    }
    adjup <<= 1;
    adjdown = orig_dx<<1;
    if (sy>0) { /* Line goes DOWN */
      if (sx>0) { /* line goes RIGHT */
	if ((adjup==0) && ((runlen&1)==0) && (!clip_first)) {
	  firstlen--;
	}
	for (;firstlen>0; firstlen--) {
	  *fb = color;
	  fb += w;
	}
	fb++;
	for (i=dx-1; i>0; i--) {
	  len = runlen;
	  e += adjup;
	  if (e>0) {
	    len++;
	    e -= adjdown;
	  }
	  for (;len>0; len--) {
	    *fb = color;
	    fb += w;
	  }
	  fb ++;
	}
	for (;lastlen>0; lastlen--) {
	  *fb = color;
	  fb += w;
	}
	return 0;
      } else { /* line goes LEFT */
	if ((adjup==0) && ((runlen&1)==0) && (!clip_last)) {
	  lastlen--;
	}
	for (;firstlen>0; firstlen--) {
	  *fb = color;
	  fb += w;
	}
	fb--;
	for (i=dx-1; i>0; i--) {
	  len = runlen;
	  e += adjup;
	  if (e>=0) {
	    len++;
	    e -= adjdown;
	  }
	  for (;len>0; len--) {
	    *fb = color;
	    fb += w;
	  }
	  fb --;
	}
	for (;lastlen>0; lastlen--) {
	  *fb = color;
	  fb += w;
	}
	return 0;
      }
    } else { /* Line goes UP */
      if (sx>0) { /* line goes RIGHT */
	if ((adjup==0) && ((runlen&1)==0) && (!clip_first)) {
	  firstlen--;
	}
	for (;firstlen>0; firstlen--) {
	  *fb = color;
	  fb -= w;
	}
	fb++;
	for (i=dx-1; i>0; i--) {
	  len = runlen;
	  e += adjup;
	  if (e>0) {
	    len++;
	    e -= adjdown;
	  }
	  for (;len>0; len--) {
	    *fb = color;
	    fb -= w;
	  }
	  fb ++;
	}
	for (;lastlen>0; lastlen--) {
	  *fb = color;
	  fb -= w;
	}
	return 0;
      } else { /* line goes LEFT */
	if ((adjup==0) && ((runlen&1)==0) && (!clip_last)) {
	  lastlen--;
	}
	for (;firstlen>0; firstlen--) {
	  *fb = color;
	  fb -= w;
	}
	fb--;
	for (i=dx-1; i>0; i--) {
	  len = runlen;
	  e += adjup;
	  if (e>=0) {
	    len++;
	    e -= adjdown;
	  }
	  for (;len>0; len--) {
	    *fb = color;
	    fb -= w;
	  }
	  fb --;
	}
	for (;lastlen>0; lastlen--) {
	  *fb = color;
	  fb -= w;
	}
	return 0;
      }
    }
  }
}

/***********************
 * Drawline, Bresenham *
 ***********************/

int bres1(ggi_visual *vis,int x1,int y1,int x2,int y2)
{ 
	int dx,dy,dz,m11,m12,m21,m22,x,y,p,q,c,e,k1,k2;

	dx=x2-x1;dy=y2-y1;dz=abs(dx)-abs(dy);
	if (dx<0) { m21=-1; } else { m21=+1; }
	if (dy<0) { m22=-1; } else { m22=+1; }
	if (dz<0) {
		p=abs(dx);q=abs(dy);m11=0;m12=m22;
	} else {
		p=abs(dy);q=abs(dx);m11=m21;m12=0;
	}
	x=x1;y=y1;c=q;k1=2*p;e=2*p-q;k2=2*p-2*q;
	if ((dz>0)&&(dy>0)) e--;
	if ((dz<0)&&(dx<0)) e--;
	GGIdrawpixel(vis,x,y);c--;
	while (c>=0) {
		if (e<0) {
			x+=m11;y+=m12;e+=k1;
		} else {
			x+=m21;y+=m22;e+=k2;
		}
		GGIdrawpixel(vis,x,y);c--;
	}
	return EOK;
}

int bres2(ggi_visual *vis,int x1,int y1,int x2,int y2)
{ 
	int dx,dy,sx,sy,st,bla,mask,c; unsigned char color,*adr;
	
	sx=1;dx=x2-x1;if (dx<0) {sx=-1;dx=-dx;}
	sy=1;dy=y2-y1;if (dy<0) {sy=-1;dy=-dy;}
	st=(dx-dy);bla=(dx>dy);
	if (bla) st-=dy;else st+=dx;
	if (bla&&sy>0) st--;
	if (!bla&&sx<0) st--;
	dx*=2;dy*=2;
	adr=((unsigned char *)VIS_FB_LINEAR(vis))+y1*VIS_FB_WIDTH(vis)+x1;
	sy*=VIS_FB_WIDTH(vis);
	color=VIS_GC_FGCOLOR(vis);
	*adr=color;
	if (bla) {
		c=abs(x1-x2);
		while(c--) {
			mask=(st>>31);adr+=(sy&mask);st+=dx&mask;
			adr+=sx;st-=dy;
			*adr=color;
		}
	} else {
		c=abs(y1-y2);
		while(c--) {
			mask=~(st>>31);adr+=(sx&mask);st-=dy&mask;
			adr+=sy;st+=dx;
			*adr=color;
		}
	}
	return EOK;
}

int bres3(ggi_visual *vis,int x1,int y1,int x2,int y2)
{ 
	int dx,dy,sx,sy,st,bla,mask,c; unsigned char color,*adr;
	
	sx=1;dx=x2-x1;if (dx<0) {sx=-1;dx=-dx;}
	sy=1;dy=y2-y1;if (dy<0) {sy=-1;dy=-dy;}
	st=(dx-dy);bla=(dx>dy);
	if (bla) st-=dy;else st+=dx;
	if (bla&&sy>0) st--;
	if (!bla&&sx<0) st--;
	dx*=2;dy*=2;
	adr=((unsigned char *)VIS_FB_LINEAR(vis))+y1*VIS_FB_WIDTH(vis)+x1;
	sy*=VIS_FB_WIDTH(vis);
	color=VIS_GC_FGCOLOR(vis);
	*adr=color;
	if (bla) {
		c=abs(x1-x2);
		while(c--) {
			if (st<0) { adr+=sy;st+=dx; }
			adr+=sx;st-=dy;
			*adr=color;
		}
	} else {
		c=abs(y1-y2);
		while(c--) {
			if (st>=0) { adr+=sx;st-=dy; }
			adr+=sy;st+=dx;
			*adr=color;
		}
	}
	return EOK;
}

int fixedpoint1(ggi_visual *vis,int x1,int y1,int x2,int y2)
{
	int dx,dy,sy,sx,x,y,slope;
	dx=abs(x2-x1);
	dy=abs(y2-y1);
	if (dy==0) {
		if (x1>x2) {x=x1;x1=x2;x2=x;}
		ggiDrawHLine(vis,x1,y1,dx+1);
	} else if (dx==0) {
		if (y1>y2) {y=y1;y1=y2;y2=y;}
		ggiDrawVLine(vis,x1,y1,dy+1);
	} else if (dy>dx) {
	        if (y1>y2) {sy=-1;} else {sy=1;};
		dx=x2-x1;
		slope=(dx<<20)/dy;
		x=(x1<<20)+(1<<19)+dy;
		for(y=y1;y!=y2+sy;y+=sy) {
			ggiDrawPixel(vis,x>>20,y);
			x+=slope;
		}
	} else {
		if (x1>x2) {sx=-1;} else {sx=1;};
		dy=y2-y1;
		slope=(dy<<20)/dx;
		y=(y1<<20)+(1<<19)+dx;
		for(x=x1;x!=x2+sx;x+=sx) {
			ggiDrawPixel(vis,x,y>>20);
			y+=slope;
		}

	}
	return 0;
}

int fixedpoint2(ggi_visual *vis,int x1,int y1,int x2,int y2)
{
	int sx,sy;
	uint dx,dy,slope,frac,temp,step;
	FBTYPE *adr,color;
	dx=abs(x2-x1);
	dy=abs(y2-y1);
	if (dy==0) {
		if (x1>x2) x1=x2;
		adr=((FBTYPE *)LIBGGI_FB_LINEAR(vis))+
		  y1*LIBGGI_FB_WIDTH(vis)+x1;
		memset(adr,VIS_GC_FGCOLOR(vis),dx+1);
	} else if (dy>=dx) {
		if (dy==dx) {slope=-1;} else
		slope=(((unsigned long long)dx)<<32)/dy;
		step=VIS_FB_WIDTH(vis);
                if (y1>y2) {step=-step;}
                if (x1>x2) {
                  step--;
                  slope=-slope;
                }
                adr=((FBTYPE *)VIS_FB_LINEAR(vis))+y1*VIS_FB_WIDTH(vis)+x1;
                frac=(1UL<<31)+dy;
                color=VIS_GC_FGCOLOR(vis);
		for (dy++;dy--;)
		  {
		    *adr=color;
		    temp=frac;
		    frac+=slope;
		    adr+=step;
		    adr+=temp>frac;
		  }
	} else {
	
		sx=1|((x2-x1)>>31);
		slope=(((unsigned long long) dy)<<32)/dx;
		frac=(1UL<<31)+dx;
		sy=VIS_FB_WIDTH(vis);
		if (y1>y2) { sy=-sy; frac=-frac; }
		adr=((FBTYPE *)LIBGGI_FB_LINEAR(vis))+
		  y1*LIBGGI_FB_WIDTH(vis)+x1;
		color=LIBGGI_GC_FGCOLOR(vis);
		for(dx++;dx--;)
		  {
		    *adr=color;
		    adr+=sx;
		    temp=frac;
		    frac+=slope;
		    adr+=sy&(-(frac<temp));
		  }

	}
	return 0;
}

#if 0
int fixedpoint_asm(ggi_visual *vis,int x1,int y1,int x2,int y2)
{
        uint slope,step,frac,temp;
        uchar *adr,color;
        int dx,dy,sy,sx,x,y,res;
        dx=abs(x2-x1);
        dy=abs(y2-y1);
        if (dy==0) {
		if (x1>x2) x1=x2;
                adr=((uchar *)VIS_FB_LINEAR(vis))+y1*VIS_FB_WIDTH(vis)+x1;
                memset(adr,VIS_GC_FGCOLOR(vis),dx+1); 
        } else if (dy>=dx) {
		if (dy==dx) {slope=-1;} else
                asm("divl %3":"=eax" (slope) : "0"(0), "edx" (dx) ,"g" (dy));
		step=VIS_FB_WIDTH(vis);
                if (y1>y2) {step=-step;}
                if (x1>x2) {
                  step--;
                  slope=-slope;
                }
                adr=((uchar *)VIS_FB_LINEAR(vis))+y1*VIS_FB_WIDTH(vis)+x1;
                frac=(1UL<<31)+dy;
                color=VIS_GC_FGCOLOR(vis);
                asm volatile ("l1: movb %4,(%1)\n\t"
			      "addl %2,%0\n\t"
			      "adcl %3,%1\n\t"
			      "decl  %5\n\t"
			      "jns l1\n\t"
			      : : "r" (frac), "r" (adr), "r" (slope), 
			      "g" (step), "r" (color),"r" (dy));
        } else {
		if (x1>x2) { sx=-1;} else {sx=1;}
                asm("divl %3":"=eax" (slope) : "0"(0), "edx" (dy) ,"g" (dx));
		sy=VIS_FB_WIDTH(vis);
		frac=(1UL<<31)+dx;
                if (y1>y2) { sy=-sy; frac=-frac; } 
		adr=((uchar *)VIS_FB_LINEAR(vis))+y1*VIS_FB_WIDTH(vis)+x1;
		color=VIS_GC_FGCOLOR(vis);
		for(dx++;--dx>=0;) {
		        *adr=color;
			adr+=sx;
			frac=(temp=frac)+slope;
			if (temp>frac) adr+=sy;
		}
	}
	return 0;
}
#endif

/**********************************************************************/

struct tms timer;
double u_time,s_time;

void time_start(void)
{ times(&timer); }

void time_offset(void)
{ struct tms end; 
  times(&end);
  u_time=-(end.tms_utime-timer.tms_utime)/(double)CLK_TCK;
  s_time=-(end.tms_stime-timer.tms_stime)/(double)CLK_TCK;
  time_start();
}

void time_stop(void)
{ struct tms end; 
  times(&end);
  u_time+=(end.tms_utime-timer.tms_utime)/(double)CLK_TCK;
  s_time+=(end.tms_stime-timer.tms_stime)/(double)CLK_TCK;
}

#define white_pixel 1


int nothing(ggi_visual *vis,int x1,int y1,int x2,int y2) {return 0;}

int getnumpixels(int x1,int y1,int x2,int y2)
{
	int x,y,c; 
	ggi_uint i;
	c=0;
	for(y=y1;y<=y2;y++)
		for(x=x1;x<=x2;x++)
		{
	  		ggiGetPixel(mode.vis,x,y,&i);
	  		if ( i != 0 ) c++;
		}
	return c;
}

void BasicConsistency(void)
{
	int c,x,y;
	ggi_uint i;
	
	/* Get/Put/DrawPixel consistency test */
	ggiSetGCForeground(mode.vis,0);
	ggiFillscreen(mode.vis);

	/* The screen should now be all zero. */
	c=0;
	for(y=0;y<mode.vy;y++)
		for(x=0;x<mode.vx;x++)
		{
	  		ggiGetPixel(mode.vis,x,y,&i);
	  		if ( i != 0 ) 
	  		{
	  			printf("Warning: Screen not blank at %d,%d (%x)\n",x,y,i);
	  			c++;
	  			if (c>16)
	  			{
		  			fprintf(stderr,"Error: Screen not blank or GetPixel not working. Disabled consitency checks.\n");
					y=mode.vy;
		  			break;
	  			}
	  		}
		}
}

void ColorWrap(void)
{
	ggi_uint i,c;
	/* Now we check when we have a color wraparound. */
	if (1)
		for(i=0;i!=0xffffffff;i++)
		{
			ggiPutPixel(mode.vis,0,0,i);
			ggiGetPixel(mode.vis,0,0,&c);
			if ( i != c ) 
			{	fprintf(stderr,"Info:Color wraps at %d\n",i);
				break;
			}
		}
}

void Hline(void)
{
	int x,y,c;

	ggiSetGCForeground(mode.vis,0);
	ggiFillscreen(mode.vis);
	if (1)
		for(x=0;x<mode.vx;x++)
		{
			for(y=0;y<=mode.vx-x;y++)
			{
				ggiSetGCForeground(mode.vis,white_pixel);
				ggiDrawHLine(mode.vis,x,0,y);
				ggiSetGCForeground(mode.vis,0);
				/* for speed reasons, we hope for no stray pixels far away ... */
				if ((c=getnumpixels(0,0,mode.vx-1,1))!=y || getnumpixels(x,0,x+y-1,0)!=y )
				{
					ggiFillscreen(mode.vis);
					fprintf(stderr,"Error:Hline(%d,0,%d); consistency failed (%d pixels measured).\n",x,y,c);
				} else
					ggiDrawHLine(mode.vis,x,0,y);
			}
		}
}

void Vline(void)
{
	int x,y,c;

	if (1)
		for(y=0;y<mode.vy;y++)
		{
			ggiSetGCForeground(mode.vis,0);
			ggiFillscreen(mode.vis);
			ggiSetGCForeground(mode.vis,white_pixel);
			for(x=0;x<=mode.vy-y;x++)
			{
				ggiDrawVLine(mode.vis,0,y,x);
				/* for speed reasons, we hope for no stray pixels far away ... */
				if ((c=getnumpixels(0,0,1,mode.vy-1))!=x || (c=getnumpixels(0,y,0,x+y-1))!=x )
				{
					fprintf(stderr,"Error:Vline(0,%d,%d); consistency failed (%d pixels measured).\n",y,x,c);
				}
			}
		}
}

void CheckLine(ggi_visual *vis,int x1,int y1,int x2,int y2)
{
	int xx,max,cx,cy;
	ggi_uint c;
	ggiSetGCForeground(vis,white_pixel);
	ggiDrawLine(vis,x1,y1,x2,y2);
	ggiSetGCForeground(vis,0);
	max=abs(x2-x1);if (abs(y2-y1)>max) max=abs(y2-y1);
	if (max==0) return;
	for(xx=0;xx<=max;xx++)
	{
		cx=(x1*xx+x2*(max-xx)+max/2)/max;
		cy=(y1*xx+y2*(max-xx)+max/2)/max;
		ggiGetPixel (vis,cx,cy,&c);
	  	if (c==0) printf("Line: Unset pixel %d,%d in line(%d,%d,%d,%d).\n",
	  			  cx,cy,x1,y1,x2,y2);
		ggiDrawPixel(vis,cx,cy);
	}
	if ((c=getnumpixels(0,0,120,120))!=0)
	{	printf("Line: %d surplus pixels in line(%d,%d,%d,%d).\n",
  			  c,x1,y1,x2,y2);
		ggiFillscreen(vis);
	}
}

void LineTest(void)
{	
	int x;
	
	ggiSetGCForeground(mode.vis,0);
	ggiFillscreen(mode.vis);
	
	for(x=10;x<110;x++)
		CheckLine(mode.vis, 10, 10,x,110);
	for(x=10;x<110;x++)
		CheckLine(mode.vis, 10, 10,110,x);
	for(x=10;x<110;x++)
		CheckLine(mode.vis,110, 10,x,110);
	for(x=10;x<110;x++)
		CheckLine(mode.vis,110, 10, 10,x);
	for(x=10;x<110;x++)
		CheckLine(mode.vis, 10,110,x, 10);
	for(x=10;x<110;x++)
		CheckLine(mode.vis, 10,110,110,x);
	for(x=10;x<110;x++)
		CheckLine(mode.vis,110,110,x, 10);
	for(x=10;x<110;x++)
		CheckLine(mode.vis,110,110, 10,x);
}

void LineSpeed(void)
{
	int x,c,mxcnt;

	for(mxcnt=1000;mxcnt<1000000000;mxcnt*=10)
	{
		time_start();
		for(c=mxcnt;c>0;c--)
			nothing(mode.vis,10,10,10,10);
		time_offset();
		for(c=mxcnt;c>0;c--)
			ggiDrawLine(mode.vis,10,10,10,10);
		time_stop();
		if ( u_time+s_time > 1.0 ) break;
	}
	printf("Line   1: %f %f %f\n",mxcnt/(u_time+s_time),u_time,s_time);
	for(mxcnt=1;mxcnt<1000000000;mxcnt*=10)
	{
		time_start();
		for(c=mxcnt/10;c>0;c--)
			for(x=10;x<20;x++)
				nothing(mode.vis,10,10,19,x);
		time_offset();
		for(c=mxcnt/10;c>0;c--)
			for(x=10;x<20;x++)
				ggiDrawLine(mode.vis,10,10,19,x);
		time_stop();
		if ( u_time+s_time > 1.0 ) break;
	}
	printf("XMajorLine  10: %f %f %f\n",mxcnt/(u_time+s_time),u_time,s_time);
	for(mxcnt=1;mxcnt<1000000000;mxcnt*=10)
	{
		time_start();
		for(c=mxcnt/10;c>0;c--)
			for(x=10;x<20;x++)
				nothing(mode.vis,10,10,x,19);
		time_offset();
		for(c=mxcnt/10;c>0;c--)
			for(x=10;x<20;x++)
				ggiDrawLine(mode.vis,10,10,x,19);
		time_stop();
		if ( u_time+s_time > 1.0 ) break;
	}
	printf("YmajorLine  10: %f %f %f\n",mxcnt/(u_time+s_time),u_time,s_time);
	for(mxcnt=1;mxcnt<1000000000;mxcnt*=10)
	{
		time_start();
		for(c=mxcnt/100;c>0;c--)
			for(x=10;x<110;x++)
				nothing(mode.vis,10,10,109,x);
		time_offset();
		for(c=mxcnt/100;c>0;c--)
			for(x=10;x<110;x++)
				ggiDrawLine(mode.vis,10,10,109,x);
		time_stop();
		if ( u_time+s_time > 1.0 ) break;
	}
	printf("XMajorLine 100: %f %f %f\n",mxcnt/(u_time+s_time),u_time,s_time);
	for(mxcnt=1;mxcnt<1000000000;mxcnt*=10)
	{
		time_start();
		for(c=mxcnt/100;c>0;c--)
			for(x=10;x<110;x++)
				nothing(mode.vis,10,10,x,109);
		time_offset();
		for(c=mxcnt/100;c>0;c--)
			for(x=10;x<110;x++)
				ggiDrawLine(mode.vis,10,10,x,109);
		time_stop();
		if ( u_time+s_time > 1.0 ) break;
	}
	printf("YmajorLine 100: %f %f %f\n",mxcnt/(u_time+s_time),u_time,s_time);
}

int main(int argc,char **argv)
{
	srandom(time(NULL));

	printf("BasicConsistency\n");
	BasicConsistency();
	printf("ColorWrap\n");
	ColorWrap();
	printf("HLine\n");
	Hline();
	printf("VLine\n");
	Vline();
	printf("sliced\n");
	ggiDrawLine=sliced;
	LineTest();
	LineSpeed();
	printf("bres1\n");
	ggiDrawLine=bres1;
	printf("LineTest Skipped\n");
	/* LineTest(); */
	LineSpeed();
	printf("bres2\n");
	ggiDrawLine=bres2;
	LineTest();
	LineSpeed();
	printf("bres3\n");
	ggiDrawLine=bres3;
	LineTest();
	LineSpeed();
	printf("fixedpoint1\n");
	ggiDrawLine=fixedpoint1;
	LineTest();
	LineSpeed(); 
	printf("fixedpoint2\n");
	ggiDrawLine=fixedpoint2;
	LineTest();
	LineSpeed();
#if 0
	printf("fixedpoint_asm\n");
	ggiDrawLine=fixedpoint_asm;
	LineTest();
	LineSpeed();
#endif
	return 0;
}


Index: [thread] [date] [subject] [author]