图形学实验(1)--OpenGL 入门

OpenGL vs2019环境配置

OpenGL vs2019环境配置
注意每次新开项目都要 在“项目”中,选择“管理NuGet程序包”,并在浏览中搜索“nupengl",两个都要安装。

实验内容熟悉:显示一个茶壶

关于glNewList() OpenGL显示列表
OpenGL glViewport()函数

#include <stdlib.h>
#include <GL/glut.h>

void init();
void display();
void reshape(GLsizei , GLsizei );

int main(int argc, char** argv) {

	//初始化工具包
	glutInit(&argc, argv);

	//设置显示模式
	  //GLUT_SINGLE 设置为单缓存,一般是渲染一张图片,如果是动画的话就需要双缓存
	  //GLUT_RGB设置颜色模式
	  //GLUT_DEPTH设置景深模式	
	glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH);
	
	//设置窗口属性
	  //设置窗口在屏幕上位置
	glutInitWindowPosition(0, 0);
	  //设置窗口大小
	glutInitWindowSize(500, 500);
	  //打开屏幕窗口
	glutCreateWindow("My first test");

	//调用绘图函数,回调函数,不间断监听
	glutReshapeFunc(reshape);
	glutDisplayFunc(display);

	init();//必要的其他初始化函数
	glutMainLoop();//进入循环

	return 0;
}

//初始化函数
void init() {

	glEnable(GL_DEPTH_TEST);// 用来开启更新深度缓冲区的功能,也就是,如果通过比较后深度值发生变化了,会进行更新深度缓冲区的操作。启动它,OpenGL就可以跟踪再Z轴上的像素,这样,它只会再那个像素前方没有东西时,才会绘画这个像素。	在做绘画3D时,这个功能最好启动,视觉效果比较真实。

	//光照系统
	 //设置一组位置信息,作为光源位置,前三个参数是xyz坐标,最后一个设为0是设定在无限远处,1则在屏幕前
	GLfloat posistion[] = { 1.0,1.0,1.0,0.0 };
	 //设置光源属性 光照系统有8个光源,这里采用的是0号光源GL_LIGHT0
	 //属性光源位置 GL_POSITION(可以替换成别的属性),传入position;
	glLightfv(GL_LIGHT0, GL_POSITION, posistion);//这两行相当于设置了一个太阳光
	//开启光照模式
	glEnable(GL_LIGHTING);
	//开启0号光源
	glEnable(GL_LIGHT0);

	//材质
	GLfloat ambient[] = { 0.0,0.0,0.0,1.0 };
	GLfloat diffuse[] = { 0.95,0.05,0.95,1.0 };
	GLfloat specular[] = { 1.0,1.0,1.0,1.0 };
	glMaterialfv(GL_FRONT, GL_AMBIENT, ambient);//环境反射
	glMaterialfv(GL_FRONT, GL_DIFFUSE, diffuse);//漫反射
	glMaterialfv(GL_FRONT, GL_SPECULAR, specular);//镜面反射
	glMaterialf(GL_FRONT, GL_SHININESS, 50.0);//镜面反射率,控制光斑大小


}

void display() {
	//glClearColor函数设置好清除颜色,即设定背景色
	glClearColor(0.75f, 0.75f, 0.75f, 1.0f);
	//glClear利用glClearColor函数设置好的当前清除颜色设置窗口颜色,即启动背景色
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	//你需要在glNewList()和glEndList()块之间存储OpenGL命令到显示列表中来优先渲染。这个过程叫做编译。glNewList()需要两个参数,第一个参数是glGenLists()函数返回的索引值,第二个参数是指定模式:是只编译还是编译并执行,GL_COMPLILE,GL_COMPLILE_AND_EXECUTE。
	 // 编译一个显示列表,存储一个茶壶
	glNewList(1, GL_COMPILE);
	  //绘制茶壶
    glutSolidTeapot(0.5);//void glutWireTeapot(GLdouble size);
	glEndList();
	 //绘制显示列表
	glCallList(1);

	//gLFlush()作用是将前面写入缓冲区中的指令(无论是否为满)立刻送给图形硬件执行,发送完立即返回;
	glFlush();

}

void reshape(GLsizei w, GLsizei h) {

	//当更改窗口大小时,可使视口会进行相应变换
	glViewport(0, 0, w, h);//w ,h 在设置窗口大小的的时候会传到这里

	//将3d坐标投影成2d坐标
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();

	//裁剪视口(x min,x max,y min,y max,z min,z max),默认茶壶是初始化在(0,0,0)
	glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);

	//将当前所选中的模型视图矩阵置为单位矩阵,即抛弃之前的更改
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();

}

茶壶

图形的绘制和图元的生成算法

理解glut程序框架

  • 绘制简单图形
#include <GL/glut.h>

void display();

int main(int argc ,char* argv[]) {
	//初始化工具包
	glutInit(&argc, argv);
	//设置显示模式
	glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);
	//设置窗口属性
	glutInitWindowPosition(100, 100);
	glutInitWindowSize(400, 400);
	glutCreateWindow("1812030065 李诗雨");
	//调用绘图函数
	glutDisplayFunc(display);
	//进入循环
	glutMainLoop();
	return 0;
}

void display() {
	//设定背景色,并把背景色设置为窗口颜色
	glClearColor(0.0, 0.0, 0.0, 0.0);
	glClear(GL_COLOR_BUFFER_BIT);
	//绘制图元
	glColor3f(1.0f, 1.0f, 1.0f);//选取一个颜色,3个参数3f,RGB
	glRectf(-0.5f, -0.5f, 0.5f, 0.5f);//用前面设定好的颜色绘制一个矩形,用的是斜率>0的对角线的顶点坐标
	//不裁剪窗口的话,屏幕的坐标位于窗口中心,0.5指占百分比,从坐标中心到窗口边界的距离百分比为1
	
	//绘制三角形
	glBegin(GL_TRIANGLES);
	glColor3f(1.0f, 0.0f, 0.0f); glVertex2f(0.0f, 1.0f);
	glColor3f(0.0f, 1.0f, 0.0f); glVertex2f(-0.8f, -0.5f);
	glColor3f(0.0f, 0.0f, 1.0f); glVertex2f(0.8f, -0.5f);
	glEnd();

	//绘制点
	glPointSize(3);//设置点的大小,范围是1-20,超过范围按极值处理
	glBegin(GL_POINTS);
	glColor3f(1.0f, 0.0f, 0.0f); glVertex2f(-0.4f, -0.4f);
	glColor3f(0.0f, 1.0f, 0.0f); glVertex2f(0.0f, 0.0f);
	glColor3f(0.0f, 0.0f, 1.0f); glVertex2f(0.4f, 0.4f);
	glEnd();

	//开始执行
	glFlush();
}

