opengl render to texture just see a black region - c

I am having some trouble in OpenGL, making a render to texture example work. At initialization, i generate a texture 'randtex' with random values of green and black. If i render this texture directly to the window (mapped into a quad) it works all well.
like this:
But if i render 'randtex' into another texture 'tex' which is attached to a framebuffer object, then rendering 'tex' on the screen just gives me a black image on the fbo's blue background and from what i know it should give me the original texture over the blue background. In other words, this is what i am getting
vertex shader for display only (display_shaderp).
#version 420
in vec4 pos;
in vec2 tex_coord;
out vec2 vtex_coord;
uniform mat4 projection;
uniform mat4 modelview;
void main(){
gl_Position = projection * modelview * pos;
vtex_coord = tex_coord;
}
fragment shader for display only (display_shaderp)
#version 420
in vec2 vtex_coord;
uniform sampler2D tex;
out vec4 color;
void main(){
color = texture2D(tex, vtex_coord);
//color = vec4(1.0f, 1.0f, 1.0f, 1.0f);
}
shader program compiles and links ok, i get no gl errors and framebuffer is complete without errors too.
This is the rendering code:
glClearColor(0.5, 0.5, 0.5, 1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glViewport(0, 0, win_width, win_height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.0f, (GLfloat)win_width / (GLfloat) win_height, 0.1f, 50.0f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslate3f(0.0f, 0.0f, -3.0f)
// render to texture
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glViewport(0,0, win_width, win_height);
glClearColor(0.0, 0.0, 0.5, 1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram(fbo_shaderp);
GLfloat m_matrix[16], p_matrix[16];
glGetFloatv(GL_MODELVIEW_MATRIX, m_matrix);
glGetFloatv(GL_PROJECTION_MATRIX, p_matrix);
glUniformMatrix4fv(glGetUniformLocation(fbo_shaderp, "modelview"),1,GL_FALSE,m_matrix);
glUniformMatrix4fv(glGetUniformLocation(fbo_shaderp, "projection"),1,GL_FALSE,p_matrix);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, randtex);
glUniform1i(glGetUniformLocation(fbo_shaderp, "tex"), randtex);
GLuint _p = glGetAttribLocation(fbo_shaderp, "pos");
GLuint _t = glGetAttribLocation(fbo_shaderp, "tex_coord");
glVertexAttribPointer(_p, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), 0);
glVertexAttribPointer(_t, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)(sizeof(float)*3));
glEnableVertexAttribArray(_p);
glEnableVertexAttribArray(_t);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, 0);
glUseProgram(0);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
// render to the window
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glViewport(0,0, win_width, win_height);
glClearColor(0.5, 0.5, 0.5, 1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram(display_shaderp);
glUniformMatrix4fv(glGetUniformLocation(display_shaderp,"modelview"),1,GL_FALSE,m_matrix);
glUniformMatrix4fv(glGetUniformLocation(display_shaderp,"projection"),1,GL_FALSE,p_matrix);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, tex);
glUniform1i(glGetUniformLocation(display_shaderp, "tex"), 0);
GLuint _p = glGetAttribLocation(display_shaderp, "pos");
GLuint _t = glGetAttribLocation(display_shaderp, "tex_coord");
glVertexAttribPointer ( _p, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), 0 );
glVertexAttribPointer ( _t, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*) (sizeof(float) * 3) );
glEnableVertexAttribArray(_p);
glEnableVertexAttribArray(_t);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, 0);
glUseProgram(0);
And the code to create textures and framebuffer
int i = 0;
// create a random texture 'randtex'
glGenTextures(1, &randtex);
glBindTexture(GL_TEXTURE_2D, randtex);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
// random data
GLubyte* data = (GLubyte *) malloc(width*height*4*sizeof(GLubyte));
GLubyte val;
for (i = 0; i < width * height * 4; i+=4){
if ((double)rand()/(double)RAND_MAX > 0.8)
val = 255;
else
val = 0;
data[i] = 0;
data[i+1] = val;
data[i+2] = 0;
data[i+3] = 255;
}
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA,GL_UNSIGNED_BYTE, data);
// create an empty texture 'tex'
glGenTextures(1, &tex);
glBindTexture(GL_TEXTURE_2D, tex);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA,GL_UNSIGNED_BYTE, 0);
// create framebuffer and attach 'tex'
glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glFramebufferTexture2D(GL_FRAMEBUFFER,GL_COLOR_ATTACHMENT0,GL_TEXTURE_2D, tex, 0);
GLenum status;
if ((status = glCheckFramebufferStatus(GL_FRAMEBUFFER)) != GL_FRAMEBUFFER_COMPLETE)
fprintf(stderr, "glCheckFramebufferStatus: error %p", status);
shaders for render to texture (fbo_shaderp)
render to texture vertex shader
in vec4 pos;
in vec2 tex_coord;
out vec2 vtex_coord;
uniform mat4 projection;
uniform mat4 modelview;
void main(){
gl_Position = projection * modelview * pos;
vtex_coord = tex_coord;
}
render to texture fragment shader
#version 420
in vec2 vtex_coord;
layout(location = 0) out vec4 color;
uniform sampler2D tex;
void main(){
color = texture2D(tex, vtex_coord);
//color = vec4(1.0f, 1.0f, 1.0f, 1.0f);
}
In this last shader, if i use the commented line to paint all white and comment out the
texture one, i do get a white image but also opengl error right after rendering to texture "OpenGL Error: invalid value", so this actually confuses me more.

