bool AAirMoveType::CanLandOnPad(const float3& padPos) const { // once distance to pad becomes smaller than current braking distance, switch states // (but do not allow state-switch until the aircraft is heading ~directly toward pad) // braking distance is 0.5*a*t*t where t is v/a --> 0.5*a*((v*v)/(a*a)) --> 0.5*v*v*(1/a) // FIXME: // apply N-frame lookahead when deciding to switch state for strafing aircraft // (see comments in StrafeAirMoveType::UpdateLanding, overshooting prevention) // the lookahead is roughly based on the time to descend to pad-target altitude const float3 flatFrontDir = (float3(owner->frontdir)).Normalize2D(); const float brakingDistSq = Square(0.5f * owner->speed.SqLength2D() / decRate); const float descendDistSq = Square(maxSpeed * ((owner->pos.y - padPos.y) / altitudeRate)) * owner->unitDef->IsStrafingAirUnit(); if (padPos.SqDistance2D(owner->pos) > std::max(brakingDistSq, descendDistSq)) return false; if (owner->unitDef->IsStrafingAirUnit()) { // horizontal guide if (flatFrontDir.dot((padPos - owner->pos).SafeNormalize2D()) < 0.985f) return false; // vertical guide if (flatFrontDir.dot((padPos - owner->pos).SafeNormalize()) < 0.707f) return false; } return true; }
int CLaserProjectile::ShieldRepulse(CPlasmaRepulser* shield, float3 shieldPos, float shieldForce, float shieldMaxSpeed) { if (!luaMoveCtrl) { const float3 rdir = (pos - shieldPos).Normalize(); if (rdir.dot(speed) < 0.0f) { speed -= (rdir * rdir.dot(speed) * 2.0f); dir = speed; dir.Normalize(); return 1; } } return 0; }
void CubeMapHandler::CreateSpecularFace( unsigned int texType, int size, const float3& cdir, const float3& xdif, const float3& ydif, float specExponent) { unsigned char* buf = new unsigned char[size * size * 4]; for (int y = 0; y < size; ++y) { for (int x = 0; x < size; ++x) { const float3 dir = (cdir + (xdif * (x + 0.5f)) / size + (ydif * (y + 0.5f)) / size).Normalize(); const float dot = std::max(0.0f, dir.dot(mapInfo->light.sunDir)); const float spec = std::min(1.0f, pow(dot, specExponent) + pow(dot, 3.0f) * 0.25f); buf[(y * size + x) * 4 + 0] = (unsigned char) (mapInfo->light.unitSpecularColor.x * spec * 255); buf[(y * size + x) * 4 + 1] = (unsigned char) (mapInfo->light.unitSpecularColor.y * spec * 255); buf[(y * size + x) * 4 + 2] = (unsigned char) (mapInfo->light.unitSpecularColor.z * spec * 255); buf[(y * size + x) * 4 + 3] = 255; } } //! note: no mipmaps, cubemap linear filtering is broken glTexImage2D(texType, 0, GL_RGBA8, size, size, 0, GL_RGBA,GL_UNSIGNED_BYTE, buf); delete[] buf; }
void CPlasmaRepulser::NewProjectile(CWeaponProjectile* p) { if (weaponDef->smartShield && teamHandler->AlliedTeams(p->owner()->team, owner->team)) { return; } float3 dir = p->speed; if (p->targetPos != ZeroVector) { dir = p->targetPos - p->pos; // assume that it will travel roughly in the direction of the targetpos if it have one } dir.y = 0.0f; dir.SafeNormalize(); const float3 dif = owner->pos - p->pos; if (weaponDef->exteriorShield && (dif.SqLength() < sqRadius)) { return; } const float closeLength = std::max(0.0f, dif.dot(dir)); const float3 closeVect = dif - dir * closeLength; const float closeDist = closeVect.SqLength2D(); // TODO: this isn't good enough in case shield is mounted on a mobile unit, // and this unit moves relatively fast compared to the projectile. // it should probably be: radius + closeLength / |projectile->speed| * |owner->speed|, // but this still doesn't solve anything for e.g. teleporting shields. if (closeDist < Square(radius * 1.5f)) { incomingProjectiles[p->id] = p; AddDeathDependence(p, DEPENDENCE_REPULSED); } }
CSmokeTrailProjectile::CSmokeTrailProjectile( const float3& pos1, const float3& pos2, const float3& dir1, const float3& dir2, CUnit* owner, bool firstSegment, bool lastSegment, float size, int time, float color, bool drawTrail, CProjectile* drawCallback, AtlasedTexture* texture): CProjectile((pos1 + pos2) * 0.5f, ZeroVector, owner, false, false, false), pos1(pos1), pos2(pos2), orgSize(size), creationTime(gs->frameNum), lifeTime(time), color(color), dir1(dir1), dir2(dir2), drawTrail(drawTrail), drawSegmented(false), firstSegment(firstSegment), lastSegment(lastSegment), drawCallbacker(drawCallback), texture(texture) { checkCol = false; castShadow = true; // if no custom texture is defined, use the default texture // Note that this will crash anyway (no idea why) so never have a null texture! if (texture == NULL) { texture = projectileDrawer->smoketrailtex; } if (!drawTrail) { const float dist = pos1.distance(pos2); dirpos1 = pos1 - dir1 * dist * 0.33f; dirpos2 = pos2 + dir2 * dist * 0.33f; } else if (dir1.dot(dir2) < 0.98f) { const float dist = pos1.distance(pos2); dirpos1 = pos1 - dir1 * dist * 0.33f; dirpos2 = pos2 + dir2 * dist * 0.33f; // float3 mp = (pos1 + pos2) / 2; midpos = CalcBeizer(0.5f, pos1, dirpos1, dirpos2, pos2); middir = (dir1 + dir2).ANormalize(); drawSegmented = true; } SetRadiusAndHeight(pos1.distance(pos2), 0.0f); if ((pos.y - ground->GetApproximateHeight(pos.x, pos.z)) > 10) { useAirLos = true; } }
float CShadowHandler::GetOrthoProjectedMapRadius(const float3& sunDir, float3& projectionMidPos) const { // to fit the map inside the frustum, we need to know // the distance from one corner to its opposing corner // // this distance is maximal when the sun direction is // orthogonal to the diagonal, but in other cases we // can gain some precision by projecting the diagonal // onto a vector orthogonal to the sun direction and // using the length of that projected vector instead // // note: "radius" is actually the diameter static const float maxMapDiameter = math::sqrtf(Square(gs->mapx * SQUARE_SIZE) + Square(gs->mapy * SQUARE_SIZE)); static float curMapDiameter = 0.0f; static float3 sunDir3D = ZeroVector; if ((sunDir3D != sunDir)) { float3 sunDir2D; float3 mapVerts[2]; sunDir3D = sunDir; sunDir2D.x = sunDir3D.x; sunDir2D.z = sunDir3D.z; sunDir2D.ANormalize(); if (sunDir2D.x >= 0.0f) { if (sunDir2D.z >= 0.0f) { // use diagonal vector from top-right to bottom-left mapVerts[0] = float3(gs->mapx * SQUARE_SIZE, 0.0f, 0.0f); mapVerts[1] = float3( 0.0f, 0.0f, gs->mapy * SQUARE_SIZE); } else { // use diagonal vector from top-left to bottom-right mapVerts[0] = float3( 0.0f, 0.0f, 0.0f); mapVerts[1] = float3(gs->mapx * SQUARE_SIZE, 0.0f, gs->mapy * SQUARE_SIZE); } } else { if (sunDir2D.z >= 0.0f) { // use diagonal vector from bottom-right to top-left mapVerts[0] = float3(gs->mapx * SQUARE_SIZE, 0.0f, gs->mapy * SQUARE_SIZE); mapVerts[1] = float3( 0.0f, 0.0f, 0.0f); } else { // use diagonal vector from bottom-left to top-right mapVerts[0] = float3( 0.0f, 0.0f, gs->mapy * SQUARE_SIZE); mapVerts[1] = float3(gs->mapx * SQUARE_SIZE, 0.0f, 0.0f); } } const float3 v1 = (mapVerts[1] - mapVerts[0]).ANormalize(); const float3 v2 = float3(-sunDir2D.z, 0.0f, sunDir2D.x); curMapDiameter = maxMapDiameter * v2.dot(v1); projectionMidPos.x = (gs->mapx * SQUARE_SIZE) * 0.5f; projectionMidPos.z = (gs->mapy * SQUARE_SIZE) * 0.5f; projectionMidPos.y = ground->GetHeightReal(projectionMidPos.x, projectionMidPos.z, false); } return curMapDiameter; }
float3 refract(float3 inDir, float3 normal) { float ri = refractiveIndex; float cosa = -normal.dot(inDir); if(cosa < 0) { cosa = -cosa; normal = -normal; ri = 1 / ri; } float disc = 1 - (1 - cosa * cosa) / ri / ri; if(disc < 0) return reflect(inDir, normal); return inDir * (1.0 / ri) + normal * (cosa / ri - sqrt(disc)); }
float CPlasmaRepulser::NewBeam(CWeapon* emitter, float3 start, float3 dir, float length, float3& newDir) { if (!isEnabled) { return -1.0f; } // ::Update handles projectile <-> shield interactions for normal weapons, but // does not get called when the owner is stunned (CUnit::Update returns early) // BeamLasers and LightningCannons are hitscan (their projectiles do not move), // they call InterceptHandler to figure out if a shield is in the way so check // the stunned-state here keep things consistent if (owner->stunned) { return -1.0f; } if (emitter->weaponDef->damages[0] > curPower) { return -1.0f; } if (weaponDef->smartShield && teamHandler->AlliedTeams(emitter->owner->team, owner->team)) { return -1.0f; } const float3 dif = weaponPos - start; if (weaponDef->exteriorShield && dif.SqLength() < sqRadius) { return -1.0f; } const float closeLength = dif.dot(dir); if (closeLength < 0.0f) { return -1.0f; } const float3 closeVect = dif - dir * closeLength; const float tmp = sqRadius - closeVect.SqLength(); if ((tmp > 0.0f) && (length > (closeLength - math::sqrt(tmp)))) { const float colLength = closeLength - math::sqrt(tmp); const float3 colPoint = start + dir * colLength; const float3 normal = (colPoint - weaponPos).Normalize(); newDir = dir - normal * normal.dot(dir) * 2; return colLength; } return -1.0f; }
static inline bool AABBInOriginPlane(const float3& plane, const float3& camPos, const float3& mins, const float3& maxs) { float3 fp; // far point fp.x = (plane.x > 0.0f) ? mins.x : maxs.x; fp.y = (plane.y > 0.0f) ? mins.y : maxs.y; fp.z = (plane.z > 0.0f) ? mins.z : maxs.z; return (plane.dot(fp - camPos) < 0.0f); }
bool CCamera::InView(const float3& p, float radius) const { const float3 t(p - pos); if ((t.dot(rgtFrustumSideDir) > radius) || (t.dot(lftFrustumSideDir) > radius) || (t.dot(botFrustumSideDir) > radius) || (t.dot(topFrustumSideDir) > radius)) { return false; } const float lsq = t.SqLength(); if (lsq > Square(globalRendering->viewRange)) { return false; } return true; }
virtual float3 shade(float3 normal, float3 viewDir, float3 lightDir, float3 lightPowerDensity) { float cosTheta = normal.dot(lightDir); if(cosTheta < 0) { return float3(0,0,0); } float3 diffuse = lightPowerDensity * kd * cosTheta; float3 halfway = (viewDir + lightDir).normalize(); float cosDelta = normal.dot(halfway); if(cosDelta < 0) { return diffuse; } return lightPowerDensity * ks * pow(cosDelta, shininess) + diffuse; }
CStarburstProjectile::CStarburstProjectile(const ProjectileParams& params, float areaOfEffect, float maxSpeed, float tracking, int uptime, float maxRange, float3 aimError) : CWeaponProjectile(params) , tracking(tracking) , maxSpeed(maxSpeed) , acceleration(0.f) , areaOfEffect(areaOfEffect) , age(0) , oldSmoke(pos) , aimError(aimError) , drawTrail(true) , numParts(0) , doturn(true) , curCallback(NULL) , missileAge(0) , distanceToTravel(maxRange) , curTracerPart(0) { projectileType = WEAPON_STARBURST_PROJECTILE; this->uptime = uptime; if (weaponDef) { if (weaponDef->flighttime == 0) { ttl = (int) std::min(3000.0f, uptime + weaponDef->range / maxSpeed + 100); } else { ttl = weaponDef->flighttime; } } maxGoodDif = math::cos(tracking * 0.6f); curSpeed = speed.Length(); dir = speed / curSpeed; oldSmokeDir = dir; const float3 camDir = (pos - camera->pos).ANormalize(); const float camDist = (camera->pos.distance(pos) * 0.2f) + ((1.0f - math::fabs(camDir.dot(dir))) * 3000); drawTrail = (camDist >= 200.0f); drawRadius = maxSpeed * 8.0f; for (int a = 0; a < NUM_TRACER_PARTS; ++a) { tracerParts[a].dir = dir; tracerParts[a].pos = pos; tracerParts[a].speedf = curSpeed; tracerParts[a].ageMods.resize(std::floor((curSpeed + 0.6f) / TRACER_PARTS_STEP), 1.0f); } castShadow = true; #ifdef TRACE_SYNC tracefile << "[" << __FUNCTION__ << "] "; tracefile << pos.x << " " << pos.y << " " << pos.z << " " << speed.x << " " << speed.y << " " << speed.z << "\n"; #endif cegID = gCEG->Load(explGenHandler, (weaponDef != NULL)? weaponDef->cegTag: ""); }
bool CWeapon::TryTarget(const float3& tgtPos, bool /*userTarget*/, CUnit* targetUnit) { if (targetUnit && !(onlyTargetCategory & targetUnit->category)) { return false; } if (targetUnit && ((targetUnit->isDead && (modInfo.fireAtKilled == 0)) || (targetUnit->crashing && (modInfo.fireAtCrashing == 0)))) { return false; } if (weaponDef->stockpile && !numStockpiled) { return false; } float3 targetPos = tgtPos; float3 targetVec = targetPos - weaponMuzzlePos; float3 targetDir = targetVec; float heightDiff = 0.0f; // negative when target below owner float weaponRange = 0.0f; // range modified by heightDiff and cylinderTargetting bool targetDirNormalized = false; if (targetBorder != 0.0f && targetUnit != NULL) { // adjust the length of <targetVec> based on the targetBorder factor targetDirNormalized = AdjustTargetVectorLength(targetUnit, targetPos, targetVec, targetDir); targetPos.y = weaponPos.y + targetVec.y; } heightDiff = targetPos.y - owner->pos.y; if (targetUnit == NULL || cylinderTargetting < 0.01f) { // check range in a sphere (with extra radius <heightDiff * heightMod>) weaponRange = GetRange2D(heightDiff * heightMod); } else { // check range in a cylinder (with height <cylinderTargetting * range>) if ((cylinderTargetting * range) > (math::fabsf(heightDiff) * heightMod)) { weaponRange = GetRange2D(0.0f); } } if (targetVec.SqLength2D() >= (weaponRange * weaponRange)) return false; if (maxMainDirAngleDif > -0.999f) { const float3 targetNormDir = targetDirNormalized? targetDir: targetDir.SafeNormalize(); const float3 modMainDir = owner->frontdir * mainDir.z + owner->rightdir * mainDir.x + owner->updir * mainDir.y; if (modMainDir.dot(targetNormDir) < maxMainDirAngleDif) return false; } return true; }
float CShadowHandler::GetOrthoProjectedMapRadius(const float3& sunDir, float3& projPos) { // to fit the map inside the frustum, we need to know // the distance from one corner to its opposing corner // // this distance is maximal when the sun direction is // orthogonal to the diagonal, but in other cases we // can gain some precision by projecting the diagonal // onto a vector orthogonal to the sun direction and // using the length of that projected vector instead // const float maxMapDiameter = readMap->GetBoundingRadius() * 2.0f; static float curMapDiameter = 0.0f; // recalculate pos only if the sun-direction has changed if (sunProjDir != sunDir) { sunProjDir = sunDir; float3 sunDirXZ = (sunDir * XZVector).ANormalize(); float3 mapVerts[2]; if (sunDirXZ.x >= 0.0f) { if (sunDirXZ.z >= 0.0f) { // use diagonal vector from top-right to bottom-left mapVerts[0] = float3(mapDims.mapx * SQUARE_SIZE, 0.0f, 0.0f); mapVerts[1] = float3( 0.0f, 0.0f, mapDims.mapy * SQUARE_SIZE); } else { // use diagonal vector from top-left to bottom-right mapVerts[0] = float3( 0.0f, 0.0f, 0.0f); mapVerts[1] = float3(mapDims.mapx * SQUARE_SIZE, 0.0f, mapDims.mapy * SQUARE_SIZE); } } else { if (sunDirXZ.z >= 0.0f) { // use diagonal vector from bottom-right to top-left mapVerts[0] = float3(mapDims.mapx * SQUARE_SIZE, 0.0f, mapDims.mapy * SQUARE_SIZE); mapVerts[1] = float3( 0.0f, 0.0f, 0.0f); } else { // use diagonal vector from bottom-left to top-right mapVerts[0] = float3( 0.0f, 0.0f, mapDims.mapy * SQUARE_SIZE); mapVerts[1] = float3(mapDims.mapx * SQUARE_SIZE, 0.0f, 0.0f); } } const float3 v1 = (mapVerts[1] - mapVerts[0]).ANormalize(); const float3 v2 = float3(-sunDirXZ.z, 0.0f, sunDirXZ.x); curMapDiameter = maxMapDiameter * v2.dot(v1); projPos.x = (mapDims.mapx * SQUARE_SIZE) * 0.5f; projPos.z = (mapDims.mapy * SQUARE_SIZE) * 0.5f; projPos.y = CGround::GetHeightReal(projPos.x, projPos.z, false); } return curMapDiameter; }
CSmokeTrailProjectile::CSmokeTrailProjectile( CUnit* owner, const float3& pos1, const float3& pos2, const float3& dir1, const float3& dir2, bool firstSegment, bool lastSegment, float size, int time, float color, bool drawTrail, CProjectile* drawCallback, AtlasedTexture* texture ): CProjectile((pos1 + pos2) * 0.5f, ZeroVector, owner, false, false, false), pos1(pos1), pos2(pos2), orgSize(size), creationTime(gs->frameNum), lifeTime(time), color(color), dir1(dir1), dir2(dir2), drawTrail(drawTrail), drawSegmented(false), firstSegment(firstSegment), lastSegment(lastSegment), drawCallbacker(drawCallback), texture(texture == NULL ? projectileDrawer->smoketrailtex : texture) { checkCol = false; castShadow = true; if (!drawTrail) { const float dist = pos1.distance(pos2); dirpos1 = pos1 - dir1 * dist * 0.33f; dirpos2 = pos2 + dir2 * dist * 0.33f; } else if (dir1.dot(dir2) < 0.98f) { const float dist = pos1.distance(pos2); dirpos1 = pos1 - dir1 * dist * 0.33f; dirpos2 = pos2 + dir2 * dist * 0.33f; // float3 mp = (pos1 + pos2) / 2; midpos = CalcBeizer(0.5f, pos1, dirpos1, dirpos2, pos2); middir = (dir1 + dir2).ANormalize(); drawSegmented = true; } SetRadiusAndHeight(pos1.distance(pos2), 0.0f); if ((pos.y - CGround::GetApproximateHeight(pos.x, pos.z)) > 10) { useAirLos = true; } }
/** * helper for TestCone * @return true if object <o> is in the firing cone, false otherwise */ inline static bool TestConeHelper( const float3& pos3D, const float3& dir3D, const float length, const float spread, const CSolidObject* obj) { const CollisionVolume* cv = obj->collisionVolume; const float3 objVec3D = cv->GetWorldSpacePos(obj, ZeroVector) - pos3D; const float objDst1D = Clamp(objVec3D.dot(dir3D), 0.0f, length); const float coneSize = math::fabs(objDst1D) * spread + 1.0f; // theoretical impact position assuming no spread const float3 expVec3D = dir3D * objDst1D; const float3 expPos3D = pos3D + expVec3D; bool ret = false; if (obj->GetBlockingMapID() < unitHandler->MaxUnits()) { if (!ret) { ret = ((cv->GetPointSurfaceDistance(static_cast<const CUnit*>(obj), NULL, pos3D) - coneSize) <= 0.0f); } if (!ret) { ret = ((cv->GetPointSurfaceDistance(static_cast<const CUnit*>(obj), NULL, expPos3D) - coneSize) <= 0.0f); } } else { if (!ret) { ret = ((cv->GetPointSurfaceDistance(static_cast<const CFeature*>(obj), NULL, pos3D) - coneSize) <= 0.0f); } if (!ret) { ret = ((cv->GetPointSurfaceDistance(static_cast<const CFeature*>(obj), NULL, expPos3D) - coneSize) <= 0.0f); } } if (globalRendering->drawdebugtraceray && (!GML::SimEnabled() || Threading::IsSimThread())) { #define go geometricObjects if (ret) { go->SetColor(go->AddLine(expPos3D - (UpVector * expPos3D.dot(UpVector)), expPos3D, 3, 1, GAME_SPEED), 1.0f, 0.0f, 0.0f, 1.0f); } else { go->SetColor(go->AddLine(expPos3D - (UpVector * expPos3D.dot(UpVector)), expPos3D, 3, 1, GAME_SPEED), 0.0f, 1.0f, 0.0f, 1.0f); } #undef go } return ret; }
bool CCamera::InView(const float3 &p, float radius) { const float3 t = (p - pos); const float l = t.Length(); if (l < 50.0f) { return true; } else if (l > gu->viewRange) { return false; } if ((t.dot(rightside) > radius) || (t.dot(leftside) > radius) || (t.dot(bottom) > radius) || (t.dot(top) > radius)) { return false; } return true; }
bool CCamera::InView(const float3& p, float radius) { const float3 t = (p - pos); const float lsq = t.SqLength(); if (lsq < 2500.0f) { return true; } else if (lsq > Square(globalRendering->viewRange)) { return false; } if ((t.dot(rightside) > radius) || (t.dot(leftside) > radius) || (t.dot(bottom) > radius) || (t.dot(top) > radius)) { return false; } return true; }
/** * GetSelectionBoxCoeff * returns the topright & bottomleft corner positions of the SelectionBox in (cam->right, cam->up)-space */ void CMouseHandler::GetSelectionBoxCoeff(const float3& pos1, const float3& dir1, const float3& pos2, const float3& dir2, float2& topright, float2& btmleft) { float dist = ground->LineGroundCol(pos1, pos1 + dir1 * globalRendering->viewRange * 1.4f, false); if(dist < 0) dist = globalRendering->viewRange * 1.4f; float3 gpos1 = pos1 + dir1 * dist; dist = ground->LineGroundCol(pos2, pos2 + dir2 * globalRendering->viewRange * 1.4f, false); if(dist < 0) dist = globalRendering->viewRange * 1.4f; float3 gpos2 = pos2 + dir2 * dist; const float3 cdir1 = (gpos1 - camera->pos).ANormalize(); const float3 cdir2 = (gpos2 - camera->pos).ANormalize(); // prevent DivByZero float cdir1_fw = cdir1.dot(camera->forward); if (cdir1_fw == 0.0f) cdir1_fw = 0.0001f; float cdir2_fw = cdir2.dot(camera->forward); if (cdir2_fw == 0.0f) cdir2_fw = 0.0001f; // one corner of the rectangle topright.x = cdir1.dot(camera->right) / cdir1_fw; topright.y = cdir1.dot(camera->up) / cdir1_fw; // opposite corner btmleft.x = cdir2.dot(camera->right) / cdir2_fw; btmleft.y = cdir2.dot(camera->up) / cdir2_fw; // sort coeff so topright really is the topright corner if (topright.x < btmleft.x) std::swap(topright.x, btmleft.x); if (topright.y < btmleft.y) std::swap(topright.y, btmleft.y); }
int CFlameProjectile::ShieldRepulse(CPlasmaRepulser* shield, float3 shieldPos, float shieldForce, float shieldMaxSpeed) { if (!luaMoveCtrl) { const float3 rdir = (pos - shieldPos).Normalize(); if (rdir.dot(speed) < shieldMaxSpeed) { speed += (rdir * shieldForce); return 2; } } return 0; }
int CExplosiveProjectile::ShieldRepulse(const float3& shieldPos, float shieldForce, float shieldMaxSpeed) { if (luaMoveCtrl) return 0; const float3 rdir = (pos - shieldPos).Normalize(); if (rdir.dot(speed) < shieldMaxSpeed) { SetVelocityAndSpeed(speed + (rdir * shieldForce)); return 2; } return 0; }
/** * helper for TestTrajectoryCone * @return true if object <o> is in the firing trajectory, false otherwise */ inline bool TestTrajectoryConeHelper( const float3& from, const float3& flatdir, float length, float linear, float quadratic, float spread, float baseSize, const CSolidObject* o) { const CollisionVolume* cv = o->collisionVolume; float3 dif = (o->midPos + cv->GetOffsets()) - from; const float3 flatdif(dif.x, 0, dif.z); float closeFlatLength = flatdif.dot(flatdir); if (closeFlatLength <= 0) return false; if (closeFlatLength > length) closeFlatLength = length; if (fabs(linear - quadratic * closeFlatLength) < 0.15f) { // relatively flat region -> use approximation dif.y -= (linear + quadratic * closeFlatLength) * closeFlatLength; // NOTE: overly conservative for non-spherical volumes const float3 closeVect = dif - flatdir * closeFlatLength; const float r = cv->GetBoundingRadius() + spread * closeFlatLength + baseSize; if (closeVect.SqLength() < r * r) { return true; } } else { float3 newfrom = from + flatdir * closeFlatLength; newfrom.y += (linear + quadratic * closeFlatLength) * closeFlatLength; float3 dir = flatdir; dir.y = linear + quadratic * closeFlatLength; dir.Normalize(); dif = (o->midPos + cv->GetOffsets()) - newfrom; const float closeLength = dif.dot(dir); // NOTE: overly conservative for non-spherical volumes const float3 closeVect = dif - dir * closeLength; const float r = cv->GetBoundingRadius() + spread * closeFlatLength + baseSize; if (closeVect.SqLength() < r * r) { return true; } } return false; }
float CPlasmaRepulser::NewBeam(CWeapon* emitter, float3 start, float3 dir, float length, float3& newDir) { if (!isEnabled) { return -1; } if (emitter->weaponDef->damages[0] > curPower) { return -1; } if (weaponDef->smartShield && teamHandler->AlliedTeams(emitter->owner->team, owner->team)) { return -1; } const float3 dif = weaponPos - start; if (weaponDef->exteriorShield && dif.SqLength() < sqRadius) { return -1; } const float closeLength = dif.dot(dir); if (closeLength < 0) { return -1; } const float3 closeVect = dif - dir * closeLength; const float tmp = sqRadius - closeVect.SqLength(); if ((tmp > 0) && (length > (closeLength - sqrt(tmp)))) { const float colLength = closeLength - sqrt(tmp); const float3 colPoint = start + dir * colLength; const float3 normal = (colPoint - weaponPos).Normalize(); newDir = dir - normal * normal.dot(dir) * 2; return colLength; } return -1; }
float CGameHelper::GuiTraceRayFeature(const float3& start, const float3& dir, float length, CFeature*& feature) { float nearHit = length; GML_RECMUTEX_LOCK(quad); // GuiTraceRayFeature std::vector<int> quads = qf->GetQuadsOnRay(start, dir, length); std::vector<int>::iterator qi; for (qi = quads.begin(); qi != quads.end(); ++qi) { const CQuadField::Quad& quad = qf->GetQuad(*qi); std::list<CFeature*>::const_iterator ui; // NOTE: switch this to custom volumes fully? // (not used for any LOF checks, maybe wasteful) for (ui = quad.features.begin(); ui != quad.features.end(); ++ui) { CFeature* f = *ui; if (!gu->spectatingFullView && !f->IsInLosForAllyTeam(gu->myAllyTeam)) { continue; } if (f->noSelect) { continue; } CollisionVolume* cv = f->collisionVolume; const float3& midPosOffset = cv? cv->GetOffsets(): ZeroVector; const float3 dif = (f->midPos + midPosOffset) - start; float closeLength = dif.dot(dir); if (closeLength < 0) continue; if (closeLength > nearHit) continue; float3 closeVect = dif - dir * closeLength; if (closeVect.SqLength() < f->sqRadius) { nearHit = closeLength; feature = f; } } } return nearHit; }
void CubeMapHandler::CreateSpecularFacePart( unsigned int texType, unsigned int size, const float3& cdir, const float3& xdif, const float3& ydif, unsigned int y, unsigned char* buf) { for (int x = 0; x < size; ++x) { const float3 dir = (cdir + (xdif * (x + 0.5f)) / size + (ydif * (y + 0.5f)) / size).Normalize(); const float dot = std::max(0.0f, dir.dot(globalRendering->sunDir)); const float spec = std::min(1.0f, pow(dot, specExp) + pow(dot, 3.0f) * 0.25f); buf[x * 4 + 0] = (mapInfo->light.unitSpecularColor.x * spec * 255); buf[x * 4 + 1] = (mapInfo->light.unitSpecularColor.y * spec * 255); buf[x * 4 + 2] = (mapInfo->light.unitSpecularColor.z * spec * 255); buf[x * 4 + 3] = 255; } }
bool CBuilder::ScriptStartBuilding(float3 pos, bool silent) { if (script->HasStartBuilding()) { const float3 wantedDir = (pos - midPos).Normalize(); const float h = GetHeadingFromVectorF(wantedDir.x, wantedDir.z); const float p = math::asin(wantedDir.dot(updir)); const float pitch = math::asin(frontdir.dot(updir)); // clamping p - pitch not needed, range of asin is -PI/2..PI/2, // so max difference between two asin calls is PI. // FIXME: convert CSolidObject::heading to radians too. script->StartBuilding(ClampRad(h - heading * TAANG2RAD), p - pitch); } if ((!silent || inBuildStance) && losStatus[gu->myAllyTeam] & LOS_INLOS) { Channels::General->PlayRandomSample(unitDef->sounds.build, pos); } return inBuildStance; }
/* Extract height and slope data from given square and make a sub-functional call for calculations upon whose data. */ float CMoveMath::SpeedMod(const MoveData& moveData, int xSquare, int zSquare,const float3& moveDir) { //Error-check if(xSquare < 0 || zSquare < 0 || xSquare >= gs->mapx || zSquare >= gs->mapy) return 0.0f; //Extract data. int square = xSquare/2 + zSquare/2 * gs->hmapx; float height = readmap->halfHeightmap[square]; float slope = readmap->slopemap[square]; float3 flatNorm=readmap->facenormals[(xSquare + zSquare * gs->mapx)*2]; flatNorm.y=0; flatNorm.Normalize(); float moveSlope=-moveDir.dot(flatNorm); float typemod=moveinfo->terrainType2MoveFamilySpeed[readmap->typemap[square]][moveData.moveFamily]; //Call calculations. return SpeedMod(moveData, height, slope,moveSlope)*typemod; }
void CBuilder::SetBuildStanceToward(float3 pos) { if (script->HasStartBuilding()) { const float3 wantedDir = (pos - midPos).Normalize(); const float h = GetHeadingFromVectorF(wantedDir.x, wantedDir.z); const float p = asin(wantedDir.dot(updir)); const float pitch = asin(frontdir.dot(updir)); // clamping p - pitch not needed, range of asin is -PI/2..PI/2, // so max difference between two asin calls is PI. // FIXME: convert CSolidObject::heading to radians too. script->StartBuilding(ClampRad(h - heading * TAANG2RAD), p - pitch); } #if (PLAY_SOUNDS == 1) if (losStatus[gu->myAllyTeam] & LOS_INLOS) { Channels::General.PlayRandomSample(unitDef->sounds.build, pos); } #endif }
void CubeMapHandler::CreateSpecularFacePart( unsigned int texType, unsigned int size, const float3& cdir, const float3& xdif, const float3& ydif, unsigned int y, unsigned char* buf) { // TODO move to a shader for (int x = 0; x < size; ++x) { const float3 dir = (cdir + (xdif * (x + 0.5f)) / size + (ydif * (y + 0.5f)) / size).Normalize(); const float dot = std::max(0.0f, dir.dot(sky->GetLight()->GetLightDir())); const float spec = std::min(1.0f, pow(dot, mapInfo->light.specularExponent) + pow(dot, 3.0f) * 0.25f); buf[x * 4 + 0] = (mapInfo->light.unitSpecularColor.x * spec * 255); buf[x * 4 + 1] = (mapInfo->light.unitSpecularColor.y * spec * 255); buf[x * 4 + 2] = (mapInfo->light.unitSpecularColor.z * spec * 255); buf[x * 4 + 3] = 255; } }
void CPlasmaRepulser::NewProjectile(CWeaponProjectile* p) { // PlasmaRepulser instances are created if type == "Shield", // but projectiles are removed from incomingProjectiles only // if def->interceptor || def->isShield --> dangling pointers // due to isShield being a separate tag (in 91.0) assert(weaponDef->isShield); if (weaponDef->smartShield && p->owner() && teamHandler->AlliedTeams(p->owner()->team, owner->team)) { return; } float3 dir = p->speed; if (p->GetTargetPos() != ZeroVector) { // assume projectile will travel roughly in the direction of its targetpos dir = p->GetTargetPos() - p->pos; } dir.y = 0.0f; dir.SafeNormalize(); const float3 dif = owner->pos - p->pos; if (weaponDef->exteriorShield && (dif.SqLength() < sqRadius)) { return; } const float closeLength = std::max(0.0f, dif.dot(dir)); const float3 closeVect = dif - dir * closeLength; const float closeDist = closeVect.SqLength2D(); // TODO: this isn't good enough in case shield is mounted on a mobile unit, // and this unit moves relatively fast compared to the projectile. // it should probably be: radius + closeLength / |projectile->speed| * |owner->speed|, // but this still doesn't solve anything for e.g. teleporting shields. if (closeDist < Square(radius * 1.5f)) { incomingProjectiles[p->id] = p; AddDeathDependence(p, DEPENDENCE_REPULSED); } }