在这里插入图片描述
添加下面代码
不知道为啥我算出来的那个值看起来少了?用0.25效果还行

//double n = 0.4 * pow(3, 0.5) - 0.5;
	double n = 0.25;
	//绘制直线
	glPointSize(3);//设置点的大小,范围是1-20,超过范围按极值处理
	glBegin(GL_LINES);
	glColor3f(1.0f, 1.0f, 1.0f); glVertex2f(-0.4f, n);
	glColor3f(1.0f, 1.0f, 1.0f); glVertex2f(0.4f, n);
	glEnd();

	glBegin(GL_LINES);
	glColor3f(1.0f, 1.0f, 1.0f); glVertex2f(-0.4f, n);
	glColor3f(1.0f, 1.0f, 1.0f); glVertex2f(0.0f, -0.5f);
	glEnd();

	glBegin(GL_LINES);
	glColor3f(1.0f, 1.0f, 1.0f); glVertex2f(0.4f, n);
	glColor3f(1.0f, 1.0f, 1.0f); glVertex2f(0.0f, -0.5f);
	glEnd();

在这里插入图片描述
或者

//绘制直线
	glPointSize(3);//设置点的大小,范围是1-20,超过范围按极值处理
	glBegin(GL_LINE_LOOP);
	glColor3f(1.0f, 0.0f, 0.0f); glVertex2f(-0.4f, n);
	glColor3f(0.0f, 1.0f, 0.0f); glVertex2f(0.4f, n);
	glColor3f(0.0f, 0.0f, 1.0f); glVertex2f(0.0f, -0.5f);
	glEnd();

绘制封闭多边形,只有线
改一下前面三角的颜色(好吧是我电脑色差的问题)
在这里插入图片描述

绘制基本图形

多边形的绘制要从凹点开始绘制

#include <GL/glut.h>
void display();

int main(int argc, char* argv[]) {
	//初始化工具包
	glutInit(&argc, argv);
	//设置显示模式
	glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);
	//设置窗口属性
	glutInitWindowPosition(100, 100);
	glutInitWindowSize(400, 400);
	glutCreateWindow("1812030065 李诗雨");
	//调用绘图函数
	glutDisplayFunc(display);
	//进入循环
	glutMainLoop();
	return 0;
}

void display() {
	//设定背景色,并把背景色设置为窗口颜色
	glClearColor(0.0, 0.0, 0.0, 0.0);
	glClear(GL_COLOR_BUFFER_BIT);
	
	//绘制多边形图形
	//以凹点为起始开始绘制
	glBegin(GL_POLYGON);
	glColor3f(1.0f, 1.0f, 1.0f);
	glVertex2f(-0.22f, 0.0f);
	glVertex2f(-0.4f,0.3f);
	glVertex2f(-0.1f, 0.3f);
	glVertex2f(0.0f, 0.5f);
	glVertex2f(0.1f, 0.3);
	glVertex2f(0.4f, 0.3);
	glVertex2f(0.22f, 0.0f);
	glVertex2f(0.4f, -0.3);
	glVertex2f(0.1f, -0.3);
	glVertex2f(0.0f, -0.5f);
	glVertex2f(-0.1f, -0.3);
	glVertex2f(-0.4f, -0.3f);

	glEnd();

	//开始执行
	glFlush();
}

在这里插入图片描述

  • 添加颜色
#include <GL/glut.h>
void display();

int main(int argc, char* argv[]) {
	//初始化工具包
	glutInit(&argc, argv);
	//设置显示模式
	glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
	//设置窗口属性
	glutInitWindowPosition(100, 100);
	glutInitWindowSize(400, 400);
	glutCreateWindow("1812030065 李诗雨");
	//调用绘图函数
	glutDisplayFunc(display);
	//进入循环
	glutMainLoop();
	return 0;
}

void display() {
	//设定背景色,并把背景色设置为窗口颜色
	glClearColor(0.0, 0.0, 0.0, 0.0);
	glClear(GL_COLOR_BUFFER_BIT);

	//绘制填色多边形图形
	
	glBegin(GL_POLYGON);
	//先画中间的点
	glColor3ub(255, 255, 255); glVertex2f(0.0f, 0.0f);
	//以凹点为起始开始绘制
	glColor3ub(0,0,255);glVertex2f(-0.22f, 0.0f);
	glColor3ub(255,255,0);glVertex2f(-0.4f, 0.3f);
	glColor3ub(255,97,0 );glVertex2f(-0.1f, 0.3f);
	glColor3ub(176,224,230);glVertex2f(0.0f, 0.5f);
	glColor3ub(255,97,0 );glVertex2f(0.1f, 0.3);
	glColor3ub(0,255,0 );glVertex2f(0.4f, 0.3);
	glColor3ub(34,139,34 );glVertex2f(0.22f, 0.0f);
	glColor3ub(139,252,201);glVertex2f(0.4f, -0.3);
	glColor3ub(135, 38, 37);glVertex2f(0.1f, -0.3);
	glColor3ub(255,0,0);glVertex2f(0.0f, -0.5f);
	glColor3ub(240,230,140 );glVertex2f(-0.1f, -0.3);
	glColor3ub(0,0,255);glVertex2f(-0.4f, -0.3f);
	//回到起始点
	glColor3ub(0, 0, 255); glVertex2f(-0.22f, 0.0f);
	glEnd();
	/*glBegin(GL_POINT);
	glEnd();*/
	//开始执行
	glutSwapBuffers();
}

在这里插入图片描述
哈哈哈哈好丑

  • 问题:实验要求填色用双缓存区,我用了之后窗口变成白色
    解决:双缓存 用glutSwapBuffers();代替glFlush,这个函数的作用是交换两个缓冲区的内容,并把隐藏的渲染好的显示出来。

