I'm currently using sdl_ttf to generate some text. I know it works as I've use it in another project and it renders it correctly. It just seems OpenGL is not loading the texture data. I print out the texture data and see the 1s and 0s. But after trying to load it in, and get it back there is no data there (assumption from glGetTexImage
, this maybe incorrect).
Sort of following LearnOpenGL - Text Rendering and source code Code Viewer. Source code: src/7.in_practice/2.text_rendering/text_rendering.cpp just with sdl_ttf instead of freetype_gl.
mod mygl;
use gl::types::*;
use glam::{Mat4, Vec3, Vec4};
use std::ffi::CString;
use std::os::raw::c_void;
use std::time::Duration;
use sdl2::event::Event;
use sdl2::keyboard::Keycode;
use sdl2::pixels::{Color, PixelFormat, PixelFormatEnum};
use sdl2::rect::Rect;
use sdl2::ttf::FontStyle;
const VERTEX_SHADER: &str = r#"#version 330
layout (location = 0) in vec3 pos;
layout (location = 1) in vec2 tex_coord;
out vec2 vertex_tex_coord;
uniform mat4 projection;
void main() {
gl_Position = projection * vec4(pos.x, pos.y, pos.z, 1.0);
vertex_tex_coord = tex_coord;
}"#;
const FRAGMENT_SHADER: &str = r#"#version 330
out vec4 color;
in vec2 vertex_tex_coord;
uniform sampler2D tex_image;
void main(void) {
vec4 sampled = vec4(1.0, 1.0, 1.0, texture(tex_image, vertex_tex_coord).r);
color = vec4(1.0, 1.0, 1.0, 1.0) * sampled;
//color = vec4(1.0, 0.0, 0.0, 1.0);
}"#;
fn main() {
let sdl_context = sdl2::init().unwrap();
let video_subsystem = sdl_context.video().unwrap();
let window = video_subsystem.window("Hello World", 640, 480)
.position_centered()
.opengl()
.build()
.unwrap();
let gl_attr = video_subsystem.gl_attr();
gl_attr.set_context_profile(sdl2::video::GLProfile::Core);
gl_attr.set_context_version(3, 3);
let gl_context = window.gl_create_context().unwrap();
let gl = gl::load_with(|s| video_subsystem.gl_get_proc_address(s) as *const std::os::raw::c_void);
unsafe {
gl::Enable(gl::BLEND);
gl::BlendFunc(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA);
}
let (width, height) = window.size();
// texture
let mut hello_world_texture: GLuint = 0;
let (hwt_width, hwt_height) = unsafe {
gl::PixelStorei(gl::UNPACK_ALIGNMENT, 1);
let ttf_context = sdl2::ttf::init().unwrap();
let mut font = ttf_context.load_font("assets/fonts/VT323/VT323-Regular.ttf", 24).unwrap();
font.set_style(FontStyle::NORMAL);
font.set_outline_width(0);
font.set_hinting(sdl2::ttf::Hinting::Mono);
font.set_kerning(false);
let hello_world_surface = font.render("Hello World")
.solid(Color::WHITE)
.unwrap();
let (hw_width, hw_height) = hello_world_surface.size();
gl::GenTextures(1, &mut hello_world_texture);
gl::BindTexture(gl::TEXTURE_2D, hello_world_texture);
gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_S, gl::CLAMP_TO_EDGE as GLint);
gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_T, gl::CLAMP_TO_EDGE as GLint);
gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::LINEAR as GLint);
gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::LINEAR as GLint);
hello_world_surface.with_lock(|data| {
println!("DATA BEFORE {:?}", data);
gl::TexImage2D(
gl::TEXTURE_2D,
0,
gl::RED as GLint,
hw_width as GLint,
hw_height as GLint,
0,
gl::RED,
gl::UNSIGNED_BYTE,
data.as_ptr().cast()
);
let mut v = Vec::<u8>::with_capacity((hw_width * hw_height) as usize);
gl::GetTexImage(gl::TEXTURE_2D, 0, gl::RED, gl::UNSIGNED_BYTE, v.as_mut_ptr().cast());
println!("DATA AFTER {:?}", v);
});
(hw_width, hw_height)
};
// orthographic projection
let trans_matrix = Mat4::from_cols_array(&[
1.0/320.0, 0.0, 0.0, 0.0,
0.0, -1.0/240.0, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0,
-1.0, 1.0, 0.0, 1.0,
]);
let (vertices, vertices_stride) = {
let center = Vec3::new((width as f32) * 0.5, (height as f32) * 0.5, 0.0);
let (w, h) = {
(hwt_width as f32 * 0.5, hwt_height as f32 * 0.5)
};
let top_left = center - Vec3::new(-w, -h, 0.0);
let top_right = center - Vec3::new(w, -h, 0.0);
let bot_left = center - Vec3::new(-w, h, 0.0);
let bot_right = center - Vec3::new(w, h, 0.0);
// let top_left = center + Vec3::new(-square_apothem, square_apothem, 0.0);
// let top_right = center + Vec3::new(square_apothem, square_apothem, 0.0);
// let bot_left = center + Vec3::new(-square_apothem, -square_apothem, 0.0);
// let bot_right = center + Vec3::new(square_apothem, -square_apothem, 0.0);
let mut v = Vec::<f32>::with_capacity((3+2) * 4);
v.extend(top_left.to_array()); v.extend([0.0, 1.0]);
v.extend(top_right.to_array()); v.extend([1.0, 1.0]);
v.extend(bot_left.to_array()); v.extend([1.0, 0.0]);
v.extend(bot_right.to_array()); v.extend([0.0, 0.0]);
(v, 5)
};
let indices = [
0, 1, 3,
0, 2, 3,
];
// set viewport size
unsafe {
gl::Viewport(0, 0, width as i32, height as i32);
}
// load program
let program: mygl::Program;
let uniform_projection: GLint;
let uniform_tex_image:GLint;
{
// vertex shader
let vertex_shader: mygl::Shader = mygl::Shader::new(mygl::ShaderType::Vertex).unwrap();
vertex_shader.set_source_with_string(VERTEX_SHADER);
vertex_shader.try_complie().expect("vertex_shader compile");
// fragment shader
let fragment_shader: mygl::Shader = mygl::Shader::new(mygl::ShaderType::Fragment).unwrap();
fragment_shader.set_source_with_string(FRAGMENT_SHADER);
fragment_shader.try_complie().expect("fragment_shader compile");
program = mygl::Program::new();
program.attach_shader(vertex_shader);
program.attach_shader(fragment_shader);
program.try_link().expect("program link");
uniform_projection = program.get_uniform_location("projection").unwrap();
// uniform_tex_image = program.get_uniform_location("tex_image").unwrap();
}
// create buffers
let mut vao: GLuint = 0;
let mut vbo: GLuint = 0;
let mut ebo: GLuint = 0;
unsafe {
gl::GenBuffers(1, &mut vbo);
gl::GenBuffers(1, &mut ebo);
gl::GenVertexArrays(1, &mut vao);
gl::BindVertexArray(vao);
gl::BindBuffer(gl::ARRAY_BUFFER, vbo);
gl::BufferData(
gl::ARRAY_BUFFER,
(vertices.len() * std::mem::size_of::<GLfloat>()) as GLsizeiptr,
vertices.as_ptr().cast(),
gl::STATIC_DRAW,
);
gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, ebo);
gl::BufferData(
gl::ELEMENT_ARRAY_BUFFER,
(indices.len() * std::mem::size_of::<GLint>()) as GLsizeiptr,
indices.as_ptr().cast(),
gl::STATIC_DRAW
);
gl::VertexAttribPointer(
0,
3,
gl::FLOAT,
gl::FALSE,
(vertices_stride * std::mem::size_of::<GLfloat>()) as GLint,
std::ptr::null()
);
gl::EnableVertexAttribArray(0);
gl::VertexAttribPointer(
1,
2,
gl::FLOAT,
gl::FALSE,
(vertices_stride * std::mem::size_of::<GLfloat>()) as GLint,
(3 * std::mem::size_of::<GLfloat>()) as *const c_void
);
gl::EnableVertexAttribArray(1);
gl::BindBuffer(gl::ARRAY_BUFFER, 0);
gl::BindVertexArray(0);
}
unsafe {
gl::ClearColor(0.2, 0.3, 0.3, 1.0);
gl::Clear(gl::COLOR_BUFFER_BIT);
program.use_program();
// gl::Uniform1i(uniform_tex_image, gl::TEXTURE0 as GLint);
gl::UniformMatrix4fv(uniform_projection, 1, gl::FALSE, trans_matrix.to_cols_array().as_ptr() );
gl::ActiveTexture(gl::TEXTURE0);
gl::BindTexture(gl::TEXTURE_2D, hello_world_texture);
gl::BindVertexArray(vao);
gl::DrawElements(gl::TRIANGLES, indices.len() as GLint, gl::UNSIGNED_INT, std::ptr::null());
// gl::DrawArrays(gl::TRIANGLES, 0, vertices.len() as GLint);
window.gl_swap_window();
}
// event loop
let mut event_pump = sdl_context.event_pump().unwrap();
'main_loop: loop {
for event in event_pump.poll_iter() {
match event {
Event::Quit {..} |
Event::KeyDown { keycode: Some(Keycode::Escape), .. } => {
break 'main_loop
},
_ => {}
}
}
// render frame
std::thread::sleep(Duration::new(0, 1_000_000_000u32 / 60));
}
}
Hopefully you can safely ignore Shader
, and Program
. They are just wrappers for gl
stuff. If you think it would help to have direct gl
calls, let me know.
Update: Decided to do a gl::GetError()
after gl::TexImage2D
and it comes back with a 1280
GL_INVALID_ENUM
. I think that just confuses me more.
Turns out it was a result of the gl::GetError()
was nothing to do with the gl::TexImage2D
. I had to remove gl::Enable(gl::TEXTURE_2D)
as that was causing GL_INVALID_ENUM
. Still no texture showing or being loaded.
Side Note: gl::Enable(gl::TEXTURE_2D)
it’s only meaningful for the fixed-function pipeline, and OpenGL 3+ core profile doesn’t support the fixed-function pipeline.