/*==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 "plInstanceDrawInterface.h"
#include "plSharedMesh.h"
#include "plMorphSequence.h"
#include "../plMessage/plReplaceGeometryMsg.h"
#include "plDrawableSpans.h"
#include "plGeometrySpan.h"
#include "../plScene/plSceneNode.h"
#include "../pnMessage/plDISpansMsg.h"
#include "hsResMgr.h"
plInstanceDrawInterface::plInstanceDrawInterface() : plDrawInterface(), fTargetID(-1) {}
plInstanceDrawInterface::~plInstanceDrawInterface() {}
void plInstanceDrawInterface::Read(hsStream* stream, hsResMgr* mgr)
{
plDrawInterface::Read(stream, mgr);
fTargetID = stream->ReadSwap32();
plSwapSpansRefMsg *sMsg = TRACKED_NEW plSwapSpansRefMsg(GetKey(), plRefMsg::kOnCreate, -1, -1);
mgr->ReadKeyNotifyMe(stream, sMsg, plRefFlags::kActiveRef);
}
void plInstanceDrawInterface::Write(hsStream* stream, hsResMgr* mgr)
{
plDrawInterface::Write(stream, mgr);
stream->WriteSwap32(fTargetID);
mgr->WriteKey(stream, fDrawable->GetKey());
}
hsBool plInstanceDrawInterface::MsgReceive(plMessage* msg)
{
#if 0 // UNUSED
// This currently isn't being used, so I'm commenting it out at
// Bob's preference. If it does come back into play, the plReplaceGeometryMsg should also
// contain an LOD field, saying which avatar LOD this is targetted for.
// Just always specifying 0 won't break anything, it just circumvents some
// optimizations the pipeline can make, so it'll look right, just slower.
plReplaceGeometryMsg *rMsg = plReplaceGeometryMsg::ConvertNoRef(msg);
if (rMsg)
{
if (rMsg->fFlags & rMsg->kAddingGeom)
AddSharedMesh(rMsg->fMesh, rMsg->fMaterial, rMsg->fFlags & rMsg->kAddToFront);
else
RemoveSharedMesh(rMsg->fMesh);
return true;
}
#endif // UNUSED
plSwapSpansRefMsg* refMsg = plSwapSpansRefMsg::ConvertNoRef(msg);
if (refMsg)
{
if( refMsg->GetContext() & (plRefMsg::kOnDestroy|plRefMsg::kOnRemove) )
fDrawable = nil;
else
fDrawable = plDrawableSpans::ConvertNoRef(refMsg->GetRef());
return true;
}
return plDrawInterface::MsgReceive(msg);
}
void plInstanceDrawInterface::AddSharedMesh(plSharedMesh *mesh, hsGMaterial *mat, hsBool addToFront, int lod, hsBool partialSort)
{
if (fDrawable == nil)
{
hsAssert(false, "Missing drawable when instancing a shared mesh. Ignoring instance.");
return;
}
#ifdef MF_NOSHADOW_ACC
// TESTHACKERY FOLLOWS - GlassesNoShadow
UInt32 noShadHack = 0;
if( mesh->GetKey() && (strstr(mesh->GetKey()->GetName(), "lasses") || strstr(mesh->GetKey()->GetName(), "oggles")) )
noShadHack = plGeometrySpan::kPropNoShadowCast;
#endif // MF_NOSHADOW_ACC
int i;
for (i = 0; i < mesh->fSpans.GetCount(); i++)
{
mesh->fSpans[i]->fMaterial = mat;
if( partialSort )
{
mesh->fSpans[i]->fProps |= plGeometrySpan::kPartialSort;
}
else
mesh->fSpans[i]->fProps &= ~plGeometrySpan::kPartialSort;
#ifdef MF_NOSHADOW_ACC
mesh->fSpans[i]->fProps |= noShadHack;
#endif // MF_NOSHADOW_ACC
}
// Add the spans to the drawable
UInt32 index = (UInt32)-1;
index = fDrawable->AppendDISpans(mesh->fSpans, index, false, true, addToFront, lod);
// Tell the drawInterface what drawable and index it wants.
UInt8 iDraw = (UInt8)GetNumDrawables();
ISetDrawable(iDraw, fDrawable);
SetDrawableMeshIndex(iDraw, index);
SetSharedMesh(iDraw, mesh);
if (GetProperty(kDisable))
fDrawables[iDraw]->SetProperty(fDrawableIndices[iDraw], kDisable, true);
#ifdef HS_DEBUGGING
plDISpansMsg* diMsg = TRACKED_NEW plDISpansMsg(fDrawable->GetKey(), plDISpansMsg::kAddingSpan, index, plDISpansMsg::kLeaveEmptyDrawable);
diMsg->SetSender(GetKey());
diMsg->Send();
#endif
plSharedMeshBCMsg *smMsg = TRACKED_NEW plSharedMeshBCMsg;
smMsg->SetSender(GetKey());
smMsg->fDraw = fDrawable;
smMsg->fMesh = mesh;
smMsg->fIsAdding = true;
smMsg->Send();
if (mesh->fMorphSet)
{
plMorphSequence *morph = const_cast(plMorphSequence::ConvertNoRef(fOwner->GetModifierByType(plMorphSequence::Index())));
if (morph)
{
//hsgResMgr::ResMgr()->AddViaNotify(mesh->GetKey(), TRACKED_NEW plGenRefMsg(morph->GetKey(), plRefMsg::kOnCreate, -1, -1), plRefFlags::kPassiveRef);
morph->AddSharedMesh(mesh);
}
}
}
void plInstanceDrawInterface::RemoveSharedMesh(plSharedMesh *mesh)
{
UInt32 geoIndex = fMeshes.Find(mesh);
if (geoIndex != fMeshes.kMissingIndex)
{
IClearIndex((UInt8)geoIndex);
plSharedMeshBCMsg *smMsg = TRACKED_NEW plSharedMeshBCMsg;
smMsg->SetSender(GetKey());
smMsg->fDraw = fDrawable;
smMsg->fMesh = mesh;
smMsg->fIsAdding = false;
smMsg->Send();
if (mesh->fMorphSet)
{
plMorphSequence *morph = const_cast(plMorphSequence::ConvertNoRef(fOwner->GetModifierByType(plMorphSequence::Index())));
if (morph)
{
//morph->GetKey()->Release(mesh->GetKey());
morph->RemoveSharedMesh(mesh);
}
}
}
}
void plInstanceDrawInterface::ICheckDrawableIndex(UInt8 which)
{
if( which >= fMeshes.GetCount() )
{
fMeshes.ExpandAndZero(which+1);
}
plDrawInterface::ICheckDrawableIndex(which);
}
void plInstanceDrawInterface::ReleaseData()
{
fMeshes.Reset();
plDrawInterface::ReleaseData();
}
void plInstanceDrawInterface::SetSharedMesh(UInt8 which, plSharedMesh *mesh)
{
ICheckDrawableIndex(which);
fMeshes[which] = mesh;
}
void plInstanceDrawInterface::IClearIndex(UInt8 which)
{
plDrawableSpans *drawable = plDrawableSpans::ConvertNoRef(fDrawables[which]);
if (drawable != nil)
{
plDISpansMsg* diMsg = TRACKED_NEW plDISpansMsg(fDrawable->GetKey(), plDISpansMsg::kRemovingSpan, fDrawableIndices[which], plDISpansMsg::kLeaveEmptyDrawable);
diMsg->SetSender(GetKey());
diMsg->Send();
}
fDrawables.Remove(which);
fDrawableIndices.Remove(which);
fMeshes.Remove(which);
}
// Temp testing - not really ideal. Check with Bob for real soln.
Int32 plInstanceDrawInterface::GetSharedMeshIndex(const plSharedMesh *mesh) const
{
int i;
for( i = 0; i < fMeshes.GetCount(); i++ )
{
if( fMeshes[i] == mesh )
return i;
}
return -1;
}