基本图元生成程序框架(画直线圆)

唉把这个写完是真的不容易
很多原本第一次看都难哭的东西,都看几遍至少都能看懂了,重要是耐心。

问题与解决

char key 这个不能用switch 用了之后,虽然没有报错但是这段代码以下都不能自动提示了。未弄清原因

void Keyboard(unsigned char key, int x, int y) {
	switch (key)
	{
	case'1': m_drawmode = 1; break;
	case'2': m_drawmode = 2; break;
	case'3': m_drawmode = 3; break;
	case'4': m_drawmode = 4; break;
	case'5': m_drawmode = 5; break;
	default:
		break;
	}
	m_pointnumber = 0;
	
	
}

这个n控制,真没看懂怎么回事,设置断点调试的时候跟直接运行结果不一样。具体可能是框架的原因吧,暂时先放这里。

	//对画线动画进行控制
	if (n == 1)
	{
		cout << "DDA算法:各点坐标\n";
	}
	else if(n==0)
	{
		return;
	}

还有这个也很迷,就是直线还挺好理解,放到圆那边就稍微有点晕,弄错了会出现一直闪的效果。

//绘制到比上一帧多一个像素点
		if (i >= n-1) {
			cout <<"n="<<n<< ", x=" << x << ", y=" << y << ", 取整后 x="
				<< (int)(x + 0.5) << ", y=" << (int)(y + 0.5) << endl << endl;
			break;
		}

程序

#include <windows.h>
#include <gl/glut.h>
#include <iostream>
using namespace std;
int m_pointnumber = 0;//动画时绘制点的数目
int m_drawmode = 1;//绘制模式
// 1 DDA算法画直线
// 2 中点Bresenham算法画直线
// 3 改进Bresenham算法画直线
// 4 八分法绘制圆
// 5 四分法绘制椭圆(选作)

//初始化窗口
void initial();
//窗口大小改变时调用的登记函数
void ChangeSize(GLsizei w, GLsizei h);
//设置键盘回调函数
void Keyboard(unsigned char key, int x, int y);
//设置时间回调函数
void TimerFunc(int value);
//在窗口中绘制图形
void Redraw();
//绘制坐标线
void DrawCordinateLine();
//绘制一个点,这里用一个正方形代表一个点
void PutPixel(GLsizei x, GLsizei y);
//参数说明:x0,y0 起始点
//         x1,y1 终止点
//         n 扫描转换时从起点开始输出的点的数目,用于动画
// 1 DDA算法画直线
void DDACreatLine(GLsizei x0, GLsizei y0, GLsizei x1, GLsizei y1, GLsizei n);
// 2 中点Bresenham算法画直线
void BresenhamLine(GLsizei x0, GLsizei y0, GLsizei x1, GLsizei y1, GLsizei n);
// 3 改进Bresenham算法画直线
void Bresenham2Line(GLsizei x0, GLsizei y0, GLsizei x1, GLsizei y1, GLsizei n);
//参数说明:x0,y0 圆心坐标
//         r 半径
//         n 扫描转换时从起点开始输出的点的数目,用于动画
// 4 八分法绘制圆
void BresenhamCircle(GLsizei x0, GLsizei y0, GLsizei r, GLsizei n);
// 5 四分法绘制椭圆(选作)
//参数说明:x0,y0 圆心坐标
//         a b 长半轴为a 短半轴为b
//         n 扫描转换时从起点开始输出的点的数目,用于动画
void BresenhamEllipse(GLsizei x0, GLsizei y0, GLsizei a, GLsizei b, GLsizei n);


int main(int argc, char* argv[]) {
	//初始化工具包
	glutInit(&argc, argv);
	//初始化显示模式和窗口属性
	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
	glutInitWindowPosition(100, 100);
	glutInitWindowSize(600, 600);
	glutCreateWindow("1812030065李诗雨 基本图元绘制程序");

	glutDisplayFunc(Redraw);
	glutReshapeFunc(ChangeSize);
	glutKeyboardFunc(Keyboard);//键盘响应回调函数
	glutTimerFunc(100, TimerFunc, 1);

	//窗口初始化
	initial();
	glutMainLoop();//启动主glut事件处理循环
	return 0;

}

void initial() {
	//设置清除色,并设置窗口背景色
	glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
	glClear(GL_COLOR_BUFFER_BIT);
}

void ChangeSize(GLsizei w, GLsizei h) {
	if (h == 0) h = 1;
	//设置视区
	glViewport(0, 0, w, h);
	//重置坐标系统
	glMatrixMode(GL_PROJECTION_MATRIX);
	glLoadIdentity();
	//建立修剪空间的范围
	if (w <= h)
		glOrtho(0.0f, 250.0f, 0.0f, 250.0f * h / w, 1.0f, -1.0f);
	else
		glOrtho(0.0f, 250.0f * w / h, 0.0f, 250.0f, 1.0f, -1.0f);
}

void Keyboard(unsigned char key, int x, int y) {
	if (key == '1') m_drawmode = 1;
	if (key == '2') m_drawmode = 2;
	if (key == '3') m_drawmode = 3;
	if (key == '4') m_drawmode = 4;
	if (key == '5') m_drawmode = 5;
	m_pointnumber = 0;
	cout << "nm_pointer 恢复为 0" << endl;
	glutPostRedisplay();
}

void TimerFunc(int value) {
	if (m_pointnumber == 0) value = 1;
	m_pointnumber = value;
	//用现有的参数重新绘图(即动画中新的一帧)
	glutPostRedisplay();
	//注意,该函数与其他的回调函数不一样的地方在于该函数只会被激发一次。为了实现连
	//续的动画,必须在定时器函数中再次重新设置定时器回调函数。
	glutTimerFunc(50, TimerFunc, value + 1);
}

void Redraw() {
	//用当前背景色填充窗口
	glClear(GL_COLOR_BUFFER_BIT);
	//画坐标线
	DrawCordinateLine();
	switch (m_drawmode)
	{
	case 1:DDACreatLine(0, 0, 20, 15, m_pointnumber); break;
	case 2:BresenhamLine(0, 20, 16, 0, m_pointnumber); break;
	case 3:Bresenham2Line(0, 20, 10, 0, m_pointnumber); break;
	case 4:BresenhamCircle(10,10,10, m_pointnumber); break;
	case 5:BresenhamEllipse(10, 10, 8 , 4, m_pointnumber); break;
	default:
		break;
	}
	glutSwapBuffers();
}

