1/*
2 * Copyright (C) 2013 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5 * in compliance with the License. You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software distributed under the License
10 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11 * or implied. See the License for the specific language governing permissions and limitations under
12 * the License.
13 */
14#include <EGL/egl.h>
15#include <GLES2/gl2.h>
16#include <GLES2/gl2ext.h>
17
18#include "FullPipelineRenderer.h"
19
20#include <graphics/PerspectiveMeshNode.h>
21#include <graphics/GLUtils.h>
22#include <graphics/TransformationNode.h>
23
24#include <Trace.h>
25
26static const int FP_NUM_VERTICES = 6;
27
28static const float FP_VERTICES[FP_NUM_VERTICES * 3] = {
29        1.0f, 1.0f, 0.0f,
30        0.0f, 1.0f, 0.0f,
31        0.0f, 0.0f, 0.0f,
32        0.0f, 0.0f, 0.0f,
33        1.0f, 0.0f, 0.0f,
34        1.0f, 1.0f, 0.0f };
35
36static const float FP_NORMALS[FP_NUM_VERTICES * 3] = {
37        0.0f, 0.0f, 1.0f,
38        0.0f, 0.0f, 1.0f,
39        0.0f, 0.0f, 1.0f,
40        0.0f, 0.0f, 1.0f,
41        0.0f, 0.0f, 1.0f,
42        0.0f, 0.0f, 1.0f };
43
44static const float FP_TEX_COORDS[FP_NUM_VERTICES * 2] = {
45        1.0f, 1.0f,
46        0.0f, 1.0f,
47        0.0f, 0.0f,
48        0.0f, 0.0f,
49        1.0f, 0.0f,
50        1.0f, 1.0f };
51
52static const char* FP_VERTEX =
53        "uniform mat4 u_MVPMatrix;"
54        "uniform mat4 u_MVMatrix;"
55        "attribute vec4 a_Position;"
56        "attribute vec3 a_Normal;"
57        "attribute vec2 a_TexCoordinate;"
58        "varying vec3 v_Position;"
59        "varying vec3 v_Normal;"
60        "varying vec2 v_TexCoordinate;"
61        "void main() {\n"
62        "  // Transform the vertex into eye space.\n"
63        "  v_Position = vec3(u_MVMatrix * a_Position);\n"
64        "  // Pass through the texture coordinate.\n"
65        "  v_TexCoordinate = a_TexCoordinate;\n"
66        "  // Transform the normal\'s orientation into eye space.\n"
67        "  v_Normal = vec3(u_MVMatrix * vec4(a_Normal, 0.0));\n"
68        "  // Multiply to get the final point in normalized screen coordinates.\n"
69        "  gl_Position = u_MVPMatrix * a_Position;\n"
70        "}";
71
72static const char* FP_FRAGMENT =
73        "precision mediump float;"
74        "uniform vec3 u_LightPos;"
75        "uniform sampler2D u_Texture;"
76        "varying vec3 v_Position;"
77        "varying vec3 v_Normal;"
78        "varying vec2 v_TexCoordinate;"
79        "void main() {\n"
80        "  // Will be used for attenuation.\n"
81        "  float distance = length(u_LightPos - v_Position);\n"
82        "  // Get a lighting direction vector from the light to the vertex.\n"
83        "  vec3 lightVector = normalize(u_LightPos - v_Position);\n"
84        "  // Calculate the dot product of the light vector and vertex normal.\n"
85        "  float diffuse = max(dot(v_Normal, lightVector), 0.0);\n"
86        "  // Add attenuation.\n"
87        "  diffuse = diffuse * (1.0 / (1.0 + (0.01 * distance)));\n"
88        "  // Add ambient lighting\n"
89        "  diffuse = diffuse + 0.25;\n"
90        "  // Multiply the diffuse illumination and texture to get final output color.\n"
91        "  gl_FragColor = (diffuse * texture2D(u_Texture, v_TexCoordinate));\n"
92        "}";
93
94FullPipelineRenderer::FullPipelineRenderer(ANativeWindow* window, bool offscreen) :
95        Renderer(window, offscreen), mProgram(NULL), mSceneGraph(NULL),
96        mModelMatrix(NULL), mViewMatrix(NULL), mProjectionMatrix(NULL), mMesh(NULL),
97        mTextureId(0) {
98}
99
100bool FullPipelineRenderer::setUp(int workload) {
101    SCOPED_TRACE();
102    if (!Renderer::setUp(workload)) {
103        return false;
104    }
105
106    mProgramId = GLUtils::createProgram(&FP_VERTEX, &FP_FRAGMENT);
107    if (mProgramId == 0) {
108        return false;
109    }
110    mProgram = new PerspectiveProgram(mProgramId);
111
112    mModelMatrix = new Matrix();
113
114    // Position the eye in front of the origin.
115    float eyeX = 0.0f;
116    float eyeY = 0.0f;
117    float eyeZ = 1.5f;
118
119    // We are looking at the origin
120    float centerX = 0.0f;
121    float centerY = 0.0f;
122    float centerZ = 0.0f;
123
124    // Set our up vector.
125    float upX = 0.0f;
126    float upY = 1.0f;
127    float upZ = 0.0f;
128
129    // Set the view matrix.
130    mViewMatrix = Matrix::newLookAt(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ);
131
132    // Create a new perspective projection matrix. The height will stay the same
133    // while the width will vary as per aspect ratio.
134    float ratio = (float) mWidth / mHeight;
135    float left = -ratio;
136    float right = ratio;
137    float bottom = -1.0f;
138    float top = 1.0f;
139    float near = 1.0f;
140    float far = 2.0f;
141
142    mProjectionMatrix = Matrix::newFrustum(left, right, bottom, top, near, far);
143
144    // Setup texture.
145    mTextureId = GLUtils::genTexture(mWidth, mHeight, GLUtils::RANDOM_FILL);
146    if (mTextureId == 0) {
147        return false;
148    }
149
150    float count = workload * workload;
151    float middle = count / 2.0f;
152    float scale = 2.0f / count;
153
154    mMesh = new Mesh(FP_VERTICES, FP_NORMALS, FP_TEX_COORDS, FP_NUM_VERTICES);
155    mSceneGraph = new ProgramNode(*mProgram);
156
157    for (int i = 0; i < count; i++) {
158        for (int j = 0; j < count; j++) {
159            Matrix* transformMatrix = Matrix::newScale(scale, scale, scale);
160            transformMatrix->translate(i - middle, j - middle, 0.0f);
161            TransformationNode* transformNode = new TransformationNode(transformMatrix);
162            mSceneGraph->addChild(transformNode);
163            PerspectiveMeshNode* meshNode = new PerspectiveMeshNode(mMesh, mTextureId);
164            transformNode->addChild(meshNode);
165        }
166    }
167    return true;
168}
169
170bool FullPipelineRenderer::tearDown() {
171    SCOPED_TRACE();
172    if (mTextureId != 0) {
173        glDeleteTextures(1, &mTextureId);
174        mTextureId = 0;
175    }
176    if (!Renderer::tearDown()) {
177        return false;
178    }
179    delete mModelMatrix;
180    mModelMatrix = NULL;
181    delete mViewMatrix;
182    mViewMatrix = NULL;
183    delete mProjectionMatrix;
184    mProjectionMatrix = NULL;
185    delete mProgram;
186    mProgram = NULL;
187    delete mSceneGraph;
188    mSceneGraph = NULL;
189    delete mMesh;
190    mMesh = NULL;
191    return true;
192}
193
194void FullPipelineRenderer::drawWorkload() {
195    SCOPED_TRACE();
196    // Set the background clear color to black.
197    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
198    // Use culling to remove back faces.
199    glEnable(GL_CULL_FACE);
200    // Use depth testing.
201    glEnable(GL_DEPTH_TEST);
202    glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
203    mModelMatrix->identity();
204    mSceneGraph->drawProgram(*mModelMatrix, *mViewMatrix, *mProjectionMatrix);
205}
206