/* Framebuffer Graphics Libary for Linux, Copyright 1993 Harm Hanemaayer */ /* line.c Line drawing */ #include #ifndef DO_NOT_USE_VGALIB #include #endif #include "inlstring.h" /* include inline string operations */ #include "vgagl.h" #include "def.h" #include "driver.h" static inline int muldiv64(int m1, int m2, int d) { return (float) m1 * (float) m2 / ((float) d); } #ifdef NO_ASSEMBLY static inline int gl_regioncode (int x, int y) { int result = 0; if (x < __clipx1) result |= 1; else if (x > __clipx2) result |= 2; if (y < __clipy1) result |= 4; else if (y > __clipy2) result |= 8; return result; } #else #define INC_IF_NEG(y, result) \ { \ __asm__("btl $31,%1\n\t" \ "adcl $0,%0" \ : "=r" ((int) result) \ : "rm" ((int) (y)), "0" ((int) result) \ ); \ } static inline int gl_regioncode (int x, int y) { int dx1, dx2, dy1, dy2; int result; result = 0; dy2 = __clipy2 - y; INC_IF_NEG (dy2, result); result <<= 1; dy1 = y - __clipy1; INC_IF_NEG (dy1, result); result <<= 1; dx2 = __clipx2 - x; INC_IF_NEG (dx2, result); result <<= 1; dx1 = x - __clipx1; INC_IF_NEG (dx1, result); return result; } #endif /* ! NO_ASSEMBLY */ #define line_start_paged(s) \ fp = y * bytesperrow + x * s; \ vga_setpage (fpp = (fp >> 16)); \ fp &= 0xFFFF; #define line_start_linear(s) \ vp = (unsigned char *)VBUF + y * bytesperrow + x * s; #define line_loop_paged_a(m,i,u,v) \ { \ int d = ay - (ax >> 1); \ if ((x = abs (dx))) \ do { \ i; \ if (d m 0) { \ fp v; \ d -= ax; \ } \ fp u; \ d += ay; \ if (fp & 0xFFFF0000) { /* has it cross a page boundary ? */ \ fpp += fp >> 16; \ vga_setpage (fpp); \ } \ fp &= 0x0000FFFF; \ } while (--x); \ } #define line_loop_linear_a(m,i,u,v) \ { \ int d = ay - (ax >> 1); \ if ((x = abs (dx))) \ do { \ i; \ if (d m 0) { \ vp v; \ d -= ax; \ } \ vp u; \ d += ay; \ } while (--x); \ } #define line_loop_paged_b(m,i,u,v) \ { \ int d = ax - (ay >> 1); \ if ((y = abs (dy))) \ do { \ i; \ if (d m 0) { \ fp u; \ d -= ay; \ } \ fp v; \ d += ax; \ if (fp & 0xFFFF0000) { \ fpp += fp >> 16; \ vga_setpage (fpp); \ } \ fp &= 0x0000FFFF; \ } while (--y); \ } #define line_loop_linear_b(m,i,u,v) \ { \ int d = ax - (ay >> 1); \ if ((y = abs (dy))) \ do { \ i; \ if (d m 0) { \ vp u; \ d -= ay; \ } \ vp v; \ d += ax; \ } while (--y); \ } /* Partly based on the work which was partly based on vgalib by Tommy Frandsen */ /* This is a lot faster now that setpixel is inlined */ void gl_line (int x1, int y1, int x2, int y2, int c) { int dx, dy, ax, ay, sx, sy, x, y; int bytesperrow; unsigned char *vp = NULL; if (__clip) /* Cohen & Sutherland algorithm */ for (;;) { int r1 = gl_regioncode (x1, y1); int r2 = gl_regioncode (x2, y2); if (!(r1 | r2)) break; /* completely inside */ if (r1 & r2) return; /* completely outside */ if (r1 == 0) { swap (x1, x2); /* make sure first */ swap (y1, y2); /* point is outside */ r1 = r2; } if (r1 & 1) { /* left */ y1 += muldiv64 (__clipx1 - x1, y2 - y1, x2 - x1); x1 = __clipx1; } else if (r1 & 2) { /* right */ y1 += muldiv64 (__clipx2 - x1, y2 - y1, x2 - x1); x1 = __clipx2; } else if (r1 & 4) { /* top */ x1 += muldiv64 (__clipy1 - y1, x2 - x1, y2 - y1); y1 = __clipy1; } else if (r1 & 8) { /* bottom */ x1 += muldiv64 (__clipy2 - y1, x2 - x1, y2 - y1); y1 = __clipy2; } } dx = x2 - x1; dy = y2 - y1; ax = abs (dx) << 1; ay = abs (dy) << 1; sx = (dx >= 0) ? 1 : -1; sy = (dy >= 0) ? 1 : -1; x = x1; y = y1; #define insert_pixel_1 *((unsigned char *) vp) = c; #define insert_pixel_2 *((unsigned short *) vp) = c; #define insert_pixel_3 *((unsigned char *) vp) = c; \ *((unsigned char *) (vp + 1)) = (c>>8); \ *((unsigned char *) (vp + 2)) = (c>>16); #define insert_pixel_4 *((unsigned int *) vp) = c; bytesperrow = BYTEWIDTH; if (MODETYPE == CONTEXT_VIRTUAL || MODETYPE == CONTEXT_LINEAR) { switch BYTESPERPIXEL { case 1: line_start_linear(1); if (ax > ay) { if(sx > 0) { line_loop_linear_a(>=,insert_pixel_1,++,+=bytesperrow*sy); } else { line_loop_linear_a(>,insert_pixel_1,--,+=bytesperrow*sy); } } else { if(sy > 0) { line_loop_linear_b(>=,insert_pixel_1,+=sx,+=bytesperrow); } else { line_loop_linear_b(>,insert_pixel_1,+=sx,-=bytesperrow); } } insert_pixel_1; break; case 2: line_start_linear(2); if (ax > ay) { if(sx > 0) { line_loop_linear_a(>=,insert_pixel_2,+=2,+=bytesperrow*sy); } else { line_loop_linear_a(>,insert_pixel_2,-=2,+=bytesperrow*sy); } } else { sx <<= 1; if(sy > 0) { line_loop_linear_b(>=,insert_pixel_2,+=sx,+=bytesperrow); } else { line_loop_linear_b(>,insert_pixel_2,+=sx,-=bytesperrow); } } insert_pixel_2; break; case 3: line_start_linear(3); if (ax > ay) { if(sx > 0) { line_loop_linear_a(>=,insert_pixel_3,+=3,+=bytesperrow*sy); } else { line_loop_linear_a(>,insert_pixel_3,-=3,+=bytesperrow*sy); } } else { sx *= 3; if(sy > 0) { line_loop_linear_b(>=,insert_pixel_3,+=sx,+=bytesperrow); } else { line_loop_linear_b(>,insert_pixel_3,+=sx,-=bytesperrow); } } insert_pixel_3; break; case 4: line_start_linear(4); if (ax > ay) { if(sx > 0) { line_loop_linear_a(>=,insert_pixel_4,+=4,+=bytesperrow*sy); } else { line_loop_linear_a(>,insert_pixel_4,-=4,+=bytesperrow*sy); } } else { sx <<= 2; if(sy > 0) { line_loop_linear_b(>=,insert_pixel_4,+=sx,+=bytesperrow); } else { line_loop_linear_b(>,insert_pixel_4,+=sx,-=bytesperrow); } } insert_pixel_4; break; } } #ifndef DO_NOT_USE_VGALIB #undef insert_pixel_1 #undef insert_pixel_2 #undef insert_pixel_3 #undef insert_pixel_4 #define insert_pixel_1 *((unsigned char *) (vp + fp)) = c; #define insert_pixel_2 *((unsigned short *) (vp + fp)) = c; #define insert_pixel_3 *((unsigned char *) (vp + fp)) = c; \ *((unsigned char *) (vp + fp + 1)) = (c>>8); \ *((unsigned char *) (vp + fp + 2)) = (c>>16); #define insert_pixel_4 *((unsigned int *) (vp + fp)) = c; if (MODETYPE == CONTEXT_PAGED) { vp = (unsigned char *)VBUF; switch BYTESPERPIXEL { int fpp; int fp; case 1: line_start_paged(1); if (ax > ay) { if(sx > 0) { line_loop_paged_a(>=,insert_pixel_1,++,+=bytesperrow*sy); } else { line_loop_paged_a(>,insert_pixel_1,--,+=bytesperrow*sy); } } else { if(sy > 0) { line_loop_paged_b(>=,insert_pixel_1,+=sx,+=bytesperrow); } else { line_loop_paged_b(>,insert_pixel_1,+=sx,-=bytesperrow); } } insert_pixel_1; break; case 2: line_start_paged(2); if (ax > ay) { if(sx > 0) { line_loop_paged_a(>=,insert_pixel_2,+=2,+=bytesperrow*sy); } else { line_loop_paged_a(>,insert_pixel_2,-=2,+=bytesperrow*sy); } } else { sx <<= 1; if(sy > 0) { line_loop_paged_b(>=,insert_pixel_2,+=sx,+=bytesperrow); } else { line_loop_paged_b(>,insert_pixel_2,+=sx,-=bytesperrow); } } insert_pixel_2; break; case 3: line_start_paged(3); if (ax > ay) { if(sx > 0) { line_loop_paged_a(>=,insert_pixel_3,+=3,+=bytesperrow*sy); } else { line_loop_paged_a(>,insert_pixel_3,-=3,+=bytesperrow*sy); } } else { sx *= 3; if(sy > 0) { line_loop_paged_b(>=,insert_pixel_3,+=sx,+=bytesperrow); } else { line_loop_paged_b(>,insert_pixel_3,+=sx,-=bytesperrow); } } insert_pixel_3; break; case 4: line_start_paged(4); if (ax > ay) { if(sx > 0) { line_loop_paged_a(>=,insert_pixel_4,+=4,+=bytesperrow*sy); } else { line_loop_paged_a(>,insert_pixel_4,-=4,+=bytesperrow*sy); } } else { sx <<= 2; if(sy > 0) { line_loop_paged_b(>=,insert_pixel_4,+=sx,+=bytesperrow); } else { line_loop_paged_b(>,insert_pixel_4,+=sx,-=bytesperrow); } } insert_pixel_4; break; } } if (!vp) { if (ax > ay) { int d = ay - (ax >> 1); while (x != x2) { setpixel (x, y, c); if (d > 0 || (d == 0 && sx == 1)) { y += sy; d -= ax; } x += sx; d += ay; } } else { int d = ax - (ay >> 1); while (y != y2) { setpixel (x, y, c); if (d > 0 || (d == 0 && sy == 1)) { x += sx; d -= ay; } y += sy; d += ax; } } setpixel (x, y, c); } #endif } static void gl_setcirclepixels(int x, int y, int sx, int sy, int c) { if (__clip) { int z = max(x, y); if (sx - z < __clipx1 || sx + z > __clipx2 || sy - z < __clipy1 || sy + z > __clipy2) { /* use setpixel clipping */ gl_setpixel(sx + x, sy + y, c); gl_setpixel(sx - x, sy + y, c); gl_setpixel(sx + x, sy - y, c); gl_setpixel(sx - x, sy - y, c); gl_setpixel(sx + y, sy + x, c); gl_setpixel(sx - y, sy + x, c); gl_setpixel(sx + y, sy - x, c); gl_setpixel(sx - y, sy - x, c); return; } } setpixel(sx + x, sy + y, c); setpixel(sx - x, sy + y, c); setpixel(sx + x, sy - y, c); setpixel(sx - x, sy - y, c); setpixel(sx + y, sy + x, c); setpixel(sx - y, sy + x, c); setpixel(sx + y, sy - x, c); setpixel(sx - y, sy - x, c); } void gl_circle(int sx, int sy, int r, int c) { int x, y, d; if (r < 1) { gl_setpixel(sx, sy, c); return; } if (__clip) if (sx + r < __clipx1 || sx - r > __clipx2 || sy + r < __clipy1 || sy - r > __clipy2) return; x = 0; y = r; d = 1 - r; gl_setcirclepixels(x, y, sx, sy, c); while (x < y) { if (d < 0) d += x * 2 + 3; else { d += x * 2 - y * 2 + 5; y--; } x++; gl_setcirclepixels(x, y, sx, sy, c); } } void gl_fillcircle(int sx, int sy, int r, int c) { int x = 0, y = r, d = 1 - r; if (r < 1) { gl_setpixel(sx, sy, c); return; } if (__clip) if (sx + r < __clipx1 || sx - r > __clipx2 || sy + r < __clipy1 || sy - r > __clipy2) return; gl_hline(sx - x, sy + y, sx + x, c); gl_hline(sx - x, sy - y, sx + x, c); gl_hline(sx - y, sy + x, sx + y, c); gl_hline(sx - y, sy - x, sx + y, c); while (x < y) { if (d < 0) { d += x * 2 + 3; } else { d += x * 2 - y * 2 + 5; y--; } x++; gl_hline(sx - x, sy + y, sx + x, c); gl_hline(sx - x, sy - y, sx + x, c); gl_hline(sx - y, sy + x, sx + y, c); gl_hline(sx - y, sy - x, sx + y, c); } } void gl_bcircle(int sx, int sy, int r, int c, int fill) { int x = 0, y = r, d = 2 * (1 - r); if (r < 1) { gl_setpixel(sx, sy, c); return; } if (__clip) if (sx + r < __clipx1 || sx - r > __clipx2 || sy + r < __clipy1 || sy - r > __clipy2) return; while (y >= 0) { if (fill == 0) { gl_setpixel(sx + x, sy + y, c); gl_setpixel(sx + x, sy - y, c); gl_setpixel(sx - x, sy + y, c); gl_setpixel(sx - x, sy - y, c); } else { gl_hline(sx - x, sy + y, sx + x, c); gl_hline(sx - x, sy - y, sx + x, c); } if ((d + y) > 0) { y--; d -= (2 * y * WIDTH / HEIGHT) - 1; } if (x > d) { x++; d += (2 * x) + 1; } } }