#include "error.h" #define OFFSET( P ) ( ( const GLvoid * ) ( sizeof( GLfloat ) * ( P ) ) ) #define STRIDE ( ( sizeof( GLfloat ) * ( 2 + 2 + 4 ) ) ) #define COLOR_0 ( 0 ) // 0 = COLOR_ATTACHMENT0 #define V_ARRAY ( 0 ) // 0 = VERTEX_ARRAY #define T_ARRAY ( 1 ) // 1 = TEXTURE_COORD_ARRAY #define C_ARRAY ( 2 ) // 2 = COLOR_ARRAY const GLchar *S[] = { // VS = VERTEX_SHADER #if GL_VERSION_3_2 "#version 150\n\n" "#define ATTRIBUTE in\n" "#define VARYING out\n\n" #else "#ifdef GL_ES\n\n" "precision mediump float;\n\n" "#endif\n\n" "#define ATTRIBUTE attribute\n" "#define VARYING varying\n\n" #endif // GL_VERSION_3_2 "ATTRIBUTE vec4 A0;\n" // A0 = gl_Vertex "ATTRIBUTE vec2 A1;\n" // A1 = gl_MultiTexCoord0.st "ATTRIBUTE vec4 A2;\n\n" // A2 = gl_Color "VARYING vec2 V0;\n" // V0 = gl_TexCoord[0].st "VARYING vec4 V1;\n\n" // V1 = gl_FrontColor "uniform mat4 M0;\n\n" // M0 = gl_ModelViewProjectionMatrix "void\n" "main( void )\n" "{\n" "\tV0 = vec2( A1 );\n" "\tV1 = vec4( A2 );\n\n" "\tgl_Position = vec4( M0 * A0 );\n" "}\n", // FS = FRAGMENT_SHADER #if GL_VERSION_3_2 "#version 150\n\n" "#define VARYING in\n" #else "#ifdef GL_ES\n\n" "precision mediump float;\n" "precision lowp sampler2D;\n\n" "#endif\n\n" "#define VARYING varying\n\n" "#define O0 gl_FragColor\n\n" #endif // GL_VERSION_3_2 "uniform sampler2D S0;\n\n" "VARYING vec2 V0;\n" // V0 = gl_TexCoord[0].st "VARYING vec4 V1;\n" // V1 = gl_Color #if GL_VERSION_3_2 "out vec4 O0;\n\n" // O0 = gl_FragColor #else "\n" #endif // GL_VERSION_3_2 "void\n" "main( void )\n" "{\n" "\tO0 = vec4( V1 * texture2D( S0, V0 ) );\n" "}\n", }; GLuint PID, VID, FID, UID, TID, AID, VAO, VBO, IBO, FBO, VAO; // SETUP STATE { // Generate (shader, texture, buffer) IDs. { PID = glCreateProgram( ); VID = glCreateShader( GL_VERTEX_SHADER ); FID = glCreateShader( GL_FRAGMENT_SHADER ); glGenTextures ( 1, &TID ); glGenTextures ( 1, &AID ); glGenBuffers ( 1, &VBO ); glGenBuffers ( 1, &IBO ); glGenFramebuffers( 1, &FBO ); #if GL_VERSION_3_2 glGenVertexArrays( 1, &VAO ); #endif // GL_VERSION_3_2 } // Compile VS, FS and setup attributes. { glShaderSource( VID, 1, &S[0], NULL ); glCompileShader( VID ); GetShaderInfoLog( VID, S[0] ); glAttachShader( PID, VID ); glShaderSource( FID, 1, &S[1], NULL ); glCompileShader( FID ); GetShaderInfoLog( FID, S[1] ); glAttachShader( PID, FID ); #if GL_VERSION_3_2 glBindFragDataLocation( PID, COLOR_0, "O0" ); // O0 = gl_FragColor, Only needed for indices > 0. #endif // GL_VERSION_3_2 glBindAttribLocation ( PID, V_ARRAY, "A0" ); // A0 = gl_Vertex, Only needed for indices > 0. glBindAttribLocation ( PID, T_ARRAY, "A1" ); // A1 = glMultiTexCoord0.st, Only needed for indices > 0. glBindAttribLocation ( PID, C_ARRAY, "A2" ); // A2 = gl_Color, Only needed for indices > 0. glLinkProgram( PID ); // TODO: Check for program errors here. glUseProgram( PID ); } // Setup uniform (matrix, sampler) state. { const GLfloat MVP[16] = { ... }; // Assumes ( MV * P ) matrix. glUniformMatrix4fv( ( UID = glGetUniformLocation( PID, "M0" ) ), 1, GL_FALSE, MVP ); glUniform1i ( ( glGetUniformLocation( PID, "S0" ) ), 0 ); // Only needed for units > GL_TEXTURE0. } // Setup VA, IA state and attribute offsets. { const GLfloat VA[ ] = { ... }; // Assumes interleaved { ..., X, Y, S, T, R, G, B, A, ... } (float ) vertex array. const GLushort IA[ ] = { ... }; // Assumes { ..., (N + 0), (N + 1), (N + 2), (N + 3), ... } (ushort) index array. #if GL_VERSION_3_2 glBindVertexArray( VAO ); #endif // GL_VERSION_3_2 glBindBuffer ( GL_ARRAY_BUFFER, VBO ); glBufferData( GL_ARRAY_BUFFER, sizeof( VA ), VA, GL_STATIC_DRAW ); glBindBuffer ( GL_ELEMENT_ARRAY_BUFFER, IBO ); glBufferData( GL_ELEMENT_ARRAY_BUFFER, sizeof( IA ), IA, GL_STATIC_DRAW ); glEnableVertexAttribArray( V_ARRAY ); glVertexAttribPointer( V_ARRAY, 2, GL_FLOAT, GL_FALSE, STRIDE, OFFSET( 0 ) ); // A0 = gl_Vertex glEnableVertexAttribArray( T_ARRAY ); glVertexAttribPointer( T_ARRAY, 2, GL_FLOAT, GL_FALSE, STRIDE, OFFSET( 2 ) ); // A1 = glMultiTexCoord0.st glEnableVertexAttribArray( C_ARRAY ); glVertexAttribPointer( C_ARRAY, 4, GL_FLOAT, GL_FALSE, STRIDE, OFFSET( 4 ) ); // A2 = gl_Color } // Setup texture state. { GLubyte *P = calloc( 1, ( W * H * 4 * sizeof( GLubyte ) ) ); { // TODO: Fill pixel buffer. } glActiveTexture( GL_TEXTURE0 ); glBindTexture ( GL_TEXTURE_2D, TID ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); // Only needed for (non default) NEAREST. glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE ); glTexImage2D ( GL_TEXTURE_2D, 0, GL_RGBA, W, H, 0, GL_RGBA, GL_UNSIGNED_BYTE, P ); free( P ); } // Setup framebuffer state (assumes support for GL_ARB_framebuffer_object). { glActiveTexture ( GL_TEXTURE0 ); glBindTexture ( GL_TEXTURE_2D, AID ); // Source. glBindFramebuffer( GL_FRAMEBUFFER, FBO ); // Destination. glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); // Only needed for (non default) NEAREST. glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE ); glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE ); glTexImage2D ( GL_TEXTURE_2D, 0, GL_RGBA, W, H, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL ); glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, AID, 0 ); CheckFramebufferStatus( ); } } // RENDER STATE { // Only needed for render to texture case. { glBindFramebuffer( GL_FRAMEBUFFER, FBO ); // Only needed for multiple texture case. { glActiveTexture( GL_TEXTURE0 ); glBindTexture ( GL_TEXTURE_2D, TID ); // Only needed for multiple buffer case. { #if GL_VERSION_3_2 glBindVertexArray( VAO ); #else glBindBuffer ( GL_ARRAY_BUFFER, VBO ); glBindBuffer ( GL_ELEMENT_ARRAY_BUFFER, IBO ); #endif // GL_VERSION_3_2 // Only needed for multiple program case. { glUseProgram ( PID ); glUniformMatrix4fv( UID, 1, GL_FALSE, MVP ); // Only needed for MVP updates. // Render primitives. { glDrawElements( GL_TRIANGLE_STRIP, ..., GL_UNSIGNED_SHORT, NULL ); } } } } } }