Transformations

This commit is contained in:
Piotr Siuszko 2020-08-18 20:29:25 +02:00
parent 4b606801ae
commit 1b4f2793ce
4 changed files with 205 additions and 80 deletions

View File

@ -1,20 +1,35 @@
// settings // settings
pub const SCR_WIDTH: u32 = 1280; pub const SCR_WIDTH: u32 = 1280;
pub const SCR_HEIGHT: u32 = 720; pub const SCR_HEIGHT: u32 = 720;
pub const VERTEX_SHADER_SRC: &str = r#" pub const VERTEX_SHADER_SRC: &str = r#"
#version 330 core #version 330 core
layout (location = 0) in vec3 aPos; layout (location = 0) in vec3 aPos;
void main() { layout (location = 1) in vec2 aTexCoord;
gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);
} out vec2 TexCoord;
uniform mat4 transform;
void main()
{
gl_Position = transform * vec4(aPos, 1.0);
TexCoord = vec2(aTexCoord.x, aTexCoord.y);
}
"#; "#;
pub const FRAGMENT_SHADER_SRC: &str = r#" pub const FRAGMENT_SHADER_SRC: &str = r#"
#version 330 core #version 330 core
out vec4 FragColor; out vec4 FragColor;
void main() {
FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f); in vec3 ourColor;
} in vec2 TexCoord;
"#;
// texture sampler
uniform sampler2D texture1;
void main()
{
FragColor = texture(texture1, TexCoord);
}
"#;

17
src/macros.rs Normal file
View File

@ -0,0 +1,17 @@
#![macro_use]
/// Macro to get c strings from literals without runtime overhead
/// Literal must not contain any interior nul bytes!
macro_rules! c_str {
($literal:expr) => {
std::ffi::CStr::from_bytes_with_nul_unchecked(concat!($literal, "\0").as_bytes())
};
}
/// Get offset to struct member, similar to `offset_of` in C/C++
/// From https://stackoverflow.com/questions/40310483/how-to-get-pointer-offset-in-bytes/40310851#40310851
macro_rules! offset_of {
($ty:ty, $field:ident) => {
&(*(ptr::null() as *const $ty)).$field as *const _ as usize
};
}

View File

