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();
}

posted on 2012-11-15 23:43  xiaofei01gm  阅读(1146)  评论(0编辑  收藏  举报