Exemplo n.º 1
0
	Pollen() noexcept
		: type((Type)Random<uint32_t>(0u,3u))
	{
		{
			Lock lock(mxCounter);
			if ((++counter) == 1)
			{			
				//create an icosphere of radius 1.0f
				std::vector<Vec3> spherePositions;
				{
					Mesh mesh;
					auto data(mesh.Sphere({}, 1.0f, YGG_DEBUG_CONDITIONAL(2,4), true).Decompose());
					for (auto i : data->Indices)
						spherePositions.push_back(data->Positions[i]);
				}

				//deform a copy of the sphere once for each type
				for (Type t = Type::Linear; t < Type::Count; t = (Type)((uint32_t)t + 1u))
				{
					uint32_t spikeCount(40);
					switch (t)
					{
						case Type::Linear: spikeCount = 3 * spikeCount / 4; break;
						case Type::Square: spikeCount = 2 * spikeCount / 3; break;
						case Type::Circular: spikeCount = spikeCount / 2; break;
					}

					//pick equidistant points around unit sphere (see http://www.cmu.edu/biolphys/deserno/pdf/sphere_equi.pdf)
					std::vector<Vec3> spikes;
					float a((4.0f * Pi) / (float)spikeCount);
					float d(sqrtf(a));
					uint32_t mTheta(Round<uint32_t>(Pi / d));
					float dTheta(Pi / (float)mTheta);
					float dAlpha(a / dTheta);
					for (uint32_t m = 0; m < mTheta; ++m)
					{
						float theta((Pi*((float)m + 0.5f)) / (float)mTheta);
						uint32_t mAlpha(Round<uint32_t>((2.0f * Pi * sinf(theta)) / dAlpha));
						for (uint32_t n = 0; n < mAlpha; ++n)
						{
							float alpha((2.0f * Pi * (float)n) / (float)mAlpha);
							spikes.emplace_back(sinf(theta) * cosf(alpha),
								sinf(theta)*sinf(alpha),
								cos(theta));
						}
					}

					//minimum distance to consider a spike as being "in range"
					float rad = d / 2.1f;

					//loop through the vertices and deform the sphere based 
					//on proximity to nearest spike
					std::vector<Vec3> positions(spherePositions);
					for (size_t v = 0; v < positions.size(); ++v)
					{
						//find closest spike
						float dist(Vec3::DistanceSquared(positions[v], spikes[0]));
						for (size_t s = 1; s < spikes.size(); ++s)
							dist = std::min(dist, Vec3::DistanceSquared(positions[v], spikes[s]));

						//convert distance into a proximity function & deform
						dist = ((rad - sqrtf(dist)) / rad);
						positions[v] *= metrics.Radius + metrics.Radius * 0.25f * ApplyDeformation(t, dist);

					}

					//create static mesh
					Mesh mesh;
					meshes.emplace_back(new StaticMesh(mesh.AddPositions(std::move(positions)).GenerateIndices().GenerateNormals()));
				}

			}
			if (Game::Physics()->Started() && !rigidBodyMesh)
				rigidBodyMesh = Game::Physics()->CreateSphereMesh(metrics.Radius);
		}


		entity.reset(Game::Scene()->Create("", this));
		auto _position(PickSpawnLocation(true));
		transform = entity->Add<Transform>(_position);
		transform->Forward(Random<Vec3>());
		static std::vector<Colour> colours
		{
			Yellow, Olive, BlanchedAlmond, YellowGreen
		};
		material.reset(new Phong(Colour(colours[Random<size_t>(0, colours.size() - 1)],0.0f)));
		entity->Add<MeshRenderer>(meshes[Random<size_t>(0, meshes.size() - 1)], material);

		if (Game::Physics()->Started())
			rigidBody.reset(Game::Physics()->Create(rigidBodyMesh, true, _position, transform->Orientation(), metrics.Density));
		entity->Add<Ticker>()->OnTick += [](Ticker* t, float deltaTime)
		{
			auto pollen(static_cast<Pollen*>(t->Entity()->Data));
			if (Game::Physics()->Started())
				pollen->transform->Pose(pollen->rigidBody->Position(), pollen->rigidBody->Orientation());

			if (!world.Contains(pollen->transform->Position()))
			{
				Vec3 newPos(PickSpawnLocation(false));
				pollen->transform->Position(newPos);
				if (Game::Physics()->Started())
					pollen->rigidBody->Position(newPos).Stop();
				pollen->spawnTime = 0.0f;
			}

			pollen->spawnTime += deltaTime;
			float alpha(std::min(pollen->spawnTime * 0.33f,1.0f));
			if (!spawnBounds.Contains(pollen->transform->Position()))
			{
				alpha = std::min(1.0f - Clamp((Vec3::Distance(spawnBounds.Center, pollen->transform->Position()) - spawnBounds.Radius)
					/ (world.Radius - spawnBounds.Radius), 0.0f, 1.0f), alpha);
			}
			pollen->material->Colour(Colour(pollen->material->Colour(), alpha));
		};
	}