#include #include #include #include #include "vogle.h" static int do_dash = 1; /* a == b or b > a */ #define NEAR(a, b) (((a) - (b)) / (a) < 0.0001) #define checkdash(l) ((*(++l->dashp) == '\0' ? *(l->dashp = l->style) : *l->dashp) != '0') /* * Set the current dash length */ void dashcode(float d) { if (d < 0.0) d = -d; if (d == 0.0) d = 0.1; vdevice.attr->a.dash = d; } /* * Set the current linestyle as a character string of 1's and 0's */ void linestyle(char *l) { Attribute *line; char *c; line = &vdevice.attr->a; if (!l || !*l) { line->style = (char *)NULL; } else { /* * If it's all non-0 (or ' ') then it's a solid line */ for (c = l; c != NULL; c++) { if (*c == '0' || *c == ' ') { if (line->style != (char *)NULL){ vfree(line->style,"from linestyle"); } line->style = (char *)vallocate(strlen(l) + 1,"from linestyle"); strcpy(line->style, l); line->dashp = line->style; line->adist = 0.0; do_dash = *line->dashp != '0'; return; } } line->style = (char *)NULL; } return; } /* * Draw dashed lines (Duh) * Assumes p0 - p1 are valid (possibly clipped endpoints) */ void dashline(register Vector p0, register Vector p1) { int vx, vy, sync; float dx, dy, dz, dw, dist, ldist, tdist; Vector pd; Attribute *line; line = &vdevice.attr->a; if (line->dash == 0.0) { vx = WtoVx(p1); vy = WtoVy(p1); (*vdevice.dev.Vdraw)(vx, vy); vdevice.cpVx = vx; vdevice.cpVy = vy; return; } /* * The distance for this line segment */ dx = p1[V_X] - p0[V_X]; dy = p1[V_Y] - p0[V_Y]; dz = p1[V_Z] - p0[V_Z]; dw = p1[V_W] - p0[V_W]; ldist = sqrt(dx*dx + dy*dy + dz*dz + dw*dw); /* * If this distance is less than it takes to * complete the current dash then just do it. */ if (ldist <= (line->dash - line->adist)) { if (NEAR(line->dash, line->adist)) { line->adist = 0.0; do_dash = checkdash(line); } line->adist += ldist; vx = WtoVx(p1); vy = WtoVy(p1); if (do_dash) (*vdevice.dev.Vdraw)(vx, vy); vdevice.cpVx = vx; vdevice.cpVy = vy; return; } else { if ((sync = vdevice.sync)) /* We'll sync at the end */ vdevice.sync = 0; /* * If this distance will take us over the end of a * dash then break it up. */ /* * Handle the initial case where we start in the middle * of a dash. */ tdist = 0.0; copyvector(pd, p0); if (line->adist > 0.0) { tdist = (line->dash - line->adist); if (NEAR(line->dash, line->adist)) { line->adist = 0.0; do_dash = checkdash(line); } line->adist += tdist; dist = tdist / ldist; pd[V_X] += dx * dist; pd[V_Y] += dy * dist; pd[V_Z] += dz * dist; pd[V_W] += dw * dist; vx = WtoVx(pd); vy = WtoVy(pd); if (do_dash) (*vdevice.dev.Vdraw)(vx, vy); vdevice.cpVx = vx; vdevice.cpVy = vy; } dx *= line->dash / ldist; dy *= line->dash / ldist; dz *= line->dash / ldist; dw *= line->dash / ldist; dist = line->dash; while (tdist <= ldist - dist) { if (NEAR(line->dash, line->adist)) { line->adist = 0.0; do_dash = checkdash(line); } pd[V_X] += dx; pd[V_Y] += dy; pd[V_Z] += dz; pd[V_W] += dw; vx = WtoVx(pd); vy = WtoVy(pd); line->adist += dist; tdist += dist; if (do_dash) (*vdevice.dev.Vdraw)(vx, vy); vdevice.cpVx = vx; vdevice.cpVy = vy; } /* * Check the last little bit.... */ if (NEAR(line->dash, line->adist)) { line->adist = 0.0; do_dash = checkdash(line); } dx = p1[V_X] - pd[V_X]; dy = p1[V_Y] - pd[V_Y]; dz = p1[V_Z] - pd[V_Z]; dw = p1[V_W] - pd[V_W]; dist = sqrt(dx*dx + dy*dy + dz*dz + dw*dw); line->adist += dist; vx = WtoVx(p1); vy = WtoVy(p1); if (do_dash) (*vdevice.dev.Vdraw)(vx, vy); vdevice.cpVx = vx; vdevice.cpVy = vy; } if (sync) { vdevice.sync = 1; (*vdevice.dev.Vsync)(); } } /******************************************************************************/ /* * draw * * draw a line form the logical graphics position to the * world coordinates x, y, z. * */ void draw(float x, float y, float z) { Token *tok; int vx, vy; Vector res; if (!vdevice.initialised) verror("draw: vogle not initialised"); if (vdevice.inpolygon) { (*vdevice.pdraw)(x, y, z); vdevice.cpW[V_X] = x; vdevice.cpW[V_Y] = y; vdevice.cpW[V_Z] = z; vdevice.cpVvalid = 0; return; } if (vdevice.inobject) { tok = newtokens(4); tok[0].i = OBJ_DRAW; tok[1].f = x; tok[2].f = y; tok[3].f = z; vdevice.cpW[V_X] = x; vdevice.cpW[V_Y] = y; vdevice.cpW[V_Z] = z; vdevice.cpVvalid = 0; return; } if (!vdevice.cpVvalid) multvector(vdevice.cpWtrans, vdevice.cpW, vdevice.transmat->m); vdevice.cpW[V_X] = x; vdevice.cpW[V_Y] = y; vdevice.cpW[V_Z] = z; multvector(res, vdevice.cpW, vdevice.transmat->m); if (vdevice.clipoff) { vx = WtoVx(res); /* just draw it */ vy = WtoVy(res); if (vdevice.attr->a.style != (char *)NULL ) { dashline(vdevice.cpWtrans, res); vdevice.cpVvalid = 0; return; } (*vdevice.dev.Vdraw)(vx, vy); vdevice.cpVx = vx; vdevice.cpVy = vy; vdevice.cpVvalid = 0; } else { if (vdevice.cpVvalid) quickclip(vdevice.cpWtrans, res); else clip(vdevice.cpWtrans, res); } vdevice.cpWtrans[V_X] = res[V_X]; vdevice.cpWtrans[V_Y] = res[V_Y]; vdevice.cpWtrans[V_Z] = res[V_Z]; vdevice.cpWtrans[V_W] = res[V_W]; } /******************************************************************************/ /* * draw2 * * draw a line from the logical graphics position to the * world coordinates x, y. * */ void draw2(float x, float y){ if (!vdevice.initialised) verror("draw2: vogle not initialised"); draw(x, y, 0.0); } /******************************************************************************/ /* * rdraw * * 3D relative draw from the logical graphics position by dx, dy, dz. * */ void rdraw(float dx, float dy, float dz) { if (!vdevice.initialised) verror("rdraw: vogle not initialised"); draw((vdevice.cpW[V_X] + dx),(vdevice.cpW[V_Y] + dy),(vdevice.cpW[V_Z] + dz)); } /******************************************************************************/ /* * rdraw2 * * 2D relative draw from the logical graphics position by dx, dy. * */ void rdraw2(float dx, float dy) { if (!vdevice.initialised) verror("rdraw2: vogle not initialised"); draw((vdevice.cpW[V_X] + dx), (vdevice.cpW[V_Y] + dy), 0.0); } /******************************************************************************/ /* * sdraw2 * * Draw directly in proportion to screen coordinates. */ void sdraw2(float xs, float ys) { int nx, ny; if (!vdevice.initialised) verror("sdraw2: vogle not initialised"); nx = (xs / 2 + 0.5) * vdevice.sizeX; ny = (0.5 + ys / 2) * vdevice.sizeY; (*vdevice.dev.Vdraw)(nx, ny); vdevice.cpVx = nx; vdevice.cpVy = ny; vdevice.cpVvalid = 0; } /******************************************************************************/ /* * rsdraw2 * * Relative draw as a fraction of screen size. */ void rsdraw2(float dxs, float dys){ int ndx, ndy; if (!vdevice.initialised) verror("rsdraw2: vogle not initialised"); ndx = dxs * vdevice.sizeSx / 2; ndy = dys * vdevice.sizeSy / 2; (*vdevice.dev.Vdraw)(vdevice.cpVx + ndx, vdevice.cpVy + ndy); vdevice.cpVx += ndx; vdevice.cpVy += ndy; } /******************************************************************************/