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 "OgreEAGLESContext.h"
30#include "OgreGLESRenderSystem.h"
31#include "OgreRoot.h"
32
33namespace Ogre {
34    EAGLESContext::EAGLESContext(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 the group argument is not NULL, then we assume that an externally created EAGLSharegroup
50        // is to be used and a context is created using that group.
51        if(group)
52        {
53            mContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1 sharegroup:group];
54        }
55        else
56        {
57            mContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1];
58        }
59
60        if (!mContext || ![EAGLContext setCurrentContext:mContext])
61        {
62            OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR,
63                        "Unable to create a suitable EAGLContext",
64                        __FUNCTION__);
65        }
66    }
67
68    EAGLESContext::~EAGLESContext()
69    {
70        GLESRenderSystem *rs =
71            static_cast<GLESRenderSystem*>(Root::getSingleton().getRenderSystem());
72
73        rs->_unregisterContext(this);
74
75        destroyFramebuffer();
76
77        if ([EAGLContext currentContext] == mContext)
78        {
79            [EAGLContext setCurrentContext:nil];
80        }
81
82        [mContext release];
83        [mDrawable release];
84    }
85
86    bool EAGLESContext::createFramebuffer()
87    {
88        destroyFramebuffer();
89
90        glGenFramebuffersOES(1, &mViewFramebuffer);
91        GL_CHECK_ERROR
92        glGenRenderbuffersOES(1, &mViewRenderbuffer);
93        GL_CHECK_ERROR
94
95        glBindFramebufferOES(GL_FRAMEBUFFER_OES, mViewFramebuffer);
96        GL_CHECK_ERROR
97        glBindRenderbufferOES(GL_RENDERBUFFER_OES, mViewRenderbuffer);
98        GL_CHECK_ERROR
99
100        if(![mContext renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:(id<EAGLDrawable>) mDrawable])
101        {
102            GL_CHECK_ERROR
103            OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR,
104                        "Failed to bind the drawable to a renderbuffer object",
105                        __FUNCTION__);
106            return false;
107        }
108
109        glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &mBackingWidth);
110        GL_CHECK_ERROR
111        glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &mBackingHeight);
112        GL_CHECK_ERROR
113        glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, mViewRenderbuffer);
114        GL_CHECK_ERROR
115
116#if GL_APPLE_framebuffer_multisample
117        if(mIsMultiSampleSupported && mNumSamples > 0)
118        {
119            // Determine how many MSAS samples to use
120            GLint maxSamplesAllowed;
121            glGetIntegerv(GL_MAX_SAMPLES_APPLE, &maxSamplesAllowed);
122            int samplesToUse = (mNumSamples > maxSamplesAllowed) ? maxSamplesAllowed : mNumSamples;
123
124            // Create the FSAA framebuffer (offscreen)
125            glGenFramebuffersOES(1, &mFSAAFramebuffer);
126            GL_CHECK_ERROR
127            glBindFramebufferOES(GL_FRAMEBUFFER_OES, mFSAAFramebuffer);
128            GL_CHECK_ERROR
129
130            /* Create the offscreen MSAA color buffer.
131             * After rendering, the contents of this will be blitted into mFSAAFramebuffer */
132            glGenRenderbuffersOES(1, &mFSAARenderbuffer);
133            GL_CHECK_ERROR
134            glBindRenderbufferOES(GL_RENDERBUFFER_OES, mFSAARenderbuffer);
135            GL_CHECK_ERROR
136            glRenderbufferStorageMultisampleAPPLE(GL_RENDERBUFFER_OES, samplesToUse, GL_RGBA8_OES, mBackingWidth, mBackingHeight);
137            GL_CHECK_ERROR
138            glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, mFSAARenderbuffer);
139            GL_CHECK_ERROR
140
141            // Create the FSAA depth buffer
142            glGenRenderbuffersOES(1, &mDepthRenderbuffer);
143            GL_CHECK_ERROR
144            glBindRenderbufferOES(GL_RENDERBUFFER_OES, mDepthRenderbuffer);
145            GL_CHECK_ERROR
146            glRenderbufferStorageMultisampleAPPLE(GL_RENDERBUFFER_OES, samplesToUse, GL_DEPTH_COMPONENT24_OES, mBackingWidth, mBackingHeight);
147            GL_CHECK_ERROR
148            glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_DEPTH_ATTACHMENT_OES, GL_RENDERBUFFER_OES, mDepthRenderbuffer);
149            GL_CHECK_ERROR
150
151            // Validate the FSAA framebuffer
152            if(glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES) != GL_FRAMEBUFFER_COMPLETE_OES)
153            {
154                GL_CHECK_ERROR
155                OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR,
156                            "Failed to make a complete FSAA framebuffer object",
157                            __FUNCTION__);
158                return false;
159            }
160        }
161        else
162#endif
163        {
164            glGenRenderbuffersOES(1, &mDepthRenderbuffer);
165            GL_CHECK_ERROR
166            glBindRenderbufferOES(GL_RENDERBUFFER_OES, mDepthRenderbuffer);
167            GL_CHECK_ERROR
168            glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_DEPTH_COMPONENT16_OES, mBackingWidth, mBackingHeight);
169            GL_CHECK_ERROR
170            glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_DEPTH_ATTACHMENT_OES, GL_RENDERBUFFER_OES, mDepthRenderbuffer);
171            GL_CHECK_ERROR
172        }
173
174        glBindFramebufferOES(GL_FRAMEBUFFER_OES, mViewFramebuffer);
175        if(glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES) != GL_FRAMEBUFFER_COMPLETE_OES)
176        {
177            GL_CHECK_ERROR
178            OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR,
179                        "Failed to make a complete framebuffer object",
180                        __FUNCTION__);
181            return false;
182        }
183
184        return true;
185    }
186
187    void EAGLESContext::destroyFramebuffer()
188    {
189        glDeleteFramebuffersOES(1, &mViewFramebuffer);
190        mViewFramebuffer = 0;
191        glDeleteRenderbuffersOES(1, &mViewRenderbuffer);
192        mViewRenderbuffer = 0;
193
194        if(mFSAARenderbuffer)
195        {
196            glDeleteRenderbuffersOES(1, &mFSAARenderbuffer);
197            mFSAARenderbuffer = 0;
198        }
199
200        if(mFSAAFramebuffer)
201        {
202            glDeleteFramebuffersOES(1, &mFSAAFramebuffer);
203            mFSAAFramebuffer = 0;
204        }
205
206        if(mDepthRenderbuffer)
207        {
208            glDeleteRenderbuffersOES(1, &mDepthRenderbuffer);
209            mDepthRenderbuffer = 0;
210        }
211    }
212
213    void EAGLESContext::setCurrent()
214    {
215        GLboolean ret = [EAGLContext setCurrentContext:mContext];
216        if (!ret)
217        {
218            OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR,
219                        "Failed to make context current",
220                        __FUNCTION__);
221        }
222    }
223
224    void EAGLESContext::endCurrent()
225    {
226        // Do nothing
227    }
228
229    GLESContext * EAGLESContext::clone() const
230    {
231        return const_cast<EAGLESContext *>(this);
232    }
233
234	CAEAGLLayer * EAGLESContext::getDrawable() const
235	{
236		return mDrawable;
237	}
238
239	EAGLContext * EAGLESContext::getContext() const
240	{
241		return mContext;
242	}
243}
244