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