老师给的题目并不难,我刻意复杂化了一下
当前存在的bug:
图形学实验就开这几周,暂时只能学到这里了,欢迎留言!
附图:(标题double buffered无视,代码用的single,鼠标点击右键触发菜单)
#include
#ifdef __APPLE__
#include
#else
#include
#endif
int ww = 500;
int wh = 500;
int need_rotate = 0;//旋转标识
//color 便于修改颜色
float red = 1;
float green = 1;
float blue = 1;
//coordinates
struct cor
{
float x;
float y;
};//存储坐标结构体
//3个坐标,用于存储直线(2个)、三角形(3个)、矩形(2个)绘制时的坐标
struct cor cc1;
struct cor cc2;
struct cor cc3;
int mode = 0;//选择绘画模式,line、triangle、rectangle三种,默认为line
int dots_now = 0;//记录已经确定的坐标个数
struct pics
{
int mode;
struct cor c1;
struct cor c2;
struct cor c3;
};//一个图形所有点的坐标结构体
struct pics saved_cords[100];//可存储100个图形的坐标和绘制模式
int ptr = -1;//如上结构体的计数指针
int reDrawMode =0;//重画模式,用于绘制新图形后,补画之前的图形
int mirrorMode =0;//镜像模式
//func delc
void reDraw();
void draw_one_line(struct cor c1,struct cor c2);
void draw_triangle(struct cor c1,struct cor c2,struct cor c3);
void draw_rectangle(struct cor c1,struct cor c2);
void display();
void main_menu_func(int option);
void sub_menu_draw_mode_func(int option);
void sub_menu_move_func(int option);
void myinit(void);
void mouse_move(int x, int y);
void mouse(int btn, int state, int x, int y);
void myReshape(GLsizei w, GLsizei h);
void draw_one_line(struct cor c1,struct cor c2)
{//绘制直线函数
if (need_rotate == 1)
{//平移-旋转-平移操作
int mid_x = (c1.x + c2.x) / 2;
int mid_y = (c1.y + c2.y) / 2;
glTranslated(mid_x, mid_y, 0);
glRotated(60, 0, 0, 1);
glTranslated(-mid_x, -mid_y, 0);
need_rotate = 0;
}
if(reDrawMode == 0)
{//在重画函数调用当前函数时,不需要清除背景
glClear(GL_COLOR_BUFFER_BIT);
}
glColor3f(red, green, blue);
if(mirrorMode == 0)
{
glBegin(GL_LINE_LOOP);
}
else
{//mirror mode,镜像画图,四个象限会对称画图
glBegin(GL_LINES);//lines,2个2个坐标成对画直线
glVertex2f(c1.x,-c1.y);//4th
glVertex2f(c2.x,-c2.y);
glVertex2f(-c1.x,-c1.y);//3rd
glVertex2f(-c2.x,-c2.y);
glVertex2f(-c1.x,c1.y);//2nd
glVertex2f(-c2.x,c2.y);
}
glVertex2f(c1.x, c1.y);
glVertex2f(c2.x, c2.y);
glEnd();
glFlush();
}
void draw_triangle(struct cor c1,struct cor c2,struct cor c3)
{//绘制三角形
if (need_rotate == 1)
{//旋转
int mid_x = (c1.x + c2.x + c3.x) / 3;
int mid_y = (c1.y + c2.y + c3.y) / 3;
glTranslated(mid_x, mid_y, 0);
glRotated(60, 0, 0, 1);
glTranslated(-mid_x, -mid_y, 0);
need_rotate = 0;
}
if(reDrawMode == 0)
{
glClear(GL_COLOR_BUFFER_BIT);
//reDraw();
}
glColor3f(red, green, blue);
if(mirrorMode == 0)
glBegin(GL_TRIANGLES);
else
{
glBegin(GL_TRIANGLES);//每3个坐标就能绘制一个三角形
glVertex2f(c1.x,-c1.y);//4th
glVertex2f(c2.x,-c2.y);
glVertex2f(c3.x,-c3.y);
glVertex2f(-c1.x,-c1.y);//3rd
glVertex2f(-c2.x,-c2.y);
glVertex2f(-c3.x,-c3.y);
glVertex2f(-c1.x,c1.y);//2nd
glVertex2f(-c2.x,c2.y);
glVertex2f(-c3.x,c3.y);
}
glVertex2f(c1.x, c1.y);
glVertex2f(c2.x, c2.y);
glVertex2f(c3.x, c3.y);
glEnd();
glFlush();
}
void draw_rectangle(struct cor c1,struct cor c2)
{//绘制矩形,用两个点绘制,分别是左上和右下点
if (need_rotate == 1)
{//旋转
int mid_x = (c1.x + c2.x) / 2;
int mid_y = (c1.y + c2.y) / 2;
glTranslated(mid_x, mid_y, 0);
glRotated(60, 0, 0, 1);
glTranslated(-mid_x, -mid_y, 0);
need_rotate = 0;
}
if(reDrawMode == 0)
{
glClear(GL_COLOR_BUFFER_BIT);
//reDraw();
}
glColor3f(red, green, blue);
if(mirrorMode == 0)
glBegin(GL_QUADS);
else
{
glBegin(GL_QUADS);//每4个坐标就能绘制出一个矩形
glVertex2f(c1.x,-c1.y);//4th
glVertex2f(c1.x,-c2.y);
glVertex2f(c2.x,-c2.y);
glVertex2f(c2.x,-c1.y);
glVertex2f(-c1.x,-c1.y);//3rd
glVertex2f(-c1.x,-c2.y);
glVertex2f(-c2.x,-c2.y);
glVertex2f(-c2.x,-c1.y);
glVertex2f(-c1.x,c1.y);//2nd
glVertex2f(-c1.x, c2.y);
glVertex2f(-c2.x, c2.y);
glVertex2f(-c2.x, c1.y);
}
// glBegin(GL_LINE_LOOP);
glVertex2f(c1.x, c1.y);
glVertex2f(c1.x, c2.y);
glVertex2f(c2.x, c2.y);
glVertex2f(c2.x, c1.y);
glEnd();
glFlush();
}
void display()
{//显示函数
if (mode == 0)
{ //draw line
draw_one_line(cc1,cc2);
}
if (mode == 1)
{ //draw triangle
draw_triangle(cc1,cc2,cc3);
}
if (mode == 2)
{ //draw rectangle
draw_rectangle(cc1,cc2);
}
//dots_now = 0;
}
void main_menu_func(int option)
{
if (option == 0)
{ //Set pic to random color
srand(time(NULL));
red = rand() % 100 / 100.00;
green = rand() % 100 / 100.00;
blue = rand() % 100 / 100.00;
}
if (option == 1)
{ //zoom in 放大(缩放投影范围)
ww -= 50;
wh -= 50;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-ww, ww, -wh, wh, -1.0, 1.0);
}
if (option == 2)
{ //zoom out
ww += 50;
wh += 50;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-ww, ww, -wh, wh, -1.0, 1.0);
}
if (option == 3)
{ //rotate
need_rotate = 1;
}
if (option == 4)
{ //clear 清除屏幕上的图形
glClear(GL_COLOR_BUFFER_BIT);
ptr = -1;
glFlush();
return;
}
if (option == 5)
{ //mirror mode
mirrorMode += 1;
mirrorMode %= 2;//两种取值范围,0(关),1(开),重复点击切换
}
if (option == -1)
{ //exit test
exit(0);
}
if (mode == 0)
draw_one_line(cc1,cc2);
if (mode == 1)
draw_triangle(cc1,cc2,cc3);
if (mode == 2)
draw_rectangle(cc1,cc2);
}
void sub_menu_draw_mode_func(int option)
{//绘制模式子菜单
if (option == 0)
{
mode = 0; //line mode
dots_now = 0;
}
if (option == 1)
{
mode = 1; //tri mode
dots_now = 0;
}
if (option == 2)
{
mode = 2; //rect mode
dots_now = 0;
}
}
void sub_menu_move_func(int option)
{//移动图形子菜单
if (option == 0)
{ //up
cc1.y += 50;
cc2.y += 50;
cc3.y += 50;
}
if (option == 1)
{ //down
cc1.y -= 50;
cc2.y -= 50;
cc3.y -= 50;
}
if (option == 2)
{ //left
cc1.x -= 50;
cc2.x -= 50;
cc3.x -= 50;
}
if (option == 3)
{ //right
cc1.x += 50;
cc2.x += 50;
cc3.x += 50;
}
if (mode == 0)
draw_one_line(cc1,cc2);
if (mode == 1)
draw_triangle(cc1,cc2,cc3);
if (mode == 2)
draw_rectangle(cc1,cc2);
}
void myinit(void)
{
glClearColor(0.0, 0.0, 0.0, 1.0);
glShadeModel(GL_FLAT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-ww, ww, -wh, wh, -1.0, 1.0);
}
void mouse_move(int x, int y)
{//监听鼠标移动函数,用于实时画图
if (dots_now == 1 && (mode == 0 || mode == 1 || mode == 2))
{ //这种情况下只能预览出线条或矩形
printf("mouse loc x:%d,y%d\n", x, y);
// sleep(1);
y = wh - y;//以下为坐标系变换
x -= ww / 2;
y -= wh / 2;
x *= 2 * ww / 500;
y *= 2 * wh / 500;
cc2.x = x;
cc2.y = y;
if (mode != 2)
draw_one_line(cc1,cc2);
else
draw_rectangle(cc1,cc2);
}
if (dots_now == 2 && mode == 1)
{ //tri 已经画出了一条线,预览即将绘制的三角形的情况
printf("mouse loc x:%d,y%d\n", x, y);
y = wh - y;//以下为坐标系变换
x -= ww / 2;
y -= wh / 2;
x *= 2 * ww / 500;
y *= 2 * wh / 500;
cc3.x = x;
cc3.y = y;
draw_triangle(cc1,cc2,cc3);
}
}
void mouse(int btn, int state, int x, int y)
{//每次鼠标左键点击记录画图坐标
if (btn == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
{
printf("click:x:%d,y:%d\n", x, y);
printf("\tc1.x=%f,c1.y=%f\n", cc1.x, cc1.y);
printf("\tc2.x=%f,c2.y=%f\n", cc2.x, cc2.y);
printf("\tc3.x=%f,c3.y=%f\n", cc3.x, cc3.y);
//坐标系变换
y = wh - y;
x -= ww / 2;
y -= wh / 2;
x *= 2 * ww / 500;
y *= 2 * wh / 500;
switch (dots_now)
{
case 0:
cc1.x = x;
cc1.y = y;
break;
case 1:
cc2.x = x;
cc2.y = y;
if (mode != 1)
{//不等于三角形模式,说明已经记录了两个点,马上确定绘制
dots_now = -1;//重置点的计数器
++ptr;
if(mode == 0)
saved_cords[ptr].mode = 0;//记录当前图形的绘制模式,用于重画
else if(mode == 2)
saved_cords[ptr].mode = 2;//记录当前图形的绘制模式,用于重画
saved_cords[ptr].c1 = cc1;
saved_cords[ptr].c2 = cc2;
//reDraw();
}
break;
case 2:
cc3.x = x;
cc3.y = y;
++ptr;
saved_cords[ptr].mode = 1;//记录当前图形的绘制模式,用于重画
saved_cords[ptr].c1 = cc1;
saved_cords[ptr].c2 = cc2;
saved_cords[ptr].c3 = cc3;
dots_now = -1;//重置点的计数器
//reDraw();
break;
default:
break;
}
++dots_now;
}
}
void reDraw()
{//每画一个新的图形后,把以前绘制的图形全部重画一次
reDrawMode = 1;
for(int i=0;i<=ptr;++i)
{
if(saved_cords[i].mode == 0)
{
draw_one_line(saved_cords[i].c1,saved_cords[i].c2);
continue;
}
if(saved_cords[i].mode == 1)
{
draw_triangle(saved_cords[i].c1,saved_cords[i].c2,saved_cords[i].c3);
continue;
}
if(saved_cords[i].mode == 2)
{
draw_rectangle(saved_cords[i].c1,saved_cords[i].c2);
continue;
}
}
reDrawMode = 0;
}
void myReshape(GLsizei w, GLsizei h)
{
/* adjust clipping box */
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-w, w, -h, h, -1.0, 1.0);
/* adjust viewport and clear */
glViewport(0, 0, w, h);
ww = w;
wh = h;
}
/* Main Loop
* Open window with initial window size, title bar,
* RGBA display mode, and handle input events.
*/
int main(int argc, char **argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize(ww, wh);
glutCreateWindow("my window");
int sub_menu1 = glutCreateMenu(sub_menu_draw_mode_func);
glutAddMenuEntry("line", 0);
glutAddMenuEntry("triangle", 1);
glutAddMenuEntry("rectangle", 2);
int sub_menu2 = glutCreateMenu(sub_menu_move_func);
glutAddMenuEntry("Up", 0);
glutAddMenuEntry("Down", 1);
glutAddMenuEntry("Left", 2);
glutAddMenuEntry("Right", 3);
glutCreateMenu(main_menu_func);
glutAddSubMenu("Draw:", sub_menu1);
glutAddSubMenu("Move:", sub_menu2);
glutAddMenuEntry("Set new color", 0);
glutAddMenuEntry("Zoom In", 1);
glutAddMenuEntry("Zoom Out", 2);
glutAddMenuEntry("Rotate", 3);
glutAddMenuEntry("Mirror",5);
glutAddMenuEntry("Clear",4);
glutAddMenuEntry("Exit", -1);
glutAttachMenu(GLUT_RIGHT_BUTTON);
glutDisplayFunc(display);
glutReshapeFunc(myReshape);
glutPassiveMotionFunc(mouse_move);
glutIdleFunc(reDraw);
glutMouseFunc(mouse);
myinit();
glutMainLoop();
}