LTBOOL CWeatherFX::Update() { // Make sure we're supposed to be here... if (m_bWantRemove || !m_hServerObject) return LTFALSE; // Determine what type of surface this brush is on top of. if (m_bFirstUpdate) { m_bFirstUpdate = LTFALSE; ClientIntersectQuery iQuery; ClientIntersectInfo iInfo; iQuery.m_Flags = INTERSECT_OBJECTS | INTERSECT_HPOLY | IGNORE_NONSOLID; iQuery.m_From = m_vPos; iQuery.m_To = m_vPos; iQuery.m_To.y = m_fFloorY - 100; if (m_pClientDE->IntersectSegment(&iQuery, &iInfo)) { m_eSurfaceType = GetSurfaceType(iInfo); // Create splash sprites if necessary... if (m_dwFlags & WFLAG_RAIN) { CreateSplashSprites(); } } } // Update Snow... if (m_dwFlags & WFLAG_SNOW) { HOBJECT hObj = m_Snow.GetObject(); if (hObj) { bool bEnable = GetConsoleInt("EnableWeatherFX",1) != 0; if (bEnable) { m_Snow.Update(); } g_pCommonLT->SetObjectFlags(hObj, OFT_Flags, bEnable ? FLAG_VISIBLE : 0, FLAG_VISIBLE); } } // Update Rain... if (m_dwFlags & WFLAG_RAIN) { HOBJECT hObj = m_Rain.GetObject(); if (hObj) { bool bEnable = GetConsoleInt("EnableWeatherFX",1) != 0; if (bEnable) { m_Rain.Update(); } g_pCommonLT->SetObjectFlags(hObj, OFT_Flags, bEnable ? FLAG_VISIBLE : 0, FLAG_VISIBLE); } // Get the camera's position...Make rain systems far away from the // camera more transparent... HOBJECT hCamera = g_pPlayerMgr->GetCamera(); if (!hCamera) return LTFALSE; LTVector vCamPos, vDist, vPos; g_pLTClient->GetObjectPos(m_Rain.GetObject(), &vPos); g_pLTClient->GetObjectPos(hCamera, &vCamPos); vCamPos.y = vPos.y; // Only wory about X and Z vDist = vCamPos - vPos; LTFLOAT fDistSqr = vDist.MagSqr(); LTFLOAT fFullAlphaSqr = (RAIN_FULL_ALPHA_SCALE_DIST*RAIN_FULL_ALPHA_SCALE_DIST); LTFLOAT fMinAlphaSqr = (RAIN_MIN_ALPHA_SCALE_DIST*RAIN_MIN_ALPHA_SCALE_DIST); LTFLOAT r, g, b, a; m_pClientDE->GetObjectColor(m_Rain.GetObject(), &r, &g, &b, &a); if (fDistSqr <= fFullAlphaSqr) { a = RAIN_MAX_ALPHA; // Full alpha } else // Calculate new alpha { LTFLOAT fDistOffset = fDistSqr - fFullAlphaSqr; LTFLOAT fTotalDist = fMinAlphaSqr - fFullAlphaSqr; a = RAIN_MAX_ALPHA - ((RAIN_MAX_ALPHA - RAIN_MIN_ALPHA) * (fDistOffset / fTotalDist)); a = a < RAIN_MIN_ALPHA ? RAIN_MIN_ALPHA : a; } m_pClientDE->SetObjectColor(m_Rain.GetObject(), r, g, b, a); // Update Splash fx... hObj = LTNULL; for (int i=0; i < NUM_SPLASH_SPRITES; i++) { hObj = m_Splash[i].GetObject(); if (hObj) { uint32 dwFlags; g_pCommonLT->GetObjectFlags(hObj, OFT_Flags, dwFlags); if (dwFlags & FLAG_VISIBLE) { if (!m_Splash[i].Update()) { // If the sprite is done, hide it... g_pCommonLT->SetObjectFlags(hObj, OFT_Flags, 0, FLAG_VISIBLE); } } } } } return LTTRUE; }
void CWeaponFX::CreateBloodSplatFX() { CGameSettings* pSettings = g_pInterfaceMgr->GetSettings(); if (!pSettings || !pSettings->Gore()) return; CSFXMgr* psfxMgr = g_pGameClientShell->GetSFXMgr(); if (!psfxMgr) return; CSpecialFX* pFX = LTNULL; LTFLOAT fRange = g_vtBloodSplatsRange.GetFloat(); // See if we should make some blood splats... ClientIntersectQuery iQuery; IntersectInfo iInfo; iQuery.m_From = m_vPos; LTVector vDir = m_vDir; // Create some blood splats... int nNumSplats = GetRandom((int)g_vtBloodSplatsMinNum.GetFloat(), (int)g_vtBloodSplatsMaxNum.GetFloat()); LTVector vU, vR, vF; g_pLTClient->GetRotationVectors(&m_rDirRot, &vU, &vR, &vF); for (int i=0; i < nNumSplats; i++) { LTVector vDir = m_vDir; // Perturb direction after first splat... if (i > 0) { float fPerturb = g_vtBloodSplatsPerturb.GetFloat(); float fRPerturb = (GetRandom(-fPerturb, fPerturb))/1000.0f; float fUPerturb = (GetRandom(-fPerturb, fPerturb))/1000.0f; vDir += (vR * fRPerturb); vDir += (vU * fUPerturb); } iQuery.m_To = vDir * fRange; iQuery.m_To += m_vPos; iQuery.m_Flags = IGNORE_NONSOLID | INTERSECT_HPOLY; if (g_pLTClient->IntersectSegment(&iQuery, &iInfo) && IsMainWorld(iInfo.m_hObject)) { SurfaceType eType = GetSurfaceType(iInfo); if (eType == ST_SKY || eType == ST_INVISIBLE) { return; // Don't leave blood on the sky } LTBOOL bBigBlood = (LTBOOL)GetConsoleInt("BigBlood", 0); // Create a blood splat... BSCREATESTRUCT sc; g_pLTClient->AlignRotation(&(sc.rRot), &(iInfo.m_Plane.m_Normal), LTNULL); // Randomly rotate the blood splat g_pLTClient->RotateAroundAxis(&(sc.rRot), &(iInfo.m_Plane.m_Normal), GetRandom(0.0f, MATH_CIRCLE)); LTVector vTemp = vDir * -2.0f; sc.vPos = iInfo.m_Point + vTemp; // Off the wall a bit sc.vVel.Init(0.0f, 0.0f, 0.0f); sc.vInitialScale.Init(1.0f, 1.0f, 1.0f); sc.vInitialScale.x = GetRandom(g_vtBloodSplatsMinScale.GetFloat(), g_vtBloodSplatsMaxScale.GetFloat()); if (bBigBlood) sc.vInitialScale.x *= g_vtBigBloodSizeScale.GetFloat(); sc.vInitialScale.y = sc.vInitialScale.x; sc.vFinalScale = sc.vInitialScale; sc.dwFlags = FLAG_VISIBLE | FLAG_ROTATEABLESPRITE | FLAG_NOLIGHT; sc.fLifeTime = GetRandom(g_vtBloodSplatsMinLifetime.GetFloat(), g_vtBloodSplatsMaxLifetime.GetFloat()); if (bBigBlood) sc.fLifeTime *= g_vtBigBloodLifeScale.GetFloat(); sc.fInitialAlpha = 1.0f; sc.fFinalAlpha = 0.0f; sc.nType = OT_SPRITE; sc.bMultiply = LTTRUE; char* pBloodFiles[] = { "Sfx\\Test\\Spr\\BloodL1.spr", "Sfx\\Test\\Spr\\BloodL2.spr", "Sfx\\Test\\Spr\\BloodL3.spr", "Sfx\\Test\\Spr\\BloodL4.spr" }; sc.pFilename = pBloodFiles[GetRandom(0,3)]; pFX = psfxMgr->CreateSFX(SFX_SCALE_ID, &sc); if (pFX) pFX->Update(); } else if (i==0) { // Didn't hit anything straight back, do don't bother to // do anymore... return; } } }
void CDestructibleModel::SetSurfaceType() { uint32 dwSurfUsrFlgs = 0; SurfaceType eSurfType = ST_UNKNOWN; // See if this object is a world model... if (GetObjectType(m_hObject) == OT_WORLDMODEL) { LTBOOL bDoBruteForce = LTTRUE; // See if we have a surface override... if (m_hstrSurfaceOverride) { const char* pSurfName = g_pLTServer->GetStringData(m_hstrSurfaceOverride); if (pSurfName) { SURFACE* pSurf = g_pSurfaceMgr->GetSurface(pSurfName); if (pSurf && pSurf->eType != ST_UNKNOWN) { eSurfType = pSurf->eType; bDoBruteForce = LTFALSE; } } } // Determine our surface...the hard way... if (bDoBruteForce) { IntersectQuery qInfo; IntersectInfo iInfo; LTVector vPos, vDims; LTRotation rRot; g_pLTServer->GetObjectPos(m_hObject, &vPos); g_pLTServer->GetObjectRotation(m_hObject, &rRot); g_pPhysicsLT->GetObjectDims(m_hObject, &vDims); LTFLOAT fMaxDims = vDims.x; fMaxDims = Max(fMaxDims, vDims.y); fMaxDims = Max(fMaxDims, vDims.z); qInfo.m_From = vPos + (rRot.Forward() * (fMaxDims + 1)); qInfo.m_To = vPos; qInfo.m_Flags = INTERSECT_OBJECTS | IGNORE_NONSOLID | INTERSECT_HPOLY; SurfaceType eType = ST_UNKNOWN; if (g_pLTServer->IntersectSegment(&qInfo, &iInfo)) { if (iInfo.m_hObject == m_hObject) { eSurfType = GetSurfaceType(iInfo); } } } } else { DEBRIS* pDebris = g_pDebrisMgr->GetDebris(m_nDebrisId); if (pDebris) { eSurfType = pDebris->eSurfaceType; } } dwSurfUsrFlgs = SurfaceToUserFlag(eSurfType); g_pCommonLT->SetObjectFlags(m_hObject, OFT_User, dwSurfUsrFlgs, dwSurfUsrFlgs); g_pCommonLT->GetObjectFlags(m_hObject, OFT_Flags, m_dwOriginalFlags); }
LTBOOL CShellCasingFX::Update() { if (!m_hObject || !m_pClientDE) return LTFALSE; if (g_pGameClientShell->IsServerPaused()) { return LTTRUE; } m_fElapsedTime += g_pGameClientShell->GetFrameTime(); m_fDieTime -= g_pGameClientShell->GetFrameTime(); if (m_fDieTime <= 0.0f) return LTFALSE; // Update object scale if necessary... LTVector vScale; m_pClientDE->GetObjectScale(m_hObject, &vScale); if (vScale != m_vFinalScale) { if (m_fElapsedTime <= g_vtShellScaleTime.GetFloat()) { LTVector vScaleRange = (m_vFinalScale - m_vInitialScale); vScale = m_vInitialScale + (vScaleRange * (m_fElapsedTime/g_vtShellScaleTime.GetFloat())); if (vScale > m_vFinalScale) { vScale = m_vFinalScale; } m_pClientDE->SetObjectScale(m_hObject, &vScale); } else { m_pClientDE->SetObjectScale(m_hObject, &m_vFinalScale); } } if (m_bResting) return LTTRUE; LTRotation rRot; g_pLTClient->GetObjectRotation(m_hObject, &rRot); // If velocity slows enough, and we're on the ground, just stop bouncing and just wait to expire. if (m_movingObj.m_dwPhysicsFlags & MO_RESTING) { m_bResting = LTTRUE; // Stop the spinning... rRot.Rotate(rRot.Up(), m_fYaw); g_pLTClient->SetObjectRotation(m_hObject, &rRot); // Shell is at rest, we can add a check here to see if we really want // to keep it around depending on detail settings... //HLOCALOBJ hObjs[1]; //uint32 nNumFound, nBogus; //m_pClientDE->FindObjectsInSphere(&m_movingObj.m_vPos, 64.0f, hObjs, 1, &nBogus, &nNumFound); // Remove thyself... //if (nNumFound > 15) return LTFALSE; } else { if (m_fPitchVel != 0 || m_fYawVel != 0) { LTFLOAT fDeltaTime = g_pGameClientShell->GetFrameTime(); m_fPitch += m_fPitchVel * fDeltaTime; m_fYaw += m_fYawVel * fDeltaTime; rRot.Rotate(rRot.Up(), m_fYaw); rRot.Rotate(rRot.Right(), m_fPitch); g_pLTClient->SetObjectRotation(m_hObject, &rRot); } } LTVector vNewPos; if (UpdateMovingObject(LTNULL, &m_movingObj, vNewPos)) { ClientIntersectInfo info; LTBOOL bBouncedOnGround = LTFALSE; if (BounceMovingObject(LTNULL, &m_movingObj, vNewPos, &info, INTERSECT_HPOLY, true, bBouncedOnGround)) { // If we hit the sky/invisible surface we're done... SurfaceType eType = GetSurfaceType(info); if (eType == ST_SKY || eType == ST_INVISIBLE) { return LTFALSE; } if (m_nBounceCount >= MAX_BOUNCE_COUNT) { if (!(m_movingObj.m_dwPhysicsFlags & MO_LIQUID)) { SURFACE* pSurf = g_pSurfaceMgr->GetSurface(eType); if (pSurf) { // Play appropriate sound... if (pSurf->szShellImpactSnds[0]) { g_pClientSoundMgr->PlaySoundFromPos(vNewPos, pSurf->szShellImpactSnds[0], pSurf->fShellSndRadius, SOUNDPRIORITY_MISC_LOW); } } } } // Adjust the bouncing.. m_fPitchVel *= 0.75f; m_fYawVel *= -0.75f; m_nBounceCount--; if (m_nBounceCount <= 0) { m_movingObj.m_dwPhysicsFlags |= MO_RESTING; } } m_movingObj.m_vPos = vNewPos; if (g_pCommonLT->GetPointStatus(&vNewPos) == LT_OUTSIDE) { return LTFALSE; } g_pLTClient->SetObjectPos(m_hObject, &vNewPos); } return LTTRUE; }
void CTargetMgr::CheckForIntersect(float &fDistAway) { m_hTarget = LTNULL; m_ActivationData.Init(); uint32 dwUsrFlags = 0; const float fMaxDist = 100000.0f; // Cast ray from the camera to see if there is an object to activate... LTRotation rRot; LTVector vPos; HLOCALOBJ hCamera = g_pPlayerMgr->GetCamera(); g_pLTClient->GetObjectPos(hCamera, &vPos); g_pLTClient->GetObjectRotation(hCamera, &rRot); m_ActivationData.m_vPos = vPos; m_ActivationData.m_rRot = rRot; IntersectQuery IQuery; IntersectInfo IInfo; IQuery.m_From = vPos; IQuery.m_To = IQuery.m_From + (rRot.Forward() * fMaxDist); // NOTE the use of the CHECK_FROM_POINT_INSIDE_OBJECTS flag. This flag will // make sure that any objects that m_From is inside are considered IQuery.m_Flags = CHECK_FROM_POINT_INSIDE_OBJECTS | INTERSECT_HPOLY | INTERSECT_OBJECTS | IGNORE_NONSOLID; IQuery.m_FilterActualIntersectFn = ActivateFilterFn; IQuery.m_pActualIntersectUserData = (void*)&IQuery; IQuery.m_PolyFilterFn = DoVectorPolyFilterFn; // [KLS 8/3/02] - ActivateFilterFn may save an object to use that may not be // the best activation choice (i.e., a fallback choice). However, if a // better choice isn't found, the fallback choice should be used. That // fallback choice is stored in g_adFallbackActivationObject so we clear // it here... g_adFallbackActivationObject.Init(); if (g_pLTClient->IntersectSegment(&IQuery, &IInfo)) { m_ActivationData.m_vIntersect = IInfo.m_Point; if (IsMainWorld(IInfo.m_hObject)) { if (IInfo.m_hPoly != INVALID_HPOLY) { SurfaceType eType = GetSurfaceType(IInfo.m_hPoly); SURFACE *pSurf = g_pSurfaceMgr->GetSurface(eType); // See if the surface we tried to activate has an activation // sound...If so, the user can activate it... if (pSurf && pSurf->szActivationSnd[0] && pSurf->fActivationSndRadius > 0) { m_hTarget = IInfo.m_hObject; m_ActivationData.m_hTarget = m_hTarget; m_ActivationData.m_nSurfaceType = eType; } } } else { LTVector vObjPos = m_ActivationData.m_vIntersect; vObjPos -= vPos; if (vObjPos.Mag() <= fMaxDist) { m_hTarget = IInfo.m_hObject; m_ActivationData.m_hTarget = m_hTarget; } } // Calculate how far away the object is... LTVector vDist = m_ActivationData.m_vIntersect - vPos; fDistAway = vDist.Mag(); } // [KLS 8/3/02] - Use the fallback object if we have one and we didn't // find another object more suitable object... bool bCanUseFallback = (m_ActivationData.m_hTarget ? false : true); if (!bCanUseFallback) { // We can still use the fallback object if it isn't the world or a // world model... if (IsMainWorld(m_ActivationData.m_hTarget) || OT_WORLDMODEL == GetObjectType(m_ActivationData.m_hTarget)) { bCanUseFallback = true; } } if ( bCanUseFallback && g_adFallbackActivationObject.m_hTarget ) { // Ok we hit the fallback object reset some of our target data LTVector vObjPos; g_pLTClient->GetObjectPos(g_adFallbackActivationObject.m_hTarget, &vObjPos); m_ActivationData.m_vIntersect = vObjPos; vObjPos -= vPos; if (vObjPos.Mag() <= fMaxDist) { m_hTarget = g_adFallbackActivationObject.m_hTarget; m_ActivationData.m_hTarget = m_hTarget; } // Calculate how far away the object is... LTVector vDist = m_ActivationData.m_vIntersect - vPos; fDistAway = vDist.Mag(); } }
void CProjectileFX::Detonate(CollisionInfo* pInfo) { if (!m_pClientDE || m_bDetonated) return; m_bDetonated = LTTRUE; SurfaceType eType = ST_UNKNOWN; LTVector vPos; m_pClientDE->GetObjectPos(m_hServerObject, &vPos); // Determine the normal of the surface we are impacting on... LTVector vNormal; VEC_SET(vNormal, 0.0f, 1.0f, 0.0f); if (pInfo) { if (pInfo->m_hObject) { eType = GetSurfaceType(pInfo->m_hObject); } else if (pInfo->m_hPoly) { eType = GetSurfaceType(pInfo->m_hPoly); VEC_COPY(vNormal, pInfo->m_Plane.m_Normal); LTRotation rRot; m_pClientDE->AlignRotation(&rRot, &vNormal, LTNULL); m_pClientDE->SetObjectRotation(m_hServerObject, &rRot); // Calculate where we really hit the plane... LTVector vVel, vP0, vP1; m_pClientDE->Physics()->GetVelocity(m_hServerObject, &vVel); VEC_COPY(vP1, vPos); VEC_MULSCALAR(vVel, vVel, g_pGameClientShell->GetFrameTime()); VEC_SUB(vP0, vP1, vVel); LTFLOAT fDot1 = VEC_DOT(pInfo->m_Plane.m_Normal, vP0) - pInfo->m_Plane.m_Dist; LTFLOAT fDot2 = VEC_DOT(pInfo->m_Plane.m_Normal, vP1) - pInfo->m_Plane.m_Dist; if (fDot1 < 0.0f && fDot2 < 0.0f || fDot1 > 0.0f && fDot2 > 0.0f) { VEC_COPY(vPos, vP1); } else { LTFLOAT fPercent = -fDot1 / (fDot2 - fDot1); VEC_LERP(vPos, vP0, vP1, fPercent); } } } else { // Since pInfo was null, this means the projectile's lifetime was up, // so we just blow-up in the air. eType = ST_AIR; } HOBJECT hObj = !!pInfo ? pInfo->m_hObject : LTNULL; ::AddLocalImpactFX(hObj, m_vFirePos, vPos, vNormal, eType, m_vPath, m_nWeaponId, m_nAmmoId, 0); m_bWantRemove = LTTRUE; }
void CTargetMgr::CheckForIntersect(float &fDistAway) { m_hTarget = NULL; m_ActivationData.Init(); // Cast ray from the camera to see if there is an object to activate... LTRotation const& rRot = g_pPlayerMgr->GetPlayerCamera()->GetCameraRotation( );; LTVector const& vPos = g_pPlayerMgr->GetPlayerCamera()->GetCameraPos( ); m_ActivationData.m_vPos = vPos; m_ActivationData.m_rRot = rRot; IntersectQuery IQuery; IntersectInfo IInfo; IQuery.m_From = vPos; IQuery.m_To = IQuery.m_From + (rRot.Forward() * kMaxDistance); // NOTE the use of the CHECK_FROM_POINT_INSIDE_OBJECTS flag. This flag will // make sure that any objects that m_From is inside are considered IQuery.m_Flags = CHECK_FROM_POINT_INSIDE_OBJECTS | INTERSECT_HPOLY | INTERSECT_OBJECTS | IGNORE_NONSOLID; IQuery.m_FilterActualIntersectFn = ActivateFilterFn; IQuery.m_pActualIntersectUserData = (void*)&IQuery; IQuery.m_PolyFilterFn = NULL; // [KLS 8/3/02] - ActivateFilterFn may save an object to use that may not be // the best activation choice (i.e., a fallback choice). However, if a // better choice isn't found, the fallback choice should be used. That // fallback choice is stored in g_adFallbackActivationObject so we clear // it here... g_adFallbackActivationObject.Init(); if (g_pLTClient->IntersectSegment(IQuery, &IInfo)) { m_ActivationData.m_vIntersect = IInfo.m_Point; bool bHitSky = false; if (IsMainWorld(IInfo.m_hObject)) { if (IInfo.m_hPoly != INVALID_HPOLY) { SurfaceType eType = GetSurfaceType(IInfo.m_hPoly); HSURFACE hSurf = g_pSurfaceDB->GetSurface(eType); // See if the surface we tried to activate has an activation // sound...If so, the user can activate it... if (hSurf) { HRECORD hActSnd = g_pSurfaceDB->GetRecordLink(hSurf,SrfDB_Srf_rActivationSnd); if (hActSnd && g_pSoundDB->GetFloat(hActSnd,SndDB_fOuterRadius) > 0) { m_hTarget = IInfo.m_hObject; m_ActivationData.m_hTarget = m_hTarget; m_ActivationData.m_nSurfaceType = eType; m_ActivationData.m_hActivateSnd = hActSnd; } bHitSky = (ST_SKY == eType); } } } else { LTVector vObjPos = m_ActivationData.m_vIntersect; vObjPos -= vPos; if (vObjPos.Mag() <= kMaxDistance) { m_hTarget = IInfo.m_hObject; m_ActivationData.m_hTarget = m_hTarget; } } // Calculate how far away the object is... LTVector vDist = m_ActivationData.m_vIntersect - vPos; if (bHitSky) fDistAway = kMaxDistance; else fDistAway = vDist.Mag(); } // [KLS 8/3/02] - Use the fallback object if we have one and we didn't // find another object more suitable object... bool bCanUseFallback = (m_ActivationData.m_hTarget ? false : true); if (!bCanUseFallback) { // We can still use the fallback object if it isn't the world or a // world model... if (IsMainWorld(m_ActivationData.m_hTarget) || OT_WORLDMODEL == GetObjectType(m_ActivationData.m_hTarget)) { bCanUseFallback = true; } } if ( bCanUseFallback && g_adFallbackActivationObject.m_hTarget ) { // Ok we hit the fallback object reset some of our target data LTVector vObjPos; g_pLTClient->GetObjectPos(g_adFallbackActivationObject.m_hTarget, &vObjPos); m_ActivationData.m_vIntersect = vObjPos; vObjPos -= vPos; if (vObjPos.Mag() <= kMaxDistance) { m_hTarget = g_adFallbackActivationObject.m_hTarget; m_ActivationData.m_hTarget = m_hTarget; } // Calculate how far away the object is... LTVector vDist = m_ActivationData.m_vIntersect - vPos; fDistAway = vDist.Mag(); } }
void subbrep_planar_init(struct subbrep_object_data *data) { if (!data) return; if (data->planar_obj) return; BU_GET(data->planar_obj, struct subbrep_object_data); subbrep_object_init(data->planar_obj, data->brep); bu_vls_sprintf(data->planar_obj->key, "%s", bu_vls_addr(data->key)); data->planar_obj->obj_cnt = data->obj_cnt; (*data->obj_cnt)++; bu_vls_sprintf(data->planar_obj->name_root, "%s_%d", bu_vls_addr(data->name_root), *(data->obj_cnt)); data->planar_obj->type = PLANAR_VOLUME; data->planar_obj->local_brep = ON_Brep::New(); std::map<int, int> face_map; std::map<int, int> surface_map; std::map<int, int> edge_map; std::map<int, int> vertex_map; std::map<int, int> loop_map; std::map<int, int> c3_map; std::map<int, int> c2_map; std::map<int, int> trim_map; std::set<int> faces; std::set<int> fil; std::set<int> loops; std::set<int> skip_verts; std::set<int> skip_edges; std::set<int> keep_verts; std::set<int> partial_edges; std::set<int> isolated_trims; // collect 2D trims whose parent loops aren't fully included here array_to_set(&faces, data->faces, data->faces_cnt); array_to_set(&fil, data->fil, data->fil_cnt); array_to_set(&loops, data->loops, data->loops_cnt); std::map<int, std::set<int> > face_loops; std::map<int, std::set<int> >::iterator fl_it; std::set<int>::iterator l_it; for (int i = 0; i < data->edges_cnt; i++) { int c3i; int new_edge_curve = 0; const ON_BrepEdge *old_edge = &(data->brep->m_E[data->edges[i]]); //std::cout << "old edge: " << old_edge->Vertex(0)->m_vertex_index << "," << old_edge->Vertex(1)->m_vertex_index << "\n"; // See if the vertices from this edge play a role in the planar volume int use_edge = 2; for (int vi = 0; vi < 2; vi++) { int vert_test = -1; int vert_ind = old_edge->Vertex(vi)->m_vertex_index; if (skip_verts.find(vert_ind) != skip_verts.end()) { vert_test = 1; } if (vert_test == -1 && keep_verts.find(vert_ind) != keep_verts.end()) { vert_test = 0; } if (vert_test == -1) { vert_test = characterize_vert(data, old_edge->Vertex(vi)); if (vert_test) { skip_verts.insert(vert_ind); ON_3dPoint vp = old_edge->Vertex(vi)->Point(); bu_log("vert %d (%f %f %f): %d\n", vert_ind, vp.x, vp.y, vp.z, vert_test); } else { keep_verts.insert(vert_ind); } } if (vert_test == 1) { use_edge--; } } if (use_edge == 0) { bu_log("skipping edge %d - both verts are skips\n", old_edge->m_edge_index); skip_edges.insert(old_edge->m_edge_index); continue; } if (use_edge == 1) { bu_log("One of the verts for edge %d is a skip.\n", old_edge->m_edge_index); partial_edges.insert(old_edge->m_edge_index); continue; } // Get the 3D curves from the edges if (c3_map.find(old_edge->EdgeCurveIndexOf()) == c3_map.end()) { ON_Curve *nc = old_edge->EdgeCurveOf()->Duplicate(); ON_Curve *tc = old_edge->EdgeCurveOf()->Duplicate(); if (tc->IsLinear()) { c3i = data->planar_obj->local_brep->AddEdgeCurve(nc); c3_map[old_edge->EdgeCurveIndexOf()] = c3i; } else { ON_Curve *c3 = new ON_LineCurve(old_edge->Vertex(0)->Point(), old_edge->Vertex(1)->Point()); c3i = data->planar_obj->local_brep->AddEdgeCurve(c3); c3_map[old_edge->EdgeCurveIndexOf()] = c3i; new_edge_curve = 1; } } else { c3i = c3_map[old_edge->EdgeCurveIndexOf()]; } // Get the vertices from the edges int v[2]; for (int vi = 0; vi < 2; vi++) { if (vertex_map.find(old_edge->Vertex(vi)->m_vertex_index) == vertex_map.end()) { ON_BrepVertex& newvvi = data->planar_obj->local_brep->NewVertex(old_edge->Vertex(vi)->Point(), old_edge->Vertex(vi)->m_tolerance); v[vi] = newvvi.m_vertex_index; vertex_map[old_edge->Vertex(vi)->m_vertex_index] = v[vi]; } else { v[vi] = vertex_map[old_edge->Vertex(vi)->m_vertex_index]; } } ON_BrepEdge& new_edge = data->planar_obj->local_brep->NewEdge(data->planar_obj->local_brep->m_V[v[0]], data->planar_obj->local_brep->m_V[v[1]], c3i, NULL ,0); edge_map[old_edge->m_edge_index] = new_edge.m_edge_index; // Get the 2D curves from the trims for (int j = 0; j < old_edge->TrimCount(); j++) { ON_BrepTrim *old_trim = old_edge->Trim(j); if (faces.find(old_trim->Face()->m_face_index) != faces.end()) { if (c2_map.find(old_trim->TrimCurveIndexOf()) == c2_map.end()) { ON_Curve *nc = old_trim->TrimCurveOf()->Duplicate(); int c2i = data->planar_obj->local_brep->AddTrimCurve(nc); c2_map[old_trim->TrimCurveIndexOf()] = c2i; //std::cout << "c2i: " << c2i << "\n"; } } } // Get the faces and surfaces from the trims for (int j = 0; j < old_edge->TrimCount(); j++) { ON_BrepTrim *old_trim = old_edge->Trim(j); if (face_map.find(old_trim->Face()->m_face_index) == face_map.end()) { if (faces.find(old_trim->Face()->m_face_index) != faces.end()) { ON_Surface *ns = old_trim->Face()->SurfaceOf()->Duplicate(); ON_Surface *ts = old_trim->Face()->SurfaceOf()->Duplicate(); if (ts->IsPlanar(NULL, BREP_PLANAR_TOL)) { int nsid = data->planar_obj->local_brep->AddSurface(ns); surface_map[old_trim->Face()->SurfaceIndexOf()] = nsid; ON_BrepFace &new_face = data->planar_obj->local_brep->NewFace(nsid); face_map[old_trim->Face()->m_face_index] = new_face.m_face_index; //std::cout << "old face " << old_trim->Face()->m_face_index << " is now " << new_face.m_face_index << "\n"; if (fil.find(old_trim->Face()->m_face_index) != fil.end()) { data->planar_obj->local_brep->FlipFace(new_face); } } } } } // Get the loops from the trims for (int j = 0; j < old_edge->TrimCount(); j++) { ON_BrepTrim *old_trim = old_edge->Trim(j); ON_BrepLoop *old_loop = old_trim->Loop(); if (face_map.find(old_trim->Face()->m_face_index) != face_map.end()) { if (loops.find(old_loop->m_loop_index) != loops.end()) { if (loop_map.find(old_loop->m_loop_index) == loop_map.end()) { face_loops[old_trim->Face()->m_face_index].insert(old_loop->m_loop_index); } } } } } for (fl_it = face_loops.begin(); fl_it != face_loops.end(); fl_it++) { int loop_cnt = fl_it->second.size(); if (loop_cnt == 1) { // If we have only one loop on a face it's an outer loop, // whatever it was in the original brep. const ON_BrepLoop *old_loop = &(data->brep->m_L[*(fl_it->second.begin())]); ON_BrepLoop &nl = data->planar_obj->local_brep->NewLoop(ON_BrepLoop::outer, data->planar_obj->local_brep->m_F[face_map[fl_it->first]]); loop_map[old_loop->m_loop_index] = nl.m_loop_index; } else { bu_log("loop_cnt: %d\n", loop_cnt); // If we ended up with multiple loops, one of them should be an outer loop // and the rest inner loops // Get the outer loop first for (l_it = fl_it->second.begin(); l_it != fl_it->second.end(); l_it++) { const ON_BrepLoop *old_loop = &(data->brep->m_L[*l_it]); if (data->brep->LoopDirection(data->brep->m_L[*l_it]) == 1) { ON_BrepLoop &nl = data->planar_obj->local_brep->NewLoop(ON_BrepLoop::outer, data->planar_obj->local_brep->m_F[face_map[fl_it->first]]); loop_map[old_loop->m_loop_index] = nl.m_loop_index; } } // Now get the inner loops; for (l_it = fl_it->second.begin(); l_it != fl_it->second.end(); l_it++) { const ON_BrepLoop *old_loop = &(data->brep->m_L[*l_it]); if (data->brep->LoopDirection(data->brep->m_L[*l_it]) != 1) { ON_BrepLoop &nl = data->planar_obj->local_brep->NewLoop(ON_BrepLoop::inner, data->planar_obj->local_brep->m_F[face_map[fl_it->first]]); loop_map[old_loop->m_loop_index] = nl.m_loop_index; } } } } // Now, create new trims using the old loop definitions and the maps std::map<int, int>::iterator loop_it; std::set<int> evaluated; for (loop_it = loop_map.begin(); loop_it != loop_map.end(); loop_it++) { const ON_BrepLoop *old_loop = &(data->brep->m_L[(*loop_it).first]); ON_BrepLoop &new_loop = data->planar_obj->local_brep->m_L[(*loop_it).second]; for (int j = 0; j < old_loop->TrimCount(); j++) { const ON_BrepTrim *old_trim = old_loop->Trim(j); ON_BrepEdge *o_edge = old_trim->Edge(); if (!o_edge) { /* If we didn't have an edge originally, we need to add the 2d curve here */ if (c2_map.find(old_trim->TrimCurveIndexOf()) == c2_map.end()) { ON_Curve *nc = old_trim->TrimCurveOf()->Duplicate(); int c2i = data->planar_obj->local_brep->AddTrimCurve(nc); c2_map[old_trim->TrimCurveIndexOf()] = c2i; } if (vertex_map.find(old_trim->Vertex(0)->m_vertex_index) == vertex_map.end()) { ON_BrepVertex& newvs = data->planar_obj->local_brep->NewVertex(old_trim->Vertex(0)->Point(), old_trim->Vertex(0)->m_tolerance); vertex_map[old_trim->Vertex(0)->m_vertex_index] = newvs.m_vertex_index; ON_BrepTrim &nt = data->planar_obj->local_brep->NewSingularTrim(newvs, new_loop, old_trim->m_iso, c2_map[old_trim->TrimCurveIndexOf()]); nt.m_tolerance[0] = old_trim->m_tolerance[0]; nt.m_tolerance[1] = old_trim->m_tolerance[1]; } else { ON_BrepTrim &nt = data->planar_obj->local_brep->NewSingularTrim(data->planar_obj->local_brep->m_V[vertex_map[old_trim->Vertex(0)->m_vertex_index]], new_loop, old_trim->m_iso, c2_map[old_trim->TrimCurveIndexOf()]); nt.m_tolerance[0] = old_trim->m_tolerance[0]; nt.m_tolerance[1] = old_trim->m_tolerance[1]; } continue; } if (evaluated.find(o_edge->m_edge_index) != evaluated.end()) { bu_log("edge %d already handled, continuing...\n", o_edge->m_edge_index); continue; } // Don't use a trim connected to an edge we are skipping if (skip_edges.find(o_edge->m_edge_index) != skip_edges.end()) { bu_log("edge %d is skipped, continuing...\n", o_edge->m_edge_index); evaluated.insert(o_edge->m_edge_index); continue; } int is_partial = 0; if (partial_edges.find(o_edge->m_edge_index) != partial_edges.end()) is_partial = 1; if (!is_partial) { ON_BrepEdge &n_edge = data->planar_obj->local_brep->m_E[edge_map[o_edge->m_edge_index]]; ON_Curve *ec = o_edge->EdgeCurveOf()->Duplicate(); if (ec->IsLinear()) { ON_BrepTrim &nt = data->planar_obj->local_brep->NewTrim(n_edge, old_trim->m_bRev3d, new_loop, c2_map[old_trim->TrimCurveIndexOf()]); nt.m_tolerance[0] = old_trim->m_tolerance[0]; nt.m_tolerance[1] = old_trim->m_tolerance[1]; nt.m_iso = old_trim->m_iso; } else { // Wasn't linear, but wasn't partial either - replace with a line ON_Curve *c2_orig = old_trim->TrimCurveOf()->Duplicate(); ON_3dPoint p1 = c2_orig->PointAt(c2_orig->Domain().Min()); ON_3dPoint p2 = c2_orig->PointAt(c2_orig->Domain().Max()); ON_Curve *c2 = new ON_LineCurve(p1, p2); c2->ChangeDimension(2); int c2i = data->planar_obj->local_brep->AddTrimCurve(c2); ON_BrepTrim &nt = data->planar_obj->local_brep->NewTrim(n_edge, old_trim->m_bRev3d, new_loop, c2i); nt.m_tolerance[0] = old_trim->m_tolerance[0]; nt.m_tolerance[1] = old_trim->m_tolerance[1]; nt.m_iso = old_trim->m_iso; delete c2_orig; } delete ec; } else { // Partial edge - let the fun begin ON_3dPoint p1, p2; ON_BrepEdge *next_edge; bu_log("working a partial edge: %d\n", o_edge->m_edge_index); int v[2]; v[0] = o_edge->Vertex(0)->m_vertex_index; v[1] = o_edge->Vertex(1)->m_vertex_index; // figure out which trim point we can use, the min or max int pos1 = 0; if (skip_verts.find(v[0]) != skip_verts.end()) { pos1 = 1; } int j_next = j; ON_Curve *c2_orig = old_trim->TrimCurveOf()->Duplicate(); ON_Curve *c2_next = NULL; int walk_dir = 1; // bump the loop iterator to get passed any skipped edges to // the next partial while (!c2_next) { (walk_dir == 1) ? j_next++ : j_next--; if (j_next == old_loop->TrimCount()) { j_next = 0; } if (j_next == -1) { j_next = old_loop->TrimCount() - 1; } const ON_BrepTrim *next_trim = old_loop->Trim(j_next); next_edge = next_trim->Edge(); if (!next_edge) continue; if (skip_edges.find(next_edge->m_edge_index) == skip_edges.end()) { if (partial_edges.find(next_edge->m_edge_index) != partial_edges.end()) { bu_log("found next partial edge %d\n", next_edge->m_edge_index); evaluated.insert(next_edge->m_edge_index); c2_next = next_trim->TrimCurveOf()->Duplicate(); } else { bu_log("partial edge %d followed by non-partial %d, need to go the other way\n", o_edge->m_edge_index, next_edge->m_edge_index); j_next--; walk_dir = -1; } } else { bu_log("skipping fully ignored edge %d\n", next_edge->m_edge_index); evaluated.insert(next_edge->m_edge_index); } } int v2[2]; v2[0] = next_edge->Vertex(0)->m_vertex_index; v2[1] = next_edge->Vertex(1)->m_vertex_index; // figure out which trim point we can use, the min or max int pos2 = 0; if (skip_verts.find(v2[0]) != skip_verts.end()) { pos2 = 1; } int vmapped[2]; if (vertex_map.find(o_edge->Vertex(pos1)->m_vertex_index) == vertex_map.end()) { ON_BrepVertex& newvvi = data->planar_obj->local_brep->NewVertex(o_edge->Vertex(pos1)->Point(), o_edge->Vertex(pos1)->m_tolerance); vertex_map[o_edge->Vertex(pos1)->m_vertex_index] = newvvi.m_vertex_index; } if (vertex_map.find(next_edge->Vertex(pos2)->m_vertex_index) == vertex_map.end()) { ON_BrepVertex& newvvi = data->planar_obj->local_brep->NewVertex(next_edge->Vertex(pos2)->Point(), next_edge->Vertex(pos2)->m_tolerance); vertex_map[next_edge->Vertex(pos2)->m_vertex_index] = newvvi.m_vertex_index; } // If walk_dir is -1, need to flip things around (I think...) the verts and trim points // will be swapped compared to a forward walk if (walk_dir == -1) { vmapped[1] = vertex_map[o_edge->Vertex(pos1)->m_vertex_index]; vmapped[0] = vertex_map[next_edge->Vertex(pos2)->m_vertex_index]; } else { vmapped[0] = vertex_map[o_edge->Vertex(pos1)->m_vertex_index]; vmapped[1] = vertex_map[next_edge->Vertex(pos2)->m_vertex_index]; } // New Edge curve ON_Curve *c3 = new ON_LineCurve(o_edge->Vertex(pos1)->Point(), next_edge->Vertex(pos2)->Point()); int c3i = data->planar_obj->local_brep->AddEdgeCurve(c3); ON_BrepEdge& new_edge = data->planar_obj->local_brep->NewEdge(data->planar_obj->local_brep->m_V[vmapped[0]], data->planar_obj->local_brep->m_V[vmapped[1]], c3i, NULL ,0); // Again, flip if walk_dir is -1 if (walk_dir == -1) { p2 = c2_orig->PointAt(c2_orig->Domain().Min()); p1 = c2_next->PointAt(c2_orig->Domain().Max()); } else { p1 = c2_orig->PointAt(c2_orig->Domain().Min()); p2 = c2_next->PointAt(c2_orig->Domain().Max()); } std::cout << "p1: " << pout(p1) << "\n"; std::cout << "p2: " << pout(p2) << "\n"; ON_Curve *c2 = new ON_LineCurve(p1, p2); c2->ChangeDimension(2); int c2i = data->planar_obj->local_brep->AddTrimCurve(c2); ON_BrepTrim &nt = data->planar_obj->local_brep->NewTrim(new_edge, false, new_loop, c2i); nt.m_tolerance[0] = old_trim->m_tolerance[0]; nt.m_tolerance[1] = old_trim->m_tolerance[1]; nt.m_iso = old_trim->m_iso; delete c2_orig; delete c2_next; } } } // If there is a possibility of a negative volume for the planar solid, do a test. // The only way to get a negative planar solid in this context is if that solid is // "inside" a non-planar shape (it would be "part of" the parent shape if it were // planar and it would be a separate shape altogether if it were not topologically // connected. So we take one partial edge, find its associated non-planar faces, // and collect all the partial and skipped edges from that face and any non-planar // faces associated with the other partial/skipped edges. // // TODO - We still have an unhandled possibility here - the self-intersecting // planar_obj. For example: // // * * // * * * * // * * * * * * // * * * * * * * * // * * * * * * // * * * * * * * * * * * * // if (partial_edges.size() > 0) { std::queue<int> connected_faces; std::set<int> relevant_edges; std::set<int>::iterator re_it; std::set<int> efaces; std::set<int>::iterator f_it; std::set<int> found_faces; const ON_BrepEdge *seed_edge = &(data->brep->m_E[*partial_edges.begin()]); for (int j = 0; j < seed_edge->TrimCount(); j++) { ON_BrepTrim *trim = seed_edge->Trim(j); efaces.insert(trim->Face()->m_face_index); } for(f_it = efaces.begin(); f_it != efaces.end(); f_it++) { surface_t stype = GetSurfaceType(data->brep->m_F[*f_it].SurfaceOf(), NULL); if (stype != SURFACE_PLANE) { connected_faces.push(data->brep->m_F[*f_it].m_face_index); } } while (!connected_faces.empty()) { int face_index = connected_faces.front(); connected_faces.pop(); std::set<int> local_edges; std::set<int>::iterator le_it; found_faces.insert(face_index); const ON_BrepFace *face = &(data->brep->m_F[face_index]); const ON_BrepLoop *loop = NULL; // Find the loop in this face that is associated with this subbrep for (int i = 0; i < face->LoopCount(); i++) { int loop_ind = face->Loop(i)->m_loop_index; if (loops.find(loop_ind) != loops.end()) { loop = &(data->brep->m_L[loop_ind]); break; } } // Collect the edges that are partial or skipped for (int i = 0; i < loop->TrimCount(); i++) { const ON_BrepTrim *trim = loop->Trim(i); ON_BrepEdge *edge = trim->Edge(); if (edge) { if (partial_edges.find(edge->m_edge_index) != partial_edges.end()) { relevant_edges.insert(edge->m_edge_index); local_edges.insert(edge->m_edge_index); } if (skip_edges.find(edge->m_edge_index) != skip_edges.end()) { relevant_edges.insert(edge->m_edge_index); local_edges.insert(edge->m_edge_index); } } } // For each collected partial/skipped edge, add any faces not already // found to the queue. for (le_it = local_edges.begin(); le_it != local_edges.end(); le_it++) { const ON_BrepEdge *edge = &(data->brep->m_E[*le_it]); for (int j = 0; j < edge->TrimCount(); j++) { ON_BrepTrim *trim = edge->Trim(j); if (found_faces.find(trim->Face()->m_face_index) == found_faces.end()) { found_faces.insert(trim->Face()->m_face_index); connected_faces.push(trim->Face()->m_face_index); } } } } // Build two bounding boxes - one with the new verts in planar_obj, and the other with // the edges found above. ON_BoundingBox pbb, ebb; ON_MinMaxInit(&pbb.m_min, &pbb.m_max); ON_MinMaxInit(&ebb.m_min, &ebb.m_max); for (int i = 0; i < data->planar_obj->local_brep->m_V.Count(); i++) { const ON_BrepVertex *v = &(data->planar_obj->local_brep->m_V[i]); pbb.Set(v->Point(), true); } for (re_it = relevant_edges.begin(); re_it != relevant_edges.end(); re_it++) { const ON_BrepEdge *e = &(data->brep->m_E[*re_it]); ON_BoundingBox cbb = e->EdgeCurveOf()->BoundingBox(); ebb.Set(cbb.m_min, true); ebb.Set(cbb.m_max, true); } //std::cout << "in pbb.s rpp " << pout(pbb.m_min) << " " << pout(pbb.m_max) << "\n"; //std::cout << "in ebb.s rpp " << pout(ebb.m_min) << " " << pout(ebb.m_max) << "\n"; if (ebb.Includes(pbb)) { bu_log("negative volume\n"); data->planar_obj->negative_shape = -1; } else { bu_log("positive volume\n"); data->planar_obj->negative_shape = 1; } data->planar_obj->params->bool_op = (data->planar_obj->negative_shape == -1) ? '-' : 'u'; } // Need to preserve the vertex map for this, since we're not done building up the brep map_to_array(&(data->planar_obj->planar_obj_vert_map), &(data->planar_obj->planar_obj_vert_cnt), &vertex_map); data->planar_obj->local_brep->SetTrimTypeFlags(true); }
void Body::HandleModelString(ArgList* pArgList) { if (!g_pLTServer || !pArgList || !pArgList->argv || pArgList->argc == 0) return; char* pKey = pArgList->argv[0]; if (!pKey) return; LTBOOL bSlump = !_stricmp(pKey, s_szKeyNoise); LTBOOL bLand = !_stricmp(pKey, s_szKeyLand); if ( bSlump || bLand ) { // Hitting the ground noise /* SurfaceType eSurface = ST_UNKNOWN; CollisionInfo Info; g_pLTServer->GetStandingOn(m_hObject, &Info); if (Info.m_hPoly && Info.m_hPoly != INVALID_HPOLY) { eSurface = (SurfaceType)GetSurfaceType(Info.m_hPoly); } else if (Info.m_hObject) // Get the texture flags from the object... { eSurface = (SurfaceType)GetSurfaceType(Info.m_hObject); } else { return; } */ LTVector vPos; g_pLTServer->GetObjectPos(m_hObject, &vPos); IntersectQuery IQuery; IntersectInfo IInfo; IQuery.m_From = vPos; IQuery.m_To = vPos - LTVector(0,96,0); IQuery.m_Flags = INTERSECT_OBJECTS | INTERSECT_HPOLY | IGNORE_NONSOLID; IQuery.m_FilterFn = GroundFilterFn; SurfaceType eSurface; g_cIntersectSegmentCalls++; if (g_pLTServer->IntersectSegment(&IQuery, &IInfo)) { if (IInfo.m_hPoly && IInfo.m_hPoly != INVALID_HPOLY) { eSurface = (SurfaceType)GetSurfaceType(IInfo.m_hPoly); } else if (IInfo.m_hObject) // Get the texture flags from the object... { eSurface = (SurfaceType)GetSurfaceType(IInfo.m_hObject); } else { return; } } else { return; } SURFACE* pSurf = g_pSurfaceMgr->GetSurface(eSurface); _ASSERT(pSurf); if (!pSurf) return; // Update the noise info. We use a time in the future so AI's don't *instantly* react to the sound // AI's twice as sensitive to landing sound (because it's louder) m_DeathScene.SetNoise(pSurf->fDeathNoiseModifier * (bLand ? 2.0f : 1.0f), g_pLTServer->GetTime() + GetRandom(0.5f, 1.0f)); } }
// Criteria: // // 1. A linear edge associated with a planar face == 0 // 2. All linear edges associated with non-planar faces are part // of the same CSG shape AND all non-linear edges' non-planar faces // are also part of that same CSG shape = 1 // 3. If not 2, 0 int characterize_vert(struct subbrep_object_data *data, const ON_BrepVertex *v) { std::set<int> non_planar_faces; std::set<int>::iterator f_it; std::set<struct filter_obj *> fobjs; std::set<struct filter_obj *>::iterator fo_it; struct filter_obj *control = NULL; for (int i = 0; i < v->m_ei.Count(); i++) { std::set<int> efaces; const ON_BrepEdge *edge = &(data->brep->m_E[v->m_ei[i]]); ON_Curve *tc = edge->EdgeCurveOf()->Duplicate(); int is_linear = tc->IsLinear(); delete tc; // Get the faces associated with the edge for (int j = 0; j < edge->TrimCount(); j++) { ON_BrepTrim *trim = edge->Trim(j); efaces.insert(trim->Face()->m_face_index); } for(f_it = efaces.begin(); f_it != efaces.end(); f_it++) { struct filter_obj *new_obj; BU_GET(new_obj, struct filter_obj); surface_t stype = GetSurfaceType(data->brep->m_F[*f_it].SurfaceOf(), new_obj); if (stype == SURFACE_PLANE) { filter_obj_free(new_obj); BU_PUT(new_obj, struct filter_obj); if (is_linear) { for (fo_it = fobjs.begin(); fo_it != fobjs.end(); fo_it++) { struct filter_obj *obj = (struct filter_obj *)(*fo_it); filter_obj_free(obj); BU_PUT(obj, struct filter_obj); } return 0; } } else { if (!control) { control = new_obj; } else { fobjs.insert(new_obj); } } } } // Can this happen? if (fobjs.size() == 0) { if (control) { filter_obj_free(control); BU_PUT(control, struct filter_obj); } return 0; } int equal = 1; for(fo_it = fobjs.begin(); fo_it != fobjs.end(); fo_it++) { if (equal && !filter_objs_equal(*fo_it, control)) equal = 0; struct filter_obj *obj = (struct filter_obj *)(*fo_it); filter_obj_free(obj); BU_PUT(obj, struct filter_obj); } filter_obj_free(control); BU_PUT(control, struct filter_obj); return equal; }
void CProjectile::AddImpact(DVector vPoint, DVector vNormal, HOBJECT hObj) { // Compute a normal vector // Cast a ray to see what we hit DVector tempPos; IntersectQuery iq; IntersectInfo ii; SurfaceType eType = SURFTYPE_UNKNOWN; DBYTE nFX = 0; VEC_NORM(m_vDir); VEC_MULSCALAR(m_vDir, m_vDir, 2.0f); VEC_SUB(iq.m_From, vPoint, m_vDir); VEC_MULSCALAR(m_vDir, m_vDir, 10.0f); VEC_ADD(iq.m_To, vPoint, m_vDir); iq.m_Flags = INTERSECT_OBJECTS | IGNORE_NONSOLID; iq.m_FilterFn = NULL; iq.m_pUserData = NULL; if (hObj && g_pServerDE->IntersectSegment(&iq, &ii)) { VEC_COPY(vNormal, ii.m_Plane.m_Normal); eType = GetSurfaceType(ii.m_hObject, ii.m_hPoly); VEC_COPY(tempPos, ii.m_Point); } else // Fake it { VEC_NEGATE(vNormal, m_vDir); VEC_COPY(tempPos, vPoint); } if(m_bExplosion) { AddExplosion(tempPos, vNormal); nFX |= WFX_SCREENSHAKE; } if(m_bClientFX) { CServerDE* pServerDE = BaseClass::GetServerDE(); if (!pServerDE) return; /* ObjectCreateStruct theStruct; INIT_OBJECTCREATESTRUCT(theStruct); VEC_COPY(theStruct.m_Pos, vPoint); HCLASS hClass = pServerDE->GetClass("CClientWeaponSFX"); CClientWeaponSFX *pWeaponFX = DNULL; if(hClass) pWeaponFX = (CClientWeaponSFX*)pServerDE->CreateObject(hClass, &theStruct); */ DDWORD nFX = WFX_SCREENSHAKE; DDWORD nExtras = WFX_EXTRA_DAMAGE; WeaponFXExtras ext; ext.fDamage = m_fDamage; // if(pWeaponFX) SendWeaponSFXMessage(&vPoint, &vPoint, &vNormal, &vNormal, nFX, nExtras, &ext); } }
void CSpear::HandleImpact(HOBJECT hObj) { if (!g_vtSpearStickPercentage.IsInitted()) { g_vtSpearStickPercentage.Init(g_pLTServer, "SpearStickPercent", LTNULL, 0.9f); } if (!m_pAmmoData || !m_pAmmoData->pProjectileFX) { CProjectile::HandleImpact(hObj); return; } CollisionInfo info; g_pLTServer->GetLastCollision(&info); LTVector vPos, vVel, vCurVel, vP0, vP1; g_pLTServer->GetObjectPos(m_hObject, &vPos); LTRotation rRot; g_pLTServer->GetObjectRotation(m_hObject, &rRot); // Should we break the spear? enum SpearAction { eSpearActionBreak, eSpearActionStickWorld, eSpearActionStickAI, eSpearActionStickPlayer, eSpearActionStickBody }; SpearAction eSpearAction = eSpearActionBreak; // Randomly break even if we could sometimes stick... if (GetRandom(0.0, 1.0f) > g_vtSpearStickPercentage.GetFloat()) { eSpearAction = eSpearActionBreak; } else if (IsMainWorld(hObj)) { // Calculate where we really hit the world... g_pLTServer->GetVelocity(m_hObject, &vVel); vP1 = vPos; vCurVel = vVel * g_pLTServer->GetFrameTime(); vP0 = vP1 - vCurVel; vP1 += vCurVel; LTFLOAT fDot1 = VEC_DOT(info.m_Plane.m_Normal, vP0) - info.m_Plane.m_Dist; LTFLOAT fDot2 = VEC_DOT(info.m_Plane.m_Normal, vP1) - info.m_Plane.m_Dist; if (fDot1 < 0.0f && fDot2 < 0.0f || fDot1 > 0.0f && fDot2 > 0.0f) { vPos = vP1; } else { LTFLOAT fPercent = -fDot1 / (fDot2 - fDot1); VEC_LERP(vPos, vP0, vP1, fPercent); } // Set our new "real" pos... g_pLTServer->SetObjectPos(m_hObject, &vPos); eSpearAction = eSpearActionStickWorld; } else if (IsMoveable(hObj)) { if (IsAI(hObj)) { // Attach to a AI eSpearAction = eSpearActionStickAI; } else if (IsPlayer(hObj)) { // Attach to a Player eSpearAction = eSpearActionStickPlayer; } else if (IsBody(hObj)) { // Attach to a body eSpearAction = eSpearActionStickBody; } else { // Could probably come up with a way to attach to moveable // non-character objects (like doors), but it is much easier // to just break it ;)... eSpearAction = eSpearActionBreak; } } // If the surface is too hard, the spear will just break when // it hits it... SurfaceType eSurf = GetSurfaceType(info); SURFACE* pSurf = g_pSurfaceMgr->GetSurface(eSurf); if ((eSpearActionBreak == eSpearAction) || ((eSpearActionStickWorld == eSpearAction) && pSurf && pSurf->fHardness > 0.5)) { // Create spear debris... DEBRIS* pDebris = g_pDebrisMgr->GetDebris(m_pAmmoData->szName); if (pDebris) { vVel.Norm(); LTVector vNegVel = -vVel; CreatePropDebris(vPos, vNegVel, pDebris->nId); } CProjectile::HandleImpact(hObj); return; } // Create the Spear powerup... char szSpawn[512]; sprintf(szSpawn, "AmmoBox AmmoType1 %s;AmmoCount1 1;Filename %s;Skin %s", m_pAmmoData->szName, m_pAmmoData->pProjectileFX->szModel, m_pAmmoData->pProjectileFX->szSkin); LTVector vScale = m_pAmmoData->pProjectileFX->vModelScale; // Make sure the spear sticks out a little ways... vVel.Norm(); vPos -= (vVel * vScale.z/2.0f); if (eSpearActionStickWorld == eSpearAction) { g_pLTServer->AlignRotation(&rRot, &vVel, LTNULL); } BaseClass* pClass = SpawnObject(szSpawn, LTVector(-10000,-10000,-10000), rRot); if (pClass) { g_pLTServer->ScaleObject(pClass->m_hObject, &vScale); LTVector vDims; g_pLTServer->GetObjectDims(pClass->m_hObject, &vDims); vDims.x *= vScale.x; vDims.y *= vScale.y; vDims.z *= vScale.z; g_pLTServer->SetObjectDims(pClass->m_hObject, &vDims); // We don't want other projectiles to impact on us... //uint32 dwUsrFlags = g_pLTServer->GetObjectUserFlags(pClass->m_hObject); //dwUsrFlags |= USRFLG_IGNORE_PROJECTILES; //g_pLTServer->SetObjectUserFlags(pClass->m_hObject, dwUsrFlags); if ( eSpearActionStickAI == eSpearAction || eSpearActionStickPlayer == eSpearAction ) { g_pLTServer->SetObjectUserFlags(pClass->m_hObject, g_pLTServer->GetObjectUserFlags(pClass->m_hObject) & ~USRFLG_GLOW); g_pLTServer->SetObjectFlags(pClass->m_hObject, g_pLTServer->GetObjectFlags(pClass->m_hObject) & ~FLAG_TOUCH_NOTIFY); if ( eSpearActionStickPlayer == eSpearAction ) { g_pLTServer->SetObjectUserFlags(pClass->m_hObject, g_pLTServer->GetObjectUserFlags(pClass->m_hObject) | USRFLG_ATTACH_HIDE1SHOW3); } // Attach it to the character CCharacter* pCharacter = (CCharacter*)g_pLTServer->HandleToObject(hObj); pCharacter->AddSpear(pClass->m_hObject, pCharacter->GetModelNodeLastHit(), rRot); } else if ( eSpearActionStickBody == eSpearAction ) { g_pLTServer->SetObjectUserFlags(pClass->m_hObject, g_pLTServer->GetObjectUserFlags(pClass->m_hObject) & ~USRFLG_GLOW); g_pLTServer->SetObjectFlags(pClass->m_hObject, g_pLTServer->GetObjectFlags(pClass->m_hObject) & ~FLAG_TOUCH_NOTIFY); // Attach it to the body Body* pBody = (Body*)g_pLTServer->HandleToObject(hObj); pBody->AddSpear(pClass->m_hObject, rRot); } else // ( eSpearActionStickWorld == eSpearAction ) { // Move it to the right position in the world g_pLTServer->SetObjectPos(pClass->m_hObject, &vPos); } } CProjectile::HandleImpact(hObj); }
void CGrenade::HandleImpact(HOBJECT hObj) { if (!g_vtGrenadeDampenPercent.IsInitted()) { g_vtGrenadeDampenPercent.Init(g_pLTServer, "GrenadeDampenPercent", LTNULL, DEFAULT_GRENADE_DAMPEN_PERCENT); } if (!g_vtGrenadeMinVelMag.IsInitted()) { g_vtGrenadeMinVelMag.Init(g_pLTServer, "GrenadeMinVelMag", LTNULL, DEFAULT_GRENADE_MIN_VELOCITY); } LTVector vVel; g_pLTServer->GetVelocity(m_hObject, &vVel); // See if we are impacting on liquid... LTBOOL bEnteringLiquid = LTFALSE; uint16 code; if (g_pLTServer->GetContainerCode(hObj, &code)) { if (IsLiquid((ContainerCode)code)) { bEnteringLiquid = LTTRUE; } } CollisionInfo info; g_pLTServer->GetLastCollision(&info); // Do the bounce, if the object we hit isn't liquid... if (!bEnteringLiquid) { vVel += (info.m_vStopVel * 2.0f); } // Dampen the grenade's new velocity based on the surface type... LTFLOAT fDampenPercent = g_vtGrenadeDampenPercent.GetFloat(); m_eLastHitSurface = GetSurfaceType(info); SURFACE* pSurf = g_pSurfaceMgr->GetSurface(m_eLastHitSurface); if (pSurf) { // Play a bounce sound (based on the surface type) if one isn't // already playing... if ( ShouldPlayBounceSound(pSurf) ) { // Only play one sound at a time... if (m_hBounceSnd) { g_pLTServer->KillSound(m_hBounceSnd); m_hBounceSnd = LTNULL; } uint32 dwFlags = PLAYSOUND_GETHANDLE | PLAYSOUND_TIME; int nVolume = IsLiquid(m_eContainerCode) ? 50 : 100; LTVector vPos; g_pLTServer->GetObjectPos(m_hObject, &vPos); m_hBounceSnd = g_pServerSoundMgr->PlaySoundFromPos(vPos, (char*)GetBounceSound(pSurf), pSurf->fGrenadeSndRadius, SOUNDPRIORITY_MISC_MEDIUM, dwFlags, nVolume); } fDampenPercent = (1.0f - pSurf->fHardness); } fDampenPercent = fDampenPercent > 1.0f ? 1.0f : (fDampenPercent < 0.0f ? 0.0f : fDampenPercent); vVel *= (1.0f - fDampenPercent); // See if we should come to a rest... LTVector vTest = vVel; vTest.y = 0.0f; if (vTest.Mag() < g_vtGrenadeMinVelMag.GetFloat()) { // If we're on the ground (or an object), stop movement... CollisionInfo standingInfo; g_pLTServer->GetStandingOn(m_hObject, &standingInfo); CollisionInfo* pInfo = standingInfo.m_hObject ? &standingInfo : &info; if (pInfo->m_hObject) { // Don't stop on walls... if (pInfo->m_Plane.m_Normal.y > 0.75f) { vVel.Init(); // Turn off gravity, solid, and touch notify.... uint32 dwFlags = g_pLTServer->GetObjectFlags(m_hObject); dwFlags &= ~(FLAG_GRAVITY | FLAG_TOUCH_NOTIFY | FLAG_SOLID); g_pLTServer->SetObjectFlags(m_hObject, dwFlags); // Rotate to rest... RotateToRest(); } } } // Reset rotation velocities due to the bounce... ResetRotationVel(&vVel, pSurf); // We need to subtact this out because the engine will add it back in, // kind of a kludge but necessary... vVel -= info.m_vStopVel; g_pLTServer->SetVelocity(m_hObject, &vVel); m_cBounces++; }
void CBodyFX::OnModelKey(HLOCALOBJ hObj, ArgList *pArgs) { if (!m_hServerObject || !hObj || !pArgs || !pArgs->argv || pArgs->argc == 0) return; char* pKey = pArgs->argv[0]; if (!pKey) return; LTBOOL bSlump = !_stricmp(pKey, "NOISE"); LTBOOL bLand = !_stricmp(pKey, "LAND"); if ( bSlump || bLand ) { LTVector vPos; g_pLTClient->GetObjectPos(m_hServerObject, &vPos); IntersectQuery IQuery; IntersectInfo IInfo; IQuery.m_From = vPos; IQuery.m_To = vPos - LTVector(0,96,0); IQuery.m_Flags = INTERSECT_OBJECTS | INTERSECT_HPOLY | IGNORE_NONSOLID; IQuery.m_FilterFn = GroundFilterFn; SurfaceType eSurface; if (g_pLTClient->IntersectSegment(&IQuery, &IInfo)) { if (IInfo.m_hPoly && IInfo.m_hPoly != INVALID_HPOLY) { eSurface = (SurfaceType)GetSurfaceType(IInfo.m_hPoly); } else if (IInfo.m_hObject) // Get the texture flags from the object... { eSurface = (SurfaceType)GetSurfaceType(IInfo.m_hObject); } else { return; } } else { return; } // Play the noise SURFACE* pSurf = g_pSurfaceMgr->GetSurface(eSurface); _ASSERT(pSurf); if (!pSurf) return; if (bSlump && pSurf->szBodyFallSnd[0]) { g_pClientSoundMgr->PlaySoundFromPos(vPos, pSurf->szBodyFallSnd, pSurf->fBodyFallSndRadius, SOUNDPRIORITY_MISC_LOW); } else if (bLand && pSurf->szBodyLedgeFallSnd[0]) { g_pClientSoundMgr->PlaySoundFromPos(vPos, pSurf->szBodyLedgeFallSnd, pSurf->fBodyLedgeFallSndRadius, SOUNDPRIORITY_MISC_LOW); } } }