diff --git a/source/EngineGpuKernels/CellConnectionProcessor.cuh b/source/EngineGpuKernels/CellConnectionProcessor.cuh index 75a65c15d..cab8f983a 100644 --- a/source/EngineGpuKernels/CellConnectionProcessor.cuh +++ b/source/EngineGpuKernels/CellConnectionProcessor.cuh @@ -279,6 +279,13 @@ __inline__ __device__ bool CellConnectionProcessor::tryAddConnectionOneWay( float desiredAngleOnCell1, ConstructorAngleAlignment angleAlignment) { + if (cell1->numConnections == MAX_CELL_BONDS) { + return false; + } + if (ConstructorAngleAlignment_None != angleAlignment && cell1->numConnections >= angleAlignment + 1) { + return false; + } + if (wouldResultInOverlappingConnection(cell1, cell2->pos)) { return false; } @@ -290,6 +297,9 @@ __inline__ __device__ bool CellConnectionProcessor::tryAddConnectionOneWay( desiredDistance = Math::length(posDelta); } + // ***** + // special case: cell1 has no connections + // ***** if (0 == cell1->numConnections) { cell1->numConnections++; cell1->connections[0].cell = cell2; @@ -297,6 +307,10 @@ __inline__ __device__ bool CellConnectionProcessor::tryAddConnectionOneWay( cell1->connections[0].angleFromPrevious = 360.0f; return true; } + + // ***** + // special case: cell1 has one connection + // ***** if (1 == cell1->numConnections) { auto connectedCellDelta = cell1->connections[0].cell->pos - cell1->pos; data.cellMap.correctDirection(connectedCellDelta); @@ -323,7 +337,11 @@ __inline__ __device__ bool CellConnectionProcessor::tryAddConnectionOneWay( return true; } - //find appropriate index for new connection + // ***** + // process general case + // ***** + + // find appropriate index for new connection int index = 0; float prevAngle = 0; float nextAngle = 0; @@ -331,64 +349,87 @@ __inline__ __device__ bool CellConnectionProcessor::tryAddConnectionOneWay( auto prevIndex = (index + cell1->numConnections - 1) % cell1->numConnections; prevAngle = Math::angleOfVector(data.cellMap.getCorrectedDirection(cell1->connections[prevIndex].cell->pos - cell1->pos)); nextAngle = Math::angleOfVector(data.cellMap.getCorrectedDirection(cell1->connections[index].cell->pos - cell1->pos)); - if (Math::isAngleInBetween(prevAngle, nextAngle, newAngle)) { + if (Math::isAngleInBetween(prevAngle, nextAngle, newAngle) || prevIndex == index) { break; } } - //create connection object + // create new connection object CellConnection newConnection; newConnection.cell = cell2; newConnection.distance = desiredDistance; - auto angleFromPrevious = 0.0f; + + float angleFromPrevious; auto refAngle = cell1->connections[index].angleFromPrevious; - if (Math::isAngleInBetween(prevAngle, nextAngle, newAngle)) { + if (0 == desiredAngleOnCell1) { auto angleDiff1 = Math::subtractAngle(newAngle, prevAngle); auto angleDiff2 = Math::subtractAngle(nextAngle, prevAngle); - auto factor = angleDiff2 != 0 ? angleDiff1 / angleDiff2 : 0.5f; - if (0 == desiredAngleOnCell1) { - angleFromPrevious = refAngle * factor; - } else { - angleFromPrevious = desiredAngleOnCell1; - } - angleFromPrevious = min(angleFromPrevious, refAngle); - - angleFromPrevious = Math::alignAngle(angleFromPrevious, angleAlignment); - angleFromPrevious = Math::alignAngleOnBoundaries(angleFromPrevious, refAngle, angleAlignment); + auto newAngleFraction = angleDiff2 != 0 ? angleDiff1 / angleDiff2 : 0.5f; + angleFromPrevious = refAngle * newAngleFraction; + } else { + angleFromPrevious = desiredAngleOnCell1; } + angleFromPrevious = min(angleFromPrevious, refAngle); + if (angleFromPrevious < NEAR_ZERO) { return false; } newConnection.angleFromPrevious = angleFromPrevious; - //adjust reference angle of next connection - auto nextAngleFromPrevious = refAngle - angleFromPrevious; - auto nextAngleFromPreviousAligned = Math::alignAngle(nextAngleFromPrevious, angleAlignment); - auto angleDiff = nextAngleFromPreviousAligned - nextAngleFromPrevious; - - auto nextIndex = index % cell1->numConnections; - auto nextNextIndex = (index + 1) % cell1->numConnections; - auto nextNextAngleFromPrevious = cell1->connections[nextNextIndex].angleFromPrevious; - if (nextNextAngleFromPrevious - angleDiff >= 0.0f && nextNextAngleFromPrevious - angleDiff <= 360.0f) { - if (nextAngleFromPreviousAligned < NEAR_ZERO || nextNextAngleFromPrevious - angleDiff < NEAR_ZERO) { - return false; + // insert new connection to a clone of the existing connection array + CellConnection newConnections[MAX_CELL_BONDS]; + for (int i = 0; i < cell1->numConnections; ++i) { + newConnections[i] = cell1->connections[i]; + } + if (index == 0) { + index = cell1->numConnections; // connection at index 0 should be an invariant + } + for (int j = cell1->numConnections; j > index; --j) { + newConnections[j] = newConnections[j - 1]; + } + newConnections[index] = newConnection; + newConnections[(index + 1) % (cell1->numConnections + 1)].angleFromPrevious = refAngle - angleFromPrevious; + + // align angles + if (angleAlignment != ConstructorAngleAlignment_None) { + auto const angleUnit = 360.0f / (angleAlignment + 1); + for (int i = 0; i < cell1->numConnections + 1; ++i) { + newConnections[i].angleFromPrevious = Math::alignAngle(newConnections[i].angleFromPrevious, angleAlignment); + if (abs(newConnections[i].angleFromPrevious) < NEAR_ZERO) { + newConnections[i].angleFromPrevious = angleUnit; + } } - cell1->connections[nextIndex].angleFromPrevious = nextAngleFromPreviousAligned; - cell1->connections[nextNextIndex].angleFromPrevious = nextNextAngleFromPrevious - angleDiff; - } else { - if (nextAngleFromPrevious < NEAR_ZERO) { - return false; + + for (int i = 0; i < MAX_CELL_BONDS; ++i) { + float sumAngle = 0; + for (int i = 0; i < cell1->numConnections + 1; ++i) { + sumAngle += newConnections[i].angleFromPrevious; + } + if (sumAngle > 360.0f + NEAR_ZERO || sumAngle < 360.0f - NEAR_ZERO) { + int indexWithMaxAngle = -1; + float maxAngle = 0; + for (int j = 0; j < cell1->numConnections + 1; ++j) { + if (newConnections[j].angleFromPrevious > maxAngle) { + maxAngle = newConnections[j].angleFromPrevious; + indexWithMaxAngle = j; + } + } + if (sumAngle > 360.0f + NEAR_ZERO) { + newConnections[indexWithMaxAngle].angleFromPrevious -= angleUnit; + } else { + newConnections[indexWithMaxAngle].angleFromPrevious += angleUnit; + } + } else { + break; + } } - cell1->connections[nextIndex].angleFromPrevious = nextAngleFromPrevious; } - //add connection - for (int j = cell1->numConnections; j > index; --j) { - cell1->connections[j] = cell1->connections[j - 1]; + // adopt new connections + cell1->numConnections++; + for (int i = 0; i < cell1->numConnections; ++i) { + cell1->connections[i] = newConnections[i]; } - cell1->connections[index] = newConnection; - ++cell1->numConnections; - return true; } diff --git a/source/EngineGpuKernels/ConstructorProcessor.cuh b/source/EngineGpuKernels/ConstructorProcessor.cuh index 22a4412d8..c13ea00fd 100644 --- a/source/EngineGpuKernels/ConstructorProcessor.cuh +++ b/source/EngineGpuKernels/ConstructorProcessor.cuh @@ -414,7 +414,21 @@ __inline__ __device__ Cell* ConstructorProcessor::continueConstruction( auto newCellPos = hostCell->pos + posDelta; - //get surrounding cells + float angleFromPrevious1; + float angleFromPrevious2; + auto const& lastConstructionCell = constructionData.lastConstructionCell; + + for (int i = 0; i < lastConstructionCell->numConnections; ++i) { + if (lastConstructionCell->connections[i].cell == hostCell) { + angleFromPrevious1 = lastConstructionCell->connections[i].angleFromPrevious; + angleFromPrevious2 = lastConstructionCell->connections[(i + 1) % lastConstructionCell->numConnections].angleFromPrevious; + break; + } + } + auto n = Math::normalized(hostCell->pos - lastConstructionCell->pos); + Math::rotateQuarterClockwise(n); + + // assemble surrounding cell candidates Cell* otherCellCandidates[MAX_CELL_BONDS * 2]; int numOtherCellCandidates = 0; data.cellMap.getMatchingCells( @@ -426,14 +440,27 @@ __inline__ __device__ Cell* ConstructorProcessor::continueConstruction( hostCell->detached, [&](Cell* const& otherCell) { if (otherCell == constructionData.lastConstructionCell || otherCell == hostCell - || (otherCell->livingState != LivingState_UnderConstruction - && otherCell->activationTime == 0) || otherCell->creatureId != hostCell->cellFunctionData.constructor.offspringCreatureId) { + || (otherCell->livingState != LivingState_UnderConstruction && otherCell->activationTime == 0) + || otherCell->creatureId != hostCell->cellFunctionData.constructor.offspringCreatureId) { return false; } + + // discard cells that are not on the correct side + auto delta = data.cellMap.getCorrectedDirection(otherCell->pos - lastConstructionCell->pos); + if (angleFromPrevious2 < angleFromPrevious1) { + if (Math::dot(delta, n) < 0) { + return false; + } + } + if (angleFromPrevious2 > angleFromPrevious1) { + if (Math::dot(delta, n) > 0) { + return false; + } + } return true; }); - //assemble surrounding cell candidates + // evaluate candidates Cell* otherCells[MAX_CELL_BONDS]; int numOtherCells = 0; for (int i = 0; i < numOtherCellCandidates; ++i) {