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