glUniform1i(glGetUniformLocation(fbo_shaderp, "tex"), randtex);
You must not give the ID of the texture, but the slot you bind the texture to. So in your case, that should be
glUniform1i(glGetUniformLocation(fbo_shaderp, "tex"), 0);

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);

Flickering 2D Texture using GLUT and C

I'm trying my hand at making a chip8 emulator using just plain C. I got most of the opcodes set so I just need to work on the display. I decided on using GLUT for the display since it appeared quick setup. The main idea is to display the chip8 sprites onto the 2D texture. I got it to display some digits though some opcode execution but it's flickering. I'm using double buffering since from what I read it's the best way to make sure something is ready to be displayed but I'm still getting flickering. Any ideas on what can cause it?
Here's all the code for OpenGL and GLUT for the display.
int main(int argc, char * argv[]) {
// if(argc < 2){
// printf("Usage: %s <bin file>\n", argv[0]);
// exit(0);
// }
//initialize chip 8
chip8_Init();
//load file if exists
chip8_load("test6.bin");
//setup graphics
glutInit(&argc, argv);
glutInitWindowSize(display_width, display_height);
glutInitWindowPosition(320, 320);
glutInitDisplayMode(GLUT_RGB|GLUT_DOUBLE|GLUT_DEPTH);
glutCreateWindow("Chip8 GL");
setupTexture();
glutDisplayFunc(renderScene);
glutReshapeFunc(changeSize);
glutIdleFunc(renderScene);
glutKeyboardFunc(chip8_keypad);
glutKeyboardUpFunc(chip8_keypadUp);
glutMainLoop();
return 0;
}
void setupTexture(){
glClearColor (0.0, 0.0, 0.0, 0.0);
glShadeModel(GL_FLAT);
glEnable(GL_DEPTH_TEST);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glGenTextures(1, &texName);
glBindTexture(GL_TEXTURE_2D, texName);
//set texture parameters
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);
//update texture
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, SCREEN_WIDTH,
SCREEN_HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE,
screenData);
}
void updateTexture(){ //display()
//update pixels
for (int i = 0; i < SCREEN_HEIGHT; i++) {
for (int j = 0; j < SCREEN_WIDTH; j++) {
if(chip8.gfx[(i * SCREEN_WIDTH)+j] == 0){
screenData[i][j][0] = 0;
screenData[i][j][1] = 0;
screenData[i][j][2] = 0;
}
else{
screenData[i][j][0] = 255;
screenData[i][j][1] = 255;
screenData[i][j][2] = 255;
}
}
}
//update texture
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, SCREEN_WIDTH,
SCREEN_HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE,
screenData);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_TEXTURE_2D);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
glBindTexture(GL_TEXTURE_2D, texName);
glBegin(GL_QUADS);
glTexCoord2f(0.0, 0.0); glVertex2d(0.0, 0.0);
glTexCoord2f(1.0, 0.0); glVertex2d(display_width, 0.0);
glTexCoord2f(1.0, 1.0); glVertex2d(display_width, display_height);
glTexCoord2f(0.0, 1.0); glVertex2d(0.0, display_height);
glEnd();
glutSwapBuffers();
}
void renderScene(){
chip8_emulateCycle();
if(drawFlag == 1){
updateTexture();
drawFlag = 0;
}
}
void changeSize(int w, int h){
glClearColor(0.0f, 0.0f, 0.5f, 0.0f);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0, w, h, 0);
glMatrixMode(GL_MODELVIEW);
glViewport(0, 0, w, h);
// Resize quad
display_width = w;
display_height = h;
}
Edit: I might have figured it out. In the draw opcode, it uses XOR. So when the draw command for the first time the sprite is displayed and when called again it disappears and so on so forth.
My opengl is very dusty, but I saw some points in your code:
You should enable GL_TEXTURE_2D before initialize it:
void setupTexture()
{
glClearColor (0.0, 0.0, 0.0, 0.0);
glShadeModel(GL_FLAT);
glEnable(GL_DEPTH_TEST);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
/* enable texturing */
glEnable(GL_TEXTURE_2D);
/* create texture */
glGenTextures(1, &texName);
/* select texture */
glBindTexture(GL_TEXTURE_2D, texName);
/* select behavior */
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
/* ... */
}
You should select the texture before modifying it
void updateTexture(){
/* update pixels */
/* ... */
/*select texture */
glBindTexture(GL_TEXTURE_2D, texName);
/*update texture */
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, SCREEN_WIDTH,
SCREEN_HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE,
screenData);
/* clear screen */
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
/* draw texture */
glBegin(GL_QUADS);
glTexCoord2f(0.0, 0.0); glVertex2d(0.0, 0.0);
glTexCoord2f(1.0, 0.0); glVertex2d(display_width, 0.0);
glTexCoord2f(1.0, 1.0); glVertex2d(display_width, display_height);
glTexCoord2f(0.0, 1.0); glVertex2d(0.0, display_height);
glEnd();
glutSwapBuffers();
}
Moreover, you may test for the result of called functions, by using glGetError():
void check_for_error(void)
{
GLenum err = glGetError();
if (GL_NO_ERROR != err)
{
fprintf("Error %d\n", err);
exit(EXIT_FAILURE);
}
}
Said that, I don't know the data inside chip8.gfx[], may be they are not as you expect.

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.

