OpenGL Texture not showing

I'm using "Learn OpenGL" Book, but I stopped on displaying a texture.

My screen would show only the Clear Color and nothing else.
If I change back shader code to show only color it will work.

Had I missed something?

My Code

sgl.rs:

use epoxy as gl;
use gl::types::*;

pub struct Buffer {}

pub struct Texture(GLuint);

impl Texture {
    pub fn from_file(path: &str) -> Result<Self, &'static str> {
        let img = match image::open(path) {
            Ok(img) => img.into_rgba8(),
            Err(_) => return Err("Can't open an image")
        };

        let mut texture: Self = Self(0);

        unsafe {
            gl::GenTextures(1, &mut texture.0);
        }

        if texture.0 == 0 {
            return Err("Couldn't initialize texture");
        }

        texture.bind();

        unsafe {
            gl::TexParameteri(
                gl::TEXTURE_2D_ARRAY,
                gl::TEXTURE_MIN_FILTER,
                gl::LINEAR as i32,
            );
            gl::TexParameteri(
                gl::TEXTURE_2D_ARRAY,
                gl::TEXTURE_MAG_FILTER,
                gl::LINEAR as i32,
            );
            gl::TexParameteri(
                gl::TEXTURE_2D_ARRAY,
                gl::TEXTURE_WRAP_S,
                gl::CLAMP_TO_EDGE as i32,
            );
            gl::TexParameteri(
                gl::TEXTURE_2D_ARRAY,
                gl::TEXTURE_WRAP_T,
                gl::CLAMP_TO_EDGE as i32,
            );

            gl::TexImage2D(
                gl::TEXTURE_2D,
                0,
                gl::RGBA8 as i32,
                img.width() as i32,
                img.height() as i32,
                0,
                gl::RGBA,
                gl::UNSIGNED_BYTE,
                (&img as &[u8]).as_ptr() as *const _, // TODO
            );

            gl::GenerateMipmap(gl::TEXTURE_2D);
        }

        return Ok( texture );
    }

    pub fn bind(&self) {
        unsafe {
            gl::ActiveTexture(gl::TEXTURE0);
            gl::BindTexture(gl::TEXTURE_2D, self.0);
        }
    }
}

pub enum ShaderType {
    Vertex = gl::VERTEX_SHADER as isize,
    Fragment = gl::FRAGMENT_SHADER as isize,
}

pub struct Shader(pub GLuint);

impl Shader {
    fn new(ty: ShaderType) -> Option<Self> {
        let shader = unsafe { gl::CreateShader(ty as GLenum) };

        if shader != 0 {
            Some(Self(shader))
        } else {
            None
        }
    }

    fn set_source(&self, src: &str) {
        unsafe {
            gl::ShaderSource(
                self.0,
                1,
                &(src.as_bytes().as_ptr().cast()),
                &(src.len().try_into().unwrap()),
            );
        }
    }

    fn compile(&self) {
        unsafe { gl::CompileShader(self.0) };
    }

    fn compile_success(&self) -> bool {
        let mut compiled = 0;
        unsafe { gl::GetShaderiv(self.0, gl::COMPILE_STATUS, &mut compiled) };
        compiled == i32::from(gl::TRUE)
    }

    fn info_log(&self) -> String {
        let mut needed_len = 0;
        unsafe { gl::GetShaderiv(self.0, gl::INFO_LOG_LENGTH, &mut needed_len) };
        let mut v: Vec<u8> = Vec::with_capacity(needed_len.try_into().unwrap());
        let mut len_written = 0_i32;
        unsafe {
            gl::GetShaderInfoLog(
                self.0,
                v.capacity().try_into().unwrap(),
                &mut len_written,
                v.as_mut_ptr().cast(),
            );
            v.set_len(len_written.try_into().unwrap());
        }
        String::from_utf8_lossy(&v).into_owned()
    }

    pub fn delete(self) {
        unsafe { gl::DeleteShader(self.0) };
    }

    pub fn from_source(ty: ShaderType, source: &str) -> Result<Self, String> {
        let id = Self::new(ty)
            .ok_or_else(|| "Couldn't allocate new shader".to_string())?;
        id.set_source(source);
        id.compile();
        if id.compile_success() {
            Ok(id)
        } else {
            let out = id.info_log();
            id.delete();
            Err(out)
        }
    }
}

refarea.rs

use gtk4 as gtk;
use epoxy as gl;

