Compare commits
3 Commits
feature/im
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dad59e261d | ||
|
|
93a3c8548e | ||
|
|
0a979dd8e0 |
@@ -1,7 +1,12 @@
|
|||||||
# RustyDoom
|
# RustyDoom
|
||||||
|
|
||||||
A Rust version of the original DOOM from the offically released source code found at [https://github.com/id-software/doom](https://github.com/id-software/doom)
|
A Rust version of the original DOOM base on the offically released source code found at [https://github.com/id-software/doom](https://github.com/id-software/doom)
|
||||||
|
|
||||||
This is more of a learning exercise than something good!
|
This is more of a learning exercise than something good! For example, the original `z_zone.c` and `z_zone.h` will be more "Rust-like" compared to the original version.
|
||||||
|
|
||||||
This repository will only contain the SHAREWARE verison of the original DOOM1, but will be able to run both IWAD and PWADS.
|
This repository will only contain the SHAREWARE verison of the original DOOM1, but will be able to run both IWAD and PWADS.
|
||||||
|
|
||||||
|
This repository will be done in two parts before a "release"
|
||||||
|
|
||||||
|
1. An initial port keeping as close to the original C code as possible, which some minor modifications where it is clear on how to convert the code to Rust
|
||||||
|
2. Rust-ify any (hopefully all) parts of the code, that is removing `unsafe` and other such things. This will also include breaking down some of the `uber` sized funtions of the original source into more managable bits
|
||||||
|
|||||||
@@ -8,9 +8,12 @@ use crate::m_argv;
|
|||||||
use crate::m_argv::M_CheckParm;
|
use crate::m_argv::M_CheckParm;
|
||||||
use crate::m_argv::M_GetOptionalArgumentValueByArgument;
|
use crate::m_argv::M_GetOptionalArgumentValueByArgument;
|
||||||
use crate::m_argv::PARM_NOT_FOUND;
|
use crate::m_argv::PARM_NOT_FOUND;
|
||||||
|
use crate::m_menu::M_Init;
|
||||||
use crate::m_misc::M_LoadDefaults;
|
use crate::m_misc::M_LoadDefaults;
|
||||||
|
|
||||||
|
use crate::v_video::V_Init;
|
||||||
use crate::w_wad::{W_CheckNumForName, W_InitMultipleFiles};
|
use crate::w_wad::{W_CheckNumForName, W_InitMultipleFiles};
|
||||||
|
use crate::z_zone::Z_Init;
|
||||||
|
|
||||||
use crate::doomdef::{
|
use crate::doomdef::{
|
||||||
VERSION,
|
VERSION,
|
||||||
@@ -400,19 +403,16 @@ pub fn D_DoomMain() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Implement subsytem inits
|
|
||||||
/*
|
|
||||||
println!("V_Init: allocate screens.");
|
println!("V_Init: allocate screens.");
|
||||||
V_Init();
|
V_Init();
|
||||||
*/
|
|
||||||
println!("M_LoadDefaults: Load system defaults.");
|
println!("M_LoadDefaults: Load system defaults.");
|
||||||
M_LoadDefaults();
|
M_LoadDefaults();
|
||||||
|
|
||||||
/*
|
|
||||||
println!("Z_init: Init zone memory allocation daemon.");
|
println!("Z_init: Init zone memory allocation daemon.");
|
||||||
Z_Init();
|
Z_Init();
|
||||||
|
|
||||||
*/
|
|
||||||
println!("W_Init: Init WADfiles");
|
println!("W_Init: Init WADfiles");
|
||||||
W_InitMultipleFiles(DOOMGLOBALS::with_ref(|g| g.wadfiles.clone())); // we are loading so how cares about a borrow
|
W_InitMultipleFiles(DOOMGLOBALS::with_ref(|g| g.wadfiles.clone())); // we are loading so how cares about a borrow
|
||||||
|
|
||||||
@@ -467,11 +467,12 @@ pub fn D_DoomMain() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Implement other inits
|
|
||||||
/*
|
|
||||||
println!("M_Init: Init miscellaneous info.");
|
println!("M_Init: Init miscellaneous info.");
|
||||||
M_Init();
|
M_Init();
|
||||||
|
|
||||||
|
// TODO: Implement other inits
|
||||||
|
/*
|
||||||
println!("R_Init: Init DOOM refresh daemon - ")
|
println!("R_Init: Init DOOM refresh daemon - ")
|
||||||
R_Init();
|
R_Init();
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,35 @@
|
|||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
|
|
||||||
|
/// DOOM version
|
||||||
pub const VERSION:i32 = 110;
|
pub const VERSION:i32 = 110;
|
||||||
pub const D_DEVSTR: &str = "Development mode ON.";
|
|
||||||
|
/// BASE_WIDTH
|
||||||
|
/// For resize of screen, at start of game.
|
||||||
|
/// It will not work dynamically, see visplanes. TODO: Investigate what this means.
|
||||||
|
pub const BASE_WIDTH: i32 = 320;
|
||||||
|
|
||||||
|
/// Screen scale multiplier?
|
||||||
|
/// Original source comment:
|
||||||
|
/// It is educational but futile to change this
|
||||||
|
/// scaling e.g. to 2. Drawing of status bar,
|
||||||
|
/// menues etc. is tied to the scale implied
|
||||||
|
/// by the graphics.
|
||||||
|
pub const SCREEN_MUL: i32 = 1;
|
||||||
|
|
||||||
|
/// Inverse of the aspect ratio
|
||||||
|
pub const INV_ASPECT_RATIO: f32 = 0.625; // 0.75, ideally according to the original source
|
||||||
|
|
||||||
|
/// SCREENWIDTH
|
||||||
|
/// = SCREEN_MUL*BASE_WIDTH //320
|
||||||
|
pub const SCREENWIDTH: i32 = 320;
|
||||||
|
|
||||||
|
/// SCREENHEIGHT
|
||||||
|
/// (int)(SCREEN_MUL*BASE_WIDTH*INV_ASPECT_RATIO) //200
|
||||||
|
pub const SCREENHEIGHT:i32 = 200;
|
||||||
|
|
||||||
|
|
||||||
|
/// The maximum number of players, multiplayer/networking.
|
||||||
|
pub const MAXPLAYERS: i32 = 4;
|
||||||
|
|
||||||
/// The number of state updates (ticks) to be done per second
|
/// The number of state updates (ticks) to be done per second
|
||||||
pub const TICRATE: i32 = 35;
|
pub const TICRATE: i32 = 35;
|
||||||
10
src/doomtype/mod.rs
Normal file
10
src/doomtype/mod.rs
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
const MAXCHAR: i8 = i8::MAX;
|
||||||
|
const MAXSHORT: i16 = i16::MAX;
|
||||||
|
const MAXINT: i32 = i32::MAX;
|
||||||
|
const MAXLONG: i32 = i32::MAX;
|
||||||
|
|
||||||
|
// Minimum values
|
||||||
|
const MINCHAR: i8 = i8::MIN;
|
||||||
|
const MINSHORT: i16 = i16::MIN;
|
||||||
|
const MININT: i32 = i32::MIN;
|
||||||
|
const MINLONG: i32 = i32::MIN;
|
||||||
320
src/m_menu/mod.rs
Normal file
320
src/m_menu/mod.rs
Normal file
@@ -0,0 +1,320 @@
|
|||||||
|
// Menu Widget stuff i.e episode selection etc.
|
||||||
|
|
||||||
|
// TODO: Implement d_event.handle
|
||||||
|
|
||||||
|
use std::ptr::addr_of_mut;
|
||||||
|
|
||||||
|
use crate::doomdef::{DOOMGLOBALS, GameMode};
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
struct menuitem_t {
|
||||||
|
status: i32,
|
||||||
|
name: [u8; 10],
|
||||||
|
routine: Option<fn(choice: i32)>,
|
||||||
|
|
||||||
|
// hotkey in menu
|
||||||
|
alpha_key: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
struct menu_t {
|
||||||
|
|
||||||
|
/// Number of items in the menu
|
||||||
|
numitems: i32,
|
||||||
|
|
||||||
|
/// Pointer to the previous menu
|
||||||
|
prevMenu: *mut menu_t,
|
||||||
|
|
||||||
|
/// The menu items
|
||||||
|
menuItems: *mut menuitem_t,
|
||||||
|
|
||||||
|
/// draw routine
|
||||||
|
routine: Option<fn()>,
|
||||||
|
|
||||||
|
/// X of the menu
|
||||||
|
x: i32,
|
||||||
|
|
||||||
|
/// y of the menu
|
||||||
|
y: i32,
|
||||||
|
|
||||||
|
/// The last item the user was on in the menu
|
||||||
|
lastOn: i32
|
||||||
|
}
|
||||||
|
|
||||||
|
/// TEMP function
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
fn VoidRoutine() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
fn VoidRoutineWithChoice(choice: i32) {
|
||||||
|
let _ = choice;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Main Menu
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
mod MainMenu {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
/// Enumeration of the main menu options
|
||||||
|
#[allow(non_camel_case_types)]
|
||||||
|
pub(super) enum main_e {
|
||||||
|
newgame = 0,
|
||||||
|
options,
|
||||||
|
loadgame,
|
||||||
|
savegame,
|
||||||
|
readthis,
|
||||||
|
quitdoom,
|
||||||
|
main_end
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Main Menu items
|
||||||
|
#[allow(non_upper_case_globals)]
|
||||||
|
pub(super) static mut MainMenu: [menuitem_t; 6] = [
|
||||||
|
menuitem_t {
|
||||||
|
status: 1,
|
||||||
|
name: *b"M_NGAME\0\0\0",
|
||||||
|
routine: Some(VoidRoutineWithChoice),
|
||||||
|
alpha_key: b'n'
|
||||||
|
},
|
||||||
|
menuitem_t {
|
||||||
|
status: 1,
|
||||||
|
name: *b"M_OPTION\0\0",
|
||||||
|
routine: Some(VoidRoutineWithChoice),
|
||||||
|
alpha_key: b'o'
|
||||||
|
},
|
||||||
|
menuitem_t {
|
||||||
|
status: 1,
|
||||||
|
name: *b"M_LOADG\0\0\0",
|
||||||
|
routine: Some(VoidRoutineWithChoice),
|
||||||
|
alpha_key: b'l'
|
||||||
|
},
|
||||||
|
menuitem_t {
|
||||||
|
status: 1,
|
||||||
|
name: *b"M_SAVEG\0\0\0",
|
||||||
|
routine: Some(VoidRoutineWithChoice),
|
||||||
|
alpha_key: b's'
|
||||||
|
},
|
||||||
|
menuitem_t {
|
||||||
|
status: 1,
|
||||||
|
name: *b"M_RDTHIS\0\0",
|
||||||
|
routine: Some(VoidRoutineWithChoice),
|
||||||
|
alpha_key: b'r'
|
||||||
|
},
|
||||||
|
menuitem_t {
|
||||||
|
status: 1,
|
||||||
|
name: *b"M_QUITG\0\0\0",
|
||||||
|
routine: Some(VoidRoutineWithChoice),
|
||||||
|
alpha_key: b'q'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
/// Default MainMenu
|
||||||
|
#[allow(non_upper_case_globals)]
|
||||||
|
pub(super) static mut MainDef: menu_t = menu_t {
|
||||||
|
numitems: main_e::main_end as i32,
|
||||||
|
prevMenu: std::ptr::null_mut(),
|
||||||
|
menuItems: &raw mut MainMenu as *mut menuitem_t, // Use &raw mut instead of .as_mut_ptr() to avoid illegal static mut references (Feels dirty)
|
||||||
|
routine: Some(VoidRoutine),
|
||||||
|
x: 97,
|
||||||
|
y: 64,
|
||||||
|
lastOn: 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// New Game menu
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
mod NewGameMenu {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
/// Enumeration of the New Game options
|
||||||
|
#[allow(non_camel_case_types)]
|
||||||
|
pub(super) enum newgame_e {
|
||||||
|
killthings,
|
||||||
|
toorough,
|
||||||
|
hurtme,
|
||||||
|
violence,
|
||||||
|
nightmare,
|
||||||
|
newg_end
|
||||||
|
}
|
||||||
|
|
||||||
|
/// New Game Menu items
|
||||||
|
#[allow(non_upper_case_globals)]
|
||||||
|
pub(super) static mut NewGameMenu: [menuitem_t; 5] = [
|
||||||
|
menuitem_t {
|
||||||
|
status: 1,
|
||||||
|
name: *b"M_JKILL\0\0\0",
|
||||||
|
routine: Some(VoidRoutineWithChoice),
|
||||||
|
alpha_key: b'i'
|
||||||
|
},
|
||||||
|
menuitem_t {
|
||||||
|
status: 1,
|
||||||
|
name: *b"M_ROUGH\0\0\0",
|
||||||
|
routine: Some(VoidRoutineWithChoice),
|
||||||
|
alpha_key: b'h'
|
||||||
|
},
|
||||||
|
menuitem_t {
|
||||||
|
status: 1,
|
||||||
|
name: *b"M_HURT\0\0\0\0",
|
||||||
|
routine: Some(VoidRoutineWithChoice),
|
||||||
|
alpha_key: b'h'
|
||||||
|
},
|
||||||
|
menuitem_t {
|
||||||
|
status: 1,
|
||||||
|
name: *b"M_ULTRA\0\0\0",
|
||||||
|
routine: Some(VoidRoutineWithChoice),
|
||||||
|
alpha_key: b'u'
|
||||||
|
},
|
||||||
|
menuitem_t {
|
||||||
|
status: 1,
|
||||||
|
name: *b"M_NMARE\0\0\0",
|
||||||
|
routine: Some(VoidRoutineWithChoice),
|
||||||
|
alpha_key: b'n'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
#[allow(non_upper_case_globals)]
|
||||||
|
pub(super) static mut NewDef: menu_t = menu_t {
|
||||||
|
numitems: newgame_e::newg_end as i32,
|
||||||
|
prevMenu: std::ptr::null_mut(), // TODO: Add EpiDef
|
||||||
|
menuItems: &raw mut NewGameMenu as *mut menuitem_t, // Use &raw mut instead of .as_mut_ptr() to avoid illegal static mut references (Feels dirty)
|
||||||
|
routine: Some(VoidRoutine),
|
||||||
|
x: 48,
|
||||||
|
y: 63,
|
||||||
|
lastOn: newgame_e::hurtme as i32,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: add OptionsMenu
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
mod ReadThis1 {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
/// Enumeration of the main menu options
|
||||||
|
#[allow(non_camel_case_types)]
|
||||||
|
pub(super) enum read_e {
|
||||||
|
rdthisempty1 = 0,
|
||||||
|
read1_end,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Read1 Menu items
|
||||||
|
#[allow(non_upper_case_globals)]
|
||||||
|
pub(super) static mut ReadMenu1: [menuitem_t; 1] = [
|
||||||
|
menuitem_t {
|
||||||
|
status: 1,
|
||||||
|
name: *b"\0\0\0\0\0\0\0\0\0\0",
|
||||||
|
routine: Some(VoidRoutineWithChoice),
|
||||||
|
alpha_key: b'0'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
/// Default MainMenu
|
||||||
|
#[allow(non_upper_case_globals)]
|
||||||
|
pub(super) static mut Read1Def: menu_t = menu_t {
|
||||||
|
numitems: read_e::rdthisempty1 as i32,
|
||||||
|
prevMenu: addr_of_mut!(MainMenu::MainDef),
|
||||||
|
menuItems: &raw mut ReadMenu1 as *mut menuitem_t, // Use &raw mut instead of .as_mut_ptr() to avoid illegal static mut references (Feels dirty)
|
||||||
|
routine: Some(VoidRoutine),
|
||||||
|
x: 280,
|
||||||
|
y: 185,
|
||||||
|
lastOn: 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: The rest of this hell!
|
||||||
|
|
||||||
|
#[allow(non_upper_case_globals)]
|
||||||
|
static mut currentMenu: *mut menu_t = std::ptr::null_mut();
|
||||||
|
|
||||||
|
#[allow(non_upper_case_globals)]
|
||||||
|
static mut menuactive: bool = false;
|
||||||
|
|
||||||
|
#[allow(non_upper_case_globals)]
|
||||||
|
static mut itemOn: i32 = 0;
|
||||||
|
|
||||||
|
#[allow(non_upper_case_globals)]
|
||||||
|
static mut whichSkull: i32 = 0;
|
||||||
|
|
||||||
|
#[allow(non_upper_case_globals)]
|
||||||
|
static mut skullAnimCounter: i32 = 0;
|
||||||
|
|
||||||
|
#[allow(non_upper_case_globals)]
|
||||||
|
static mut screenSize: i32 = 0;
|
||||||
|
|
||||||
|
#[allow(non_upper_case_globals)]
|
||||||
|
static mut screenBlocks: i32 = 0;
|
||||||
|
|
||||||
|
#[allow(non_upper_case_globals)]
|
||||||
|
static mut messageToPrint: i32 = 0;
|
||||||
|
|
||||||
|
#[allow(non_upper_case_globals)]
|
||||||
|
static mut messageString: *mut u8 = std::ptr::null_mut();
|
||||||
|
|
||||||
|
#[allow(non_upper_case_globals)]
|
||||||
|
static mut messageLastMenuActive: i32 = 0;
|
||||||
|
|
||||||
|
#[allow(non_upper_case_globals)]
|
||||||
|
static mut quickSaveSlot: i32 = -1;
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
pub fn M_Ticket() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
pub fn M_Drawer() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
pub fn M_Init() {
|
||||||
|
unsafe {
|
||||||
|
currentMenu = addr_of_mut!(MainMenu::MainDef);
|
||||||
|
menuactive = false;
|
||||||
|
itemOn = (*currentMenu).lastOn;
|
||||||
|
whichSkull = 0;
|
||||||
|
skullAnimCounter = 10;
|
||||||
|
screenSize = screenBlocks - 3;
|
||||||
|
messageToPrint = 0;
|
||||||
|
messageString = std::ptr::null_mut();
|
||||||
|
messageLastMenuActive = menuactive as i32;
|
||||||
|
quickSaveSlot = -1;
|
||||||
|
|
||||||
|
|
||||||
|
match DOOMGLOBALS::with_ref(|g| g.gamemode) {
|
||||||
|
GameMode::Commercial => {
|
||||||
|
/*
|
||||||
|
Original source code comment:
|
||||||
|
// This is used because DOOM 2 had only one HELP
|
||||||
|
// page. I use CREDIT as second page now, but
|
||||||
|
// kept this hack for educational purposes.
|
||||||
|
*/
|
||||||
|
MainMenu::MainMenu[MainMenu::main_e::readthis as usize] = MainMenu::MainMenu[MainMenu::main_e::quitdoom as usize];
|
||||||
|
MainMenu::MainDef.numitems -=1;
|
||||||
|
MainMenu::MainDef.y += 8;
|
||||||
|
NewGameMenu::NewDef.prevMenu = addr_of_mut!(MainMenu::MainDef);
|
||||||
|
ReadThis1::Read1Def.routine = Some(VoidRoutine);
|
||||||
|
ReadThis1::Read1Def.x = 330;
|
||||||
|
ReadThis1::Read1Def.y = 165;
|
||||||
|
ReadThis1::ReadMenu1[ReadThis1::read_e::rdthisempty1 as usize].routine = Some(VoidRoutineWithChoice);
|
||||||
|
},
|
||||||
|
GameMode::Shareware | GameMode::Registered => {
|
||||||
|
// TODO EpiDef.numitems--
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
// do nothing :)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
pub fn M_StartControlPanel() {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,20 +1,10 @@
|
|||||||
use std::ptr::addr_of_mut;
|
use std::ptr::addr_of_mut;
|
||||||
|
|
||||||
use crate::d_strings;
|
use crate::d_strings;
|
||||||
|
use crate::doomtype;
|
||||||
use crate::hu_stuff::get_chat_macro_ptr;
|
use crate::hu_stuff::get_chat_macro_ptr;
|
||||||
use crate::m_argv::{M_CheckParm, M_GetOptionalArgumentValueByArgument, PARM_NOT_FOUND};
|
use crate::m_argv::{M_CheckParm, M_GetOptionalArgumentValueByArgument, PARM_NOT_FOUND};
|
||||||
|
|
||||||
const MAXCHAR: i8 = i8::MAX;
|
|
||||||
const MAXSHORT: i16 = i16::MAX;
|
|
||||||
const MAXINT: i32 = i32::MAX;
|
|
||||||
const MAXLONG: i32 = i32::MAX;
|
|
||||||
|
|
||||||
// Minimum values
|
|
||||||
const MINCHAR: i8 = i8::MIN;
|
|
||||||
const MINSHORT: i16 = i16::MIN;
|
|
||||||
const MININT: i32 = i32::MIN;
|
|
||||||
const MINLONG: i32 = i32::MIN;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// static mut variable stuff
|
// static mut variable stuff
|
||||||
@@ -280,7 +270,6 @@ pub fn M_WriteFile(name: &str, source: std::fs::File, length: i64) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
|
|
||||||
pub fn M_ReadFile(name: &str, buffer: Vec<u8>) {
|
pub fn M_ReadFile(name: &str, buffer: Vec<u8>) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,14 @@
|
|||||||
mod d_main;
|
mod d_main;
|
||||||
mod d_strings;
|
mod d_strings;
|
||||||
mod doomdef;
|
mod doomdef;
|
||||||
|
mod doomtype;
|
||||||
mod hu_stuff;
|
mod hu_stuff;
|
||||||
mod m_argv;
|
mod m_argv;
|
||||||
|
mod m_menu;
|
||||||
mod m_misc;
|
mod m_misc;
|
||||||
|
mod v_video;
|
||||||
mod w_wad;
|
mod w_wad;
|
||||||
|
mod z_zone;
|
||||||
mod math;
|
mod math;
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
43
src/v_video/mod.rs
Normal file
43
src/v_video/mod.rs
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
use crate::doomdef::{SCREENHEIGHT, SCREENWIDTH};
|
||||||
|
use crate::doomtype;
|
||||||
|
|
||||||
|
pub const CENTERY: i32 = SCREENHEIGHT / 2;
|
||||||
|
|
||||||
|
// static var stuff
|
||||||
|
#[allow(non_upper_case_globals)]
|
||||||
|
static mut screens: [[u8; (SCREENWIDTH*SCREENHEIGHT) as usize]; 5] = [[0u8; (SCREENWIDTH*SCREENHEIGHT) as usize]; 5];
|
||||||
|
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
pub fn V_Init() {
|
||||||
|
// Do nothing :)
|
||||||
|
// the memory is already allocated
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
pub fn V_CopyRect(srcx: i32, srcy: i32, srcscrn: i32, width: i32, height: i32, destx: i32, desty: i32, destscrn: i32) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
TODO: Implement "r_data"
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
pub fn V_DrawPatch(x: i32, y: i32, scrn: i32, patch: Vec<patch_t>) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
pub fn V_DrawPatchDirect(x: i32, y: i32, scrn: i32, patch: Vec<patch_t>) {
|
||||||
|
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
pub fn V_GetBlock(x: i32, y: i32, scrn: i32, width: i32, height: i32, dest: Vec<u8>) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
pub fn V_MarkRect(x: i32, y: i32, width: i32, height: i32) {
|
||||||
|
|
||||||
|
}
|
||||||
165
src/z_zone/mod.rs
Normal file
165
src/z_zone/mod.rs
Normal file
@@ -0,0 +1,165 @@
|
|||||||
|
/// Memory allocator stuff
|
||||||
|
/// Compared to the original source, this will be some what "lean n' mean"
|
||||||
|
use std::cell::RefCell;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
|
||||||
|
/// The PurgeTags (PUs)
|
||||||
|
/// Tags < 100 are not overwritten untill freed
|
||||||
|
pub enum PurgeTag {
|
||||||
|
/// Static the entire execution time
|
||||||
|
Static = 1,
|
||||||
|
/// Static while playing
|
||||||
|
Sound = 2,
|
||||||
|
/// static while playing
|
||||||
|
Music = 3,
|
||||||
|
/// Original source comment: anything else dave wants static
|
||||||
|
Dave = 4,
|
||||||
|
/// static until level exit
|
||||||
|
Level = 50,
|
||||||
|
/// static for special thinkers in a level
|
||||||
|
LevSpec = 51,
|
||||||
|
// Tags >= 100 are "purgable" whenever needed
|
||||||
|
PurgeLevel = 100,
|
||||||
|
Cache = 101,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Provides metadata on
|
||||||
|
struct AllocMeta {
|
||||||
|
/// The size of the allocation
|
||||||
|
size: usize,
|
||||||
|
/// The PU tag associated with the allocation
|
||||||
|
tag: i32,
|
||||||
|
/// A pointer to the caller's tracking pointer, cleared automatically upon freeing
|
||||||
|
user: *mut *mut u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
thread_local! {
|
||||||
|
// We promise not to be naughty and access this from another thread :)
|
||||||
|
/// Mapping from pointers (as usize) to the correspond AllocationMeta
|
||||||
|
static REGISTRY: RefCell<HashMap<usize, AllocMeta>> = RefCell::new(HashMap::new());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper method that we can use to access the registry
|
||||||
|
fn with_registry<F, R>(f: F) -> R
|
||||||
|
where
|
||||||
|
F: FnOnce(&mut HashMap<usize, AllocMeta>) -> R
|
||||||
|
{
|
||||||
|
REGISTRY.with(|registry| f(&mut *registry.borrow_mut()))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
/// Initalized the Zone memory allocator sub-system
|
||||||
|
pub fn Z_Init() {
|
||||||
|
// do nothing, we get lazy init of the registry.
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
/// Allocate a contiguous chunk of zeroed memory from the zone allocator
|
||||||
|
/// # Safety
|
||||||
|
/// This function returns a raw pointer that bypasses Rust's automatic memory
|
||||||
|
/// tracking. The returned memory must be manually reclaimed using `Z_Free`.
|
||||||
|
pub unsafe fn Z_Malloc(size: usize, tag: i32, user: *mut *mut u8) -> *mut u8 {
|
||||||
|
let mut buffer = vec![0u8; size];
|
||||||
|
let ptr = buffer.as_mut_ptr();
|
||||||
|
|
||||||
|
// ensures Rust does not drop the buffer at the end of this block
|
||||||
|
std::mem::forget(buffer);
|
||||||
|
|
||||||
|
// Update the engine's tracking pointer if one was provided
|
||||||
|
if !user.is_null() {
|
||||||
|
unsafe {
|
||||||
|
*user = ptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save allocation details using the pointer address as the key
|
||||||
|
with_registry(|map| {
|
||||||
|
map.insert(ptr as usize, AllocMeta { size, tag, user });
|
||||||
|
});
|
||||||
|
|
||||||
|
ptr
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
/// Reclaims and frees a allocation from Z_Malloc
|
||||||
|
/// # Safety
|
||||||
|
/// The provided pointer must point to a valid allocation tracked by the registry.
|
||||||
|
/// Passing an invalid or already freed pointer can result in undefined behavior
|
||||||
|
pub unsafe fn Z_Free(ptr: *mut u8) {
|
||||||
|
if ptr.is_null() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let removed = with_registry(|map| map.remove(&(ptr as usize)));
|
||||||
|
|
||||||
|
if let Some(meta) = removed {
|
||||||
|
// Clear the caller's tracking pointer to prevent use-after-free
|
||||||
|
if !meta.user.is_null() {
|
||||||
|
unsafe {
|
||||||
|
*meta.user = std::ptr::null_mut();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// re-build the vector so Rust can drop it
|
||||||
|
unsafe {
|
||||||
|
let _dropped_vec = Vec::from_raw_parts(ptr, meta.size, meta.size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
/// Frees all memory allocations between the specific lifetime PU tags.
|
||||||
|
/// # Safety
|
||||||
|
/// All pointers tracked within this tag boundary are invalidated and deallocate
|
||||||
|
pub unsafe fn Z_FreeTags(low_tag: i32, high_tag: i32) {
|
||||||
|
|
||||||
|
// get all of the allocations to free
|
||||||
|
let tags_to_free: Vec<usize> = with_registry(|map| {
|
||||||
|
map.iter()
|
||||||
|
.filter(|(_, meta)| meta.tag >= low_tag && meta.tag <= high_tag)
|
||||||
|
.map(|(ptr_addr,_)| *ptr_addr)
|
||||||
|
.collect()
|
||||||
|
});
|
||||||
|
|
||||||
|
// remove each pointer returned from the map and drop the memory
|
||||||
|
|
||||||
|
for ptr_addr in tags_to_free {
|
||||||
|
let removed_ptr = with_registry(|map| map.remove(&ptr_addr));
|
||||||
|
|
||||||
|
if let Some(meta) = removed_ptr {
|
||||||
|
let p = ptr_addr as *mut u8;
|
||||||
|
unsafe {
|
||||||
|
// clear caller tracking pointer to preven use after free
|
||||||
|
if !meta.user.is_null() {
|
||||||
|
*meta.user = std::ptr::null_mut();
|
||||||
|
}
|
||||||
|
|
||||||
|
let _dropped_vec = Vec::from_raw_parts(p, meta.size, meta.size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Internal ChangeTag function
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
fn Z_ChangeTagInternal(ptr: *mut u8, tag: i32) {
|
||||||
|
if ptr.is_null() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
with_registry(|map| {
|
||||||
|
if let Some(meta) = map.get_mut(&(ptr as usize)) {
|
||||||
|
meta.tag = tag;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
/// Modifies the lifetime tag of an active allocation.
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
/// The provided pointer must point to a valid allocation tracked by the registry
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
pub unsafe fn Z_ChangeTag(ptr: *mut u8, tag: i32) {
|
||||||
|
// removes the original helper macro from the original C, we don't need withcraft here
|
||||||
|
Z_ChangeTagInternal(ptr, tag);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user