SvgaLib/gl/line.c

547 lines
12 KiB
C
Raw Permalink Normal View History

/* Framebuffer Graphics Libary for Linux, Copyright 1993 Harm Hanemaayer */
/* line.c Line drawing */
#include <stdlib.h>
#ifndef DO_NOT_USE_VGALIB
#include <vga.h>
#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;
}
}
}