Search code examples
opengl-esopengl-es-2.0emscriptenegl

Program stops drawing after compiling shaders


I am working on a C program to be compiled to WASM and display an image in the browser. The point of this program is to learn to set things up using EGL, and therefore I am not interested in any answers involving e.g. SDL, GLFW, etc.

This code works to clear the screen to blue (I've ommitted error checking to reduce size):

#include <GLES2/gl2.h>
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "emscripten.h"

struct Environment
{
    EGLint majorVersion;
    EGLint minorVersion;

    EGLDisplay display;
    EGLSurface surface;
};

static struct Environment g_env = {};

bool initGL(struct Environment* env)
{
    env->display = eglGetDisplay(EGL_DEFAULT_DISPLAY);

    eglInitialize(env->display, &env->majorVersion, &env->minorVersion);

    EGLint numConfigs = 0;
    EGLint attribList[] = 
    {
        EGL_RED_SIZE, 5,
        EGL_GREEN_SIZE, 6,
        EGL_BLUE_SIZE, 5,
        EGL_DEPTH_SIZE, 1,
        EGL_NONE
    };
    EGLConfig config;
    eglChooseConfig(env->display, attribList, &config, 1, &numConfigs);

    env->surface = eglCreateWindowSurface(env->display, config, 0, NULL);

    static const EGLint contextAttribList[] = 
    {
        EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE
    };
    EGLContext context = eglCreateContext(env->display, config, EGL_NO_CONTEXT, contextAttribList);


    eglMakeCurrent(env->display, env->surface, env->surface, context);


    glClearColor(0.0f, 0.0f, 1.0f, 1.0f);


    return true;
}

void draw()
{
    glViewport(0, 0, 300, 150);
    glClear(GL_COLOR_BUFFER_BIT);
    eglSwapBuffers(g_env.display, g_env.surface);
}

int main(int argc, char *argv[])
{
    if (!initGL(&g_env))
    {
        return 1;
    }
    emscripten_set_main_loop(clearScreen, 0, 1);
    return 0;
}

But as soon as I add the following after glClearColor(...), I no longer see a blue screen in the browser:

const GLuint vertex_shader = load_shader(GL_VERTEX_SHADER, VERTEX_SHADER);
const GLuint fragment_shader = load_shader(GL_FRAGMENT_SHADER, FRAGMENT_SHADER);

I suspect the shader code is not at all relevent to the problem, but just in case, here is the code for load_shader, taken from the OpenGL ES 2 book (error checking ommitted)

GLuint load_shader ( GLenum type, const char *shaderSrc )
{
   GLuint shader;
   GLint compiled;

   // Create the shader object
   shader = glCreateShader ( type );

   // Load the shader source
   glShaderSource ( shader, 1, &shaderSrc, NULL );

   // Compile the shader
   glCompileShader ( shader );

   // Check the compile status
   glGetShaderiv ( shader, GL_COMPILE_STATUS, &compiled );

   return shader;
}

And the shaders themselves:

char VERTEX_SHADER[] =  
  "attribute vec4 vPosition;    \n"
  "void main()                  \n"
  "{                            \n"
  "   gl_Position = vPosition;  \n"
  "}                            \n";

char FRAGMENT_SHADER[] =  
  "precision mediump float;\n"\
  "void main()                                  \n"
  "{                                            \n"
  "  gl_FragColor = vec4 ( 1.0, 0.0, 0.0, 1.0 );\n"
  "}   

Here is how I compile:

EMSCRIPTEN_OPTS = \
-s WASM=1 \
-s FULL_ES2=1 \
-s MODULARIZE=1
${EMCC} main_web.c -o hello.js ${EMSCRIPTEN_OPTS}

glGetError() is not returning an error code.

And here is my HTML:

<html>
<body>
<p id="output" />
<canvas id="canvas"></canvas>
<script type="application/javascript" src="hello.js"></script>
<script type="application/javascript">
    Module({
        canvas: (() => document.getElementById('canvas'))(),
        print: (() => {
            var element = document.getElementById('output');
            return function(text) {
                element.innerHTML += text + "<br>";
            };
        })()
    })
</script>
</body>
</html>

Why do I stop clearing the screen when I just load the shaders?


Solution

  • The problem is with the HTML. When printing to stdout, the inline element was interefering with the block <canvas> element.

    Problem solved by wrapping <p id="output"/> in a div.