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.

584 lines
16 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 "plAccessGeometry.h"
#include "../pnSceneObject/plDrawInterface.h"
#include "plDrawableSpans.h"
#include "plGeometrySpan.h"
#include "plAccessSpan.h"
#include "plAccessPartySpan.h"
#include "plAccessTriSpan.h"
#include "plAccessVtxSpan.h"
#include "plAccessSnapShot.h"
// For dipping directly into device buffers.
#include "../plPipeline/plGBufferGroup.h"
#include "../plPipeline/hsGDeviceRef.h"
#include "plPipeline.h"
#include "plTweak.h"
//////////////////////////////////////////////////////////////////////////////////
// Dropping these here, because they have no place else to go except a header.
void plAccessSpan::SetSource(plSpan* s)
{
fLocalToWorld = &s->fLocalToWorld;
fWorldToLocal = &s->fWorldToLocal;
fLocalBounds = &s->fLocalBounds;
fWorldBounds = &s->fWorldBounds;
fWaterHeight = s->fProps & plSpan::kWaterHeight ? &s->fWaterHeight : nil;
}
void plAccessSpan::SetSource(plGeometrySpan* s)
{
fLocalToWorld = &s->fLocalToWorld;
fWorldToLocal = &s->fWorldToLocal;
fLocalBounds = &s->fLocalBounds;
fWorldBounds = &s->fWorldBounds;
fWaterHeight = s->fProps & plGeometrySpan::kWaterHeight ? &s->fWaterHeight : nil;
}
//////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////
// Simple constructor
plAccessGeometry::plAccessGeometry(plPipeline* pipe)
: fPipe(pipe)
{
}
//////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////
// Global access stuff.
plAccessGeometry* plAccessGeometry::fInstance = nil;
void plAccessGeometry::Init(plPipeline* pipe)
{
plAccessGeometry* oldAcc = fInstance;
fInstance = NEW(plAccessGeometry)(pipe);
hsRefCnt_SafeUnRef(oldAcc);
}
void plAccessGeometry::DeInit()
{
if( fInstance )
fInstance->Nilify();
hsRefCnt_SafeUnRef(fInstance);
}
void plAccessGeometry::SetTheIntance(plAccessGeometry* i)
{
hsRefCnt_SafeAssign(fInstance, i);
}
//////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////
// The first couple of these just interpret between the SceneObjects we like to
// think about and the clumps of geometry that comprise each one.
void plAccessGeometry::OpenRO(const plDrawInterface* di, hsTArray<plAccessSpan>& accs, hsBool useSnap) const
{
int numGot = 0;
accs.SetCount(di->GetNumDrawables());
accs.SetCount(0);
int j;
for( j = 0; j < di->GetNumDrawables(); j++ )
{
plDrawableSpans* dr = plDrawableSpans::ConvertNoRef(di->GetDrawable(j));
// Nil dr - it hasn't loaded yet or something.
if( dr )
{
plDISpanIndex& diIndex = dr->GetDISpans(di->GetDrawableMeshIndex(j));
if( !diIndex.IsMatrixOnly() )
{
int k;
for( k = 0; k < diIndex.GetCount(); k++ )
{
accs.Expand(numGot+1);
accs.SetCount(numGot+1);
OpenRO(dr, diIndex[k], accs[numGot++]);
}
}
}
}
}
void plAccessGeometry::OpenRW(const plDrawInterface* di, hsTArray<plAccessSpan>& accs, hsBool idxToo) const
{
int numGot = 0;
accs.Expand(di->GetNumDrawables());
accs.SetCount(0);
int j;
for( j = 0; j < di->GetNumDrawables(); j++ )
{
plDrawableSpans* dr = plDrawableSpans::ConvertNoRef(di->GetDrawable(j));
// Nil dr - it hasn't loaded yet or something.
if( dr )
{
plDISpanIndex& diIndex = dr->GetDISpans(di->GetDrawableMeshIndex(j));
if( !diIndex.IsMatrixOnly() )
{
int k;
for( k = 0; k < diIndex.GetCount(); k++ )
{
accs.Expand(numGot+1);
accs.SetCount(numGot+1);
OpenRW(dr, diIndex[k], accs[numGot++], idxToo);
}
}
}
}
}
void plAccessGeometry::Close(hsTArray<plAccessSpan>& accs) const
{
int i;
for( i = 0; i < accs.GetCount(); i++ )
Close(accs[i]);
}
void plAccessGeometry::TakeSnapShot(const plDrawInterface* di, UInt32 channels) const
{
int j;
for( j = 0; j < di->GetNumDrawables(); j++ )
{
plDrawableSpans* dr = plDrawableSpans::ConvertNoRef(di->GetDrawable(j));
// Nil dr - it hasn't loaded yet or something.
if( dr )
{
plDISpanIndex& diIndex = dr->GetDISpans(di->GetDrawableMeshIndex(j));
if( !diIndex.IsMatrixOnly() )
{
int k;
for( k = 0; k < diIndex.GetCount(); k++ )
{
TakeSnapShot(dr, diIndex[k], channels);
}
}
}
}
}
void plAccessGeometry::RestoreSnapShot(const plDrawInterface* di, UInt32 channels) const
{
int j;
for( j = 0; j < di->GetNumDrawables(); j++ )
{
plDrawableSpans* dr = plDrawableSpans::ConvertNoRef(di->GetDrawable(j));
// Nil dr - it hasn't loaded yet or something.
if( dr )
{
plDISpanIndex& diIndex = dr->GetDISpans(di->GetDrawableMeshIndex(j));
if( !diIndex.IsMatrixOnly() )
{
int k;
for( k = 0; k < diIndex.GetCount(); k++ )
{
RestoreSnapShot(dr, diIndex[k], channels);
}
}
}
}
}
void plAccessGeometry::ReleaseSnapShot(const plDrawInterface* di) const
{
int j;
for( j = 0; j < di->GetNumDrawables(); j++ )
{
plDrawableSpans* dr = plDrawableSpans::ConvertNoRef(di->GetDrawable(j));
// Nil dr - it hasn't loaded yet or something.
if( dr )
{
plDISpanIndex& diIndex = dr->GetDISpans(di->GetDrawableMeshIndex(j));
if( !diIndex.IsMatrixOnly() )
{
int k;
for( k = 0; k < diIndex.GetCount(); k++ )
{
ReleaseSnapShot(dr, diIndex[k]);
}
}
}
}
}
//////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////
void plAccessGeometry::Close(plAccessSpan& acc) const
{
if( !fPipe )
return;
fPipe->CloseAccess(acc);
}
void plAccessGeometry::IOpen(plDrawable* d, UInt32 spanIdx, plAccessSpan& acc, hsBool useSnap, hsBool readOnly, hsBool idxToo) const
{
acc.SetType(plAccessSpan::kUndefined);
plDrawableSpans* drawable = plDrawableSpans::ConvertNoRef(d);
if( !drawable )
return;
if( drawable->GetSourceSpans().GetCount() && !drawable->GetNumSpans() )
IAccessSpanFromSourceSpan(acc, drawable->GetSourceSpans()[spanIdx]);
else
IAccessSpanFromSpan(acc, drawable, drawable->GetSpan(spanIdx), useSnap, readOnly);
if( !readOnly )
{
// Need to mark the drawable's data as dirty.
plDrawableSpans* ds = plDrawableSpans::ConvertNoRef(drawable);
if( !ds )
return;
if( acc.HasAccessVtx() )
{
plVertexSpan* vtx = (plVertexSpan*)ds->GetSpan(spanIdx);
ds->DirtyVertexBuffer(vtx->fGroupIdx, vtx->fVBufferIdx);
}
if( idxToo && acc.HasAccessTri() )
{
plIcicle* ice = (plIcicle*)ds->GetSpan(spanIdx);
ds->DirtyIndexBuffer(ice->fGroupIdx, ice->fIBufferIdx);
}
}
}
void plAccessGeometry::OpenRO(plDrawable* d, UInt32 spanIdx, plAccessSpan& acc, hsBool useSnap) const
{
IOpen(d, spanIdx, acc, useSnap, true);
}
void plAccessGeometry::OpenRW(plDrawable* drawable, UInt32 spanIdx, plAccessSpan& acc, hsBool idxToo) const
{
IOpen(drawable, spanIdx, acc, false, false, idxToo);
}
//////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////
void plAccessGeometry::TakeSnapShot(plDrawable* drawable, UInt32 spanIdx, UInt32 channels) const
{
plDrawableSpans* ds = plDrawableSpans::ConvertNoRef(drawable);
if( !ds )
return;
const plSpan* span = ds->GetSpan(spanIdx);
if( !span->fSnapShot )
span->fSnapShot = NEW(plAccessSnapShot);
plAccessSpan tmp;
OpenRO(drawable, spanIdx, tmp, false);
if( tmp.HasAccessVtx() )
{
span->fSnapShot->IncRef();
span->fSnapShot->CopyFrom(tmp.AccessVtx(), channels);
}
}
void plAccessGeometry::RestoreSnapShot(plDrawable* drawable, UInt32 spanIdx, UInt32 channels) const
{
plDrawableSpans* ds = plDrawableSpans::ConvertNoRef(drawable);
if( !ds )
return;
const plSpan* span = ds->GetSpan(spanIdx);
if( !span->fSnapShot )
return;
plAccessSpan tmp;
OpenRW(drawable, spanIdx, tmp);
if( tmp.HasAccessVtx() )
span->fSnapShot->CopyTo(tmp.AccessVtx(), channels);
}
void plAccessGeometry::ReleaseSnapShot(plDrawable* drawable, UInt32 spanIdx) const
{
plDrawableSpans* ds = plDrawableSpans::ConvertNoRef(drawable);
if( !ds )
return;
const plSpan* span = ds->GetSpan(spanIdx);
if( !span->fSnapShot )
return;
span->fSnapShot->Release();
}
//////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////
void plAccessGeometry::IAccessSpanFromSourceSpan(plAccessSpan& dst, const plGeometrySpan* src) const
{
// Get the connectivity info
dst.SetType(plAccessSpan::kTri);
plAccessTriSpan& tri = dst.AccessTri();
tri.fNumTris = src->fNumIndices / 3;
tri.fTris = src->fIndexData;
tri.fIdxDeviceRef = nil;
dst.SetSource(const_cast<plGeometrySpan*>(src));
dst.SetMaterial(src->fMaterial);
plAccessVtxSpan& acc = dst.AccessVtx();
acc.fNumVerts = (UInt16)(src->fNumVerts);
UInt32 sz = src->GetVertexSize(src->fFormat);
UInt8* ptr = src->fVertexData;
acc.PositionStream(ptr, (UInt16)sz, 0);
ptr += sizeof(hsPoint3);
acc.NormalStream(ptr, (UInt16)sz, 0);
ptr += sizeof(hsVector3);
acc.DiffuseStream(src->fDiffuseRGBA, sizeof(UInt32), 0);
acc.SpecularStream(src->fSpecularRGBA, sizeof(UInt32), 0);
acc.UVWStream(ptr, (UInt16)sz, 0);
acc.SetNumUVWs(src->CalcNumUVs(src->fFormat));
acc.fVtxDeviceRef = nil;
}
void plAccessGeometry::IAccessSpanFromSpan(plAccessSpan& dst, plDrawableSpans* drawable, const plSpan* span, hsBool useSnap, hsBool readOnly) const
{
dst.SetType(plAccessSpan::kUndefined);
dst.SetSource(const_cast<plSpan*> (span));
if( span->fTypeMask & plSpan::kIcicleSpan )
{
IAccessSpanFromIcicle(dst, drawable, (const plIcicle*)span, readOnly);
}
else if( span->fTypeMask & plSpan::kParticleSpan )
{
IAccessSpanFromParticle(dst, drawable, (const plParticleSpan*)span, readOnly);
}
if( useSnap )
{
IAccessSpanFromSnap(dst, drawable, span);
}
}
void plAccessGeometry::IAccessSpanFromSnap(plAccessSpan& dst, plDrawableSpans* drawable, const plSpan* span) const
{
plAccessVtxSpan& acc = dst.AccessVtx();
if( span->fSnapShot )
{
span->fSnapShot->SetupChannels(acc);
}
}
void plAccessGeometry::IAccessSpanFromVertexSpan(plAccessSpan& dst, plDrawableSpans* drawable, const plVertexSpan* span, hsBool readOnly) const
{
dst.SetMaterial(drawable->GetMaterial(span->fMaterialIdx));
plAccessVtxSpan& acc = dst.AccessVtx();
plGBufferGroup* grp = drawable->GetBufferGroup(span->fGroupIdx);
//#define MF_TOSSER
#ifndef MF_TOSSER
plConst(hsBool) useDev(false);
#else // MF_TOSSER
plConst(hsBool) useDev(true);
#endif // MF_TOSSER
if( useDev && !drawable->GetNativeProperty(plDrawable::kPropVolatile) && grp->GetVertexBufferRef(span->fVBufferIdx) )
{
fPipe->OpenAccess(dst, drawable, span, readOnly);
return;
}
acc.fNumVerts = (UInt16)(span->fVLength);
plGBufferCell* cell = grp->GetCell(span->fVBufferIdx, span->fCellIdx);
UInt8* ptr = grp->GetVertBufferData(span->fVBufferIdx);
// Interleaved
if( cell->fColorStart == UInt32(-1) )
{
UInt32 stride = grp->GetVertexSize();
ptr += cell->fVtxStart + span->fCellOffset * stride;
Int32 offset = (-(Int32)(span->fVStartIdx)) * (Int32)stride;
acc.PositionStream(ptr, (UInt16)stride, offset);
ptr += sizeof(hsPoint3);
int numWgts = grp->GetNumWeights();
if( numWgts )
{
acc.SetNumWeights(numWgts);
acc.WeightStream(ptr, (UInt16)stride, offset);
ptr += numWgts * sizeof(hsScalar);
if( grp->GetVertexFormat() & plGBufferGroup::kSkinIndices )
{
acc.WgtIndexStream(ptr, (UInt16)stride, offset);
ptr += sizeof(UInt32);
}
else
{
acc.WgtIndexStream(nil, 0, offset);
}
}
else
{
acc.SetNumWeights(0);
}
acc.NormalStream(ptr, (UInt16)stride, offset);
ptr += sizeof(hsVector3);
acc.DiffuseStream(ptr, (UInt16)stride, offset);
ptr += sizeof(UInt32);
acc.SpecularStream(ptr, (UInt16)stride, offset);
ptr += sizeof(UInt32);
acc.UVWStream(ptr, (UInt16)stride, offset);
acc.SetNumUVWs(grp->GetNumUVs());
}
else
{
UInt32 stride = grp->GetVertexLiteStride();
ptr += cell->fVtxStart + span->fCellOffset * stride;
Int32 posOffset = (-(Int32)(span->fVStartIdx)) * (Int32)stride;
acc.PositionStream(ptr, (UInt16)stride, posOffset);
ptr += sizeof(hsPoint3);
int numWgts = grp->GetNumWeights();
if( numWgts )
{
acc.SetNumWeights(numWgts);
acc.WeightStream(ptr, (UInt16)stride, posOffset);
ptr += numWgts * sizeof(hsScalar);
if( grp->GetVertexFormat() & plGBufferGroup::kSkinIndices )
{
acc.WgtIndexStream(ptr, (UInt16)stride, posOffset);
ptr += sizeof(UInt32);
}
else
{
acc.WgtIndexStream(nil, 0, 0);
}
}
else
{
acc.SetNumWeights(0);
}
acc.NormalStream(ptr, (UInt16)stride, posOffset);
ptr += sizeof(hsVector3);
plGBufferColor* col = grp->GetColorBufferData(span->fVBufferIdx) + cell->fColorStart;
Int16 colOffset = (Int16)((-(Int32)(span->fVStartIdx)) * (Int32)stride);
colOffset = (Int16)((-(Int32)(span->fVStartIdx)) * sizeof(*col));
acc.DiffuseStream(&col->fDiffuse, sizeof(*col), colOffset);
acc.SpecularStream(&col->fSpecular, sizeof(*col), colOffset);
acc.UVWStream(ptr, (UInt16)stride, posOffset);
acc.SetNumUVWs(grp->GetNumUVs());
}
acc.fVtxDeviceRef = nil;
}
void plAccessGeometry::IAccessConnectivity(plAccessSpan& dst, plDrawableSpans* drawable, const plSpan* src) const
{
if( src->fTypeMask & plSpan::kIcicleSpan )
{
const plIcicle* span = (const plIcicle*)src;
dst.SetType(plAccessSpan::kTri);
plAccessTriSpan& acc = dst.AccessTri();
acc.fNumTris = span->fILength / 3;
plGBufferGroup* grp = drawable->GetBufferGroup(span->fGroupIdx);
acc.fTris = grp->GetIndexBufferData(span->fIBufferIdx) + span->fIStartIdx;
acc.fIdxDeviceRef = nil;
}
// Hmm, particle should probably go here...
else
{
dst.SetType(plAccessSpan::kVtx);
}
}
void plAccessGeometry::IAccessSpanFromIcicle(plAccessSpan& dst, plDrawableSpans* drawable, const plIcicle* span, hsBool readOnly) const
{
dst.SetType(plAccessSpan::kTri);
plAccessTriSpan& acc = dst.AccessTri();
IAccessSpanFromVertexSpan(dst, drawable, span, readOnly);
acc.fNumTris = span->fILength / 3;
plGBufferGroup* grp = drawable->GetBufferGroup(span->fGroupIdx);
acc.fTris = grp->GetIndexBufferData(span->fIBufferIdx) + span->fIStartIdx;
acc.fIdxDeviceRef = nil;
}
void plAccessGeometry::IAccessSpanFromParticle(plAccessSpan& dst, plDrawableSpans* drawable, const plParticleSpan* span, hsBool readOnly) const
{
hsAssert(false, "Aint got to it yet");
// dst.SetType(plAccessSpan::kParty);
}