1/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "Renderer.h"
18
19#include "mosaic/Log.h"
20#define LOG_TAG "Renderer"
21
22#include <GLES2/gl2ext.h>
23
24Renderer::Renderer()
25      : mGlProgram(0),
26        mInputTextureName(-1),
27        mInputTextureWidth(0),
28        mInputTextureHeight(0),
29        mSurfaceWidth(0),
30        mSurfaceHeight(0)
31{
32    InitializeGLContext();
33}
34
35Renderer::~Renderer() {
36}
37
38GLuint Renderer::loadShader(GLenum shaderType, const char* pSource) {
39    GLuint shader = glCreateShader(shaderType);
40    if (shader) {
41        glShaderSource(shader, 1, &pSource, NULL);
42        glCompileShader(shader);
43        GLint compiled = 0;
44        glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
45        if (!compiled) {
46            GLint infoLen = 0;
47            glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
48            if (infoLen) {
49                char* buf = (char*) malloc(infoLen);
50                if (buf) {
51                    glGetShaderInfoLog(shader, infoLen, NULL, buf);
52                    LOGE("Could not compile shader %d:\n%s\n",
53                            shaderType, buf);
54                    free(buf);
55                }
56                glDeleteShader(shader);
57                shader = 0;
58            }
59        }
60    }
61    return shader;
62}
63
64GLuint Renderer::createProgram(const char* pVertexSource, const char* pFragmentSource)
65{
66    GLuint vertexShader = loadShader(GL_VERTEX_SHADER, pVertexSource);
67    if (!vertexShader)
68    {
69        return 0;
70    }
71
72    GLuint pixelShader = loadShader(GL_FRAGMENT_SHADER, pFragmentSource);
73    if (!pixelShader)
74    {
75        return 0;
76    }
77
78    GLuint program = glCreateProgram();
79    if (program)
80    {
81        glAttachShader(program, vertexShader);
82        checkGlError("glAttachShader");
83        glAttachShader(program, pixelShader);
84        checkGlError("glAttachShader");
85
86        glLinkProgram(program);
87        GLint linkStatus = GL_FALSE;
88        glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
89
90        LOGI("Program Linked!");
91
92        if (linkStatus != GL_TRUE)
93        {
94            GLint bufLength = 0;
95            glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength);
96            if (bufLength)
97            {
98                char* buf = (char*) malloc(bufLength);
99                if (buf)
100                {
101                    glGetProgramInfoLog(program, bufLength, NULL, buf);
102                    LOGE("Could not link program:\n%s\n", buf);
103                    free(buf);
104                }
105            }
106            glDeleteProgram(program);
107            program = 0;
108        }
109    }
110    return program;
111}
112
113// Set this renderer to use the default frame-buffer (screen) and
114// set the viewport size to be the given width and height (pixels).
115bool Renderer::SetupGraphics(int width, int height)
116{
117    bool succeeded = false;
118    do {
119        if (mGlProgram == 0)
120        {
121            if (!InitializeGLProgram())
122            {
123              break;
124            }
125        }
126        glUseProgram(mGlProgram);
127        if (!checkGlError("glUseProgram")) break;
128
129        glBindFramebuffer(GL_FRAMEBUFFER, 0);
130
131        mFrameBuffer = NULL;
132        mSurfaceWidth = width;
133        mSurfaceHeight = height;
134
135        glViewport(0, 0, mSurfaceWidth, mSurfaceHeight);
136        if (!checkGlError("glViewport")) break;
137        succeeded = true;
138    } while (false);
139
140    return succeeded;
141}
142
143
144// Set this renderer to use the specified FBO and
145// set the viewport size to be the width and height of this FBO.
146bool Renderer::SetupGraphics(FrameBuffer* buffer)
147{
148    bool succeeded = false;
149    do {
150        if (mGlProgram == 0)
151        {
152            if (!InitializeGLProgram())
153            {
154              break;
155            }
156        }
157        glUseProgram(mGlProgram);
158        if (!checkGlError("glUseProgram")) break;
159
160        glBindFramebuffer(GL_FRAMEBUFFER, buffer->GetFrameBufferName());
161
162        mFrameBuffer = buffer;
163        mSurfaceWidth = mFrameBuffer->GetWidth();
164        mSurfaceHeight = mFrameBuffer->GetHeight();
165
166        glViewport(0, 0, mSurfaceWidth, mSurfaceHeight);
167        if (!checkGlError("glViewport")) break;
168        succeeded = true;
169    } while (false);
170
171    return succeeded;
172}
173
174bool Renderer::Clear(float r, float g, float b, float a)
175{
176    bool succeeded = false;
177    do {
178        bool rt = (mFrameBuffer == NULL)?
179                SetupGraphics(mSurfaceWidth, mSurfaceHeight) :
180                SetupGraphics(mFrameBuffer);
181
182        if(!rt)
183            break;
184
185        glClearColor(r, g, b, a);
186        glClear(GL_COLOR_BUFFER_BIT);
187
188        succeeded = true;
189    } while (false);
190    return succeeded;
191
192}
193
194void Renderer::InitializeGLContext()
195{
196    if(mFrameBuffer != NULL)
197    {
198        delete mFrameBuffer;
199        mFrameBuffer = NULL;
200    }
201
202    mInputTextureName = -1;
203    mInputTextureType = GL_TEXTURE_2D;
204    mGlProgram = 0;
205}
206
207int Renderer::GetTextureName()
208{
209    return mInputTextureName;
210}
211
212void Renderer::SetInputTextureName(GLuint textureName)
213{
214    mInputTextureName = textureName;
215}
216
217void Renderer::SetInputTextureType(GLenum textureType)
218{
219    mInputTextureType = textureType;
220}
221
222void Renderer::SetInputTextureDimensions(int width, int height)
223{
224    mInputTextureWidth = width;
225    mInputTextureHeight = height;
226}
227