home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Creative Computers
/
CreativeComputers.iso
/
shareware
/
text
/
dvi_3.62
/
source
/
dvisrc.lha
/
dvidraw.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-10-26
|
11KB
|
572 lines
/*
** Datei: DVIDRAW.C
** Autor: Ingo Eichenseher
*/
#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
#include <math.h>
#include <string.h>
#include "dvi.h"
#include "dvisplin.h"
#include "dvidraw.h"
#include "dviframe.h"
gstate_t gstate;
static int pic_bytewidth, pic_height;
static int xmin=0, ymin=0, xmax=639, ymax=399;
void setframe(int width, int height)
{
pic_bytewidth = width;
pic_height = height;
xmin = ymin = 0;
xmax = width*8 - 1;
ymax = height - 1;
}
int iabs(int x)
{
return x>=0 ? x : -x;
}
int isgn(int x)
{
return x==0 ? 0 : x<0 ? -1 : 1;
}
static real dmax(real x, real y)
{
return x>y ? x : y;
}
static long address(int x, int y)
{
long addr;
addr = ((long)y*(long)pic_bytewidth);
if (x>=0) addr += x/8;
else addr -= (7-x)/8;
return addr;
}
static unsigned char bitpos(int x)
{
if (x>=0) return( (unsigned char)( 128>>(x%8) ) );
return( (unsigned char)( 1<<((7-x)%8) ) );
}
#if 0
static void plot(int x1, int y1)
{
register unsigned char huge *addr, bit;
if (x1<xmin || x1>xmax || y1<ymin || y1>ymax) return;
if (clip_active)
{
SW_Y(y1); SW_X(x1);
if (SW)
{
addr = address(x1,y1);
bit = bitpos(x1);
frame_or(addr,bit);
}
}
else
{
addr = address(x1,y1);
bit = bitpos(x1);
frame_or(addr,bit);
}
}
#endif
static void vline(int x1, int y1, int y2)
{
register unsigned long addr;
register unsigned char bit;
if (y1>y2) { int h=y1; y1=y2; y2=h; }
if (x1<xmin || x1>xmax) return;
if (y1<ymin) y1=ymin;
if (y2>ymax) y2=ymax;
addr = address(x1,y1);
bit = bitpos(x1);
if (clip_active)
{
while(y1<=y2)
{
SW_Y(y1); SW_X(x1);
if (SW) frame_or(addr,bit);
addr += pic_bytewidth;
y1++;
}
}
else
{
while(y1<=y2)
{
frame_or(addr,bit);
addr += pic_bytewidth;
y1++;
}
}
}
void hline(int x1, int y1, int x2, unsigned char pattern)
{
register unsigned char bit;
register long addr;
if (y1<ymin || y1>ymax) return;
if (x1>x2) { int h=x1; x1=x2; x2=h; }
if (x1<xmin) x1 = xmin;
if (x2>xmax) x2 = xmax;
if (x1>x2) return;
addr = address(x1,y1);
bit = bitpos(x1);
if (clip_active)
{
SW_Y(y1);
while( x1<=x2 )
{
SW_X(x1);
if (SW)
if (pattern&bit) frame_or(addr,bit);
else frame_and(addr,~bit);
if ( (bit >>= 1)==0)
{
addr++;
bit = 128;
}
x1 ++;
}
}
else
{
if (bit!=128)
{
while( x1<=x2 && bit )
{
if (pattern&bit) frame_or(addr,bit);
else frame_and(addr,~bit);
bit >>= 1;
x1 ++;
}
addr++;
bit = 128;
}
while(x1 <= x2-8)
{
frame_poke(addr,pattern);
addr ++;
x1 += 8;
}
while(x1<=x2)
{
if (pattern&bit) frame_or(addr,bit);
else frame_and(addr,~bit);
bit >>= 1;
x1 ++;
}
}
}
static void circle(int x0, int y0, int a, int b)
{
if (a && b)
{
int x = 0, y = b;
long aq = (long)a*(long)a, aq2=aq+aq, bq=(long)b*(long)b, bq2=bq+bq;
long d = bq-aq*(long)b+aq/4l, dx=0, dy=aq2*(long)b;
while(dx<dy)
{
hline(x0-x,y0+y,x0+x,0xff);
hline(x0-x,y0-y,x0+x,0xff);
if (d>0l) --y, dy -= aq2, d -= dy;
++x, dx += bq2, d += bq+dx;
}
d += (3l*(aq-bq)/2l-(dx+dy))/2l;
while(y>=0)
{
hline(x0-x,y0+y,x0+x,0xff);
hline(x0-x,y0-y,x0+x,0xff);
if (d<0l) ++x, dx += bq2, d+=dx;
--y, dy -= aq2, d += aq-dy;
}
}
else if (a) hline(x0-a,y0,x0+a,0xff);
else if (b) vline(x0,y0-b,y0+b);
}
void g_circle(const coord *p, real r)
{
int a, b;
a = iround(r);
b = iround(r*aspect_ratio);
circle(iround(p->x),iround(p->y),a,b);
}
static void thin_line(int x1, int y1, int x2, int y2)
{
register int dx, dy, e, i, offset, sy, sx;
register long addr;
register unsigned char bit;
real diag, ylen;
ylen = 1.0/aspect_ratio;
addr = address(x1,y1);
bit = bitpos(x1);
dx = iabs(x2-x1);
sx = isgn(x2-x1);
dy = iabs(y2-y1);
sy = isgn(y2-y1);
offset = sy*pic_bytewidth;
if (clip_active)
{
if (dx==0 && dy==0)
{
SW_Y(y1);
SW_X(x1);
if (SW) frame_or(addr,bit);
return;
}
if (dy>dx)
{
diag = sqrt(1.0+ylen*ylen)-1.0;
dx *= 2;
i = dy;
e = dx-dy;
dy *= 2;
while( i-- >= 0 )
{
SW_Y(y1);
SW_X(x1);
if (x1>=xmin && x1<=xmax && y1>=ymin && y1<=ymax)
if (SW & gstate.dash_color) frame_or(addr,bit);
if (gstate.dash_len>0)
{
if (gstate.dash_count <= 0)
{
if (++gstate.dash_index >= gstate.dash_len)
gstate.dash_index=0;
gstate.dash_count +=
gstate.dash_vector[gstate.dash_index];
gstate.dash_color = !gstate.dash_color;
}
}
if (e>=0)
{
if (dx)
{
if (sx>0)
{
if ((bit >>= 1)==0) { bit=128; addr++;}
x1++;
}
else
{
if ((bit <<= 1)==0) { bit=1; addr--;}
x1--;
}
}
e -= dy;
if (gstate.dash_len) gstate.dash_count -= diag;
}
if (gstate.dash_len) gstate.dash_count -= ylen;
addr += offset;
e += dx;
y1 += sy;
}
}
else
{
diag = sqrt(1.0+ylen*ylen)-1.0;
dy *= 2;
i = dx;
e = dy-dx;
dx *= 2;
while ( i-- >= 0)
{
SW_Y(y1);
SW_X(x1);
if (x1>=xmin && x1<=xmax && y1>=ymin && y1<=ymax)
if (SW && gstate.dash_color) frame_or(addr,bit);
if (gstate.dash_len>0)
{
if (gstate.dash_count <= 0)
{
if (++gstate.dash_index >= gstate.dash_len)
gstate.dash_index=0;
gstate.dash_count +=
gstate.dash_vector[gstate.dash_index];
gstate.dash_color = !gstate.dash_color;
}
}
if (e>=0)
{
addr += offset;
y1 += sy;
e -= dx;
if (gstate.dash_len) gstate.dash_count -= diag;
}
if (gstate.dash_len) gstate.dash_count -= 1.0;
if (dx)
{
if (sx>0)
{
if ((bit >>= 1)==0) { bit=128; addr++;}
x1++;
}
else
{
if ((bit <<= 1)==0) { bit=1; addr--;}
x1--;
}
}
e += dy;
}
}
}
else
{
if (dx==0 && dy==0)
{
frame_or(addr,bit);
return;
}
if (dy>dx)
{
diag = sqrt(1.0+ylen*ylen)-1.0;
dx *= 2;
i = dy;
e = dx-dy;
dy *= 2;
while( i-- >= 0 )
{
if (x1>=xmin && x1<=xmax && y1>=ymin && y1<=ymax)
if (gstate.dash_color) frame_or(addr,bit);
if (gstate.dash_len>0)
{
if (gstate.dash_count <= 0)
{
if (++gstate.dash_index >= gstate.dash_len)
gstate.dash_index=0;
gstate.dash_count +=
gstate.dash_vector[gstate.dash_index];
gstate.dash_color = !gstate.dash_color;
}
}
if (e>=0)
{
if (dx)
{
if (sx>0)
{
if ((bit >>= 1)==0) { bit=128; addr++;}
x1++;
}
else
{
if ((bit <<= 1)==0) { bit=1; addr--;}
x1--;
}
}
e -= dy;
if (gstate.dash_len) gstate.dash_count -= diag;
}
if (gstate.dash_len) gstate.dash_count -= ylen;
addr += offset;
e += dx;
y1 += sy;
}
}
else
{
diag = sqrt(1.0+ylen*ylen)-1.0;
dy *= 2;
i = dx;
e = dy-dx;
dx *= 2;
while ( i-- >= 0)
{
if (x1>=xmin && x1<=xmax && y1>=ymin && y1<=ymax)
if (gstate.dash_color) frame_or(addr,bit);
if (gstate.dash_len>0)
{
if (gstate.dash_count <= 0)
{
if (++gstate.dash_index >= gstate.dash_len)
gstate.dash_index=0;
gstate.dash_count +=
gstate.dash_vector[gstate.dash_index];
gstate.dash_color = !gstate.dash_color;
}
}
if (e>=0)
{
addr += offset;
y1 += sy;
e -= dx;
if (gstate.dash_len) gstate.dash_count -= diag;
}
if (gstate.dash_len) gstate.dash_count -= 1.0;
if (dx)
{
if (sx>0)
{
if ((bit >>= 1)==0) { bit=128; addr++;}
x1++;
}
else
{
if ((bit <<= 1)==0) { bit=1; addr--;}
x1--;
}
}
e += dy;
}
}
}
}
void g_line(const coord *p1, const coord *p2)
{
int savepos, savecolor;
real savecount;
static real last_x2, last_y2;
if (fill_mode)
{
clip_line(iround(p1->x),iround(p1->y),iround(p2->x),iround(p2->y));
return;
}
if (gstate.dash_len>0 &&
(fabs(p1->x-last_x2)>1.0 || fabs(p1->y-last_y2)>1.0) )
{
gstate.dash_index = 0;
gstate.dash_color = 1;
gstate.dash_count = gstate.dash_vector[gstate.dash_index];
}
savepos = gstate.dash_index;
savecolor = gstate.dash_color;
savecount = gstate.dash_count;
last_x2 = p2->x;
last_y2 = p2->y;
if (gstate.line_width<=1.0)
thin_line(iround(p1->x),iround(p1->y),iround(p2->x),iround(p2->y));
else
{
register int dx, dy, sx, sy, e, xe, ye, xa, ya, xb, yb;
real f, g, norm, delta_x, delta_y;
delta_x = p2->x - p1->x;
delta_y = p2->y - p1->y;
norm = sqrt(delta_x*delta_x+delta_y*delta_y
/aspect_ratio/aspect_ratio);
if (norm<0.01) return;
f = (gstate.line_width-1.0)/norm/2;
g = delta_x * aspect_ratio * f;
f = delta_y / aspect_ratio * f;
xa = iround(p1->x + f);
ya = iround(p1->y - g);
xb = iround(p2->x + f);
yb = iround(p2->y - g);
xe = iround((real)xa - 2*f);
ye = iround((real)ya + 2*g);
dx = iabs(xe-xa);
dy = iabs(ye-ya);
sx = isgn(xe-xa);
sy = isgn(ye-ya);
e = dx - dy;
thin_line(xa, ya, xb, yb);
while(xa!=xe || ya!=ye)
{
if (e<0) e += dx, ya += sy, yb += sy;
else e -= dy, xa += sx, xb += sx;
gstate.dash_index = savepos;
gstate.dash_color = savecolor;
gstate.dash_count = savecount;
thin_line(xa,ya,xb,yb);
}
}
}
void g_join(const coord *p)
{
if (gstate.dash_len==0 && !fill_mode && gstate.line_width>=3.0)
g_circle(p,floor((gstate.line_width-1)/2));
}
void g_bezier(const coord *p1,const coord *p2,const coord *p3,const coord *p4, int ttl)
{
real dx, dy, dm;
static int r, t=0;
if (ttl==0)
gr_error("Stack overflow in curve");
dx = p4->x-p1->x;
dy = p4->y-p1->y;
dm = dmax(fabs(dx),fabs(dy));
if (dx!=0 || dy!=0)
{
if ( fabs((p3->y-p1->y)*dx-(p3->x-p1->x)*dy) > dm ||
fabs((p2->y-p1->y)*dx-(p2->x-p1->x)*dy) > dm ) r=1;
else
{
g_line(p1,p4);
r = 0;
}
}
else
{
if ( (p2->x-p1->x)*(p2->x-p1->x)+(p2->y-p1->y)*(p2->y-p1->y) > 0.25 ||
(p3->x-p1->x)*(p3->x-p1->x)+(p3->y-p1->y)*(p3->y-p1->y) > 0.25 )
r = 1;
}
if (r)
{
coord p12, p23, p34, p123, p234, p1234;
p12.x = (p1->x+p2->x)/2; p12.y = (p1->y+p2->y)/2;
p23.x = (p2->x+p3->x)/2; p23.y = (p2->y+p3->y)/2;
p34.x = (p3->x+p4->x)/2; p34.y = (p3->y+p4->y)/2;
p123.x = (p12.x+p23.x)/2; p123.y = (p12.y+p23.y)/2;
p234.x = (p23.x+p34.x)/2; p234.y = (p23.y+p34.y)/2;
p1234.x = (p123.x+p234.x)/2; p1234.y = (p123.y+p234.y)/2;
g_bezier(p1,&p12,&p123,&p1234,ttl-1);
g_join(&p1234);
g_bezier(&p1234,&p234,&p34,p4,ttl-1);
}
t--;
}
void setdash(real *pat, int len)
{
if ((gstate.dash_len=len)<=0) gstate.dash_color = 1;
else
{
gstate.dash_color = 1;
gstate.dash_vector = pat;
gstate.dash_index = 0;
gstate.dash_count = gstate.dash_vector[gstate.dash_index];
}
}