Problem with OpenGL Texture Initialisation/Rendering - c

Im trying to render a non power of 2 texture using a model class that creates a texture and stores it's ID and size (thanks to ADC and another stackoverflow member), and additional code the create VBO's and render it (The code for VBO's and rendering is for testing purposes, it is properly divided in my models).
When I use this code, but remove the texture-specific code, it works fine. When adding the texture specific code however, it only renders what I believe to be the bottom-right pixel, from trying out multiple complex images and using DigitalColor Meter to check the images and output.
I don't suppose that texture coordinates have to be specified explicitly when using this setup, and if they do, how would I?
Main OpenGL Code
// Create vertex buffer
GLuint memoryPointer = 0;
GLuint colourMemoryPointer = 0;
GLfloat *vertices;
size_t vertex_size = 0;
int check = AllocateVertexBuffer(2, 4, &vertices, &vertex_size);
CDMeshVertexesCreateRectangle(200, 200, vertices);
// Create colour buffer
GLfloat *colors;
size_t color_size;
int check2 = AllocateVertexBuffer(4, 4, &colors, &color_size);
CDMeshColorsCreateGrey(1.0, 4, colors);
// Create texture buffer
CDTexture *texture = [CDTexture loadPngTexture:#"Rawr"];
// Allocate the buffer
glGenBuffers(1, &memoryPointer);
// Bind the buffer object (tell OpenGL what to use)
glBindBuffer(GL_ARRAY_BUFFER, memoryPointer);
// Allocate space for the VBO
glBufferData(GL_ARRAY_BUFFER, vertex_size, vertices, GL_STATIC_DRAW);
// Allocate the buffer
glGenBuffers(1, &colourMemoryPointer);
// Bind the buffer object (tell OpenGL what to use)
glBindBuffer(GL_ARRAY_BUFFER, colourMemoryPointer);
// Allocate space for the VBO
glBufferData(GL_ARRAY_BUFFER, color_size, colors, GL_STATIC_DRAW);
glEnableClientState(GL_VERTEX_ARRAY); // Activate vertex coordinates array
glEnableClientState(GL_COLOR_ARRAY);
glBindBuffer(GL_ARRAY_BUFFER, memoryPointer);
glVertexPointer(2, GL_FLOAT, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, colourMemoryPointer);
glColorPointer(4, GL_FLOAT, 0, 0);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, texture.ID);
glTexCoordPointer(2, GL_FLOAT, 0, 0);
//[texture render];
//render
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
glDisableClientState(GL_VERTEX_ARRAY); // Deactivate vertex coordinates array
glDisableClientState(GL_COLOR_ARRAY);
free(vertices);
free(colors);
CDTexture loadPngTexture: Method
CFURLRef textureURL = CFBundleCopyResourceURL(CFBundleGetMainBundle(),
(CFStringRef)fileName,
CFSTR("png"),
NULL);
NSAssert(textureURL, #"Texture name invalid");
// Get the image source using a file path
CGImageSourceRef myImageSourceRef = CGImageSourceCreateWithURL(textureURL, NULL);
NSAssert(myImageSourceRef, #"Invalid Image Path.");
NSAssert((CGImageSourceGetCount(myImageSourceRef) > 0), #"No Image in Image Source.");
// Get the image reference using the source reference, -_-
CGImageRef myImageRef = CGImageSourceCreateImageAtIndex (myImageSourceRef, 0, NULL);
NSAssert(myImageSourceRef, #"Image not created.");
// Start gathering data from the image, before releasing it
GLuint myTextureName;
size_t width = CGImageGetWidth(myImageRef);
size_t height = CGImageGetHeight(myImageRef);
CGRect rect = {{0, 0}, {width, height}};
void * myData = calloc(width * 4, height);
CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
CGContextRef myBitmapContext = CGBitmapContextCreate (myData,
width, height, 8,
width*4, space,
kCGBitmapByteOrder32Host |
kCGImageAlphaPremultipliedFirst);
CGColorSpaceRelease(space);
// Flip so that it isn't upside-down
CGContextTranslateCTM(myBitmapContext, 0, height);
CGContextScaleCTM(myBitmapContext, 1.0f, -1.0f);
CGContextSetBlendMode(myBitmapContext, kCGBlendModeCopy);
CGContextDrawImage(myBitmapContext, rect, myImageRef);
CGContextRelease(myBitmapContext);
glEnable(GL_TEXTURE_RECTANGLE_ARB);
// Generate texture buffer
glGenTextures(1, &myTextureName);
// Bind buffer for use
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, myTextureName);
// Set storage methods
glPixelStorei(GL_UNPACK_ROW_LENGTH, width);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
// Set the parameter required for non power of two textures
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB,
GL_TEXTURE_MIN_FILTER, GL_LINEAR);
// Load the texture data into the buffer
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA8, width, height,
0, GL_BGRA_EXT, GL_UNSIGNED_INT_8_8_8_8_REV, myData);
// Free the data used, as it's now in the buffer
free(myData);
// Return information on texture object
CDTexture *texture = [[CDTexture alloc] init];
texture.ID = myTextureName;
texture.size = NSMakeSize(width, height);
return texture;
UPDATE
I've tried using a texture pointer to define the area, and this results in the same problem. The colour/texture it draws will do so even without binding and using a pointer. I have also tried enabling and disabling GL_TEXTURE_COORD_ARRAY before and after it is used and rendered, and results in the same problem.
Unless i've done something wrong, the problem doesn't seem related with texture pointers.
GLfloat texCoords[8] = {
0.0, 0.0,
0.0, 1.0,
1.0, 1.0,
1.0, 0.0
};
...
glBindBuffer(GL_ARRAY_BUFFER, colourMemoryPointer);
glColorPointer(4, GL_FLOAT, 0, 0);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, texture.ID);
glTexCoordPointer(2, GL_FLOAT, 0, texCoords);
//[texture render];
//render
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
UPDATE 2
I've tried obtaining an error code from OpenGL to try and solve the problem, but no error codes have been printed.
UPDATE 3
I have tried using a different method to get raw image data, and the same result happens (albeit with some discolouration, as I must not be using the right colour settings). OpenGL's interpretation of the data must be flawed here. I have experimented with glPixelStorei() but nothing has changed so far. As OpenGL isn't reporting any error, it must be with the programs interpretation of the data, so either the parameters I have set for how data is stored, or vertex problems that is causing only 1 pixel to be displayed, although because of this precision, it is most likely to be parameters.
New process for raw image data (thanks to another stackoverflow user). Posted for reference.
NSBitmapImageRep *theImage;
int bitsPPixel, bytesPRow;
NSSize size;
unsigned char *theImageData;
NSData* imgData = [NSData dataWithContentsOfFile:fileName options:NSUncachedRead error:nil]; // use FileURL
theImage = [NSBitmapImageRep imageRepWithData:imgData];
if( theImage != nil )
{
bitsPPixel = [theImage bitsPerPixel];
bytesPRow = [theImage bytesPerRow];
size.width = [theImage pixelsWide];
size.height = [theImage pixelsHigh];
}
enter code here
UPDATE 4
Changed to GL_TEXTURE_2D for efficiency. The bottom-left pixel is still only being rendered. Here is the full order of the code:
// Create vertex buffer
GLuint memoryPointer = 0;
GLuint colourMemoryPointer = 0;
GLfloat *vertices;
size_t vertex_size = 0;
AllocateVertexBuffer(2, 4, &vertices, &vertex_size);
CDMeshVertexesCreateRectangle(200, 200, vertices);
// Create colour buffer
GLfloat *colors;
size_t color_size;
AllocateVertexBuffer(4, 4, &colors, &color_size);
CDMeshColorsCreateGrey(1.0, 4, colors);
// Create Texture UV Coordinates
GLfloat *texture;
size_t texture_size;
AllocateVertexBuffer(4, 2, &texture, &texture_size);
CDMeshVertexesCreateRectangle(1, 1, texture);
// Create texture buffer
NSString *fileName = #"Rawr3";
CFURLRef textureURL = CFBundleCopyResourceURL(CFBundleGetMainBundle(),
(CFStringRef)fileName,
CFSTR("png"),
NULL);
NSAssert(textureURL, #"Texture name invalid");
// Get the image source using a file path
CGImageSourceRef myImageSourceRef = CGImageSourceCreateWithURL(textureURL, NULL);
NSAssert(myImageSourceRef, #"Invalid Image Path.");
NSAssert((CGImageSourceGetCount(myImageSourceRef) > 0), #"No Image in Image Source.");
// Get the image reference using the source reference, -_-
CGImageRef myImageRef = CGImageSourceCreateImageAtIndex (myImageSourceRef, 0, NULL);
NSAssert(myImageSourceRef, #"Image not created.");
// Start gathering data from the image, before releasing it
GLuint myTextureName;
size_t width = CGImageGetWidth(myImageRef);
size_t height = CGImageGetHeight(myImageRef);
CGRect rect = {{0, 0}, {width, height}}; //Doesnt need fiddling
void * myData = calloc(width * 4, height); //Fiddled
CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
CGContextRef myBitmapContext = CGBitmapContextCreate (myData,
width, height, 8,
width*4, space,
kCGBitmapByteOrder32Host |
kCGImageAlphaPremultipliedFirst);
CGColorSpaceRelease(space);
// Flip so that it isn't upside-down
CGContextTranslateCTM(myBitmapContext, 0, height);
CGContextScaleCTM(myBitmapContext, 1.0f, -1.0f);
CGContextSetBlendMode(myBitmapContext, kCGBlendModeCopy);
CGContextDrawImage(myBitmapContext, rect, myImageRef);
CGContextRelease(myBitmapContext);
// Generate texture buffer
glGenTextures(1, &myTextureName);
// Bind buffer for use
glBindTexture(GL_TEXTURE_2D, myTextureName);
// Set storage methods
glTexParameteri(GL_TEXTURE_2D,
GL_TEXTURE_STORAGE_HINT_APPLE,
GL_STORAGE_CACHED_APPLE);
glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
// Set clamping and rendering preferences
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_MAG_FILTER,
GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
GL_NEAREST);
// Load the texture data into the buffer
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height,
0, GL_BGRA_EXT, GL_UNSIGNED_INT_8_8_8_8_REV, myData);
glGetError();
// Free the data used, as it's now in the buffer
free(myData);
// Return information on texture object
CDTexture *textureObj = [[CDTexture alloc] init];
textureObj.ID = myTextureName;
textureObj.size = NSMakeSize(width, height);
// Allocate the buffer
glGenBuffers(1, &memoryPointer);
// Bind the buffer object (tell OpenGL what to use)
glBindBuffer(GL_ARRAY_BUFFER, memoryPointer);
// Allocate space for the VBO
glBufferData(GL_ARRAY_BUFFER, vertex_size, vertices, GL_STATIC_DRAW);
// Allocate the buffer
glGenBuffers(1, &colourMemoryPointer);
// Bind the buffer object (tell OpenGL what to use)
glBindBuffer(GL_ARRAY_BUFFER, colourMemoryPointer);
// Allocate space for the VBO
glBufferData(GL_ARRAY_BUFFER, color_size, colors, GL_STATIC_DRAW);
glEnableClientState(GL_VERTEX_ARRAY); // Activate vertex coordinates array
glEnableClientState(GL_COLOR_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glEnable(GL_TEXTURE_2D);
glBindBuffer(GL_ARRAY_BUFFER, memoryPointer);
glVertexPointer(2, GL_FLOAT, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, colourMemoryPointer);
glColorPointer(4, GL_FLOAT, 0, 0);
glBindTexture(GL_TEXTURE_2D, textureObj.ID);
glTexCoordPointer(2, GL_FLOAT, 0, texture);
GetGLError();
//render
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
glDisableClientState(GL_VERTEX_ARRAY); // Deactivate vertex coordinates array
glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisable(GL_TEXTURE_2D);
glDeleteBuffers(1, &memoryPointer);
glDeleteBuffers(1, &colourMemoryPointer);
GLuint texID = textureObj.ID;
glDeleteBuffers(1, &texID);
free(vertices);
free(colors);
free(texture);
}
UPDATE 5
From glTexImage2D(), it will render the bottom-left pixel of the texture even if I don't bind the texture and add coordinates for it, which seems strange, considering that it should be drawn using glTexCoordPointer().
UPDATE 6
Probably the last update, used the texture initialisation code with another more, 'manual' technique of drawing and it worked fine. I have removed the Apple specific elements. When removing the colour VBO and pointer from this code, a white box is still rendered for some odd reason. The problem is with the VBO's, but I cant see why. GL_TEXTURE_RECTANGLE_ARB is just being used for my coloured texture right now, will be changed when this problem is solved.
// Create vertex buffer
GLuint memoryPointer = 0;
GLuint colourMemoryPointer = 0;
GLfloat *vertices;
size_t vertex_size = 0;
AllocateVertexBuffer(2, 4, &vertices, &vertex_size);
CDMeshVertexesCreateRectangle(200, 200, vertices);
GetGLError();
// Create colour buffer
GLfloat *colors;
size_t color_size;
AllocateVertexBuffer(4, 4, &colors, &color_size);
CDMeshColorsCreateGrey(0.4, 4, colors);
// Allocate the buffer
glGenBuffers(1, &memoryPointer);
glBindBuffer(GL_ARRAY_BUFFER, memoryPointer);
glBufferData(GL_ARRAY_BUFFER, vertex_size, vertices, GL_STATIC_DRAW);
// Allocate the buffer
glGenBuffers(1, &colourMemoryPointer);
glBindBuffer(GL_ARRAY_BUFFER, colourMemoryPointer);
glBufferData(GL_ARRAY_BUFFER, color_size, colors, GL_STATIC_DRAW);
// Enable client states for drawing the various arrays
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
// Bind each buffer and use the VBO's to draw (apart from the texture buffer)
glBindBuffer(GL_ARRAY_BUFFER, memoryPointer);
glVertexPointer(2, GL_FLOAT, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, colourMemoryPointer);
glColorPointer(4, GL_FLOAT, 0, 0);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, myTextureName); //
glTexCoordPointer(2, GL_FLOAT, 0, texture);
//render
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
// Disale client states as were done with them.
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisable(GL_TEXTURE_RECTANGLE_ARB);
GetGLError();
// Delete buffers to avoid problems
glDeleteBuffers(1, &memoryPointer);
glDeleteBuffers(1, &colourMemoryPointer);
glDeleteBuffers(1, &myTextureName);
free(vertices);
free(colors);
free(texture);

Of course you must supply texture coordinates. Either as part of the vertex attribute vector, or by generating them (in a shader). But you must supply texture coordinates somehow, you can't get around this.

I solved the problem (finally) by creating a Vertex Buffer Object (VBO) for the texture, instead of trying to supply vertex data directly to glTextureCoordPointer(). I guess the lesson here is that if you are going to use VBO's, use them for everything! For reference, here is the complete code:
Texture Creation
// Create texture buffer, start with the name of the image.
NSString *fileName = #"Rawr";
CFURLRef textureURL = CFBundleCopyResourceURL(CFBundleGetMainBundle(),
(CFStringRef)fileName,
CFSTR("png"),
NULL);
NSAssert(textureURL, #"Texture name invalid");
// Get the image source using a file path
CGImageSourceRef myImageSourceRef = CGImageSourceCreateWithURL(textureURL, NULL);
NSAssert(myImageSourceRef, #"Invalid Image Path.");
NSAssert((CGImageSourceGetCount(myImageSourceRef) > 0), #"No Image in Image Source.");
// Get the image reference using the source reference, -_-
CGImageRef myImageRef = CGImageSourceCreateImageAtIndex (myImageSourceRef, 0, NULL);
NSAssert(myImageSourceRef, #"Image not created.");
// Start gathering data from the image, before releasing it
GLuint myTextureName;
size_t width = CGImageGetWidth(myImageRef);
size_t height = CGImageGetHeight(myImageRef);
CGRect rect = {{0, 0}, {width, height}}; //Doesnt need fiddling
void * myData = calloc(width * 4, height); //Fiddled
CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
CGContextRef myBitmapContext = CGBitmapContextCreate (myData,
width, height, 8,
width*4, space,
kCGBitmapByteOrder32Host |
kCGImageAlphaPremultipliedFirst);
CGColorSpaceRelease(space);
// Flip so that it isn't upside-down
CGContextTranslateCTM(myBitmapContext, 0, height);
CGContextScaleCTM(myBitmapContext, 1.0f, -1.0f);
CGContextSetBlendMode(myBitmapContext, kCGBlendModeCopy);
CGContextDrawImage(myBitmapContext, rect, myImageRef);
CGContextRelease(myBitmapContext);
GetGLError();
// The extension GL_TEXTURE_RECTANGLE_ARB can be used for non-power of two textures, but it is slower than GL_TEXTURE_2D and not
// supported by all graphics cards.
glEnable(GL_TEXTURE_RECTANGLE_ARB);
glGenTextures(1, &myTextureName);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, myTextureName);
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER,GL_NEAREST);
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER,GL_NEAREST);
glTexParameterf(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, myData);
//glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT ,GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB,myTextureName, 0);
free(myData);
VBO Creation
// Create vertex buffer
GLuint memoryPointer = 0;
GLuint colourMemoryPointer = 0;
GLuint texPointer = 0;
GLfloat *vertices;
size_t vertex_size = 0;
AllocateVertexBuffer(2, 4, &vertices, &vertex_size);
CDMeshVertexesCreateRectangle(200, 200, vertices);
GetGLError();
// Create colour buffer
GLfloat *colors;
size_t color_size;
AllocateVertexBuffer(4, 4, &colors, &color_size);
CDMeshColorsCreateGrey(0.0, 4, colors);
// Create Texture UV Coordinates
GLfloat *texture;
size_t texture_size;
AllocateVertexBuffer(2, 4, &texture, &texture_size);
CDMeshVertexesCreateRectangle(200, 200, texture);
// Allocate the vertex VBO
glGenBuffers(1, &memoryPointer);
glBindBuffer(GL_ARRAY_BUFFER, memoryPointer);
glBufferData(GL_ARRAY_BUFFER, vertex_size, vertices, GL_STATIC_DRAW);
// Allocate the colour VBO
glGenBuffers(1, &colourMemoryPointer);
glBindBuffer(GL_ARRAY_BUFFER, colourMemoryPointer);
glBufferData(GL_ARRAY_BUFFER, color_size, colors, GL_STATIC_DRAW);
// Allocate the texture VBO
glGenBuffers(1, &texPointer);
glBindBuffer(GL_ARRAY_BUFFER, texPointer);
glBufferData(GL_ARRAY_BUFFER, texture_size, texture, GL_STATIC_DRAW);
Rendering and Deleting VBO and Data
// Enable client states for drawing the various arrays
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
// Bind each buffer and use the VBO's to draw
glBindBuffer(GL_ARRAY_BUFFER, memoryPointer);
glVertexPointer(2, GL_FLOAT, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, colourMemoryPointer);
glColorPointer(4, GL_FLOAT, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, texPointer);
glTexCoordPointer(2, GL_FLOAT, 0, 0);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, myTextureName);
// RENDER!
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
// Disale client states as were done with them.
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisable(GL_TEXTURE_RECTANGLE_ARB);
GetGLError();
// Delete buffers when they arent being used.
glDeleteBuffers(1, &memoryPointer);
glDeleteBuffers(1, &colourMemoryPointer);
glDeleteBuffers(1, &myTextureName);
glGenTextures(GL_TEXTURE_RECTANGLE_ARB, 0);
// Free vertexes when done using them
free(vertices);
free(colors);
free(texture);

Related

Textured Triangle Loads as Solid Color

I'm trying to render a textured triangle. I'm using STB image to load a png. The triangle is displayed as a single color for a host of different images that I've tried. The color seems to be an average of the total colors displayed in the image.
I've looked into many solutions for similar questions and have ensured (or so I think) that I've not fallen into the common 'gotchas': glEnable(GL_TEXTURE_2D) is called. My calls to glVertexAttribPoitners() are set up correctly. I've tried to tell OpenGl that I don't want to use mipmapping with glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR), and I've enabled the relevant vertex arrays via glEnableVertexAttribArray(). My shaders compile with no errors.
#include <practice/practice.h>
#include <test_dep/stb_image.h>
void
initRenderer_practice()
{
const char* vertex_shader = GLSL(450 core,
layout (location = 0) in vec2 vCoords;
layout (location = 1) in vec2 tCoords;
out vec2 ftCoords;
void main()
{
gl_Position = vec4(vCoords.x, vCoords.y, 0.0, 1.0);
ftCoords = tCoords;
}
);
const char* fragment_shader = GLSL(450 core,
uniform sampler2D texture_data;
in vec2 ftCoords;
out vec4 fragColor;
void main()
{
fragColor = texture(texture_data, ftCoords.st);
}
);
GLfloat vCoordsLocal[] =
{
//
// POSITION COORDS
//
// bottom left
-0.5, -0.5,
// bottom right
0.5, -0.5,
// top center
0.0, 0.5,
//
// TEXTURE COORDS
//
// left bottom
0.0, 0.0,
// right bottom
1.0, 0.0,
// center top
0.5, 1.0,
};
if (!practice_target)
{
practice_target = (uGLRenderTarget*)malloc(sizeof(uGLRenderTarget));
practice_target->shader_program = 0;
practice_target->vertex_array_object = (GLuint) -1;
practice_target->vertex_buffer_object = (GLuint) -1;
}
practice_target->shader_program = uGLCreateShaderProgram_vf(&vertex_shader,
&fragment_shader);
assert(practice_target->shader_program);
glUseProgram(practice_target->shader_program);
glError;
glGenVertexArrays(1, &practice_target->vertex_array_object);
glBindVertexArray(practice_target->vertex_array_object);
glError;
glGenBuffers(1, &practice_target->vertex_buffer_object);
glBindBuffer(GL_ARRAY_BUFFER, practice_target->vertex_buffer_object);
glBufferData(GL_ARRAY_BUFFER,
sizeof(vCoordsLocal),
vCoordsLocal,
GL_STATIC_DRAW);
glError;
glGenTextures(1, &practice_target->texture_id);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, practice_target->texture_id);
practice_target->shdr_texture_2d_location = glGetUniformLocation(practice_target->shader_program, "texture_data");
glUniform1i(practice_target->shdr_texture_2d_location, 0);
assert(practice_target->shdr_texture_2d_location != -1);
glError;
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glError;
stbi_set_flip_vertically_on_load(true);
u8* texture_data = NULL;
GLint width, height, channels = 0;
texture_data = stbi_load("./assets/index.png", &width, &height, &channels, 0);
if (texture_data)
{
/*
void glTexImage2D(GLenum target,
GLint level,
GLint internalFormat,
GLsizei width,
GLsizei height,
GLint border,
GLenum format,
GLenum type,
const GLvoid * data);
*/
glTexImage2D(GL_TEXTURE_2D,
0,
GL_RGB,
width,
height,
0,
GL_RGB,
GL_UNSIGNED_BYTE,
texture_data);
glGenerateMipmap(GL_TEXTURE_2D);
glError;
printf("\n\n numchannels: %d\n\n", channels);
}
else
{
puts("[ debug ] Load texture failed\n");
assert(0);
}
stbi_image_free(texture_data);
/*
void glVertexAttribPointer(GLuint index,
GLint size,
GLenum type,
GLboolean normalized,
GLsizei stride,
const GLvoid * pointer);
*/
// Vertex coordinate attribute
glVertexAttribPointer(0,
2,
GL_FLOAT,
GL_FALSE,
0,
(void*) 0);
glEnableVertexAttribArray(0);
// Texture coordinate attribute
glVertexAttribPointer(1,
2,
GL_FLOAT,
GL_FALSE,
0,
(void*) 6);
glEnableVertexAttribArray(1);
glError;
glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glUseProgram(0);
glError;
}
void
render_practice()
{
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(practice_target->shader_program);
glEnable(GL_TEXTURE_2D);
glBindVertexArray(practice_target->vertex_array_object);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, practice_target->texture_id);
glDrawArrays(GL_TRIANGLES, 0, 3);
glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glUseProgram(0);
glError;
}
The expected result is to have the texture mapped onto the triangle, rather than a single color.
The vertex attribute specification for the texture coordinates is misaligned.
The memory layout of the attributes is
x0 y0, x1, y1, x2, y2, u0 v0, u1, v1, u2, v2
So the first texture coordinate is 6th element in the buffer.
But, the last parameter of glVertexAttribPointer is a byte offset into the buffer object's data store.
This mean the offset has to be 6*sizeof(GLfloat) rather than 6
glVertexAttribPointer(1,
2,
GL_FLOAT,
GL_FALSE,
0,
(void*)(6*sizeof(GLfloat)); // <-----
I recommend to change the vertex attribute arrangement, to an extendable layout:
x0 y0 u0 v0 x1 y1 u1 v1 x2 y2 u2 v2 ...
and to use the corresponding vertex attribute specification:
GLsizei stride = (GLsizei)(4*sizeof(GLfloat)); // 4 because of (x, y, u ,v)
void* vertOffset = (void*)(0); // 0 because the vertex coords are 1st
void* texOffset = (void*)(2*sizeof(GLfloat)); // 2 because u, v are after x, y
// Vertex coordinate attribute
glVertexAttribPointer(0,
2,
GL_FLOAT,
GL_FALSE,
stride,
vertOffset);
glEnableVertexAttribArray(0);
// Texture coordinate attribute
glVertexAttribPointer(1,
2,
GL_FLOAT,
GL_FALSE,
stride,
texOffset;
glEnableVertexAttribArray(1);

OpenGL compute shader not changing buffer

I want to change the content of a buffer that i share between multiple shaders, in the compute shader. Specifically the normals in this case.
No matter what i set the value of one or more vertices in the buffer to, it doesn't seem to take effect in any of the other shaders. Probably i just forgot something or am not seeing something (I am new to compute shaders)
Here is the relevant part of the code. If you need more parts of the code, just ask. Please understand though that its hard to give a working piece of code because that requires quiet a bit more code than just a few lines.
utils_createComputeProgram(&g_simulateWaterProgram, "content/shaders/simulatewater/simulatewater.comp");
// Initialize first position buffer
{
glGenBuffers(1, &app->positionBufferOne);
glBindBuffer(GL_ARRAY_BUFFER, app->positionBufferOne);
glBufferData(GL_ARRAY_BUFFER, NUM_VERTICES*sizeof(MLvec4), NULL, GL_STATIC_DRAW);
MLvec4* positions = glMapBuffer(GL_ARRAY_BUFFER, GL_READ_WRITE);
for (int i = 0; i < NUM_VERTICES; ++i) {
...
positions[i] = mlMakeVec4(x, y, z, v);
}
glUnmapBuffer(GL_ARRAY_BUFFER);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
// Initialize second position buffer with 0
{
glGenBuffers(1, &app->positionBufferTwo);
glBindBuffer(GL_ARRAY_BUFFER, app->positionBufferTwo);
glBufferData(GL_ARRAY_BUFFER, NUM_VERTICES*sizeof(MLvec4), NULL, GL_STATIC_DRAW);
MLvec4* positions = glMapBuffer(GL_ARRAY_BUFFER, GL_READ_WRITE);
for (int i = 0; i < NUM_VERTICES; ++i) {
positions[i] = mlMakeVec4(0, 0, 0, 0);
}
glUnmapBuffer(GL_ARRAY_BUFFER);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
// initialize normal buffer
{
glGenBuffers(1, &app->normalBuffer);
glBindBuffer(GL_ARRAY_BUFFER, app->normalBuffer);
glBufferData(GL_ARRAY_BUFFER, NUM_VERTICES*sizeof(MLvec4), NULL, GL_STATIC_DRAW);
MLvec4* normals = glMapBuffer(GL_ARRAY_BUFFER, GL_READ_WRITE);
for (int i = 0; i < NUM_VERTICES; ++i) {
normals[i] = mlMakeVec4(0, 0, 1, 0);
}
glUnmapBuffer(GL_ARRAY_BUFFER);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
// Attach buffers to program
{
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, app->positionBufferOne);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, app->positionBufferTwo);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, app->normalBuffer);
}
utils_createProgramVertexFragment(&g_renderWaterProgram, "content/shaders/renderwater/renderwater.vert", "content/shaders/renderwater/renderwater.frag");
// initialize VAO
{
glGenVertexArrays(1, &g_waterVertexArrayObject);
utils_setAttributePointer(g_waterVertexArrayObject, app->positionBufferOne, 0, 4, GL_FLOAT, GL_FALSE, 0, 0);
utils_setAttributePointer(g_waterVertexArrayObject, app->positionBufferTwo, 1, 4, GL_FLOAT, GL_FALSE, 0, 0);
utils_setAttributePointer(g_waterVertexArrayObject, app->normalBuffer, 2, 4, GL_FLOAT, GL_FALSE, 0, 0);
}
// initialize index array
{
...
glBindVertexArray(g_waterVertexArrayObject);
glGenBuffers(1, &g_elementArrayBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, g_elementArrayBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint) * NUM_INDICES, g_waterIndices, GL_STATIC_DRAW);
}
void rendering_render(Application* app, int framebufferWidth, int framebufferHeight) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glViewport(0, 0, framebufferWidth, framebufferHeight);
MLvec3 center = mlMakeVec3(app->camera.cx, app->camera.cy, app->camera.cz);
MLvec3 eye = positionOfCamera(app->camera);
MLmat4 modelMatrix = mlIdentity4;
MLmat4 projectionMatrix = mlMakePerspectiveFromFOV(100, (float)framebufferWidth / framebufferHeight, 0.01, 100.0);
MLmat4 viewMatrix = mlMakeLookAt(eye, center, mlMakeVec3(0, 1, 0));
// Hier muss gewartet werden, bis der Compute Shader alle Schreiboperationen auf die Shader Storage Buffer ausgeführt hat.
//glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
glMemoryBarrier(GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT);
glUseProgram(g_renderWaterProgram);
utils_setUniformMat4(renderWaterProgram_ProjectionMatrix, &projectionMatrix);
utils_setUniformMat4(renderWaterProgram_ViewMatrix, &viewMatrix);
utils_setUniformMat4(renderWaterProgram_ModelMatrix, &modelMatrix);
if (app->debug) {
glDrawElements(GL_POINTS, NUM_INDICES, GL_UNSIGNED_INT, NULL);
}
else {
glDrawElements(GL_TRIANGLES, NUM_INDICES, GL_UNSIGNED_INT, NULL);
}
glUseProgram(0);
}
Compute shader:
layout (local_size_x = 1000, local_size_y = 1, local_size_z = 1) in;
layout (location = 0) uniform float Dt;
layout (std430, binding = 0) buffer PositionBufferOne {
vec4 positions[];
};
layout (std430, binding = 1) buffer PositionBufferTwo {
vec4 positionsNew[];
};
layout (std430, binding = 2) buffer NormalBuffer {
vec4 normals[];
};
vec3 calcNormal() {
return normalize(vec3(1, 1, 1));
}
void main() {
uint index = gl_GlobalInvocationID.x;
normals[index] = vec4(calcNormal(), 0.0);
}
utils:
GLuint utils_createShader(GLenum shaderType, const char* filename) {
GLuint shader = glCreateShader(shaderType);
const char* sources[2];
sources[0] = common_readfile("content/shaders/utils.glsl");
sources[1] = common_readfile(filename);
glShaderSource(shader, 2, sources, NULL);
free((void*)sources[0]);
free((void*)sources[1]);
glCompileShader(shader);
utils_checkShaderLog(filename, shader);
return shader;
}
void utils_createComputeProgram(GLuint *program, const char* computeShaderFilename) {
glDeleteProgram(*program);
GLuint computeShader = utils_createShader(GL_COMPUTE_SHADER, computeShaderFilename);
*program = glCreateProgram();
glAttachShader(*program, computeShader);
glLinkProgram(*program);
utils_checkProgramLog(*program);
glDeleteShader(computeShader);
}
void utils_setAttributePointer(GLuint vertexArrayObject, GLuint buffer, GLint location, GLint size, GLenum type, GLboolean normalized, GLsizei stride, unsigned offset) {
GLint previousVertexArrayObject;
glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &previousVertexArrayObject);
GLint previousArrayBuffer;
glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &previousArrayBuffer);
glBindVertexArray(vertexArrayObject);
glBindBuffer(GL_ARRAY_BUFFER, buffer);
glEnableVertexAttribArray(location);
glVertexAttribPointer(location, size, type, normalized, stride, (void*)(intptr_t)offset);
glBindBuffer(GL_ARRAY_BUFFER, previousArrayBuffer);
glBindVertexArray(previousVertexArrayObject);
}
void utils_setUniformMat4(GLuint location, MLmat4* m) {
glUniformMatrix4fv(location, 1, GL_FALSE, (GLfloat*)m);
}
I tested changes by using the normals as the colors for my fragments.
In this example i set the normals to 0/0/0 during initialization and in the compute shader i change the value of every normal to normalized 1/1/1 thus expect so see the geometry in somewhat of a greyish color, but it stays black.
// EDIT
After starting from scratch and testing the result basically after every row of code i added i found out the problem was this line: glDispatchCompute(NUM_VERTICES / NUM_PARTICLES_PER_LOCAL_WORK_GROUP, 1, 1); i guess this evaluated to zero, which kind of makes sense with a "low" number of vertices and relatively high number of particles per work group.
That resulted in whatever i did in the compute shader was never actually being executed thus, not changing the buffer content.

