示例#1
0
/*!
 * Returns true if the \a m_nodetypeList contains the type of the element defined with \a sourceRow and \a sourceParent
 */
bool NodesFilterModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
{

	SceneModel* sceneModel = dynamic_cast< SceneModel* > ( sourceModel() );
	QModelIndex index = sceneModel->index(sourceRow, 0, sourceParent);

	InstanceNode* nodeInstance = sceneModel->NodeFromIndex( index );
	if( !nodeInstance )		return false;

	SoNode* node = nodeInstance->GetNode();
	if( !node )		return false;


	if( node->getTypeId().isDerivedFrom( TSeparatorKit::getClassTypeId() ) )	return ( true );
	if( node->getTypeId().isDerivedFrom( TShapeKit::getClassTypeId() ) )
	{
		if( m_shapeTypeList.count() < 1 )	return ( true );

		TShapeKit* shapeKit = static_cast< TShapeKit* >( node );
		if(!shapeKit)	return ( false );
		TShape* shape = static_cast< TShape* >( shapeKit->getPart( "shape", false ) );

		if( shape  &&  m_shapeTypeList.contains( shape->getTypeId().getName().getString() ) )
			return ( true );
	}


	return ( false );
}
/**
 * Creates a new group node insert command that adds a \a separatorKit to \a parentIndex node in the \a model.
 *
 * If \a parent is not null, this command is appended to parent's child list and then owns this command.
 */
CmdInsertSeparatorKit::CmdInsertSeparatorKit( TSeparatorKit* separatorKit,  const QModelIndex& parentIndex, SceneModel* model, QUndoCommand* parent )
: QUndoCommand("InsertSeparatorKit", parent), m_separatorKit ( separatorKit ), m_coinParent( 0 ), m_pModel( model ), m_row( -1 )
{
	if( !m_separatorKit ) gf::SevereError( "CmdInsertSeparatorKit Null separatorKit." );
	m_separatorKit->ref();

	if( !parentIndex.isValid() ) gf::SevereError( "CmdInsertSeparatorKit called with invalid ModelIndex." );
	InstanceNode* instanceParent = m_pModel->NodeFromIndex( parentIndex );
	m_coinParent = static_cast< SoBaseKit* > ( instanceParent->GetNode() );
}
示例#3
0
/**
 * Creates a new tracker insert command that adds a \a tracker to a parent node with \a parentIndex in the \a model.
 *
 * If \a parent is not null, this command is appended to parent's child list and then owns this command.
 */
CmdInsertTracker::CmdInsertTracker( TTracker* tracker,  const QModelIndex& parentIndex, SoSceneKit* scene, SceneModel* model, QUndoCommand* parent )
: QUndoCommand("Insert Tracker", parent), m_tracker ( tracker ), m_coinParent( 0 ), m_scene( scene ), m_pModel( model ), m_row( 0 )
{
	if( !m_tracker ) gf::SevereError( "CmdInsertTracker Null tracker." );
	m_tracker->ref();

	if( !parentIndex.isValid() ) gf::SevereError( "CmdInsertTracker called with invalid ModelIndex." );
	InstanceNode* instanceParent = m_pModel->NodeFromIndex( parentIndex );
	if( !instanceParent->GetNode() ) gf::SevereError( "CmdInsertTracker called with NULL parent node." );
	m_coinParent = static_cast< SoBaseKit* > ( instanceParent->GetNode() );
}
示例#4
0
/**
 * Creates a new cut command that represents the cut the node located with \a index from the \a model.
 * The node is stored at the \a clipborad.
 *
 * If \a parent is not null, this command is appended to parent's child list and then owns this command.
 */
CmdCut::CmdCut( const QModelIndex& selectedIndex, SoNode*& clipboard, SceneModel* model, QUndoCommand* parent )
: QUndoCommand("Cut", parent), m_pClipboard ( clipboard ), m_previousNode ( 0 ), m_coinNode( 0 ), m_coinParent( 0 ), m_pModel( model ), m_row ( -1 )
{
	InstanceNode* instanceNode = m_pModel->NodeFromIndex( selectedIndex );
	m_coinNode = instanceNode->GetNode();
	m_coinNode->ref();
	m_coinParent = static_cast< SoBaseKit* > (instanceNode->GetParent()->GetNode() );

	m_previousNode = clipboard ;

	m_row = instanceNode->GetParent()->children.indexOf( instanceNode );
}
/**
 * Creates a new analyzerkit insert command that adds a \a analyzerkit node to a node given with the \a parentIndex node in the \a model.
 *
 * If \a parent is not null, this command is appended to parent's child list and then owns this command.
 */
