This commit is contained in:
ScorpionX90
2025-09-02 23:54:35 +02:00
parent 6b11a651be
commit 4ee805a408
20 changed files with 2867 additions and 0 deletions

4
gloom-rs/.gitattributes vendored Normal file
View File

@@ -0,0 +1,4 @@
* text=auto
*.sh text eol=lf
*.bat text eol=crlf

5
gloom-rs/.gitignore vendored Normal file
View File

@@ -0,0 +1,5 @@
/target
/.vscode
*.pdf
*.html
source.zip

2000
gloom-rs/Cargo.lock generated Normal file

File diff suppressed because it is too large Load Diff

19
gloom-rs/Cargo.toml Normal file
View File

@@ -0,0 +1,19 @@
[package]
name = "gloom-rs"
version = "0.3.0"
authors = [
"Peder b. Sundt <pbsds@hotmail.com>",
"Michael H. Gimle <michael.gimle@gmail.com>",
]
edition = "2018" # rust edition
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
glutin = "0.29.1"
gl = "0.14.0"
tobj = ">3.1.0"
image = "0.24.3"
nalgebra-glm = "0.17.0"
rand = "0.8.4"
libc = "0.2.132"

55
gloom-rs/README.md Normal file
View File

@@ -0,0 +1,55 @@
# Gloom-rs
To get started, make sure you have `git`, `cargo` and, `rustc` installed and available.
git clone https://github.com/pbsds/gloom-rs
cd gloom-rs
cargo run
## GLM
We use a variant of GLM known as [nalgebra-glm](https://docs.rs/nalgebra-glm/0.15.0/nalgebra_glm/), which differs *slightly* from the standard GLM library.
## Report
You're free to write your report any way you'd like, as long as it is delivered as a PDF file.
To spread the gospel, I have included a `pandoc` report skeleton in the `report` folder.
To use pandoc, make sure you have `pandoc` installed along with a supported latex engine.
Make sure it works before using it to write your report.
## Cybele
If you're using the lab computers in Cybele, you will be using a network-mounted home directory which is subject to both low quotas and high latency.
To speed up your work we highly reccomend running the following, to put the build directory in RAM rather than on disk:
```shell
test -d target/ && rm -rf target/
ln -s /dev/shm target
```
## Code delivery
We want the following files and folders to be delivered in a ZIP file:
* `resources`
* `shaders`
* `src`
* `Cargo.lock`
* `Cargo.toml`
**Important:** Do not include the `target` folder!
To automatically make an archive (`source.zip`) ready for uploading to blackboard:
* Make sure any extra assets or resources you might have added are located in the `resources` folder
* Then run either:
* `./create_code_archive_for_blackboard_LINUX.sh`
* `create_code_archive_for_blackboard_WINDOWS.bat`.
This zip script will explicitly ignore the `target` folder, and the following two of the files given as a handout for exercise 3 (just to save space):
* `resources/helicopter.obj`
* `resources/lunarsurface.obj`

View File

@@ -0,0 +1,13 @@
#!/bin/sh
if test -f source.zip; then
rm -v source.zip
fi
zip -r source.zip \
Cargo.lock \
Cargo.toml \
src \
shaders \
resources/* \
-x"resources/helicopter.obj" \
-x"resources/lunarsurface.obj" \
-x"resources/.gitkeep"

View File

@@ -0,0 +1,14 @@
if exist source.zip (
del source.zip
)
"%~dp0/vendor/7za.exe" -tzip a source.zip ^
Cargo.lock ^
Cargo.toml ^
src ^
shaders ^
resources/* ^
-x!resources/helicopter.obj ^
-x!resources/lunarsurface.obj ^
-x!resources/.gitkeep
pause

4
gloom-rs/report/.envrc Normal file
View File

@@ -0,0 +1,4 @@
#!/usr/bin/env bash
# this file is automatically loaded by `direnv`, if installed
use nix # this will load the file `shell.nix`

31
gloom-rs/report/Makefile Normal file
View File

@@ -0,0 +1,31 @@
PANDOC_ARGS += --verbose
PANDOC_ARGS += --highlight-style=pygments # the default theme
# Optional filters, needs be installed separately:
#PANDOC_ARGS += --filter pandoc-include
#PANDOC_ARGS += --filter pandoc-include-code
#PANDOC_ARGS += --filter pandoc-imagine
#PANDOC_ARGS += --filter pandoc-crossref
#PANDOC_ARGS += --filter include-files.lua # this only works in the nix environment
#PANDOC_ARGS += --filter include-code-files.lua # this only works in the nix environment
.PHONY: help
help:
@echo "try running 'make template.pdf'"
.PHONY: has-%
has-%:
@command -v $* >/dev/null || ( \
echo "ERROR: Command '$*' not found! Make sure it is installed and available in PATH"; \
false; \
) >&2
%.pdf: %.md Makefile | has-pandoc
pandoc -i $< ${PANDOC_ARGS} -o $@ #--pdf-engine=pdflatex
%.tex: %.md Makefile | has-pandoc
pandoc -i $< ${PANDOC_ARGS} -o $@ --standalone
%.html: %.md Makefile | has-pandoc
pandoc -i $< ${PANDOC_ARGS} -o $@ --katex --standalone --self-contained

14
gloom-rs/report/README.md Normal file
View File

@@ -0,0 +1,14 @@
To use this skeleton, install [pandoc](https://pandoc.org/installing.html).
We provide a working nix shell for those familiar with nix.
To compile `myfile.md` to PDF on linux, run:
make myfile.pdf
To compile and view our provided example, `template.md`, run:
make template.pdf
On Windows, use pandoc directly:
pandoc template.md -o template.pdf

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

31
gloom-rs/report/shell.nix Normal file
View File

@@ -0,0 +1,31 @@
# This virtual environment may be loaded with the command `nix-shell`
# it require that you have nix installed, and nixpkgs configured as the a channel
{ pkgs ? import <nixpkgs> {} }:
pkgs.mkShell {
buildInputs = with pkgs; [
# pandoc and pandoc-lua-filters
(pkgs.writeShellScriptBin "pandoc" ''
export XDG_DATA_HOME=${pandoc-lua-filters}/share
exec ${pkgs.pandoc}/bin/pandoc "$@"
'')
# optional pandoc filters:
#pandoc-include
#pandoc-imagine
#haskellPackages.pandoc-crossref
#haskellPackages.pandoc-include-code
# latex environment
(texlive.combine { inherit (texlive)
scheme-small
fontaxes
atkinson
;})
];
}

120
gloom-rs/report/template.md Normal file
View File

@@ -0,0 +1,120 @@
---
# This is a YAML preamble, defining pandoc meta-variables.
# Reference: https://pandoc.org/MANUAL.html#variables
# Change them as you see fit.
title: TDT4195 Exercise X
author:
- Gyrd Bannamule Gyrdsson
- Gjavleik Britonis Podebusk
date: \today # This is a latex command, ignored for HTML output
lang: en-US
papersize: a4
geometry: margin=4cm
toc: false
toc-title: "Table of Contents"
toc-depth: 2
numbersections: true
header-includes:
# The `atkinson` font, requires 'texlive-fontsextra' on arch or the 'atkinson' CTAN package
# Uncomment this line to enable:
#- '`\usepackage[sfdefault]{atkinson}`{=latex}'
colorlinks: true
links-as-notes: true
# The document is following this break is written using "Markdown" syntax
---
<!--
This is a HTML-style comment, not visible in the final PDF.
-->
# Heading
## Subheading
### Subsubheading
This is a paragraph.
This is the same paragraph.
This is a new paragraph, with *italic*, **bold**, and `inline code` formatting.
It is possible to use special classes to format text: [this is a test]{.smallcaps}.
```rust
//this is a code block with rust syntax highlighting
println!("Hello, {}", 42);
```
[This](https://www.ntnu.no) is a link.
[This][] is also a link. <!-- defined below -->
This[^this_is_a_unique_footnote_label] is a footnote. <!-- defined below -->
This^[Footnotes can also be written inline] is also a footnote.
[This]: https://www.uio.no
[^this_is_a_unique_footnote_label]: In footnotes you can write anything tangentially related.
* This
* is
* a
* unordered
* list
1. This
1. is
1. a
1. ordered
1. list
a. with
a. sub
a. list
with multiple paragraphs
This is still on the first page
`\clearpage`{=latex}
<!--
Above is a raw LaTeX statement.
Those are included when exporting to LaTeX or PDF, and ignored when exporting to HTML.
-->
This is on the second page
i) Roman ordered list
i) Roman ordered list
i) Roman ordered list
This
: is a definition
> this is a
block quote
This is a paragraph with _inline_ \LaTeX\ style math: $\frac{1}{2}$.
Below is a math _block_:
$$
\int_{a}^{b} f(x)dx
$$
| This | is | a | table |
| ---- | --- | --- | ----- |
| 1 | 2 | 3 | 4 |
| 5 | 6 | 7 | 8 |
: This is a table caption
This is an inline image with a fixed height:
![](images/logo.png){height=5em}
Below is a _figure_ (i.e. an image with a caption).
It floats and may as a result move to a different page depending on the layout.
![
Image with caption
](images/logo.png)
Enable and use the `pandoc-crossref` filter to reference figures, tables and equations.

View File

View File

@@ -0,0 +1,8 @@
#version 410 core
out vec4 color;
void main()
{
color = vec4(1.0f, 1.0f, 1.0f, 1.0f);
}

View File

@@ -0,0 +1,8 @@
#version 410 core
in vec3 position;
void main()
{
gl_Position = vec4(position, 1.0f);
}

355
gloom-rs/src/main.rs Normal file
View File

@@ -0,0 +1,355 @@
// Uncomment these following global attributes to silence most warnings of "low" interest:
/*
#![allow(dead_code)]
#![allow(non_snake_case)]
#![allow(unreachable_code)]
#![allow(unused_mut)]
#![allow(unused_unsafe)]
#![allow(unused_variables)]
*/
extern crate nalgebra_glm as glm;
use std::{ mem, ptr, os::raw::c_void };
use std::thread;
use std::sync::{Mutex, Arc, RwLock};
mod shader;
mod util;
use glutin::event::{Event, WindowEvent, DeviceEvent, KeyboardInput, ElementState::{Pressed, Released}, VirtualKeyCode::{self, *}};
use glutin::event_loop::ControlFlow;
// initial window size
const INITIAL_SCREEN_W: u32 = 800;
const INITIAL_SCREEN_H: u32 = 600;
// == // Helper functions to make interacting with OpenGL a little bit prettier. You *WILL* need these! // == //
// Get the size of an arbitrary array of numbers measured in bytes
// Example usage: byte_size_of_array(my_array)
fn byte_size_of_array<T>(val: &[T]) -> isize {
std::mem::size_of_val(&val[..]) as isize
}
// Get the OpenGL-compatible pointer to an arbitrary array of numbers
// Example usage: pointer_to_array(my_array)
fn pointer_to_array<T>(val: &[T]) -> *const c_void {
&val[0] as *const T as *const c_void
}
// Get the size of the given type in bytes
// Example usage: size_of::<u64>()
fn size_of<T>() -> i32 {
mem::size_of::<T>() as i32
}
// Get an offset in bytes for n units of type T, represented as a relative pointer
// Example usage: offset::<u64>(4)
fn offset<T>(n: u32) -> *const c_void {
(n * mem::size_of::<T>() as u32) as *const T as *const c_void
}
// Get a null pointer (equivalent to an offset of 0)
// ptr::null()
// == // Generate your VAO here
unsafe fn create_vao(vertices: &Vec<f32>, indices: &Vec<u32>) -> u32 {
let mut vao: u32 = 0;
gl::GenVertexArrays(1, &mut vao as *mut u32);
gl::BindVertexArray(vao);
let mut vbo: u32 = 0;
gl::GenBuffers(1, &mut vbo as *mut u32);
gl::BindBuffer(gl::ARRAY_BUFFER, vbo);
gl::BufferData(gl::ARRAY_BUFFER, byte_size_of_array(vertices), pointer_to_array(vertices), gl::STATIC_DRAW);
gl::VertexAttribPointer(
0,
3,
gl::FLOAT,
gl::FALSE,
size_of::<f32>() * 3,
ptr::null()
);
gl::EnableVertexAttribArray(0);
let mut ibo = 0;
gl::GenBuffers(1, &mut ibo as *mut u32);
gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, ibo);
gl::BufferData(gl::ELEMENT_ARRAY_BUFFER, byte_size_of_array(indices), pointer_to_array(indices), gl::STATIC_DRAW);
return vao;
}
fn main() {
// Set up the necessary objects to deal with windows and event handling
let el = glutin::event_loop::EventLoop::new();
let wb = glutin::window::WindowBuilder::new()
.with_title("Gloom-rs")
.with_resizable(true)
.with_inner_size(glutin::dpi::LogicalSize::new(INITIAL_SCREEN_W, INITIAL_SCREEN_H));
let cb = glutin::ContextBuilder::new()
.with_vsync(true);
let windowed_context = cb.build_windowed(wb, &el).unwrap();
// Uncomment these if you want to use the mouse for controls, but want it to be confined to the screen and/or invisible.
// windowed_context.window().set_cursor_grab(true).expect("failed to grab cursor");
// windowed_context.window().set_cursor_visible(false);
// Set up a shared vector for keeping track of currently pressed keys
let arc_pressed_keys = Arc::new(Mutex::new(Vec::<VirtualKeyCode>::with_capacity(10)));
// Make a reference of this vector to send to the render thread
let pressed_keys = Arc::clone(&arc_pressed_keys);
// Set up shared tuple for tracking mouse movement between frames
let arc_mouse_delta = Arc::new(Mutex::new((0f32, 0f32)));
// Make a reference of this tuple to send to the render thread
let mouse_delta = Arc::clone(&arc_mouse_delta);
// Set up shared tuple for tracking changes to the window size
let arc_window_size = Arc::new(Mutex::new((INITIAL_SCREEN_W, INITIAL_SCREEN_H, false)));
// Make a reference of this tuple to send to the render thread
let window_size = Arc::clone(&arc_window_size);
// Spawn a separate thread for rendering, so event handling doesn't block rendering
let render_thread = thread::spawn(move || {
// Acquire the OpenGL Context and load the function pointers.
// This has to be done inside of the rendering thread, because
// an active OpenGL context cannot safely traverse a thread boundary
let context = unsafe {
let c = windowed_context.make_current().unwrap();
gl::load_with(|symbol| c.get_proc_address(symbol) as *const _);
c
};
let mut window_aspect_ratio = INITIAL_SCREEN_W as f32 / INITIAL_SCREEN_H as f32;
// Set up openGL
unsafe {
gl::Enable(gl::DEPTH_TEST);
gl::DepthFunc(gl::LESS);
gl::Enable(gl::CULL_FACE);
gl::Disable(gl::MULTISAMPLE);
gl::Enable(gl::BLEND);
gl::BlendFunc(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA);
gl::Enable(gl::DEBUG_OUTPUT_SYNCHRONOUS);
gl::DebugMessageCallback(Some(util::debug_callback), ptr::null());
// Print some diagnostics
println!("{}: {}", util::get_gl_string(gl::VENDOR), util::get_gl_string(gl::RENDERER));
println!("OpenGL\t: {}", util::get_gl_string(gl::VERSION));
println!("GLSL\t: {}", util::get_gl_string(gl::SHADING_LANGUAGE_VERSION));
}
// == // Set up your VAO around here
let verticiesVec: Vec<f32> = vec![
// Triangle 1
-0.9, -0.9, 0.0,
-0.7, -0.9, 0.0,
-0.8, -0.7, 0.0,
// Triangle 2
-0.6, -0.2, 0.0,
-0.2, -0.5, 0.0,
0.4, 0.7, 0.0,
// Triangle 3
0.5, 0.0, 0.0,
0.0, -0.9, 0.0,
0.6, -0.9, 0.0,
// Triangle 4
-0.4, 0.9, 0.0,
-0.9, 0.4, 0.0,
-0.2, 0.2, 0.0,
// Triangle 5
0.9, -0.9, 0.0,
0.9, 0.9, 0.0,
0.5, 0.9, 0.0,
];
let indexVec: Vec<u32> = vec![
0,1,2,
3,4,5,
6,7,8,
9,10,11,
12,13,14
];
let my_vao = unsafe {create_vao(&verticiesVec, &indexVec)};
// == // Set up your shaders here
// Basic usage of shader helper:
// The example code below creates a 'shader' object.
// It which contains the field `.program_id` and the method `.activate()`.
// The `.` in the path is relative to `Cargo.toml`.
// This snippet is not enough to do the exercise, and will need to be modified (outside
// of just using the correct path), but it only needs to be called once
let simple_shader = unsafe {
shader::ShaderBuilder::new()
.attach_file("./shaders/simple.vert")
.attach_file("./shaders/simple.frag")
.link()
};
unsafe{
gl::UseProgram(simple_shader.program_id);
}
// Used to demonstrate keyboard handling for exercise 2.
let mut _arbitrary_number = 0.0; // feel free to remove
// The main rendering loop
let first_frame_time = std::time::Instant::now();
let mut previous_frame_time = first_frame_time;
loop {
// Compute time passed since the previous frame and since the start of the program
let now = std::time::Instant::now();
let elapsed = now.duration_since(first_frame_time).as_secs_f32();
let delta_time = now.duration_since(previous_frame_time).as_secs_f32();
previous_frame_time = now;
// Handle resize events
if let Ok(mut new_size) = window_size.lock() {
if new_size.2 {
context.resize(glutin::dpi::PhysicalSize::new(new_size.0, new_size.1));
window_aspect_ratio = new_size.0 as f32 / new_size.1 as f32;
(*new_size).2 = false;
println!("Window was resized to {}x{}", new_size.0, new_size.1);
unsafe { gl::Viewport(0, 0, new_size.0 as i32, new_size.1 as i32); }
}
}
// Handle keyboard input
if let Ok(keys) = pressed_keys.lock() {
for key in keys.iter() {
match key {
// The `VirtualKeyCode` enum is defined here:
// https://docs.rs/winit/0.25.0/winit/event/enum.VirtualKeyCode.html
VirtualKeyCode::A => {
_arbitrary_number += delta_time;
}
VirtualKeyCode::D => {
_arbitrary_number -= delta_time;
}
// default handler:
_ => { }
}
}
}
// Handle mouse movement. delta contains the x and y movement of the mouse since last frame in pixels
if let Ok(mut delta) = mouse_delta.lock() {
// == // Optionally access the accumulated mouse movement between
// == // frames here with `delta.0` and `delta.1`
*delta = (0.0, 0.0); // reset when done
}
// == // Please compute camera transforms here (exercise 2 & 3)
unsafe {
// Clear the color and depth buffers
gl::ClearColor(0.035, 0.046, 0.078, 1.0); // night sky
gl::Clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT);
// == // Issue the necessary gl:: commands to draw your scene here
gl::DrawElements(gl::TRIANGLES, indexVec.len() as i32, gl::UNSIGNED_INT, ptr::null());
}
// Display the new color buffer on the display
context.swap_buffers().unwrap(); // we use "double buffering" to avoid artifacts
}
});
// == //
// == // From here on down there are only internals.
// == //
// Keep track of the health of the rendering thread
let render_thread_healthy = Arc::new(RwLock::new(true));
let render_thread_watchdog = Arc::clone(&render_thread_healthy);
thread::spawn(move || {
if !render_thread.join().is_ok() {
if let Ok(mut health) = render_thread_watchdog.write() {
println!("Render thread panicked!");
*health = false;
}
}
});
// Start the event loop -- This is where window events are initially handled
el.run(move |event, _, control_flow| {
*control_flow = ControlFlow::Wait;
// Terminate program if render thread panics
if let Ok(health) = render_thread_healthy.read() {
if *health == false {
*control_flow = ControlFlow::Exit;
}
}
match event {
Event::WindowEvent { event: WindowEvent::Resized(physical_size), .. } => {
println!("New window size received: {}x{}", physical_size.width, physical_size.height);
if let Ok(mut new_size) = arc_window_size.lock() {
*new_size = (physical_size.width, physical_size.height, true);
}
}
Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => {
*control_flow = ControlFlow::Exit;
}
// Keep track of currently pressed keys to send to the rendering thread
Event::WindowEvent { event: WindowEvent::KeyboardInput {
input: KeyboardInput { state: key_state, virtual_keycode: Some(keycode), .. }, .. }, .. } => {
if let Ok(mut keys) = arc_pressed_keys.lock() {
match key_state {
Released => {
if keys.contains(&keycode) {
let i = keys.iter().position(|&k| k == keycode).unwrap();
keys.remove(i);
}
},
Pressed => {
if !keys.contains(&keycode) {
keys.push(keycode);
}
}
}
}
// Handle Escape and Q keys separately
match keycode {
Escape => { *control_flow = ControlFlow::Exit; }
Q => { *control_flow = ControlFlow::Exit; }
_ => { }
}
}
Event::DeviceEvent { event: DeviceEvent::MouseMotion { delta }, .. } => {
// Accumulate mouse movement
if let Ok(mut position) = arc_mouse_delta.lock() {
*position = (position.0 + delta.0 as f32, position.1 + delta.1 as f32);
}
}
_ => { }
}
});
}

