diff --git a/.all-contributorsrc b/.all-contributorsrc
index 02245a2..7b00059 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -48,6 +48,28 @@
"bug",
"test"
]
+ },
+ {
+ "login": "Dead-Deus",
+ "name": "Dead-Deus",
+ "avatar_url": "https://avatars.githubusercontent.com/u/89898198?v=4",
+ "profile": "https://github.com/Dead-Deus",
+ "contributions": [
+ "infra",
+ "bug"
+ ]
+ },
+ {
+ "login": "JonathSpirit",
+ "name": "GuillaumeG.",
+ "avatar_url": "https://avatars.githubusercontent.com/u/48102745?v=4",
+ "profile": "https://github.com/JonathSpirit",
+ "contributions": [
+ "bug",
+ "test",
+ "code",
+ "ideas"
+ ]
}
],
"projectName": "Candle",
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..e1f2113
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+# Ignoring build dir
+build/
\ No newline at end of file
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 4dc14e3..593e7dd 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -13,15 +13,27 @@ set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY lib)
# might need to set manually SFML_ROOT to the install location of SFML for Windows users
# set(SFML_ROOT "")
+if(SFML_ROOT STREQUAL "")
+ find_package(SFML 2.5 REQUIRED COMPONENTS graphics)
+endif()
# if the user wants to use static SFML libs
# set(SFML_STATIC_LIBRARIES TRUE)
-find_package(SFML 2.5 REQUIRED COMPONENTS graphics)
-
+set(CANDLE_HEADERS
+ include/Candle/LightingArea.hpp
+ include/Candle/LightSource.hpp
+ include/Candle/RadialLight.hpp
+ include/Candle/DirectedLight.hpp
+ include/Candle/geometry/Line.hpp
+ include/Candle/geometry/Polygon.hpp
+ include/Candle/geometry/Vector2.hpp
+ include/Candle/graphics/Color.hpp
+ include/Candle/graphics/VertexArray.hpp
+ include/Candle/Constants.hpp
+)
set(CANDLE_SRC
-
src/LightingArea.cpp
src/LightSource.cpp
src/RadialLight.cpp
@@ -31,11 +43,10 @@ set(CANDLE_SRC
src/Color.cpp
src/VertexArray.cpp
src/Constants.cpp
-
)
# Static library target
-add_library(Candle-s STATIC ${CANDLE_SRC})
+add_library(Candle-s STATIC ${CANDLE_SRC} ${CANDLE_HEADERS})
target_include_directories(Candle-s PUBLIC include)
target_link_libraries(Candle-s sfml-graphics)
diff --git a/README.md b/README.md
index 478eb1d..dc4b20a 100644
--- a/README.md
+++ b/README.md
@@ -78,7 +78,9 @@ Thanks to the people that have contributed to this project: ([emoji key](https:/
Modar Nasser π π π |
nightroy99 π π |
Lukas DΓΌrrenberger π |
- Tim Stoddard π»π β οΈ |
+ Tim Stoddard π» π β οΈ |
+ Dead-Deus π π |
+ GuillaumeG. π β οΈ π» π€ |
diff --git a/include/Candle/RadialLight.hpp b/include/Candle/RadialLight.hpp
index e7ab17b..f3384ce 100644
--- a/include/Candle/RadialLight.hpp
+++ b/include/Candle/RadialLight.hpp
@@ -13,15 +13,15 @@ namespace candle{
/**
* @brief LightSource that emits light from a single point
* @details
- *
+ *
* A RadialLight is defined, mainly, by the position, the orientation, the
* range of the light and the beam angle. To manipulate the
* position and the orientation of the light, you can change the position
* and rotation of the object as you would do with any sf::Transformable.
* The range can be manipulated as with other LightSources, with
- * @ref LightSource::setRange, and the angle of the beam with
+ * @ref LightSource::setRange, and the angle of the beam with
* @ref setBeamAngle.
- *
+ *
*
*
* Variables schema |
@@ -33,23 +33,23 @@ namespace candle{
private:
static int s_instanceCount;
float m_beamAngle;
-
+
void draw(sf::RenderTarget& t, sf::RenderStates st) const override;
void resetColor() override;
-
+
public:
/**
* @brief Constructor
*/
RadialLight();
-
+
/**
* @brief Destructor
*/
virtual ~RadialLight();
-
+
void castLight(const EdgeVector::iterator& begin, const EdgeVector::iterator& end) override;
-
+
/**
* @brief Set the range for which rays may be casted.
* @details The angle shall be specified in degrees. The angle in which the rays will be casted will be
@@ -58,14 +58,26 @@ namespace candle{
* @see getBeamAngle
*/
void setBeamAngle(float angle);
-
+
/**
* @brief Get the range for which rays may be casted.
- * @details It defaults to 360ΒΊ.
+ * @details It defaults to 360ΒΊ.
* @see setBeamAngle
*/
- float getBeamAngle() const;
-
+ float getBeamAngle() const;
+
+ /**
+ * @brief Get the local bounding rectangle of the light.
+ * @returns The local bounding rectangle in float.
+ */
+ sf::FloatRect getLocalBounds() const;
+
+ /**
+ * @brief Get the global bounding rectangle of the light.
+ * @returns The global bounding rectangle in float.
+ */
+ sf::FloatRect getGlobalBounds() const;
+
};
}
diff --git a/include/Candle/geometry/Line.hpp b/include/Candle/geometry/Line.hpp
index b4eaaf9..daeb2c7 100644
--- a/include/Candle/geometry/Line.hpp
+++ b/include/Candle/geometry/Line.hpp
@@ -10,6 +10,7 @@
#include
#include
+#include
#include "Candle/geometry/Vector2.hpp"
#include "Candle/Constants.hpp"
@@ -29,7 +30,7 @@ namespace sfu{
};
sf::Vector2f m_origin; ///< Origin point of the line.
sf::Vector2f m_direction; ///< Direction vector (not necessarily normalized)
-
+
/**
* @brief Construct a line that passes through @p p1 and @p p2
* @details The direction is interpreted as p2 - p1.
@@ -37,7 +38,7 @@ namespace sfu{
* @param p2 Second point
*/
Line(const sf::Vector2f& p1, const sf::Vector2f& p2);
-
+
/**
* @brief Construct a line defined by a point and an angle.
* @details The direction is interpreted as {cos(angle), sin(angle)}.
@@ -45,7 +46,16 @@ namespace sfu{
* @param angle Angle defining the line
*/
Line(const sf::Vector2f& p, float angle);
-
+
+ /**
+ * @brief Get the global bounding rectangle of the line.
+ * @details The returned rectangle is in global coordinates, which
+ * means that it takes into account the transformations (translation,
+ * rotation, scale, ...) (see SFML).
+ * @returns Global bounding rectangle in float
+ */
+ sf::FloatRect getGlobalBounds() const;
+
/**
* @brief Return the relative position of a point to the line.
* @details If the point is to the right of the direction vector, the
@@ -55,21 +65,21 @@ namespace sfu{
* @returns -1, 0 or 1
*/
int relativePosition(const sf::Vector2f& point) const;
-
+
/**
* @brief Return the minimum distance of a point to the line.
* @param point
* @returns The minimum distance of a point to the line.
*/
float distance(const sf::Vector2f& point) const;
-
+
/**
* @brief Returns the relative position of one line to another.
* @param line
* @returns The relative position of the two lines.
*/
LineRelativePosition intersection(const Line& line) const;
-
+
/**
* @brief Returns the relative position of one line to another.
* @details If the relative position is SECANT, the output argument
@@ -81,12 +91,12 @@ namespace sfu{
* @see point
*/
LineRelativePosition intersection(const Line& line, float& t) const;
-
+
/**
* @brief Returns the relative position of one line to another.
* @details If the relative position is SECANT, the output argument
* @p t1 contains the parameter required to get the intersection
- * point with **this** line and @p t2, the parameter required to
+ * point with **this** line and @p t2, the parameter required to
* get it with @p line.
* @param line
* @param t1 (Output argument)
@@ -95,7 +105,7 @@ namespace sfu{
* @see point
*/
LineRelativePosition intersection(const Line& line, float& t1, float& t2) const;
-
+
/**
* @brief Get a point of the line.
* @details The point is obtained is m_origin + param * m_direction
@@ -103,20 +113,20 @@ namespace sfu{
* @returns A point of the line
*/
sf::Vector2f point(float param) const;
-
+
};
-
+
/**
* @brief Cast a ray against a set of segments.
- * @details Use a line as a ray, casted from its
- * [origin](@ref sfu::Line::m_origin) in its
+ * @details Use a line as a ray, casted from its
+ * [origin](@ref sfu::Line::m_origin) in its
* [direction](@ref sfu::Line::m_direction). It is intersected with * a set
* of segments, represented as [Lines](sfu::Line) too, and the one closest
* to the cast point is returned.
- *
+ *
* Segments are interpreted to be delimited by the @p ray.m_origin and
* @p ray.point(1).
- *
+ *
* @param begin Iterator to the first ray.
* @param end Iterator to the last ray.
* @param ray
@@ -126,7 +136,7 @@ namespace sfu{
template
sf::Vector2f castRay(const Iterator& begin,
const Iterator& end,
- Line ray,
+ Line ray,
float maxRange=std::numeric_limits::infinity()){
float minRange = maxRange;
ray.m_direction = sfu::normalize(ray.m_direction);
diff --git a/src/Line.cpp b/src/Line.cpp
index 70a6d5c..a9f22ce 100644
--- a/src/Line.cpp
+++ b/src/Line.cpp
@@ -7,7 +7,7 @@ namespace sfu{
Line::Line(const sf::Vector2f& p1, const sf::Vector2f& p2):
m_origin(p1),
m_direction(p2 - p1){}
-
+
Line::Line(const sf::Vector2f& p, float angle):
m_origin(p)
{
@@ -17,13 +17,26 @@ namespace sfu{
ang -= sfu::PI;
m_direction = {std::cos(ang), std::sin(ang)};
}
-
-
+
+ sf::FloatRect Line::getGlobalBounds() const{
+ const sf::Vector2f& point1 = m_origin;
+ sf::Vector2f point2 = m_direction + m_origin;
+
+ //Make sure that the rectangle begin from the upper left corner
+ sf::FloatRect rect;
+ rect.left = (point1.x < point2.x) ? point1.x : point2.x;
+ rect.top = (point1.y < point2.y) ? point1.y : point2.y;
+ rect.width = std::abs(m_direction.x) + 1.0f; //The +1 is here to avoid having a width of zero
+ rect.height = std::abs(m_direction.y) + 1.0f; //(SFML doesn't like 0 in rect)
+
+ return rect;
+ }
+
int Line::relativePosition(const sf::Vector2f& point) const{
float f = (point.x-m_origin.x) / m_direction.x - (point.y-m_origin.y) / m_direction.y;
return (0.f < f) - (f < 0.f);
}
-
+
float Line::distance(const sf::Vector2f& point) const{
float d;
if(m_direction.x == 0){
@@ -38,7 +51,7 @@ namespace sfu{
}
return d;
}
-
+
Line::LineRelativePosition Line::intersection(const Line& l) const{
float t1, t2;
return intersection(l,t1,t2);
@@ -52,7 +65,7 @@ namespace sfu{
auto& v = m_direction;
auto& b = l.m_origin;
auto& w = l.m_direction;
-
+
float th = angle(v, w);
if(th < 0.001f || th > 359.99f){
if(relativePosition(a) == 0){
@@ -61,7 +74,7 @@ namespace sfu{
return PARALLEL;
}
}
-
+
if(std::abs(w.y) < 0.001f){
t1 = (b.y-a.y) / v.y;
t2 = (a.x + t1*v.x - b.x) / w.x;
@@ -69,7 +82,7 @@ namespace sfu{
t1 = (w.y * (b.x-a.x) + w.x * (a.y-b.y)) / (v.x*w.y - v.y*w.x);
t2 = (t1*v.y + a.y - b.y) / w.y;
}
-
+
return SECANT;
}
sf::Vector2f Line::point(float param) const{
diff --git a/src/RadialLight.cpp b/src/RadialLight.cpp
index 9cfa737..bbefad6 100644
--- a/src/RadialLight.cpp
+++ b/src/RadialLight.cpp
@@ -17,18 +17,18 @@ namespace candle{
bool l_texturesReady(false);
std::unique_ptr l_lightTextureFade;
std::unique_ptr l_lightTexturePlain;
-
+
void initializeTextures(){
#ifdef CANDLE_DEBUG
std::cout << "RadialLight: InitializeTextures" << std::endl;
#endif
int points = 100;
-
+
l_lightTextureFade.reset(new sf::RenderTexture);
l_lightTexturePlain.reset(new sf::RenderTexture);
l_lightTextureFade->create(BASE_RADIUS*2 + 2, BASE_RADIUS*2 + 2);
l_lightTexturePlain->create(BASE_RADIUS*2 + 2, BASE_RADIUS*2 + 2);
-
+
sf::VertexArray lightShape(sf::TriangleFan, points+2);
float step = sfu::PI*2.f/points;
lightShape[0].position = {BASE_RADIUS + 1, BASE_RADIUS + 1};
@@ -43,20 +43,20 @@ namespace candle{
l_lightTextureFade->draw(lightShape);
l_lightTextureFade->display();
l_lightTextureFade->setSmooth(true);
-
+
sfu::setColor(lightShape, sf::Color::White);
l_lightTexturePlain->clear(sf::Color::Transparent);
l_lightTexturePlain->draw(lightShape);
l_lightTexturePlain->display();
l_lightTexturePlain->setSmooth(true);
}
-
+
float module360(float x){
x = (float)fmod(x,360.f);
if(x < 0.f) x += 360.f;
return x;
}
-
+
RadialLight::RadialLight()
: LightSource()
{
@@ -67,17 +67,17 @@ namespace candle{
}
m_polygon.setPrimitiveType(sf::TriangleFan);
m_polygon.resize(6);
- m_polygon[0].position =
+ m_polygon[0].position =
m_polygon[0].texCoords = {BASE_RADIUS+1, BASE_RADIUS+1};
- m_polygon[1].position =
+ m_polygon[1].position =
m_polygon[5].position =
- m_polygon[1].texCoords =
+ m_polygon[1].texCoords =
m_polygon[5].texCoords = {0.f, 0.f};
- m_polygon[2].position =
+ m_polygon[2].position =
m_polygon[2].texCoords = {BASE_RADIUS*2 + 2, 0.f};
- m_polygon[3].position =
+ m_polygon[3].position =
m_polygon[3].texCoords = {BASE_RADIUS*2 + 2, BASE_RADIUS*2 + 2};
- m_polygon[4].position =
+ m_polygon[4].position =
m_polygon[4].texCoords = {0.f, BASE_RADIUS*2 + 2};
Transformable::setOrigin(BASE_RADIUS, BASE_RADIUS);
setRange(1.0f);
@@ -85,7 +85,7 @@ namespace candle{
// castLight();
s_instanceCount++;
}
-
+
RadialLight::~RadialLight(){
s_instanceCount--;
#ifdef RADIAL_LIGHT_FIX
@@ -102,7 +102,7 @@ namespace candle{
}
#endif
}
-
+
void RadialLight::draw(sf::RenderTarget& t, sf::RenderStates s) const{
sf::Transform trm = Transformable::getTransform();
trm.scale(m_range/BASE_RADIUS, m_range/BASE_RADIUS, BASE_RADIUS, BASE_RADIUS);
@@ -121,49 +121,59 @@ namespace candle{
void RadialLight::resetColor(){
sfu::setColor(m_polygon, m_color);
}
-
+
void RadialLight::setBeamAngle(float r){
m_beamAngle = module360(r);
}
-
+
float RadialLight::getBeamAngle() const{
return m_beamAngle;
+ }
+
+ sf::FloatRect RadialLight::getLocalBounds() const{
+ return sf::FloatRect(0.0f, 0.0f, m_range*4, m_range*4);
+ }
+
+ sf::FloatRect RadialLight::getGlobalBounds() const{
+ float scaledRange = m_range / BASE_RADIUS;
+ sf::Transform trm = Transformable::getTransform();
+ trm.scale(scaledRange, scaledRange, BASE_RADIUS, BASE_RADIUS);
+ return trm.transformRect( getLocalBounds() );
}
-
+
void RadialLight::castLight(const EdgeVector::iterator& begin, const EdgeVector::iterator& end){
float scaledRange = m_range / BASE_RADIUS;
sf::Transform trm = Transformable::getTransform();
trm.scale(scaledRange, scaledRange, BASE_RADIUS, BASE_RADIUS);
std::vector rays;
-
+
rays.reserve(2 + std::distance(begin, end) * 2 * 3); // 2: beam angle, 4: corners, 2: pnts/sgmnt, 3 rays/pnt
-
+
// Start casting
float bl1 = module360(getRotation() - m_beamAngle/2);
float bl2 = module360(getRotation() + m_beamAngle/2);
bool beamAngleBigEnough = m_beamAngle < 0.1f;
auto castPoint = Transformable::getPosition();
float off = .001f;
-
+
auto angleInBeam = [&](float a)-> bool {
- return beamAngleBigEnough
+ return beamAngleBigEnough
||(bl1 < bl2 && a > bl1 && a < bl2)
||(bl1 > bl2 && (a > bl1 || a < bl2));
};
-
+
for(float a = 45.f; a < 360.f; a += 90.f){
if(beamAngleBigEnough || angleInBeam(a)){
rays.emplace_back(castPoint, a);
}
}
-
+
+ sf::FloatRect lightBounds = getGlobalBounds();
for(auto it = begin; it != end; it++){
auto& s = *it;
- float d1 = s.distance(castPoint);
- // float d2 = sfu::magnitude(s.m_origin - castPoint);
- // float d3 = sfu::magnitude(s.point(1.f) - castPoint);
- // if(std::max(std::min(d2, d3), d1) <= m_range*std::sqrt(2)){
- if(d1 <= m_range){
+
+ //Only cast a ray if the line is in range
+ if( lightBounds.intersects( s.getGlobalBounds() ) ){
sfu::Line r1(castPoint, s.m_origin);
sfu::Line r2(castPoint, s.point(1.f));
float a1 = sfu::angle(r1.m_direction);
@@ -180,7 +190,7 @@ namespace candle{
}
}
}
-
+
if(bl1 > bl2){
std::sort(
rays.begin(),
@@ -198,7 +208,7 @@ namespace candle{
rays.begin(),
rays.end(),
[bl1] (sfu::Line& r1, sfu::Line& r2){
- return
+ return
sfu::angle(r1.m_direction) < sfu::angle(r2.m_direction);
}
);
@@ -207,7 +217,7 @@ namespace candle{
rays.emplace(rays.begin(), castPoint, bl1);
rays.emplace_back(castPoint, bl2);
}
-
+
sf::Transform tr_i = trm.getInverse();
// keep only the ones within the area
std::vector points;
@@ -225,7 +235,7 @@ namespace candle{
sf::Vector2f al2(std::cos(bl2rad), std::sin(bl2rad));
int d_n = points.size()*2 + 4;
m_debug.resize(d_n);
- m_debug[d_n-1].color = m_debug[d_n-2].color = sf::Color::Cyan;
+ m_debug[d_n-1].color = m_debug[d_n-2].color = sf::Color::Cyan;
m_debug[d_n-3].color = m_debug[d_n-4].color = sf::Color::Yellow;
m_debug[d_n-1].position = m_debug[d_n-3].position = m_polygon[0].position;
m_debug[d_n-2].position = tr_i.transformPoint(castPoint + m_range * al1);
@@ -240,7 +250,7 @@ namespace candle{
m_debug[i*2].position = m_polygon[0].position;
m_debug[i*2+1].position = p;
m_debug[i*2].color = m_debug[i*2+1].color = sf::Color::Magenta;
-#endif
+#endif
}
if(beamAngleBigEnough){
m_polygon[points.size()+1] = m_polygon[1];