/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#ifndef plAccessVtxSpan_inc
#define plAccessVtxSpan_inc
#include "hsGeometry3.h"
#include "hsColorRGBA.h"
class hsGMaterial;
struct hsMatrix44;
class hsGDeviceRef;
// AccessSpan - a generic "vertex array". It'll at least act like one,
// whatever the underlying storage mechanism. For random access, just
// use the accessor functions. For faster sequential iteration, use
// the iterator classes defined further down. I'm leaving the actual
// data (fChannels & fStrides) public, but I'll probably regret it.
// I have to dig pretty deep to come up with a reason not to use
// either the indexed accessors or the iterator classes.
//
// You may be wondering why have separate strides for each of the data channels,
// especially since this means doing nChan pointer adds to advance rather than
// one. The answer is two part. First, the different channels may be in different
// buffers, either because we're on the export side and haven't glommed them together
// into a single stream yet, or because we finally got around to using multiple
// streams on the runtime side (say to support instancing). The point is for you
// to be able to write your code without knowing or caring. The second part is that
// those nChan adds aren't really costing you anything. Say the data is stored contiguously,
// and we keep a base pointer and an advance just adds the (single) stride to the base
// pointer. That's probably your position, and we've just saved a bunch of adds in advancing
// it. Now you want to access your normal, well, you still have to do an add on the base pointer
// to get to your normal, and another to get to your color, etc. So if you really want to
// eliminate those extra adds, go ahead and use the iterator, just make sure you use
// the most focused iterator available. Like if you're just looking at position and
// normal, use the plAccPosNormIterator.
class plAccessVtxSpan
{
public:
enum Channel
{
kPosition = 0,
kWeight,
kWgtIndex,
kNormal,
kDiffuse,
kSpecular,
kUVW,
kNumValidChans,
kInvalid = 0xffff
};
// Mask versions, to be or'ed together and passed in when using plAccessGeometry::SnapShotStuff.
enum
{
kPositionMask = (1 << kPosition),
kWeightMask = (1 << kWeight),
kWgtIndexMask = (1 << kWgtIndex),
kNormalMask = (1 << kNormal),
kDiffuseMask = (1 << kDiffuse),
kSpecularMask = (1 << kSpecular),
kUVWMask = (1 << kUVW)
};
hsGDeviceRef* fVtxDeviceRef;
UInt8* fChannels[kNumValidChans];
UInt16 fStrides[kNumValidChans];
Int32 fOffsets[kNumValidChans];
UInt16 fNumWeights;
UInt16 fNumUVWsPerVert;
UInt16 fNumVerts;
//////////////////////////////////
// QUERY SECTION
// Queries on how much of what we got.
UInt32 VertCount() const { return fNumVerts; }
hsBool HasChannel(Channel chan) const { return fStrides[chan] > 0; }
hsBool HasPositions() const { return HasChannel(kPosition); }
hsBool HasWeights() const { return HasChannel(kWeight); }
int NumWeights() const { return fNumWeights; }
hsBool HasWgtIndex() const { return HasChannel(kWgtIndex); }
hsBool HasNormals() const { return HasChannel(kNormal); }
hsBool HasDiffuse() const { return HasChannel(kDiffuse); }
hsBool HasSpecular() const { return HasChannel(kSpecular); }
hsBool HasUVWs() const { return HasChannel(kUVW); }
hsBool HasUVWs(int n) { return HasChannel(kUVW) && (n <= fNumUVWsPerVert); }
int NumUVWs() const { return fNumUVWsPerVert; }
//////////////////////////////////
// ACCESSOR SECTION
hsPoint3& Position(int i) const { return *(hsPoint3*)(fChannels[kPosition] + i*fStrides[kPosition]); }
hsVector3& Normal(int i) const { return *(hsVector3*)(fChannels[kNormal] + i*fStrides[kNormal]); }
hsScalar& Weight(int iVtx, int iWgt) const { return *(hsScalar*)(fChannels[kWeight] + iVtx*fStrides[kWeight] + iWgt*sizeof(hsScalar)); }
hsScalar* Weights(int i) const { return (hsScalar*)(fChannels[kWeight] + i*fStrides[kWeight]); }
UInt32& WgtIndices(int i) const { return *(UInt32*)(fChannels[kWgtIndex] + i * fStrides[kWgtIndex]); }
UInt8& WgtIndex(int iVtx, int iWgt) const { return *(fChannels[kWgtIndex] + iVtx*fStrides[kWgtIndex] + iWgt); }
UInt32& Diffuse32(int i) const { return *(UInt32*)(fChannels[kDiffuse] + i*fStrides[kDiffuse]); }
UInt32& Specular32(int i) const { return *(UInt32*)(fChannels[kSpecular] + i*fStrides[kSpecular]); }
hsColorRGBA DiffuseRGBA(int i) const { return hsColorRGBA().FromARGB32(Diffuse32(i)); }
hsColorRGBA SpecularRGBA(int i) const { return hsColorRGBA().FromARGB32(Specular32(i)); }
// Two versions of UVW, first to get the iVtx'th vertex's iUVW'th uvw.
// Second just gets the vertex's uvw array, which is hopefully stored contiguously or we're screwed.
hsPoint3& UVW(int iVtx, int iUVW) const { return *(hsPoint3*)(fChannels[kUVW] + iVtx*fStrides[kUVW] + iUVW*sizeof(hsPoint3)); }
hsPoint3* UVWs(int i) const { return (hsPoint3*)(fChannels[kUVW] + i*fStrides[kUVW]); }
// OFFSET VERSIONS
// Tri and particle accessors call the offset versions because they have indices into the original
// buffers, but our pointers are based at the beginning of our data.
hsPoint3& PositionOff(int i) const { return *(hsPoint3*)(fChannels[kPosition] + i*fStrides[kPosition] + fOffsets[kPosition]); }
hsVector3& NormalOff(int i) const { return *(hsVector3*)(fChannels[kNormal] + i*fStrides[kNormal] + fOffsets[kNormal]); }
hsScalar& WeightOff(int iVtx, int iWgt) const { return *(hsScalar*)(fChannels[kWeight] + iVtx*fStrides[kWeight] + fOffsets[kWeight] + iWgt*sizeof(hsScalar)); }
hsScalar* WeightsOff(int i) const { return (hsScalar*)(fChannels[kWeight] + i*fStrides[kWeight] + fOffsets[kWeight]); }
UInt32& WgtIndicesOff(int i) const { return *(UInt32*)(fChannels[kWgtIndex] + i * fStrides[kWgtIndex] + fOffsets[kWgtIndex]); }
UInt8& WgtIndexOff(int iVtx, int iWgt) const { return *(fChannels[kWgtIndex] + iVtx*fStrides[kWgtIndex] + fOffsets[kWgtIndex] + iWgt); }
UInt32& Diffuse32Off(int i) const { return *(UInt32*)(fChannels[kDiffuse] + i*fStrides[kDiffuse] + fOffsets[kDiffuse]); }
UInt32& Specular32Off(int i) const { return *(UInt32*)(fChannels[kSpecular] + i*fStrides[kSpecular] + fOffsets[kSpecular]); }
hsColorRGBA DiffuseRGBAOff(int i) const { return hsColorRGBA().FromARGB32(Diffuse32Off(i)); }
hsColorRGBA SpecularRGBAOff(int i) const { return hsColorRGBA().FromARGB32(Specular32Off(i)); }
// Two versions of UVW, first to get the iVtx'th vertex's iUVW'th uvw.
// Second just gets the vertex's uvw array, which is hopefully stored contiguously or we're screwed.
hsPoint3& UVWOff(int iVtx, int iUVW) const { return *(hsPoint3*)(fChannels[kUVW] + iVtx*fStrides[kUVW] + fOffsets[kUVW] + iUVW*sizeof(hsPoint3)); }
hsPoint3* UVWsOff(int i) const { return (hsPoint3*)(fChannels[kUVW] + i*fStrides[kUVW] + fOffsets[kUVW]); }
//////////////////////////////////
// SETUP SECTION.
//////////////////////////////////
//////////////////////////////////
// Call Clear to initialize.
void ClearVerts();
// Must at least set a count and the valid channels. Note below on setting up for UVW access.
plAccessVtxSpan& SetVertCount(UInt16 c) { fNumVerts = c; return *this; }
plAccessVtxSpan& SetStream(void* p, UInt16 stride, Int32 offset, Channel chan) { fChannels[chan] = (UInt8*)p; fStrides[chan] = stride; fOffsets[chan] = offset; return *this; }
//////////////////////////////////
// Convenience versions. You get the idea.
plAccessVtxSpan& PositionStream(void* p, UInt16 stride, Int32 offset) { return SetStream(p, stride, offset, kPosition); }
plAccessVtxSpan& NormalStream(void* p, UInt16 stride, Int32 offset) { return SetStream(p, stride, offset, kNormal); }
plAccessVtxSpan& DiffuseStream(void* p, UInt16 stride, Int32 offset) { return SetStream(p, stride, offset, kDiffuse); }
plAccessVtxSpan& SpecularStream(void* p, UInt16 stride, Int32 offset) { return SetStream(p, stride, offset, kSpecular); }
plAccessVtxSpan& WeightStream(void* p, UInt16 stride, Int32 offset) { return SetStream(p, stride, offset, kWeight); }
plAccessVtxSpan& WgtIndexStream(void* p, UInt16 stride, Int32 offset) { return SetStream(p, stride, offset, kWgtIndex); }
plAccessVtxSpan& SetNumWeights(int n) { if( !(fNumWeights = n) ) SetStream(nil, 0, 0, kWeight).SetStream(nil, 0, 0, kWgtIndex); return *this; }
// Note on UVW access setup, you don't actually "have" to set the number of uvws per vertex,
// but one way or another you'll need to know to access the uvws. If you're going to be setting
// up the AccessSpan and passing it off for processing, you definitely better set it. But the
// accessor and iterators don't ever use it.
// Note that this means the UVWStream stride is from uvw[0][0] to uvw[1][0] in bytes.
plAccessVtxSpan& UVWStream(void* p, UInt16 stride, Int32 offset) { return SetStream(p, stride, offset, kUVW); }
plAccessVtxSpan& SetNumUVWs(int n) { if( !(fNumUVWsPerVert = n) )SetStream(nil, 0, 0, kUVW); return *this; }
//////////////////////////////////
// Cache away any device stuff that needed to be opened (locked) to get this data, so
// we can close (unlock) it later.
void SetVtxDeviceRef(hsGDeviceRef* ref) { fVtxDeviceRef = ref; }
hsGDeviceRef* GetVtxDeviceRef() const { return fVtxDeviceRef; }
};
inline void plAccessVtxSpan::ClearVerts()
{
int i;
for( i = 0; i < kNumValidChans; i++ )
{
fChannels[i] = nil;
fStrides[i] = 0;
}
fNumVerts = 0;
fNumUVWsPerVert = 0;
fNumWeights = 0;
}
template class plAccIterator
{
private:
union
{
T* fValue;
UInt8* fValueByte;
};
UInt8* fValueEnd;
plAccessVtxSpan* fAccess;
plAccessVtxSpan::Channel fChan;
void ISetEnd() { fValueEnd = fAccess->fChannels[fChan] + fAccess->fNumVerts * fAccess->fStrides[fChan]; }
public:
plAccIterator(plAccessVtxSpan* acc, plAccessVtxSpan::Channel chan) { Set(acc, chan); }
plAccIterator(const plAccIterator& accIt) { *this = accIt; }
plAccIterator() : fValueByte(nil), fValueEnd(nil), fAccess(nil), fChan(plAccessVtxSpan::kInvalid) {}
void Set(plAccessVtxSpan* acc, plAccessVtxSpan::Channel chan) { fAccess = acc; fChan = chan; ISetEnd(); }
T* Value() const { return fValue; }
int Count() const { return fAccess->VertCount(); }
int GetCount() const { return Count(); }
void Begin() { fValueByte = fAccess->fChannels[fChan]; }
void Advance() { fValueByte += fAccess->fStrides[fChan]; }
hsBool More() const { return fValueByte < fValueEnd; }
};
class plAccPositionIterator
{
protected:
plAccIterator fPosition;
public:
plAccPositionIterator(plAccessVtxSpan* acc)
: fPosition(acc, plAccessVtxSpan::kPosition) {}
plAccPositionIterator() {}
plAccPositionIterator& Set(plAccessVtxSpan* acc)
{
fPosition.Set(acc, plAccessVtxSpan::kPosition);
return *this;
}
hsPoint3* Position() const { return fPosition.Value(); }
void Begin() { fPosition.Begin(); }
void Advance() { fPosition.Advance(); }
hsBool More() const { return fPosition.More(); }
};
class plAccPosNormIterator
{
protected:
plAccIterator fPosition;
plAccIterator fNormal;
public:
plAccPosNormIterator(plAccessVtxSpan* acc)
: fPosition(acc, plAccessVtxSpan::kPosition),
fNormal(acc, plAccessVtxSpan::kNormal) {}
plAccPosNormIterator() {}
plAccPosNormIterator& Set(plAccessVtxSpan* acc)
{
fPosition.Set(acc, plAccessVtxSpan::kPosition);
fNormal.Set(acc, plAccessVtxSpan::kNormal);
return *this;
}
hsPoint3* Position() const { return fPosition.Value(); }
hsVector3* Normal() const { return fNormal.Value(); }
void Begin() { fPosition.Begin(); fNormal.Begin(); }
void Advance() { fPosition.Advance(); fNormal.Advance(); }
hsBool More() const { return fPosition.More(); }
};
class plAccPosNormUVWIterator
{
protected:
plAccIterator fPosition;
plAccIterator fNormal;
plAccIterator fUVW;
public:
plAccPosNormUVWIterator(plAccessVtxSpan* acc)
: fPosition(acc, plAccessVtxSpan::kPosition),
fNormal(acc, plAccessVtxSpan::kNormal),
fUVW(acc, plAccessVtxSpan::kUVW) {}
plAccPosNormUVWIterator() {}
plAccPosNormUVWIterator& Set(plAccessVtxSpan* acc)
{
fPosition.Set(acc, plAccessVtxSpan::kPosition);
fNormal.Set(acc, plAccessVtxSpan::kNormal);
fUVW.Set(acc, plAccessVtxSpan::kUVW);
return *this;
}
hsPoint3* Position() const { return fPosition.Value(); }
hsVector3* Normal() const { return fNormal.Value(); }
hsPoint3* UVWs() const { return fUVW.Value(); }
hsPoint3* UVW(int i) const { return fUVW.Value() + i; }
void Begin() { fPosition.Begin(); fNormal.Begin(); fUVW.Begin(); }
void Advance() { fPosition.Advance(); fNormal.Advance(); fUVW.Advance(); }
hsBool More() const { return fPosition.More(); }
};
class plAccUVWIterator
{
plAccIterator fUVW;
public:
plAccUVWIterator(plAccessVtxSpan* acc)
: fUVW(acc, plAccessVtxSpan::kUVW) {}
plAccUVWIterator() {}
plAccUVWIterator& Set(plAccessVtxSpan* acc)
{
fUVW.Set(acc, plAccessVtxSpan::kUVW);
return *this;
}
hsPoint3* UVWs() const { return fUVW.Value(); }
hsPoint3* UVW(int i) const { return fUVW.Value() + i; }
void Begin() { fUVW.Begin(); }
void Advance() { fUVW.Advance(); }
hsBool More() const { return fUVW.More(); }
};
class plAccDiffuseIterator
{
plAccIterator fDiffuse;
public:
plAccDiffuseIterator(plAccessVtxSpan* acc)
: fDiffuse(acc, plAccessVtxSpan::kDiffuse) {}
plAccDiffuseIterator() {}
plAccDiffuseIterator& Set(plAccessVtxSpan* acc)
{
fDiffuse.Set(acc, plAccessVtxSpan::kDiffuse);
return *this;
}
UInt32* Diffuse32() const { return fDiffuse.Value(); }
hsColorRGBA DiffuseRGBA() const { return hsColorRGBA().FromARGB32(*Diffuse32()); }
void Begin() { fDiffuse.Begin(); }
void Advance() { fDiffuse.Advance(); }
hsBool More() const { return fDiffuse.More(); }
};
class plAccDiffSpecIterator
{
protected:
plAccIterator fDiffuse;
plAccIterator fSpecular;
public:
plAccDiffSpecIterator(plAccessVtxSpan* acc)
: fDiffuse(acc, plAccessVtxSpan::kDiffuse),
fSpecular(acc, plAccessVtxSpan::kSpecular) {}
plAccDiffSpecIterator() {}
plAccDiffSpecIterator& Set(plAccessVtxSpan* acc)
{
fDiffuse.Set(acc, plAccessVtxSpan::kDiffuse);
fSpecular.Set(acc, plAccessVtxSpan::kSpecular);
return *this;
}
UInt32* Diffuse32() const { return fDiffuse.Value(); }
UInt32* Specular32() const { return fSpecular.Value(); }
hsColorRGBA DiffuseRGBA() const { return hsColorRGBA().FromARGB32(*Diffuse32()); }
hsColorRGBA SpecularRGBA() const { return hsColorRGBA().FromARGB32(*Specular32()); }
void Begin() { fDiffuse.Begin(); fSpecular.Begin(); }
void Advance() { fDiffuse.Advance(); fSpecular.Advance(); }
hsBool More() const { return fDiffuse.More(); }
};
class plAccVertexIterator
{
protected:
plAccIterator fPosition;
plAccIterator fWeight;
plAccIterator fWgtIndex;
plAccIterator fNormal;
plAccIterator fDiffuse;
plAccIterator fSpecular;
plAccIterator fUVW;
public:
plAccVertexIterator(plAccessVtxSpan* acc)
: fPosition(acc, plAccessVtxSpan::kPosition),
fWeight(acc, plAccessVtxSpan::kWeight),
fWgtIndex(acc, plAccessVtxSpan::kWgtIndex),
fNormal(acc, plAccessVtxSpan::kNormal),
fDiffuse(acc, plAccessVtxSpan::kDiffuse),
fSpecular(acc, plAccessVtxSpan::kSpecular),
fUVW(acc, plAccessVtxSpan::kUVW) {}
plAccVertexIterator() {}
plAccVertexIterator& Set(plAccessVtxSpan* acc)
{
fPosition.Set(acc, plAccessVtxSpan::kPosition);
fWeight.Set(acc, plAccessVtxSpan::kWeight);
fWgtIndex.Set(acc, plAccessVtxSpan::kWgtIndex);
fNormal.Set(acc, plAccessVtxSpan::kNormal);
fDiffuse.Set(acc, plAccessVtxSpan::kDiffuse);
fSpecular.Set(acc, plAccessVtxSpan::kSpecular);
fUVW.Set(acc, plAccessVtxSpan::kUVW);
return *this;
}
hsPoint3* Position() const { return fPosition.Value(); }
hsScalar* Weights() const { return fWeight.Value(); }
hsScalar* Weight(int i) const { return fWeight.Value() + i; }
UInt32* WgtIndices() const { return (UInt32*)(fWgtIndex.Value()); }
UInt8* WgtIndex(int i) const { return fWgtIndex.Value() + i; }
hsVector3* Normal() const { return fNormal.Value(); }
hsPoint3* UVWs() const { return fUVW.Value(); }
hsPoint3* UVW(int i) const { return fUVW.Value() + i; }
UInt32* Diffuse32() const { return fDiffuse.Value(); }
UInt32* Specular32() const { return fSpecular.Value(); }
hsColorRGBA DiffuseRGBA() const { return hsColorRGBA().FromARGB32(*Diffuse32()); }
hsColorRGBA SpecularRGBA() const { return hsColorRGBA().FromARGB32(*Specular32()); }
void Begin() { fPosition.Begin(); fWeight.Begin(); fNormal.Begin(); fDiffuse.Begin(); fSpecular.Begin(); fUVW.Begin(); }
void Advance() { fPosition.Advance(); fWeight.Advance(); fNormal.Advance(); fDiffuse.Begin(); fSpecular.Begin(); fUVW.Advance(); }
hsBool More() const { return fPosition.More(); }
};
#endif // plAccessVtxSpan_inc