/* * Typesetter/Terminal Emulator for the DMD 5620 * * Lou Salkind * New York University * Thu Apr 2 01:21:09 EST 1987 * * This program was inspired by the DMD proof program * and the Impress typesetting language. It is used by * the TeX DVIDMD driver. */ #include #include "layer.h" #include "font.h" #include "dmdcodes.h" #define MAXFAMILY 128 /* number of different fonts */ #define MAXFONTNAME 16 /* maximum font string */ #define PAGECHAR 8192 /* buffered characters to save */ #define MAXPAGE 127 #define SCROLLSIZE 20 /* scrolling border */ #define PAGEPIXELS 1010 /* XXX - length of page (should be an argument) */ #define NEWLINESIZE 16 #define CURSOR '\01' /* cursor char in font */ #define LINEBUFSIZE 100 #define MOVED 256 #ifdef PAGECHAR /* treatment of input characters */ #define CHAR_DISCARD 0 #define CHAR_STORE 1 #define CHAR_FETCH 2 int savechars; char savebuf[PAGECHAR]; char *saveptr; #endif #define RoundUp(a, b) (((a) + (b) - 1) & ~((b) - 1)) #ifdef MPX #undef cursinhibit #undef cursallow #define cursinhibit() {} #define cursallow() {} #endif static Texture16 prompt = { 0x0000, 0x0000, 0x0000, 0x322E, 0x4B69, 0x4369, 0x42A9, 0x42A9, 0x42A9, 0x4229, 0x4229, 0x4229, 0x322E, 0x0000, 0x0000, 0x0000 }; Point fudge = {5, 3}; /* DAG - offsets from corners */ int dotypeset; /* 1==typesetter, 0==terminal */ int cursvis; /* is cursor visible */ Point org; /* current origin */ Point typeorg; /* current typesetter origin */ Point curpt; /* current typesetter point relative to origin */ Point curpos; /* current ascii terminal position */ struct line { char buf[LINEBUFSIZE]; char *bufp; }; struct line line; struct glyph { Bitmap g_bitmap; short g_pxwidth; short g_xoffset; short g_yoffset; }; struct fontinfo { char f_name[MAXFONTNAME]; struct glyph f_glyph[128]; }; struct fontinfo *ftbl[MAXFAMILY]; struct fontinfo *curfont; Point inpoint(); main() { register int c; resetmode(DMD_TERM); #ifdef MPX P->state |= RESHAPED; /* set window parameters */ #else Drect = inset(Drect, 2); #endif /* MPX */ windowupdate(); for(;;) { c = inchar(); if (dotypeset) typeset(c); else { if(cursvis) term(CURSOR, 0); /* undraw cursor */ term(c, 1); while (own()&RCV) term(inchar(), 1); term(CURSOR, 0); /* draw at new spot */ cursvis = 1; } } } /* terminal emulation */ term(c, advance) register int c; { register struct line *linep = &line; register Point *pp = &curpos; register Fontchar *fp; Rectangle r; Point p; if (c & 0x80) { if (c == DMD_TYPESET) { resetmode(DMD_TYPESET); send(DMD_ACK); return; } c &= 0x7F; } switch(c) { default: fp = defont.info+c; if (fp->width+pp->x >= Drect.corner.x) newline(linep, pp); p = *pp; r.origin.x = fp->x; r.corner.x = (fp+1)->x; if (advance) { r.origin.y = 0; r.corner.y = defont.height; bitblt(defont.bits, r, &display, p, F_STORE); pp->x += fp->width; if (linep->bufp < linep->buf+LINEBUFSIZE) *linep->bufp++ = c; } else { r.origin.y = fp->top; r.corner.y = fp->bottom; p.y += fp->top; bitblt(defont.bits, r, &display, p, F_XOR); } break; case '\n': newline(linep, pp); break; case '\7': ringbell(); /* DAG -- should work? */ case 0: break; case '\r': pp->x=Drect.origin.x+fudge.x; /* DAG -- changed 5 to fudge.x */ linep->bufp = linep->buf; break; case '\013': /* ^K: reverse linefeed */ if(pp->y>Drect.origin.y+fudge.y+defont.height) pp->y-=NEWLINESIZE; break; case '\b': backspace(linep, pp); break; case '\014': formfeed(linep, pp); break; case '\t': pp->x=nexttab(pp->x); if(pp->x>=Drect.corner.x) newline(linep, pp); if(linep->bufpbuf+LINEBUFSIZE) *linep->bufp++=c; break; } } /*int eightspaces=8*dispatch[' '].c_wid;*/ int eightspaces=72; nexttab(x) { register int xx = x-Drect.origin.x-fudge.x; return(xx-(xx%eightspaces)+eightspaces+Drect.origin.x+fudge.x); } backspace(linep, pp) register struct line *linep; register Point *pp; { register char *p; register int x = Drect.origin.x+fudge.x; if (linep->bufp>linep->buf) { for (p=linep->buf; pbufp-1; p++) if (*p=='\t') x = nexttab(x); else x += defont.info[*p].width; pp->x = x; --linep->bufp; if (*p!='\t') term(*p, 0); } } newline(linep, pp) struct line *linep; register Point *pp; { register cursoff=0; if (pp->y+2*NEWLINESIZE > Drect.corner.y-fudge.y+1) { /* weirdness is because the tail of the arrow may be anywhere */ if (rectXrect(Rect(mouse.xy.x-16, mouse.xy.y-16, mouse.xy.x+16, mouse.xy.y+16), Drect)){ cursinhibit(); cursoff++; } lscroll(); if(cursoff) cursallow(); } else pp->y += NEWLINESIZE; pp->x = Drect.origin.x+fudge.x; linep->bufp = linep->buf; } lscroll() { Rectangle r; r = Drect; r.origin.y += NEWLINESIZE; bitblt(&display, r, &display, Pt(r.origin.x, r.origin.y-NEWLINESIZE), F_STORE); stipple(Rpt(Pt(Drect.origin.x, Drect.corner.y-NEWLINESIZE), Drect.corner)); } formfeed(linep, pp) struct line *linep; Point *pp; { cursinhibit(); stipple(Drect); cursallow(); *pp=add(Drect.origin, fudge); linep->bufp=linep->buf; } stipple(r) Rectangle r; { cursinhibit(); rectf(&display, r, F_CLR); cursallow(); } /* routines to handle command input */ inchar() { register int c; #ifdef PAGECHAR if (savechars == CHAR_FETCH) return(*saveptr++ & 0377); #endif #ifdef MPX wait(RCV); if (P->state&(RESHAPED|MOVED)) windowupdate(); c = rcvchar(); #else for ( ; ; ) { wait(RCV|KBD); if (own() & RCV) { c = rcvchar(); break; } if (!dotypeset) send(kbdchar()); } #endif MPX #ifdef PAGECHAR if (savechars == CHAR_STORE) { if (saveptr < &savebuf[PAGECHAR]) *saveptr++ = c; else savechars = CHAR_DISCARD; } #endif return(c&0377); } insignchar() { register int c; c = inchar(); if (c > 127) c -= 256; return(c); } inshort() { register short i; i = inchar() << 8; i |= inchar(); return(i); } Point inpoint() { Point p; p.x = inshort() + typeorg.x; p.y = inshort() + typeorg.y; return(p); } send(c) { char cc = c; sendnchars(1, &cc); } /* typesetter emulation */ typeset(c) register int c; { register struct glyph *g; register Bitmap *b; Point pprime; int old; if (c <= 127) { if (curfont == 0) return; g = &curfont->f_glyph[c]; b = &g->g_bitmap; if (b->base == 0) { curpt.x += g->g_pxwidth; return; } pprime = add(curpt, typeorg); pprime.x -= g->g_xoffset; pprime.y -= g->g_yoffset; bitblt(b, b->rect, &display, pprime, F_OR); curpt.x += g->g_pxwidth; return; } switch (c) { case DMD_EXIT: bye(); break; case DMD_TERM: #ifdef PAGECHAR savechars = CHAR_DISCARD; #endif resetmode(DMD_TERM); break; case DMD_CLEAR: stipple(Drect); curpos = add(org, fudge); break; case DMD_TYPESET: send(DMD_ACK); break; case DMD_ASCII: #ifdef PAGECHAR if (savechars == CHAR_STORE) saveptr--; old = savechars; savechars = CHAR_DISCARD; #endif while (c = inchar()) term(c, 1); #ifdef PAGECHAR savechars = old; #endif break; case DMD_RULE: { short w, h; Rectangle r; w = inshort(); h = inshort(); pprime = add(curpt, typeorg); pprime.y++; r.origin = pprime; r.origin.y = pprime.y - h; r.corner = pprime; r.corner.x = pprime.x + w; rectf(&display, r, F_STORE); break; } case DMD_FORW: curpt.x++; break; case DMD_BACK: curpt.x--; break; case DMD_HABS: curpt.x = inshort(); break; case DMD_HREL: curpt.x += insignchar(); break; case DMD_VABS: curpt.y = inshort(); break; case DMD_VREL: curpt.y += insignchar(); break; case DMD_PAGE: #ifdef PAGECHAR saveptr = savebuf; savechars = CHAR_STORE; #endif stipple(Drect); curpos = add(org, fudge); curpt.x = curpt.y = 0; break; case DMD_ENDPAGE: pagecmd(); break; case DMD_SETFONT: { int i; i = inchar(); if (i < MAXFAMILY) curfont = ftbl[i]; break; } case DMD_MKFONT: case DMD_SGLYPH: case DMD_BGLYPH: #ifdef PAGECHAR if (savechars == CHAR_STORE) saveptr--; old = savechars; savechars = CHAR_DISCARD; #endif if (c == DMD_MKFONT) ldfont(); else ldglyph(c); #ifdef PAGECHAR savechars = old; #endif break; case DMD_SEGMENT: case DMD_SPLINE: define_path(c); break; case DMD_CIRCLE: define_circle(); break; case DMD_ELLIPSE: define_ellipse(); break; case DMD_DRAWPATH: draw_path(); break; case DMD_FILLPATH: fill_path(); break; case DMD_PENSIZE: set_pen(); break; default: break; } } /* request an index number for a new font */ ldfont() { register struct fontinfo *f; register int i, j; register int x = -1; char name[MAXFONTNAME]; register char *p; char loaded[16]; p = name; while (*p++ = inchar()) if (p >= &name[MAXFONTNAME]) { while (inchar()) continue; break; } for (i = 0; i < sizeof(loaded); i++) loaded[i] = 0; /* look for the font... */ for (i = 0; i < MAXFAMILY; i++) { f = ftbl[i]; if (f && strncmp(f->f_name, name, sizeof(f->f_name)) == 0) { for (j = 0; j < 128; j++) { if (f->f_glyph[j].g_bitmap.base) loaded[j>>3] |= 1 << (~j & 07); } send(i); sendnchars(sizeof(loaded), loaded); return; } if (x == -1 && f == 0) x = i; } if (x == -1) { send(-1); return; } f = (struct fontinfo *)alloc(sizeof (struct fontinfo)); if (f == 0) { send(-1); return; } ftbl[x] = f; strncpy(f->f_name, name, sizeof(f->f_name)); send(x); sendnchars(sizeof(loaded), loaded); } /* download a particular character in a font */ ldglyph(c) int c; { register struct glyph *g; register int i, j; register char *p; short chr, fam, w; int words; int o; short xs, ys; int endb; static struct glyph gdummy; w = inshort(); fam = (w >> 7) & 0177; chr = w & 0177; if (ftbl[fam]) g = &(ftbl[fam]->f_glyph[chr]); else { ftbl[fam] = (struct fontinfo *)alloc(sizeof (struct fontinfo)); g = ftbl[fam] ? &(ftbl[fam]->f_glyph[chr]) : &gdummy; } if (c == DMD_SGLYPH) { g->g_pxwidth = insignchar(); xs = inchar(); g->g_xoffset = insignchar(); ys = inchar(); g->g_yoffset = insignchar(); } else { g->g_pxwidth = inshort(); xs = inshort(); g->g_xoffset = inshort(); ys = inshort(); g->g_yoffset = inshort(); } words = RoundUp(xs, WORDSIZE) >> WORDSHIFT; o = RoundUp(xs, 8) >> 3; endb = words * sizeof(Word); if (g->g_bitmap.base) free(g->g_bitmap.base); if (g == &gdummy || (p = alloc(ys * endb)) == 0) { /* skip raster bytes */ j = o * ys; for (i = 0; i < j; i++) inchar(); } else { /* read raster here */ g->g_bitmap.base = (Word *)p; g->g_bitmap.width = words; g->g_bitmap.rect.origin.x = 0; g->g_bitmap.rect.origin.y = 0; g->g_bitmap.rect.corner.x = xs; g->g_bitmap.rect.corner.y = ys; g->g_bitmap._null = 0; p = (char *)g->g_bitmap.base; for (j = 0; j < ys; j++) { for (i = 0; i < o; i++) *p++ = inchar(); for ( ; i < endb; i++) *p++ = 0; } } } /* mouse and keyboard input routines at end of page */ static char *b3m[] = { "redraw", "next", "prev", "quit", "exit", NULL }; static Menu menu = { b3m }; Texture16 ok = { 0x1C44, 0x2248, 0x2250, 0x2270, 0x2248, 0x1C44, 0x0000, 0x0380, 0x0440, 0x0440, 0x0080, 0x0100, 0x0100, 0x0100, 0x0000, 0x0100, }; minkbd() { Texture16 *t; register int i; int oscroll = 0; register int inscroll = 0; Point selpt; while (i = wait(KBD|MOUSE|RCV)) { if (i&KBD) return(kbdchar()); else if (i&RCV) return(rcvchar()); selpt = mouse.xy; i = selpt.x - Drect.origin.x; inscroll = 0; if (i >= 0 && i < SCROLLSIZE) inscroll += 1; i = Drect.corner.y - selpt.y; if (i >= 0 && i < SCROLLSIZE) inscroll += 2; if (inscroll != oscroll) { cursswitch(inscroll ? &C_crosshair : &prompt); oscroll = inscroll; } switch (inscroll) { case 0: if (!bttn3()) break; switch (i = menuhit(&menu, 3)) { case -1: break; case 4: t = cursswitch(&ok); while (!bttn123()) sleep(1); i = bttn3(); while (bttn123()) sleep(1); (void)cursswitch(t); if (i) return('x'); break; default: return("rnpq"[i]); } break; case 1: if (!bttn13()) break; if (bttn1()) typeorg.y -= selpt.y - Drect.origin.y; else typeorg.y += selpt.y - Drect.origin.y; /* primitive scroll for now */ while (bttn123()); return('s'); case 2: if (!bttn13()) break; if (bttn1()) typeorg.x -= selpt.x - Drect.origin.x; else typeorg.x += selpt.x - Drect.origin.x; /* primitive scroll for now */ while (bttn123()); return('s'); case 3: if (bttn1()) return('n'); else if (bttn2()) return('r'); else if (bttn3()) return('p'); break; } sleep(1); } /*NOT REACHED*/ } pagecmd() { register int i; register Texture16 *t; int cmd; Point p1, p2; int redraw; #ifdef PAGECHAR int pagesaved; char buf[40]; pagesaved = savechars != CHAR_DISCARD; #endif t = cursswitch(&prompt); pgstart: redraw = 0; /* * draw outlines of scroll bars. We will draw * the whole lines when we can't write in the * scroll area, but for now, do it this way. */ p1 = Drect.origin; p1.x += SCROLLSIZE; p2.x = p1.x; p2.y = p1.y + SCROLLSIZE; segment(&display, p1, p2, F_STORE); p1.y = Drect.corner.y - 2*SCROLLSIZE; p2.y = Drect.corner.y; segment(&display, p1, p2, F_STORE); p1.y = Drect.corner.y - SCROLLSIZE; p2.y = p1.y; p1.x = Drect.origin.x; p2.x = p1.x + 2*SCROLLSIZE; segment(&display, p1, p2, F_STORE); p1.x = Drect.corner.x - SCROLLSIZE; p2.x = Drect.corner.x; segment(&display, p1, p2, F_STORE); #ifdef PAGECHAR savechars = CHAR_DISCARD; #ifdef DEBUG sprintf(buf, "%d", saveptr-savebuf); p1 = org; p1.x += 20; p1.y += 20; string(&defont, buf, &display, p1, F_XOR); #endif #endif switch (cmd = minkbd()) { case 0177: case 04: case 'q': send(DMD_EXIT); resetmode(DMD_TERM); t = 0; break; case 'x': send(DMD_EXIT); bye(); break; case 'r': case '\f': typeorg = org; /* fall into... */ case 's': redraw = 1; break; case 'n': case ' ': typeorg.y -= Drect.corner.y - Drect.origin.y; if (org.y - typeorg.y < PAGEPIXELS) { redraw = 1; break; } /* fall into... */ case '+': case '\r': case '\n': typeorg = org; send(DMD_PAGE); send(1); break; case 'p': typeorg.y += Drect.corner.y - Drect.origin.y; if (org.y >= typeorg.y) { redraw = 1; break; } /* fall into... */ case '-': typeorg = org; send(DMD_PAGE); send(-1); break; default: /* ringbell(); */ goto pgstart; } if (redraw) { #ifdef PAGECHAR if (pagesaved) { #ifdef MPX if (P->state&(RESHAPED|MOVED)) windowupdate(); #endif typeset(DMD_PAGE); saveptr = savebuf; savechars = CHAR_FETCH; while ((i = inchar()) != DMD_ENDPAGE) typeset(i); (void)cursswitch(&prompt); goto pgstart; } #endif send(DMD_PAGE); send(0); } (void)cursswitch(t); } inkbd() { wait(RCV|KBD); return((own()&KBD)? kbdchar():rcvchar()); } bye() { register int i; for (i = 0; i < MAXFAMILY; i++) { if (ftbl[i]) freefont(ftbl[i]); } exit(); } freefont(f) struct fontinfo *f; { struct glyph *g; for (g = f->f_glyph; g < &f->f_glyph[128]; g++) if (g->g_bitmap.base) free((char *)g->g_bitmap.base); free((char *)f); } #ifdef notdef edit(s) char *s; { char buf[40]; Point p; int c; register i; strcpy(buf, s); p = mouse.xy; disp(buf, p); for(i = strlen(buf); (c = inkbd()) != '\r';) { disp(buf, p); p = mouse.xy; switch(c) { case '\b': if((buf[i] != ' ') && (i > 0)) buf[--i] = 0; break; case '@': while(buf[i] != ' ') i--; buf[++i] = 0; break; default: buf[i++] = c; buf[i] = 0; break; } disp(buf, p); } disp(buf, p); strcpy(s, buf); } disp(s, p) char *s; Point p; { string(&defont, "\001", &display, string(&defont, s, &display, p, F_XOR), F_XOR); } #endif resetmode(c) int c; { if (c == DMD_TERM) { cursvis = dotypeset = 0; #ifdef MPX request(SEND|RCV); #else request(SEND|RCV|KBD); #endif curpos.x = org.x + fudge.x; curpos.y = Drect.corner.y - fudge.y - defont.height; } else { dotypeset = 1; request(SEND|RCV|KBD|MOUSE); typeorg = org; } } windowupdate() { #ifdef MPX if (P->state&RESHAPED) { #endif org = Drect.origin; typeorg = org; curpos = add(org, fudge); line.bufp = line.buf; if (cursvis) { term(CURSOR, 0); /* flip state */ cursvis = 0; } #ifdef MPX } else { curpos = add(sub(curpos, org), Drect.origin); typeorg = add(sub(typeorg, org), Drect.origin); org = Drect.origin; } P->state &= ~(MOVED|RESHAPED); #endif artdeco(); } static Texture16 vstripe = { 0xf0f0, 0xf0f0, 0xf0f0, 0xf0f0, 0xf0f0, 0xf0f0, 0xf0f0, 0xf0f0, 0xf0f0, 0xf0f0, 0xf0f0, 0xf0f0, 0xf0f0, 0xf0f0, 0xf0f0, 0xf0f0 }; static Texture16 hstripe = { 0xffff, 0xffff, 0xffff, 0xffff, 0x0000, 0x0000, 0x0000, 0x0000, 0xffff, 0xffff, 0xffff, 0xffff, 0x0000, 0x0000, 0x0000, 0x0000, }; artdeco() { texture16(&display, Rect(display.rect.origin.x, display.rect.origin.y, display.rect.corner.x, Drect.origin.y), &vstripe, F_XOR); texture16(&display, Rect(display.rect.origin.x, Drect.origin.y, Drect.origin.x, Drect.corner.y), &hstripe, F_XOR); texture16(&display, Rect(Drect.corner.x, Drect.origin.y, display.rect.corner.x, Drect.corner.y), &hstripe, F_XOR); texture16(&display, Rect(display.rect.origin.x, Drect.corner.y, display.rect.corner.x, display.rect.corner.y), &vstripe, F_XOR); } /* graphics support; for now there are some unimplemented operations */ #define MAXPOINTS 60 #define PATH_NONE -1 #define PATH_SEGMENT 0 #define PATH_SPLINE 1 #define PATH_CIRCLE 2 #define PATH_ELLIPSE 3 int path_type = PATH_NONE; int pen_size = 1; struct { Point c_center; Point c_start; Point c_finish; } path_circle; struct { Point e_center; Point e_start; Point e_finish; short e_xradius; short e_yradius; } path_ellipse; Point path_pts[MAXPOINTS+2]; int path_len; define_path(c) { register int i, n; register Point *pp; path_type = (c==DMD_SEGMENT) ? PATH_SEGMENT : PATH_SPLINE; n = inshort(); path_len = n; if (path_len > MAXPOINTS) { path_len = MAXPOINTS; for (i = path_len; i < n; i++) (void)inpoint(); } pp = &path_pts[1]; for (i = 0; i < path_len; i++) *pp++ = inpoint(); } define_circle() { path_circle.c_center = inpoint(); path_circle.c_start = inpoint(); path_circle.c_finish = inpoint(); path_type = PATH_CIRCLE; } define_ellipse() { path_ellipse.e_center = inpoint(); path_ellipse.e_start = inpoint(); path_ellipse.e_finish = inpoint(); path_ellipse.e_xradius = inshort(); path_ellipse.e_yradius = inshort(); path_type = PATH_ELLIPSE; } draw_path() { int rop; rop = inchar(); /* ignore for now */ switch (path_type) { case PATH_SEGMENT: draw_segment(F_OR); break; case PATH_SPLINE: draw_spline(F_OR); break; case PATH_CIRCLE: draw_circle(F_OR); break; case PATH_ELLIPSE: draw_ellipse(F_OR); break; } } fill_path() { int rop; rop = inchar(); /* ignore for now */ } set_pen() { int i = inchar(); if (i < 1) i = 1; pen_size = i; } /* draw a spline path */ draw_spline(f) int f; { register Point *pp = path_pts; register long w, t1, t2, t3, scale=1000; register int i, j, steps=10; int n = path_len + 1; Point p, q; pp[0] = pp[1]; pp[n] = pp[n-1]; p = pp[0]; for (i = 0; i < n-1; i++) { for (j = 0; j < steps; j++) { w = scale * j / steps; t1 = w * w / (2 * scale); w = w - scale/2; t2 = 3*scale/4 - w * w / scale; w = w - scale/2; t3 = w * w / (2*scale); q.x = (t1*pp[i+2].x + t2*pp[i+1].x + t3*pp[i].x + scale/2) / scale; q.y = (t1*pp[i+2].y + t2*pp[i+1].y + t3*pp[i].y + scale/2) / scale; line_btw(p, q, f); p = q; } } } /* draw a segment path */ draw_segment(f) int f; { register Point *pp; register int i; pp = &path_pts[1]; if (path_len == 1) { if (pen_size > 1) disc(&display, pp[0], pen_size, f); else point(&display, pp[0], f); } else { for (i = 1; i < path_len; i++) { line_btw(pp[0], pp[1], f); pp++; } } } draw_circle(f) int f; { /* ignore pen size for now */ if (path_circle.c_center.x == path_circle.c_finish.x && path_circle.c_center.y == path_circle.c_finish.y) { circle(&display, path_circle.c_center, path_circle.c_start.x, f); } else { arc(&display, path_circle.c_center, path_circle.c_start, path_circle.c_finish, f); } } draw_ellipse(f) int f; { /* ignore pen size for now */ if (path_ellipse.e_center.x == path_ellipse.e_finish.x && path_ellipse.e_center.y == path_ellipse.e_finish.y) { ellipse(&display, path_ellipse.e_center, path_ellipse.e_xradius, path_ellipse.e_yradius, f); } else { elarc(&display, path_ellipse.e_center, path_ellipse.e_xradius, path_ellipse.e_yradius, path_ellipse.e_start, path_ellipse.e_finish, f); } } /* Draw a line on the screen. */ line_btw(p0, p1, rop) Point p0, p1; { register int i; register int incx; if (abs(p1.y-p0.y) > abs(p1.x-p0.x)) { incx = 1; p0.x -= pen_size/2; p1.x -= pen_size/2; } else { incx = 0; p0.y -= pen_size/2; p1.y -= pen_size/2; } for (i = 0; i < pen_size; i++) { segment(&display, p0, p1, rop); if (incx) { p0.x++; p1.x++; } else { p0.y++; p1.y++; } } }