Debug FPS display with rendering backend info
This commit is contained in:
1 parent
ee7b76fa6a
commit
07371cc893
8 files changed
+133
-4
No files matched your search
@@ -339,6 +339,7 @@ dir.nw = Nordwesten
|
|||||||
|
|
||||||
val.auto = Auto ({0}x)
|
val.auto = Auto ({0}x)
|
||||||
set.render_scale = 3D-Auflösung
|
set.render_scale = 3D-Auflösung
|
||||||
|
set.debug_fps = FPS-Anzeige
|
||||||
|
|
||||||
hint.pickup_prisoner_where = Gefangene können nur auf eigenem Gebiet aufgehoben werden.
|
hint.pickup_prisoner_where = Gefangene können nur auf eigenem Gebiet aufgehoben werden.
|
||||||
hint.punch_where = Die Hand kann Helden nur auf eigenem Gebiet schlagen.
|
hint.punch_where = Die Hand kann Helden nur auf eigenem Gebiet schlagen.
|
||||||
|
|||||||
@@ -340,6 +340,7 @@ dir.nw = north-west
|
|||||||
|
|
||||||
val.auto = Auto ({0}x)
|
val.auto = Auto ({0}x)
|
||||||
set.render_scale = 3D resolution
|
set.render_scale = 3D resolution
|
||||||
|
set.debug_fps = FPS debug
|
||||||
|
|
||||||
hint.pickup_prisoner_where = Prisoners can only be picked up on your own territory.
|
hint.pickup_prisoner_where = Prisoners can only be picked up on your own territory.
|
||||||
hint.punch_where = The hand can only punch heroes on your own territory.
|
hint.punch_where = The hand can only punch heroes on your own territory.
|
||||||
|
|||||||
+35
-2
@@ -394,6 +394,8 @@ struct App {
|
|||||||
ws_id: i32,
|
ws_id: i32,
|
||||||
match_mode: bool,
|
match_mode: bool,
|
||||||
coop: bool,
|
coop: bool,
|
||||||
|
fps: f32,
|
||||||
|
renderer: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl App {
|
impl App {
|
||||||
@@ -600,7 +602,7 @@ async fn main() {
|
|||||||
let seed = (miniquad::date::now() * 1000.0) as u32 | 1;
|
let seed = (miniquad::date::now() * 1000.0) as u32 | 1;
|
||||||
// behind the title menu: the endless bridge battle
|
// behind the title menu: the endless bridge battle
|
||||||
let (game, cam) = Game::new_demo(seed);
|
let (game, cam) = Game::new_demo(seed);
|
||||||
let mut app = App { game, cam, settings, seed, status: None, recorded: false, client: MatchClient::new(), ws_id: 0, match_mode: false, coop: false };
|
let mut app = App { game, cam, settings, seed, status: None, recorded: false, client: MatchClient::new(), ws_id: 0, match_mode: false, coop: false, fps: 0.0, renderer: platform::renderer() };
|
||||||
menu.progress = platform::storage_get(PROGRESS_KEY).and_then(|s| serde_json::from_str(&s).ok()).unwrap_or_default();
|
menu.progress = platform::storage_get(PROGRESS_KEY).and_then(|s| serde_json::from_str(&s).ok()).unwrap_or_default();
|
||||||
app.game.hints = app.settings.hints;
|
app.game.hints = app.settings.hints;
|
||||||
let mut inp = Input { ldown: None, rdown: None, rlast: (0.0, 0.0), rdrag: false, mlast: None, minimap_drag: false, tlast: None, touch_world: false, inspect: None };
|
let mut inp = Input { ldown: None, rdown: None, rlast: (0.0, 0.0), rdrag: false, mlast: None, minimap_drag: false, tlast: None, touch_world: false, inspect: None };
|
||||||
@@ -614,8 +616,11 @@ async fn main() {
|
|||||||
let mut cache_t = 0.0f32;
|
let mut cache_t = 0.0f32;
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let dt = get_frame_time().min(0.1);
|
let raw_dt = get_frame_time();
|
||||||
|
let dt = raw_dt.min(0.1);
|
||||||
let now = get_time();
|
let now = get_time();
|
||||||
|
let fps_now = 1.0 / raw_dt.max(0.001);
|
||||||
|
app.fps = if app.fps <= 0.0 { fps_now } else { app.fps + (fps_now - app.fps) * 0.08 };
|
||||||
let mut settings_changed = false;
|
let mut settings_changed = false;
|
||||||
|
|
||||||
// ---------------- touch or mouse: which interface is active
|
// ---------------- touch or mouse: which interface is active
|
||||||
@@ -1423,4 +1428,32 @@ fn draw_frame(app: &mut App, gfx: &Gfx, r3d: &mut R3d, ui: &mut Ui, menu: &mut M
|
|||||||
if !touch {
|
if !touch {
|
||||||
ui.draw_cursor(gfx, &app.game, now, blocked);
|
ui.draw_cursor(gfx, &app.game, now, blocked);
|
||||||
}
|
}
|
||||||
|
if app.settings.debug_fps {
|
||||||
|
draw_debug_fps(app, gfx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn draw_debug_fps(app: &App, gfx: &Gfx) {
|
||||||
|
ui::begin_ui();
|
||||||
|
let scale = ui::SMALL().max(1.0);
|
||||||
|
let fps = app.fps.max(0.0).round() as i32;
|
||||||
|
let renderer = {
|
||||||
|
let r = app.renderer.trim();
|
||||||
|
if r.is_empty() {
|
||||||
|
if cfg!(target_arch = "wasm32") {
|
||||||
|
"WebGL"
|
||||||
|
} else {
|
||||||
|
"OpenGL"
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
r
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let max_cols = (((ui::sw() - 6.0) / ui::CW()).floor() as i32).max(12) as usize;
|
||||||
|
let line: String = format!("{} FPS {}", fps, renderer).chars().take(max_cols).collect();
|
||||||
|
let w = gfx.measure(&line, scale);
|
||||||
|
let x = (ui::sw() - w - 2.0).max(2.0);
|
||||||
|
let y = 2.0;
|
||||||
|
draw_rectangle(x - 2.0, y - 2.0, w + 4.0, scale * 10.0 + 4.0, Color::from_rgba(0, 0, 0, 150));
|
||||||
|
gfx.text(&line, x, y, scale, GOLD);
|
||||||
}
|
}
|
||||||
+5
-1
@@ -50,6 +50,7 @@ pub enum Item {
|
|||||||
Lights,
|
Lights,
|
||||||
UiScale,
|
UiScale,
|
||||||
RenderScale,
|
RenderScale,
|
||||||
|
DebugFps,
|
||||||
GameSpeed,
|
GameSpeed,
|
||||||
Hints,
|
Hints,
|
||||||
TouchUi,
|
TouchUi,
|
||||||
@@ -62,7 +63,7 @@ fn tab_items(tab: usize) -> &'static [Item] {
|
|||||||
0 => &[Language, Volume, MusicVolume, Mute, Voice],
|
0 => &[Language, Volume, MusicVolume, Mute, Voice],
|
||||||
1 => &[RotateSpeed, PanSpeed, ZoomSpeed, EdgeScroll, InvertMouse],
|
1 => &[RotateSpeed, PanSpeed, ZoomSpeed, EdgeScroll, InvertMouse],
|
||||||
2 => &[Outlines, WallDetail, Lights, UiScale, RenderScale],
|
2 => &[Outlines, WallDetail, Lights, UiScale, RenderScale],
|
||||||
3 => &[GameSpeed, Hints, TouchUi],
|
3 => &[GameSpeed, Hints, TouchUi, DebugFps],
|
||||||
_ => &[],
|
_ => &[],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -83,6 +84,7 @@ fn item_label(it: Item) -> String {
|
|||||||
Item::Lights => "set.lights",
|
Item::Lights => "set.lights",
|
||||||
Item::UiScale => "set.ui_scale",
|
Item::UiScale => "set.ui_scale",
|
||||||
Item::RenderScale => "set.render_scale",
|
Item::RenderScale => "set.render_scale",
|
||||||
|
Item::DebugFps => "set.debug_fps",
|
||||||
Item::GameSpeed => "set.game_speed",
|
Item::GameSpeed => "set.game_speed",
|
||||||
Item::Hints => "set.hints",
|
Item::Hints => "set.hints",
|
||||||
Item::TouchUi => "set.touch_ui",
|
Item::TouchUi => "set.touch_ui",
|
||||||
@@ -124,6 +126,7 @@ fn item_value(it: Item, s: &Settings) -> String {
|
|||||||
format!("{}x", s.ui_factor)
|
format!("{}x", s.ui_factor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Item::DebugFps => onoff(s.debug_fps),
|
||||||
Item::RenderScale => {
|
Item::RenderScale => {
|
||||||
// the setting is for a 1080 pixel high window; show what applies to this one
|
// the setting is for a 1080 pixel high window; show what applies to this one
|
||||||
let now = crate::render3d::effective_div(s.render_scale.max(1) as u32, crate::ui::sh());
|
let now = crate::render3d::effective_div(s.render_scale.max(1) as u32, crate::ui::sh());
|
||||||
@@ -174,6 +177,7 @@ fn item_change(it: Item, s: &mut Settings, d: i32) {
|
|||||||
Item::Lights => s.max_lights = cycle(&[8u8, 16, 24], s.max_lights, d),
|
Item::Lights => s.max_lights = cycle(&[8u8, 16, 24], s.max_lights, d),
|
||||||
Item::UiScale => s.ui_factor = cycle(&[0u8, 1, 2, 3, 4], s.ui_factor, d),
|
Item::UiScale => s.ui_factor = cycle(&[0u8, 1, 2, 3, 4], s.ui_factor, d),
|
||||||
Item::RenderScale => s.render_scale = cycle(&(1u8..=16).collect::<Vec<u8>>(), s.render_scale.clamp(1, 16), d),
|
Item::RenderScale => s.render_scale = cycle(&(1u8..=16).collect::<Vec<u8>>(), s.render_scale.clamp(1, 16), d),
|
||||||
|
Item::DebugFps => s.debug_fps = !s.debug_fps,
|
||||||
Item::GameSpeed => s.game_speed = cycle(&[1.0f32, 2.0], s.game_speed, d),
|
Item::GameSpeed => s.game_speed = cycle(&[1.0f32, 2.0], s.game_speed, d),
|
||||||
Item::Hints => s.hints = !s.hints,
|
Item::Hints => s.hints = !s.hints,
|
||||||
Item::TouchUi => s.touch_ui = cycle(&[0u8, 1, 2], s.touch_ui, d),
|
Item::TouchUi => s.touch_ui = cycle(&[0u8, 1, 2], s.touch_ui, d),
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ mod imp {
|
|||||||
fn dc_ws_send(id: i32, p: *const u8, pl: u32) -> i32;
|
fn dc_ws_send(id: i32, p: *const u8, pl: u32) -> i32;
|
||||||
fn dc_ws_take(id: i32) -> i32;
|
fn dc_ws_take(id: i32) -> i32;
|
||||||
fn dc_ws_close(id: i32);
|
fn dc_ws_close(id: i32);
|
||||||
|
fn dc_renderer() -> i32;
|
||||||
}
|
}
|
||||||
|
|
||||||
// starts a request; poll the returned id with http_poll()
|
// starts a request; poll the returned id with http_poll()
|
||||||
@@ -171,6 +172,18 @@ mod imp {
|
|||||||
unsafe { dc_ws_close(id) }
|
unsafe { dc_ws_close(id) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn renderer() -> String {
|
||||||
|
unsafe {
|
||||||
|
let n = dc_renderer();
|
||||||
|
if n < 0 {
|
||||||
|
return String::new();
|
||||||
|
}
|
||||||
|
let mut buf = vec![0u8; n as usize];
|
||||||
|
dc_storage_take(buf.as_mut_ptr());
|
||||||
|
String::from_utf8(buf).unwrap_or_default()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
@@ -233,6 +246,21 @@ mod imp {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
pub fn ws_close(_id: i32) {}
|
pub fn ws_close(_id: i32) {}
|
||||||
|
|
||||||
|
pub fn renderer() -> String {
|
||||||
|
#[cfg(target_vendor = "apple")]
|
||||||
|
{
|
||||||
|
use macroquad::miniquad::conf::AppleGfxApi;
|
||||||
|
return match macroquad::miniquad::window::apple_gfx_api() {
|
||||||
|
AppleGfxApi::Metal => "Metal".into(),
|
||||||
|
AppleGfxApi::OpenGl => "OpenGL".into(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#[cfg(not(target_vendor = "apple"))]
|
||||||
|
{
|
||||||
|
return "OpenGL".into();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub use imp::*;
|
pub use imp::*;
|
||||||
|
|||||||
@@ -150,6 +150,7 @@ pub struct Settings {
|
|||||||
pub ui_factor: u8, // interface size: 0 = automatic, 1..4 = fixed integer factor
|
pub ui_factor: u8, // interface size: 0 = automatic, 1..4 = fixed integer factor
|
||||||
pub render_scale: u8, // 3D world resolution divisor: 1 = full, 2..16 = pixel look
|
pub render_scale: u8, // 3D world resolution divisor: 1 = full, 2..16 = pixel look
|
||||||
pub touch_ui: u8, // touch interface: 0 = automatic (after the first touch), 1 = on, 2 = off
|
pub touch_ui: u8, // touch interface: 0 = automatic (after the first touch), 1 = on, 2 = off
|
||||||
|
pub debug_fps: bool, // show FPS and rendering backend
|
||||||
// game
|
// game
|
||||||
pub game_speed: f32, // 1 or 2
|
pub game_speed: f32, // 1 or 2
|
||||||
pub hints: bool,
|
pub hints: bool,
|
||||||
@@ -179,6 +180,7 @@ impl Default for Settings {
|
|||||||
ui_factor: 0,
|
ui_factor: 0,
|
||||||
render_scale: 1,
|
render_scale: 1,
|
||||||
touch_ui: 0,
|
touch_ui: 0,
|
||||||
|
debug_fps: false,
|
||||||
game_speed: 1.0,
|
game_speed: 1.0,
|
||||||
hints: true,
|
hints: true,
|
||||||
difficulty: 1,
|
difficulty: 1,
|
||||||
@@ -225,3 +227,19 @@ impl Settings {
|
|||||||
serde_json::from_str(s).ok()
|
serde_json::from_str(s).ok()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn debug_fps_round_trips() {
|
||||||
|
let mut s = Settings::default();
|
||||||
|
assert!(!s.debug_fps);
|
||||||
|
s.debug_fps = true;
|
||||||
|
let l = Settings::from_json(&s.to_json()).expect("settings serialize back");
|
||||||
|
assert!(l.debug_fps);
|
||||||
|
let old = Settings::from_json(r#"{"language":"en","map_w":64,"map_h":64}"#).expect("old settings remain readable");
|
||||||
|
assert!(!old.debug_fps);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -261,5 +261,49 @@
|
|||||||
window.addEventListener(ev, startAudio, true);
|
window.addEventListener(ev, startAudio, true);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function gfxInfo() {
|
||||||
|
try {
|
||||||
|
var canvas = document.getElementById("glcanvas");
|
||||||
|
if (!canvas) {
|
||||||
|
var cs = document.getElementsByTagName("canvas");
|
||||||
|
canvas = cs.length ? cs[0] : null;
|
||||||
|
}
|
||||||
|
if (!canvas) return "";
|
||||||
|
var gl = canvas.getContext("webgl2");
|
||||||
|
var version = "WebGL 2";
|
||||||
|
if (!gl) {
|
||||||
|
gl = canvas.getContext("webgl");
|
||||||
|
version = "WebGL 1";
|
||||||
|
}
|
||||||
|
if (!gl) return "";
|
||||||
|
var versionName = gl.getParameter(gl.VERSION) || version;
|
||||||
|
var dbg = gl.getExtension("WEBGL_debug_renderer_info");
|
||||||
|
var gpu = dbg ? gl.getParameter(dbg.UNMASKED_RENDERER_WEBGL) || "" : "";
|
||||||
|
var vendor = dbg ? gl.getParameter(dbg.UNMASKED_VENDOR_WEBGL) || "" : "";
|
||||||
|
var api = "WebGL";
|
||||||
|
var all = versionName + " " + gpu + " " + vendor;
|
||||||
|
if (all.indexOf("Vulkan") >= 0) api = "Vulkan";
|
||||||
|
else if (all.indexOf("Metal") >= 0) api = "Metal";
|
||||||
|
else if (all.indexOf("Direct3D") >= 0 || all.indexOf("D3D") >= 0) api = "D3D";
|
||||||
|
else if (all.indexOf("OpenGL") >= 0) api = "OpenGL";
|
||||||
|
return versionName + " | " + api + " | " + (gpu || vendor || api);
|
||||||
|
} catch (e) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function registerGfx(importObject) {
|
||||||
|
importObject.env.dc_renderer = function () {
|
||||||
|
pending = new TextEncoder().encode(gfxInfo());
|
||||||
|
return pending.length;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
var oldRegister = register;
|
||||||
|
register = function (importObject) {
|
||||||
|
oldRegister(importObject);
|
||||||
|
registerGfx(importObject);
|
||||||
|
};
|
||||||
|
|
||||||
miniquad_add_plugin({ register_plugin: register, version: 1, name: "dungeoncraft" });
|
miniquad_add_plugin({ register_plugin: register, version: 1, name: "dungeoncraft" });
|
||||||
})();
|
})();
|
||||||
Reference in new issue
Block a user