You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

271 lines
6.6 KiB

/*==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 <http://www.gnu.org/licenses/>.
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==*/
#include "hsTypes.h"
#include "plAccessSnapShot.h"
#include "hsGeometry3.h"
#include <memory.h>
void plAccessSnapShot::Clear()
{
ClearVerts();
int i;
for( i = 0; i < kNumValidChans; i++ )
fChanSize[i] = 0;
}
void plAccessSnapShot::Destroy()
{
Clear();
delete [] fData;
fRefCnt = 0;
}
void plAccessSnapShot::Release()
{
hsAssert(fRefCnt, "Releasing a snapshot with no refs. Check matching TakeSnapShot/ReleaseSnapShot calls.");
if( !--fRefCnt )
{
Destroy();
}
}
UInt32 plAccessSnapShot::ICheckAlloc(const plAccessVtxSpan& src, UInt32 chanMask, UInt32 chan, UInt16 chanSize)
{
if( ((1 << chan) & chanMask) && src.fStrides[chan] )
{
if( fChanSize[chan] )
{
// We already have this one
chanMask &= ~(1 << chan);
}
else
{
// We'll get this one
fChanSize[chan] = chanSize;
}
}
else
{
// either we haven't been asked for this or src doesn't have it.
// either way, we're never going to get it.
chanMask &= ~(1 << chan);
}
return chanMask;
}
void plAccessSnapShot::IRecordSizes(UInt16 sizes[]) const
{
int chan;
for( chan = 0; chan < kNumValidChans; chan++ )
sizes[chan] = fChanSize[chan];
}
UInt16 plAccessSnapShot::IComputeStride() const
{
UInt16 stride = 0;
int chan;
for( chan = 0; chan < kNumValidChans; chan++ )
stride += fChanSize[chan];
return stride;
}
void plAccessSnapShot::ICopyOldData(UInt8* data, const UInt16* const oldSizes, UInt16 oldStride, UInt16 newStride)
{
UInt32 oldOffset = 0;
UInt32 newOffset = 0;
UInt8* srcChannels[kNumValidChans];
UInt8* dstChannels[kNumValidChans];
int chan;
for( chan = 0; chan < kNumValidChans; chan++ )
{
if( oldSizes[chan] )
{
hsAssert(fChanSize[chan], "Copying a channel we don't have");
srcChannels[chan] = data + oldOffset;
oldOffset += oldSizes[chan];
}
if( fChanSize[chan] )
{
dstChannels[chan] = fData + newOffset;
newOffset += fChanSize[chan];
}
}
int i;
for( i = 0; i < fNumVerts; i++ )
{
for( chan = 0; chan < kNumValidChans; chan++ )
{
if( oldSizes[chan] )
{
memcpy(dstChannels[chan], srcChannels[chan], oldSizes[chan]);
dstChannels[chan] += newStride;
srcChannels[chan] += oldStride;
}
}
}
}
void plAccessSnapShot::ISetupPointers(UInt16 newStride)
{
fData = TRACKED_NEW UInt8[fNumVerts * newStride];
int size = 0;
int chan;
for( chan = 0; chan < kNumValidChans; chan++ )
{
if( fChanSize[chan] )
{
fStrides[chan] = newStride;
fChannels[chan] = fData + size;
size += fChanSize[chan];
}
}
}
UInt32 plAccessSnapShot::CopyFrom(const plAccessVtxSpan& src, UInt32 chanMask)
{
hsAssert(!fNumVerts || (fNumVerts == src.fNumVerts), "Copying from a different sized span");
fNumVerts = src.fNumVerts;
UInt16 oldSize[kNumValidChans];
UInt8* oldData = fData;
IRecordSizes(oldSize);
UInt16 oldStride = IComputeStride();
// First, allocate any storage we need. Kill any requested channels out of the
// mask that we already have.
chanMask = ICheckAlloc(src, chanMask, kPosition, sizeof(hsPoint3));
chanMask = ICheckAlloc(src, chanMask, kWeight, sizeof(hsScalar) * src.fNumWeights);
if( fChanSize[kWeight] )
fNumWeights = src.fNumWeights;
chanMask = ICheckAlloc(src, chanMask, kWgtIndex, sizeof(UInt32));
chanMask = ICheckAlloc(src, chanMask, kNormal, sizeof(hsVector3));
chanMask = ICheckAlloc(src, chanMask, kDiffuse, sizeof(UInt32));
chanMask = ICheckAlloc(src, chanMask, kSpecular, sizeof(UInt32));
chanMask = ICheckAlloc(src, chanMask, kUVW, sizeof(hsPoint3) * src.fNumUVWsPerVert);
if( fChanSize[kUVW] )
fNumUVWsPerVert = src.fNumUVWsPerVert;
// If our chanMask has gone to zero, we've only been asked to record
// channels we already have, so there's nothing to do.
if( !chanMask )
return 0;
UInt16 newStride = IComputeStride();
ISetupPointers(newStride);
ICopyOldData(oldData, oldSize, oldStride, newStride);
UInt8* srcChannels[kNumValidChans];
UInt8* dstChannels[kNumValidChans];
int chan;
for( chan = 0; chan < kNumValidChans; chan++ )
{
srcChannels[chan] = src.fChannels[chan];
dstChannels[chan] = fChannels[chan];
}
int i;
for( i = 0; i < src.VertCount(); i++ )
{
for( chan = 0; chan < kNumValidChans; chan++ )
{
if( (1<< chan) & chanMask )
{
memcpy(dstChannels[chan], srcChannels[chan], fChanSize[chan]);
dstChannels[chan] += fStrides[chan];
srcChannels[chan] += src.fStrides[chan];
}
}
}
return chanMask;
}
UInt32 plAccessSnapShot::CopyTo(const plAccessVtxSpan& dst, UInt32 chanMask)
{
hsAssert(fNumVerts == dst.fNumVerts, "Vertex count mismatch, is this our real source?");
int chan;
for( chan = 0; chan < kNumValidChans; chan++ )
{
if( !(fChanSize[chan] && dst.fStrides[chan]) )
chanMask &= ~(1 << chan);
}
// If chanMask has gone to zero, either we don't have any of the requested channels
// recorded, or dst doesn't have them. Both being true is valid, but
// us having a channel recorded that's not in dst is probably an error.
if( !chanMask )
return 0;
int i;
for( i = 0; i < fNumVerts; i++ )
{
for( chan = 0; chan < kNumValidChans; chan++ )
{
if( (1 << chan) & chanMask )
{
memcpy(
dst.fChannels[chan] + dst.fStrides[chan] * i,
fChannels[chan] + fStrides[chan] * i,
fChanSize[chan]);
}
}
}
return chanMask;
}
void plAccessSnapShot::SetupChannels(plAccessVtxSpan& dst) const
{
int chan;
for( chan = 0; chan < kNumValidChans; chan++ )
{
if( fChanSize[chan] )
{
dst.fChannels[chan] = fChannels[chan];
dst.fStrides[chan] = fStrides[chan];
dst.fOffsets[chan] = 0;
}
}
}