State::stateResult_t OccludeeRenderer::doEnableState(FrameContext & context, Node * rootNode, const RenderParam & rp) {
	if (rp.getFlag(SKIP_RENDERER)) {
		return State::STATE_SKIPPED;
	}

	static PolygonModeState polygonMode;
	polygonMode.changeParameters().setMode(Rendering::PolygonModeParameters::LINE);

	occlusionCullingRenderer->setMode(OccRenderer::MODE_CULLING);
	const State::stateResult_t resultCulling = occlusionCullingRenderer->enableState(context, rootNode, rp);
	if(resultCulling != State::STATE_SKIP_RENDERING) {
		WARN("Using the OccRenderer for culling failed.");
		return resultCulling;
	}

	// Clear the depth buffer to be able to render the occluded geometry in front of the previously rendered geometry.
	context.getRenderingContext().clearDepth(1.0f);

	// Activate wireframe mode.
	polygonMode.enableState(context, rootNode, rp);

	occlusionCullingRenderer->setMode(OccRenderer::MODE_SHOW_CULLED);
	RenderParam rpWorldMatrix = rp;
	rpWorldMatrix.setFlag(USE_WORLD_MATRIX);
	const State::stateResult_t resultShowCulled = occlusionCullingRenderer->enableState(context, rootNode, rpWorldMatrix);
	if(resultShowCulled != State::STATE_SKIP_RENDERING) {
		WARN("Using the OccRenderer for showing the culled geometry failed.");
		return resultShowCulled;
	}

	// Deactivate wireframe mode.
	polygonMode.disableState(context, rootNode, rp);

	return State::STATE_SKIP_RENDERING;
}
void FakeInstanceNode::doDisplay(FrameContext & frameContext, const RenderParam & rp) {
	if(fakePrototype.isNull()) {
		Node::doDisplay(frameContext, rp);
		return;
	}

	auto camera = static_cast<AbstractCameraNode*>(frameContext.getCamera()->clone());
	const Geometry::Matrix4x4f & cameraMatrix = frameContext.getCamera()->getWorldTransformationMatrix();
	camera->setRelTransformation(	fakePrototype->getWorldTransformationMatrix() 
						* getWorldToLocalMatrix() 
						* cameraMatrix);

	frameContext.pushAndSetCamera(camera);
	frameContext.displayNode(fakePrototype.get(), rp);
	frameContext.popCamera();
}
Exemple #3
0
void OccRenderer::updateNodeInformation(FrameContext & context,Node * rootNode)const{
	/***
	 ** Vis ---|> NodeVisitor
	 ***/
	struct Vis:public NodeVisitor {
		const OccRenderer & r;
		AbstractCameraNode * camera;
		const Node * rootNode;
		int insideFrustum;
		Geometry::Vec3 camPos;

		Vis(const OccRenderer & _r, const Node * _rootNode, AbstractCameraNode * _camera) :
				r(_r), camera(_camera), rootNode(_rootNode), insideFrustum(0), camPos(_camera->getWorldOrigin()) {}
		virtual ~Vis() {}

		// ---|> NodeVisitor
		NodeVisitor::status enter(Node * node) override {
			NodeInfo * info=r.getNodeInfo(node);
			info->setActualSubtreeComplexity(0);

			// the current subtree is completely inside the frustum, so we need not to test inside this subtree
			if(insideFrustum>0){
				info->setActualFrustumStatus(Geometry::Frustum::INSIDE);
				insideFrustum++;
			}else{
				int i=camera->testBoxFrustumIntersection( node->getWorldBB());
				info->setActualFrustumStatus(i);
				if(i==Geometry::Frustum::OUTSIDE){
					return NodeVisitor::BREAK_TRAVERSAL;
				}else if(i==Geometry::Frustum::INSIDE){
					insideFrustum++;
				}
			}
			if(node->isClosed() && node!=rootNode){
				unsigned int c = insideFrustum > 0 ? countTriangles(node) : countTrianglesInFrustum(node, camera->getFrustum());
				info->increaseActualSubtreeComplexity( c );
				return BREAK_TRAVERSAL;
			}
			return CONTINUE_TRAVERSAL;
		}
		// ---|> NodeVisitor
		NodeVisitor::status leave(Node * node) override {
			if(insideFrustum>0){
				insideFrustum--;
			}
			unsigned int complexity=r.getNodeInfo(node)->getActualSubtreeComplexity();
			if(complexity>0 && rootNode!=node && node->hasParent()){
				NodeInfo * pinfo=r.getNodeInfo(node->getParent());
				pinfo->increaseActualSubtreeComplexity(complexity);
			}
			return CONTINUE_TRAVERSAL;
		}
	} visitor(*this,rootNode,context.getCamera());
	rootNode->traverse(visitor);
	return;
}
//! (internal)
bool ColorCubeGenerator::prepareCamera(FrameContext& context, const Box& _box, Geometry::side_t side) {

	Geometry::Box box(_box);
	camera->resetRelTransformation();
	camera->setRelOrigin(box.getCenter());
	switch(side){
		case Geometry::SIDE_X_POS:
			camera->rotateRel(Geometry::Angle::deg(90.0f), Geometry::Vec3(0, 1, 0));
			if(box.getExtentY() == 0 || box.getExtentZ() == 0) return false; // width or height equal zero
			if(box.getExtentX() == 0) box.resizeAbs(0.1,0,0); // depth equal zero
			box.resizeRel(1.01,1,1);
			break;
		case Geometry::SIDE_X_NEG:
			camera->rotateRel(Geometry::Angle::deg(-90.0f), Geometry::Vec3(0, 1, 0));
			if(box.getExtentY() == 0 || box.getExtentZ() == 0) return false; // width or height equal zero
			if(box.getExtentX() == 0) box.resizeAbs(0.1,0,0); // depth equal zero
			box.resizeRel(1.01,1,1);
			break;
		case Geometry::SIDE_Y_POS:
			camera->rotateRel(Geometry::Angle::deg(-90.0f), Geometry::Vec3(1, 0, 0));
			if(box.getExtentX() == 0 || box.getExtentZ() == 0) return false; // width or height equal zero
			if(box.getExtentY() == 0) box.resizeAbs(0,0.1,0); // depth equal zero
			box.resizeRel(1,1.01,1);
			break;
		case Geometry::SIDE_Y_NEG:
			camera->rotateRel(Geometry::Angle::deg(90.0f), Geometry::Vec3(1, 0, 0));
			if(box.getExtentX() == 0 || box.getExtentZ() == 0) return false; // width or height equal zero
			if(box.getExtentY() == 0) box.resizeAbs(0,0.1,0); // depth equal zero
			box.resizeRel(1,1.01,1);
			break;
		case Geometry::SIDE_Z_POS:
			if(box.getExtentX() == 0 || box.getExtentY() == 0) return false; // width or height equal zero
			if(box.getExtentZ() == 0) box.resizeAbs(0,0,0.1); // depth equal zero
			box.resizeRel(1,1,1.01);
			break;
		case Geometry::SIDE_Z_NEG:
			camera->rotateRel(Geometry::Angle::deg(180.0f), Geometry::Vec3(0, 1, 0));
			if(box.getExtentX() == 0 || box.getExtentY() == 0) return false; // width or height equal zero
			if(box.getExtentZ() == 0) box.resizeAbs(0,0,0.1); // depth equal zero
			box.resizeRel(1,1,1.01);
			break;
		default:
			throw std::logic_error("the roof is on fire");
	}
	
	//box.resizeRel(1.01);
	Geometry::Frustum f = Geometry::calcEnclosingOrthoFrustum(box, camera->getWorldTransformationMatrix().inverse());
	camera->setClippingPlanes(f.getLeft(), f.getRight(), f.getBottom(), f.getTop());
	camera->setNearFar(f.getNear() , f.getFar());
	camera->setViewport(Geometry::Rect_i(maxTexSize*static_cast<uint8_t>(side), 0, maxTexSize, maxTexSize), true);
	context.setCamera(camera.get());

	return true;
}
Exemple #5
0
State::stateResult_t OccRenderer::showCulled(FrameContext & context,Node * rootNode, const RenderParam & rp){
	std::deque<Node *> nodes;
	nodes.push_back(rootNode);
	while(!nodes.empty()){
		Node * node=nodes.front();
		nodes.pop_front();
		NodeInfo * nInfo=getNodeInfo(node);

		if(!conditionalFrustumTest(context.getCamera()->getFrustum(), node->getWorldBB(), rp))
			continue;
		else if(node->isClosed() ){
			if(nInfo->getVisibleFrameNumber()!=frameNumber)
				context.displayNode(node,rp);
		}else {
			const auto children = getChildNodes(node);
			nodes.insert(nodes.end(), children.begin(), children.end());
		}
	}
	return State::STATE_SKIP_RENDERING;
}
//! ---|> [State]
State::stateResult_t ShaderUniformState::doEnableState(FrameContext & context, Node *, const RenderParam & /*rp*/) {
	priorValueStack.push( std::vector<Rendering::Uniform>() );

	Rendering::Shader * shader = context.getRenderingContext().getActiveShader();

	if(shader!=nullptr){
		// assure that possible changes in the renderingContext are applied to the sg-uniforms before querying the uniforms
		context.getRenderingContext().applyChanges();

		for(const auto & uniformEntry : uMap) {
			const Rendering::Uniform & uniform(uniformEntry.second);
			const Rendering::Uniform & priorUniform(shader->getUniform(uniform.getNameId()));
			if(priorUniform.isNull())
				continue;
			priorValueStack.top().push_back(priorUniform);
			shader->setUniform(context.getRenderingContext(),uniform,true); // warn if unused--> should not happen
		}
	}
	return State::STATE_OK;
}
Exemple #7
0
State::stateResult_t SurfelRenderer::doEnableState(FrameContext & context, Node * node, const RenderParam & rp) {
	State::stateResult_t result = NodeRendererState::doEnableState(context,node,rp);
	if( result == State::STATE_OK ){
		CameraNode* camera = dynamic_cast<CameraNode*>( context.getCamera() );
		if(camera){ // else: an orthographic camera is used; just re-use the previous values.
			cameraOrigin = camera->getWorldOrigin();
			projectionScale = camera->getWidth() / (std::tan((camera->getRightAngle()-camera->getLeftAngle()).rad()*0.5f)*2.0f);
		}
	
	}
	return result;
}
bool VisibilitySubdivisionRenderer::renderCellSubset(FrameContext & context, cell_ptr cell, uint32_t budgetBegin, uint32_t budgetEnd) {
	try {
		const auto & vv = getVV(cell);

		std::vector<std::pair<float, object_ptr>> displayObjects;
		const uint32_t maxIndex = vv.getIndexCount();
		for(uint_fast32_t index = 0; index < maxIndex; ++index) {
			if(vv.getBenefits(index) == 0) {
				continue;
			}
			const VisibilityVector::costs_t costs = vv.getCosts(index);
			const VisibilityVector::benefits_t benefits = vv.getBenefits(index);
			const float score = static_cast<float>(costs) / static_cast<float>(benefits);
			displayObjects.emplace_back(score, vv.getNode(index));
		}

		const Geometry::Frustum & frustum = context.getCamera()->getFrustum();
		uint32_t renderedTriangles = 0;
		std::sort(displayObjects.begin(), displayObjects.end());
		for(const auto & objectRatioPair : displayObjects) {
			object_ptr o = objectRatioPair.second;
			Geometry::Frustum::intersection_t result = frustum.isBoxInFrustum(o->getWorldBB());
			if (result == Geometry::Frustum::intersection_t::INSIDE || result == Geometry::Frustum::intersection_t::INTERSECT) {
				if(renderedTriangles >= budgetBegin) {
					context.displayNode(o, 0);
				}
				renderedTriangles += o->getTriangleCount();
			}

			if (budgetEnd != 0 && renderedTriangles >= budgetEnd) {
				break;
			}
		}
	} catch(...) {
		// Invalid information. => Fall back to standard rendering.
		return false;
	}
	return true;
}
//! Distribute the budget based on the projected size of the child nodes.
static void distributeProjectedSize(double value, const Util::StringIdentifier & attributeId, Node * node, FrameContext & context) {
	const auto children = getChildNodes(node);

	// A pair stores a node and its projected size.
	std::vector<std::pair<Node *, float>> nodeProjSizePairs;
	nodeProjSizePairs.reserve(children.size());
	double projSizeSum = 0.0;

	const Geometry::Rect_f screenRect(context.getRenderingContext().getWindowClientArea());
	for(const auto & child : children) {
		// Clip the projected rect to the screen.
		auto projRect = context.getProjectedRect(child);
		projRect.clipBy(screenRect);

		const auto projSize = projRect.getArea();
		projSizeSum += projSize;
		nodeProjSizePairs.emplace_back(child, projSize);
	}
	for(const auto & nodeProjSizePair : nodeProjSizePairs) {
		const double factor = nodeProjSizePair.second / projSizeSum;
		setOrUpdateAttribute(nodeProjSizePair.first, attributeId, factor * value);
	}
}
void VisibilitySubdivisionRenderer::debugDisplay(uint32_t & renderedTriangles, object_ptr object, FrameContext & context, const RenderParam & rp) {
	const Util::Color4f specular(0.1f, 0.1f, 0.1f, 1.0f);


	const float ratio = static_cast<float> (renderedTriangles) / static_cast<float> (maxRuntime);

	// Gradient from light blue to red.
	Util::Color4f color(ratio, 0.5f - 0.5f * ratio, 1.0f - ratio, 1.0f);

	Rendering::MaterialParameters material;
	material.setAmbient(color);
	material.setDiffuse(color);
	material.setSpecular(specular);
	material.setShininess(64.0f);

	context.getRenderingContext().pushAndSetMaterial(material);

	context.displayNode(object, rp);

	context.getRenderingContext().popMaterial();

	renderedTriangles += object->getTriangleCount();
}
Exemple #11
0
//! ---|> [State]
State::stateResult_t ShaderState::doEnableState(FrameContext & context, Node *, const RenderParam & /*rp*/) {
	if( !shader )
		return State::STATE_SKIPPED;

	auto & rCtxt = context.getRenderingContext();

	// push current shader to stack
	rCtxt.pushAndSetShader(shader.get());
	
	if( !rCtxt.isShaderEnabled(shader.get()) ){
		rCtxt.popShader();
		deactivate();
		WARN("Enabling ShaderState failed. State has been deactivated!");
		return State::STATE_SKIPPED;
	}
	
	for(const auto & uniformEntry : uMap) 
		shader->setUniform(rCtxt, uniformEntry.second);
	return State::STATE_OK;
}
Exemple #12
0
/**
 * (internal)
 */