void DrawCordinateLine() {
	glColor3f(0.0f, 0.0f, 0.0f);//坐标线为黑色
	glBegin(GL_LINES);
	for (int i = 10; i <= 250; i += 10) {
		glVertex2f((float)i, 0.0f);
		glVertex2f((float)i, 250.0f);
		glVertex2f(0.0f, (float)i);
		glVertex2f(250.0f, (float)i);
	}
	glEnd();
}

void PutPixel(GLsizei x, GLsizei y) {
	//绘制矩形所在的坐标?
	glRectf(x * 10, y * 10, x * 10 + 10, y * 10 + 10);
}

void DDACreatLine(GLsizei x0, GLsizei y0, GLsizei x1, GLsizei y1, GLsizei n) {
	//设置颜色
	glColor3f(1.0f, 0.0f, 0.0f);
	//对画线动画进行控制
	if (n == 1)
	{
		cout << "DDA算法:各点坐标\n";
	}
	else if(n==0)
	{
		return;
	}
	//画线算法实现
	GLsizei dx, dy, epsl, i;
	GLfloat x, y, xincre, yincre;
	dx = x1 - x0;
	dy = y1 - y0;
	x = x0; y = y0;
	//通过epsl可以通过斜率绝对值确定是x还是y每次自增1
	if (abs(dx) > abs(dy)) epsl = abs(dx);
	else epsl = abs(dy);
	//x y 的增量 例如 xincre=1,yincre=k
	xincre = (float)dx / epsl;
	yincre = (float)dy / epsl;
	//epsl 的值是dx或dy(epsl+1)就决定了要画像素的数目
	for (i = 0; i <= epsl; i++) {
		PutPixel((int)(x + 0.5), (int)(y + 0.5));
		//绘制到比上一帧多一个像素点
		if (i >= n-1) {
			cout <<"n="<<n<< ", x=" << x << ", y=" << y << ", 取整后 x="
				<< (int)(x + 0.5) << ", y=" << (int)(y + 0.5) << endl << endl;
			break;
		}
		x += xincre;
		y += yincre;
		//超出窗口坐标
		if (x >= 25 || y >= 25) break;
	}	
}

void BresenhamLine(GLsizei x0, GLsizei y0, GLsizei x1, GLsizei y1, GLsizei n) {
	//设置颜色
	glColor3f(1.0f, 0.0f, 0.0f);
	if (n == 1)
	{
		cout << "中点BresenhamLine算法:各点坐标及判别式的值\n";
	}
	else if (n == 0) {
		return;
	}
	//画线算法实现
	GLsizei dx, dy;
	GLfloat x, y, d,xincre,yincre;
	dx = x1 - x0;
	dy = y1 - y0;
	x = x0; y = y0;
	//x y 的增量 
	xincre = (float)dx / abs(dx);
	yincre = (float)dy / abs(dy);
 	//x还是y每次自增1 画线参数不同	
		d = dx - 2 * min(abs(dx), abs(dy));
		//max(abs(dx), abs(dy)))就决定了要画像素的数目
		for (int i = 0; i <= max(abs(dx), abs(dy)); i++) {
			PutPixel(x, y);		
			if (d < 0) {//取Pu
				if (max(abs(dx), abs(dy)) == abs(dx)) {
					y += yincre;
				}
				else {
					x += xincre;
				}
				d = d + 2 * max(abs(dx), abs(dy)) - 2 * min(abs(dx), abs(dy));
			}
			else {//取pd
				d = d - 2 * min(abs(dx), abs(dy));
			}
			if (max(abs(dx), abs(dy)) == abs(dx)) {
				x += xincre;
			}
			else {
				y += yincre;
			}
			//绘制到比上一帧多一个像素点
			if (i >= n - 1) {
				cout << "n=" << n << ", x=" << x << ", y=" << y << ", 判别式 d="
					<< d << endl << endl;
				break;
			}
			//超出窗口坐标
			if (x >= 25 || y >= 25) break;
		}	
	
}

void Bresenham2Line(GLsizei x0, GLsizei y0, GLsizei x1, GLsizei y1, GLsizei n) {
	//设置颜色
	glColor3f(1.0f, 0.0f, 0.0f);
	if (n == 1)
	{
		cout << "BresenhamLine算法:各点坐标及判别式的值\n";
	}
	else if (n == 0) {
		return;
	}
	//画线算法实现
	GLsizei dx, dy;
	GLfloat x, y, e, xincre, yincre;
	dx = x1 - x0;
	dy = y1 - y0;
	x = x0; y = y0;
	//x y 的增量 
	xincre = (float)dx / abs(dx);
	yincre = (float)dy / abs(dy);
	//x还是y每次自增1 和 相关参数 取决于 dx 和 dy 的绝对值大小	
		e = -max(abs(dx), abs(dy));
		for (int i = 0; i <= max(abs(dx), abs(dy)); i++) {
			PutPixel(x, y);
			e += 2 * min(abs(dx), abs(dy));//这个判别式 是距离 都是正的
			if (e > 0) {
				e -= 2 * max(abs(dx), abs(dy));
				if (max(abs(dx), abs(dy)) == abs(dx)) {
					y += yincre;
				}
				else {
					x += xincre;
				}
			}
			if (max(abs(dx), abs(dy)) == abs(dx)) {
				x += xincre;
			}
			else {
				y += yincre;
			}
			//绘制到比上一帧多一个像素点
			if (i >= n) {
				cout << "n=" << n << ", x=" << x << ", y=" << y << ". 判别式 e="
					<< e << endl << endl;
				break;
			}
			//超出窗口坐标
			if (x >= 25 || y >= 25) break;
		}
}

