void plWin32StreamingSound::IStreamUpdate() { if(!fReallyPlaying) return; if(hsTimer::GetMilliSeconds() - fLastStreamingUpdate < STREAMING_UPDATE_MS) // filter out update requests so we aren't doing this more that we need to return; plProfile_BeginTiming( StreamSndShoveTime ); if(fDSoundBuffer) { if(fDSoundBuffer->BuffersQueued() == 0 && fDataStream->NumBytesLeft() == 0 && !fDSoundBuffer->IsLooping()) { // If we are fading out it's possible that we will hit this multiple times causing this sound to try and fade out multiple times, never allowing it to actually stop if(!fStopping) { fStopping = true; Stop(); plProfile_EndTiming( StreamSndShoveTime ); } return; } if(!fDSoundBuffer->StreamingFillBuffer(fDataStream)) { plStatusLog::AddLineS("audio.log", "%s Streaming buffer fill failed", GetKeyName().c_str()); } } plProfile_EndTiming( StreamSndShoveTime ); }
void plCoordinateInterface::ITransformChanged(hsBool force, uint16_t reasons, hsBool checkForDelay) { plProfile_IncCount(CITrans, 1); plProfile_BeginTiming(CITransT); // inherit reasons for transform change from our parents fReason |= reasons; uint16_t propagateReasons = fReason; hsBool process = !(checkForDelay && GetProperty(kDelayedTransformEval)) || !fDelayedTransformsEnabled; if (process) { if( fState & kTransformDirty ) force = true; } if( force ) { IRecalcTransforms(); plProfile_IncCount(CISet, 1); plProfile_BeginTiming(CISetT); if( IGetOwner() ) { IGetOwner()->ISetTransform(fLocalToWorld, fWorldToLocal); } plProfile_EndTiming(CISetT); fState &= ~kTransformDirty; } plProfile_EndTiming(CITransT); if (process) { int i; for( i = 0; i < fChildren.GetCount(); i++ ) { if( fChildren[i] && fChildren[i]->GetVolatileCoordinateInterface() ) fChildren[i]->GetVolatileCoordinateInterface()->ITransformChanged(force, propagateReasons, checkForDelay); } } else if (force) { plProfile_IncCount(CIDirty, 1); plProfile_BeginTiming(CITransT); // Our parent is dirty and we're bailing out on evaluating right now. // Need to ensure we'll be evaluated in the delay pass plProfile_BeginTiming(CIDirtyT); IDirtyTransform(); plProfile_EndTiming(CIDirtyT); plProfile_EndTiming(CITransT); } }
void plGBufferGroup::ISendStorageToBuffers( plPipeline *pipe, bool adjustForNvidiaLighting ) { plProfile_BeginTiming(DrawRefillVertex); /// Creating or refreshing? for (size_t i = 0; i < fVertBuffStorage.size(); i++) pipe->CheckVertexBufferRef(this, i); plProfile_EndTiming(DrawRefillVertex); plProfile_BeginTiming(DrawRefillIndex); for (size_t i = 0; i < fIdxBuffStorage.size(); i++) pipe->CheckIndexBufferRef(this, i); plProfile_EndTiming(DrawRefillIndex); }
void plPipelineViewSettings::RefreshCullTree() { if (fCullTreeDirty) { plProfile_BeginTiming(DrawOccBuild); fCullTree.Reset(); fCullTree.SetViewPos(GetViewPositionWorld()); if (fCullProxy && !fPipeline->IsDebugFlagSet(plPipeDbg::kFlagOcclusionSnap)) { fCullProxy->GetKey()->UnRefObject(); fCullProxy = nullptr; fDrawableTypeMask &= ~plDrawable::kOccSnapProxy; } bool doCullSnap = fPipeline->IsDebugFlagSet(plPipeDbg::kFlagOcclusionSnap) && !fCullProxy && !fPipeline->GetViewStackSize(); if( doCullSnap ) { fCullTree.BeginCapturePolys(); fCullTree.SetVisualizationYon(fTransform.GetYon()); } fCullTree.InitFrustum(fTransform.GetWorldToNDC()); fCullTreeDirty = false; if (fMaxCullNodes) { int i; for (i = 0; i < fCullPolys.GetCount(); i++) { fCullTree.AddPoly(*fCullPolys[i]); if (fCullTree.GetNumNodes() >= fMaxCullNodes) break; } fCullPolys.SetCount(0); plProfile_Set(OccPolyUsed, i); for (i = 0; i < fCullHoles.GetCount(); i++) { fCullTree.AddPoly(*fCullHoles[i]); } fCullHoles.SetCount(0); plProfile_Set(OccNodeUsed, fCullTree.GetNumNodes()); } if (doCullSnap) { fCullTree.EndCapturePolys(); MakeOcclusionSnap(); } plProfile_EndTiming(DrawOccBuild); } }
hsBool plAVIWriterImp::MsgReceive(plMessage* msg) { #if HS_BUILD_FOR_WIN32 plRenderMsg* renderMsg = plRenderMsg::ConvertNoRef(msg); if (renderMsg) { plProfile_BeginTiming(AviCapture); ICaptureFrame(renderMsg->Pipeline()); plProfile_EndTiming(AviCapture); } #endif return hsKeyedObject::MsgReceive(msg); }
void plCoordinateInterface::IRecalcTransforms() { plProfile_IncCount(CIRecalc, 1); plProfile_BeginTiming(CIRecalcT); if( fParent ) { fLocalToWorld = IMatrixMul34(fParent->GetLocalToWorld(), fLocalToParent); fWorldToLocal = IMatrixMul34(fParentToLocal, fParent->GetWorldToLocal()); } else { fLocalToWorld = fLocalToParent; fWorldToLocal = fParentToLocal; } plProfile_EndTiming(CIRecalcT); }
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 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); }
void pl3DPipeline::BeginVisMgr(plVisMgr* visMgr) { // Make Light Lists ///////////////////////////////////////////////////// // Look through all the current lights, and fill out two lists. // Only active lights (not disabled, not exactly black, and not // ignored because of visibility regions by plVisMgr) will // be considered. // The first list is lights that will affect the avatar and similar // indeterminately mobile (physical) objects - fCharLights. // The second list is lights that aren't restricted by light include // lists. // These two abbreviated lists will be further refined for each object // and avatar to find the strongest 8 lights which affect that object. // A light with an include list, or LightGroup Component) has // been explicitly told which objects it affects, so they don't // need to be in the search lists. // These lists are only constructed once per render, but searched // multiple times plProfile_BeginTiming(FindSceneLights); fCharLights.SetCount(0); fVisLights.SetCount(0); if (visMgr) { const hsBitVector& visSet = visMgr->GetVisSet(); const hsBitVector& visNot = visMgr->GetVisNot(); plLightInfo* light; for (light = fActiveLights; light != nullptr; light = light->GetNext()) { plProfile_IncCount(LightActive, 1); if (!light->IsIdle() && !light->InVisNot(visNot) && light->InVisSet(visSet)) { plProfile_IncCount(LightOn, 1); if (light->GetProperty(plLightInfo::kLPHasIncludes)) { if (light->GetProperty(plLightInfo::kLPIncludesChars)) fCharLights.Append(light); } else { fVisLights.Append(light); fCharLights.Append(light); } } } } else { plLightInfo* light; for (light = fActiveLights; light != nullptr; light = light->GetNext()) { plProfile_IncCount(LightActive, 1); if (!light->IsIdle()) { plProfile_IncCount(LightOn, 1); if (light->GetProperty(plLightInfo::kLPHasIncludes)) { if (light->GetProperty(plLightInfo::kLPIncludesChars)) fCharLights.Append(light); } else { fVisLights.Append(light); fCharLights.Append(light); } } } } plProfile_IncCount(LightVis, fVisLights.GetCount()); plProfile_IncCount(LightChar, fCharLights.GetCount()); plProfile_EndTiming(FindSceneLights); }
void hsAffineParts::ComposeInverseMatrix(hsMatrix44 *out) const { plProfile_BeginTiming(Compose); #ifndef PL_OPTIMIZE_COMPOSE // Built U matrix hsMatrix44 U; fU.Conjugate().MakeMatrix(&U); // Build scale factor matrix hsMatrix44 K; hsVector3 invK; invK.Set(hsInvert(fK.fX),hsInvert(fK.fY),hsInvert(fK.fZ)); K.MakeScaleMat(&invK); // Build Utranspose matrix hsMatrix44 Utp; U.GetTranspose(&Utp); // Build R matrix hsMatrix44 R; fQ.Conjugate().MakeMatrix(&R); // Build flip matrix // hsAssert(fF == 1.0 || fF == -1.0, "Invalid flip portion of affine parts"); hsMatrix44 F; if (fF==-1.0) { hsVector3 s; s.Set(-1,-1,-1); F.MakeScaleMat(&s); } else F.Reset(); // Build translate matrix hsMatrix44 T; T.MakeTranslateMat(&-fT); // // Concat mats // *out = Utp * K; *out = (*out) * U; *out = (*out) * R; *out = (*out) * F; *out = (*out) * T; #else // PL_OPTIMIZE_COMPOSE // Same kind of thing here, except now M = Ut K U R F T // and again // T = |1 0 0 Tx| // |0 1 0 Ty| // |0 0 1 Tz| // F = |f 0 0 0| // |0 f 0 0| // |0 0 f 0|, where f is either 1 or -1 // R = |R00 R01 R02 0| // |R10 R11 R12 0| // |R20 R21 R22 0| // U = |U00 U01 U02 0| // |U10 U11 U12 0| // |U20 U21 U22 0| // K = |Sx 0 0 0| // |0 Sy 0 0| // |0 0 Sz 0| // Ut = |U00 U10 U20 0| // |U01 U11 U21 0| // |U02 U12 U22 0|, where Uij is from matrix U // // So, Ut * K = // |U00*Sx U10*Sy U20*Sz 0| // |U01*Sx U11*Sy U21*Sz 0| // |U02*Sx U12*Sy U22*Sz 0| // // (Ut * K) * U = UK = // |Ut0*S dot Ut0 Ut0*S dot Ut1 Ut0*S dot Ut2 0| // |Ut1*S dot Ut0 Ut1*S dot Ut1 Ut1*S dot Ut2 0| // |Ut2*S dot Ut0 Ut2*S dot Ut1 Ut2*S dot Ut2 0| // // (((Ut * K) * U) * R)[i][j] = UK[i] dot Rc[j] // // Again we'll stuff the flip into the scale. // // Now, because the T is on the other end of the concat (closest // to the vertex), we can't just stuff it in. If Mr is the // rotation part of the final matrix (Ut * K * U * R * F), then // the translation components M[i][3] = Mr[i] dot T. // // hsVector3 Ut[3]; QuatTo3VectorsTranspose(fU.Conjugate(), Ut); int i, j; hsVector3 invK; invK.Set(hsInvert(fK.fX),hsInvert(fK.fY),hsInvert(fK.fZ)); hsVector3 UK[3]; for( i = 0; i < 3; i++ ) { for( j = 0; j < 3; j++ ) { // SUt[i] = (Ut[i].fX * invK.fX, Ut[i].fY * invK.fY, Ut[i].fZ * invK.fZ) // So SUt[i].InnerProduct(Ut[j]) == // Ut[i].fX * invK.fX * Ut[j].fX // + Ut[i].fY * invK.fY * Ut[j].fY // + Ut[i].fZ * invK.fZ * Ut[j].fZ UK[i][j] = Ut[i].fX * invK.fX * Ut[j].fX + Ut[i].fY * invK.fY * Ut[j].fY + Ut[i].fZ * invK.fZ * Ut[j].fZ; } } hsVector3 Rt[3]; QuatTo3VectorsTranspose(fQ.Conjugate(), Rt); float f = fF < 0 ? -1.f : 1.f; for( i = 0; i < 3; i++ ) { for( j = 0; j < 3; j++ ) { out->fMap[i][j] = UK[i].InnerProduct(Rt[j]) * f; } out->fMap[i][3] = -(fT.InnerProduct((hsPoint3*)(&out->fMap[i]))); } out->fMap[3][0] = out->fMap[3][1] = out->fMap[3][2] = 0.f; out->fMap[3][3] = 1.f; out->NotIdentity(); #endif // PL_OPTIMIZE_COMPOSE plProfile_EndTiming(Compose); }
// // Create an affine matrix from the various parts // // AffineParts: // Vector t; /* Translation components */ // Quat q; /* Essential rotation */ // Quat u; /* Stretch rotation */ // Vector k; /* Stretch factors */ // float f; /* Sign of determinant */ // // A matrix M is decomposed by : M = T F R U K Utranspose. // T is the translate mat. // F is +-Identity (to flip the rotation or not). // R is the rot matrix. // U is the stretch matrix. // K is the scale factor matrix. // void hsAffineParts::ComposeMatrix(hsMatrix44 *out) const { plProfile_BeginTiming(Compose); #ifndef PL_OPTIMIZE_COMPOSE // Built U matrix hsMatrix44 U; fU.MakeMatrix(&U); // Build scale factor matrix hsMatrix44 K; K.MakeScaleMat(&fK); // Build Utranspose matrix hsMatrix44 Utp; U.GetTranspose(&Utp); // Build R matrix hsMatrix44 R; fQ.MakeMatrix(&R); // Build flip matrix // hsAssert(fF == 1.0 || fF == -1.0, "Invalid flip portion of affine parts"); hsMatrix44 F; if (fF==-1.0) { hsVector3 s; s.Set(-1,-1,-1); F.MakeScaleMat(&s); } else F.Reset(); // Build translate matrix hsMatrix44 T; T.MakeTranslateMat(&fT); // // Concat mats // *out = K * Utp; *out = U * (*out); *out = R * (*out); // Q *out = F * (*out); *out = T * (*out); // Translate happens last #else // PL_OPTIMIZE_COMPOSE // M = T F R U K Ut, // but these are mostly very sparse matrices. So rather // than construct the full 6 matrices and concatenate them, // we'll work out by hand what the non-zero results will be. // T = |1 0 0 Tx| // |0 1 0 Ty| // |0 0 1 Tz| // F = |f 0 0 0| // |0 f 0 0| // |0 0 f 0|, where f is either 1 or -1 // R = |R00 R01 R02 0| // |R10 R11 R12 0| // |R20 R21 R22 0| // U = |U00 U01 U02 0| // |U10 U11 U12 0| // |U20 U21 U22 0| // K = |Sx 0 0 0| // |0 Sy 0 0| // |0 0 Sz 0| // Ut = |U00 U10 U20 0| // |U01 U11 U21 0| // |U02 U12 U22 0|, where Uij is from matrix U // // So, K * Ut = // |Sx*U00 Sx*U10 Sx*U20 0| // |Sy*U01 Sy*U11 Sy*U21 0| // |Sz*U02 Sz*U12 Sz*U22 0| // // U * (K * Ut) = // | U0 dot S*U0 U0 dot S*U1 U0 dot S*U2 0| // | U1 dot S*U0 U1 dot S*U1 U1 dot S*U2 0| // | U2 dot S*U0 U2 dot S*U1 U2 dot S*U2 0| // // Let's call that matrix UK // // Now R * U * K * Ut = R * UK = // | R0 dot UKc0 R0 dot UKc1 R0 dot UKc2 0| // | R1 dot UKc0 R1 dot UKc1 R1 dot UKc2 0| // | R2 dot UKc0 R2 dot UKc1 R2 dot UKc2 0|, where UKci is column i from UK // // if f is -1, we negate the matrix we have so far, else we don't. We can // accomplish this cleanly by just negating the scale vector S if f == -1. // // Since the translate is last, we can just stuff it into the 4th column. // // Since we only ever use UK as column vectors, we'll just construct it // into 3 vectors representing the columns. // // The quat MakeMatrix function is pretty efficient, but it does a little more work // than it has to filling out the whole matrix when we only need the 3x3 rotation, // and we'd rather have it in the form of vectors anyway, so we'll use our own // quat to 3 vectors function here. hsVector3 U[3]; QuatTo3Vectors(fU, U); int i, j; hsVector3 UKt[3]; for( i = 0; i < 3; i++ ) { for( j = 0; j < 3; j++ ) { // SU[j] = (fK.fX * U[j].fX, fK.fY * U[j].fY, fK.fZ * U[j].fZ) UKt[j][i] = U[i].fX * fK.fX * U[j].fX + U[i].fY * fK.fY * U[j].fY + U[i].fZ * fK.fZ * U[j].fZ; } } hsVector3 R[3]; QuatTo3Vectors(fQ, R); float f = fF < 0 ? -1.f : 1.f; for( i = 0; i < 3; i++ ) { for( j = 0; j < 3; j++ ) { out->fMap[i][j] = R[i].InnerProduct(UKt[j]) * f; } out->fMap[i][3] = fT[i]; } out->fMap[3][0] = out->fMap[3][1] = out->fMap[3][2] = 0.f; out->fMap[3][3] = 1.f; out->NotIdentity(); #endif // PL_OPTIMIZE_COMPOSE plProfile_EndTiming(Compose); }
hsBool plLOSDispatch::MsgReceive(plMessage* msg) { plLOSRequestMsg* requestMsg = plLOSRequestMsg::ConvertNoRef(msg); if (requestMsg) { plProfile_BeginTiming(LineOfSight); plSimulationMgr* sim = plSimulationMgr::GetInstance(); plKey worldKey = requestMsg->fWorldKey; if (!worldKey) { plArmatureMod* av = plAvatarMgr::GetInstance()->GetLocalAvatar(); if ( av && av->GetController() ) worldKey = av->GetController()->GetSubworld(); } hsPoint3 from = requestMsg->fFrom; hsPoint3 at = requestMsg->fTo; // requests are always sent in world space, but they might // need to be converted to subworld space hsMatrix44 l2w, w2l; if (worldKey) { plSceneObject* so = plSceneObject::ConvertNoRef(worldKey->ObjectIsLoaded()); if (so) { l2w = so->GetLocalToWorld(); w2l = so->GetWorldToLocal(); from = w2l * from; at = w2l * at; } } else { l2w.Reset(); w2l.Reset(); } NxScene* scene = sim->GetScene(worldKey); gMyReport.InitCast(requestMsg->GetRequestType(), requestMsg->GetTestType()); hsVector3 norm = hsVector3(at - from); float dist = norm.Magnitude(); norm.Normalize(); NxRay worldRay; worldRay.dir = plPXConvert::Vector(norm); worldRay.orig = plPXConvert::Point(from); //PhysX will complain to log if ray distance is less than or equal to Zero, besides shouldn't bother throwing // a point, and if we have negative we have some serious problems if(dist>0.0f) { scene->raycastAllShapes(worldRay, gMyReport, NX_ALL_SHAPES, 0xffffffff, dist, NX_RAYCAST_DISTANCE | NX_RAYCAST_IMPACT | NX_RAYCAST_NORMAL); } else{ SimLog("%s sent out a LOS request with a ray length of %d.", requestMsg->GetSender()->GetName().c_str(), dist); } if (gMyReport.GotHit()) { // We got a hit, save off the info plMessage* hitMsg = ICreateHitMsg(requestMsg, l2w); if (requestMsg->GetCullDB() != plSimDefs::kLOSDBNone) { // If we have a cull db, adjust the length of the raycast to be from the // original point to the object we hit. If we find anything from the cull // db in there, the cast fails. float dist = gMyReport.GetDistance(); if(dist!=0.0) { gMyReport.InitCast(requestMsg->GetCullDB(), plLOSRequestMsg::kTestAny); scene->raycastAllShapes(worldRay, gMyReport, NX_ALL_SHAPES, 0xffffffff, dist, NX_RAYCAST_DISTANCE | NX_RAYCAST_IMPACT | NX_RAYCAST_NORMAL); if (gMyReport.GotHit()) { delete hitMsg; hitMsg = nil; if (requestMsg->GetReportType() == plLOSRequestMsg::kReportMiss || requestMsg->GetReportType() == plLOSRequestMsg::kReportHitOrMiss) { ICreateMissMsg(requestMsg)->Send(); } } } else// we are right on top of the object I assume that means we hit it {// since PhysX would have complained we will log it anyways. Just so we have a better idea, where this //was happening previously SimLog("%s sent out a LOS request. The second cast for culling was of length 0. ABORTING and assuming hit.", requestMsg->GetSender()->GetName().c_str()); } } if (hitMsg && (requestMsg->GetReportType() == plLOSRequestMsg::kReportHit || requestMsg->GetReportType() == plLOSRequestMsg::kReportHitOrMiss)) hitMsg->Send(); } else { if (requestMsg->GetReportType() == plLOSRequestMsg::kReportMiss || requestMsg->GetReportType() == plLOSRequestMsg::kReportHitOrMiss) { ICreateMissMsg(requestMsg)->Send(); } } plProfile_EndTiming(LineOfSight); gMyReport.ResetHitObj(); return true; } return hsKeyedObject::MsgReceive(msg); }
void plWin32GroupedSound::IFillCurrentSound( int16_t newCurrent /*= -1*/ ) { //void *dataPtr; //uint32_t dataLength; if( !fDSoundBuffer && plgAudioSys::Active() ) LoadSound( IsPropertySet( kPropIs3DSound ) ); plProfile_BeginTiming( StaticSndShoveTime ); // Make sure we're stopped first. Don't want to be filling while we're playing Stop(); if( newCurrent != -1 ) { fCurrentSound = (uint16_t)newCurrent; if( fCurrentSound >= fStartPositions.GetCount() ) { // Invalid index! hsAssert( false, "Invalid index in plWin32GroupedSound::IFillCurrentSound()" ); fCurrentSound = -1; return; } // Set our length based on the current sound fCurrentSoundLength = IGetSoundbyteLength( fCurrentSound ); if( fDataBufferKey->ObjectIsLoaded() ) SetLength( fCurrentSoundLength / ((plSoundBuffer *)fDataBufferKey->ObjectIsLoaded())->GetHeader().fAvgBytesPerSec ); // Update our volume as well SetVolume( fVolumes[ fCurrentSound ] ); } if( fDSoundBuffer != nil ) { /// Lock our buffer //fDSoundBuffer->Lock( dataLength, dataPtr ); /// Copy or de-swizzle? //if( fDataBuffer->GetHeader().fNumChannels == fNumDestChannels ) { // Just copy //memcpy( dataPtr, (uint8_t *)fDataBuffer->GetData() + fStartPositions[ fCurrentSound ], fCurrentSoundLength ); //dataPtr = (uint8_t *)dataPtr + fCurrentSoundLength; //dataLength -= fCurrentSoundLength; } //else { // We're extracting a single channel of sound into our sound buffer, so it isn't a straight copy... /*plProfile_BeginTiming( StaticSwizzleTime ); plSoundDeswizzler deswiz( (uint8_t *)fDataBuffer->GetData() + fStartPositions[ fCurrentSound ], fCurrentSoundLength, (uint8_t)(fDataBuffer->GetHeader().fNumChannels), fNumDestBytesPerSample ); deswiz.Extract( fChannelSelect, dataPtr ); dataPtr = (uint8_t *)dataPtr + fCurrentSoundLength / fDataBuffer->GetHeader().fNumChannels; dataLength -= fCurrentSoundLength / fDataBuffer->GetHeader().fNumChannels; plProfile_EndTiming( StaticSwizzleTime );*/ } /// Fill the remaining part with empty space //memset( dataPtr, 0, dataLength ); /// Finally, unlock! //fDSoundBuffer->Unlock(); } /// All done! plProfile_EndTiming( StaticSndShoveTime ); }
void plDispatch::IMsgDispatch() { if( !fMsgDispatchLock.TryLock() ) return; if( fMsgActive ) { fMsgDispatchLock.Unlock(); return; } fMsgActive = true; int responseLevel=0; fMsgCurrentMutex.Lock(); plMsgWrap* origTail = fMsgTail; while((fMsgCurrent = fMsgHead)) { IDequeue(&fMsgHead, &fMsgTail); fMsgCurrentMutex.Unlock(); plMessage* msg = fMsgCurrent->fMsg; bool nonLocalMsg = msg && msg->HasBCastFlag(plMessage::kNetNonLocal); #ifdef HS_DEBUGGING int watchIdx = fMsgWatch.Find(msg); if( fMsgWatch.kMissingIndex != watchIdx ) { fMsgWatch.Remove(watchIdx); #if HS_BUILD_FOR_WIN32 __asm { int 3 } #endif // HS_BUILD_FOR_WIN32 } #endif // HS_DEBUGGING static uint64_t startTicks = 0; if (plDispatchLogBase::IsLogging()) startTicks = hsTimer::GetFullTickCount(); int i, numReceivers=0; for( i = 0; fMsgCurrent && i < fMsgCurrent->GetNumReceivers(); i++ ) { const plKey& rcvKey = fMsgCurrent->GetReceiver(i); plReceiver* rcv = rcvKey ? plReceiver::ConvertNoRef(rcvKey->ObjectIsLoaded()) : nil; if( rcv ) { if (nonLocalMsg) { // localOnly objects should not get remote messages plSynchedObject* synchedObj = plSynchedObject::ConvertNoRef(rcv); if (synchedObj && !synchedObj->IsNetSynched() ) { continue; } if (plNetObjectDebuggerBase::GetInstance()) { // log net msg if this is a debug object hsKeyedObject* ko = hsKeyedObject::ConvertNoRef(rcv); if (plNetObjectDebuggerBase::GetInstance()->IsDebugObject(ko)) { hsLogEntry(plNetObjectDebuggerBase::GetInstance()->LogMsg( plString::Format("<RCV> object:%s, GameMessage %s st=%.3f rt=%.3f", ko->GetKeyName().c_str(), msg->ClassName(), hsTimer::GetSysSeconds(), hsTimer::GetSeconds()).c_str())); } } } #ifndef PLASMA_EXTERNAL_RELEASE uint32_t rcvTicks = hsTimer::GetPrecTickCount(); // Object could be deleted by this message, so we need to log this stuff now plString keyname = "(unknown)"; const char* className = "(unknown)"; uint32_t clonePlayerID = 0; if (plDispatchLogBase::IsLoggingLong()) { hsKeyedObject* ko = hsKeyedObject::ConvertNoRef(rcv); if (ko) { keyname = ko->GetKeyName(); clonePlayerID = ko->GetKey()->GetUoid().GetClonePlayerID(); className = ko->ClassName(); } } #endif // PLASMA_EXTERNAL_RELEASE #ifdef HS_DEBUGGING if (msg->GetBreakBeforeDispatch()) DebugBreakIfDebuggerPresent(); #endif plProfile_BeginTiming(MsgReceive); rcv->MsgReceive(msg); plProfile_EndTiming(MsgReceive); #ifndef PLASMA_EXTERNAL_RELEASE if (plDispatchLogBase::IsLoggingLong()) { rcvTicks = hsTimer::GetPrecTickCount() - rcvTicks; float rcvTime = (float)(hsTimer::PrecTicksToSecs(rcvTicks) * 1000.f); // If the receiver takes more than 5 ms to process its message, log it if (rcvTime > 5.f) plDispatchLogBase::GetInstance()->LogLongReceive(keyname.c_str(), className, clonePlayerID, msg, rcvTime); } #endif // PLASMA_EXTERNAL_RELEASE numReceivers++; if (fMsgRecieveCallback != nil) fMsgRecieveCallback(); } } // for message logging // if (plDispatchLogBase::IsLogging()) // { // float sendTime = hsTimer::FullTicksToMs(hsTimer::GetFullTickCount() - startTicks); // // plDispatchLogBase::GetInstance()->DumpMsg(msg, numReceivers, (int)sendTime, responseLevel*2 /* indent */); // if (origTail==fMsgCurrent) // { // if we deliver more msgs after this, they must be response msgs // responseLevel++; // origTail = fMsgTail; // } // } fMsgCurrentMutex.Lock(); delete fMsgCurrent; // TEMP fMsgCurrent = (class plMsgWrap *)0xdeadc0de; }
void plSimulationMgr::Advance(float delSecs) { if (fSuspended) return; fAccumulator += delSecs; if (fAccumulator < kDefaultStepSize) { // Not enough time has passed to perform a substep. plPXPhysicalControllerCore::UpdateNonPhysical(fAccumulator / kDefaultStepSize); return; } else if (fAccumulator > kDefaultMaxDelta) { if (fExtraProfile) Log("Step clamped from %f to limit of %f", fAccumulator, kDefaultMaxDelta); fAccumulator = kDefaultMaxDelta; } ++fStepCount; // Perform as many whole substeps as possible saving the remainder in our accumulator. int numSubSteps = (int)(fAccumulator / kDefaultStepSize + 0.000001f); float delta = numSubSteps * kDefaultStepSize; fAccumulator -= delta; plProfile_IncCount(StepLen, (int)(delta*1000)); plProfile_BeginTiming(Step); plPXPhysicalControllerCore::Apply(delta); for (SceneMap::iterator it = fScenes.begin(); it != fScenes.end(); it++) { NxScene* scene = it->second; bool do_advance = true; if (fSubworldOptimization) { plKey world = (plKey)it->first; if (world == GetKey()) world = nil; do_advance = plPXPhysicalControllerCore::AnyControllersInThisWorld(world); } if (do_advance) { scene->simulate(delta); scene->flushStream(); scene->fetchResults(NX_RIGID_BODY_FINISHED, true); } } plPXPhysicalControllerCore::Update(numSubSteps, fAccumulator / kDefaultStepSize); plProfile_EndTiming(Step); #ifndef PLASMA_EXTERNAL_RELEASE if(plSimulationMgr::fDisplayAwakeActors)IDrawActiveActorList(); #endif if (fExtraProfile) { int contacts = 0, dynActors = 0, dynShapes = 0, awake = 0, stShapes=0, actors=0, scenes=0, controllers=0 ; for (SceneMap::iterator it = fScenes.begin(); it != fScenes.end(); it++) { bool do_advance = true; if (fSubworldOptimization) { plKey world = (plKey)it->first; if (world == GetKey()) world = nil; do_advance = plPXPhysicalControllerCore::AnyControllersInThisWorld(world); } if (do_advance) { NxScene* scene = it->second; NxSceneStats stats; scene->getStats(stats); contacts += stats.numContacts; dynActors += stats.numDynamicActors; dynShapes += stats.numDynamicShapes; awake += stats.numDynamicActorsInAwakeGroups; stShapes += stats.numStaticShapes; actors += stats.numActors; scenes += 1; controllers += plPXPhysicalControllerCore::NumControllers(); } } plProfile_IncCount(Awake, awake); plProfile_IncCount(Contacts, contacts); plProfile_IncCount(DynActors, dynActors); plProfile_IncCount(DynShapes, dynShapes); plProfile_IncCount(StaticShapes, stShapes); plProfile_IncCount(Actors, actors); plProfile_IncCount(Scenes, scenes); plProfile_IncCount(Controllers, controllers); } plProfile_IncCount(AnimatedPhysicals, plPXPhysical::fNumberAnimatedPhysicals); plProfile_IncCount(AnimatedActivators, plPXPhysical::fNumberAnimatedActivators); fSoundMgr->Update(); plProfile_BeginTiming(ProcessSyncs); IProcessSynchs(); plProfile_EndTiming(ProcessSyncs); plProfile_BeginTiming(UpdateContexts); ISendUpdates(); plProfile_EndTiming(UpdateContexts); }
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 plSimulationMgr::Advance(float delSecs) { if (fSuspended) return; plProfile_IncCount(StepLen, (int)(delSecs*1000)); #ifndef PLASMA_EXTERNAL_RELASE uint32_t stepTime = hsTimer::GetPrecTickCount(); #endif plProfile_BeginTiming(Step); plPXPhysicalControllerCore::UpdatePrestep(delSecs); plPXPhysicalControllerCore::UpdatePoststep( delSecs); for (SceneMap::iterator it = fScenes.begin(); it != fScenes.end(); it++) { NxScene* scene = it->second; bool do_advance = true; if (fSubworldOptimization) { plKey world = (plKey)it->first; if (world == GetKey()) world = nil; do_advance = plPXPhysicalControllerCore::AnyControllersInThisWorld(world); } if (do_advance) { scene->simulate(delSecs); scene->flushStream(); scene->fetchResults(NX_RIGID_BODY_FINISHED, true); } } plPXPhysicalControllerCore::UpdatePostSimStep(delSecs); plProfile_EndTiming(Step); #ifndef PLASMA_EXTERNAL_RELEASE if(plSimulationMgr::fDisplayAwakeActors)IDrawActiveActorList(); #endif if (fExtraProfile) { int contacts = 0, dynActors = 0, dynShapes = 0, awake = 0, stShapes=0, actors=0, scenes=0, controllers=0 ; for (SceneMap::iterator it = fScenes.begin(); it != fScenes.end(); it++) { bool do_advance = true; if (fSubworldOptimization) { plKey world = (plKey)it->first; if (world == GetKey()) world = nil; do_advance = plPXPhysicalControllerCore::AnyControllersInThisWorld(world); } if (do_advance) { NxScene* scene = it->second; NxSceneStats stats; scene->getStats(stats); contacts += stats.numContacts; dynActors += stats.numDynamicActors; dynShapes += stats.numDynamicShapes; awake += stats.numDynamicActorsInAwakeGroups; stShapes += stats.numStaticShapes; actors += stats.numActors; scenes += 1; controllers += plPXPhysicalControllerCore::NumControllers(); } } plProfile_IncCount(Awake, awake); plProfile_IncCount(Contacts, contacts); plProfile_IncCount(DynActors, dynActors); plProfile_IncCount(DynShapes, dynShapes); plProfile_IncCount(StaticShapes, stShapes); plProfile_IncCount(Actors, actors); plProfile_IncCount(Scenes, scenes); plProfile_IncCount(Controllers, controllers); } plProfile_IncCount(AnimatedPhysicals, plPXPhysical::fNumberAnimatedPhysicals); plProfile_IncCount(AnimatedActivators, plPXPhysical::fNumberAnimatedActivators); fSoundMgr->Update(); plProfile_BeginTiming(ProcessSyncs); IProcessSynchs(); plProfile_EndTiming(ProcessSyncs); plProfile_BeginTiming(UpdateContexts); ISendUpdates(); plProfile_EndTiming(UpdateContexts); }
bool plWin32StaticSound::LoadSound( bool is3D ) { if (fFailed) return false; if( fPriority > plgAudioSys::GetPriorityCutoff() ) return false; // Don't set the failed flag, just return if (plgAudioSys::Active() && !fDSoundBuffer) { // Debug flag #1 if( fChannelSelect > 0 && plgAudioSys::IsDebugFlagSet( plgAudioSys::kDisableRightSelect ) ) { // Force a fail fFailed = true; return false; } // We need it to be resident to read in plSoundBuffer::ELoadReturnVal retVal = IPreLoadBuffer(true); plSoundBuffer *buffer = (plSoundBuffer *)fDataBufferKey->ObjectIsLoaded(); if(!buffer) { return plSoundBuffer::kError; } if( retVal == plSoundBuffer::kPending) // we are still reading data. { return true; } if( retVal == plSoundBuffer::kError ) { plString str = plFormat("Unable to open .wav file {}", fDataBufferKey ? fDataBufferKey->GetName() : "nil"); IPrintDbgMessage( str.c_str(), true ); fFailed = true; return false; } SetProperty( kPropIs3DSound, is3D ); plWAVHeader header = buffer->GetHeader(); // Debug flag #2 if( fChannelSelect == 0 && header.fNumChannels > 1 && plgAudioSys::IsDebugFlagSet( plgAudioSys::kDisableLeftSelect ) ) { // Force a fail fFailed = true; return false; } uint32_t bufferSize = buffer->GetDataLength(); if( header.fNumChannels > 1 && is3D ) { // We can only do a single channel of 3D sound. So copy over one (later) bufferSize /= header.fNumChannels; header.fBlockAlign /= header.fNumChannels; header.fAvgBytesPerSec /= header.fNumChannels; header.fNumChannels = 1; } bool tryStatic = true; // If we want FX, we can't use a static voice, but EAX doesn't fit under that limitation :) if( 0 ) tryStatic = false; // Create our DSound buffer (or rather, the wrapper around it) fDSoundBuffer = new plDSoundBuffer( bufferSize, header, is3D, IsPropertySet( kPropLooping ), tryStatic ); if( !fDSoundBuffer->IsValid() ) { plString str = plFormat("Can't create sound buffer for {}.wav. This could happen if the wav file is a stereo file." " Stereo files are not supported on 3D sounds. If the file is not stereo then please report this error.", GetFileName()); IPrintDbgMessage(str.c_str(), true); fFailed = true; delete fDSoundBuffer; fDSoundBuffer = nil; return false; } plProfile_BeginTiming( StaticSndShoveTime ); if(!fDSoundBuffer->FillBuffer(buffer->GetData(), buffer->GetDataLength(), &header)) { delete fDSoundBuffer; fDSoundBuffer = nil; plStatusLog::AddLineS("audio.log", "Could not play static sound, no voices left %s", GetKeyName().c_str()); return false; } plProfile_EndTiming( StaticSndShoveTime ); IRefreshEAXSettings( true ); fTotalBytes = bufferSize; plProfile_NewMem(MemSounds, fTotalBytes); // get pertinent info float length = (float)bufferSize / (float)header.fAvgBytesPerSec; SetLength(length); if( fLoadFromDiskOnDemand && !IsPropertySet( kPropLoadOnlyOnCall ) ) FreeSoundData(); return true; } return false; }