• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 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 
18 #include "renderer.h"
19 
20 #include <cassert>
21 #include <memory>
22 #include <vector>
23 
24 #include <EGL/eglext.h>
25 #include <GLES2/gl2.h>
26 
27 
28 namespace android {
29 namespace gamecore {
30 
31 namespace {
32 
33 const float RADIUS = 0.1f;
34 
printGLString(const char * name,GLenum s)35 void printGLString(const char *name, GLenum s) {
36     const char *v = (const char *) glGetString(s);
37     LOGI("GL %s = %s\n", name, v);
38 }
39 
40 } // end of anonymous namespace
41 
Renderer(int numCircles)42 Renderer::Renderer(int numCircles) {
43     memset(&egl, 0, sizeof(egl));
44     state.numCircles = numCircles;
45 }
46 
initDisplay(NativeWindowType window)47 int Renderer::initDisplay(NativeWindowType window) {
48     egl.window = window;
49 
50     // initialize OpenGL ES and EGL
51 
52     /*
53      * Here specify the attributes of the desired configuration.
54      * Below, we select an EGLConfig with at least 8 bits per color
55      * component compatible with on-screen windows
56      */
57     const EGLint attribs[] = {
58             EGL_RENDERABLE_TYPE,
59             EGL_OPENGL_ES2_BIT,
60             EGL_BLUE_SIZE, 8,
61             EGL_GREEN_SIZE, 8,
62             EGL_RED_SIZE, 8,
63             EGL_NONE
64     };
65     EGLint w;
66     EGLint h;
67     EGLint format;
68     EGLint numConfigs;
69     EGLConfig config;
70     EGLSurface surface;
71     EGLContext context;
72 
73     EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
74 
75     eglInitialize(display, 0, 0);
76 
77     /* Here, the application chooses the configuration it desires.
78      * find the best match if possible, otherwise use the very first one
79      */
80     eglChooseConfig(display, attribs, nullptr,0, &numConfigs);
81     std::unique_ptr<EGLConfig[]> supportedConfigs(new EGLConfig[numConfigs]);
82     assert(supportedConfigs);
83     eglChooseConfig(display, attribs, supportedConfigs.get(), numConfigs, &numConfigs);
84     assert(numConfigs);
85     auto i = 0;
86     for (; i < numConfigs; i++) {
87         auto& cfg = supportedConfigs[i];
88         EGLint r, g, b, d;
89         if (eglGetConfigAttrib(display, cfg, EGL_RED_SIZE, &r)   &&
90             eglGetConfigAttrib(display, cfg, EGL_GREEN_SIZE, &g) &&
91             eglGetConfigAttrib(display, cfg, EGL_BLUE_SIZE, &b)  &&
92             eglGetConfigAttrib(display, cfg, EGL_DEPTH_SIZE, &d) &&
93             r == 8 && g == 8 && b == 8 && d == 0 ) {
94 
95             config = supportedConfigs[i];
96             break;
97         }
98     }
99     if (i == numConfigs) {
100         config = supportedConfigs[0];
101     }
102 
103     EGLint attrib_list[] = {
104             EGL_CONTEXT_CLIENT_VERSION, 2,
105             EGL_NONE
106     };
107 
108     /* EGL_NATIVE_VISUAL_ID is an attribute of the EGLConfig that is
109      * guaranteed to be accepted by ANativeWindow_setBuffersGeometry().
110      * As soon as we picked a EGLConfig, we can safely reconfigure the
111      * ANativeWindow buffers to match, using EGL_NATIVE_VISUAL_ID. */
112     eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &format);
113     surface = eglCreateWindowSurface(display, config, window, NULL);
114     context = eglCreateContext(display, config, NULL, attrib_list);
115 
116     // Enable Android timing.
117     eglSurfaceAttrib(display, surface, EGL_TIMESTAMPS_ANDROID, EGL_TRUE);
118 
119     if (eglMakeCurrent(display, surface, surface, context) == EGL_FALSE) {
120         LOGW("Unable to eglMakeCurrent");
121         return -1;
122     }
123 
124     eglQuerySurface(display, surface, EGL_WIDTH, &w);
125     eglQuerySurface(display, surface, EGL_HEIGHT, &h);
126 
127     egl.display = display;
128     egl.context = context;
129     egl.surface = surface;
130     egl.width = w;
131     egl.height = h;
132     float ratio = float(w) / h;
133     egl.left = -ratio;
134     egl.right = ratio;
135     egl.top = 1.0f;
136     egl.bottom = -1.0f;
137 
138     // Check openGL on the system
139     auto opengl_info = {GL_VENDOR, GL_RENDERER, GL_VERSION, GL_EXTENSIONS};
140     for (auto name : opengl_info) {
141         auto info = glGetString(name);
142         LOGI("OpenGL Info: %s", info);
143     }
144     printGLString("Version", GL_VERSION);
145     printGLString("Vendor", GL_VENDOR);
146     printGLString("Renderer", GL_RENDERER);
147     printGLString("Extensions", GL_EXTENSIONS);
148 
149     // Initialize GL state.
150     glEnable(GL_CULL_FACE);
151     glDisable(GL_DEPTH_TEST);
152 
153     // Initialize world state.
154     state.circles.resize(state.numCircles, Circle(RADIUS));
155     state.velocities.resize(state.numCircles);
156     for (auto& v : state.velocities) {
157         v = Vec2(
158                 0.05f * (float(rand()) / RAND_MAX - 0.5f),
159                 0.05f * (float(rand()) / RAND_MAX - 0.5f));
160     }
161 
162     return 0;
163 }
164 
terminateDisplay()165 void Renderer::terminateDisplay() {
166     if (egl.display != EGL_NO_DISPLAY) {
167         eglMakeCurrent(egl.display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
168         if (egl.context != EGL_NO_CONTEXT) {
169             eglDestroyContext(egl.display, egl.context);
170         }
171         if (egl.surface != EGL_NO_SURFACE) {
172             eglDestroySurface(egl.display, egl.surface);
173         }
174         eglTerminate(egl.display);
175     }
176     egl.display = EGL_NO_DISPLAY;
177     egl.context = EGL_NO_CONTEXT;
178     egl.surface = EGL_NO_SURFACE;
179 }
180 
update()181 void Renderer::update() {
182     // Done with events; draw next animation frame.
183     for (int i = 0; i < state.circles.size(); ++i) {
184         auto& circle = state.circles[i];
185         Vec2& v = state.velocities[i];
186         circle.setPosition(circle.getPosition() + Vec3(v, 0.0f));
187         Vec3 position = circle.getPosition();
188 
189         float x;
190         float y;
191         float z;
192         position.Value(x, y, z);
193         float vx;
194         float vy;
195         v.Value(vx, vy);
196         if (x + RADIUS >= egl.right || x - RADIUS <= egl.left) {
197             vx = -vx;
198         }
199         if (y + RADIUS >= egl.top || y - RADIUS <= egl.bottom) {
200             vy = -vy;
201         }
202         v = Vec2(vx, vy);
203     }
204 }
205 
draw()206 void Renderer::draw() {
207     if (egl.display == NULL) {
208         // No display.
209         return;
210     }
211 
212     // Just fill the screen with a color.
213     glClearColor(0.2f, 0.2f, 0.2f, 1.0f);
214     glClear( GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
215 
216     float ratio = float(egl.width) / egl.height;
217     Mat4 projectionMatrix = Mat4::Ortho2D(-ratio, 1.0f, ratio, -1.0f);
218     Mat4 viewMatrix =
219             Mat4::LookAt(
220                 Vec3(0.0f, 0.0f, -1.0f),
221                 Vec3(0.0f, 0.0f, 1.0f),
222                 Vec3(0.0f, 1.0f, 0.0f));
223 
224     for (int i = 0; i < state.circles.size(); ++i) {
225         auto& circle = state.circles[i];
226         circle.updateViewProjection(projectionMatrix * viewMatrix);
227         circle.draw();
228     }
229     eglSwapBuffers(egl.display, egl.surface);
230 }
231 
232 } // end of namespace gamecore
233 } // end of namespace android
234 
235 
236