【OpenGL】水果忍者的刀鋒模擬程序

學習OpenGL的一個好玩程序,沒想到它的功能那麼厲害,有三個文件,雖然不是本人原創,是大神分享的,在這裏給大家分享一下

#ifndef _BLADE_H_  
#define _BLADE_H_  
  
#include   
#include   
  
class Blade  
{  
public :  
    int winWidth, winHeight;  
    GLint mousePosX, mousePosY;  
  
    Blade();  
    ~Blade();  
  
    void drawBlade(void );  
    void sampleFadeBlade(void);  
    void mouse2BladeState(int btn, int state, int x, int y);  
  
    void recordOrthoData(GLfloat left, GLfloat right, GLfloat bottom, GLfloat up);  
  
private :  
    static const int MAXTIMER = 10;  
    static const int vertexArrHead = 0;  
    static const int vertexArrTail = 20;  
    static const int POINTTHRESHOLD = 16;  
    static const GLint sampleTimerFlag = 0;  
    static const GLint fadeTimerFlag = 1;  
  
    int vertexArrStartPos;  
    //int vertexArrEndPos;  
  
    GLint pointCount;  
    GLint drawFlag;  
    GLint mouseDownFlag;      
    GLfloat bodyVertex[vertexArrTail][2];  
    GLfloat uniformSideVertex[vertexArrTail][2][2];  
    GLfloat outerSideVertex[vertexArrTail][2][2];  
    GLfloat innerSideVertex[vertexArrTail][2][2];  
    GLfloat bladeThreshold;  
  
    clock_t start[MAXTIMER], finish[MAXTIMER];  
    GLfloat sampleInterval;  
    GLfloat fadeInterval;  
  
    GLfloat orthoLeft;  
    GLfloat orthoRight;  
    GLfloat orthoBottom;  
    GLfloat orthoUp;  
  
    void init(void);  
    void calcSideVertex(GLfloat *startVertex, GLfloat *endVertex, GLfloat returnSideVertex[][2], GLfloat sideWidth, GLfloat end2StartRatio);  
    void vertexSampling();  
    GLint isTimeUp(GLint timerFlag, GLfloat timeInterval);  
    void vertexFading(void );  
    void recalculateBladeWidth(void );  
};  
  
#endif  

#include "stdafx.h"
#include "Blade.h"  
#include   
#include   
//#include   
#include    
//#include   
  
Blade::Blade()  
{  
    winWidth = 0;  
    winHeight = 0;  
    mousePosX = 0;  
    mousePosY = 0;  
  
    vertexArrStartPos = 0;  
    //vertexArrEndPos = 0;  
  
    pointCount = 0;  
    drawFlag = 0;  
    mouseDownFlag = 0;      
  
    sampleInterval = 0.015f;  
    fadeInterval = 0.02f;  
  
    bladeThreshold = 0.032f;  
  
    init();  
}  
  
Blade::~Blade()  
{}  
  
void Blade::calcSideVertex(GLfloat *startVertex, GLfloat *endVertex, GLfloat returnSideVertex[][2], GLfloat sideWidth, GLfloat end2StartRatio)  
{  
    GLfloat tmpAngle = 0.0;  
    GLfloat tmpVertex[2] = {0.0f, 0.0f};  
    GLfloat tmpSideVertex[2][2] = {{0.0f, 0.0f}, {0.0f, 0.0f}};  
    GLfloat tmpResult = 0.0;  
  
    tmpAngle = atan((endVertex[1] - startVertex[1])/(endVertex[0] - startVertex[0]));  
  
    tmpVertex[0] = endVertex[0]-(endVertex[0]-startVertex[0])*end2StartRatio;  
    tmpVertex[1] = endVertex[1]-(endVertex[1]-startVertex[1])*end2StartRatio;  
  
    if (endVertex[0] > startVertex[0]) {  
        tmpSideVertex[0][0] = tmpVertex[0] + (sideWidth * sin(tmpAngle));  
        tmpSideVertex[0][1] = tmpVertex[1] - (sideWidth * cos(tmpAngle));  
        tmpSideVertex[1][0] = tmpVertex[0] - (sideWidth * sin(tmpAngle));  
        tmpSideVertex[1][1] = tmpVertex[1] + (sideWidth * cos(tmpAngle));  
    } else {  
        tmpSideVertex[0][0] = tmpVertex[0] - (sideWidth * sin(tmpAngle));  
        tmpSideVertex[0][1] = tmpVertex[1] + (sideWidth * cos(tmpAngle));  
        tmpSideVertex[1][0] = tmpVertex[0] + (sideWidth * sin(tmpAngle));  
        tmpSideVertex[1][1] = tmpVertex[1] - (sideWidth * cos(tmpAngle));  
    }  
  
    //判斷點在向量的左邊還是右邊  
    tmpResult = (startVertex[0] - tmpSideVertex[0][0])*(endVertex[1] - tmpSideVertex[0][1]) - (startVertex[1] - tmpSideVertex[0][1])*(endVertex[0] - tmpSideVertex[0][0]);  
    if (tmpResult > 0.0f) {  
        returnSideVertex[0][0] = tmpSideVertex[1][0];  
        returnSideVertex[0][1] = tmpSideVertex[1][1];  
        returnSideVertex[1][0] = tmpSideVertex[0][0];  
        returnSideVertex[1][1] = tmpSideVertex[0][1];  
    } else {  
        returnSideVertex[0][0] = tmpSideVertex[0][0];  
        returnSideVertex[0][1] = tmpSideVertex[0][1];  
        returnSideVertex[1][0] = tmpSideVertex[1][0];  
        returnSideVertex[1][1] = tmpSideVertex[1][1];  
    }  
}  
  
void Blade::init(void)  
{  
    int i = 0;  
  
    for (i = 0; i < vertexArrTail; i++)    {  
        bodyVertex[i][0] = 0.0f;  
        bodyVertex[i][1] = 0.0f;  
  
        uniformSideVertex[i][0][0] = 0.0f;  
        uniformSideVertex[i][0][1] = 0.0f;  
        uniformSideVertex[i][1][0] = 0.0f;  
        uniformSideVertex[i][1][1] = 0.0f;  
  
        outerSideVertex[i][0][0] = 0.0f;  
        outerSideVertex[i][0][1] = 0.0f;  
        outerSideVertex[i][1][0] = 0.0f;  
        outerSideVertex[i][1][1] = 0.0f;  
  
        innerSideVertex[i][0][0] = 0.0f;  
        innerSideVertex[i][0][1] = 0.0f;  
        innerSideVertex[i][1][0] = 0.0f;  
        innerSideVertex[i][1][1] = 0.0f;          
    }  
}  
  
void Blade::vertexSampling()  
{  
    int tmpIndex1 = 0, tmpIndex2 = 0;  
    GLfloat uniformX = 0.0f, uniformY = 0.0f;  
    GLfloat realX = 0.0f, realY = 0.0f;  
    drawFlag = 0;  
    pointCount++;  
  
    uniformX = (GLfloat)mousePosX / (GLfloat)winWidth;  
    uniformY = (GLfloat)(winHeight - mousePosY) / (GLfloat)winHeight;  
    realX = uniformX*(orthoRight - orthoLeft) + orthoLeft;  
    realY = uniformY*(orthoUp - orthoBottom) + orthoBottom;  
    if (pointCount == 0) {  
        bodyVertex[vertexArrStartPos][0] = realX;  
        bodyVertex[vertexArrStartPos][1] = realY;  
    } else {  
        tmpIndex1 = (vertexArrStartPos + pointCount - 1)%vertexArrTail;  
        tmpIndex2 = (tmpIndex1 + 1)%vertexArrTail;  
  
        bodyVertex[tmpIndex2][0] = realX;  
        bodyVertex[tmpIndex2][1] = realY;  
  
        calcSideVertex(bodyVertex[tmpIndex1], bodyVertex[tmpIndex2], uniformSideVertex[tmpIndex2], bladeThreshold, 0.4);  
    }      
    if (pointCount >= 3)  
        drawFlag = 1;  
    //vertexArrEndPos++;  
    //if (vertexArrEndPos >= vertexArrTail)  
    //    vertexArrEndPos -= vertexArrTail;  
}  
  
GLint Blade::isTimeUp(GLint timerFlag, GLfloat timeInterval)  
{  
    double duration = 0.0;  
  
    finish[timerFlag] = clock();  
    duration = (double)(finish[timerFlag] - start[timerFlag]) / CLOCKS_PER_SEC;  
    if (duration >= timeInterval) {  
        start[timerFlag] = clock();  
        return 1;  
    }  
    return 0;  
}  
  
void Blade::vertexFading()  
{  
    vertexArrStartPos++;  
    if (vertexArrStartPos >= vertexArrTail)  
        vertexArrStartPos -= vertexArrTail;  
    pointCount--;  
    if (pointCount <= 2)  
        drawFlag = 0;  
}  
  
void Blade::recalculateBladeWidth(void )  
{  
    int i = 0;      
    int tmpIndex = 0;  
    GLfloat ratio = 0.0f;  
    GLfloat tmp[4] = {0.0f, 0.0f, 0.0f, 0.0f};  
  
    //reclaculate the blade width  
    for (i = 1; i < pointCount - 1; i++) {  
        tmpIndex = (vertexArrStartPos + i)%vertexArrTail;  
        tmp[0] = uniformSideVertex[tmpIndex][0][0] + uniformSideVertex[tmpIndex][1][0];  
        tmp[1] = uniformSideVertex[tmpIndex][0][0] - uniformSideVertex[tmpIndex][1][0];  
        tmp[2] = uniformSideVertex[tmpIndex][0][1] + uniformSideVertex[tmpIndex][1][1];  
        tmp[3] = uniformSideVertex[tmpIndex][0][1] - uniformSideVertex[tmpIndex][1][1];  
        if (i == (pointCount-2))  
            ratio = 1.0;  
        else  
            ratio = (GLfloat)i/(GLfloat)pointCount;  
  
        outerSideVertex[tmpIndex][0][0] = 0.5*(tmp[0] + ratio*tmp[1]);  
        outerSideVertex[tmpIndex][0][1] = 0.5*(tmp[2] + ratio*tmp[3]);  
        outerSideVertex[tmpIndex][1][0] = 0.5*(tmp[0] - ratio*tmp[1]);  
        outerSideVertex[tmpIndex][1][1] = 0.5*(tmp[2] - ratio*tmp[3]);  
  
        innerSideVertex[tmpIndex][0][0] = 0.5*(tmp[0] + ratio*2.0/3.0*tmp[1]);  
        innerSideVertex[tmpIndex][0][1] = 0.5*(tmp[2] + ratio*2.0/3.0*tmp[3]);  
        innerSideVertex[tmpIndex][1][0] = 0.5*(tmp[0] - ratio*2.0/3.0*tmp[1]);  
        innerSideVertex[tmpIndex][1][1] = 0.5*(tmp[2] - ratio*2.0/3.0*tmp[3]);  
    }  
}  
  
  
  
void Blade::drawBlade()  
{  
    int i = 0;  
  
    //printf("%d\n", pointCount);  
    //printf("%d\n", vertexArrStartPos);  
    //printf("Flag:%d\n\n", drawFlag);  
  
    if (drawFlag == 0){  
        return;  
    }  
  
    /*****--------------------------------------*****/  
    //glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);  
    //glPolygonMode(GL_FRONT, GL_LINE);  
    /*****--------------------------------------*****/  
    //draw the outer blade  
    glColor4f(0.2f, 0.2f, 0.9f, 0.5f);  
    glBegin(GL_POLYGON);  
    glVertex2fv(bodyVertex[vertexArrStartPos]);  
    glVertex2fv(outerSideVertex[(vertexArrStartPos+1)%vertexArrTail][0]);  
    glVertex2fv(outerSideVertex[(vertexArrStartPos+1)%vertexArrTail][1]);  
    glEnd();  
    for (i = 1; i < pointCount - 2; i++)    {  
        glBegin(GL_POLYGON);  
        glVertex2fv(outerSideVertex[(vertexArrStartPos + i)%vertexArrTail][0]);  
        glVertex2fv(outerSideVertex[(vertexArrStartPos + i + 1)%vertexArrTail][0]);  
        glVertex2fv(outerSideVertex[(vertexArrStartPos + i)%vertexArrTail][1]);  
        glEnd();  
        glBegin(GL_POLYGON);  
        glVertex2fv(outerSideVertex[(vertexArrStartPos + i + 1)%vertexArrTail][1]);  
        glVertex2fv(outerSideVertex[(vertexArrStartPos + i)%vertexArrTail][1]);  
        glVertex2fv(outerSideVertex[(vertexArrStartPos + i + 1)%vertexArrTail][0]);  
        glEnd();  
    }  
    glBegin(GL_POLYGON);  
    glVertex2fv(outerSideVertex[(vertexArrStartPos + pointCount - 2)%vertexArrTail][0]);          
    glVertex2fv(bodyVertex[(vertexArrStartPos + pointCount - 1)%vertexArrTail]);  
    glVertex2fv(outerSideVertex[(vertexArrStartPos + pointCount - 2)%vertexArrTail][1]);  
    glEnd();  
  
  
    //draw the inner blade  
    glColor4f(1.0f, 1.0f, 1.0f, 1.0f);  
    glBegin(GL_POLYGON);  
    glVertex2fv(bodyVertex[vertexArrStartPos]);  
    glVertex2fv(innerSideVertex[(vertexArrStartPos+1)%vertexArrTail][0]);  
    glVertex2fv(innerSideVertex[(vertexArrStartPos+1)%vertexArrTail][1]);  
    glEnd();  
  
    for (i = 1; i < pointCount - 2; i++)    {  
        glBegin(GL_POLYGON);  
        glVertex2fv(innerSideVertex[(vertexArrStartPos + i)%vertexArrTail][0]);  
        glVertex2fv(innerSideVertex[(vertexArrStartPos + i + 1)%vertexArrTail][0]);  
        glVertex2fv(innerSideVertex[(vertexArrStartPos + i)%vertexArrTail][1]);  
        glEnd();  
        glBegin(GL_POLYGON);  
        glVertex2fv(innerSideVertex[(vertexArrStartPos + i + 1)%vertexArrTail][1]);  
        glVertex2fv(innerSideVertex[(vertexArrStartPos + i)%vertexArrTail][1]);  
        glVertex2fv(innerSideVertex[(vertexArrStartPos + i + 1)%vertexArrTail][0]);  
        glEnd();  
    }  
    glBegin(GL_POLYGON);  
    glVertex2fv(innerSideVertex[(vertexArrStartPos + pointCount - 2)%vertexArrTail][0]);          
    glVertex2fv(bodyVertex[(vertexArrStartPos + pointCount - 1)%vertexArrTail]);  
    glVertex2fv(innerSideVertex[(vertexArrStartPos + pointCount - 2)%vertexArrTail][1]);  
    glEnd();  
}  
  
