Browse Source

Mostly documentation changes.

master
Alison Watson 11 months ago
parent
commit
a0d3b5f3c4
  1. 8
      Cargo.lock
  2. 4
      Cargo.toml
  3. 68
      bl/main.rs
  4. 6
      fw/conf.rs
  5. 2
      fw/data.rs
  6. 5
      fw/data/color.rs
  7. 1
      fw/data/deflate.rs
  8. 68
      fw/data/image.rs
  9. 18
      fw/data/model.rs
  10. 46
      fw/data/read.rs
  11. 32
      fw/data/shader.rs
  12. 16
      fw/data/text.rs
  13. 6
      fw/data/uniforms.rs
  14. 10
      fw/data/vertex.rs
  15. 33
      fw/data/vfs.rs
  16. 10
      fw/data/vfs/phy.rs
  17. 10
      fw/data/vfs/sub.rs
  18. 2
      fw/ffi.rs
  19. 4
      fw/hal/ctx.rs
  20. 16
      fw/hal/evt.rs
  21. 74
      fw/hal/sdl.rs
  22. 7
      fw/hal/win.rs
  23. 18
      fw/iter.rs
  24. 1
      fw/lib.rs
  25. 7
      fw/meta.rs
  26. 39
      fw/render.rs
  27. 10
      fw/render/buffer.rs
  28. 2
      fw/render/model.rs
  29. 10
      fw/render/shader.rs
  30. 2
      fw/render/texture.rs
  31. 7
      fw/types.rs
  32. 8
      fw/vire/rt/function.rs
  33. 15
      ma/lib.rs

8
Cargo.lock generated

