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