Why won't this simple OpenGL ES 2.0/SDL 2 program let me change my point sprite size?

6.8k Views Asked by At

I was working on a simple OpenGL ES 2.0 program (along with SDL 2 to make things a bit easier) and decided to try out point sprites. I was able to get them to draw successfully, but I wasn't able to change their size by outputting gl_PointSize from the vertex shader. Theoretically, that should be all that I have to do.

The following code snippet is a very stripped-down version of my barely-C++ code (no error-checking at all, but that is because nothing should go wrong with it) that demonstrates how I am trying to change the size of my point sprites. It has been tested on two rather different computers with similar results (Linux, but 32-bit/software rendering vs 64-bit/discrete GPU), and may be compiled using g++ with g++ main.cpp -lSDL2 -Wall -D_REENTRANT -lGLESv2.

#include <GLES2/gl2.h>
#include <SDL2/SDL.h>

struct myData {
    SDL_Window *window;
    SDL_GLContext context;
};

const GLchar vertex[] =
    "#version 100\n"
    "precision mediump float;\n"
    "void main()\n"
    "{\n"
    "   gl_Position = vec4(0.0, 0.0, 0.0, 1.0);\n"
    "   gl_PointSize = 128.0;\n"
    "}\0";

const GLchar fragment[] =
    "#version 100\n"
    "precision mediump float;\n"
    "void main()\n"
    "{\n"
    "   gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n"
    "}\0";

GLuint loadShader(GLuint program, GLenum type, const GLchar *shaderSrc) {
    GLuint shader;
    shader = glCreateShader(type);
    glShaderSource(shader, 1, &shaderSrc, NULL);
    glCompileShader(shader);
    glAttachShader(program, shader);
    return 0;
}

int sdlInit(myData *data) {
    SDL_Init(SDL_INIT_VIDEO);
    SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
    SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);

    data->window = SDL_CreateWindow("Demo", 0, 0, 512, 512, SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN);
    data->context = SDL_GL_CreateContext(data->window);

    return 0;
}

int glInit(myData *data) {
    GLuint programObject;
    programObject = glCreateProgram();
    loadShader(programObject, GL_VERTEX_SHADER, vertex);
    loadShader(programObject, GL_FRAGMENT_SHADER, fragment);
    glLinkProgram(programObject);
    glUseProgram(programObject);

    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
    glViewport(0, 0, 512, 512);

    return 0;
}

int loopFunc(myData *data) {
    SDL_Event event;
    while (SDL_PollEvent(&event)) {
        if (event.type == SDL_QUIT) {
            return 1;
        }
    }

    glClear(GL_COLOR_BUFFER_BIT);
    glDrawArrays(GL_POINTS, 0, 1);
    SDL_GL_SwapWindow(data->window);

    return 0;
}

void sdlQuit(myData *data) {
    SDL_GL_DeleteContext(data->context);
    SDL_DestroyWindow(data->window);
    SDL_Quit();
    return;
}

int main() {
    myData data;

    sdlInit(&data);

    glInit(&data);

    while (!loopFunc(&data));

    sdlQuit(&data);

    return 0;
}

When ran, the program should produce a point sprite with a size of 128 pixels, per the value that I set in the vertex shader. However, when actually executed, the size of the points sprite in the center of the window is exactly one pixel. What am I doing wrong?

2

There are 2 best solutions below

0
On

A couple things:

  • As jumapico pointed out make sure you actually request an ES 2.0 context from SDL otherwise you might get a regular desktop OpenGL context that happens to support OpenGL ES's #version 100 GLSL code; desktop OpenGL requires that you turn on gl_PointSize via glEnable(GL_PROGRAM_POINT_SIZE).
  • Make sure your GL implementation actually supports a gl_PointSize of 128.0 by checking GL_ALIASED_POINT_SIZE_RANGE; the spec only requires implementations support a range of 1.0 to 1.0, anything above that is optional.

Workin' fine on this Debian Buster box:

screenshot of large GL_POINT

SDL/OpenGL ES info:

SDL compiled version: 2.0.9
SDL linked version  : 2.0.9
GL_VENDOR   : X.Org
GL_RENDERER : AMD Radeon (TM) R9 Fury Series (FIJI, DRM 3.27.0, 4.19.0-2-amd64, LLVM 7.0.1)
GL_VERSION  : OpenGL ES 3.2 Mesa 18.3.4
GLSL version: OpenGL ES GLSL ES 3.20
gl_PointSize min: 1
gl_PointSize max: 2048

