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-2013 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 "OgreEAGLES2Context.h"
30#include "OgreGLES2RenderSystem.h"
31#include "OgreRoot.h"
32
33namespace Ogre {
34    EAGLES2Context::EAGLES2Context(CAEAGLLayer *drawable, EAGLSharegroup *group)
35        :
36        mBackingWidth(0),
37        mBackingHeight(0),
38        mViewRenderbuffer(0),
39        mViewFramebuffer(0),
40        mDepthRenderbuffer(0),
41        mIsMultiSampleSupported(false),
42        mNumSamples(0),
43        mFSAAFramebuffer(0),
44        mFSAARenderbuffer(0)
45    {
46
47        mDrawable = [drawable retain];
48
49#if OGRE_NO_GLES3_SUPPORT == 0
50        NSUInteger renderingAPI = kEAGLRenderingAPIOpenGLES3;
51#else
52        NSUInteger renderingAPI = kEAGLRenderingAPIOpenGLES2;
53#endif
54        // If the group argument is not NULL, then we assume that an externally created EAGLSharegroup
55        // is to be used and a context is created using that group.
56        if(group)
57        {
58            mContext = [[EAGLContext alloc] initWithAPI:renderingAPI sharegroup:group];
59        }
60        else
61        {
62            mContext = [[EAGLContext alloc] initWithAPI:renderingAPI];
63        }
64
65        if (!mContext || ![EAGLContext setCurrentContext:mContext])
66        {
67            OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR,
68                        "Unable to create a suitable EAGLContext",
69                        __FUNCTION__);
70        }
71    }
72
73    EAGLES2Context::~EAGLES2Context()
74    {
75        GLES2RenderSystem *rs =
76            static_cast<GLES2RenderSystem*>(Root::getSingleton().getRenderSystem());
77
78        rs->_unregisterContext(this);
79
80        destroyFramebuffer();
81
82        if ([EAGLContext currentContext] == mContext)
83        {
84            [EAGLContext setCurrentContext:nil];
85        }
86
87        [mContext release];
88        [mDrawable release];
89    }
90
91    bool EAGLES2Context::createFramebuffer()
92    {
93        destroyFramebuffer();
94
95        OGRE_CHECK_GL_ERROR(glGenFramebuffers(1, &mViewFramebuffer));
96        OGRE_CHECK_GL_ERROR(glGenRenderbuffers(1, &mViewRenderbuffer));
97
98        OGRE_CHECK_GL_ERROR(glBindFramebuffer(GL_FRAMEBUFFER, mViewFramebuffer));
99        OGRE_CHECK_GL_ERROR(glBindRenderbuffer(GL_RENDERBUFFER, mViewRenderbuffer));
100
101        if(![mContext renderbufferStorage:GL_RENDERBUFFER fromDrawable:(id<EAGLDrawable>) mDrawable])
102        {
103            glGetError();
104            OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR,
105                        "Failed to bind the drawable to a renderbuffer object",
106                        __FUNCTION__);
107            return false;
108        }
109
110        OGRE_CHECK_GL_ERROR(glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &mBackingWidth));
111        OGRE_CHECK_GL_ERROR(glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &mBackingHeight));
112        OGRE_CHECK_GL_ERROR(glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, mViewRenderbuffer));
113
114#if GL_APPLE_framebuffer_multisample
115        if(mIsMultiSampleSupported && mNumSamples > 0)
116        {
117            // Determine how many MSAS samples to use
118            GLint maxSamplesAllowed;
119            glGetIntegerv(GL_MAX_SAMPLES_APPLE, &maxSamplesAllowed);
120            int samplesToUse = (mNumSamples > maxSamplesAllowed) ? maxSamplesAllowed : mNumSamples;
121
122            // Create the FSAA framebuffer (offscreen)
123            OGRE_CHECK_GL_ERROR(glGenFramebuffers(1, &mFSAAFramebuffer));
124            OGRE_CHECK_GL_ERROR(glBindFramebuffer(GL_FRAMEBUFFER, mFSAAFramebuffer));
125
126            /* Create the offscreen MSAA color buffer.
127             * After rendering, the contents of this will be blitted into mFSAAFramebuffer */
128            OGRE_CHECK_GL_ERROR(glGenRenderbuffers(1, &mFSAARenderbuffer));
129            OGRE_CHECK_GL_ERROR(glBindRenderbuffer(GL_RENDERBUFFER, mFSAARenderbuffer));
130            OGRE_CHECK_GL_ERROR(glRenderbufferStorageMultisampleAPPLE(GL_RENDERBUFFER, samplesToUse, GL_RGBA8_OES, mBackingWidth, mBackingHeight));
131            OGRE_CHECK_GL_ERROR(glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, mFSAARenderbuffer));
132
133            // Create the FSAA depth buffer
134            OGRE_CHECK_GL_ERROR(glGenRenderbuffers(1, &mDepthRenderbuffer));
135            OGRE_CHECK_GL_ERROR(glBindRenderbuffer(GL_RENDERBUFFER, mDepthRenderbuffer));
136            OGRE_CHECK_GL_ERROR(glRenderbufferStorageMultisampleAPPLE(GL_RENDERBUFFER, samplesToUse, GL_DEPTH_COMPONENT24_OES, mBackingWidth, mBackingHeight));
137            OGRE_CHECK_GL_ERROR(glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, mDepthRenderbuffer));
138
139            // Validate the FSAA framebuffer
140            if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
141            {
142                glGetError();
143                OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR,
144                            "Failed to make a complete FSAA framebuffer object",
145                            __FUNCTION__);
146                return false;
147            }
148        }
149        else
150#endif
151        {
152            OGRE_CHECK_GL_ERROR(glGenRenderbuffers(1, &mDepthRenderbuffer));
153            OGRE_CHECK_GL_ERROR(glBindRenderbuffer(GL_RENDERBUFFER, mDepthRenderbuffer));
154            OGRE_CHECK_GL_ERROR(glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, mBackingWidth, mBackingHeight));
155            OGRE_CHECK_GL_ERROR(glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, mDepthRenderbuffer));
156        }
157
158        OGRE_CHECK_GL_ERROR(glBindFramebuffer(GL_FRAMEBUFFER, mViewFramebuffer));
159        if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
160        {
161            glGetError();
162            OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR,
163                        "Failed to make a complete framebuffer object",
164                        __FUNCTION__);
165            return false;
166        }
167
168        return true;
169    }
170
171    void EAGLES2Context::destroyFramebuffer()
172    {
173        OGRE_CHECK_GL_ERROR(glDeleteFramebuffers(1, &mViewFramebuffer));
174        mViewFramebuffer = 0;
175        OGRE_CHECK_GL_ERROR(glDeleteRenderbuffers(1, &mViewRenderbuffer));
176        mViewRenderbuffer = 0;
177
178        if(mFSAARenderbuffer)
179        {
180            OGRE_CHECK_GL_ERROR(glDeleteRenderbuffers(1, &mFSAARenderbuffer));
181            mFSAARenderbuffer = 0;
182        }
183
184        if(mFSAAFramebuffer)
185        {
186            OGRE_CHECK_GL_ERROR(glDeleteFramebuffers(1, &mFSAAFramebuffer));
187            mFSAAFramebuffer = 0;
188        }
189
190        if(mDepthRenderbuffer)
191        {
192            OGRE_CHECK_GL_ERROR(glDeleteRenderbuffers(1, &mDepthRenderbuffer));
193            mDepthRenderbuffer = 0;
194        }
195    }
196
197    void EAGLES2Context::setCurrent()
198    {
199        BOOL ret = [EAGLContext setCurrentContext:mContext];
200        if (!ret)
201        {
202            OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR,
203                        "Failed to make context current",
204                        __FUNCTION__);
205        }
206    }
207
208    void EAGLES2Context::endCurrent()
209    {
210        // Do nothing
211    }
212
213    GLES2Context * EAGLES2Context::clone() const
214    {
215		return new EAGLES2Context(mDrawable, [mContext sharegroup]);
216    }
217
218	CAEAGLLayer * EAGLES2Context::getDrawable() const
219	{
220		return mDrawable;
221	}
222
223	EAGLContext * EAGLES2Context::getContext() const
224	{
225		return mContext;
226	}
227}
228