void BresenhamCircle(GLsizei x0, GLsizei y0, GLsizei r,  GLsizei n) {
	//设置颜色
	glColor3f(1.0f, 0.0f, 0.0f);
	if (n == 1)
	{
		cout << "BresenhamLine算法画圆:各点坐标及判别式的值\n";
	}
	else if(n==0) {
		return;
	}
	GLsizei x, y, d, count;
	count = 0;
	x = 0; y = r; d = 1 - r;
	while (	x<=y)
	{
		PutPixel(x0 + x, y0 + y); PutPixel(x0 + y, y0 + x);
		PutPixel(x0 - y, y0 + x); PutPixel(x0 - x, y0 + y);
		PutPixel(x0 - x, y0 - y); PutPixel(x0 - y, y0 - x);
		PutPixel(x0 + y, y0 - x); PutPixel(x0 + x, y0 - y);
		count++;
		if (count >= n) {
			cout << "n=" << n << ", x=" << x << ", y=" << y << ". 判别式 d="
				<< d << endl << endl;
			break;
		}
		if (d < 0) {
			d += 2 * x + 3;
		}
		else {
			d += 2 * (x - y) + 5;
				y--;
		}
		x++;		
		
		//超出窗口坐标
		if (x >= 25 || y >= 25) break;
	}

}

void BresenhamEllipse(GLsizei x0, GLsizei y0, GLsizei a,  GLsizei b, GLsizei n) {
	//设置颜色
	glColor3f(1.0f, 0.0f, 0.0f);
	if (n == 1)
	{
		cout << "BresenhamLine算法画椭圆:各点坐标及判别式的值\n";
	}
	else if (n == 0) {
		return;
	}
	GLsizei x, y, count;
	GLfloat d1, d2;
	x = 0; y = b; count = 0;
	d1 = b * b + a * a * (-b + 0.25);

	while (b * b * (x + 1) <= a * a * (y - 0.5))
	{
		PutPixel(x0 + x, y0 + y); PutPixel(x0 - x, y0 - y);
		PutPixel(x0 - x, y0 + y); PutPixel(x0 + x, y0 - y);
		count++;
		if (count >= n) {
			cout << "n=" << n << ", x=" << x << ", y=" << y << ". 判别式 d1="
				<< d1 << endl << endl;
			break;
		}
		if (d1 <= 0) {
			d1 += b * b * (2 * x + 3);
			x++;
		}
		else
		{
			d1 += b * b * (2 * x + 3) + a * a * (-2 * y + 2);
			x++; y--;
		}
		
		//超出窗口坐标
		if (x >= 25 || y >= 25) break;		
	}
	if (b * b * (x + 1) >= a * a * (y - 0.5)) {
		d2 = b * b * (x + 0.5) * (x + 0.5) + a * a * (y - 1) * (y - 1) - a * a * b * b;
		while (y >= 0)
		{
			PutPixel(x0 + x, y0 + y); PutPixel(x0 - x, y0 - y);
			PutPixel(x0 - x, y0 + y); PutPixel(x0 + x, y0 - y);
			count++;
			if (count >= n) {
				cout << "n=" << n << ", x=" << x << ", y=" << y << ". 判别式 d2="
					<< d2 << endl << endl;
				break;
			}

			if (d2 <= 0)
			{
				d2 += b * b * (2 * x + 2) + a * a * (-2 * x + 3);
				x++; y--;
			}
			else {
				d2 += a * a * (-2 * x + 3);
				y--;
			}
			//超出窗口坐标
			if (x >= 25 || y >= 25) break;
		}
	}
	
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

反走样

原来 changesize的函数不是通用啊。。。。

#include <windows.h>
#include <gl/glut.h>
#include <iostream>
using namespace std;
//指定显示列表
GLuint lineList;
//初始化窗口
void initial();
//窗口大小改变时调用的登记函数
void ChangeSize(GLsizei w, GLsizei h);

void Displayt();
void Displayw();

int main(int argc, char* argv[]) {
	//初始化工具包
	glutInit(&argc, argv);
	//初始化显示模式和窗口属性
	glutInitDisplayMode(GLUT_SINGLE| GLUT_RGB);
	glutInitWindowSize(600, 600);
	glutCreateWindow("1812030065李诗雨 原始图形");
	glutDisplayFunc(Displayt);
	glutReshapeFunc(ChangeSize);
	//窗口初始化
	initial();

	glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
	glutInitWindowPosition(300, 300);
	glutInitWindowSize(600, 600);
	glutCreateWindow("1812030065李诗雨 反走样图形");
	glutDisplayFunc(Displayw);
	glutReshapeFunc(ChangeSize);
	//窗口初始化
	initial();

	glutMainLoop();//启动主glut事件处理循环
	return 0;

}

void initial() {
	//设置清除色,并设置窗口背景色
	glClearColor(1.0f, 1.0f, 1.0f, 0.0f);
	glLineWidth(12.0f);
	glColor4f(0.0, 0.6, 1.0, 1.0);
	lineList = glGenLists(1);
	//定义显示列表
	glNewList(lineList, GL_COMPILE);
	glBegin(GL_LINE_LOOP);
	glVertex2f(1.0f, 1.0f);
	glVertex2f(4.0f, 2.0f);
	glVertex2f(2.0f, 5.0f);
	glEnd();
	glEndList();
}

void ChangeSize(GLsizei w, GLsizei h) {
	if (h == 0) h = 1;
	//设置视区
	glViewport(0, 0, w, h);
	//重置坐标系统
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	//建立修剪空间的范围
	if (w <= h)
		gluOrtho2D(0.0, 5.0, 0.0, 6.0 *(GLfloat) h / (GLfloat)w);
	else
		gluOrtho2D(0.0, 5.0 * (GLfloat)w / (GLfloat)h, 0.0, 6.0f);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
}

void Displayt() {
	glClear(GL_COLOR_BUFFER_BIT);
	glCallList(lineList);
	glFlush();
}

void Displayw() {
	glClear(GL_COLOR_BUFFER_BIT);
	glEnable(GL_LINE_SMOOTH);//使用反走样
	glEnable(GL_BLEND);//使用混合函数
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);//指定混合函数
	glCallList(lineList);
	glFlush();
}

在这里插入图片描述

显示字符

#include <windows.h>
#include <gl/glut.h>
#include <iostream>
using namespace std;
void Display();
void ChangeSize(GLsizei w, GLsizei h);
void output(int x,int y,const char *string); 

