int test_spherical_sampling_serialization() {
#ifdef MINSG_EXT_SVS
	std::cout << "Test serialization of SVS objects ... ";
	Util::Timer timer;
	timer.reset();

	using namespace MinSG::SVS;
	MinSG::SceneManagement::SceneManager sceneManager;

	const uint32_t count = 10;
	std::array<Util::Reference<MinSG::GeometryNode>, count> nodes;
	for(uint_fast32_t i = 0; i < count; ++i) {
		nodes[i] = new MinSG::GeometryNode;
		sceneManager.registerNode(std::string("Node") + Util::StringUtils::toString(i), nodes[i].get());
	}
	MinSG::VisibilitySubdivision::VisibilityVector vv;
	for(uint_fast32_t i = 0; i < count; ++i) {
		vv.setNode(nodes[i].get(), i);
	}

	std::vector<SamplePoint> samples;
	{
		using namespace Rendering::MeshUtils::PlatonicSolids;
		Util::Reference<Rendering::Mesh> mesh = createEdgeSubdivisionSphere(createIcosahedron(), 4);
		auto accessor = Rendering::PositionAttributeAccessor::create(mesh->openVertexData(), Rendering::VertexAttributeIds::POSITION);
		for(std::size_t i = 0; accessor->checkRange(i); ++i) {
			samples.emplace_back(accessor->getPosition(i));
		}
	}
	{
		std::stringstream stream;
		stream.precision(std::numeric_limits<long double>::digits10);
		// Serialize
		for(const auto & sample : samples) {
			stream << sample.getPosition() << ' ';
			sample.getValue().serialize(stream, sceneManager);
			stream << ' ';
		}
		// Unserialize
		std::vector<SamplePoint> newSamples;
		for(std::size_t s = 0; s < samples.size(); ++s) {
			Geometry::Vec3f pos;
			stream >> pos;
			SamplePoint sample(pos);
			sample.setValue(MinSG::VisibilitySubdivision::VisibilityVector::unserialize(stream, sceneManager));
			newSamples.push_back(sample);
		}
		for(std::size_t s = 0; s < samples.size(); ++s) {
			const SamplePoint & oldSample = samples[s];
			const SamplePoint & newSample = newSamples[s];
			if(oldSample.getPosition().distance(newSample.getPosition()) > std::numeric_limits<float>::epsilon()) {
				std::cout << "Serialization/unserialization failed." << std::endl;
				return EXIT_FAILURE;
			}
			const auto & oldVV = oldSample.getValue();
			const auto & newVV = newSample.getValue();
			for(uint_fast32_t n = 0; n < count; ++n) {
				if(oldVV.getBenefits(nodes[n].get()) != newVV.getBenefits(nodes[n].get())) {
					std::cout << "Serialization/unserialization failed." << std::endl;
					return EXIT_FAILURE;
				}
			}
		}
	}
	VisibilitySphere visibilitySphere(Geometry::Sphere_f(Geometry::Vec3f(1.0f, 2.0f, 3.0f), 17.0f), samples);
	{
		std::stringstream stream;
		stream.precision(std::numeric_limits<long double>::digits10);
		// Serialize
		stream << visibilitySphere.getSphere() << ' ' << samples.size();
		for(const auto & sample : samples) {
			stream << ' ' << sample.getPosition() << ' ';
			sample.getValue().serialize(stream, sceneManager);
			stream << ' ';
		}
		
		// Unserialize
		Geometry::Sphere_f sphere;
		stream >> sphere;
		std::size_t sampleCount;
		stream >> sampleCount;
		std::vector<SamplePoint> newSamples;
		for(std::size_t s = 0; s < sampleCount; ++s) {
			Geometry::Vec3f pos;
			stream >> pos;
			SamplePoint sample(pos);
			sample.setValue(MinSG::VisibilitySubdivision::VisibilityVector::unserialize(stream, sceneManager));
			newSamples.push_back(sample);
		}
		
		VisibilitySphere newVisibilitySphere(sphere, newSamples);
		if(!(visibilitySphere.getSphere() == newVisibilitySphere.getSphere())) {
			std::cout << "Serialization/unserialization failed." << std::endl;
			return EXIT_FAILURE;
		}
		for(std::size_t s = 0; s < samples.size(); ++s) {
			const SamplePoint & oldSample = visibilitySphere.getSamples()[s];
			const SamplePoint & newSample = newVisibilitySphere.getSamples()[s];
			if(oldSample.getPosition().distance(newSample.getPosition()) > std::numeric_limits<float>::epsilon()) {
				std::cout << "Serialization/unserialization failed." << std::endl;
				return EXIT_FAILURE;
			}
			const auto & oldVV = oldSample.getValue();
			const auto & newVV = newSample.getValue();
			for(uint_fast32_t n = 0; n < count; ++n) {
				if(oldVV.getBenefits(nodes[n].get()) != newVV.getBenefits(nodes[n].get())) {
					std::cout << "Serialization/unserialization failed." << std::endl;
					return EXIT_FAILURE;
				}
			}
		}
	}

	timer.stop();
	std::cout << "done (duration: " << timer.getSeconds() << " s).\n";
#endif /* MINSG_EXT_SVS */
	return EXIT_SUCCESS;
}
Example #2
0
int test_large_scene(Util::UI::Window * window, Util::UI::EventContext & eventContext) {
	// texture registry
	std::map<std::string, Util::Reference<Rendering::Texture> > textures;

	std::cout << "Create FrameContext...\n";
	FrameContext fc;

	unsigned int renderingFlags = /*BOUNDING_BOXES|SHOW_META_OBJECTS|*/FRUSTUM_CULLING/*|SHOW_COORD_SYSTEM*/;//|SHOW_COORD_SYSTEM;


	std::cout << "Create scene graph...\n";
	Util::Reference<GroupNode> root = new MinSG::ListNode();


	/// Skybox
	SkyboxState * sb = SkyboxState::createSkybox("Data/texture/?.bmp");
	root->addState(sb);


	/// Some shperes...
	{
		std::default_random_engine engine;
		std::uniform_real_distribution<float> coordinateDist(0.0f, 200.0f);
		
		std::vector<Util::Reference<Rendering::Mesh> > spheres;
		Util::Reference<Rendering::Mesh> icosahedron = Rendering::MeshUtils::PlatonicSolids::createIcosahedron();
		for(int i=0;i<6;++i)
			spheres.push_back(Rendering::MeshUtils::PlatonicSolids::createEdgeSubdivisionSphere(icosahedron.get(), i)); // 6... 81920 triangles each

		for (int i = 0; i < 1000; i++) {
			// create a real clone inclusive internal data!
			MinSG::GeometryNode * gn = new GeometryNode(spheres[std::uniform_int_distribution<std::size_t>(0, spheres.size() - 1)(engine)]->clone());
			gn->moveRel(Geometry::Vec3(coordinateDist(engine), coordinateDist(engine), coordinateDist(engine)));
			root->addChild(gn);
			gn->scale(0.1 + std::uniform_real_distribution<float>(0.0f, 1000.0f)(engine) / 400.0);
		}
	}

	/// Camera
	Node * schwein = loadModel(Util::FileName("Data/model/Schwein.low.t.ply"), MESH_AUTO_CENTER | MESH_AUTO_SCALE);

	ListNode * camera = new ListNode();
	CameraNode * camNode = new CameraNode();
	camNode->setViewport(Geometry::Rect_i(0, 0, 1024, 768));
	camNode->setNearFar(0.1, 2000);
	camNode->applyVerticalAngle(80);
	camNode->moveRel(Geometry::Vec3(0, 4, 10));
	camera->addChild(camNode);
	camera->addChild(schwein);
	schwein->moveRel(Geometry::Vec3(0, 0, 0));
	schwein->rotateLocal_deg(180, Geometry::Vec3(0, 1, 0));

	LightNode * myHeadLight = LightNode::createPointLight();
	myHeadLight->scale(1);
	myHeadLight->moveRel(Geometry::Vec3(0, 0, 0));
	camera->addChild(myHeadLight);
	LightingState * lightState = new LightingState;
	lightState->setLight(myHeadLight);
	root->addState(lightState);

	root->addChild(camera);


	/// Eventhandler
	MoveNodeHandler * eh = new MoveNodeHandler();
	MoveNodeHandler::initClaudius(eh, camera);


	// ---------------------------------------------------------------------------------------------

	Rendering::RenderingContext::clearScreen(Util::Color4f(0.5f, 0.5f, 0.5f, 0.5f));

	// ----
	GET_GL_ERROR();

	uint32_t fpsFrameCounter = 0;
	Util::Timer fpsTimer;

	std::cout << "\nEntering main loop...\n";


	// program main loop
	bool done = false;
	while (!done) {
		++fpsFrameCounter;
		double seconds = fpsTimer.getSeconds();
		if (seconds > 1.0) {
			double fps = static_cast<double> (fpsFrameCounter) / seconds;
			std::cout << "\r " << fps << " fps    ";
			std::cout.flush();
			fpsTimer.reset();
			fpsFrameCounter = 0;
		}

		// message processing loop
		eventContext.getEventQueue().process();
		while (eventContext.getEventQueue().getNumEventsAvailable() > 0) {
			Util::UI::Event event = eventContext.getEventQueue().popEvent();
			// check for messages
			switch (event.type) {
				// exit if the window is closed
				case Util::UI::EVENT_QUIT:
					done = true;
					break;


					// check for keypresses
				case Util::UI::EVENT_KEYBOARD: {
					if(event.keyboard.pressed && event.keyboard.key == Util::UI::KEY_ESCAPE) {
						done = true;
					}
					break;
				}

			} // end switch
		} // end of message processing

		// apply translation
		eh->execute();


		// clear screen
		Rendering::RenderingContext::clearScreen(Util::Color4f(0.0f, 0.0f, 0.0f, 1.0f));


		// enable Camera
		fc.setCamera(camNode);


		// render Scene
		root->display(fc, renderingFlags);

		window->swapBuffers();
		GET_GL_ERROR();
	} // end main loop


	// destroy scene graph
	MinSG::destroy(root.get());
	root = nullptr;

	// all is well ;)
	std::cout << "Exited cleanly\n";
	//system("pause");
	return EXIT_SUCCESS;
}
int test_spherical_sampling() {
#ifdef MINSG_EXT_SVS
	std::cout << "Test SVS ... ";
	Util::Timer timer;
	timer.reset();

	MinSG::SceneManagement::SceneManager sceneManager;
	MinSG::FrameContext frameContext;

	Rendering::VertexDescription vertexDesc;
	vertexDesc.appendPosition3D();
	Util::Reference<Rendering::Mesh> boxMesh = Rendering::MeshUtils::MeshBuilder::createBox(vertexDesc, Geometry::Box(Geometry::Vec3f(0.5f, 0.5f, 0.5f), 1));

	/*
	 * Create a 1D array of n unit-size boxes in the x axis
	 *
	 *          /
	 *        ..L2
	 *        /  /
	 *    ......L1  /
	 *    /    /  /
	 *  ...L0....  /  /
	 *  /  /  /  /  /
	 * ------------------------- ... -----
	 * | 0 | 1 | 2 | 3 | 4 | 5 |   | n |
	 * |  |  |  |  |  |  |   |  |
	 * ------------------------- ... -----
	 * ^        ^       ^
	 * |        |       |
	 * x=0       x=4      x=n
	 *
	 * The first three boxes are put into the first list node L0.
	 * L0 together with the fourth box are put into the second list node L1.
	 */
	const uint32_t count = 512;

	std::vector<Util::Reference<MinSG::ListNode>> listNodes;
	std::vector<Util::Reference<MinSG::GeometryNode>> boxNodes;
	for(uint_fast32_t x = 0; x < count; ++x) {
		MinSG::GeometryNode * geoNode = new MinSG::GeometryNode(boxMesh);
		geoNode->moveLocal(Geometry::Vec3f(x, 0, 0));
		sceneManager.registerNode(std::string("Node") + Util::StringUtils::toString(x), geoNode);
		boxNodes.push_back(geoNode);
		if(x != 1 && x != 2) {
			listNodes.push_back(new MinSG::ListNode);
		}
		if(x < 3) {
			listNodes.front()->addChild(geoNode);
		} else {
			listNodes[x - 2]->addChild(listNodes[x - 3].get());
			listNodes[x - 2]->addChild(geoNode);
		}
	}

	// Debug output of created scene graph
	//MinSG::GraphVizOutput::treeToFile(listNodes.back().get(), &sceneManager, Util::FileName("output.dot"));

	// Perform the sampling
	std::vector<Geometry::Vec3f> positions;
	positions.emplace_back(-1, 0, 0); // left
	positions.emplace_back(1, 0, 0); // right
	positions.emplace_back(0, 1, 0); // top
	positions.emplace_back(0, 0, 1); // back

	// The resolution has to be at least the number of boxes. Otherwise, boxes will be missed during visibility testing.
	MinSG::SVS::PreprocessingContext preprocessingContext(sceneManager, frameContext, listNodes.back().get(), positions, count, false, false);
	while(!preprocessingContext.isFinished()) {
		preprocessingContext.preprocessSingleNode();
	}

	// Validate the results
	for(uint_fast32_t listIndex = 0; listIndex < count - 2; ++listIndex) {
		MinSG::ListNode * listNode = listNodes[listIndex].get();
		const MinSG::SVS::VisibilitySphere & visibilitySphere = MinSG::SVS::retrieveVisibilitySphere(listNode);
		{
			// Because the geometry is built of axis-aligned bounding boxes only, the sphere has to contain the group's bounding box.
			assert(visibilitySphere.getSphere().distance(listNode->getBB().getMin()) < 1.0e-9);
			assert(visibilitySphere.getSphere().distance(listNode->getBB().getMax()) < 1.0e-9);
		}
		{
			// left => only first box must be visible
			const auto vv = visibilitySphere.queryValue(positions[0], MinSG::SVS::INTERPOLATION_NEAREST);
			assert(vv.getBenefits(boxNodes.front().get()) > 0);
			for(uint_fast32_t boxIndex = 1; boxIndex < count; ++boxIndex) {
				MinSG::GeometryNode * geoNode = boxNodes[boxIndex].get();
				assert(vv.getBenefits(geoNode) == 0);
			}
		}
		{
			// right => only last box inside the subtree must be visible
			const auto vv = visibilitySphere.queryValue(positions[1], MinSG::SVS::INTERPOLATION_NEAREST);
			const uint32_t lastBoxIndex = listIndex + 2;
			assert(vv.getBenefits(boxNodes[lastBoxIndex].get()) > 0);
			for(uint_fast32_t boxIndex = 0; boxIndex < count; ++boxIndex) {
				if(boxIndex != lastBoxIndex) {
					MinSG::GeometryNode * geoNode = boxNodes[boxIndex].get();
					assert(vv.getBenefits(geoNode) == 0);
				}
			}
		}
		// top, back => all boxes in the subtree must be visible
		for(uint_fast32_t posIndex = 2; posIndex <= 3; ++posIndex) {
			const auto vv = visibilitySphere.queryValue(positions[posIndex], MinSG::SVS::INTERPOLATION_NEAREST);
			const auto geoNodes = MinSG::collectNodes<MinSG::GeometryNode>(listNode);
			for(const auto & geoNode : geoNodes) {
				assert(vv.getBenefits(geoNode) > 0);
			}
		}
	}

	boxNodes.clear();
	MinSG::destroy(listNodes.back().get());
	listNodes.clear();

	timer.stop();
	std::cout << "done (duration: " << timer.getSeconds() << " s).\n";
#endif /* MINSG_EXT_SVS */
	return EXIT_SUCCESS;
}
Example #4
0
int test_OutOfCore() {
#ifdef MINSG_EXT_OUTOFCORE
	const bool verbose = true;

	// Tests for MinSG::OutOfCore::CacheObjectPriority
	if(sizeof(MinSG::OutOfCore::CacheObjectPriority) != 8) {
		return EXIT_FAILURE;
	}
	if(!(MinSG::OutOfCore::CacheObjectPriority(1, 2, 3) == MinSG::OutOfCore::CacheObjectPriority(1, 2, 3))) {
		return EXIT_FAILURE;
	}
	if(!(MinSG::OutOfCore::CacheObjectPriority(1, 100, 100) < MinSG::OutOfCore::CacheObjectPriority(2, 0, 0))) {
		return EXIT_FAILURE;
	}
	if(!(MinSG::OutOfCore::CacheObjectPriority(2, 1, 100) < MinSG::OutOfCore::CacheObjectPriority(2, 2, 0))) {
		return EXIT_FAILURE;
	}
	if(!(MinSG::OutOfCore::CacheObjectPriority(2, 2, 1) < MinSG::OutOfCore::CacheObjectPriority(2, 2, 2))) {
		return EXIT_FAILURE;
	}

	std::default_random_engine engine;
	std::uniform_int_distribution<std::size_t> vertexCountDist(10, 1000);
	const uint32_t numMeshes = 30000;
	const Util::TemporaryDirectory tempDir("MinSGTest_OutOfCore");
	
	// Create empty meshes and save them into a subdirectory.
	{
		Rendering::VertexDescription vertexDesc;
		vertexDesc.appendPosition3D();
		
		for(uint_fast32_t i = 0; i < numMeshes; ++i) {
			Util::Reference<Rendering::Mesh> mesh = new Rendering::Mesh(vertexDesc, vertexCountDist(engine), 64);
			Rendering::MeshVertexData & vertexData = mesh->openVertexData();
			std::fill_n(vertexData.data(), vertexData.dataSize(), 0);
			vertexData.markAsChanged();
			Rendering::MeshIndexData & indexData = mesh->openIndexData();
			std::fill_n(indexData.data(), indexData.getIndexCount(), 0);
			indexData.markAsChanged();
			const std::string numberString = Util::StringUtils::toString<uint32_t>(i);
			Rendering::Serialization::saveMesh(mesh.get(), Util::FileName(tempDir.getPath().getDir() + numberString + ".mmf"));
		}
	}
	
	// Set up the OutOfCore system.
	MinSG::FrameContext frameContext;
	
	MinSG::OutOfCore::setUp(frameContext);

	MinSG::OutOfCore::CacheManager & manager = MinSG::OutOfCore::getCacheManager();
	manager.addCacheLevel(MinSG::OutOfCore::CacheLevelType::FILE_SYSTEM, 0);
	manager.addCacheLevel(MinSG::OutOfCore::CacheLevelType::FILES, 512 * kibibyte);
	manager.addCacheLevel(MinSG::OutOfCore::CacheLevelType::MAIN_MEMORY, 256 * kibibyte);
	
	Util::Timer addTimer;
	addTimer.reset();
	std::cout << "Adding meshes ..." << std::flush;
	
	// Add the meshes to the OutOfCore system.
	std::vector<Util::Reference<Rendering::Mesh> > meshes;
	meshes.reserve(numMeshes);
	static const Geometry::Box boundingBox(-1.0f, 1.0f, -1.0f, 1.0f, -1.0f, 1.0f);
	for(uint_fast32_t i = 0; i < numMeshes; ++i) {
		const std::string numberString = Util::StringUtils::toString<uint32_t>(i);
		meshes.push_back(MinSG::OutOfCore::addMesh(Util::FileName(tempDir.getPath().getDir() + numberString + ".mmf"), boundingBox));
	}
	
	manager.trigger();
	
	addTimer.stop();
	std::cout << " done (" << addTimer.getSeconds() << " s)" << std::endl;
	
	Util::Timer displayTimer;
	Util::Timer assureLocalTimer;
	Util::Timer overallTimer;
	overallTimer.reset();

	uint32_t frame = 0;

	{
		// Simulate frames to get the OutOfCore system working.
		std::uniform_int_distribution<std::size_t> indexDist(0, meshes.size() - 1);
		for(; frame < 10; ++frame) {
			std::cout << "Executing frame " << frame << " ..." << std::flush;
			frameContext.beginFrame();
			displayTimer.reset();
			// Simulate display of meshes to change the priorities of the system.
			for(uint32_t i = 0; i < meshes.size() / 2; ++i) {
				const uint32_t meshIndex = indexDist(engine);
				Rendering::Mesh * mesh = meshes[meshIndex].get();
				manager.meshDisplay(mesh);
			}
			manager.trigger();
			displayTimer.stop();
			assureLocalTimer.reset();
			for(uint32_t i = 0; i < 10; ++i) {
				const uint32_t meshIndex = indexDist(engine);
				
				Rendering::Mesh * mesh = meshes[meshIndex].get();
				const Rendering::MeshVertexData & vd = mesh->openVertexData();
				const Rendering::MeshIndexData & id = mesh->openIndexData();
				
				if (!vd.hasLocalData() || !id.hasLocalData()) {
					std::cout << "Error: Mesh has no local data." << std::endl;
					return EXIT_FAILURE;
				}
			}
			assureLocalTimer.stop();
			frameContext.endFrame();
			std::cout << " done (display: " << displayTimer.getSeconds() << " s, assureLocal: " << assureLocalTimer.getSeconds() << " s)" << std::endl;

			if(verbose) {
				outputCacheLevelInformation();
			}
		}
	}

	for(uint32_t round = 0; round < 10; ++round) {
		Util::Timer addAgainTimer;
		addAgainTimer.reset();
		std::cout << "Adding additional meshes ..." << std::flush;
		
		// Simulate loading a second scene by adding meshes again.
		meshes.reserve(meshes.size() + 3 * numMeshes);
		for(uint_fast32_t i = 0; i < numMeshes; ++i) {
			const std::string numberString = Util::StringUtils::toString<uint32_t>(i);
			meshes.push_back(MinSG::OutOfCore::addMesh(Util::FileName(tempDir.getPath().getDir() + numberString + ".mmf"), boundingBox));
			meshes.push_back(MinSG::OutOfCore::addMesh(Util::FileName(tempDir.getPath().getDir() + numberString + ".mmf"), boundingBox));
			meshes.push_back(MinSG::OutOfCore::addMesh(Util::FileName(tempDir.getPath().getDir() + numberString + ".mmf"), boundingBox));
		}
		
		manager.trigger();
		
		addAgainTimer.stop();
		std::cout << " done (" << addAgainTimer.getSeconds() << " s)" << std::endl;

		// Simulate frames to get the OutOfCore system working.
		std::normal_distribution<double> indexDist(meshes.size() / 2, std::sqrt(meshes.size() / 2));
		const auto untilFrame = frame + 5;
		for(; frame < untilFrame; ++frame) {
			std::cout << "Executing frame " << frame << " ..." << std::flush;
			frameContext.beginFrame();
			displayTimer.reset();
			// Simulate display of meshes to change the priorities of the system.
			for(uint32_t i = 0; i < meshes.size() / 10; ++i) {
				const std::size_t meshIndex = std::max(static_cast<std::size_t>(0), std::min(static_cast<std::size_t>(indexDist(engine)), meshes.size() - 1));
				Rendering::Mesh * mesh = meshes[meshIndex].get();
				manager.meshDisplay(mesh);
			}
			manager.trigger();
			displayTimer.stop();
			frameContext.endFrame();
			std::cout << " done (display: " << displayTimer.getSeconds() << " s)" << std::endl;

			if(verbose) {
				outputCacheLevelInformation();
			}
		}
	}

	overallTimer.stop();
	std::cout << "Overall duration: " << overallTimer.getSeconds() << " s" << std::endl;
	
	MinSG::OutOfCore::shutDown();
	
	return EXIT_SUCCESS;
#else /* MINSG_EXT_OUTOFCORE */
	return EXIT_FAILURE;
#endif /* MINSG_EXT_OUTOFCORE */
}