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.
583 lines
16 KiB
583 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); |
|
} |
|
|
|
|
|
|
|
|
|
|