--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/plugin/poi/landmarks/overlay/src/Overlay.cpp Fri Jun 25 12:50:05 2010 +0200
@@ -0,0 +1,384 @@
+/*
+ * Name : Overlay.cpp
+ * Description :
+ * Project : This file is part of OpenMAR, an Open Mobile Augmented Reality browser
+ * Website : http://OpenMAR.org
+ *
+ * Copyright (c) 2010 David Caabeiro
+ *
+ * All rights reserved. This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0 which accompanies this
+ * distribution, and is available at http://www.eclipse.org/legal/epl-v10.html
+ *
+ */
+
+#include "Overlay.h"
+
+#include <coemain.h>
+#include <gdi.h>
+#include <w32std.h>
+
+#include "Vector3d.h"
+#include "Vector4d.h"
+
+#include "Accelerometer.h"
+#include "Magnetometer.h"
+#include "AutoRotation.h"
+
+#include "Logger.h"
+
+#include "Manager.h"
+
+COverlay* COverlay::NewL(SParameter& aParameter)
+{
+ COverlay* self = new(ELeave) COverlay(aParameter);
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ CleanupStack::Pop(self);
+
+ return self;
+}
+
+COverlay::COverlay(SParameter& aParameter)
+ : iWindow(aParameter.iWindow), iRect(aParameter.iRect)
+{}
+
+void COverlay::ConstructL()
+{
+ LOGTXT("Initializing EGL..");
+
+ iEglDisplay = ::eglGetDisplay(EGL_DEFAULT_DISPLAY);
+
+ if (iEglDisplay == 0)
+ {
+ _LIT(KGetDisplayFailed, "eglGetDisplay failed");
+ User::Panic(KGetDisplayFailed, 0);
+ }
+
+ if (::eglInitialize(iEglDisplay, 0, 0) == EGL_FALSE)
+ {
+ _LIT(KInitializeFailed, "eglInitialize failed");
+ User::Panic(KInitializeFailed, 0);
+ }
+
+ EGLConfig* configList = 0;
+ EGLint configSize = 0;
+ EGLint numOfConfigs = 0;
+
+ // Get the number of possible EGLConfigs
+ if (::eglGetConfigs(iEglDisplay, configList, configSize, &numOfConfigs) == EGL_FALSE)
+ {
+ _LIT(KGetConfigsFailed, "eglGetConfigs failed");
+ User::Panic( KGetConfigsFailed, 0 );
+ }
+
+ configSize = numOfConfigs;
+
+ // Allocate memory for the configList
+ configList = (EGLConfig*) User::Alloc(sizeof(EGLConfig) * configSize);
+ if (configList == 0)
+ {
+ _LIT(KConfigAllocFailed, "Config alloc failed");
+ User::Panic(KConfigAllocFailed, 0);
+ }
+
+ /*
+ * Define properties for the wanted EGLSurface. To get the best possible
+ * performance, choose an EGLConfig with a buffersize matching the current
+ * window's display mode
+ */
+
+ TDisplayMode displayMode = iWindow.DisplayMode();
+ TInt bufferSize = 0;
+
+ switch (displayMode)
+ {
+ case EColor4K:
+ bufferSize = 12;
+ break;
+
+ case EColor64K:
+ bufferSize = 16;
+ break;
+
+ case EColor16M:
+ bufferSize = 24;
+ break;
+
+ case EColor16MU:
+ case EColor16MA:
+ case EColor16MAP:
+ bufferSize = 32;
+ break;
+
+ default:
+ _LIT(KDisplayModeError, "Unsupported display mode");
+ User::Panic(KDisplayModeError, 0);
+ break;
+ }
+
+ // Define properties for the wanted EGLSurface
+ const EGLint attrib_list[] = {
+ EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
+// EGL_TRANSPARENT_TYPE, EGL_TRANSPARENT_RGB,
+ EGL_BUFFER_SIZE, bufferSize,
+ EGL_NONE
+ };
+
+ // Choose an EGLConfig that best matches to the properties in attrib_list_fsaa
+ if (::eglChooseConfig(iEglDisplay, attrib_list, configList, configSize, &numOfConfigs) == EGL_FALSE)
+ {
+ _LIT( KChooseConfigFailed, "eglChooseConfig failed");
+ User::Panic(KChooseConfigFailed, 0);
+ }
+
+ iConfig = configList[0]; // Choose the best EGLConfig. EGLConfigs
+ // returned by eglChooseConfig are sorted so
+ // that the best matching EGLConfig is first in
+ // the list.
+ User::Free(configList);
+
+ TInt width = iRect.Size().iWidth;
+ TInt height = iRect.Size().iHeight;
+
+ LOGARG("Window size is %d x %d", width, height);
+
+ const EGLint attrib_list2[] = {
+ EGL_WIDTH, width,
+ EGL_HEIGHT, height,
+ EGL_NONE
+ };
+
+ // Create a window where the graphics are blitted
+ iEglSurface = ::eglCreatePbufferSurface(iEglDisplay, iConfig, attrib_list2);
+
+ if (iEglSurface == 0)
+ {
+ _LIT(KCreateWindowSurfaceFailed, "eglCreateWindowSurface failed");
+ User::Panic(KCreateWindowSurfaceFailed, 0);
+ }
+
+ // Create a rendering context
+ iEglContext = ::eglCreateContext(iEglDisplay, iConfig, EGL_NO_CONTEXT, 0);
+
+ if (iEglContext == 0)
+ {
+ _LIT(KCreateContextFailed, "eglCreateContext failed");
+ User::Panic(KCreateContextFailed, 0);
+ }
+
+ // Make the context current. Binds context to the current rendering thread and surface.
+ if (::eglMakeCurrent(iEglDisplay, iEglSurface, iEglSurface, iEglContext) == EGL_FALSE)
+ {
+ _LIT(KMakeCurrentFailed, "eglMakeCurrent failed");
+ User::Panic(KMakeCurrentFailed, 0);
+ }
+
+ // Create a Symbian bitmap where the graphics from the Pbuffer are copied
+ iPixmap = new(ELeave) CWsBitmap(CCoeEnv::Static()->WsSession());
+ iPixmap->Create(iRect.Size(), iWindow.DisplayMode());
+
+ // Manager is in charge of POIs from different providers
+ iManager = CManager::NewL();
+}
+
+COverlay::~COverlay()
+{
+ delete iManager;
+
+ delete iPixmap;
+ iPixmap = 0;
+
+ ::eglMakeCurrent(iEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+ ::eglDestroyContext(iEglDisplay, iEglContext);
+ ::eglDestroySurface(iEglDisplay, iEglSurface);
+ ::eglTerminate(iEglDisplay);
+}
+
+void COverlay::StartL()
+{
+ // First off we enable the position and orientation sensors
+ iPosition = CPosition::NewL(*this);
+ iPosition->Request();
+
+#if defined(__MARM__)
+ iAccelerometer = CAccelerometer::NewL();
+ iAccelerometer->StartL();
+
+ iMagnetometer = CMagnetometer::NewL();
+ iMagnetometer->StartL();
+
+ iAutoRotation = CAutoRotation::NewL();
+ iAutoRotation->ResetL();
+#endif
+
+ // We now calculate the view frustum and create the appropriate projection matrix
+ TReal near = 1.0f;
+ TReal far = 3000.0f;
+
+ TReal fovy = 0;
+ Math::Tan(fovy, 45 * KDegToRad / 2);
+
+ TInt width = iWindow.Size().iWidth;
+ TInt height = iWindow.Size().iHeight;
+ TReal aspectRatio = static_cast<TReal>(width) / height;
+
+ TReal top = near * fovy;
+ TReal bottom = -top;
+ TReal left = bottom * aspectRatio;
+ TReal right = top * aspectRatio;
+
+ iProjection.Load(
+ 2 * near / (right - left), 0, 0, 0,
+ 0 , 2 * near / (top - bottom), 0, 0,
+ (right + left) / (right - left), (top + bottom) / (top - bottom), -(far + near) / (far - near), -1,
+ 0 , 0 , - 2 * far * near / (far - near), 0
+ );
+
+ ::glViewport(0, 0, width, height);
+ ::glMatrixMode(GL_PROJECTION);
+ ::glLoadMatrixf(iProjection.m);
+
+ ::glMatrixMode(GL_MODELVIEW);
+
+ ::glEnableClientState(GL_VERTEX_ARRAY);
+ ::glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+// ::glEnableClientState(GL_NORMAL_ARRAY);
+
+ ::glEnable(GL_DEPTH_TEST);
+ ::glDepthFunc(GL_LESS);
+
+ // Set background transparency
+ ::glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
+}
+
+void COverlay::Stop()
+{
+ ::glDisable(GL_DEPTH_TEST);
+
+// ::glDisableClientState(GL_NORMAL_ARRAY);
+ ::glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+ ::glDisableClientState(GL_VERTEX_ARRAY);
+
+#if defined(__MARM__)
+ iAutoRotation->RestoreL();
+ delete iAutoRotation;
+ iAutoRotation = 0;
+
+ iMagnetometer->Stop();
+ delete iMagnetometer;
+ iMagnetometer = 0;
+
+ iAccelerometer->Stop();
+ delete iAccelerometer;
+ iAccelerometer = 0;
+#endif
+
+ delete iPosition;
+ iPosition = 0;
+}
+
+const CFbsBitmap& COverlay::RenderScene()
+{
+ // Estimate orientation based on sensor data
+#if defined(__MARM__)
+/*
+ * +X is defined as the cross product Y.Z (it is tangential to
+ * the ground at the device's current location and roughly points East)
+ * +Y is tangential to the ground at the device's current location and
+ * points towards the magnetic North Pole
+ * +Z points towards the sky and is perpendicular to the ground
+ */
+ Vector3d A = iAccelerometer->GetValue();
+ Vector3d E = iMagnetometer->GetValue();
+
+ Vector3d H = Vector3d::Cross(E, A);
+ Scalar hNorm = H.Norm();
+ H.mX /= hNorm;
+ H.mY /= hNorm;
+ H.mZ /= hNorm;
+
+ Scalar aNorm = A.Norm();
+ A.mX /= aNorm;
+ A.mY /= aNorm;
+ A.mZ /= aNorm;
+
+ Vector3d M = Vector3d::Cross(A, H);
+
+ iModelView.Load(
+ H.mX, H.mY, H.mZ, 0,
+ M.mX, M.mY, M.mZ, 0,
+ A.mX, A.mY, A.mZ, 0,
+ 0, 0, 0, 1
+ );
+ ::glLoadMatrixf(iModelView.m);
+#else
+ ::glLoadIdentity();
+#endif
+
+ ::glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ iManager->Render();
+
+ ::eglCopyBuffers(iEglDisplay, iEglSurface, iPixmap);
+
+ return *iPixmap;
+}
+
+/*
+ * Callback from position provider. We use current position to set up world's origin
+ * and make request to different providers
+ */
+void COverlay::PositionUpdateL(TInt aError, const TPosition& aPosition)
+{
+ LOGARG("Got position: lat=%f,lon=%f,alt=%f", aPosition.Latitude(), aPosition.Longitude(), aPosition.Altitude());
+
+ // Set the "world" origin
+ iManager->SetOrigin(aPosition);
+ // Request POIs for that position
+ iManager->RequestL(aPosition);
+}
+
+/*
+ * From the current list of POIs retrieved, find the one that is closest to the
+ * screen center.
+ *
+ * We use both projection and modelview transforms to obtain screen coordinates.
+ * Note that both matrices are in column-major ordering, so we need to transpose them.
+ */
+TInt COverlay::GetFocusedPOI()
+{
+ const TPoint viewportCenter(iRect.Center());
+
+ TInt mostCentered = KMaxTInt;
+ TInt focused = KErrNotFound;
+
+ for (TInt i = 0; i < iManager->iObjectList.Count(); ++i)
+ {
+ const Vector3d position(iManager->iObjectList[i]->GetPosition());
+
+ const Vector4d world(position.mX, position.mY, position.mZ, 1);
+ const Vector4d camera(iModelView.Transpose() * world);
+ const Vector4d projection(iProjection.Transpose() * camera);
+
+ // Screen transformation
+ TReal x = projection.mX / projection.mW;
+ TReal y = projection.mY / projection.mW;
+ TReal z = projection.mZ / projection.mW;
+
+ TReal screenX = viewportCenter.iX * (x + 1);
+ TReal screenY = viewportCenter.iY * (y + 1);
+// TReal screenZ = (z + 1) / 2;
+
+ TBool visible = (x > -1 && x < 1) && (y > -1 && y < 1) && (z > -1 && z < 1);
+ TInt centered = (screenX - viewportCenter.iX) * (screenX - viewportCenter.iX) + (screenY - viewportCenter.iY) * (screenY - viewportCenter.iY);
+
+ if (visible && centered < mostCentered)
+ {
+ mostCentered = centered;
+ focused = i;
+ }
+ }
+
+ return focused;
+}