plugin/poi/landmarks/overlay/src/Overlay.cpp
changeset 0 c316ab048e9d
equal deleted inserted replaced
-1:000000000000 0:c316ab048e9d
       
     1 /*
       
     2  * Name        : Overlay.cpp
       
     3  * Description : 
       
     4  * Project     : This file is part of OpenMAR, an Open Mobile Augmented Reality browser
       
     5  * Website     : http://OpenMAR.org
       
     6  *
       
     7  * Copyright (c) 2010 David Caabeiro
       
     8  *
       
     9  * All rights reserved. This program and the accompanying materials are made available 
       
    10  * under the terms of the Eclipse Public License v1.0 which accompanies this 
       
    11  * distribution, and is available at http://www.eclipse.org/legal/epl-v10.html
       
    12  *
       
    13  */
       
    14 
       
    15 #include "Overlay.h"
       
    16 
       
    17 #include <coemain.h>
       
    18 #include <gdi.h>
       
    19 #include <w32std.h>
       
    20 
       
    21 #include "Vector3d.h"
       
    22 #include "Vector4d.h"
       
    23 
       
    24 #include "Accelerometer.h"
       
    25 #include "Magnetometer.h"
       
    26 #include "AutoRotation.h"
       
    27 
       
    28 #include "Logger.h"
       
    29 
       
    30 #include "Manager.h"
       
    31 
       
    32 COverlay* COverlay::NewL(SParameter& aParameter)
       
    33 {
       
    34     COverlay* self = new(ELeave) COverlay(aParameter);
       
    35     CleanupStack::PushL(self);
       
    36     self->ConstructL();
       
    37     CleanupStack::Pop(self);
       
    38 
       
    39     return self;
       
    40 }
       
    41 
       
    42 COverlay::COverlay(SParameter& aParameter)
       
    43     : iWindow(aParameter.iWindow), iRect(aParameter.iRect)
       
    44 {}
       
    45 
       
    46 void COverlay::ConstructL()
       
    47 {
       
    48     LOGTXT("Initializing EGL..");
       
    49 
       
    50     iEglDisplay = ::eglGetDisplay(EGL_DEFAULT_DISPLAY);
       
    51 
       
    52     if (iEglDisplay == 0)
       
    53     {
       
    54         _LIT(KGetDisplayFailed, "eglGetDisplay failed");
       
    55         User::Panic(KGetDisplayFailed, 0);
       
    56     }
       
    57 
       
    58     if (::eglInitialize(iEglDisplay, 0, 0) == EGL_FALSE)
       
    59     {
       
    60         _LIT(KInitializeFailed, "eglInitialize failed");
       
    61         User::Panic(KInitializeFailed, 0);
       
    62     }
       
    63 
       
    64     EGLConfig* configList = 0;
       
    65     EGLint configSize     = 0;
       
    66     EGLint numOfConfigs   = 0;
       
    67 
       
    68     // Get the number of possible EGLConfigs
       
    69     if (::eglGetConfigs(iEglDisplay, configList, configSize, &numOfConfigs) == EGL_FALSE)
       
    70     {
       
    71         _LIT(KGetConfigsFailed, "eglGetConfigs failed");
       
    72         User::Panic( KGetConfigsFailed, 0 );
       
    73     }
       
    74 
       
    75     configSize = numOfConfigs;
       
    76 
       
    77     // Allocate memory for the configList
       
    78     configList = (EGLConfig*) User::Alloc(sizeof(EGLConfig) * configSize);
       
    79     if (configList == 0)
       
    80     {
       
    81         _LIT(KConfigAllocFailed, "Config alloc failed");
       
    82         User::Panic(KConfigAllocFailed, 0);
       
    83     }
       
    84 
       
    85     /*
       
    86      * Define properties for the wanted EGLSurface. To get the best possible 
       
    87      * performance, choose an EGLConfig with a buffersize matching the current 
       
    88      * window's display mode
       
    89      */
       
    90 
       
    91     TDisplayMode displayMode = iWindow.DisplayMode();
       
    92     TInt bufferSize = 0;
       
    93 
       
    94     switch (displayMode)
       
    95     {
       
    96         case EColor4K:
       
    97             bufferSize = 12;
       
    98             break;
       
    99 
       
   100         case EColor64K:
       
   101             bufferSize = 16;
       
   102             break;
       
   103 
       
   104         case EColor16M:
       
   105             bufferSize = 24;
       
   106             break;
       
   107 
       
   108         case EColor16MU:
       
   109         case EColor16MA:
       
   110         case EColor16MAP:
       
   111             bufferSize = 32;
       
   112             break;
       
   113 
       
   114         default:
       
   115             _LIT(KDisplayModeError, "Unsupported display mode");
       
   116             User::Panic(KDisplayModeError, 0);
       
   117             break;
       
   118     }
       
   119 
       
   120     // Define properties for the wanted EGLSurface 
       
   121     const EGLint attrib_list[] = { 
       
   122             EGL_SURFACE_TYPE,       EGL_PBUFFER_BIT,
       
   123 //            EGL_TRANSPARENT_TYPE,   EGL_TRANSPARENT_RGB,
       
   124             EGL_BUFFER_SIZE,        bufferSize,
       
   125             EGL_NONE
       
   126     };
       
   127 
       
   128     // Choose an EGLConfig that best matches to the properties in attrib_list_fsaa
       
   129     if (::eglChooseConfig(iEglDisplay, attrib_list, configList, configSize, &numOfConfigs) == EGL_FALSE)
       
   130     {
       
   131         _LIT( KChooseConfigFailed, "eglChooseConfig failed");
       
   132         User::Panic(KChooseConfigFailed, 0);
       
   133     }
       
   134 
       
   135     iConfig = configList[0];    // Choose the best EGLConfig. EGLConfigs
       
   136                                 // returned by eglChooseConfig are sorted so
       
   137                                 // that the best matching EGLConfig is first in
       
   138                                 // the list.
       
   139     User::Free(configList);
       
   140 
       
   141     TInt width  = iRect.Size().iWidth;
       
   142     TInt height = iRect.Size().iHeight;
       
   143 
       
   144     LOGARG("Window size is %d x %d", width, height);
       
   145 
       
   146     const EGLint attrib_list2[] = { 
       
   147             EGL_WIDTH,  width,
       
   148             EGL_HEIGHT, height,
       
   149             EGL_NONE
       
   150     };
       
   151 
       
   152     // Create a window where the graphics are blitted
       
   153     iEglSurface = ::eglCreatePbufferSurface(iEglDisplay, iConfig, attrib_list2);
       
   154 
       
   155     if (iEglSurface == 0)
       
   156     {
       
   157         _LIT(KCreateWindowSurfaceFailed, "eglCreateWindowSurface failed");
       
   158         User::Panic(KCreateWindowSurfaceFailed, 0);
       
   159     }
       
   160 
       
   161     // Create a rendering context
       
   162     iEglContext = ::eglCreateContext(iEglDisplay, iConfig, EGL_NO_CONTEXT, 0);
       
   163 
       
   164     if (iEglContext == 0)
       
   165     {
       
   166         _LIT(KCreateContextFailed, "eglCreateContext failed");
       
   167         User::Panic(KCreateContextFailed, 0);
       
   168     }
       
   169 
       
   170     // Make the context current. Binds context to the current rendering thread and surface.
       
   171     if (::eglMakeCurrent(iEglDisplay, iEglSurface, iEglSurface, iEglContext) == EGL_FALSE)
       
   172     {
       
   173         _LIT(KMakeCurrentFailed, "eglMakeCurrent failed");
       
   174         User::Panic(KMakeCurrentFailed, 0);
       
   175     }
       
   176 
       
   177     // Create a Symbian bitmap where the graphics from the Pbuffer are copied
       
   178     iPixmap = new(ELeave) CWsBitmap(CCoeEnv::Static()->WsSession());
       
   179     iPixmap->Create(iRect.Size(), iWindow.DisplayMode());
       
   180 
       
   181     // Manager is in charge of POIs from different providers
       
   182     iManager = CManager::NewL();
       
   183 }
       
   184 
       
   185 COverlay::~COverlay()
       
   186 {
       
   187     delete iManager;
       
   188 
       
   189     delete iPixmap;
       
   190     iPixmap = 0;
       
   191 
       
   192     ::eglMakeCurrent(iEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
       
   193     ::eglDestroyContext(iEglDisplay, iEglContext);
       
   194     ::eglDestroySurface(iEglDisplay, iEglSurface);
       
   195     ::eglTerminate(iEglDisplay);
       
   196 }
       
   197 
       
   198 void COverlay::StartL()
       
   199 {
       
   200     // First off we enable the position and orientation sensors
       
   201     iPosition = CPosition::NewL(*this);
       
   202     iPosition->Request();
       
   203 
       
   204 #if defined(__MARM__)
       
   205     iAccelerometer = CAccelerometer::NewL();
       
   206     iAccelerometer->StartL();
       
   207 
       
   208     iMagnetometer = CMagnetometer::NewL();
       
   209     iMagnetometer->StartL();
       
   210 
       
   211     iAutoRotation = CAutoRotation::NewL();
       
   212     iAutoRotation->ResetL();
       
   213 #endif
       
   214 
       
   215     // We now calculate the view frustum and create the appropriate projection matrix
       
   216     TReal near = 1.0f;
       
   217     TReal far  = 3000.0f;
       
   218 
       
   219     TReal fovy = 0;
       
   220     Math::Tan(fovy, 45 * KDegToRad / 2);
       
   221 
       
   222     TInt width  = iWindow.Size().iWidth;
       
   223     TInt height = iWindow.Size().iHeight;
       
   224     TReal aspectRatio = static_cast<TReal>(width) / height;
       
   225 
       
   226     TReal top    = near * fovy;
       
   227     TReal bottom = -top;
       
   228     TReal left   = bottom * aspectRatio;
       
   229     TReal right  = top * aspectRatio;
       
   230 
       
   231     iProjection.Load(
       
   232             2 * near / (right - left),       0,                               0,                            0,
       
   233             0                        ,       2 * near / (top - bottom),       0,                            0,
       
   234             (right + left) / (right - left), (top + bottom) / (top - bottom), -(far + near) / (far - near), -1,
       
   235             0                              , 0                              , - 2 * far * near / (far - near), 0
       
   236     );
       
   237 
       
   238     ::glViewport(0, 0, width, height);
       
   239     ::glMatrixMode(GL_PROJECTION);
       
   240     ::glLoadMatrixf(iProjection.m);
       
   241 
       
   242     ::glMatrixMode(GL_MODELVIEW);
       
   243 
       
   244     ::glEnableClientState(GL_VERTEX_ARRAY);
       
   245     ::glEnableClientState(GL_TEXTURE_COORD_ARRAY);
       
   246 //    ::glEnableClientState(GL_NORMAL_ARRAY);
       
   247 
       
   248     ::glEnable(GL_DEPTH_TEST);
       
   249     ::glDepthFunc(GL_LESS);
       
   250 
       
   251     // Set background transparency 
       
   252     ::glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
       
   253 }
       
   254 
       
   255 void COverlay::Stop()
       
   256 {
       
   257     ::glDisable(GL_DEPTH_TEST);
       
   258 
       
   259 //    ::glDisableClientState(GL_NORMAL_ARRAY);
       
   260     ::glDisableClientState(GL_TEXTURE_COORD_ARRAY);
       
   261     ::glDisableClientState(GL_VERTEX_ARRAY);
       
   262 
       
   263 #if defined(__MARM__)
       
   264     iAutoRotation->RestoreL();
       
   265     delete iAutoRotation;
       
   266     iAutoRotation = 0;
       
   267 
       
   268     iMagnetometer->Stop();
       
   269     delete iMagnetometer;
       
   270     iMagnetometer = 0;
       
   271 
       
   272     iAccelerometer->Stop();
       
   273     delete iAccelerometer;
       
   274     iAccelerometer = 0;
       
   275 #endif
       
   276 
       
   277     delete iPosition;
       
   278     iPosition = 0;
       
   279 }
       
   280 
       
   281 const CFbsBitmap& COverlay::RenderScene()
       
   282 {
       
   283     // Estimate orientation based on sensor data
       
   284 #if defined(__MARM__)
       
   285 /*
       
   286  * +X is defined as the cross product Y.Z (it is tangential to
       
   287  * the ground at the device's current location and roughly points East)
       
   288  * +Y is tangential to the ground at the device's current location and
       
   289  * points towards the magnetic North Pole
       
   290  * +Z points towards the sky and is perpendicular to the ground
       
   291  */
       
   292     Vector3d A = iAccelerometer->GetValue();
       
   293     Vector3d E = iMagnetometer->GetValue();
       
   294 
       
   295     Vector3d H = Vector3d::Cross(E, A);
       
   296     Scalar hNorm = H.Norm();
       
   297     H.mX /= hNorm;
       
   298     H.mY /= hNorm;
       
   299     H.mZ /= hNorm;
       
   300 
       
   301     Scalar aNorm = A.Norm();
       
   302     A.mX /= aNorm;
       
   303     A.mY /= aNorm;
       
   304     A.mZ /= aNorm;
       
   305 
       
   306     Vector3d M = Vector3d::Cross(A, H);
       
   307 
       
   308     iModelView.Load(
       
   309             H.mX, H.mY, H.mZ, 0,
       
   310             M.mX, M.mY, M.mZ, 0,
       
   311             A.mX, A.mY, A.mZ, 0,
       
   312             0, 0, 0, 1
       
   313     );
       
   314     ::glLoadMatrixf(iModelView.m);
       
   315 #else
       
   316     ::glLoadIdentity();
       
   317 #endif
       
   318 
       
   319     ::glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
       
   320 
       
   321     iManager->Render();
       
   322 
       
   323     ::eglCopyBuffers(iEglDisplay, iEglSurface, iPixmap);
       
   324 
       
   325     return *iPixmap;
       
   326 }
       
   327 
       
   328 /*
       
   329  * Callback from position provider. We use current position to set up world's origin
       
   330  * and make request to different providers
       
   331  */
       
   332 void COverlay::PositionUpdateL(TInt aError, const TPosition& aPosition)
       
   333 {
       
   334     LOGARG("Got position: lat=%f,lon=%f,alt=%f", aPosition.Latitude(), aPosition.Longitude(), aPosition.Altitude());
       
   335 
       
   336     // Set the "world" origin
       
   337     iManager->SetOrigin(aPosition);
       
   338     // Request POIs for that position
       
   339     iManager->RequestL(aPosition);
       
   340 }
       
   341 
       
   342 /*
       
   343  * From the current list of POIs retrieved, find the one that is closest to the
       
   344  * screen center.
       
   345  * 
       
   346  * We use both projection and modelview transforms to obtain screen coordinates.
       
   347  * Note that both matrices are in column-major ordering, so we need to transpose them.
       
   348  */
       
   349 TInt COverlay::GetFocusedPOI()
       
   350 {
       
   351     const TPoint viewportCenter(iRect.Center());
       
   352 
       
   353     TInt mostCentered = KMaxTInt; 
       
   354     TInt focused = KErrNotFound;
       
   355 
       
   356     for (TInt i = 0; i < iManager->iObjectList.Count(); ++i)
       
   357     {
       
   358         const Vector3d position(iManager->iObjectList[i]->GetPosition());
       
   359 
       
   360         const Vector4d world(position.mX, position.mY, position.mZ, 1);
       
   361         const Vector4d camera(iModelView.Transpose() * world);
       
   362         const Vector4d projection(iProjection.Transpose() * camera);
       
   363 
       
   364         // Screen transformation
       
   365         TReal x = projection.mX / projection.mW;
       
   366         TReal y = projection.mY / projection.mW;
       
   367         TReal z = projection.mZ / projection.mW;
       
   368 
       
   369         TReal screenX = viewportCenter.iX * (x + 1);
       
   370         TReal screenY = viewportCenter.iY * (y + 1);
       
   371 //        TReal screenZ = (z + 1) / 2;
       
   372 
       
   373         TBool visible = (x > -1 && x < 1) && (y > -1 && y < 1) && (z > -1 && z < 1);
       
   374         TInt centered = (screenX - viewportCenter.iX) * (screenX - viewportCenter.iX) + (screenY - viewportCenter.iY) * (screenY - viewportCenter.iY);
       
   375 
       
   376         if (visible && centered < mostCentered)
       
   377         {
       
   378             mostCentered = centered; 
       
   379             focused = i;
       
   380         }
       
   381     }
       
   382 
       
   383     return focused;
       
   384 }