1/*
2-----------------------------------------------------------------------------
3This source file is part of OGRE
4    (Object-oriented Graphics Rendering Engine)
5For the latest info, see http://www.ogre3d.org/
6
7Copyright (c) 2000-2014 Torus Knot Software Ltd
8
9Permission is hereby granted, free of charge, to any person obtaining a copy
10of this software and associated documentation files (the "Software"), to deal
11in the Software without restriction, including without limitation the rights
12to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13copies of the Software, and to permit persons to whom the Software is
14furnished to do so, subject to the following conditions:
15
16The above copyright notice and this permission notice shall be included in
17all copies or substantial portions of the Software.
18
19THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25THE SOFTWARE.
26-----------------------------------------------------------------------------
27*/
28
29#include "OgreRoot.h"
30#include "OgreException.h"
31#include "OgreLogManager.h"
32#include "OgreStringConverter.h"
33#include "OgreWindowEventUtilities.h"
34
35#include "OgreGLESPrerequisites.h"
36#include "OgreGLESRenderSystem.h"
37
38#include "OgreAndroidEGLSupport.h"
39#include "OgreAndroidEGLWindow.h"
40#include "OgreAndroidEGLContext.h"
41#include "OgreAndroidResourceManager.h"
42#include "OgreViewport.h"
43
44#include <iostream>
45#include <algorithm>
46#include <climits>
47
48namespace Ogre {
49    AndroidEGLWindow::AndroidEGLWindow(AndroidEGLSupport *glsupport)
50        : EGLWindow(glsupport),
51          mMaxBufferSize(32),
52          mMaxDepthSize(24),
53          mMaxStencilSize(8)
54    {
55    }
56
57    AndroidEGLWindow::~AndroidEGLWindow()
58    {
59    }
60
61    EGLContext* AndroidEGLWindow::createEGLContext() const
62    {
63        return new AndroidEGLContext(mEglDisplay, mGLSupport, mEglConfig, mEglSurface);
64    }
65
66    void AndroidEGLWindow::getLeftAndTopFromNativeWindow( int & left, int & top, uint width, uint height )
67    {
68        // We don't have a native window.... but I think all android windows are origined
69        left = top = 0;
70    }
71
72    void AndroidEGLWindow::initNativeCreatedWindow(const NameValuePairList *miscParams)
73    {
74    }
75
76    void AndroidEGLWindow::createNativeWindow( int &left, int &top, uint &width, uint &height, String &title )
77    {
78    }
79
80    void AndroidEGLWindow::reposition( int left, int top )
81    {
82    }
83
84    void AndroidEGLWindow::resize(uint width, uint height)
85    {
86    }
87
88    void AndroidEGLWindow::windowMovedOrResized()
89    {
90        if(mActive)
91        {
92            eglQuerySurface(mEglDisplay, mEglSurface, EGL_WIDTH, (EGLint*)&mWidth);
93            EGL_CHECK_ERROR
94
95            eglQuerySurface(mEglDisplay, mEglSurface, EGL_HEIGHT, (EGLint*)&mHeight);
96            EGL_CHECK_ERROR
97
98            // Notify viewports of resize
99            ViewportList::iterator it = mViewportList.begin();
100            while( it != mViewportList.end() )
101                (*it++).second->_updateDimensions();
102        }
103    }
104
105    void AndroidEGLWindow::switchFullScreen(bool fullscreen)
106    {
107
108    }
109
110    void AndroidEGLWindow::create(const String& name, uint width, uint height,
111                               bool fullScreen, const NameValuePairList *miscParams)
112    {
113        mName = name;
114        mWidth = width;
115        mHeight = height;
116        mLeft = 0;
117        mTop = 0;
118        mIsFullScreen = fullScreen;
119        void* eglContext = NULL;
120        AConfiguration* config = NULL;
121
122        if (miscParams)
123        {
124            NameValuePairList::const_iterator opt;
125            NameValuePairList::const_iterator end = miscParams->end();
126
127            if ((opt = miscParams->find("currentGLContext")) != end &&
128                StringConverter::parseBool(opt->second))
129            {
130                eglContext = eglGetCurrentContext();
131                if (eglContext)
132                {
133                    OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR,
134                                "currentGLContext was specified with no current GL context",
135                                "EGLWindow::create");
136                }
137
138                eglContext = eglGetCurrentContext();
139                mEglSurface = eglGetCurrentSurface(EGL_DRAW);
140            }
141
142
143            if((opt = miscParams->find("externalWindowHandle")) != end)
144            {
145                mWindow = (ANativeWindow*)(Ogre::StringConverter::parseInt(opt->second));
146            }
147
148            if((opt = miscParams->find("androidConfig")) != end)
149            {
150                config = (AConfiguration*)(Ogre::StringConverter::parseInt(opt->second));
151            }
152
153            int ctxHandle = -1;
154            if((miscParams->find("externalGLContext")) != end)
155            {
156                mIsExternalGLControl = true;
157                ctxHandle = Ogre::StringConverter::parseInt(opt->second);
158            }
159
160            if((opt = miscParams->find("maxColourBufferSize")) != end)
161            {
162                mMaxBufferSize = Ogre::StringConverter::parseInt(opt->second);
163            }
164
165            if((opt = miscParams->find("maxDepthBufferSize")) != end)
166            {
167                mMaxDepthSize = Ogre::StringConverter::parseInt(opt->second);
168            }
169
170            if((opt = miscParams->find("maxStencilBufferSize")) != end)
171            {
172                mMaxStencilSize = Ogre::StringConverter::parseInt(opt->second);
173            }
174        }
175
176        initNativeCreatedWindow(miscParams);
177
178        if (mEglSurface)
179        {
180            mEglConfig = mGLSupport->getGLConfigFromDrawable (mEglSurface, &width, &height);
181        }
182
183        if (!mEglConfig && eglContext)
184        {
185            mEglConfig = mGLSupport->getGLConfigFromContext(eglContext);
186
187            if (!mEglConfig)
188            {
189                // This should never happen.
190                OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR,
191                            "Unexpected failure to determine a EGLFBConfig",
192                            "EGLWindow::create");
193            }
194        }
195
196        mIsExternal = (mEglSurface != 0);
197
198        if (!mEglConfig)
199        {
200
201            _createInternalResources(mWindow, config);
202            mHwGamma = false;
203        }
204
205        mContext = createEGLContext();
206
207        mActive = true;
208        mVisible = true;
209        mClosed = false;
210    }
211
212    void AndroidEGLWindow::_destroyInternalResources()
213    {
214        GLESRenderSystem::getResourceManager()->notifyOnContextLost();
215        mContext->_destroyInternalResources();
216
217        eglDestroySurface(mEglDisplay, mEglSurface);
218        EGL_CHECK_ERROR
219
220        eglTerminate(mEglDisplay);
221        EGL_CHECK_ERROR
222
223        mEglDisplay = 0;
224        mEglSurface = 0;
225
226        mActive = false;
227        mVisible = false;
228        mClosed = true;
229    }
230
231    void AndroidEGLWindow::_createInternalResources(NativeWindowType window, AConfiguration* config)
232    {
233        mWindow = window;
234
235        int minAttribs[] = {
236            EGL_RENDERABLE_TYPE, EGL_OPENGL_ES_BIT,
237            EGL_BUFFER_SIZE, 16,
238            EGL_DEPTH_SIZE, 16,
239            EGL_NONE
240        };
241
242        int maxAttribs[] = {
243            EGL_RENDERABLE_TYPE, EGL_OPENGL_ES_BIT,
244            EGL_BUFFER_SIZE, mMaxBufferSize,
245            EGL_DEPTH_SIZE, mMaxDepthSize,
246            EGL_STENCIL_SIZE, mMaxStencilSize,
247            EGL_NONE
248        };
249
250        mEglDisplay = mGLSupport->getGLDisplay();
251        mEglConfig = mGLSupport->selectGLConfig(minAttribs, maxAttribs);
252
253        EGLint format;
254        eglGetConfigAttrib(mEglDisplay, mEglConfig, EGL_NATIVE_VISUAL_ID, &format);
255        EGL_CHECK_ERROR
256
257        ANativeWindow_setBuffersGeometry(mWindow, 0, 0, format);
258
259        mEglSurface = createSurfaceFromWindow(mEglDisplay, mWindow);
260
261        if(config)
262        {
263            bool isLandscape = (int)AConfiguration_getOrientation(config) == 2;
264            mGLSupport->setConfigOption("Orientation", isLandscape ? "Landscape" : "Portrait");
265        }
266
267        eglQuerySurface(mEglDisplay, mEglSurface, EGL_WIDTH, (EGLint*)&mWidth);
268        eglQuerySurface(mEglDisplay, mEglSurface, EGL_HEIGHT, (EGLint*)&mHeight);
269        EGL_CHECK_ERROR
270
271        if(mContext)
272        {
273            mActive = true;
274            mVisible = true;
275            mClosed = false;
276
277            mContext->_createInternalResources(mEglDisplay, mEglConfig, mEglSurface, NULL);
278            mContext->setCurrent();
279
280            windowMovedOrResized();
281            static_cast<GLESRenderSystem*>(Ogre::Root::getSingletonPtr()->getRenderSystem())->resetRenderer(this);
282        }
283    }
284}