Sei sulla pagina 1di 6

/* Start Header ****************************************************************

*/
/*!
/file Path.cpp
/author Team42, Jiawei Gu
/e-mail jiawei.gu@digipen.edu
/date 10/24/2015
/Brief Copyright (C) 2015 DigiPen Institute of Technology. Reproduction or
disclosure of this file or its contents without the prior written consent of
DigiPen Institute of Technology is prohibited.
*/
/* End Header ******************************************************************
*/
#include "Path.h"
#define CURVE_TABLE_ERROR 1e-4
namespace Anime
{
Path::Path() :
spline(),
accS(0.0f),
direction(0, 0, 0),
controlPointsCount(0),
interPolatedPointsCount(0),
drawControlPoints(true),
drawPath(true)
{
VAO[0] = 0; VAO[1] = 0;
VBO[0] = 0; VBO[1] = 0;
spline.SetAutoCalculate(false);
}
void Path::AddControlPoint(const Vector3 & point)
{
controlPoints.push_back(point);
}
void Path::UpdateControlPoint(unsigned int index, const Vector3 & point)
{
controlPoints[index] = point;
}
void Path::CalculatePath()
{
spline.SetControlPoints(controlPoints);
spline.RecalculateTangents();
wholePath.clear();
curveTable.Clear();
wholePath.push_back(controlPoints[0]);
curveTable.AddIncreaseLength(0.0f, 0.0f);
if (controlPoints.size() > 1)
{
float deltaU = 1.0f / (controlPoints.size() - 1);
for (unsigned int i = 0; i < controlPoints.size() - 1; +
+i)
MakeCurveTable(controlPoints[i], controlPoints[i

+ 1], deltaU * i, deltaU * (i + 1));


}
Reset();
SetupOpenGL();
}
void Path::MakeCurveTable(const Vector3 & pointA, const Vector3 & pointB
, float uA, float uB)
{
Vector3 linearMid = (pointA + pointB) * 0.5f;
float uMid = (uA + uB) * 0.5f;
Vector3 interMid = spline.Interpolate(uMid);
if (linearMid.SquaredDistance(interMid) < CURVE_TABLE_ERROR)
{
wholePath.push_back(pointB);
curveTable.AddIncreaseLength(pointA.Distance(pointB), uB
);
}
else
{
MakeCurveTable(pointA, interMid, uA, uMid);
MakeCurveTable(interMid, pointB, uMid, uB);
}
}
void Path::Update(float dt, float * speed, float maxSpeed, float accelar
ation)
{
if (maxSpeed == 0.0f)
{
*speed = 0.0f;
return;
}
float s = curveTable.GetTotalCurveLength() * (1.0f - accS);
float t1, t2;
// case 1: for current v_c, slow down the speed can guarantee co
vering the rest path
//
v_c
//
|\
//
| \
//
| \ t
// t1 = t2 = 0
if ((*speed / accelaration) * (*speed / accelaration) * accelara
tion >= s)
t1 = t2 = 0;
else if (*speed < maxSpeed)
{
float vx = sqrt(accelaration * s + (*speed) * (*speed) /
2.0f);
// case 2: still need accelaration, but won't hit the ma
x speed
//
v_x
//
/|\
// v_c / | \
//
| | \ t
//
t1 = t2
if (vx <= maxSpeed)

t1 = t2 = (vx - *speed) / accelaration;


// case 3: still need accelaration, and will hit the max
speed
// v_max _______
//
/|
|\
// v_c / |
| \
//
| |
| \
//
0 t1
t2 t
else
{
t1 = (maxSpeed - *speed) / accelaration;
t2 = s / maxSpeed - *speed * (2 * maxSpeed - *sp
eed) / (2 * accelaration * maxSpeed);
}
}
else //if (*speed == maxSpeed)
{
// case 4: in the max speed
// v_c = v_max _______
//
|
|\
//
|
| \
//
|
| \
//
t1 = 0 t2 t
t1 = 0;
t2 = s / maxSpeed - maxSpeed / (2 * accelaration);
}
if (dt < t1)
{
*speed += accelaration * dt;
if (*speed > maxSpeed)
*speed = maxSpeed;
}
else if (dt > t2)
{
*speed -= accelaration * dt;
if (*speed < 0.0f)
*speed = 0.0f;
}
else
{
if (*speed > maxSpeed)
{
*speed -= accelaration * dt;
if (*speed < maxSpeed)
*speed = maxSpeed;
}
else if (*speed < maxSpeed)
{
*speed += accelaration * dt;
if (*speed > maxSpeed)
*speed = maxSpeed;
}
}
float moveTime = curveTable.GetTotalCurveLength() / *speed;
if (accS < 1.0f)
{
accS += dt/moveTime;

if (accS > 1.0f)


accS = 1.0f;
}
if (controlPoints.size() > 1)
{
curPos = nextPos;
unsigned int index = curveTable.BinarySearch(accS);
float deltaU = curveTable.GetParaU(index + 1) - curveTab
le.GetParaU(index);
float k = deltaU / (curveTable.GetCurveLength(index + 1)
- curveTable.GetCurveLength(index));
// u = u_i + k * (s - s_i), where k = deltaU / (s_i+1 s_i)
float u = curveTable.GetParaU(index) + k * (accS - curve
Table.GetCurveLength(index));
nextPos = spline.Interpolate(u);
}
}
void Path::Clear()
{
controlPoints.clear();
wholePath.clear();
curveTable.Clear();
AddControlPoint(Vector3(0, 0, 0));
Reset();
}
void Path::Reset()
{
nextPos = curPos = Vector3(0, 0, 0);
direction = Vector3::UNIT_Z;
accS = 0.0f;
controlPointsCount = controlPoints.size();
interPolatedPointsCount = wholePath.size();
}
Transform Path::GetTransform()
{
Vector3 newDir = nextPos - curPos;
if (newDir.SquaredLength() > Math::EPSILON)
direction = newDir;
Quaternion rot = Vector3::UNIT_Z.GetRotationTo(direction, Vector
3::UNIT_Y);
Transform trans(curPos, rot, 1);
return trans;
}
unsigned int Path::GetControlPointsNum() const
{
return controlPoints.size();
}
unsigned int Path::GetClosestPointIndex(const Vector3 & click) const
{
assert(controlPoints.size() > 1);
float minDistance = click.SquaredDistance(controlPoints[1]);

unsigned int index = 1;


for (unsigned int i = 2; i < controlPoints.size(); ++i)
{
if (click.SquaredDistance(controlPoints[i]) < minDistanc
e)
{
minDistance = click.SquaredDistance(controlPoint
s[i]);
index = i;
}
}
return index;
}
float Path::GetPathLength() const
{
return curveTable.GetTotalCurveLength();
}
void Path::SetupOpenGL()
{
if (VAO != 0)
glDeleteVertexArrays(1, VAO);
if (VBO != 0)
glDeleteBuffers(1, VBO);
glGenVertexArrays(2, VAO);
glGenBuffers(2, VBO);
glBindVertexArray(VAO[0]);
glBindBuffer(GL_ARRAY_BUFFER, VBO[0]);
glBufferData(GL_ARRAY_BUFFER, controlPoints.size() * sizeof(Vect
or3), &controlPoints[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glBindVertexArray(0);
glBindVertexArray(VAO[1]);
glBindBuffer(GL_ARRAY_BUFFER, VBO[1]);
glBufferData(GL_ARRAY_BUFFER, wholePath.size() * sizeof(Vector3)
, &wholePath[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glBindVertexArray(0);
}
void Path::DrawControlPoints()
{
if (drawControlPoints)
{
glBindVertexArray(VAO[0]);
glDrawArrays(GL_POINTS, 0, controlPoints.size());
glBindVertexArray(0);
}
}

void Path::DrawPath()
{
if (drawPath)
{
glBindVertexArray(VAO[1]);
glDrawArrays(GL_LINES, 0, wholePath.size());
glBindVertexArray(0);
}
}
void Path::SetupEditor(EditorUnit * editor)
{
editor->AddVariableRO("Control Pts", "Path", &controlPointsCount
);
editor->AddVariableRO("Inter Pts", "Path", &interPolatedPointsCo
unt);
editor->AddVariableRW("Draw Ctrl Pts", "Path", &drawControlPoint
s);
editor->AddVariableRW("Draw Path", "Path", &drawPath);
}
void Path::SwitchDrawControlPoints()
{
drawControlPoints = !drawControlPoints;
}
void Path::SwitchDrawPath()
{
drawPath = !drawPath;
}
}

Potrebbero piacerti anche