計算機圖形學OpenGL學習實驗一

  • 寫在開頭:

相關實驗是學校開設課程的相關實驗,本人所作較爲粗淺,若有同校師弟瀏覽,望看懂借鑑而非照搬全抄。


  • 實驗目的:

利用鼠標、鍵盤,菜單等方式對圖元進行交互操作


  • 實驗內容:

1、用鼠標拖動畫直線,線段終點始終跟隨鼠標移動;

2、使用菜單界面修改直線的顏色;

3、利用鍵盤控制直線在屏幕上移動;


  • 實現效果及步驟(或流程)

實現效果:

1.鼠標左鍵選取直線,通過鍵盤的方向鍵對直線進行移動

2.繪製折線,鼠標右鍵開始折線繪製,單擊鍵盤Q鍵,結束本次繪製

3.鼠標中鍵彈出菜單按鈕,選擇顏色對直線進行修改

實現步驟:


  • 相關功能實現方法
  1. 繪製折線

相關代碼在方法mousePlot、drawLines、quitLinePlot中

#include <GL/glut.h>
#include <vector>
#include <iostream>

void mouseMovePtPlot(GLint xMouse, GLint yMouse);
GLsizei winWidth = 400, winHeight = 300;
GLint point[2][2];
bool ptCtr = true;
bool lineCtr = false;
GLenum fillMode = GL_SMOOTH;  // Initial polygon fill: color interpolation.
float color[1][3] = {0.0,0.0,0.0};

int tag;//記錄選取的點在數組中的位置

std::vector<GLint> points;//用於存儲線段


void init(void) {
	glClearColor(1.0, 1.0, 1.0, 1.0);
	glClear(GL_COLOR_BUFFER_BIT);
	glMatrixMode(GL_PROJECTION);
	gluOrtho2D(0.0, 200.0, 0.0, 150.0);
}

void displayFcn() {

	glColor3f(0.0, 0.0, 0.0);
	glPointSize(3.0);

}

//繪製已保存的線段
void drawLines() {

	int length = points.size();
	glColor3fv(color[0]);
	glBegin(GL_LINES);
		for (GLint i = 0; i <length - 3 ; i+=2) {
			if (points[i + 2] == points[i] && points[i + 3] == points[i + 1]) {
				i += 2;//跳過下一個點
				std::cout << "斷點(" << points[i] << "," << points[i + 1] << ") " << std::endl;
				continue;
			}
			glVertex2i(points[i], points[i+1]);
			glVertex2i(points[i+2], points[i + 3]);
		}
		glVertex2i(points[length - 2], points[length - 1]);
		glVertex2iv(point[1]);//該點是鼠標移動過程中的點,是一個暫時的點,鼠標右鍵擡起時纔會保存

		glEnd();
}

void drawChangedLines() {
	glClear(GL_COLOR_BUFFER_BIT);
	int length = points.size();
	glColor3fv(color[0]);
	glBegin(GL_LINES);
	for (GLint i = 0; i < length - 3; i += 2) {
		if (points[i + 2] == points[i] && points[i + 3] == points[i + 1]) {
			i += 2;//跳過下一個點
			std::cout << "斷點(" << points[i] << "," << points[i + 1] << ") " << std::endl;
			continue;
		}
		glVertex2i(points[i], points[i + 1]);
		glVertex2i(points[i + 2], points[i + 3]);
	}
	glEnd();
	glFlush();
}

void winReshapeFcn(GLint newWidth, GLint newHeight) {
	glViewport(0, 0, newWidth, newHeight);
	glLoadIdentity();
	gluOrtho2D(0.0, GLdouble(newWidth), 0.0, GLdouble(newHeight));

	winWidth = newWidth;
	winHeight = newHeight;
}


//退出折線繪製
void quitLinePlot(GLubyte curvePlotKey, GLint xMouse, GLint yMouse)
{
	GLint x = xMouse;
	GLint y = winHeight - yMouse;
	switch (curvePlotKey)
	{
	case 'q':
		ptCtr = true;
		points.push_back(point[1][0]);
		points.push_back(point[1][1]);
		break;
	default:
		break;
	}
	glFlush();
}


void mouseMoveLinePlot(GLint xMouse, GLint yMouse) {
	if (lineCtr) {
		glClear(GL_COLOR_BUFFER_BIT);
		point[1][0] = xMouse;
		point[1][1] = winHeight - yMouse;

		drawLines();
		//plotLine(point);

		glFlush();
	}
	
	

}

