1 /* 2 Copyright (r) 1997-2014 Sam Lantinga <slouken (at) libsdl.org> 3 4 This software is provided 'as-is', without any express or implied 5 warranty. In no event will the authors be held liable for any damages 6 arising from the use of this software. 7 8 Permission is granted to anyone to use this software for any purpose, 9 including commercial applications, and to alter it and redistribute it 10 freely. 11 */ 12 #include <stdlib.h> 13 #include <stdio.h> 14 #include <string.h> 15 #include <math.h> 16 17 #include "SDL_test_common.h" 18 19 #if defined(__IPHONEOS__) || defined(__ANDROID__) 20 #define HAVE_OPENGLES2 21 #endif 22 23 #ifdef HAVE_OPENGLES2 24 25 #include "SDL_opengles2.h" 26 27 typedef struct GLES2_Context 28 { 29 #define SDL_PROC(ret,func,params) ret (APIENTRY *func) params; 30 #include "../src/render/opengles2/SDL_gles2funcs.h" 31 #undef SDL_PROC 32 } GLES2_Context; 33 34 35 static SDLTest_CommonState *state; 36 static SDL_GLContext *context = NULL; 37 static int depth = 16; 38 static GLES2_Context ctx; 39 40 static int LoadContext(GLES2_Context * data) 41 { 42 #if SDL_VIDEO_DRIVER_UIKIT 43 #define __SDL_NOGETPROCADDR__ 44 #elif SDL_VIDEO_DRIVER_ANDROID 45 #define __SDL_NOGETPROCADDR__ 46 #elif SDL_VIDEO_DRIVER_PANDORA 47 #define __SDL_NOGETPROCADDR__ 48 #endif 49 50 #if defined __SDL_NOGETPROCADDR__ 51 #define SDL_PROC(ret,func,params) data->func=func; 52 #else 53 #define SDL_PROC(ret,func,params) \ 54 do { \ 55 data->func = SDL_GL_GetProcAddress(#func); \ 56 if ( ! data->func ) { \ 57 return SDL_SetError("Couldn't load GLES2 function %s: %s\n", #func, SDL_GetError()); \ 58 } \ 59 } while ( 0 ); 60 #endif /* _SDL_NOGETPROCADDR_ */ 61 62 #include "../src/render/opengles2/SDL_gles2funcs.h" 63 #undef SDL_PROC 64 return 0; 65 } 66 67 /* Call this instead of exit(), so we can clean up SDL: atexit() is evil. */ 68 static void 69 quit(int rc) 70 { 71 int i; 72 73 if (context != NULL) { 74 for (i = 0; i < state->num_windows; i++) { 75 if (context[i]) { 76 SDL_GL_DeleteContext(context[i]); 77 } 78 } 79 80 SDL_free(context); 81 } 82 83 SDLTest_CommonQuit(state); 84 exit(rc); 85 } 86 87 #define GL_CHECK(x) \ 88 x; \ 89 { \ 90 GLenum glError = ctx.glGetError(); \ 91 if(glError != GL_NO_ERROR) { \ 92 SDL_Log("glGetError() = %i (0x%.8x) at line %i\n", glError, glError, __LINE__); \ 93 quit(1); \ 94 } \ 95 } 96 97 /* 98 * Simulates desktop's glRotatef. The matrix is returned in column-major 99 * order. 100 */ 101 static void 102 rotate_matrix(double angle, double x, double y, double z, float *r) 103 { 104 double radians, c, s, c1, u[3], length; 105 int i, j; 106 107 radians = (angle * M_PI) / 180.0; 108 109 c = cos(radians); 110 s = sin(radians); 111 112 c1 = 1.0 - cos(radians); 113 114 length = sqrt(x * x + y * y + z * z); 115 116 u[0] = x / length; 117 u[1] = y / length; 118 u[2] = z / length; 119 120 for (i = 0; i < 16; i++) { 121 r[i] = 0.0; 122 } 123 124 r[15] = 1.0; 125 126 for (i = 0; i < 3; i++) { 127 r[i * 4 + (i + 1) % 3] = u[(i + 2) % 3] * s; 128 r[i * 4 + (i + 2) % 3] = -u[(i + 1) % 3] * s; 129 } 130 131 for (i = 0; i < 3; i++) { 132 for (j = 0; j < 3; j++) { 133 r[i * 4 + j] += c1 * u[i] * u[j] + (i == j ? c : 0.0); 134 } 135 } 136 } 137 138 /* 139 * Simulates gluPerspectiveMatrix 140 */ 141 static void 142 perspective_matrix(double fovy, double aspect, double znear, double zfar, float *r) 143 { 144 int i; 145 double f; 146 147 f = 1.0/tan(fovy * 0.5); 148 149 for (i = 0; i < 16; i++) { 150 r[i] = 0.0; 151 } 152 153 r[0] = f / aspect; 154 r[5] = f; 155 r[10] = (znear + zfar) / (znear - zfar); 156 r[11] = -1.0; 157 r[14] = (2.0 * znear * zfar) / (znear - zfar); 158 r[15] = 0.0; 159 } 160 161 /* 162 * Multiplies lhs by rhs and writes out to r. All matrices are 4x4 and column 163 * major. In-place multiplication is supported. 164 */ 165 static void 166 multiply_matrix(float *lhs, float *rhs, float *r) 167 { 168 int i, j, k; 169 float tmp[16]; 170 171 for (i = 0; i < 4; i++) { 172 for (j = 0; j < 4; j++) { 173 tmp[j * 4 + i] = 0.0; 174 175 for (k = 0; k < 4; k++) { 176 tmp[j * 4 + i] += lhs[k * 4 + i] * rhs[j * 4 + k]; 177 } 178 } 179 } 180 181 for (i = 0; i < 16; i++) { 182 r[i] = tmp[i]; 183 } 184 } 185 186 /* 187 * Create shader, load in source, compile, dump debug as necessary. 188 * 189 * shader: Pointer to return created shader ID. 190 * source: Passed-in shader source code. 191 * shader_type: Passed to GL, e.g. GL_VERTEX_SHADER. 192 */ 193 void 194 process_shader(GLuint *shader, const char * source, GLint shader_type) 195 { 196 GLint status = GL_FALSE; 197 const char *shaders[1] = { NULL }; 198 199 /* Create shader and load into GL. */ 200 *shader = GL_CHECK(ctx.glCreateShader(shader_type)); 201 202 shaders[0] = source; 203 204 GL_CHECK(ctx.glShaderSource(*shader, 1, shaders, NULL)); 205 206 /* Clean up shader source. */ 207 shaders[0] = NULL; 208 209 /* Try compiling the shader. */ 210 GL_CHECK(ctx.glCompileShader(*shader)); 211 GL_CHECK(ctx.glGetShaderiv(*shader, GL_COMPILE_STATUS, &status)); 212 213 // Dump debug info (source and log) if compilation failed. 214 if(status != GL_TRUE) { 215 SDL_Log("Shader compilation failed"); 216 quit(-1); 217 } 218 } 219 220 /* 3D data. Vertex range -0.5..0.5 in all axes. 221 * Z -0.5 is near, 0.5 is far. */ 222 const float _vertices[] = 223 { 224 /* Front face. */ 225 /* Bottom left */ 226 -0.5, 0.5, -0.5, 227 0.5, -0.5, -0.5, 228 -0.5, -0.5, -0.5, 229 /* Top right */ 230 -0.5, 0.5, -0.5, 231 0.5, 0.5, -0.5, 232 0.5, -0.5, -0.5, 233 /* Left face */ 234 /* Bottom left */ 235 -0.5, 0.5, 0.5, 236 -0.5, -0.5, -0.5, 237 -0.5, -0.5, 0.5, 238 /* Top right */ 239 -0.5, 0.5, 0.5, 240 -0.5, 0.5, -0.5, 241 -0.5, -0.5, -0.5, 242 /* Top face */ 243 /* Bottom left */ 244 -0.5, 0.5, 0.5, 245 0.5, 0.5, -0.5, 246 -0.5, 0.5, -0.5, 247 /* Top right */ 248 -0.5, 0.5, 0.5, 249 0.5, 0.5, 0.5, 250 0.5, 0.5, -0.5, 251 /* Right face */ 252 /* Bottom left */ 253 0.5, 0.5, -0.5, 254 0.5, -0.5, 0.5, 255 0.5, -0.5, -0.5, 256 /* Top right */ 257 0.5, 0.5, -0.5, 258 0.5, 0.5, 0.5, 259 0.5, -0.5, 0.5, 260 /* Back face */ 261 /* Bottom left */ 262 0.5, 0.5, 0.5, 263 -0.5, -0.5, 0.5, 264 0.5, -0.5, 0.5, 265 /* Top right */ 266 0.5, 0.5, 0.5, 267 -0.5, 0.5, 0.5, 268 -0.5, -0.5, 0.5, 269 /* Bottom face */ 270 /* Bottom left */ 271 -0.5, -0.5, -0.5, 272 0.5, -0.5, 0.5, 273 -0.5, -0.5, 0.5, 274 /* Top right */ 275 -0.5, -0.5, -0.5, 276 0.5, -0.5, -0.5, 277 0.5, -0.5, 0.5, 278 }; 279 280 const float _colors[] = 281 { 282 /* Front face */ 283 /* Bottom left */ 284 1.0, 0.0, 0.0, /* red */ 285 0.0, 0.0, 1.0, /* blue */ 286 0.0, 1.0, 0.0, /* green */ 287 /* Top right */ 288 1.0, 0.0, 0.0, /* red */ 289 1.0, 1.0, 0.0, /* yellow */ 290 0.0, 0.0, 1.0, /* blue */ 291 /* Left face */ 292 /* Bottom left */ 293 1.0, 1.0, 1.0, /* white */ 294 0.0, 1.0, 0.0, /* green */ 295 0.0, 1.0, 1.0, /* cyan */ 296 /* Top right */ 297 1.0, 1.0, 1.0, /* white */ 298 1.0, 0.0, 0.0, /* red */ 299 0.0, 1.0, 0.0, /* green */ 300 /* Top face */ 301 /* Bottom left */ 302 1.0, 1.0, 1.0, /* white */ 303 1.0, 1.0, 0.0, /* yellow */ 304 1.0, 0.0, 0.0, /* red */ 305 /* Top right */ 306 1.0, 1.0, 1.0, /* white */ 307 0.0, 0.0, 0.0, /* black */ 308 1.0, 1.0, 0.0, /* yellow */ 309 /* Right face */ 310 /* Bottom left */ 311 1.0, 1.0, 0.0, /* yellow */ 312 1.0, 0.0, 1.0, /* magenta */ 313 0.0, 0.0, 1.0, /* blue */ 314 /* Top right */ 315 1.0, 1.0, 0.0, /* yellow */ 316 0.0, 0.0, 0.0, /* black */ 317 1.0, 0.0, 1.0, /* magenta */ 318 /* Back face */ 319 /* Bottom left */ 320 0.0, 0.0, 0.0, /* black */ 321 0.0, 1.0, 1.0, /* cyan */ 322 1.0, 0.0, 1.0, /* magenta */ 323 /* Top right */ 324 0.0, 0.0, 0.0, /* black */ 325 1.0, 1.0, 1.0, /* white */ 326 0.0, 1.0, 1.0, /* cyan */ 327 /* Bottom face */ 328 /* Bottom left */ 329 0.0, 1.0, 0.0, /* green */ 330 1.0, 0.0, 1.0, /* magenta */ 331 0.0, 1.0, 1.0, /* cyan */ 332 /* Top right */ 333 0.0, 1.0, 0.0, /* green */ 334 0.0, 0.0, 1.0, /* blue */ 335 1.0, 0.0, 1.0, /* magenta */ 336 }; 337 338 const char* _shader_vert_src = 339 " attribute vec4 av4position; " 340 " attribute vec3 av3color; " 341 " uniform mat4 mvp; " 342 " varying vec3 vv3color; " 343 " void main() { " 344 " vv3color = av3color; " 345 " gl_Position = mvp * av4position; " 346 " } "; 347 348 const char* _shader_frag_src = 349 " precision lowp float; " 350 " varying vec3 vv3color; " 351 " void main() { " 352 " gl_FragColor = vec4(vv3color, 1.0); " 353 " } "; 354 355 typedef struct shader_data 356 { 357 GLuint shader_program, shader_frag, shader_vert; 358 359 GLint attr_position; 360 GLint attr_color, attr_mvp; 361 362 int angle_x, angle_y, angle_z; 363 364 } shader_data; 365 366 static void 367 Render(unsigned int width, unsigned int height, shader_data* data) 368 { 369 float matrix_rotate[16], matrix_modelview[16], matrix_perspective[16], matrix_mvp[16]; 370 371 /* 372 * Do some rotation with Euler angles. It is not a fixed axis as 373 * quaterions would be, but the effect is cool. 374 */ 375 rotate_matrix(data->angle_x, 1.0, 0.0, 0.0, matrix_modelview); 376 rotate_matrix(data->angle_y, 0.0, 1.0, 0.0, matrix_rotate); 377 378 multiply_matrix(matrix_rotate, matrix_modelview, matrix_modelview); 379 380 rotate_matrix(data->angle_z, 0.0, 1.0, 0.0, matrix_rotate); 381 382 multiply_matrix(matrix_rotate, matrix_modelview, matrix_modelview); 383 384 /* Pull the camera back from the cube */ 385 matrix_modelview[14] -= 2.5; 386 387 perspective_matrix(45.0, (double)width/(double)height, 0.01, 100.0, matrix_perspective); 388 multiply_matrix(matrix_perspective, matrix_modelview, matrix_mvp); 389 390 GL_CHECK(ctx.glUniformMatrix4fv(data->attr_mvp, 1, GL_FALSE, matrix_mvp)); 391 392 data->angle_x += 3; 393 data->angle_y += 2; 394 data->angle_z += 1; 395 396 if(data->angle_x >= 360) data->angle_x -= 360; 397 if(data->angle_x < 0) data->angle_x += 360; 398 if(data->angle_y >= 360) data->angle_y -= 360; 399 if(data->angle_y < 0) data->angle_y += 360; 400 if(data->angle_z >= 360) data->angle_z -= 360; 401 if(data->angle_z < 0) data->angle_z += 360; 402 403 GL_CHECK(ctx.glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)); 404 GL_CHECK(ctx.glDrawArrays(GL_TRIANGLES, 0, 36)); 405 } 406 407 int 408 main(int argc, char *argv[]) 409 { 410 int fsaa, accel; 411 int value; 412 int i, done; 413 SDL_DisplayMode mode; 414 SDL_Event event; 415 Uint32 then, now, frames; 416 int status; 417 shader_data *datas, *data; 418 419 /* Initialize parameters */ 420 fsaa = 0; 421 accel = 0; 422 423 /* Initialize test framework */ 424 state = SDLTest_CommonCreateState(argv, SDL_INIT_VIDEO); 425 if (!state) { 426 return 1; 427 } 428 for (i = 1; i < argc;) { 429 int consumed; 430 431 consumed = SDLTest_CommonArg(state, i); 432 if (consumed == 0) { 433 if (SDL_strcasecmp(argv[i], "--fsaa") == 0) { 434 ++fsaa; 435 consumed = 1; 436 } else if (SDL_strcasecmp(argv[i], "--accel") == 0) { 437 ++accel; 438 consumed = 1; 439 } else if (SDL_strcasecmp(argv[i], "--zdepth") == 0) { 440 i++; 441 if (!argv[i]) { 442 consumed = -1; 443 } else { 444 depth = SDL_atoi(argv[i]); 445 consumed = 1; 446 } 447 } else { 448 consumed = -1; 449 } 450 } 451 if (consumed < 0) { 452 SDL_Log ("Usage: %s %s [--fsaa] [--accel] [--zdepth %%d]\n", argv[0], 453 SDLTest_CommonUsage(state)); 454 quit(1); 455 } 456 i += consumed; 457 } 458 459 /* Set OpenGL parameters */ 460 state->window_flags |= SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_BORDERLESS; 461 state->gl_red_size = 5; 462 state->gl_green_size = 5; 463 state->gl_blue_size = 5; 464 state->gl_depth_size = depth; 465 state->gl_major_version = 2; 466 state->gl_minor_version = 0; 467 state->gl_profile_mask = SDL_GL_CONTEXT_PROFILE_ES; 468 469 if (fsaa) { 470 state->gl_multisamplebuffers=1; 471 state->gl_multisamplesamples=fsaa; 472 } 473 if (accel) { 474 state->gl_accelerated=1; 475 } 476 if (!SDLTest_CommonInit(state)) { 477 quit(2); 478 return 0; 479 } 480 481 context = SDL_calloc(state->num_windows, sizeof(context)); 482 if (context == NULL) { 483 SDL_Log("Out of memory!\n"); 484 quit(2); 485 } 486 487 /* Create OpenGL ES contexts */ 488 for (i = 0; i < state->num_windows; i++) { 489 context[i] = SDL_GL_CreateContext(state->windows[i]); 490 if (!context[i]) { 491 SDL_Log("SDL_GL_CreateContext(): %s\n", SDL_GetError()); 492 quit(2); 493 } 494 } 495 496 /* Important: call this *after* creating the context */ 497 if (LoadContext(&ctx) < 0) { 498 SDL_Log("Could not load GLES2 functions\n"); 499 quit(2); 500 return 0; 501 } 502 503 504 505 if (state->render_flags & SDL_RENDERER_PRESENTVSYNC) { 506 SDL_GL_SetSwapInterval(1); 507 } else { 508 SDL_GL_SetSwapInterval(0); 509 } 510 511 SDL_GetCurrentDisplayMode(0, &mode); 512 SDL_Log("Screen bpp: %d\n", SDL_BITSPERPIXEL(mode.format)); 513 SDL_Log("\n"); 514 SDL_Log("Vendor : %s\n", ctx.glGetString(GL_VENDOR)); 515 SDL_Log("Renderer : %s\n", ctx.glGetString(GL_RENDERER)); 516 SDL_Log("Version : %s\n", ctx.glGetString(GL_VERSION)); 517 SDL_Log("Extensions : %s\n", ctx.glGetString(GL_EXTENSIONS)); 518 SDL_Log("\n"); 519 520 status = SDL_GL_GetAttribute(SDL_GL_RED_SIZE, &value); 521 if (!status) { 522 SDL_Log("SDL_GL_RED_SIZE: requested %d, got %d\n", 5, value); 523 } else { 524 SDL_Log( "Failed to get SDL_GL_RED_SIZE: %s\n", 525 SDL_GetError()); 526 } 527 status = SDL_GL_GetAttribute(SDL_GL_GREEN_SIZE, &value); 528 if (!status) { 529 SDL_Log("SDL_GL_GREEN_SIZE: requested %d, got %d\n", 5, value); 530 } else { 531 SDL_Log( "Failed to get SDL_GL_GREEN_SIZE: %s\n", 532 SDL_GetError()); 533 } 534 status = SDL_GL_GetAttribute(SDL_GL_BLUE_SIZE, &value); 535 if (!status) { 536 SDL_Log("SDL_GL_BLUE_SIZE: requested %d, got %d\n", 5, value); 537 } else { 538 SDL_Log( "Failed to get SDL_GL_BLUE_SIZE: %s\n", 539 SDL_GetError()); 540 } 541 status = SDL_GL_GetAttribute(SDL_GL_DEPTH_SIZE, &value); 542 if (!status) { 543 SDL_Log("SDL_GL_DEPTH_SIZE: requested %d, got %d\n", depth, value); 544 } else { 545 SDL_Log( "Failed to get SDL_GL_DEPTH_SIZE: %s\n", 546 SDL_GetError()); 547 } 548 if (fsaa) { 549 status = SDL_GL_GetAttribute(SDL_GL_MULTISAMPLEBUFFERS, &value); 550 if (!status) { 551 SDL_Log("SDL_GL_MULTISAMPLEBUFFERS: requested 1, got %d\n", value); 552 } else { 553 SDL_Log( "Failed to get SDL_GL_MULTISAMPLEBUFFERS: %s\n", 554 SDL_GetError()); 555 } 556 status = SDL_GL_GetAttribute(SDL_GL_MULTISAMPLESAMPLES, &value); 557 if (!status) { 558 SDL_Log("SDL_GL_MULTISAMPLESAMPLES: requested %d, got %d\n", fsaa, 559 value); 560 } else { 561 SDL_Log( "Failed to get SDL_GL_MULTISAMPLESAMPLES: %s\n", 562 SDL_GetError()); 563 } 564 } 565 if (accel) { 566 status = SDL_GL_GetAttribute(SDL_GL_ACCELERATED_VISUAL, &value); 567 if (!status) { 568 SDL_Log("SDL_GL_ACCELERATED_VISUAL: requested 1, got %d\n", value); 569 } else { 570 SDL_Log( "Failed to get SDL_GL_ACCELERATED_VISUAL: %s\n", 571 SDL_GetError()); 572 } 573 } 574 575 datas = SDL_calloc(state->num_windows, sizeof(shader_data)); 576 577 /* Set rendering settings for each context */ 578 for (i = 0; i < state->num_windows; ++i) { 579 580 status = SDL_GL_MakeCurrent(state->windows[i], context[i]); 581 if (status) { 582 SDL_Log("SDL_GL_MakeCurrent(): %s\n", SDL_GetError()); 583 584 /* Continue for next window */ 585 continue; 586 } 587 ctx.glViewport(0, 0, state->window_w, state->window_h); 588 589 data = &datas[i]; 590 data->angle_x = 0; data->angle_y = 0; data->angle_z = 0; 591 592 /* Shader Initialization */ 593 process_shader(&data->shader_vert, _shader_vert_src, GL_VERTEX_SHADER); 594 process_shader(&data->shader_frag, _shader_frag_src, GL_FRAGMENT_SHADER); 595 596 /* Create shader_program (ready to attach shaders) */ 597 data->shader_program = GL_CHECK(ctx.glCreateProgram()); 598 599 /* Attach shaders and link shader_program */ 600 GL_CHECK(ctx.glAttachShader(data->shader_program, data->shader_vert)); 601 GL_CHECK(ctx.glAttachShader(data->shader_program, data->shader_frag)); 602 GL_CHECK(ctx.glLinkProgram(data->shader_program)); 603 604 /* Get attribute locations of non-fixed attributes like color and texture coordinates. */ 605 data->attr_position = GL_CHECK(ctx.glGetAttribLocation(data->shader_program, "av4position")); 606 data->attr_color = GL_CHECK(ctx.glGetAttribLocation(data->shader_program, "av3color")); 607 608 /* Get uniform locations */ 609 data->attr_mvp = GL_CHECK(ctx.glGetUniformLocation(data->shader_program, "mvp")); 610 611 GL_CHECK(ctx.glUseProgram(data->shader_program)); 612 613 /* Enable attributes for position, color and texture coordinates etc. */ 614 GL_CHECK(ctx.glEnableVertexAttribArray(data->attr_position)); 615 GL_CHECK(ctx.glEnableVertexAttribArray(data->attr_color)); 616 617 /* Populate attributes for position, color and texture coordinates etc. */ 618 GL_CHECK(ctx.glVertexAttribPointer(data->attr_position, 3, GL_FLOAT, GL_FALSE, 0, _vertices)); 619 GL_CHECK(ctx.glVertexAttribPointer(data->attr_color, 3, GL_FLOAT, GL_FALSE, 0, _colors)); 620 621 GL_CHECK(ctx.glEnable(GL_CULL_FACE)); 622 GL_CHECK(ctx.glEnable(GL_DEPTH_TEST)); 623 } 624 625 /* Main render loop */ 626 frames = 0; 627 then = SDL_GetTicks(); 628 done = 0; 629 while (!done) { 630 /* Check for events */ 631 ++frames; 632 while (SDL_PollEvent(&event) && !done) { 633 switch (event.type) { 634 case SDL_WINDOWEVENT: 635 switch (event.window.event) { 636 case SDL_WINDOWEVENT_RESIZED: 637 for (i = 0; i < state->num_windows; ++i) { 638 if (event.window.windowID == SDL_GetWindowID(state->windows[i])) { 639 status = SDL_GL_MakeCurrent(state->windows[i], context[i]); 640 if (status) { 641 SDL_Log("SDL_GL_MakeCurrent(): %s\n", SDL_GetError()); 642 break; 643 } 644 /* Change view port to the new window dimensions */ 645 ctx.glViewport(0, 0, event.window.data1, event.window.data2); 646 /* Update window content */ 647 Render(event.window.data1, event.window.data2, &datas[i]); 648 SDL_GL_SwapWindow(state->windows[i]); 649 break; 650 } 651 } 652 break; 653 } 654 } 655 SDLTest_CommonEvent(state, &event, &done); 656 } 657 if (!done) { 658 for (i = 0; i < state->num_windows; ++i) { 659 status = SDL_GL_MakeCurrent(state->windows[i], context[i]); 660 if (status) { 661 SDL_Log("SDL_GL_MakeCurrent(): %s\n", SDL_GetError()); 662 663 /* Continue for next window */ 664 continue; 665 } 666 Render(state->window_w, state->window_h, &datas[i]); 667 SDL_GL_SwapWindow(state->windows[i]); 668 } 669 } 670 } 671 672 /* Print out some timing information */ 673 now = SDL_GetTicks(); 674 if (now > then) { 675 SDL_Log("%2.2f frames per second\n", 676 ((double) frames * 1000) / (now - then)); 677 } 678 #if !defined(__ANDROID__) 679 quit(0); 680 #endif 681 return 0; 682 } 683 684 #else /* HAVE_OPENGLES2 */ 685 686 int 687 main(int argc, char *argv[]) 688 { 689 SDL_Log("No OpenGL ES support on this system\n"); 690 return 1; 691 } 692 693 #endif /* HAVE_OPENGLES2 */ 694 695 /* vi: set ts=4 sw=4 expandtab: */ 696