// 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 . #ifndef NL_VERTEX_BUFFER_H #define NL_VERTEX_BUFFER_H #include "nel/misc/types_nl.h" #include "nel/misc/smart_ptr.h" #include "nel/misc/rgba.h" #include "nel/misc/vector.h" #include "nel/misc/vectord.h" #include "nel/misc/debug.h" #include "nel/misc/uv.h" #include #include namespace NLMISC { class CUV; } namespace NL3D { using NLMISC::CRefCount; using NLMISC::CRefPtr; using NLMISC::CRGBA; using NLMISC::CBGRA; using NLMISC::CVector; using NLMISC::CVectorD; using NLMISC::CUV; class IDriver; class CVertexBufferReadWrite; class CVertexBufferRead; // -------------------------------------------------- // List typedef. class IVBDrvInfos; class CVertexBuffer; typedef std::list TVBDrvInfoPtrList; typedef TVBDrvInfoPtrList::iterator ItVBDrvInfoPtrList; // *************************************************************************** /** Describe index for palette skinning. * Id must be in range [0, IDriver::MaxModelMatrix [ */ struct CPaletteSkin { uint8 MatrixId[4]; void serial(NLMISC::IStream &f); }; // *************************************************************************** /** * A vertex buffer to work with the driver * * Before the vertex buffer is resident (IDriver::activeVertexBuffer), it is in system memory. * Once the vertex buffer is resident, the driver creates its proprietary vertex buffer and release the internal vertex buffer. * At this moment the vertex buffer can be in VRAM, AGP or system memory. * * The vertex buffers resident in AGP and VRAM are writeonly, i-e, you can't read them after a lock(). If you change the capacity * of the format of a writeonly buffer, the content is lost. * */ /* *** IMPORTANT ******************** * *** IF YOU MODIFY THE STRUCTURE OF THIS CLASS, PLEASE INCREMENT IDriver::InterfaceVersion TO INVALIDATE OLD DRIVER DLL * ********************************** */ // All these flags are similar to DX8 class CVertexBuffer : public CRefCount { public: friend class CVertexBufferReadWrite; friend class CVertexBufferRead; /** * Type of preferred memory */ enum TPreferredMemory { RAMPreferred = 0, // A block of driver RAM memory is allocated for this buffer. The buffer is read/write. AGPPreferred, // A block of driver AGP memory is allocated for this buffer. The buffer is writeonly. StaticPreferred, // The buffer will not be modified. A block of driver AGP or VRAM memory is allocated for this buffer. The buffer is writeonly. RAMVolatile, // A block of temporary driver RAM memory will be returned by lock(). The buffer must be entirely filled after each swapBuffers(). The buffer is writeonly. AGPVolatile, // A block of temporary driver AGP memory will be returned by lock(). The buffer must be entirely filled after each swapBuffers(). The buffer is writeonly. PreferredCount }; /** * Type of buffer location */ enum TLocation { RAMResident = 0, AGPResident, VRAMResident, NotResident, LocationCount }; /** * Value ID, there is 16 value id */ enum TValue { Position =0, Normal =1, TexCoord0 =2, TexCoord1 =3, TexCoord2 =4, TexCoord3 =5, TexCoord4 =6, TexCoord5 =7, TexCoord6 =8, TexCoord7 =9, PrimaryColor =10, SecondaryColor =11, Weight =12, PaletteSkin =13, Fog =14, Empty =15, NumValue =16 }; /** * Misc infos */ enum { FirstTexCoordValue = TexCoord0, LastTexCoordValue = TexCoord7 }; /** * Value flags */ enum { PositionFlag = 1< DrvInfos; uint getTouchFlags() const { return _InternalFlags&TouchedAll; } /** Used by the driver implementation. The driver must first allocate its internal buffer and fill DrvInfos. Then it has to call setLocation(true). * * If newLocation!=NotResident, setLocation() will copy the non resident buffer in the choosed resident memory and * untouch the buffer. If the buffer preferres RAM or AGP memory, it will release the non resident memory. * * If newLocation==NotResident, setLocation() will realloc the non resident buffer, copy the vertex data if the buffer was resident in RAM. Then * it will touch the buffer.*/ void setLocation (TLocation newLocation); // The driver implementation must set the location after activeVertexBuffer. /** Called by the driver implementation during the buffer activation */ void fillBuffer (); // @} public: /* *********************************************** * 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 * ***********************************************/ /** * Default constructor. Make an empty vertex buffer. No value, no vertex. Vertex color format is set to TRGBA. */ CVertexBuffer(void); /** * Named vertex buffer. Make an empty vertex buffer. No value, no vertex. Vertex color format is set to TRGBA. */ CVertexBuffer(const char *name); /** * Copy constructor. * Do not copy DrvInfos, copy all infos and set IDRV_VF_TOUCHED_ALL. */ CVertexBuffer(const CVertexBuffer &vb); /** * Destructor. */ ~CVertexBuffer(void); /** * Copy operator. * Do not copy DrvInfos, copy all infos and set IDRV_VF_TOUCHED_ALL. * All the destination vertex buffer is invalidated. Data are lost. * The source and destination vertex buffers must be unlocked. * Vertices datas are not copied */ CVertexBuffer &operator=(const CVertexBuffer &vb); /** Copy a vertex buffer, including vertices data. Destination vb is not resident. * May be slow if there's agp / vram readback. * Initial content of the destination vertex buffer is lost. * Use this to retrieve content of a write-only buffer. * Using lock with CVertexBufferRead won't work (used as a foolkeeper to prevent * reading of a resident buffer that is not in ram) * NB : will assert when used with volatile vb */ void copyVertices(CVertexBuffer &dest) const; /** * Set the buffer preferred memory. Default preferred memory is RAM. * * Preferre RAM if the buffer is changed several times in the same render pass. * Preferre AGP if the buffer is changed only one time in the same render pass. * Preferre Static if the buffer is changed only one time for initialisation. * * If static memory is chosen, the driver will choose VRAM or AGP depending of the user configuration. * * If static or RAM memory is preferred, the buffer won't be lost after a driver reset. * * If the buffer preferres AGP memory, the buffer is lost after a driver reset. When the buffer is lost, it returns * in a non resident state. The state must be tested at each pass with isResident(). If the buffer is in a * non resident state, the user must refill it. * * If VRAM memory allocation failed, the driver will try with AGP and then with RAM. * If AGP memory allocation failed, the driver will try with RAM. * RAM allocation should never failed. * * Performance note: * - for RAM CVertexBuffer, you can read / write as you like. * - for AGP CVertexBuffer, you should write sequentially to take full advantage of the write combiners. You can't read. * - for Static CVertexBuffer, you should write only one time, to init. You can read. Each modification will be done * in a RAM buffer. Then the unlocked area will be copied into the VRAM or AGP memory. * * Volatile buffers must be completely filled at each pass. They are lost after each swapBuffers(). They are writeonly. * Volatile buffers must be resized before the lock call. Only one lock per render must be done with volatile buffers if * keepLocalMemory is false. * * If keepLocalMemory is true, lock() will return a local memory pointer. The local memory will copied in resident memory * during the activation of the buffer. The not all the buffer capacity is copied but only the used size. * * If the buffer preferres AGP memory, the data are lost. * The buffer is no more resident. * The buffer is invalidated. * The buffer must be unlocked before the call. */ void setPreferredMemory (TPreferredMemory preferredMemory, bool keepLocalMemory); /** * Get the vertex buffer preferred memory. */ TPreferredMemory getPreferredMemory () const { return _PreferredMemory; } /** * Get the keep local memory flag. */ bool getKeepLocalMemory () const { return _KeepLocalMemory; } /** * Get the vertex buffer current location. */ TLocation getLocation () const { return _Location; } /** * Returns if the vertex buffer is driver resident or not. * The vertex buffer is resident after a call to IDriver::activeVertexBuffer(). */ bool isResident () const { return (_Location != NotResident) && DrvInfos; } /** * \name Standard values vertex buffer mgt. * \name Thoses methods manage the vertex buffer (position, normal, colors and uv) with standard value. */ // @{ /** * Setup the vertex format using standard values. Do it before any other standard methods. * * Use one or several flag between : PositionFlag, WeightFlag, NormalFlag, PrimaryColorFlag, * SecondaryColorFlag, FogFlag, TexCoord0Flag, TexCoord1Flag, TexCoord2Flag, * TexCoord3Flag, TexCoord4Flag, TexCoord5Flag, TexCoord6Flag, TexCoord7Flag, PaletteSkinFlag * * If the buffer preferres AGP memory, the data are lost. * The vertex buffer is no more resident. * The vertex buffer is invalidated. * The vertex buffer must be unlocked before the call. * * If WeightFlag is specified, 4 float are used to setup the skinning value on 4 bones. */ bool setVertexFormat (uint32 Flags); /** * Return the vertex format used by the vertex buffer. * * Return one or several flags between : PositionFlag, WeightFlag, NormalFlag, PrimaryColorFlag, * SecondaryColorFlag, FogFlag, TexCoord0Flag, TexCoord1Flag, TexCoord2Flag, * TexCoord3Flag, TexCoord4Flag, TexCoord5Flag, TexCoord6Flag, TexCoord7Flag, PaletteSkinFlag * * If WeightFlag is specified, 4 float are used to setup the skinning value on 4 bones. */ uint16 getVertexFormat (void) const { return(_Flags); }; /// Returns the number of texture coordinate stages used by this vertex buffer uint getNumTexCoordUsed() const; // It is an error (assert) to query a vertex offset of a vertex component not setuped in setVertexFormat(). // NB: The Vertex offset is always 0. sint getNormalOff() const {nlassert(_Flags & NormalFlag); return _Offset[Normal];} sint getTexCoordOff(uint8 stage=0) const {nlassert(_Flags & (TexCoord0Flag< _NonResidentVertices; // The locked vertex buffer mutable uint8* _LockedBuffer; // Offset of each value uint16 _Offset[NumValue]; // The UV routing table uint8 _UVRouting[MaxStage]; // The vertex buffer is locked n times mutable uint _LockCounter; // Prefered memory TPreferredMemory _PreferredMemory; // Location of the buffer TLocation _Location; // Resident buffer size uint32 _ResidentSize; // Debug string std::string _Name; // Keep in local memory bool _KeepLocalMemory; }; // *** IMPORTANT ******************** // *** IF YOU MODIFY THE STRUCTURE OF THIS CLASS, PLEASE INCREMENT IDriver::InterfaceVersion TO INVALIDATE OLD DRIVER DLL // ********************************** class IVBDrvInfos : public CRefCount { protected: IDriver *_Driver; private: ItVBDrvInfoPtrList _DriverIterator; public: CRefPtr VertexBufferPtr; IVBDrvInfos(IDriver *drv, ItVBDrvInfoPtrList it, CVertexBuffer *vb) {_Driver= drv; _DriverIterator= it; VertexBufferPtr=vb;} /** Lock method. Lock the region between begin and end (in bytes). * What ever begin is, the returned pointer always points on the index 0. */ virtual uint8 *lock (uint begin, uint end, bool readOnly) =0; /** Unlock method. Unlock the region between begin and end (in bytes). */ virtual void unlock (uint begin, uint end) =0; /* The virtual dtor is important. * The driver implementation must call setLocation (NotResident) if VertexBufferPtr!=NULL.*/ virtual ~IVBDrvInfos(); }; /** * The vertex buffer accessor read / write */ class CVertexBufferReadWrite { public: friend class CVertexBuffer; CVertexBufferReadWrite() { _Parent = NULL; } ~CVertexBufferReadWrite() { unlock(); } /** * Unlock the vertex buffer. * After this call, the accessor should not be used before a new lock. */ void unlock() { if (_Parent) { _Parent->unlock(_First, _Last); _Parent = NULL; } } /* Set a value into the vertex buffer. */ inline void setVertexCoord(uint idx, float x, float y, float z); inline void setVertexCoord(uint idx, const CVector &v); inline void setNormalCoord(uint idx, const CVector &v); inline void setTexCoord(uint idx, uint8 stage, float u, float v); inline void setTexCoord(uint idx, uint8 stage, const CUV &uv); inline void setColor(uint idx, CRGBA rgba); inline void setSpecular(uint idx, CRGBA rgba); inline void setWeight(uint idx, uint8 wgt, float w); inline void setPaletteSkin(uint idx, CPaletteSkin ps); inline void setValueFloat1Ex (CVertexBuffer::TValue valueId, uint idx, float value); inline void setValueFloat2Ex (CVertexBuffer::TValue valueId, uint idx, float x, float y); inline void setValueFloat3Ex (CVertexBuffer::TValue valueId, uint idx, float x, float y, float z); inline void setValueFloat3Ex (CVertexBuffer::TValue valueId, uint idx, const CVector& vector); inline void setValueFloat4Ex (CVertexBuffer::TValue valueId, uint idx, float x, float y, float z, float w); inline void setValueUChar4Ex (CVertexBuffer::TValue valueId, uint idx, CRGBA rgba); /** Get a pointer on a value. * * For Color pointers : * This method returns a (CRGBA*) or a (CBGRA*) regarding the vertex color format returned by CVertexBufferReadWrite::getVertexColorFormat(). * A call to IDriver::activeVertexBuffer() will change this format to the format returned by IDriver::getVertexColorFormat(). * So, before each write of vertex color in the vertex buffer, the vertex color format must be checked with CVertexBuffer::getVertexColorFormat(). */ NLMISC::CVector* getVertexCoordPointer(uint idx=0); NLMISC::CVector* getNormalCoordPointer(uint idx=0); NLMISC::CUV* getTexCoordPointer(uint idx=0, uint8 stage=0); void* getColorPointer(uint idx=0); void* getSpecularPointer(uint idx=0); float* getWeightPointer(uint idx=0, uint8 wgt=0); CPaletteSkin* getPaletteSkinPointer(uint idx=0); void* getValueEx (CVertexBuffer::TValue valueId, uint idx=0) { nlassert (_Parent->checkLockedBuffer()); nlassert (_Parent->_Flags & (1<_LockedBuffer+idx*_Parent->_VertexSize+_Parent->getValueOffEx (valueId)); } /** Touch the updated vertices. If the method is not call, the accessor update all the vertices. * \param first is the index of the first vertices to update. * \param last is the index of the last vertices to update + 1. */ void touchVertices (uint first, uint last); const CVertexBuffer *getParent() const { return _Parent; } private: // No copy operators available void operator=(const CVertexBufferReadWrite& /* other */) {} CVertexBufferReadWrite(const CVertexBufferReadWrite& /* other */) {} CVertexBuffer *_Parent; uint _First, _Last; }; /** * The vertex buffer read accessor */ class CVertexBufferRead { public: friend class CVertexBuffer; CVertexBufferRead() { _Parent = NULL; } ~CVertexBufferRead() { unlock(); } /** * Unlock the vertex buffer. * After this call, the accessor should not be used before a new lock. */ void unlock() { if (_Parent) { _Parent->unlock(); _Parent = NULL; } } /** Get a pointer on a value. * * For Color pointers : * This method returns a (CRGBA*) or a (CBGRA*) regarding the vertex color format returned by CVertexBufferRead::getVertexColorFormat(). * A call to IDriver::activeVertexBuffer() will change this format to the format returned by IDriver::getVertexColorFormat(). * So, before each write of vertex color in the vertex buffer, the vertex color format must be checked with CVertexBuffer::getVertexColorFormat(). */ const NLMISC::CVector* getVertexCoordPointer(uint idx=0) const; const NLMISC::CVector* getNormalCoordPointer(uint idx=0) const; const NLMISC::CUV* getTexCoordPointer(uint idx=0, uint8 stage=0) const; const void* getColorPointer(uint idx=0) const; const void* getSpecularPointer(uint idx=0) const; const float* getWeightPointer(uint idx=0, uint8 wgt=0) const; const CPaletteSkin* getPaletteSkinPointer(uint idx=0) const; const void* getValueEx (CVertexBuffer::TValue valueId, uint idx=0) const { nlassert (_Parent->_Flags & (1<_LockedBuffer+idx*_Parent->_VertexSize+_Parent->getValueOffEx (valueId)); } const CVertexBuffer *getParent() const { return _Parent; } private: // No copy operators available void operator=(const CVertexBufferRead& /* other */) {} CVertexBufferRead(const CVertexBufferRead& /* other */) {} const CVertexBuffer *_Parent; }; ////////////////////////////////////// // implementation of inline methods // ////////////////////////////////////// // -------------------------------------------------- inline void CVertexBufferReadWrite::setVertexCoord(uint idx, float x, float y, float z) { float* ptr; nlassert (_Parent->checkLockedBuffer()); nlassert (_Parent->_Flags & CVertexBuffer::PositionFlag); nlassert (_Parent->_Type[CVertexBuffer::Position]==CVertexBuffer::Float3); ptr=(float*)(&_Parent->_LockedBuffer[idx*_Parent->_VertexSize]); *ptr=x; ptr++; *ptr=y; ptr++; *ptr=z; } // -------------------------------------------------- inline void CVertexBufferReadWrite::setVertexCoord(uint idx, const CVector &v) { uint8* ptr; nlassert (_Parent->checkLockedBuffer()); nlassert (_Parent->_Flags & CVertexBuffer::PositionFlag); nlassert (_Parent->_Type[CVertexBuffer::Position]==CVertexBuffer::Float3); ptr=&_Parent->_LockedBuffer[idx*_Parent->_VertexSize]; memcpy(ptr, &(v.x), 3*sizeof(float)); } // -------------------------------------------------- inline void CVertexBufferReadWrite::setNormalCoord(uint idx, const CVector &v) { uint8* ptr; nlassert (_Parent->checkLockedBuffer()); nlassert (_Parent->_Flags & CVertexBuffer::NormalFlag); nlassert (_Parent->_Type[CVertexBuffer::Normal]==CVertexBuffer::Float3); ptr=&_Parent->_LockedBuffer[idx*_Parent->_VertexSize]; ptr+=_Parent->_Offset[CVertexBuffer::Normal]; memcpy(ptr, &(v.x), 3*sizeof(float)); } // -------------------------------------------------- inline void CVertexBufferReadWrite::setColor(uint idx, CRGBA rgba) { uint8* ptr; nlassert (_Parent->checkLockedBuffer()); nlassert(_Parent->_Flags & CVertexBuffer::PrimaryColorFlag); nlassert (_Parent->_Type[CVertexBuffer::PrimaryColor]==CVertexBuffer::UChar4); ptr=(uint8*)(&_Parent->_LockedBuffer[idx*_Parent->_VertexSize]); ptr+=_Parent->_Offset[CVertexBuffer::PrimaryColor]; if (_Parent->getVertexColorFormat () == CVertexBuffer::TRGBA) *(CRGBA*)ptr = rgba; else *(CBGRA*)ptr = rgba; } // -------------------------------------------------- inline void CVertexBufferReadWrite::setSpecular(uint idx, CRGBA rgba) { uint8* ptr; nlassert (_Parent->checkLockedBuffer()); nlassert(_Parent->_Flags & CVertexBuffer::SecondaryColorFlag); nlassert (_Parent->_Type[CVertexBuffer::SecondaryColor]==CVertexBuffer::UChar4); ptr=(uint8*)(&_Parent->_LockedBuffer[idx*_Parent->_VertexSize]); ptr+=_Parent->_Offset[CVertexBuffer::SecondaryColor]; if (_Parent->getVertexColorFormat () == CVertexBuffer::TRGBA) *(CRGBA*)ptr = rgba; else *(CBGRA*)ptr = rgba; } // -------------------------------------------------- inline void CVertexBufferReadWrite::setTexCoord(uint idx, uint8 stage, float u, float v) { uint8* ptr; float* ptrf; nlassert (_Parent->checkLockedBuffer()); nlassert(stage_Flags & (CVertexBuffer::TexCoord0Flag<_Type[CVertexBuffer::TexCoord0+stage]==CVertexBuffer::Float2); ptr=(uint8*)(&_Parent->_LockedBuffer[idx*_Parent->_VertexSize]); ptr+=_Parent->_Offset[CVertexBuffer::TexCoord0+stage]; ptrf=(float*)ptr; *ptrf=u; ptrf++; *ptrf=v; } // -------------------------------------------------- inline void CVertexBufferReadWrite::setTexCoord(uint idx, uint8 stage, const CUV &uv) { uint8* ptr; CUV* ptruv; nlassert (_Parent->checkLockedBuffer()); nlassert(stage_Flags & (CVertexBuffer::TexCoord0Flag<_Type[CVertexBuffer::TexCoord0+stage]==CVertexBuffer::Float2); ptr=(uint8*)(&_Parent->_LockedBuffer[idx*_Parent->_VertexSize]); ptr+=_Parent->_Offset[CVertexBuffer::TexCoord0+stage]; ptruv=(CUV*)ptr; *ptruv=uv; } // -------------------------------------------------- inline void CVertexBufferReadWrite::setWeight(uint idx, uint8 wgt, float w) { uint8* ptr; float* ptrf; nlassert (_Parent->checkLockedBuffer()); nlassert(wgt_Flags & (CVertexBuffer::WeightFlag)); ptr=(uint8*)(&_Parent->_LockedBuffer[idx*_Parent->_VertexSize]); ptr+=_Parent->_Offset[CVertexBuffer::Weight]+sizeof(float)*wgt; ptrf=(float*)ptr; *ptrf=w; } // -------------------------------------------------- inline void CVertexBufferReadWrite::setPaletteSkin(uint idx, CPaletteSkin ps) { uint8* ptr; CPaletteSkin *pPalSkin; nlassert (_Parent->checkLockedBuffer()); nlassert ( (_Parent->_Flags & CVertexBuffer::PaletteSkinFlag) == CVertexBuffer::PaletteSkinFlag); nlassert (_Parent->_Type[CVertexBuffer::PaletteSkin]==CVertexBuffer::UChar4); ptr=(uint8*)(&_Parent->_LockedBuffer[idx*_Parent->_VertexSize]); ptr+=_Parent->_Offset[CVertexBuffer::PaletteSkin]; pPalSkin= (CPaletteSkin*)ptr; *pPalSkin= ps; } // -------------------------------------------------- inline void CVertexBufferReadWrite::setValueFloat1Ex (CVertexBuffer::TValue valueId, uint idx, float value) { uint8* ptr; float* ptrf; nlassert (_Parent->checkLockedBuffer()); nlassert(valueId_Flags & (1<<(uint)valueId)); nlassert((_Parent->_Type[valueId]==CVertexBuffer::Float4)||(_Parent->_Type[valueId]==CVertexBuffer::Float3)||(_Parent->_Type[valueId]==CVertexBuffer::Float2)||(_Parent->_Type[valueId]==CVertexBuffer::Float1)); ptr=(uint8*)(&_Parent->_LockedBuffer[idx*_Parent->_VertexSize]); ptr+=_Parent->_Offset[valueId]; ptrf=(float*)ptr; *ptrf=value; } // -------------------------------------------------- inline void CVertexBufferReadWrite::setValueFloat2Ex (CVertexBuffer::TValue valueId, uint idx, float x, float y) { uint8* ptr; float* ptrf; nlassert (_Parent->checkLockedBuffer()); nlassert(valueId_Flags & (1<<(uint)valueId)); nlassert((_Parent->_Type[valueId]==CVertexBuffer::Float4)||(_Parent->_Type[valueId]==CVertexBuffer::Float3)||(_Parent->_Type[valueId]==CVertexBuffer::Float2)); ptr=(uint8*)(&_Parent->_LockedBuffer[idx*_Parent->_VertexSize]); ptr+=_Parent->_Offset[valueId]; ptrf=(float*)ptr; ptrf[0]=x; ptrf[1]=y; } // -------------------------------------------------- inline void CVertexBufferReadWrite::setValueFloat3Ex (CVertexBuffer::TValue valueId, uint idx, float x, float y, float z) { uint8* ptr; float* ptrf; nlassert (_Parent->checkLockedBuffer()); nlassert(valueId_Flags & (1<<(uint)valueId)); nlassert((_Parent->_Type[valueId]==CVertexBuffer::Float4)||(_Parent->_Type[valueId]==CVertexBuffer::Float3)); ptr=(uint8*)(&_Parent->_LockedBuffer[idx*_Parent->_VertexSize]); ptr+=_Parent->_Offset[valueId]; ptrf=(float*)ptr; ptrf[0]=x; ptrf[1]=y; ptrf[2]=z; } // -------------------------------------------------- inline void CVertexBufferReadWrite::setValueFloat3Ex (CVertexBuffer::TValue valueId, uint idx, const NLMISC::CVector& theVector) { uint8* ptr; float* ptrf; nlassert (_Parent->checkLockedBuffer()); nlassert(valueId_Flags & (1<<(uint)valueId)); nlassert((_Parent->_Type[valueId]==CVertexBuffer::Float4)||(_Parent->_Type[valueId]==CVertexBuffer::Float3)); ptr=(uint8*)(&_Parent->_LockedBuffer[idx*_Parent->_VertexSize]); ptr+=_Parent->_Offset[valueId]; ptrf=(float*)ptr; memcpy (ptrf, &theVector, sizeof(float)*3); } // -------------------------------------------------- inline void CVertexBufferReadWrite::setValueFloat4Ex (CVertexBuffer::TValue valueId, uint idx, float x, float y, float z, float w) { uint8* ptr; float* ptrf; nlassert (_Parent->checkLockedBuffer()); nlassert(valueId_Flags & (1<<(uint)valueId)); nlassert(_Parent->_Type[valueId]==CVertexBuffer::Float4); ptr=(uint8*)(&_Parent->_LockedBuffer[idx*_Parent->_VertexSize]); ptr+=_Parent->_Offset[valueId]; ptrf=(float*)ptr; ptrf[0]=x; ptrf[1]=y; ptrf[2]=z; ptrf[3]=w; } // -------------------------------------------------- inline void CVertexBufferReadWrite::setValueUChar4Ex (CVertexBuffer::TValue valueId, uint idx, CRGBA rgba) { uint8* ptr; CRGBA* ptrr; nlassert (_Parent->checkLockedBuffer()); nlassert(valueId_Flags & (1<<(uint)valueId)); nlassert(_Parent->_Type[valueId]==CVertexBuffer::UChar4); ptr=(uint8*)(&_Parent->_LockedBuffer[idx*_Parent->_VertexSize]); ptr+=_Parent->_Offset[valueId]; ptrr=(CRGBA*)ptr; *ptrr=rgba; } // -------------------------------------------------- inline void CVertexBuffer::lock (CVertexBufferReadWrite &accessor, uint first, uint last) { accessor.unlock(); accessor._Parent = this; accessor._First = 0; accessor._Last = 0; // Already locked ? if (_LockCounter == 0) { nlassert (_LockedBuffer == NULL); // No if (isResident() && !_KeepLocalMemory) { if (last == 0) last = _NbVerts; _LockedBuffer = DrvInfos->lock (first*_VertexSize, last*_VertexSize, false); } else { if (_NonResidentVertices.empty()) _LockedBuffer = NULL; else _LockedBuffer = &(_NonResidentVertices[0]); } } else { nlassert ((first==0)&&(last==0)); } _LockCounter++; } // -------------------------------------------------- inline void CVertexBuffer::lock (CVertexBufferRead &accessor, uint first, uint last) const { accessor.unlock(); accessor._Parent = this; // Already locked ? if (_LockCounter == 0) { nlassert (_LockedBuffer == NULL); // No if (isResident() && !_KeepLocalMemory) { if (last == 0) last = _NbVerts; // Can read it ? nlassertex (_Location==RAMResident, ("Try to read a write only vertex buffer")); _LockedBuffer = DrvInfos->lock (first*_VertexSize, last*_VertexSize, true); } else { if (_NonResidentVertices.empty()) _LockedBuffer = NULL; else _LockedBuffer = const_cast(&(_NonResidentVertices[0])); } } else { nlassert ((first==0)&&(last==0)); } _LockCounter++; } // -------------------------------------------------- inline void CVertexBuffer::unlock (uint /* first */, uint /* end */) { nlassertex (_LockCounter!=0, ("Vertex buffer not locked")); nlassert (_LockedBuffer || (!isResident() && _NonResidentVertices.empty())); if (_LockCounter) _LockCounter--; if (_LockCounter == 0) { if (isResident() && !_KeepLocalMemory) DrvInfos->unlock (0, 0); _LockedBuffer = NULL; } } // -------------------------------------------------- inline void CVertexBuffer::unlock () const { nlassertex (_LockCounter!=0, ("Vertex buffer not locked")); nlassert (_LockedBuffer || (!isResident() && _NonResidentVertices.empty())); if (_LockCounter) _LockCounter--; if (_LockCounter == 0) { if (isResident() && !_KeepLocalMemory) DrvInfos->unlock (0, 0); _LockedBuffer = NULL; } } // -------------------------------------------------- } // NL3D #endif // NL_VERTEX_BUFFER_H /* End of vertex_buffer.h */