Code:

// g++ `pkg-config --cflags sdl2 glesv2` main.cpp `pkg-config --libs sdl2 glesv2`
#include <SDL.h>
#include <SDL_opengles2.h>
#include <iostream>

void CheckStatus( GLuint obj, bool isShader )
{
    GLint status = GL_FALSE, log[ 1 << 11 ] = { 0 };
    ( isShader ? glGetShaderiv : glGetProgramiv )( obj, isShader ? GL_COMPILE_STATUS : GL_LINK_STATUS, &status );
    if( status == GL_TRUE ) return;
    ( isShader ? glGetShaderInfoLog : glGetProgramInfoLog )( obj, sizeof( log ), NULL, (GLchar*)log );
    std::cerr << (GLchar*)log << "\n";
    std::exit( EXIT_FAILURE );
}

void AttachShader( GLuint program, GLenum type, const char* src )
{
    GLuint shader = glCreateShader( type );
    glShaderSource( shader, 1, &src, NULL );
    glCompileShader( shader );
    CheckStatus( shader, true );
    glAttachShader( program, shader );
    glDeleteShader( shader );
}

const char* const vert = 1 + R"GLSL(
#version 100
precision mediump float;
void main()
{
    gl_Position = vec4( 0.0, 0.0, 0.0, 1.0 );
    gl_PointSize = 128.0;
}
)GLSL";

const char* const frag = 1 + R"GLSL(
#version 100
precision mediump float;
void main()
{
    gl_FragColor = vec4( 1.0, 0.0, 0.0, 1.0 );
}
)GLSL";

int main( int argc, char** argv )
{
    SDL_Init( SDL_INIT_VIDEO );
    SDL_GL_SetAttribute( SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES );
    SDL_GL_SetAttribute( SDL_GL_CONTEXT_MAJOR_VERSION, 2 );
    SDL_GL_SetAttribute( SDL_GL_CONTEXT_MINOR_VERSION, 0 );
    SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );
    SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, 24 );
    SDL_Window *window = SDL_CreateWindow( "SDL2", 0, 0, 640, 480, SDL_WINDOW_OPENGL );
    SDL_GLContext context = SDL_GL_CreateContext( window );

    // SDL info
    SDL_version compiled;
    SDL_version linked;
    SDL_VERSION( &compiled );
    SDL_GetVersion( &linked );
    std::cout << "SDL compiled version: " << (int)compiled.major << "." << (int)compiled.minor << "." << (int)compiled.patch << "\n";
    std::cout << "SDL linked version  : " << (int)linked.major << "." << (int)linked.minor << "." << (int)linked.patch << "\n";

    // GL info
    std::cout << "GL_VENDOR   : " << glGetString( GL_VENDOR ) << "\n";
    std::cout << "GL_RENDERER : " << glGetString( GL_RENDERER ) << "\n";
    std::cout << "GL_VERSION  : " << glGetString( GL_VERSION ) << "\n";
    std::cout << "GLSL version: " << glGetString( GL_SHADING_LANGUAGE_VERSION ) << "\n";
    float pointSizeRange[2] = { -1.0, -1.0 };
    glGetFloatv( GL_ALIASED_POINT_SIZE_RANGE, pointSizeRange );
    std::cout << "gl_PointSize min: " << pointSizeRange[0] << "\n";
    std::cout << "gl_PointSize max: " << pointSizeRange[1] << "\n";

    GLuint prog = glCreateProgram();
    AttachShader( prog, GL_VERTEX_SHADER, vert );
    AttachShader( prog, GL_FRAGMENT_SHADER, frag );
    glLinkProgram( prog );
    CheckStatus( prog, false );
    glUseProgram( prog );

    bool running = true;
    while( running )
    {
        SDL_Event ev;
        while( SDL_PollEvent( &ev ) )
        {
            if( ev.type == SDL_QUIT )
            {
                running = false;
            }
        }

        glClearColor( 0.0f, 0.0f, 0.0f, 0.0f );
        glClear( GL_COLOR_BUFFER_BIT );
        glDrawArrays( GL_POINTS, 0, 1 );
        SDL_GL_SwapWindow( window );
    }

    SDL_GL_DeleteContext( context ); 
    SDL_DestroyWindow( window );
    SDL_Quit();
    return EXIT_SUCCESS;
}
1
On

I think you forgot initialize the opengles2 context.

SDL_Init(SDL_INIT_VIDEO);

SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);

SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);