opengl 区域填充之种子填充线扫描法
青岚影视 www.qldyy.net
在事先画好的一个区域内,使用区域填充之种子填充线扫描法将其填充完毕。同时带有鼠标和键盘事件,并添加了菜单。对于存在的改变窗口大小程序会出现问题还没有很好的解决,只是仅仅将窗口大小固定住了,不能随意改变大小。不对的地方,还请大家多多指正,希望与大家多交流哦。
#include <GL/glut.h>
#include <stdio.h>
//#include <conio.h>
//#include <dos.h>
#include <windows.h>
const int length = 3;
const int coord = 2;
const int num = 10;
int stack_top;
int stack[10000];
int fill = 0; /* fill flag */
// 长宽比受到限制,就现在而言只能是宽要大于长,原因有两个,
//一个为(画点)原点位置不正确,另一个是围城区域的线条宽度太小
int Wheight = 200;
int Wwidth = 200;
int control = 0;
typedef float Color[length];
typedef int POI[coord];
Color newColor = {1.0f, 1.0f, 0};
// 背景颜色
Color oldColor = {1.0f, 0, 0};
// 函数调用前至少要先声明,或者直接定义到掉用地之前
int stackPop()
{
int val;
val = stack[stack_top];
stack_top = stack_top-1;
return val;
}
void stackPush(int p_xy)
{
stack_top += 1;
stack[stack_top] = p_xy;
}
int isStackEmpty()
{
if(stack_top>0)
return 1;
else
return 0;
}
void setStackEmpty()
{
int i;
for(i=0; i<=stack_top; i++)
stack[i]=0;
stack_top=0;
}
//画点函数
void setPixel(float x, float y, Color color)
{
glBegin(GL_POINTS);
glColor3f(color[0], color[1], color[2]);
glVertex2f(x, y);
glEnd();
}
//颜色判定函数,颜色相同的话返回1,不相同的话则返回0
int judgeColor(float x, float y, Color color)
{
Color tmp;
int res = 1;
glReadPixels(x, y, 1, 1, GL_RGB, GL_FLOAT, tmp);
for (int i = 0; i < length; i++)
{
if(color[i] != tmp[i])
{
res = 0;
//printf("%f,%f",x,y);
}
}
return res;
}
// 填充函数(从最下侧向上填充)
void floodFill(int x, int y, Color newColor, Color oldColor, int dir){
int xl, xr, x0, xnextspan;
bool spanNeedFill;
//将栈清空
setStackEmpty();
//种子入栈
stackPush(x);
stackPush(y);
while(isStackEmpty() != 0)
{
//栈顶出栈,注意出栈顺序
y = stackPop();
x = stackPop();
//printf("nihao1");
setPixel(x, y, newColor);
x0 = x+1;
while(judgeColor(x0,y,oldColor) == 1) //向右填充
{
//printf("nihao2");
setPixel(x0,y,newColor);
x0++;
}
xr = x0-1; //最右元素
x0 = x-1; //恢复到起始元素
while(judgeColor(x0,y,oldColor) == 1) //向左填充
{
setPixel(x0, y, newColor);
x0--;
}
xl=x0+1; //最左元素
//处理下面一条扫描线
x0=xl;
y=y+dir;
if (isStackEmpty() == 0)
{
}
// 从最左到最右均无oldColor元素将不再压栈
while (x0<=xr)
{
spanNeedFill=FALSE;
while (judgeColor(x0,y,oldColor) == 1)
{
if (spanNeedFill==FALSE)
spanNeedFill=TRUE;
x0++;
}
// 将元素压栈
if(spanNeedFill)
{
if (x0==xr)
{
stackPush(x0);
stackPush(y);
}
else
{
stackPush(x0-1);
stackPush(y);
}
spanNeedFill=FALSE;
}
xnextspan=x0;
// 立即跳出循环
while(judgeColor(x0,y,oldColor)!=1 && x0<xr) x0++;
// 如果是最边上的
if (xnextspan==x0)
x0++;
}
}
}
void drawLine()
{
glBegin(GL_LINE_LOOP);
glVertex2i(130, 130);
glVertex2i(60, 130);
glVertex2i(60, 10);
glVertex2i(130, 10);
glEnd();
glFlush();
}
// 界面刷新
void refresh()
{
glClearColor(1.0, 0.0, 0.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT);
glFlush();
drawLine();
}
void myDisplay(void)
{
glClearColor(1.0, 0.0, 0.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT);
// 单色方式
glShadeModel(GL_FLAT);
// 设置点的大小
//glPointSize(100.0f);
// 设置视口
//glViewport(1.0f, 1.0f, 600, 400);
glOrtho(-0.5f, Wwidth, -0.5f, Wheight, -200, 200);
// 设置点的颜色
glColor3f(0.0, 1.0f, 0.0f);
glLineWidth(2);
//glBegin(GL_POINTS);
// 绘制“点”的原点是在窗口正中间
drawLine();
//glPopAttrib();
}
// 鼠标左键事件
void mouse(int btn, int state, int x, int y)
{
// x,y为窗口左上角为原点的鼠标位置
if(btn==GLUT_LEFT_BUTTON && state==GLUT_DOWN)
{
floodFill(x, Wheight-y, newColor, oldColor, 1);
floodFill(x, Wheight-y, newColor, oldColor, -1);
printf("开始填充");
//printf("%d,\t%d",x,y);
}
}
// 鼠标右键事件
void right_menu(int id)
{
if(id == 2) exit(0);
else if (id == 0)
{
floodFill(61, 129, newColor, oldColor, -1);
printf("开始绘制");
}
else{
// myDisplay();
refresh();
}
}
// 键盘事件
void keyboard(unsigned char key, int x, int y)
{
switch (key) {
case 27:
// Esc键退出
exit(0);
break;
default:
break;
}
}
/*
//换算比例
void changeSize(int w, int h) {
// 防止除数即高度为0
// (你可以设置窗口宽度为0).
if(h == 0)
h = 1;
float ratio = 1.0* w / h;
// 单位化投影矩阵。
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
// 设置视口大小为增个窗口大小
glViewport(0, 0, w, h);
// 设置正确的投影矩阵
gluPerspective(45,ratio,1,1000);
//下面是设置模型视图矩阵
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0.0,0.0,5.0, 0.0,0.0,-1.0,0.0f,1.0f,0.0f);
}*/
void main()
{
int f_menu;
int gMainHandle;
glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);
glutInitWindowSize(Wwidth, Wheight);
glutInitWindowPosition(100, 150);
gMainHandle = glutCreateWindow("Seed Fill");
glutSetWindow(gMainHandle);
HWND hwnd = FindWindow(NULL,"Seed Fill");
if( hwnd )
{
LONG style;
style = GetWindowLong(hwnd,GWL_STYLE);
style &= ~WS_THICKFRAME;
SetWindowLong(hwnd,GWL_STYLE,style);
}
f_menu = glutCreateMenu(right_menu);
glutAddMenuEntry("开始",0);
glutAddMenuEntry("清空",1);
glutAddMenuEntry("退出",2);
glutAttachMenu(GLUT_RIGHT_BUTTON);
glutMouseFunc(mouse);
glutKeyboardFunc(keyboard);
glutDisplayFunc(&myDisplay);
//换算比例
//glutReshapeFunc(NULL);
glutMainLoop();
}