@ -1,17 +1,26 @@
extern crate glfw; extern crate glfw;
use self::glfw::{Context, Key, Action}; use self::glfw::{Action, Context, Key};
extern crate gl; extern crate gl;
use self::gl::types::*; use self::gl::types::*;
use std::sync::mpsc::Receiver;
use std::ffi::CString; use std::ffi::CString;
use std::ptr;
use std::str;
use std::mem; use std::mem;
use std::os::raw::c_void; use std::os::raw::c_void;
use std::ptr;
use std::str;
use std::sync::mpsc::Receiver;
use std::path::Path;
extern crate image;
use image::GenericImage;
use cgmath::prelude::*;
use cgmath::{vec3, Matrix4, Rad};
mod consts; mod consts;
mod macros;
mod shader; mod shader;
pub fn main() { pub fn main() {
@ -19,13 +28,21 @@ pub fn main() {
// ------------------------------ // ------------------------------
let mut glfw = glfw::init(glfw::FAIL_ON_ERRORS).unwrap(); let mut glfw = glfw::init(glfw::FAIL_ON_ERRORS).unwrap();
glfw.window_hint(glfw::WindowHint::ContextVersion(3, 3)); glfw.window_hint(glfw::WindowHint::ContextVersion(3, 3));
glfw.window_hint(glfw::WindowHint::OpenGlProfile(glfw::OpenGlProfileHint::Core)); glfw.window_hint(glfw::WindowHint::OpenGlProfile(
glfw::OpenGlProfileHint::Core,
));
#[cfg(target_os = "macos")] #[cfg(target_os = "macos")]
glfw.window_hint(glfw::WindowHint::OpenGlForwardCompat(true)); glfw.window_hint(glfw::WindowHint::OpenGlForwardCompat(true));
// glfw window creation // glfw window creation
// -------------------- // --------------------
let (mut window, events) = glfw.create_window(consts::SCR_WIDTH, consts::SCR_HEIGHT, "LearnOpenGL", glfw::WindowMode::Windowed) let (mut window, events) = glfw
.create_window(
consts::SCR_WIDTH,
consts::SCR_HEIGHT,
"chRustedGL",
glfw::WindowMode::Windowed,
)
.expect("Failed to create GLFW window"); .expect("Failed to create GLFW window");
window.make_current(); window.make_current();
@ -36,46 +53,63 @@ pub fn main() {
// --------------------------------------- // ---------------------------------------
gl::load_with(|symbol| window.get_proc_address(symbol) as *const _); gl::load_with(|symbol| window.get_proc_address(symbol) as *const _);
let (shader_object, vao, vbo, ebo, texture) = unsafe {
let (shaderObject, VAO) = unsafe { let v_shader = CString::new(consts::VERTEX_SHADER_SRC.as_bytes()).unwrap();
let vShaderCode = CString::new(consts::VERTEX_SHADER_SRC.as_bytes()).unwrap(); let f_shader = CString::new(consts::FRAGMENT_SHADER_SRC.as_bytes()).unwrap();
let fShaderCode = CString::new(consts::FRAGMENT_SHADER_SRC.as_bytes()).unwrap(); let shader = crate::shader::Shader::new(v_shader, f_shader);
let shader = crate::shader::Shader::new(vShaderCode, fShaderCode);
// set up vertex data (and buffer(s)) and configure vertex attributes // set up vertex data (and buffer(s)) and configure vertex attributes
// ------------------------------------------------------------------ // ------------------------------------------------------------------
// HINT: type annotation is crucial since default for float literals is f64 // HINT: type annotation is crucial since default for float literals is f64
let vertices: [f32; 12] = [ let vertices: [f32; 20] = [
0.5, 0.5, 0.0, // top right // positions // texture coords
0.5, -0.5, 0.0, // bottom right 0.5, 0.5, 0.0, 1.0, 1.0, // top right
-0.5, -0.5, 0.0, // bottom left 0.5, -0.5, 0.0, 1.0, 0.0, // bottom right
-0.5, 0.5, 0.0 // top left -0.5, -0.5, 0.0, 0.0, 0.0, // bottom left
-0.5, 0.5, 0.0, 0.0, 1.0, // top left
]; ];
let indices = [ // note that we start from 0! let indices = [
0, 1, 3, // first Triangle // note that we start from 0!
1, 2, 3 // second Triangle 0, 1, 3, // first Triangle
1, 2, 3, // second Triangle
]; ];
let (mut VBO, mut VAO, mut EBO) = (0, 0, 0); let (mut vbo, mut vao, mut ebo) = (0, 0, 0);
gl::GenVertexArrays(1, &mut VAO); gl::GenVertexArrays(1, &mut vao);
gl::GenBuffers(1, &mut VBO); gl::GenBuffers(1, &mut vbo);
gl::GenBuffers(1, &mut EBO); gl::GenBuffers(1, &mut ebo);
// bind the Vertex Array Object first, then bind and set vertex buffer(s), and then configure vertex attributes(s). // bind the Vertex Array Object first, then bind and set vertex buffer(s), and then configure vertex attributes(s).
gl::BindVertexArray(VAO); gl::BindVertexArray(vao);
gl::BindBuffer(gl::ARRAY_BUFFER, VBO); gl::BindBuffer(gl::ARRAY_BUFFER, vbo);
gl::BufferData(gl::ARRAY_BUFFER, gl::BufferData(
(vertices.len() * mem::size_of::<GLfloat>()) as GLsizeiptr, gl::ARRAY_BUFFER,
&vertices[0] as *const f32 as *const c_void, (vertices.len() * mem::size_of::<GLfloat>()) as GLsizeiptr,
gl::STATIC_DRAW); &vertices[0] as *const f32 as *const c_void,
gl::STATIC_DRAW,
);
gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, EBO); gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, ebo);
gl::BufferData(gl::ELEMENT_ARRAY_BUFFER, gl::BufferData(
(indices.len() * mem::size_of::<GLfloat>()) as GLsizeiptr, gl::ELEMENT_ARRAY_BUFFER,
&indices[0] as *const i32 as *const c_void, (indices.len() * mem::size_of::<GLfloat>()) as GLsizeiptr,
gl::STATIC_DRAW); &indices[0] as *const i32 as *const c_void,
gl::STATIC_DRAW,
);
gl::VertexAttribPointer(0, 3, gl::FLOAT, gl::FALSE, 3 * mem::size_of::<GLfloat>() as GLsizei, ptr::null()); let stride = 5 * mem::size_of::<GLfloat>() as GLsizei;
// position attribute
gl::VertexAttribPointer(0, 3, gl::FLOAT, gl::FALSE, stride, ptr::null());
gl::EnableVertexAttribArray(0); gl::EnableVertexAttribArray(0);
// texture coord attribute
gl::VertexAttribPointer(
1,
2,
gl::FLOAT,
gl::FALSE,
stride,
(3 * mem::size_of::<GLfloat>()) as *const c_void,
);
gl::EnableVertexAttribArray(1);
// note that this is allowed, the call to gl::VertexAttribPointer registered VBO as the vertex attribute's bound vertex buffer object so afterwards we can safely unbind // note that this is allowed, the call to gl::VertexAttribPointer registered VBO as the vertex attribute's bound vertex buffer object so afterwards we can safely unbind
gl::BindBuffer(gl::ARRAY_BUFFER, 0); gl::BindBuffer(gl::ARRAY_BUFFER, 0);
@ -90,14 +124,41 @@ pub fn main() {
// uncomment this call to draw in wireframe polygons. // uncomment this call to draw in wireframe polygons.
// gl::PolygonMode(gl::FRONT_AND_BACK, gl::LINE); // gl::PolygonMode(gl::FRONT_AND_BACK, gl::LINE);
(shader, VAO) // -------------------------
let mut texture = 0;
gl::GenTextures(1, &mut texture);
gl::BindTexture(gl::TEXTURE_2D, texture); // all upcoming GL_TEXTURE_2D operations now have effect on this texture object
// set the texture wrapping parameters
gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_S, gl::REPEAT as i32); // set texture wrapping to gl::REPEAT (default wrapping method)
gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_T, gl::REPEAT as i32);
// set texture filtering parameters
gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::LINEAR as i32);
gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::LINEAR as i32);
// load image, create texture and generate mipmaps
let img = image::open(&Path::new("resources/garlic_dog_space.jpg"))
.expect("Failed to load texture");
let flipped = img.flipv();
let data = flipped.raw_pixels();
gl::TexImage2D(
gl::TEXTURE_2D,
0,
gl::RGB as i32,
img.width() as i32,
img.height() as i32,
0,
gl::RGB,
gl::UNSIGNED_BYTE,
&data[0] as *const u8 as *const c_void,
);
gl::GenerateMipmap(gl::TEXTURE_2D);
(shader, vao, vbo, ebo, texture)
}; };
// render loop // render loop
// ----------- // -----------
let color_r = 0.3; let color_r = 0.188;
let color_g = 0.3; let color_g = 0.22;
let color_b = 0.6; let color_b = 0.235;
while !window.should_close() { while !window.should_close() {
// events // events
// ----- // -----
@ -109,9 +170,19 @@ pub fn main() {
gl::ClearColor(color_r, color_g, color_b, 1.0); gl::ClearColor(color_r, color_g, color_b, 1.0);
gl::Clear(gl::COLOR_BUFFER_BIT); gl::Clear(gl::COLOR_BUFFER_BIT);
// draw our first triangle gl::BindTexture(gl::TEXTURE_2D, texture);
shaderObject.useProgram(); // create transformations
gl::BindVertexArray(VAO); // seeing as we only have a single VAO there's no need to bind it every time, but we'll do so to keep things a bit more organized let mut transform: Matrix4<f32> = Matrix4::identity();
transform = transform * Matrix4::<f32>::from_translation(vec3(0.5, -0.5, 0.0));
transform = transform * Matrix4::<f32>::from_angle_z(Rad(glfw.get_time() as f32));
// get matrix's uniform location and set matrix
shader_object.useProgram();
let transform_loc =
gl::GetUniformLocation(shader_object.ID, c_str!("transform").as_ptr());
gl::UniformMatrix4fv(transform_loc, 1, gl::FALSE, transform.as_ptr());
gl::BindVertexArray(vao); // seeing as we only have a single VAO there's no need to bind it every time, but we'll do so to keep things a bit more organized
gl::DrawElements(gl::TRIANGLES, 6, gl::UNSIGNED_INT, ptr::null()); gl::DrawElements(gl::TRIANGLES, 6, gl::UNSIGNED_INT, ptr::null());
} }
@ -131,7 +202,9 @@ fn process_events(window: &mut glfw::Window, events: &Receiver<(f64, glfw::Windo
// height will be significantly larger than specified on retina displays. // height will be significantly larger than specified on retina displays.
unsafe { gl::Viewport(0, 0, width, height) } unsafe { gl::Viewport(0, 0, width, height) }
} }
glfw::WindowEvent::Key(Key::Escape, _, Action::Press, _) => window.set_should_close(true), glfw::WindowEvent::Key(Key::Escape, _, Action::Press, _) => {
window.set_should_close(true)
}
glfw::WindowEvent::Key(_, _, Action::Press, _) => println!("Other key pressed"), glfw::WindowEvent::Key(_, _, Action::Press, _) => println!("Other key pressed"),
_ => {} _ => {}
} }

View File

@ -1,5 +1,5 @@
#![allow(non_snake_case)] #![allow(non_snake_case)]
use std::ffi::{CString, CStr}; use std::ffi::{CStr, CString};
use std::fs::File; use std::fs::File;
use std::io::Read; use std::io::Read;
use std::ptr; use std::ptr;
@ -8,8 +8,8 @@ use std::str;
use gl; use gl;
use gl::types::*; use gl::types::*;
use cgmath::{Matrix, Matrix4, Vector3};
use cgmath::prelude::*; use cgmath::prelude::*;
use cgmath::{Matrix, Matrix4, Vector3};
pub struct Shader { pub struct Shader {
pub ID: u32, pub ID: u32,
@ -19,7 +19,6 @@ pub struct Shader {
/// a few more setters for uniforms) /// a few more setters for uniforms)
#[allow(dead_code)] #[allow(dead_code)]
impl Shader { impl Shader {
pub fn new(vShaderCode: CString, fShaderCode: CString) -> Shader { pub fn new(vShaderCode: CString, fShaderCode: CString) -> Shader {
let mut shader = Shader { ID: 0 }; let mut shader = Shader { ID: 0 };
@ -52,10 +51,10 @@ impl Shader {
pub fn from_file(vertexPath: &str, fragmentPath: &str) -> Shader { pub fn from_file(vertexPath: &str, fragmentPath: &str) -> Shader {
// 1. retrieve the vertex/fragment source code from filesystem // 1. retrieve the vertex/fragment source code from filesystem
let mut vShaderFile = File::open(vertexPath) let mut vShaderFile =
.unwrap_or_else(|_| panic!("Failed to open {}", vertexPath)); File::open(vertexPath).unwrap_or_else(|_| panic!("Failed to open {}", vertexPath));
let mut fShaderFile = File::open(fragmentPath) let mut fShaderFile =
.unwrap_or_else(|_| panic!("Failed to open {}", fragmentPath)); File::open(fragmentPath).unwrap_or_else(|_| panic!("Failed to open {}", fragmentPath));
let mut vertexCode = String::new(); let mut vertexCode = String::new();
let mut fragmentCode = String::new(); let mut fragmentCode = String::new();
vShaderFile vShaderFile
@ -92,7 +91,11 @@ impl Shader {
} }
/// ------------------------------------------------------------------------ /// ------------------------------------------------------------------------
pub unsafe fn setVector3(&self, name: &CStr, value: &Vector3<f32>) { pub unsafe fn setVector3(&self, name: &CStr, value: &Vector3<f32>) {
gl::Uniform3fv(gl::GetUniformLocation(self.ID, name.as_ptr()), 1, value.as_ptr()); gl::Uniform3fv(
gl::GetUniformLocation(self.ID, name.as_ptr()),
1,
value.as_ptr(),
);
} }
/// ------------------------------------------------------------------------ /// ------------------------------------------------------------------------
pub unsafe fn setVec3(&self, name: &CStr, x: f32, y: f32, z: f32) { pub unsafe fn setVec3(&self, name: &CStr, x: f32, y: f32, z: f32) {
@ -100,7 +103,12 @@ impl Shader {
} }
/// ------------------------------------------------------------------------ /// ------------------------------------------------------------------------
pub unsafe fn setMat4(&self, name: &CStr, mat: &Matrix4<f32>) { pub unsafe fn setMat4(&self, name: &CStr, mat: &Matrix4<f32>) {
gl::UniformMatrix4fv(gl::GetUniformLocation(self.ID, name.as_ptr()), 1, gl::FALSE, mat.as_ptr()); gl::UniformMatrix4fv(
gl::GetUniformLocation(self.ID, name.as_ptr()),
1,
gl::FALSE,
mat.as_ptr(),
);
} }
/// utility function for checking shader compilation/linking errors. /// utility function for checking shader compilation/linking errors.
@ -112,36 +120,48 @@ impl Shader {
if type_ != "PROGRAM" { if type_ != "PROGRAM" {
gl::GetShaderiv(shader, gl::COMPILE_STATUS, &mut success); gl::GetShaderiv(shader, gl::COMPILE_STATUS, &mut success);
if success != gl::TRUE as GLint { if success != gl::TRUE as GLint {
gl::GetShaderInfoLog(shader, 1024, ptr::null_mut(), infoLog.as_mut_ptr() as *mut GLchar); gl::GetShaderInfoLog(
println!("ERROR::SHADER_COMPILATION_ERROR of type: {}\n{}\n \ shader,
1024,
ptr::null_mut(),
infoLog.as_mut_ptr() as *mut GLchar,
);
println!(
"ERROR::SHADER_COMPILATION_ERROR of type: {}\n{}\n \
-- --------------------------------------------------- -- ", -- --------------------------------------------------- -- ",
type_, type_,
str::from_utf8(&infoLog).unwrap()); str::from_utf8(&infoLog).unwrap()
);
} }
} else { } else {
gl::GetProgramiv(shader, gl::LINK_STATUS, &mut success); gl::GetProgramiv(shader, gl::LINK_STATUS, &mut success);
if success != gl::TRUE as GLint { if success != gl::TRUE as GLint {
gl::GetProgramInfoLog(shader, 1024, ptr::null_mut(), infoLog.as_mut_ptr() as *mut GLchar); gl::GetProgramInfoLog(
println!("ERROR::PROGRAM_LINKING_ERROR of type: {}\n{}\n \ shader,
1024,
ptr::null_mut(),
infoLog.as_mut_ptr() as *mut GLchar,
);
println!(
"ERROR::PROGRAM_LINKING_ERROR of type: {}\n{}\n \
-- --------------------------------------------------- -- ", -- --------------------------------------------------- -- ",
type_, type_,
str::from_utf8(&infoLog).unwrap()); str::from_utf8(&infoLog).unwrap()
);
} }
} }
} }
/// Only used in 4.9 Geometry shaders - ignore until then (shader.h in original C++) /// Only used in 4.9 Geometry shaders - ignore until then (shader.h in original C++)
pub fn with_geometry_shader(vertexPath: &str, fragmentPath: &str, geometryPath: &str) -> Self { pub fn with_geometry_shader(vertexPath: &str, fragmentPath: &str, geometryPath: &str) -> Self {
let mut shader = Shader { ID: 0 }; let mut shader = Shader { ID: 0 };
// 1. retrieve the vertex/fragment source code from filesystem // 1. retrieve the vertex/fragment source code from filesystem
let mut vShaderFile = File::open(vertexPath) let mut vShaderFile =
.unwrap_or_else(|_| panic!("Failed to open {}", vertexPath)); File::open(vertexPath).unwrap_or_else(|_| panic!("Failed to open {}", vertexPath));
let mut fShaderFile = File::open(fragmentPath) let mut fShaderFile =
.unwrap_or_else(|_| panic!("Failed to open {}", fragmentPath)); File::open(fragmentPath).unwrap_or_else(|_| panic!("Failed to open {}", fragmentPath));
let mut gShaderFile = File::open(geometryPath) let mut gShaderFile =
.unwrap_or_else(|_| panic!("Failed to open {}", geometryPath)); File::open(geometryPath).unwrap_or_else(|_| panic!("Failed to open {}", geometryPath));
let mut vertexCode = String::new(); let mut vertexCode = String::new();
let mut fragmentCode = String::new(); let mut fragmentCode = String::new();
let mut geometryCode = String::new(); let mut geometryCode = String::new();