// 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 */