int main(int argc, char* argv[]) {
	//初始化工具包
	glutInit(&argc, argv);
	//初始化显示模式和窗口属性
	glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
	glutInitWindowSize(600, 600);
	glutCreateWindow("1812030065李诗雨 字符显示");
	glutDisplayFunc(Display);
	glutReshapeFunc(ChangeSize);
	//窗口初始化
	//initial();
	glutMainLoop();//启动主glut事件处理循环
	return 0;

}

void ChangeSize(GLsizei w, GLsizei h) {
	glViewport(0, 0, w, h);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluOrtho2D(0.0, w, 0.0, h);
}

void output(int x, int y, const char* string) {
	int len, i;
	glRasterPos2f(x, y);
	len = (int)strlen(string);
	for (int i = 0; i < len; i++) {
		glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_24, string[i]);
	}
}

void Display() {
	//设置清除色,并设置窗口背景色
	glClearColor(1.0f, 1.0f, 1.0f, 0.0f);
	glClear(GL_COLOR_BUFFER_BIT);
	glColor3f(1.0f, 0.0f, 0.0f);
	output(100, 100, "hello!");
	glFlush();
}


在这里插入图片描述

不同属性的点和线

#include <windows.h>
#include <gl/glut.h>
#include <iostream>
using namespace std;
int winWidth = 400, winHeight = 300;  //窗口的宽度和高度
void myDisplay(void);
void ChangeSize(int w, int h);

int main(int argc, char* argv[])
{
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);
    glutInitWindowPosition(100, 100);
    glutInitWindowSize(400, 300);
    glutCreateWindow("1812030065 李诗雨");

    glutDisplayFunc(myDisplay);
    glutReshapeFunc(ChangeSize);
    glutMainLoop();

    return 0;
}
void myDisplay(void)
{
	glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
	glClear(GL_COLOR_BUFFER_BIT); //用当前背景色填充窗口
	glColor3f(0.0f, 0.0f, 0.0f); //设置当前的绘图绘图RGB颜色

	//绘制不同大小的点
	GLfloat sizes[2];       //保存绘制点的尺寸范围
	GLfloat step = 0.125;     //保存绘制点尺寸的步长
	GLfloat curSize;        //当前绘制的点的大小

	glGetFloatv(GL_POINT_SIZE_RANGE, sizes);

	curSize = sizes[0];

	for (int i = 0; i < 25; i++)
	{
		glPointSize(curSize);
		glBegin(GL_POINTS);
		glVertex3f(25.0 + i * 8, 200.0, 0.0);
		glEnd();
		curSize += step * 2;
	}
	//绘制一条宽度为5的直线
	glLineWidth(5);
	glBegin(GL_LINES);
	glVertex3f(25.0, 160.0, 0.0);
	glVertex3f(225.0, 160.0, 0.0);
	glEnd();

	//绘制一条虚线
	glEnable(GL_LINE_STIPPLE);
	glLineStipple(1, 0x00FF);
	glBegin(GL_LINES);
	glVertex3f(25.0, 120.0, 0.0);
	glVertex3f(225.0, 120.0, 0.0);
	glEnd();

	//绘制一条宽度为3的点划线
	glLineWidth(3);
	glLineStipple(1, 0xFF0C);
	glBegin(GL_LINES);
	glVertex3f(25.0, 80.0, 0.0);
	glVertex3f(225.0, 80.0, 0.0);
	glEnd();

	//增加重复因子绘制的点划线
	glLineStipple(4, 0xFF0C);
	glBegin(GL_LINES);
	glVertex3f(25.0, 40.0, 0.0);
	glVertex3f(225.0, 40.0, 0.0);
	glEnd();
	glDisable(GL_LINE_STIPPLE);

	glFlush();    //刷新OpenGL命令队列
}
void ChangeSize(int w, int h)
{
	winWidth = w;  winHeight = h;
	glViewport(0, 0, w, h);               //指定窗口的显示区域
	glMatrixMode(GL_PROJECTION);       //设置投影参数
	glLoadIdentity();
	gluOrtho2D(0.0, winWidth, 0.0, winHeight);
}

在这里插入图片描述

扫描填充算法

要在项目下新建一个输入坐标的 polypoints.txt

#include <gl/glut.h>
#include <iostream>
#include <vector>
#include <fstream>
using namespace std;

int Vertexs;

typedef struct _EdgeItem
{
	float	x;
	int		yMax;
	float	reverseK;					// 1/k
	_EdgeItem* next;
}EdgeItem;
vector<EdgeItem*> g_pItemVector;

typedef struct _Point
{
	int x;
	int y;
}Point;

typedef struct _EdgePtr
{
	int		nScanLine;					// Current scan line
	EdgeItem* pItem;					// Pointer to edge item
}EdgePtr;

typedef struct _PolyPoints
{
	Point* pPoint;						// Pointer to points
	int		n;							// Number of points
	int		yMax;						// Max y of all points
	int		yMin;						// Min y of all points
}PolyPoints;

EdgePtr* g_pEdgeList;					// Edge list
EdgePtr* g_pActiveEdgeList;			// Active edge list
PolyPoints g_polyPoints;				// Storage for points of polygons

ifstream scin("polypoints.txt");

void PutPixel(GLsizei x, GLsizei y)
{
	glRectf(10 * x, 10 * y, 10 * x + 10, 10 * y + 10);
}


void inputPoints(void)
{
	int n;
	scin >> n;
	Vertexs = n;
	if (n < 3)
	{
		cout << "number of points can not be less than 3" << endl;
		exit(0);
	}
	g_polyPoints.n = n;
	g_polyPoints.pPoint = new Point[n];
	g_polyPoints.yMax = INT_MIN;
	g_polyPoints.yMin = INT_MAX;
	int x, y;
	for (int i = 0; i < n; ++i)
	{
		scin >> x >> y;
		g_polyPoints.pPoint[i].x = x;
		g_polyPoints.pPoint[i].y = y;
		if (g_polyPoints.yMax < y)
		{
			g_polyPoints.yMax = y;
		}
		if (g_polyPoints.yMin > y)
		{
			g_polyPoints.yMin = y;
		}
	}
}
// Calculate the reverse of k
float calculateReverseK(const Point& p1, const Point& p2)
{
	return (float)(p2.x - p1.x) / (float)(p2.y - p1.y);
}

