Page 1 of 1

An example project for beginner's of OpenGL ES 2

Posted: Sat Sep 19, 2015 7:42 pm
by pizzaboy150
Hi Everyone,

I have been learning OpenGL ES 2 for the last few weeks and its been a steep learning curve to say the least.

Lots of hours spent looking at code and reading documentation to where I am now.

I thought it might be useful to anyone else learning to see more example code to make life a little easier.

so here it is for a basic spinning triangle with vertex colours.

Hope someone finds it useful?

tar file ... sp=sharing


Code: Select all

#include <stdio.h>
#include <stdlib.h>
#include "bcm_host.h"
#include "egl.h"
#include "gl2.h"
#include "glMath.h"

EGLDisplay egldisplay;
EGLConfig eglconfig;
EGLSurface eglsurface;
EGLContext eglcontext;
uint32_t width, height;

void Init()
    //BCM host bit used to get a nativewindow to pass to EGL
    int s;
    static EGL_DISPMANX_WINDOW_T nativewindow;
    DISPMANX_ELEMENT_HANDLE_T dispman_element;
    DISPMANX_DISPLAY_HANDLE_T dispman_display;
    DISPMANX_UPDATE_HANDLE_T dispman_update;
    VC_RECT_T dst_rect;
    VC_RECT_T src_rect;
    s = graphics_get_display_size(0 /* LCD */, &width, &height);
    dst_rect.x = 0;
    dst_rect.y = 0;
    dst_rect.width = width;
    dst_rect.height = height;
    src_rect.x = 0;
    src_rect.y = 0;
    src_rect.width = width << 16;
    src_rect.height = height << 16;
    dispman_display = vc_dispmanx_display_open( 0 /* LCD */);
    dispman_update = vc_dispmanx_update_start( 0 );
    dispman_element = vc_dispmanx_element_add ( dispman_update, dispman_display,
    1/*layer*/, &dst_rect, 0/*src*/,
    &src_rect, DISPMANX_PROTECTION_NONE, 0 /*alpha*/, 0/*clamp*/, 0/*transform*/);
    nativewindow.element = dispman_element;
    nativewindow.width = width;
    nativewindow.height = height;
    vc_dispmanx_update_submit_sync( dispman_update );
    NativeWindowType *win = &nativewindow;
    //Lets fire up EGL for our context
    static const EGLint s_configAttribs[] =
        EGL_RED_SIZE,        8,
        EGL_GREEN_SIZE,     8,
        EGL_BLUE_SIZE,        8,
        EGL_ALPHA_SIZE,     8,
        EGL_SAMPLES,        1,
    //This seems important for using ES2
    static const EGLint context_attributes[] =
    //Finish off the startup
    EGLint numconfigs;
    egldisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
    eglInitialize(egldisplay, NULL, NULL);
    eglChooseConfig(egldisplay, s_configAttribs, &eglconfig, 1, &numconfigs);
    eglsurface = eglCreateWindowSurface(egldisplay, eglconfig, win, NULL);
    eglcontext = eglCreateContext(egldisplay, eglconfig, EGL_NO_CONTEXT, context_attributes);
    eglMakeCurrent(egldisplay, eglsurface, eglsurface, eglcontext);

void Deinit()
    //clean up functions to clear memory
    eglMakeCurrent(egldisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);

//Function to read a file and return its contents in a character string
char * ReadFile(const char *url)
    //open the file for reading
    FILE *file = fopen(url, "rb");
        printf("unable to open file : %s", url);
    //read the contents of a file
    //seek to the end of the file to get the size
    long lSize;
    fseek (file, 0L, SEEK_END);
    lSize = ftell(file);
    //lets allocate the memory for the file
    char *buffer = calloc(1, lSize+1);
        printf("Unable to allocate memory for file buffer!n");
    //lets copy the data into the buffer
    if(fread(buffer, lSize, 1, file) == 0)
        //nothing read
        printf("Nothing read from file : %s", url);
    return buffer;
    //close the file now we are finished with it