glDrawArrays won't work draw dynamic array

I'm trying to render a tetrahedron that I could expand to other objects.
Using static arrays works fine, draws the tetrahedron.
But when I read in an OFF file into a dynamic array, nothing appears. No errors appear when I compile.
GLfloat *tetra_vertices = NULL; //This is declared at the start
The following is used in the function that grabs the data from the OFF file.
mod->faces grabs the number of faces from the OFF file. In this case it is 4.
I checked reading in the vertices from the OFF file and that is accurate. Even compared it to the static array.
tetra_vertices = (GLfloat *)malloc(sizeof(GLfloat) * mod->faces * 3 * 3);
for(i=0; i< (mod->faces * 3); i++){
tetra_vertices[i*3]=mod->verts[(mod->face[i])*3];
tetra_vertices[i*3+1]=mod->verts[(mod->face[i])*3+1];
tetra_vertices[i*3+2]=mod->verts[(mod->face[i])*3+2];
}
In init():
glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(tetra_vertices), tetra_vertices, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, vbo[1]);
glBufferData(GL_ARRAY_BUFFER, sizeof(tetra_colors), tetra_colors, GL_STATIC_DRAW);
program = initshader( "a4a_vs.glsl", "a4a_fs.glsl" );
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
pos = glGetAttribLocation(program, "vPos");
glEnableVertexAttribArray(pos);
glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
glVertexAttribPointer(pos, 3, GL_FLOAT, GL_FALSE, 0, NULL);
color = glGetAttribLocation(program, "vColor");
glEnableVertexAttribArray(color);
glBindBuffer(GL_ARRAY_BUFFER, vbo[1]);
glVertexAttribPointer(color, 3, GL_FLOAT, GL_FALSE, 0, NULL);
ModelView = glGetUniformLocation(program, "modelview");
Projection = glGetUniformLocation(program, "projection");
glEnable (GL_DEPTH_TEST);
glClearColor( 0.0, 0.0, 0.0, 1.0 );
glewExperimental = GL_TRUE;
glewInit();
And finally in my main():
GLFWwindow *window = glfwCreateWindow (512, 512, "Hello Cube", NULL, NULL);
glfwMakeContextCurrent (window);
setup(argc, argv); //This creates reads in the OFF file and creates the arrays.
init();
reshape(window, 512, 512);
glfwSetKeyCallback(window, keyboard);
glfwSetWindowSizeCallback(window, reshape);
while (!glfwWindowShouldClose (window)) {
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
identity(transform);
lookat(transform, eye, at, up);
glUseProgram(program);
glBindVertexArray(vao);
glUniformMatrix4fv(ModelView, 1, GL_FALSE, transform);
glUniformMatrix4fv(Projection, 1, GL_FALSE, projection);
glDrawArrays(GL_TRIANGLES, 0, (mod->faces * 3));
glfwSwapBuffers (window);
if (animation)
update();
glfwPollEvents ();
}
Eventually I want to store the array into a list so I can cycle throw different objects from different OFF files. But for now I just want it to draw something. Any assistance would be greatly appreciated. Thank you.
The sizeof operator queries the size of the object or type, it returns the size in bytes of the type that would be returned by the expression you pass to it. Since the type of tetra_vertices is GLfloat*, sizeof(tetra_vertices) returns the size of the pointer type, which probably is 4 or 8 depending on the hardware.
The 2nd parameter of glBufferData is the size of the data buffer in bytes.
This means you have to change your code like this:
size_t vertex_size = sizeof(GLfloat) * mod->faces * 3 * 3;
glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)vertex_size, tetra_vertices, GL_STATIC_DRAW);
You have to do the same for the color attribute buffer tetra_colors.