How to properly draw texture in modern Opengl

as at the object, having these:
const char* vshader =
"attribute vec4 Position;\n"
"uniform mat4 modelView;\n"
"uniform mat4 projection;\n"
"attribute vec2 texcoord;\n"
"varying vec2 TextureCoord;\n"
"\n"
"void main(void) {\n"
" TextureCoord = texcoord;\n"
" gl_Position = projection * modelView * Position;\n"
"}\n";
const char* fshader =
"uniform sampler2D u_Texture;\n"
"varying vec2 TextureCoord;\n"
"\n"
"void main(void) {\n"
" gl_FragColor = texture2D(u_Texture, TextureCoord);\n"
"}\n";
these are the mesh data and initialization:
float (*cpts)[3]; //controlpoints
int ncpts;
unsigned int (*tris)[3]; //triangles indices
int ntris;
float (*tuv)[2]; //texture UVs
int ntuv;
int (*tuvi)[3]; //UVs indices (same count of ntris)
//bind vertices
glGenBuffers(1,&indexID);
glBindBuffer(GL_ARRAY_BUFFER, indexID);
glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*ncpts, cpts, GL_STATIC_DRAW);
//bind indices
glGenBuffers(1, &indexID);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexID);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(float)*3*ntris, tris, GL_STATIC_DRAW);
this is the texture init:
glBindTexture(GL_TEXTURE_2D,textures[0].ID);
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_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, 3, textures[0].width, textures[0].height, 0, GL_RGB, GL_UNSIGNED_BYTE, textures[0].buf);
//bind texture
glGenBuffers(1, &textureID);
glBindBuffer(GL_ARRAY_BUFFER, textureID);
glBufferData(GL_ARRAY_BUFFER, sizeof(float)*2*ntuv, tuv, GL_STATIC_DRAW);
and this is the program init:
glUseProgram(texture_program_id);
texcoord_slot = glGetAttribLocation(texture_program_id, "texcoord");
texture_slot = glGetUniformLocation(texture_program_id, "u_Texture");
position_slot = glGetAttribLocation(texture_program_id, "Position");
// color_slot = glGetAttribLocation(program_id, "SourceColor");
model_slot = glGetUniformLocation(texture_program_id, "modelView");
projection_slot = glGetUniformLocation(texture_program_id, "projection");
glEnableVertexAttribArray(position_slot);
glEnableVertexAttribArray(color_slot);
glEnableVertexAttribArray(texcoord_slot);
glUniformMatrix4fv(model_slot, 1,0,mstack.mtxstack[mstack.level]);
glUniformMatrix4fv(projection_slot, 1,0,mstack.proj);
finally the draw routine:
glEnable(GL_TEXTURE_2D);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D,textures[0].ID);
glUniform1i(texture_slot, 0);
glBindBuffer(GL_ARRAY_BUFFER, vertexID);
glVertexAttribPointer(position_slot,3,GL_FLOAT,GL_FALSE,sizeof(float)*3,0);
glBindBuffer(GL_ARRAY_BUFFER, textureID);
glVertexAttribPointer(texcoord_slot,2,GL_FLOAT,GL_FALSE,sizeof(float)*2,0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexID);
glDrawElements(GL_TRIANGLES,ntris*3,GL_UNSIGNED_INT,0);
the result is nothing.
how i make all works?
EDIT: editing all this has shown me that texture UVs are also indexed.....
so how i give to the shader the texture UVs indices?