// Sort one scan line's list, first sort by x, if x is equal then sort by 1/k
void sortOneScanLineEdgeList(EdgePtr& edgePtr)
{
	// Sort by x (select sort)
	EdgeItem* pEdgeItem = edgePtr.pItem;
	EdgeItem* pNext;
	EdgeItem* pTmp;
	while (pEdgeItem)
	{
		pNext = pEdgeItem->next;
		pTmp = pEdgeItem;
		while (pNext)
		{
			if (pNext->x < pTmp->x)
			{
				pTmp = pNext;
			}
			pNext = pNext->next;
		}
		if (pTmp != pEdgeItem)
		{
			// Swap x
			float fTmp = pTmp->x;
			pTmp->x = pEdgeItem->x;
			pEdgeItem->x = fTmp;
			// Swap yMax

			int iTmp = pTmp->yMax;
			pTmp->yMax = pEdgeItem->yMax;
			pEdgeItem->yMax = iTmp;
			// Swap 1/k
			float kTmp = pTmp->reverseK;
			pTmp->reverseK = pEdgeItem->reverseK;
			pEdgeItem->reverseK = kTmp;
		}
		pEdgeItem = pEdgeItem->next;
	}
	// When the x is the same, then sort by 1/k
	pEdgeItem = edgePtr.pItem;
	EdgeItem* pStart = NULL;
	EdgeItem* pEnd = NULL;
	while (pEdgeItem)
	{
		// Find the start pointer and end pointer with the same x, then sort them
		pEnd = pStart = pEdgeItem;
		pNext = pStart->next;
		while (pNext && (pNext->x == pStart->x))
		{
			pEnd = pNext;
			pNext = pNext->next;
		}
		// Sort the edge list from pStart to pEnd by 1/k (select sort)
		while (pStart != pEnd)
		{
			pTmp = pStart;
			pNext = pTmp->next;
			while (pNext != pEnd)
			{
				if (pNext->reverseK < pTmp->reverseK)
				{
					pTmp = pNext;
				}
				pNext = pNext->next;
			}
			// Swap values
			if (pTmp != pStart)
			{
				// Swap x
				float fTmp = pTmp->x;
				pTmp->x = pStart->x;
				pStart->x = fTmp;
				// Swap yMax
				int iTmp = pTmp->yMax;
				pTmp->yMax = pStart->yMax;
				pStart->yMax = iTmp;
				// Swap 1/k
				float kTmp = pTmp->reverseK;
				pTmp->reverseK = pStart->reverseK;
				pStart->reverseK = kTmp;

			}
			pStart = pStart->next;
		} // while (pStart != pEnd)
		pEdgeItem = pEnd->next;
	}
}
// Construct the edge list
void constructEdgeList(void)
{
	// Construct the edge list
	int nScanLines = g_polyPoints.yMax - g_polyPoints.yMin + 1;
	g_pEdgeList = new EdgePtr[nScanLines];
	memset(g_pEdgeList, 0, sizeof(EdgePtr) * nScanLines);
	Point* pPoint = g_polyPoints.pPoint;
	int nScanLine = g_polyPoints.yMin;

	EdgeItem* pEdgeItem = NULL;
	for (int i = 0; i < nScanLines; ++i, ++nScanLine)		//对每一个扫描线 nScanLine,将多边形的较低顶点在 nScanLine上的边,装入边表 g_pEdgeList 的 第 nScanLine 分量中
	{
		g_pEdgeList[i].nScanLine = nScanLine;
		for (int j = 0; j < g_polyPoints.n; ++j)			//遍历多边形的顶点,找到满足条件的边
		{
			if (pPoint[j].y == nScanLine)
			{
				int j1 = (j + g_polyPoints.n - 1) % g_polyPoints.n;
				int j2 = (j + 1) % g_polyPoints.n;
				// if point j1's y > nScanLine then add this edge to the current scanline's list
				if (pPoint[j1].y > nScanLine)
				{
					pEdgeItem = new EdgeItem;
					pEdgeItem->reverseK = calculateReverseK(pPoint[j], pPoint[j1]);
					pEdgeItem->x = (float)pPoint[j].x;
					pEdgeItem->yMax = pPoint[j1].y;
					// Add pEdgeItem to the scanline's list
					pEdgeItem->next = g_pEdgeList[i].pItem;
					g_pEdgeList[i].pItem = pEdgeItem;

				}
				// if point j2's y > nScanLine then add this edge to the curretn scanline's list
				if (pPoint[j2].y > nScanLine)
				{
					pEdgeItem = new EdgeItem;
					pEdgeItem->reverseK = calculateReverseK(pPoint[j], pPoint[j2]);
					pEdgeItem->x = (float)pPoint[j].x;
					pEdgeItem->yMax = pPoint[j2].y;
					// Add pEdgeItem to the scanline's list
					pEdgeItem->next = g_pEdgeList[i].pItem;
					g_pEdgeList[i].pItem = pEdgeItem;
				}
			} // if (pPoints[j].y == nScanLine)
		} // for (int j = 0; j < g_polyPoints.n; ++j)
		sortOneScanLineEdgeList(g_pEdgeList[i]);
	}
	// Init the active edge list
	g_pActiveEdgeList = new EdgePtr[nScanLines];
}
// free the memory
void destroy(void)
{
	if (g_pActiveEdgeList)
	{
		delete g_pActiveEdgeList;
	}
	int nScanLines = g_polyPoints.yMax - g_polyPoints.yMin + 1;
	EdgeItem* pItem, * pNext;
	if (g_pEdgeList)
	{
		for (int i = 0; i < nScanLines; ++i)
		{
			if (g_pEdgeList[i].pItem)
			{
				pItem = g_pEdgeList[i].pItem;
				pNext = pItem;
				while (pItem)
				{
					pNext = pItem->next;
					delete pItem;
					pItem = pNext;
				}
			}
		}
	}
}
void init(void)
{
	glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
}