//鼠標事件回調函數
void mousePlot(GLint button, GLint action, GLint xMouse, GLint yMouse) {
	//獲得起始點座標
	if (button == GLUT_LEFT_BUTTON && action == GLUT_DOWN)
	{
		if (points.size() != 0) {
			GLint x = xMouse;
			GLint y = winHeight - yMouse;
			for (GLint i = 0; i < points.size() - 3; i += 2) {
				if (points[i + 2] == points[i] && points[i + 3] == points[i + 1]) {
					i += 2;//跳過下一個點
					std::cout << "斷點(" << points[i] << "," << points[i + 1] << ") " << std::endl;
					continue;
				}
				GLint x1, y1, x2, y2;
				x1 = points[i];
				y1 = points[i + 1];
				x2 = points[i + 2];
				y2 = points[i + 3];
				int k = x2 * y - x1 * y - y2 * x + y1 * x - x2 * y1 + x1 * y2;
				if (k + 1000 > 0 && k - 1000 < 0) {
					tag = i;
				}
			}
		}
		
	}
	else if (button == GLUT_RIGHT_BUTTON && action == GLUT_DOWN) {
		lineCtr = true;
		if (ptCtr) {
			point[0][0] = xMouse;
			point[0][1] = winHeight - yMouse;
			glutMotionFunc(mouseMoveLinePlot);
			points.push_back(point[0][0]);
			points.push_back(point[0][1]);
			ptCtr = false;
		}else {
			point[1][0] = xMouse;
			point[1][1] = winHeight - yMouse;
			glutMotionFunc(mouseMoveLinePlot);
		}
	}
	else if (button == GLUT_RIGHT_BUTTON && action == GLUT_UP) {
		
		point[0][0] = point[1][0];
		point[0][1] = point[1][1];
		std::cout << "線段終點(" << point[0][0]<< "," << point[0][1] << ") " << std::endl;
		points.push_back(point[1][0]);
		points.push_back(point[1][1]);
		for (int i = 0; i < points.size() - 1; i+=2) {
			std::cout << "(" << points[i] << "," << points[i+1] << ") ";
		}
		std::cout << std::endl;
		lineCtr = false;
	}
}

//菜單事件回調函數
void colorOption(GLint selectedOption)
{
	switch (selectedOption) {
	case 1:  
		color[0][0] = 1.0;
		color[0][1] = color[0][2] = 0.0;
		break;
	case 2:  
		color[0][1] = 1.0;
		color[0][0] = color[0][2] = 0.0;
		break;
	case 3:
		color[0][2] = 1.0;
		color[0][0] = color[0][1] = 0.0;
		break;
	default:
		break;
	}
	drawChangedLines();
}

//特殊鍵位移動直線
void moveLine(GLint reductionKey, GLint xMouse, GLint yMouse)
{
	switch (reductionKey)
	{
	case GLUT_KEY_UP:
		points[tag + 1] += 20;
		points[tag + 3] += 20;
		drawChangedLines();
		break;
	case GLUT_KEY_DOWN:
		points[tag + 1] -= 20;
		points[tag + 3] -= 20;
		drawChangedLines();
		break;
	case GLUT_KEY_LEFT:
		points[tag] -= 20;
		points[tag + 2] -= 20;
		drawChangedLines();
		break;
	case GLUT_KEY_RIGHT:
		points[tag] += 20;
		points[tag + 2] += 20;
		drawChangedLines();
		break;
	default:
		break;
	}
}


void main(int argc, char ** argv) {
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
	glutInitWindowPosition(100, 100);
	glutInitWindowSize(winWidth, winHeight);
	glutCreateWindow("CGLab2_CAIYIPEI");

	init();

	glutDisplayFunc(displayFcn);
	glutReshapeFunc(winReshapeFcn);
	glutMouseFunc(mousePlot);
	glutKeyboardFunc(quitLinePlot);
	glutCreateMenu(colorOption);              // Create pop-up menu.
		glutAddMenuEntry("RED", 1);
		glutAddMenuEntry("GREEN", 2);
		glutAddMenuEntry("BLUE", 3);

	glutSpecialFunc(moveLine);
	/*  Select a menu option using the right mouse button.  */
	glutAttachMenu(GLUT_MIDDLE_BUTTON);

	glutMainLoop();
}

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章