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