实验4—OpenGL的鼠标交互绘制

news2024/11/19 17:38:08
一、实验目的

1.掌握OpenGL的鼠标按钮响应函数。
2.掌握OpenGL的鼠标移动响应函数。
3.进一步巩固OpenGL的基本图元绘制基础

二、实验内容

1.鼠标画草图——实现鼠标点到哪,线就画到哪。
思路:
1 )在主程序注册鼠标响应和鼠标移动子函数:

glutMouseFunc(mymouse);
glutMotionFunc(mymotion)

放在display注册之后和mainloop之前。
2)在程序头部声明鼠标响应和鼠标移动子函数:

void myMouse(int button,int state,int x,int y); 
void myMotion(int x,int y);

3)构造鼠标响应子函数:
//鼠标按钮响应事件

void myMouse(int button, int state,int x,int y)
{
//鼠标左键按下——确定起始点
//鼠标左键松开——画最后一个顶点,画线结束
}

4)构造鼠标移动子函数:
//鼠标移动时获得鼠标移动中的坐标

void myMotion(int x,int y)
{
/ /鼠标移动	线画到哪
}

5 )修改显示函数Display():

#include "stdafx.h"
#include "Shiyan4.h"
#include <windows.h>
#include <gl/glut.h>
//画直线程序框架
int ww, hh;	//显示窗口宽和高
void Myinit(void);
void Reshape(int w, int h);
void Display(void);
int APIENTRY _tWinMain(HINSTANCE hlnstance, HINSTANCE hPrevInstance, LPTSTR	IpCmdLine,int	nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(IpCmdLine);
char *argv[] = {"hello"," "}; 
int argc = 2; // argv中的字符串数	
glutInit(&argc, argv);
glutInitWindowSize(800, 600);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
glutCreateWindow("H鼠标画线小程序演示");
Myinit ();	//初始化GLUT库
//设置显示窗口大小
//设置显示模式(注意双缓存)
//创建显示窗口
glutDisplayFunc(Display);
glutReshapeFunc(Reshape);	//注册显示回调函数
//注册窗口改变回调函数	
glutMainLoop(); 
return 0;	//进入事件处理循环	
}
void Myinit(void)
{
	glClearColor(0.0,0.0,0.0,0.0);
	glLineWidth(3.0);
}
//渲染绘制子程序
void Display(void)
{
glClear (GL_COLOR_BUFFER_BIT) ; // 刷新颜色缓存区 glBegin(GL_LINES);
glVertex2f(0, 0);
glVertex2f(ww,hh);
glEnd();
glutSwapBuffers ();	//双缓存的刷新模式
}
void Reshape(int w, int h){
	glMatrixMode(GL_PROJECTION);	//投影矩阵模式
	glLoadIdentity();	//矩阵堆栈清空
	glViewport(0, 0, w, h);	//设置视区大小
	gluOrtho2D(0, w, 0, h);	//设置裁剪窗口大小
	ww=w;	
	hh=h;	
}

2.鼠标画线。阅读OpenGL鼠标画线程序,能够实现在绘制窗口用鼠标交互绘制若干条 直线,鼠标左键首先按下确定直线的起始点,鼠标左键按下同时移动,看到画线过程,鼠标 左键松开时确定直线的终点,可重复画多条直线。
思路:
1) 写出画静止若干条直线程序框架,坐标用变量替代。
2) 在主函数里注册鼠标按钮响应函数和鼠标移动响应函数。
3) 在鼠标按钮响应子函数里给岀鼠标按钮响应事件。
4) 在鼠标移动响应子函数里给出鼠标移动响应事件。
5) 读懂程序并分析程序,保留程序。

