// NeL - MMORPG Framework
// 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 .
#include "std3d.h"
#include "nel/3d/ps_plane_basis_maker.h"
#include "nel/3d/ps_register_plane_basis_attribs.h"
namespace NL3D
{
CPlaneBasis CPSPlaneBasisGradient::DefaultPlaneBasisTab[] = { CPlaneBasis(NLMISC::CVector::I), CPlaneBasis(NLMISC::CVector::J) };
/////////////////////////////////////////////
// CPSPlaneBasisFollowSpeed implementation //
/////////////////////////////////////////////
///============================================================================
CPlaneBasis CPSPlaneBasisFollowSpeed::get(CPSLocated *loc, uint32 index)
{
return (CPlaneBasis(loc->getSpeed()[index]));
}
CPlaneBasis CPSPlaneBasisFollowSpeed::get(const CPSEmitterInfo &infos)
{
return (CPlaneBasis(infos.Speed));
}
///============================================================================
void *CPSPlaneBasisFollowSpeed::make(CPSLocated *loc,
uint32 startIndex,
void *tab, uint32 stride,
uint32 numAttrib,
bool enableNoCopy /* = false*/,
uint32 srcStep /*= (1 << 16)*/,
bool forceClampEntry /* = false */
) const
{
nlassert(numAttrib);
if (srcStep == (1 << 16))
{
TPSAttribVector::const_iterator speedIt = loc->getSpeed().begin() + startIndex
, endSpeedIt = loc->getSpeed().begin() + startIndex + numAttrib;
uint8 *ptDat = (uint8 *) tab;
switch(_ProjectionPlane)
{
case NoProjection:
do
{
*(CPlaneBasis *) ptDat = CPlaneBasis(*speedIt);
++ speedIt;
ptDat += stride;
}
while (speedIt != endSpeedIt);
break;
case XY:
do
{
float norm = sqrtf(speedIt->x * speedIt->x + speedIt->y * speedIt->y);
float invNorm = (norm != 0.f) ? 1.f / norm : 0.f;
CPlaneBasis &pb = *(CPlaneBasis *) ptDat;
pb.X.set(invNorm * speedIt->x, invNorm * speedIt->y, 0.f);
pb.Y.set(- pb.X.y, pb.X.x, 0.f);
++ speedIt;
ptDat += stride;
}
while (speedIt != endSpeedIt);
break;
case XZ:
do
{
float norm = sqrtf(speedIt->x * speedIt->x + speedIt->z * speedIt->z);
float invNorm = (norm != 0.f) ? 1.f / norm : 0.f;
CPlaneBasis &pb = *(CPlaneBasis *) ptDat;
pb.X.set(invNorm * speedIt->x, 0.f, invNorm * speedIt->z);
pb.Y.set(- pb.X.z, 0.f, pb.X.x);
++ speedIt;
ptDat += stride;
}
while (speedIt != endSpeedIt);
break;
case YZ:
do
{
float norm = sqrtf(speedIt->y * speedIt->y + speedIt->z * speedIt->z);
float invNorm = (norm != 0.f) ? 1.f / norm : 0.f;
CPlaneBasis &pb = *(CPlaneBasis *) ptDat;
pb.X.set(0.f, invNorm * speedIt->y, invNorm * speedIt->z);
pb.Y.set(0.f, - pb.X.z, pb.X.y);
++ speedIt;
ptDat += stride;
}
while (speedIt != endSpeedIt);
break;
default:
nlstop; // unknow projection mode
break;
}
return tab;
}
else
{
uint32 fpIndex = startIndex * srcStep;
const TPSAttribVector::const_iterator speedIt = loc->getSpeed().begin();
uint8 *ptDat = (uint8 *) tab;
switch(_ProjectionPlane)
{
case NoProjection:
while (numAttrib --)
{
*(CPlaneBasis *) ptDat = CPlaneBasis(*(speedIt + (fpIndex >> 16)));
ptDat += stride;
fpIndex += srcStep;
}
break;
case XY:
while (numAttrib --)
{
const CVector *speedVect = &(*(speedIt + (fpIndex >> 16)));
float norm = sqrtf(speedVect->x * speedVect->x + speedVect->y * speedVect->y);
float invNorm = (norm != 0.f) ? 1.f / norm : 0.f;
CPlaneBasis &pb = *(CPlaneBasis *) ptDat;
pb.X.set(invNorm * speedVect->x, invNorm * speedVect->y, 0.f);
pb.Y.set(- pb.X.y, pb.X.x, 0.f);
ptDat += stride;
fpIndex += srcStep;
}
break;
case XZ:
while (numAttrib --)
{
const CVector *speedVect = &(*(speedIt + (fpIndex >> 16)));
float norm = sqrtf(speedVect->x * speedVect->x + speedVect->z * speedVect->z);
float invNorm = (norm != 0.f) ? 1.f / norm : 0.f;
CPlaneBasis &pb = *(CPlaneBasis *) ptDat;
pb.X.set(invNorm * speedVect->x, 0.f, invNorm * speedVect->z);
pb.Y.set(- pb.X.z, 0.f, pb.X.x);
ptDat += stride;
fpIndex += srcStep;
}
break;
case YZ:
while (numAttrib --)
{
const CVector *speedVect = &(*(speedIt + (fpIndex >> 16)));
float norm = sqrtf(speedVect->y * speedVect->y + speedVect->z * speedVect->z);
float invNorm = (norm != 0.f) ? 1.f / norm : 0.f;
CPlaneBasis &pb = *(CPlaneBasis *) ptDat;
pb.X.set(0.f, invNorm * speedVect->y, invNorm * speedVect->z);
pb.Y.set(0.f, - pb.X.z, pb.X.y);
ptDat += stride;
fpIndex += srcStep;
}
break;
default:
nlstop; // unknow projection mode
break;
}
return tab;
}
}
///============================================================================
void CPSPlaneBasisFollowSpeed::make4(CPSLocated *loc,
uint32 startIndex,
void *tab,
uint32 stride,
uint32 numAttrib,
uint32 srcStep /*= (1 << 16)*/
) const
{
nlassert(numAttrib);
if (srcStep == (1 << 16))
{
TPSAttribVector::const_iterator speedIt = loc->getSpeed().begin() + startIndex
, endSpeedIt = loc->getSpeed().begin() + startIndex + numAttrib;
uint8 *ptDat = (uint8 *) tab;
do
{
*(CPlaneBasis *) ptDat = CPlaneBasis(*speedIt);
*(CPlaneBasis *) (ptDat + stride) = *(CPlaneBasis *) ptDat;
ptDat += stride;
*(CPlaneBasis *) (ptDat + stride) = *(CPlaneBasis *) ptDat;
ptDat += stride;
*(CPlaneBasis *) (ptDat + stride) = *(CPlaneBasis *) ptDat;
ptDat += stride << 1;
++ speedIt;
}
while (speedIt != endSpeedIt);
}
else
{
uint32 fpIndex = startIndex * srcStep;
const TPSAttribVector::const_iterator speedIt = loc->getSpeed().begin();
uint8 *ptDat = (uint8 *) tab;
while (numAttrib --)
{
*(CPlaneBasis *) ptDat = CPlaneBasis(*(speedIt + (fpIndex >> 16)));
*(CPlaneBasis *) (ptDat + stride) = *(CPlaneBasis *) ptDat;
ptDat += stride;
*(CPlaneBasis *) (ptDat + stride) = *(CPlaneBasis *) ptDat;
ptDat += stride;
*(CPlaneBasis *) (ptDat + stride) = *(CPlaneBasis *) ptDat;
ptDat += stride << 1;
fpIndex += srcStep;
}
}
}
///============================================================================
void CPSPlaneBasisFollowSpeed::makeN(CPSLocated *loc,
uint32 startIndex,
void *tab,
uint32 stride,
uint32 numAttrib,
uint32 nbReplicate,
uint32 srcStep /*= (1 << 16) */
) const
{
nlassert(numAttrib);
if (srcStep == (1 << 16))
{
nlassert(nbReplicate > 1);
TPSAttribVector::const_iterator speedIt = loc->getSpeed().begin() + startIndex
, endSpeedIt = loc->getSpeed().begin() + startIndex + numAttrib;
uint8 *ptDat = (uint8 *) tab;
uint k;
do
{
*(CPlaneBasis *) ptDat = CPlaneBasis(*speedIt);
k = nbReplicate - 1;
do
{
*(CPlaneBasis *) (ptDat + stride) = *(CPlaneBasis *) ptDat;
ptDat += stride;
}
while (--k);
ptDat += stride;
++ speedIt;
}
while (speedIt != endSpeedIt);
}
else
{
uint32 fpIndex = startIndex * srcStep;
nlassert(nbReplicate > 1);
const TPSAttribVector::const_iterator speedIt = loc->getSpeed().begin();
uint8 *ptDat = (uint8 *) tab;
uint k;
while (numAttrib --)
{
*(CPlaneBasis *) ptDat = CPlaneBasis(*(speedIt + (fpIndex >> 16)));
k = nbReplicate - 1;
do
{
*(CPlaneBasis *) (ptDat + stride) = *(CPlaneBasis *) ptDat;
ptDat += stride;
}
while (--k);
ptDat += stride;
fpIndex += srcStep;
}
}
}
/////////////////////////////////////////////
// CSpinnerFunctor implementation //
/////////////////////////////////////////////
///============================================================================
CSpinnerFunctor::CSpinnerFunctor() : _NbSamples(0), _Axis(NLMISC::CVector::K)
{
}
///============================================================================
void CSpinnerFunctor::setAxis(const NLMISC::CVector &axis)
{
_Axis = axis;
updateSamples();
}
///============================================================================
void CSpinnerFunctor::setNumSamples(uint32 nbSamples)
{
nlassert(nbSamples > 0);
_NbSamples = nbSamples;
updateSamples();
}
///============================================================================
uint32 CSpinnerFunctor::getNumSamples(void) const
{
return _NbSamples;
}
///============================================================================
void CSpinnerFunctor::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
{
f.serialVersion(1);
f.serial(_Axis, _NbSamples);
if (f.isReading()) updateSamples();
}
///============================================================================
void CSpinnerFunctor::updateSamples(void)
{
if (_NbSamples == 0) return;
// compute step between each angle
const float angInc = (float) (2.f * NLMISC::Pi / _NbSamples);
_PBTab.resize(_NbSamples + 1);
NLMISC::CMatrix mat;
CPSUtil::buildSchmidtBasis(_Axis, mat);
NLMISC::CVector I = mat.getI();
NLMISC::CVector J = mat.getJ();
// compute basis for rotation
for (uint32 k = 0; k < _NbSamples; ++k)
{
float ca = cosf(k * angInc);
float sa = sinf(k * angInc);
_PBTab[k].X.set(ca * I.x + sa * J.x,
ca * I.y + sa * J.y,
ca * I.z + sa * J.z);
_PBTab[k].Y.set(- sa * I.x + ca * J.x,
- sa * I.y + ca * J.y,
- sa * I.z + ca * J.z);
}
}
///============================================================================
void PSRegisterPlaneBasisAttribs()
{
NLMISC_REGISTER_CLASS(CPSPlaneBasisBlender);
NLMISC_REGISTER_CLASS(CPSPlaneBasisGradient);
NLMISC_REGISTER_CLASS(CPSPlaneBasisMemory);
NLMISC_REGISTER_CLASS(CPSPlaneBasisBinOp);
NLMISC_REGISTER_CLASS(CPSPlaneBasisFollowSpeed);
NLMISC_REGISTER_CLASS(CPSBasisSpinner);
}
} // NL3D