void PositionJavaPinButtonExample::Draw()
{
	//lazily create the pin button when we start drawing so it is not displayed on top of the loading screen
	if(m_world.Initialising())
	{
		return;
	}
	else if(m_buttonID == 0)
	{
		CreateButton();
	}

	//get an env for the current thread
	//
	//AndroidSafeNativeThreadAttachment will detach the thread if required at the end of the method
	AndroidSafeNativeThreadAttachment attached(m_nativeState);
	JNIEnv* env = attached.envForThread;

	//calculate a screen position for the pin based on an ECEF location
	const Eegeo::Space::LatLongAltitude pinLocation = Eegeo::Space::LatLongAltitude::FromDegrees(37.7858,-122.401, 0.f);
	Eegeo::v3 screenPosition;
	Project(pinLocation, screenPosition);

	//update the screen position of the pin using the cached update method on the cached object reference to
	//the pin controller, using the parameters we have calculated and the handle to the pin created earlier
	env->CallVoidMethod(
	    m_hudPinController,
	    m_updateLocationMethodId,
	    m_buttonID,
	    screenPosition.GetX(),
	    screenPosition.GetY()
	);
}
bool ModifiedRenderingExample::IsToBeReplacedWithAlternative(const TSceneElement* pSceneElement)  const
{
	const TRenderable& renderable = pSceneElement->GetResource();

	if(!renderable.GetMaterial()->GetName().compare(Eegeo::Rendering::MaterialNames::Buildings))
	{
		const double filterRadius = 400.0f;
		const double filterRadiusSq = filterRadius*filterRadius;
        
        Eegeo::Camera::CameraState cameraState(GetCurrentCameraState());
        
		Eegeo::v3 cameraRelativePos = Eegeo::Camera::CameraHelpers::CameraRelativePoint(renderable.GetEcefPosition(),
                                                                                        cameraState.InterestPointEcef());

		double delta = cameraRelativePos.LengthSq();
		bool closeToInterest = delta < filterRadiusSq;

		if (closeToInterest)
		{
			return true;
		}
	}

	return false;
}
 void WorldPinsScaleController::GetScreenLocation(const WorldPinItemModel& worldPinItemModel,
         Eegeo::v2& screenLocation,
         const Eegeo::Camera::RenderCamera& renderCamera) const
 {
     Eegeo::dv3 ecefLocation;
     m_worldPinsService.GetPinEcefAndScreenLocations(worldPinItemModel, ecefLocation, screenLocation);
     Eegeo::v3 cameraLocal = (ecefLocation - renderCamera.GetEcefLocation()).ToSingle();
     Eegeo::v3 screenPos;
     renderCamera.Project(cameraLocal, screenPos);
     screenLocation.Set(screenPos.GetX(), screenPos.GetY());
 }
            Eegeo::v3 ComputeHeadingVector(Eegeo::dv3 interestPosition, float heading)
            {
                Eegeo::v3 interestForward(0,1,0);
                Eegeo::dv3 interestEcefUp = interestPosition.Norm();
                Eegeo::v3 interestUp = interestEcefUp.ToSingle();

                Eegeo::v3 interestRight = Eegeo::v3::Cross(interestUp, interestForward);
                interestRight = interestRight.Norm();

                interestForward = Eegeo::v3::Cross(interestRight, interestUp);
                interestForward = interestForward.Norm();

                Eegeo::Quaternion rotation;
                rotation.Set(interestUp, heading);
                interestForward = rotation.RotatePoint(interestForward);

                return interestForward;
            }
