void plEAXListener::ProcessMods( hsTArray<plEAXListenerMod *> &modArray ) { #ifdef EAX_SDK_AVAILABLE int i; float totalStrength; hsBool firstOne; plEAXListenerMod *thisBigRegion = nil; EAXLISTENERPROPERTIES finalProps; static int oldTime = timeGetTime(); // Get starting time int newTime; hsBool bMorphing = false; static plStatusLog *myLog = nil; if( myLog == nil && plgAudioSys::AreExtendedLogsEnabled() ) myLog = plStatusLogMgr::GetInstance().CreateStatusLog( 30, "EAX Reverbs", plStatusLog::kFilledBackground | plStatusLog::kDeleteForMe | plStatusLog::kDontWriteFile ); else if( myLog != nil && !plgAudioSys::AreExtendedLogsEnabled() ) { delete myLog; myLog = nil; } if( myLog != nil ) myLog->Clear(); if( modArray.GetCount() != fLastModCount ) { kDebugLog "Clearing cache..." ); ClearProcessCache(); // Code path changed, clear the entire cache fLastModCount = modArray.GetCount(); }
void plCullNode::ITakeHalfPoly(const plCullPoly& srcPoly, const hsTArray<int>& vtxIdx, const hsBitVector& onVerts, plCullPoly& outPoly) const { if( vtxIdx.GetCount() > 2 ) { int i; for( i = 0; i < vtxIdx.GetCount(); i++ ) { int next = i < vtxIdx.GetCount()-1 ? i+1 : 0; int last = i ? i-1 : vtxIdx.GetCount()-1; // If these 3 verts are all on the plane, we may have created a collinear vertex (the middle one) // which we now want to skip. if( onVerts.IsBitSet(vtxIdx[i]) && onVerts.IsBitSet(vtxIdx[last]) && onVerts.IsBitSet(vtxIdx[next]) ) { #if 0 // FISH float dot = hsVector3(&srcPoly.fVerts[vtxIdx[last]], &srcPoly.fVerts[vtxIdx[i]]).InnerProduct(hsVector3(&srcPoly.fVerts[vtxIdx[next]], &srcPoly.fVerts[vtxIdx[i]])); if( dot <= 0 ) #endif // FISH continue; } if( srcPoly.fClipped.IsBitSet(vtxIdx[i]) ||(onVerts.IsBitSet(vtxIdx[i]) && onVerts.IsBitSet(vtxIdx[next])) ) outPoly.fClipped.SetBit(outPoly.fVerts.GetCount()); outPoly.fVerts.Append(srcPoly.fVerts[vtxIdx[i]]); } } else { // Just need a break point hsStatusMessage("Under 2"); // FISH } }
void plMorphDelta::SetDeltas(int iSpan, const hsTArray<plVertDelta>& deltas, int numUVWChans, const hsPoint3* uvws) { AllocDeltas(iSpan, deltas.GetCount(), numUVWChans); if( deltas.GetCount() ) { HSMemory::BlockMove(&deltas[0], fSpans[iSpan].fDeltas.AcquireArray(), deltas.GetCount() * sizeof(plVertDelta)); if( numUVWChans ) HSMemory::BlockMove(uvws, fSpans[iSpan].fUVWs, deltas.GetCount() * numUVWChans * sizeof(*uvws)); } }
// MorphDelta - ComputeDeltas void plMorphDelta::ComputeDeltas(const hsTArray<plAccessSpan>& base, const hsTArray<plAccessSpan>& moved) { SetNumSpans(base.GetCount()); // For each span { // for( i = 0; i < numVerts; i++ ) { // NOTE: we want to discard zero deltas, but a // delta in any channel forces us to save the whole thing. // But we don't want to compare to zero (because we'll end // up with a lot of near zero deltas), but the epsilon we // compare to needs to be different for comparing something // like a normal delta and a position delta. // // For position, normal, color and all uvws // Calc del and delLenSq // If any delLenSq big enough, set nonZero to true // If nonZero { // Append to deltas (i, del's) } } } }
static int ISearchLayerRecur(hsGMaterial* mat, const ST::string &segName, hsTArray<plKey>& keys) { ST::string name = ( segName.compare( ENTIRE_ANIMATION_NAME ) == 0 ) ? ST::null : segName; int i; for( i = 0; i < mat->GetNumLayers(); i++ ) ISearchLayerRecur(mat->GetLayer(i), name, keys); return keys.GetCount(); }
void plSceneNode::Harvest(plVolumeIsect* isect, hsTArray<plDrawVisList>& levList) { static hsTArray<int16_t> visList; visList.SetCount(0); GetSpaceTree()->HarvestLeaves(isect, visList); static hsTArray<int16_t> visSpans; visSpans.SetCount(0); int i; for( i = 0; i < visList.GetCount(); i++ ) { int idx = visList[i]; fDrawPool[idx]->GetSpaceTree()->HarvestLeaves(isect, visSpans); if( visSpans.GetCount() ) { plDrawVisList* drawVis = levList.Push(); drawVis->fDrawable = fDrawPool[idx]; drawVis->fVisList.Swap(visSpans); } } }
void plMorphSequence::IRenormalize(hsTArray<plAccessSpan>& dst) const { int i; for( i = 0; i < dst.GetCount(); i++ ) { hsAssert(dst[i].HasAccessVtx(), "Come on, everyone has vertices"); plAccessVtxSpan& accVtx = dst[i].AccessVtx(); int j; for( j = 0; j < accVtx.VertCount(); j++ ) { hsFastMath::Normalize(accVtx.Normal(j)); } } }
bool plGeoSpanDice::Dice(hsTArray<plGeometrySpan*>& spans) const { int startingCount = spans.GetCount(); hsTArray<plGeometrySpan*> out; hsTArray<plGeometrySpan*> next; while(spans.GetCount()) { int i; for( i = 0; i < spans.GetCount(); i++ ) { if( !IHalf(spans[i], next) ) { out.Append(spans[i]); } } spans.Swap(next); next.SetCount(0); } spans.Swap(out); return spans.GetCount() != startingCount; }
void plInterMeshSmooth::FindEdges(hsTArray<plSpanHandle>& sets, hsTArray<uint16_t>* edgeVerts) { int i; for( i = 0; i < sets.GetCount(); i++ ) { const plSpan* span = sets[i].fDrawable->GetSpan(sets[i].fSpanIdx); if( !(span->fTypeMask & plSpan::kIcicleSpan) ) continue; uint32_t nTris = sets[i].fDrawable->CvtGetNumTris(sets[i].fSpanIdx); uint16_t* idxList = sets[i].fDrawable->CvtGetIndexList(sets[i].fSpanIdx); uint32_t maxVertIdx = sets[i].fDrawable->CvtGetNumVerts(sets[i].fSpanIdx)-1; FindEdges(maxVertIdx, nTris, idxList, edgeVerts[i]); } }
bool plPipelineViewSettings::SubmitOccluders(const hsTArray<const plCullPoly*>& polyList) { fCullPolys.SetCount(0); fCullHoles.SetCount(0); int i; for (i = 0; i < polyList.GetCount(); i++) { if (polyList[i]->IsHole()) fCullHoles.Append(polyList[i]); else fCullPolys.Append(polyList[i]); } fCullTreeDirty = true; return true; }
void plInterMeshSmooth::FindSharedVerts(hsPoint3& searchPos, plSpanHandle& set, hsTArray<uint16_t>& edgeVerts, hsTArray<uint16_t>& shareVtx, hsVector3& normAccum) { int i; for( i = 0; i < edgeVerts.GetCount(); i++ ) { hsPoint3 pos = GetPosition(set, edgeVerts[i]); hsVector3 norm = GetNormal(set, edgeVerts[i]); if( searchPos == pos ) { if( norm.InnerProduct(normAccum) > fMinNormDot ) { shareVtx.Append(edgeVerts[i]); normAccum += norm; } } } }
void pl3DPipeline::IAttachSlaveToReceivers(int which, plDrawableSpans* drawable, const hsTArray<int16_t>& visList) { plShadowSlave* slave = fShadows[which]; // Whether the drawable is a character affects which lights/shadows affect it. bool isChar = drawable->GetNativeProperty(plDrawable::kPropCharacter); // If the shadow is part of a light group, it gets handled in ISetShadowFromGroup. // Unless the drawable is a character (something that moves around indeterminately, // like the avatar or a physical object), and the shadow affects all characters. if (slave->ObeysLightGroups() && !(slave->IncludesChars() && isChar)) return; // Do a space tree harvest looking for spans that are visible and whose bounds // intercect the shadow volume. plSpaceTree* space = drawable->GetSpaceTree(); static hsBitVector cache; cache.Clear(); space->EnableLeaves(visList, cache); static hsTArray<int16_t> hitList; hitList.SetCount(0); space->HarvestEnabledLeaves(slave->fIsect, cache, hitList); // For the visible spans that intercect the shadow volume, attach the shadow // to all appropriate for receiving this shadow map. for (size_t i = 0; i < hitList.GetCount(); i++) { const plSpan* span = drawable->GetSpan(hitList[i]); hsGMaterial* mat = drawable->GetMaterial(span->fMaterialIdx); // Check that the span isn't flagged as unshadowable, or has // a material that we can't shadow onto. if (!IReceivesShadows(span, mat)) continue; // Check for self shadowing. If the shadow doesn't want self shadowing, // and the span is part of the shadow caster, then skip. if (!IAcceptsShadow(span, slave)) continue; // Add it to this span's shadow list for this frame. span->AddShadowSlave(fShadows[which]->fIndex); } }
bool plPipelineViewSettings::HarvestVisible(plSpaceTree* space, hsTArray<int16_t>& visList) { if (!space) return false; space->SetViewPos(GetViewPositionWorld()); space->Refresh(); if (fCullTreeDirty) RefreshCullTree(); plProfile_BeginTiming(Harvest); fCullTree.Harvest(space, visList); plProfile_EndTiming(Harvest); return visList.GetCount() != 0; }
void plInterMeshSmooth::SmoothNormals(hsTArray<plSpanHandle>& sets) { hsTArray<uint16_t>* shareVtx = new hsTArray<uint16_t>[sets.GetCount()]; hsTArray<uint16_t>* edgeVerts = new hsTArray<uint16_t>[sets.GetCount()]; FindEdges(sets, edgeVerts); int i; for( i = 0; i < sets.GetCount()-1; i++ ) { int j; for( j = edgeVerts[i].GetCount()-1; j >= 0; --j ) { hsPoint3 pos = GetPosition(sets[i], edgeVerts[i][j]); hsVector3 normAccum = GetNormal(sets[i], edgeVerts[i][j]);; shareVtx[i].Append(edgeVerts[i][j]); int k; for( k = i+1; k < sets.GetCount(); k++ ) { FindSharedVerts(pos, sets[k], edgeVerts[k], shareVtx[k], normAccum); } normAccum.Normalize(); GetNormal(sets[i], edgeVerts[i][j]) = normAccum; for( k = i+1; k < sets.GetCount(); k++ ) { SetNormals(sets[k], shareVtx[k], normAccum); } // Now remove all the shared verts (which we just processed) // from edgeVerts so we don't process them again. for( k = i; k < sets.GetCount(); k++ ) { int m; for( m = 0; m < shareVtx[k].GetCount(); m++ ) { int idx = edgeVerts[k].Find(shareVtx[k][m]); hsAssert(idx != edgeVerts[k].kMissingIndex, "Lost vertex between find and remove"); edgeVerts[k].Remove(idx); } shareVtx[k].SetCount(0); } } } delete [] shareVtx; delete [] edgeVerts; }
void plSceneNode::CollectForRender(plPipeline* pipe, hsTArray<plDrawVisList>& levList, plVisMgr* visMgr) { static hsTArray<int16_t> visList; visList.SetCount(0); pipe->HarvestVisible(GetSpaceTree(), visList); static hsTArray<int16_t> visSpans; visSpans.SetCount(0); int i; for( i = 0; i < visList.GetCount(); i++ ) { int idx = visList[i]; if( pipe->PreRender(fDrawPool[idx], visSpans, visMgr) ) { plDrawVisList* drawVis = levList.Push(); drawVis->fDrawable = fDrawPool[idx]; drawVis->fVisList.Swap(visSpans); } } }
void hsVertexShader::ShadeNode(INode* node, hsMatrix44& l2w, hsMatrix44& w2l, hsTArray<plGeometrySpan *> &spans) { // If we're flagged for WaterColor, our vertex colors are already done. if( ((plMaxNodeBase*)node)->GetCalcEdgeLens() || node->UserPropExists("XXXWaterColor") ) return; fLightMapGen->InitNode(node); fLocalToWorld = l2w; hsMatrix44 tempMatrix = w2l; // l2w's inverse tempMatrix.GetTranspose( &fNormalToWorld ); // Inverse-transpose of the fLocalToWorld matrix, int i; for( i = 0; i < spans.GetCount(); i++ ) IShadeSpan( spans[ i ], node); fLightMapGen->DeInitNode(); fShaded++; }
void plPipelineViewSettings::GetVisibleSpans(plDrawableSpans* drawable, hsTArray<int16_t>& visList, plVisMgr* visMgr) { static hsTArray<int16_t> tmpVis; tmpVis.SetCount(0); visList.SetCount(0); drawable->GetSpaceTree()->SetViewPos(GetViewPositionWorld()); drawable->GetSpaceTree()->Refresh(); if (fCullTreeDirty) RefreshCullTree(); const float viewDist = GetViewDirWorld().InnerProduct(GetViewPositionWorld()); const hsTArray<plSpan *> &spans = drawable->GetSpanArray(); plProfile_BeginTiming(Harvest); if (visMgr) { drawable->SetVisSet(visMgr); fCullTree.Harvest(drawable->GetSpaceTree(), tmpVis); drawable->SetVisSet(nullptr); } else { fCullTree.Harvest(drawable->GetSpaceTree(), tmpVis); } // This is a big waste of time, As a desparate "optimization" pass, the artists // insist on going through and marking objects to fade or pop out of rendering // past a certain distance. This breaks the batching and requires more CPU to // check the objects by distance. Since there is no pattern to the distance at // which objects will be told not to draw, there's no way to make this hierarchical, // which is what it would take to make it a performance win. So they succeed in // reducing the poly count, but generally the frame rate goes _down_ as well. // Unfortunately, this technique actually does work in a few key areas, so // I haven't been able to purge it. if (fPipeline->IsDebugFlagSet(plPipeDbg::kFlagSkipVisDist)) { int i; for (i = 0; i < tmpVis.GetCount(); i++) { if (spans[tmpVis[i]]->fSubType & fSubDrawableTypeMask) { visList.Append(tmpVis[i]); } } } else { int i; for (i = 0; i < tmpVis.GetCount(); i++) { if (spans[tmpVis[i]]->fSubType & fSubDrawableTypeMask) { // We'll check here for spans we can discard because they've completely distance faded out. // Note this is based on view direction distance (because the fade is), rather than the // preferrable distance to camera we sort by. float minDist, maxDist; if (drawable->GetSubVisDists(tmpVis[i], minDist, maxDist)) { const hsBounds3Ext& bnd = drawable->GetSpaceTree()->GetNode(tmpVis[i]).fWorldBounds; hsPoint2 depth; bnd.TestPlane(GetViewDirWorld(), depth); if ((0 < minDist + viewDist - depth.fY) ||(0 > maxDist + viewDist - depth.fX)) continue; } visList.Append(tmpVis[i]); } } } plProfile_EndTiming(Harvest); }
void pl3DPipeline::ICheckLighting(plDrawableSpans* drawable, hsTArray<int16_t>& visList, plVisMgr* visMgr) { if (fView.fRenderState & kRenderNoLights) return; if (!visList.GetCount()) return; plLightInfo* light; plProfile_BeginTiming(FindLights); // First add in the explicit lights (from LightGroups). // Refresh the lights as they are added (actually a lazy eval). plProfile_BeginTiming(FindPerm); for (size_t j = 0; j < visList.GetCount(); j++) { drawable->GetSpan(visList[j])->ClearLights(); if (IsDebugFlagSet(plPipeDbg::kFlagNoRuntimeLights)) continue; // Set the bits for the lights added from the permanent lists (during ClearLights()). const hsTArray<plLightInfo*>& permaLights = drawable->GetSpan(visList[j])->fPermaLights; for (size_t k = 0; k < permaLights.GetCount(); k++) { permaLights[k]->Refresh(); if (permaLights[k]->GetProperty(plLightInfo::kLPShadowLightGroup) && !permaLights[k]->IsIdle()) { // If it casts a shadow, attach the shadow now. ISetShadowFromGroup(drawable, drawable->GetSpan(visList[j]), permaLights[k]); } } const hsTArray<plLightInfo*>& permaProjs = drawable->GetSpan(visList[j])->fPermaProjs; for (size_t k = 0; k < permaProjs.GetCount(); k++) { permaProjs[k]->Refresh(); if (permaProjs[k]->GetProperty(plLightInfo::kLPShadowLightGroup) && !permaProjs[k]->IsIdle()) { // If it casts a shadow, attach the shadow now. ISetShadowFromGroup(drawable, drawable->GetSpan(visList[j]), permaProjs[k]); } } } plProfile_EndTiming(FindPerm); if (IsDebugFlagSet(plPipeDbg::kFlagNoRuntimeLights)) { plProfile_EndTiming(FindLights); return; } // Sort the incoming spans as either // A) moving - affected by all lights - moveList // B) specular - affected by specular lights - specList // C) visible - affected by moving lights - visList static hsTArray<int16_t> tmpList; static hsTArray<int16_t> moveList; static hsTArray<int16_t> specList; moveList.SetCount(0); specList.SetCount(0); plProfile_BeginTiming(FindSpan); for (size_t k = 0; k < visList.GetCount(); k++) { const plSpan* span = drawable->GetSpan(visList[k]); if (span->fProps & plSpan::kPropRunTimeLight) { moveList.Append(visList[k]); specList.Append(visList[k]); } else if (span->fProps & plSpan::kPropMatHasSpecular) { specList.Append(visList[k]); } } plProfile_EndTiming(FindSpan); // Make a list of lights that can potentially affect spans in this drawable // based on the drawables bounds and properties. // If the drawable has the PropCharacter property, it is affected by lights // in fCharLights, else only by the smaller list of fVisLights. plProfile_BeginTiming(FindActiveLights); static hsTArray<plLightInfo*> lightList; lightList.SetCount(0); if (drawable->GetNativeProperty(plDrawable::kPropCharacter)) { for (size_t i = 0; i < fCharLights.GetCount(); i++) { if (fCharLights[i]->AffectsBound(drawable->GetSpaceTree()->GetWorldBounds())) lightList.Append(fCharLights[i]); } } else { for (size_t i = 0; i < fVisLights.GetCount(); i++) { if (fVisLights[i]->AffectsBound(drawable->GetSpaceTree()->GetWorldBounds())) lightList.Append(fVisLights[i]); } } plProfile_EndTiming(FindActiveLights); // Loop over the lights and for each light, extract a list of the spans that light // affects. Append the light to each spans list with a scalar strength of how strongly // the light affects it. Since the strength is based on the object's center position, // it's not very accurate, but good enough for selecting which lights to use. plProfile_BeginTiming(ApplyActiveLights); for (size_t k = 0; k < lightList.GetCount(); k++) { light = lightList[k]; tmpList.SetCount(0); if (light->GetProperty(plLightInfo::kLPMovable)) { plProfile_BeginTiming(ApplyMoving); const hsTArray<int16_t>& litList = light->GetAffected(drawable->GetSpaceTree(), visList, tmpList, drawable->GetNativeProperty(plDrawable::kPropCharacter)); // PUT OVERRIDE FOR KILLING PROJECTORS HERE!!!! bool proj = nil != light->GetProjection(); if (fView.fRenderState & kRenderNoProjection) proj = false; for (size_t j = 0; j < litList.GetCount(); j++) { // Use the light IF light is enabled and // 1) light is movable // 2) span is movable, or // 3) Both the light and the span have specular const plSpan* span = drawable->GetSpan(litList[j]); bool currProj = proj; if (span->fProps & plSpan::kPropProjAsVtx) currProj = false; if (!(currProj && (span->fProps & plSpan::kPropSkipProjection))) { float strength, scale; light->GetStrengthAndScale(span->fWorldBounds, strength, scale); // We can't pitch a light because it's "strength" is zero, because the strength is based // on the center of the span and isn't conservative enough. We can pitch based on the // scale though, since a light scaled down to zero will have no effect no where. if (scale > 0) { plProfile_Inc(FindLightsFound); span->AddLight(light, strength, scale, currProj); } } } plProfile_EndTiming(ApplyMoving); } else if (light->GetProperty(plLightInfo::kLPHasSpecular)) { if (!specList.GetCount()) continue; plProfile_BeginTiming(ApplyToSpec); const hsTArray<int16_t>& litList = light->GetAffected(drawable->GetSpaceTree(), specList, tmpList, drawable->GetNativeProperty(plDrawable::kPropCharacter)); // PUT OVERRIDE FOR KILLING PROJECTORS HERE!!!! bool proj = nil != light->GetProjection(); if (fView.fRenderState & kRenderNoProjection) proj = false; for (size_t j = 0; j < litList.GetCount(); j++) { // Use the light IF light is enabled and // 1) light is movable // 2) span is movable, or // 3) Both the light and the span have specular const plSpan* span = drawable->GetSpan(litList[j]); bool currProj = proj; if (span->fProps & plSpan::kPropProjAsVtx) currProj = false; if (!(currProj && (span->fProps & plSpan::kPropSkipProjection))) { float strength, scale; light->GetStrengthAndScale(span->fWorldBounds, strength, scale); // We can't pitch a light because it's "strength" is zero, because the strength is based // on the center of the span and isn't conservative enough. We can pitch based on the // scale though, since a light scaled down to zero will have no effect no where. if (scale > 0) { plProfile_Inc(FindLightsFound); span->AddLight(light, strength, scale, currProj); } } } plProfile_EndTiming(ApplyToSpec); } else { if (!moveList.GetCount()) continue; plProfile_BeginTiming(ApplyToMoving); const hsTArray<int16_t>& litList = light->GetAffected(drawable->GetSpaceTree(), moveList, tmpList, drawable->GetNativeProperty(plDrawable::kPropCharacter)); // PUT OVERRIDE FOR KILLING PROJECTORS HERE!!!! bool proj = nil != light->GetProjection(); if (fView.fRenderState & kRenderNoProjection) proj = false; for (size_t j = 0; j < litList.GetCount(); j++) { // Use the light IF light is enabled and // 1) light is movable // 2) span is movable, or // 3) Both the light and the span have specular const plSpan* span = drawable->GetSpan(litList[j]); bool currProj = proj; if (span->fProps & plSpan::kPropProjAsVtx) currProj = false; if (!(currProj && (span->fProps & plSpan::kPropSkipProjection))) { float strength, scale; light->GetStrengthAndScale(span->fWorldBounds, strength, scale); // We can't pitch a light because it's "strength" is zero, because the strength is based // on the center of the span and isn't conservative enough. We can pitch based on the // scale though, since a light scaled down to zero will have no effect no where. if (scale > 0) { plProfile_Inc(FindLightsFound); span->AddLight(light, strength, scale, currProj); } } } plProfile_EndTiming(ApplyToMoving); } } plProfile_EndTiming(ApplyActiveLights); IAttachShadowsToReceivers(drawable, visList); plProfile_EndTiming(FindLights); }
uint32_t plDrawableSpans::AddDISpans( hsTArray<plGeometrySpan *> &spans, uint32_t index ) { int i; uint32_t spanIdx; plSpan *span; hsBounds3Ext bounds; /// Do garbage cleanup first if( fNeedCleanup ) IRemoveGarbage(); if (index == (uint32_t)-1) // need a new one { /// Create a lookup entry index = fDIIndices.GetCount(); fDIIndices.Append( new plDISpanIndex ); fDIIndices[ index ]->fFlags = plDISpanIndex::kNone; } plDISpanIndex *spanLookup = fDIIndices[ index ]; /// Add the geometry spans to our list. Also add our internal span /// copies for( i = 0; i < spans.GetCount(); i++ ) { spanLookup->Append( fSourceSpans.GetCount() ); spans[ i ]->fSpanRefIndex = fSourceSpans.GetCount(); fSourceSpans.Append( spans[ i ] ); spanIdx = fIcicles.GetCount(); fIcicles.Append( plIcicle() ); plIcicle *icicle = &fIcicles[ spanIdx ]; span = (plSpan *)icicle; /// Set common stuff IAssignMatIdxToSpan( span, spans[ i ]->fMaterial ); span->fLocalToWorld = spans[ i ]->fLocalToWorld; span->fWorldToLocal = spans[ i ]->fWorldToLocal; span->fProps |= ( spans[ i ]->fProps & plGeometrySpan::kPropRunTimeLight ) ? plSpan::kPropRunTimeLight : 0; if( spans[i]->fProps & plGeometrySpan::kPropNoShadowCast ) span->fProps |= plSpan::kPropNoShadowCast; if( spans[i]->fProps & plGeometrySpan::kPropNoShadow ) span->fProps |= plSpan::kPropNoShadow; if( spans[i]->fProps & plGeometrySpan::kPropForceShadow ) span->fProps |= plSpan::kPropForceShadow; if( spans[i]->fProps & plGeometrySpan::kPropReverseSort ) span->fProps |= plSpan::kPropReverseSort; if( spans[i]->fProps & plGeometrySpan::kPartialSort ) span->fProps |= plSpan::kPartialSort; if( spans[i]->fProps & plGeometrySpan::kVisLOS ) { span->fProps |= plSpan::kVisLOS; fProps |= plDrawable::kPropHasVisLOS; } span->fNumMatrices = spans[ i ]->fNumMatrices; span->fBaseMatrix = spans[ i ]->fBaseMatrix; span->fLocalUVWChans = spans[i]->fLocalUVWChans; span->fMaxBoneIdx = spans[i]->fMaxBoneIdx; span->fPenBoneIdx = (uint16_t)(spans[i]->fPenBoneIdx); bounds = spans[ i ]->fLocalBounds; span->fLocalBounds = bounds; bounds.Transform( &span->fLocalToWorld ); span->fWorldBounds = bounds; span->fFogEnvironment = spans[ i ]->fFogEnviron; /// Add to our source indices fSpans.Append( span ); fSpanSourceIndices.Append( spanIdx ); } /// Rebuild the pointer array IRebuildSpanArray(); SetSpaceTree(nil); fOptimized = false; return index; }
// MorphDelta - ComputeDeltas void plMorphDelta::ComputeDeltas(const hsTArray<plGeometrySpan*>& base, const hsTArray<plGeometrySpan*>& moved, const hsMatrix44& d2b, const hsMatrix44& d2bTInv) { SetNumSpans(base.GetCount()); hsPoint3 delUVWs[8]; // For each span int iSpan; for( iSpan = 0; iSpan < base.GetCount(); iSpan++ ) { plAccessSpan baseAcc; plAccessGeometry::Instance()->AccessSpanFromGeometrySpan(baseAcc, base[iSpan]); plAccessSpan movedAcc; plAccessGeometry::Instance()->AccessSpanFromGeometrySpan(movedAcc, moved[iSpan]); plAccPosNormUVWIterator baseIter(&baseAcc.AccessVtx()); plAccPosNormUVWIterator movedIter(&movedAcc.AccessVtx()); plMorphSpan& dst = fSpans[iSpan]; const uint16_t numUVWs = baseAcc.AccessVtx().NumUVWs(); hsTArray<plVertDelta> deltas; hsTArray<hsPoint3> uvws; deltas.SetCount(0); uvws.SetCount(0); int iVert = 0;; for( baseIter.Begin(), movedIter.Begin(); baseIter.More(); baseIter.Advance(), movedIter.Advance() ) { // NOTE: we want to discard zero deltas, but a // delta in any channel forces us to save the whole thing. // But we don't want to compare to zero (because we'll end // up with a lot of near zero deltas), but the epsilon we // compare to needs to be different for comparing something // like a normal delta and a position delta. // // For position, normal, color and all uvws // Calc del and delLenSq // If any delLenSq big enough, set nonZero to true bool nonZero = false; // These are actually min del SQUARED. plConst(float) kMinDelPos(1.e-4f); // From Budtpueller's Handbook of Constants plConst(float) kMinDelNorm(3.e-2f); // About 10 degrees plConst(float) kMinDelUVW(1.e-4f); // From BHC hsPoint3 mPos = d2b * *movedIter.Position(); hsVector3 delPos( &mPos, baseIter.Position()); float delPosSq = delPos.MagnitudeSquared(); if( delPosSq > kMinDelPos ) nonZero = true; else delPos.Set(0,0,0); hsVector3 delNorm = (d2bTInv * *movedIter.Normal()) - *baseIter.Normal(); float delNormSq = delNorm.MagnitudeSquared(); if( delNormSq > kMinDelNorm ) nonZero = true; else delNorm.Set(0,0,0); int i; for( i = 0; i < numUVWs; i++ ) { delUVWs[i] = *movedIter.UVW(i) - *baseIter.UVW(i); float delUVWSq = delUVWs[i].MagnitudeSquared(); if( delUVWSq > kMinDelUVW ) nonZero = true; else delUVWs[i].Set(0,0,0); } if( nonZero ) { // Append to deltas (i, del's) plVertDelta del; del.fIdx = iVert; del.fPos = delPos; del.fNorm = delNorm; deltas.Append(del); for( i = 0; i < numUVWs; i++ ) uvws.Append(delUVWs[i]); } else { nonZero = false; // Breakpoint. } iVert++; } SetDeltas(iSpan, deltas, numUVWs, uvws.AcquireArray()); } }
// // wireframe debug draw method. // doesn't use any fancy subdivision or curvature measure when drawing. // Changes current time. // void plAnimPath::IMakeSegment(hsTArray<uint16_t>& idx, hsTArray<hsPoint3>& pos, hsPoint3& p1, hsPoint3& p2) { hsVector3 del(&p2, &p1); hsVector3 up; up.Set(0,0,1.f); const float kOutLength = 0.25f; hsVector3 a = del % up; float magSq = a.MagnitudeSquared(); if( magSq < 1.e-3f ) { a.Set(kOutLength, 0, 0); } else { a *= hsFastMath::InvSqrtAppr(magSq); a *= kOutLength; } hsVector3 b = a % del; hsFastMath::Normalize(b); b *= kOutLength; hsPoint3 p1out, p2out; int baseIdx = pos.GetCount(); pos.Append(p1); pos.Append(p2); p1out = p1; p1out += a; p2out = p2; p2out += a; pos.Append(p1out); pos.Append(p2out); p1out += -2.f * a; p2out += -2.f * a; pos.Append(p1out); pos.Append(p2out); p1out = p1; p1out += b; p2out = p2; p2out += b; pos.Append(p1out); pos.Append(p2out); p1out += -2.f * b; p2out += -2.f * b; pos.Append(p1out); pos.Append(p2out); int i; for( i = 0; i < 4; i++ ) { int outIdx = baseIdx + 2 + i * 2; idx.Append(baseIdx); idx.Append(baseIdx + 1); idx.Append(baseIdx + outIdx); idx.Append(baseIdx + outIdx); idx.Append(baseIdx + 1); idx.Append(baseIdx + outIdx + 1); } }
hsBool plMorphSequence::MsgReceive(plMessage* msg) { plRenderMsg* rend = plRenderMsg::ConvertNoRef(msg); if( rend ) { // For now, I'm ignoring the target weight stuff for shared meshes. // Can always add it in later if desired. if( fTgtWgts.GetCount() ) { float delWgt = hsTimer::GetDelSysSeconds() / (kMorphTime > 0 ? kMorphTime : 1.e-3f); int i; for( i = 0; i < fTgtWgts.GetCount(); i++ ) { float currWgt = GetWeight(fTgtWgts[i].fLayer, fTgtWgts[i].fDelta); if( fTgtWgts[i].fWeight < currWgt ) { if( fTgtWgts[i].fWeight >= (currWgt -= delWgt) ) currWgt = fTgtWgts[i].fWeight; } else if( fTgtWgts[i].fWeight > currWgt ) { if( fTgtWgts[i].fWeight <= (currWgt += delWgt) ) currWgt = fTgtWgts[i].fWeight; } fMorphs[fTgtWgts[i].fLayer].SetWeight(fTgtWgts[i].fDelta, currWgt); if( fTgtWgts[i].fWeight == currWgt ) { fTgtWgts.Remove(i); i--; } } ISetDirty(true); } if( !(fMorphFlags & kDirty) ) { // We went a whole frame without getting dirty, // we can stop refreshing now. plgDispatch::Dispatch()->UnRegisterForExactType(plRenderMsg::Index(), GetKey()); return true; } ISetDirty(false); if( fMorphFlags & kDirtyIndices ) IFindIndices(); if( fMorphFlags & kHaveShared ) { IApplyShared(); } else { Apply(); } return true; } plSharedMeshBCMsg *smMsg = plSharedMeshBCMsg::ConvertNoRef(msg); if (smMsg) { if (IGetDrawInterface()->GetKey() == smMsg->GetSender() || IIsUsingDrawable(smMsg->fDraw)) fMorphFlags |= kDirtyIndices; } plGenRefMsg *refMsg = plGenRefMsg::ConvertNoRef(msg); if (refMsg) { plSharedMesh *mesh = plSharedMesh::ConvertNoRef(refMsg->GetRef()); if (mesh) { if( refMsg->GetContext() & (plRefMsg::kOnCreate|plRefMsg::kOnRequest) ) { AddSharedMesh(mesh); } else if( refMsg->GetContext() & plRefMsg::kOnReplace) { plSharedMesh *oldMesh = plSharedMesh::ConvertNoRef(refMsg->GetOldRef()); if (oldMesh) RemoveSharedMesh(oldMesh); AddSharedMesh(mesh); } else if( refMsg->GetContext() & (plRefMsg::kOnDestroy|plRefMsg::kOnRemove) ) RemoveSharedMesh(mesh); return true; } } return plSingleModifier::MsgReceive(msg); }
void plInterMeshSmooth::SetNormals(plSpanHandle& set, hsTArray<uint16_t>& shareVtx, hsVector3& norm) { int i; for( i = 0; i < shareVtx.GetCount(); i++ ) GetNormal(set, shareVtx[i]) = norm; }
uint32_t GetNumReceivers() const { return fReceivers.GetCount(); }