Hello everyone,
I'm trying to display a 2D texture to screen but the rendering isn't working correctly.
First of all I did follow this tutorial to be able to render a Text to screen (I adapted it to render with OpenGL ES 2.0) : https://learnopengl.com/code_viewer.php?code=in-practice/text_rendering
So here is the shader I'm using :
const char gVertexShader[] =
"#version 320 es\n"
"layout (location = 0) in vec4 vertex;\n"
"out vec2 TexCoords;\n"
"uniform mat4 projection;\n"
"void main() {\n"
" gl_Position = projection * vec4(vertex.xy, 0.0, 1.0);\n"
" TexCoords = vertex.zw;\n"
"}\n";
const char gFragmentShader[] =
"#version 320 es\n"
"precision mediump float;\n"
"in vec2 TexCoords;\n"
"out vec4 color;\n"
"uniform sampler2D text;\n"
"uniform vec3 textColor;\n"
"void main() {\n"
" vec4 sampled = vec4(1.0, 1.0, 1.0, texture(text, TexCoords).r);\n"
" color = vec4(textColor, 1.0) * sampled;\n"
"}\n";
The render text works very well so I would like to keep those Shaders program to render a texture loaded from PNG.
For that I'm using libPNG to load the PNG to a texture, here is my code :
GLuint Cluster::loadPngFromPath(const char *file_name, int *width, int *height) {
png_byte header[8];
FILE *fp = fopen(file_name, "rb");
if (fp == 0) {
return 0;
}
fread(header, 1, 8, fp);
if (png_sig_cmp(header, 0, 8)) {
fclose(fp);
return 0;
}
png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (!png_ptr) {
fclose(fp);
return 0;
}
png_infop info_ptr = png_create_info_struct(png_ptr);
if (!info_ptr) {
png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
fclose(fp);
return 0;
}
png_infop end_info = png_create_info_struct(png_ptr);
if (!end_info) {
png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp) NULL);
fclose(fp);
return 0;
}
if (setjmp(png_jmpbuf(png_ptr))) {
png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
fclose(fp);
return 0;
}
png_init_io(png_ptr, fp);
png_set_sig_bytes(png_ptr, 8);
png_read_info(png_ptr, info_ptr);
int bit_depth, color_type;
png_uint_32 temp_width, temp_height;
png_get_IHDR(png_ptr, info_ptr, &temp_width, &temp_height, &bit_depth, &color_type, NULL, NULL, NULL);
if (width) {
*width = temp_width;
}
if (height) {
*height = temp_height;
}
png_read_update_info(png_ptr, info_ptr);
int rowbytes = png_get_rowbytes(png_ptr, info_ptr);
rowbytes += 3 - ((rowbytes-1) % 4);
png_byte * image_data;
image_data = (png_byte *) malloc(rowbytes * temp_height * sizeof(png_byte)+15);
if (image_data == NULL) {
png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
fclose(fp);
return 0;
}
png_bytep * row_pointers = (png_bytep *) malloc(temp_height * sizeof(png_bytep));
if (row_pointers == NULL) {
png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
free(image_data);
fclose(fp);
return 0;
}
int i;
for (i = 0; i < temp_height; i++) {
row_pointers[temp_height - 1 - i] = image_data + i * rowbytes;
}
png_read_image(png_ptr, row_pointers);
GLuint texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexImage2D(GL_TEXTURE_2D, GL_ZERO, GL_RGB, temp_width, temp_height, GL_ZERO, GL_RGB, GL_UNSIGNED_BYTE, image_data);
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_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
free(image_data);
free(row_pointers);
fclose(fp);
return texture;
}
This code just generates the texture and I store the id on memory
And then I want to display my texture on any position (X, Y) of my screen so I did the following (That's works, at least the positioning).
//MY TEXTURE IS 32x32 pixels !
void Cluster::printTexture(GLuint idTexture, GLfloat x, GLfloat y) {
glActiveTexture(GL_TEXTURE0);
glBindVertexArray(VAO);
GLfloat vertices[6][4] = {
{ x, y + 32, 0.0, 0.0 },
{ x, y, 0.0, 1.0 },
{ x + 32, y, 1.0, 1.0 },
{ x, y + 32, 0.0, 0.0 },
{ x + 32, y, 1.0, 1.0 },
{ x + 32, y + 32, 1.0, 0.0 }
};
glBindTexture(GL_TEXTURE_2D, idTexture);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferSubData(GL_ARRAY_BUFFER, GL_ZERO, sizeof(vertices), vertices);
glBindBuffer(GL_ARRAY_BUFFER, GL_ZERO);
glUniform1i(this->mTextShaderHandle, GL_ZERO);
glDrawArrays(GL_TRIANGLE_STRIP, GL_ZERO, 6);
}
My .png is a blue square.
The result is that my texture is not loaded correctly. It is not complete and there are many small black spots. I don't know what's going on ? It could be the vertices or the load ? Or maybe I need to add something on the shader. I don't know, I really need help.
Thanks !