#include <windows.h>
#include <stdio.h>
#include "stdafx.h"
#include "Shiyan4.h"
#include <gl/glut.h>
#define N 1000				//线段最大条数
int line[N][4], k = 0;		//线段坐标存储数组, 线段计数
int ww, hh;					//显示窗口的宽和高
void myMouse(int button, int state, int x, int y);
void myMotion(int x, int y);
void Myinit(void);
void Reshape(int w, int h);
void display(void);
void drawines();
int APIENTRY wWinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPTSTR    lpCmdLine,int       nCmdShow)
{
    UNREFERENCED_PARAMETER(hPrevInstance);
    UNREFERENCED_PARAMETER(lpCmdLine);
	char* argv[] = { "hello "," " };
	int argc = 2;		//argv中的字符串数
	int sheight = glutGet(GLUT_SCREEN_WIDTH);
	int swidth = glutGet(GLUT_SCREEN_HEIGHT);
	glutInit(&argc, argv);							//初始化GLUT库
	glutInitWindowSize(800, 600);					//绘图窗口大小
	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
	glutCreateWindow("鼠标画线小程序演示");	//创建显示窗口
	Myinit();
	glutDisplayFunc(display);				//注册显示回调函数
	glutMouseFunc(myMouse);					//注册鼠标按钮回调函数
	glutMotionFunc(myMotion);				//注册鼠标移动回调函数
	glutReshapeFunc(Reshape);				//注册窗口改变回调函数
	glutMainLoop();							//表示开始运行程序,用于程序的结尾
	return 0;
}
void Myinit(void) {
	glClearColor(0.0, 0.0, 0.0, 0.0);
	glLineWidth(3.0);
}
//画线子程序
void drawlines() {
	for (int i = 0; i <= k; i++) {
		glBegin(GL_LINES);
		glVertex2f(line[i][0], line[i][1]);
		glVertex2f(line[i][2], line[i][3]);
		glEnd();
	}
}
//渲染绘制子程序
void display(void) {
	glClear(GL_COLOR_BUFFER_BIT);//刷新颜色缓存区
	drawlines();				//画线子程序
	glutSwapBuffers();			//双缓存的刷新模式
}
void Reshape(int w, int h)		//窗口改变时自动获取显示窗口的宽w和高h
{
	glMatrixMode(GL_PROJECTION);//投影矩阵模式
	glLoadIdentity();			//矩阵堆栈清空
	glViewport(0, 0, w, h);		//设置视区大小
	gluOrtho2D(0, w, 0, h);		//设置裁剪窗口大小
	ww = w;
	hh = h;
}
//鼠标按钮响应事件
void myMouse(int button, int state, int x, int y)
{
	//鼠标左键按下——确定起始点
	if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
	{
		line[k][0] = x;				//线段起点x坐标
		line[k][1] = hh - y;		//线段终点y坐标
	}
	//鼠标左键松开——画最后一个顶点,画线结束
	if (button == GLUT_LEFT_BUTTON && state == GLUT_UP) {
		line[k][2] = x;				//线段起点x坐标
		line[k][3] = hh - y;		//线段终点y坐标
		k++;
		glutPostRedisplay();
	}
}
//鼠标移动时获得鼠标移动中的坐标
void myMotion(int x, int y)
{
	//get the line's motion point
	line[k][2] = x;				//动态终点的x坐标
	line[k][3] = hh - y;		//动态终点的y坐标
	glutPostRedisplay();
}

实验结果:
在这里插入图片描述
3.鼠标绘制矩形。修改鼠标画线程序,要求:能够实现在绘制窗口用鼠标交互绘制若干 矩形,鼠标左键首先按下确定矩形对角线的起始点,鼠标左键按下同时移动时看到画矩形过 程,鼠标左键松开确定矩形对角线的另一点,可重复画多个矩形。如图所示。
实验结果:
在这里插入图片描述
代码:

