1
0
Fork 0
mirror of https://github.com/doukutsu-rs/doukutsu-rs synced 2024-11-25 07:02:58 +00:00

CaveStory+ data files fixes

This commit is contained in:
Alula 2020-08-19 02:55:21 +02:00
parent c8c847396b
commit ae45e5513c
No known key found for this signature in database
GPG key ID: 3E00485503A1D8BA
13 changed files with 207 additions and 146 deletions

View file

@ -13,6 +13,8 @@ byteorder = "1.3"
ggez = { git = "https://github.com/ggez/ggez", rev = "4f4bdebff463881c36325c7e10520c9a4fd8f75c" }
imgui = "0.4.0"
imgui-ext = "0.3.0"
image = {version = "0.22", default-features = false, features = ["png_codec", "pnm", "bmp"] }
itertools = "0.9.0"
lazy_static = "1.4.0"
log = "0.4"
maplit = "1.0.2"

View file

@ -5,13 +5,13 @@ Later plans might involve turning it into a fully-featured modding tool with liv
**The project is still in a very early state and nowhere near being playable. Expect lots of breaking changes and bugs**
[Join the Discord server](https://discord.gg/k8fYBDS)
[Join the Discord server](https://discord.gg/fbRsNNB)
#### Data files
doukutsu-rs project does not re-distribute any copyrighted files.
The engine should work fine with [CSE2](https://github.com/Clownacy/CSE2)/[NXEngine](https://github.com/nxengine/nxengine-evo) modified freeware data files and [Cave Story+](https://www.nicalis.com/games/cavestory+) (Nicalis commercial release, partial loading is supported but note we're not aiming to fully support it's features) data files.
The engine should work fine with [CSE2](https://github.com/Clownacy/CSE2) or [NXEngine](https://github.com/nxengine/nxengine-evo) modified freeware data files and [Cave Story+](https://www.nicalis.com/games/cavestory+) (Nicalis commercial release, loading is supported but note we're not aiming to fully support it's features) data files.
#### Roadmap

View file

@ -1,8 +0,0 @@
use criterion::{black_box, Criterion, criterion_group, criterion_main};
use fpa::I23F9;
fn criterion_benchmark(c: &mut Criterion) {
//c.bench_function("fpa lib", |b| b.iter(|| fpa_lib()));
}
criterion_group!(benches, criterion_benchmark);
criterion_main!(benches);

View file

@ -1,3 +1,4 @@
use log::info;
use std::collections::HashMap;
use maplit::hashmap;
@ -46,6 +47,7 @@ pub struct MyCharConsts {
#[derive(Debug)]
pub struct EngineConstants {
pub is_cs_plus: bool,
pub my_char: MyCharConsts,
pub booster: BoosterConsts,
pub tex_sizes: HashMap<String, (usize, usize)>,
@ -54,6 +56,7 @@ pub struct EngineConstants {
impl Clone for EngineConstants {
fn clone(&self) -> Self {
EngineConstants {
is_cs_plus: self.is_cs_plus,
my_char: self.my_char,
booster: self.booster,
tex_sizes: self.tex_sizes.clone(),
@ -62,8 +65,9 @@ impl Clone for EngineConstants {
}
impl EngineConstants {
pub fn defaults() -> EngineConstants {
pub fn defaults() -> Self {
EngineConstants {
is_cs_plus: false,
my_char: MyCharConsts {
cond: 0x80,
flags: 0,
@ -248,4 +252,11 @@ impl EngineConstants {
},
}
}
pub fn apply_csplus_patches(&mut self) {
info!("Applying Cave Story+ constants patches...");
self.is_cs_plus = true;
self.tex_sizes.insert(str!("MyChar"), (200, 384));
}
}

View file

@ -5,7 +5,7 @@ extern crate strum_macros;
use std::{env, mem};
use std::path;
use ggez::{Context, ContextBuilder, event, GameResult};
use ggez::{Context, ContextBuilder, event, GameResult, filesystem};
use ggez::conf::{WindowMode, WindowSetup};
use ggez::event::{KeyCode, KeyMods};
use ggez::event::winit_event::{ElementState, Event, KeyboardInput, WindowEvent};
@ -97,6 +97,18 @@ impl Game {
let scale = 2.0;
let screen_size = graphics::drawable_size(ctx);
let canvas_size = (screen_size.0 / scale, screen_size.1 / scale);
let mut constants = EngineConstants::defaults();
let mut base_path = "/";
if filesystem::exists(ctx, "/base/Nicalis.bmp") {
info!("Cave Story+ data files detected.");
constants.apply_csplus_patches();
base_path = "/base/";
} else if filesystem::exists(ctx, "/mrmap.bin") || filesystem::exists(ctx, "/Font/font") {
info!("CSE2E data files detected.");
} else if filesystem::exists(ctx, "/stage.dat") || filesystem::exists(ctx, "/sprites.sif") {
info!("NXEngine-evo data files detected.");
}
let s = Game {
scene: None,
@ -108,11 +120,11 @@ impl Game {
flags: GameFlags(0),
key_state: KeyState(0),
key_trigger: KeyState(0),
texture_set: TextureSet::new("/"),
base_path: "/".to_string(),
texture_set: TextureSet::new(base_path),
base_path: str!(base_path),
stages: Vec::new(),
sound_manager: SoundManager::new(),
constants: EngineConstants::defaults(),
constants,
scale,
screen_size,
canvas_size,

View file

@ -11,7 +11,7 @@ pub struct Map {
}
impl Map {
pub fn load_from<R: io::Read>(mut map_data: R, mut attrib_data: R) -> io::Result<Map> {
pub fn load_from<R: io::Read>(mut map_data: R, mut attrib_data: R) -> io::Result<Self> {
let mut magic = [0; 3];
map_data.read_exact(&mut magic)?;
@ -28,7 +28,7 @@ impl Map {
let mut attrib = [0u8; 0x100];
map_data.read_exact(&mut tiles)?;
attrib_data.read_exact(&mut attrib);
attrib_data.read_exact(&mut attrib)?;
let map = Map {
width,

View file

@ -107,7 +107,7 @@ impl Player {
let constants = &state.constants;
let tex_player_name = str!("MyChar");
state.texture_set.ensure_texture_loaded(ctx, &tex_player_name)?;
state.texture_set.ensure_texture_loaded(ctx, constants, &tex_player_name)?;
Ok(Player {
x: 0,
@ -580,19 +580,15 @@ impl GameEntity for Player {
// todo draw weapon
let sb = state.texture_set.tex_map.get_mut(&self.tex_player_name);
if sb.is_none() {
return Ok(());
if let Some(batch) = state.texture_set.tex_map.get_mut(&self.tex_player_name) {
batch.add_rect(
(((self.x - self.view.left as isize) / 0x200) - (frame.x / 0x200)) as f32,
(((self.y - self.view.top as isize) / 0x200) - (frame.y / 0x200)) as f32,
&self.anim_rect,
);
batch.draw(ctx)?;
}
let batch = sb.unwrap();
batch.add_rect(
(((self.x - self.view.left as isize) / 0x200) - (frame.x / 0x200)) as f32,
(((self.y - self.view.top as isize) / 0x200) - (frame.y / 0x200)) as f32,
&self.anim_rect,
);
batch.draw(ctx)?;
Ok(())
}
}

View file

@ -1,6 +1,7 @@
use ggez::{Context, GameResult};
use ggez::nalgebra::clamp;
use log::info;
use num_traits::abs;
use crate::common::Rect;
use crate::entity::GameEntity;
@ -10,7 +11,6 @@ use crate::scene::Scene;
use crate::SharedGameState;
use crate::stage::{BackgroundType, Stage};
use crate::str;
use num_traits::abs;
pub struct GameScene {
pub tick: usize,
@ -38,8 +38,8 @@ pub enum Alignment {
}
impl GameScene {
pub fn new(state: &mut SharedGameState, ctx: &mut Context, id: usize) -> GameResult<GameScene> {
let stage = Stage::load(ctx, &state.stages[id])?;
pub fn new(state: &mut SharedGameState, ctx: &mut Context, id: usize) -> GameResult<Self> {
let stage = Stage::load(ctx, &state.base_path, &state.stages[id])?;
info!("Loaded stage: {}", stage.data.name);
info!("Map size: {}x{}", stage.map.width, stage.map.height);
@ -47,11 +47,11 @@ impl GameScene {
let tex_background_name = stage.data.background.filename();
let tex_hud_name = str!("TextBox");
state.texture_set.ensure_texture_loaded(ctx, &tex_tileset_name)?;
state.texture_set.ensure_texture_loaded(ctx, &tex_background_name)?;
state.texture_set.ensure_texture_loaded(ctx, &tex_hud_name)?;
state.texture_set.ensure_texture_loaded(ctx, &state.constants, &tex_tileset_name)?;
state.texture_set.ensure_texture_loaded(ctx, &state.constants, &tex_background_name)?;
state.texture_set.ensure_texture_loaded(ctx, &state.constants, &tex_hud_name)?;
Ok(GameScene {
Ok(Self {
tick: 0,
stage,
player: Player::new(state, ctx)?,
@ -197,50 +197,46 @@ impl GameScene {
}
fn draw_tiles(&self, state: &mut SharedGameState, ctx: &mut Context, layer: TileLayer) -> GameResult {
let set = state.texture_set.tex_map.get_mut(&self.tex_tileset_name);
if set.is_none() {
return Ok(());
}
if let Some(batch) = state.texture_set.tex_map.get_mut(&self.tex_tileset_name) {
let mut rect = Rect::<usize>::new(0, 0, 16, 16);
let mut rect = Rect::<usize>::new(0, 0, 16, 16);
let batch = set.unwrap();
let tile_start_x = clamp(self.frame.x / 0x200 / 16, 0, self.stage.map.width as isize) as usize;
let tile_start_y = clamp(self.frame.y / 0x200 / 16, 0, self.stage.map.height as isize) as usize;
let tile_end_x = clamp((self.frame.x / 0x200 + 8 + state.canvas_size.0 as isize) / 16 + 1, 0, self.stage.map.width as isize) as usize;
let tile_end_y = clamp((self.frame.y / 0x200 + 8 + state.canvas_size.1 as isize) / 16 + 1, 0, self.stage.map.height as isize) as usize;
let tile_start_x = clamp(self.frame.x / 0x200 / 16, 0, self.stage.map.width as isize) as usize;
let tile_start_y = clamp(self.frame.y / 0x200 / 16, 0, self.stage.map.height as isize) as usize;
let tile_end_x = clamp((self.frame.x / 0x200 + 8 + state.canvas_size.0 as isize) / 16 + 1, 0, self.stage.map.width as isize) as usize;
let tile_end_y = clamp((self.frame.y / 0x200 + 8 + state.canvas_size.1 as isize) / 16 + 1, 0, self.stage.map.height as isize) as usize;
for y in tile_start_y..tile_end_y {
for x in tile_start_x..tile_end_x {
let tile = *self.stage.map.tiles
.get((y * self.stage.map.width) + x)
.unwrap();
for y in tile_start_y..tile_end_y {
for x in tile_start_x..tile_end_x {
let tile = *self.stage.map.tiles
.get((y * self.stage.map.width) + x)
.unwrap();
match layer {
TileLayer::Background => {
if self.stage.map.attrib[tile as usize] >= 0x20 {
continue;
match layer {
TileLayer::Background => {
if self.stage.map.attrib[tile as usize] >= 0x20 {
continue;
}
}
}
TileLayer::Foreground => {
let attr = self.stage.map.attrib[tile as usize];
if attr < 0x40 || attr >= 0x80 {
continue;
TileLayer::Foreground => {
let attr = self.stage.map.attrib[tile as usize];
if attr < 0x40 || attr >= 0x80 {
continue;
}
}
_ => {}
}
_ => {}
rect.left = (tile as usize % 16) * 16;
rect.top = (tile as usize / 16) * 16;
rect.right = rect.left + 16;
rect.bottom = rect.top + 16;
batch.add_rect((x as f32 * 16.0 - 8.0) - (self.frame.x / 0x200) as f32, (y as f32 * 16.0 - 8.0) - (self.frame.y / 0x200) as f32, &rect);
}
rect.left = (tile as usize % 16) * 16;
rect.top = (tile as usize / 16) * 16;
rect.right = rect.left + 16;
rect.bottom = rect.top + 16;
batch.add_rect((x as f32 * 16.0 - 8.0) - (self.frame.x / 0x200) as f32, (y as f32 * 16.0 - 8.0) - (self.frame.y / 0x200) as f32, &rect);
}
}
batch.draw(ctx)?;
batch.draw(ctx)?;
}
Ok(())
}
}

View file

@ -1,18 +1,17 @@
use ggez::{Context, GameResult};
use crate::player::Player;
use crate::stage::StageData;
use crate::scene::game_scene::GameScene;
use crate::scene::Scene;
use crate::SharedGameState;
use crate::stage::StageData;
pub struct LoadingScene {
tick: usize,
}
impl LoadingScene {
pub fn new() -> LoadingScene {
LoadingScene {
pub fn new() -> Self {
Self {
tick: 0,
}
}
@ -20,14 +19,14 @@ impl LoadingScene {
impl Scene for LoadingScene {
fn init(&mut self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult {
state.texture_set.ensure_texture_loaded(ctx, "Loading")?;
state.texture_set.ensure_texture_loaded(ctx, &state.constants, "Loading")?;
Ok(())
}
fn tick(&mut self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult {
// deferred to let the loading image draw
if self.tick == 1 {
let stages = StageData::load_stage_table(ctx, "/")?;
let stages = StageData::load_stage_table(ctx, &state.base_path)?;
state.stages = stages;
state.next_scene = Some(Box::new(GameScene::new(state, ctx, 53)?));
}

View file

@ -18,11 +18,11 @@ impl SoundManager {
}
pub fn play_song(&mut self, ctx: &mut Context) -> GameResult {
self.intro.get_mut().clear();
/*self.intro.get_mut().clear();
ggez::filesystem::open(ctx, "/Soundtracks/Arranged/oside_intro.ogg")?.read_to_end(self.intro.get_mut())?;
let sink = rodio::play_once(ctx.audio_context.device(), self.intro.clone())?;
sink.detach();
sink.detach();*/
Ok(())
}

View file

@ -24,34 +24,8 @@ lazy_static! {
};
}
pub struct PixToneData {
}
pub struct PixToneData {}
pub struct PixTone {}
impl PixTone {
}
fn dupa() -> [[i8; 0x100]; 6] {
let mut seed = 0;
let mut sine = [0i8; 0x100];
let mut triangle = [0i8; 0x100];
let mut saw_up = [0i8; 0x100];
let mut saw_down = [0i8; 0x100];
let mut square = [0i8; 0x100];
let mut random = [0i8; 0x100];
for i in 0..255 {
seed = (seed * 214013) + 2531011;
sine[i] = (64.0 * (i as f32 * std::f32::consts::PI).sin()) as i8;
triangle[i] = (if (0x40 + i as isize) & 0x80 != 0 { 0x80 - i as isize } else { i as isize }) as i8;
saw_up[i] = (-0x40 + i as isize / 2) as i8;
saw_down[i] = (0x40 - i as isize / 2) as i8;
square[i] = (0x40 - (i as isize & 0x80)) as i8;
random[i] = ((seed >> 16) / 2) as i8;
}
[sine, triangle, saw_up, saw_down, square, random]
}
impl PixTone {}

View file

@ -1,7 +1,7 @@
use std::io::{Cursor, Read};
use std::str::from_utf8;
use byteorder::{LE, ReadBytesExt};
use byteorder::{BE, LE, ReadBytesExt};
use ggez::{Context, filesystem, GameResult};
use ggez::GameError::ResourceLoadError;
use log::info;
@ -63,15 +63,15 @@ pub struct Tileset {
impl Clone for Tileset {
fn clone(&self) -> Self {
Tileset {
Self {
name: self.name.clone(),
}
}
}
impl Tileset {
pub fn new(name: &str) -> Tileset {
Tileset {
pub fn new(name: &str) -> Self {
Self {
name: name.to_owned(),
}
}
@ -97,15 +97,15 @@ pub struct Background {
impl Clone for Background {
fn clone(&self) -> Self {
Background {
Self {
name: self.name.clone(),
}
}
}
impl Background {
pub fn new(name: &str) -> Background {
Background {
pub fn new(name: &str) -> Self {
Self {
name: name.to_owned(),
}
}
@ -129,17 +129,17 @@ pub enum BackgroundType {
}
impl BackgroundType {
pub fn new(id: u8) -> BackgroundType {
pub fn new(id: usize) -> Self {
match id {
0 => { BackgroundType::Stationary }
1 => { BackgroundType::MoveDistant }
2 => { BackgroundType::MoveNear }
3 => { BackgroundType::Water }
4 => { BackgroundType::Black }
5 => { BackgroundType::Autoscroll }
6 => { BackgroundType::OutsideWind }
7 => { BackgroundType::Outside }
_ => { BackgroundType::Stationary }
0 => { Self::Stationary }
1 => { Self::MoveDistant }
2 => { Self::MoveNear }
3 => { Self::Water }
4 => { Self::Black }
5 => { Self::Autoscroll }
6 => { Self::OutsideWind }
7 => { Self::Outside }
_ => { Self::Black }
}
}
}
@ -172,11 +172,13 @@ impl Clone for StageData {
}
impl StageData {
pub fn load_stage_table(ctx: &mut Context, root: &str) -> GameResult<Vec<StageData>> {
// todo: refactor to make it less repetitive.
pub fn load_stage_table(ctx: &mut Context, root: &str) -> GameResult<Vec<Self>> {
let stage_tbl_path = [root, "stage.tbl"].join("");
let mrmap_bin_path = [root, "mrmap.bin"].join("");
if filesystem::exists(ctx, &stage_tbl_path) {
// Cave Story+ stage table. Probably one of most awful formats out there.
let mut stages = Vec::new();
info!("Loading stage table from {}", &stage_tbl_path);
@ -186,10 +188,59 @@ impl StageData {
let count = data.len() / 0xe5;
let mut f = Cursor::new(data);
for i in 0..count {}
for _ in 0..count {
let mut ts_buf = vec![0u8; 0x20];
let mut map_buf = vec![0u8; 0x20];
let mut back_buf = vec![0u8; 0x20];
let mut npc_buf = vec![0u8; 0x20];
let mut boss_buf = vec![0u8; 0x20];
let mut name_jap_buf = vec![0u8; 0x20];
let mut name_buf = vec![0u8; 0x20];
f.read_exact(&mut ts_buf)?;
f.read_exact(&mut map_buf)?;
let bg_type = f.read_u32::<LE>()? as usize;
f.read_exact(&mut back_buf)?;
f.read_exact(&mut npc_buf)?;
f.read_exact(&mut boss_buf)?;
let boss_no = f.read_u8()? as usize;
f.read_exact(&mut name_jap_buf)?;
f.read_exact(&mut name_buf)?;
let tileset = from_utf8(&ts_buf)
.map_err(|_| ResourceLoadError("UTF-8 error in tileset field".to_string()))?
.trim_matches('\0').to_owned();
let map = from_utf8(&map_buf)
.map_err(|_| ResourceLoadError("UTF-8 error in map field".to_string()))?
.trim_matches('\0').to_owned();
let background = from_utf8(&back_buf)
.map_err(|_| ResourceLoadError("UTF-8 error in background field".to_string()))?
.trim_matches('\0').to_owned();
let boss = from_utf8(&boss_buf)
.map_err(|_| ResourceLoadError("UTF-8 error in boss field".to_string()))?
.trim_matches('\0').to_owned();
let name = from_utf8(&name_buf)
.map_err(|_| ResourceLoadError("UTF-8 error in name field".to_string()))?
.trim_matches('\0').to_owned();
println!("bg type: {}", bg_type);
let stage = Self {
name: name.clone(),
map: map.clone(),
boss: boss.clone(),
boss_no,
tileset: Tileset::new(&tileset),
background: Background::new(&background),
background_type: BackgroundType::new(bg_type),
npc: NpcType::Zero,
};
stages.push(stage);
}
return Ok(stages);
} else if filesystem::exists(ctx, &mrmap_bin_path) {
// CSE2 stage table
let mut stages = Vec::new();
info!("Loading stage table from {}", &mrmap_bin_path);
@ -205,18 +256,17 @@ impl StageData {
}
let mut f = Cursor::new(data);
for _ in 0..count {
let mut map_buf = Box::new(vec![0u8; 0x10]);
let mut boss_buf = Box::new(vec![0u8; 0x10]);
let mut name_buf = Box::new(vec![0u8; 0x22]);
let mut ts_buf = vec![0u8; 0x10];
let mut map_buf = vec![0u8; 0x10];
let mut back_buf = vec![0u8; 0x10];
let mut npc_buf = vec![0u8; 0x10];
let mut boss_buf = vec![0u8; 0x10];
let mut name_buf = vec![0u8; 0x22];
f.read_exact(&mut ts_buf)?;
f.read_exact(&mut map_buf)?;
let bg_type = f.read_u8()?;
let bg_type = f.read_u8()? as usize;
f.read_exact(&mut back_buf)?;
f.read_exact(&mut npc_buf)?;
f.read_exact(&mut boss_buf)?;
@ -239,7 +289,7 @@ impl StageData {
.map_err(|_| ResourceLoadError("UTF-8 error in name field".to_string()))?
.trim_matches('\0').to_owned();
let stage = StageData {
let stage = Self {
name: name.clone(),
map: map.clone(),
boss: boss.clone(),
@ -254,6 +304,7 @@ impl StageData {
return Ok(stages);
}
// todo: NXEngine stage.dat support?
Err(ResourceLoadError("No stage table found.".to_string()))
}
@ -265,12 +316,12 @@ pub struct Stage {
}
impl Stage {
pub fn load(ctx: &mut Context, data: &StageData) -> GameResult<Stage> {
let map_file = filesystem::open(ctx, ["/Stage/", &data.map, ".pxm"].join(""))?;
let attrib_file = filesystem::open(ctx, ["/Stage/", &data.tileset.name, ".pxa"].join(""))?;
pub fn load(ctx: &mut Context, root: &str, data: &StageData) -> GameResult<Self> {
let map_file = filesystem::open(ctx, [root, "Stage/", &data.map, ".pxm"].join(""))?;
let attrib_file = filesystem::open(ctx, [root, "Stage/", &data.tileset.name, ".pxa"].join(""))?;
let map = Map::load_from(map_file, attrib_file)?;
let stage = Stage {
let stage = Self {
map,
data: data.clone(),
};

View file

@ -1,13 +1,16 @@
use std::collections::HashMap;
use std::io::Read;
use ggez::{Context, GameError, GameResult};
use ggez::filesystem;
use ggez::graphics::{Drawable, DrawParam, FilterMode, Image, Rect};
use ggez::graphics::spritebatch::SpriteBatch;
use ggez::nalgebra::{Point2, Vector2};
use itertools::Itertools;
use log::info;
use crate::common;
use crate::engine_constants::EngineConstants;
use crate::str;
pub struct SizedBatch {
@ -88,25 +91,50 @@ impl TextureSet {
}
}
pub fn load_texture(&self, ctx: &mut Context, path: &str) -> GameResult<SizedBatch> {
fn load_image(&self, ctx: &mut Context, constants: &EngineConstants, path: &str) -> GameResult<Image> {
let img = {
let mut buf = Vec::new();
let mut reader = filesystem::open(ctx, path)?;
let _ = reader.read_to_end(&mut buf)?;
let mut rgba = image::load_from_memory(&buf)?.to_rgba();
// Cave Story+ data files don't have an alpha channel, therefore they need a special treatment.
if constants.is_cs_plus {
for (r, g, b, a) in rgba.iter_mut().tuples() {
if *r == 0 && *g == 0 && *b == 0 {
*a = 0;
}
}
}
rgba
};
let (width, height) = img.dimensions();
Image::from_rgba8(ctx, width as u16, height as u16, img.as_ref())
}
pub fn load_texture(&self, ctx: &mut Context, constants: &EngineConstants, name: &str) -> GameResult<SizedBatch> {
let path = FILE_TYPES
.iter()
.map(|ext| [&self.base_path, path, ext].join(""))
.map(|ext| [&self.base_path, name, ext].join(""))
.find(|path| filesystem::exists(ctx, path))
.ok_or_else(|| GameError::ResourceLoadError(format!("Texture {:?} does not exist.", path)))?;
.ok_or_else(|| GameError::ResourceLoadError(format!("Texture {:?} does not exist.", name)))?;
info!("Loading texture: {}", path);
let image = Image::new(ctx, path)?;
let image = self.load_image(ctx, constants, &path)?;
let size = image.dimensions();
assert_ne!(size.w, 0.0, "size.w == 0");
assert_ne!(size.h, 0.0, "size.h == 0");
let scale_x = 1.0;
let scale_y = 1.0;
let width = (size.w / scale_x) as usize;
let height = (size.h / scale_y) as usize;
let dim = (size.w as usize, size.h as usize);
let orig_dimensions = constants.tex_sizes.get(name).unwrap_or_else(|| &dim);
let scale_x = orig_dimensions.0 as f32 / size.w;
let scale_y = orig_dimensions.1 as f32 / size.h;
let width = (size.w * scale_x) as usize;
let height = (size.h * scale_y) as usize;
Ok(SizedBatch {
batch: SpriteBatch::new(image),
@ -119,12 +147,12 @@ impl TextureSet {
})
}
pub fn ensure_texture_loaded(&mut self, ctx: &mut Context, name: &str) -> GameResult {
pub fn ensure_texture_loaded(&mut self, ctx: &mut Context, constants: &EngineConstants, name: &str) -> GameResult {
if self.tex_map.contains_key(name) {
return Ok(());
}
let batch = self.load_texture(ctx, name)?;
let batch = self.load_texture(ctx, constants, name)?;
self.tex_map.insert(str!(name), batch);
Ok(())