void CAddCameraController::onLMouseUp(int x, int y)
{
	IView *pView = getIView();
	ICameraSceneNode *cam = pView->getSceneMgr()->getActiveCamera();
		
	// get position
	core::vector3df hit;
	bool b = getPickPosition( &hit );
	
	if ( b )
	{
		core::vector3df camPos = cam->getAbsolutePosition();		
		core::line3df camRay( camPos, hit );

		if ( camRay.getLength() < 5000 )
		{
			CGameCamera *pObj =	pView->getCurrentZone()->createCamera();
			
			pObj->setPosition( hit );
			pObj->setVisible( true );

			// add history
			CHistoryManager::getInstance()->beginHistory();
			CHistoryManager::getInstance()->addHistoryCreateObj( pObj );
			CHistoryManager::getInstance()->endHistory();

		}
		else
			pView->alertError( L"Can not create object because is too far" );
	}
	else
		pView->alertError( L"Can not create object because is too far" );
}
예제 #2
0
//! render
void CBillboardSceneNode::render()
{
	video::IVideoDriver* driver = SceneManager->getVideoDriver();
	ICameraSceneNode* camera = SceneManager->getActiveCamera();

	if (!camera || !driver)
		return;

	// make billboard look to camera

	core::vector3df pos = getAbsolutePosition();

	core::vector3df campos = camera->getAbsolutePosition();
	core::vector3df target = camera->getTarget();
	core::vector3df up = camera->getUpVector();
	core::vector3df view = target - campos;
	view.normalize();

	core::vector3df horizontal = up.crossProduct(view);
	if ( horizontal.getLength() == 0 )
	{
		horizontal.set(up.Y,up.X,up.Z);
	}
	horizontal.normalize();
	horizontal *= 0.5f * Size.Width;

	core::vector3df vertical = horizontal.crossProduct(view);
	vertical.normalize();
	vertical *= 0.5f * Size.Height;

	view *= -1.0f;

	for (s32 i=0; i<4; ++i)
		vertices[i].Normal = view;

	vertices[0].Pos = pos + horizontal + vertical;
	vertices[1].Pos = pos + horizontal - vertical;
	vertices[2].Pos = pos - horizontal - vertical;
	vertices[3].Pos = pos - horizontal + vertical;

	// draw

	if (DebugDataVisible)
	{
		driver->setTransform(video::ETS_WORLD, AbsoluteTransformation);
		video::SMaterial m;
		m.Lighting = false;
		driver->setMaterial(m);
		driver->draw3DBox(BBox, video::SColor(0,208,195,152));
	}

	core::matrix4 mat;
	driver->setTransform(video::ETS_WORLD, mat);

	driver->setMaterial(Material);

	driver->drawIndexedTriangleList(vertices, 4, indices, 2);
}
bool CBaseAddController::getPickPosition( core::vector3df *pos )
{
	IView *pView = getIView();

	// move object
	core::line3df	ray = pView->getSelectRay();

	// check hit on terrain
	CDocument *pDoc = (CDocument*) pView->getDocument();
	ArrayZone* zones = pDoc->getAllZone();
	
	ArrayZoneIter i = zones->begin(), end = zones->end();
	while ( i != end )
	{
		core::vector3df		colPoint;
		core::triangle3df	colTri;
		float maxDistance = ray.getLengthSQ();

		if ( (*i)->getTerrainCollision( ray, maxDistance, colPoint, colTri ) == true )
		{
			*pos = colPoint;
			return true;
		}
		i++;
	}

	core::plane3df	plane( core::vector3df(0.0f, 0.0f, 0.0f), core::vector3df(0.0f, 1.0f, 0.0f) );
	
	// get position
	core::vector3df hit;
	bool b = plane.getIntersectionWithLine( ray.start, ray.getVector(), hit );
	
	if ( b )
	{
		ICameraSceneNode *cam = pView->getSceneMgr()->getActiveCamera();

		core::vector3df camPos = cam->getAbsolutePosition();		
		core::line3df camRay( camPos, hit );

		if ( camRay.getLength() < 5000 )
		{
			*pos = hit;
			return true;
		}
	}

	return false;
}
void CAddWaypointController::onLMouseUp	(int x, int y)
{
	IView *pView = getIView();
	ICameraSceneNode *cam = pView->getSceneMgr()->getActiveCamera();
		
	// get position
	core::vector3df hit;
	bool b = getPickPosition( &hit );
	
	if ( b )
	{
		core::vector3df camPos = cam->getAbsolutePosition();		
		core::line3df camRay( camPos, hit );

		if ( camRay.getLength() < 5000 )
		{
			CWayPoint *pObj =	pView->getCurrentZone()->createWaypoint();
			
			pObj->setPosition( hit );
			pObj->setVisible( true );

			// add history
			CHistoryManager* pHistory = CHistoryManager::createGetInstance();
			pHistory->beginHistory();
			pHistory->addHistoryCreateObj( pObj );

			if ( m_connect )
			{
				pHistory->addHistoryBeginModifyObj( m_connect );
				m_connect->setNext( pObj );
				pHistory->addHistoryEndModifyObj( m_connect );
				
				pHistory->addHistoryBeginModifyObj( pObj );
				pObj->setBack( m_connect );
				pHistory->addHistoryEndModifyObj( pObj );
			}
									
			pHistory->endHistory();

			m_connect = pObj;
		}
		else
			pView->alertError( L"Can not create object because is too far" );
	}
	else
		pView->alertError( L"Can not create object because is too far" );
}
예제 #5
0
//! pre render event
void CBillboardTextSceneNode::OnAnimate(u32 timeMs)
{
	if (!IsVisible || !Font || !Mesh)
		return;

	ICameraSceneNode* camera = SceneManager->getActiveCamera();
	if (!camera)
		return;

	// get text width
	f32 textLength = 0.f;
	u32 i;
	for(i=0; i!=Symbol.size(); ++i)
	{
		SSymbolInfo &info = Symbol[i];
		textLength += info.Kerning + info.Width;
	}
	if (textLength<0.0f)
		textLength=1.0f;

	//const core::matrix4 &m = camera->getViewFrustum()->Matrices[ video::ETS_VIEW ];

	// make billboard look to camera
	core::vector3df pos = getAbsolutePosition();

	core::vector3df campos = camera->getAbsolutePosition();
	core::vector3df target = camera->getTarget();
	core::vector3df up = camera->getUpVector();
	core::vector3df view = target - campos;
	view.normalize();

	core::vector3df horizontal = up.crossProduct(view);
	if ( horizontal.getLength() == 0 )
	{
		horizontal.set(up.Y,up.X,up.Z);
	}

	horizontal.normalize();
	core::vector3df space = horizontal;

	horizontal *= 0.5f * Size.Width;

	core::vector3df vertical = horizontal.crossProduct(view);
	vertical.normalize();
	vertical *= 0.5f * Size.Height;

	view *= -1.0f;

	// center text
	pos += space * (Size.Width * -0.5f);

	for ( i = 0; i!= Symbol.size(); ++i )
	{
		SSymbolInfo &info = Symbol[i];
		f32 infw = info.Width / textLength;
		f32 infk = info.Kerning / textLength;
		f32 w = (Size.Width * infw * 0.5f);
		pos += space * w;

		SMeshBuffer* buf = (SMeshBuffer*)Mesh->getMeshBuffer(info.bufNo);

		buf->Vertices[info.firstVert+0].Normal = view;
		buf->Vertices[info.firstVert+1].Normal = view;
		buf->Vertices[info.firstVert+2].Normal = view;
		buf->Vertices[info.firstVert+3].Normal = view;

		buf->Vertices[info.firstVert+0].Pos = pos + (space * w) + vertical;
		buf->Vertices[info.firstVert+1].Pos = pos + (space * w) - vertical;
		buf->Vertices[info.firstVert+2].Pos = pos - (space * w) - vertical;
		buf->Vertices[info.firstVert+3].Pos = pos - (space * w) + vertical;

		pos += space * (Size.Width*infk + w);
	}

	// make bounding box

	for (i=0; i< Mesh->getMeshBufferCount() ; ++i)
		Mesh->getMeshBuffer(i)->recalculateBoundingBox();
	Mesh->recalculateBoundingBox();

	BBox = Mesh->getBoundingBox();
	core::matrix4 mat( getAbsoluteTransformation(), core::matrix4::EM4CONST_INVERSE );
	mat.transformBoxEx(BBox);
}
		void CSSceneNodeAnimatorFPS::animateNode(ISceneNode* node, u32 timeMs)
		{
			if (!node || node->getType() != ESNT_CAMERA)
				return;

			ICameraSceneNode* camera = static_cast<ICameraSceneNode*>(node);

			if (firstUpdate)
			{
				camera->updateAbsolutePosition();
				if (CursorControl)
				{
					CursorControl->setPosition(m_CursorOffsetX, m_CursorOffsetY);
					CursorPos = CenterCursor = CursorControl->getRelativePosition();
				}

				LastAnimationTime = timeMs;

				firstUpdate = false;
			}

			// If the camera isn't the active camera, and receiving input, then don't process it.
			if (!camera->isInputReceiverEnabled())
			{
				firstInput = true;
				return;
			}

			if (firstInput)
			{
				allKeysUp();
				firstInput = false;
			}

			scene::ISceneManager * smgr = camera->getSceneManager();
			if (smgr && smgr->getActiveCamera() != camera)
				return;

			// get time
			f32 timeDiff = (f32)(timeMs - LastAnimationTime);
			LastAnimationTime = timeMs;

			// update position
			core::vector3df pos = camera->getPosition();

			// Update rotation
			core::vector3df target = (camera->getTarget() - camera->getAbsolutePosition());
			core::vector3df relativeRotation = target.getHorizontalAngle();

			if (CursorControl)
			{
				if (CursorPos != CenterCursor)
				{
					relativeRotation.Y -= (m_CursorOffsetX - CursorPos.X) * RotateSpeed;
					relativeRotation.X -= (m_CursorOffsetY - CursorPos.Y) * RotateSpeed * MouseYDirection;

					// X < MaxVerticalAngle or X > 360-MaxVerticalAngle

					if (relativeRotation.X > MaxVerticalAngle * 2 &&
						relativeRotation.X < 360.0f - MaxVerticalAngle)
					{
						relativeRotation.X = 360.0f - MaxVerticalAngle;
					}
					else
						if (relativeRotation.X > MaxVerticalAngle &&
							relativeRotation.X < 360.0f - MaxVerticalAngle)
						{
						relativeRotation.X = MaxVerticalAngle;
						}

					// Do the fix as normal, special case below
					// reset cursor position to the centre of the window.
					CursorControl->setPosition(m_CursorOffsetX, m_CursorOffsetY);
					CenterCursor = CursorControl->getRelativePosition();

					// needed to avoid problems when the event receiver is disabled
					CursorPos = CenterCursor;
				}

				// Special case, mouse is whipped outside of window before it can update.
				video::IVideoDriver* driver = smgr->getVideoDriver();
				core::vector2d<u32> mousepos(u32(CursorControl->getPosition().X), u32(CursorControl->getPosition().Y));
				core::rect<u32> screenRect(0, 0, driver->getScreenSize().Width, driver->getScreenSize().Height);

				// Only if we are moving outside quickly.
				bool reset = !screenRect.isPointInside(mousepos);

				if (reset)
				{
					// Force a reset.
					CursorControl->setPosition(m_CursorOffsetX, m_CursorOffsetY);
					CenterCursor = CursorControl->getRelativePosition();
					CursorPos = CenterCursor;
				}
			}

			// set target

			target.set(0, 0, core::max_(1.f, pos.getLength()));
			core::vector3df movedir = target;

			core::matrix4 mat;
			mat.setRotationDegrees(core::vector3df(relativeRotation.X, relativeRotation.Y, 0));
			mat.transformVect(target);

			if (NoVerticalMovement)
			{
				mat.setRotationDegrees(core::vector3df(0, relativeRotation.Y, 0));
				mat.transformVect(movedir);
			}
			else
			{
				movedir = target;
			}

			movedir.normalize();

			if (CursorKeys[EKA_MOVE_FORWARD])
				pos += movedir * timeDiff * MoveSpeed;

			if (CursorKeys[EKA_MOVE_BACKWARD])
				pos -= movedir * timeDiff * MoveSpeed;

			// strafing

			core::vector3df strafevect = target;
			strafevect = strafevect.crossProduct(camera->getUpVector());

			if (NoVerticalMovement)
				strafevect.Y = 0.0f;

			strafevect.normalize();

			if (CursorKeys[EKA_STRAFE_LEFT])
				pos += strafevect * timeDiff * MoveSpeed;

			if (CursorKeys[EKA_STRAFE_RIGHT])
				pos -= strafevect * timeDiff * MoveSpeed;

			// For jumping, we find the collision response animator attached to our camera
			// and if it's not falling, we tell it to jump.
			if (CursorKeys[EKA_JUMP_UP])
			{
				const ISceneNodeAnimatorList& animators = camera->getAnimators();
				ISceneNodeAnimatorList::ConstIterator it = animators.begin();
				while (it != animators.end())
				{
					if (ESNAT_COLLISION_RESPONSE == (*it)->getType())
					{
						ISceneNodeAnimatorCollisionResponse * collisionResponse =
							static_cast<ISceneNodeAnimatorCollisionResponse *>(*it);

						if (!collisionResponse->isFalling())
							collisionResponse->jump(JumpSpeed);
					}

					it++;
				}
			}

			// write translation
			camera->setPosition(pos);

			// write right target
			target += pos;
			camera->setTarget(target);
		}
