-
-
Save lephilousophe/1f8bb6757a8d621e6400fc9edd57a306 to your computer and use it in GitHub Desktop.
Blend color bug on big-endian
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// cc -g blend_color_bug.c -lSDL2 -lGLESv2 -o blend_color_bug | |
// | |
#include <GLES2/gl2.h> | |
#include <SDL2/SDL.h> | |
#include <SDL2/SDL_opengl.h> | |
#include <stdbool.h> | |
typedef struct | |
{ | |
unsigned int width; | |
unsigned int height; | |
// Handle to a program object | |
GLuint testProg; | |
unsigned int drawMode; | |
} UserData; | |
/// | |
// Create a shader object, load the shader source, and | |
// compile the shader. | |
// | |
GLuint LoadShader ( GLenum type, const char *shaderSrc ) | |
{ | |
GLuint shader; | |
GLint compiled; | |
// Create the shader object | |
shader = glCreateShader ( type ); | |
if ( shader == 0 ) | |
{ | |
fprintf( stderr, "glCreateShader error: %d\n", glGetError() ); | |
return 0; | |
} | |
// Load the shader source | |
glShaderSource ( shader, 1, &shaderSrc, NULL ); | |
// Compile the shader | |
glCompileShader ( shader ); | |
// Check the compile status | |
glGetShaderiv ( shader, GL_COMPILE_STATUS, &compiled ); | |
if ( !compiled ) | |
{ | |
GLint infoLen = 0; | |
glGetShaderiv ( shader, GL_INFO_LOG_LENGTH, &infoLen ); | |
if ( infoLen > 1 ) | |
{ | |
char* infoLog = malloc (sizeof(char) * infoLen ); | |
glGetShaderInfoLog ( shader, infoLen, NULL, infoLog ); | |
fprintf( stderr, "Error compiling shader:\n%s\n", infoLog ); | |
free ( infoLog ); | |
} | |
glDeleteShader ( shader ); | |
return 0; | |
} | |
return shader; | |
} | |
GLuint LinkProgram(const char *vertexSrc, const char *fragmentSrc) { | |
GLuint vertexShader; | |
GLuint fragmentShader; | |
GLuint programObject; | |
GLint linked; | |
// Load the vertex/fragment shaders | |
vertexShader = LoadShader ( GL_VERTEX_SHADER, vertexSrc ); | |
fragmentShader = LoadShader ( GL_FRAGMENT_SHADER, fragmentSrc ); | |
// Create the program object | |
programObject = glCreateProgram ( ); | |
if ( programObject == 0 ) | |
return 0; | |
glAttachShader ( programObject, vertexShader ); | |
glAttachShader ( programObject, fragmentShader ); | |
// Link the program | |
glLinkProgram ( programObject ); | |
// Check the link status | |
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 ); | |
fprintf ( stderr, "Error linking program:\n%s\n", infoLog ); | |
free ( infoLog ); | |
} | |
glDeleteProgram ( programObject ); | |
return 0; | |
} | |
return programObject; | |
} | |
/// | |
// Initialize the shader and program object | |
// | |
int Init ( UserData *userData ) | |
{ | |
GLbyte vShaderStr[] = | |
"#version 100\n" | |
"attribute vec4 aPosition;\n" | |
"attribute vec4 aColor;\n" | |
"varying vec4 vColor;\n" | |
"void main() {\n" | |
" gl_Position = aPosition;\n" | |
" vColor = aColor;\n" | |
"}\n"; | |
GLbyte fShaderStr[] = | |
"#version 100\n" | |
"precision mediump float;\n" | |
"varying vec4 vColor;\n" | |
"void main() {\n" | |
" gl_FragColor = vColor;\n" | |
"}\n"; | |
// Store the test program object | |
userData->testProg = LinkProgram(vShaderStr, fShaderStr); | |
if (userData->testProg == 0) { | |
return GL_FALSE; | |
} | |
glClearColor ( 0.0f, 0.0f, 0.0f, 0.0f ); | |
return GL_TRUE; | |
} | |
/// | |
// Draw a triangle using the shader pair created in Init() | |
// | |
void DrawTest ( UserData *userData ) | |
{ | |
GLfloat vVertices[] = { | |
0.5f, -0.5f, 0.5f, | |
-0.5f, -0.5f, 0.5f, | |
0.5f, -0.0f, 0.5f, | |
-0.5f, -0.0f, 0.5f, | |
-0.5f, -0.0f, 0.5f, | |
0.5f, 0.5f, 0.5f, | |
0.5f, -0.0f, 0.5f, | |
0.5f, 0.5f, 0.5f, | |
0.5f, 0.5f, 0.5f, | |
-0.5f, 0.0f, 0.5f, | |
-0.5f, 0.5f, 0.5f, | |
}; | |
GLfloat vColors_f[] = { | |
0.f, 1.f, 0.f, 1.f, | |
0.f, 1.f, 0.f, 1.f, | |
0.f, 1.f, 0.f, 1.f, | |
0.f, 1.f, 0.f, 1.f, | |
1.f, 0.f, 0.f, 1.f, | |
1.f, 0.f, 0.f, 1.f, | |
1.f, 0.f, 0.f, 1.f, | |
0.f, 0.f, 0.f, 0.f, | |
0.f, 0.f, 1.f, 1.f, | |
0.f, 0.f, 1.f, 1.f, | |
0.f, 0.f, 1.f, 1.f, | |
}; | |
glEnable(GL_BLEND); | |
switch(userData->drawMode) { | |
case 0: | |
glBlendColor(1.f, 1.f, 1.f, 0.f); | |
break; | |
case 1: | |
glBlendColor(0.f, 1.f, 1.f, 1.f); | |
break; | |
case 2: | |
glBlendColor(1.f, 0.f, 1.f, 1.f); | |
break; | |
case 3: | |
glBlendColor(1.f, 1.f, 0.f, 1.f); | |
break; | |
case 4: | |
glBlendColor(0.f, 0.f, 0.f, 0.f); | |
break; | |
} | |
glBlendFunc(GL_CONSTANT_COLOR, GL_ONE_MINUS_CONSTANT_COLOR); | |
// Use the program object | |
glUseProgram ( userData->testProg ); | |
// Load the vertex data | |
glVertexAttribPointer ( glGetAttribLocation(userData->testProg, "aPosition"), 3, GL_FLOAT, GL_FALSE, 0, vVertices ); | |
glVertexAttribPointer ( glGetAttribLocation(userData->testProg, "aColor"), 4, GL_FLOAT, GL_FALSE, 0, vColors_f ); | |
glEnableVertexAttribArray ( glGetAttribLocation(userData->testProg, "aPosition") ); | |
glEnableVertexAttribArray ( glGetAttribLocation(userData->testProg, "aColor") ); | |
glDrawArrays ( GL_TRIANGLE_STRIP, 0, sizeof(vVertices)/(sizeof(GLfloat)*3) ); | |
} | |
void Draw(UserData *userData) { | |
// Set the viewport | |
glViewport ( 0, 0, userData->width, userData->height ); | |
// Clear the color buffer | |
glClear ( GL_COLOR_BUFFER_BIT ); | |
DrawTest(userData); | |
} | |
static const char *MODES[] = { | |
"Blue and Red triangles + Green square", | |
"Blue triangle + Green square", | |
"Blue and Red triangles", | |
"Red triangle + Green square", | |
"Black screen", | |
}; | |
void changeState( const SDL_Event *e, UserData *userData ) { | |
switch (e->key.keysym.sym) { | |
case SDLK_g: | |
userData->drawMode++; | |
if (userData->drawMode > 4) { | |
userData->drawMode = 0; | |
} | |
break; | |
} | |
fprintf(stderr, "Current mode: <Current mode>=%d - %s\n", | |
userData->drawMode, | |
MODES[userData->drawMode]); | |
} | |
int main() | |
{ | |
UserData userData; | |
memset(&userData, 0, sizeof(userData)); | |
userData.width = 640; | |
userData.height = 480; | |
// For EGL on X11 to use with RenderDoc | |
#ifdef SDL_VIDEO_DRIVER_X11 | |
SDL_SetHint(SDL_HINT_VIDEO_X11_FORCE_EGL, "1"); | |
SDL_SetHint(SDL_HINT_OPENGL_ES_DRIVER, "1"); | |
#endif | |
SDL_InitSubSystem(SDL_INIT_VIDEO); | |
//SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG); | |
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_Window *window = SDL_CreateWindow("SDL GLES2", -1, -1, userData.width, userData.height, SDL_WINDOW_OPENGL); | |
if (!window) { | |
fprintf(stderr, "SDL_CreateWindow: error=%s\n", SDL_GetError() ); | |
return 1; | |
} | |
SDL_GLContext context = SDL_GL_CreateContext(window); | |
if (!context) { | |
fprintf(stderr, "SDL_GL_CreateContext: error=%s\n", SDL_GetError() ); | |
return 1; | |
} | |
if (SDL_GL_MakeCurrent(window, context)) { | |
fprintf(stderr, "SDL_GL_MakeCurrent: error=%s\n", SDL_GetError() ); | |
return 1; | |
} | |
fprintf(stderr, "%s\n", glGetString(GL_RENDERER) ); | |
if ( !Init ( &userData ) ) { | |
fprintf(stderr, "Failed to init\n"); | |
return 0; | |
} | |
bool quit = false; | |
SDL_Event e; | |
memset(&e, 0, sizeof(e)); | |
// Print default state | |
changeState(&e, &userData); | |
while (!quit) { | |
while (SDL_PollEvent(&e) != 0) { | |
switch (e.type) { | |
case SDL_QUIT: quit = true; break; | |
case SDL_KEYUP: changeState( &e, &userData ); break; | |
} | |
} | |
Draw( &userData ); | |
SDL_GL_SwapWindow(window); | |
} | |
SDL_GL_DeleteContext(context); | |
SDL_DestroyWindow(window); | |
SDL_Quit(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment