/*==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 "hsGMaterial.h" #include #include "hsTypes.h" #include "hsMemory.h" //#include "../plGeometry/hsTriangle3.h" #include "hsResMgr.h" #include "plLayerInterface.h" #include "plLayer.h" #include "plMessage/plMatRefMsg.h" #include "plProfile.h" plProfile_CreateTimer("MaterialAnims", "Animation", MaterialAnims); plLayer defaultLayer; ////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////// hsGMaterial::hsGMaterial() : fLOD(0), fCompFlags(0), fLoadFlags(0), fLastUpdateTime(0) { } hsGMaterial::~hsGMaterial() { IClearLayers(); } plLayerInterface* hsGMaterial::GetPiggyBack(UInt32 which) { return fPiggyBacks[which]; } plLayerInterface* hsGMaterial::GetLayer(UInt32 which) { return fLayers[which]; } UInt32 hsGMaterial::IMakeExtraLayer() { fLayers.ExpandAndZero(GetNumLayers()+1); return fLayers.GetCount(); } void hsGMaterial::IClearLayers() { fLayers.Reset(); } void hsGMaterial::SetNumLayers(int cnt) { if( cnt < fLayers.GetCount() ) fLayers.SetCount(cnt); else fLayers.ExpandAndZero(cnt); } hsGMaterial* hsGMaterial::Clone() { hsGMaterial* clo = CloneNoLayers(); clo->SetNumLayers(GetNumLayers()); int i; for( i = 0; i < GetNumLayers(); i++ ) clo->SetLayer(fLayers[i], i); return clo; } hsGMaterial* hsGMaterial::CloneNoLayers() { hsGMaterial* clo = TRACKED_NEW hsGMaterial; clo->fCompFlags = fCompFlags; clo->fLoadFlags = fLoadFlags; return clo; } plLayer* hsGMaterial::MakeBaseLayer() { plLayer* newLay = TRACKED_NEW plLayer; newLay->InitToDefault(); IClearLayers(); hsAssert(GetKey(), "All materials need a key (or temp key)"); char buff[256]; if( GetKey()->GetName() ) sprintf(buff, "%s_%s", GetKey()->GetName(), "Layer"); else strcpy(buff, "Layer"); hsgResMgr::ResMgr()->NewKey( buff, newLay, GetKey() != nil ? GetKey()->GetUoid().GetLocation() : plLocation::kGlobalFixedLoc ); // Add layer so we have it now. AddLayerViaNotify(newLay); return newLay; } UInt32 hsGMaterial::AddLayerViaNotify(plLayerInterface* layer) { int idx = GetNumLayers(); // Add via notify so we'll dispose of it properly later. plMatRefMsg* msg = TRACKED_NEW plMatRefMsg(GetKey(), plRefMsg::kOnRequest, idx, plMatRefMsg::kLayer); hsgResMgr::ResMgr()->SendRef(layer->GetKey(), msg, plRefFlags::kActiveRef); fLayers.SetCount(idx+1); fLayers[idx] = layer; return idx; } void hsGMaterial::ReplaceLayer(plLayerInterface* oldLay, plLayerInterface* newLay, hsBool piggyBack) { hsTArray& layers = piggyBack ? fPiggyBacks : fLayers; int i; for( i = 0; i < layers.GetCount(); i++ ) { if( layers[i] == oldLay ) break; } hsAssert(i < layers.GetCount(), "Replacing a layer we don't have"); if( i >= layers.GetCount() ) return; SetLayer(newLay, i, piggyBack); } void hsGMaterial::RemoveLayer(plLayerInterface* lay, hsBool piggyBack) { hsTArray& layers = piggyBack ? fPiggyBacks : fLayers; int i; for( i = 0; i < layers.GetCount(); i++ ) { if( layers[i] == lay ) break; } if (i >= layers.GetCount()) return; layers.Remove(i); } void hsGMaterial::InsertLayer(plLayerInterface* layer, Int32 which, hsBool piggyBack) { hsTArray& layers = piggyBack ? fPiggyBacks : fLayers; hsAssert(which <= layers.GetCount(), "Material layers Exceeding test depth"); layers.InsertAtIndex(which, layer); } void hsGMaterial::SetLayer(plLayerInterface* layer, Int32 which, hsBool insert, hsBool piggyBack) { if( insert ) { InsertLayer(layer, which, piggyBack); } else { hsTArray& layers = piggyBack ? fPiggyBacks : fLayers; if( which < 0 ) which = layers.GetCount(); hsAssert(which <= layers.GetCount(), "Material layers Exceeding test depth"); if( which < layers.GetCount() ) layers[which] = layer; else layers.Append(layer); } } void hsGMaterial::Write(hsStream* s) { s->WriteSwap32(fLoadFlags); s->WriteSwap32(fCompFlags); s->WriteSwap32(GetNumLayers()); s->WriteSwap32(GetNumPiggyBacks()); } void hsGMaterial::Read(hsStream* s) { fLoadFlags = s->ReadSwap32(); fCompFlags = s->ReadSwap32(); IClearLayers(); int n = s->ReadSwap32(); fLayers.SetCountAndZero(n); n = s->ReadSwap32(); fPiggyBacks.SetCountAndZero(n); } void hsGMaterial::Write(hsStream *stream, hsResMgr *group) { plSynchedObject::Write(stream, group); Write(stream); // Write one (or many) texture indices int iLay; for( iLay = 0; iLay < GetNumLayers(); iLay++ ) { group->WriteKey(stream,GetLayer(iLay)); } for( iLay = 0; iLay < GetNumPiggyBacks(); iLay++ ) { group->WriteKey(stream, GetPiggyBack(iLay)); } } void hsGMaterial::Read(hsStream *stream, hsResMgr *group) { plSynchedObject::Read(stream, group); Read(stream); int iLay; // Assign texture(s) for (iLay = 0; iLay < GetNumLayers(); iLay++) { plMatRefMsg* msg = TRACKED_NEW plMatRefMsg(GetKey(), plRefMsg::kOnCreate, iLay, plMatRefMsg::kLayer); plKey key = group->ReadKeyNotifyMe(stream, msg, plRefFlags::kActiveRef); } for (iLay = 0; iLay < GetNumPiggyBacks(); iLay++) { plMatRefMsg* msg = TRACKED_NEW plMatRefMsg(GetKey(), plRefMsg::kOnCreate, iLay, plMatRefMsg::kPiggyBack); plKey key = group->ReadKeyNotifyMe(stream, msg, plRefFlags::kActiveRef); } } void hsGMaterial::Eval(double secs, UInt32 frame) { plProfile_BeginLap(MaterialAnims, GetKeyName()); int i; for( i = 0; i < GetNumLayers(); i++ ) { if( fLayers[i] ) fLayers[i]->Eval(secs, frame, 0); } for( i = 0; i < GetNumPiggyBacks(); i++ ) { if( fPiggyBacks[i] ) fPiggyBacks[i]->Eval(secs, frame, 0); } plProfile_EndLap(MaterialAnims, GetKeyName()); } void hsGMaterial::Reset() { int i; for( i = 0; i < GetNumLayers(); i++ ) { if( fLayers[i] ) fLayers[i]->Eval(0, 0, 0); } } void hsGMaterial::Init() { Reset(); } hsBool hsGMaterial::MsgReceive(plMessage* msg) { plMatRefMsg* refMsg = plMatRefMsg::ConvertNoRef(msg); if( refMsg ) { int which = refMsg->fWhich; hsBool piggyBack = 0 != (refMsg->fType & plMatRefMsg::kPiggyBack); plLayerInterface* lay= plLayerInterface::ConvertNoRef(refMsg->GetRef()); if( refMsg->GetContext() & (plRefMsg::kOnCreate|plRefMsg::kOnRequest) ) { hsBool insert = 0 != (refMsg->fType & plMatRefMsg::kInsert); SetLayer(lay, which, insert, piggyBack ); } else if( refMsg->GetContext() & plRefMsg::kOnReplace ) ReplaceLayer(plLayerInterface::ConvertNoRef(refMsg->GetOldRef()), lay, piggyBack); else if( refMsg->GetContext() & (plRefMsg::kOnRemove | plRefMsg::kOnDestroy) ) RemoveLayer(lay, piggyBack); else ReplaceLayer(lay, &defaultLayer, piggyBack); return true; } return plSynchedObject::MsgReceive(msg); }