1. 程式人生 > >[OpenGL]用滑鼠拖拽圖形移動

[OpenGL]用滑鼠拖拽圖形移動

今天做計算機圖形學實驗。題目佈置了寫程式使圖形移動,於是我就寫了這個程式。

使用的環境是Code::Blocks + GLUT,Code::Blocks配置GLUT實現OpenGL的教程可以看這篇:

想要實現用滑鼠拖拽使圖形移動,首先需要考慮兩個問題:

1.如何接受滑鼠產生的訊號。

2.如何判斷滑鼠在圖形內。

解決第一個問題,只需要瞭解到OpenGL中的GLUT給的函式就可以。

glutMouseFunc( (void*)Func(int button, int state, int x, int y) );
如果沒有記錯,上面是這個函式的原型。其中x,y是當前滑鼠指標所在的位置。

正好利用這個資訊可以得到是否在圖形內。

而獲取到了這些,還需要獲取滑鼠的動作。OpenGL提供了兩個函式。

glutMotionFunc( (void*)func(int x, int y) );
glutPassiveMotionFunc( (void*)func(int x, int y) );
利用這些函式就可以解決問題了。

而第二個問題。涉及到凸包,在一個多邊形內如果判斷點是否在圖形內。這部分因為時間問題並沒有寫,所以先佔個坑,回頭補。

下面實現了簡略的程式碼。執行拖動時會出現閃屏,因為沒有加快取。

#include <cmath>
#include <cstdlib>
#include <iostream>
#include <windows.h>
#include <GL/glut.h>
using namespace std;

GLdouble newMat[4][2] = {0,0, 100,0, 100,100, 0,100};
const GLdouble mat[4][2] = {0,0, 100,0, 100,100, 0,100};

void init() {
    glClearColor( 0.0, 0.0, 0.0, 0.0 );
    glMatrixMode( GL_PROJECTION );
    gluOrtho2D( 0.0, 800.0, 0.0, 600.0 );
}
bool isEqual() {
    for( int i = 0; i < 4; ++i ) {
        if( fabs( mat[i][0] - newMat[i][0] ) >= 1e-6 ) return false;
        if( fabs( mat[i][1] - newMat[i][1] ) >= 1e-6 ) return false;
    }
    return true;
}
void display() {
    glClear( GL_COLOR_BUFFER_BIT );
    glBegin( GL_POLYGON );
        glColor3f( 1.0, 0.0, 0.0 );
        for( int i = 0; i < 4; ++i )
            glVertex2d( mat[i][0], mat[i][1] );
    glEnd();
    glFlush();

    if( !isEqual() ) {
        glBegin( GL_POLYGON );
            glColor3f( 0.0, 1.0, 0.0 ); //移動後用綠色矩陣表示
            for( int i = 0; i < 4; ++i )
                glVertex2d( newMat[i][0], newMat[i][1] );
        glEnd();
        glFlush();
    }
}
bool isInner( int x, int y ) {
    unsigned short int c = 0;
    if( x < newMat[0][0] ) c |= 1; c <<= 1;
    if( x > newMat[1][0] ) c |= 1; c <<= 1;
    if( y > newMat[2][1] ) c |= 1; c <<= 1;
    if( y < newMat[0][1] ) c |= 1;
    if( c == 0 ) return true;
    else return false;
}
void mouse_process( int button, int state, int x, int y ) {
    /*
    if( button == GLUT_LEFT_BUTTON && state == GLUT_DOWN ) {

    }
    */
}
void mouse_process_active( int x, int y ) {
    y = 600 - y; //因為獲取的滑鼠位置
    if( isInner( x, y ) ) {
        double avgx = ( newMat[0][0] + newMat[1][0] ) / 2.0;
        double avgy = ( newMat[0][1] + newMat[3][1] ) / 2.0;

        double dx = x - avgx;
        double dy = y - avgy;
        for(int i = 0; i < 4; ++i) {
            newMat[i][0] += dx;
            newMat[i][1] += dy;

            if( newMat[i][0] > 800) {
                int dx = newMat[i][0] - 800;
                for(int j = 0; j < 4; ++j)
                    newMat[j][0] -= dx;
                MessageBox( NULL, TEXT("Coordinate out of range"), TEXT("Warning"), MB_ICONWARNING | MB_OK );
                Sleep(1000);
            } else if( newMat[i][0] < 0 ){
                int dx = 0 - newMat[i][0];
                for(int j = 0; j < 4; ++j)
                    newMat[j][0] += dx;
                MessageBox( NULL, TEXT("Coordinate out of range"), TEXT("Warning"), MB_ICONWARNING | MB_OK );
                Sleep(1000);
            } else if( newMat[i][1] > 600 ){
                int dy = newMat[i][1] - 600;
                for(int j = 0; j < 4; ++j)
                    newMat[j][1] -= dy;
                MessageBox( NULL, TEXT("Coordinate out of range"), TEXT("Warning"), MB_ICONWARNING | MB_OK );
                Sleep(1000);
            } else if( newMat[i][1] < 0 ) {
                int dy = 0 - newMat[i][1];
                for(int j = 0; j < 4; ++j)
                    newMat[j][1] += dy;
                MessageBox( NULL, TEXT("Coordinate out of range"), TEXT("Warning"), MB_ICONWARNING | MB_OK );
                Sleep(1000);
            }
        }
        glutPostRedisplay();
    }
}
void mouse_process_passtive( int x, int y ) {}
int main( int argv, char** argc ) {
    glutInit( &argv, argc );
    glutInitDisplayMode( GLUT_SINGLE | GLUT_RGBA );
    glutInitWindowPosition( 100, 100 );
    glutInitWindowSize( 800, 600 );
    glutCreateWindow( "Lab 3" );
    init();

    glutDisplayFunc( display );
    glutMouseFunc( mouse_process );
    glutMotionFunc( mouse_process_active );
    glutPassiveMotionFunc( mouse_process_passtive );

    glutMainLoop();
    return 0;
}