Details of OpenGL scanline filling algorithm

  • 2020-07-21 09:22:19
  • OfStack

The example of this paper shares OpenGL scanline filling algorithm for your reference, the specific content is as follows

instructions

The latest 1 series of classical graphics algorithms to achieve 1. The derivation of this series will be written later. But it has been fully analyzed in the notes.

Case discussion

Note that we need to discuss horizontal lines in particular, but not vertical lines in particular. Think 1 Think why?

code


#include <iostream>
#include <GLUT/GLUT.h>
#include <map>
#include <vector>
#include <list>
#include <algorithm>
using namespace std;
int hmin,hmax;     // Record where the scan line begins and ends 
struct Line {     // Defines the structure of a line segment 
 float dx,x,y,ym;    // Don't have to record K Direct recording dx and x Can be 
 Line(float x1,float y1,float x2,float y2) {
 if(y1==y2){    // Let's talk about horizontal lines separately 
  this->y = y1;
  this->ym = y1;
  if(x1 < x2){
  dx = x1; x = x2;
  }else{
  dx =x2;x = x1;}
 }else if(y2<y1){   // Choose those who depend on you x value 
  this -> x = x2;   // Top of record x value 1 Convenient for handling critical moments (for insertion AET Sort) 
  this ->y = y2;   // Top of record y Value for sorting 
  this -> ym = y1;   // By nobody ym
 }else{
  this -> x = x1;
  this ->y = y1;
  this -> ym = y2;
 }
 dx = (x2-x1)/(y2-y1);
 }
};
typedef list<Line> TESTLIST;
vector<vector<Line>> con; // Keep a list of important events (in order), but this can also use priority queues 
list<Line> AET;   // Scroll through the active side table , There will be 
      // The edge table full storage is of little significance so the scroll storage method is adopted 
map<int, int> mapper;  // For data ( y Value) discretization 
int x1,y1,x2,y2;   // Describe the two ends that make up the line 
int x0,y0;    // Record the starting position of the graph 
float h_min,h_max;  // Draw the beginning and end of the line 
int flag = 1;    // It is used to record the number of times the user clicks, draw a point once and draw a line twice. 
int if_drawable = 1;  // The user does not change the information when he clicks the mouse again 
int window_size=600;  // This is the size of our display interface 
vector<vector<Line>> con2;
int level = 1;
/*
  Operating instructions: The algorithm does not have strict graphics rendering inspection. Just for a graphical algorithm demonstration. 
  You use the left mouse button to draw points. Please make sure that no lines are crossed. 
  When you click the right mouse button to draw the last 1 A point. The system will automatically connect it to the starting point. 
  Overall idea description: use map will y Is discretized and the "key events" are recorded in an ordered table 
  Is to add edges ( 1 Delete edge operation. In the use 1 Five scrollable active edge tables are traversed to draw lines. 
 */