//鼠标绘制矩形rect_draw.cpp
#include <GL/glut.h>
#include <iostream>
#define N 1000				//矩形最大个数
int k = 0;					//矩形计数
int ww, hh;					//显示窗口的宽和高
//int corner[N][4];
struct GLintPoint {		//矩形结构
	int x, y;
};
GLintPoint corner[N][2];
/*矩形存储数组,第i个矩形坐标
x0 = corner[i][0].x
y0 = corner[i][0].y
x1 = corner[i][1].x
y1 = corner[i][1].y
*/
void myMouse(int button, int state, int x, int y);
void myMotion(int x, int y);
void myinit(void);
void Reshape(int w, int h);
void display(void);
void drawRects();
INT WINAPI wWinMain(HINSTANCE hInstance,
	HINSTANCE hPrevInstance,
	LPTSTR	lpCmdline,
	int		nCmdShow)
{
	UNREFERENCED_PARAMETER(hPrevInstance);
	UNREFERENCED_PARAMETER(lpCmdline);
	char *argv[] = { (char *)"hello ",(char *)" " };
	int argc = 2;
	glutInit(&argc, argv);			//initialize glut  library
	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
	glutInitWindowSize(800, 600);
	glutInitWindowPosition(0, 0);
	glutCreateWindow("Mouse draw Rectangle");
	myinit();
	glutDisplayFunc(display);
	glutMouseFunc(myMouse);
	glutMotionFunc(myMotion);
	glutReshapeFunc(Reshape);
	glutMainLoop();
	return 0;
}

void myinit(void) {
	glClearColor(0, 0, 0, 0);
	glLineWidth(3.0);
}
//矩阵绘制子程序
void drawRects() {
	for (int i = 0; i <= k; i++) {
		glBegin(GL_LINE_LOOP);
		glVertex2f(corner[i][0].x, corner[i][0].y);		//x0,y0
		glVertex2f(corner[i][0].x, corner[i][1].y);		//x0,y1
		glVertex2f(corner[i][1].x, corner[i][1].y);		//x1,y1
		glVertex2f(corner[i][1].x, corner[i][0].y);		//x1,y0	
		glEnd();
	}
}
//display()函数
void display(void) {
	glClear(GL_COLOR_BUFFER_BIT);
	drawRects();

	glutSwapBuffers();
}
void Reshape(int w, int h)		//窗口改变时自动获取显示窗口的宽w和高h
{
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	glViewport(0, 0, w, h);		//设置视区大小
	gluOrtho2D(0, w, 0, h);		//设置裁剪窗口大小
	ww = w;
	hh = h;
}
//鼠标按钮响应事件
void myMouse(int button, int state, int x, int y)
{
	//鼠标左键按下——确定第一个矩形对角点
	if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
	{
		corner[k][0].x = x;		//x1
		corner[k][0].y = hh - y;	//y1
	}
	//鼠标左键松开——画下一个对角点,将矩形个数加1,画线结束
	if (button == GLUT_LEFT_BUTTON && state == GLUT_UP) {
		corner[k][1].x = x;		//x2
		corner[k][1].y = hh - y;	//y2
		k++;
		glutPostRedisplay();
	}
}
void myMotion(int x, int y)
{
	//get the line's motion point
	corner[k][1].x = x;
	corner[k][1].y = hh - y;
	glutPostRedisplay();
}

4.思考题:鼠标画圆。鼠标画圆应如何修改代码?
实验结果:
在这里插入图片描述
代码:

