glm::vec2 ArcPath::getPoint(float f) const
		{
			float rad = fabs(radius+offset);

			if (rad < 400) //TODO: nasty condition here... to protect from 'straight lines'
			{
				float r1 = atan2(begin.y - origin.y, begin.x - origin.x);
				float r2 = atan2(end.y - origin.y, end.x - origin.x);

				float inc = 0;
				if (!sign_n)
					inc = angleDist(r2, r1) * f;
				else
					inc = angleDist(r1, r2) * f;

				if (sign_n)
					inc = -inc;

				//todo: fix condition here
				float angle = r1 + inc;
				return origin + rad * blib::util::fromAngle(angle);
			}
			else
			{
				glm::vec2 beginNormal(begindirection.y, -begindirection.x);
				return begin + (sign_t ? -offset : offset) * glm::normalize(beginNormal) + f * (end - begin);
			}


		}
		void ArcPath::buildLines()
		{
			float rad = fabs(radius+offset);

			if (rad < 400) //TODO: nasty condition here... to protect from 'straight lines'
			{
				float r1 = atan2(begin.y - origin.y, begin.x - origin.x);
				float r2 = atan2(end.y - origin.y, end.x - origin.x);

                float inc = blib::math::pif / (5 + glm::min(100.0f, glm::abs(radius+offset)));
				if (sign_n)
					inc = -inc;

				//todo: fix condition here
				float last = r1;
				for (float f = r1; fabs(angleDist(f + inc, r2)) > fabs(inc); f += inc)
				{
                    if (f > blib::math::pif)
                        f -= blib::math::pif * 2;
                    if (f < -blib::math::pif)
                        f += blib::math::pif * 2;

					lines.push_back(LinePart(origin + rad * blib::util::fromAngle(f), origin + rad * blib::util::fromAngle(f + inc)));
					last = f + inc;
				}
				if (!lines.empty())
				{
					//	lines.pop_back();
					lines.push_back(LinePart(origin + rad * blib::util::fromAngle(last), origin + rad * blib::util::fromAngle(r2)));
				}
				else
					lines.push_back(LinePart(origin + rad * blib::util::fromAngle(r1), origin + rad * blib::util::fromAngle(r2)));
			}
			else
			{
				lines.push_back(LinePart(begin, end));
			}
		}
void CitySceneGenerator::generate(Scene* scene) {
	auto renderer = scene->renderer();
	auto material = std::make_shared<PhongMaterial>(renderer);
	material->setShader(renderer->shaderManager()->getGlslProgram("phong"));

	PhongMaterialData materialData = { glm::vec4(0.0f, 0.1f, 0.0f, 1.0f), 
		glm::vec4(0.8f, 0.3f, 0.1f, 1.0f), glm::vec4(0.3f, 0.3f, 0.3f, 1.0f), 5.0f };

	material->properties()->setData(materialData);
	material->properties()->flushData();

	auto mesh = std::make_shared<Mesh>();
	mesh->setPrimitiveType(PrimitiveType::TriangleList);

	size_t buildingVerticesCount = sizeof(buildingVertices) / sizeof(*buildingVertices);
	std::vector<char> vertices(reinterpret_cast<const char*>(buildingVertices), 
		reinterpret_cast<const char*>(buildingVertices) + sizeof(buildingVertices));
	std::vector<VertexElement> layout = {
		VertexElement(3, VertexElementType::Float),
		VertexElement(3, VertexElementType::Float)
	};
	mesh->loadVertices(vertices, buildingVerticesCount, layout);

	size_t buildingIndicesCount = sizeof(buildingIndices) / sizeof(*buildingIndices);
	std::vector<uint32_t> indices(reinterpret_cast<const unsigned*>(buildingIndices), 
		reinterpret_cast<const unsigned*>(buildingIndices) + buildingIndicesCount);
	mesh->loadIndices(indices);

	size_t numBuildings = 1000;
	float citySize = 500.0f;
	float minBuildingSize = 10.0f;
	float maxBuildingSize = 60.0f;
	float minHeightToWidthRatio = 8.0f;
	float maxHeightToWidthRatio = 16.0f;

	std::uniform_real_distribution<float> angleDist(0.0f, 360.0f);
	std::uniform_real_distribution<float> positionDist(-citySize, citySize);
	std::uniform_real_distribution<float> canonicalDist;

	std::vector<std::shared_ptr<BaseSceneObject>> buildings;
	for (size_t i = 0; i < numBuildings; i++) {
		auto building = std::make_shared<Building>(mesh, material);

		// set random position
		glm::mat4 model = glm::translate(glm::mat4(1.0f),
			glm::vec3(positionDist(m_rng), positionDist(m_rng), 0.0f)
		);

		// rotate around z with random angle
		model = glm::rotate(model, angleDist(m_rng), glm::vec3(0.0f, 0.0f, 1.0f));

		glm::vec3 scale;
		// multiplying uniform distribution will generate beta distribution
		scale.x = canonicalDist(m_rng) * canonicalDist(m_rng) * canonicalDist(m_rng) * canonicalDist(m_rng)
			* (maxBuildingSize - minBuildingSize) + minBuildingSize;
		scale.y = scale.x;
		scale.z = canonicalDist(m_rng) * canonicalDist(m_rng) * canonicalDist(m_rng) * scale.x
			* (maxHeightToWidthRatio - minHeightToWidthRatio) + minHeightToWidthRatio;
		model = glm::scale(model, scale);

		building->setModelMatrix(model);
		building->calculateBBox();

		buildings.push_back(building);
	}

	scene->setStaticGeometry(std::move(buildings));
}