use gtk::prelude::*;
use gtk::subclass::prelude::*;
use gtk::{glib, gdk::GLContext, GLArea, Widget};

use crate::sgl::*;

use core::mem::{size_of, size_of_val};
use std::cell::Cell;
use std::ffi::CString;

glib::wrapper! {
    pub struct RefAreaWidget (
        ObjectSubclass<RefAreaWidgetPriv>
    ) @extends GLArea, Widget;
}

impl RefAreaWidget {
    pub fn new() -> Self {
        glib::Object::new::<Self>()
    }
}

impl Default for RefAreaWidget {
    fn default() -> Self {
        Self::new()
    }
}

pub struct RefAreaWidgetPriv {
    shader_program: Cell<gl::types::GLuint>
}

impl ObjectImpl for RefAreaWidgetPriv {
    fn constructed(&self) {
        self.parent_constructed();
    }
}

#[glib::object_subclass]
impl ObjectSubclass for RefAreaWidgetPriv {
    const NAME: &'static str = "RefAreaWidget";
    type Type = RefAreaWidget;
    type ParentType = GLArea;

    fn new() -> Self {
        let mut refarea = Self {
            shader_program: Cell::new(0),
        };

        return refarea;
    }
}

impl WidgetImpl for RefAreaWidgetPriv {
    fn realize(&self) {
        self.parent_realize();
    }
}

impl GLAreaImpl for RefAreaWidgetPriv {
    fn create_context(&self) -> Option<GLContext> {
        println!("Create Context");

        let new_ctx = self.parent_create_context();

        if let Some(ctx) = &new_ctx {
            ctx.make_current();

            unsafe {
                gl::ClearColor(0.1, 0.0, 0.1, 1.);

                //gl::BlendFunc(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA);
                //gl::Enable(gl::BLEND);

                //gl::FrontFace(gl::CULL_FACE);
            }

            let texture = Texture::from_file("debug2.png").unwrap();
            texture.bind();

            unsafe {
                let mut vao = 0;
                gl::GenVertexArrays(1, &mut vao);
                assert_ne!(vao, 0);

                gl::BindVertexArray(vao);
            }

            type Vertex = [f32; 8];
            type TriIndexes = [u32; 3];

            const VERTICES: [Vertex; 4] = [
                [0.5, 0.5, 0.,   1., 0., 0.,  1., 1.],
                [0.5, -0.5, 0.,  0., 1., 0.,  1., 0.],
                [-0.5, -0.5, 0., 0., 0., 1.,  0., 0.],
                [-0.5, 0.5, 0.,  1., 1., 1.,  0., 1.]
            ];
            const INDICES: [TriIndexes; 2] = [[0, 1, 3], [1, 2, 3]];

            unsafe {
                let mut vbo = 0;
                gl::GenBuffers(1, &mut vbo);
                assert_ne!(vbo, 0);

                gl::BindBuffer(gl::ARRAY_BUFFER, vbo);

                gl::BufferData(
                    gl::ARRAY_BUFFER,
                    size_of_val(&VERTICES) as isize,
                    VERTICES.as_ptr().cast(),
                    gl::STATIC_DRAW,
                );
            }

            unsafe {
                let mut ebo = 0;
                gl::GenBuffers(2, &mut ebo);
                assert_ne!(ebo, 0);

                gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, ebo);

                gl::BufferData(
                    gl::ELEMENT_ARRAY_BUFFER,
                    size_of_val(&INDICES) as isize,
                    INDICES.as_ptr().cast(),
                    gl::STATIC_DRAW,
                );
            }

            unsafe {
                gl::VertexAttribPointer(
                    0,
                    3,
                    gl::FLOAT,
                    gl::FALSE,
                    size_of::<Vertex>().try_into().unwrap(),
                    0 as *const _
                );
                gl::EnableVertexAttribArray(0);

                gl::VertexAttribPointer(
                    1,
                    3,
                    gl::FLOAT,
                    gl::FALSE,
                    size_of::<Vertex>().try_into().unwrap(),
                    size_of::<[f32; 3]>() as *const _
                );
                gl::EnableVertexAttribArray(1);

                gl::VertexAttribPointer(
                    2,
                    2,
                    gl::FLOAT,
                    gl::FALSE,
                    size_of::<Vertex>().try_into().unwrap(),
                    size_of::<[f32; 6]>() as *const _
                );
                gl::EnableVertexAttribArray(2);
            }

            // Vertex Shader

            const VERT_SHADER: &str = r#"
                #version 330 core
                layout (location = 0) in vec3 pos;
                layout (location = 1) in vec3 color;
                layout (location = 2) in vec2 texture;

                out vec4 outColor;
                out vec2 texturePos;

                void main() {
                    gl_Position = vec4(pos, 1.0);
                    outColor = vec4(color, 1.0);
                    texturePos = texture;
                }
            "#;

            let vertex_shader = match Shader::from_source(ShaderType::Vertex, VERT_SHADER) {
                Ok(ok) => ok,
                Err(err) => panic!("Vertex Compile Error: {}", err)
            };

            // Fragment Shader

            const FRAG_SHADER: &str = r#"
                #version 330 core
                out vec4 finalColor;

                in vec4 outColor;
                in vec2 texturePos;

                uniform sampler2D texture0;

                void main() {
                    finalColor = texture(texture0, texturePos);
                    //finalColor = outColor;
                }
            "#;

            let fragment_shader = match Shader::from_source(ShaderType::Fragment, FRAG_SHADER) {
                Ok(ok) => ok,
                Err(err) => panic!("Fragment Compile Error: {}", err)
            };

            // Setup Program

            unsafe {
                self.shader_program.set(gl::CreateProgram());
                gl::AttachShader(self.shader_program.get(), vertex_shader.0);
                gl::AttachShader(self.shader_program.get(), fragment_shader.0);
                gl::LinkProgram(self.shader_program.get());

                let mut success = 0;
                gl::GetProgramiv(self.shader_program.get(), gl::LINK_STATUS, &mut success);
                if success == 0 {
                    let mut v: Vec<u8> = Vec::with_capacity(1024);
                    let mut log_len = 0_i32;
                    gl::GetProgramInfoLog(
                        self.shader_program.get(),
                        1024,
                        &mut log_len,
                        v.as_mut_ptr().cast(),
                    );
                    v.set_len(log_len.try_into().unwrap());
                    panic!("Program Link Error: {}", String::from_utf8_lossy(&v));
                }

                vertex_shader.delete();
                fragment_shader.delete();

                gl::UseProgram(self.shader_program.get());
            }

            unsafe {
                let cstr = CString::new("texture0").unwrap();
                gl::Uniform1i(
                    gl::GetUniformLocation(
                        self.shader_program.get(),
                        cstr.as_ptr()
                    ),
                    0
                );
            }
        }

