1418 lines
34 KiB
C++
1418 lines
34 KiB
C++
// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
|
|
// Copyright (C) 2010 Winch Gate Property Limited
|
|
//
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU Affero General Public License as
|
|
// published by the Free Software Foundation, either version 3 of the
|
|
// License, or (at your option) any later version.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU Affero General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU Affero General Public License
|
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
#include "std3d.h"
|
|
|
|
#include "nel/3d/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);
|
|
}
|
|
|
|
// --------------------------------------------------
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|