// 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/seg_remanence_shape.h" #include "nel/3d/seg_remanence.h" #include "nel/3d/driver.h" #include "nel/3d/scene.h" // #include "nel/misc/bsphere.h" namespace NL3D { //=========================================================== CSegRemanenceShape::CSegRemanenceShape() : _GeomTouched(true), _MatTouched(true), _TextureShifting(true), _NumSlices(8), _SliceTime(0.05f), _RollUpRatio(1.f), _AnimatedMat(NULL) { _BBox.setCenter(NLMISC::CVector::Null); _BBox.setHalfSize(NLMISC::CVector(3, 3, 3)); setNumCorners(2); } //=========================================================== void CSegRemanenceShape::serial(NLMISC::IStream &f) throw(NLMISC::EStream) { // version 2 : added default tracks // version 1 : rollup ratio // version 0 : base version sint ver = f.serialVersion(2); f.serial(_NumSlices); f.serial(_SliceTime); f.serialCont(_Corners); f.serial(_Mat); f.serial(_BBox); f.serial(_TextureShifting); f.serialPtr(_AnimatedMat); if (f.isReading()) { _GeomTouched = true; _MatTouched = true; } if (ver >= 1) { f.serial(_RollUpRatio); } if (ver >= 2) { f.serial(_DefaultPos); f.serial(_DefaultRotQuat); f.serial(_DefaultScale); } } //=========================================================== void CSegRemanenceShape::setSliceTime(float sliceTime) { nlassert(sliceTime > 0); _SliceTime = sliceTime; } //=========================================================== void CSegRemanenceShape::setCorner(uint corner, const NLMISC::CVector &value) { nlassert(corner < _Corners.size()); _Corners[corner] = value; } //=========================================================== void CSegRemanenceShape::setNumSlices(uint32 numSlices) { nlassert(numSlices >= 2); _NumSlices = numSlices; _GeomTouched = true; } //=========================================================== NLMISC::CVector CSegRemanenceShape::getCorner(uint corner) const { nlassert(corner < _Corners.size()); return _Corners[corner]; } //=========================================================== void CSegRemanenceShape::setNumCorners(uint numCorners) { nlassert(numCorners >= 2); _Corners.resize(numCorners); std::fill(_Corners.begin(), _Corners.end(), NLMISC::CVector::Null); _GeomTouched = true; } //=========================================================== void CSegRemanenceShape::render(IDriver *drv, CTransformShape *trans, bool opaquePass) { if ((!opaquePass && _Mat.getBlend()) || (opaquePass && !_Mat.getBlend()) ) { CSegRemanence *sr = NLMISC::safe_cast(trans); #ifndef DEBUG_SEG_REMANENCE_DISPLAY if (!sr->isStarted()) return; #endif setupMaterial(); // sr->render(drv, _Mat); } } //=========================================================== void CSegRemanenceShape::flushTextures(IDriver &driver, uint selectedTexture) { _Mat.flushTextures(driver, selectedTexture); } //=========================================================== CTransformShape *CSegRemanenceShape::createInstance(CScene &scene) { CSegRemanence *sr = NLMISC::safe_cast(scene.createModel(NL3D::SegRemanenceShapeId) ); sr->Shape = this; CAnimatedMaterial *aniMat = NULL; if (_AnimatedMat) { aniMat = new CAnimatedMaterial(_AnimatedMat); aniMat->setMaterial(&_Mat); } sr->setAnimatedMaterial(aniMat); sr->setupFromShape(); // SegRemanence are added to the "Fx" Load Balancing Group. sr->setLoadBalancingGroup("Fx"); sr->ITransformable::setPos( _DefaultPos.getDefaultValue() ); sr->ITransformable::setRotQuat( _DefaultRotQuat.getDefaultValue() ); sr->ITransformable::setScale( _DefaultScale.getDefaultValue() ); sr->setSliceTime(_SliceTime); return sr; } //=========================================================== float CSegRemanenceShape::getNumTriangles(float distance) { return (float) (_NumSlices * 2); } //=========================================================== void CSegRemanenceShape::setBBox(const NLMISC::CAABBox &bbox) { _BBox = bbox; } //=========================================================== void CSegRemanenceShape::setMaterial(const CMaterial &mat) { _Mat = mat; _MatTouched = true; } //=========================================================== void CSegRemanenceShape::setTextureShifting(bool on /*=true*/) { _TextureShifting = on; _MatTouched = true; } //=========================================================== void CSegRemanenceShape::setRollupRatio(float ratio) { nlassert(ratio > 0); _RollUpRatio = ratio; } //=========================================================== void CSegRemanenceShape::setupMaterial() { if (!_MatTouched) return; _Mat.enableUserTexMat(0); if (_Mat.getTexture(0)) { _Mat.getTexture(0)->setWrapS(ITexture::Clamp); _Mat.getTexture(0)->setWrapT(ITexture::Clamp); } _Mat.setDoubleSided(true); _Mat.setLighting(false); // lighting not supported (the vb has no normals anyway..) _MatTouched = false; } //=========================================================== void CSegRemanenceShape::setAnimatedMaterial(const std::string &name) { nlassert(!name.empty()); nlassert(_AnimatedMat == NULL); _AnimatedMat = new CMaterialBase; _AnimatedMat->Name = name; } //=========================================================== CSegRemanenceShape::CSegRemanenceShape(const CSegRemanenceShape &other) : IShape(other), _AnimatedMat(NULL) { copyFromOther(other); } //=========================================================== CSegRemanenceShape &CSegRemanenceShape::operator = (const CSegRemanenceShape &other) { if (&other != this) { copyFromOther(other); (IShape &) *this = (IShape &) other; // copy base part } return *this; } //=========================================================== CSegRemanenceShape::~CSegRemanenceShape() { delete _AnimatedMat; } //=========================================================== void CSegRemanenceShape::copyFromOther(const CSegRemanenceShape &other) { if (&other == this) return; CMaterialBase *otherAnimatedMat = other._AnimatedMat != NULL ? new CMaterialBase(*other._AnimatedMat) : NULL; delete _AnimatedMat; _AnimatedMat = otherAnimatedMat; _GeomTouched = other._GeomTouched; _MatTouched = other._MatTouched; _TextureShifting = other._TextureShifting; _NumSlices = other._NumSlices; _SliceTime = other._SliceTime; _Corners = other._Corners; _Mat = other._Mat; _BBox = other._BBox; _RollUpRatio = other._RollUpRatio; } //=========================================================== bool CSegRemanenceShape::clip(const std::vector &pyramid, const CMatrix &worldMatrix) { // Speed Clip: clip just the sphere. NLMISC::CBSphere localSphere(_BBox.getCenter(), _BBox.getRadius()); NLMISC::CBSphere worldSphere; // transform the sphere in WorldMatrix (with nearly good scale info). localSphere.applyTransform(worldMatrix, worldSphere); // if out of only plane, entirely out. for(sint i=0;i<(sint)pyramid.size();i++) { // We are sure that pyramid has normalized plane normals. // if SpherMax OUT return false. float d= pyramid[i]*worldSphere.Center; if(d>worldSphere.Radius) return false; } return true; } }