OpenGL how to set a shader texture from the program (sampler2D)

I want to combine 2 textures in a GLSL shader to 1.
the problem is that I fail to set the sampler2D in the shader from my program. (the shader/program compiles correctly, the textures load correctly, the vertex shader is correct too) I tried it with the following code from a tutorial:
glUniform1i(program.getUniformLocation("Texture0"), 0);
glUniform1i(program.getUniformLocation("Texture1"), 1);
//texture 0, first texture
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, colorTexture.handle);
//texture 1, other texture
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, normalTexture.handle);
the fragment shader code looks like this
uniform sampler2D Texture0;
uniform sampler2D Texture1;
void main(void)
{
vec4 color = texture2D(Texture0, vec2(gl_TexCoord[0]));
vec4 normal = texture2D(Texture1, vec2(gl_TexCoord[0]));
gl_FragColor = normal + color;
}
it gets drawn with
glUseProgram(program.handle);
glColor3f(1, 1, 1);
glBegin(GL_QUADS);
glTexCoord2f(0, 0);
glVertex3f(0, 0, 0);
glTexCoord2f(1, 0);
glVertex3f(500, 0, 0);
glTexCoord2f(1, 1);
glVertex3f(500, 500, 0);
glTexCoord2f(0, 1);
glVertex3f(0, 500, 0);
glEnd();
try changing the second sampler to use gl_TexCoord[1]
uniform sampler2D Texture0;
uniform sampler2D Texture1;
void main(void)
{
vec4 color = texture2D(Texture0, vec2(gl_TexCoord[0]));
vec4 normal = texture2D(Texture1, vec2(gl_TexCoord[1]));
gl_FragColor = normal + color;
}

Resources