        return new_ctx;
    }

    fn render(&self, ctx: &GLContext) -> bool {
        println!("Render");

        ctx.make_current();

        unsafe {
            gl::Clear(gl::COLOR_BUFFER_BIT);

            gl::DrawElements(gl::TRIANGLES, 6, gl::UNSIGNED_INT, 0 as *const _);
        }

        //self.parent_render(context)
        return true;
    }

    fn resize(&self, width: i32, height: i32) {
        println!("Resize");

        self.parent_resize(width, height)
    }
}

main.rs

use gtk4 as gtk;

use gtk::prelude::*;
use gtk::{glib, Application, ApplicationWindow, Label};

use core::ptr;

mod sgl;
mod refarea;

use refarea::*;

fn main() -> glib::ExitCode {
     // Load GL pointers from epoxy (GL context management library used by GTK).
    {
        #[cfg(target_os = "macos")]
        let library = unsafe { libloading::os::unix::Library::new("libepoxy.0.dylib") }.unwrap();
        #[cfg(all(unix, not(target_os = "macos")))]
        let library = unsafe { libloading::os::unix::Library::new("libepoxy.so.0") }.unwrap();
        #[cfg(windows)]
        let library = libloading::os::windows::Library::open_already_loaded("epoxy-0.dll").unwrap();

        epoxy::load_with(|name| {
            unsafe { library.get::<_>(name.as_bytes()) }
                .map(|symbol| *symbol)
                .unwrap_or(ptr::null())
        });
    }

    let app = Application::builder()
        .application_id("xyz.jptrzy.Grefe")
        .build();

    app.connect_activate(|app| {
        let window = ApplicationWindow::builder()
            .application(app)
            .default_width(320)
            .default_height(200)
            .title("Grefe")
            .build();

        let label = Label::builder()
            .label("GTK 😍 RUST")
            .build();

        let refarea = RefAreaWidget::new();

        window.set_child(Some(&refarea));

        window.present();
    });

    app.run()
}

Aaaaaa :anger:

For some reason before I use DrawElements I need to rebind the texture.

I hate OpenGL and its marvelous take on API

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.