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
https://drive.google.com/file/d/0B78wUP ... sp=sharing
main.c
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
bcm_host_init();
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_LUMINANCE_SIZE, EGL_DONT_CARE,
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
EGL_SAMPLES, 1,
EGL_NONE
}
;
//This seems important for using ES2
static const EGLint context_attributes[] =
{
EGL_CONTEXT_CLIENT_VERSION, 2,
EGL_NONE
}
;
//Finish off the startup
EGLint numconfigs;
egldisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
eglInitialize(egldisplay, NULL, NULL);
eglBindAPI(EGL_OPENGL_ES_API);
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);
eglTerminate(egldisplay);
eglReleaseThread();
}
//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");
if(!file)
{
printf("unable to open file : %s", url);
exit(1);
}
//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);
rewind(file);
//lets allocate the memory for the file
char *buffer = calloc(1, lSize+1);
if(!buffer)
{
printf("Unable to allocate memory for file buffer!n");
fclose(file);
free(buffer);
exit(1);
}
//lets copy the data into the buffer
if(fread(buffer, lSize, 1, file) == 0)
{
//nothing read
printf("Nothing read from file : %s", url);
fclose(file);
free(buffer);
exit(1);
}
return buffer;
//close the file now we are finished with it
fclose(file);
}
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");
return;
}
fShader = glCreateShader(GL_FRAGMENT_SHADER);
if(fShader == 0) {
printf("Unable to create fragment shadern");
return;
}
//load vertex shader source
glShaderSource(vShader, 1, &vShaderStr, NULL);
//Compile vertex shader
glCompileShader(vShader);
// Check the compile status
glGetShaderiv(vShader, GL_COMPILE_STATUS, &vCompiled);
if(!vCompiled)
{
printf("Unable to compile vertex shader!n");
return;
}
//load fragment shader source
glShaderSource(fShader, 1, &fShaderStr, NULL);
//compile fragment shader
glCompileShader(fShader);
// Check the compile status
glGetShaderiv(fShader, GL_COMPILE_STATUS, &fCompiled);
if(!fCompiled)
{
printf("Unable to compile fragment shader!n");
return;
}
// Create the program object
programObject = glCreateProgram();
if(programObject == 0) {
printf("Unable to create Program Objectn");
return;
}
//Attach shaders to the program object
glAttachShader(programObject, vShader);
glAttachShader(programObject, fShader);
// Link the program
glLinkProgram(programObject);
// 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);
free(infoLog);
}
glDeleteProgram(programObject);
return;
}
return programObject;
}
int main(int argc, char *argv[])
{
//Setup the display
Init();
//make and compile the shaders
GLuint program = InitShader();
//use the compiled shaders
glUseProgram(program);
//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
glEnableVertexAttribArray(vPosition);
glEnableVertexAttribArray(vColor);
//set stuff
//glEnable(GL_DEPTH_TEST);
//glEnable(GL_CULL_FACE);
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
glClear(GL_COLOR_BUFFER_BIT);
//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
count++;
}
Deinit();
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)
{
matrixIdentity(matrix);
// Translate slots.
matrix[12] = x;
matrix[13] = y;
matrix[14] = z;
}
void matrixScale(float sx, float sy, float sz, mat4 matrix)
{
matrixIdentity(matrix);
// Scale slots.
matrix[0] = sx;
matrix[5] = sy;
matrix[10] = sz;
}
void matrixRotateX(float degrees, mat4 matrix)
{
float radians = degreesToRadians(degrees);
matrixIdentity(matrix);
// 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);
matrixIdentity(matrix);
// 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);
matrixIdentity(matrix);
// 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
IN=main.c
OUT=main.bin
FLAGS=-w
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=gcc
all:
$(COMP) $(FLAGS) $(IN) -o $(OUT) $(INC) $(LIBS)