v1.4.4
This commit is contained in:
commit
9c94d113d3
10260 changed files with 1237388 additions and 0 deletions
590
source/base/StarCellularLightArray.hpp
Normal file
590
source/base/StarCellularLightArray.hpp
Normal file
|
@ -0,0 +1,590 @@
|
|||
#ifndef STAR_CELLULAR_LIGHT_ARRAY_HPP
|
||||
#define STAR_CELLULAR_LIGHT_ARRAY_HPP
|
||||
|
||||
#include "StarList.hpp"
|
||||
#include "StarVector.hpp"
|
||||
|
||||
namespace Star {
|
||||
|
||||
// Operations for simple scalar lighting.
|
||||
struct ScalarLightTraits {
|
||||
typedef float Value;
|
||||
|
||||
static float spread(float source, float dest, float drop);
|
||||
static float subtract(float value, float drop);
|
||||
|
||||
static float maxIntensity(float value);
|
||||
static float minIntensity(float value);
|
||||
|
||||
static float max(float v1, float v2);
|
||||
};
|
||||
|
||||
// Operations for 3 component (colored) lighting. Spread and subtract are
|
||||
// applied proportionally, so that color ratios stay the same, to prevent hues
|
||||
// changing as light spreads.
|
||||
struct ColoredLightTraits {
|
||||
typedef Vec3F Value;
|
||||
|
||||
static Vec3F spread(Vec3F const& source, Vec3F const& dest, float drop);
|
||||
static Vec3F subtract(Vec3F value, float drop);
|
||||
|
||||
static float maxIntensity(Vec3F const& value);
|
||||
static float minIntensity(Vec3F const& value);
|
||||
|
||||
static Vec3F max(Vec3F const& v1, Vec3F const& v2);
|
||||
};
|
||||
|
||||
template <typename LightTraits>
|
||||
class CellularLightArray {
|
||||
public:
|
||||
typedef typename LightTraits::Value LightValue;
|
||||
|
||||
struct Cell {
|
||||
LightValue light;
|
||||
bool obstacle;
|
||||
};
|
||||
|
||||
struct SpreadLight {
|
||||
Vec2F position;
|
||||
LightValue value;
|
||||
};
|
||||
|
||||
struct PointLight {
|
||||
Vec2F position;
|
||||
LightValue value;
|
||||
float beam;
|
||||
float beamAngle;
|
||||
float beamAmbience;
|
||||
};
|
||||
|
||||
void setParameters(unsigned spreadPasses, float spreadMaxAir, float spreadMaxObstacle,
|
||||
float pointMaxAir, float pointMaxObstacle, float pointObstacleBoost);
|
||||
|
||||
// The border around the target lighting array where initial lighting / light
|
||||
// source data is required. Based on parameters.
|
||||
size_t borderCells() const;
|
||||
|
||||
// Begin a new calculation, setting internal storage to new width and height
|
||||
// (if these are the same as last time this is cheap). Always clears all
|
||||
// existing light and collision data.
|
||||
void begin(size_t newWidth, size_t newHeight);
|
||||
|
||||
// Position is in index space, spread lights will have no effect if they are
|
||||
// outside of the array. Integer points are assumed to be on the corners of
|
||||
// the grid (not the center)
|
||||
void addSpreadLight(SpreadLight const& spreadLight);
|
||||
void addPointLight(PointLight const& pointLight);
|
||||
|
||||
// Directly set the lighting values for this position.
|
||||
void setLight(size_t x, size_t y, LightValue const& light);
|
||||
|
||||
// Get current light value. Call after calling calculate() to pull final
|
||||
// data out.
|
||||
LightValue getLight(size_t x, size_t y) const;
|
||||
|
||||
// Set obstacle values for this position
|
||||
void setObstacle(size_t x, size_t y, bool obstacle);
|
||||
bool getObstacle(size_t x, size_t y) const;
|
||||
|
||||
Cell const& cell(size_t x, size_t y) const;
|
||||
Cell& cell(size_t x, size_t y);
|
||||
|
||||
Cell const& cellAtIndex(size_t index) const;
|
||||
Cell& cellAtIndex(size_t index);
|
||||
|
||||
// Calculate lighting in the given sub-rect, in order to properly do spread
|
||||
// lighting, and initial lighting must be given for the ambient border this
|
||||
// given rect, and the array size must be at least that large. xMax / yMax
|
||||
// are not inclusive, the range is [xMin, xMax) and [yMin, yMax).
|
||||
void calculate(size_t xMin, size_t yMin, size_t xMax, size_t yMax);
|
||||
|
||||
private:
|
||||
// Set 4 points based on interpolated light position and free space
|
||||
// attenuation.
|
||||
void setSpreadLightingPoints();
|
||||
|
||||
// Spreads light out in an octagonal based cellular automata
|
||||
void calculateLightSpread(size_t xmin, size_t ymin, size_t xmax, size_t ymax);
|
||||
|
||||
// Loops through each light and adds light strength based on distance and
|
||||
// obstacle attenuation. Calculates within the given sub-rect
|
||||
void calculatePointLighting(size_t xmin, size_t ymin, size_t xmax, size_t ymax);
|
||||
|
||||
// Run Xiaolin Wu's anti-aliased line drawing algorithm from start to end,
|
||||
// summing each block that would be drawn to to produce an attenuation. Not
|
||||
// circularized.
|
||||
float lineAttenuation(Vec2F const& start, Vec2F const& end, float perObstacleAttenuation, float maxAttenuation);
|
||||
|
||||
size_t m_width;
|
||||
size_t m_height;
|
||||
unique_ptr<Cell[]> m_cells;
|
||||
List<SpreadLight> m_spreadLights;
|
||||
List<PointLight> m_pointLights;
|
||||
|
||||
unsigned m_spreadPasses;
|
||||
float m_spreadMaxAir;
|
||||
float m_spreadMaxObstacle;
|
||||
float m_pointMaxAir;
|
||||
float m_pointMaxObstacle;
|
||||
float m_pointObstacleBoost;
|
||||
};
|
||||
|
||||
typedef CellularLightArray<ColoredLightTraits> ColoredCellularLightArray;
|
||||
typedef CellularLightArray<ScalarLightTraits> ScalarCellularLightArray;
|
||||
|
||||
inline float ScalarLightTraits::spread(float source, float dest, float drop) {
|
||||
return std::max(source - drop, dest);
|
||||
}
|
||||
|
||||
inline float ScalarLightTraits::subtract(float c, float drop) {
|
||||
return std::max(c - drop, 0.0f);
|
||||
}
|
||||
|
||||
inline float ScalarLightTraits::maxIntensity(float value) {
|
||||
return value;
|
||||
}
|
||||
|
||||
inline float ScalarLightTraits::minIntensity(float value) {
|
||||
return value;
|
||||
}
|
||||
|
||||
inline float ScalarLightTraits::max(float v1, float v2) {
|
||||
return std::max(v1, v2);
|
||||
}
|
||||
|
||||
inline Vec3F ColoredLightTraits::spread(Vec3F const& source, Vec3F const& dest, float drop) {
|
||||
float maxChannel = std::max(source[0], std::max(source[1], source[2]));
|
||||
if (maxChannel <= 0.0f)
|
||||
return dest;
|
||||
|
||||
drop /= maxChannel;
|
||||
return Vec3F(
|
||||
std::max(source[0] - source[0] * drop, dest[0]),
|
||||
std::max(source[1] - source[1] * drop, dest[1]),
|
||||
std::max(source[2] - source[2] * drop, dest[2])
|
||||
);
|
||||
}
|
||||
|
||||
inline Vec3F ColoredLightTraits::subtract(Vec3F c, float drop) {
|
||||
float max = std::max(std::max(c[0], c[1]), c[2]);
|
||||
if (max <= 0.0f)
|
||||
return c;
|
||||
|
||||
for (size_t i = 0; i < 3; ++i) {
|
||||
float pdrop = (drop * c[i]) / max;
|
||||
if (c[i] > pdrop)
|
||||
c[i] -= pdrop;
|
||||
else
|
||||
c[i] = 0;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
inline float ColoredLightTraits::maxIntensity(Vec3F const& value) {
|
||||
return value.max();
|
||||
}
|
||||
|
||||
inline float ColoredLightTraits::minIntensity(Vec3F const& value) {
|
||||
return value.min();
|
||||
}
|
||||
|
||||
inline Vec3F ColoredLightTraits::max(Vec3F const& v1, Vec3F const& v2) {
|
||||
return vmax(v1, v2);
|
||||
}
|
||||
|
||||
template <typename LightTraits>
|
||||
void CellularLightArray<LightTraits>::setParameters(unsigned spreadPasses, float spreadMaxAir, float spreadMaxObstacle,
|
||||
float pointMaxAir, float pointMaxObstacle, float pointObstacleBoost) {
|
||||
m_spreadPasses = spreadPasses;
|
||||
m_spreadMaxAir = spreadMaxAir;
|
||||
m_spreadMaxObstacle = spreadMaxObstacle;
|
||||
m_pointMaxAir = pointMaxAir;
|
||||
m_pointMaxObstacle = pointMaxObstacle;
|
||||
m_pointObstacleBoost = pointObstacleBoost;
|
||||
}
|
||||
|
||||
template <typename LightTraits>
|
||||
size_t CellularLightArray<LightTraits>::borderCells() const {
|
||||
return (size_t)ceil(max(0.0f, max(m_spreadMaxAir, m_pointMaxAir)));
|
||||
}
|
||||
|
||||
template <typename LightTraits>
|
||||
void CellularLightArray<LightTraits>::begin(size_t newWidth, size_t newHeight) {
|
||||
m_spreadLights.clear();
|
||||
m_pointLights.clear();
|
||||
starAssert(newWidth > 0 && newHeight > 0);
|
||||
|
||||
if (!m_cells || newWidth != m_width || newHeight != m_height) {
|
||||
m_width = newWidth;
|
||||
m_height = newHeight;
|
||||
|
||||
m_cells.reset(new Cell[m_width * m_height]());
|
||||
|
||||
} else {
|
||||
std::fill(m_cells.get(), m_cells.get() + m_width * m_height, Cell{LightValue{}, false});
|
||||
}
|
||||
}
|
||||
|
||||
template <typename LightTraits>
|
||||
void CellularLightArray<LightTraits>::addSpreadLight(SpreadLight const& spreadLight) {
|
||||
m_spreadLights.append(spreadLight);
|
||||
}
|
||||
|
||||
template <typename LightTraits>
|
||||
void CellularLightArray<LightTraits>::addPointLight(PointLight const& pointLight) {
|
||||
m_pointLights.append(pointLight);
|
||||
}
|
||||
|
||||
template <typename LightTraits>
|
||||
void CellularLightArray<LightTraits>::setLight(size_t x, size_t y, LightValue const& lightValue) {
|
||||
cell(x, y).light = lightValue;
|
||||
}
|
||||
|
||||
template <typename LightTraits>
|
||||
void CellularLightArray<LightTraits>::setObstacle(size_t x, size_t y, bool obstacle) {
|
||||
cell(x, y).obstacle = obstacle;
|
||||
}
|
||||
|
||||
template <typename LightTraits>
|
||||
auto CellularLightArray<LightTraits>::getLight(size_t x, size_t y) const -> LightValue {
|
||||
return cell(x, y).light;
|
||||
}
|
||||
|
||||
template <typename LightTraits>
|
||||
bool CellularLightArray<LightTraits>::getObstacle(size_t x, size_t y) const {
|
||||
return cell(x, y).obstacle;
|
||||
}
|
||||
|
||||
template <typename LightTraits>
|
||||
auto CellularLightArray<LightTraits>::cell(size_t x, size_t y) const -> Cell const & {
|
||||
starAssert(x < m_width && y < m_height);
|
||||
return m_cells[x * m_height + y];
|
||||
}
|
||||
|
||||
template <typename LightTraits>
|
||||
auto CellularLightArray<LightTraits>::cell(size_t x, size_t y) -> Cell & {
|
||||
starAssert(x < m_width && y < m_height);
|
||||
return m_cells[x * m_height + y];
|
||||
}
|
||||
|
||||
template <typename LightTraits>
|
||||
auto CellularLightArray<LightTraits>::cellAtIndex(size_t index) const -> Cell const & {
|
||||
starAssert(index < m_width * m_height);
|
||||
return m_cells[index];
|
||||
}
|
||||
|
||||
template <typename LightTraits>
|
||||
auto CellularLightArray<LightTraits>::cellAtIndex(size_t index) -> Cell & {
|
||||
starAssert(index < m_width * m_height);
|
||||
return m_cells[index];
|
||||
}
|
||||
|
||||
template <typename LightTraits>
|
||||
void CellularLightArray<LightTraits>::calculate(size_t xMin, size_t yMin, size_t xMax, size_t yMax) {
|
||||
setSpreadLightingPoints();
|
||||
calculateLightSpread(xMin, yMin, xMax, yMax);
|
||||
calculatePointLighting(xMin, yMin, xMax, yMax);
|
||||
}
|
||||
|
||||
template <typename LightTraits>
|
||||
void CellularLightArray<LightTraits>::setSpreadLightingPoints() {
|
||||
for (SpreadLight const& light : m_spreadLights) {
|
||||
// - 0.5f to correct for lights being on the grid corners and not center
|
||||
int minX = floor(light.position[0] - 0.5f);
|
||||
int minY = floor(light.position[1] - 0.5f);
|
||||
int maxX = minX + 1;
|
||||
int maxY = minY + 1;
|
||||
|
||||
float xdist = light.position[0] - minX - 0.5f;
|
||||
float ydist = light.position[1] - minY - 0.5f;
|
||||
|
||||
// Pick falloff here based on closest block obstacle value (probably not
|
||||
// best)
|
||||
Vec2I pos(light.position.floor());
|
||||
float oneBlockAtt;
|
||||
if (pos[0] >= 0 && pos[0] < (int)m_width && pos[1] >= 0 && pos[1] < (int)m_height && getObstacle(pos[0], pos[1]))
|
||||
oneBlockAtt = 1.0f / m_spreadMaxObstacle;
|
||||
else
|
||||
oneBlockAtt = 1.0f / m_spreadMaxAir;
|
||||
|
||||
// "pre fall-off" a 2x2 area of blocks to smooth out floating point
|
||||
// positions using the cellular algorithm
|
||||
|
||||
if (minX >= 0 && minX < (int)m_width && minY >= 0 && minY < (int)m_height)
|
||||
setLight(minX, minY, LightTraits::max(getLight(minX, minY), LightTraits::subtract(light.value, oneBlockAtt * (2.0f - (1.0f - xdist) - (1.0f - ydist)))));
|
||||
|
||||
if (minX >= 0 && minX < (int)m_width && maxY >= 0 && maxY < (int)m_height)
|
||||
setLight(minX, maxY, LightTraits::max(getLight(minX, maxY), LightTraits::subtract(light.value, oneBlockAtt * (2.0f - (1.0f - xdist) - (ydist)))));
|
||||
|
||||
if (maxX >= 0 && maxX < (int)m_width && minY >= 0 && minY < (int)m_height)
|
||||
setLight(maxX, minY, LightTraits::max(getLight(maxX, minY), LightTraits::subtract(light.value, oneBlockAtt * (2.0f - (xdist) - (1.0f - ydist)))));
|
||||
|
||||
if (maxX >= 0 && maxX < (int)m_width && maxY >= 0 && maxY < (int)m_height)
|
||||
setLight(maxX, maxY, LightTraits::max(getLight(maxX, maxY), LightTraits::subtract(light.value, oneBlockAtt * (2.0f - (xdist) - (ydist)))));
|
||||
}
|
||||
}
|
||||
|
||||
template <typename LightTraits>
|
||||
void CellularLightArray<LightTraits>::calculateLightSpread(size_t xMin, size_t yMin, size_t xMax, size_t yMax) {
|
||||
starAssert(m_width > 0 && m_height > 0);
|
||||
|
||||
float dropoffAir = 1.0f / m_spreadMaxAir;
|
||||
float dropoffObstacle = 1.0f / m_spreadMaxObstacle;
|
||||
float dropoffAirDiag = 1.0f / m_spreadMaxAir * Constants::sqrt2;
|
||||
float dropoffObstacleDiag = 1.0f / m_spreadMaxObstacle * Constants::sqrt2;
|
||||
|
||||
// enlarge x/y min/max taking into ambient spread of light
|
||||
xMin = xMin - min(xMin, (size_t)ceil(m_spreadMaxAir));
|
||||
yMin = yMin - min(yMin, (size_t)ceil(m_spreadMaxAir));
|
||||
xMax = min(m_width, xMax + (size_t)ceil(m_spreadMaxAir));
|
||||
yMax = min(m_height, yMax + (size_t)ceil(m_spreadMaxAir));
|
||||
|
||||
for (unsigned p = 0; p < m_spreadPasses; ++p) {
|
||||
// Spread right and up and diag up right / diag down right
|
||||
for (size_t x = xMin + 1; x < xMax - 1; ++x) {
|
||||
size_t xCellOffset = x * m_height;
|
||||
size_t xRightCellOffset = (x + 1) * m_height;
|
||||
|
||||
for (size_t y = yMin + 1; y < yMax - 1; ++y) {
|
||||
auto cell = cellAtIndex(xCellOffset + y);
|
||||
auto& cellRight = cellAtIndex(xRightCellOffset + y);
|
||||
auto& cellUp = cellAtIndex(xCellOffset + y + 1);
|
||||
auto& cellRightUp = cellAtIndex(xRightCellOffset + y + 1);
|
||||
auto& cellRightDown = cellAtIndex(xRightCellOffset + y - 1);
|
||||
|
||||
float straightDropoff = cell.obstacle ? dropoffObstacle : dropoffAir;
|
||||
float diagDropoff = cell.obstacle ? dropoffObstacleDiag : dropoffAirDiag;
|
||||
|
||||
cellRight.light = LightTraits::spread(cell.light, cellRight.light, straightDropoff);
|
||||
cellUp.light = LightTraits::spread(cell.light, cellUp.light, straightDropoff);
|
||||
|
||||
cellRightUp.light = LightTraits::spread(cell.light, cellRightUp.light, diagDropoff);
|
||||
cellRightDown.light = LightTraits::spread(cell.light, cellRightDown.light, diagDropoff);
|
||||
}
|
||||
}
|
||||
|
||||
// Spread left and down and diag up left / diag down left
|
||||
for (size_t x = xMax - 2; x > xMin; --x) {
|
||||
size_t xCellOffset = x * m_height;
|
||||
size_t xLeftCellOffset = (x - 1) * m_height;
|
||||
|
||||
for (size_t y = yMax - 2; y > yMin; --y) {
|
||||
auto cell = cellAtIndex(xCellOffset + y);
|
||||
auto& cellLeft = cellAtIndex(xLeftCellOffset + y);
|
||||
auto& cellDown = cellAtIndex(xCellOffset + y - 1);
|
||||
auto& cellLeftUp = cellAtIndex(xLeftCellOffset + y + 1);
|
||||
auto& cellLeftDown = cellAtIndex(xLeftCellOffset + y - 1);
|
||||
|
||||
float straightDropoff = cell.obstacle ? dropoffObstacle : dropoffAir;
|
||||
float diagDropoff = cell.obstacle ? dropoffObstacleDiag : dropoffAirDiag;
|
||||
|
||||
cellLeft.light = LightTraits::spread(cell.light, cellLeft.light, straightDropoff);
|
||||
cellDown.light = LightTraits::spread(cell.light, cellDown.light, straightDropoff);
|
||||
|
||||
cellLeftUp.light = LightTraits::spread(cell.light, cellLeftUp.light, diagDropoff);
|
||||
cellLeftDown.light = LightTraits::spread(cell.light, cellLeftDown.light, diagDropoff);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename LightTraits>
|
||||
void CellularLightArray<LightTraits>::calculatePointLighting(size_t xmin, size_t ymin, size_t xmax, size_t ymax) {
|
||||
float perBlockObstacleAttenuation = 1.0f / m_pointMaxObstacle;
|
||||
float perBlockAirAttenuation = 1.0f / m_pointMaxAir;
|
||||
|
||||
for (PointLight light : m_pointLights) {
|
||||
if (light.position[0] < 0 || light.position[0] > m_width - 1 || light.position[1] < 0 || light.position[1] > m_height - 1)
|
||||
continue;
|
||||
|
||||
float maxIntensity = LightTraits::maxIntensity(light.value);
|
||||
Vec2F beamDirection = Vec2F(1, 0).rotate(light.beamAngle);
|
||||
|
||||
float maxRange = maxIntensity * m_pointMaxAir;
|
||||
// The min / max considering the radius of the light
|
||||
size_t lxmin = std::floor(std::max<float>(xmin, light.position[0] - maxRange));
|
||||
size_t lymin = std::floor(std::max<float>(ymin, light.position[1] - maxRange));
|
||||
size_t lxmax = std::ceil(std::min<float>(xmax, light.position[0] + maxRange));
|
||||
size_t lymax = std::ceil(std::min<float>(ymax, light.position[1] + maxRange));
|
||||
|
||||
for (size_t x = lxmin; x < lxmax; ++x) {
|
||||
for (size_t y = lymin; y < lymax; ++y) {
|
||||
LightValue lvalue = getLight(x, y);
|
||||
// + 0.5f to correct block position to center
|
||||
Vec2F blockPos = Vec2F(x + 0.5f, y + 0.5f);
|
||||
|
||||
Vec2F relativeLightPosition = blockPos - light.position;
|
||||
float distance = relativeLightPosition.magnitude();
|
||||
if (distance == 0.0f) {
|
||||
setLight(x, y, LightTraits::max(light.value, lvalue));
|
||||
continue;
|
||||
}
|
||||
|
||||
float attenuation = distance * perBlockAirAttenuation;
|
||||
if (attenuation >= 1.0f)
|
||||
continue;
|
||||
|
||||
Vec2F direction = relativeLightPosition / distance;
|
||||
if (light.beam > 0.0f) {
|
||||
attenuation += (1.0f - light.beamAmbience) * clamp(light.beam * (1.0f - direction * beamDirection), 0.0f, 1.0f);
|
||||
if (attenuation >= 1.0f)
|
||||
continue;
|
||||
}
|
||||
|
||||
float remainingAttenuation = maxIntensity - LightTraits::minIntensity(lvalue) - attenuation;
|
||||
if (remainingAttenuation <= 0.0f)
|
||||
continue;
|
||||
|
||||
// Need to circularize manhattan attenuation here
|
||||
float circularizedPerBlockObstacleAttenuation = perBlockObstacleAttenuation / max(fabs(direction[0]), fabs(direction[1]));
|
||||
float blockAttenuation = lineAttenuation(blockPos, light.position, circularizedPerBlockObstacleAttenuation, remainingAttenuation);
|
||||
|
||||
// Apply single obstacle boost (determine single obstacle by one
|
||||
// block unit of attenuation).
|
||||
attenuation += blockAttenuation + min(blockAttenuation, circularizedPerBlockObstacleAttenuation) * m_pointObstacleBoost;
|
||||
|
||||
if (attenuation < 1.0f)
|
||||
setLight(x, y, LightTraits::max(LightTraits::subtract(light.value, attenuation), lvalue));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename LightTraits>
|
||||
float CellularLightArray<LightTraits>::lineAttenuation(Vec2F const& start, Vec2F const& end,
|
||||
float perObstacleAttenuation, float maxAttenuation) {
|
||||
// Run Xiaolin Wu's line algorithm from start to end, summing over colliding
|
||||
// blocks using perObstacleAttenuation.
|
||||
float obstacleAttenuation = 0.0;
|
||||
|
||||
// Apply correction because integer coordinates are lower left corner.
|
||||
float x1 = start[0] - 0.5;
|
||||
float y1 = start[1] - 0.5;
|
||||
float x2 = end[0] - 0.5;
|
||||
float y2 = end[1] - 0.5;
|
||||
|
||||
float dx = x2 - x1;
|
||||
float dy = y2 - y1;
|
||||
|
||||
if (fabs(dx) < fabs(dy)) {
|
||||
if (y2 < y1) {
|
||||
swap(y1, y2);
|
||||
swap(x1, x2);
|
||||
}
|
||||
|
||||
float gradient = dx / dy;
|
||||
|
||||
// first end point
|
||||
float yend = round(y1);
|
||||
float xend = x1 + gradient * (yend - y1);
|
||||
float ygap = rfpart(y1 + 0.5);
|
||||
int ypxl1 = yend;
|
||||
int xpxl1 = ipart(xend);
|
||||
|
||||
if (cell(xpxl1, ypxl1).obstacle)
|
||||
obstacleAttenuation += rfpart(xend) * ygap * perObstacleAttenuation;
|
||||
|
||||
if (cell(xpxl1 + 1, ypxl1).obstacle)
|
||||
obstacleAttenuation += fpart(xend) * ygap * perObstacleAttenuation;
|
||||
|
||||
if (obstacleAttenuation >= maxAttenuation)
|
||||
return maxAttenuation;
|
||||
|
||||
float interx = xend + gradient;
|
||||
|
||||
// second end point
|
||||
yend = round(y2);
|
||||
xend = x2 + gradient * (yend - y2);
|
||||
ygap = fpart(y2 + 0.5);
|
||||
int ypxl2 = yend;
|
||||
int xpxl2 = ipart(xend);
|
||||
|
||||
if (cell(xpxl2, ypxl2).obstacle)
|
||||
obstacleAttenuation += rfpart(xend) * ygap * perObstacleAttenuation;
|
||||
|
||||
if (cell(xpxl2 + 1, ypxl2).obstacle)
|
||||
obstacleAttenuation += fpart(xend) * ygap * perObstacleAttenuation;
|
||||
|
||||
if (obstacleAttenuation >= maxAttenuation)
|
||||
return maxAttenuation;
|
||||
|
||||
for (int y = ypxl1 + 1; y < ypxl2; ++y) {
|
||||
int interxIpart = ipart(interx);
|
||||
float interxFpart = interx - interxIpart;
|
||||
float interxRFpart = 1.0 - interxFpart;
|
||||
|
||||
if (cell(interxIpart, y).obstacle)
|
||||
obstacleAttenuation += interxRFpart * perObstacleAttenuation;
|
||||
if (cell(interxIpart + 1, y).obstacle)
|
||||
obstacleAttenuation += interxFpart * perObstacleAttenuation;
|
||||
|
||||
if (obstacleAttenuation >= maxAttenuation)
|
||||
return maxAttenuation;
|
||||
|
||||
interx += gradient;
|
||||
}
|
||||
} else {
|
||||
if (x2 < x1) {
|
||||
swap(x1, x2);
|
||||
swap(y1, y2);
|
||||
}
|
||||
|
||||
float gradient = dy / dx;
|
||||
|
||||
// first end point
|
||||
float xend = round(x1);
|
||||
float yend = y1 + gradient * (xend - x1);
|
||||
float xgap = rfpart(x1 + 0.5);
|
||||
int xpxl1 = xend;
|
||||
int ypxl1 = ipart(yend);
|
||||
|
||||
if (cell(xpxl1, ypxl1).obstacle)
|
||||
obstacleAttenuation += rfpart(yend) * xgap * perObstacleAttenuation;
|
||||
|
||||
if (cell(xpxl1, ypxl1 + 1).obstacle)
|
||||
obstacleAttenuation += fpart(yend) * xgap * perObstacleAttenuation;
|
||||
|
||||
if (obstacleAttenuation >= maxAttenuation)
|
||||
return maxAttenuation;
|
||||
|
||||
float intery = yend + gradient;
|
||||
|
||||
// second end point
|
||||
xend = round(x2);
|
||||
yend = y2 + gradient * (xend - x2);
|
||||
xgap = fpart(x2 + 0.5);
|
||||
int xpxl2 = xend;
|
||||
int ypxl2 = ipart(yend);
|
||||
|
||||
if (cell(xpxl2, ypxl2).obstacle)
|
||||
obstacleAttenuation += rfpart(yend) * xgap * perObstacleAttenuation;
|
||||
|
||||
if (cell(xpxl2, ypxl2 + 1).obstacle)
|
||||
obstacleAttenuation += fpart(yend) * xgap * perObstacleAttenuation;
|
||||
|
||||
if (obstacleAttenuation >= maxAttenuation)
|
||||
return maxAttenuation;
|
||||
|
||||
for (int x = xpxl1 + 1; x < xpxl2; ++x) {
|
||||
int interyIpart = ipart(intery);
|
||||
float interyFpart = intery - interyIpart;
|
||||
float interyRFpart = 1.0 - interyFpart;
|
||||
|
||||
if (cell(x, interyIpart).obstacle)
|
||||
obstacleAttenuation += interyRFpart * perObstacleAttenuation;
|
||||
if (cell(x, interyIpart + 1).obstacle)
|
||||
obstacleAttenuation += interyFpart * perObstacleAttenuation;
|
||||
|
||||
if (obstacleAttenuation >= maxAttenuation)
|
||||
return maxAttenuation;
|
||||
|
||||
intery += gradient;
|
||||
}
|
||||
}
|
||||
|
||||
return min(obstacleAttenuation, maxAttenuation);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
Loading…
Add table
Add a link
Reference in a new issue