Changeset View
Changeset View
Standalone View
Standalone View
ps/trunk/source/simulation2/components/CCmpRangeManager.cpp
/* Copyright (C) 2019 Wildfire Games. | /* Copyright (C) 2020 Wildfire Games. | ||||
* This file is part of 0 A.D. | * This file is part of 0 A.D. | ||||
* | * | ||||
* 0 A.D. is free software: you can redistribute it and/or modify | * 0 A.D. is free software: you can redistribute it and/or modify | ||||
* it under the terms of the GNU General Public License as published by | * it under the terms of the GNU General Public License as published by | ||||
* the Free Software Foundation, either version 2 of the License, or | * the Free Software Foundation, either version 2 of the License, or | ||||
* (at your option) any later version. | * (at your option) any later version. | ||||
* | * | ||||
* 0 A.D. is distributed in the hope that it will be useful, | * 0 A.D. is distributed in the hope that it will be useful, | ||||
▲ Show 20 Lines • Show All 146 Lines • ▼ Show 20 Lines | |||||
* Checks whether v is in a parabolic range of (0,0,0) | * Checks whether v is in a parabolic range of (0,0,0) | ||||
* The highest point of the paraboloid is (0,range/2,0) | * The highest point of the paraboloid is (0,range/2,0) | ||||
* and the circle of distance 'range' around (0,0,0) on height y=0 is part of the paraboloid | * and the circle of distance 'range' around (0,0,0) on height y=0 is part of the paraboloid | ||||
* | * | ||||
* Avoids sqrting and overflowing. | * Avoids sqrting and overflowing. | ||||
*/ | */ | ||||
static bool InParabolicRange(CFixedVector3D v, fixed range) | static bool InParabolicRange(CFixedVector3D v, fixed range) | ||||
{ | { | ||||
i32 x = v.X.GetInternalValue(); // abs(x) <= 2^31 | u64 xx = SQUARE_U64_FIXED(v.X); // xx <= 2^62 | ||||
i32 z = v.Z.GetInternalValue(); | u64 zz = SQUARE_U64_FIXED(v.Z); | ||||
u64 xx = (u64)FIXED_MUL_I64_I32_I32(x, x); // xx <= 2^62 | |||||
u64 zz = (u64)FIXED_MUL_I64_I32_I32(z, z); | |||||
i64 d2 = (xx + zz) >> 1; // d2 <= 2^62 (no overflow) | i64 d2 = (xx + zz) >> 1; // d2 <= 2^62 (no overflow) | ||||
i32 y = v.Y.GetInternalValue(); | i32 y = v.Y.GetInternalValue(); | ||||
i32 c = range.GetInternalValue(); | i32 c = range.GetInternalValue(); | ||||
i32 c_2 = c >> 1; | i32 c_2 = c >> 1; | ||||
i64 c2 = FIXED_MUL_I64_I32_I32(c_2 - y, c); | i64 c2 = MUL_I64_I32_I32(c_2 - y, c); | ||||
if (d2 <= c2) | if (d2 <= c2) | ||||
return true; | return true; | ||||
return false; | return false; | ||||
} | } | ||||
struct EntityParabolicRangeOutline | struct EntityParabolicRangeOutline | ||||
▲ Show 20 Lines • Show All 1,107 Lines • ▼ Show 20 Lines | public: | ||||
{ | { | ||||
std::vector<entity_pos_t> r; | std::vector<entity_pos_t> r; | ||||
CmpPtr<ICmpTerrain> cmpTerrain(GetSystemEntity()); | CmpPtr<ICmpTerrain> cmpTerrain(GetSystemEntity()); | ||||
if (!cmpTerrain) | if (!cmpTerrain) | ||||
return r; | return r; | ||||
// angle = 0 goes in the positive Z direction | // angle = 0 goes in the positive Z direction | ||||
entity_pos_t precision = entity_pos_t::FromInt((int)TERRAIN_TILE_SIZE)/8; | u64 precisionSquared = SQUARE_U64_FIXED(entity_pos_t::FromInt(static_cast<int>(TERRAIN_TILE_SIZE)) / 8); | ||||
CmpPtr<ICmpWaterManager> cmpWaterManager(GetSystemEntity()); | CmpPtr<ICmpWaterManager> cmpWaterManager(GetSystemEntity()); | ||||
entity_pos_t waterLevel = cmpWaterManager ? cmpWaterManager->GetWaterLevel(pos.X, pos.Z) : entity_pos_t::Zero(); | entity_pos_t waterLevel = cmpWaterManager ? cmpWaterManager->GetWaterLevel(pos.X, pos.Z) : entity_pos_t::Zero(); | ||||
entity_pos_t thisHeight = pos.Y > waterLevel ? pos.Y : waterLevel; | entity_pos_t thisHeight = pos.Y > waterLevel ? pos.Y : waterLevel; | ||||
for (int i = 0; i < numberOfSteps; ++i) | for (int i = 0; i < numberOfSteps; ++i) | ||||
{ | { | ||||
entity_pos_t angle = minAngle + (maxAngle - minAngle) / numberOfSteps * i; | entity_pos_t angle = minAngle + (maxAngle - minAngle) / numberOfSteps * i; | ||||
Show All 12 Lines | for (int i = 0; i < numberOfSteps; ++i) | ||||
if (InParabolicRange(CFixedVector3D(maxVector.X, targetHeight-thisHeight, maxVector.Y), maxRange)) | if (InParabolicRange(CFixedVector3D(maxVector.X, targetHeight-thisHeight, maxVector.Y), maxRange)) | ||||
{ | { | ||||
r.push_back(maxVector.X); | r.push_back(maxVector.X); | ||||
r.push_back(maxVector.Y); | r.push_back(maxVector.Y); | ||||
continue; | continue; | ||||
} | } | ||||
// Loop until vectors come close enough | // Loop until vectors come close enough | ||||
while ((maxVector - minVector).CompareLength(precision) > 0) | while ((maxVector - minVector).CompareLengthSquared(precisionSquared) > 0) | ||||
{ | { | ||||
// difference still bigger than precision, bisect to get smaller difference | // difference still bigger than precision, bisect to get smaller difference | ||||
entity_pos_t newDistance = (minDistance+maxDistance)/entity_pos_t::FromInt(2); | entity_pos_t newDistance = (minDistance+maxDistance)/entity_pos_t::FromInt(2); | ||||
CFixedVector2D newVector = CFixedVector2D(sin, cos).Multiply(newDistance); | CFixedVector2D newVector = CFixedVector2D(sin, cos).Multiply(newDistance); | ||||
// get the height of the ground | // get the height of the ground | ||||
targetHeight = cmpTerrain->GetGroundLevel(pos.X+newVector.X, pos.Z+newVector.Y); | targetHeight = cmpTerrain->GetGroundLevel(pos.X+newVector.X, pos.Z+newVector.Y); | ||||
▲ Show 20 Lines • Show All 1,132 Lines • Show Last 20 Lines |
Wildfire Games · Phabricator