#include #include #include #include #include #include #include #include #include #include #include #include //#define TEST_EXPLICIT_CONTEXT_SWAP // - If set, test WebGL context creation .explicitSwapControl=true and call emscripten_webgl_commit_frame() to swap. Otherwise utilize implicit swapping. //#define TEST_EMSCRIPTEN_SET_MAIN_LOOP // - If set, test emscripten_set_main_loop(). If unset, run our own synchronously blocking loop //#define TEST_MANUALLY_SET_ELEMENT_CSS_SIZE // - If set, manually update CSS pixel size of the canvas. If unset, leave the CSS size to auto and expect the browser to resize the canvas size. #if !defined(TEST_EMSCRIPTEN_SET_MAIN_LOOP) && !defined(__EMSCRIPTEN_PTHREADS__) #error TEST_EMSCRIPTEN_SET_MAIN_LOOP=false, but blocking main loops require using -sPROXY_TO_PTHREADS= and multithreading (build with -sPROXY_TO_PTHREAD and -pthread) #endif #if !defined(TEST_EMSCRIPTEN_SET_MAIN_LOOP) && !defined(TEST_EXPLICIT_CONTEXT_SWAP) #error If using own main loop, must use explicit context swapping (explicitSwapControl=true) (build with either -DTEST_EMSCRIPTEN_SET_MAIN_LOOP=1 or -DTEST_EXPLICIT_CONTEXT_SWAP=1) #endif #define NUM_FRAMES_TO_RENDER 100 GLuint vb; int program; int frameNumber = 0; EMSCRIPTEN_WEBGL_CONTEXT_HANDLE ctx; void tick() { double sizeScale = 21.0 + 20.0 * sin(emscripten_get_now()*0.001); double w = 18.0*sizeScale; double h = 11.0*sizeScale; EMSCRIPTEN_RESULT r; #if TEST_MANUALLY_SET_ELEMENT_CSS_SIZE r = emscripten_set_element_css_size("#canvas", w / emscripten_get_device_pixel_ratio(), h / emscripten_get_device_pixel_ratio()); assert(r == EMSCRIPTEN_RESULT_SUCCESS); #endif r = emscripten_set_canvas_element_size("#canvas", (int)w, (int)h); assert(r == EMSCRIPTEN_RESULT_SUCCESS); int verifyWidth, verifyHeight; r = emscripten_get_canvas_element_size("#canvas", &verifyWidth, &verifyHeight); assert(r == EMSCRIPTEN_RESULT_SUCCESS); assert(verifyWidth == (int)w); assert(verifyHeight == (int)h); glViewport(0, 0, (int)w, (int)h); glUseProgram(program); glBindBuffer(GL_ARRAY_BUFFER, vb); glDisable(GL_DEPTH_TEST); int posLoc = glGetAttribLocation(program, "pos"); glVertexAttribPointer(posLoc, 2, GL_FLOAT, false, 0, 0); glEnableVertexAttribArray(posLoc); glUniform1f(glGetUniformLocation(program, "t"), emscripten_get_now()*0.0001f); glClearColor(0,1,0,1); // Clear to green color which should never be visible glClear(GL_COLOR_BUFFER_BIT); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); #if TEST_EXPLICIT_CONTEXT_SWAP r = emscripten_webgl_commit_frame(); assert(r == EMSCRIPTEN_RESULT_SUCCESS); #endif ++frameNumber; if (frameNumber >= NUM_FRAMES_TO_RENDER) { #if TEST_EMSCRIPTEN_SET_MAIN_LOOP emscripten_cancel_main_loop(); #endif emscripten_webgl_make_context_current(0); emscripten_webgl_destroy_context(ctx); printf("quit\n"); exit(0); } } void init() { glGenBuffers(1, &vb); glBindBuffer(GL_ARRAY_BUFFER, vb); float vertices[] = { -1, -1, -1, 1, 1, -1, 1, 1 }; glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); const char *vsCode = "attribute vec2 pos;" "varying lowp vec2 tex;" "void main() { tex = pos * 0.5 + vec2(0.5,0.5); gl_Position = vec4(pos, 0.0, 1.0); }"; int vs = glCreateShader(GL_VERTEX_SHADER); glShaderSource(vs, 1, &vsCode, NULL); glCompileShader(vs); const char *fsCode = "varying lowp vec2 tex;" "uniform highp float t;" "uniform sampler2D sampler;" "void main() { highp float x = tex.x + sin((t + tex.y)*10.0)*0.005; highp float y = tex.y + sin((t + tex.x)*10.0)*0.02; x = x*1.3 - 0.1; y = y * 1.3 - 0.23;" "gl_FragColor = (tex.x > 0.05 && tex.x < 0.09) ? vec4(0,0,0,1) : ((x >= 0.0 && x <= 1.0 && y >= 0.0 && y <= 1.0) ? (((x >= 5.0/18.0 && x <= 8.0/18.0) || (x >= 0.0 && x <= 1.0 && y >= 4.0/11.0 && y <= 7.0/11.0)) ? vec4(0,0,1,1) : vec4(1,1,1,1)) : vec4(0.75,0.75,0.75,1)); }"; int fs = glCreateShader(GL_FRAGMENT_SHADER); glShaderSource(fs, 1, &fsCode, NULL); glCompileShader(fs); program = glCreateProgram(); glAttachShader(program, vs); glAttachShader(program, fs); glLinkProgram(program); } int main() { EmscriptenWebGLContextAttributes attr; emscripten_webgl_init_context_attributes(&attr); #if TEST_EXPLICIT_CONTEXT_SWAP attr.explicitSwapControl = EM_TRUE; #endif ctx = emscripten_webgl_create_context("#canvas", &attr); printf("Created context with handle %u\n", (unsigned int)ctx); if (!ctx) { EM_ASM({ if (typeof OffscreenCanvas === 'undefined') { xhr = new XMLHttpRequest(); xhr.open('GET', 'http://localhost:8888/report_result?skipped:%20OffscreenCanvas%20is%20not%20supported!'); xhr.send(); setTimeout(function() { window.close() }, 2000); } }); return 0; } emscripten_webgl_make_context_current(ctx); init(); printf("You should see the flag of Finland.\n"); #if TEST_EMSCRIPTEN_SET_MAIN_LOOP emscripten_set_main_loop(tick, 0, 0); #else for(int i = 0; i < NUM_FRAMES_TO_RENDER; ++i) { tick(); emscripten_current_thread_process_queued_calls(); usleep(16*1000); } #endif return 99; }