547 lines
12 KiB
C
547 lines
12 KiB
C
|
/* 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;
|
||
|
}
|
||
|
}
|
||
|
}
|