@ -28,10 +28,10 @@ name = "blonkus"
version = "0.1.0"
dependencies = [
"ash",
"bitflags",
"blonkus-ma",
"cc",
"easy-cast",
"flagset",
"glam",
"half",
"seahash",
@ -69,6 +69,12 @@ version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4bd102ee8c418348759919b83b81cdbdc933ffe29740b903df448b4bafaa348e"
[[package]]
name = "flagset"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1207393e01e20804589a3fc9781c9df2a70687cd81362ca58e33b2a726ec83cf"
[[package]]
name = "glam"
version = "0.13.1"

4
Cargo.toml

@ -20,11 +20,11 @@ build = "fw/build.rs"
blonkus-ma = { path = "ma" }
# types:
# - bitflags for FFI usage
# - flagset for FFI usage
# - smallvec for potentially small dynamic arrays
# - smol_str for potentially small immutable strings
# - thiserror for implementing error types
bitflags = "~1.2"
flagset = "~0.4"
smallvec = { version = "~1.6", features = ["const_generics", "union"] }
smol_str = "~0.1"
thiserror = "~1.0"

68
bl/main.rs

@ -2,72 +2,26 @@
use blonkus_fw as fw;
fn entry(_conf: &fw::conf::Conf) -> Result<(), Box<dyn std::error::Error>> {
fn entry(conf: &fw::conf::Conf) -> Result<(), Box<dyn std::error::Error>> {
let mut vfs = fw::data::vfs::Vfs::default();
vfs.add_path("testres")?;
eprintln!("{:#?}", vfs);
//let start_time = std::time::Instant::now();
/*
let mut vfs = data::vfs::Vfs::default();
vfs.add_arc(data::vfs::Arc::read_path("testres".as_ref())?);
*/
//blonkus_fw::vire::rt::Rt::new()?;
/*
let hal = hal::ctx::Context::new()?;
let window = hal::win::Window::new(&hal, meta::ffi::NAME, 640, 480)?;
let mut ren = render::Renderer::new(
&window,
&conf.render,
&[
data::shader::Module::read(
vfs.get("shaders/main.vert.o.gz")?.data(),
data::shader::Stage::Vertex,
"main",
),
data::shader::Module::read(
vfs.get("shaders/main.frag.o.gz")?.data(),
data::shader::Stage::Fragment,
"main",
),
],
)?;
/*
let img = {
let arc = data::vfs::Arc::read_tar(
&mut vfs.get("scientist/hltex000.texture")?.data(),
)?;
let img = data::image::MipImage::read(&*arc)?;
Image::from_indep(IndepImage::create(&cmd_pool, &img)?)
};
let img_view = ImageView::create(img)?;
let img_sampler = Sampler::create(device.clone(), &conf.render)?;
let model = data::model::Model::read(&mut Cursor::new(
vfs.get("scientist/scientist.iqm")?.data(),
))?;
let model = Model::create(&cmd_pool, model.0, model.1)?;
*/
let hal = fw::hal::ctx::Context::new()?;
let win = fw::hal::win::Window::new(&hal, fw::c_str!("BLONKUS"), 640, 480)?;
let ren = fw::render::Renderer::new(&win, &conf.render);
'main_loop: loop {
// FIXME: can remove allow once this has more events
#[allow(clippy::never_loop)]
for event in hal::evt::EventIterator {
for event in fw::hal::evt::EventIterator::new(&hal) {
match event {
| hal::evt::Event::Quit => break 'main_loop,
| fw::hal::evt::Event::Quit => {
break 'main_loop;
}
| _ => {}
}
}
ren.draw_frame()?;
//ren.draw_frame()?;
}
*/
Ok(())
}
@ -75,7 +29,7 @@ fn entry(_conf: &fw::conf::Conf) -> Result<(), Box<dyn std::error::Error>> {
fn main() {
let conf = fw::conf::Conf::read("blonkus.toml").unwrap_or_else(|err| {
match err {
| fw::conf::ErrConfLoad::NoFile => {
| fw::conf::Err::NoFile => {
println!("{}", err)
}
| _ => eprintln!("{}", err),

6
fw/conf.rs

@ -5,7 +5,7 @@ pub struct Conf {
}
#[derive(thiserror::Error, Debug)]
pub enum ErrConfLoad {
pub enum Err {
#[error("No existing configuration file")]
NoFile,
#[error("Couldn't open configuration file `{0}'")]
@ -14,7 +14,7 @@ pub enum ErrConfLoad {
Parse(#[from] toml::de::Error),
}
impl From<std::io::Error> for ErrConfLoad {
impl From<std::io::Error> for Err {
fn from(err: std::io::Error) -> Self {
match err.kind() {
| std::io::ErrorKind::NotFound => Self::NoFile,
@ -24,7 +24,7 @@ impl From<std::io::Error> for ErrConfLoad {
}
impl Conf {
pub fn read(path: &'static str) -> Result<Self, ErrConfLoad> {
pub fn read(path: &'static str) -> Result<Self, Err> {
Ok(toml::from_str(&std::fs::read_to_string(path)?)?)
}
}

2
fw/data.rs

@ -1,3 +1,5 @@
//! Functionality representing and supporting external storage formats.
pub mod color;
pub mod deflate;
pub mod image;

5
fw/data/color.rs

@ -1,5 +1,8 @@
//! Portable color types.
/// A four-channel 8-bit color with a packed C layout.
#[repr(C, packed)]
pub struct Color {
pub struct Rgba8888 {
pub r: u8,
pub g: u8,
pub b: u8,

1
fw/data/deflate.rs

@ -9,6 +9,7 @@ use std::cmp::Ordering;
type AlphabetTable = StkVec<[u16; 320]>;
/// The error type which is returned from reading a DEFLATE bitstream.
#[derive(thiserror::Error, Debug)]
pub enum Err {
#[error("Bad stream block type")]

68
fw/data/image.rs

@ -1,12 +1,15 @@
//! Portable image types.
use crate::{
data::{color::Color, read, vfs},
data::{color::Rgba8888, read, vfs},
iter::MaybeRev,
};
use std::io::{self, Read};
/// The error type which is returned from reading an image.
#[derive(thiserror::Error, Debug)]
#[non_exhaustive]
pub enum ErrImageRead {
pub enum Err {
#[error("Bad color encoding in texture")]
Encoding,
#[error("No first mip level in texture")]
@ -15,22 +18,25 @@ pub enum ErrImageRead {
Io(#[from] io::Error),
}
/// A two-dimensional RGBA8888 (LDR) image.
pub struct Image {
data: Vec<Color>,
data: Vec<Rgba8888>,
width: usize,
heigh: usize,
}
/// A set of [`Image`]s with mip-levels.
pub struct MipImage {
datum: Vec<Image>,
data: Vec<Image>,
width: usize,
heigh: usize,
}
impl Image {
pub fn get(&self, x: usize, y: usize) -> Option<&Color> {
/// Returns the color at the pixel `(x, y)`.
pub fn get(&self, x: usize, y: usize) -> Option<&Rgba8888> {
if x < self.width && y < self.heigh {
self.data.get(y * self.width + x)
} else {
@ -38,35 +44,38 @@ impl Image {
}
}
pub fn data(&self) -> &[Color] {
/// Returns a slice into the raw image data.
pub fn data(&self) -> &[Rgba8888] {
&self.data
}
/// Returns the width of the image.
pub const fn w(&self) -> usize {
self.width
}
/// Returns the height of the image.
pub const fn h(&self) -> usize {
self.heigh
}
/// Creates an [`Image`] with a basic XOR texture in the specified
/// dimensions.
pub fn xor_texture(width: usize, heigh: usize) -> Self {
let mut data = Vec::with_capacity(width * heigh);
for x in 0..width {
for y in 0..heigh {
let c = x as u8 ^ y as u8;
data.push(Color { r: c, g: c, b: c, a: u8::MAX });
data.push(Rgba8888 { r: c, g: c, b: c, a: u8::MAX });
}
}
Self { data, width, heigh }
}
pub fn read<R>(rd: &mut R) -> Result<Self, ErrImageRead>
where
R: Read,
{
/// Creates an [`Image`] by reading a TARGA format stream.
pub fn read(rd: &mut impl Read) -> Result<Self, Err> {
let mut head = [0; 18];
rd.read_exact(&mut head)?;
@ -74,7 +83,7 @@ impl Image {
let alpha = match head[16] {
| 24 => false,
| 32 => true,
| _ => return Err(ErrImageRead::Encoding),
| _ => return Err(Err::Encoding),
};
let descr = head[17];
@ -85,7 +94,7 @@ impl Image {
|| (!alpha && descr & 0xF != 0)
|| descr & 0xC0 != 0
{
return Err(ErrImageRead::Encoding);
return Err(Err::Encoding);
}
// compile size info
@ -112,9 +121,9 @@ impl Image {
for line in MaybeRev::rev_if(cdat.chunks(wscan), from_bot) {
for color in MaybeRev::rev_if(line.chunks(comps), !from_lft) {
data.push(if alpha {
Color { r: color[2], g: color[1], b: color[0], a: color[3] }
Rgba8888 { r: color[2], g: color[1], b: color[0], a: color[3] }
} else {
Color { r: color[2], g: color[1], b: color[0], a: u8::MAX }
Rgba8888 { r: color[2], g: color[1], b: color[0], a: u8::MAX }
});
}
}
@ -124,32 +133,39 @@ impl Image {
}
impl MipImage {
/// Returns the specified mip level's [`Image`].
pub fn get(&self, level: usize) -> Option<&Image> {
self.datum.get(level)
self.data.get(level)
}
/// Returns a slice with all of the mip levels.
pub fn data(&self) -> &[Image] {
&self.datum
&self.data
}
/// Returns the level 0 image's width.
pub const fn w(&self) -> usize {
self.width
}
/// Returns the level 0 image's height.
pub const fn h(&self) -> usize {
self.heigh
}
/// Returns the number of images.
pub fn levels(&self) -> usize {
self.datum.len()
self.data.len()
}
/// Returns `true` if there are no mip levels in this set.
pub fn is_empty(&self) -> bool {
self.datum.is_empty()
self.data.is_empty()
}
pub fn read(vfs: &vfs::Vfs) -> Result<Self, ErrImageRead> {
let mut datum = Vec::new();
/// Reads a mip-mapped image collection from a [`vfs::Vfs`].
pub fn read(vfs: &vfs::Vfs) -> Result<Self, Err> {
let mut data = Vec::new();
let mut width = 0;
let mut heigh = 0;
@ -163,21 +179,21 @@ impl MipImage {
heigh = img.h();
}
datum.push(img);
data.push(img);
i += 1;
}
if !datum.is_empty() {
Ok(Self { datum, width, heigh })
if !data.is_empty() {
Ok(Self { data, width, heigh })
} else {
Err(ErrImageRead::InsufficientLevels)
Err(Err::InsufficientLevels)
}
}
}
impl std::ops::Index<(usize, usize)> for Image {
type Output = Color;
type Output = Rgba8888;
fn index(&self, index: (usize, usize)) -> &Self::Output {
self.get(index.0, index.1).unwrap()

18
fw/data/model.rs

@ -1,3 +1,5 @@
//! Portable model format types.
use crate::{
data::{read, vertex::Vertex},
ffi,
@ -11,6 +13,7 @@ use std::{
str::Utf8Error,
};
/// The error type which is returned from reading a model.
#[derive(thiserror::Error, Debug)]
#[non_exhaustive]
pub enum Err {
@ -48,6 +51,7 @@ struct Joint {
inv: Mat4,
}
/// Information for an individual mesh.
pub struct Mesh {
mat: StkStr,
vtx: Range<usize>,
@ -57,7 +61,9 @@ pub struct Mesh {
/// Data to be uploaded to the GPU. Separate from Model so that it may
/// be dropped after upload.
pub struct ModelData {
/// The vertex array.
pub vtx: Vec<Vertex>,
/// The index array.
pub idx: Vec<u32>,
}
@ -128,36 +134,45 @@ fn fmt_read_nrm(fm: u32, vec: &[u8], pos: usize) -> f32 {
}
impl Mesh {
/// Returns the material name for this mesh.
pub fn get_mat(&self) -> &str {
&self.mat
}
/// Returns the first index into the vertex array for this mesh.
pub const fn vtx_beg(&self) -> usize {
self.vtx.start
}
/// Returns the last index into the vertex array for this mesh.
pub const fn vtx_end(&self) -> usize {
self.vtx.end
}
/// Returns the number of used indices in the vertex array.
pub const fn vtx_len(&self) -> usize {
self.vtx.end - self.vtx.start
}
/// Returns the first index into the indices array for this mesh.
pub const fn idx_beg(&self) -> usize {
self.idx.start
}
/// Returns the last index into the indices array for this mesh.
pub const fn idx_end(&self) -> usize {
self.idx.end
}
/// Returns the number of used indices in the index array.
pub const fn idx_len(&self) -> usize {
self.idx.end - self.idx.start
}
}
impl Model {
/// Creates a [`Model`] and [`ModelData`] by reading an
/// INTERQUAKEMODEL format stream.
pub fn read<R>(rd: &mut R) -> Result<(Self, ModelData), Err>
where
R: Read + Seek,
@ -437,10 +452,13 @@ impl Model {
))
}
/// Returns a matrix for the specified joint at the specified
/// frame.
pub fn frame(&self, joint: usize, frame: usize) -> Option<Mat4> {
Some(*self.frames.get(frame)?.get(joint)?)
}
/// Returns the number of frames of animation in this model.
pub const fn num_frames(&self) -> usize {
self.num_frms
}

46
fw/data/read.rs

@ -1,38 +1,49 @@
//! Primitive data reading functions.
use half::f16;
use std::io::{self, Read};
/// Reads an [`i8`] from a [`&[u8]`][slice].
pub const fn i8x(b: &[u8], p: usize) -> i8 {
i8::from_ne_bytes([b[p]])
}
/// Reads a [`u8`] from a [`&[u8]`][slice].
pub const fn u8x(b: &[u8], p: usize) -> u8 {
b[p]
}
/// Reads an [`i16`] in little-endian order from a [`&[u8]`][slice].
pub const fn i16le(b: &[u8], p: usize) -> i16 {
i16::from_le_bytes([b[p], b[p + 1]])
}
/// Reads a [`u16`] in little-endian order from a [`&[u8]`][slice].
pub const fn u16le(b: &[u8], p: usize) -> u16 {
u16::from_le_bytes([b[p], b[p + 1]])
}
/// Reads an [`i32`] in little-endian order from a [`&[u8]`][slice].
pub const fn i32le(b: &[u8], p: usize) -> i32 {
i32::from_le_bytes([b[p], b[p + 1], b[p + 2], b[p + 3]])
}
/// Reads a [`u32`] in little-endian order from a [`&[u8]`][slice].
pub const fn u32le(b: &[u8], p: usize) -> u32 {
u32::from_le_bytes([b[p], b[p + 1], b[p + 2], b[p + 3]])
}
/// Reads an [`f16`] in little-endian order from a [`&[u8]`][slice].
pub fn f16le(b: &[u8], p: usize) -> f16 {
f16::from_le_bytes([b[p], b[p + 1]])
}
/// Reads an [`f32`] in little-endian order from a [`&[u8]`][slice].
pub fn f32le(b: &[u8], p: usize) -> f32 {
f32::from_le_bytes([b[p], b[p + 1], b[p + 2], b[p + 3]])
}
/// Reads an [`f64`] in little-endian order from a [`&[u8]`][slice].
pub fn f64le(b: &[u8], p: usize) -> f64 {
f64::from_le_bytes([
b[p],
@ -46,6 +57,9 @@ pub fn f64le(b: &[u8], p: usize) -> f64 {
])
}
/// Reads a sequence of `N` `step`-sized chunks using `v` as a buffer
/// for output and `f` as a mapping function, beginning at `beg` in
/// `b`.
pub fn array<T, const N: usize>(
f: impl Fn(&[u8], usize) -> T, b: &[u8], mut v: [T; N], step: usize,
beg: usize,
@ -57,6 +71,7 @@ pub fn array<T, const N: usize>(
v
}
/// Reads exactly `size` bytes from `rd`.
pub fn hunk(rd: &mut impl Read, size: usize) -> io::Result<Vec<u8>> {
let mut data = Vec::with_capacity(size);
unsafe {
@ -70,13 +85,15 @@ pub fn hunk(rd: &mut impl Read, size: usize) -> io::Result<Vec<u8>> {
macro_rules! bits_impl {
($t:ty, $be:ident, $le:ident) => {
/// Reads `width` bits from `b` starting at bit `cr_bit` into an
/// integer, most significant bit first.
///
/// # Errors
///
/// This function will return `None` if there are not enough bits left
/// in the buffer.
#[doc = concat!(
"Reads `width` bits from `b` starting at bit `cr_bit` into one [`",
stringify!($t), "`] most significant bit first.\n",
"\n",
"# Errors\n",
"\n",
"This function will return `None` if there are not enough bits left ",
"in the buffer."
)]
#[inline]
pub const fn $be(
b: &[u8], cr_bit: usize, mut width: usize,
@ -115,12 +132,15 @@ macro_rules! bits_impl {
Some(res)
}
/// The same as `bbe*`, but least-significant bit first.
///
/// # Errors
///
/// This function will return `None` if there are not enough bits left
/// in the buffer.
#[doc = concat!(
"The same as [`", stringify!($be), "`], but least-significant bit ",
"first.\n",
"\n",
"# Errors\n",
"\n",
"This function will return [`None`] if there are not enough bits ",
"left in the buffer."
)]
#[inline]
pub const fn $le(
b: &[u8], cr_bit: usize, mut width: usize,

32
fw/data/shader.rs

@ -1,31 +1,39 @@
use super::read;
#[repr(u32)]
pub enum Stage {
Compute,
Fragment,
Geometry,
Vertex,
//! SPIR-V shaders.
flagset::flags! {
/// A flag set of shader stages.
pub enum ShaderStage {
Compute,
Fragment,
Geometry,
TessControl,
TessEvaluation,
Vertex,
}
}
impl From<ShaderStage> for ash::vk::ShaderStageFlags {
}
/// A SPIR-V IR module.
pub struct Module {
pub code: Vec<u32>,
pub size: usize,
pub stage: Stage,
pub name: String,
}
impl Module {
pub fn read(bytecode: &[u8], stage: Stage, name: &str) -> Self {
/// Reads SPIR-V IR in from a buffer.
pub fn read(bytecode: &[u8], name: &str) -> Self {
let mut code = Vec::with_capacity(bytecode.len() / 4);
for word in bytecode.chunks_exact(4) {
code.push(read::u32le(word, 0));
code.push(super::read::u32le(word, 0));
}
let size = code.len() * 4;
Self { code, size, stage, name: name.to_owned() }
Self { code, size, name: name.to_owned() }
}
}

16
fw/data/text.rs

@ -1,20 +1,28 @@
//! Text utilities.
use std::{fmt, iter::Peekable};
/// A position within a text file.
#[derive(Copy, Clone)]
pub struct Position {
name: [u8; 32],
nlen: usize,
/// The line this position points to.
pub line: usize,
/// The column this position points to.
pub colu: usize,
}
/// An iterator over a [`str`]'s characters that can also return
/// [`Position`]s.
pub struct PosReader<'a> {
itr: Peekable<std::str::Chars<'a>>,
pos: Position,
}
impl Position {
/// Returns a printable name for the source of this position.
pub fn name(&self) -> &str {
unsafe { std::str::from_utf8_unchecked(&self.name[..self.nlen]) }
}
@ -40,6 +48,7 @@ impl Iterator for PosReader<'_> {
}
impl<'a> PosReader<'a> {
/// Creates a [`PosReader`] over a [`str`] with the specified name.
pub fn new(s: &'a str, (name, nlen): ([u8; 32], usize)) -> Self {
Self {
itr: s.chars().peekable(),
@ -47,10 +56,12 @@ impl<'a> PosReader<'a> {
}
}
/// Returns the next character in the iterator if it exists.
pub fn peek(&mut self) -> Option<char> {
self.itr.peek().copied()
}
/// Returns a copy of the current [`Position`].
pub const fn pos(&self) -> Position {
self.pos
}
@ -103,8 +114,8 @@ pub fn ellipsize_small_str(inp: &str) -> ([u8; 32], usize) {
}
}
/// Converts `c` to an integer unsafely. This differs from
/// `char::to_digit` in that it may be optimized into a few
/// Converts `c` to an integer semi-safely. This differs from
/// [`char::to_digit`] in that it may be optimized into a few
/// instructions, and will convert from any base between 1 and 36.
/// This will return 0 if `c` is out of range. You will need to ensure
/// the input is correct beforehand.
@ -118,6 +129,7 @@ pub const fn radix(c: char) -> u8 {
}
}
/// Creates a displayable debug string for an arbitrary byte [slice].
pub fn disp_ascii(buf: impl AsRef<[u8]>) -> String {
use std::{ascii, iter::once};
once('"')

6
fw/data/uniforms.rs

@ -1,9 +1,15 @@
//! Uniforms for the GPU to read.
use crate::math::Mat4;
/// Matrices used by the vertex shader.
#[repr(C)]
pub struct Uniforms {
/// The *object* matrix.
pub object: Mat4,
/// The *camera* matrix.
pub camera: Mat4,
/// The *projection* matrix.
pub projec: Mat4,
}

10
fw/data/vertex.rs

@ -1,14 +1,24 @@
//! Portable vertex types.
use crate::math::{Vec3, Vec4};
/// A basic vertex.
#[repr(packed)]
#[derive(blonkus_ma::FieldInfo)]
pub struct Vertex {
/// The position.
pub pos: Vec3,
/// The texture coordinates.
pub tex: Vec3,
/// The normal.
pub nrm: Vec3,
/// The tangent.
pub tan: Vec4,
/// The bone indices.
pub idx: Vec4,
/// The bone weights.
pub wgt: Vec4,
/// The color.
pub clr: Vec4,
}

33
fw/data/vfs.rs

@ -1,3 +1,5 @@
//! Virtual file systems.
mod phy;
mod sub;
@ -12,9 +14,10 @@ use std::{
str::Utf8Error,
};
/// The error type which is returned from adding to a [`Vfs`].
#[derive(thiserror::Error, Debug)]
#[non_exhaustive]
pub enum ErrVfs {
pub enum Err {
#[error("Bad file type for `{0}'")]
FileType(FileName),
#[error("Invalid tar format")]
@ -27,9 +30,13 @@ pub enum ErrVfs {
Utf8(#[from] Utf8Error),
}
/// A portable UTF-8 file name.
pub type FileName = crate::types::StkStr;
/// A cell holding cached file data.
pub type FileData = UnsafeCell<Vec<u8>>;
/// A virtual file system. Maps names to physical files and sub-files.
#[derive(Default)]
pub struct Vfs {
files: HashMap<FileName, Box<dyn File>>,
@ -41,7 +48,9 @@ impl fmt::Debug for Vfs {
}
}
/// A trait for cacheable files.
pub trait File {
/// Returns a slice to the file data, safely.
fn data(&self) -> &[u8] {
unsafe {
let buf = self.buffer().get().as_mut().unwrap();
@ -60,23 +69,37 @@ pub trait File {
}
}
/// Returns [`File::data()`] as text.
fn text(&self) -> Result<&str, Utf8Error> {
std::str::from_utf8(self.data())
}
fn load(&self) -> Vec<u8>;
fn buffer(&self) -> &FileData;
/// Loads in a buffer from the file's data to be cached.
///
/// # Safety
///
/// This function is unsafe for general use and may return invalid
/// data when called directly.
unsafe fn load(&self) -> Vec<u8>;
/// Returns a reference to the file data cache cell.
///
/// # Safety
///
/// This function is unsafe for general use and may return invalid
/// data when called directly.
unsafe fn buffer(&self) -> &FileData;
}
impl Vfs {
pub fn add_path(&mut self, path: impl AsRef<Path>) -> Result<(), ErrVfs> {
pub fn add_path(&mut self, path: impl AsRef<Path>) -> Result<(), Err> {
let path = path.as_ref();
if path.is_dir() {
self.add_dir(path)
} else if path.is_file() {
self.add_tar(fs::File::open(path)?)
} else {
Err(ErrVfs::FileType(FileName::new(path.to_string_lossy())))
Err(Err::FileType(FileName::new(path.to_string_lossy())))
}
}

10
fw/data/vfs/phy.rs

@ -6,31 +6,31 @@ struct FilePhy {
}
impl File for FilePhy {
fn load(&self) -> Vec<u8> {
unsafe fn load(&self) -> Vec<u8> {
fs::read(&self.path).unwrap_or_else(|_| Vec::new())
}
fn buffer(&self) -> &FileData {
unsafe fn buffer(&self) -> &FileData {
&self.data
}
}
impl Vfs {
pub fn add_dir(&mut self, path: impl AsRef<Path>) -> Result<(), ErrVfs> {
pub fn add_dir(&mut self, path: impl AsRef<Path>) -> Result<(), Err> {
fn path_to_local(top_path: &Path, path: &Path) -> FileName {
FileName::new(path.strip_prefix(top_path).unwrap().to_string_lossy())
}
fn recurse(
top_path: &Path, cur_path: &Path, vfs: &mut Vfs,
) -> Result<(), ErrVfs> {
) -> Result<(), Err> {
for ent in fs::read_dir(cur_path)? {
let path = ent?.path();
if path.is_dir() {
recurse(top_path, &path, vfs)?;
} else if fs::read_link(&path).is_ok() {
return Err(ErrVfs::FileType(path_to_local(top_path, &path)));
return Err(Err::FileType(path_to_local(top_path, &path)));
} else {
let name = path_to_local(top_path, &path);
vfs.files.insert(

10
fw/data/vfs/sub.rs

@ -7,7 +7,7 @@ struct FileSub<R: Read + Seek> {
}
impl<R: Read + Seek> File for FileSub<R> {
fn load(&self) -> Vec<u8> {
unsafe fn load(&self) -> Vec<u8> {
let rd = unsafe { &mut *self.read.get() };
if rd.seek(io::SeekFrom::Start(self.area.0)).is_ok() {
let mut v = Vec::new();
@ -18,7 +18,7 @@ impl<R: Read + Seek> File for FileSub<R> {
Vec::new()
}
fn buffer(&self) -> &FileData {
unsafe fn buffer(&self) -> &FileData {
&self.data
}
}
@ -26,7 +26,7 @@ impl<R: Read + Seek> File for FileSub<R> {
impl Vfs {
pub fn add_tar<R: 'static + Read + Seek>(
&mut self, rd: R,
) -> Result<(), ErrVfs> {
) -> Result<(), Err> {
enum FileType {
Skip,
File,
@ -88,7 +88,7 @@ impl Vfs {
FileType::File
};
} else {
return Err(ErrVfs::InvalidFormat);
return Err(Err::InvalidFormat);
}
match ftyp {
@ -106,7 +106,7 @@ impl Vfs {
);
}
| FileType::Unsupported => {
return Err(ErrVfs::FileType(name));
return Err(Err::FileType(name));
}
}
}

2
fw/ffi.rs

@ -9,7 +9,7 @@ use std::{
macro_rules! c_str {
($s:expr) => {{
const S: &'static str = std::concat!($s, "\0");
S.as_ptr() as crate::ffi::Nts
S.as_ptr() as $crate::ffi::Nts
}};
}

4
fw/hal/ctx.rs

@ -1,12 +1,14 @@
use super::*;
use flagset::FlagSet;
#[non_exhaustive]
pub struct Context;
impl Context {
pub fn new() -> Result<Self, Err> {
unsafe {
sdl::set_main_ready();
if sdl::init(sdl::InitFlags::VIDEO) == 0 {
if sdl::init(FlagSet::from(sdl::InitFlags::Video).bits()) == 0 {
Ok(Self)
} else {
Err(Err::new_sdl())

16
fw/hal/evt.rs

@ -1,12 +1,22 @@
use super::*;
use std::marker::PhantomData;
pub struct EventIterator;
#[non_exhaustive]
pub enum Event {
Quit,
}
impl Iterator for EventIterator {
pub struct EventIterator<'a> {
hal: PhantomData<&'a ctx::Context>,
}
impl<'a> EventIterator<'a> {
pub fn new(_hal: &'a ctx::Context) -> Self {
Self { hal: PhantomData }
}
}
impl<'a> Iterator for EventIterator<'a> {
type Item = Event;
fn next(&mut self) -> Option<Self::Item> {

74
fw/hal/sdl.rs

@ -6,45 +6,41 @@ use std::os::raw;
pub const WINDOW_POS_UNDEF: raw::c_int = 0x1FFF0000;
bitflags::bitflags! {
#[repr(transparent)]
pub struct InitFlags: u32 {
const TIMER = 0x01;
const AUDIO = 0x10;
const VIDEO = 0x20;
const JOYSTICK = 0x200;
const HAPTIC = 0x1000;
const GAME_CONTROLLER = 0x2000;
const EVENTS = 0x4000;
const SENSOR = 0x8000;
flagset::flags! {
pub enum InitFlags: u32 {
Timer = 0x01,
Audio = 0x10,
Video = 0x20,
Joystick = 0x200,
Haptic = 0x1000,
GameController = 0x2000,
Events = 0x4000,
Sensor = 0x8000,
}
}
bitflags::bitflags! {
#[repr(transparent)]
pub struct WindowFlags: u32 {
const FULLSCREEN = 0x00000001;
const OPENGL = 0x00000002;
const SHOWN = 0x00000004;
const HIDDEN = 0x00000008;
const BORDERLESS = 0x00000010;
const RESIZABLE = 0x00000020;
const MINIMIZED = 0x00000040;
const MAXIMIZED = 0x00000080;
const INPUT_GRABBED = 0x00000100;
const INPUT_FOCUS = 0x00000200;
const MOUSE_FOCUS = 0x00000400;
const FULLSCREEN_DESKTOP = Self::FULLSCREEN.bits | 0x00001000;
const FOREIGN = 0x00000800;
const ALLOW_HIGH_DPI = 0x00002000;
const MOUSE_CAPTURE = 0x00004000;
const ALWAYS_ON_TOP = 0x00008000;
const SKIP_TASKBAR = 0x00010000;
const UTILITY = 0x00020000;
const TOOLTIP = 0x00040000;
const POPUP_MENU = 0x00080000;
const VULKAN = 0x10000000;
const METAL = 0x20000000;
pub enum WindowFlags: u32 {
Fullscreen = 0x00000001,
OpenGl = 0x00000002,
Shown = 0x00000004,
Hidden = 0x00000008,
Borderless = 0x00000010,
Resizable = 0x00000020,
Minimized = 0x00000040,
Maximized = 0x00000080,
InputGrabbed = 0x00000100,
InputFocus = 0x00000200,
MouseFocus = 0x00000400,
Foreign = 0x00000800,
FullscreenDesktop = 0x00001000,
AllowHighDpi = 0x00002000,
MouseCapture = 0x00004000,
AlwaysOnTop = 0x00008000,
SkipTaskbar = 0x00010000,
Utility = 0x00020000,
Tooltip = 0x00040000,
PopupMenu = 0x00080000,
Vulkan = 0x10000000,
Metal = 0x20000000,
}
}
@ -145,7 +141,7 @@ extern "C" {
pub fn set_main_ready();
#[link_name = "SDL_Init"]
pub fn init(flags: InitFlags) -> raw::c_int;
pub fn init(flags: u32) -> raw::c_int;
#[link_name = "SDL_Quit"]
pub fn quit();
@ -162,7 +158,7 @@ extern "C" {
#[link_name = "SDL_CreateWindow"]
pub fn create_window(
title: Nts, x: raw::c_int, y: raw::c_int, w: raw::c_int, h: raw::c_int,
flags: WindowFlags,
flags: u32,
) -> *mut Window;
#[link_name = "SDL_DestroyWindow"]

7
fw/hal/win.rs

@ -19,9 +19,10 @@ impl<'a> Window<'a> {
sdl::WINDOW_POS_UNDEF,
w.into(),
h.into(),
sdl::WindowFlags::SHOWN
| sdl::WindowFlags::VULKAN
| sdl::WindowFlags::RESIZABLE,
(sdl::WindowFlags::Shown
| sdl::WindowFlags::Vulkan
| sdl::WindowFlags::Resizable)
.bits(),
);
if !handle.is_null() {
Ok(Self { handle, hal: PhantomData })

18
fw/iter.rs

@ -4,28 +4,28 @@ macro_rules! coll {
IntoIterator::into_iter($it).map($xp).collect::<$t>()
};
(<$t:ty> $xp:expr; $sz:expr) => {
crate::coll![<$t> (0..$sz), |_| $xp]
$crate::coll![<$t> (0..$sz), |_| $xp]
};
}
#[macro_export]
macro_rules! vec_r {
($it:expr, $xp:expr) => {crate::coll![<Result<Vec<_>, _>> $it, $xp]};
($xp:expr; $sz:expr) => {crate::coll![<Result<Vec<_>, _>> $xp; $sz]};
($it:expr, $xp:expr) => {$crate::coll![<Result<Vec<_>, _>> $it, $xp]};
($xp:expr; $sz:expr) => {$crate::coll![<Result<Vec<_>, _>> $xp; $sz]};
}
#[macro_export]
macro_rules! vec_e {
($it:expr, $xp:expr) => {crate::coll![<Vec<_>> $it, $xp]};
($xp:expr; $sz:expr) => {crate::coll![<Vec<_>> $xp; $sz]};
($it:expr, $xp:expr) => {$crate::coll![<Vec<_>> $it, $xp]};
($xp:expr; $sz:expr) => {$crate::coll![<Vec<_>> $xp; $sz]};
}
#[macro_export]
macro_rules! stkvec_r {
(<$t:ty> $it:expr, $xp:expr) => {crate::coll![<Result<StkVec<$t>, _>> $it, $xp]};
(<$t:ty> $xp:expr; $sz:expr) => {crate::coll![<Result<StkVec<$t>, _>> $xp; $sz]};
($it:expr, $xp:expr) => {crate::coll![<Result<StkVec<_>, _>> $it, $xp]};
($xp:expr; $sz:expr) => {crate::coll![<Result<StkVec<_>, _>> $xp; $sz]};
(<$t:ty> $it:expr, $xp:expr) => {$crate::coll![<Result<StkVec<$t>, _>> $it, $xp]};
(<$t:ty> $xp:expr; $sz:expr) => {$crate::coll![<Result<StkVec<$t>, _>> $xp; $sz]};
($it:expr, $xp:expr) => {$crate::coll![<Result<StkVec<_>, _>> $it, $xp]};
($xp:expr; $sz:expr) => {$crate::coll![<Result<StkVec<_>, _>> $xp; $sz]};
}
macro_rules! zips {

1
fw/lib.rs

@ -13,6 +13,7 @@
#![deny(unsafe_op_in_unsafe_fn)]
#![deny(unused_import_braces)]
#![deny(unused_qualifications)]
#![warn(clippy::missing_const_for_fn)]
#![allow(clippy::precedence)]
#![cfg_attr(test, allow(dead_code))]

7
fw/meta.rs

@ -4,10 +4,13 @@ macro_rules! meta_str {
($($(#[$outer:meta])* $name:ident = $e:expr;)*) => {
$($(#[$outer])* pub const $name: &'static str = $e;)*
/// FFI versions of [`crate::meta`].
/// FFI versions of [`meta`][crate::meta].
pub mod ffi {
$(
#[doc = concat!("FFI version of [`crate::meta::", stringify!($name) , "`]")]
#[doc = concat!(
"FFI version of [`meta::", stringify!($name),
"`][crate::meta::", stringify!($name), "]."
)]
pub const $name: crate::ffi::Nts = crate::c_str!($e);
)*
}

39
fw/render.rs

@ -134,7 +134,7 @@ pub struct Renderer {
#[derive(thiserror::Error, Debug)]
#[non_exhaustive]
pub enum ErrRenderer {
pub enum Err {
// vulkan errors
#[error(transparent)]
Vk(#[from] vk::Result),
@ -164,8 +164,9 @@ pub enum ErrRenderer {
impl StaticData {
unsafe fn new(
window: &Window, conf: &Conf, shaders: &[data::shader::Module],
) -> Result<Self, ErrRenderer> {
window: &Window, conf: &Conf,
shaders: &[(data::shader::Module, vk::ShaderStageFlags)],
) -> Result<Self, Err> {
let ent = unsafe { ash::Entry::new()? };