Exemplo n.º 1
0
	bool plane::isInPlane(const line& l)const
	{
		auto dot = norm_.dotProduct(l.dir());
		if (!floatEqual(dot, 0.0f))
			return false;

		return isInPlane(l.start());
	}
Exemplo n.º 2
0
	bool line::isParallel(const line& l)const
	{
		auto dot = dir_.dotProduct(l.dir_);
		return floatEqual(dot, 0.0f);
	}
Exemplo n.º 3
0
	bool operator == (const vector3& v1, const vector3& v2)
	{
		return floatEqual(v1.x_, v2.x_) && floatEqual(v1.y_, v2.y_) && floatEqual(v1.z_, v2.z_);
	}
Exemplo n.º 4
0
	bool plane::isInPlane(const vector3& p)const
	{
		auto dot = norm_.dotProduct(p - point_);
		return floatEqual(dot, 0.0f);
	}
Exemplo n.º 5
0
	void Light::OnUpdate(sf::Time interval) {
		std::lock_guard<std::recursive_mutex> lg(m_mutex);
		if (!m_active || !m_render || !GetParent()->IsRender()) return;
		sf::Vector2f pos = GetGlobalPosition();
		const auto& view = m_scene->GetGame()->GetWindow()->getView();
		auto vr = sf::FloatRect(view.getCenter().x - view.getSize().x / 2, view.getCenter().y - view.getSize().y / 2,
								view.getSize().x,
								view.getSize().y);
		if (!vr.intersects(sf::Rect<float>(pos.x - m_radius, pos.y - m_radius, 2 * m_radius, 2 * m_radius))) {
			m_blocked = true;
			return;
		}
		b2AABB center;
		center.lowerBound.x = pos.x / m_scene->GetPixelMeterRatio();
		center.lowerBound.y = pos.y / m_scene->GetPixelMeterRatio();
		float onep = (1.f / m_scene->GetPixelMeterRatio());
		center.upperBound.x = center.lowerBound.x + onep;
		center.upperBound.y = center.lowerBound.y + onep;
		CenterQuery cq(center.lowerBound.x, center.lowerBound.y);
		GetScene()->GetWorld()->QueryAABB(&cq, center);
		if (cq.hit) {
			cq.node->OnLightRay.Fire(this);
			m_blocked = true;
			return;
		}
		m_blocked = false;
		float rayDistance =
				(2 - cosf(m_openingAngle / (m_rayCount - 1))) * m_radius / m_scene->GetPixelMeterRatio();
		b2Vec2 basePos(pos.x / m_scene->GetPixelMeterRatio(),
					   pos.y / m_scene->GetPixelMeterRatio());
		struct edgeData {
			b2Vec2 pos;
			b2Fixture* fixture;
			int vertex;
		};
		std::map<int, edgeData> edges;

		auto EdgeFromPos = [&, this](const b2Vec2& p) -> edgeData* {
			float angle = atan2f(basePos.y - p.y, basePos.x - p.x) + fPI;
			if (angle > m_angle + m_openingAngle || angle < m_angle) {
				return nullptr;
			}
			int i = static_cast<int>(angle / fPI * 180) % 360;
			auto it = edges.find(i);
			if (it == edges.end()) {
				float r = m_radius / m_scene->GetPixelMeterRatio();
				edgeData def{basePos + b2Vec2(r, r), nullptr, 0};
				edges.insert(std::make_pair(i, def));
				return &edges.find(i)->second;
			}
			return &it->second;
		};

		auto aabbCallback = engine::MakeAABBQueryCallback([&, this](b2Fixture* fixture) -> bool {
			if (!fixture->GetBody()->GetUserData() ||
				static_cast<Node*>(fixture->GetBody()->GetUserData())->IsOpaque())
				return true;

			if (fixture->GetShape()->GetType() == b2Shape::e_polygon) {
				b2PolygonShape* shape = static_cast<b2PolygonShape*>(fixture->GetShape());
				for (size_t i = 0; i < shape->GetVertexCount(); i++) {
					const b2Vec2& vertex = shape->GetVertex(i);
					b2Vec2 vertexPos = b2Mul(fixture->GetBody()->GetTransform(), vertex);
					auto vLen = (vertexPos - basePos).Length();
					if (vLen < m_radius / m_scene->GetPixelMeterRatio()) {
						auto edge = EdgeFromPos(vertexPos);
						if (!edge) continue;
						// Is the vertex we found better
						b2Vec2 dif = edge->pos - basePos;
						if (vLen < dif.Length()) {
							edge->pos = vertexPos;
						}
						edge->fixture = fixture;
						edge->vertex = i;
					}
				}
			}
			return true;
		});

		b2AABB aabb;
		aabb.lowerBound = b2Vec2((pos.x - m_radius) / m_scene->GetPixelMeterRatio(),
								 (pos.y - m_radius) / m_scene->GetPixelMeterRatio());
		aabb.upperBound = b2Vec2((pos.x + m_radius) / m_scene->GetPixelMeterRatio(),
								 (pos.y + m_radius) / m_scene->GetPixelMeterRatio());
		m_scene->GetWorld()->QueryAABB(&aabbCallback, aabb);
		float step = m_openingAngle / static_cast<float> (m_rayCount - 1);
		float angle = m_angle;
		auto it = edges.begin();
		m_vertices.resize(1); // keep the center vertex
		float f = 1.0;
		Node* hitNode = nullptr;
		auto rayCastCallback = MakeRayCastCallback([&](b2Fixture* fixture, const b2Vec2& point,
													   const b2Vec2& normal, float32 fraction) {
			Node* n = static_cast<Node*> (fixture->GetBody()->GetUserData());
			if (n && !n->IsOpaque() && fraction < f) {
				f = fraction;
				hitNode = n;
			}
			return f;
		});
		sf::Vertex v;
		float edgeAngle = 0;
		v.position.x = cosf(angle) * m_radius;
		v.position.y = sinf(angle) * m_radius;
		f = 1.0;
		m_scene->GetWorld()->RayCast(&rayCastCallback, basePos, basePos + b2Vec2(v.position.x /
																				 m_scene->GetPixelMeterRatio(),
																				 v.position.y /
																				 m_scene->GetPixelMeterRatio()));
		if (hitNode) hitNode->OnLightRay.Fire(this);
		v.position.x *= f;
		v.position.y *= f;
		AssignLightColor(v, f, m_lightColor);
		m_vertices.push_back(v);
		angle += step;
		for (size_t i = 2; i < m_rayCount + 1; i++, angle += step) {
			bool had = false;
			while (it != edges.end()) {
				edgeAngle = b2Angle(basePos, it->second.pos);
				if (edgeAngle < 0) edgeAngle += fPI * 2;
				if (angle < edgeAngle || edgeAngle >= angle + step) {
					break;
				}
				if (it->second.fixture == nullptr) {
					++it;
					continue;
				}
				f = 1.0;
				m_scene->GetWorld()->RayCast(&rayCastCallback, basePos, it->second.pos);
				// Check if this edge is blocked, skip if it is
				if (f < 1.0 - 10.0f / m_radius) {
					++it;
					continue;
				}
				if (hitNode) hitNode->OnLightRay.Fire(this);
				had = true;
				float edgeLengthPct =
						m_scene->MeterToPixel((basePos - it->second.pos).Length()) / m_radius + (10.0f / m_radius);
				auto addPoint = [&, this](b2Vec2 point) {
					v.position.x = m_scene->MeterToPixel(point.x) - pos.x;
					v.position.y = m_scene->MeterToPixel(point.y) - pos.y;
					f = sqrtf(v.position.x * v.position.x + v.position.y * v.position.y) / m_radius;
					AssignLightColor(v, f, m_lightColor);
					m_vertices.push_back(v);
				};
				// Check surrounding edges by using half a degree differences
				float checkAngle = edgeAngle - (fPI / 840.f);
				if (checkAngle > 0) {
					f = 1.0;
					b2Vec2 edge = b2Vec2(cosf(edgeAngle - (fPI / 840.f)),
										 sinf(edgeAngle - (fPI / 840.f)));
					edge *= (m_radius / m_scene->GetPixelMeterRatio());
					edge += basePos;
					m_scene->GetWorld()->RayCast(&rayCastCallback, basePos, edge);
					if (f > edgeLengthPct) {
						b2Vec2 p = (basePos - edge);
						p *= -f;
						addPoint(basePos + p);
					}
				}
				addPoint(it->second.pos);
				f = 1.0;
				checkAngle = edgeAngle + (fPI / 840.f);
				if (checkAngle < fPI * 2) {
					b2Vec2 edge =
							b2Vec2(cosf(checkAngle),
								   sinf(checkAngle));
					edge *= (m_radius / m_scene->GetPixelMeterRatio());
					edge += basePos;
					m_scene->GetWorld()->RayCast(&rayCastCallback, basePos, edge);
					if (f > edgeLengthPct) {
						b2Vec2 p = (basePos - edge);
						p *= -f;
						addPoint(basePos + p);
					}
				}
				++it;
			}
			// Prevent overlapping rays
			if (!had || had && !floatEqual(edgeAngle, angle, fPI / 180.0f) || i == 1 ||
				i == m_rayCount) {
				v.position.x = cosf(angle) * m_radius;
				v.position.y = sinf(angle) * m_radius;
				f = 1.0;
				m_scene->GetWorld()->RayCast(&rayCastCallback, basePos, basePos + b2Vec2(v.position.x /
																						 m_scene->GetPixelMeterRatio(),
																						 v.position.y /
																						 m_scene->GetPixelMeterRatio()));
				if (hitNode) hitNode->OnLightRay.Fire(this);
				v.position.x *= f;
				v.position.y *= f;
				AssignLightColor(v, f, m_lightColor);
				m_vertices.push_back(v);
			}
		}
	}