Opengl 330 core creating and using a texture 2D

It's been a while since I've wrote some graphics programming and I've been staring at this for quite some time now and can't figure out what i'm doing wrong.
This is how I am creating my texture.
GLuint create_texture(const char* filename) {
SDL_Surface* surface;
GLenum tex_format;
GLint num_colors;
GLuint tex_id;
char* file_path;
file_path = get_resource(filename);
surface = IMG_Load(file_path);
if (!surface) {
SDL_Log("failed to create surface\n");
SDL_Quit();
return -1;
} else {
if ((surface->w & (surface->w - 1)) != 0) {
SDL_Log("image { %s } width is not power of 2\n", filename);
}
if ((surface->h & (surface->h - 1)) != 0) {
SDL_Log("image { %s } height is not power of 2\n", filename);
}
num_colors = surface->format->BytesPerPixel;
if (num_colors == 4) {
if (surface->format->Rmask == 0x000000ff)
tex_format = GL_RGBA;
else
tex_format = GL_BGRA;
}
if (num_colors == 3) {
if (surface->format->Rmask == 0x000000ff)
tex_format = GL_RGB;
else
tex_format = GL_BGR;
} else {
SDL_Log("pixel image format shouldn't get here! Quitting\n");
SDL_Quit();
};
glGenTextures(1, &tex_id);
glBindTexture(GL_TEXTURE_2D, tex_id);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, tex_format, surface->w, surface->h, 0,
tex_format, GL_UNSIGNED_BYTE, surface->pixels);
}
if (surface) SDL_FreeSurface(surface);
free(file_path);
return tex_id;
}
this code above works correctly for loading the image data.
vertex shader
#version 330 core
layout (location = 0) in vec3 a_pos;
layout (location = 1) in vec4 a_col;
layout (location = 2) in vec2 a_tex;
uniform mat4 u_mvp_mat;
uniform mat4 u_mod_mat;
uniform mat4 u_view_mat;
uniform mat4 u_proj_mat;
out vec4 f_color;
out vec2 f_tex;
void main()
{
gl_Position = u_mvp_mat * vec4(a_pos, 1.0);
f_tex = a_tex;
f_color = a_col;
}
fragment shader.
#version 330 core
in vec4 f_color;
out vec4 o_color;
in vec2 f_tex;
uniform sampler2D u_sprite_tex;
void main (void)
{
o_color = f_color;
o_color = texture(u_sprite_tex, f_tex);
}
this is how i setup my VBO
quad = ren2d_new(); //just a wrapper around a quad or two tri.
ren2d_set_tint(quad, 0, 1, 0, 1); //setting the color to green
pos_loc = get_attrib_location(ce_get_default_shader(), "a_pos");
col_loc = get_attrib_location(ce_get_default_shader(), "a_col");
mvp_matrix_loc = get_uniform_location(ce_get_default_shader(), "u_mvp_mat");
model_mat_loc = get_uniform_location(ce_get_default_shader(), "u_mod_mat");
view_mat_loc = get_uniform_location(ce_get_default_shader(), "u_view_mat");
proj_matrix_loc =
get_uniform_location(ce_get_default_shader(), "u_proj_mat");
tex_loc = get_uniform_location(ce_get_default_shader(), "u_sprite_tex");
camera = cam_2d_new(ce_get_width(), ce_get_height());
model_mat = mat4_identity();
mat4_scale(model_mat, 128, 128, 1);
tex_id = create_texture("test.png");
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glGenBuffers(1, &vert_buff);
glBindBuffer(GL_ARRAY_BUFFER, vert_buff);
glBufferData(GL_ARRAY_BUFFER, sizeof(quad->vertices), quad->vertices,
GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glGenBuffers(1, &col_buff);
glBindBuffer(GL_ARRAY_BUFFER, col_buff);
glBufferData(GL_ARRAY_BUFFER, sizeof(quad->colors), quad->colors,
GL_STATIC_DRAW);
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, sizeof(quad->tex_coords),
quad->tex_coords);
glEnableVertexAttribArray(2);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glGenBuffers(1, &ind_buff);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ind_buff);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(quad->indices), quad->indices,
GL_STATIC_DRAW);
glBindVertexArray(0);
this is my render function:
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
//could my texturing problems be here?
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, tex_id);
glUniform1i(tex_loc, 0);
glUseProgram(ce_get_default_shader()->shader_program);
glBindVertexArray(vao);
//excuse the silly names
ce_get_view_matrices(&vview_mat, &pproj_mat, &mmvp_mat);
mat4_multi(&mmvp_mat, &vview_mat, model_mat);
mat4_multi(&mmvp_mat, &pproj_mat, &mmvp_mat);
glUniformMatrix4fv(mvp_matrix_loc, 1, GL_FALSE, mat4_get_data(&mmvp_mat));
glUniformMatrix4fv(model_mat_loc, 1, GL_FALSE, mat4_get_data(model_mat));
glUniformMatrix4fv(view_mat_loc, 1, GL_FALSE, mat4_get_data(&vview_mat));
glUniformMatrix4fv(proj_matrix_loc, 1, GL_FALSE, mat4_get_data(&pproj_mat));
glDrawElements(GL_TRIANGLES, quad->vertex_count, GL_UNSIGNED_SHORT, 0);
glBindVertexArray(0);
I am just getting a black quad. I can't track it down and i've been staring at this for quite a few hours now.
doing some very basic testing in the fragment shader like this.
#version 330 core
in vec4 f_color;
out vec4 o_color;
in vec2 f_tex;
uniform sampler2D u_sprite_tex;
void main (void)
{
//o_color = f_color;
vec4 c;
if(f_tex.y == 1.0) { c = vec4(1.0, 0.0, 0.0, 1.0); }
if(f_tex.y == 0.0) { c = vec4(0.0, 0.0, 1.0, 1.0); }
o_color = c;
o_color = texture(u_sprite_tex, f_tex);
}
my quads turn out to be blue both along the x and the y axis. That seems to be that the only value being passed in in 0.0 which doesn't make sense.
okay this was definitely a problem of my own creation. The reason that I was getting segmentation fault was because of this code.
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glGenBuffers(1, &vert_buff);
glBindBuffer(GL_ARRAY_BUFFER, vert_buff);
glBufferData(GL_ARRAY_BUFFER, sizeof(quad->vertices), quad->vertices,
GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glGenBuffers(1, &col_buff);
glBindBuffer(GL_ARRAY_BUFFER, col_buff);
glBufferData(GL_ARRAY_BUFFER, sizeof(quad->colors), quad->colors,
GL_STATIC_DRAW);
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, 0); //right here
glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, sizeof(quad->tex_coords),
quad->tex_coords);
glEnableVertexAttribArray(2);
glGenBuffers(1, &ind_buff);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ind_buff);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(quad->indices), quad->indices,
GL_STATIC_DRAW);
glBindVertexArray(0);
after you bind your vbo buffer to zero attempting to access it will cause a segmentation fault...
After that just making sure that I sent the proper data to the gpu and all other code worked as expected.
GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glGenBuffers(1, &col_buff);
glBindBuffer(GL_ARRAY_BUFFER, col_buff);
glBufferData(GL_ARRAY_BUFFER, sizeof(quad->colors), quad->colors,
GL_STATIC_DRAW);
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(1);
//glBindBuffer(GL_ARRAY_BUFFER, 0); //right here remove this
//properly setup the local data to gpu data
glBufferData(GL_ARRAY_BUFFER, rend2d_get_sizeof_tex_coord(quad),
rend2d_get_tex_coord_data(quad), GL_STATIC_DRAW);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(2);
glBindBuffer(GL_ARRAY_BUFFER, 0); //put it here after finished with vbo
after those two changes everything worked as expected. Hopefully this can save someone some time.
There are at least two things that might be wrong:
glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, sizeof(quad->tex_coords),
quad->tex_coords);
Are you sure that quad->tex_coords contains 4-dimensional vectors? The fragment shader expects vec2. If you only supply two floats per vertex, you have to change the second parameter to two. When OpenGL tries to read from a too small ARRAY_BUFFER this can also cause segmentation faults. Note, that attributes are set to inactive if they do not contribute to the final color, thus the texture coordinates might only be read when textures are used.
Second: You are calling glGenerateMipmap before uploading data to the texture.

OpenGL C++ order for using a vertex buffer and a texture buffer

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.

Resources