double CalculateWeightsMask(QPointF p, QVector<QPoint> *boundary, double *weights, QImage& mask) { double sum = 0.; int size = boundary->size() - 1; CVector3f pointX; CVector3f p0, p1, p2; CVector3f v1, v2; pointX.x = p.x() + EPSILON; pointX.y = p.y() + EPSILON; pointX.z = .0; memset(weights, 0, sizeof(double) * size); for (int i = 0; i < size; i++) { QPoint pt = boundary->at(i); if (qGray(mask.pixel(pt)) < 200) // if the boundary point is not marked { weights[i] = 0; continue; } p0.x = boundary->at((i - 1 + size) % size).x(); p0.y = boundary->at((i - 1 + size) % size).y(); p0.z = .0; p1.x = boundary->at(i).x(); p1.y = boundary->at(i).y(); p1.z = 0.00001; p2.x = boundary->at((i + 1 + size) % size).x(); p2.y = boundary->at((i + 1 + size) % size).y(); p2.z = .0; v1 = p0 - pointX; v2 = p1 - pointX; double angle1 = AngleBetweenVectors(v1, v2); if (v1.x * v2.y - v1.y * v2.x > 0) angle1 = -angle1; v1 = v2; v2 = p2 - pointX; double angle2 = AngleBetweenVectors(v1, v2); if (v1.x * v2.y - v1.y * v2.x > 0) angle2 = -angle2; weights[i] = (tan(angle1 / 2.) + tan(angle2 / 2.)) / (Distance(p1, pointX) + 0.001); sum += weights[i]; } return sum; }
XnBool XnVPushDetector::IsPushDetected(const XnV3DVector& vImmediateVelocity, const XnV3DVector& vPreviousVelocity, XnFloat& fZAngle) { // Check if current motion is too slow if (vImmediateVelocity.Magnitude() < m_fPushImmediateMinVelocity) { return false; } if (vPreviousVelocity.Magnitude() < m_fPushPreviousMinVelocity) { fZAngle = AngleBetweenVectors(vImmediateVelocity, XnV3DVector(0,0,-1)); if (fZAngle < m_fPushMaxAngleFromZ) { xnLogVerbose(XNV_NITE_MASK_EVENTS, "Push Detector %s [0x%08x]: " "Immediate Velocity %5.3f over threshold %5.3f in the last %d ms (%d ms offset), " "Previous Velocity %5.3f under threshold %5.3f in the last %d ms (%d ms offset), " "Angle between Immediate and the Z Axis is %5.3f, under the threshold of %5.3f", GetListenerName(), this, vImmediateVelocity.Magnitude(), m_fPushImmediateMinVelocity, m_nPushImmediateDuration, m_nPushImmediateOffset, vPreviousVelocity.Magnitude(), m_fPushPreviousMinVelocity, m_nPushPreviousDuration, m_nPushPreviousOffset, fZAngle, m_fPushMaxAngleFromZ); return true; } return false; } XnFloat fAngle = AngleBetweenVectors(vPreviousVelocity, vImmediateVelocity); if (fAngle > m_fPushMinAngleImmediateAndPrevious) { fZAngle = AngleBetweenVectors(vImmediateVelocity, XnV3DVector(0,0,-1)); if (fZAngle < m_fPushMaxAngleFromZ) { xnLogVerbose(XNV_NITE_MASK_EVENTS, "Push Detector %s [0x%08x]: " "Immediate Velocity %5.3f over threshold %5.3f in the last %d ms (%d ms offset), " "Previous Velocity %5.3f over threshold %5.3f in the last %d ms (%d ms offset), " "Angle between Immediate and the Z Axis is %5.3f, under the threshold of %5.3f, " "Angle between Immediate and Previous direction is %5.3f, over the threshold of %5.3f", GetListenerName(), this, vImmediateVelocity.Magnitude(), m_fPushImmediateMinVelocity, m_nPushImmediateDuration, m_nPushImmediateOffset, vPreviousVelocity.Magnitude(), m_fPushPreviousMinVelocity, m_nPushPreviousDuration, m_nPushPreviousOffset, fZAngle, m_fPushMaxAngleFromZ, fAngle, m_fPushMinAngleImmediateAndPrevious); return true; } } return false; } // XnVPushDetector::IsPushDetected
int RenderScene(GameState *State, SDL_Renderer *Renderer) { SDL_RenderClear(Renderer); SDL_RenderCopy(Renderer, State->Background, NULL, NULL); Entity Player = State->Entities[State->PlayerEntity]; SDL_Rect DescRect; float Width = Player.Width * State->MeterToPixels; float Height = Player.Height * State->MeterToPixels; float CenterX = Player.Pos.x - 0.5f * Width; float CenterY = Player.Pos.y - 0.5f * Height; DescRect.x = CenterX; DescRect.y = CenterY; DescRect.w = Width; DescRect.h = Height; SDL_Point Center; Center.x = CenterX; Center.y = CenterY; vec2 NaturalDirection = {0, -1}; float Angle = AngleBetweenVectors(Player.Direction, NaturalDirection); char buffer[128]; sprintf(buffer, "Angle: %f\n", Angle); OutputDebugString(buffer); SDL_RenderCopyEx(Renderer, State->Pointer, NULL, &DescRect, Angle, NULL, SDL_FLIP_NONE); Angle = AngleBetweenVectors(Player.Vel, NaturalDirection); SDL_RenderCopyEx(Renderer, State->Player, NULL, &DescRect, Angle, NULL, SDL_FLIP_NONE); SDL_RenderCopyEx(Renderer, State->Circle, NULL, &DescRect, Angle, NULL, SDL_FLIP_NONE); SDL_RenderPresent(Renderer); return 0; }
float WeightedAngle(vec_t *vec1, vec_t *vec2) { float a = AngleBetweenVectors(vec1, vec2); if (a < 11.25f) { return 1; } else if (a < 22.5f) { return 0.5f; } else if (a < 45.0f) { return 0.25f; } else if (a < 90.0f) { return 0.125f; } return 0.05f; }
bool InsidePolygon(Vector3 vIntersection, Vector3 Poly[], long verticeCount)//判断交点是否在多边形内 { const double MATCH_FACTOR = 0.99; // 覆盖不需要的小数位 double Angle = 0.0; Vector3 vA, vB; for (int i = 0; i < verticeCount; i++) { vA = Poly[i] - vIntersection; vB = Poly[(i + 1) % verticeCount] - vIntersection; Angle += AngleBetweenVectors(vA, vB); } if(Angle >= (MATCH_FACTOR * (2.0 * PI)) ) // 弧度大于或等于2PI,在多边形内 return true; return false; }
bool InsidePolygon(CVector3 vIntersection, CVector3 Poly[], long verticeCount) { const double MATCH_FACTOR = 0.99; // Used to cover up the error in floating point double Angle = 0.0; // Initialize the angle CVector3 vA, vB; // Create temp vectors for (int i = 0; i < verticeCount; i++) // Go in a circle to each vertex and get the angle between { vA = Poly[i] - vIntersection; // Subtract the intersection point from the current vertex // Subtract the point from the next vertex vB = Poly[(i + 1) % verticeCount] - vIntersection; Angle += AngleBetweenVectors(vA, vB); // Find the angle between the 2 vectors and add them all up as we go along } if(Angle >= (MATCH_FACTOR * (2.0 * PI)) ) // If the angle is greater than 2 PI, (360 degrees) return true; // The point is inside of the polygon return false; // If you get here, it obviously wasn't inside the polygon, so Return FALSE }
void Projectile::TurnToTarget( float _dt ) { // Calculate the vector from this token to the Target's position D3DXVECTOR2 vToTarget(0,0); D3DXVECTOR2 tDefault(0,-1); D3DXVECTOR2 pos = ((BaseEntity*)m_Target)->GetPos() + ((BaseEntity*)m_Target)->GetImgCenter(); vToTarget.x = pos.x - (this->GetPos().x + this->GetImgCenter().x); vToTarget.y = pos.y - (this->GetPos().y + this->GetImgCenter().y); // Calculate forward vector D3DXVECTOR2 forward = Rotate2D( tDefault, this->GetRot() ); // calculate the angle between the vectors float angle = AngleBetweenVectors( vToTarget, forward ); if(Steering(forward, vToTarget) < 0.0f) this->SetRot(this->GetRot() - 3.0f*_dt); else this->SetRot(this->GetRot() + 3.0f*_dt); forward = Rotate2D( tDefault, this->GetRot() ); D3DXVec2Normalize(&forward,&forward); this->SetDir(forward); }
// Wandering code (based on old ACE movement code) void ACEMV_Wander(gentity_t * self) { vec3_t tmp; // do not move if(self->bs.next_move_time > level.time) return; // Special check for elevators, stand still until the ride comes to a complete stop. /* * FIXME if(self->groundentity != NULL && self->groundentity->use == Use_Plat) if(self->groundentity->moveinfo.state == STATE_UP || self->groundentity->moveinfo.state == STATE_DOWN) // only move when platform not { self->velocity[0] = 0; self->velocity[1] = 0; self->velocity[2] = 0; self->next_move_time = level.time + 500; return; } */ // touched jumppad last Frame? if(self->s.groundEntityNum == ENTITYNUM_NONE) { if(VectorLength(self->client->ps.velocity) > 120) { VectorNormalize2(self->client->ps.velocity, tmp); if(AngleBetweenVectors(self->bs.moveVector, tmp) >= 120) { // we might have been knocked back by someone or something .. if(!self->bs.moveTarget) { VectorCopy(tmp, self->bs.moveVector); ACEMV_ChangeBotAngle(self); } } } //ACEMV_ChangeBotAngle(self); //self->client->ps.velocity[0] = self->bs.moveVector[0] * 360; //self->client->ps.velocity[1] = self->bs.moveVector[1] * 360; //return; } // is there a target to move to if(self->bs.moveTarget) { ACEMV_MoveToGoal(self); } // swimming? VectorCopy(self->client->ps.origin, tmp); tmp[2] += 24; if(trap_PointContents(tmp, self->s.number) & MASK_WATER) { // if drowning and no node, move up if(self->client->airOutTime > 0) { self->client->pers.cmd.upmove = 1; self->bs.viewAngles[PITCH] = -45; } else self->client->pers.cmd.upmove = 15; self->client->pers.cmd.forwardmove = 100; } else { //self->client->airOutTime = 0; // probably shound not be messing with this, but } // lava? tmp[2] -= 48; if(trap_PointContents(tmp, self->s.number) & (CONTENTS_LAVA | CONTENTS_SLIME)) { // safe_bprintf(PRINT_MEDIUM,"lava jump\n"); self->bs.viewAngles[YAW] += random() * 360 - 180; self->client->pers.cmd.forwardmove = 127; self->client->pers.cmd.upmove = 127; return; } // check for special movement if we have a normal move (have to test) if(VectorLength(self->client->ps.velocity) < 37) { //if(random() > 0.1 && ACEMV_SpecialMove(self)) // return; //removed this because when wandering, the last thing you want is bots jumping //over things and going off ledges. It's better for them to just bounce around the map. self->bs.viewAngles[YAW] += random() * 180 - 90; if(ACEMV_CanMove(self, MOVE_FORWARD)) self->client->pers.cmd.forwardmove = 127; else if(ACEMV_CanMove(self, MOVE_BACK)) self->client->pers.cmd.forwardmove = -127; // if there is ground continue otherwise wait for next move if( /*!M_CheckBottom || */ self->s.groundEntityNum != ENTITYNUM_NONE) { if(ACEMV_CanMove(self, MOVE_FORWARD)) self->client->pers.cmd.forwardmove = 127; } return; } if(ACEMV_CheckEyes(self)) return; if(ACEMV_CanMove(self, MOVE_FORWARD)) self->client->pers.cmd.forwardmove = 127; }
void G_HomingMissile(gentity_t * ent) { gentity_t *target = NULL; gentity_t *blip = NULL; vec3_t dir, blipdir; vec_t angle; qboolean chaff; //qboolean ignorechaff = qfalse; const int HOMING_THINK_TIME = 60; // explode after 15 seconds without a hit if(ent->spawnTime + 15000 <= level.time) { G_ExplodeMissile(ent); return; } /* if(ent->parent->health <= 0) { ent->nextthink = level.time + 15000; ent->think = G_ExplodeMissile; return; } */ /* if(ent->parent && ent->parent->client) { ignorechaff = (ent->parent->client->ps.powerups[PW_ACCURACY] > 0); } */ while((blip = G_FindRadius(blip, ent->r.currentOrigin, 2000)) != NULL) { #if 0 if(blip->s.weapon == WP_CHAFF) { if(ignorechaff) { continue; } chaff = qtrue; } else #endif { chaff = qfalse; if(blip->client == NULL) continue; if(blip == ent->parent) continue; if(blip->health <= 0) continue; if(blip->client->sess.sessionTeam >= TEAM_SPECTATOR) continue; if((g_gametype.integer == GT_TEAM || g_gametype.integer == GT_CTF) && OnSameTeam(blip, ent->parent)) continue; } if(!G_IsVisible(ent, blip->r.currentOrigin)) continue; VectorSubtract(blip->r.currentOrigin, ent->r.currentOrigin, blipdir); if(chaff) { VectorScale(blipdir, 0.5, blipdir); } if((target == NULL) || (VectorLength(blipdir) < VectorLength(dir))) { if(chaff) { VectorScale(blipdir, 2, blipdir); } angle = AngleBetweenVectors(ent->r.currentAngles, blipdir); if(angle < 120.0f) { // We add it as our target target = blip; VectorCopy(blipdir, dir); } } } if(target == NULL) { ent->nextthink = level.time + HOMING_THINK_TIME; // + 10000; ent->think = G_HomingMissile; } else { // for exact trajectory calculation, set current point to base. VectorCopy(ent->r.currentOrigin, ent->s.pos.trBase); VectorNormalize(dir); // 0.5 is swing rate. VectorScale(dir, 0.5, dir); VectorAdd(dir, ent->r.currentAngles, dir); // turn nozzle to target angle VectorNormalize(dir); VectorCopy(dir, ent->r.currentAngles); // scale direction, put into trDelta if(g_rocketAcceleration.integer) { // use acceleration instead of linear velocity ent->s.pos.trType = TR_ACCELERATION; ent->s.pos.trAcceleration = g_rocketAcceleration.value; VectorScale(dir, g_rocketVelocity.value, ent->s.pos.trDelta); } else { ent->s.pos.trType = TR_LINEAR; VectorScale(dir, g_rocketVelocity.value * 0.25, ent->s.pos.trDelta); } ent->s.pos.trTime = level.time; SnapVector(ent->s.pos.trDelta); // save net bandwidth ent->nextthink = level.time + HOMING_THINK_TIME; // decrease this value also makes fast swing ent->think = G_HomingMissile; //G_Printf("targeting %s\n", target->classname); } }
/* ================ G_HomingMissile From XREAL r3036 ================ */ void G_HomingMissile(gentity_t * ent) { gentity_t *target = NULL; gentity_t *blip = NULL; vec3_t dir, blipdir; vec_t angle; const int HOMING_THINK_TIME = 60; #ifdef TA_WEAPSYS // XREAL: spawnTime // explode after 15 seconds without a hit if (bg_projectileinfo[ent->s.weapon].timetolive != -1 && ent->spawnTime + bg_projectileinfo[ent->s.weapon].timetolive <= level.time) { G_ExplodeMissile(ent); return; } #endif /* if(ent->parent->health <= 0) { ent->nextthink = level.time + 15000; ent->think = G_ExplodeMissile; return; } */ while((blip = G_FindRadius(blip, ent->r.currentOrigin, 2000)) != NULL) { if(blip->player == NULL) continue; if(blip == ent->parent) continue; if(blip->health <= 0) continue; if(blip->flags & FL_NOTARGET) continue; if(blip->player->sess.sessionTeam >= TEAM_SPECTATOR) continue; if(OnSameTeam(blip, ent->parent)) continue; if(!G_IsVisible(ent->s.number, ent->r.currentOrigin, blip->r.currentOrigin)) continue; VectorSubtract(blip->r.currentOrigin, ent->r.currentOrigin, blipdir); if((target == NULL) || (VectorLength(blipdir) < VectorLength(dir))) { angle = AngleBetweenVectors(ent->r.currentAngles, blipdir); if(angle < 120.0f) { // We add it as our target target = blip; VectorCopy(blipdir, dir); } } } if (target == NULL) { ent->nextthink = level.time + HOMING_THINK_TIME; // + 10000; ent->think = G_HomingMissile; } else { // for exact trajectory calculation, set current point to base. VectorCopy(ent->r.currentOrigin, ent->s.pos.trBase); VectorNormalize(dir); // 0.5 is swing rate. VectorScale(dir, 0.5, dir); VectorAdd(dir, ent->r.currentAngles, dir); // turn nozzle to target angle VectorNormalize(dir); VectorCopy(dir, ent->r.currentAngles); ent->s.pos.trTime = level.time; G_SetMissileVelocity(ent, dir, ent->s.weapon); ent->nextthink = level.time + HOMING_THINK_TIME; // decrease this value also makes fast swing ent->think = G_HomingMissile; //G_Printf("targeting %s\n", target->classname); } }
double CalculateWeightsVec(QPointF p, QVector<QPoint> *boundary, double *weights, QVector<int>& mask) { double sum = 0.; int size = boundary->size() - 1; CVector3f pointX; CVector3f p0, p1, p2; CVector3f v1, v2; pointX.x = p.x() + EPSILON; pointX.y = p.y() + EPSILON; pointX.z = .0; memset(weights, 0, sizeof(double) * size); for (int n = 0; n < mask.size(); ++n) { int i = mask[n]; QPoint pt = boundary->at(i); p0.x = boundary->at((i - 1 + size) % size).x(); p0.y = boundary->at((i - 1 + size) % size).y(); p0.z = .0; p1.x = boundary->at(i).x(); p1.y = boundary->at(i).y(); p1.z = 0.00001; p2.x = boundary->at((i + 1 + size) % size).x(); p2.y = boundary->at((i + 1 + size) % size).y(); p2.z = .0; v1 = p0 - pointX; v2 = p1 - pointX; double angle1 = AngleBetweenVectors(v1, v2); if (v1.x * v2.y - v1.y * v2.x > 0) angle1 = -angle1; v1 = v2; v2 = p2 - pointX; double angle2 = AngleBetweenVectors(v1, v2); if (v1.x * v2.y - v1.y * v2.x > 0) angle2 = -angle2; weights[i] = (tan(angle1 / 2.) + tan(angle2 / 2.)) / (Distance(p1, pointX) + 0.001); sum += weights[i]; } // for (int i = 0; i < size; i++) // { // QPoint pt = boundary->at(i); // // if (!mask.contains(i)) // if the boundary point is not marked // { // weights[i] = 0; // continue; // } // // p0.x = boundary->at((i - 1 + size) % size).x(); // p0.y = boundary->at((i - 1 + size) % size).y(); // p0.z = .0; // // p1.x = boundary->at(i).x(); // p1.y = boundary->at(i).y(); // p1.z = 0.00001; // // p2.x = boundary->at((i + 1 + size) % size).x(); // p2.y = boundary->at((i + 1 + size) % size).y(); // p2.z = .0; // // v1 = p0 - pointX; // v2 = p1 - pointX; // // double angle1 = AngleBetweenVectors(v1, v2); // if (v1.x * v2.y - v1.y * v2.x > 0) // angle1 = -angle1; // // v1 = v2; // v2 = p2 - pointX; // // double angle2 = AngleBetweenVectors(v1, v2); // if (v1.x * v2.y - v1.y * v2.x > 0) // angle2 = -angle2; // // weights[i] = (tan(angle1 / 2.) + tan(angle2 / 2.)) / (Distance(p1, pointX) + 0.001); // sum += weights[i]; // } return sum; }
void GLViewer::timerEvent (QTimerEvent *event) { if (resetTimer) { killTimer(event->timerId ()); resetTimer = false; if (enableGravity) { this->startTimer(200); } else { this->startTimer (200); } } QPoint point = mapFromGlobal(QCursor::pos ()); camera()->convertClickToLine(point, orig, dir); // Find the selectedPoint coordinates, using camera()->pointUnderPixel(). bool found; selectedPoint = camera()->pointUnderPixel(point, found); selectedPoint -= 0.01f*dir; // Small offset to make point clearly visible. if (enableGravity) { if ((qAbs(m_frame.translation ().z) > velocity) && (m_frame.translation ().z < 0)) { double liftAmount = fallZOffset(m_frame.translation ().z); this->oldZValue = m_frame.translation ().z; if (!m_frame.isManipulated ()) { if (liftAmount > 0) { m_frame.translate (0.0f, 0.0f, (float) gravityForce); velocity = 0 - liftAmount + gravityForce; } if (liftAmount < 0) { velocity += gravityForce; m_frame.translate (0.0f, 0.0f, (float) velocity); } } } else { m_frame.setTranslation ( m_frame.translation ().x, m_frame.translation ().y, 0.0f); this->oldZValue = m_frame.translation ().z; velocity = (-1 * (velocity - qAbs(m_frame.translation ().z))); if (qAbs(velocity) > gravityForce) { m_frame.translate (0.0f, 0.0f, (float) velocity); } else { m_frame.setTranslation ( m_frame.translation ().x, m_frame.translation ().y, 0.0f); velocity = 0; this->oldZValue = m_frame.translation ().z; } } } QString msg; msg.append("[OrientAxis->Viewdir, OrientAngle] Angle: "); msg.append(QString("%1").arg(AngleBetweenVectors (fromVec(camera()->orientation().axis ()), fromVec(camera()->viewDirection ())))); msg.append(" , "); msg.append(QString("%1").arg(camera()->orientation ().angle ())); msg.append(" | [Cam] Orient Axis [View Dir]: "); msg.append(stringFromVector3d(fromVec(camera()->orientation ().axis ()))); msg.append(QString(" [%1]").arg(stringFromVector3d(fromVec(camera()->viewDirection ())))); //camera()->setOrientation (Quaternion(camera()->orientation ().axis (), AngleBetweenVectors (fromVec(selectedPoint), fromVec(orig)))); emit this->sbMsg (msg); this->update (); }
/* ================== V_CalcSpectatorRefdef ================== */ void V_CalcSpectatorRefdef ( struct ref_params_s * pparams ) { vec3_t angles; static viewinterp_t ViewInterp; static float bob = 0.0f; static vec3_t velocity ( 0.0f, 0.0f, 0.0f); static int lastWeaponModelIndex = 0; static int lastViewModelIndex = 0; cl_entity_t * ent = gEngfuncs.GetEntityByIndex( g_iUser2 ); cl_entity_t * gunModel = gEngfuncs.GetViewModel(); static float lasttime; static float lastang[3]; static float lastorg[3]; vec3_t delta; pparams->onlyClientDraw = false; // refresh position VectorCopy ( pparams->simorg, v_sim_org ); // get old values VectorCopy ( pparams->cl_viewangles, v_cl_angles ); VectorCopy ( pparams->viewangles, v_angles ); VectorCopy ( pparams->vieworg, v_origin ); v_frametime = pparams->frametime; if ( pparams->nextView == 0 ) { // first renderer cycle, full screen switch ( g_iUser1 ) { case OBS_CHASE_LOCKED: V_GetChasePos( g_iUser2, NULL, v_origin, v_angles ); break; case OBS_CHASE_FREE: V_GetChasePos( g_iUser2, v_cl_angles, v_origin, v_angles ); break; case OBS_ROAMING : VectorCopy (v_cl_angles, v_angles); VectorCopy (v_sim_org, v_origin); break; case OBS_IN_EYE : V_GetInEyePos( g_iUser2, v_origin, v_angles ); break; case OBS_MAP_FREE : pparams->onlyClientDraw = true; V_GetMapFreePosition( v_cl_angles, v_origin, v_angles ); break; case OBS_MAP_CHASE : pparams->onlyClientDraw = true; V_GetMapChasePosition( g_iUser2, v_cl_angles, v_origin, v_angles ); break; } if ( gHUD.m_Spectator.m_pip->value ) pparams->nextView = 1; // force a second renderer view gHUD.m_Spectator.m_iDrawCycle = 0; } else { // second renderer cycle, inset window // set inset parameters pparams->viewport[0] = XRES(gHUD.m_Spectator.m_OverviewData.insetWindowX); // change viewport to inset window pparams->viewport[1] = YRES(gHUD.m_Spectator.m_OverviewData.insetWindowY); pparams->viewport[2] = XRES(gHUD.m_Spectator.m_OverviewData.insetWindowWidth); pparams->viewport[3] = YRES(gHUD.m_Spectator.m_OverviewData.insetWindowHeight); pparams->nextView = 0; // on further view pparams->onlyClientDraw = false; // override some settings in certain modes switch ( (int)gHUD.m_Spectator.m_pip->value ) { case INSET_CHASE_FREE : V_GetChasePos( g_iUser2, v_cl_angles, v_origin, v_angles ); break; case INSET_IN_EYE : V_GetInEyePos( g_iUser2, v_origin, v_angles ); break; case INSET_MAP_FREE : pparams->onlyClientDraw = true; V_GetMapFreePosition( v_cl_angles, v_origin, v_angles ); break; case INSET_MAP_CHASE : pparams->onlyClientDraw = true; if ( g_iUser1 == OBS_ROAMING ) V_GetMapChasePosition( 0, v_cl_angles, v_origin, v_angles ); else V_GetMapChasePosition( g_iUser2, v_cl_angles, v_origin, v_angles ); break; } gHUD.m_Spectator.m_iDrawCycle = 1; } // do the smoothing only once per frame, not in roaming or map mode if ( (gHUD.m_Spectator.m_iDrawCycle == 0) && (g_iUser1 == OBS_IN_EYE) ) { // smooth angles VectorSubtract( v_angles, lastang, delta ); if ( Length( delta ) != 0.0f ) { VectorCopy( v_angles, ViewInterp.Angles[ ViewInterp.CurrentAngle & ORIGIN_MASK ] ); ViewInterp.AngleTime[ ViewInterp.CurrentAngle & ORIGIN_MASK ] = pparams->time; ViewInterp.CurrentAngle++; VectorCopy( v_angles, lastang ); } if ( cl_vsmoothing && cl_vsmoothing->value ) { int foundidx; int i; float t; t = pparams->time - cl_vsmoothing->value; for ( i = 1; i < ORIGIN_MASK; i++ ) { foundidx = ViewInterp.CurrentAngle - 1 - i; if ( ViewInterp.AngleTime[ foundidx & ORIGIN_MASK ] <= t ) break; } if ( i < ORIGIN_MASK && ViewInterp.AngleTime[ foundidx & ORIGIN_MASK ] != 0.0 ) { // Interpolate double dt; float da; vec3_t v1,v2; AngleVectors( ViewInterp.Angles[ foundidx & ORIGIN_MASK ], v1, NULL, NULL ); AngleVectors( ViewInterp.Angles[ (foundidx + 1) & ORIGIN_MASK ], v2, NULL, NULL ); da = AngleBetweenVectors( v1, v2 ); dt = ViewInterp.AngleTime[ (foundidx + 1) & ORIGIN_MASK ] - ViewInterp.AngleTime[ foundidx & ORIGIN_MASK ]; if ( dt > 0.0 && ( da < 22.5f) ) { double frac; frac = ( t - ViewInterp.AngleTime[ foundidx & ORIGIN_MASK] ) / dt; frac = min( 1.0, frac ); // interpolate angles InterpolateAngles( ViewInterp.Angles[ foundidx & ORIGIN_MASK ], ViewInterp.Angles[ (foundidx + 1) & ORIGIN_MASK ], v_angles, frac ); } } } // smooth origin VectorSubtract( v_origin, lastorg, delta ); if ( Length( delta ) != 0.0 ) { VectorCopy( v_origin, ViewInterp.Origins[ ViewInterp.CurrentOrigin & ORIGIN_MASK ] ); ViewInterp.OriginTime[ ViewInterp.CurrentOrigin & ORIGIN_MASK ] = pparams->time; ViewInterp.CurrentOrigin++; VectorCopy( v_origin, lastorg ); } // don't smooth in roaming (already smoothd), if ( cl_vsmoothing && cl_vsmoothing->value ) { int foundidx; int i; float t; t = pparams->time - cl_vsmoothing->value; for ( i = 1; i < ORIGIN_MASK; i++ ) { foundidx = ViewInterp.CurrentOrigin - 1 - i; if ( ViewInterp.OriginTime[ foundidx & ORIGIN_MASK ] <= t ) break; } if ( i < ORIGIN_MASK && ViewInterp.OriginTime[ foundidx & ORIGIN_MASK ] != 0.0 ) { // Interpolate vec3_t delta; double frac; double dt; vec3_t neworg; dt = ViewInterp.OriginTime[ (foundidx + 1) & ORIGIN_MASK ] - ViewInterp.OriginTime[ foundidx & ORIGIN_MASK ]; if ( dt > 0.0 ) { frac = ( t - ViewInterp.OriginTime[ foundidx & ORIGIN_MASK] ) / dt; frac = min( 1.0, frac ); VectorSubtract( ViewInterp.Origins[ ( foundidx + 1 ) & ORIGIN_MASK ], ViewInterp.Origins[ foundidx & ORIGIN_MASK ], delta ); VectorMA( ViewInterp.Origins[ foundidx & ORIGIN_MASK ], frac, delta, neworg ); // Dont interpolate large changes if ( Length( delta ) < 64 ) { VectorCopy( neworg, v_origin ); } } } } } // Hack in weapon model: if ( (g_iUser1 == OBS_IN_EYE || gHUD.m_Spectator.m_pip->value == INSET_IN_EYE) && ent && g_iUser2 ) { // get position for weapon model VectorCopy( v_origin, gunModel->origin); VectorCopy( v_angles, gunModel->angles); // add idle tremble gunModel->angles[PITCH]*=-1; // calculate player velocity float timeDiff = ent->curstate.msg_time - ent->prevstate.msg_time; if ( timeDiff > 0 ) { vec3_t distance; VectorSubtract(ent->prevstate.origin, ent->curstate.origin, distance); VectorScale(distance, 1/timeDiff, distance ); velocity[0] = velocity[0]*0.66f + distance[0]*0.33f; velocity[1] = velocity[1]*0.66f + distance[1]*0.33f; velocity[2] = velocity[2]*0.66f + distance[2]*0.33f; VectorCopy(velocity, pparams->simvel); pparams->onground = 1; bob = V_CalcBob( pparams ); } vec3_t forward; AngleVectors(v_angles, forward, NULL, NULL ); for ( int i = 0; i < 3; i++ ) { gunModel->origin[ i ] += bob * 0.4 * forward[ i ]; } // throw in a little tilt. gunModel->angles[YAW] -= bob * 0.5; gunModel->angles[ROLL] -= bob * 1; gunModel->angles[PITCH] -= bob * 0.3; VectorCopy( gunModel->angles, gunModel->curstate.angles ); VectorCopy( gunModel->angles, gunModel->latched.prevangles ); if ( lastWeaponModelIndex != ent->curstate.weaponmodel ) { // weapon model changed lastWeaponModelIndex = ent->curstate.weaponmodel; lastViewModelIndex = V_FindViewModelByWeaponModel( lastWeaponModelIndex ); if ( lastViewModelIndex ) { gEngfuncs.pfnWeaponAnim(0,0); // reset weapon animation } else { // model not found gunModel->model = NULL; // disable weaopn model lastWeaponModelIndex = lastViewModelIndex = 0; } } if ( lastViewModelIndex ) { gunModel->model = IEngineStudio.GetModelByIndex( lastViewModelIndex ); gunModel->curstate.modelindex = lastViewModelIndex; gunModel->curstate.frame = 0; gunModel->curstate.colormap = 0; gunModel->index = g_iUser2; } else { gunModel->model = NULL; // disable weaopn model } } else { gunModel->model = NULL; // disable weaopn model lastWeaponModelIndex = lastViewModelIndex = 0; } lasttime = pparams->time; // write back new values into pparams VectorCopy ( v_angles, pparams->viewangles ) VectorCopy ( v_origin, pparams->vieworg ); }