mirror of
https://port.numenaute.org/aleajactaest/khanat-opennel-code.git
synced 2024-12-16 14:28:43 +00:00
599 lines
17 KiB
C++
599 lines
17 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/ps_tail_dot.h"
|
||
#include "nel/3d/ps_macro.h"
|
||
#include "nel/3d/driver.h"
|
||
#include "nel/3d/particle_system.h"
|
||
#include "nel/3d/texture_mem.h"
|
||
#include "nel/misc/smart_ptr.h"
|
||
|
||
#include <memory>
|
||
|
||
namespace NL3D
|
||
{
|
||
static NLMISC::CRGBA GradientB2W[] = {NLMISC::CRGBA(0, 0, 0, 0), NLMISC::CRGBA(255, 255, 255, 255) };
|
||
|
||
/// private use : this create a gradient texture that goew from black to white
|
||
static ITexture *CreateGradientTexture()
|
||
{
|
||
NL_PS_FUNC(CreateGradientTexture)
|
||
std::auto_ptr<CTextureMem> tex(new CTextureMem((uint8 *) &GradientB2W,
|
||
sizeof(GradientB2W),
|
||
false, /* dont delete */
|
||
false, /* not a file */
|
||
2, 1)
|
||
);
|
||
tex->setWrapS(ITexture::Clamp);
|
||
tex->setShareName("#GradBW");
|
||
return tex.release();
|
||
}
|
||
|
||
|
||
///////////////////////////////
|
||
// CPSTailDot implementation //
|
||
///////////////////////////////
|
||
|
||
CPSTailDot::TVBMap CPSTailDot::_VBMap; // index / vertex buffers with no color
|
||
CPSTailDot::TVBMap CPSTailDot::_FadedVBMap; // index / vertex buffers for constant color with fading
|
||
CPSTailDot::TVBMap CPSTailDot::_ColoredVBMap; // index / vertex buffer + colors
|
||
CPSTailDot::TVBMap CPSTailDot::_FadedColoredVBMap; // index / vertex buffer + faded colors
|
||
|
||
//=======================================================
|
||
CPSTailDot::CPSTailDot() : _ColorFading(false),
|
||
_GlobalColor(false),
|
||
_Lighted(false),
|
||
_ForceLighted(false),
|
||
_Touch(true)
|
||
{
|
||
NL_PS_FUNC(CPSTailDot_CPSTailDot)
|
||
setInterpolationMode(Linear);
|
||
setSegDuration(0.06f);
|
||
if (CParticleSystem::getSerializeIdentifierFlag()) _Name = std::string("TailDot");
|
||
}
|
||
|
||
//=======================================================
|
||
CPSTailDot::~CPSTailDot()
|
||
{
|
||
NL_PS_FUNC(CPSTailDot_CPSTailDotDtor)
|
||
// delete _DyingRibbons;
|
||
}
|
||
|
||
//=======================================================
|
||
void CPSTailDot::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
|
||
{
|
||
NL_PS_FUNC(CPSTailDot_serial)
|
||
|
||
sint ver = f.serialVersion(3);
|
||
if (ver == 1)
|
||
{
|
||
nlassert(f.isReading());
|
||
|
||
/// we had CPSParticle::serial(f), but this is not the base class anymore, so we emulate this...
|
||
/// version 2 : auto-lod saved
|
||
sint ver2 = f.serialVersion(2);
|
||
|
||
// here is CPSLocatedBindable::serial(f)
|
||
sint ver3 = f.serialVersion(4);
|
||
f.serialPtr(_Owner);
|
||
if (ver3 > 1) f.serialEnum(_LOD);
|
||
if (ver3 > 2) f.serial(_Name);
|
||
if (ver3 > 3)
|
||
{
|
||
if (f.isReading())
|
||
{
|
||
uint32 id;
|
||
f.serial(id);
|
||
setExternID(id);
|
||
}
|
||
else
|
||
{
|
||
f.serial(_ExternID);
|
||
}
|
||
}
|
||
|
||
if (ver2 >= 2)
|
||
{
|
||
bool bDisableAutoLOD;
|
||
f.serial(bDisableAutoLOD);
|
||
disableAutoLOD(bDisableAutoLOD);
|
||
}
|
||
|
||
uint32 tailNbSegs;
|
||
bool colorFading;
|
||
bool systemBasisEnabled;
|
||
|
||
CPSColoredParticle::serialColorScheme(f);
|
||
f.serial(tailNbSegs, colorFading, systemBasisEnabled);
|
||
|
||
_ColorFading = colorFading;
|
||
_NbSegs = tailNbSegs >> 1;
|
||
if (_NbSegs < 2) _NbSegs = 2;
|
||
setInterpolationMode(Linear);
|
||
serialMaterial(f);
|
||
|
||
|
||
nlassert(_Owner);
|
||
resize(_Owner->getMaxSize());
|
||
initDateVect();
|
||
resetFromOwner();
|
||
}
|
||
|
||
if (ver >= 2)
|
||
{
|
||
CPSRibbonBase::serial(f);
|
||
CPSColoredParticle::serialColorScheme(f);
|
||
CPSMaterial::serialMaterial(f);
|
||
bool colorFading = _ColorFading;
|
||
f.serial(colorFading);
|
||
_ColorFading = colorFading;
|
||
if (ver >= 3)
|
||
{
|
||
uint32 tailNbSegs = _NbSegs;
|
||
f.serial(tailNbSegs);
|
||
}
|
||
if (f.isReading())
|
||
{
|
||
setTailNbSeg(_NbSegs);
|
||
touch();
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
//=======================================================
|
||
void CPSTailDot::step(TPSProcessPass pass)
|
||
{
|
||
NL_PS_FUNC(CPSTailDot_step)
|
||
if (pass == PSMotion)
|
||
{
|
||
if (!_Parametric)
|
||
{
|
||
updateGlobals();
|
||
}
|
||
}
|
||
else
|
||
if (
|
||
(pass == PSBlendRender && hasTransparentFaces())
|
||
|| (pass == PSSolidRender && hasOpaqueFaces())
|
||
)
|
||
{
|
||
uint32 step;
|
||
uint numToProcess;
|
||
computeSrcStep(step, numToProcess);
|
||
if (!numToProcess) return;
|
||
|
||
/// update the material color
|
||
CParticleSystem &ps = *(_Owner->getOwner());
|
||
if (ps.getForceGlobalColorLightingFlag() || usesGlobalColorLighting())
|
||
{
|
||
_Mat.setColor(ps.getGlobalColorLighted());
|
||
}
|
||
else
|
||
{
|
||
_Mat.setColor(ps.getGlobalColor());
|
||
}
|
||
|
||
/** We support Auto-LOD for ribbons, although there is a built-in LOD (that change the geometry rather than the number of ribbons)
|
||
* that gives better result (both can be used simultaneously)
|
||
*/
|
||
|
||
displayRibbons(numToProcess, step);
|
||
|
||
}
|
||
else
|
||
if (pass == PSToolRender) // edition mode only
|
||
{
|
||
//showTool();
|
||
}
|
||
}
|
||
|
||
|
||
//=======================================================
|
||
void CPSTailDot::newElement(const CPSEmitterInfo &info)
|
||
{
|
||
NL_PS_FUNC(CPSTailDot_newElement)
|
||
CPSRibbonBase::newElement(info);
|
||
newColorElement(info);
|
||
}
|
||
|
||
|
||
//=======================================================
|
||
void CPSTailDot::deleteElement(uint32 index)
|
||
{
|
||
NL_PS_FUNC(CPSTailDot_deleteElement)
|
||
CPSRibbonBase::deleteElement(index);
|
||
deleteColorElement(index);
|
||
}
|
||
|
||
|
||
//=======================================================
|
||
void CPSTailDot::resize(uint32 size)
|
||
{
|
||
NL_PS_FUNC(CPSTailDot_resize)
|
||
nlassert(size < (1 << 16));
|
||
CPSRibbonBase::resize(size);
|
||
resizeColor(size);
|
||
}
|
||
|
||
//=======================================================
|
||
void CPSTailDot::updateMatAndVbForColor(void)
|
||
{
|
||
NL_PS_FUNC(CPSTailDot_updateMatAndVbForColor)
|
||
touch();
|
||
}
|
||
|
||
//==========================================================================
|
||
void CPSTailDot::displayRibbons(uint32 nbRibbons, uint32 srcStep)
|
||
{
|
||
// if (!FilterPS[8]) return;
|
||
NL_PS_FUNC(CPSTailDot_displayRibbons)
|
||
if (!nbRibbons) return;
|
||
nlassert(_Owner);
|
||
CPSRibbonBase::updateLOD();
|
||
if (_UsedNbSegs < 2) return;
|
||
const float date = _Owner->getOwner()->getSystemDate();
|
||
uint8 *currVert;
|
||
CVBnPB &VBnPB = getVBnPB(); // get the appropriate vb (built it if needed)
|
||
CVertexBuffer &VB = VBnPB.VB;
|
||
CIndexBuffer &PB = VBnPB.PB;
|
||
const uint32 vertexSize = VB.getVertexSize();
|
||
uint colorOffset=0;
|
||
|
||
IDriver *drv = this->getDriver();
|
||
#ifdef NL_DEBUG
|
||
nlassert(drv);
|
||
#endif
|
||
drv->setupModelMatrix(getLocalToWorldTrailMatrix());
|
||
_Owner->incrementNbDrawnParticles(nbRibbons); // for benchmark purpose
|
||
const uint numRibbonBatch = getNumRibbonsInVB(); // number of ribons to process at once
|
||
if (_UsedNbSegs == 0) return;
|
||
|
||
////////////////////
|
||
// Material setup //
|
||
////////////////////
|
||
CParticleSystem &ps = *(_Owner->getOwner());
|
||
bool useGlobalColor = ps.getColorAttenuationScheme() != NULL || ps.isUserColorUsed();
|
||
if (useGlobalColor != _GlobalColor)
|
||
{
|
||
_GlobalColor = useGlobalColor;
|
||
touch();
|
||
}
|
||
if (usesGlobalColorLighting() != _Lighted)
|
||
{
|
||
_Lighted = usesGlobalColorLighting();
|
||
touch();
|
||
}
|
||
if (ps.getForceGlobalColorLightingFlag() != _ForceLighted)
|
||
{
|
||
_ForceLighted = ps.getForceGlobalColorLightingFlag();
|
||
touch();
|
||
}
|
||
updateMaterial();
|
||
setupGlobalColor();
|
||
//
|
||
if (_ColorScheme)
|
||
{
|
||
colorOffset = VB.getColorOff();
|
||
}
|
||
|
||
/////////////////////
|
||
// Compute ribbons //
|
||
/////////////////////
|
||
|
||
uint toProcess;
|
||
uint ribbonIndex = 0; // index of the first ribbon in the batch being processed
|
||
uint32 fpRibbonIndex = 0; // fixed point index in source
|
||
if (_ColorScheme)
|
||
{
|
||
_ColorScheme->setColorType(drv->getVertexColorFormat());
|
||
}
|
||
do
|
||
{
|
||
toProcess = std::min((uint) (nbRibbons - ribbonIndex) /* = left to do */, numRibbonBatch);
|
||
VB.setNumVertices((_UsedNbSegs + 1) * toProcess);
|
||
{
|
||
CVertexBufferReadWrite vba;
|
||
VB.lock (vba);
|
||
currVert = (uint8 *) vba.getVertexCoordPointer();
|
||
|
||
/// compute colors
|
||
if (_ColorScheme)
|
||
{
|
||
_ColorScheme->makeN(this->_Owner, ribbonIndex, currVert + colorOffset, vertexSize, toProcess, _UsedNbSegs + 1, srcStep);
|
||
}
|
||
uint k = toProcess;
|
||
//////////////////////////////////////////////////////////////////////////////////////
|
||
// interpolate and project points the result is directly setup in the vertex buffer //
|
||
//////////////////////////////////////////////////////////////////////////////////////
|
||
if (!_Parametric)
|
||
{
|
||
|
||
//////////////////////
|
||
// INCREMENTAL CASE //
|
||
//////////////////////
|
||
do
|
||
{
|
||
// the parent class has a method to get the ribbons positions
|
||
computeRibbon((uint) (fpRibbonIndex >> 16), (CVector *) currVert, vertexSize);
|
||
currVert += vertexSize * (_UsedNbSegs + 1);
|
||
fpRibbonIndex += srcStep;
|
||
}
|
||
while (--k);
|
||
}
|
||
else
|
||
{
|
||
//////////////////////
|
||
// PARAMETRIC CASE //
|
||
//////////////////////
|
||
do
|
||
{
|
||
// we compute each pos thanks to the parametric curve
|
||
_Owner->integrateSingle(date - _UsedSegDuration * (_UsedNbSegs + 1), _UsedSegDuration, _UsedNbSegs + 1, (uint) (fpRibbonIndex >> 16),
|
||
(NLMISC::CVector *) currVert, vertexSize);
|
||
currVert += vertexSize * (_UsedNbSegs + 1);
|
||
fpRibbonIndex += srcStep;
|
||
}
|
||
while (--k);
|
||
|
||
}
|
||
}
|
||
const uint numLine = _UsedNbSegs * toProcess;
|
||
PB.setNumIndexes(2 * numLine);
|
||
// display the result
|
||
drv->activeIndexBuffer(PB);
|
||
drv->activeVertexBuffer(VB);
|
||
drv->renderLines (_Mat, 0, numLine);
|
||
ribbonIndex += toProcess;
|
||
}
|
||
while (ribbonIndex != nbRibbons);
|
||
}
|
||
|
||
//==========================================================================
|
||
bool CPSTailDot::hasTransparentFaces(void)
|
||
{
|
||
NL_PS_FUNC(CPSTailDot_hasTransparentFaces)
|
||
return getBlendingMode() != CPSMaterial::alphaTest ;
|
||
}
|
||
|
||
|
||
//==========================================================================
|
||
bool CPSTailDot::hasOpaqueFaces(void)
|
||
{
|
||
NL_PS_FUNC(CPSTailDot_hasOpaqueFaces)
|
||
return !hasTransparentFaces();
|
||
}
|
||
|
||
//==========================================================================
|
||
uint32 CPSTailDot::getNumWantedTris() const
|
||
{
|
||
NL_PS_FUNC(CPSTailDot_getNumWantedTris)
|
||
nlassert(_Owner);
|
||
//return _Owner->getMaxSize() * _NbSegs;
|
||
return _Owner->getSize() * _NbSegs;
|
||
}
|
||
|
||
|
||
|
||
//==========================================================================
|
||
CPSTailDot::CVBnPB &CPSTailDot::getVBnPB()
|
||
{
|
||
NL_PS_FUNC(CPSTailDot_getVBnPB)
|
||
/// choose the right vb
|
||
TVBMap &map = _ColorScheme ? (_ColorFading ? _FadedColoredVBMap : _ColoredVBMap) // per ribbon colo<6C>r
|
||
: (_ColorFading ? _FadedVBMap : _VBMap); // global color
|
||
TVBMap::iterator it = map.find(_UsedNbSegs + 1);
|
||
if (it != map.end())
|
||
{
|
||
return it->second;
|
||
}
|
||
else // must create this vb, with few different size, it is still interseting, though they are only destroyed at exit
|
||
{
|
||
const uint numRibbonInVB = getNumRibbonsInVB();
|
||
CVBnPB &VBnPB = map[_UsedNbSegs + 1]; // make an entry
|
||
|
||
/// set the vb format & size
|
||
/// In the case of a ribbon with color and fading, we encode the fading in a texture
|
||
/// If the ribbon has fading, but only a global color, we encode it in the primary color
|
||
CVertexBuffer &vb = VBnPB.VB;
|
||
vb.setPreferredMemory(CVertexBuffer::AGPVolatile, true);
|
||
vb.setVertexFormat(CVertexBuffer::PositionFlag
|
||
|(_ColorScheme || _ColorFading ? CVertexBuffer::PrimaryColorFlag : 0)
|
||
| (_ColorScheme && _ColorFading ? CVertexBuffer::TexCoord0Flag : 0));
|
||
|
||
vb.setNumVertices((_UsedNbSegs + 1) * numRibbonInVB ); // 1 seg = 1 line + terminal vertices
|
||
|
||
// set the primitive block size
|
||
CIndexBuffer &pb = VBnPB.PB;
|
||
pb.setFormat(NL_DEFAULT_INDEX_BUFFER_FORMAT);
|
||
pb.setNumIndexes(2 * _UsedNbSegs * numRibbonInVB);
|
||
/// Setup the pb and vb parts. Not very fast but executed only once
|
||
uint vbIndex = 0;
|
||
uint pbIndex = 0;
|
||
CIndexBufferReadWrite ibaWrite;
|
||
pb.lock (ibaWrite);
|
||
CVertexBufferReadWrite vba;
|
||
vb.lock (vba);
|
||
for (uint i = 0; i < numRibbonInVB; ++i)
|
||
{
|
||
for (uint k = 0; k < (_UsedNbSegs + 1); ++k)
|
||
{
|
||
|
||
if (_ColorScheme && _ColorFading)
|
||
{
|
||
vba.setTexCoord(vbIndex, 0, 0.5f - 0.5f * ((float) k / _UsedNbSegs), 0);
|
||
}
|
||
else if (_ColorFading)
|
||
{
|
||
uint8 intensity = (uint8) (255 * (1.f - ((float) k / _UsedNbSegs)));
|
||
NLMISC::CRGBA col(intensity, intensity, intensity, intensity);
|
||
vba.setColor(vbIndex, col);
|
||
}
|
||
|
||
/// add 1 line in the primitive block
|
||
if (k != _UsedNbSegs)
|
||
{
|
||
ibaWrite.setLine(pbIndex, vbIndex, vbIndex + 1);
|
||
pbIndex+=2;
|
||
}
|
||
++vbIndex;
|
||
}
|
||
}
|
||
vb.setName("CPSTailDot");
|
||
NL_SET_IB_NAME(pb, "CPSTailDot");
|
||
return VBnPB;
|
||
}
|
||
}
|
||
|
||
//==========================================================================
|
||
uint CPSTailDot::getNumRibbonsInVB() const
|
||
{
|
||
NL_PS_FUNC(CPSTailDot_getNumRibbonsInVB)
|
||
/// approximation of the max number of vertices we want in a vb
|
||
const uint vertexInVB = 256;
|
||
return std::max(1u, (uint) (vertexInVB / (_UsedNbSegs + 1)));
|
||
}
|
||
|
||
|
||
//==========================================================================
|
||
void CPSTailDot::updateMaterial()
|
||
{
|
||
NL_PS_FUNC(CPSTailDot_updateMaterial)
|
||
if (!_Touch) return;
|
||
|
||
static NLMISC::CRefPtr<ITexture> ptGradTexture;
|
||
|
||
CParticleSystem &ps = *(_Owner->getOwner());
|
||
if (_ColorScheme)
|
||
{ // PER RIBBON COLOR
|
||
if (ps.getForceGlobalColorLightingFlag() || usesGlobalColorLighting() || ps.getColorAttenuationScheme() || ps.isUserColorUsed())
|
||
{
|
||
if (_ColorFading) // global color + fading + per ribbon color
|
||
{
|
||
// the first stage is used to get fading * global color
|
||
// the second stage multiply the result by the diffuse colot
|
||
if (ptGradTexture == NULL) // have we got a gradient texture ?
|
||
{
|
||
ptGradTexture = CreateGradientTexture();
|
||
}
|
||
_Mat.setTexture(0, ptGradTexture);
|
||
CPSMaterial::forceTexturedMaterialStages(2); // use constant color 0 * diffuse, 1 stage needed
|
||
SetupModulatedStage(_Mat, 0, CMaterial::Texture, CMaterial::Constant);
|
||
SetupModulatedStage(_Mat, 1, CMaterial::Previous, CMaterial::Diffuse);
|
||
}
|
||
else // per ribbon color with global color
|
||
{
|
||
CPSMaterial::forceTexturedMaterialStages(1); // use constant color 0 * diffuse, 1 stage needed
|
||
SetupModulatedStage(_Mat, 0, CMaterial::Diffuse, CMaterial::Constant);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if (_ColorFading) // per ribbon color, fading
|
||
{
|
||
if (ptGradTexture == NULL) // have we got a gradient texture ?
|
||
{
|
||
ptGradTexture = CreateGradientTexture();
|
||
}
|
||
_Mat.setTexture(0, ptGradTexture);
|
||
CPSMaterial::forceTexturedMaterialStages(1);
|
||
SetupModulatedStage(_Mat, 0, CMaterial::Texture, CMaterial::Diffuse);
|
||
}
|
||
else // per color ribbon with no fading, and no global color
|
||
{
|
||
CPSMaterial::forceTexturedMaterialStages(0); // no texture use constant diffuse only
|
||
}
|
||
}
|
||
}
|
||
else // GLOBAL COLOR
|
||
{
|
||
if (_ColorFading)
|
||
{
|
||
CPSMaterial::forceTexturedMaterialStages(1); // use constant color 0 * diffuse, 1 stage needed
|
||
SetupModulatedStage(_Mat, 0, CMaterial::Diffuse, CMaterial::Constant);
|
||
}
|
||
else // constant color
|
||
{
|
||
CPSMaterial::forceTexturedMaterialStages(0); // no texture use constant diffuse only
|
||
}
|
||
}
|
||
|
||
_Touch = false;
|
||
}
|
||
|
||
//==========================================================================
|
||
void CPSTailDot::setupGlobalColor()
|
||
{
|
||
NL_PS_FUNC(CPSTailDot_setupGlobalColor)
|
||
/// setup the global color if it is used
|
||
CParticleSystem &ps = *(_Owner->getOwner());
|
||
if (_ColorScheme)
|
||
{
|
||
if (ps.getForceGlobalColorLightingFlag() || usesGlobalColorLighting())
|
||
{
|
||
_Mat.texConstantColor(0, ps.getGlobalColorLighted());
|
||
}
|
||
else
|
||
{
|
||
_Mat.texConstantColor(0, ps.getGlobalColor());
|
||
}
|
||
}
|
||
else // GLOBAL COLOR with / without fading
|
||
{
|
||
if (ps.getForceGlobalColorLightingFlag() || usesGlobalColorLighting())
|
||
{
|
||
NLMISC::CRGBA col;
|
||
col.modulateFromColor(ps.getGlobalColorLighted(), _Color);
|
||
if (_ColorFading)
|
||
{
|
||
_Mat.texConstantColor(0, col);
|
||
}
|
||
else // color attenuation, no fading :
|
||
{
|
||
_Mat.setColor(col);
|
||
}
|
||
}
|
||
else
|
||
if (ps.getColorAttenuationScheme() || ps.isUserColorUsed())
|
||
{
|
||
NLMISC::CRGBA col;
|
||
col.modulateFromColor(ps.getGlobalColor(), _Color);
|
||
if (_ColorFading)
|
||
{
|
||
_Mat.texConstantColor(0, col);
|
||
}
|
||
else // color attenuation, no fading :
|
||
{
|
||
_Mat.setColor(col);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if (_ColorFading)
|
||
{
|
||
_Mat.texConstantColor(0, _Color);
|
||
}
|
||
else // constant color
|
||
{
|
||
_Mat.setColor(_Color);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
} // NL3D
|