mirror of
https://github.com/Theaninova/mhlib.git
synced 2026-01-22 01:42:44 +00:00
initial commit
This commit is contained in:
133
rust/src/godot/sprites.rs
Normal file
133
rust/src/godot/sprites.rs
Normal file
@@ -0,0 +1,133 @@
|
||||
use crate::formats::sprites::{CropMode, RenderMode, Sprites};
|
||||
use godot::builtin::{GodotString, Rect2, StringName, ToVariant, Vector2};
|
||||
use godot::engine::utilities::printerr;
|
||||
use godot::engine::{
|
||||
load, AtlasTexture, ImageTexture, PlaceholderTexture2D, ResourceLoader, SpriteFrames,
|
||||
};
|
||||
use godot::obj::{Gd, Share};
|
||||
use godot::prelude::GodotClass;
|
||||
|
||||
const FPS: f64 = 15.0;
|
||||
const SPRITE_EXTENSIONS: &[&str] = &["bmp", "rle"];
|
||||
|
||||
pub fn load_sprite_frames(sprites: Vec<Sprites>, path: GodotString) -> Gd<SpriteFrames> {
|
||||
let dir = path
|
||||
.to_string()
|
||||
.strip_suffix("/sprites.txt")
|
||||
.unwrap()
|
||||
.to_string();
|
||||
let mut sprite_frames = SpriteFrames::new();
|
||||
for sprite in sprites.into_iter() {
|
||||
if let RenderMode::FlipX = sprite.render_mode {
|
||||
continue;
|
||||
}
|
||||
sprite_frames.add_animation(StringName::from(&sprite.name));
|
||||
sprite_frames.set_animation_speed(StringName::from(&sprite.name), FPS);
|
||||
|
||||
match select_from_extensions(&dir, &sprite.file_name) {
|
||||
Some((path, "rle")) => extract_rle_frames(&mut sprite_frames, &sprite, path),
|
||||
Some((path, "bmp")) => extract_bitmap_frames(&mut sprite_frames, &sprite, path),
|
||||
Some(_) | None => {
|
||||
printerr(
|
||||
format!("Missing sprite '{}'", sprite.file_name).to_variant(),
|
||||
&[],
|
||||
);
|
||||
let texture = PlaceholderTexture2D::new();
|
||||
sprite_frames.add_frame(
|
||||
StringName::from(&sprite.name),
|
||||
texture.upcast(),
|
||||
60.0 / FPS,
|
||||
0,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sprite_frames
|
||||
}
|
||||
|
||||
/// Loads an RLE file as SpriteFrames and extracts
|
||||
/// its frames into `sprite_frames`
|
||||
fn extract_rle_frames(sprite_frames: &mut SpriteFrames, sprite: &Sprites, path: String) {
|
||||
let frames: Gd<SpriteFrames> = load(path);
|
||||
for frame_idx in 0..frames.get_frame_count("default".into()) {
|
||||
sprite_frames.add_frame(
|
||||
StringName::from(&sprite.name),
|
||||
frames
|
||||
.get_frame_texture("default".into(), frame_idx)
|
||||
.unwrap(),
|
||||
60.0 / FPS,
|
||||
0,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Loads a bitmap and extracts its frames into `sprite_frames`
|
||||
/// creates an atlas if there are multiple frames.
|
||||
fn extract_bitmap_frames(sprite_frames: &mut SpriteFrames, sprite: &Sprites, path: String) {
|
||||
let texture: Gd<ImageTexture> = load(path);
|
||||
|
||||
let frame_count = if let Some(CropMode::FrameCount(frame_count)) = sprite.frames {
|
||||
frame_count
|
||||
} else {
|
||||
1
|
||||
};
|
||||
|
||||
if frame_count > 1 {
|
||||
let height = texture.get_height();
|
||||
let width = texture.get_width();
|
||||
let frame_height = height / frame_count as i64;
|
||||
|
||||
for i in 0..frame_count as i64 {
|
||||
let mut atlas = AtlasTexture::new();
|
||||
atlas.set_atlas(texture.share().upcast());
|
||||
atlas.set_region(Rect2 {
|
||||
position: Vector2 {
|
||||
x: 0.0,
|
||||
y: (i * frame_height) as f32,
|
||||
},
|
||||
size: Vector2 {
|
||||
x: width as f32,
|
||||
y: frame_height as f32,
|
||||
},
|
||||
});
|
||||
|
||||
sprite_frames.add_frame(
|
||||
StringName::from(&sprite.name),
|
||||
atlas.upcast(),
|
||||
60.0 / FPS,
|
||||
0,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
sprite_frames.add_frame(
|
||||
StringName::from(&sprite.name),
|
||||
texture.upcast(),
|
||||
60.0 / FPS,
|
||||
0,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Selects the extension based on which file exists
|
||||
fn select_from_extensions(dir: &str, file_name: &str) -> Option<(String, &'static str)> {
|
||||
SPRITE_EXTENSIONS
|
||||
.iter()
|
||||
.map(|ext| {
|
||||
(
|
||||
format!("{}/sprites/{}.{}", dir, file_name.to_lowercase(), ext),
|
||||
*ext,
|
||||
)
|
||||
})
|
||||
.find(|(path, ext)| {
|
||||
ResourceLoader::singleton().exists(
|
||||
path.clone().into(),
|
||||
match *ext {
|
||||
"rle" => SpriteFrames::CLASS_NAME.to_string(),
|
||||
"bmp" => ImageTexture::CLASS_NAME.to_string(),
|
||||
_ => panic!(),
|
||||
}
|
||||
.into(),
|
||||
)
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user