http://www.cnblogs.com/lghost/archive/2012/05/05/2484888.html
修复版1
修复版2
之前在视频中许诺过五一之后写个关于这个刀锋实现的文章的,但发现最近真的很忙。。。。所以。。。先放出到现在为止的源代码,具体实现思路和方法以后再补上。
Ninja.cpp
#include <Windows.h> #include <GL/glut.h> #include "Blade.h" #ifndef _LINUX_ #include <windows.h> void mySleep(int millisecond) {Sleep(millisecond);}; #else #include <unistd.h> 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; }
Blade.h
#ifndef _BLADE_H_ #define _BLADE_H_ #include <GL/glut.h> #include <time.h> 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
Blade.cpp
#include "Blade.h" #include <GL/glut.h> #include <math.h> //#include <stdio.h> #include <time.h> //#include <stdlib.h> 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; }
只要将以上三个文件放到同一个工程编译即可。
程序入口(main函数)在Ninjia.cpp文件中定义。
对了!要感谢这篇文章的作者,他给了我思路。其实,我的工作也大概是将他的翻译成OpenGL版本并且再做点修改而已。
http://www.blogjava.net/oathleo/archive/2011/09/23/android_Fruit_Ninja.html