void show_v(Line a){
 /*
  Function description: display point information 
 */
 cout << "(" <<a.x << "," << a.y <<")";
 cout << " (" <<a.dx<<")" << " The lower limit: "<<a.ym;
 cout << " -- "<<endl;
}
bool higher(const vector<Line> & l1, const vector<Line>& l2) {
 // Will be in the key events table line In accordance with the y Values are sorted; 
 // Notice that our canvas is incrementing from top to bottom from left to right 
 return l1[0].y < l2[0].y;// Can guarantee 1 Set at least 1 An otherwise map Does not map to 
}
bool AET_lefter(const Line & l1, const Line & l2) {
 // will AET In the table line In accordance with the x Values are sorted; 
 return l1.x < l2.x;// Can guarantee 1 Set at least 1 An otherwise map Does not map to 
}
bool lefter(const Line & l1, const Line & l2) {
 /*
  Function description: put the key events in the table line In accordance with the x Values, and dx Sort; 
 */
 if(l1.x < l2.x){
 return 1;
 }else if (l1.x == l2.x){
 if(l1.dx<0&&l2.dx>0)
  return 1;
 else
  return 0;
 }else
 return 0;
}
void sort_con(){
 /*
  Function description: key event table for sorting processing 
  Among them y From small to large, x The direction is the sum of the slopes x Sort size from left to right 
 */
 for (int i = 0 ; i < con.size(); i++)
 if (con[i].size()>=2)
  sort(con[i].begin(),con[i].end(),lefter);
 for (int i = 0;i < con.size(); i++) {
 vector<Line> a;
 for (int j =0; j < con[i].size(); j++)
  a.push_back(con[i][j]);
 con2.push_back(a);   // Copy the event table here, and 1 One way is to take map The mapping corresponds to the change 
 }
 sort(con.begin(), con.end(), higher);
}
void draw_lines(float x1,float y1,float x2,float y2){
 glBegin(GL_LINES);
 glColor3f(1.0,1.0,0.0);
 glVertex2f(x1,window_size-y1);
 glVertex2f(x2,window_size-y2);
 glEnd();
 glFlush();
}
void show_con(){
 // Output the sorted table of key events 
 for (int i = 0; i < con.size(); i++) {
 cout <<"number : "<<i <<endl;
 for (int j = 0; j < con[i].size(); j++) {
  vector<Line> a = con[i];
  show_v (a[j]);
 }cout <<"================"<<endl;
 }
}
void lines_filling(){    // The actual scanline filling process 
 if (con.empty())    // To show the details of the process, some functions do not use functions ti
 return;
 int h_leveler = 0;    // Height ergoer 
 map<int,int>::iterator iter;  // define 1 Multiple iteration pointer iter
 for(h_leveler = h_min;h_leveler <= h_max;h_leveler++){// Start scanning 
 int id = mapper[h_leveler];
 if (!id) {     // It indicates that the key node has not been reached, so we only need to draw and update. 
  float xx = 0.0; flag = 1; //flag Used to control every two groups of paintings 1 The time line 
  for(list<Line> ::iterator it=AET.begin();it!=AET.end();)
  { if (flag%2==0) {  // It's time to draw a line! 
   draw_lines(xx, h_leveler,it->x,h_leveler);
   for (TESTLIST::iterator pl = AET.begin(); pl != AET.end();)
   if (pl->ym == h_leveler)
    AET.erase(pl++);
   else
    pl++;  // This one is responsible for deleting for The loop executes after the line is drawn to avoid white space 
   it->x = it->x +it->dx;
  }else{
   if (it->y == it->ym) {
   xx = x1;
   }else{
   xx =it->x;
   it->x = it->x +it->dx;
   }
  }flag++;it++;}
 }else{     // If there is a critical event, then wire and unwire 
  list<Line> ::iterator it;
  float xx = 0.0;int counter = 1;
  for(it=AET.begin();it!=AET.end();it++)
  { Line temp= *it;
  if (counter%2==0)  // It's time to draw a line! 
   draw_lines(xx, h_leveler,temp.x,h_leveler);
  else
   xx =temp.x;   // Draw a line to avoid white space before deleting an edge 
  counter++;
  }
  for (TESTLIST::iterator it = AET.begin(); it != AET.end();)
  if (it->ym == h_leveler)
   AET.erase(it++);
  else
   it++;    // Key time to remove edges 
  for (int i =0 ; i < con2[id-1].size(); i++)
  if (con2[id-1][i].y == con2[id-1][i].ym)
   continue;   // If it's a horizontal line you don't have to add the horizontal line 
  else
   AET.push_back(con2[id-1][i]);
  AET.sort(AET_lefter);  // Maintains the order of the scrolling active edge tables 
 }}}
