434 lines
13 KiB
C++
434 lines
13 KiB
C++
// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
|
|
// Copyright (C) 2010 Winch Gate Property Limited
|
|
//
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU Affero General Public License as
|
|
// published by the Free Software Foundation, either version 3 of the
|
|
// License, or (at your option) any later version.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU Affero General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU Affero General Public License
|
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
#include "std3d.h"
|
|
|
|
#include "nel/3d/bezier_patch.h"
|
|
|
|
using namespace NLMISC;
|
|
|
|
namespace NL3D {
|
|
|
|
// ***************************************************************************
|
|
void CBezierPatch::make(CVector vertices[4], CVector normals[4])
|
|
{
|
|
sint i;
|
|
static sint starts[8]= {0,1, 1,2, 2,3, 3,0};
|
|
static sint ends[8]= {1,0, 2,1, 3,2, 0,3};
|
|
|
|
for(i=0;i<4;i++)
|
|
Vertices[i]= vertices[i];
|
|
|
|
// For all tangents.
|
|
for(i=0;i<8;i++)
|
|
{
|
|
CVector tgt= Vertices[ends[i]] - Vertices[starts[i]];
|
|
CVector I,J,K;
|
|
J= normals[starts[i]];
|
|
I= J^tgt;
|
|
K= I^J;
|
|
K.normalize();
|
|
// Yes, we store tangents as position, not vectors...
|
|
Tangents[i]= Vertices[starts[i]] + K*tgt.norm()/3;
|
|
}
|
|
|
|
makeInteriors();
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CBezierPatch::makeInteriors()
|
|
{
|
|
CVector &a = Vertices[0];
|
|
CVector &b = Vertices[1];
|
|
CVector &c = Vertices[2];
|
|
CVector &d = Vertices[3];
|
|
Interiors[0] = Tangents[7] + Tangents[0] - a;
|
|
Interiors[1] = Tangents[1] + Tangents[2] - b;
|
|
Interiors[2] = Tangents[3] + Tangents[4] - c;
|
|
Interiors[3] = Tangents[5] + Tangents[6] - d;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CBezierPatch::applyMatrix(const CMatrix &m)
|
|
{
|
|
sint i;
|
|
|
|
for(i=0;i<4;i++)
|
|
Vertices[i]= m*Vertices[i];
|
|
for(i=0;i<8;i++)
|
|
Tangents[i]= m*Tangents[i];
|
|
for(i=0;i<4;i++)
|
|
Interiors[i]= m*Interiors[i];
|
|
}
|
|
|
|
// ***************************************************************************
|
|
static inline void mulAdd(CVector &tgt, const CVector &src, float f)
|
|
{
|
|
tgt.x+= src.x*f;
|
|
tgt.y+= src.y*f;
|
|
tgt.z+= src.z*f;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
static inline void mulAddD(CVectorD &tgt, const CVector &src, double f)
|
|
{
|
|
tgt.x+= src.x*f;
|
|
tgt.y+= src.y*f;
|
|
tgt.z+= src.z*f;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
CVector CBezierPatch::eval(float ps, float pt) const
|
|
{
|
|
CVector p;
|
|
|
|
float ps2 = ps * ps;
|
|
float ps1 = 1.0f - ps;
|
|
float ps12 = ps1 * ps1;
|
|
float s0 = ps12 * ps1;
|
|
float s1 = 3.0f * ps * ps12;
|
|
float s2 = 3.0f * ps2 * ps1;
|
|
float s3 = ps2 * ps;
|
|
float pt2 = pt * pt;
|
|
float pt1 = 1.0f - pt;
|
|
float pt12 = pt1 * pt1;
|
|
float t0 = pt12 * pt1;
|
|
float t1 = 3.0f * pt * pt12;
|
|
float t2 = 3.0f * pt2 * pt1;
|
|
float t3 = pt2 * pt;
|
|
|
|
p.set(0,0,0);
|
|
mulAdd(p, Vertices[0] , s0 * t0);
|
|
mulAdd(p, Tangents[7] , s1 * t0);
|
|
mulAdd(p, Tangents[6] , s2 * t0);
|
|
mulAdd(p, Vertices[3] , s3 * t0);
|
|
mulAdd(p, Tangents[0] , s0 * t1);
|
|
mulAdd(p, Interiors[0], s1 * t1);
|
|
mulAdd(p, Interiors[3], s2 * t1);
|
|
mulAdd(p, Tangents[5] , s3 * t1);
|
|
mulAdd(p, Tangents[1] , s0 * t2);
|
|
mulAdd(p, Interiors[1], s1 * t2);
|
|
mulAdd(p, Interiors[2], s2 * t2);
|
|
mulAdd(p, Tangents[4] , s3 * t2);
|
|
mulAdd(p, Vertices[1] , s0 * t3);
|
|
mulAdd(p, Tangents[2] , s1 * t3);
|
|
mulAdd(p, Tangents[3] , s2 * t3);
|
|
mulAdd(p, Vertices[2] , s3 * t3);
|
|
|
|
return p;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
CVectorD CBezierPatch::evalDouble(double ps, double pt) const
|
|
{
|
|
CVectorD p;
|
|
|
|
double ps2 = ps * ps;
|
|
double ps1 = 1.0f - ps;
|
|
double ps12 = ps1 * ps1;
|
|
double s0 = ps12 * ps1;
|
|
double s1 = 3.0f * ps * ps12;
|
|
double s2 = 3.0f * ps2 * ps1;
|
|
double s3 = ps2 * ps;
|
|
double pt2 = pt * pt;
|
|
double pt1 = 1.0f - pt;
|
|
double pt12 = pt1 * pt1;
|
|
double t0 = pt12 * pt1;
|
|
double t1 = 3.0f * pt * pt12;
|
|
double t2 = 3.0f * pt2 * pt1;
|
|
double t3 = pt2 * pt;
|
|
|
|
p.set(0,0,0);
|
|
mulAddD(p, Vertices[0] , s0 * t0);
|
|
mulAddD(p, Tangents[7] , s1 * t0);
|
|
mulAddD(p, Tangents[6] , s2 * t0);
|
|
mulAddD(p, Vertices[3] , s3 * t0);
|
|
mulAddD(p, Tangents[0] , s0 * t1);
|
|
mulAddD(p, Interiors[0], s1 * t1);
|
|
mulAddD(p, Interiors[3], s2 * t1);
|
|
mulAddD(p, Tangents[5] , s3 * t1);
|
|
mulAddD(p, Tangents[1] , s0 * t2);
|
|
mulAddD(p, Interiors[1], s1 * t2);
|
|
mulAddD(p, Interiors[2], s2 * t2);
|
|
mulAddD(p, Tangents[4] , s3 * t2);
|
|
mulAddD(p, Vertices[1] , s0 * t3);
|
|
mulAddD(p, Tangents[2] , s1 * t3);
|
|
mulAddD(p, Tangents[3] , s2 * t3);
|
|
mulAddD(p, Vertices[2] , s3 * t3);
|
|
|
|
return p;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
CVector CBezierPatch::evalNormal(float ps, float pt) const
|
|
{
|
|
CVector tgtS, tgtT;
|
|
|
|
float s0,s1,s2,s3;
|
|
float t0,t1,t2,t3;
|
|
float ps2 = ps * ps;
|
|
float ps1 = 1.0f - ps;
|
|
float ps12 = ps1 * ps1;
|
|
float pt2 = pt * pt;
|
|
float pt1 = 1.0f - pt;
|
|
float pt12 = pt1 * pt1;
|
|
|
|
// Compute tangentS
|
|
//=================
|
|
// s/ds.
|
|
s0 = -3* ps12;
|
|
s1 = 9*ps2 + 3 -12*ps;
|
|
s2 =-9*ps2 + 6*ps ;
|
|
s3 = 3* ps2;
|
|
// t/dt.
|
|
t0 = pt12 * pt1;
|
|
t1 = 3.0f * pt * pt12;
|
|
t2 = 3.0f * pt2 * pt1;
|
|
t3 = pt2 * pt;
|
|
|
|
tgtS.set(0,0,0);
|
|
mulAdd(tgtS, Vertices[0] , s0 * t0);
|
|
mulAdd(tgtS, Tangents[7] , s1 * t0);
|
|
mulAdd(tgtS, Tangents[6] , s2 * t0);
|
|
mulAdd(tgtS, Vertices[3] , s3 * t0);
|
|
mulAdd(tgtS, Tangents[0] , s0 * t1);
|
|
mulAdd(tgtS, Interiors[0], s1 * t1);
|
|
mulAdd(tgtS, Interiors[3], s2 * t1);
|
|
mulAdd(tgtS, Tangents[5] , s3 * t1);
|
|
mulAdd(tgtS, Tangents[1] , s0 * t2);
|
|
mulAdd(tgtS, Interiors[1], s1 * t2);
|
|
mulAdd(tgtS, Interiors[2], s2 * t2);
|
|
mulAdd(tgtS, Tangents[4] , s3 * t2);
|
|
mulAdd(tgtS, Vertices[1] , s0 * t3);
|
|
mulAdd(tgtS, Tangents[2] , s1 * t3);
|
|
mulAdd(tgtS, Tangents[3] , s2 * t3);
|
|
mulAdd(tgtS, Vertices[2] , s3 * t3);
|
|
|
|
// Compute tangentT
|
|
//=================
|
|
// s/ds.
|
|
s0 = ps12 * ps1;
|
|
s1 = 3.0f * ps * ps12;
|
|
s2 = 3.0f * ps2 * ps1;
|
|
s3 = ps2 * ps;
|
|
// t/dt.
|
|
t0 = -3* pt12;
|
|
t1 = 9*pt2 + 3 -12*pt;
|
|
t2 =-9*pt2 + 6*pt ;
|
|
t3 = 3* pt2;
|
|
|
|
tgtT.set(0,0,0);
|
|
mulAdd(tgtT, Vertices[0] , s0 * t0);
|
|
mulAdd(tgtT, Tangents[7] , s1 * t0);
|
|
mulAdd(tgtT, Tangents[6] , s2 * t0);
|
|
mulAdd(tgtT, Vertices[3] , s3 * t0);
|
|
mulAdd(tgtT, Tangents[0] , s0 * t1);
|
|
mulAdd(tgtT, Interiors[0], s1 * t1);
|
|
mulAdd(tgtT, Interiors[3], s2 * t1);
|
|
mulAdd(tgtT, Tangents[5] , s3 * t1);
|
|
mulAdd(tgtT, Tangents[1] , s0 * t2);
|
|
mulAdd(tgtT, Interiors[1], s1 * t2);
|
|
mulAdd(tgtT, Interiors[2], s2 * t2);
|
|
mulAdd(tgtT, Tangents[4] , s3 * t2);
|
|
mulAdd(tgtT, Vertices[1] , s0 * t3);
|
|
mulAdd(tgtT, Tangents[2] , s1 * t3);
|
|
mulAdd(tgtT, Tangents[3] , s2 * t3);
|
|
mulAdd(tgtT, Vertices[2] , s3 * t3);
|
|
|
|
// Return the normal.
|
|
CVector norm= tgtT^tgtS;
|
|
norm.normalize();
|
|
return norm;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
CVector CBezierPatch::evalTangentS(float ps, float pt) const
|
|
{
|
|
CVector tgtS;
|
|
|
|
float s0,s1,s2,s3;
|
|
float t0,t1,t2,t3;
|
|
float ps2 = ps * ps;
|
|
float ps1 = 1.0f - ps;
|
|
float ps12 = ps1 * ps1;
|
|
float pt2 = pt * pt;
|
|
float pt1 = 1.0f - pt;
|
|
float pt12 = pt1 * pt1;
|
|
|
|
// Compute tangentS
|
|
//=================
|
|
// s/ds.
|
|
s0 = -3* ps12;
|
|
s1 = 9*ps2 + 3 -12*ps;
|
|
s2 =-9*ps2 + 6*ps ;
|
|
s3 = 3* ps2;
|
|
// t/dt.
|
|
t0 = pt12 * pt1;
|
|
t1 = 3.0f * pt * pt12;
|
|
t2 = 3.0f * pt2 * pt1;
|
|
t3 = pt2 * pt;
|
|
|
|
tgtS.set(0,0,0);
|
|
mulAdd(tgtS, Vertices[0] , s0 * t0);
|
|
mulAdd(tgtS, Tangents[7] , s1 * t0);
|
|
mulAdd(tgtS, Tangents[6] , s2 * t0);
|
|
mulAdd(tgtS, Vertices[3] , s3 * t0);
|
|
mulAdd(tgtS, Tangents[0] , s0 * t1);
|
|
mulAdd(tgtS, Interiors[0], s1 * t1);
|
|
mulAdd(tgtS, Interiors[3], s2 * t1);
|
|
mulAdd(tgtS, Tangents[5] , s3 * t1);
|
|
mulAdd(tgtS, Tangents[1] , s0 * t2);
|
|
mulAdd(tgtS, Interiors[1], s1 * t2);
|
|
mulAdd(tgtS, Interiors[2], s2 * t2);
|
|
mulAdd(tgtS, Tangents[4] , s3 * t2);
|
|
mulAdd(tgtS, Vertices[1] , s0 * t3);
|
|
mulAdd(tgtS, Tangents[2] , s1 * t3);
|
|
mulAdd(tgtS, Tangents[3] , s2 * t3);
|
|
mulAdd(tgtS, Vertices[2] , s3 * t3);
|
|
|
|
// Return the tgt normalized
|
|
return tgtS.normed();
|
|
}
|
|
|
|
// ***************************************************************************
|
|
CVector CBezierPatch::evalTangentT(float ps, float pt) const
|
|
{
|
|
CVector tgtT;
|
|
|
|
float s0,s1,s2,s3;
|
|
float t0,t1,t2,t3;
|
|
float ps2 = ps * ps;
|
|
float ps1 = 1.0f - ps;
|
|
float ps12 = ps1 * ps1;
|
|
float pt2 = pt * pt;
|
|
float pt1 = 1.0f - pt;
|
|
float pt12 = pt1 * pt1;
|
|
|
|
// Compute tangentT
|
|
//=================
|
|
// s/ds.
|
|
s0 = ps12 * ps1;
|
|
s1 = 3.0f * ps * ps12;
|
|
s2 = 3.0f * ps2 * ps1;
|
|
s3 = ps2 * ps;
|
|
// t/dt.
|
|
t0 = -3* pt12;
|
|
t1 = 9*pt2 + 3 -12*pt;
|
|
t2 =-9*pt2 + 6*pt ;
|
|
t3 = 3* pt2;
|
|
|
|
tgtT.set(0,0,0);
|
|
mulAdd(tgtT, Vertices[0] , s0 * t0);
|
|
mulAdd(tgtT, Tangents[7] , s1 * t0);
|
|
mulAdd(tgtT, Tangents[6] , s2 * t0);
|
|
mulAdd(tgtT, Vertices[3] , s3 * t0);
|
|
mulAdd(tgtT, Tangents[0] , s0 * t1);
|
|
mulAdd(tgtT, Interiors[0], s1 * t1);
|
|
mulAdd(tgtT, Interiors[3], s2 * t1);
|
|
mulAdd(tgtT, Tangents[5] , s3 * t1);
|
|
mulAdd(tgtT, Tangents[1] , s0 * t2);
|
|
mulAdd(tgtT, Interiors[1], s1 * t2);
|
|
mulAdd(tgtT, Interiors[2], s2 * t2);
|
|
mulAdd(tgtT, Tangents[4] , s3 * t2);
|
|
mulAdd(tgtT, Vertices[1] , s0 * t3);
|
|
mulAdd(tgtT, Tangents[2] , s1 * t3);
|
|
mulAdd(tgtT, Tangents[3] , s2 * t3);
|
|
mulAdd(tgtT, Vertices[2] , s3 * t3);
|
|
|
|
// Return the tgt normalized
|
|
return tgtT.normed();
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CBezierPatch::CBezierCurve::subdivide(CBezierCurve &left, CBezierCurve &right, float t)
|
|
{
|
|
float t1= 1-t;
|
|
|
|
// Subdivide the 2 curves.
|
|
left.P0= P0;
|
|
right.P3= P3;
|
|
|
|
left.P1= t1*P0 + t*P1;
|
|
right.P2= t1*P2 + t*P3;
|
|
CVector middle12= t1*P1 + t*P2;
|
|
|
|
left.P2= t1*left.P1 + t*middle12;
|
|
right.P1= t1*middle12 + t*right.P2;
|
|
|
|
left.P3= right.P0= t1*left.P2 + t*right.P1;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CBezierPatch::subdivideS(CBezierPatch &left, CBezierPatch &right, float s) const
|
|
{
|
|
CBezierCurve curveT[4];
|
|
CBezierCurve curveTLeft[4];
|
|
CBezierCurve curveTRight[4];
|
|
|
|
// Setup horizontal curves.
|
|
curveT[0].set(Vertices[0], Tangents[7] , Tangents[6] , Vertices[3]);
|
|
curveT[1].set(Tangents[0], Interiors[0], Interiors[3], Tangents[5]);
|
|
curveT[2].set(Tangents[1], Interiors[1], Interiors[2], Tangents[4]);
|
|
curveT[3].set(Vertices[1], Tangents[2] , Tangents[3] , Vertices[2]);
|
|
|
|
// Subdivide curves.
|
|
for(sint i=0;i<4;i++)
|
|
curveT[i].subdivide(curveTLeft[i], curveTRight[i], s);
|
|
|
|
// Setup bezier patchs.
|
|
// left.
|
|
curveTLeft[0].get(left.Vertices[0], left.Tangents[7] , left.Tangents[6] , left.Vertices[3]);
|
|
curveTLeft[1].get(left.Tangents[0], left.Interiors[0], left.Interiors[3], left.Tangents[5]);
|
|
curveTLeft[2].get(left.Tangents[1], left.Interiors[1], left.Interiors[2], left.Tangents[4]);
|
|
curveTLeft[3].get(left.Vertices[1], left.Tangents[2] , left.Tangents[3] , left.Vertices[2]);
|
|
// right.
|
|
curveTRight[0].get(right.Vertices[0], right.Tangents[7] , right.Tangents[6] , right.Vertices[3]);
|
|
curveTRight[1].get(right.Tangents[0], right.Interiors[0], right.Interiors[3], right.Tangents[5]);
|
|
curveTRight[2].get(right.Tangents[1], right.Interiors[1], right.Interiors[2], right.Tangents[4]);
|
|
curveTRight[3].get(right.Vertices[1], right.Tangents[2] , right.Tangents[3] , right.Vertices[2]);
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CBezierPatch::subdivideT(CBezierPatch &top, CBezierPatch &bottom, float t) const
|
|
{
|
|
CBezierCurve curveS[4];
|
|
CBezierCurve curveSTop[4];
|
|
CBezierCurve curveSBottom[4];
|
|
|
|
// Setup vertical curves.
|
|
curveS[0].set(Vertices[0], Tangents[0] , Tangents[1] , Vertices[1]);
|
|
curveS[1].set(Tangents[7], Interiors[0], Interiors[1], Tangents[2]);
|
|
curveS[2].set(Tangents[6], Interiors[3], Interiors[2], Tangents[3]);
|
|
curveS[3].set(Vertices[3], Tangents[5] , Tangents[4] , Vertices[2]);
|
|
|
|
// Subdivide curves.
|
|
for(sint i=0;i<4;i++)
|
|
curveS[i].subdivide(curveSTop[i], curveSBottom[i], t);
|
|
|
|
// Setup bezier patchs.
|
|
// top.
|
|
curveSTop[0].get(top.Vertices[0], top.Tangents[0] , top.Tangents[1] , top.Vertices[1]);
|
|
curveSTop[1].get(top.Tangents[7], top.Interiors[0], top.Interiors[1], top.Tangents[2]);
|
|
curveSTop[2].get(top.Tangents[6], top.Interiors[3], top.Interiors[2], top.Tangents[3]);
|
|
curveSTop[3].get(top.Vertices[3], top.Tangents[5] , top.Tangents[4] , top.Vertices[2]);
|
|
// bottom.
|
|
curveSBottom[0].get(bottom.Vertices[0], bottom.Tangents[0] , bottom.Tangents[1] , bottom.Vertices[1]);
|
|
curveSBottom[1].get(bottom.Tangents[7], bottom.Interiors[0], bottom.Interiors[1], bottom.Tangents[2]);
|
|
curveSBottom[2].get(bottom.Tangents[6], bottom.Interiors[3], bottom.Interiors[2], bottom.Tangents[3]);
|
|
curveSBottom[3].get(bottom.Vertices[3], bottom.Tangents[5] , bottom.Tangents[4] , bottom.Vertices[2]);
|
|
}
|
|
|
|
} // NL3D
|