void OccRenderer::processNode(FrameContext & context,Node * node,NodeInfo * nodeInfo,NodeDistancePriorityQueue_F2B & distanceQueue,const RenderParam & rp){
	if (!node->isActive())
		return;

	nodeInfo->setProcessedFrameNumber(frameNumber);

	if(node->isClosed()){
		context.displayNode(node, rp );
	}else{
		const auto children = getChildNodes(node);
		for(auto & child : children){
			NodeInfo * i=getNodeInfo(child);
			if( rp.getFlag(FRUSTUM_CULLING) && i->getActualFrustumStatus()==Geometry::Frustum::OUTSIDE) //context.getCamera()->testBoxFrustumIntersection( (*it)->getWorldBB()) == Frustum::OUTSIDE )
				continue;
			if( i->getActualSubtreeComplexity() == 0){
				continue;
			}

			distanceQueue.push(child);
		}
	}
}
void ParticlePointRenderer::operator()(ParticleSystemNode* psys, FrameContext & context, const RenderParam & rp /* = 0 */) {
	if ( (rp.getFlag(NO_GEOMETRY)) )
		return;

	// render particles
	std::vector<Particle> & particles = psys->getParticles();
	uint32_t count = psys->getParticleCount();

	Rendering::VertexDescription vertexDesc;
	const Rendering::VertexAttribute & posAttrib = vertexDesc.appendPosition3D();
	const Rendering::VertexAttribute & colorAttrib = vertexDesc.appendColorRGBAByte();
	// The usage of a cache for the mesh has been tested. Reusing a preallocated mesh is not faster.
	Util::Reference<Rendering::Mesh> mesh = new Rendering::Mesh(vertexDesc, count, count);
	mesh->setDataStrategy(Rendering::SimpleMeshDataStrategy::getPureLocalStrategy());
	mesh->setDrawMode(Rendering::Mesh::DRAW_POINTS);
//	mesh->setUseIndexData(false);
	Rendering::MeshIndexData & indexData = mesh->openIndexData();
	Rendering::MeshVertexData & vertexData = mesh->openVertexData();
	Util::Reference<Rendering::PositionAttributeAccessor> positionAccessor = Rendering::PositionAttributeAccessor::create(vertexData, posAttrib.getNameId());
	Util::Reference<Rendering::ColorAttributeAccessor> colorAccessor = Rendering::ColorAttributeAccessor::create(vertexData, colorAttrib.getNameId());
	uint32_t * indices = indexData.data();

	for(uint_fast32_t index = 0; index < count; ++index) {
		const Particle & p = particles[index];

		colorAccessor->setColor(index, p.color);
		positionAccessor->setPosition(index, p.position);

		*indices++ = index;
	}

	indexData.markAsChanged();
	indexData.updateIndexRange();
	vertexData.markAsChanged();
	vertexData.updateBoundingBox();
	context.displayMesh(mesh.get());
}
//! ---|> [State]
State::stateResult_t EnvironmentState::doEnableState(FrameContext & context, Node * /*node*/, const RenderParam & rp) {

	if (rp.getFlag(NO_GEOMETRY))
		return State::STATE_SKIPPED;

	if (!environment.isNull()) {

		// extract rotation of the camera
		Geometry::SRT camRotationSrt = context.getRenderingContext().getMatrix_worldToCamera()._toSRT();
		camRotationSrt.setTranslation(Geometry::Vec3(0,0,0));
		camRotationSrt.setScale(1.0);

		// render the environment node as seen standing at the origin (0,0,0) but looking in the camera's direction.
		context.getRenderingContext().pushMatrix_modelToCamera();
		context.getRenderingContext().setMatrix_modelToCamera(Geometry::Matrix4x4(camRotationSrt));
		context.getRenderingContext().multMatrix_modelToCamera(Geometry::Matrix4x4f(Geometry::SRT(Geometry::Vec3f(0,0,0), context.getWorldFrontVector(), context.getWorldUpVector())));
		context.displayNode(environment.get(), rp);
		context.getRenderingContext().popMatrix_modelToCamera();

	}

	return State::STATE_OK;
}
//! Distribute the budget based on the projected size and the primitive count of the child nodes in an iterative manner for correct distribution.
static void distributeProjectedSizeAndPrimitiveCountIterative(double value, const Util::StringIdentifier & attributeId, Node * node, FrameContext & context) {
	static const Util::StringIdentifier primitiveCountId("PrimitiveCount");
	struct PrimitiveCountAnnotationVisitor : public NodeVisitor {
		const Util::StringIdentifier & m_primitiveCountId;
		PrimitiveCountAnnotationVisitor(const Util::StringIdentifier & p_primitiveCountId) : m_primitiveCountId(p_primitiveCountId) {
		}
		virtual ~PrimitiveCountAnnotationVisitor() {
		}
		NodeVisitor::status leave(Node * _node) override {
			auto geoNode = dynamic_cast<GeometryNode *>(_node);
			uint32_t primitiveCount = 0;
			if(geoNode != nullptr) {
				const auto mesh = geoNode->getMesh();
				primitiveCount = mesh == nullptr ? 0 : mesh->getPrimitiveCount();
			} else {
				const auto children = getChildNodes(_node);
				for(const auto & child : children) {
					primitiveCount += child->getAttribute(m_primitiveCountId)->toUnsignedInt();
				}
			}
			_node->setAttribute(m_primitiveCountId, Util::GenericAttribute::createNumber(primitiveCount));
			return CONTINUE_TRAVERSAL;
		}
	};

	const auto children = getChildNodes(node);

	// A pair stores the primitive count, the node and its projected size.
	std::deque<std::tuple<uint32_t, Node *, float>> primitiveCountNodeProjSizeTuples;
	double projSizeSum = 0.0;

	const Geometry::Rect_f screenRect(context.getRenderingContext().getWindowClientArea());
	for(const auto & child : children) {
		if(!child->isAttributeSet(primitiveCountId)) {
			PrimitiveCountAnnotationVisitor visitor(primitiveCountId);
			child->traverse(visitor);
		}
		const auto primitiveCount = child->getAttribute(primitiveCountId)->toUnsignedInt();

		// Clip the projected rect to the screen.
		auto projRect = context.getProjectedRect(child);
		projRect.clipBy(screenRect);

		const auto projSize = projRect.getArea();
		projSizeSum += projSize;
		primitiveCountNodeProjSizeTuples.emplace_back(primitiveCount, child, projSize);
	}

	// Begin with the node with the lowest primitive count
	std::sort(primitiveCountNodeProjSizeTuples.begin(), primitiveCountNodeProjSizeTuples.end());

	/* Distribute budget until one node gets all budget it asked for.
	 * This means the previous distributions would receive more budget,
	 * thus remove that node from distribution (update value and projSizeSum)
	 * and start again.
	 */
	std::deque<std::tuple<uint32_t, Node *, float>> tmpDeque(primitiveCountNodeProjSizeTuples); // TODO: fails to copy values correctly!!!
	bool nodeRemoved;
	double tmpValue;
	double tmpProjSizeSum;
	double remainingProjSizeSum = projSizeSum;
	do{
		nodeRemoved = false;
		tmpValue = value;
		tmpProjSizeSum = remainingProjSizeSum;
		for(auto it=tmpDeque.begin(); it!=tmpDeque.end(); ++it) {
			std::tuple<uint32_t, Node *, float> element = *it;
			const auto primitiveCount = std::get<0>(element);
			const auto projSize = std::get<2>(element);
			const auto projSizeFactor = projSize / tmpProjSizeSum;

			const auto primitiveAssignment = std::min(static_cast<uint32_t>(projSizeFactor * tmpValue), primitiveCount);
			setOrUpdateAttribute(std::get<1>(element), attributeId, primitiveAssignment);

			if(primitiveAssignment == primitiveCount){
				nodeRemoved = true;
				tmpDeque.erase(it);
				value -= primitiveCount;
				remainingProjSizeSum -= projSize;
				break;
			}
			tmpValue -= primitiveAssignment;
			tmpProjSizeSum -= projSize;
		}
	}while(nodeRemoved);

	// distribute remaining part of value based on projected size only
	if(tmpValue >= 1){
		for(const auto & primitiveCountNodeProjSizeTuple : primitiveCountNodeProjSizeTuples) {
			const auto projSize = std::get<2>(primitiveCountNodeProjSizeTuple);
			const auto projSizeFactor = projSize / projSizeSum;

			const auto attribute = dynamic_cast<Util::_NumberAttribute<double> *>(std::get<1>(primitiveCountNodeProjSizeTuple)->getAttribute(attributeId));
			attribute->set(attribute->get() + projSizeFactor * tmpValue);
		}
	}
}
//! ---|> Evaluator
void OccOverheadEvaluator::measure(FrameContext & context,Node & node,const Geometry::Rect & /*r*/) {

	//float currentRenderingTime=0;
	//int numTests=0;
	//int numVBO=0;
	int numPoly=0;
	Util::Color4f clearColor(0.5f, 0.5f, 0.9f, 1.0f);
	{ // 1. normal render pass
//        rc.clearScreen(0.5,0.5,0.9);
//        context.getRenderingContext().finish();
//        node.display(rc,renderingFlags);
		context.getRenderingContext().clearScreen(clearColor);
		node.display(context,renderingFlags|USE_WORLD_MATRIX);

		context.getRenderingContext().clearScreen(clearColor);
		context.getRenderingContext().finish();
		context.getStatistics().beginFrame();
		node.display(context,renderingFlags|USE_WORLD_MATRIX);
		context.getRenderingContext().finish();
		context.getStatistics().endFrame();
		numPoly=static_cast<int>(context.getStatistics().getValueAsDouble(context.getStatistics().getTrianglesCounter()));
	}

	// 2. test all group nodes if their bb is visible and collect them
	std::deque<GroupNode *> visibleGroupNodes;

	{
		// collect geometry nodes in frustum
		const auto groupNodesInVFList = collectNodesInFrustum<GroupNode>(&node,context.getCamera()->getFrustum());

		// setup occlusion queries
		int numQueries=groupNodesInVFList.size();
		if (numQueries==0) {
			values->push_back(nullptr); // TODO!!!
			return; // TODO??
		}

		auto queries = new Rendering::OcclusionQuery[numQueries];

		//  test bounding boxes
		context.getRenderingContext().pushAndSetDepthBuffer(Rendering::DepthBufferParameters(true, true, Rendering::Comparison::LEQUAL));
		int i=0;
		// start queries
		Rendering::OcclusionQuery::enableTestMode(context.getRenderingContext());
		for(const auto & groupNode : groupNodesInVFList) {
			queries[i].begin();
//            queries[i].fastBoxTest((*it)->getWorldBB());
			Rendering::drawAbsBox(context.getRenderingContext(), groupNode->getWorldBB() );
			queries[i].end();
			++i;
		}
		Rendering::OcclusionQuery::disableTestMode(context.getRenderingContext());
		i=0;
		// get results
		for(const auto & groupNode : groupNodesInVFList) {
			Geometry::Box extendedBox=groupNode->getWorldBB();
			extendedBox.resizeAbs(context.getCamera()->getNearPlane());

			if (queries[i].getResult() > 0 || extendedBox.contains(context.getCamera()->getWorldOrigin()) ) {
				visibleGroupNodes.push_back(groupNode);
			}
			++i;
		}
		context.getRenderingContext().popDepthBuffer();

		delete [] queries;
	}
	std::deque<GeometryNode *> geoNodesInVisibleGroupNodes;

	// 3. collect all direct geometry-node children
	{
		struct GeoChildrenCollector:public NodeVisitor {
			GeoChildrenCollector(std::deque<GeometryNode*> & _geoNodes,FrameContext & _context):
				geoNodes(_geoNodes),firstNode(true),frameContext(_context) {}
			virtual ~GeoChildrenCollector() {}

			std::deque<GeometryNode*> & geoNodes;
			bool firstNode;
			FrameContext & frameContext;

			// ---|> NodeVisitor
			NodeVisitor::status enter(Node * _node) override {
				// if this is the first call, continue...
				if(firstNode) {
					firstNode=false;
					return CONTINUE_TRAVERSAL;
				}
				// else collect the geometry children and break the traversal.
				GeometryNode * gn=dynamic_cast<GeometryNode *>(_node);
				if(gn){
					if(frameContext.getCamera()->testBoxFrustumIntersection( _node->getWorldBB()) != Geometry::Frustum::intersection_t::OUTSIDE)
						geoNodes.push_back(gn);
				}
				return BREAK_TRAVERSAL;
			}
		};
		for (auto & visibleGroupNode : visibleGroupNodes) {
			GeoChildrenCollector vis(geoNodesInVisibleGroupNodes,context);
			(visibleGroupNode)->traverse(vis);
		}

	}

	// 4. clear screen and measure time drawing children
	float perfectRenderingTime=0;
	{
		context.getRenderingContext().clearScreen(clearColor);

		context.getRenderingContext().finish();
		Util::Timer timer;
		timer.reset();

		for (auto & geoNodesInVisibleGroupNode : geoNodesInVisibleGroupNodes) {
			context.displayNode((geoNodesInVisibleGroupNode),renderingFlags|USE_WORLD_MATRIX);
		}

		context.getRenderingContext().finish();
		timer.stop();
		perfectRenderingTime=timer.getMilliseconds();
	}

//    // Test-costs:
//    float result=numTests!=0?(currentRenderingTime-perfectRenderingTime)/numTests:0;

	// currentRenderingTime-perfRendering:
//    float result=currentRenderingTime-perfectRenderingTime;

	float result=numPoly>0?perfectRenderingTime*1000/numPoly:0;

//    std::cout <<currentRenderingTime<<"-"<<perfectRenderingTime<<"="<<result<<"\t"<<numTests<<"\n";
//    std::cout <<numVBO<<":"<<geoNodesInVisibleGroupNodes.size()<<"\n";

//   float result=perfectRenderingTime;
//    values.push_back(currentRenderingTime);
//    values.push_back(perfectRenderingTime);
	values->push_back(new Util::_NumberAttribute<float>(result));

//    if(mode==SINGLE_VALUE){
//        if(result>renderingTime || renderingTime==0)
//            renderingTime=result;
//    }else{
//        values.push_back(result);
//    }

//    renderingTime=0;
}
void ParticleBillboardRenderer::operator()(ParticleSystemNode * psys, FrameContext & context, const RenderParam & rp) {
	if(rp.getFlag(NO_GEOMETRY)) {
		return;
	}

	const auto & worldToCamera = context.getRenderingContext().getMatrix_worldToCamera();
	const auto cameraToWorld = worldToCamera.inverse();

	const auto halfRight = cameraToWorld.transformDirection(context.getWorldRightVector() * 0.5f);
	const auto halfUp = cameraToWorld.transformDirection(context.getWorldUpVector() * 0.5f);

	// 2. just update position for each particle and render
	// render particles
	const uint32_t count = psys->getParticleCount();

	Rendering::VertexDescription vertexDesc;
	const Rendering::VertexAttribute & posAttrib = vertexDesc.appendPosition3D();
	const Rendering::VertexAttribute & colorAttrib = vertexDesc.appendColorRGBAByte();
	const Rendering::VertexAttribute & texCoordAttrib = vertexDesc.appendTexCoord();
	// The usage of a cache for the mesh has been tested. Reusing a preallocated mesh is not faster.
	Util::Reference<Rendering::Mesh> mesh = new Rendering::Mesh(vertexDesc, 4 * count, 6 * count);
	mesh->setDataStrategy(Rendering::SimpleMeshDataStrategy::getPureLocalStrategy());
	Rendering::MeshIndexData & indexData = mesh->openIndexData();
	Rendering::MeshVertexData & vertexData = mesh->openVertexData();
	Util::Reference<Rendering::PositionAttributeAccessor> positionAccessor = Rendering::PositionAttributeAccessor::create(vertexData, posAttrib.getNameId());
	Util::Reference<Rendering::ColorAttributeAccessor> colorAccessor = Rendering::ColorAttributeAccessor::create(vertexData, colorAttrib.getNameId());
	Util::Reference<Rendering::TexCoordAttributeAccessor> texCoordAccessor = Rendering::TexCoordAttributeAccessor::create(vertexData, texCoordAttrib.getNameId());
	uint32_t * indices = indexData.data();

	uint_fast32_t index = 0;
	for(const auto & p : psys->getParticles()) {
		const Geometry::Vec3f upOffset = halfUp * p.size.getHeight();
		const Geometry::Vec3f rightOffset = halfRight * p.size.getWidth();

		colorAccessor->setColor(index + 0, p.color);
		texCoordAccessor->setCoordinate(index + 0, Geometry::Vec2f(0.0f, 0.0f));
		positionAccessor->setPosition(index + 0, p.position + upOffset - rightOffset);

		colorAccessor->setColor(index + 1, p.color);
		texCoordAccessor->setCoordinate(index + 1, Geometry::Vec2f(0.0f, 1.0f));
		positionAccessor->setPosition(index + 1, p.position - upOffset - rightOffset);

		colorAccessor->setColor(index + 2, p.color);
		texCoordAccessor->setCoordinate(index + 2, Geometry::Vec2f(1.0f, 1.0f));
		positionAccessor->setPosition(index + 2, p.position - upOffset + rightOffset);

		colorAccessor->setColor(index + 3, p.color);
		texCoordAccessor->setCoordinate(index + 3, Geometry::Vec2f(1.0f, 0.0f));
		positionAccessor->setPosition(index + 3, p.position + upOffset + rightOffset);

		*indices++ = index + 0;
		*indices++ = index + 1;
		*indices++ = index + 3;

		*indices++ = index + 1;
		*indices++ = index + 2;
		*indices++ = index + 3;

		index += 4;
	}

	indexData.markAsChanged();
	indexData.updateIndexRange();
	vertexData.markAsChanged();
	vertexData.updateBoundingBox();
	context.displayMesh(mesh.get());
}
Exemple #18
0
void VSThreadPool::runTasks(VSThreadPool *owner, std::atomic<bool> &stop) {
#ifdef VS_TARGET_CPU_X86
    if (!vs_isMMXStateOk())
        vsFatal("Bad MMX state detected after creating new thread");
#endif
#ifdef VS_TARGET_OS_WINDOWS
    if (!vs_isFPUStateOk())
        vsWarning("Bad FPU state detected after creating new thread");
    if (!vs_isSSEStateOk())
        vsFatal("Bad SSE state detected after creating new thread");
#endif

    std::unique_lock<std::mutex> lock(owner->lock);

    while (true) {
        bool ranTask = false;

/////////////////////////////////////////////////////////////////////////////////////////////
// Go through all tasks from the top (oldest) and process the first one possible
        for (std::list<PFrameContext>::iterator iter = owner->tasks.begin(); iter != owner->tasks.end(); ++iter) {
            FrameContext *mainContext = iter->get();
            FrameContext *leafContext = nullptr;

/////////////////////////////////////////////////////////////////////////////////////////////
// Handle the output tasks
            if (mainContext->frameDone && mainContext->returnedFrame) {
                PFrameContext mainContextRef(*iter);
                owner->tasks.erase(iter);
                owner->returnFrame(mainContextRef, mainContext->returnedFrame);
                ranTask = true;
                break;
            }

            if (mainContext->frameDone && mainContext->hasError()) {
                PFrameContext mainContextRef(*iter);
                owner->tasks.erase(iter);
                owner->returnFrame(mainContextRef, mainContext->getErrorMessage());
                ranTask = true;
                break;
            }

            bool hasLeafContext = mainContext->returnedFrame || mainContext->hasError();
            if (hasLeafContext)
            {
                leafContext = mainContext;
                mainContext = mainContext->upstreamContext.get();
            }

            VSNode *clip = mainContext->clip;
            int filterMode = clip->filterMode;

/////////////////////////////////////////////////////////////////////////////////////////////
// This part handles the locking for the different filter modes

            bool parallelRequestsNeedsUnlock = false;
            if (filterMode == fmUnordered) {
                // already busy?
                if (!clip->serialMutex.try_lock())
                    continue;
            } else if (filterMode == fmSerial) {
                // already busy?
                if (!clip->serialMutex.try_lock())
                    continue;
                // no frame in progress?
                if (clip->serialFrame == -1) {
                    clip->serialFrame = mainContext->n;
                //
                } else if (clip->serialFrame != mainContext->n) {
                    clip->serialMutex.unlock();
                    continue;
                }
                // continue processing the already started frame
            } else if (filterMode == fmParallel) {
                std::lock_guard<std::mutex> lock(clip->concurrentFramesMutex);
                // is the filter already processing another call for this frame? if so move along
                if (clip->concurrentFrames.count(mainContext->n)) {
                    continue;
                } else {
                    clip->concurrentFrames.insert(mainContext->n);
                }
            } else if (filterMode == fmParallelRequests) {
                std::lock_guard<std::mutex> lock(clip->concurrentFramesMutex);
                // is the filter already processing another call for this frame? if so move along
                if (clip->concurrentFrames.count(mainContext->n)) {
                    continue;
                } else {
                    // do we need the serial lock since all frames will be ready this time?
                    // check if we're in the arAllFramesReady state so we need additional locking
                    if (mainContext->numFrameRequests == 1) {
                        if (!clip->serialMutex.try_lock())
                            continue;
                        parallelRequestsNeedsUnlock = true;
                        clip->concurrentFrames.insert(mainContext->n);
                    }
                }
            }

/////////////////////////////////////////////////////////////////////////////////////////////
// Remove the context from the task list

            PFrameContext mainContextRef;
            PFrameContext leafContextRef;
            if (hasLeafContext) {
                leafContextRef = *iter;
                mainContextRef = leafContextRef->upstreamContext;
            } else {
                mainContextRef = *iter;
            }

            owner->tasks.erase(iter);

/////////////////////////////////////////////////////////////////////////////////////////////
// Figure out the activation reason

            VSActivationReason ar = arInitial;
            bool skipCall = false; // Used to avoid multiple error calls for the same frame request going into a filter
            if ((hasLeafContext && leafContext->hasError()) || mainContext->hasError()) {
                ar = arError;
                skipCall = mainContext->setError(leafContext->getErrorMessage());
                --mainContext->numFrameRequests;
            } else if (hasLeafContext && leafContext->returnedFrame) {
                if (--mainContext->numFrameRequests > 0)
                    ar = arFrameReady;
                else
                    ar = arAllFramesReady;

                mainContext->availableFrames.insert(std::make_pair(NodeOutputKey(leafContext->clip, leafContext->n, leafContext->index), leafContext->returnedFrame));
                mainContext->lastCompletedN = leafContext->n;
                mainContext->lastCompletedNode = leafContext->node;
            }

            assert(mainContext->numFrameRequests >= 0);

            bool hasExistingRequests = !!mainContext->numFrameRequests;

/////////////////////////////////////////////////////////////////////////////////////////////
// Do the actual processing

            lock.unlock();

            VSFrameContext externalFrameCtx(mainContextRef);
            assert(ar == arError || !mainContext->hasError());
            PVideoFrame f;
            if (!skipCall)
                f = clip->getFrameInternal(mainContext->n, ar, externalFrameCtx);
            ranTask = true;
            bool frameProcessingDone = f || mainContext->hasError();
            if (mainContext->hasError() && f)
                vsFatal("A frame was returned by %s but an error was also set, this is not allowed", clip->name.c_str());
                
/////////////////////////////////////////////////////////////////////////////////////////////
// Unlock so the next job can run on the context
            if (filterMode == fmUnordered) {
                clip->serialMutex.unlock();
            } else if (filterMode == fmSerial) {
                if (frameProcessingDone)
                    clip->serialFrame = -1;
                clip->serialMutex.unlock();
            } else if (filterMode == fmParallel) {
                std::lock_guard<std::mutex> lock(clip->concurrentFramesMutex);
                clip->concurrentFrames.erase(mainContext->n);
            } else if (filterMode == fmParallelRequests) {
                std::lock_guard<std::mutex> lock(clip->concurrentFramesMutex);
                clip->concurrentFrames.erase(mainContext->n);
                if (parallelRequestsNeedsUnlock)
                    clip->serialMutex.unlock();
            }

/////////////////////////////////////////////////////////////////////////////////////////////
// Handle frames that were requested
            bool requestedFrames = !externalFrameCtx.reqList.empty() && !frameProcessingDone;

            lock.lock();

            if (requestedFrames) {
                for (auto &reqIter : externalFrameCtx.reqList)
                    owner->startInternal(reqIter);
                externalFrameCtx.reqList.clear();
            }

            if (frameProcessingDone)
                owner->allContexts.erase(NodeOutputKey(mainContext->clip, mainContext->n, mainContext->index));

/////////////////////////////////////////////////////////////////////////////////////////////
// Propagate status to other linked contexts
// CHANGES mainContextRef!!!

            if (mainContext->hasError() && !hasExistingRequests && !requestedFrames) {
                PFrameContext n;
                do {
                    n = mainContextRef->notificationChain;

                    if (n) {
                        mainContextRef->notificationChain.reset();
                        n->setError(mainContextRef->getErrorMessage());
                    }

                    if (mainContextRef->upstreamContext) {
                        owner->startInternal(mainContextRef);
                    }

                    if (mainContextRef->frameDone) {
                        owner->returnFrame(mainContextRef, mainContextRef->getErrorMessage());
                    }
                } while ((mainContextRef = n));
            } else if (f) {
                if (hasExistingRequests || requestedFrames)
                    vsFatal("A frame was returned at the end of processing by %s but there are still outstanding requests", clip->name.c_str());
                PFrameContext n;

                do {
                    n = mainContextRef->notificationChain;

                    if (n)
                        mainContextRef->notificationChain.reset();

                    if (mainContextRef->upstreamContext) {
                        mainContextRef->returnedFrame = f;
                        owner->startInternal(mainContextRef);
                    }

                    if (mainContextRef->frameDone)
                        owner->returnFrame(mainContextRef, f);
                } while ((mainContextRef = n));
            } else if (hasExistingRequests || requestedFrames) {
                // already scheduled, do nothing
            } else {
                vsFatal("No frame returned at the end of processing by %s", clip->name.c_str());
            }
            break;
        }


        if (!ranTask || owner->activeThreadCount() > owner->threadCount()) {
            --owner->activeThreads;
            if (stop) {
                lock.unlock();
                break;
            }
            ++owner->idleThreads;
            owner->newWork.wait(lock);
            --owner->idleThreads;
            ++owner->activeThreads;
        }
    }
}
State::stateResult_t TwinPartitionsRenderer::doEnableState(FrameContext & context, Node *, const RenderParam & rp) {
	if (rp.getFlag(SKIP_RENDERER)) {
		return State::STATE_SKIPPED;
	}

	if (data == nullptr) {
		// Invalid information. => Fall back to standard rendering.
		return State::STATE_SKIPPED;
	}

	const Geometry::Vec3f pos = context.getCamera()->getWorldOrigin();
	// Check if cached cell can be used.
	if (currentCell == INVALID_CELL || !data->cells[currentCell].bounds.contains(pos)) {
		// Search the cell that contains the camera position.
		bool cellFound = false;
		const uint32_t cellCount = data->cells.size();
		for (uint_fast32_t cell = 0; cell < cellCount; ++cell) {
			if (data->cells[cell].bounds.contains(pos)) {
// #ifdef MINSG_EXT_OUTOFCORE
// 				// Set new priorities if the current cell changes.
// 				if (currentCell != cell) {
// 					// Low priority for old depth mesh.
// 					if (currentCell != INVALID_CELL) {
// 						for(std::vector<uint32_t>::const_iterator it = data->cells[currentCell].surroundingIds.begin(); it != data->cells[currentCell].surroundingIds.end(); ++it) {
// 							Rendering::Mesh * depthMesh = data->depthMeshes[*it].get();
// 							OutOfCore::getCacheManager().setUserPriority(depthMesh, 0);
// 						}
// 					}
// 					// High priority for new depth mesh.
// 					{
// 						for(std::vector<uint32_t>::const_iterator it = data->cells[cell].surroundingIds.begin(); it != data->cells[cell].surroundingIds.end(); ++it) {
// 							Rendering::Mesh * depthMesh = data->depthMeshes[*it].get();
// 							OutOfCore::getCacheManager().setUserPriority(depthMesh, 20);
// 						}
// 					}
// 					// Low priority for meshes visible from the old cell.
// 					if (currentCell != INVALID_CELL) {
// 						const uint32_t oldVisibleSetIndex = data->cells[currentCell].visibleSetId;
// 						const PartitionsData::visible_set_t & oldVisibleSet = data->visibleSets[oldVisibleSetIndex];
// 						for (PartitionsData::visible_set_t::const_iterator it = oldVisibleSet.begin(); it != oldVisibleSet.end(); ++it) {
// 							Rendering::Mesh * mesh = data->objects[it->second].get();
// 							OutOfCore::getCacheManager().setUserPriority(mesh, 0);
// 						}
// 					}
// 					// High priority for meshes visible from the new cell.
// 					{
// 						const uint32_t visibleSetIndex = data->cells[cell].visibleSetId;
// 						const PartitionsData::visible_set_t & visibleSet = data->visibleSets[visibleSetIndex];
// 						for (PartitionsData::visible_set_t::const_iterator it = visibleSet.begin(); it != visibleSet.end(); ++it) {
// 							Rendering::Mesh * mesh = data->objects[it->second].get();
// 							OutOfCore::getCacheManager().setUserPriority(mesh, 10);
// 						}
// 					}
// 				}
// #endif /* MINSG_EXT_OUTOFCORE */
				// Load new textures.
				textures.clear();
				if(drawTexturedDepthMeshes) {
					textures.reserve(6);
					for(auto & elem : data->cells[cell].surroundingIds) {
						const std::string & textureFile = data->textureFiles[elem];
						Util::Reference<Rendering::Texture> texture = Rendering::Serialization::loadTexture(Util::FileName(textureFile));
						if(texture == nullptr) {
							WARN("Failed to load texture for depth mesh.");
						} else {
							textures.push_back(texture);
						}
					}
				}

				currentCell = cell;
				cellFound = true;
				break;
			}
		}
		if (!cellFound) {
			// Camera outside view space.
			currentCell = INVALID_CELL;
			return State::STATE_SKIPPED;
		}
	}

	uint32_t renderedTriangles = 0;

	const uint32_t visibleSetIndex = data->cells[currentCell].visibleSetId;
	const PartitionsData::visible_set_t & visibleSet = data->visibleSets[visibleSetIndex];

	if(drawTexturedDepthMeshes) {
		for(auto & elem : data->cells[currentCell].surroundingIds) {
			Rendering::Mesh * depthMesh = data->depthMeshes[elem].get();
			// Count the depth meshes here already.
			renderedTriangles += depthMesh->getPrimitiveCount();
		}
	}
	const Geometry::Frustum & frustum = context.getCamera()->getFrustum();

	/*float minDist = 9999999.0f;
	float maxDist = 0.0f;
	float prioSum = 0.0f;
	uint_fast32_t objectCounter = 0;
	for (PartitionsData::visible_set_t::const_iterator it = visibleSet.begin(); it != visibleSet.end(); ++it) {
		Rendering::Mesh * mesh = data->objects[it->second].get();
		float dist = mesh->getBoundingBox().getDistance(pos);
		minDist = std::min(dist, minDist);
		maxDist = std::max(dist, maxDist);
		if(objectCounter < 10) {
			prioSum += it->first;
			++objectCounter;
		}
	}

	std::ofstream output("twinOutput.tsv", ios_base::out | ios_base::app);
	output << currentCell << '\t' << data->cells[currentCell].bounds.getDiameter() << '\t' << (data->cells[currentCell].bounds.getCenter() - pos).length() << '\t'
	 << visibleSet.begin()->first << '\t'
	 << visibleSet.rbegin()->first << '\t'
	 << minDist << '\t' << maxDist << '\t' << prioSum << '\t';
	for(std::vector<uint32_t>::const_iterator it = data->cells[currentCell].surroundingIds.begin(); it != data->cells[currentCell].surroundingIds.end(); ++it) {
		Rendering::Mesh * depthMesh = data->depthMeshes[*it].get();
		const Geometry::Box & depthMeshBB = depthMesh->getBoundingBox();

		const Geometry::Vec3f originalDirection = (depthMeshBB.getCenter() - data->cells[currentCell].bounds.getCenter()).normalize();
		const Geometry::Vec3f currentDirection = (depthMeshBB.getCenter() - pos).normalize();
		const float angle = currentDirection.dot(originalDirection);
		const bool visible = (frustum.isBoxInFrustum(depthMeshBB) != Frustum::OUTSIDE);
		output << '\t';
		if(visible) {

			output << angle ;
		} else {
				output << "NA";
		}
	}
	for(uint_fast32_t i = data->cells[currentCell].surroundingIds.size(); i < 6; ++i) {
		output << "\tNA";
	}
	output << std::endl;
	output.close();*/


	for (auto & elem : visibleSet) {
		Rendering::Mesh * mesh = data->objects[elem.second].get();
		if (conditionalFrustumTest(frustum, mesh->getBoundingBox(), rp)) {
			context.displayMesh(mesh);
			renderedTriangles += mesh->getPrimitiveCount();
		}
		if(rp.getFlag(BOUNDING_BOXES)) {
			Rendering::drawWireframeBox(context.getRenderingContext(), mesh->getBoundingBox(), Util::ColorLibrary::RED);
		}
		if (maxRuntime != 0 && renderedTriangles >= maxRuntime) {
			break;
		}
	}
	// Draw the textured depth meshes at the end.
	if(drawTexturedDepthMeshes) {
		context.getRenderingContext().pushAndSetPolygonOffset(Rendering::PolygonOffsetParameters(polygonOffsetFactor, polygonOffsetUnits));
		context.getRenderingContext().pushAndSetShader(getTDMShader());
		context.getRenderingContext().pushTexture(0);
		auto texIt = textures.begin();
		for(auto & elem : data->cells[currentCell].surroundingIds) {
			Rendering::Mesh * depthMesh = data->depthMeshes[elem].get();
			Rendering::Texture * texture = texIt->get();

			context.getRenderingContext().setTexture(0, texture);

			if (conditionalFrustumTest(frustum, depthMesh->getBoundingBox(), rp)) {
				context.displayMesh(depthMesh);
			}

			++texIt;
		}
		context.getRenderingContext().popTexture(0);
		context.getRenderingContext().popShader();
		context.getRenderingContext().popPolygonOffset();
	}

	return State::STATE_SKIP_RENDERING;
}
Exemple #20
0
void ShaderState::setUniform(FrameContext & context, const Rendering::Uniform & value) {
	setUniform(value);
	shader->setUniform(context.getRenderingContext(),value,true,true); // warn if uniform is not defined in shader and force at least one try on applying the uniform
}
State::stateResult_t VisibilitySubdivisionRenderer::doEnableState(
																	FrameContext & context,
																	Node *,
																	const RenderParam & rp) {
	if (rp.getFlag(SKIP_RENDERER)) {
		return State::STATE_SKIPPED;
	}

	if (viSu == nullptr) {
		// Invalid information. => Fall back to standard rendering.
		return State::STATE_SKIPPED;
	}

	// [AccumRendering]
	if(accumRenderingEnabled){
		// camera moved? -> start new frame
		const Geometry::Matrix4x4 & newCamMat=context.getCamera()->getWorldTransformationMatrix();
		if(newCamMat!=lastCamMatrix){
			lastCamMatrix = newCamMat;
			startRuntime=0;
		}
	}else{
		startRuntime=0;
	}
	// ----

	uint32_t renderedTriangles = 0;
	if (hold) {
		for (const auto & object : holdObjects) {
			if (debugOutput) {
				debugDisplay(renderedTriangles, object, context, rp);
			} else {
				context.displayNode(object, rp);
			}
		}
		return State::STATE_SKIP_RENDERING;
	}

	Geometry::Vec3 pos = context.getCamera()->getWorldOrigin();
	bool refreshCache = false;
	// Check if cached cell can be used.
	if (currentCell == nullptr || !currentCell->getBB().contains(pos)) {
		currentCell = viSu->getNodeAtPosition(pos);
		refreshCache = true;
	}
	if (currentCell == nullptr || !currentCell->isLeaf()) {
		// Invalid information. => Fall back to standard rendering.
		return State::STATE_SKIPPED;
	}

	if (refreshCache) {
		try {
			const auto & vv = getVV(currentCell);

			const uint32_t maxIndex = vv.getIndexCount();
			objects.clear();
			objects.reserve(maxIndex);
			for(uint_fast32_t index = 0; index < maxIndex; ++index) {
				if(vv.getBenefits(index) == 0) {
					continue;
				}
				const VisibilityVector::costs_t costs = vv.getCosts(index);
				const VisibilityVector::benefits_t benefits = vv.getBenefits(index);
				const float score = static_cast<float>(costs) / static_cast<float>(benefits);
				objects.emplace_back(score, vv.getNode(index));
			}
		} catch(...) {
			// Invalid information. => Fall back to standard rendering.
			return State::STATE_SKIPPED;
		}

		if (displayTexturedDepthMeshes) {
#ifdef MINSG_EXT_OUTOFCORE
			for (const auto & depthMesh : depthMeshes) {
				OutOfCore::getCacheManager().setUserPriority(depthMesh.get(), 0);
			}
#endif /* MINSG_EXT_OUTOFCORE */
			depthMeshes.clear();
			depthMeshes.reserve(6);
			textures.clear();
			textures.reserve(6);

			const std::string dmDirectionStrings[6] = { "-dir_x1_y0_z0", "-dir_x-1_y0_z0",
														"-dir_x0_y1_z0", "-dir_x0_y-1_z0",
														"-dir_x0_y0_z1", "-dir_x0_y0_z-1" };
			for (auto & dmDirectionString : dmDirectionStrings) {
				Util::GenericAttribute * attrib = currentCell->getAttribute("DepthMesh" + dmDirectionString);
				if (attrib == nullptr) {
					continue;
				}
				Util::FileName dmMeshPath(attrib->toString());
				Util::Reference<Rendering::Mesh> dmMesh;
#ifdef MINSG_EXT_OUTOFCORE
				Util::GenericAttribute * bbAttrib = currentCell->getAttribute("DepthMesh" + dmDirectionString + "-bounds");
				if (bbAttrib == nullptr) {
					WARN("Found depth mesh with no bounding box.");
					continue;
				}

				std::vector<float> bbValues = Util::StringUtils::toFloats(bbAttrib->toString());
				FAIL_IF(bbValues.size() != 6);
				const Geometry::Box meshBB(Geometry::Vec3(bbValues[0], bbValues[1], bbValues[2]), bbValues[3], bbValues[4], bbValues[5]);

				dmMesh = OutOfCore::addMesh(dmMeshPath, meshBB);
#else /* MINSG_EXT_OUTOFCORE */
				dmMesh = Rendering::Serialization::loadMesh(dmMeshPath);
#endif /* MINSG_EXT_OUTOFCORE */
				depthMeshes.emplace_back(dmMesh);
				// Count the depth mesh here already.
				renderedTriangles += dmMesh->getPrimitiveCount();

				Util::GenericAttribute * texAttrib = currentCell->getAttribute("Texture" + dmDirectionString);
				if (texAttrib == nullptr) {
					continue;
				}
				Util::FileName texturePath(texAttrib->toString());
				Util::Reference<Rendering::Texture> texture = Rendering::Serialization::loadTexture(texturePath);
				if (texture.isNull()) {
					WARN("Loading texture for depth mesh failed.");
					continue;
				}
				textures.emplace_back(texture);
			}
		}
	}

	const Geometry::Frustum & frustum = context.getCamera()->getFrustum();
	holdObjects.clear();
	holdObjects.reserve(objects.size());

	std::sort(objects.begin(), objects.end());
	for(const auto & ratioObjectPair : objects) {
		object_ptr o = ratioObjectPair.second;
#ifdef MINSG_EXT_OUTOFCORE
		OutOfCore::getCacheManager().setUserPriority(o->getMesh(), 5);
#endif /* MINSG_EXT_OUTOFCORE */
		
		if (conditionalFrustumTest(frustum, o->getWorldBB(), rp)) {
			// [AccumRendering]
			// skip geometry rendered in the last frame
			if(renderedTriangles<startRuntime){
				renderedTriangles += o->getTriangleCount();
				continue;
			}
			// ----

			if (debugOutput) {
				debugDisplay(renderedTriangles, o, context, rp);
			} else {
				context.displayNode(o, rp);
				renderedTriangles += o->getTriangleCount();
			}
			holdObjects.push_back(o);
		}
		if (maxRuntime != 0 && renderedTriangles >= startRuntime+maxRuntime) {
			break;
		}
	}

	// Draw the textured depth meshes at the end.
	if (displayTexturedDepthMeshes) {
		context.getRenderingContext().pushAndSetPolygonOffset(Rendering::PolygonOffsetParameters(polygonOffsetFactor, polygonOffsetUnits));
		auto texIt = textures.cbegin();
		for (const auto & depthMesh : depthMeshes) {
			context.getRenderingContext().pushAndSetShader(getTDMShader());
			context.getRenderingContext().pushAndSetTexture(0,texIt->get());
			
			if (conditionalFrustumTest(frustum, depthMesh->getBoundingBox(), rp)) {
				context.displayMesh(depthMesh.get());
			}
			context.getRenderingContext().popTexture(0);
			context.getRenderingContext().popShader();
#ifdef MINSG_EXT_OUTOFCORE
			OutOfCore::getCacheManager().setUserPriority(depthMesh.get(), 2);
#endif /* MINSG_EXT_OUTOFCORE */
			++texIt;
		}
		context.getRenderingContext().popPolygonOffset();
	}
	// [AccumRendering]
	startRuntime=renderedTriangles;
	// ----
	return State::STATE_SKIP_RENDERING;
}
Exemple #22
0
State::stateResult_t PhotonRenderer::doEnableState(FrameContext & context, Node * node, const RenderParam & rp){
#ifdef MINSG_THESISSTANISLAW_GATHER_STATISTICS
  Rendering::RenderingContext::finish();
  _timer.reset();
#endif // MINSG_THESISSTANISLAW_GATHER_STATISTICS

  if(!_photonSampler){
    WARN("No PhotonSampler present in PhotonRenderer!");
    return State::stateResult_t::STATE_SKIPPED;
  }
  
  if(!_approxScene){
    WARN("No approximated Scene present in PhotonRenderer!");
    return State::stateResult_t::STATE_SKIPPED;
  }
  
  
  auto& rc = context.getRenderingContext();
  rc.setImmediateMode(true);
  rc.applyChanges();
  
  if(_fboChanged){
    if(!initializeFBO(rc)){
      WARN("Could not initialize FBO for PhotonRenderer!");
      return State::stateResult_t::STATE_SKIPPED;
    }
    _fboChanged = false;
  }
  
  RenderParam newRp;
  
  rc.pushAndSetFBO(_fbo.get());
  rc.clearDepth(1.0f);
  
  rc.applyChanges();
  
  for(int32_t i = 0; i < _photonSampler->getPhotonNumber(); i++){
    _fbo->setDrawBuffers(2);
    rc.pushAndSetShader(_indirectLightShader.get());
    _lightPatchRenderer->bindTBO(rc, true, false);
    _photonSampler->bindPhotonBuffer(1);
    context.pushAndSetCamera(_photonCamera.get());
    _indirectLightShader->setUniform(rc, Rendering::Uniform("photonID", i));
    
    rc.clearDepth(1.0f);
    rc.clearColor(Util::Color4f(0.f, 0.f, 0.f, 0.f));
    _approxScene->display(context, newRp);
    
    context.popCamera();
    _photonSampler->unbindPhotonBuffer(1);
    _lightPatchRenderer->unbindTBO(rc);
    rc.popShader();
    
    
    // Accumulate all pixel values in one photon 
    _fbo->setDrawBuffers(0);
    rc.pushAndSetShader(_accumulationShader.get());
    _accumulationShader->setUniform(rc, Rendering::Uniform("photonID", i));
    _accumulationShader->setUniform(rc, Rendering::Uniform("samplingWidth", static_cast<int>(_samplingWidth)));
    _accumulationShader->setUniform(rc, Rendering::Uniform("samplingHeight", static_cast<int>(_samplingHeight)));
    _photonSampler->bindPhotonBuffer(1);
    rc.clearDepth(1.0f);
    Rendering::TextureUtils::drawTextureToScreen(rc, Geometry::Rect_i(0, 0, _samplingWidth, _samplingHeight), *_indirectLightTexture.get(), Geometry::Rect_f(0.0f, 0.0f, 1.0f, 1.0f));
    _photonSampler->unbindPhotonBuffer(1);
    rc.popShader();
  }
  
  rc.popFBO();
  
  rc.setImmediateMode(false);
  
//  rc.pushAndSetShader(nullptr);
//  Rendering::TextureUtils::drawTextureToScreen(rc, Geometry::Rect_i(0, 0, _samplingWidth, _samplingHeight), *(_indirectLightTexture.get()), Geometry::Rect_f(0.0f, 0.0f, 1.0f, 1.0f));
//  rc.popShader();
//  return State::stateResult_t::STATE_SKIP_RENDERING;

#ifdef MINSG_THESISSTANISLAW_GATHER_STATISTICS
  Rendering::RenderingContext::finish();
  _timer.stop();
  auto& stats = context.getStatistics();
  Statistics::instance(stats).addPhotonRendererTime(stats, _timer.getMilliseconds());
#endif // MINSG_THESISSTANISLAW_GATHER_STATISTICS

  return State::stateResult_t::STATE_OK;
}
Exemple #23
0
//! ---|> [State]
State::stateResult_t CHCRenderer::doEnableState(FrameContext & context,Node * rootNode, const RenderParam & rp){
	if(rp.getFlag(SKIP_RENDERER))
		return State::STATE_SKIPPED;
	if(debugShowVisible){
		std::deque<Node *> nodes;
		{
			const auto children = getChildNodes(rootNode);
			nodes.insert(nodes.end(), children.begin(), children.end());
		}
		while(!nodes.empty()){
			Node& node = *nodes.front();
			nodes.pop_front();
			auto& nodeInfo = getNodeInfo(node);
			if(nodeInfo.frameNr == frameNr && nodeInfo.visible){
				if(node.isClosed())
					context.displayNode(&node,rp);
				else {
					const auto children = getChildNodes(&node);
					nodes.insert(nodes.end(), children.begin(), children.end());
				}
			}
		}
	}else{
		++frameNr;
		
		// used for statistics
		unsigned int stat_numTests = 0;
		unsigned int stat_numTestsInvisible = 0;
		unsigned int stat_numTestsVisible = 0;
		Statistics & statistics = context.getStatistics();

		RenderParam childParam = rp + USE_WORLD_MATRIX;

		const auto& camera = *context.getCamera();
		const Geometry::Vec3 camPos = camera.getWorldOrigin();
		const float bbEnlargement = camera.getNearPlane();
		NodeDistancePriorityQueue_F2B distanceQueue(camPos);
		std::queue<std::pair<Rendering::OcclusionQuery, Node*>> queryQueue;

		const auto traverseNode = [&](Node& node){
			if( node.isClosed() ){ // leaf node
				context.displayNode(&node, childParam );
			}else{
				for(auto & child : getChildNodes(&node))
					distanceQueue.push(child);
			}
		};
		const auto pullUpVisibility = [&](Node& node){
			for(Node* n=&node; n&&n!=rootNode; n = n->getParent()){
				auto& nodeInfo = getNodeInfo(*n);
				if(nodeInfo.frameNr == frameNr && nodeInfo.visible)
					break;
				nodeInfo.visible = true;
				nodeInfo.frameNr = frameNr;
				
			};
		};
		const auto startQuery = [&](Node& node,const Geometry::Box& worldBoundingBox){
			Rendering::OcclusionQuery query;
			Rendering::OcclusionQuery::enableTestMode(context.getRenderingContext());
			query.begin();
			Rendering::drawAbsBox(context.getRenderingContext(), worldBoundingBox );
			query.end();
			Rendering::OcclusionQuery::disableTestMode(context.getRenderingContext());
			return std::make_pair(std::move(query),&node);
		};
		
		traverseNode(*rootNode);
		while(!distanceQueue.empty() || !queryQueue.empty()){
				
			// ---- PART 1: process finished occlusion queries
			while( !queryQueue.empty() && (distanceQueue.empty() || queryQueue.front().first.isResultAvailable()) ){
				if( queryQueue.front().first.getResult()>0 ){
					++stat_numTestsVisible;
					statistics.pushEvent( Statistics::EVENT_TYPE_END_TEST_VISIBLE, 1);

					Node& node = *queryQueue.front().second;
					pullUpVisibility(node);
					auto& nodeInfo = getNodeInfo( node );
					if( !nodeInfo.wasVisible )
						traverseNode(node);
				}else{
					++stat_numTestsInvisible;
					statistics.pushEvent( Statistics::EVENT_TYPE_END_TEST_INVISIBLE, 1);
				}
				queryQueue.pop();
			}
			
			// ---- PART 2: tree traversal
			if( !distanceQueue.empty() ){
				Node& node = *distanceQueue.top();
				distanceQueue.pop();
				const Geometry::Box worldBoundingBox = node.getWorldBB();
				if (camera.testBoxFrustumIntersection( node.getWorldBB()) == Geometry::Frustum::intersection_t::OUTSIDE) {
					continue;
				}
				Geometry::Box enlargedBox = worldBoundingBox;
				enlargedBox.resizeAbs( bbEnlargement );
				if( enlargedBox.contains(camPos) ){
					pullUpVisibility(node);
					traverseNode(node);
					continue;
				}
				auto& nodeInfo = getNodeInfo( node );
				// identify previously visible nodes
				const bool wasVisible = nodeInfo.frameNr == frameNr-1 && nodeInfo.visible;
				nodeInfo.wasVisible = wasVisible;
				
				// reset node's visibility flag
				nodeInfo.visible = false;
				// update node's visited flag
				nodeInfo.frameNr = frameNr;
				
				// test leafs and previously invisible nodes
				if( node.isClosed() || !wasVisible){ // on testing front
					// start test
					++stat_numTests;
					statistics.pushEvent(Statistics::EVENT_TYPE_START_TEST, 1);
					queryQueue.push( std::move(startQuery(node,worldBoundingBox)) );
				}
				// traverse a node unless it was invisible
				if( wasVisible )
					traverseNode( node );
			}
		}

		statistics.addValue(OcclusionCullingStatistics::instance(statistics).getOccTestVisibleCounter(), stat_numTestsVisible);
		statistics.addValue(OcclusionCullingStatistics::instance(statistics).getOccTestInvisibleCounter(), stat_numTestsInvisible);
		statistics.addValue(OcclusionCullingStatistics::instance(statistics).getOccTestCounter(), stat_numTests);
	}
//			std::cout << std::endl;

	return State::STATE_SKIP_RENDERING;
}
Exemple #24
0
//! ---|> [State]
void ShaderState::doDisableState(FrameContext & context, Node *, const RenderParam & /*rp*/) {
	// restore old shader
	context.getRenderingContext().popShader();
}
Exemple #25
0
State::stateResult_t SkyboxState::doEnableState(FrameContext & context, Node *, const RenderParam & rp) {
	if (rp.getFlag(NO_GEOMETRY)) {
		return State::STATE_SKIPPED;
	}

	Vec3 pos = context.getCamera()->getWorldOrigin();
	Geometry::Matrix4x4 matrix;
	matrix.translate(pos);
	context.getRenderingContext().pushMatrix_modelToCamera();
	context.getRenderingContext().multMatrix_modelToCamera(matrix);
	context.getRenderingContext().pushTexture(0);

	context.getRenderingContext().pushAndSetDepthBuffer(Rendering::DepthBufferParameters(true, false, Rendering::Comparison::LESS));
	context.getRenderingContext().pushAndSetLighting(Rendering::LightingParameters(false));

	Geometry::Box box(Geometry::Vec3(0.0f, 0.0f, 0.0f), sideLength);
	for (uint_fast8_t side = 0; side < 6; ++side) {
		if (!textures[side].isNull()) {
			context.getRenderingContext().setTexture(0,textures[side].get());
			const Geometry::corner_t * corners = Geometry::Helper::getCornerIndices(static_cast<Geometry::side_t> (side));
			// Reverse the corner order because we need the inner surface.
			Rendering::drawQuad(context.getRenderingContext(), box.getCorner(corners[1]), box.getCorner(corners[0]), box.getCorner(corners[3]), box.getCorner(corners[2]),Util::ColorLibrary::WHITE);

		}
	}
	context.getRenderingContext().popLighting();
	context.getRenderingContext().popDepthBuffer();
	context.getRenderingContext().popTexture(0);

	context.getRenderingContext().popMatrix_modelToCamera();
	return State::STATE_OK;
}
Exemple #26
0
//! (internal) Main culling method
State::stateResult_t OccRenderer::performCulling(FrameContext & context,Node * rootNode, const RenderParam & rp){
	if(mode==MODE_UNCONDITIONED){ // destroy temporal coherence
		frameNumber++;
	}
	frameNumber++;

	updateNodeInformation(context,rootNode); // ???

	// used for statistics
	unsigned int tests=0;
	int testsVisible=0;
	int testsInvisible=0;
	int occludedGeometryNodes=0;


	Statistics & statistics = context.getStatistics();

	RenderParam childParam = rp + USE_WORLD_MATRIX;

	const Geometry::Vec3 camPos=context.getCamera()->getWorldOrigin();


//	NodeDistancePriorityQueue_F2B distanceQueue(camPos);
	NodeDistancePriorityQueue_F2B distanceQueue(camPos);

	{	// add root node's children
		const auto children = getChildNodes(rootNode);
		for(auto & child : children) {
			distanceQueue.push(child);
		}
	}

	std::queue<std::pair<Rendering::OcclusionQuery, Node *>> queryQueue;

//    bool wasIdle=true;
	int idleCount=0;
	while ( (!distanceQueue.empty()) || (!queryQueue.empty() ) ) {
		bool idle=true;

		while ( !queryQueue.empty() && queryQueue.front().first.isResultAvailable() ) {
			idle=false;

			const OcclusionQuery & currentQuery = queryQueue.front().first;
			unsigned int result = currentQuery.getResult();
			Node * node = queryQueue.front().second;

			queryQueue.pop();
			NodeInfo * nodeInfo = getNodeInfo(node);

			// Node is visible?
			if (result>0 ) {

				statistics.pushEvent(Statistics::EVENT_TYPE_END_TEST_VISIBLE,nodeInfo->getActualSubtreeComplexity());

				testsVisible++;
				if (node->isClosed()) {
					// mark parents as visible
					Node * n=node;
					NodeInfo * ni=nodeInfo;
					while( ni->getVisibleFrameNumber()!=frameNumber){
						ni->setVisibleFrameNumber(frameNumber);
						n=n->getParent();
						if(n==nullptr || n==rootNode) break;
						ni=getNodeInfo(n);
					}
				}
				nodeInfo->setVisibleFrameNumber(frameNumber);

				// haben wir schon bearbeitet? -> Weiter...
				if (nodeInfo->getProcessedFrameNumber()==frameNumber)
					continue;

////                if(node->visibleFrameNumber != (frameNumber-1)){ ????
				// Process node
				processNode(context,node,nodeInfo,distanceQueue,childParam);

////                }
			}// Node is fully occluded?
			else {
				testsInvisible++;


				statistics.pushEvent(Statistics::EVENT_TYPE_END_TEST_INVISIBLE, nodeInfo->getActualSubtreeComplexity());

				// not processed yet?
				if (nodeInfo->getProcessedFrameNumber()!=frameNumber) {
					// TODO: Store and propagate in tree.
					occludedGeometryNodes+=collectNodesInFrustum<GeometryNode>(node,context.getCamera()->getFrustum()).size();

					// mark the node as processed
					nodeInfo->setProcessedFrameNumber(frameNumber);
				}
				// In diesem Frame verdeckt worden? (dann haben wir nicht mit der Bearbeitung gewartet und
				// die Kinder liegen bereits in der distanceQueue; die sollten jetzt �bersprungen werden)
				if ( nodeInfo->getVisibleFrameNumber() == (frameNumber-1) ) {
					if (!node->isClosed()) {
						const auto children = getChildNodes(node);
						for(auto & child : children) {
							getNodeInfo(child)->setProcessedFrameNumber(frameNumber);
							// TODO: Check if ancestors have to be removed too.
						}
					}
				}
			}
		}
		// ...
		if ( ! distanceQueue.empty()) {

			idle=false;

			Node * node=distanceQueue.top();
			NodeInfo * nodeInfo=getNodeInfo(node);
			distanceQueue.pop();

			// If the current node has already been processed, then continue.
			if (nodeInfo->getProcessedFrameNumber()==frameNumber ) continue; // ||node->isEmpty()

//			// skip empty subtrees // does never happen (checked in processNode)
//			if( nodeInfo->getActualSubtreeComplexity() == 0){
//                nullBoxes++;
//                continue;
//			}

			// Kamera innerhalb der (um die nearplane vergroesserte) Box? -> immer sichtbar
			// [2008-01-04_CJ] Bugfix: added nearplane addition; could result in dissapearing scene-parts.
			Geometry::Box extendedBox=node->getWorldBB(); //node->getGeometryBB();
			extendedBox.resizeAbs(context.getCamera()->getNearPlane());
			if (extendedBox.contains(camPos)) {

				nodeInfo->setVisibleFrameNumber(frameNumber);

				// Process node
				processNode(context,node,nodeInfo,distanceQueue,childParam);
				continue;
			}

			// !IS_INSIDE_FRUSTUM(node)
			if ( nodeInfo->getActualFrustumStatus()== Geometry::Frustum::OUTSIDE)
				continue;

			// [MODE_OPT_CULLING] For optimal culling, skip all unnecessary tests
			if(mode==MODE_OPT_CULLING && nodeInfo->getVisibleFrameNumber() == (frameNumber-1)){
				nodeInfo->setVisibleFrameNumber(frameNumber);
				// Process node
				processNode(context,node,nodeInfo,distanceQueue,childParam);
				continue;
			}

			// if query reasonable
			// TODO: Something missing here?

			{ // start occlusion test for the current node
				Rendering::OcclusionQuery query;

				Rendering::OcclusionQuery::enableTestMode(context.getRenderingContext());
				query.begin();
				Rendering::drawFastAbsBox(context.getRenderingContext(), node->getWorldBB());
				query.end();
				Rendering::OcclusionQuery::disableTestMode(context.getRenderingContext());
				tests++;
				queryQueue.emplace(std::move(query), node);

				statistics.pushEvent(Statistics::EVENT_TYPE_START_TEST, nodeInfo->getActualSubtreeComplexity());
			}

			// if the current node was visible in the last frame,
			//  then assume that it is also visible in this frame and process it.
			if (nodeInfo->getVisibleFrameNumber() == (frameNumber-1) ) {
				// Process node
				processNode(context,node,nodeInfo,distanceQueue,childParam);
			}

		}
//		else{
			// waiting

//		}
		if (idle) {
			statistics.pushEvent(Statistics::EVENT_TYPE_IDLE, idleCount++);
		} else {
			idleCount = 0;
		}

	}

	statistics.addValue(OcclusionCullingStatistics::instance(statistics).getOccTestCounter(), tests);
	statistics.addValue(OcclusionCullingStatistics::instance(statistics).getOccTestVisibleCounter(), testsVisible);
	statistics.addValue(OcclusionCullingStatistics::instance(statistics).getOccTestInvisibleCounter(), testsInvisible);
	statistics.addValue(OcclusionCullingStatistics::instance(statistics).getCulledGeometryNodeCounter(), occludedGeometryNodes);
	statistics.pushEvent(Statistics::EVENT_TYPE_FRAME_END,0.3);

	return State::STATE_SKIP_RENDERING;
}
//! Distribute the budget based on the projected size and the primitive count of the child nodes.
static void distributeProjectedSizeAndPrimitiveCount(double value, const Util::StringIdentifier & attributeId, Node * node, FrameContext & context) {
	static const Util::StringIdentifier primitiveCountId("PrimitiveCount");
	struct PrimitiveCountAnnotationVisitor : public NodeVisitor {
		const Util::StringIdentifier & m_primitiveCountId;
		PrimitiveCountAnnotationVisitor(const Util::StringIdentifier & p_primitiveCountId) : m_primitiveCountId(p_primitiveCountId) {
		}
		virtual ~PrimitiveCountAnnotationVisitor() {
		}
		NodeVisitor::status leave(Node * _node) override {
			auto geoNode = dynamic_cast<GeometryNode *>(_node);
			uint32_t primitiveCount = 0;
			if(geoNode != nullptr) {
				const auto mesh = geoNode->getMesh();
				primitiveCount = mesh == nullptr ? 0 : mesh->getPrimitiveCount();
			} else {
				const auto children = getChildNodes(_node);
				for(const auto & child : children) {
					primitiveCount += child->getAttribute(m_primitiveCountId)->toUnsignedInt();
				}
			}
			_node->setAttribute(m_primitiveCountId, Util::GenericAttribute::createNumber(primitiveCount));
			return CONTINUE_TRAVERSAL;
		}
	};

	const auto children = getChildNodes(node);

	// A tuple stores the primitive count, the node and its projected size.
	std::vector<std::tuple<uint32_t, Node *, float>> primitiveCountNodeProjSizeTuples;
	primitiveCountNodeProjSizeTuples.reserve(children.size());
	double projSizeSum = 0.0;

	const Geometry::Rect_f screenRect(context.getRenderingContext().getWindowClientArea());
	for(const auto & child : children) {
		if(!child->isAttributeSet(primitiveCountId)) {
			PrimitiveCountAnnotationVisitor visitor(primitiveCountId);
			child->traverse(visitor);
		}
		const auto primitiveCount = child->getAttribute(primitiveCountId)->toUnsignedInt();

		// Clip the projected rect to the screen.
		auto projRect = context.getProjectedRect(child);
		projRect.clipBy(screenRect);

		const auto projSize = projRect.getArea();
		projSizeSum += projSize;
		primitiveCountNodeProjSizeTuples.emplace_back(primitiveCount, child, projSize);
	}

	// Begin with the node with the lowest primitive count
	std::sort(primitiveCountNodeProjSizeTuples.begin(), primitiveCountNodeProjSizeTuples.end());

	for(const auto & primitiveCountNodeProjSizeTuple : primitiveCountNodeProjSizeTuples) {
		const auto primitiveCount = std::get<0>(primitiveCountNodeProjSizeTuple);
		const auto projSize = std::get<2>(primitiveCountNodeProjSizeTuple);
		const auto projSizeFactor = projSize / projSizeSum;
		
		const auto primitiveAssignment = std::min(static_cast<uint32_t>(projSizeFactor * value), primitiveCount);
		setOrUpdateAttribute(std::get<1>(primitiveCountNodeProjSizeTuple), attributeId, primitiveAssignment);
		value -= primitiveAssignment;
		projSizeSum -= projSize;
	}
}
//! ---|> Evaluator
void VisibilityEvaluator::measure(FrameContext & context,Node & node,const Geometry::Rect & /*r*/) {
	// first pass - fill depth buffer.
	context.getRenderingContext().clearScreen(Util::Color4f(0.9f, 0.9f, 0.9f, 1.0f));
	node.display(context,USE_WORLD_MATRIX|FRUSTUM_CULLING);

	if (getMaxValue()->toInt() == 0.0) {
		setMaxValue_i(collectNodes<GeometryNode>(&node).size());
	}

	if (mode==SINGLE_VALUE) {

		// collect geometry nodes in frustum
		auto objectsInVFList = collectNodesInFrustum<GeometryNode>(&node, context.getCamera()->getFrustum());
		for(const auto & geoNode : objectsInVFList) {
			objectsInVF[reinterpret_cast<uintptr_t>(geoNode)] = geoNode;
		}


		// setup occlusion queries
		int numQueries=objectsInVFList.size();
		if (numQueries==0) return;


		auto queries = new Rendering::OcclusionQuery[numQueries];

		{ // optional second pass: test bounding boxes
			context.getRenderingContext().pushAndSetDepthBuffer(Rendering::DepthBufferParameters(true, true, Rendering::Comparison::LEQUAL));
			context.getRenderingContext().pushAndSetPolygonOffset(Rendering::PolygonOffsetParameters(0.0f, -1.0f));
			int i=0;
			// start queries
			Rendering::OcclusionQuery::enableTestMode(context.getRenderingContext());
			for(const auto & geoNode : objectsInVFList) {
				queries[i].begin();
				Rendering::drawAbsBox(context.getRenderingContext(), geoNode->getWorldBB() );
				queries[i].end();
				++i;
			}
			Rendering::OcclusionQuery::disableTestMode(context.getRenderingContext());
			i=0;
			// get results
			for(auto & geoNode : objectsInVFList) {
				if (queries[i].getResult() == 0 && !geoNode->getWorldBB().contains(context.getCamera()->getWorldOrigin()) ) {
					geoNode=nullptr;
				}
				++i;
			}
			context.getRenderingContext().popPolygonOffset();
			context.getRenderingContext().popDepthBuffer();
		}


		{ // third pass: test if nodes are exactly visible
			context.getRenderingContext().pushAndSetDepthBuffer(Rendering::DepthBufferParameters(true, true, Rendering::Comparison::EQUAL));
			int i=0;
			// start queries
			for(const auto & geoNode : objectsInVFList) {
				if (!geoNode)
					continue;
				queries[i].begin();
				// render object i
				context.displayNode(geoNode, USE_WORLD_MATRIX);
				queries[i].end();
				++i;
			}
			i=0;
			// get results
			for(const auto & geoNode : objectsInVFList) {
				if (!geoNode)
					continue;
				if (queries[i].getResult() > 0) {
					visibleObjects[reinterpret_cast<uintptr_t>(geoNode)] = geoNode;
				}
				++i;
			}
			context.getRenderingContext().popDepthBuffer();
		}

		delete [] queries;
	} else {//mode == DIRECTION_VALUES
		const auto nodes = collectVisibleNodes(&node, context);
		if(doesCountPolygons()){
			uint32_t numPolys=0;
			for(const auto & n : nodes) {
				numPolys += n->getTriangleCount();
			}
			values->push_back(new Util::_NumberAttribute<float>(numPolys));
		}else{
			values->push_back(new Util::_NumberAttribute<float>(nodes.size()));
		}

	}
}
void ColorVisibilityEvaluator::measure(FrameContext & context, Node & node, const Geometry::Rect & rect) {
	Rendering::RenderingContext & rCtxt = context.getRenderingContext();

	// ### Set up textures for the framebuffer object. ###
	const uint32_t width = static_cast<uint32_t> (rect.getWidth());
	const uint32_t height = static_cast<uint32_t> (rect.getHeight());
	if (colorTexture == nullptr || width != static_cast<uint32_t> (colorTexture->getWidth()) || height != static_cast<uint32_t> (colorTexture->getHeight())) {
		// (Re-)Create textures with correct dimension.
		rCtxt.pushAndSetFBO(fbo.get());
		fbo->detachColorTexture(context.getRenderingContext());
		fbo->detachDepthTexture(context.getRenderingContext());
		rCtxt.popFBO();

		colorTexture = Rendering::TextureUtils::createStdTexture(width, height, true);
		depthTexture = Rendering::TextureUtils::createDepthTexture(width, height);

		// Bind textures to FBO.
		rCtxt.pushAndSetFBO(fbo.get());
		fbo->attachColorTexture(context.getRenderingContext(),colorTexture.get());
		fbo->attachDepthTexture(context.getRenderingContext(),depthTexture.get());
		rCtxt.popFBO();
	}

	// ### Render the scene into a framebuffer object. ###
	rCtxt.pushAndSetFBO(fbo.get());

	rCtxt.pushAndSetShader(getShader());
	rCtxt.clearScreen(Util::Color4f(0.0f, 0.0f, 0.0f, 0.0f));


	// Color counter for assignment of unique colors to triangles.
	// Background is black (color 0).
	int32_t currentColor = 1;


	// Collect potentially visible geometry nodes.
	const auto geoNodes = collectNodesInFrustum<GeometryNode>(&node, context.getCamera()->getFrustum());
	for(const auto & geoNode : geoNodes) {
		getShader()->setUniform(rCtxt, Rendering::Uniform("colorOffset", currentColor));
		context.displayNode(geoNode, USE_WORLD_MATRIX | NO_STATES);
		currentColor += geoNode->getTriangleCount();
	}

	rCtxt.popShader();
	rCtxt.popFBO();


	// ### Read texture and analyze colors. ###

	// Map from colors to number of occurrences.
	std::map<uint32_t, uint32_t> colorUsage;


	// Current color is compared with the previous color. If they match, the local count variable is used as cache before insertion into map is performed.
	uint32_t lastColor = 0;
	uint32_t lastCount = 0;

	colorTexture->downloadGLTexture(rCtxt);
	const uint32_t * texData = reinterpret_cast<const uint32_t *> (colorTexture->openLocalData(rCtxt));
	const uint32_t numPixels = width * height;
	for (uint_fast32_t p = 0; p < numPixels; ++p) {
		const uint32_t & color = texData[p];

		if (color == 0) {
			// Ignore background.
			continue;
		}

		if (color == lastColor) {
			++lastCount;
			continue;
		} else {
			// Insert previous color.
			if (lastColor != 0) {
				increaseColorUsage(lastColor, lastCount, colorUsage);
			}

			lastColor = color;
			lastCount = 1;
		}
	}
	if (lastColor != 0) {
		increaseColorUsage(lastColor, lastCount, colorUsage);
	}

	if (mode == SINGLE_VALUE) {
		numTrianglesVisible += colorUsage.size();
	} else {
		values->push_back(Util::GenericAttribute::createNumber(colorUsage.size()));
	}
}
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;
}