예제 #7
0
//! render
void CParticleSystemSceneNode::render()
{
	video::IVideoDriver* driver = SceneManager->getVideoDriver();
	ICameraSceneNode* camera = SceneManager->getActiveCamera();

	if (!camera || !driver)
		return;


#if 0
	// calculate vectors for letting particles look to camera
	core::vector3df view(camera->getTarget() - camera->getAbsolutePosition());
	view.normalize();

	view *= -1.0f;

#else

	const core::matrix4 &m = camera->getViewFrustum()->getTransform( video::ETS_VIEW );

	const core::vector3df view ( -m[2], -m[6] , -m[10] );

#endif

	// reallocate arrays, if they are too small
	reallocateBuffers();

	// create particle vertex data
	s32 idx = 0;
	for (u32 i=0; i<Particles.size(); ++i)
	{
		const SParticle& particle = Particles[i];

		#if 0
			core::vector3df horizontal = camera->getUpVector().crossProduct(view);
			horizontal.normalize();
			horizontal *= 0.5f * particle.size.Width;

			core::vector3df vertical = horizontal.crossProduct(view);
			vertical.normalize();
			vertical *= 0.5f * particle.size.Height;

		#else
			f32 f;

			f = 0.5f * particle.size.Width;
			const core::vector3df horizontal ( m[0] * f, m[4] * f, m[8] * f );

			f = -0.5f * particle.size.Height;
			const core::vector3df vertical ( m[1] * f, m[5] * f, m[9] * f );
		#endif

		Buffer->Vertices[0+idx].Pos = particle.pos + horizontal + vertical;
		Buffer->Vertices[0+idx].Color = particle.color;
		Buffer->Vertices[0+idx].Normal = view;

		Buffer->Vertices[1+idx].Pos = particle.pos + horizontal - vertical;
		Buffer->Vertices[1+idx].Color = particle.color;
		Buffer->Vertices[1+idx].Normal = view;

		Buffer->Vertices[2+idx].Pos = particle.pos - horizontal - vertical;
		Buffer->Vertices[2+idx].Color = particle.color;
		Buffer->Vertices[2+idx].Normal = view;

		Buffer->Vertices[3+idx].Pos = particle.pos - horizontal + vertical;
		Buffer->Vertices[3+idx].Color = particle.color;
		Buffer->Vertices[3+idx].Normal = view;

		idx +=4;
	}

	// render all
	core::matrix4 mat;
	if (!ParticlesAreGlobal)
		mat.setTranslation(AbsoluteTransformation.getTranslation());
	driver->setTransform(video::ETS_WORLD, mat);

	driver->setMaterial(Buffer->Material);

	driver->drawVertexPrimitiveList(Buffer->getVertices(), Particles.size()*4,
		Buffer->getIndices(), Particles.size()*2, video::EVT_STANDARD, EPT_TRIANGLES,Buffer->getIndexType());

	// for debug purposes only:
	if ( DebugDataVisible & scene::EDS_BBOX )
	{
		driver->setTransform(video::ETS_WORLD, AbsoluteTransformation);
		video::SMaterial deb_m;
		deb_m.Lighting = false;
		driver->setMaterial(deb_m);
		driver->draw3DBox(Buffer->BoundingBox, video::SColor(0,255,255,255));
	}
}
void CSceneNodeAnimatorCameraFPS::animateNode(IDummyTransformationSceneNode* node, uint32_t timeMs)
{
	if (!node || node->getType() != ESNT_CAMERA)
		return;

	ICameraSceneNode* camera = static_cast<ICameraSceneNode*>(node);

	if (firstUpdate)
	{
		camera->updateAbsolutePosition();
		if (CursorControl )
		{
			CursorControl->setPosition(0.5f, 0.5f);
			CursorPos = CenterCursor = CursorControl->getRelativePosition();
		}

		LastAnimationTime = timeMs;

		firstUpdate = false;
	}

	// If the camera isn't the active camera, and receiving input, then don't process it.
	if(!camera->isInputReceiverEnabled())
	{
		firstInput = true;
		return;
	}

	if ( firstInput )
	{
		allKeysUp();
		firstInput = false;
	}

	scene::ISceneManager * smgr = camera->getSceneManager();
	if(smgr && smgr->getActiveCamera() != camera)
		return;

	// get time
	float timeDiff = (float) ( timeMs - LastAnimationTime );
	LastAnimationTime = timeMs;

	// update position
	core::vector3df pos = camera->getPosition();

	// Update rotation
	core::vector3df target = (camera->getTarget() - camera->getAbsolutePosition());
	core::vector3df relativeRotation = target.getHorizontalAngle();

	if (CursorControl)
	{
		if (CursorPos != CenterCursor)
		{
			relativeRotation.Y -= (0.5f - CursorPos.X) * RotateSpeed;
			relativeRotation.X -= (0.5f - CursorPos.Y) * RotateSpeed * MouseYDirection;

			// X < MaxVerticalAngle or X > 360-MaxVerticalAngle

			if (relativeRotation.X > MaxVerticalAngle*2 &&
				relativeRotation.X < 360.0f-MaxVerticalAngle)
			{
				relativeRotation.X = 360.0f-MaxVerticalAngle;
			}
			else
			if (relativeRotation.X > MaxVerticalAngle &&
				relativeRotation.X < 360.0f-MaxVerticalAngle)
			{
				relativeRotation.X = MaxVerticalAngle;
			}

			// Do the fix as normal, special case below
			// reset cursor position to the centre of the window.
			CursorControl->setPosition(0.5f, 0.5f);
			CenterCursor = CursorControl->getRelativePosition();

			// needed to avoid problems when the event receiver is disabled
			CursorPos = CenterCursor;
		}

		// Special case, mouse is whipped outside of window before it can update.
		video::IVideoDriver* driver = smgr->getVideoDriver();
		core::vector2d<uint32_t> mousepos(uint32_t(CursorControl->getPosition().X), uint32_t(CursorControl->getPosition().Y));
		core::rect<uint32_t> screenRect(0, 0, driver->getScreenSize().Width, driver->getScreenSize().Height);

		// Only if we are moving outside quickly.
		bool reset = !screenRect.isPointInside(mousepos);

		if(reset)
		{
			// Force a reset.
			CursorControl->setPosition(0.5f, 0.5f);
			CenterCursor = CursorControl->getRelativePosition();
			CursorPos = CenterCursor;
 		}
	}

	// set target

	target.set(0,0, core::max_(1.f, pos.getLength()));
	core::vector3df movedir = target;

	core::matrix4x3 mat;
	mat.setRotationDegrees(core::vector3df(relativeRotation.X, relativeRotation.Y, 0));
	mat.transformVect(&target.X);

	if (NoVerticalMovement)
	{
		mat.setRotationDegrees(core::vector3df(0, relativeRotation.Y, 0));
		mat.transformVect(&movedir.X);
	}
	else
	{
		movedir = target;
	}

	movedir.normalize();

	if (CursorKeys[EKA_MOVE_FORWARD])
		pos += movedir * timeDiff * MoveSpeed;

	if (CursorKeys[EKA_MOVE_BACKWARD])
		pos -= movedir * timeDiff * MoveSpeed;

	// strafing

	core::vector3df strafevect = target;
	strafevect = strafevect.crossProduct(camera->getUpVector());

	if (NoVerticalMovement)
		strafevect.Y = 0.0f;

	strafevect.normalize();

	if (CursorKeys[EKA_STRAFE_LEFT])
		pos += strafevect * timeDiff * MoveSpeed;

	if (CursorKeys[EKA_STRAFE_RIGHT])
		pos -= strafevect * timeDiff * MoveSpeed;

	// write translation
	camera->setPosition(pos);

	// write right target
	target += pos;
	camera->setTarget(target);
}
예제 #9
0
// registering the scene node for rendering, here we take the opportunity
// to make LOD adjustments to child nodes
void CLODSceneNode::OnRegisterSceneNode()
{
	//if this node is invisible forget any child nodes
	if (!IsVisible)
		return;

	// get a timer to calculate the amount to fade objects
	u32 time = device->getTimer()->getTime();

	// get the camera position
	ICameraSceneNode* cam = smgr->getActiveCamera();
	core::vector3df vectorCam = cam->getAbsolutePosition();

	// loop through all child nodes
	u32 i,j;
	u32 lod, fade;
	SMaterial * material;
	for (i=0; i < children.size(); ++i)
	{
		// get the node associated with this link
		SChildLink &child = children[i];
		IAnimatedMeshSceneNode *node = (IAnimatedMeshSceneNode *)child.node;

		// calculate the distance to the node. at the moment we do this the
		// slow linear way instead of using the distance squared method
		core::vector3df vectorNode = node->getAbsolutePosition();
		float distance = vectorNode.getDistanceFrom( vectorCam );

		// itterate through all of the LOD levels and find the lod distance
		// that is appropriate for this distance
		lod = 0xFFFFFFFF;
		for (j=0; j < lods.size(); ++j)
		{
			if ( distance >= lods[j].distance )
			{
				lod = j;
			}
		}

        // if a LOD level was found
		if ( lod != 0xFFFFFFFF )
		{
            // if this lod is associated with a mesh
            if ( lods[lod].mesh )
            {
                // if this lod differs from the child lod
                if ( lod != children[i].lod )
                {
                    children[i].lod = lod;

                    // if the node is an animated mesh node
                    if ( ( node->getType()) == ESNT_ANIMATED_MESH )
                    {
                        // set the new mesh to be used
                        node->setMeshClean( lods[lod].mesh );
                    }
                }
                // handle instances where the node is faded
                switch ( children[i].mode )
                {
                    case LOD_INVISIBLE:
                        // make the node visible
                        node->setVisible( true );
                        children[i].mode = LOD_FADE_IN;
                        children[i].fade = time;
                    break;

                    // we are partially faded we need to fade back in
                    case LOD_FADE_IN:
                        // fade the node in by 1 multiplied by the time passed
                        fade = (time - children[i].fade) / fadeScale;
                        if ( fade > 0xFF ) fade = 0xFF;

                        // if the node is fully opaque again
                        if ( fade == 0xFF )
                        {
                            // restore the origonal material type
                            node->setMaterialType(children[i].matType);
                            children[i].mode = LOD_OPAQUE;
                            if ( callback ) callback( true, node );
                        }

                        // fade the node through its materials
                        fade *= 0x01010101;
                        material = &node->getMaterial( 0 );
						if ( useAlpha )
						{
							material->DiffuseColor.set( fade );
							material->AmbientColor.set( fade );
						}
						else
						{
							material->DiffuseColor.set( fade & 0xFFFFFF );
							material->AmbientColor.set( fade & 0xFFFFFF );
						}

                    break;

					// we were in the process of fading out
					case LOD_FADE_OUT:
						children[i].fade = time - ( 0xFF * fadeScale - ( time - children[i].fade ));
						children[i].mode = LOD_FADE_IN;
					break;
                }
            }
			else
			{
                // we have a lod without a mesh, this is an instruction to fade
			    switch ( children[i].mode )
			    {
			        // the node is fully opaque start fading
			        case LOD_OPAQUE:
                        children[i].mode = LOD_FADE_OUT;
                        children[i].fade = time;

						// note the material type
                        children[i].matType = node->getMaterial(0).MaterialType;

						// set the material type based on mapping
						node->setMaterialType( matmap[children[i].matType] );
                    //break;

                    // the node is in the process of fading
                    case LOD_FADE_OUT:
                        // fade the node out by 1 multiplied by the time passed
                        fade = (time - children[i].fade) / fadeScale;
                        if ( fade > 0xFF ) fade = 0xFF;

                        // if the node is fully transparent
                        if ( fade == 0xFF )
                        {
                            // make it completely invisible
                            node->setVisible( false );
                            children[i].mode = LOD_INVISIBLE;
                            if ( callback ) callback( false, node );
                        }

                        // fade the node through its materials
						fade *= 0x01010101;
                        fade = 0xFFFFFFFF - fade;
                        material = &node->getMaterial( 0 );
						if ( useAlpha )
						{
							material->DiffuseColor.set( fade );
							material->AmbientColor.set( fade );
						}
						else
						{
							material->DiffuseColor.set( fade & 0xFFFFFF );
							material->AmbientColor.set( fade & 0xFFFFFF );
						}

                    break;

					// we were in the process of fading in
					case LOD_FADE_IN:
						children[i].fade = time - ( 0xFF * fadeScale - ( time - children[i].fade ));
						children[i].mode = LOD_FADE_OUT;
					break;
			    } // switch
			}
		}
		else
		{
            // handle instances where the node is faded
            switch ( children[i].mode )
            {
                case LOD_INVISIBLE:
                    // make the node visible
                    node->setVisible( true );
                    children[i].mode = LOD_FADE_IN;
                    children[i].fade = time;
                    if ( callback ) callback( true, node );
                break;

                // we are partially faded we need to fade back in
                case LOD_FADE_IN:
                    // fade the node in by 1 multiplied by the time passed
                    fade = (time - children[i].fade) / fadeScale;
                    if ( fade > 255 ) fade = 255;

                    // if the node is fully opaque again
                    if ( fade == 0xFF )
                    {
                        // restore the origonal material type
                        node->setMaterialType(children[i].matType);
                        children[i].mode = LOD_OPAQUE;
                    }

                    // fade the node through its materials
					fade *= 0x01010101;
                    material = &node->getMaterial( 0 );
					if ( useAlpha )
					{
						material->DiffuseColor.set( fade );
						material->AmbientColor.set( fade );
					}
					else
					{
						material->DiffuseColor.set( fade & 0xFFFFFF );
						material->AmbientColor.set( fade & 0xFFFFFF );
					}

                break;

				// we were in the process of fading out
				case LOD_FADE_OUT:
					children[i].fade = time - ( 0xFF * fadeScale - ( time - children[i].fade ));
					children[i].mode = LOD_FADE_IN;
				break;
            }
		}
	}

	ISceneNode::OnRegisterSceneNode();
}
void CSceneNodeAnimatorCameraFPS::animateNode(ISceneNode* node, u32 timeMs)
{
	if (node->getType() != ESNT_CAMERA)
		return;

	ICameraSceneNode* camera = static_cast<ICameraSceneNode*>(node);

	if (firstUpdate)
	{
		camera->updateAbsolutePosition();
		if (CursorControl && camera)
		{
			CursorControl->setPosition(0.5f, 0.5f);
			CursorPos = CenterCursor = CursorControl->getRelativePosition();
		}

		LastAnimationTime = timeMs;

		firstUpdate = false;
	}

	// get time
	f32 timeDiff = (f32) ( timeMs - LastAnimationTime );
	LastAnimationTime = timeMs;

	// update position
	core::vector3df pos = camera->getPosition();

	// Update rotation
	core::vector3df target = (camera->getTarget() - camera->getAbsolutePosition());
	core::vector3df relativeRotation = target.getHorizontalAngle();

	if (CursorControl)
	{
		if (CursorPos != CenterCursor)
		{
			relativeRotation.Y -= (0.5f - CursorPos.X) * RotateSpeed;
			relativeRotation.X -= (0.5f - CursorPos.Y) * RotateSpeed;

			// X < MaxVerticalAngle or X > 360-MaxVerticalAngle

			if (relativeRotation.X > MaxVerticalAngle*2 &&
				relativeRotation.X < 360.0f-MaxVerticalAngle)
			{
				relativeRotation.X = 360.0f-MaxVerticalAngle;
			}
			else
			if (relativeRotation.X > MaxVerticalAngle &&
				relativeRotation.X < 360.0f-MaxVerticalAngle)
			{
				relativeRotation.X = MaxVerticalAngle;
			}

			// reset cursor position
			CursorControl->setPosition(0.5f, 0.5f);
			CenterCursor = CursorControl->getRelativePosition();
			// needed to avoid problems when the ecent receiver is
			// disabled
			CursorPos = CenterCursor;
		}
	}

	// set target

	target.set(0,0, core::max_(1.f, pos.getLength()));
	core::vector3df movedir = target;

	core::matrix4 mat;
	mat.setRotationDegrees(core::vector3df(relativeRotation.X, relativeRotation.Y, 0));
	mat.transformVect(target);

	if (NoVerticalMovement)
	{
		mat.setRotationDegrees(core::vector3df(0, relativeRotation.Y, 0));
		mat.transformVect(movedir);
	}
	else
	{
		movedir = target;
	}

	movedir.normalize();

	if (CursorKeys[EKA_MOVE_FORWARD])
		pos += movedir * timeDiff * MoveSpeed;

	if (CursorKeys[EKA_MOVE_BACKWARD])
		pos -= movedir * timeDiff * MoveSpeed;

	// strafing

	core::vector3df strafevect = target;
	strafevect = strafevect.crossProduct(camera->getUpVector());

	if (NoVerticalMovement)
		strafevect.Y = 0.0f;

	strafevect.normalize();

	if (CursorKeys[EKA_STRAFE_LEFT])
		pos += strafevect * timeDiff * MoveSpeed;

	if (CursorKeys[EKA_STRAFE_RIGHT])
		pos -= strafevect * timeDiff * MoveSpeed;

	// For jumping, we find the collision response animator attached to our camera
	// and if it's not falling, we tell it to jump.
	if (CursorKeys[EKA_JUMP_UP])
	{
		const core::list<ISceneNodeAnimator*> & animators = camera->getAnimators();
		core::list<ISceneNodeAnimator*>::ConstIterator it = animators.begin();
		while(it != animators.end())
		{
			if(ESNAT_COLLISION_RESPONSE == (*it)->getType())
			{
				ISceneNodeAnimatorCollisionResponse * collisionResponse = 
					static_cast<ISceneNodeAnimatorCollisionResponse *>(*it);

				if(!collisionResponse->isFalling())
					collisionResponse->jump(JumpSpeed);
			}

			it++;
		}
	}

	// write translation
	camera->setPosition(pos);

	// write right target

	TargetVector = target;
	target += pos;
	camera->setTarget(target);
}
예제 #11
0
/* Every time it gets drawn, this function gets called */
void CLensFlareSceneNode::render()
{
	video::IVideoDriver* driver = SceneManager->getVideoDriver();
	ICameraSceneNode* camera = SceneManager->getActiveCamera();

	// Bail out if function dosn't have enough info
	// Will fail here if no textures supplied
	if (!camera || !driver || !Material.getTexture(0))
		return;

	driver->setTransform(video::ETS_WORLD, core::matrix4());
	const core::vector3df campos = camera->getAbsolutePosition();
	const core::dimension2d<u32> sz = SceneManager->getVideoDriver()->getScreenSize();
	const core::vector2df mid = core::vector2df((f32)sz.Width, (f32)sz.Height) * 0.5f;

	const core::position2di lp = SceneManager->getSceneCollisionManager()->
			getScreenCoordinatesFrom3DPosition(getAbsolutePosition(), camera);

	const core::vector2df lightpos = core::vector2df((f32)lp.X, (f32)lp.Y);

	const u32 nframes = Material.getTexture(0)->getOriginalSize().Width /
			Material.getTexture(0)->getOriginalSize().Height;
	int texw = 8;
	float texp = 1.0f / nframes;

	core::vector3df target = camera->getTarget();
	core::vector3df up = camera->getUpVector();
	core::vector3df view = target - campos;
	view.normalize();
	core::vector3df horizontal = up.crossProduct(view);
	horizontal.normalize();
	core::vector3df vertical;
	vertical = horizontal.crossProduct(view);
	vertical.normalize();
	view *= -1.0f;
	for (u32 i=0; i<4; ++i)
		vertices[i].Normal = view;
	driver->setMaterial(Material);
	core::vector3df pos;

    core::vector3df hor;
    core::vector3df ver;


	for (u32 ax = 0; ax < nframes; ++ax)
	{
		if (ax == 0 )
		{
			pos = getAbsolutePosition();
			texw = Material.getTexture(0)->getSize().Height;

            hor = horizontal * (sourceScale * texw);
            ver = vertical   * (sourceScale * texw);
		}
		else
		{
			core::vector2df ipos = mid.getInterpolated(lightpos, (2.0f / nframes) * ax);

			pos = SceneManager->getSceneCollisionManager()->getRayFromScreenCoordinates(
					core::position2d<s32>(int(ipos.X ), int(ipos.Y ) ), camera).end;
			core::vector3df dir = core::vector3df(campos - pos).normalize();
			pos = campos + (dir * -10.0f);
			texw = 4;

            hor = horizontal * (opticsScale * texw);
            ver = vertical   * (opticsScale * texw);
		}

		vertices[0].TCoords.set(   ax * texp,  1.0f);
		vertices[1].TCoords.set(   ax * texp,  0.0f);
		vertices[2].TCoords.set((ax+1) * texp, 0.0f);
		vertices[3].TCoords.set((ax+1) * texp, 1.0f);

		vertices[0].Pos = pos + hor + ver;
		vertices[1].Pos = pos + hor - ver;
		vertices[2].Pos = pos - hor - ver;
		vertices[3].Pos = pos - hor + ver;

		driver->drawIndexedTriangleList(vertices, 4, indices, 2);
	}
}
//! render
void CParticleSystemSceneNode::render()
{
	video::IVideoDriver* driver = SceneManager->getVideoDriver();
	ICameraSceneNode* camera = SceneManager->getActiveCamera();

	if (!camera || !driver)
		return;

	// calculate vectors for letting particles look to camera
	core::vector3df campos = camera->getAbsolutePosition();
	core::vector3df target = camera->getTarget();
	core::vector3df up = camera->getUpVector();
	core::vector3df view = target - campos;
	view.normalize();

	core::vector3df horizontal = up.crossProduct(view);
	horizontal.normalize();

	core::vector3df vertical = horizontal.crossProduct(view);
	vertical.normalize();

	horizontal *= 0.5f * ParticleSize.Width;
	vertical *= 0.5f * ParticleSize.Height;	

	view *= -1.0f;

	// reallocate arrays, if they are too small
	reallocateBuffers();

	// create particle vertex data
	for (u32 i=0; i<Particles.size(); ++i)
	{
		const SParticle& particle = Particles[i];

		s32 idx = i*4;

		Vertices[0+idx].Pos = particle.pos + horizontal + vertical;
		Vertices[0+idx].Color = particle.color;
		Vertices[0+idx].Normal = view;

		Vertices[1+idx].Pos = particle.pos + horizontal - vertical;
		Vertices[1+idx].Color = particle.color;
		Vertices[1+idx].Normal = view;

		Vertices[2+idx].Pos = particle.pos - horizontal - vertical;
		Vertices[2+idx].Color = particle.color;
		Vertices[2+idx].Normal = view;

		Vertices[3+idx].Pos = particle.pos - horizontal + vertical;
		Vertices[3+idx].Color = particle.color;
		Vertices[3+idx].Normal = view;
	}

	// render all 
	core::matrix4 mat;
	if (!ParticlesAreGlobal)
		mat.setTranslation(AbsoluteTransformation.getTranslation());
	driver->setTransform(video::ETS_WORLD, mat);
		

	driver->setMaterial(Material);

	driver->drawIndexedTriangleList(Vertices.pointer(), Particles.size()*4,
		Indices.pointer(), Particles.size()*2);

	// for debug purposes only:
	if (DebugDataVisible)
	{
		driver->setTransform(video::ETS_WORLD, AbsoluteTransformation);
		video::SMaterial m;
		m.Lighting = false;
		driver->setMaterial(m);
		driver->draw3DBox(Box, video::SColor(0,255,255,255));
	}
}
예제 #13
0
void CImpostorSceneNode::renderNode(SNodeLink& Imp)
{
	ISceneNode* n = Imp.Node;

	updatePosAndVector(Imp);

	// remember old viewport and render target
	core::rect<s32> oldView = SceneManager->getVideoDriver()->getViewPort();

	if (!oldView.isRectCollided(Imp.NewPos))
		return;

	ICameraSceneNode* cam = SceneManager->getActiveCamera();
	cam->updateAbsolutePosition();

	core::vector3df camP = cam->getAbsolutePosition();
	f32 distance = camP.getDistanceFrom(n->getTransformedBoundingBox().getCenter());

	// project into screen

	core::vector3df pUL = SceneManager->getSceneCollisionManager()->getRayFromScreenCoordinates(Imp.NewPos.UpperLeftCorner, cam).getVector();
	pUL.setLength(distance);
	core::vector3df pLR = SceneManager->getSceneCollisionManager()->getRayFromScreenCoordinates(Imp.NewPos.LowerRightCorner, cam).getVector();
	pLR.setLength(distance);
	core::vector3df pUR = SceneManager->getSceneCollisionManager()->getRayFromScreenCoordinates(core::position2di(Imp.NewPos.LowerRightCorner.X, Imp.NewPos.UpperLeftCorner.Y), cam).getVector();
	pUR.setLength(distance);
	core::vector3df pLL = SceneManager->getSceneCollisionManager()->getRayFromScreenCoordinates(core::position2di(Imp.NewPos.UpperLeftCorner.X, Imp.NewPos.LowerRightCorner.Y), cam).getVector();
	pLL.setLength(distance);

	Imp.BilPos1 = camP + pUL;
	Imp.BilPos2 = camP + pLR;
	Imp.BilPos3 = camP + pUR;
	Imp.BilPos4 = camP + pLL;

	// translate and scale, but don't rotate
	core::matrix4 invMat = n->getAbsoluteTransformation();
	invMat.makeInverse();
	Imp.BilPos1 *= invMat.getScale();
	invMat.translateVect(Imp.BilPos1);
	Imp.BilPos2 *= invMat.getScale();
	invMat.translateVect(Imp.BilPos2);
	Imp.BilPos3 *= invMat.getScale();
	invMat.translateVect(Imp.BilPos3);
	Imp.BilPos4 *= invMat.getScale();
	invMat.translateVect(Imp.BilPos4);

	Imp.ScreenPos = Imp.NewPos;
	Imp.RotVec = Imp.NewVec;
	video::ITexture* rt = 0; // SceneManager->getVideoDriver()->getRenderTarget();

	// set up the camera and viewport for rendering
	ISceneManager* oldManager = n->getSceneManager();

	// set up the camera
	ICameraSceneNode* cam2= LocalManager->getActiveCamera();

	cam2->setPosition(cam->getAbsolutePosition());

	core::vector3df v = n->getTransformedBoundingBox().getCenter();
	cam2->setUpVector(cam->getUpVector());
	cam2->setTarget(cam->getTarget());
	cam2->updateAbsolutePosition();

	f32 scaleW = f32(oldView.getWidth()) / f32(Imp.ScreenPos.getWidth());
	f32 scaleH = f32(oldView.getHeight()) / f32(Imp.ScreenPos.getHeight());

	//f32 transW = f32(Impostors[i].ScreenPos.getWidth()/2) / (f32(oldView.getWidth()) - f32(Impostors[i].ScreenPos.getCenter().X));
	//f32 transH = f32(Impostors[i].ScreenPos.getHeight()/2) / (f32(oldView.getHeight()) - f32(Impostors[i].ScreenPos.getCenter().X));

	f32 transW = (f32(oldView.getCenter().X) - f32(Imp.ScreenPos.getCenter().X)) / f32(Imp.ScreenPos.getWidth());
	f32 transH = (f32(oldView.getCenter().Y) -  f32(Imp.ScreenPos.getCenter().Y)) / f32(Imp.ScreenPos.getHeight());

	core::matrix4 proj(cam->getProjectionMatrix());
	core::matrix4 zoom, trans;

	Imp.Time = Timer->getRealTime();

	zoom.setScale(core::vector3df(scaleW, scaleH, 1.0));
	trans.setTranslation(core::vector3df(transW*2,-transH*2,0.0));


	proj = zoom * proj;
#if defined(GENERATE_METHOD_1)
	proj = trans * proj;
#endif




	// set the correct render target and viewport
	setTarget(Imp);

	// draw the scene
	cam2->setProjectionMatrix(proj);
	E_CULLING_TYPE culltype = EAC_FRUSTUM_BOX;
	n->setAutomaticCulling(EAC_OFF);
	//cam2->render();
//	n->setSceneManager(LocalManager);
	n->OnRegisterSceneNode();
	LocalManager->drawAll();

	n->setAutomaticCulling(culltype);

	//s32 numberzzz = LocalManager->getParameters()->getAttributeAsInt("culled");

	// copy work buffer back
	s32 slot = Buffers[Imp.BufferID].SlotSize;
	//SceneManager->getGUIEnvironment()->getBuiltInFont()->draw(L"HI THERE!", core::rect<s32>(0, 0, slot, slot), video::SColor(), true, true);
	SceneManager->getVideoDriver()->setRenderTarget(Buffers[ Imp.BufferID].Texture, false, true);
	//SceneManager->getVideoDriver()->setRenderTarget(0);



	//LocalManager->getVideoDriver()->setViewPort( core::rect<s32>(0,0,TextureWidth,TextureWidth) );

	s32 d = TextureWidth / slot;
	s32 x = (Imp.SlotID % d) * slot;
	s32 y = (Imp.SlotID / d) * slot;

	//LocalManager->getVideoDriver()->setViewPort( core::rect<s32>(0,0,TextureWidth,TextureWidth) );
/*
	SceneManager->getVideoDriver()->draw2DRectangle(
		video::SColor(127,0,0,0),
		core::rect<s32>(x,y,x+slot,y+slot));
	SceneManager->getVideoDriver()->draw2DRectangle(
		video::SColor(100,0,0,0),
		core::rect<s32>(x,y,x+slot,y+slot));
	SceneManager->getVideoDriver()->draw2DRectangle(
		video::SColor(100,0,0,0),
		core::rect<s32>(x,y,x+slot,y+slot));
*/
	//SceneManager->getVideoDriver()->setTransform

	core::rect<s32> clipRect(x,y, x+slot,y+slot);

	video::SMaterial m;
	m.MaterialTypeParam =video::pack_texureBlendFunc(video::EBF_ONE, video::EBF_ONE_MINUS_DST_ALPHA, video::EMFN_MODULATE_1X);
	m.MaterialType = video::EMT_ONETEXTURE_BLEND;
	m.Lighting=false;
	m.ZBuffer = false;
	m.ZWriteEnable = false;
	m.TextureLayer[0].TextureWrapU = video::ETC_CLAMP;
	m.setTexture(0, WorkTexture);

	video::S3DVertex Vertices[6];

	Vertices[0] = video::S3DVertex(-1.0f, -1.0f, 0.0f,1,1,0, video::SColor(255,255,255,255), 0.0f, YDirection);
	Vertices[1] = video::S3DVertex(-1.0f,  1.0f, 0.0f,1,1,0, video::SColor(255,255,255,255), 0.0f, 0.0f);
	Vertices[2] = video::S3DVertex( 1.0f,  1.0f, 0.0f,1,1,0, video::SColor(255,255,255,255), 1.0f, 0.0f);
	Vertices[3] = video::S3DVertex( 1.0f, -1.0f, 0.0f,1,1,0, video::SColor(255,255,255,255), 1.0f, YDirection);
	Vertices[4] = video::S3DVertex(-1.0f, -1.0f, 0.0f,1,1,0, video::SColor(255,255,255,255), 0.0f, YDirection);
	Vertices[5] = video::S3DVertex( 1.0f,  1.0f, 0.0f,1,1,0, video::SColor(255,255,255,255), 1.0f, 0.0f);

	const u16 i1[] = {0,1,2,3,4,5};
	const u16 i2[] = {0,2,1,3,5,4};
	const u16* indices = i1;

	core::matrix4 matrix, matrix2;
	if (YDirection == -1.0f)
	{
		matrix2.setScale(core::vector3df(1.0f,-1.0f,1.0f));
		indices = i2;
	}
	LocalManager->getVideoDriver()->setViewPort( clipRect );
	LocalManager->getVideoDriver()->setMaterial(m);
	SceneManager->getVideoDriver()->setTransform(video::ETS_WORLD, matrix);
	SceneManager->getVideoDriver()->setTransform(video::ETS_PROJECTION, matrix2);
	SceneManager->getVideoDriver()->setTransform(video::ETS_VIEW, matrix);
	SceneManager->getVideoDriver()->drawIndexedTriangleList(&Vertices[0], 6, &indices[0], 2);
	LocalManager->getVideoDriver()->setViewPort(core::rect<s32>(0,0,TextureWidth, TextureWidth));

	//SceneManager->getVideoDriver()->draw2DImage(
	//	WorkTexture,
	//	core::position2di(x,y),
	//	core::rect<s32>(0,0,slot, slot),
	//	&clipRect,
	//	video::SColor(255,255,255,255),true);

	if (DebugDataVisible & EDS_IMPOSTOR_INFO && DebugFont)
	{
		core::stringw text;
		video::SColor col(255,255,0,0);
		core::rect<s32> clip(x, y, x+slot, 0);
		s32 third = s32(f32(slot)*0.5f);

		text=L"Buf: "; text+=Imp.BufferID;
		clip.UpperLeftCorner.Y = y+third;
		clip.LowerRightCorner.Y = y+ third*2;
		DebugFont->draw(text.c_str(), clip, col, true, true, &clip);

		text=L"Region: "; text+=Imp.SlotID;
		clip.UpperLeftCorner.Y = y+third*2;
		clip.LowerRightCorner.Y = y+slot;
		DebugFont->draw(text.c_str(), clip, col, true, true, &clip);
	}


	//core::rect<s32> blaView = SceneManager->getVideoDriver()->getViewPort();

	//SceneManager->getVideoDriver()->setTransform(video::ETS_WORLD, n->getAbsoluteTransformation());
	//SceneManager->getVideoDriver()->draw3DBox(n->getBoundingBox());

	// restore states
	SceneManager->getVideoDriver()->setRenderTarget(0, false, false);
	LocalManager->getVideoDriver()->setViewPort(oldView);

//	n->setSceneManager(oldManager);
}
예제 #14
0
void CImpostorSceneNode::OnRegisterSceneNode()
{
	if (!IsVisible)
		return;

	RenderCount++;

	// in here we:
	// decide which nodes need updates, add them to the queue
	// process the render queue
	//  allocate textures and mesh buffers if required
	// perform clean up tasks:
	//  garbage collection- free up spaces
	//  reorganise


	// get collision manager
	ISceneCollisionManager* colmgr = SceneManager->getSceneCollisionManager();

	// and the active camera
	ICameraSceneNode* cam = SceneManager->getActiveCamera();
	core::aabbox3df camBB = cam->getViewFrustum()->getBoundingBox();
	u32 now = Timer->getRealTime();

	// loop through all impostor nodes
	u32 i;
	for (i=0; i < Impostors.size(); ++i)
	{
		SNodeLink &Imp = Impostors[i];
		ISceneNode *n = Imp.Node;

		// skip invisible and culled nodes
		if (!n->isVisible() || !camBB.intersectsWithBox(n->getTransformedBoundingBox()))
		{
			//Culled++;
			Imp.IsActive = false;
			continue;
		}

		updatePosAndVector(Imp);

		// now we have the screen position...
		core::rect<s32> r = SceneManager->getVideoDriver()->getViewPort();

		if (!Imp.NewPos.isValid() || !r.isRectCollided(Imp.NewPos) )
		{
			// culled
			// Culled++;
			continue;
		}

		core::dimension2di newSize = Imp.NewPos.getSize();

		// Change in rotation: a.length >= a.dotProduct(b) <= -a.length
		f32 diff = 0;

		// far plane = never update, near plane = always update
		f32 far = cam->getFarValue();
		far *= far;
		f32 dist = Imp.Node->getAbsolutePosition().getDistanceFromSQ(cam->getAbsolutePosition());
		dist = 1.0 - (far/dist); // value between 0 and 1
		diff = dist;
		Imp.Score = dist;

		//s32 a = core::max_<s32>(Imp.NewPos.getWidth(), Imp.NewPos.getHeight());
		//diff *= f32(a);

		bool reRender = diff > Threshold;
		//reRender =true;

		reRender = reRender ||
			( !Imp.IsQueued && Imp.BufferID != -1 &&
			Buffers[Imp.BufferID].SlotSize < getTextureSizeFromSurfaceSize(core::max_<s32>(newSize.Width, newSize.Height)));

		// so small that we don't care about it
		if (newSize.Width < 4 || newSize.Height < 4)
		{
			Imp.IsActive = false;
			// object was culled
			//Culled++;
			continue;
		}

		// too large to fit in a texture slot
		if (newSize.Width > MaxSize || newSize.Height > MaxSize)
		{
			// get rid
			releaseSlot(Imp);
			Imp.IsActive = false;
		}
		else
		{
			Imp.IsActive = true;
		}

		if (Imp.IsActive && Imp.BufferID == -1 && !Imp.IsQueued )
			reRender = true;

		if (Imp.IsActive)
		{
			// impostor replaces the node
			if (reRender && now > Imp.Time + MinTime)
			{

				if (!Imp.IsQueued)
				{
					CacheMisses++;

					Imp.IsQueued = true;

					SRenderQueueItem q;
					q.Node = &Imp;
					//q.Value = val;

					RenderQueue.push_back(q);
				}
				else
				{
					//QueueHits++;
				}
			}
			else
			{
				// don't re-render the impostor texture, only draw it
				CacheHits++;
			}
		}
		if (!Imp.IsActive) // || ( Imp.BufferID == -1 && Imp.IsQueued))
		{
			// original node is visible
			n->OnRegisterSceneNode();
			// cache miss
			CacheMisses++;
		}
	}

	SceneManager->registerNodeForRendering(this, ESNRP_TRANSPARENT);
}
void CLensFlareSceneNode::render()
{
    video::IVideoDriver* driver = SceneManager->getVideoDriver();
    ICameraSceneNode* camera = SceneManager->getActiveCamera();

    if ( !camera || !driver || !material.Texture1 )
    {
      return;
    }

    driver->setTransform( video::ETS_WORLD, core::matrix4() );

    core::vector3df campos = camera->getAbsolutePosition();


    core::dimension2d<s32> sz = SceneManager->getVideoDriver()->getScreenSize();
    core::vector2df mid = core::vector2df( sz.Width, sz.Height );
    mid /= 2;

    core::position2d<s32> lp = SceneManager->getSceneCollisionManager()->getScreenCoordinatesFrom3DPosition( getAbsolutePosition(), camera ); 
    core::vector2df lightpos = core::vector2df( lp.X, lp.Y );

    core::vector2df ipos;

    int nframes = material.Texture1->getOriginalSize().Width / material.Texture1->getOriginalSize().Height;
    int imageheight = material.Texture1->getSize().Height;
    int texw = 8; // fix height of lens flares to 32 pixels
    float texp = 1.0f / nframes;

    // calc billboard rotation to face camera
    core::vector3df target = camera->getTarget();
    core::vector3df up = camera->getUpVector();
    core::vector3df view = target - campos;
    view.normalize();
    core::vector3df horizontal = up.crossProduct( view );
    horizontal.normalize();
    core::vector3df vertical;
    vertical = horizontal.crossProduct( view );
    vertical.normalize();
    view *= -1.0f;
    for ( s32 i = 0; i < 4; ++i )
    {
      vertices[i].Normal = view;
    }

    core::vector3df hor;
    core::vector3df ver;

    // set material 
    driver->setMaterial( material );
    core::vector3df pos;
    for ( int ax = 0; ax < nframes; ax++ )
    {
      if ( ax == 0 )
      {
        // first burst is 3d
        pos = getAbsolutePosition();
        texw = imageheight * 10;
      }
      else
      {
        // calc screen position for each flare
        ipos = mid.getInterpolated( lightpos, ( 2.0f / nframes ) * ax );

        // try to find the correspondent world coordinate for screen position
        pos = SceneManager->getSceneCollisionManager()->getRayFromScreenCoordinates( core::position2d<s32>( int( ipos.X ), int( ipos.Y ) ), camera ).end;

        // try to put this position vetor near in front of camera
        core::vector3df dir = core::vector3df( campos - pos ).normalize();
        pos = campos + ( dir * -10.0f );// put 10 units in front
        texw = 4;
      }

      // render flares

      // move texcoords to next flare in texture
      vertices[0].TCoords.set( ax * texp, 1.0f );
      vertices[1].TCoords.set( ax * texp, 0.0f );
      vertices[2].TCoords.set( ( ax + 1 ) * texp, 0.0f );
      vertices[3].TCoords.set( ( ax + 1 ) * texp, 1.0f );

      hor = horizontal * ( 0.5f * texw );
      ver = vertical * ( 0.5f * texw );

      vertices[0].Pos = pos + hor + ver;
      vertices[1].Pos = pos + hor - ver;
      vertices[2].Pos = pos - hor - ver;
      vertices[3].Pos = pos - hor + ver;

      // draw image part
      driver->drawIndexedTriangleList( vertices, 4, indices, 2 );
    }
}
void CBillboardGroupSceneNode::updateBillboards()
{
    ICameraSceneNode* camera = SceneManager->getActiveCamera();
    
    if ( !camera )
        return;
    
    core::vector3df camPos = camera->getAbsolutePosition();
        
    core::vector3df ref = core::vector3df(0,1,0);
    
    camera->getAbsoluteTransformation().rotateVect(ref);
    
    core::vector3df view, right, up;
    
    bool farAway = false;
    
    core::vector3df center = BoundingBox.getCenter();
    AbsoluteTransformation.transformVect(center);
    
    core::vector3df camDir = camPos - center;
    
    if ( camDir.getLengthSQ() >= (FarDistance + Radius)*(FarDistance + Radius) )
    {
        farAway = true;
        view = center - camPos;
        view.normalize();
        
        right = ref.crossProduct( view );
        
        up = view.crossProduct( right );
    }
    
    core::vector3df rotatedCamDir = camDir;
    AbsoluteTransformation.inverseRotateVect( rotatedCamDir );
    
    if ( farAway && (rotatedCamDir - LastCamDir).getLengthSQ() < 1000.0f )
    {
        return;
    }
    
    LastCamDir = rotatedCamDir;
    
    // Update the position of every billboard
    for ( s32 i=0; i<Billboards.size(); i++ )
    {
        if ( !farAway )
        {
            core::vector3df pos = Billboards[i].Position;
            
            AbsoluteTransformation.transformVect( pos );
            
            view = pos - camPos;
            
            view.normalize();
        }
        
        core::vector3df thisRight = right;
        core::vector3df thisUp = up;
        
        if ( Billboards[i].HasAxis )
        {
            core::vector3df axis = Billboards[i].Axis;
            
            AbsoluteTransformation.rotateVect(axis);
            
            thisRight = axis.crossProduct( view );
            
            thisUp = axis;
        }
        else if ( !farAway )
        {
            thisRight = ref.crossProduct( view );
            
            thisUp = view.crossProduct( thisRight );
        }
        
        f32 rollrad = Billboards[i].Roll * core::DEGTORAD;
        f32 cos_roll = cos( rollrad );
        f32 sin_roll = sin( rollrad );
        
        core::vector3df a =  cos_roll * thisRight + sin_roll * thisUp;
        core::vector3df b = -sin_roll * thisRight + cos_roll * thisUp;
        
        a *= Billboards[i].Size.Width / 2.0f;
        b *= Billboards[i].Size.Height / 2.0f;
        
        s32 vertexIndex = 4 * i;  // 4 vertices per billboard
        
        core::vector3df billPos = Billboards[i].Position;
        
        AbsoluteTransformation.transformVect(billPos);
        
        MeshBuffer.Vertices[vertexIndex  ].Pos = billPos - a + b;
        MeshBuffer.Vertices[vertexIndex+1].Pos = billPos + a + b;
        MeshBuffer.Vertices[vertexIndex+2].Pos = billPos + a - b;
        MeshBuffer.Vertices[vertexIndex+3].Pos = billPos - a - b;
    }
}