init
This commit is contained in:
4
gloom-rs/.gitattributes
vendored
Normal file
4
gloom-rs/.gitattributes
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
* text=auto
|
||||
|
||||
*.sh text eol=lf
|
||||
*.bat text eol=crlf
|
||||
5
gloom-rs/.gitignore
vendored
Normal file
5
gloom-rs/.gitignore
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
/target
|
||||
/.vscode
|
||||
*.pdf
|
||||
*.html
|
||||
source.zip
|
||||
2000
gloom-rs/Cargo.lock
generated
Normal file
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
19
gloom-rs/Cargo.toml
Normal 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
55
gloom-rs/README.md
Normal 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`
|
||||
13
gloom-rs/create_code_archive_for_blackboard_LINUX.sh
Executable file
13
gloom-rs/create_code_archive_for_blackboard_LINUX.sh
Executable 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"
|
||||
14
gloom-rs/create_code_archive_for_blackboard_WINDOWS.bat
Normal file
14
gloom-rs/create_code_archive_for_blackboard_WINDOWS.bat
Normal 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
4
gloom-rs/report/.envrc
Normal 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
31
gloom-rs/report/Makefile
Normal 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
14
gloom-rs/report/README.md
Normal 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
|
||||
BIN
gloom-rs/report/images/logo.png
Normal file
BIN
gloom-rs/report/images/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.5 KiB |
31
gloom-rs/report/shell.nix
Normal file
31
gloom-rs/report/shell.nix
Normal 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
120
gloom-rs/report/template.md
Normal 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:
|
||||
{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.
|
||||
|
||||

|
||||
|
||||
Enable and use the `pandoc-crossref` filter to reference figures, tables and equations.
|
||||
0
gloom-rs/resources/.gitkeep
Normal file
0
gloom-rs/resources/.gitkeep
Normal file
8
gloom-rs/shaders/simple.frag
Normal file
8
gloom-rs/shaders/simple.frag
Normal file
@@ -0,0 +1,8 @@
|
||||
#version 410 core
|
||||
|
||||
out vec4 color;
|
||||
|
||||
void main()
|
||||
{
|
||||
color = vec4(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
}
|
||||
8
gloom-rs/shaders/simple.vert
Normal file
8
gloom-rs/shaders/simple.vert
Normal 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
355
gloom-rs/src/main.rs
Normal 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
154
gloom-rs/src/shader.rs
Normal 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
32
gloom-rs/src/util.rs
Normal 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
BIN
gloom-rs/vendor/7za.exe
vendored
Normal file
Binary file not shown.
Reference in New Issue
Block a user