void InitEnvironment()   // Initialize the environment 
{ glClearColor(0.0,0.0,0.0,0);
 glClear(GL_COLOR_BUFFER_BIT);
 glPointSize(7);
 glMatrixMode(GL_MODELVIEW);
 glLoadIdentity();
 gluOrtho2D(0,window_size,0,window_size);
}
void myDisplay(void)
{ glClear(GL_COLOR_BUFFER_BIT);
 glFlush();
}
void OnMouse(int button,int state,int x,int y)
/*
  Function description: to perform user interaction operations 
  Every two points 1 Groups perform operations. Set left and right hand gestures 
 */
{if(button==GLUT_LEFT_BUTTON&&state==GLUT_DOWN&&if_drawable)
 {if (flag ==1 &&if_drawable) {
  glColor3f(1,0,0);
  glBegin(GL_POINTS);
  glVertex2f(x,window_size-y);
  x0 = x;y0 =y;
  x1 = x;y1 = y;
  h_min = y0;
  h_max = y0;
  glEnd();
  glFlush();
  flag++;
 }else{
  glColor3f(1,0,0);
  glBegin(GL_POINTS);
  glVertex2f(x,window_size-y);
  glEnd();
  x2 = x;y2 = y;
  glBegin(GL_LINES);
  glColor3f(1.0,0.0,0.0);
  glVertex2f(x1,window_size-y1);
  glVertex2f(x2,window_size-y2);
  if (y1 !=y2) {
  Line a(x1,y1,x2,y2);
  int r_y = min (y1,y2);
  if (y1 < h_min)
   h_min = y1;
  if (y2 < h_min)
   h_min = y2;
  if (y1 > h_max)
   h_max = y1;
  if (y2 >h_max)
   h_max = y2;
  int pos = mapper[r_y];
  if (pos==0) {  // This indicates that the variable has not been discretized 
  mapper[r_y] = level++;
  vector<Line> lines;
  lines.push_back(a);
  con.push_back(lines);}
  else
  con[pos-1].push_back(a);
  }
  x1 = x2; y1 = y2;
  glEnd();
  glFlush();
 }
 }
 if(button==GLUT_RIGHT_BUTTON&&state==GLUT_DOWN&&if_drawable)
 { // Click on the right 
 glColor3f(1,0,0);
 glBegin(GL_POINTS);
 glVertex2f(x,window_size-y);
 glEnd();
 x2 = x;y2 = y;
 glBegin(GL_LINES);
 glColor3f(1.0,0.0,0.0);
 glVertex2f(x1,window_size-y1);
 glVertex2f(x2,window_size-y2);
 Line a(x1,y1,x2,y2);
 int r_y = min (y1,y2);
 int pos = mapper[r_y];
 if (pos==0) {  // This indicates that the variable has not been discretized 
  mapper[r_y] = level++;
  vector<Line> lines;
  lines.push_back(a);
  con.push_back(lines);}
 else
  con[pos-1].push_back(a);
 glEnd();
 glFlush();
 glBegin(GL_LINES);
 glColor3f(1.0,0.0,0.0);
 glVertex2f(x0,window_size-y0);
 glVertex2f(x2,window_size-y2);
 glEnd();
 glFlush();
 Line aa(x0,y0,x2,y2);
 r_y = min (y0,y2);
 pos = mapper[r_y];
 if (pos==0) {  // This indicates that the variable has not been discretized 
  mapper[r_y] = level++;
  vector<Line> lines;
  lines.push_back(aa);
  con.push_back(lines);}
 else
  con[pos-1].push_back(aa);
 sort_con();
 lines_filling();
 if_drawable = 0;
 }
}

int main(int argc, char *argv[])
{ glutInit(&argc, argv); // Initialize the GLUT
 glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);
 glutInitWindowPosition(300, 100);
 glutInitWindowSize(window_size, window_size);
 glutCreateWindow("hw2_filling_line");
 InitEnvironment(); // Initialize the 
 glutMouseFunc(&OnMouse); // Register mouse events 
 glutDisplayFunc(&myDisplay); // The callback function 
 glutMainLoop(); // Continues to display, when the window changes will redraw the graph 
 return 0;
}

Related articles: