// 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/vertex_buffer.h" #include "nel/misc/vector.h" #include "nel/misc/fast_mem.h" #include "nel/3d/driver.h" using namespace NLMISC; namespace NL3D { // -------------------------------------------------- const uint CVertexBuffer::SizeType[NumType]= { 1*sizeof(double), 1*sizeof(float), 1*sizeof(short), 2*sizeof(double), 2*sizeof(float), 2*sizeof(short), 3*sizeof(double), 3*sizeof(float), 3*sizeof(short), 4*sizeof(double), 4*sizeof(float), 4*sizeof(short), 4*sizeof(char), }; const uint CVertexBuffer::NumComponentsType[NumType] = { 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 4 }; // -------------------------------------------------- const CVertexBuffer::TType CVertexBuffer::DefaultValueType[NumValue]= { Float3, // Position Float3, // Normal Float2, // TexCoord0 Float2, // TexCoord1 Float2, // TexCoord2 Float2, // TexCoord3 Float2, // TexCoord4 Float2, // TexCoord5 Float2, // TexCoord6 Float2, // TexCoord7 UChar4, // Primary color UChar4, // Secondary color Float4, // 4 Weights UChar4, // PaletteSkin Float1, // Fog Float1, // Empty }; // -------------------------------------------------- void CVertexBuffer::construct() { /* *********************************************** * WARNING: This Class/Method must be thread-safe (ctor/dtor/serial): no static access for instance * It can be loaded/called through CAsyncFileManager for instance * ***********************************************/ _Flags = 0; _Capacity = 0; _NbVerts = 0; _InternalFlags = 0; _VertexSize = 0; _VertexColorFormat = TRGBA; _LockCounter = 0; _LockedBuffer = NULL; _PreferredMemory = RAMPreferred; _Location = NotResident; _ResidentSize = 0; _KeepLocalMemory = false; // Default routing uint i; for (i=0; i<MaxStage; i++) _UVRouting[i] = i; } // -------------------------------------------------- CVertexBuffer::CVertexBuffer() { construct(); } CVertexBuffer::CVertexBuffer(const char *name) { construct(); _Name = name; } // -------------------------------------------------- CVertexBuffer::CVertexBuffer(const CVertexBuffer &vb) : CRefCount() { /* *********************************************** * WARNING: This Class/Method must be thread-safe (ctor/dtor/serial): no static access for instance * It can be loaded/called through CAsyncFileManager for instance * ***********************************************/ _Flags = 0; _Capacity = 0; _NbVerts = 0; _VertexSize = 0; _LockCounter = 0; _LockedBuffer = NULL; _PreferredMemory = RAMPreferred; _Location = NotResident; _ResidentSize = 0; _KeepLocalMemory = false; operator=(vb); // Default routing uint i; for (i=0; i<MaxStage; i++) _UVRouting[i] = i; } // -------------------------------------------------- CVertexBuffer::~CVertexBuffer() { /* *********************************************** * WARNING: This Class/Method must be thread-safe (ctor/dtor/serial): no static access for instance * It can be loaded/called through CAsyncFileManager for instance * ***********************************************/ if (DrvInfos) DrvInfos->VertexBufferPtr = NULL; // Tell the driver info to not restaure memory when it will die // Must kill the drv mirror of this VB. DrvInfos.kill(); } // -------------------------------------------------- CVertexBuffer &CVertexBuffer::operator=(const CVertexBuffer &vb) { nlassertex (!isLocked(), ("The vertex buffer is locked.")); nlassertex (!vb.isLocked(), ("Source buffer is locked.")); // Single value _VertexSize = vb._VertexSize; _Flags = vb._Flags; _InternalFlags = vb._InternalFlags; _NbVerts = vb._NbVerts; _Capacity = vb._Capacity; _NonResidentVertices = vb._NonResidentVertices; _VertexColorFormat = vb._VertexColorFormat; _PreferredMemory = vb._PreferredMemory; _KeepLocalMemory = vb._KeepLocalMemory; uint i; _LockCounter = 0; _LockedBuffer = NULL; // Arraies for (uint value=0; value<NumValue; value++) { _Offset[value]= vb._Offset[value]; _Type[value]= vb._Type[value]; } // Copy the routing for (i=0; i<MaxStage; i++) _UVRouting[i] = vb._UVRouting[i]; // Set touch flags _InternalFlags |= TouchedAll; _Location = NotResident; _ResidentSize = 0; return *this; } // -------------------------------------------------- void CVertexBuffer::copyVertices(CVertexBuffer &dest) const { nlassert(_PreferredMemory != RAMVolatile); nlassert(_PreferredMemory != AGPVolatile); // copy setup dest = *this; CVertexBufferReadWrite srcDatas; const_cast<CVertexBuffer *>(this)->lock(srcDatas); nlassert(dest.getLocation() == NotResident); CVertexBufferReadWrite destDatas; dest.lock(destDatas); // will be in vram NLMISC::CFastMem::memcpy (destDatas.getVertexCoordPointer(), srcDatas.getVertexCoordPointer(), getVertexSize() * getNumVertices()); } // -------------------------------------------------- bool CVertexBuffer::setVertexFormat(uint32 flags) { nlassertex (!isLocked(), ("The vertex buffer is locked.")); uint i; // Clear extended values clearValueEx (); // Position ? if (flags & PositionFlag) { // Add a standard position value addValueEx (Position, Float3); } // Normal ? if (flags & NormalFlag) { // Add a standard normal value addValueEx (Normal, Float3); } // For each uv values for(i=0 ; i<MaxStage ; i++) { // UV ? if (flags & (TexCoord0Flag<<i)) { // Add a standard uv value addValueEx ((TValue)(TexCoord0+i), Float2); } } // Fog ? if (flags & FogFlag) { // Add a standard primary color value addValueEx (Fog, Float1); } // Primary color ? if (flags & PrimaryColorFlag) { // Add a standard primary color value addValueEx (PrimaryColor, UChar4); } // Secondary color ? if (flags & SecondaryColorFlag) { // Add a standard primary color value addValueEx (SecondaryColor, UChar4); } // Weight ? if (flags & WeightFlag) { // Add a standard primary color value addValueEx (Weight, Float4); } // Palette skin ? if ((flags & PaletteSkinFlag)==CVertexBuffer::PaletteSkinFlag) { // Add a standard primary color value addValueEx (PaletteSkin, UChar4); } // Compute the vertex buffer initEx (); // Force non resident restaureNonResidentMemory(); return (true); } // -------------------------------------------------- CVertexBuffer::TValue CVertexBuffer::getValueIdByNumberEx (uint valueNumber) { // See NV_vertex_program spec, or driver_opengl_vertex.cpp:: GLVertexAttribIndex. static TValue lut[16]= { Position, Weight, Normal, PrimaryColor, SecondaryColor, Fog, PaletteSkin, Empty, TexCoord0, TexCoord1, TexCoord2, TexCoord3, TexCoord4, TexCoord5, TexCoord6, TexCoord7, }; return lut[valueNumber]; } // -------------------------------------------------- void CVertexBuffer::clearValueEx () { nlassertex (!isLocked(), ("The vertex buffer is locked.")); // Reset format flags _Flags=0; } // -------------------------------------------------- void CVertexBuffer::dumpFormat() const { for(uint k = 0; k < NumValue; ++k) { if (_Flags & (1 << k)) { std::string result = "Component :"; switch(k) { case Position: result += "Position"; break; case Normal: result += "Normal"; break; case TexCoord0: result += "TexCoord0"; break; case TexCoord1: result += "TexCoord1"; break; case TexCoord2: result += "TexCoord2"; break; case TexCoord3: result += "TexCoord3"; break; case TexCoord4: result += "TexCoord4"; break; case TexCoord5: result += "TexCoord5"; break; case TexCoord6: result += "TexCoord6"; break; case TexCoord7: result += "TexCoord7"; break; case PrimaryColor: result += "PrimaryColor"; break; case SecondaryColor:result += "SecondaryColor"; break; case Weight: result += "Weight"; break; case PaletteSkin: result += "PaletteSkin"; break; case Fog: result += "Fog"; break; case Empty: result += "Empty"; break; case NumValue: result += "NumValue"; break; default: result += "???"; break; } result += "; type :"; switch(_Type[k]) { case Double1: result +="Double1"; break; case Float1: result +="Float1"; break; case Short1: result +="Short1"; break; case Double2: result +="Double2"; break; case Float2: result +="Float2"; break; case Short2: result +="Short2"; break; case Double3: result +="Double3"; break; case Float3: result +="Float3"; break; case Short3: result +="Short3"; break; case Double4: result +="Double4"; break; case Float4: result +="Float4"; break; case Short4: result +="Short4"; break; case UChar4: result +="UChar4"; break; default: result += "???"; break; } nlinfo(result.c_str()); } } } // -------------------------------------------------- void CVertexBuffer::addValueEx (TValue valueId, TType type) { nlassertex (!isLocked(), ("The vertex buffer is locked.")); // Reset format flags _Flags |= 1<<valueId; // Set the type _Type[valueId]=(uint8)type; uint numComp = NumComponentsType[type]; // unfortunately, some vertex program implementations don't allow any type for any value switch (valueId) { case Position: nlassert(numComp >= 2); break; case Normal: nlassert(numComp == 3); break; case PrimaryColor: nlassert(numComp == 4); break; case SecondaryColor: nlassert(numComp == 4); break; case Weight: nlassert(numComp == 4); break; case PaletteSkin: nlassert(numComp == 4); break; case Fog: nlassert(numComp == 4); break; default: break; } } // -------------------------------------------------- bool CVertexBuffer::hasValueEx(TValue valueId) const { return (_Flags & (1 << valueId)) != 0; } // -------------------------------------------------- void CVertexBuffer::initEx () { nlassert (!isLocked()); // Calc vertex size and set value's offset _VertexSize=0; for (uint value=0; value<NumValue; value++) { // Value used ? if (_Flags&(1<<value)) { // Set offset _Offset[value]=_VertexSize; // New size _VertexSize+=SizeType[_Type[value]]; } } // Reset number of vertices _NbVerts=0; // Compute new capacity if (_VertexSize) _Capacity = (uint32)_NonResidentVertices.size()/_VertexSize; else _Capacity = 0; // Force non resident restaureNonResidentMemory(); } // -------------------------------------------------- void CVertexBuffer::reserve(uint32 n) { nlassert (!isLocked()); if (_Capacity != n) { _Capacity= n; _NbVerts=std::min (_NbVerts,_Capacity); // Force non resident restaureNonResidentMemory(); } } // -------------------------------------------------- void CVertexBuffer::setNumVertices(uint32 n) { if(_Capacity<n) { reserve(n); } if(_NbVerts != n) { _InternalFlags |= TouchedNumVertices; _NbVerts=n; } } // -------------------------------------------------- void CVertexBuffer::deleteAllVertices() { if (_Capacity) { nlassert (!isLocked()); // free memory. contReset(_NonResidentVertices); _Capacity= 0; if(_NbVerts!=0) { _NbVerts=0; _InternalFlags |= TouchedNumVertices; } // Force non resident restaureNonResidentMemory(); // Delete driver info nlassert (DrvInfos == NULL); } } // -------------------------------------------------- uint16 CVertexBuffer::remapV2Flags (uint32 oldFlags, uint& weightCount) { // Old flags const uint32 OLD_IDRV_VF_XYZ = 0x00000001; const uint32 OLD_IDRV_VF_W0 = 0x00000002; const uint32 OLD_IDRV_VF_W1 = 0x00000004; const uint32 OLD_IDRV_VF_W2 = 0x00000008; const uint32 OLD_IDRV_VF_W3 = 0x00000010; const uint32 OLD_IDRV_VF_NORMAL = 0x00000020; const uint32 OLD_IDRV_VF_COLOR = 0x00000040; const uint32 OLD_IDRV_VF_SPECULAR = 0x00000080; const uint32 OLD_IDRV_VF_UV0 = 0x00000100; const uint32 OLD_IDRV_VF_UV1 = 0x00000200; const uint32 OLD_IDRV_VF_UV2 = 0x00000400; const uint32 OLD_IDRV_VF_UV3 = 0x00000800; const uint32 OLD_IDRV_VF_UV4 = 0x00001000; const uint32 OLD_IDRV_VF_UV5 = 0x00002000; const uint32 OLD_IDRV_VF_UV6 = 0x00004000; const uint32 OLD_IDRV_VF_UV7 = 0x00008000; const uint32 OLD_IDRV_VF_PALETTE_SKIN = 0x00010000 | OLD_IDRV_VF_W0 | OLD_IDRV_VF_W1 | OLD_IDRV_VF_W2 | OLD_IDRV_VF_W3; // Old Flags uint16 newFlags=0; // Number of weight values weightCount=0; // Remap the flags if (oldFlags&OLD_IDRV_VF_XYZ) newFlags|=PositionFlag; if (oldFlags&OLD_IDRV_VF_NORMAL) newFlags|=NormalFlag; if (oldFlags&OLD_IDRV_VF_COLOR) newFlags|=PrimaryColorFlag; if (oldFlags&OLD_IDRV_VF_SPECULAR) newFlags|=SecondaryColorFlag; if (oldFlags&OLD_IDRV_VF_UV0) newFlags|=TexCoord0Flag; if (oldFlags&OLD_IDRV_VF_UV1) newFlags|=TexCoord1Flag; if (oldFlags&OLD_IDRV_VF_UV2) newFlags|=TexCoord2Flag; if (oldFlags&OLD_IDRV_VF_UV3) newFlags|=TexCoord3Flag; if (oldFlags&OLD_IDRV_VF_UV4) newFlags|=TexCoord4Flag; if (oldFlags&OLD_IDRV_VF_UV5) newFlags|=TexCoord5Flag; if (oldFlags&OLD_IDRV_VF_UV6) newFlags|=TexCoord6Flag; if (oldFlags&OLD_IDRV_VF_UV7) newFlags|=TexCoord7Flag; if (oldFlags&OLD_IDRV_VF_W0) { weightCount=1; newFlags|=WeightFlag; } if (oldFlags&OLD_IDRV_VF_W1) { weightCount=2; newFlags|=WeightFlag; } if (oldFlags&OLD_IDRV_VF_W2) { weightCount=3; newFlags|=WeightFlag; } if (oldFlags&OLD_IDRV_VF_W3) { weightCount=4; newFlags|=WeightFlag; } if (oldFlags&(OLD_IDRV_VF_PALETTE_SKIN)) newFlags|=PaletteSkinFlag; // Return the new flags return newFlags; } // -------------------------------------------------- void CVertexBuffer::serialOldV1Minus(NLMISC::IStream &f, sint ver) { /* *********************************************** * WARNING: This Class/Method must be thread-safe (ctor/dtor/serial): no static access for instance * It can be loaded/called through CAsyncFileManager for instance * ***********************************************/ /* Version 1: - PaletteSkin version. Version 0: - base verison. */ // old Flags uint32 oldFlags; // Serial VBuffers format/size. //============================= f.serial(oldFlags); // Remap the flags uint weightCount; uint16 newFlags=remapV2Flags (oldFlags, weightCount); // Must be reading nlassert (f.isReading()); // Set default value type uint i; for (i=0; i<NumValue; i++) _Type[i]=DefaultValueType[i]; uint32 nbVert; // Read only f.serial(nbVert); reserve(0); setVertexFormat(newFlags); setNumVertices(nbVert); // All other infos (but _NonResidentVertices) are computed by setVertexFormat() and setNumVertices(). // Weight count ? switch (weightCount) { case 1: _Type[Weight]=Float1; break; case 2: _Type[Weight]=Float2; break; case 3: _Type[Weight]=Float3; break; case 4: _Type[Weight]=Float4; break; } // Serial VBuffers components. //============================ for(sint id=0;id<(sint)_NbVerts;id++) { uint8 *pointer = &(*_NonResidentVertices.begin()); uint stridedId = id * _VertexSize; // XYZ. if(_Flags & PositionFlag) { CVector &vert= *(CVector*)(pointer + stridedId + _Offset[Position]); f.serial(vert); } // Normal if(_Flags & NormalFlag) { CVector &norm= *(CVector*)(pointer + stridedId + _Offset[Normal]); f.serial(norm); } // Uvs. for(i=0;i<MaxStage;i++) { if(_Flags & (TexCoord0Flag<<i)) { CUV &uv= *(CUV*)(pointer + stridedId + _Offset[TexCoord0+i]); f.serial(uv); } } // Color. if(_Flags & PrimaryColorFlag) { CRGBA &col= *(CRGBA*)(pointer + stridedId + _Offset[PrimaryColor]); f.serial(col); } // Specular. if(_Flags & SecondaryColorFlag) { CRGBA &col= *(CRGBA*)(pointer + stridedId + _Offset[SecondaryColor]); f.serial(col); } // Weights for(i=0;i<weightCount;i++) { // Weight channel available ? float &w= *(float*)(pointer + stridedId + _Offset[Weight] + i*sizeof(float)); f.serial(w); } // CPaletteSkin (version 1+ only). if((ver>=1) && ((_Flags & PaletteSkinFlag) == CVertexBuffer::PaletteSkinFlag) ) { CPaletteSkin &ps= *(CPaletteSkin*)(pointer + stridedId + _Offset[PaletteSkin]); f.serial(ps); } } // Set touch flags _InternalFlags = 0; if(f.isReading()) { // Force non resident restaureNonResidentMemory(); } } // -------------------------------------------------- void CVertexBuffer::serial(NLMISC::IStream &f) { /* *********************************************** * WARNING: This Class/Method must be thread-safe (ctor/dtor/serial): no static access for instance * It can be loaded/called through CAsyncFileManager for instance * ***********************************************/ /* Version 2: - cut to use serialHeader() serialSubset(). Version 1: - PaletteSkin version. Version 0: - base verison. */ nlassert (!isLocked()); sint ver= f.serialVersion(2); if (ver<2) { // old serial method serialOldV1Minus(f, ver); } else { // read write the header of the VBuffer. serialHeader(f); // read write the entire subset. serialSubset(f, 0, _NbVerts); } } // -------------------------------------------------- void CVertexBuffer::serialHeader(NLMISC::IStream &f) { /* *********************************************** * WARNING: This Class/Method must be thread-safe (ctor/dtor/serial): no static access for instance * It can be loaded/called through CAsyncFileManager for instance * ***********************************************/ /* Version 3: - Preferred memory. Version 2: - Vertex color format management. Version 1: - Extended vertex format management. Version 0: - base verison of the header serialisation. */ sint ver= f.serialVersion(3); // Hulud // Serial VBuffers format/size. //============================= // Flags uint16 flags=_Flags; if (ver<1) { // Must be reading nlassert (f.isReading()); // Serial old flags uint32 oldFlags; f.serial(oldFlags); // Remap flags uint weightCount; flags=remapV2Flags (oldFlags, weightCount); // Set default value type for (uint i=0; i<NumValue; i++) _Type[i]=DefaultValueType[i]; // weight count ? switch (weightCount) { case 1: _Type[Weight]=Float1; break; case 2: _Type[Weight]=Float2; break; case 3: _Type[Weight]=Float3; break; case 4: _Type[Weight]=Float4; break; } } else { // Serial new vertex flags f.serial(flags); // Serial type of values for (uint i=0; i<NumValue; i++) { if (!(flags & (1 << i))) { _Type[i] = DefaultValueType[i]; } f.serial (_Type[i]); } } // Serial nb vertices uint32 nbVerts=_NbVerts; f.serial(nbVerts); if(f.isReading()) { reserve(0); // Init vertex format setup clearValueEx (); // Init vertex format for (uint i=0; i<NumValue; i++) { // Setup this value ? if (flags&(1<<i)) { // Add a value addValueEx ((TValue)i, (TType)_Type[i]); } } // Build final vertex format initEx (); // Set num of vertices setNumVertices(nbVerts); } // All other infos (but _NonResidentVertices) are computed by initEx() and setNumVertices(). if (ver>=2) f.serial (_VertexColorFormat); if (ver>=3) { f.serialEnum(_PreferredMemory); f.serial(_Name); } else { // Init preferred memory if(f.isReading()) { _PreferredMemory = RAMPreferred; _Name = ""; } } } // -------------------------------------------------- uint CVertexBuffer:: getNumTexCoordUsed() const { for (sint k = (MaxStage - 1); k >= 0; --k) { if (_Flags & (TexCoord0Flag << k)) return (uint) (k + 1); } return 0; } // -------------------------------------------------- uint8 CVertexBuffer::getNumWeight () const { // Num weight switch (_Type[Weight]) { case Float1: return 1; case Float2: return 2; case Float3: return 3; case Float4: return 4; } // No weight return 0; } // -------------------------------------------------- void CVertexBuffer::serialSubset(NLMISC::IStream &f, uint vertexStart, uint vertexEnd) { /* *********************************************** * WARNING: This Class/Method must be thread-safe (ctor/dtor/serial): no static access for instance * It can be loaded/called through CAsyncFileManager for instance * ***********************************************/ /* Version 2: - UVRouting Version 1: - weight is 4 float in standard format. Version 0: - base verison of a vbuffer subset serialisation. */ sint ver = f.serialVersion(2); // Serial VBuffers components. //============================ nlassert(vertexStart<_NbVerts || _NbVerts==0); nlassert(vertexEnd<=_NbVerts); for(uint id=vertexStart; id<vertexEnd; id++) { // For each value for (uint value=0; value<NumValue; value++) { // Value used ? if (_Flags&(1<<value)) { // Get the pointer on it void *ptr=(void*)((&(*_NonResidentVertices.begin()))+id*_VertexSize+getValueOffEx ((TValue)value)); f.serialBuffer ((uint8*)ptr, SizeType[_Type[value]]); } } } // Serial the UV Routing table //============================ if (ver>=2) { f.serialBuffer (_UVRouting, sizeof(uint8)*MaxStage); } else { // Reset the table uint i; for (i=0; i<MaxStage; i++) _UVRouting[i] = i; } // Set touch flags if(f.isReading()) { // Force non resident restaureNonResidentMemory(); } } // -------------------------------------------------- bool CVertexBuffer::setVertexColorFormat (TVertexColorType format) { // If resident, quit if (isResident()) return false; nlassert (!isLocked()); // Format is not good ? if ((TVertexColorType)_VertexColorFormat != format) { // Diffuse or specualr component ? if (_Flags & (PrimaryColorFlag|SecondaryColorFlag)) { uint i; uint32 *ptr0 = (_Flags&PrimaryColorFlag)?(uint32*)&(_NonResidentVertices[_Offset[PrimaryColor]]):NULL; uint32 *ptr1 = (_Flags&SecondaryColorFlag)?(uint32*)&(_NonResidentVertices[_Offset[SecondaryColor]]):NULL; for (i=0; i<_NbVerts; i++) { if (ptr0) { const register uint32 value = *ptr0; #ifdef NL_LITTLE_ENDIAN *ptr0 = (value&0xff00ff00)|((value&0xff)<<16)|((value&0xff0000)>>16); #else // NL_LITTLE_ENDIAN *ptr0 = (value&0x00ff00ff)|((value&0xff00)<<16)|((value&0xff000000)>>16); #endif // NL_LITTLE_ENDIAN ptr0 = (uint32*)(((uint8*)ptr0)+_VertexSize); } if (ptr1) { const register uint32 value = *ptr1; #ifdef NL_LITTLE_ENDIAN *ptr1 = (value&0xff00ff00)|((value&0xff)<<16)|((value&0xff0000)>>16); #else // NL_LITTLE_ENDIAN *ptr1 = (value&0x00ff00ff)|((value&0xff00)<<16)|((value&0xff000000)>>16); #endif // NL_LITTLE_ENDIAN ptr1 = (uint32*)(((uint8*)ptr1)+_VertexSize); } } } _VertexColorFormat = (uint8)format; // Force non resident restaureNonResidentMemory(); } return true; } // -------------------------------------------------- void CVertexBuffer::setPreferredMemory (TPreferredMemory preferredMemory, bool keepLocalMemory) { if ((_PreferredMemory != preferredMemory) || (_KeepLocalMemory != keepLocalMemory)) { _PreferredMemory = preferredMemory; _KeepLocalMemory = keepLocalMemory; // Force non resident restaureNonResidentMemory(); } } // -------------------------------------------------- void CVertexBuffer::setLocation (TLocation newLocation) { // Upload ? if (newLocation != NotResident) { // The driver must have setuped the driver info nlassert (DrvInfos); // Current size of the buffer const uint size = ((_PreferredMemory==RAMVolatile)||(_PreferredMemory==AGPVolatile))?_NbVerts*_VertexSize:_Capacity*_VertexSize; // The buffer must not be resident if (_Location != NotResident) setLocation (NotResident); // Copy the buffer containt uint8 *dest = DrvInfos->lock (0, size, false); nlassert (size<=_NonResidentVertices.size()); // Internal buffer must have the good size memcpy (dest, &(_NonResidentVertices[0]), size); DrvInfos->unlock(0, 0); // Reset the non resident container if not a static preferred memory and not put in RAM if ((_PreferredMemory != StaticPreferred) && (_Location != RAMResident) && !_KeepLocalMemory) contReset(_NonResidentVertices); // Clear touched flags resetTouchFlags (); _Location = newLocation; _ResidentSize = size; } else { // Current size of the buffer const uint size = _Capacity*_VertexSize; // Resize the non resident buffer _NonResidentVertices.resize (size); // If resident in RAM, backup the data in non resident memory if ((_Location == RAMResident) && (_PreferredMemory != RAMVolatile) && (_PreferredMemory != AGPVolatile) && !_KeepLocalMemory) { // The driver must have setuped the driver info nlassert (DrvInfos); // Copy the old buffer data const uint8 *src = DrvInfos->lock (0, _ResidentSize, true); if (!_NonResidentVertices.empty()) memcpy (&(_NonResidentVertices[0]), src, std::min (size, (uint)_ResidentSize)); DrvInfos->unlock(0, 0); } _Location = NotResident; _ResidentSize = 0; // Touch the buffer _InternalFlags |= TouchedAll; } } // -------------------------------------------------- void CVertexBuffer::restaureNonResidentMemory() { setLocation (NotResident); if (DrvInfos) DrvInfos->VertexBufferPtr = NULL; // Tell the driver info to not restaure memory when it will die // Must kill the drv mirror of this VB. DrvInfos.kill(); } // -------------------------------------------------- void CVertexBuffer::fillBuffer () { if (DrvInfos && _KeepLocalMemory) { // Copy the local memory in local memory const uint size = _NbVerts*_VertexSize; nlassert (size<=_NonResidentVertices.size()); uint8 *dest = DrvInfos->lock (0, size, false); NLMISC::CFastMem::memcpy (dest, &(_NonResidentVertices[0]), size); DrvInfos->unlock(0, size); } } // -------------------------------------------------- // CPaletteSkin serial (no version chek). void CPaletteSkin::serial(NLMISC::IStream &f) { f.serial(MatrixId[0], MatrixId[1], MatrixId[2], MatrixId[3]); } // -------------------------------------------------- IVBDrvInfos::~IVBDrvInfos() { _Driver->removeVBDrvInfoPtr(_DriverIterator); } // -------------------------------------------------- // CVertexBufferReadWrite // -------------------------------------------------- NLMISC::CVector* CVertexBufferReadWrite::getVertexCoordPointer(uint idx) { nlassert (_Parent->checkLockedBuffer()); uint8* ptr; ptr=_Parent->_LockedBuffer; ptr+=(idx*_Parent->_VertexSize); return((NLMISC::CVector*)ptr); } // -------------------------------------------------- NLMISC::CVector* CVertexBufferReadWrite::getNormalCoordPointer(uint idx) { nlassert (_Parent->checkLockedBuffer()); uint8* ptr; if ( !(_Parent->_Flags & CVertexBuffer::NormalFlag) ) { return(NULL); } ptr=_Parent->_LockedBuffer; ptr+=_Parent->_Offset[CVertexBuffer::Normal]; ptr+=idx*_Parent->_VertexSize; return((NLMISC::CVector*)ptr); } // -------------------------------------------------- void* CVertexBufferReadWrite::getColorPointer(uint idx) { nlassert (_Parent->checkLockedBuffer()); uint8* ptr; if ( !(_Parent->_Flags & CVertexBuffer::PrimaryColorFlag) ) { return(NULL); } ptr=_Parent->_LockedBuffer; ptr+=_Parent->_Offset[CVertexBuffer::PrimaryColor]; ptr+=idx*_Parent->_VertexSize; return((void*)ptr); } // -------------------------------------------------- void* CVertexBufferReadWrite::getSpecularPointer(uint idx) { nlassert (_Parent->checkLockedBuffer()); uint8* ptr; if ( !(_Parent->_Flags & CVertexBuffer::SecondaryColorFlag) ) { return(NULL); } ptr=_Parent->_LockedBuffer; ptr+=_Parent->_Offset[CVertexBuffer::SecondaryColor]; ptr+=idx*_Parent->_VertexSize; return((void*)ptr); } // -------------------------------------------------- NLMISC::CUV* CVertexBufferReadWrite::getTexCoordPointer(uint idx, uint8 stage) { nlassert (_Parent->checkLockedBuffer()); uint8* ptr; if ( !(_Parent->_Flags & (CVertexBuffer::TexCoord0Flag<<stage)) ) { return(NULL); } ptr=_Parent->_LockedBuffer; ptr+=_Parent->_Offset[CVertexBuffer::TexCoord0+stage]; ptr+=idx*_Parent->_VertexSize; return((NLMISC::CUV*)ptr); } // -------------------------------------------------- float* CVertexBufferReadWrite::getWeightPointer(uint idx, uint8 wgt) { nlassert (_Parent->checkLockedBuffer()); uint8* ptr; nlassert(wgt<CVertexBuffer::MaxWeight); if( !(_Parent->_Flags & CVertexBuffer::WeightFlag)) return NULL; ptr=(uint8*)(&_Parent->_LockedBuffer[idx*_Parent->_VertexSize]); ptr+=_Parent->_Offset[CVertexBuffer::Weight]+wgt*sizeof(float); return (float*)ptr; } // -------------------------------------------------- CPaletteSkin* CVertexBufferReadWrite::getPaletteSkinPointer(uint idx) { nlassert (_Parent->checkLockedBuffer()); uint8* ptr; if ( (_Parent->_Flags & CVertexBuffer::PaletteSkinFlag) != CVertexBuffer::PaletteSkinFlag ) { return(NULL); } ptr=_Parent->_LockedBuffer; ptr+=_Parent->_Offset[CVertexBuffer::PaletteSkin]; ptr+=idx*_Parent->_VertexSize; return((CPaletteSkin*)ptr); } // -------------------------------------------------- void CVertexBufferReadWrite::touchVertices (uint first, uint last) { nlassert (_Parent->checkLockedBuffer()); _First = first; _Last = last; } // -------------------------------------------------- // CVertexBufferRead // -------------------------------------------------- const NLMISC::CVector* CVertexBufferRead::getVertexCoordPointer(uint idx) const { nlassert (_Parent->checkLockedBuffer()); const uint8* ptr; ptr=_Parent->_LockedBuffer; ptr+=(idx*_Parent->_VertexSize); return((const NLMISC::CVector*)ptr); } // -------------------------------------------------- const NLMISC::CVector* CVertexBufferRead::getNormalCoordPointer(uint idx) const { nlassert (_Parent->checkLockedBuffer()); const uint8* ptr; if ( !(_Parent->_Flags & CVertexBuffer::NormalFlag) ) { return(NULL); } ptr=_Parent->_LockedBuffer; ptr+=_Parent->_Offset[CVertexBuffer::Normal]; ptr+=idx*_Parent->_VertexSize; return((const NLMISC::CVector*)ptr); } // -------------------------------------------------- const void* CVertexBufferRead::getColorPointer(uint idx) const { nlassert (_Parent->checkLockedBuffer()); const uint8* ptr; if ( !(_Parent->_Flags & CVertexBuffer::PrimaryColorFlag) ) { return(NULL); } ptr=_Parent->_LockedBuffer; ptr+=_Parent->_Offset[CVertexBuffer::PrimaryColor]; ptr+=idx*_Parent->_VertexSize; return((const void*)ptr); } // -------------------------------------------------- const void* CVertexBufferRead::getSpecularPointer(uint idx) const { nlassert (_Parent->checkLockedBuffer()); const uint8* ptr; if ( !(_Parent->_Flags & CVertexBuffer::SecondaryColorFlag) ) { return(NULL); } ptr=_Parent->_LockedBuffer; ptr+=_Parent->_Offset[CVertexBuffer::SecondaryColor]; ptr+=idx*_Parent->_VertexSize; return((const void*)ptr); } // -------------------------------------------------- const NLMISC::CUV* CVertexBufferRead::getTexCoordPointer(uint idx, uint8 stage) const { nlassert (_Parent->checkLockedBuffer()); const uint8* ptr; if ( !(_Parent->_Flags & (CVertexBuffer::TexCoord0Flag<<stage)) ) { return(NULL); } ptr=_Parent->_LockedBuffer; ptr+=_Parent->_Offset[CVertexBuffer::TexCoord0+stage]; ptr+=idx*_Parent->_VertexSize; return((const NLMISC::CUV*)ptr); } // -------------------------------------------------- const float* CVertexBufferRead::getWeightPointer(uint idx, uint8 wgt) const { nlassert (_Parent->checkLockedBuffer()); const uint8* ptr; nlassert(wgt<CVertexBuffer::MaxWeight); if( !(_Parent->_Flags & CVertexBuffer::WeightFlag)) return NULL; ptr=(uint8*)(&_Parent->_LockedBuffer[idx*_Parent->_VertexSize]); ptr+=_Parent->_Offset[CVertexBuffer::Weight]+wgt*sizeof(float); return (float*)ptr; } // -------------------------------------------------- const CPaletteSkin* CVertexBufferRead::getPaletteSkinPointer(uint idx) const { nlassert (_Parent->checkLockedBuffer()); const uint8* ptr; if ( (_Parent->_Flags & CVertexBuffer::PaletteSkinFlag) != CVertexBuffer::PaletteSkinFlag ) { return(NULL); } ptr=_Parent->_LockedBuffer; ptr+=_Parent->_Offset[CVertexBuffer::PaletteSkin]; ptr+=idx*_Parent->_VertexSize; return((const CPaletteSkin*)ptr); } // -------------------------------------------------- }