void Blade::sampleFadeBlade(void)  
{  
    if (mouseDownFlag == 1) {  
        sampleInterval = (pointCount <= 2 ? 0.005 : 0.015);  
  
        if (isTimeUp(sampleTimerFlag, sampleInterval) == 1) {  
            vertexSampling();  
            recalculateBladeWidth();  
            glutPostRedisplay();  
        }  
    }  
  
    if (pointCount > 0) {  
        fadeInterval = (pointCount >= POINTTHRESHOLD ? 0.0 : 0.016);  
        fadeInterval = (mouseDownFlag == 0 ? 0.0 : fadeInterval);  
        //printf("%f\n", fadeInterval);  
  
        if (isTimeUp(fadeTimerFlag, fadeInterval) == 1) {  
            vertexFading();  
            recalculateBladeWidth();  
            glutPostRedisplay();  
        }  
    }  
}  
  
void Blade::mouse2BladeState(int btn, int state, int x, int y)  
{  
    if (btn == GLUT_LEFT_BUTTON) {  
        if (state == GLUT_DOWN) {              
            mousePosX = x;  
            mousePosY = y;  
            mouseDownFlag = 1;  
  
            start[sampleTimerFlag] = clock();  
            start[fadeTimerFlag] = clock();  
  
            pointCount = 0;  
        } else if (state == GLUT_UP) {  
            mouseDownFlag = 0;  
        }  
    }  
}  
  
void Blade::recordOrthoData(GLfloat left, GLfloat right, GLfloat bottom, GLfloat up)  
{  
    orthoLeft = left;  
    orthoRight = right;  
    orthoBottom = bottom;  
    orthoUp = up;  
}  
#include "stdafx.h"
#include   
#include   
#include "Blade.h"  
  
#ifndef _LINUX_  
#include   
void mySleep(int millisecond) {Sleep(millisecond);};  
#else  
#include   
void mySleep(int millisecond) {sleep((float)millisecond/1000.0);};  
#endif  
  
Blade myBlade;  
  
const int sleepTime = 1;  
  
void display(void )  
{  
    glClearColor(0.3f, 0.3f, 0.3f, 1.0f);  
    glClear(GL_COLOR_BUFFER_BIT);  
  
    myBlade.drawBlade();  
  
    glutSwapBuffers();  
}  
  
void mouseButton(int btn, int state, int x, int y)  
{  
    myBlade.mouse2BladeState(btn, state, x, y);  
    //if (btn == GLUT_RIGHT_BUTTON)  
    //    glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);  
}  
  
void reshape(int w, int h)  
{  
    myBlade.winWidth = w;  
    myBlade.winHeight = h;  
}  
  
void mouseMove(int x, int y)  
{  
    myBlade.mousePosX = x;  
    myBlade.mousePosY = y;  
}  
  
void idle(void)  
{  
    mySleep(sleepTime);  
  
    myBlade.sampleFadeBlade();  
}  
int main(int argc, char *argv[])  
{  
    glutInit(&argc, argv);  
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);  
    glutInitWindowPosition(100, 100);  
    glutInitWindowSize(800, 600);  
    glutCreateWindow("Ninjia blade");  
  
    gluOrtho2D(0.0f, 1.0f, 0.0f, 1.0f);  
    myBlade.recordOrthoData(0.0f, 1.0f, 0.0f, 1.0f);  
    //gluOrtho2D(0.0f, -1.0f, -2.0f, 1.0f);  
    //myBlade.recordOrthoData(0.0f, -1.0f, -2.0f, 1.0f);  
    glEnable(GL_LINE_SMOOTH);  
  
    glEnable(GL_CULL_FACE);  
    glFrontFace(GL_CCW);  
  
    glutDisplayFunc(&display);  
    glutMouseFunc(&mouseButton);  
    glutReshapeFunc(&reshape);  
    glutMotionFunc(&mouseMove);  
    glutIdleFunc(&idle);  
  
    glutMainLoop();  
    return 0;  
}  


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