154
gloom-rs/src/shader.rs Normal file
View File

@@ -0,0 +1,154 @@
use gl;
use std::{
ptr,
str,
ffi::CString,
path::Path,
};
pub struct Shader {
pub program_id: u32,
}
pub struct ShaderBuilder {
program_id: u32,
shaders: Vec::<u32>,
}
#[allow(dead_code)]
pub enum ShaderType {
Vertex,
Fragment,
TessellationControl,
TessellationEvaluation,
Geometry,
}
impl Shader {
// Make sure the shader is active before calling this
pub unsafe fn get_uniform_location(&self, name: &str) -> i32 {
let name_cstr = CString::new(name).expect("CString::new failed");
gl::GetUniformLocation(self.program_id, name_cstr.as_ptr())
}
pub unsafe fn activate(&self) {
gl::UseProgram(self.program_id);
}
}
impl Into<gl::types::GLenum> for ShaderType {
fn into(self) -> gl::types::GLenum {
match self {
ShaderType::Vertex => { gl::VERTEX_SHADER },
ShaderType::Fragment => { gl::FRAGMENT_SHADER },
ShaderType::TessellationControl => { gl::TESS_CONTROL_SHADER },
ShaderType::TessellationEvaluation => { gl::TESS_EVALUATION_SHADER } ,
ShaderType::Geometry => { gl::GEOMETRY_SHADER },
}
}
}
impl ShaderType {
fn from_ext(ext: &std::ffi::OsStr) -> Result<ShaderType, String> {
match ext.to_str().expect("Failed to read extension") {
"vert" => { Ok(ShaderType::Vertex) },
"frag" => { Ok(ShaderType::Fragment) },
"tcs" => { Ok(ShaderType::TessellationControl) },
"tes" => { Ok(ShaderType::TessellationEvaluation) },
"geom" => { Ok(ShaderType::Geometry) },
e => { Err(e.to_string()) },
}
}
}
impl ShaderBuilder {
pub unsafe fn new() -> ShaderBuilder {
ShaderBuilder {
program_id: gl::CreateProgram(),
shaders: vec![],
}
}
pub unsafe fn attach_file(self, shader_path: &str) -> ShaderBuilder {
let path = Path::new(shader_path);
if let Some(extension) = path.extension() {
let shader_type = ShaderType::from_ext(extension)
.expect("Failed to parse file extension.");
let shader_src = std::fs::read_to_string(path)
.expect(&format!("Failed to read shader source. {}", shader_path));
self.compile_shader(&shader_src, shader_type)
} else {
panic!("Failed to read extension of file with path: {}", shader_path);
}
}
pub unsafe fn compile_shader(mut self, shader_src: &str, shader_type: ShaderType) -> ShaderBuilder {
let shader = gl::CreateShader(shader_type.into());
let c_str_shader = CString::new(shader_src.as_bytes()).unwrap();
gl::ShaderSource(shader, 1, &c_str_shader.as_ptr(), ptr::null());
gl::CompileShader(shader);
if !self.check_shader_errors(shader) {
panic!("Shader failed to compile.");
}
self.shaders.push(shader);
self
}
unsafe fn check_shader_errors(&self, shader_id: u32) -> bool {
let mut success = i32::from(gl::FALSE);
let mut info_log = Vec::with_capacity(512);
info_log.set_len(512 - 1);
gl::GetShaderiv(shader_id, gl::COMPILE_STATUS, &mut success);
if success != i32::from(gl::TRUE) {
gl::GetShaderInfoLog(
shader_id,
512,
ptr::null_mut(),
info_log.as_mut_ptr() as *mut gl::types::GLchar,
);
println!("ERROR::Shader Compilation Failed!\n{}", String::from_utf8_lossy(&info_log));
return false;
}
true
}
unsafe fn check_linker_errors(&self) -> bool {
let mut success = i32::from(gl::FALSE);
let mut info_log = Vec::with_capacity(512);
info_log.set_len(512 - 1);
gl::GetProgramiv(self.program_id, gl::LINK_STATUS, &mut success);
if success != i32::from(gl::TRUE) {
gl::GetProgramInfoLog(
self.program_id,
512,
ptr::null_mut(),
info_log.as_mut_ptr() as *mut gl::types::GLchar,
);
println!("ERROR::SHADER::PROGRAM::COMPILATION_FAILED\n{}", String::from_utf8_lossy(&info_log));
return false;
}
true
}
#[must_use = "The shader program is useless if not stored in a variable."]
pub unsafe fn link(self) -> Shader {
for &shader in &self.shaders {
gl::AttachShader(self.program_id, shader);
}
gl::LinkProgram(self.program_id);
// todo:: use this to make safer abstraction
self.check_linker_errors();
for &shader in &self.shaders {
gl::DeleteShader(shader);
}
Shader {
program_id: self.program_id
}
}
}

