69,371
社区成员
发帖
与我相关
我的任务
分享
/*用Bresenham算法画一条线(不检查参数,自定义颜色)
//==================================================================
//函数名: draw_line()
//日期: 2008-12-16
//输入参数:(x1, y1):画线的起始座标
(x2, y2):画线的结束座标
DISP_MODE_PUT: 直接设置
DISP_MODE_OR: 与屏幕原有值“或取”后再写
DISP_MODE_XOR: 与屏幕原有值“异或”后再写
DISP_MODE_AND: 与屏幕原有值“与取”后再写
draw_dot:画点函数
color:点的颜色(也可以替换成别的参数)
//返回值: 成功返回0,
失败返回<0
//注意事项:1、无。
//=================================================================*/
int draw_line(int x0, int y0, int x1, int y1,
int (*draw_dot)(int x, int y, unsigned char color),
unsigned char color)
{
if ((x0 == x1) && (y0 == y1))
{
return *draw_dot(x0, y0, color);
}
int dx,dy; //定义X.Y轴上增加的变量值
int sub;
int retval;
dx = abs(x1 - x0); //X轴方向上的增量
dy = abs(y1 - y0); //Y轴方向上的增量
/* 布兰森汉姆(Bresenham)算法画线 */
if (dx > dy) //靠近X轴
{
sub = 2 * dy - dx; //计算下个点的位置
while (x0 != x1)
{
retval = *draw_dot(x0, y0, color); //画起点
if (retval < 0)
{
return retval;
}
if (x1 > x0)
{
x0++;
}
else
{
x0--; //X轴上加1
}
if (sub > 0) //判断下下个点的位置
{
if (y1 > y0)
{
y0++;
}
else
{
y0--; //为右上相邻点,即(x0+1,y0+1)
}
sub += (2 * dy) - (2 * dx);
}
else
{
sub += 2 * dy; //判断下下个点的位置
}
}
retval = *draw_dot(x0, y0, color);;
if (retval < 0)
{
return retval;
}
}
else
{
sub = 2 * dx - dy; //靠近Y轴
while (y0 != y1)
{
retval = *draw_dot(x0, y0, color); //画起点
if (retval < 0)
{
return retval;
}
if (y1 > y0)
{
y0++;
}
else
{
y0--;
}
if (sub > 0) //判断下下个点的位置
{
if (x1 > x0)
{
x0++;
}
else
{
x0--;
}
sub += (2 * dx) - (2 * dy);
}
else
{
sub += 2 * dx;
}
}
retval = *draw_dot(x0, y0, color);
if (retval < 0)
{
return retval;
}
}
return 0;
}
static unsigned char far *get_video_buf(void)
{
return Graph_device_cntx.vdo_buf;
}
#include <stdio.h>
#include <dos.h>
#include <math.h>
#include <assert.h>
#define VIDEO_BUF_ADDR 0xA0000000L /* 0xA0000,破16bit的短指针,转换一下 */
#define EMPTY_COLOR (-1) /* 非法的颜色值 */
#define SWAP(a, b) do { a ^= b; b ^= a; a ^= b; } while (0)
#define NUM_ELEM(a) (sizeof(a)/sizeof((a)[0]))
typedef struct _video_attribute
{
video_mode_t vdo_mode;
u32_t max_color;
int scrn_w, scrn_h; /* screen resolution: width x height */
} video_attr_t, p_video_attr_t;
typedef struct _graph_device_context
{
video_attr_t * vdo_attr_p;
unsigned char far * vdo_buf;
color_t bg_color;
color_t fg_color;
} graph_device_cntx_t;
static graph_device_cntx_t Graph_device_cntx;
static video_attr_t Video_attrs[] =
{
{VIDEO_MODE_VGA256, 256, 320, 200},
{VIDEO_MODE_TEXT, 0, 0, 0 }
};
static unsigned char far *get_video_buf(void);
void init_graph(void)
{
Graph_device_cntx.vdo_attr_p = NULL;
Graph_device_cntx.vdo_buf = (unsigned char far *)VIDEO_BUF_ADDR;
Graph_device_cntx.bg_color = EMPTY_COLOR;
Graph_device_cntx.fg_color = EMPTY_COLOR;
}
int set_video_mode(video_mode_t vdo_mode)
{
union REGS in_reg, out_reg;
int i;
assert(vdo_mode >= 0 && vdo_mode != VIDEO_MODE_NONE);
for (i = 0; i < NUM_ELEM(Video_attrs); i++)
{
if (Video_attrs[i].vdo_mode == vdo_mode)
{
Graph_device_cntx.vdo_attr_p = &Video_attrs[i];
break;
}
}
assert(i < NUM_ELEM(Video_attrs));
in_reg.h.ah = 0;
in_reg.h.al = (unsigned char)vdo_mode;
int86(0x10, &in_reg, &out_reg);
return 1;
}
int get_scrn_width(void)
{
return Graph_device_cntx.vdo_attr_p->scrn_w;
}
void set_bg_color(color_t c)
{
unsigned char far *vdo_buf = get_video_buf();
int x, y, scrn_w, scrn_h;
Graph_device_cntx.bg_color = c;
x = 0;
y = 0;
scrn_w = get_scrn_width();
scrn_h = get_scrn_height();
for (x = 0; x < scrn_w; x++)
for (y = 0; y < scrn_h; y++)
vdo_buf[y*scrn_w+x] = c;
}
unsigned long get_max_color(void)
{
return Graph_device_cntx.vdo_attr_p->max_color;
}
void gui_put_pixel_ex(int x, int y, color_t c)
{
unsigned char far *vdo_buf = get_video_buf();
assert(0 <= c && c <= get_max_color());
vdo_buf[y * get_scrn_width() + x] = c;
}
void gui_bresenham_draw_line_ex(int x1, int y1, int x2, int y2, color_t c)
{
int b_steep = abs(y2 - y1) > abs(x2 - x1);
int dx, dy;
int error;
int x, y, y_step;
/* if abs(slope) > 1, swap x and y coordinates */
if (b_steep)
{
SWAP(x1, y1);
SWAP(x2, y2);
}
/* if draw line direction from right to left, reverse it */
if (x1 > x2)
{
SWAP(x1, x2);
SWAP(y1, y2);
}
dx = x2 - x1;
dy = abs(y2 - y1);
error = dx >> 1; /* dx / 2 */
y = y1;
/* determinate the inc in y-axis direction */
if (y1 < y2)
y_step = 1;
else
y_step = -1;
for (x = x1; x <= x2; x++)
{
if (b_steep)
gui_put_pixel_ex(y, x, c);
else
gui_put_pixel_ex(x, y, c);
error -= dy;
if (error < 0)
{
y += y_step;
error += dx;
}
}
}
/* 调用 */
#include <conio.h> /* 借用enum COLORS颜色值 */
int main(void)
{
init_graph();
set_video_mode(VIDEO_MODE_VGA256);
set_bg_color(255);
gui_bresenham_draw_line_ex(200, 20, 14, 143, LIGHTMAGENTA);
gui_bresenham_draw_line_ex(17, 14, 234, 156, RED);
getch();
set_video_mode(VIDEO_MODE_TEXT);
return 0;
}
/*
* 平台相关代码
*/
#define WIN32 /* 当然Turbo C 2.0下没有WIN32这个宏, 为运行为Turbo C 2.0定义的函数,定义它 */
#ifdef WIN32
#define VIDEO_BUF_ADDR 0xA0000000L /* 0xA0000 */
#define SCREEN_WIDTH 320
#define SCREEN_HEIGHT 200
typedef enum _video_mode_tag
{
VIDEO_MODE_VGA256 = 0x13,
VIDEO_MODE_TEXT = 0x03,
VIDEO_MODE_NONE
} video_mode_t;
/* 函数set_video_mode(), set_bg_color()与平台有关,各个平台可能都要实现 */
void set_video_mode(int mode)
{
union REGS inregs, outregs;
inregs.h.ah = 0;
inregs.h.al = (unsigned char)mode;
int86(0x10, &inregs, &outregs);
}
void set_bg_color(color_t c)
{
unsigned char far *vdo_buf = VIDEO_BUF_ADDR;
int x, y, scrn_w, scrn_h;
x = 0;
y = 0;
scrn_w = SCREEN_WIDTH;
scrn_h = SCREEN_HEIGHT;
for (x = 0; x < scrn_w; x++)
for (y = 0; y < scrn_h; y++)
vdo_buf[y * scrn_w + x] = c;
}
void gui_put_pixel_ex(int x, int y, color_t c)
{
unsigned char far *vdo_buf = VIDEO_BUF_ADDR;
vdo_buf[y * SCREEN_WIDTH + x] = c;
}
#elif defined(UNIX)
void gui_put_pixel_ex(int x, int y, color_t c)
{
/* unix 平台画点实现 */
}
#elif /* 其他平台 */
void gui_put_pixel_ex(int x, int y, color_t c)
{
/* 其他平台画点实现函数 */
}
#endif
/*
* 平台无关代码
*/
/* 交换a和b的值 */
typedef long color_t;
#define SWAP(a, b) do { a ^= b; b ^= a; a ^= b; } while (0)
void gui_bresenham_draw_line_ex(int x1, int y1, int x2, int y2, color_t c)
{
int b_steep = abs(y2 - y1) > abs(x2 - x1);
int dx, dy;
int error;
int x, y, y_step;
/* if abs(slope) > 1, swap x and y coordinates */
if (b_steep)
{
SWAP(x1, y1);
SWAP(x2, y2);
}
/* if draw line direction from right to left, reverse it */
if (x1 > x2)
{
SWAP(x1, x2);
SWAP(y1, y2);
}
dx = x2 - x1;
dy = abs(y2 - y1);
error = dx >> 1; /* dx / 2 */
y = y1;
/* determinate the inc in y-axis direction */
if (y1 < y2)
y_step = 1;
else
y_step = -1;
for (x = x1; x <= x2; x++)
{
if (b_steep)
gui_put_pixel_ex(y, x, c);
else
gui_put_pixel_ex(x, y, c);
error -= dy;
if (error < 0)
{
y += y_step;
error += dx;
}
}
}
/*
* 使用
*/
#include <conio.h>
int main(void)
{
/* 设置视频模式为VGA 256色 */
set_video_mode(VIDEO_MODE_VGA256);
/* 设置背景色为白色 */
set_bg_color(255);
/* 画线: 借用conio.h中的枚举值enum COLORS(实际的颜色值为[0, 255]) */
gui_bresenham_draw_line_ex(200, 20, 14, 143, LIGHTMAGENTA);
gui_bresenham_draw_line_ex(17, 14, 234, 156, RED);
getch();
set_video_mode(VIDEO_MODE_TEXT); /* 恢复视频模式为文本模式 */
return 0;
}