CmdInsertAnalyzerKit::CmdInsertAnalyzerKit( const QModelIndex& parentIndex, TAnalyzerKit* analyzerKit, SceneModel* model, QUndoCommand* parent )
    : QUndoCommand("InsertAnalyzerKit", parent), m_coinParent( 0 ), m_analyzerKit(analyzerKit), m_pModel(model), m_row( -1 )
{
    if( m_analyzerKit == 0 ) gf::SevereError( "CmdInsertAnalyzerKit called with NULL TAnalyzerKit*" );
    m_analyzerKit->ref();

    if( !parentIndex.isValid() ) gf::SevereError( "CmdInsertAnalyzerKit called with invalid ModelIndex." );
    InstanceNode* instanceParent = m_pModel->NodeFromIndex( parentIndex );
    if( !instanceParent->GetNode() ) gf::SevereError( "CmdInsertAnalyzerKit called with NULL parent node." );
    m_coinParent = static_cast< SoBaseKit* > ( instanceParent->GetNode() );

}
示例#6
0
/*
 * Returns the type of the surface
 */
QString FluxAnalysis::GetSurfaceType( QString nodeURL )
{
	QModelIndex nodeIndex = m_pCurrentSceneModel->IndexFromNodeUrl( nodeURL );
	if( !nodeIndex.isValid()  )		return QLatin1String( "" );

	InstanceNode* instanceNode = m_pCurrentSceneModel->NodeFromIndex( nodeIndex );
	if( !instanceNode || instanceNode == 0 )	return QLatin1String( "" );

	TShapeKit* shapeKit = static_cast< TShapeKit* > ( instanceNode->GetNode() );
	if( !shapeKit || shapeKit == 0 )	return QLatin1String( "" );

	TShape* shape = static_cast< TShape* >( shapeKit->getPart( "shape", false ) );
	if( !shape || shape == 0 )	return QLatin1String( "" );

	return ( shape->getTypeId().getName().getString() );
}
示例#7
0
/*
 * Fun flux analysis
 */