#include "stdafx.h"
#include "ShiYan4-2.h"
//鼠标绘制矩形
#define GLUT_DISABLE_ATEXIT_HACK
#include <windows.h>
#include <gl/glut.h>
#include <math.h>
#define N 1000				//圆最大个数
#define PI  3.14159			//设置圆周率 
int n = 3600, R;			//多边形边数,外接圆半径 
float theta = 0.0;			//旋转初始角度值
int k = 0;		//圆数据存储数组,圆计数
int r[N][3];
int ww, hh;					//显示窗口的宽和高
struct GLintPoint {		//矩形结构
	int x, y;
};
GLintPoint corner[N][2];
void myMouse(int button, int state, int x, int y)
{
	//鼠标左键按下——确定第一个圆的对角点
	if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
	{
		corner[k][0].x = x;			//x1
		corner[k][0].y = hh - y;	//y1
	}
	//鼠标左键松开——画下一个对角点,将圆个数加1,画线结束
	if (button == GLUT_LEFT_BUTTON && state == GLUT_UP) {
		corner[k][1].x = x;		//x2
		corner[k][1].y = hh - y;	//y2
		r[k][0] = (corner[k][0].x + corner[k][1].x) / 2;
		r[k][1] = (corner[k][0].y + corner[k][1].y) / 2;
		r[k][2] = sqrt(double((corner[k][0].x - corner[k][1].x)*(corner[k][0].x - corner[k][1].x) +(corner[k][0].y - corner[k][1].y) *(corner[k][0].y - corner[k][1].y))) / 2;
		k++;
		glutPostRedisplay();
	}
}
void myMotion(int x, int y)
{
	//get the line's motion point
	corner[k][1].x = x;
	corner[k][1].y = hh - y;
	glutPostRedisplay();
}
void Myinit(void) {
	glClearColor(0, 0, 0, 0);
	glLineWidth(3.0);
}
void Reshape(int w, int h)		//窗口改变时自动获取显示窗口的宽w和高h
{
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	glViewport(0, 0, w, h);		//设置视区大小
	gluOrtho2D(0, w, 0, h);		//设置裁剪窗口大小
	ww = w;
	hh = h;
}
//圆绘制子程序
void drawRound() {
	for (int i = 0; i <= k; i++) {
		glBegin(GL_LINE_LOOP);
		for (int j = 0; j < n; j++)
			glVertex2f((r[i][0] + r[i][2] * cos(j * 2 * PI / n)), (r[i][1] + r[i][2] * sin(j * 2 * PI / n)));  //顶点坐标 
		glEnd();
	}
}
void display(void) {
	glClear(GL_COLOR_BUFFER_BIT);
	drawRound();
	glutSwapBuffers();
}
INT WINAPI wWinMain(HINSTANCE hInstance,
	HINSTANCE hPrevInstance,
	LPTSTR	lpCmdline,
	int		nCmdShow)
{
	UNREFERENCED_PARAMETER(hPrevInstance);
	UNREFERENCED_PARAMETER(lpCmdline);
	char* argv[] = { (char*)"hello ",(char*)" " };
	int argc = 2;
	glutInit(&argc, argv);			//initialize glut  library
	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
	glutInitWindowSize(800, 600);
	glutInitWindowPosition(0, 0);
	glutCreateWindow("鼠标绘制圆形");
	Myinit();
	glutDisplayFunc(display);
	glutMouseFunc(myMouse);
	glutMotionFunc(myMotion);
	glutReshapeFunc(Reshape);
	glutMainLoop();
	return 0;
}
三、参考函数与代码

基本图元绘制函数参考教材第5章,鼠标交互函数参考第6章。
1)裁剪窗口设置函数:

gluOrtho2D(xwmin,xwmax,ywmin,ywmax);

2)视区设置函数:

glViewport(startx,starty,viewport_width,viewport_height);

3)鼠标绘制折线代码示例:
//鼠标按下时开始画折线,鼠标按钮松开时结束

glutMotionFunc(mymotion);
void mymotion(int x,int y)
{.
if (first_time_called)
glBegin(GL_LINE_STRIP);
glVertex2f (sx* (GLfloat) x, sy* (GLfloat) (h-y));
}
//注意:鼠标按钮松开时产生glEndO

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/562721.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ChatGPT:你真的了解网络安全吗?浅谈网络安全攻击防御进行时之网络安全新防御

ChatGPT&#xff1a;你真的了解网络安全吗&#xff1f;浅谈网络安全攻击防御进行时 网络安全新防御1. 针对人工智能2. 针对5G和物联网3. 针对云安全4.针对社交工程5. 针对加密技术6. 针对多层次的安全控制 ChatGPT&#xff08;全名&#xff1a;Chat Generative Pre-trained Tra…

针对Rokcetmq引入的缺点提供相应解决方案

