So I am trying to render a character in OpenGL using freetype2. If I replace the variable vertex_location in my code with 0 I can see some kind of pixelated thing being rendered but it seems wrong because every time I restart the application the pixelated thing is different... So I am guessing it's just some random bytes or something.
Note: I am using GLEW, freetype2, glfw3, cglm
Anyways, here is my code:
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <stdio.h>
#include <cglm/cglm.h>
#include <cglm/call.h>
#include <math.h>
#include <ft2build.h>
#include FT_FREETYPE_H
/**
* Capture errors from glfw.
*/
static void error_callback(int error, const char* description)
{
fprintf(stderr, "Error: %s\n", description);
}
/**
* Capture key callbacks from glfw
*/
static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
{
if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
glfwSetWindowShouldClose(window, GLFW_TRUE);
}
typedef struct CHARACTER_STRUCT
{
GLuint texture; // ID handle of the glyph texture
vec2 size; // Size of glyph
float width;
float height;
float bearing_left;
float bearing_top;
GLuint advance; // Horizontal offset to advance to next glyph
} character_T;
character_T* get_character(char c)
{
// FreeType
FT_Library ft;
// All functions return a value different than 0 whenever an error occurred
if (FT_Init_FreeType(&ft))
perror("ERROR::FREETYPE: Could not init FreeType Library");
// Load font as face
FT_Face face;
if (FT_New_Face(ft, "/usr/share/fonts/truetype/lato/Lato-Medium.ttf", 0, &face))
perror("ERROR::FREETYPE: Failed to load font");
// Set size to load glyphs as
FT_Set_Pixel_Sizes(face, 0, 32);
// Disable byte-alignment restriction
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
// Load character glyph
if (FT_Load_Char(face, c, FT_LOAD_RENDER))
perror("ERROR::FREETYTPE: Failed to load Glyph");
// Generate texture
GLuint texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(
GL_TEXTURE_2D,
0,
GL_RED,
face->glyph->bitmap.width,
face->glyph->bitmap.rows,
0,
GL_RED,
GL_UNSIGNED_BYTE,
face->glyph->bitmap.buffer
);
// Set texture options
/*glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);*/
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
// Now store character for later use
character_T* character = calloc(1, sizeof(struct CHARACTER_STRUCT));
character->texture = texture;
character->width = face->glyph->bitmap.width;
character->height = face->glyph->bitmap.rows;
character->bearing_left = face->glyph->bitmap_left;
character->bearing_top = face->glyph->bitmap_top;
character->advance = face->glyph->advance.x;
glBindTexture(GL_TEXTURE_2D, 0);
// Destroy FreeType once we're finished
FT_Done_Face(face);
FT_Done_FreeType(ft);
return character;
}
int main(int argc, char* argv[])
{
glfwSetErrorCallback(error_callback);
/**
* Initialize glfw to be able to use it.
*/
if (!glfwInit())
perror("Failed to initialize glfw.\n");
/**
* Setting some parameters to the window,
* using OpenGL 3.3
*/
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_FLOATING, GL_TRUE);
glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
/**
* Creating our window
*/
GLFWwindow* window = glfwCreateWindow(640, 480, "My Title", NULL, NULL);
if (!window)
perror("Failed to create window.\n");
glfwSetKeyCallback(window, key_callback);
/**
* Enable OpenGL as current context
*/
glfwMakeContextCurrent(window);
/**
* Initialize glew and check for errors
*/
GLenum err = glewInit();
if (GLEW_OK != err)
fprintf(stderr, "Error: %s\n", glewGetErrorString(err));
fprintf(stdout, "Status: Using GLEW %s\n", glewGetString(GLEW_VERSION));
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
unsigned int VAO;
glGenVertexArrays(1, &VAO);
unsigned int VBO;
glGenBuffers(1, &VBO);
GLuint vertex_shader, fragment_shader, program;
GLint mvp_location, vertex_location;
/**
* Vertex Shader
*/
static const char* vertex_shader_text =
"#version 330 core\n"
"uniform mat4 MVP;\n"
"attribute vec4 thevertex;\n"
"out vec2 TexCoord;\n"
"void main()\n"
"{\n"
" gl_Position = MVP * vec4(thevertex.xy, 0.0, 1.0);\n"
" TexCoord = thevertex.zw;"
"}\n";
/**
* Fragment Shader
*/
static const char* fragment_shader_text =
"#version 330 core\n"
"varying vec3 color;\n"
"in vec2 TexCoord;\n"
"uniform sampler2D ourTexture;\n"
"void main()\n"
"{\n"
" vec4 sampled = vec4(1.0, 1.0, 1.0, texture(ourTexture, TexCoord).r);\n"
" gl_FragColor = vec4(vec3(1, 1, 1), 1.0) * sampled;\n"
"}\n";
int success;
char infoLog[512];
/**
* Compile vertex shader and check for errors
*/
vertex_shader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertex_shader, 1, &vertex_shader_text, NULL);
glCompileShader(vertex_shader);
glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, &success);
if(!success)
{
printf("Vertex Shader Error\n");
glGetShaderInfoLog(vertex_shader, 512, NULL, infoLog);
perror(infoLog);
}
/**
* Compile fragment shader and check for errors
*/
fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragment_shader, 1, &fragment_shader_text, NULL);
glCompileShader(fragment_shader);
glGetShaderiv(fragment_shader, GL_COMPILE_STATUS, &success);
if(!success)
{
printf("Fragment Shader Error\n");
glGetShaderInfoLog(fragment_shader, 512, NULL, infoLog);
perror(infoLog);
}
/**
* Create shader program and check for errors
*/
program = glCreateProgram();
glAttachShader(program, vertex_shader);
glAttachShader(program, fragment_shader);
glLinkProgram(program);
glGetProgramiv(program, GL_LINK_STATUS, &success);
if(!success)
{
glGetProgramInfoLog(program, 512, NULL, infoLog);
perror(infoLog);
}
/**
* Grab locations from shader
*/
vertex_location = glGetUniformLocation(program, "thevertex");
mvp_location = glGetUniformLocation(program, "MVP");
glBindVertexArray(VAO);
/**
* Create and bind texture
*/
character_T* character = get_character('s');
unsigned int texture = character->texture;
float scale = 1.0f;
GLfloat xpos = 0;
GLfloat ypos = 0;
GLfloat w = character->width * scale;
GLfloat h = character->height * scale;
GLfloat vertices[6][4] = {
{ xpos, ypos + h, 0.0, 0.0 },
{ xpos, ypos, 0.0, 1.0 },
{ xpos + w, ypos, 1.0, 1.0 },
{ xpos, ypos + h, 0.0, 0.0 },
{ xpos + w, ypos, 1.0, 1.0 },
{ xpos + w, ypos + h, 1.0, 0.0 }
};
/**
* Main loop
*/
while (!glfwWindowShouldClose(window))
{
int width, height;
mat4 p, mvp;
double t = glfwGetTime();
glfwGetFramebufferSize(window, &width, &height);
glViewport(0, 0, width, height);
glClear(GL_COLOR_BUFFER_BIT);
mat4 m = GLM_MAT4_IDENTITY_INIT;
glm_translate(m, (vec3){ -sin(t), -cos(t), 0 });
glm_ortho_default(width / (float) height, p);
glm_mat4_mul(p, m, mvp);
glUseProgram(program);
glUniformMatrix4fv(mvp_location, 1, GL_FALSE, (const GLfloat*) mvp);
/**
* Draw texture
*/
glActiveTexture(GL_TEXTURE0);
glBindVertexArray(VAO);
glBindTexture(GL_TEXTURE_2D, texture);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 6 * 4, vertices, GL_STATIC_DRAW);
glEnableVertexAttribArray(vertex_location);
glVertexAttribPointer(vertex_location, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), 0);
glDrawArrays(GL_TRIANGLES, 0, 6);
glfwSwapBuffers(window);
glfwPollEvents();
}
glfwDestroyWindow(window);
glfwTerminate();
return 0;
}
thevertex is a vertex attribute.
attribute vec4 thevertex;
thus you have to get the resource index of the attribute by glGetAttribLocation rather than glGetUniformLocation.
vertex_location = glGetUniformLocation(program, "thevertex");
vertex_location = glGetAttribLocation(program, "thevertex");
glGetUniformLocation is meant to retrieve the the active resource index (location) of an uniform variable.
Related
UPDATE
Ok, I read Learn OpenGL book from https://learnopengl.com/ and changed the OP code in order to support OpenGL 3.3 and later. I don't have the time now for writing the complete solution but if someone is interested ask!
OLD OP
I wrote an emulator using SDL2 and what I want is to add a barrel distortion, like an old CRT, to final rectangular video frame texture.
OpenGL SL vertex and fragment shaders come from here.
This is the code, icon.bmp is here:
#include <stdio.h>
#include "SDL.h"
#include "SDL_opengl.h"
static SDL_bool shaders_supported;
static int current_shader = 0;
enum
{
SHADER_1,
SHADER_2,
NUM_SHADERS
};
typedef struct
{
GLhandleARB program;
GLhandleARB vert_shader;
GLhandleARB frag_shader;
const char *vert_source;
const char *frag_source;
} ShaderData;
static ShaderData shaders[NUM_SHADERS] =
{
// SHADER_1
{0, 0, 0,
/* vertex shader */
"varying vec4 v_color;\n"
"varying vec2 v_texCoord;\n"
"\n"
"void main()\n"
"{\n"
" gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n"
" v_color = gl_Color;\n"
" v_texCoord = vec2(gl_MultiTexCoord0);\n"
"}",
/* fragment shader */
"varying vec4 v_color;\n"
"varying vec2 v_texCoord;\n"
"uniform sampler2D tex0;\n"
"\n"
"void main()\n"
"{\n"
" gl_FragColor = texture2D(tex0, v_texCoord) * v_color;\n"
"}"
},
// SHADER_2
{0, 0, 0,
/* vertex shader */
"varying vec4 Vertex_UV;\n"
"uniform mat4 gxl3d_ModelViewProjectionMatrix;\n"
"void main()\n"
"{\n"
" gl_Position = gxl3d_ModelViewProjectionMatrix * gl_Vertex;\n"
" Vertex_UV = gl_MultiTexCoord0;\n"
"}",
/* fragment shader */
"uniform sampler2D tex0;\n"
"varying vec4 Vertex_UV;\n"
"const float PI = 3.1415926535;\n"
"uniform float BarrelPower;\n"
"\n"
"vec2 Distort(vec2 p)\n"
"{\n"
" float theta = atan(p.y, p.x);\n"
" float radius = length(p);\n"
" radius = pow(radius, BarrelPower);\n"
" p.x = radius * cos(theta);\n"
" p.y = radius * sin(theta);\n"
" return 0.5 * (p + 1.0);\n"
"}\n"
"\n"
"void main()\n"
"{\n"
" vec2 xy = 2.0 * Vertex_UV.xy - 1.0;\n"
" vec2 uv;\n"
" float d = length(xy);\n"
" if (d < 1.0)\n"
" {\n"
" uv = Distort(xy);\n"
" }\n"
" else\n"
" {\n"
" uv = Vertex_UV.xy;\n"
" }\n"
" vec4 c = texture2D(tex0, uv);\n"
" gl_FragColor = c;\n"
"}"
}
};
static PFNGLATTACHOBJECTARBPROC glAttachObjectARB;
static PFNGLCOMPILESHADERARBPROC glCompileShaderARB;
static PFNGLCREATEPROGRAMOBJECTARBPROC glCreateProgramObjectARB;
static PFNGLCREATESHADEROBJECTARBPROC glCreateShaderObjectARB;
static PFNGLDELETEOBJECTARBPROC glDeleteObjectARB;
static PFNGLGETINFOLOGARBPROC glGetInfoLogARB;
static PFNGLGETOBJECTPARAMETERIVARBPROC glGetObjectParameterivARB;
static PFNGLGETUNIFORMLOCATIONARBPROC glGetUniformLocationARB;
static PFNGLLINKPROGRAMARBPROC glLinkProgramARB;
static PFNGLSHADERSOURCEARBPROC glShaderSourceARB;
static PFNGLUNIFORM1IARBPROC glUniform1iARB;
static PFNGLUSEPROGRAMOBJECTARBPROC glUseProgramObjectARB;
static SDL_bool CompileShader(GLhandleARB shader, const char *source)
{
GLint status = 0;
glShaderSourceARB(shader, 1, &source, NULL);
glCompileShaderARB(shader);
glGetObjectParameterivARB(shader, GL_OBJECT_COMPILE_STATUS_ARB, &status);
if (status == 0)
{
GLint length = 0;
char *info;
glGetObjectParameterivARB(shader, GL_OBJECT_INFO_LOG_LENGTH_ARB, &length);
info = (char *)SDL_malloc(length + 1);
if (!info)
{
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Out of memory!");
}
else
{
glGetInfoLogARB(shader, length, NULL, info);
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to compile shader:\n%s\n%s", source, info);
SDL_free(info);
}
return SDL_FALSE;
}
else
return SDL_TRUE;
}
static SDL_bool LinkProgram(ShaderData *data)
{
GLint status = 0;
glAttachObjectARB(data->program, data->vert_shader);
glAttachObjectARB(data->program, data->frag_shader);
glLinkProgramARB(data->program);
glGetObjectParameterivARB(data->program, GL_OBJECT_LINK_STATUS_ARB, &status);
if (status == 0)
{
GLint length = 0;
char *info;
glGetObjectParameterivARB(data->program, GL_OBJECT_INFO_LOG_LENGTH_ARB, &length);
info = (char *) SDL_malloc(length + 1);
if (!info)
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Out of memory!");
else
{
glGetInfoLogARB(data->program, length, NULL, info);
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to link program:\n%s", info);
SDL_free(info);
}
return SDL_FALSE;
}
else
return SDL_TRUE;
}
static SDL_bool CompileShaderProgram(ShaderData *data)
{
const int num_tmus_bound = 4;
int i;
GLint location;
glGetError();
/* Create one program object to rule them all */
data->program = glCreateProgramObjectARB();
/* Create the vertex shader */
data->vert_shader = glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB);
if (!CompileShader(data->vert_shader, data->vert_source))
return SDL_FALSE;
/* Create the fragment shader */
data->frag_shader = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);
if (!CompileShader(data->frag_shader, data->frag_source))
return SDL_FALSE;
/* ... and in the darkness bind them */
if (!LinkProgram(data))
return SDL_FALSE;
/* Set up some uniform variables */
glUseProgramObjectARB(data->program);
for (i = 0; i < num_tmus_bound; ++i)
{
char tex_name[5];
SDL_snprintf(tex_name, SDL_arraysize(tex_name), "tex%d", i);
location = glGetUniformLocationARB(data->program, tex_name);
if (location >= 0)
glUniform1iARB(location, i);
}
glUseProgramObjectARB(0);
return (glGetError() == GL_NO_ERROR) ? SDL_TRUE : SDL_FALSE;
}
static void DestroyShaderProgram(ShaderData *data)
{
if (shaders_supported)
{
glDeleteObjectARB(data->vert_shader);
glDeleteObjectARB(data->frag_shader);
glDeleteObjectARB(data->program);
}
}
static SDL_bool InitShaders()
{
int i;
/* Check for shader support */
shaders_supported = SDL_FALSE;
if (SDL_GL_ExtensionSupported("GL_ARB_shader_objects") &&
SDL_GL_ExtensionSupported("GL_ARB_shading_language_100") &&
SDL_GL_ExtensionSupported("GL_ARB_vertex_shader") &&
SDL_GL_ExtensionSupported("GL_ARB_fragment_shader"))
{
glAttachObjectARB = (PFNGLATTACHOBJECTARBPROC) SDL_GL_GetProcAddress("glAttachObjectARB");
glCompileShaderARB = (PFNGLCOMPILESHADERARBPROC) SDL_GL_GetProcAddress("glCompileShaderARB");
glCreateProgramObjectARB = (PFNGLCREATEPROGRAMOBJECTARBPROC) SDL_GL_GetProcAddress("glCreateProgramObjectARB");
glCreateShaderObjectARB = (PFNGLCREATESHADEROBJECTARBPROC) SDL_GL_GetProcAddress("glCreateShaderObjectARB");
glDeleteObjectARB = (PFNGLDELETEOBJECTARBPROC) SDL_GL_GetProcAddress("glDeleteObjectARB");
glGetInfoLogARB = (PFNGLGETINFOLOGARBPROC) SDL_GL_GetProcAddress("glGetInfoLogARB");
glGetObjectParameterivARB = (PFNGLGETOBJECTPARAMETERIVARBPROC) SDL_GL_GetProcAddress("glGetObjectParameterivARB");
glGetUniformLocationARB = (PFNGLGETUNIFORMLOCATIONARBPROC) SDL_GL_GetProcAddress("glGetUniformLocationARB");
glLinkProgramARB = (PFNGLLINKPROGRAMARBPROC) SDL_GL_GetProcAddress("glLinkProgramARB");
glShaderSourceARB = (PFNGLSHADERSOURCEARBPROC) SDL_GL_GetProcAddress("glShaderSourceARB");
glUniform1iARB = (PFNGLUNIFORM1IARBPROC) SDL_GL_GetProcAddress("glUniform1iARB");
glUseProgramObjectARB = (PFNGLUSEPROGRAMOBJECTARBPROC) SDL_GL_GetProcAddress("glUseProgramObjectARB");
if (glAttachObjectARB && glCompileShaderARB && glCreateProgramObjectARB && glCreateShaderObjectARB &&
glDeleteObjectARB && glGetInfoLogARB && glGetObjectParameterivARB && glGetUniformLocationARB &&
glLinkProgramARB && glShaderSourceARB && glUniform1iARB && glUseProgramObjectARB)
shaders_supported = SDL_TRUE;
}
if (!shaders_supported)
return SDL_FALSE;
/* Compile all the shaders */
for (i = 0; i < NUM_SHADERS; ++i)
{
if (!CompileShaderProgram(&shaders[i]))
{
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Unable to compile shader!\n");
return SDL_FALSE;
}
}
/* We're done! */
return SDL_TRUE;
}
static void QuitShaders()
{
int i;
for (i = 0; i < NUM_SHADERS; ++i)
DestroyShaderProgram(&shaders[i]);
}
/* Quick utility function for texture creation */
static int power_of_two(int input)
{
int value = 1;
while (value < input)
value <<= 1;
return value;
}
GLuint
SDL_GL_LoadTexture(SDL_Surface * surface, GLfloat * texcoord)
{
GLuint texture;
int w, h;
SDL_Surface *image;
SDL_Rect area;
SDL_BlendMode saved_mode;
/* Use the surface width and height expanded to powers of 2 */
w = power_of_two(surface->w);
h = power_of_two(surface->h);
texcoord[0] = 0.0f; /* Min X */
texcoord[1] = 0.0f; /* Min Y */
texcoord[2] = (GLfloat) surface->w / w; /* Max X */
texcoord[3] = (GLfloat) surface->h / h; /* Max Y */
image = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, 32,
#if SDL_BYTEORDER == SDL_LIL_ENDIAN /* OpenGL RGBA masks */
0x000000FF,
0x0000FF00,
0x00FF0000,
0xFF000000
#else
0xFF000000,
0x00FF0000,
0x0000FF00,
0x000000FF
#endif
);
if (image == NULL)
return 1;
/* Save the alpha blending attributes */
SDL_GetSurfaceBlendMode(surface, &saved_mode);
SDL_SetSurfaceBlendMode(surface, SDL_BLENDMODE_NONE);
/* Copy the surface into the GL texture image */
area.x = 0;
area.y = 0;
area.w = surface->w;
area.h = surface->h;
SDL_BlitSurface(surface, &area, image, &area);
/* Restore the alpha blending attributes */
SDL_SetSurfaceBlendMode(surface, saved_mode);
/* Create an OpenGL texture for the image */
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D,
0,
GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, image->pixels);
SDL_FreeSurface(image); /* No longer needed */
return texture;
}
/* A general OpenGL initialization function. Sets all of the initial parameters. */
void InitGL(int Width, int Height) /* We call this right after our OpenGL window is created. */
{
GLdouble aspect;
glViewport(0, 0, Width, Height);
glClearColor(0.0f, 0.0f, 0.0f, 0.0f); /* This Will Clear The Background Color To Black */
glClearDepth(1.0); /* Enables Clearing Of The Depth Buffer */
glDepthFunc(GL_LESS); /* The Type Of Depth Test To Do */
glEnable(GL_DEPTH_TEST); /* Enables Depth Testing */
glShadeModel(GL_SMOOTH); /* Enables Smooth Color Shading */
glMatrixMode(GL_PROJECTION);
glLoadIdentity(); /* Reset The Projection Matrix */
aspect = (GLdouble)Width / Height;
glOrtho(-1.0, 1.0, -1.0 / aspect, 1.0 / aspect, 0.0, 1.0);
glMatrixMode(GL_MODELVIEW);
}
/* The main drawing function. */
void DrawGLScene(SDL_Window *window, GLuint texture, GLfloat * texcoord)
{
/* Texture coordinate lookup, to make it simple */
enum
{
MINX,
MINY,
MAXX,
MAXY
};
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); /* Clear The Screen And The Depth Buffer */
glLoadIdentity(); /* Reset The View */
/* Enable blending */
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
/* draw a textured square (quadrilateral) */
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, texture);
glColor3f(0.5f, 0.5f, 0.5f);
if (shaders_supported)
glUseProgramObjectARB(shaders[current_shader].program);
glBegin(GL_QUADS); /* start drawing a polygon (4 sided) */
glTexCoord2f(texcoord[MINX], texcoord[MINY]);
glVertex3f(-1.0f, 1.0f, 0.0f); /* Top Left */
glTexCoord2f(texcoord[MAXX], texcoord[MINY]);
glVertex3f( 1.0f, 1.0f, 0.0f); /* Top Right */
glTexCoord2f(texcoord[MAXX], texcoord[MAXY]);
glVertex3f( 1.0f,-1.0f, 0.0f); /* Bottom Right */
glTexCoord2f(texcoord[MINX], texcoord[MAXY]);
glVertex3f(-1.0f,-1.0f, 0.0f); /* Bottom Left */
glEnd(); /* done with the polygon */
if (shaders_supported)
glUseProgramObjectARB(0);
glDisable(GL_TEXTURE_2D);
/* swap buffers to display, since we're double buffered. */
SDL_GL_SwapWindow(window);
}
int main(int argc, char **argv)
{
int done;
SDL_Window *window;
SDL_Surface *surface;
GLuint texture;
GLfloat texcoords[4];
/* Enable standard application logging */
SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO);
/* Initialize SDL for video output */
if ( SDL_Init(SDL_INIT_VIDEO) < 0 )
{
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Unable to initialize SDL: %s\n", SDL_GetError());
exit(1);
}
/* Create a 500x500 OpenGL screen */
window = SDL_CreateWindow( "Shader Demo", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 500, 500, SDL_WINDOW_OPENGL );
if ( !window )
{
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Unable to create OpenGL window: %s\n", SDL_GetError());
SDL_Quit();
exit(2);
}
if ( !SDL_GL_CreateContext(window))
{
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Unable to create OpenGL context: %s\n", SDL_GetError());
SDL_Quit();
exit(3);
}
printf("Vendor graphic card: %s\n", glGetString(GL_VENDOR));
printf("Renderer: %s\n", glGetString(GL_RENDERER));
printf("Version GL: %s\n", glGetString(GL_VERSION));
printf("Version GLSL: %s\n", glGetString(GL_SHADING_LANGUAGE_VERSION));
surface = SDL_LoadBMP("icon.bmp");
if ( ! surface )
{
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Unable to load icon.bmp: %s\n", SDL_GetError());
SDL_Quit();
exit(4);
}
texture = SDL_GL_LoadTexture(surface, texcoords);
SDL_FreeSurface(surface);
/* Loop, drawing and checking events */
InitGL(500, 500);
if (InitShaders())
SDL_Log("Shaders supported, press SPACE to cycle them.\n");
else
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Shaders not supported!\n");
done = 0;
while ( ! done )
{
DrawGLScene(window, texture, texcoords);
/* This could go in a separate function */
{ SDL_Event event;
while ( SDL_PollEvent(&event) )
{
if ( event.type == SDL_QUIT )
done = 1;
if ( event.type == SDL_KEYDOWN )
{
if ( event.key.keysym.sym == SDLK_SPACE )
current_shader = (current_shader + 1) % NUM_SHADERS;
if ( event.key.keysym.sym == SDLK_ESCAPE )
done = 1;
}
}
}
}
QuitShaders();
SDL_Quit();
return 0;
}
As you can see when you press SPACE on keyboard the second shader shows a black window. I tried many barrel/fish eye shaders from internet but I always got the same behaviour, so something is wrong in this code.
I used to develop with SDL2 so I know only the theory behind OpenGL SL and I don't want to learn all OpenGL.
Really appreciate any suggestion.
So the source you've used is not using modern OpenGL as you've noted. I've taken it as an example and nabbed some of your code to get a basic version working with modern OpenGL which I believe has the effect you're looking for. Note that I've used GLEW to write my version so I can get access to all the OpenGL functions.
Here is what happens when you press the spacebar in my version. I have the BarrelPower set at 2 as a constant in my shader, but you can play around with that value to inspect the results. You could also quite easily pass it in as an attribute for better configurability.
Below is my source code which I have commented up to explain the changes. I figure that's better than listing them here since you can take a local copy and study it. Between this and LearnOpenGL.com it should be enough to get you up and running.
Let me know if this helps!
#include <stdio.h>
#include <stdbool.h>
#include <GL/glew.h>
#include <SDL.h>
#include <SDL_opengl.h>
#define WINDOW_WIDTH 640
#define WINDOW_HEIGHT 480
#define NUM_SHADERS 2
// Some globals since this is an example
SDL_Window* window = NULL;
SDL_GLContext glContext;
// Vertices (and texture coords) and indices
// See "SetupDrawing" function for their initialisation
float vertices[20];
int indices[6];
// Handles for out VBO and IBO
int vbo = -1;
int ibo = -1;
// Existing shader structure (unchanged)
typedef struct
{
GLhandleARB program;
GLhandleARB vert_shader;
GLhandleARB frag_shader;
const char* vert_source;
const char* frag_source;
} ShaderData;
// Array of shaders - see comments for updates
static ShaderData shaders[NUM_SHADERS] =
{
// SHADER_1
{0, 0, 0,
/* vertex shader - In our basic vertex shader you can see we take
* position and textureCoord attributes. These are setup from our
* global vertices array later in the code. You can also see that
* we are passing out a textureCoord value which is picked up by
* the fragment shader later on in the pipeline
*/
"#version 330\n"
"attribute vec3 position;\n"
"attribute vec2 texCoord;\n"
"out vec2 textureCoord;\n"
"\n"
"void main()\n"
"{\n"
" gl_Position = vec4(position, 1.0);\n"
" textureCoord = texCoord;\n"
"}",
/* fragment shader - Our fragment shader is very basic. It gets texture
coords passed through our vertex shader and a texture. We then use the
glsl texture function to perform our texturing. When you initially run
the app, this is the fragment shader that will be in use
*/
"#version 330\n"
"in vec2 textureCoord;\n"
"uniform sampler2D theTexture;\n"
"void main()\n"
"{\n"
" gl_FragColor = texture(theTexture, textureCoord);\n"
"}"
},
// SHADER_2
{0, 0, 0,
/* vertex shader - Our vertex shader remains unchanged for the second program.
The barrel distortion effect is being applied in the fragment shader only
*/
"#version 330\n"
"attribute vec3 position;\n"
"attribute vec2 texCoord;\n"
"out vec2 textureCoord;\n"
"\n"
"void main()\n"
"{\n"
" gl_Position = vec4(position, 1.0);\n"
" textureCoord = texCoord;\n"
"}",
/* fragment shader - Here is the barrel distortion fragment shader. Not
too much has changed here. The updates are simply to the expected inputs
which are the same as our basic fragment shader. Barrel power has been
made constant for simplicity. You can increase and decrease this value to
observe the effects. In the main the code is essentially the same, I've
just changed the Vertex_UV.xy to textureCoord since that's what would've
been in the Vertex_UV.x and .y variables in the old version. */
"#version 330\n"
"in vec2 textureCoord;\n"
"uniform sampler2D theTexture;\n"
"const float PI = 3.1415926535;\n"
"const float BarrelPower = 2.0;\n"
"\n"
"vec2 Distort(vec2 p)\n"
"{\n"
" float theta = atan(p.y, p.x);\n"
" float radius = length(p);\n"
" radius = pow(radius, BarrelPower);\n"
" p.x = radius * cos(theta);\n"
" p.y = radius * sin(theta);\n"
" return 0.5 * (p + 1.0);\n"
"}\n"
"\n"
"void main()\n"
"{\n"
" vec2 xy = 2.0 * textureCoord - 1.0;\n"
" vec2 uv;\n"
" float d = length(xy);\n"
" if (d < 1.0)\n"
" {\n"
" uv = Distort(xy);\n"
" }\n"
" else\n"
" {\n"
" uv = textureCoord;\n"
" }\n"
" vec4 c = texture2D(theTexture, uv);\n"
" gl_FragColor = c;\n"
"}"
}
};
bool Setup()
{
bool setupSuccess = false;
bool sdlInitialised = SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS) == 0;
if (sdlInitialised)
{
window = SDL_CreateWindow("Barrel Distortion Test", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, WINDOW_WIDTH, WINDOW_HEIGHT, SDL_WINDOW_OPENGL);
if (window)
{
glContext = SDL_GL_CreateContext(window);
glewInit();
glViewport(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT);
glClearColor(0.9f, 0.9f, 0.9f, 0.f);
setupSuccess = true;
}
else
{
printf("Could not initialise GL window\n");
}
}
else
{
printf("Could not initialise SDL\n");
}
return setupSuccess;
}
void Teardown()
{
SDL_DestroyWindow(window);
window = NULL;
glDeleteBuffers(1, &vbo);
glDeleteBuffers(1, &ibo);
}
void SetupDrawing()
{
// Setup vertices and texture coords. We setup a stride later for indexing these. The
// first three values on each line are the vertices, the last two are the texture
// coordinates (U, V)
vertices[0] = 1.0f; vertices[1] = 1.0f; vertices[2] = 0.0f; vertices[3] = 0.f; vertices[4] = 0.f;
vertices[5] = 1.0f; vertices[6] = -1.0f; vertices[7] = 0.0f; vertices[8] = 0.f; vertices[9] = 1.f;
vertices[10] = -1.0f; vertices[11] = -1.0f; vertices[12] = 0.0f; vertices[13] = 1.f; vertices[14] = 1.f;
vertices[15] = -1.0f; vertices[16] = 1.0f; vertices[17] = 0.0f; vertices[18] = 1.f; vertices[19] = 0.f;
// Setup indices
indices[0] = 0; indices[1] = 1; indices[2] = 3;
indices[3] = 1; indices[4] = 2; indices[5] = 3;
// Setup buffers
glGenBuffers(1, &vbo);
glGenBuffers(1, &ibo);
}
static SDL_bool CompileShader(GLhandleARB shader, const char* source)
{
GLint status = 0;
glShaderSource(shader, 1, &source, NULL);
glCompileShader(shader);
glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
if (status == 0)
{
GLint length = 0;
char* info;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length);
info = (char*)SDL_malloc(length + 1);
if (!info)
{
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Out of memory!");
}
else
{
glGetInfoLogARB(shader, length, NULL, info);
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to compile shader:\n%s\n%s", source, info);
//SDL_free(info);
}
return SDL_FALSE;
}
else
return SDL_TRUE;
}
static SDL_bool LinkProgram(ShaderData* data)
{
GLint status = 0;
glAttachShader(data->program, data->vert_shader);
glAttachShader(data->program, data->frag_shader);
glLinkProgram(data->program);
glGetProgramiv(data->program, GL_LINK_STATUS, &status);
if (status == 0)
{
GLint length = 0;
char* info;
glGetProgramiv(data->program, GL_INFO_LOG_LENGTH, &length);
info = (char*)SDL_malloc(length + 1);
if (!info)
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Out of memory!");
else
{
glGetProgramInfoLog(data->program, length, NULL, info);
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to link program:\n%s", info);
SDL_free(info);
}
return SDL_FALSE;
}
else
return SDL_TRUE;
}
static SDL_bool CompileShaderProgram(ShaderData* data)
{
const int num_tmus_bound = 4;
int i;
GLint location;
glGetError();
/* Create one program object to rule them all */
data->program = glCreateProgram();
/* Create the vertex shader */
data->vert_shader = glCreateShader(GL_VERTEX_SHADER);
if (!CompileShader(data->vert_shader, data->vert_source))
return SDL_FALSE;
/* Create the fragment shader */
data->frag_shader = glCreateShader(GL_FRAGMENT_SHADER);
if (!CompileShader(data->frag_shader, data->frag_source))
return SDL_FALSE;
/* ... and in the darkness bind them */
if (!LinkProgram(data))
return SDL_FALSE;
return (glGetError() == GL_NO_ERROR) ? SDL_TRUE : SDL_FALSE;
}
static void DestroyShaderProgram(ShaderData* data)
{
glDeleteShader(data->vert_shader);
glDeleteShader(data->frag_shader);
glDeleteProgram(data->program);
}
/* Quick utility function for texture creation */
static int power_of_two(int input)
{
int value = 1;
while (value < input)
value <<= 1;
return value;
}
GLuint SDL_GL_LoadTexture(SDL_Surface* surface/*, GLfloat* texcoord*/)
{
GLuint texture;
int w, h;
SDL_Surface* image;
SDL_Rect area;
SDL_BlendMode saved_mode;
/* Use the surface width and height expanded to powers of 2 */
w = power_of_two(surface->w);
h = power_of_two(surface->h);
image = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, 32,
#if SDL_BYTEORDER == SDL_LIL_ENDIAN /* OpenGL RGBA masks */
0x000000FF,
0x0000FF00,
0x00FF0000,
0xFF000000
#else
0xFF000000,
0x00FF0000,
0x0000FF00,
0x000000FF
#endif
);
if (image == NULL)
return 1;
/* Save the alpha blending attributes */
SDL_GetSurfaceBlendMode(surface, &saved_mode);
SDL_SetSurfaceBlendMode(surface, SDL_BLENDMODE_NONE);
/* Copy the surface into the GL texture image */
area.x = 0;
area.y = 0;
area.w = surface->w;
area.h = surface->h;
SDL_BlitSurface(surface, &area, image, &area);
/* Restore the alpha blending attributes */
SDL_SetSurfaceBlendMode(surface, saved_mode);
/* Create an OpenGL texture for the image */
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, image->pixels);
SDL_FreeSurface(image); /* No longer needed */
return texture;
}
static SDL_bool InitShaders()
{
int i;
/* Compile all the shaders */
for (i = 0; i < NUM_SHADERS; ++i)
{
if (!CompileShaderProgram(&shaders[i]))
{
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Unable to compile shader!\n");
return SDL_FALSE;
}
}
/* We're done! */
return SDL_TRUE;
}
static void QuitShaders()
{
int i;
for (i = 0; i < NUM_SHADERS; ++i)
DestroyShaderProgram(&shaders[i]);
}
void Run()
{
bool shadersInitialised = InitShaders();
if (!shadersInitialised)
return;
SetupDrawing();
int texture = -1;
SDL_Surface* surface = SDL_LoadBMP("icon.bmp");
if (surface)
{
texture = SDL_GL_LoadTexture(surface);
}
int shaderIndex = 0;
SDL_Event e;
bool run = true;
while (run)
{
while (SDL_PollEvent(&e))
{
if (e.type == SDL_QUIT)
{
run = false;
}
else if (e.type == SDL_KEYDOWN & e.key.keysym.sym == SDLK_SPACE)
{
if (shaderIndex == 0)
{
shaderIndex = 1;
}
else if (shaderIndex == 1)
{
shaderIndex = 0;
}
}
}
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram(shaders[shaderIndex].program);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);
// Bind our vertices to our array
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_DYNAMIC_DRAW);
// Find our attributes in the current shader program and once found setup the
// attribute pointers
int position = glGetAttribLocation(shaders[shaderIndex].program, "position");
if (position != -1)
{
glVertexAttribPointer(position, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void *)0);
}
int textureCoord = glGetAttribLocation(shaders[shaderIndex].program, "texCoord");
if (textureCoord != -1)
{
glVertexAttribPointer(textureCoord, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void *)(3 * sizeof(float)));
}
// Bind our indices to our array
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_DYNAMIC_DRAW);
// Enable vertex attrib array
glEnableVertexAttribArray(position);
glEnableVertexAttribArray(textureCoord);
// Draw
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
// Disable vertex attrib array
glDisableVertexAttribArray(position);
glDisableVertexAttribArray(textureCoord);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
SDL_GL_SwapWindow(window);
}
}
int main(int argc, char** argv)
{
bool setupSuccess = Setup();
if (setupSuccess)
{
Run();
}
Teardown();
return 0;
}
I'm trying to write a code to draw a triangle with changing color, following the tutorial LearnOpenGL - Shaders.
But my code doesn't work, the triangle is blinking instead of gradually change the color, I don't know if it is a hardware or software problem.
Can anyone help me?
I'm using OpenGL 3.0 with Mesa 18.3.4.
And compiling with gcc shaders_change.c -lGL -lglfw -lm
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <GL/gl.h>
#include <GLFW/glfw3.h>
void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void processInput(GLFWwindow *window);
const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 600;
const char *vertexShaderSource ="#version 330 core\n"
"layout (location = 0) in vec3 aPos;\n"
"void main()\n"
"{\n"
" gl_Position = vec4(aPos, 1.0);\n"
"}\n\0";
const char *fragmentShaderSource = "#version 330\n"
"out vec4 FragColor;\n"
"uniform vec4 ourColor;\n"
"void main()\n"
"{\n"
" FragColor = ourColor;\n"
"}\n\0";
int main(){
// glfw: initialize and configure
// ------------------------------
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
// glfw window creation
// --------------------
GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL);
if (window == NULL)
{
printf("Failed to create GLFW window");
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
// build and compile our shader program
// ------------------------------------
// vertex shader
int vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
glCompileShader(vertexShader);
// check for shader compile errors
int success;
char infoLog[512];
glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
printf("ERROR::SHADER::VERTEX::COMPILATION_FAILED\n%s",infoLog);
}
// fragment shader
int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
glCompileShader(fragmentShader);
// check for shader compile errors
glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);
printf("ERROR::SHADER::VERTEX::COMPILATION_FAILED\n%s",infoLog);
}
// link shaders
int shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);
// check for linking errors
glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
if (!success) {
glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);
printf("ERROR::SHADER::VERTEX::COMPILATION_FAILED\n%s",infoLog);
}
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
// set up vertex data (and buffer(s)) and configure vertex attributes
// ------------------------------------------------------------------
float vertices[] = {
// positions // colors
0.5f, -0.5f, 0.0f, // bottom right
-0.5f, -0.5f, 0.0f, // bottom left
0.0f, 0.5f, 0.0f, // top
};
unsigned int VBO, VAO;
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
// bind the Vertex Array Object first, then bind and set vertex buffer(s), and then configure vertex attributes(s).
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
// position attribute
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), 0);
glEnableVertexAttribArray(0);
// color attribute
//glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3 * sizeof(float)));
//glEnableVertexAttribArray(VAO);
// You can unbind the VAO afterwards so other VAO calls won't accidentally modify this VAO, but this rarely happens. Modifying other
// VAOs requires a call to glBindVertexArray anyways so we generally don't unbind VAOs (nor VBOs) when it's not directly necessary.
// as we only have a single shader, we could also just activate our shader once beforehand if we want to
glBindVertexArray(VAO);
// render loop
// -----------
float timeValue;
float greenValue;
int vertexColorLocation;
while (!glfwWindowShouldClose(window)){
// input
// -----
processInput(window);
// render
// ------
//glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(shaderProgram);
timeValue = glfwGetTime();
greenValue = sin(timeValue) / 2.0f + 0.5f;
vertexColorLocation = glGetUniformLocation(shaderProgram, "ourColor");
glUniform4f(vertexColorLocation, 0.0f, greenValue, 0.0f, 1.0f);
// render the triangle
glBindVertexArray(VAO);
glDrawArrays(GL_TRIANGLES, 0, 3);
// glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.)
// -------------------------------------------------------------------------------
glfwSwapBuffers(window);
glfwPollEvents();
}
// optional: de-allocate all resources once they've outlived their purpose:
// ------------------------------------------------------------------------
glDeleteVertexArrays(1, &VAO);
glDeleteBuffers(1, &VBO);
// glfw: terminate, clearing all previously allocated GLFW resources.
// ------------------------------------------------------------------
glfwTerminate();
return 0;
}
void processInput(GLFWwindow *window){
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
glfwSetWindowShouldClose(window, 1);
}
void framebuffer_size_callback(GLFWwindow* window, int width, int height){
glViewport(0, 0, width, height);
}
thank you all for help!!
I'd discover what is my problem, I'd just forgot to include de glad.h library and the libdl.
I'm using OpenGL 3 and Glew in order to draw a triangle, I have a window (changing the background color works fine) but I can't put my shader on it. I did some tests like:
glGetProgramiv(shader_programme, GL_LINK_STATUS, &isLinked);
printf("\nProg : %i",isLinked);
And it's fine; print returns 1 for the program, the vertex and the frag.
I suppose I missed a clear somewhere, but I'm not sure and also pretty lost here...
This is my code:
#include "../include/scop.h"
#include <OpenGL/gl.h>
#include ".../lfw3/3.2.1/include/GLFW/glfw3.h"
t_scop *ft_init_window(t_scop *scop, t_parse parse)
{
if (!glfwInit())
ft_putstr("error init");
else
{
glfwWindowHint(GLFW_SAMPLES, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
WIN = glfwCreateWindow(WIN_X, WIN_Y, "Scop", NULL, NULL);
glfwMakeContextCurrent(WIN);
glfwSetInputMode(WIN, GLFW_STICKY_KEYS, GL_TRUE);
glfwSetInputMode(WIN, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
glfwPollEvents();
glfwSetCursorPos(WIN, WIN_X / 2.0, WIN_Y / 2.0);
glClearColor(0.0f, 0.5f, 0.4f, 0.0f);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
}
float points[] = {
-1.0f, -1.0f, 0.0f,
1.0f, -1.0f, 0.0f,
0.0f, 1.0f, 0.0f
};
//init buffer and fill it
GLuint vbo = 0;
glGenBuffers (1, &vbo);
glBindBuffer (GL_ARRAY_BUFFER, vbo);
glBufferData (GL_ARRAY_BUFFER, 9 * sizeof (float), points, GL_STATIC_DRAW);
//init VertexArray
GLuint vao = 0;
glGenVertexArraysAPPLE (1, &vao);
glBindVertexArrayAPPLE (vao);
glEnableVertexAttribArray (0);
glBindBuffer (GL_ARRAY_BUFFER, vbo);
glVertexAttribPointer (0, 3, GL_FLOAT, GL_FALSE, 0, NULL);
glDrawArrays(GL_TRIANGLES, 0, 3);
const char* vertex_shader =
"#version 330 core\n"
"layout (location = 0) in vec3 position;\n"
"void main () {"
"gl_Position.xyz = position;"
"gl_Position.w = 1.0;"
"}\0";
const char* fragment_shader =
"#version 330 core\n"
"out vec3 color;"
"void main () {"
"color = vec3(1,0,0);"
"}\0";
//create vertex
GLuint vs = glCreateShader (GL_VERTEX_SHADER);
glShaderSource (vs, 1, &vertex_shader, NULL);
glCompileShader (vs);
//tests
GLint success = 0;
glGetShaderiv(vs, GL_COMPILE_STATUS, &success);
printf ("Taille du source:%i\n", success);
if (GL_FALSE == success)
printf("false");
else printf("true");
//create frag
GLuint fs = glCreateShader (GL_FRAGMENT_SHADER);
glShaderSource (fs, 1, &fragment_shader, NULL);
glCompileShader (fs);
//tests
success = 0;
glGetShaderiv(fs, GL_COMPILE_STATUS, &success);
printf("Taille fs : %i",success);
// GLuint shader_programme = LoadShaders (vs,fs);
GLint shader_programme = glCreateProgram ();
glAttachShader (shader_programme, vs);
glAttachShader (shader_programme, fs);
glLinkProgram (shader_programme);
//tests
GLint isLinked = 0;
glGetProgramiv(shader_programme, GL_LINK_STATUS, &isLinked);
printf("\nProg : %i",isLinked);
//idk if i need to do this now
glDetachShader(shader_programme, vs);
glDetachShader(shader_programme, fs);
glDeleteShader(vs);
glDeleteShader(fs);
glGetError();
while (!glfwWindowShouldClose(WIN))
{
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glClearDepth(GL_DEPTH_TEST);
glUseProgram (shader_programme);
glBindVertexArrayAPPLE (vao);
glDrawArrays (GL_TRIANGLES, 0, 3);
//glUseProgram(0); ???
glfwPollEvents ();
glBindVertexArrayAPPLE (0);
glfwSwapBuffers(WIN);
}
// glfwTerminate();
return (scop);
}
Any help is greatly appreciated!
The problem lies in this line:
glClearDepth(GL_DEPTH_TEST);
glClearDepth (doc) specifies with which value the depth buffer should be cleared and expects a floating point value between 0 and 1. It is the similar to glClearColor, just for depth.
Additionally, you should be using the core profile VAO functions instead of the ones from the APPLE extension. The apple extension should only be used in a OpenGL context <= 2.1.
I'm having issues loading a texture onto my triangle strips. I'm following Anton Gerdelan's tutorial, and after failing with my main program, I went back to the basics and just tried to make a plain square and put his texture on it (the skull and crossbones).
I completely copy and pasted code from his "Hello Triangle" page, which worked, but once trying to fit in code from his texture tutorial above (and changing the triangle to a square), all I'm getting is a big white square with no texture.
I've checked the status of my shaders with glGetShaderiv() and they returned positive, I checked the image I loaded to see if the pixel data was sensible, so I believe my error is in declaring my VBOs, or the order/parameters in which I'm using them.
Here's the complete code which I copied, which compiles fine in Visual Studio 2013, except the output isn't what is expected.
I am using the static libraries of GLEW and GLFW, along with the STBI Image header
#include <GL/glew.h> // include GLEW and new version of GL on Windows
#include <GL/glfw3.h> // GLFW helper library
#include <stdio.h>
#define STB_IMAGE_IMPLEMENTATION
#include <stb/stb_image.h>
const char* vertex_shader =
"#version 400\n"
"in vec3 vp;"
"layout (location=1) in vec2 vt; // per-vertex texture co-ords"
"out vec2 texture_coordinates; "
"void main () {"
" gl_Position = vec4 (vp, 1.0);"
" texture_coordinates = vt; "
"}";
const char* fragment_shader =
"#version 400\n"
"in vec2 texture_coordinates;"
"uniform sampler2D basic_texture;"
"out vec4 frag_colour;"
"void main () {"
"vec4 texel = texture(basic_texture, texture_coordinates);"
"frag_colour = texel; "
"}";
float points[] = {
-0.5f, -0.5f, 0.0f,
-0.5f, 0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
0.5f, 0.5f, 0.0f
};
float texcoords[] = {
0.0f, 1.0f,
0.0f, 0.0f,
1.0, 0.0,
1.0, 0.0,
1.0, 1.0,
0.0, 1.0
};
GLFWwindow* window;
unsigned int vt_vbo;
unsigned int tex = 0;
GLuint vao = 0;
GLuint vbo = 0;
GLuint shader_programme;
void initializeGL(){
// start GL context and O/S window using the GLFW helper library
if (!glfwInit()) {
printf("ERROR: could not start GLFW3\n");
return;
}
window = glfwCreateWindow(640, 480, "Texture Test", NULL, NULL);
if (!window) {
printf("ERROR: could not open window with GLFW3\n");
glfwTerminate();
return;
}
glfwMakeContextCurrent(window);
// start GLEW extension handler
glewExperimental = GL_TRUE;
glewInit();
// get version info
const GLubyte* renderer = glGetString(GL_RENDERER); // get renderer string
const GLubyte* version = glGetString(GL_VERSION); // version as a string
printf("Renderer: %s\n", renderer);
printf("OpenGL version supported %s\n", version);
// tell GL to only draw onto a pixel if the shape is closer to the viewer
glEnable(GL_DEPTH_TEST); // enable depth-testing
glDepthFunc(GL_LESS); // depth-testing interprets a smaller value as "closer"
}
void startShaders(){
GLuint vs = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vs, 1, &vertex_shader, NULL);
glCompileShader(vs);
GLuint fs = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fs, 1, &fragment_shader, NULL);
glCompileShader(fs);
shader_programme = glCreateProgram();
glAttachShader(shader_programme, fs);
glAttachShader(shader_programme, vs);
glLinkProgram(shader_programme);
GLint vsstat;
glGetShaderiv(vs, GL_COMPILE_STATUS, &vsstat);
GLint fsstat;
glGetShaderiv(fs, GL_COMPILE_STATUS, &fsstat);
printf("%i\n%i\n", vsstat, fsstat);
}
void loadImage(){
int x, y, n;
int force_channels = 4;
unsigned char* image_data = stbi_load("skulluvmap.png", &x, &y, &n, force_channels);
if (!image_data) {
printf("ERROR: could not load %s\n", "skulluvmap.png");
}
int width_in_bytes = x * 4;
unsigned char *top = NULL;
unsigned char *bottom = NULL;
unsigned char temp = 0;
int half_height = y / 2;
for (int row = 0; row < half_height; row++) {
top = image_data + row * width_in_bytes;
bottom = image_data + (y - row - 1) * width_in_bytes;
for (int col = 0; col < width_in_bytes; col++) {
temp = *top;
*top = *bottom;
*bottom = temp;
top++;
bottom++;
}
}
printf("first 4 bytes are: %i %i %i %i\n",
image_data[0], image_data[1], image_data[2], image_data[3]
);
glGenTextures(1, &tex);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, tex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, x, y, 0, GL_RGBA, GL_UNSIGNED_BYTE, image_data);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
}
void generateBuffers(){
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, 12 * sizeof(float), points, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, NULL);
glEnableVertexAttribArray(0); // don't forget this!
glGenBuffers(1, &vt_vbo);
glBindBuffer(GL_ARRAY_BUFFER, vt_vbo);
glBufferData(GL_ARRAY_BUFFER, 12 * sizeof(float), texcoords, GL_STATIC_DRAW);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, NULL);
glEnableVertexAttribArray(1); // don't forget this!
}
void mainLoop(){
while (!glfwWindowShouldClose(window)) {
// wipe the drawing surface clear
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
int tex_loc = glGetUniformLocation(shader_programme, "basic_texture");
glUseProgram(shader_programme);
glUniform1i(tex_loc, 0); // use active texture 0
// draw points 0-4 from the currently bound VAO with current in-use shader
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
// update other events like input handling
glfwPollEvents();
// put the stuff we've been drawing onto the display
glfwSwapBuffers(window);
}
}
int main() {
initializeGL();
startShaders();
loadImage();
generateBuffers();
mainLoop();
// close GL context and any other GLFW resources
glfwTerminate();
return 0;
}
You're misusing your second buffer which is supposed to be the buffer with texcoords. So what you really want to achieve is having a pair of texture coordinates for every vertex. It means that you texcoords array should in fact store 4 pairs because you have 4 triples in the points array. So that's the first fix. You probably want it to look like:
float texcoords[] = {
0.0f, 1.0f,
0.0f, 0.0f,
1.0, 0.0,
1.0, 1.0,
};
Then in the generateBuffers, your vt_vbo is wrong. The data should be passed this way:
glBufferData(GL_ARRAY_BUFFER, 8 * sizeof(float), texcoords, GL_STATIC_DRAW);
because you only want to pass 8 values there. 2 texcoords for each vertex.
Edit:
This however, doesn't fully explain why your texture doesn't appear at all. I primarily thought that there might be a problem with your texcoords pointer but it doesn't seem to be the case.
I am trying to render a single char as a demo in opengl by utilizing the bitmap buffer offered by freetype glyphs. I know my triangle fan is correct because right now i see a black textured triangle_fan against a green background. Ideally i should be seeing a character in my triangle_fan primitive instead of just a full solid black square.
void fontDataNums_init(const char * fname) {
float h = font.h = 16;
/*Dynamically allocated variables, clean before exit */
FT_Face face;
FT_Library library;
GLubyte * expanded_data;
/* Create And Initilize A FreeType Font Library. */
if(FT_Init_FreeType( &library )) {
printf("fontDataNums_init::FT_Init_FreeType failed\n");
exit(1);
}
/* Initialize face, load font from ttf file */
if(FT_New_Face( library, fname, 0, &face )){
printf("fontDataNums_init::FT_New_Face failed\n");
exit(1);
}
if(FT_Set_Char_Size( face, h * 64, h * 64, 96, 96)){
printf("fontDataNums_init::FT_Set_Char_Size failed.\n");
exit(1);
}
font.textures = (GLuint *) malloc(sizeof(GLuint) * 10);
glGenTextures(10, font.textures);
/* CREATE CHARACTER BITMAPS I WANT LOADED */
unsigned char g;
int i, j;
for( g='A'; g < 'J'; g++){
if(FT_Load_Char(face, g, FT_LOAD_RENDER)){
printf("fontDataNums::FT_Load_Char unable to load glyph for character\n");
exit(1);
}
FT_Glyph glyph;
if(FT_Get_Glyph(face->glyph, &glyph) ) { printf("GetGlyph failed.\n");}
if(FT_Glyph_To_Bitmap(&glyph, ft_render_mode_normal, 0, 1)){
printf("fontDataNums::FT_Glyph_To_Bitmap failed to create bitmap.\n");
exit(1);
}
FT_BitmapGlyph bitmap_glyph = (FT_BitmapGlyph)glyph;
int width = next_p2( bitmap_glyph->bitmap.width );
int height = next_p2( bitmap_glyph->bitmap.rows );
printf("WIDTH: %i and HEIGHT: %i \n", width, height);
/* PADDING FOR BITMAP */
expanded_data = (GLubyte *) malloc(sizeof(GLubyte) * 2 * width * height);
for(j=0; j <height;j++) {
for(i=0; i < width; i++){
expanded_data[2*(i+j*width)] = expanded_data[2*(i+j*width)+1] =
(i>=bitmap_glyph->bitmap.width || j>=bitmap_glyph->bitmap.rows) ?
0 :
bitmap_glyph->bitmap.buffer[i + bitmap_glyph->bitmap.width*j];
}
}
/* LOAD TEXTURE INTO OPENGL */
glActiveTexture(GL_TEXTURE0);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glBindTexture( GL_TEXTURE_2D, font.textures[g]);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, expanded_data );
free(expanded_data);
FT_Done_Glyph(glyph);
}
/* Clean Up */
FT_Done_Face(face);
FT_Done_FreeType(library);
}
int next_p2 (int a )
{
int rval=1;
/* rval<<=1 Is A Prettier Way Of Writing rval*=2; */
while(rval<a) rval<<=1;
return rval;
}
void drawGlyph(){
renderGlyph(font.textures[1]);
}
void renderGlyph(GLuint textureName) {
GLuint tbo = 0;
GLuint vbo = 0;
glClear(GL_COLOR_BUFFER_BIT);
/* SETUP VERTICES */
GLfloat verts[8]={ 0.0f, 16.0f,
0.0f, 0.0f,
17.0f , 0.0f,
17.0f , 16.0f};
glEnableVertexAttribArray(GLT_ATTRIBUTE_VERTEX);
if(vbo == 0){glGenBuffers(1, &vbo);}
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 8, verts, GL_DYNAMIC_DRAW);
glVertexAttribPointer(GLT_ATTRIBUTE_VERTEX, 2, GL_FLOAT, GL_FALSE, 0, 0);
/* Setup Texture Buffer */
float x = 17.0f / 32.0f;
float y = 16.0f / 16.0f;
GLfloat vTex[8] = { 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f };
glEnableVertexAttribArray(GLT_ATTRIBUTE_TEXTURE0);
if(tbo == 0) { glGenBuffers(1, &tbo);}
glBindBuffer(GL_ARRAY_BUFFER, tbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 8, vTex, GL_DYNAMIC_DRAW);
glVertexAttribPointer(GLT_ATTRIBUTE_TEXTURE0, 2, GL_FLOAT, GL_FALSE, 0, 0);
/*Create Shaders*/
static const char *szIdentityShaderVP =
"#version 330\n"
"in vec4 vVertex;\n"
"in vec2 TexCoords;\n"
"out vec2 varyingTexCoords;\n"
"uniform mat4 mvp;\n"
"void main(void) \n"
"{"
"varyingTexCoords = TexCoords;\n"
"gl_Position = mvp * vVertex;\n"
"}\n";
static const char *szIdentityShaderFP =
"#version 330\n"
"uniform sampler2D colormap;\n"
"uniform vec4 showFan;"
"in vec2 varyingTexCoords;\n"
"void main(void) \n"
"{"
//"gl_FragColor = showFan;\n"
"gl_FragColor = texture(colormap, varyingTexCoords);\n"
"}\n";
GLuint shaderName = 0;
shaderName = gltLoadShaderPairSrcWithAttributes(szIdentityShaderVP, szIdentityShaderFP, 2, GLT_ATTRIBUTE_VERTEX, "vVertex", GLT_ATTRIBUTE_TEXTURE0, "TexCoords");
if(shaderName == 0) { printf("***shader compile failed****\n");}
glUseProgram(shaderName);
vmathM4MakeOrthographic( &pmatrix, -50.0f, 50.0f, -50.0f, 50.0f, -50.0f, 50.0f);
GLint mvp = 0;
mvp = glGetUniformLocation(shaderName, "mvp");
glUniformMatrix4fv(mvp, 1, GL_FALSE, (GLfloat *) &pmatrix);
GLint texUniform = 0;
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, textureName);
texUniform = glGetUniformLocation(shaderName, "colormap");
glUniform1i(texUniform, 0);
GLint showFan= 0;
showFan = glGetUniformLocation(shaderName, "showFan");
glUniform4f(showFan, 1.0f, 0.0f, 0.0f, 1.0f);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
SDL_GL_SwapWindow(gcore.mainwindow);
glDisableVertexAttribArray(GLT_ATTRIBUTE_VERTEX);
glDisableVertexAttribArray(GLT_ATTRIBUTE_TEXTURE0);
glDeleteProgram(shaderName);
glDeleteBuffers(1, &vbo);
glDeleteBuffers(1, &tbo);
glCheckError();
}
void glCheckError(){
GLenum checkError = glGetError();
if(checkError != GL_NO_ERROR)
printf("Error: %i\n", checkError);
}
I use freetype in an IPhone device, it works creating the texture with...
glTexImage2D( GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, width, height, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, data);