void FluxAnalysis::RunFluxAnalysis( QString nodeURL, QString surfaceSide, unsigned long nOfRays, bool increasePhotonMap, int heightDivisions, int widthDivisions )
{
	m_surfaceURL = nodeURL;
	m_surfaceSide = surfaceSide;

	//Delete a photonCounts
	if( m_photonCounts && m_photonCounts != 0 )
	{
		for( int h = 0; h < m_heightDivisions; h++ )
		{
			delete[] m_photonCounts[h];
		}

		delete[] m_photonCounts;
	}
	m_photonCounts = 0;
	m_heightDivisions = heightDivisions;
	m_widthDivisions = widthDivisions;

	//Check if there is a scene
	if ( !m_pCurrentScene )  return;

	//Check if there is a transmissivity defined
	TTransmissivity* transmissivity = 0;
	if ( !m_pCurrentScene->getPart( "transmissivity", false ) )	transmissivity = 0;
	else
		transmissivity = static_cast< TTransmissivity* > ( m_pCurrentScene->getPart( "transmissivity", false ) );

	//Check if there is a rootSeparator InstanceNode
	if( !m_pRootSeparatorInstance ) return;

	InstanceNode* sceneInstance = m_pRootSeparatorInstance->GetParent();
	if ( !sceneInstance )  return;

	//Check if there is a light and is properly configured
	if ( !m_pCurrentScene->getPart( "lightList[0]", false ) )return;
	TLightKit* lightKit = static_cast< TLightKit* >( m_pCurrentScene->getPart( "lightList[0]", false ) );

	InstanceNode* lightInstance = sceneInstance->children[0];
	if ( !lightInstance ) return;

	if( !lightKit->getPart( "tsunshape", false ) ) return;
	TSunShape* sunShape = static_cast< TSunShape * >( lightKit->getPart( "tsunshape", false ) );

	if( !lightKit->getPart( "icon", false ) ) return;
	TLightShape* raycastingSurface = static_cast< TLightShape * >( lightKit->getPart( "icon", false ) );

	if( !lightKit->getPart( "transform" ,false ) ) return;
	SoTransform* lightTransform = static_cast< SoTransform * >( lightKit->getPart( "transform" ,false ) );

	//Check if there is a random generator is defined.
	if( !m_pRandomDeviate || m_pRandomDeviate== 0 )	return;

	//Check if the surface and the surface side defined is suitable
	if( CheckSurface() == false || CheckSurfaceSide() == false ) return;

	//Create the photon map where photons are going to be stored
	if( !m_pPhotonMap  || !increasePhotonMap )
	{
		if( m_pPhotonMap ) 	m_pPhotonMap->EndStore( -1 );
		delete m_pPhotonMap;
		m_pPhotonMap = new TPhotonMap();
		m_pPhotonMap->SetBufferSize( HUGE_VAL );
		m_tracedRays = 0;
		m_wPhoton = 0;
		m_totalPower = 0;
	}

	QVector< InstanceNode* > exportSuraceList;
	QModelIndex nodeIndex = m_pCurrentSceneModel->IndexFromNodeUrl( m_surfaceURL );
	if( !nodeIndex.isValid()  )	return;

	InstanceNode* surfaceNode = m_pCurrentSceneModel->NodeFromIndex( nodeIndex );
	if( !surfaceNode || surfaceNode == 0 )	return;
	exportSuraceList.push_back( surfaceNode );

	//UpdateLightSize();
	TSeparatorKit* concentratorRoot = static_cast< TSeparatorKit* >( m_pCurrentScene->getPart( "childList[0]", false ) );
	if ( !concentratorRoot )	return;

	SoGetBoundingBoxAction* bbAction = new SoGetBoundingBoxAction( SbViewportRegion() ) ;
	concentratorRoot->getBoundingBox( bbAction );

	SbBox3f box = bbAction->getXfBoundingBox().project();
	delete bbAction;
	bbAction = 0;

	BBox sceneBox;
	if( !box.isEmpty() )
	{
		sceneBox.pMin = Point3D( box.getMin()[0], box.getMin()[1], box.getMin()[2] );
		sceneBox.pMax = Point3D( box.getMax()[0], box.getMax()[1], box.getMax()[2] );
		if( lightKit ) lightKit->Update( sceneBox );
	}

	m_pCurrentSceneModel->UpdateSceneModel();

	//Compute bounding boxes and world to object transforms
	trf::ComputeSceneTreeMap( m_pRootSeparatorInstance, Transform( new Matrix4x4 ), true );

	m_pPhotonMap->SetConcentratorToWorld( m_pRootSeparatorInstance->GetIntersectionTransform() );

	QStringList disabledNodes = QString( lightKit->disabledNodes.getValue().getString() ).split( ";", QString::SkipEmptyParts );
	QVector< QPair< TShapeKit*, Transform > > surfacesList;
	trf::ComputeFistStageSurfaceList( m_pRootSeparatorInstance, disabledNodes, &surfacesList );
	lightKit->ComputeLightSourceArea( m_sunWidthDivisions, m_sunHeightDivisions, surfacesList );
	if( surfacesList.count() < 1 )	return;

	QVector< long > raysPerThread;
	int maximumValueProgressScale = 100;

	unsigned long  t1 = nOfRays/ maximumValueProgressScale;
	for( int progressCount = 0; progressCount < maximumValueProgressScale; ++ progressCount )
		raysPerThread<< t1;

	if( ( t1 * maximumValueProgressScale ) < nOfRays )	raysPerThread<< ( nOfRays - ( t1* maximumValueProgressScale) );

	Transform lightToWorld = tgf::TransformFromSoTransform( lightTransform );
	lightInstance->SetIntersectionTransform( lightToWorld.GetInverse() );

	// Create a progress dialog.
	QProgressDialog dialog;
	dialog.setLabelText( QString("Progressing using %1 thread(s)..." ).arg( QThread::idealThreadCount() ) );

	// Create a QFutureWatcher and conncect signals and slots.
	QFutureWatcher< void > futureWatcher;
	QObject::connect(&futureWatcher, SIGNAL(finished()), &dialog, SLOT(reset()));
	QObject::connect(&dialog, SIGNAL(canceled()), &futureWatcher, SLOT(cancel()));
	QObject::connect(&futureWatcher, SIGNAL(progressRangeChanged(int, int)), &dialog, SLOT(setRange(int, int)));
	QObject::connect(&futureWatcher, SIGNAL(progressValueChanged(int)), &dialog, SLOT(setValue(int)));

	QMutex mutex;
	QMutex mutexPhotonMap;
	QFuture< void > photonMap;
	if( transmissivity )
		photonMap = QtConcurrent::map( raysPerThread, RayTracer( m_pRootSeparatorInstance,
							 lightInstance, raycastingSurface, sunShape, lightToWorld,
							 transmissivity,
							 *m_pRandomDeviate,
							 &mutex, m_pPhotonMap, &mutexPhotonMap,
							 exportSuraceList ) );
	else
		photonMap = QtConcurrent::map( raysPerThread, RayTracerNoTr( m_pRootSeparatorInstance,
						lightInstance, raycastingSurface, sunShape, lightToWorld,
						*m_pRandomDeviate,
						&mutex, m_pPhotonMap, &mutexPhotonMap,
						exportSuraceList ) );

	futureWatcher.setFuture( photonMap );

	// Display the dialog and start the event loop.
	dialog.exec();
	futureWatcher.waitForFinished();

	m_tracedRays += nOfRays;

	double irradiance = sunShape->GetIrradiance();
	double inputAperture = raycastingSurface->GetValidArea();
	m_wPhoton = double ( inputAperture * irradiance ) / m_tracedRays;

	UpdatePhotonCounts();
}
void ModelEntity::renderNode(const Node& node, const InstanceNode& instanceNode, float time, int32_t animStackIndex, int32_t animLayerIndex) const
{
	enum RenderFilter renderFilter = Entity::getRenderFilter();
	bool finalTransparent = (instanceNode.isTransparentActive() && instanceNode.isTransparent()) || (!instanceNode.isTransparentActive() && node.isTransparent());
	bool renderMesh = (renderFilter == RENDER_ALL) || (finalTransparent && renderFilter == RENDER_TRANSPARENT) || (!finalTransparent && renderFilter == RENDER_OPAQUE);

	if (isDebug())
	{
		if (node.getCamera().get())
		{
			node.getCamera()->debugDraw(instanceNode.getPosition(), instanceNode.getRotation(), true);
		}

		if (node.getLight().get())
		{
			node.getLight()->debugDraw(instanceNode.getPosition(), instanceNode.getRotation());
		}
	}

	if (isWireframe())
	{
		glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
	}

	if (node.getMesh().get() && renderMesh)
	{
		VAOSP currentVAO;
		ProgramSP currentProgram;
		SubMeshSP currentSubMesh;
		SurfaceMaterialSP currentSurfaceMaterial;

		const std::vector<std::shared_ptr<AnimationStack> >& allAnimStacks = node.getAllAnimStacks();

		for (uint32_t subMeshIndex = 0; subMeshIndex < node.getMesh()->getSubMeshesCount(); subMeshIndex++)
		{
			currentSubMesh = node.getMesh()->getSubMeshAt(subMeshIndex);

			if (subMeshIndex >= node.getMesh()->getSurfaceMaterialsCount())
			{
				break;
			}

			currentSurfaceMaterial = node.getMesh()->getSurfaceMaterialAt(subMeshIndex);

			float currentEmissive[4] = { 0.0f, 0.0f, 0.0f, 1.0f };
			float currentAmbient[4] = { 0.0f, 0.0f, 0.0f, 1.0f };
			float currentDiffuse[4] = { 0.0f, 0.0f, 0.0f, 1.0f };
			float currentSpecular[4] = { 0.0f, 0.0f, 0.0f, 1.0f };
			float currentReflection[4] = { 0.0f, 0.0f, 0.0f, 1.0f };
			float currentRefraction[4] = { 0.0f, 0.0f, 0.0f, 1.0f };
			float currentShininess = 0.0f;
			float currentTransparency = 0.0f;

			for (int32_t i = 0; i < 4; i++)
			{
				currentEmissive[i] = currentSurfaceMaterial->getEmissive().getRGBA()[i];
				currentAmbient[i] = currentSurfaceMaterial->getAmbient().getRGBA()[i];
				currentDiffuse[i] = currentSurfaceMaterial->getDiffuse().getRGBA()[i];
				currentSpecular[i] = currentSurfaceMaterial->getSpecular().getRGBA()[i];
				currentReflection[i] = currentSurfaceMaterial->getReflection().getRGBA()[i];
				currentRefraction[i] = currentSurfaceMaterial->getRefraction().getRGBA()[i];
			}
			currentShininess = currentSurfaceMaterial->getShininess();
			currentTransparency = currentSurfaceMaterial->getTransparency();

			if (animStackIndex >= 0 && animLayerIndex >= 0 && static_cast<decltype(allAnimStacks.size())>(animStackIndex) < allAnimStacks.size() && animLayerIndex < allAnimStacks[animStackIndex]->getAnimationLayersCount())
			{
				// Animate values depending on time
				const AnimationLayerSP& animLayer = allAnimStacks[animStackIndex]->getAnimationLayer(animLayerIndex);

				for (enum AnimationLayer::eCHANNELS_RGBA i = AnimationLayer::R; i <= AnimationLayer::A;
						i = static_cast<enum AnimationLayer::eCHANNELS_RGBA>(i + 1))
				{
					if (animLayer->hasEmissiveColorValue(i))
					{
						currentEmissive[i] = animLayer->getEmissiveColorValue(i, time);
					}
					if (animLayer->hasAmbientColorValue(i))
					{
						currentAmbient[i] = animLayer->getAmbientColorValue(i, time);
					}
					if (animLayer->hasDiffuseColorValue(i))
					{
						currentDiffuse[i] = animLayer->getDiffuseColorValue(i, time);
					}
					if (animLayer->hasSpecularColorValue(i))
					{
						currentSpecular[i] = animLayer->getSpecularColorValue(i, time);
					}
					if (animLayer->hasReflectionColorValue(i))
					{
						currentReflection[i] = animLayer->getReflectionColorValue(i, time);
					}
					if (animLayer->hasRefractionColorValue(i))
					{
						currentRefraction[i] = animLayer->getRefractionColorValue(i, time);
					}
				}

				if (animLayer->hasShininessValue(AnimationLayer::S))
				{
					currentShininess = animLayer->getShininessValue(AnimationLayer::S, time);
				}
				if (animLayer->hasTransparencyValue(AnimationLayer::S))
				{
					currentTransparency = animLayer->getTransparencyValue(AnimationLayer::S, time);
				}
			}

			currentVAO = currentSubMesh->getVAOByProgramType(getCurrentProgramType());

			currentProgram = currentVAO->getProgram();

			currentProgram->use();

			glUniformMatrix4fv(currentProgram->getUniformLocation(u_modelMatrix), 1, GL_FALSE, instanceNode.getModelMatrix().getM());

			// We have the inverse and transpose by setting the matrix
			glUniformMatrix3fv(currentProgram->getUniformLocation(u_normalModelMatrix), 1, GL_TRUE, instanceNode.getNormalModelMatrix().getM());

			currentVAO->bind();

			glUniform4fv(currentProgram->getUniformLocation(u_emissiveColor), 1, currentEmissive);
			glUniform4fv(currentProgram->getUniformLocation(u_ambientColor), 1, currentAmbient);

			if (currentSurfaceMaterial->getDiffuseTextureName() != 0)
			{
				glUniform1i(currentProgram->getUniformLocation(u_hasDiffuseTexture), 1);

				glActiveTexture(GL_TEXTURE0);
				glBindTexture(GL_TEXTURE_2D, currentSurfaceMaterial->getDiffuseTextureName());
				glUniform1i(currentProgram->getUniformLocation(u_diffuseTexture), 0);
			}
			else
			{
				glUniform1i(currentProgram->getUniformLocation(u_hasDiffuseTexture), 0);

				glActiveTexture(GL_TEXTURE0);
				glBindTexture(GL_TEXTURE_2D, 0);
				glUniform1i(currentProgram->getUniformLocation(u_diffuseTexture), 0);
			}
			glUniform4fv(currentProgram->getUniformLocation(u_diffuseColor), 1, currentDiffuse);

			if (currentSurfaceMaterial->getSpecularTextureName() != 0)
			{
				glUniform1i(currentProgram->getUniformLocation(u_hasSpecularTexture), 1);

				glActiveTexture(GL_TEXTURE1);
				glBindTexture(GL_TEXTURE_2D, currentSurfaceMaterial->getSpecularTextureName());
				glUniform1i(currentProgram->getUniformLocation(u_specularTexture), 1);
			}
			else
			{
				glUniform1i(currentProgram->getUniformLocation(u_hasSpecularTexture), 0);

				glActiveTexture(GL_TEXTURE1);
				glBindTexture(GL_TEXTURE_2D, 0);
				glUniform1i(currentProgram->getUniformLocation(u_specularTexture), 0);
			}
			glUniform4fv(currentProgram->getUniformLocation(u_specularColor), 1, currentSpecular);
			glUniform1f(currentProgram->getUniformLocation(u_shininess), currentShininess);

			glUniform1f(currentProgram->getUniformLocation(u_transparency), currentTransparency);

			if (currentSurfaceMaterial->getNormalMapTextureName() != 0)
			{
				glUniform1i(currentProgram->getUniformLocation(u_hasNormalMapTexture), 1);

				glActiveTexture(GL_TEXTURE2);
				glBindTexture(GL_TEXTURE_2D, currentSurfaceMaterial->getNormalMapTextureName());
				glUniform1i(currentProgram->getUniformLocation(u_normalMapTexture), 2);
				glActiveTexture(GL_TEXTURE0);
			}
			else
			{
				glUniform1i(currentProgram->getUniformLocation(u_hasNormalMapTexture), 0);

				glActiveTexture(GL_TEXTURE2);
				glBindTexture(GL_TEXTURE_2D, 0);
				glUniform1i(currentProgram->getUniformLocation(u_normalMapTexture), 2);
				glActiveTexture(GL_TEXTURE0);
			}

			glUniform1i(currentProgram->getUniformLocation(u_convertDirectX), currentSurfaceMaterial->isConvertDirectX());

			glUniform4fv(currentProgram->getUniformLocation(u_reflectionColor), 1, currentReflection);
			glUniform4fv(currentProgram->getUniformLocation(u_refractionColor), 1, currentRefraction);

			float environmentRefractiveIndex = refractiveIndex;

			if (environmentRefractiveIndex != RI_NOTHING)
			{
				float materialRefractiveIndex = currentSurfaceMaterial->getRefractiveIndex();

				float eta = environmentRefractiveIndex / materialRefractiveIndex;

				float reflectanceNormalIncidence = ((environmentRefractiveIndex - materialRefractiveIndex) * (environmentRefractiveIndex - materialRefractiveIndex)) / ((environmentRefractiveIndex + materialRefractiveIndex) * (environmentRefractiveIndex + materialRefractiveIndex));

				glUniform1f(currentProgram->getUniformLocation(u_eta), eta);
				glUniform1f(currentProgram->getUniformLocation(u_reflectanceNormalIncidence), reflectanceNormalIncidence);
			}
			else
			{
				glUniform1f(currentProgram->getUniformLocation(u_eta), 0.0f);
				glUniform1f(currentProgram->getUniformLocation(u_reflectanceNormalIncidence), 0.0f);
			}

			if (SkyManager::getInstance()->hasActiveSky())
			{
				glUniform1i(currentProgram->getUniformLocation(u_hasCubeMapTexture), 1);

				SkySP activeSky = SkyManager::getInstance()->getActiveSky();

				glActiveTexture(GL_TEXTURE3);
				glBindTexture(GL_TEXTURE_CUBE_MAP, activeSky->getSkyTextureName());
				glUniform1i(currentProgram->getUniformLocation(u_cubemap), 3);
				glActiveTexture(GL_TEXTURE0);
			}
			else
			{
				glUniform1i(currentProgram->getUniformLocation(u_hasCubeMapTexture), 0);

				glActiveTexture(GL_TEXTURE3);
				glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
				glUniform1i(currentProgram->getUniformLocation(u_cubemap), 3);
				glActiveTexture(GL_TEXTURE0);
			}

			// Only allow dynamic cube map, if also a sky cube map is available
			if (Entity::getDynamicCubeMaps() && currentSurfaceMaterial->getDynamicCubeMapTextureName() != 0 && SkyManager::getInstance()->hasActiveSky())
			{
				glUniform1i(currentProgram->getUniformLocation(u_hasDynamicCubeMapTexture), 1);
				glActiveTexture(GL_TEXTURE4);
				glBindTexture(GL_TEXTURE_CUBE_MAP, currentSurfaceMaterial->getDynamicCubeMapTextureName());
				glUniform1i(currentProgram->getUniformLocation(u_dynamicCubeMapTexture), 4);
				glActiveTexture(GL_TEXTURE0);
			}
			else
			{
				glUniform1i(currentProgram->getUniformLocation(u_hasDynamicCubeMapTexture), 0);
				glActiveTexture(GL_TEXTURE4);
				glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
				glUniform1i(currentProgram->getUniformLocation(u_dynamicCubeMapTexture), 4);
				glActiveTexture(GL_TEXTURE0);
			}

			if (!Entity::getDynamicCubeMaps())
			{
				glUniformMatrix4fv(currentProgram->getUniformLocation(u_cubeMapViewMatrix), 6, GL_FALSE, Entity::getCubeMapViewMatrices()[0].getM());
				glUniformMatrix4fv(currentProgram->getUniformLocation(u_cubeMapProjectionMatrix), 1, GL_FALSE, Entity::getCubeMapProjectionMatrix().getM());
			}

			// Skinning
			if (node.getMesh()->hasSkinning())
			{
				glUniform1i(currentProgram->getUniformLocation(u_hasSkinning), 1);

				glUniformMatrix4fv(currentProgram->getUniformLocation(u_bindMatrix), model->getNumberJoints(), GL_FALSE, bindMatrices[0].getM());
				glUniformMatrix3fv(currentProgram->getUniformLocation(u_bindNormalMatrix), model->getNumberJoints(), GL_TRUE, bindNormalMatrices[0].getM());

				glUniformMatrix4fv(currentProgram->getUniformLocation(u_inverseBindMatrix), model->getNumberJoints(), GL_FALSE, inverseBindMatrices[0].getM());
				glUniformMatrix3fv(currentProgram->getUniformLocation(u_inverseBindNormalMatrix), model->getNumberJoints(), GL_TRUE, inverseBindNormalMatrices[0].getM());
			}
			else
			{
				glUniform1i(currentProgram->getUniformLocation(u_hasSkinning), 0);

				glUniformMatrix4fv(currentProgram->getUniformLocation(u_bindMatrix), model->getNumberJoints(), GL_FALSE, Matrix4x4().getM());
				glUniformMatrix3fv(currentProgram->getUniformLocation(u_bindNormalMatrix), model->getNumberJoints(), GL_TRUE, Matrix3x3().getM());

				glUniformMatrix4fv(currentProgram->getUniformLocation(u_inverseBindMatrix), model->getNumberJoints(), GL_FALSE, Matrix4x4().getM());
				glUniformMatrix3fv(currentProgram->getUniformLocation(u_inverseBindNormalMatrix), model->getNumberJoints(), GL_TRUE, Matrix3x3().getM());
			}

			// Write bright color
			glUniform1i(currentProgram->getUniformLocation(u_writeBrightColor), writeBrightColor);
			glUniform1f(currentProgram->getUniformLocation(u_brightColorLimit), brightColorLimit);

			if (finalTransparent)
			{
				glEnable(GL_BLEND);
				glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
			}

			glDrawElements(GL_TRIANGLES, currentSubMesh->getTriangleCount() * 3, GL_UNSIGNED_INT, reinterpret_cast<const GLvoid *>(currentSubMesh->getIndicesOffset() * sizeof(uint32_t)));

			if (finalTransparent)
			{
				glDisable(GL_BLEND);
			}

			if (currentSurfaceMaterial->getDiffuseTextureName() != 0)
			{
				glActiveTexture(GL_TEXTURE0);
				glBindTexture(GL_TEXTURE_2D, 0);
			}

			if (currentSurfaceMaterial->getSpecularTextureName() != 0)
			{
				glActiveTexture(GL_TEXTURE1);
				glBindTexture(GL_TEXTURE_2D, 0);
			}

			if (currentSurfaceMaterial->getNormalMapTextureName() != 0)
			{
				glActiveTexture(GL_TEXTURE2);
				glBindTexture(GL_TEXTURE_2D, 0);
			}

			if (SkyManager::getInstance()->hasActiveSky())
			{
				glActiveTexture(GL_TEXTURE3);
				glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
			}

			if (currentSurfaceMaterial->getDynamicCubeMapTexture() != 0)
			{
				glActiveTexture(GL_TEXTURE4);
				glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
			}

			glActiveTexture(GL_TEXTURE0);

			currentVAO->unbind();
		}
	}

	if (isWireframe())
	{
		glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
	}
}