32
gloom-rs/src/util.rs Normal file
View File

@@ -0,0 +1,32 @@
use std::ffi::CString;
use libc;
pub unsafe fn get_gl_string(name: gl::types::GLenum) -> String {
std::ffi::CStr::from_ptr(gl::GetString(name) as *mut libc::c_char).to_string_lossy().to_string()
}
// Debug callback to panic upon encountering any OpenGL error
pub extern "system" fn debug_callback(
source: u32, e_type: u32, id: u32,
severity: u32, _length: i32,
msg: *const libc::c_char, _data: *mut std::ffi::c_void
) {
if e_type != gl::DEBUG_TYPE_ERROR { return }
if severity == gl::DEBUG_SEVERITY_HIGH ||
severity == gl::DEBUG_SEVERITY_MEDIUM ||
severity == gl::DEBUG_SEVERITY_LOW
{
let severity_string = match severity {
gl::DEBUG_SEVERITY_HIGH => "high",
gl::DEBUG_SEVERITY_MEDIUM => "medium",
gl::DEBUG_SEVERITY_LOW => "low",
_ => "unknown",
};
unsafe {
let string = CString::from_raw(msg as *mut libc::c_char);
let error_message = String::from_utf8_lossy(string.as_bytes()).to_string();
panic!("{}: Error of severity {} raised from {}: {}\n",
id, severity_string, source, error_message);
}
}
}

BIN
gloom-rs/vendor/7za.exe vendored Normal file

Binary file not shown.