Gotta move
This commit is contained in:
parent
f3617e61bc
commit
c155390e22
8 changed files with 218 additions and 123 deletions
|
@ -8,8 +8,8 @@ uniform sampler2D texture;
|
|||
uniform vec2 screen_resolution;
|
||||
|
||||
uniform vec2 curvature = vec2(3.0, 3.0);
|
||||
uniform vec2 scanline_opacity = vec2(1.0, 1.0);
|
||||
uniform float brightness = 3.0;
|
||||
uniform vec2 scanline_opacity = vec2(0.5, 0.5);
|
||||
uniform float brightness = 2.0;
|
||||
|
||||
out vec4 f_color;
|
||||
|
||||
|
|
BIN
assets/textures/backgrounds/grass-hills.png
Normal file
BIN
assets/textures/backgrounds/grass-hills.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 23 KiB |
0
assets/textures/tiles/atlas
Normal file
0
assets/textures/tiles/atlas
Normal file
153
src/assets.rs
Normal file
153
src/assets.rs
Normal file
|
@ -0,0 +1,153 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
use glium::{
|
||||
texture::{RawImage2d, SrgbTexture2d},
|
||||
Display, Program,
|
||||
};
|
||||
use glob::glob;
|
||||
|
||||
pub type Textures = HashMap<String, SrgbTexture2d>;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct TextureAtlas {
|
||||
pub texture: SrgbTexture2d,
|
||||
rects: HashMap<String, glium::Rect>,
|
||||
width: u32,
|
||||
height: u32,
|
||||
}
|
||||
|
||||
pub struct AtlasUVs {
|
||||
pub bottom_left: [f32; 2],
|
||||
pub bottom_right: [f32; 2],
|
||||
pub top_left: [f32; 2],
|
||||
pub top_right: [f32; 2],
|
||||
}
|
||||
|
||||
impl TextureAtlas {
|
||||
fn new(display: &Display) -> TextureAtlas {
|
||||
log::info!("Loading textures");
|
||||
let paths = glob("assets/textures/**/*.png").unwrap();
|
||||
let items = paths.map(|entry| {
|
||||
let path = entry.unwrap();
|
||||
|
||||
let image = image::open(&path).unwrap().to_rgba8();
|
||||
let image_dimensions = image.dimensions();
|
||||
let image = image.into_raw();
|
||||
|
||||
let name_path = path
|
||||
.with_extension("")
|
||||
.strip_prefix("assets/textures/")
|
||||
.unwrap()
|
||||
.to_owned();
|
||||
let mut name = String::new();
|
||||
for part in name_path.iter() {
|
||||
name.push_str(part.to_str().unwrap());
|
||||
name.push(':');
|
||||
}
|
||||
name.pop();
|
||||
|
||||
crunch::Item::new(
|
||||
(name, image),
|
||||
image_dimensions.0 as usize,
|
||||
image_dimensions.1 as usize,
|
||||
crunch::Rotation::None,
|
||||
)
|
||||
});
|
||||
|
||||
log::info!("Packing textures into atlas");
|
||||
let (width, height, items) = crunch::pack_into_po2(4096, items).unwrap();
|
||||
|
||||
let items = items.into_iter().map(|entry| {
|
||||
let rect = glium::Rect {
|
||||
left: entry.0.x as u32,
|
||||
bottom: entry.0.y as u32,
|
||||
width: entry.0.w as u32,
|
||||
height: entry.0.h as u32,
|
||||
};
|
||||
let name = entry.1 .0;
|
||||
let image = entry.1 .1;
|
||||
(name, image, rect)
|
||||
});
|
||||
let mut atlas = TextureAtlas {
|
||||
texture: SrgbTexture2d::empty(display, width as u32, height as u32).unwrap(),
|
||||
rects: HashMap::new(),
|
||||
width: width as u32,
|
||||
height: height as u32,
|
||||
};
|
||||
for (name, image, rect) in items {
|
||||
atlas.texture.write(
|
||||
rect,
|
||||
RawImage2d::from_raw_rgba_reversed(&image, (rect.width, rect.height)),
|
||||
);
|
||||
atlas.rects.insert(name, rect);
|
||||
}
|
||||
atlas
|
||||
}
|
||||
|
||||
pub fn get_uv(&self, name: String) -> AtlasUVs {
|
||||
let rect = self.rects.get(&name).unwrap();
|
||||
AtlasUVs {
|
||||
bottom_left: Self::coord_to_uv(
|
||||
rect.left,
|
||||
rect.bottom + rect.height,
|
||||
self.width,
|
||||
self.height,
|
||||
),
|
||||
bottom_right: Self::coord_to_uv(
|
||||
rect.left + rect.width,
|
||||
rect.bottom + rect.height,
|
||||
self.width,
|
||||
self.height,
|
||||
),
|
||||
top_left: Self::coord_to_uv(rect.left, rect.bottom, self.width, self.height),
|
||||
top_right: Self::coord_to_uv(
|
||||
rect.left + rect.width,
|
||||
rect.bottom,
|
||||
self.width,
|
||||
self.height,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
fn coord_to_uv(x: u32, y: u32, width: u32, height: u32) -> [f32; 2] {
|
||||
[x as f32 / width as f32, (y as f32 / height as f32)]
|
||||
}
|
||||
}
|
||||
|
||||
pub type Shaders = HashMap<String, Program>;
|
||||
|
||||
fn load_shaders(display: &Display) -> Shaders {
|
||||
log::info!("Loading shaders.");
|
||||
let mut shaders: Shaders = Shaders::new();
|
||||
for entry in glob("assets/shaders/*").unwrap() {
|
||||
if let Ok(path) = entry {
|
||||
// Operate only on directories
|
||||
if path.is_file() {
|
||||
continue;
|
||||
}
|
||||
|
||||
let vert_source = std::fs::read_to_string(path.join("vert.glsl")).unwrap();
|
||||
let frag_source = std::fs::read_to_string(path.join("frag.glsl")).unwrap();
|
||||
let program = Program::from_source(display, &vert_source, &frag_source, None).unwrap();
|
||||
|
||||
let name = path.file_name().unwrap().to_str().unwrap().to_owned();
|
||||
shaders.insert(name.to_string(), program);
|
||||
log::info!("Loaded shader {:?} from {:?}.", name, path);
|
||||
}
|
||||
}
|
||||
shaders
|
||||
}
|
||||
|
||||
pub struct Assets {
|
||||
pub texture_atlas: TextureAtlas,
|
||||
pub shaders: Shaders,
|
||||
}
|
||||
|
||||
impl Assets {
|
||||
pub fn new(display: &Display) -> Assets {
|
||||
Assets {
|
||||
texture_atlas: TextureAtlas::new(display),
|
||||
shaders: load_shaders(display),
|
||||
}
|
||||
}
|
||||
}
|
26
src/main.rs
26
src/main.rs
|
@ -1,21 +1,24 @@
|
|||
use std::time::{Duration, Instant};
|
||||
|
||||
use anymap::AnyMap;
|
||||
use assets::{Assets, Shaders};
|
||||
use cgmath::Matrix3;
|
||||
use glium::{
|
||||
glutin, index::PrimitiveType, texture::Texture2d, uniform, Display, Frame, IndexBuffer,
|
||||
Surface, VertexBuffer,
|
||||
};
|
||||
use glium_glyph::{glyph_brush::Section, GlyphBrush};
|
||||
use glium_glyph::{
|
||||
glyph_brush::{rusttype::Font, Section},
|
||||
GlyphBrush,
|
||||
};
|
||||
use glutin::{
|
||||
event::{Event, WindowEvent},
|
||||
event_loop::ControlFlow,
|
||||
};
|
||||
use resources::Shaders;
|
||||
use simplelog::{TermLogger, TerminalMode};
|
||||
use state::GameState;
|
||||
|
||||
pub mod resources;
|
||||
pub mod assets;
|
||||
pub mod state;
|
||||
|
||||
const TIMESTEP: f32 = 1.0 / 20.0;
|
||||
|
@ -41,7 +44,7 @@ struct State {
|
|||
current_state: Box<dyn GameState>,
|
||||
next_state: Option<Box<dyn GameState>>,
|
||||
|
||||
resources: AnyMap,
|
||||
resources: Assets,
|
||||
}
|
||||
|
||||
impl State {
|
||||
|
@ -83,12 +86,11 @@ impl State {
|
|||
};
|
||||
|
||||
// Set initial state
|
||||
let current_state = Box::new(state::TestState);
|
||||
let current_state = Box::new(state::TestState { time: 0.0 });
|
||||
let next_state = None;
|
||||
|
||||
// The resources map
|
||||
let mut resources = AnyMap::new();
|
||||
resources::load_resources(display, &mut resources);
|
||||
let resources = Assets::new(display);
|
||||
|
||||
// Package it all together UwU
|
||||
State {
|
||||
|
@ -130,7 +132,7 @@ impl State {
|
|||
let render_indices =
|
||||
IndexBuffer::new(display, PrimitiveType::TriangleStrip, &[1, 2, 0, 3 as u16]).unwrap();
|
||||
|
||||
let program = self.resources.get::<Shaders>().unwrap().get("crt").unwrap();
|
||||
let program = self.resources.shaders.get("crt").unwrap();
|
||||
|
||||
let mut scale = (1.0, 1.0);
|
||||
if self.screen_scale.0 < self.screen_scale.1 {
|
||||
|
@ -143,7 +145,7 @@ impl State {
|
|||
let uniforms = uniform! {
|
||||
matrix: cgmath::conv::array3x3(scale_matrix),
|
||||
texture: self.render_texture.sampled().magnify_filter(glium::uniforms::MagnifySamplerFilter::Nearest),
|
||||
screen_resolution: [SCREEN_WIDTH, SCREEN_HEIGHT],
|
||||
screen_resolution: [SCREEN_HEIGHT, SCREEN_HEIGHT],
|
||||
/*curvature: [3.0, 3.0 as f32],
|
||||
scanline_opacity: [0.5, 0.5 as f32],
|
||||
brightness: 2.0 as f32,*/
|
||||
|
@ -180,6 +182,11 @@ fn main() {
|
|||
Display::new(wb, cb, &event_loop).unwrap()
|
||||
};
|
||||
|
||||
// For font rendering
|
||||
let dejavu = std::fs::read("assets/fonts/DejaVuSans.ttf").unwrap();
|
||||
let fonts = vec![Font::from_bytes(dejavu).unwrap()];
|
||||
let mut glyph_brush = GlyphBrush::new(&display, fonts);
|
||||
|
||||
// The main state of program or whatever
|
||||
let mut state = State::new(&display);
|
||||
|
||||
|
@ -220,7 +227,6 @@ fn main() {
|
|||
state.render(&display, &mut target);
|
||||
|
||||
// Draw the FPS Indicator
|
||||
let glyph_brush = state.resources.get_mut::<GlyphBrush>().unwrap();
|
||||
glyph_brush.queue(Section {
|
||||
text: &format!("FPS: {:?}", state.current_fps),
|
||||
screen_position: (0.0, 0.0),
|
||||
|
|
|
@ -1,74 +0,0 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
use anymap::AnyMap;
|
||||
use glium::{texture::SrgbTexture2d, Display, Program};
|
||||
use glium_glyph::{glyph_brush::rusttype::Font, GlyphBrush};
|
||||
use glob::glob;
|
||||
|
||||
pub type Textures = HashMap<String, SrgbTexture2d>;
|
||||
pub type Shaders = HashMap<String, Program>;
|
||||
|
||||
// Set up and load all global resources.
|
||||
pub fn load_resources(display: &Display, resources: &mut AnyMap) {
|
||||
// Load images
|
||||
log::info!("Loading textures");
|
||||
let mut textures: Textures = HashMap::new();
|
||||
for entry in glob("assets/textures/**/*.png").unwrap() {
|
||||
use image::io::Reader;
|
||||
|
||||
if let Ok(path) = entry {
|
||||
let image = Reader::open(&path).unwrap().decode().unwrap().to_rgba8();
|
||||
let image_dimensions = image.dimensions();
|
||||
|
||||
let image = glium::texture::RawImage2d::from_raw_rgba_reversed(
|
||||
&image.into_raw(),
|
||||
image_dimensions,
|
||||
);
|
||||
let texture = SrgbTexture2d::new(display, image).unwrap();
|
||||
|
||||
let name_path = path
|
||||
.with_extension("")
|
||||
.strip_prefix("assets/textures/")
|
||||
.unwrap()
|
||||
.to_owned();
|
||||
let mut name = String::new();
|
||||
for part in name_path.iter() {
|
||||
name.push_str(part.to_str().unwrap());
|
||||
name.push(':');
|
||||
}
|
||||
name.pop();
|
||||
|
||||
textures.insert(name.to_string(), texture);
|
||||
log::info!("Loaded texture {:?} from {:?}.", name, path);
|
||||
}
|
||||
}
|
||||
resources.insert(textures);
|
||||
|
||||
// Load shaders
|
||||
log::info!("Loading shaders.");
|
||||
let mut shaders: HashMap<String, Program> = HashMap::new();
|
||||
for entry in glob("assets/shaders/*").unwrap() {
|
||||
if let Ok(path) = entry {
|
||||
// Operate only on directories
|
||||
if path.is_file() {
|
||||
continue;
|
||||
}
|
||||
|
||||
let vert_source = std::fs::read_to_string(path.join("vert.glsl")).unwrap();
|
||||
let frag_source = std::fs::read_to_string(path.join("frag.glsl")).unwrap();
|
||||
let program = Program::from_source(display, &vert_source, &frag_source, None).unwrap();
|
||||
|
||||
let name = path.file_name().unwrap().to_str().unwrap().to_owned();
|
||||
shaders.insert(name.to_string(), program);
|
||||
log::info!("Loaded shader {:?} from {:?}.", name, path);
|
||||
}
|
||||
}
|
||||
resources.insert(shaders);
|
||||
|
||||
// Set up font stuff
|
||||
let dejavu = std::fs::read("assets/fonts/DejaVuSans.ttf").unwrap();
|
||||
let fonts = vec![Font::from_bytes(dejavu).unwrap()];
|
||||
let glyph_brush = GlyphBrush::new(display, fonts);
|
||||
log::info!("Set up font.");
|
||||
resources.insert(glyph_brush);
|
||||
}
|
20
src/state.rs
20
src/state.rs
|
@ -4,26 +4,22 @@ use glium::{framebuffer::SimpleFrameBuffer, glutin::event::Event, Display, Frame
|
|||
mod test_state;
|
||||
pub use test_state::TestState;
|
||||
|
||||
use crate::assets::Assets;
|
||||
|
||||
pub trait GameState {
|
||||
fn input(&mut self, resources: &mut AnyMap, event: &Event<()>);
|
||||
fn update(&mut self, resources: &mut AnyMap, dt: f32) -> Option<Box<dyn GameState>>;
|
||||
fn render(&mut self, resources: &mut AnyMap, display: &Display, target: &mut SimpleFrameBuffer);
|
||||
fn input(&mut self, assets: &Assets, event: &Event<()>);
|
||||
fn update(&mut self, assets: &Assets, dt: f32) -> Option<Box<dyn GameState>>;
|
||||
fn render(&mut self, assets: &Assets, display: &Display, target: &mut SimpleFrameBuffer);
|
||||
}
|
||||
|
||||
pub struct DummyState;
|
||||
|
||||
impl GameState for DummyState {
|
||||
fn update(&mut self, _resourcess: &mut AnyMap, _dt: f32) -> Option<Box<dyn GameState>> {
|
||||
fn update(&mut self, _assets: &Assets, _dt: f32) -> Option<Box<dyn GameState>> {
|
||||
None
|
||||
}
|
||||
|
||||
fn input(&mut self, _resources: &mut AnyMap, _event: &Event<()>) {}
|
||||
fn input(&mut self, _assets: &Assets, _event: &Event<()>) {}
|
||||
|
||||
fn render(
|
||||
&mut self,
|
||||
_resources: &mut AnyMap,
|
||||
_display: &Display,
|
||||
_target: &mut SimpleFrameBuffer,
|
||||
) {
|
||||
}
|
||||
fn render(&mut self, _assets: &Assets, _display: &Display, _target: &mut SimpleFrameBuffer) {}
|
||||
}
|
||||
|
|
|
@ -2,24 +2,26 @@ use glium::{
|
|||
framebuffer::SimpleFrameBuffer, implement_vertex, index::PrimitiveType, uniform,
|
||||
uniforms::Sampler, IndexBuffer, Surface, VertexBuffer,
|
||||
};
|
||||
use resources::Shaders;
|
||||
|
||||
use crate::resources::{self, Textures};
|
||||
use crate::assets::Assets;
|
||||
|
||||
use super::GameState;
|
||||
|
||||
pub struct TestState;
|
||||
pub struct TestState {
|
||||
pub time: f32,
|
||||
}
|
||||
|
||||
impl GameState for TestState {
|
||||
fn input(&mut self, resources: &mut anymap::AnyMap, event: &glium::glutin::event::Event<()>) {}
|
||||
fn input(&mut self, assets: &Assets, event: &glium::glutin::event::Event<()>) {}
|
||||
|
||||
fn update(&mut self, resources: &mut anymap::AnyMap, dt: f32) -> Option<Box<dyn GameState>> {
|
||||
fn update(&mut self, assets: &Assets, dt: f32) -> Option<Box<dyn GameState>> {
|
||||
self.time += 0.0;
|
||||
None
|
||||
}
|
||||
|
||||
fn render(
|
||||
&mut self,
|
||||
resources: &mut anymap::AnyMap,
|
||||
assets: &Assets,
|
||||
display: &glium::Display,
|
||||
target: &mut SimpleFrameBuffer,
|
||||
) {
|
||||
|
@ -33,24 +35,46 @@ impl GameState for TestState {
|
|||
|
||||
implement_vertex!(Vertex, position, tex_coords);
|
||||
|
||||
let tex_coords = crate::assets::AtlasUVs {
|
||||
top_left: [0.0, 0.0],
|
||||
top_right: [1.0, 0.0],
|
||||
bottom_left: [0.0, 1.0],
|
||||
bottom_right: [1.0, 1.0],
|
||||
};
|
||||
let tex_coords = assets
|
||||
.texture_atlas
|
||||
.get_uv("backgrounds:grass-hills".to_string());
|
||||
|
||||
VertexBuffer::new(
|
||||
display,
|
||||
&[
|
||||
Vertex {
|
||||
position: [-1.0, -1.0],
|
||||
tex_coords: [0.0, 0.0],
|
||||
tex_coords: [
|
||||
(tex_coords.top_left[0] - self.time.sin() / 8.0),
|
||||
tex_coords.top_left[1],
|
||||
],
|
||||
},
|
||||
Vertex {
|
||||
position: [-1.0, 1.0],
|
||||
tex_coords: [0.0, 1.0],
|
||||
tex_coords: [
|
||||
(tex_coords.bottom_left[0] - self.time.sin() / 8.0),
|
||||
tex_coords.bottom_left[1],
|
||||
],
|
||||
},
|
||||
Vertex {
|
||||
position: [1.0, 1.0],
|
||||
tex_coords: [1.0, 1.0],
|
||||
tex_coords: [
|
||||
(tex_coords.bottom_right[0] / 2.0 - self.time.sin() / 8.0),
|
||||
tex_coords.bottom_right[1],
|
||||
],
|
||||
},
|
||||
Vertex {
|
||||
position: [1.0, -1.0],
|
||||
tex_coords: [1.0, 0.0],
|
||||
tex_coords: [
|
||||
(tex_coords.top_right[0] / 2.0 - self.time.sin() / 8.0),
|
||||
tex_coords.top_right[1],
|
||||
],
|
||||
},
|
||||
],
|
||||
)
|
||||
|
@ -60,23 +84,13 @@ impl GameState for TestState {
|
|||
let index_buffer =
|
||||
IndexBuffer::new(display, PrimitiveType::TriangleStrip, &[1 as u16, 2, 0, 3]).unwrap();
|
||||
|
||||
let program = resources.get::<Shaders>().unwrap().get("basic").unwrap();
|
||||
|
||||
let texture = resources
|
||||
.get::<Textures>()
|
||||
.unwrap()
|
||||
.get("tiles:dirt")
|
||||
.unwrap();
|
||||
let program = assets.shaders.get("basic").unwrap();
|
||||
|
||||
let uniforms = uniform! {
|
||||
/*matrix: [
|
||||
[1.0,0.0,0.0],
|
||||
[0.0,1.0,0.0],
|
||||
[0.0,0.0,1.0 as f32],
|
||||
],*/
|
||||
matrix: cgmath::conv::array3x3(cgmath::Matrix3::from_nonuniform_scale(1.0/crate::SCREEN_WIDTH*16.0, 1.0/crate::SCREEN_HEIGHT*16.0)),
|
||||
texture: texture.sampled().magnify_filter(glium::uniforms::MagnifySamplerFilter::Nearest),
|
||||
|
||||
matrix: cgmath::conv::array3x3(
|
||||
cgmath::Matrix3::from_nonuniform_scale(1.0, 1.0 as f32)
|
||||
),
|
||||
texture: assets.texture_atlas.texture.sampled().magnify_filter(glium::uniforms::MagnifySamplerFilter::Nearest),
|
||||
};
|
||||
|
||||
target
|
||||
|
|
Loading…
Reference in a new issue