/*==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==*/ #include "hsTypes.h" #include "plAccessSnapShot.h" #include "hsGeometry3.h" #include 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; } } }