void activEdgeListFillPolygon(void)
{
	int nScanLines = g_polyPoints.yMax - g_polyPoints.yMin + 1;
	memset(g_pActiveEdgeList, 0, sizeof(EdgePtr) * nScanLines);
	int nScanLine = g_polyPoints.yMin;
	int i;
	for (i = 0; i < nScanLines; ++nScanLine, ++i)					//找到第一个非空活动边表 g_pActiveEdgeList[i].pItem
	{
		if (g_pEdgeList[i].pItem)
		{
			g_pActiveEdgeList[i].pItem = g_pEdgeList[i].pItem;
			break;
		}
	}
	for (int j = i; j < nScanLines; ++j, ++nScanLine)
	{
		if (g_pActiveEdgeList[j].pItem)
		{
			// Delete the edge where yMax = nScanLine				//填充之前先删除ymax=y(当前扫描线)的边结点
			EdgeItem* pPre = NULL;
			EdgeItem* pNext = g_pActiveEdgeList[j].pItem;
			bool bEven = true;
			while (pNext)
			{
				if (pNext->yMax == nScanLine)
				{
					if (!pPre)
					{
						g_pActiveEdgeList[j].pItem = pNext->next;
						pNext = pNext->next;
					}
					else
					{
						pPre->next = pNext->next;
						pNext = pNext->next;
					}
				}
				else
				{
					bEven = !bEven;
					pPre = pNext;
					pNext = pNext->next;
				}
			} // while (pNext)

			// Fill the scan line when bFill is true
			bool bFill = false;
			pNext = g_pActiveEdgeList[j].pItem;					//对当前活动边表 g_pActiveEdgeList[j].pItem 进行填充
			while (pNext && bEven)
			{
				bFill = !bFill;
				if (bFill)										//通过bFill控制填充区间的始点
				{
					int x1 = (int)(pNext->x + 0.5);
					int x2 = (int)(pNext->next->x + 0.5);

					for (int i = x1; i <= x2; ++i)
					{
						PutPixel(i, nScanLine);
					}
				}
				pNext = pNext->next;
			}	// while (pNext)
			pNext = g_pActiveEdgeList[j].pItem;
			int kk = j + 1;
			if (kk < nScanLines)
			{
				while (pNext)											//此循环将活动边表 g_pActiveEdgeList[kk].pItem 每个结点的x变为x+1/k,修正后的结点顺序正好倒序了
				{
					EdgeItem* pItem = new EdgeItem;
					pItem->x = pNext->x + pNext->reverseK;
					pItem->reverseK = pNext->reverseK;
					pItem->yMax = pNext->yMax;
					pItem->next = g_pActiveEdgeList[kk].pItem;
					g_pActiveEdgeList[kk].pItem = pItem;
					pNext = pNext->next;
					g_pItemVector.push_back(pItem);
				} // while (pNext)
				// Add edge list to active edge list
				pNext = g_pEdgeList[kk].pItem;
				EdgeItem* pTemp = NULL;
				while (pNext)											//此循环将边表 g_pEdgeList[kk].pItem 中第kk扫描线的边结点信息倒序插在 活动边表 g_pActiveEdgeList[kk].pItem 之前
				{
					pTemp = new EdgeItem;
					pTemp->reverseK = pNext->reverseK;
					pTemp->x = pNext->x;
					pTemp->yMax = pNext->yMax;
					g_pItemVector.push_back(pTemp);
					pTemp->next = g_pActiveEdgeList[kk].pItem;
					g_pActiveEdgeList[kk].pItem = pTemp;
					pNext = pNext->next;
				}
				sortOneScanLineEdgeList(g_pActiveEdgeList[kk]);
			}


		} // 			if (g_pActiveEdgeList[j].pItem)
	}
	//这里为了简单所以把分配的内存放在vector容器中,方便删除
	vector<EdgeItem*>::iterator itr = g_pItemVector.begin();
	vector<EdgeItem*>::iterator endItr = g_pItemVector.end();
	while (itr != endItr)
	{
		delete (*itr);
		++itr;
	}
	g_pItemVector.clear();
}

//绘制坐标线
void DrawCordinateLine(void)
{
	int i = 0;
	//坐标线为黑色
	glColor3f(0.0f, 0.0f, 0.0f);
	glBegin(GL_LINES);
	for (i = 10; i <= 250; i = i + 10)
	{
		glVertex2f((float)(i), 0.0f);
		glVertex2f((float)(i), 250.0f);
		glVertex2f(0.0f, (float)(i));
		glVertex2f(250.0f, (float)(i));
	}
	glEnd();
}

void DrawPolygonLine(void)
{
	glColor3f(0.0f, 1.0f, 0.0f);
	glBegin(GL_LINE_LOOP);
	for (int i = 0; i < Vertexs; ++i)
	{
		glVertex2i(10 * g_polyPoints.pPoint[i].x, 10 * g_polyPoints.pPoint[i].y);
	}
	glEnd();

}
//绘制一个点,这里用一个正方形表示一个点。
void display(void)
{
	glClear(GL_COLOR_BUFFER_BIT);

	//画出坐标线
	DrawCordinateLine();


	// Fill a polygon
	glColor3f(1.0f, 0.0f, 0.0f);
	activEdgeListFillPolygon();
	DrawPolygonLine();
	glutSwapBuffers();
}

void reshape(GLsizei w, GLsizei h)
{
	if (h == 0)
		h = 1;
	// 设置视区尺寸
	glViewport(0, 0, w, h);

	// 重置坐标系统
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();

	//建立修剪空间的范围
	if (w <= h)
		glOrtho(0.0f, 250.0f, 0.0f, 250.0f * h / w, 1.0, -1.0);
	else
		glOrtho(0.0f, 250.0f * w / h, 0.0f, 250.0f, 1.0, -1.0);
}
void keyboard(unsigned char key, int x, int y)
{
	switch (key)
	{
	case 27: // 'VK_ESCAPE'		destroy ();      exit (0);
		break;
	default:
		break;
	}
}
int main(int argc, char** argv)
{
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
	glutInitWindowSize(600, 600);
	glutInitWindowPosition(100, 100);
	glutCreateWindow("1812030065 李诗雨 Optimized active edge list");
	init();
	inputPoints();
	constructEdgeList();

	glutDisplayFunc(display);
	glutReshapeFunc(reshape);
	glutKeyboardFunc(keyboard);
	glutMainLoop();
	destroy();
	return 0;
}

在这里插入图片描述

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值