void PositionJavaPinButtonExample::Project (const Eegeo::Space::LatLongAltitude& location, Eegeo::v3& screenPosition)
{
	//project a 3D Ecef location to the screen
	Eegeo::m44 finalMatrix;

	Eegeo::Camera::RenderCamera renderCamera(GetGlobeCameraController().GetRenderCamera());

	Eegeo::m44::Mul (finalMatrix,
	                 renderCamera.GetProjectionMatrix(),
	                 renderCamera.GetViewMatrix());

	Eegeo::v3 local = (location.ToECEF() - renderCamera.GetEcefLocation()).ToSingle();
	Eegeo::v4 inVector(local, 1.0f);

	// get clip space coords
	Eegeo::v4 outVector = Eegeo::v4::Mul(inVector, finalMatrix);

	// divide through by w to get normalized device space coords -- range [-1, 1]
	screenPosition.SetX((outVector.GetX()/outVector.GetW()));
	screenPosition.SetY((outVector.GetY()/outVector.GetW()));
	screenPosition.SetZ((outVector.GetZ()/outVector.GetW()));

	// transform from [-1, 1] to [0, 1]
	screenPosition.SetX((screenPosition.GetX() + 1.0f) * 0.5f);
	screenPosition.SetY(1.0f - ((screenPosition.GetY() + 1.0f) * 0.5f));

	float viewport[] = {0, 0, renderCamera.GetViewportWidth(), renderCamera.GetViewportHeight()};

	// transform from [0, 1] to screen coords.
	screenPosition.SetX((screenPosition.GetX()*(viewport[2]-viewport[0])) + viewport[0]);
	screenPosition.SetY((screenPosition.GetY()*(viewport[3]-viewport[1])) + viewport[1]);
}
            void WorldPinsInFocusController::Update(float deltaSeconds, const Eegeo::dv3& ecefInterestPoint, const Eegeo::Camera::RenderCamera& renderCamera)
            {
                const IWorldPinsInFocusModel* pClosest = NULL;
                double minDistanceSq = std::numeric_limits<double>::max();
                Eegeo::v2 closestScreenPinLocation;
                Eegeo::v2 screenInterestPoint = ProjectEcefToScreen(ecefInterestPoint, renderCamera);

                if(m_focusEnabled)
                {
                    for(size_t i = 0; i < m_worldPinsRepository.GetItemCount(); ++i)
                    {
                        ExampleApp::WorldPins::SdkModel::WorldPinItemModel* worldPinItemModel = m_worldPinsRepository.GetItemAtIndex(i);

                        if (!worldPinItemModel->IsFocusable())
                        {
                            continue;
                        }
                        
                        Eegeo::dv3 ecefPinLocation;
                        Eegeo::v2 screenPinLocation;

                        m_worldPinsService.GetPinEcefAndScreenLocations(*worldPinItemModel,
                                ecefPinLocation,
                                screenPinLocation);

                        Eegeo::v3 cameraLocal = (ecefPinLocation - renderCamera.GetEcefLocation()).ToSingle();
                        Eegeo::v3 cameraSurfaceNormal = cameraLocal.Norm();

                        Eegeo::v3 upNormal = ecefPinLocation.Norm().ToSingle();
                        float dp = Eegeo::v3::Dot(cameraSurfaceNormal, upNormal);

                        if(dp > 0.0f)
                        {
                            continue;
                        }

                        screenPinLocation = ProjectEcefToScreen(ecefPinLocation, renderCamera);

                        double distanceToFocusSq = (screenInterestPoint - screenPinLocation).LengthSq();

                        if(distanceToFocusSq < minDistanceSq && worldPinItemModel->IsVisible())
                        {
                            pClosest = &worldPinItemModel->GetInFocusModel();
                            minDistanceSq = distanceToFocusSq;
                            closestScreenPinLocation = screenPinLocation;
                        }
                    }
                }

                if(m_pLastFocussedModel != pClosest)
                {
                    m_pLastFocussedModel = pClosest;

                    if(m_pLastFocussedModel != NULL)
                    {
                        m_messageBus.Publish(WorldPinGainedFocusMessage(WorldPinsInFocusModel(m_pLastFocussedModel->GetPinId(),
                                             m_pLastFocussedModel->GetTitle(),
                                             m_pLastFocussedModel->GetSubtitle(),
                                             m_pLastFocussedModel->GetVendor(),
                                             m_pLastFocussedModel->GetJsonData(),
                                             m_pLastFocussedModel->GetRatingsImage(),
                                             m_pLastFocussedModel->GetReviewCount()),
                                             closestScreenPinLocation));
                    }
                    else
                    {
                        m_messageBus.Publish(WorldPinLostFocusMessage());
                    }
                }
                else
                {
                    if(m_pLastFocussedModel != NULL)
                    {
                        m_messageBus.Publish(WorldPinInFocusChangedLocationMessage(closestScreenPinLocation));
                    }
                }
            }
 void WorldMenuController::PositionItems()
 {
     
     if(!m_menuItemsShouldRender)
         return;
     
     Eegeo::m33 headTrackedOrientation;
     Eegeo::m33::Mul(headTrackedOrientation, m_uiCameraProvider.GetBaseOrientation(), m_cachedHeadTracker);
     
     float halfCount = m_viewsByModel.size()/2;
     if(m_viewsByModel.size()%2==0)
         halfCount-=0.5f;
     
     Eegeo::dv3 center = m_uiCameraProvider.GetRenderCameraForUI().GetEcefLocation();
     Eegeo::v3 forward(headTrackedOrientation.GetRow(2));
     Eegeo::v3 top(center.ToSingle().Norm());
     Eegeo::v3 right(Eegeo::v3::Cross(top, forward));
     
     Eegeo::v3 vA = center.ToSingle();
     Eegeo::v3 vB = m_uiCameraProvider.GetOrientation().GetRow(2);
     float angle = Eegeo::Math::Rad2Deg(Eegeo::Math::ACos(Eegeo::v3::Dot(vA, vB)/(vA.Length()*vB.Length())));
     
     
     const float MarginAngle = 85;
     const int PositionMultiplier = 600;
     
     bool shouldUpdatePosition = false;
     
     if(!m_isMenuShown && angle<=MarginAngle)
     {
         m_isMenuShown = true;
         shouldUpdatePosition = true;
         m_cachedHeadTracker = m_uiCameraProvider.GetHeadTrackerOrientation();
         m_cachedCenter = center;
     }
     else if(m_isMenuShown && angle>MarginAngle)
     {
         m_isMenuShown = false;
         shouldUpdatePosition = true;
     }
     
     if ((m_cachedCenter - center).LengthSq() > 1) {
         m_cachedCenter = center;
         shouldUpdatePosition = true;
     }
     
     if(shouldUpdatePosition || m_isMenuShown)
     {
         
         std::vector<WorldMenuItemView*> items;
         for(TViewsByModel::iterator it = m_viewsByModel.begin(); it != m_viewsByModel.end(); ++it)
         {
             std::vector<WorldMenuItemView*>::iterator itItems = items.begin();
             for(; itItems != items.end(); ++itItems)
             {
                 if((*itItems)->GetWorldMenuItem().GetId() < it->second->GetWorldMenuItem().GetId())
                 {
                     break;
                 }
             }
             items.insert(itItems, it->second);
         }
         
         float margin = 0.f;
         
         for(std::vector<WorldMenuItemView*>::iterator it = items.begin(); it != items.end(); ++it)
         {
             WorldMenuItemView* pView = *it;
             if(!m_isMenuShown)
             {
                 pView->SetItemShouldRender(false);
                 m_pSelectedArrow->SetItemShouldRender(false);
                 continue;
             }
             margin += pView->GetWorldMenuItem().GetMarginRight();
             
             Eegeo::dv3 position(center + (forward*PositionMultiplier) + (top*45) + ((right*55*halfCount)-(right*margin)));
             pView->SetEcefPosition(position);
             pView->SetItemShouldRender(true);
             m_pSelectedArrow->SetItemShouldRender(true);
             if(m_menuItemId==pView->GetWorldMenuItem().GetId())
             {
                 m_pSelectedArrow->SetEcefPosition(center + (forward*PositionMultiplier) + (top*92) + (right*55*halfCount)-(right*margin));
             }
             halfCount-=1;
             
             margin += pView->GetWorldMenuItem().GetMarginLeft();
             pView->SetItemShouldRender(m_menuItemsShouldRender);
         }
         
         items.clear();
         m_lastCameraPosition = center;
     }
 }
    void BoundsVisualiser::Build(const Eegeo::v3& minExtents, const Eegeo::v3& maxExtents)
    {
        Vertex vertexBuffer[NumVerts];
        u16 indexBuffer[NumIndices];
        
        float minX = minExtents.GetX();
        float minY = minExtents.GetY();
        float minZ = minExtents.GetZ();
        float maxX = maxExtents.GetX();
        float maxY = maxExtents.GetY();
        float maxZ = maxExtents.GetZ();

        std::vector<Eegeo::v3> verts;
        verts.push_back(Eegeo::v3(minX, minY, minZ));
        verts.push_back(Eegeo::v3(minX, minY, maxZ));
        verts.push_back(Eegeo::v3(minX, maxY, minZ));
        verts.push_back(Eegeo::v3(minX, maxY, maxZ));
        verts.push_back(Eegeo::v3(maxX, minY, minZ));
        verts.push_back(Eegeo::v3(maxX, minY, maxZ));
        verts.push_back(Eegeo::v3(maxX, maxY, minZ));
        verts.push_back(Eegeo::v3(maxX, maxY, maxZ));
        
        for(size_t i = 0; i < NumVerts; ++ i)
        {
            vertexBuffer[i].x = verts[i].GetX();
            vertexBuffer[i].y = verts[i].GetY();
            vertexBuffer[i].z = verts[i].GetZ();
        }
        
        indexBuffer[0] = 0;
        indexBuffer[1] = 1;
        indexBuffer[2] = 2;
        
        indexBuffer[3] = 1;
        indexBuffer[4] = 3;
        indexBuffer[5] = 2;
        
        indexBuffer[6] = 4;
        indexBuffer[7] = 5;
        indexBuffer[8] = 6;
        
        indexBuffer[9] = 5;
        indexBuffer[10] = 7;
        indexBuffer[11] = 6;
        
        indexBuffer[12] = 4;
        indexBuffer[13] = 1;
        indexBuffer[14] = 0;
        
        indexBuffer[15] = 4;
        indexBuffer[16] = 5;
        indexBuffer[17] = 1;
        
        indexBuffer[18] = 5;
        indexBuffer[19] = 3;
        indexBuffer[20] = 1;
        
        indexBuffer[21] = 7;
        indexBuffer[22] = 3;
        indexBuffer[23] = 5;
        
        indexBuffer[24] = 2;
        indexBuffer[25] = 3;
        indexBuffer[26] = 7;
        
        indexBuffer[27] = 7;
        indexBuffer[28] = 6;
        indexBuffer[29] = 2;
        
        indexBuffer[30] = 4;
        indexBuffer[31] = 0;
        indexBuffer[32] = 6;
        
        indexBuffer[33] = 2;
        indexBuffer[34] = 6;
        indexBuffer[35] = 0;
        
        InitMeshGLBuffers(vertexBuffer, indexBuffer);
    }