1.针对Rokcermq引入可用性降低问题 Rocketmq实现高可用模式&#xff0c;Rocketmq有三种模式&#xff1a;单机模式、主从模式、分片集群模式。 单机模式 单机模式&#xff0c;就是 Demo 级别的&#xff0c;一般就是你本地启动了玩玩儿的&#xff0c;没人生产用单机模式。 docker…

Postman传递@requestbody标注的List集合的传参遇到的问题

Postman传递requestbody标注的List集合的传参遇到的问题 引子如何测试以及遇到的问题参考文献 引子 我们想测试如下接口 RequestMapping(value "saveMessageRecover", method RequestMethod.POST) ResponseBody public AjaxMessage saveMessageRecover(RequestBod…

聚观早报 |必应成为中国第一大桌面搜索引擎;快手上市后首次盈利

今日要闻&#xff1a;必应成为中国第一大桌面搜索引擎&#xff1b;快手上市后集团层面首次盈利&#xff1b;ChatGPT相关诈骗攻击与日俱增&#xff1b;比亚迪回应法国建厂传闻&#xff1b;薇娅夫妇半年收获两家上市公司 必应成为中国第一大桌面搜索引擎 5 月 22 日消息&#xf…

媒体专访|美创胡大海:国内数据安全市场正处于战略机遇期

引言 &#xff1a;我国在《“十四五”数字经济发展规划》中强调深化应用、规范发展、普惠共享&#xff0c;更多强调了数据资源为关键要素的重要性&#xff0c;并呼应了数据要素正式被纳入生产要素的政策&#xff0c;着重提出了数字经济具有“融合应用”和“全要素数字化转型”的…

断言无忧!接口自动化框架封装,Mysql数据库断言

目录 前言&#xff1a; 一、项目背景 二、框架封装 1. Mysql数据库连接 2. 查询功能 3. 断言功能 4. 使用示例 三、总结 前言&#xff1a; 随着互联网行业的迅猛发展&#xff0c;接口自动化测试在软件开发过程中扮演着越来越重要的角色。而在进行接口测试的过程中&…

初学UE5,UE4的教程适用UE5吗?

在UE5出版后&#xff0c;很多人问UE4还要不要学、UE4适不适用于UE5等问题。 UE5是最近推出的一款游戏引擎&#xff0c;相较于UE4而言&#xff0c;它有着更好的性能和灵活的工作流程&#xff0c;同时也引入了一些新的功能。对于一些游戏开发初学者来说&#xff0c;他们可能会想…

Flask restful分页接口实现

1.先定义一个工作信息表: 指定一些相关的字段:工作名称、年限、级别等 class Work(db.Model):__tablename__ = workid = db.Column(db.Integer, primary_key=True)workName = db.Column(db.String(5),nullable=False)year = db.Column(db.String(20), nullable=False)level = …

加密与解密 调试篇 动态调试技术 (二)

我们在 (一)中调试了一个程序 接着我们开始继续学习 常见的断点 这里有 INT 3断点 硬件断点 内存断点 消息断点等 1.INT 3 断点 我们在OllyDbg中 可以使用 命令 bp 或者 F12进行断点 INT3断点 就是在程序中 对该位置的代码 进行替换 替换为INT3 INT3 是一个软中断指令…

ChatGPT:你真的了解网络安全吗?浅谈网络安全攻击防御进行时之网络安全新定义

ChatGPT&#xff1a;你真的了解网络安全吗&#xff1f;浅谈网络安全攻击防御进行时 网络安全新定义 ChatGPT&#xff08;全名&#xff1a;Chat Generative Pre-trained Transformer&#xff09;&#xff0c;美国OpenAI 研发的聊天机器人程序&#xff0c;是人工智能技术驱动的自…

如何利用ChatGPT在工作中提高生产力?

[请微信搜索“云智AI助手”、“云智博瑞”关注我们 │ 谢谢支持 ] Cloud wisdom, AI assistant 每次人工智能成为头条新闻&#xff0c;都会引发对它是否会让人类失业的讨论。尽管某些工作可能会变得多余&#xff0c;我们应该学会与人工智能共同工作&#xff0c;将其作为增强自…

Python统计学13——回归的多重共线性、异方差、自相关的检验

在基础统计学&#xff0c;或者是计量经济学里面&#xff0c;需要对回归问题进行一些违背经典假设的检验&#xff0c;例如多重共线性、异方差、自相关的检验。这些检验用stata&#xff0c;r&#xff0c;Eviews什么都很简单&#xff0c;但是用python很多人都不会。下面就带大家实…

2023.5.14Ubuntu忘记MySQL密码

如果您忘记了MySQL的密码&#xff0c;可以按照以下步骤重置MySQL的密码&#xff1a; 停止MySQL服务&#xff1a; sudo service mysql stop启动MySQL服务&#xff0c;并跳过授权表&#xff1a; sudo mysqld_safe --skip-grant-tables &使用MySQL客户端连接到MySQL&#x…

【搭建轻量级图床】本地搭建LightPicture开源图床管理系统 - 异地远程访问

文章目录 1.前言2. Lightpicture网站搭建2.1. Lightpicture下载和安装2.2. Lightpicture网页测试2.3.cpolar的安装和注册 3.本地网页发布3.1.Cpolar云端设置3.2.Cpolar本地设置 4.公网访问测试5.结语 1.前言 现在的手机越来越先进&#xff0c;功能也越来越多&#xff0c;而手机…

吃鸡史:傻鸡是怎么进化并“称霸”世界的?

鸡&#xff0c;给我们的印象是温顺的&#xff1a;温顺地长大&#xff0c;温顺地下蛋&#xff0c;温顺地进油锅… 若是鸡祖宗们知道&#xff0c;有一天它们的鸡子鸡孙会进化成一群不会飞、只知道吃的傻鸡&#xff0c;几千年前的红原鸡骨怕是都要惊得飞出土了&#xff01; 毕竟…

day17 回话跟踪技术Cookie与Session

会话跟踪技术 问题:一次会话中的多次请求不会共享数据,不能显示.若通过传参数在路径上来解决该问题,不安全. 作用:解决HTTP无状态 http,cookie,session使用的区别 如果使用http中的request.setAttribute(),只能一次共享一个 若使用cookie,cookie存在浏览器中,每一次请求都…

JAVA——类间双向关联关系的实现-Contact与Phone类(电话簿管理系统)

首先&#xff1a;确定代码雏形框架&#xff08;原始代码&#xff09; 先根据以往经验写出一般的电话簿管理系统&#xff0c;先把代码雏形框架确定好。 原始代码运行结果&#xff1a; 原始代码源码&#xff1a; package bidirectionalDome;import java.util.ArrayList;public…

前端基础面试题八股文

html语义化的理解 代码结构: 使页面在没有css的情况下,也能够呈现出好的内容结构 有利于SEO: 爬虫根据标签来分配关键字的权重,因此可以和搜索引擎建立良好的沟通,帮助爬虫抓取更多的有效信息 方便其他设备解析&#xff1a; 如屏幕阅读器、盲人阅读器、移动设备等&#xff0c…

【敬伟ps教程】自由变换

文章目录 自由变换 自由变换 变换可以针对整个图层(组或链接图层)&#xff0c;或者选区内 基本操作 编辑–自由变换&#xff08;CtrilT&#xff09;&#xff1b; 自由变换的控件框来控制变换的效果&#xff1b; 自由变换是独立进行操作的模式&#xff0c;操作结束后需要点击确…

nginx -- 基本操作命令

修改nginx 配置&#xff0c;重新启动nginx流程,先进入到nginx目录 查看nginx状态 ps -ef | grep nginx 修改完/conf/nginx.conf 配置文件后保存 检查配置文件是否正确 ./sbin/nginx -t 检查文件配置正常 关闭nginx ./sbin/nginx -s quit 启动nginx ./sbin/nginx 完成