Compare commits
No commits in common. "fd94cd670150642a7d61803d005339e0916a39d0" and "5279eeb7d45bf5c8857a365f09f1a93f67918722" have entirely different histories.
fd94cd6701
...
5279eeb7d4
2
assets
2
assets
|
@ -1 +1 @@
|
||||||
Subproject commit 45f65b6a639f3e59d9d1db2a4cf452fe406bd4b2
|
Subproject commit 66b7aab8af273cac9b805d813f2e5cb70a920000
|
|
@ -3,26 +3,11 @@
|
||||||
name = "12 Autumn above"
|
name = "12 Autumn above"
|
||||||
|
|
||||||
[object.star]
|
[object.star]
|
||||||
sprite = "star::star"
|
sprite = "star::a0"
|
||||||
position = [0.0, 0.0]
|
center = [0.0, 0.0]
|
||||||
size = 1000
|
|
||||||
parallax = 20.0
|
|
||||||
|
|
||||||
|
|
||||||
[object.earth]
|
[object.earth]
|
||||||
sprite = "planet::earth"
|
sprite = "planet::earth"
|
||||||
position.center = "star"
|
center = "star"
|
||||||
position.radius = 4000
|
radius = 200
|
||||||
position.angle = 0
|
angle = 14
|
||||||
size = 1000
|
|
||||||
parallax = 10.0
|
|
||||||
|
|
||||||
|
|
||||||
[object.luna]
|
|
||||||
sprite = "planet::luna"
|
|
||||||
position.center = "earth"
|
|
||||||
position.radius = 1600
|
|
||||||
position.angle = 135
|
|
||||||
size = 500
|
|
||||||
angle = -45
|
|
||||||
parallax = 7.8
|
|
||||||
|
|
|
@ -1,25 +1,24 @@
|
||||||
use anyhow::{Context, Result};
|
use anyhow::Result;
|
||||||
use std::path::PathBuf;
|
|
||||||
|
|
||||||
use super::{syntax, ContentType};
|
use super::{syntax, ContentType};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Content {
|
pub struct Content {
|
||||||
pub systems: Vec<syntax::system::System>,
|
systems: Vec<syntax::System>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Content {
|
impl Content {
|
||||||
pub fn new(cv: Vec<(PathBuf, ContentType)>) -> Result<Self> {
|
pub fn new(cv: Vec<ContentType>) -> Result<Self> {
|
||||||
let mut content = Self {
|
let mut content = Self {
|
||||||
systems: Vec::new(),
|
systems: Vec::new(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// TODO: locate bad files
|
||||||
|
|
||||||
// These methods check intra-file consistency
|
// These methods check intra-file consistency
|
||||||
for (p, c) in cv {
|
for c in cv {
|
||||||
match c {
|
match c {
|
||||||
ContentType::System(v) => content
|
ContentType::System(v) => content.add_system(v)?,
|
||||||
.add_system(v)
|
|
||||||
.with_context(|| format!("Could not parse {}", p.display()))?,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,7 +26,7 @@ impl Content {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_system(&mut self, toml: syntax::system::toml::SystemRoot) -> Result<()> {
|
fn add_system(&mut self, toml: syntax::system::toml::SystemRoot) -> Result<()> {
|
||||||
self.systems.push(syntax::system::System::parse(toml)?);
|
self.systems.push(syntax::System::parse(toml)?);
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use anyhow::{bail, Result};
|
use anyhow::Result;
|
||||||
use std::{fs::File, io::Read, path::Path};
|
use std::{fs::File, io::Read, path::Path};
|
||||||
|
|
||||||
use super::syntax;
|
use super::syntax;
|
||||||
|
@ -12,21 +12,12 @@ pub enum ContentType {
|
||||||
impl ContentType {
|
impl ContentType {
|
||||||
pub fn try_parse(file_string: &str) -> Result<Option<Self>> {
|
pub fn try_parse(file_string: &str) -> Result<Option<Self>> {
|
||||||
// TODO: More advanced parsing, read the whole top comment
|
// TODO: More advanced parsing, read the whole top comment
|
||||||
let first = match file_string.split_once("\n") {
|
let (first, _) = file_string.split_once("\n").unwrap();
|
||||||
None => bail!("This file is empty."),
|
|
||||||
Some((first, _)) => first,
|
|
||||||
};
|
|
||||||
let type_spec = first[1..].trim(); // Remove hash
|
let type_spec = first[1..].trim(); // Remove hash
|
||||||
|
|
||||||
let type_spec = if type_spec.starts_with("content type: ") {
|
return Ok(match type_spec {
|
||||||
type_spec[14..].to_owned()
|
"content type: system" => Some(Self::System(toml::from_str(&file_string)?)),
|
||||||
} else {
|
_ => None,
|
||||||
bail!("No content type specified")
|
|
||||||
};
|
|
||||||
|
|
||||||
return Ok(match &type_spec[..] {
|
|
||||||
"system" => Some(Self::System(toml::from_str(&file_string)?)),
|
|
||||||
_ => bail!("Invalid content type `{}`", type_spec),
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,38 +4,3 @@ mod syntax;
|
||||||
|
|
||||||
pub use content::Content;
|
pub use content::Content;
|
||||||
pub use contenttype::ContentType;
|
pub use contenttype::ContentType;
|
||||||
pub use syntax::system;
|
|
||||||
|
|
||||||
use anyhow::{Context, Result};
|
|
||||||
use walkdir::WalkDir;
|
|
||||||
|
|
||||||
pub fn load_content_dir(path: &str) -> Result<Content> {
|
|
||||||
let mut raw_content = Vec::new();
|
|
||||||
for e in WalkDir::new(path).into_iter().filter_map(|e| e.ok()) {
|
|
||||||
if e.metadata().unwrap().is_file() {
|
|
||||||
// TODO: better warnings
|
|
||||||
match e.path().extension() {
|
|
||||||
Some(t) => {
|
|
||||||
if t.to_str() != Some("toml") {
|
|
||||||
println!("[WARNING] {e:#?} is not a toml file, skipping.");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
println!("[WARNING] {e:#?} is not a toml file, skipping.");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let c = crate::content::ContentType::from_path(e.path())
|
|
||||||
.with_context(|| format!("Could not load {:#?}", e.path()))?;
|
|
||||||
|
|
||||||
match c {
|
|
||||||
Some(c) => raw_content.push((e.path().to_path_buf(), c)),
|
|
||||||
None => continue,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return crate::content::Content::new(raw_content);
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,2 +1,3 @@
|
||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
pub mod system;
|
pub mod system;
|
||||||
|
pub use system::System;
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
use anyhow::{bail, Context, Result};
|
use anyhow::{bail, Result};
|
||||||
use cgmath::{Deg, Point2};
|
use cgmath::Point2;
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use crate::physics::{Pfloat, Polar};
|
use crate::physics::Pfloat;
|
||||||
|
|
||||||
/// Toml file syntax
|
/// Toml file syntax
|
||||||
pub(in crate::content) mod toml {
|
pub(in crate::content) mod toml {
|
||||||
|
@ -24,106 +24,43 @@ pub(in crate::content) mod toml {
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
pub struct Object {
|
pub struct Object {
|
||||||
pub sprite: String,
|
pub sprite: String,
|
||||||
pub position: Position,
|
pub center: Center,
|
||||||
|
|
||||||
pub size: Pfloat,
|
#[serde(default)]
|
||||||
pub parallax: Pfloat,
|
|
||||||
|
|
||||||
pub radius: Option<Pfloat>,
|
|
||||||
pub angle: Option<Pfloat>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
|
||||||
#[serde(untagged)]
|
|
||||||
pub enum Position {
|
|
||||||
Polar(PolarCoords),
|
|
||||||
Cartesian(Coordinates),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
|
||||||
pub struct PolarCoords {
|
|
||||||
pub center: Coordinates,
|
|
||||||
pub radius: Pfloat,
|
pub radius: Pfloat,
|
||||||
|
#[serde(default)]
|
||||||
pub angle: Pfloat,
|
pub angle: Pfloat,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
#[serde(untagged)]
|
#[serde(untagged)]
|
||||||
pub enum Coordinates {
|
pub enum Center {
|
||||||
Label(String),
|
Label(String),
|
||||||
Coords([Pfloat; 2]),
|
Coords([Pfloat; 2]),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToString for Coordinates {
|
|
||||||
fn to_string(&self) -> String {
|
|
||||||
match self {
|
|
||||||
Self::Label(s) => s.to_owned(),
|
|
||||||
Self::Coords(v) => format!("{:?}", v),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct System {
|
pub struct System {
|
||||||
pub name: String,
|
name: String,
|
||||||
pub objects: Vec<Object>,
|
objects: Vec<Object>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Object {
|
struct Object {
|
||||||
pub sprite: String,
|
sprite: String,
|
||||||
pub position: Point2<f32>,
|
center: Point2<Pfloat>,
|
||||||
pub size: Pfloat,
|
radius: Pfloat,
|
||||||
pub parallax: Pfloat,
|
angle: Pfloat,
|
||||||
pub angle: Deg<Pfloat>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolve_coordinates(
|
fn resolve_center(
|
||||||
objects: &HashMap<String, toml::Object>,
|
|
||||||
cor: &toml::Coordinates,
|
|
||||||
mut cycle_detector: HashSet<String>,
|
|
||||||
) -> Result<Point2<f32>> {
|
|
||||||
match cor {
|
|
||||||
toml::Coordinates::Coords(c) => Ok((*c).into()),
|
|
||||||
toml::Coordinates::Label(l) => {
|
|
||||||
if cycle_detector.contains(l) {
|
|
||||||
bail!(
|
|
||||||
"Found coordinate cycle: `{}`",
|
|
||||||
cycle_detector.iter().fold(String::new(), |sum, a| {
|
|
||||||
if sum.is_empty() {
|
|
||||||
a.to_string()
|
|
||||||
} else {
|
|
||||||
sum + " -> " + a
|
|
||||||
}
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
cycle_detector.insert(l.to_owned());
|
|
||||||
|
|
||||||
let p = match objects.get(l) {
|
|
||||||
Some(p) => p,
|
|
||||||
None => bail!("Could not resolve coordinate label `{l}`"),
|
|
||||||
};
|
|
||||||
Ok(resolve_position(&objects, &p, cycle_detector)
|
|
||||||
.with_context(|| format!("In object {:#?}", l))?)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn resolve_position(
|
|
||||||
objects: &HashMap<String, toml::Object>,
|
objects: &HashMap<String, toml::Object>,
|
||||||
obj: &toml::Object,
|
obj: &toml::Object,
|
||||||
cycle_detector: HashSet<String>,
|
) -> Option<Point2<f32>> {
|
||||||
) -> Result<Point2<f32>> {
|
match &obj.center {
|
||||||
match &obj.position {
|
toml::Center::Label(s) => resolve_center(&objects, objects.get(s)?),
|
||||||
toml::Position::Cartesian(c) => Ok(resolve_coordinates(objects, c, cycle_detector)?),
|
toml::Center::Coords(v) => Some(Point2::from(*v)),
|
||||||
toml::Position::Polar(p) => Ok(Polar {
|
|
||||||
center: resolve_coordinates(&objects, &p.center, cycle_detector)?,
|
|
||||||
radius: p.radius,
|
|
||||||
angle: Deg(p.angle),
|
|
||||||
}
|
|
||||||
.to_cartesian()),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -131,17 +68,22 @@ impl System {
|
||||||
pub fn parse(value: toml::SystemRoot) -> Result<Self> {
|
pub fn parse(value: toml::SystemRoot) -> Result<Self> {
|
||||||
let mut objects = Vec::new();
|
let mut objects = Vec::new();
|
||||||
|
|
||||||
for (label, obj) in &value.object {
|
for (_, obj) in &value.object {
|
||||||
let mut cycle_detector = HashSet::new();
|
let center = match resolve_center(&value.object, obj) {
|
||||||
cycle_detector.insert(label.to_owned());
|
Some(v) => v,
|
||||||
|
None => {
|
||||||
|
bail!(
|
||||||
|
"Failed to parse content file: could not resolve center label `{:?}`",
|
||||||
|
obj.center
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
objects.push(Object {
|
objects.push(Object {
|
||||||
sprite: obj.sprite.clone(),
|
sprite: obj.sprite.clone(),
|
||||||
position: resolve_position(&value.object, &obj, cycle_detector)
|
center,
|
||||||
.with_context(|| format!("In object {:#?}", label))?,
|
radius: obj.radius,
|
||||||
size: obj.size,
|
angle: obj.angle,
|
||||||
parallax: obj.parallax,
|
|
||||||
angle: Deg(obj.angle.unwrap_or(0.0)),
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,18 +6,17 @@ pub struct Doodad {
|
||||||
pub sprite: SpriteTexture,
|
pub sprite: SpriteTexture,
|
||||||
pub pos: Point2<Pfloat>,
|
pub pos: Point2<Pfloat>,
|
||||||
pub parallax: Pfloat,
|
pub parallax: Pfloat,
|
||||||
pub size: Pfloat,
|
pub height: Pfloat,
|
||||||
pub angle: Deg<Pfloat>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Spriteable for Doodad {
|
impl Spriteable for Doodad {
|
||||||
fn get_sprite(&self) -> Sprite {
|
fn get_sprite(&self) -> Sprite {
|
||||||
return Sprite {
|
return Sprite {
|
||||||
texture: self.sprite.clone(),
|
texture: self.sprite.clone(),
|
||||||
scale: 1.0,
|
|
||||||
pos: self.pos,
|
pos: self.pos,
|
||||||
angle: self.angle,
|
angle: Deg { 0: 0.0 },
|
||||||
size: self.size,
|
scale: 1.0,
|
||||||
|
height: self.height,
|
||||||
parallax: self.parallax,
|
parallax: self.parallax,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
36
src/main.rs
36
src/main.rs
|
@ -8,8 +8,8 @@ mod system;
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use cgmath::{Deg, Point2};
|
use cgmath::{Deg, Point2};
|
||||||
use content::Content;
|
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
|
use walkdir::WalkDir;
|
||||||
use winit::{
|
use winit::{
|
||||||
event::{
|
event::{
|
||||||
ElementState, Event, KeyboardInput, MouseButton, MouseScrollDelta, TouchPhase,
|
ElementState, Event, KeyboardInput, MouseButton, MouseScrollDelta, TouchPhase,
|
||||||
|
@ -69,10 +69,10 @@ struct Sprite {
|
||||||
|
|
||||||
/// The size of this sprite,
|
/// The size of this sprite,
|
||||||
/// given as height in world units.
|
/// given as height in world units.
|
||||||
size: Pfloat,
|
height: Pfloat,
|
||||||
|
|
||||||
/// Scale factor.
|
/// Scale factor.
|
||||||
/// if this is 1, sprite height is exactly self.size.
|
/// if this is 1, sprite height is exactly self.height.
|
||||||
scale: Pfloat,
|
scale: Pfloat,
|
||||||
|
|
||||||
/// This sprite's rotation
|
/// This sprite's rotation
|
||||||
|
@ -95,7 +95,7 @@ struct Game {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Game {
|
impl Game {
|
||||||
fn new(ct: Content) -> Self {
|
fn new() -> Self {
|
||||||
Game {
|
Game {
|
||||||
last_update: Instant::now(),
|
last_update: Instant::now(),
|
||||||
input: InputStatus::new(),
|
input: InputStatus::new(),
|
||||||
|
@ -104,7 +104,7 @@ impl Game {
|
||||||
pos: (0.0, 0.0).into(),
|
pos: (0.0, 0.0).into(),
|
||||||
zoom: 500.0,
|
zoom: 500.0,
|
||||||
},
|
},
|
||||||
system: System::new(&ct.systems[0]),
|
system: System::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -128,11 +128,11 @@ impl Game {
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.input.key_right {
|
if self.input.key_right {
|
||||||
self.player.body.rot(Deg(35.0) * t);
|
self.player.body.rot(Deg { 0: 35.0 } * t);
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.input.key_left {
|
if self.input.key_left {
|
||||||
self.player.body.rot(Deg(-35.0) * t);
|
self.player.body.rot(Deg { 0: -35.0 } * t);
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.input.v_scroll != 0.0 {
|
if self.input.v_scroll != 0.0 {
|
||||||
|
@ -140,7 +140,6 @@ impl Game {
|
||||||
self.input.v_scroll = 0.0;
|
self.input.v_scroll = 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
println!("{:?}", self.player.body.pos);
|
|
||||||
self.player.body.tick(t);
|
self.player.body.tick(t);
|
||||||
self.camera.pos = self.player.body.pos;
|
self.camera.pos = self.player.body.pos;
|
||||||
|
|
||||||
|
@ -164,11 +163,12 @@ impl Game {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn run(mut game: Game) -> Result<()> {
|
pub async fn run() -> Result<()> {
|
||||||
let event_loop = EventLoop::new();
|
let event_loop = EventLoop::new();
|
||||||
let window = WindowBuilder::new().build(&event_loop).unwrap();
|
let window = WindowBuilder::new().build(&event_loop).unwrap();
|
||||||
|
|
||||||
let mut gpu = GPUState::new(window).await?;
|
let mut gpu = GPUState::new(window).await?;
|
||||||
|
let mut game = Game::new();
|
||||||
|
|
||||||
gpu.update_starfield_buffer(&game);
|
gpu.update_starfield_buffer(&game);
|
||||||
|
|
||||||
|
@ -231,10 +231,20 @@ async fn run(mut game: Game) -> Result<()> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() -> Result<()> {
|
fn main() -> Result<()> {
|
||||||
let content = content::load_content_dir("./content")?;
|
let mut raw_content = Vec::new();
|
||||||
println!("{:?}", content);
|
for e in WalkDir::new("content").into_iter().filter_map(|e| e.ok()) {
|
||||||
let game = Game::new(content);
|
if e.metadata().unwrap().is_file() {
|
||||||
|
let c = crate::content::ContentType::from_path(e.path())?;
|
||||||
|
match c {
|
||||||
|
Some(c) => raw_content.push(c),
|
||||||
|
None => continue,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pollster::block_on(run(game))?;
|
let a = crate::content::Content::new(raw_content)?;
|
||||||
|
println!("{:?}", a);
|
||||||
|
|
||||||
|
//pollster::block_on(run())?;
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ impl PhysBody {
|
||||||
pos,
|
pos,
|
||||||
vel: (0.0, 0.0).into(),
|
vel: (0.0, 0.0).into(),
|
||||||
mass: 0.3,
|
mass: 0.3,
|
||||||
angle: Deg(0.0),
|
angle: Deg { 0: 0.0 },
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,7 +43,9 @@ impl PhysBody {
|
||||||
|
|
||||||
// Wrap angles
|
// Wrap angles
|
||||||
if self.angle.0.abs() > 180.0 {
|
if self.angle.0.abs() > 180.0 {
|
||||||
self.angle -= Deg(self.angle.0.signum() * 360.0);
|
self.angle -= Deg {
|
||||||
|
0: self.angle.0.signum() * 360.0,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use super::Pfloat;
|
use super::Pfloat;
|
||||||
use cgmath::{Angle, Deg, Point2, Vector2};
|
use cgmath::{Angle, Deg, EuclideanSpace, Point2};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub struct Polar {
|
pub struct Polar {
|
||||||
|
@ -10,11 +10,9 @@ pub struct Polar {
|
||||||
|
|
||||||
impl Polar {
|
impl Polar {
|
||||||
pub fn to_cartesian(self) -> Point2<Pfloat> {
|
pub fn to_cartesian(self) -> Point2<Pfloat> {
|
||||||
let v = Vector2 {
|
return Point2 {
|
||||||
x: self.radius * self.angle.sin(),
|
x: self.radius * self.angle.sin(),
|
||||||
y: self.radius * self.angle.cos(),
|
y: self.radius * self.angle.cos(),
|
||||||
};
|
} + self.center.to_vec();
|
||||||
|
|
||||||
return self.center + v;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -223,7 +223,7 @@ impl GPUState {
|
||||||
|
|
||||||
// Game dimensions of this sprite post-scale.
|
// Game dimensions of this sprite post-scale.
|
||||||
// Don't divide by 2, we use this later.
|
// Don't divide by 2, we use this later.
|
||||||
let height = s.size * s.scale / s.parallax;
|
let height = s.height * s.scale;
|
||||||
let width = height * texture.aspect;
|
let width = height * texture.aspect;
|
||||||
|
|
||||||
// Don't draw (or compute matrices for)
|
// Don't draw (or compute matrices for)
|
||||||
|
@ -311,7 +311,7 @@ impl GPUState {
|
||||||
instances.push(StarfieldInstance {
|
instances.push(StarfieldInstance {
|
||||||
position: (s.pos + offset).into(),
|
position: (s.pos + offset).into(),
|
||||||
parallax: s.parallax,
|
parallax: s.parallax,
|
||||||
size: s.size,
|
height: s.height,
|
||||||
tint: s.tint.into(),
|
tint: s.tint.into(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,8 +7,10 @@ mod vertexbuffer;
|
||||||
pub use gpustate::GPUState;
|
pub use gpustate::GPUState;
|
||||||
|
|
||||||
/// A handle to a sprite texture
|
/// A handle to a sprite texture
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub struct SpriteTexture(pub String);
|
pub struct SpriteTexture {
|
||||||
|
pub name: &'static str,
|
||||||
|
}
|
||||||
|
|
||||||
// API correction matrix.
|
// API correction matrix.
|
||||||
// cgmath uses OpenGL's matrix format, which
|
// cgmath uses OpenGL's matrix format, which
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
struct InstanceInput {
|
struct InstanceInput {
|
||||||
@location(2) position: vec2<f32>,
|
@location(2) position: vec2<f32>,
|
||||||
@location(3) parallax: f32,
|
@location(3) parallax: f32,
|
||||||
@location(4) size: f32,
|
@location(4) height: f32,
|
||||||
@location(5) tint: vec2<f32>,
|
@location(5) tint: vec2<f32>,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -57,7 +57,7 @@ fn vertex_shader_main(
|
||||||
|
|
||||||
// Apply sprite aspect ratio & scale factor
|
// Apply sprite aspect ratio & scale factor
|
||||||
// also applies screen aspect ratio
|
// also applies screen aspect ratio
|
||||||
var scale: f32 = instance.size / global.camera_zoom.x;
|
var scale: f32 = instance.height / global.camera_zoom.x;
|
||||||
|
|
||||||
// Minimum scale to prevent flicker at large zoom levels
|
// Minimum scale to prevent flicker at large zoom levels
|
||||||
var real_size = scale * global.window_size.xy;
|
var real_size = scale * global.window_size.xy;
|
||||||
|
|
|
@ -21,7 +21,7 @@ impl TextureArray {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_sprite_texture(&self, sprite: SpriteTexture) -> Texture {
|
pub fn get_sprite_texture(&self, sprite: SpriteTexture) -> Texture {
|
||||||
return self.get_texture(&sprite.0);
|
return self.get_texture(sprite.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_texture(&self, name: &str) -> Texture {
|
fn get_texture(&self, name: &str) -> Texture {
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use std::{collections::HashMap, fs::File, io::Read, path::Path, path::PathBuf};
|
use std::{collections::HashMap, fs::File, io::Read, path::Path};
|
||||||
|
|
||||||
use super::{rawtexture::RawTexture, Texture, TextureArrayConfig};
|
use super::{rawtexture::RawTexture, Texture, TextureArrayConfig};
|
||||||
|
|
||||||
mod fields {
|
mod fields {
|
||||||
|
use super::{File, Path, RawTexture, Read, Result, TextureArrayConfig};
|
||||||
use super::{File, HashMap, Path, PathBuf, RawTexture, Read, Result, TextureArrayConfig};
|
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
// Config is used outside of this file,
|
// Config is used outside of this file,
|
||||||
|
@ -14,7 +13,7 @@ mod fields {
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
pub struct Index {
|
pub struct Index {
|
||||||
pub config: TextureArrayConfig,
|
pub config: TextureArrayConfig,
|
||||||
pub include: Option<HashMap<PathBuf, String>>,
|
pub include: Option<Vec<String>>,
|
||||||
pub texture: Vec<Texture>,
|
pub texture: Vec<Texture>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,7 +31,7 @@ mod fields {
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
pub struct SubIndex {
|
pub struct SubIndex {
|
||||||
pub include: Option<HashMap<PathBuf, String>>,
|
pub include: Option<Vec<String>>,
|
||||||
pub texture: Vec<Texture>,
|
pub texture: Vec<Texture>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -153,8 +152,8 @@ impl TextureLoader {
|
||||||
|
|
||||||
// Load included files
|
// Load included files
|
||||||
if let Some(include) = index.include {
|
if let Some(include) = index.include {
|
||||||
for (path, sub_prefix) in include {
|
for i in include {
|
||||||
let sub_root = texture_root.join(&path);
|
let sub_root = texture_root.join(&i);
|
||||||
let index: fields::SubIndex = {
|
let index: fields::SubIndex = {
|
||||||
let mut texture_index_string = String::new();
|
let mut texture_index_string = String::new();
|
||||||
let _ = File::open(sub_root.join(Self::INDEX_NAME))?
|
let _ = File::open(sub_root.join(Self::INDEX_NAME))?
|
||||||
|
@ -168,9 +167,9 @@ impl TextureLoader {
|
||||||
index,
|
index,
|
||||||
&sub_root,
|
&sub_root,
|
||||||
if prefix.is_empty() {
|
if prefix.is_empty() {
|
||||||
sub_prefix
|
i
|
||||||
} else {
|
} else {
|
||||||
format!("{prefix}::{sub_prefix}")
|
format!("{prefix}::{i}")
|
||||||
},
|
},
|
||||||
)?;
|
)?;
|
||||||
for (s, data) in sub_textures {
|
for (s, data) in sub_textures {
|
||||||
|
|
|
@ -44,7 +44,9 @@ pub struct StarfieldInstance {
|
||||||
/// Parallax factor (same unit as usual)
|
/// Parallax factor (same unit as usual)
|
||||||
pub parallax: f32,
|
pub parallax: f32,
|
||||||
|
|
||||||
pub size: f32,
|
/// Height of (unrotated) sprite in world units
|
||||||
|
pub height: f32,
|
||||||
|
|
||||||
pub tint: [f32; 2],
|
pub tint: [f32; 2],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,7 +68,7 @@ impl BufferObject for StarfieldInstance {
|
||||||
shader_location: 3,
|
shader_location: 3,
|
||||||
format: wgpu::VertexFormat::Float32,
|
format: wgpu::VertexFormat::Float32,
|
||||||
},
|
},
|
||||||
// Size
|
// Height
|
||||||
wgpu::VertexAttribute {
|
wgpu::VertexAttribute {
|
||||||
offset: mem::size_of::<[f32; 3]>() as wgpu::BufferAddress,
|
offset: mem::size_of::<[f32; 3]>() as wgpu::BufferAddress,
|
||||||
shader_location: 4,
|
shader_location: 4,
|
||||||
|
|
|
@ -12,10 +12,10 @@ impl ShipKind {
|
||||||
Self::Gypsum => "ship::gypsum",
|
Self::Gypsum => "ship::gypsum",
|
||||||
};
|
};
|
||||||
|
|
||||||
return SpriteTexture(name.to_owned());
|
return SpriteTexture { name };
|
||||||
}
|
}
|
||||||
|
|
||||||
fn size(&self) -> Pfloat {
|
fn height(&self) -> Pfloat {
|
||||||
match self {
|
match self {
|
||||||
Self::Gypsum => 100.0,
|
Self::Gypsum => 100.0,
|
||||||
}
|
}
|
||||||
|
@ -44,7 +44,7 @@ impl Spriteable for Ship {
|
||||||
angle: self.body.angle,
|
angle: self.body.angle,
|
||||||
scale: 1.0,
|
scale: 1.0,
|
||||||
parallax: 1.0,
|
parallax: 1.0,
|
||||||
size: self.kind.size(),
|
height: self.kind.height(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
content, physics::Pfloat, render::SpriteTexture, Doodad, Sprite, Spriteable, STARFIELD_COUNT,
|
physics::{Pfloat, Polar},
|
||||||
STARFIELD_PARALLAX_MAX, STARFIELD_PARALLAX_MIN, STARFIELD_SIZE,
|
render::SpriteTexture,
|
||||||
|
Doodad, Sprite, Spriteable, STARFIELD_COUNT, STARFIELD_PARALLAX_MAX, STARFIELD_PARALLAX_MIN,
|
||||||
|
STARFIELD_SIZE,
|
||||||
};
|
};
|
||||||
use cgmath::{Point2, Vector2};
|
use cgmath::{Deg, Point2, Vector2};
|
||||||
use rand::{self, Rng};
|
use rand::{self, Rng};
|
||||||
|
|
||||||
pub struct StarfieldStar {
|
pub struct StarfieldStar {
|
||||||
|
@ -10,9 +12,8 @@ pub struct StarfieldStar {
|
||||||
/// These are relative to the center of a starfield tile.
|
/// These are relative to the center of a starfield tile.
|
||||||
pub pos: Point2<Pfloat>,
|
pub pos: Point2<Pfloat>,
|
||||||
|
|
||||||
// TODO: z-coordinate?
|
|
||||||
pub parallax: Pfloat,
|
pub parallax: Pfloat,
|
||||||
pub size: Pfloat,
|
pub height: Pfloat,
|
||||||
|
|
||||||
/// Color/brightness variation.
|
/// Color/brightness variation.
|
||||||
/// See shader.
|
/// See shader.
|
||||||
|
@ -20,17 +21,15 @@ pub struct StarfieldStar {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct System {
|
pub struct System {
|
||||||
pub name: String,
|
|
||||||
bodies: Vec<Doodad>,
|
bodies: Vec<Doodad>,
|
||||||
pub starfield: Vec<StarfieldStar>,
|
pub starfield: Vec<StarfieldStar>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl System {
|
impl System {
|
||||||
pub fn new(ct: &content::system::System) -> Self {
|
pub fn new() -> Self {
|
||||||
let mut rng = rand::thread_rng();
|
let mut rng = rand::thread_rng();
|
||||||
let sz = STARFIELD_SIZE as f32 / 2.0;
|
let sz = STARFIELD_SIZE as f32 / 2.0;
|
||||||
let mut s = System {
|
let mut s = System {
|
||||||
name: ct.name.clone(),
|
|
||||||
bodies: Vec::new(),
|
bodies: Vec::new(),
|
||||||
starfield: (0..STARFIELD_COUNT)
|
starfield: (0..STARFIELD_COUNT)
|
||||||
.map(|_| StarfieldStar {
|
.map(|_| StarfieldStar {
|
||||||
|
@ -39,7 +38,7 @@ impl System {
|
||||||
y: rng.gen_range(-sz..=sz),
|
y: rng.gen_range(-sz..=sz),
|
||||||
},
|
},
|
||||||
parallax: rng.gen_range(STARFIELD_PARALLAX_MIN..STARFIELD_PARALLAX_MAX),
|
parallax: rng.gen_range(STARFIELD_PARALLAX_MIN..STARFIELD_PARALLAX_MAX),
|
||||||
size: rng.gen_range(0.2..0.8), // TODO: configurable
|
height: rng.gen_range(0.2..0.8), // TODO: configurable
|
||||||
tint: Vector2 {
|
tint: Vector2 {
|
||||||
x: rng.gen_range(0.0..=1.0),
|
x: rng.gen_range(0.0..=1.0),
|
||||||
y: rng.gen_range(0.0..=1.0),
|
y: rng.gen_range(0.0..=1.0),
|
||||||
|
@ -48,15 +47,26 @@ impl System {
|
||||||
.collect(),
|
.collect(),
|
||||||
};
|
};
|
||||||
|
|
||||||
for o in &ct.objects {
|
|
||||||
s.bodies.push(Doodad {
|
s.bodies.push(Doodad {
|
||||||
pos: o.position,
|
pos: (0.0, 0.0).into(),
|
||||||
sprite: SpriteTexture(o.sprite.to_owned()),
|
sprite: SpriteTexture { name: "star::star" },
|
||||||
size: o.size,
|
parallax: 10.0,
|
||||||
parallax: o.parallax,
|
height: 80.0,
|
||||||
angle: o.angle,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
s.bodies.push(Doodad {
|
||||||
|
pos: Polar {
|
||||||
|
center: (0.0, 0.0).into(),
|
||||||
|
radius: 5000.0,
|
||||||
|
angle: Deg { 0: 31.0 },
|
||||||
}
|
}
|
||||||
|
.to_cartesian(),
|
||||||
|
sprite: SpriteTexture {
|
||||||
|
name: "planet::earth",
|
||||||
|
},
|
||||||
|
parallax: 5.0,
|
||||||
|
height: 120.0,
|
||||||
|
});
|
||||||
|
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue