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