Thanks, the incorrect library was the main issue with this program! Another few things I noticed while experimenting with this code snippet:
apparently Vertex Arrays don't work with GLESv2 (
stackoverflow), so you have to use Vertex Buffers
errors in vertex/fragment shader are only detected when linking the program, not on compilation
when using opengl extensions (e.g. GL_OES_mapbuffer, see
Raspberry Pi Video Core API for available extensions) you have to put#define GL_GLEXT_PROTOTYPES before including SDL2/SDL_opengles2.h and additionally link with -lbrcmEGL in order to get the functions
if you don't call SDL_Quit() before exiting your program, the raspberry pi's console will be blocked (it seems like the input focus is still on the SDL window otherwise)
I updated the code with a few more comments and fixed some stuff:
main.c:
#include <SDL2/SDL.h>
#include <SDL2/SDL_opengles2.h>
#define FULLSCREEN 1
#define TRIANGLE_SIZE 0.9f
#define INFO_LOG_BUFFER_SIZE 1024
// Shader sources
const GLchar* vertexSource =
"attribute vec2 position;\n"
"attribute vec4 color;\n"
"varying vec4 out_color;\n"
"uniform mat4 proj_mat;\n"
"uniform mat4 model_mat;\n"
"void main()\n"
"{\n"
" gl_Position = proj_mat*model_mat*vec4(position, 0, 1.0);\n"
" out_color = color;\n"
"}\n";
const GLchar* fragmentSource =
"varying vec4 out_color;\n"
"void main()\n"
"{\n"
" gl_FragColor = out_color;\n"
"}\n";
// struct representing a colored 2D vertex
typedef struct{
float x;
float y;
float r;
float g;
float b;
float a;
}Vertex;
// adjusting viewport and projection matrix to fit current window dimensions
void resize(int w, int h, GLint proj_mat_location);
// create rotation matrix (z axis) and upload to shader at given uniform location
void setRotationMatrix(float rad, GLint model_mat_location);
// create orthogonal matrix and upload to shader at given uniform location
void setOrthoMatrix(float left, float right, float bottom,
float top, float n, float f, GLint proj_mat_location);
int main()
{
// initialize SDL
printf("Initializing SDL...\n");
if (SDL_Init(SDL_INIT_VIDEO) < 0)
{
printf("ERROR: Failed to initialize SDL: %s\n", SDL_GetError());
return 1;
}
// setting SDL flags
unsigned int sdl_flags = SDL_WINDOW_OPENGL;
SDL_DisplayMode current;
current.w = 800;
current.h = 600;
if(FULLSCREEN){
sdl_flags |= SDL_WINDOW_FULLSCREEN;
// getting current display-resolution
if (SDL_GetDesktopDisplayMode(0, ¤t) != 0){
printf("Could not retrieve current display resolution: %s\n", SDL_GetError());
}
}else{
sdl_flags |= SDL_WINDOW_RESIZABLE;
}
const char * fullscreen_string = FULLSCREEN ? "(fullscreen)" : "";
printf("Creating window %dx%d%s...\n", current.w, current.h, fullscreen_string);
SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16);
// use GLESv2
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
// activate V-Sync
SDL_GL_SetSwapInterval(1);
SDL_Window * window = SDL_CreateWindow("Hello GLES!", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
current.w, current.h, sdl_flags);
if(window == NULL)
{
printf("Error while creating window: %s\n", SDL_GetError());
SDL_Quit();
return 1;
}
// create gl context
printf("Creating OpenGL context...\n");
SDL_GLContext context = SDL_GL_CreateContext(window);
if(context == NULL)
{
printf("Error while creating OpenGL Context: %s\n", SDL_GetError());
SDL_DestroyWindow(window);
SDL_Quit();
return 1;
}
// hide mouse cursor
SDL_ShowCursor(0);
// set gl parameters
glClearColor(1.f, 1.f, 1.f, 1.f);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_DEPTH_TEST);
glDisable(GL_CULL_FACE);
// create RGB-triangle data and copy to vertex buffer
GLuint vbo;
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
Vertex vertices[3];
for(int i = 0; i < 3; i++){
vertices[i].x = cos(i*(2*M_PI/3.0f))*TRIANGLE_SIZE;
vertices[i].y = sin(i*(2*M_PI/3.0f))*TRIANGLE_SIZE;
vertices[i].r = 0.0f;
vertices[i].g = 0.0f;
vertices[i].b = 0.0f;
vertices[i].a = 1.0f;
}
vertices[0].r = 1.0f;
vertices[1].g = 1.0f;
vertices[2].b = 1.0f;
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
printf("Compiling Shader...\n");
// compile the vertex shader
GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &vertexSource, NULL);
glCompileShader(vertexShader);
// compile the fragment shader
GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragmentSource, NULL);
glCompileShader(fragmentShader);
// link vertex and fragment shader into shader program
GLuint shader_program = glCreateProgram();
glAttachShader(shader_program, vertexShader);
glAttachShader(shader_program, fragmentShader);
glLinkProgram(shader_program);
// program info log
char info_log_buffer[INFO_LOG_BUFFER_SIZE];
info_log_buffer[0] = '\0';
glGetProgramInfoLog(shader_program, INFO_LOG_BUFFER_SIZE, 0, info_log_buffer);
if(info_log_buffer[0] != '\0')
printf("Shader-Program-Info:\n%s\n", info_log_buffer);
// linking successfull?
int status;
glGetProgramiv(shader_program, GL_LINK_STATUS, &status);
if(status == GL_FALSE){
SDL_GL_DeleteContext(context);
SDL_DestroyWindow(window);
SDL_Quit();
return 1;
}
// use custom shader
glUseProgram(shader_program);
// feed vertex attributes with triangle-data
// position
GLint posAttrib = glGetAttribLocation(shader_program, "position");
glEnableVertexAttribArray(posAttrib);
glVertexAttribPointer(posAttrib, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), 0);
// color
GLint colorAttrib = glGetAttribLocation(shader_program, "color");
glEnableVertexAttribArray(colorAttrib);
glVertexAttribPointer(colorAttrib, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const GLvoid*)(2*sizeof(float)));
// retrieve uniform locations
GLint proj_mat_location = glGetUniformLocation(shader_program, "proj_mat");
GLint model_mat_location = glGetUniformLocation(shader_program, "model_mat");
// inital resize to set viewport and projection mastrix
resize(current.w, current.h, proj_mat_location);
// run main loop
printf("Rendering triangle...\n");
while(1){
int quit = 0;
SDL_Event e;
while(SDL_PollEvent(&e)){
if(e.type == SDL_QUIT || e.type == SDL_KEYDOWN)
quit = 1;
else if(e.type == SDL_WINDOWEVENT && e.window.event == SDL_WINDOWEVENT_RESIZED)
resize(e.window.data1, e.window.data2, proj_mat_location);
}
if(quit){
printf("Program was quit by user!\n");
break;
}
glClearColor(1,1,1,1);
glClear(GL_COLOR_BUFFER_BIT);
setRotationMatrix(SDL_GetTicks()/1000.f * M_PI/2.f, model_mat_location);
glDrawArrays(GL_TRIANGLES, 0, 3);
SDL_GL_SwapWindow(window);
}
// clean up
SDL_GL_DeleteContext(context);
SDL_DestroyWindow(window);
SDL_Quit();
return 0;
}
void setRotationMatrix(float rad, GLint model_mat_location)
{
// rotation around z axis
float sin_angle = sin(rad);
float cos_angle = cos(rad);
float mat[16];
mat[0] = cos_angle;
mat[1] = sin_angle;
mat[2] = 0;
mat[3] = 0;
mat[4] = -sin_angle;
mat[5] = cos_angle;
mat[6] = 0;
mat[7] = 0;
mat[8] = 0;
mat[9] = 0;
mat[10] = 1;
mat[11] = 0;
mat[12] = 0;
mat[13] = 0;
mat[14] = 0;
mat[15] = 1;
glUniformMatrix4fv(model_mat_location, 1, GL_FALSE, mat);
}
void resize(int w, int h, GLint proj_mat_location)
{
glViewport(0, 0, w, h);
// set orthogonal view so that coordinates [-1, 1] area always visible and proportional on x and y axis
if(w > h){
float f = w/(float)h;
setOrthoMatrix(-f, f, -1, 1, -1, 1, proj_mat_location);
}else{
float f = h/(float)w;
setOrthoMatrix(-1, 1, -f, f, -1, 1, proj_mat_location);
}
}
void setOrthoMatrix(float left, float right, float bottom,
float top, float n, float f, GLint proj_mat_location)
{
// set orthogonal matrix
float mat[16];
mat[0] = 2.0f/(right-left);
mat[1] = 0.f;
mat[2] = 0.f;
mat[3] = 0.f;
mat[4] = 0.f;
mat[5] = 2.0f/(top-bottom);
mat[6] = 0.f;
mat[7] = 0.f;
mat[8] = 0.f;
mat[9] = 0.f;
mat[10] =-2.f/(f-n);
mat[11] = 0.f;
mat[12] =-(right+left)/(right-left);
mat[13] =-(top+bottom)/(top-bottom);
mat[14] =-(f+n)/(f-n);
mat[15] = 1.f;
glUniformMatrix4fv(proj_mat_location, 1, GL_FALSE, mat);
}
Compiles and runs on Raspberry Pi 3:
gcc main.c -o gles_test -lSDL2 -lSDL2main -L/opt/vc/lib -lbrcmGLESv2 -lm
./gles_test
triangle.png
I hope this might be usefull to someone :)
@mitu Thanks again for your quick reply!