GLuint InitShader()
    GLchar *vShaderStr = ReadFile("vertex.shader");
    GLchar *fShaderStr = ReadFile("fragment.shader");
    GLint linked;
    GLuint vShader;
    GLuint fShader;
    GLint vCompiled;
    GLint fCompiled;
    GLuint programObject;
    //Create shader objects
    vShader = glCreateShader(GL_VERTEX_SHADER);
    if(vShader == 0) {
        printf("Unable to create vertex shadern");
    fShader = glCreateShader(GL_FRAGMENT_SHADER);
    if(fShader == 0) {
        printf("Unable to create fragment shadern");
    //load vertex shader source
    glShaderSource(vShader, 1, &vShaderStr, NULL);
    //Compile vertex shader
    // Check the compile status
    glGetShaderiv(vShader, GL_COMPILE_STATUS, &vCompiled);
        printf("Unable to compile vertex shader!n");
    //load fragment shader source
    glShaderSource(fShader, 1, &fShaderStr, NULL);
    //compile fragment shader
    // Check the compile status
    glGetShaderiv(fShader, GL_COMPILE_STATUS, &fCompiled);
        printf("Unable to compile fragment shader!n");
    // Create the program object
    programObject = glCreateProgram();
    if(programObject == 0) {
        printf("Unable to create Program Objectn");
    //Attach shaders to the program object
    glAttachShader(programObject, vShader);
    glAttachShader(programObject, fShader);
    // Link the program
    // Check the link status and print the errors
    glGetProgramiv(programObject, GL_LINK_STATUS, &linked);
    if(!linked) {
        GLint infoLen = 0;
        glGetProgramiv(programObject, GL_INFO_LOG_LENGTH, &infoLen);
        if(infoLen > 1)
            char* infoLog = malloc(sizeof(char) * infoLen);
            glGetProgramInfoLog(programObject, infoLen, NULL, infoLog);
            printf("Error linking program:n%sn", infoLog);
    return programObject;

int main(int argc, char *argv[])
    //Setup the display
    //make and compile the shaders
    GLuint program = InitShader();
    //use the compiled shaders
    //Triangle data 3*float and pixel color 4*float x,y,z, r,g,b,a
    GLfloat vTriangle[] = {
        -0.5f, -0.5f, 0.0f, 0.0f, 0.0f, 1.0, 1.0f,
        0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f,
        0.0f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f,
    //showing off now by using the index of vTriangle to build my
    //primitives instead of declaring vertices mutiple times
    GLushort triIndices [] = {
        0, 1, 2
    //Buffer to store the data in sexy GPU memory
    GLuint triBuffer;
    glGenBuffers(1, &triBuffer);
    glBindBuffer(GL_ARRAY_BUFFER, triBuffer);
    //Buffer to store indices
    GLuint triIndicesBuffer;
    glGenBuffers(1, &triIndicesBuffer);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, triIndicesBuffer);
    //set Buffer Data and copy into GPU Memory
    glBufferData(GL_ARRAY_BUFFER, sizeof(vTriangle), vTriangle, GL_STATIC_DRAW);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(triIndices), triIndices, GL_STATIC_DRAW);
    //create the link between the shader attributes and variables in here!
    GLint vPosition = glGetAttribLocation(program, "vPosition");
    GLint vColor = glGetAttribLocation(program, "vColor");
    GLint rotX = glGetUniformLocation(program, "rotX");
    GLint rotY = glGetUniformLocation(program, "rotY");
    GLint rotZ = glGetUniformLocation(program, "rotZ");
    GLint scale = glGetUniformLocation(program, "scale");
    //lets create some matrx'is to store our changing information
    mat4 rotXmat;
    mat4 rotYmat;
    mat4 rotZmat;
    mat4 scaleMat;
    GLfloat xrot = 0.0f;
    GLfloat yrot = 0.0f;
    GLfloat zrot = 10.0f;
    GLfloat scaleX = 0.8f; //on my display the height is 80% of the width
    GLfloat scaleY = 1.0f;
    GLfloat scaleZ = 1.0f;
    //define vertex attribute data arrays
    glVertexAttribPointer(vPosition, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat)*7, 0);
    glVertexAttribPointer(vColor, 4, GL_FLOAT, GL_FALSE, sizeof(GLfloat)*7, (GLvoid*)(sizeof(GLfloat)*3));
    //enable the attribute arrays
    //set stuff
    glClearColor(0.2f, 0.2f, 0.2f, 1.0f);
    //60 frames per second at 600 = 10 seconds
    //Assuming vsync 60hz here
    int count = 0;
    while (count < 600) {
        //clear the buffer
        //perform rotation
        matrixRotateZ(zrot, rotZmat);
        //so it would be nice to scale everything given the ratio of the display otherwise it will stretch
        matrixScale(scaleX, scaleY, scaleZ, scaleMat);
        //well we want it to spin so best change the angle
        zrot += 1;
        //well we have done the rotation so now we need to give it to the shader drrr
        glUniformMatrix4fv(rotZ, 1, GL_FALSE, rotZmat);
        glUniformMatrix4fv(scale, 1, GL_FALSE, scaleMat);
        //Draw the triangles from looking at the indices and refering to the vertex array data
        //the last param is special being 0 because we are using buffers, I do not understand why
        //we do not just pass in a pointer but hey ho it works
        glDrawElements(GL_TRIANGLES, sizeof(triIndices) / sizeof(triIndices[0]), GL_UNSIGNED_SHORT, 0);
        //actually draw the stuff to the screen
        eglSwapBuffers(egldisplay, eglsurface);
        //Increment timer
    return 0;

Code: Select all

#include <math.h>

// Pre-calculated value of PI / 180.
#define kPI180     0.017453

// Pre-calculated value of 180 / PI.
#define k180PI    57.295780

// Converts degrees to radians.
#define degreesToRadians(x) (x * kPI180)

// Converts radians to degrees.
#define radiansToDegrees(x) (x * k180PI)

/*	=======================================================
	For example, to translate, rotate and scale an object 
	you must create each matrix separately and then perform
	the multiplication ((Scale * Rotation) * Translation) 
	to get the final transformation matrix.

typedef float mat4[16];

void matrixIdentity(mat4 m)  
    m[0] = m[5] = m[10] = m[15] = 1.0;
    m[1] = m[2] = m[3] = m[4] = 0.0;
    m[6] = m[7] = m[8] = m[9] = 0.0;
    m[11] = m[12] = m[13] = m[14] = 0.0;

void matrixTranslate(float x, float y, float z, mat4 matrix)  

    // Translate slots.
    matrix[12] = x;
    matrix[13] = y;
    matrix[14] = z;   

void matrixScale(float sx, float sy, float sz, mat4 matrix)  

    // Scale slots.
    matrix[0] = sx;
    matrix[5] = sy;
    matrix[10] = sz;

void matrixRotateX(float degrees, mat4 matrix)  
    float radians = degreesToRadians(degrees);


    // Rotate X formula.
    matrix[5] = cosf(radians);
    matrix[6] = -sinf(radians);
    matrix[9] = -matrix[6];
    matrix[10] = matrix[5];

void matrixRotateY(float degrees, mat4 matrix)  
    float radians = degreesToRadians(degrees);


    // Rotate Y formula.
    matrix[0] = cosf(radians);
    matrix[2] = sinf(radians);
    matrix[8] = -matrix[2];
    matrix[10] = matrix[0];

void matrixRotateZ(float degrees, mat4 matrix)  
    float radians = degreesToRadians(degrees);


    // Rotate Z formula.
    matrix[0] = cosf(radians);
    matrix[1] = sinf(radians);
    matrix[4] = -matrix[1];
    matrix[5] = matrix[0];

void matrixMultiply(mat4 m1, mat4 m2, mat4 result)  
    // Fisrt Column
    result[0] = m1[0]*m2[0] + m1[4]*m2[1] + m1[8]*m2[2] + m1[12]*m2[3];
    result[1] = m1[1]*m2[0] + m1[5]*m2[1] + m1[9]*m2[2] + m1[13]*m2[3];
    result[2] = m1[2]*m2[0] + m1[6]*m2[1] + m1[10]*m2[2] + m1[14]*m2[3];
    result[3] = m1[3]*m2[0] + m1[7]*m2[1] + m1[11]*m2[2] + m1[15]*m2[3];

    // Second Column
    result[4] = m1[0]*m2[4] + m1[4]*m2[5] + m1[8]*m2[6] + m1[12]*m2[7];
    result[5] = m1[1]*m2[4] + m1[5]*m2[5] + m1[9]*m2[6] + m1[13]*m2[7];
    result[6] = m1[2]*m2[4] + m1[6]*m2[5] + m1[10]*m2[6] + m1[14]*m2[7];
    result[7] = m1[3]*m2[4] + m1[7]*m2[5] + m1[11]*m2[6] + m1[15]*m2[7];

    // Third Column
    result[8] = m1[0]*m2[8] + m1[4]*m2[9] + m1[8]*m2[10] + m1[12]*m2[11];
    result[9] = m1[1]*m2[8] + m1[5]*m2[9] + m1[9]*m2[10] + m1[13]*m2[11];
    result[10] = m1[2]*m2[8] + m1[6]*m2[9] + m1[10]*m2[10] + m1[14]*m2[11];
    result[11] = m1[3]*m2[8] + m1[7]*m2[9] + m1[11]*m2[10] + m1[15]*m2[11];

    // Fourth Column
    result[12] = m1[0]*m2[12] + m1[4]*m2[13] + m1[8]*m2[14] + m1[12]*m2[15];
    result[13] = m1[1]*m2[12] + m1[5]*m2[13] + m1[9]*m2[14] + m1[13]*m2[15];
    result[14] = m1[2]*m2[12] + m1[6]*m2[13] + m1[10]*m2[14] + m1[14]*m2[15];
    result[15] = m1[3]*m2[12] + m1[7]*m2[13] + m1[11]*m2[14] + m1[15]*m2[15];

Code: Select all

attribute vec4 vPosition;
attribute vec4 vColor;
uniform mat4 rotX;
uniform mat4 rotY;
uniform mat4 rotZ;
uniform mat4 scale;
varying vec4 color;

void main()

	gl_Position = scale * rotZ * vPosition;
	color = vColor;

Code: Select all

varying vec4 color;

void main()

	gl_FragColor = color;

Code: Select all


INC=-I/opt/vc/include/ -I/opt/vc/include/EGL -I/opt/vc/include/interface/vcos/pthreads -I/opt/vc/include/interface/vmcs_host/linux -I/opt/vc/include/GLES2/
LIBS=-L/opt/vc/lib/ -L./ -lbcm_host -lEGL -lGLESv2 -lvcos -lvchiq_arm -lpthread -lrt -lm

	$(COMP) $(FLAGS) $(IN) -o $(OUT) $(INC) $(LIBS)

Re: An example project for beginner's of OpenGL ES 2

Posted: Sat Sep 19, 2015 7:57 pm
by PeterO
Can you make a tar ball of your code to make it easier to try ?

Re: An example project for beginner's of OpenGL ES 2

Posted: Sat Sep 19, 2015 9:16 pm
by pizzaboy150
I have attached a tar file to my gmail account ... sp=sharing

Re: An example project for beginner's of OpenGL ES 2

Posted: Sat Sep 19, 2015 10:28 pm
by Paeryn
pizzaboy150 wrote:

Code: Select all

        //Draw the triangles from looking at the indices and refering to the vertex array data
        //the last param is special being 0 because we are using buffers, I do not understand why
        //we do not just pass in a pointer but hey ho it works
        glDrawElements(GL_TRIANGLES, sizeof(triIndices) / sizeof(triIndices[0]), GL_UNSIGNED_SHORT, 0);
The reason you pass 0 as the last parameter to glDrawElements when using buffers is that the pointer to the data is set according to the buffer that was bound with glBindBuffer. When you used glBufferData earlier gl allocated its own memory and copied your vertex data into it. The glBindBuffer lets gl know which buffer you want to use and so that last parameter to glDrawElements isn't needed. It's there for compatibility with the older method before there were buffers so you have just the one function call that works whether you use buffers or not. If you weren't using buffers then you would have to pass the pointer to the vertex data as the last parameter to glDrawElements.

Re: An example project for beginner's of OpenGL ES 2

Posted: Sun Sep 20, 2015 6:48 am
by PeterO
pizzaboy150 wrote:I have attached a tar file to my gmail account ... sp=sharing

Re: An example project for beginner's of OpenGL ES 2

Posted: Fri Nov 06, 2015 8:25 pm
by optimist
Hello Pizzaboy!

Thanks a lot for your work!

Early this week I got my brand new Rasberry Pi with the nice new touch screen and now would like to port a some OpenGL code I have running in Vizual Studio Express to the RasPi. I'd like to use Geany, but come into issues as the program does not find the relevant header file as egl.h ; gl2.h and gl2ext.h which Compiler do you use or better - do you know how I can tell Geany how to find the header files in /opt/vc/include/..

Thank you for a hint!