scaling / ui tweaks, persistent timing
This commit is contained in:
parent
4854d9e758
commit
d147242199
|
@ -1,5 +1,5 @@
|
||||||
use crate::common::Rect;
|
use crate::common::Rect;
|
||||||
use crate::components::draw_common::{Alignment, draw_number};
|
use crate::components::draw_common::{draw_number, Alignment};
|
||||||
use crate::entity::GameEntity;
|
use crate::entity::GameEntity;
|
||||||
use crate::frame::Frame;
|
use crate::frame::Frame;
|
||||||
use crate::framework::context::Context;
|
use crate::framework::context::Context;
|
||||||
|
@ -61,6 +61,15 @@ impl InventoryUI {
|
||||||
fn get_item_event_number_action(&self, inventory: &Inventory) -> u16 {
|
fn get_item_event_number_action(&self, inventory: &Inventory) -> u16 {
|
||||||
inventory.get_item_idx(self.selected_item as usize).map(|i| i.0 + 6000).unwrap_or(6000)
|
inventory.get_item_idx(self.selected_item as usize).map(|i| i.0 + 6000).unwrap_or(6000)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn exit(&mut self, state: &mut SharedGameState, player: &mut Player, inventory: &mut Inventory) {
|
||||||
|
self.focus = InventoryFocus::None;
|
||||||
|
inventory.current_item = 0;
|
||||||
|
self.text_y_pos = 16;
|
||||||
|
state.textscript_vm.reset();
|
||||||
|
state.textscript_vm.set_mode(ScriptMode::Map);
|
||||||
|
player.controller.update_trigger();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GameEntity<(&mut Context, &mut Player, &mut Inventory)> for InventoryUI {
|
impl GameEntity<(&mut Context, &mut Player, &mut Inventory)> for InventoryUI {
|
||||||
|
@ -80,12 +89,7 @@ impl GameEntity<(&mut Context, &mut Player, &mut Inventory)> for InventoryUI {
|
||||||
|| player.controller.trigger_menu_back()
|
|| player.controller.trigger_menu_back()
|
||||||
|| (state.settings.touch_controls && state.touch_controls.consume_click_in(slot_rect)))
|
|| (state.settings.touch_controls && state.touch_controls.consume_click_in(slot_rect)))
|
||||||
{
|
{
|
||||||
self.focus = InventoryFocus::None;
|
self.exit(state, player, inventory);
|
||||||
inventory.current_item = 0;
|
|
||||||
self.text_y_pos = 16;
|
|
||||||
state.textscript_vm.reset();
|
|
||||||
state.textscript_vm.set_mode(ScriptMode::Map);
|
|
||||||
player.controller.update_trigger();
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -231,6 +235,7 @@ impl GameEntity<(&mut Context, &mut Player, &mut Inventory)> for InventoryUI {
|
||||||
self.selected_weapon = i;
|
self.selected_weapon = i;
|
||||||
inventory.current_weapon = i;
|
inventory.current_weapon = i;
|
||||||
state.textscript_vm.start_script(get_weapon_event_number(inventory));
|
state.textscript_vm.start_script(get_weapon_event_number(inventory));
|
||||||
|
self.exit(state, player, inventory);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -128,6 +128,13 @@ fn get_insets() -> GameResult<(f32, f32, f32, f32)> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_scaled_size(width: u32, height: u32) -> (f32, f32) {
|
||||||
|
let scaled_height = ((height / 480).max(1) * 480) as f32;
|
||||||
|
let scaled_width = width as f32 * (scaled_height as f32 / height as f32);
|
||||||
|
|
||||||
|
(scaled_width, scaled_height)
|
||||||
|
}
|
||||||
|
|
||||||
impl BackendEventLoop for GlutinEventLoop {
|
impl BackendEventLoop for GlutinEventLoop {
|
||||||
fn run(&mut self, game: &mut Game, ctx: &mut Context) {
|
fn run(&mut self, game: &mut Game, ctx: &mut Context) {
|
||||||
let event_loop = EventLoop::new();
|
let event_loop = EventLoop::new();
|
||||||
|
@ -137,7 +144,8 @@ impl BackendEventLoop for GlutinEventLoop {
|
||||||
|
|
||||||
{
|
{
|
||||||
let size = window.window().inner_size();
|
let size = window.window().inner_size();
|
||||||
ctx.screen_size = (size.width.max(1) as f32, size.height.max(1) as f32);
|
ctx.real_screen_size = (size.width, size.height);
|
||||||
|
ctx.screen_size = get_scaled_size(size.width.max(1), size.height.max(1));
|
||||||
state_ref.handle_resize(ctx).unwrap();
|
state_ref.handle_resize(ctx).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -188,7 +196,8 @@ impl BackendEventLoop for GlutinEventLoop {
|
||||||
imgui.io_mut().display_size = [size.width as f32, size.height as f32];
|
imgui.io_mut().display_size = [size.width as f32, size.height as f32];
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.screen_size = (size.width as f32, size.height as f32);
|
ctx.real_screen_size = (size.width, size.height);
|
||||||
|
ctx.screen_size = get_scaled_size(size.width.max(1), size.height.max(1));
|
||||||
state_ref.handle_resize(ctx).unwrap();
|
state_ref.handle_resize(ctx).unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -197,19 +206,21 @@ impl BackendEventLoop for GlutinEventLoop {
|
||||||
{
|
{
|
||||||
let mut controls = &mut state_ref.touch_controls;
|
let mut controls = &mut state_ref.touch_controls;
|
||||||
let scale = state_ref.scale as f64;
|
let scale = state_ref.scale as f64;
|
||||||
|
let loc_x = (touch.location.x * ctx.screen_size.0 as f64 / ctx.real_screen_size.0 as f64) / scale;
|
||||||
|
let loc_y = (touch.location.y * ctx.screen_size.1 as f64 / ctx.real_screen_size.1 as f64) / scale;
|
||||||
|
|
||||||
match touch.phase {
|
match touch.phase {
|
||||||
TouchPhase::Started | TouchPhase::Moved => {
|
TouchPhase::Started | TouchPhase::Moved => {
|
||||||
if let Some(point) = controls.points.iter_mut().find(|p| p.id == touch.id) {
|
if let Some(point) = controls.points.iter_mut().find(|p| p.id == touch.id) {
|
||||||
point.last_position = point.position;
|
point.last_position = point.position;
|
||||||
point.position = (touch.location.x / scale, touch.location.y / scale);
|
point.position = (loc_x, loc_y);
|
||||||
} else {
|
} else {
|
||||||
controls.touch_id_counter = controls.touch_id_counter.wrapping_add(1);
|
controls.touch_id_counter = controls.touch_id_counter.wrapping_add(1);
|
||||||
|
|
||||||
let point = TouchPoint {
|
let point = TouchPoint {
|
||||||
id: touch.id,
|
id: touch.id,
|
||||||
touch_id: controls.touch_id_counter,
|
touch_id: controls.touch_id_counter,
|
||||||
position: (touch.location.x / scale, touch.location.y / scale),
|
position: (loc_x, loc_y),
|
||||||
last_position: (0.0, 0.0),
|
last_position: (0.0, 0.0),
|
||||||
};
|
};
|
||||||
controls.points.push(point);
|
controls.points.push(point);
|
||||||
|
|
|
@ -9,6 +9,7 @@ pub struct Context {
|
||||||
pub(crate) filesystem: Filesystem,
|
pub(crate) filesystem: Filesystem,
|
||||||
pub(crate) renderer: Option<Box<dyn BackendRenderer>>,
|
pub(crate) renderer: Option<Box<dyn BackendRenderer>>,
|
||||||
pub(crate) keyboard_context: KeyboardContext,
|
pub(crate) keyboard_context: KeyboardContext,
|
||||||
|
pub(crate) real_screen_size: (u32, u32),
|
||||||
pub(crate) screen_size: (f32, f32),
|
pub(crate) screen_size: (f32, f32),
|
||||||
pub(crate) screen_insets: (f32, f32, f32, f32),
|
pub(crate) screen_insets: (f32, f32, f32, f32),
|
||||||
}
|
}
|
||||||
|
@ -20,6 +21,7 @@ impl Context {
|
||||||
filesystem: Filesystem::new(),
|
filesystem: Filesystem::new(),
|
||||||
renderer: None,
|
renderer: None,
|
||||||
keyboard_context: KeyboardContext::new(),
|
keyboard_context: KeyboardContext::new(),
|
||||||
|
real_screen_size: (320, 240),
|
||||||
screen_size: (320.0, 240.0),
|
screen_size: (320.0, 240.0),
|
||||||
screen_insets: (0.0, 0.0, 0.0, 0.0),
|
screen_insets: (0.0, 0.0, 0.0, 0.0),
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ use std::cell::{RefCell, UnsafeCell};
|
||||||
use std::ffi::{c_void, CStr};
|
use std::ffi::{c_void, CStr};
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::mem::MaybeUninit;
|
use std::mem::MaybeUninit;
|
||||||
|
use std::ptr::null;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use imgui::{DrawCmd, DrawCmdParams, DrawData, DrawIdx, DrawVert};
|
use imgui::{DrawCmd, DrawCmdParams, DrawData, DrawIdx, DrawVert};
|
||||||
|
@ -395,6 +396,9 @@ struct ImguiData {
|
||||||
ebo: GLuint,
|
ebo: GLuint,
|
||||||
font_texture: GLuint,
|
font_texture: GLuint,
|
||||||
font_tex_size: (f32, f32),
|
font_tex_size: (f32, f32),
|
||||||
|
surf_framebuffer: GLuint,
|
||||||
|
surf_texture: GLuint,
|
||||||
|
last_size: (u32, u32),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ImguiData {
|
impl ImguiData {
|
||||||
|
@ -409,6 +413,9 @@ impl ImguiData {
|
||||||
ebo: 0,
|
ebo: 0,
|
||||||
font_texture: 0,
|
font_texture: 0,
|
||||||
font_tex_size: (1.0, 1.0),
|
font_tex_size: (1.0, 1.0),
|
||||||
|
surf_framebuffer: 0,
|
||||||
|
surf_texture: 0,
|
||||||
|
last_size: (320, 240),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -510,7 +517,36 @@ impl ImguiData {
|
||||||
atlas.tex_id = (self.font_texture as usize).into();
|
atlas.tex_id = (self.font_texture as usize).into();
|
||||||
}
|
}
|
||||||
|
|
||||||
gl.gl.BindTexture(gl::TEXTURE_2D, current_texture as _);
|
let texture_id = return_param(|x| gl.gl.GenTextures(1, x));
|
||||||
|
|
||||||
|
gl.gl.BindTexture(gl::TEXTURE_2D, texture_id);
|
||||||
|
gl.gl.TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::LINEAR as _);
|
||||||
|
gl.gl.TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::LINEAR as _);
|
||||||
|
|
||||||
|
gl.gl.TexImage2D(
|
||||||
|
gl::TEXTURE_2D,
|
||||||
|
0,
|
||||||
|
gl::RGBA as _,
|
||||||
|
320 as _,
|
||||||
|
240 as _,
|
||||||
|
0,
|
||||||
|
gl::RGBA,
|
||||||
|
gl::UNSIGNED_BYTE,
|
||||||
|
null() as _,
|
||||||
|
);
|
||||||
|
|
||||||
|
gl.gl.BindTexture(gl::TEXTURE_2D, 0 as _);
|
||||||
|
|
||||||
|
self.surf_texture = texture_id;
|
||||||
|
|
||||||
|
let framebuffer_id = return_param(|x| gl.gl.GenFramebuffers(1, x));
|
||||||
|
|
||||||
|
gl.gl.BindFramebuffer(gl::FRAMEBUFFER, framebuffer_id);
|
||||||
|
gl.gl.FramebufferTexture2D(gl::FRAMEBUFFER, gl::COLOR_ATTACHMENT0, gl::TEXTURE_2D, texture_id, 0);
|
||||||
|
let draw_buffers = [gl::COLOR_ATTACHMENT0];
|
||||||
|
gl.gl.DrawBuffers(1, draw_buffers.as_ptr() as _);
|
||||||
|
|
||||||
|
self.surf_framebuffer = framebuffer_id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -631,10 +667,36 @@ impl BackendRenderer for OpenGLRenderer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some((context, gl)) = self.get_context() {
|
let ImguiData { program_tex, surf_texture, tex_locs: Locs { proj_mtx, .. }, .. } = self.imgui_data;
|
||||||
unsafe {
|
|
||||||
gl.gl.Finish();
|
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
if let Some((_, gl)) = self.get_context() {
|
||||||
|
gl.gl.BindFramebuffer(gl::FRAMEBUFFER, 0);
|
||||||
|
gl.gl.ClearColor(0.0, 0.0, 0.0, 1.0);
|
||||||
|
gl.gl.Clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT);
|
||||||
|
|
||||||
|
let matrix =
|
||||||
|
[[2.0f32, 0.0, 0.0, 0.0], [0.0, -2.0, 0.0, 0.0], [0.0, 0.0, -1.0, 0.0], [-1.0, 1.0, 0.0, 1.0]];
|
||||||
|
|
||||||
|
gl.gl.UseProgram(program_tex);
|
||||||
|
gl.gl.UniformMatrix4fv(proj_mtx, 1, gl::FALSE, matrix.as_ptr() as _);
|
||||||
|
|
||||||
|
let color = (255, 255, 255, 255);
|
||||||
|
let vertices = vec![
|
||||||
|
VertexData { position: (0.0, 1.0), uv: (0.0, 0.0), color },
|
||||||
|
VertexData { position: (0.0, 0.0), uv: (0.0, 1.0), color },
|
||||||
|
VertexData { position: (1.0, 0.0), uv: (1.0, 1.0), color },
|
||||||
|
VertexData { position: (0.0, 1.0), uv: (0.0, 0.0), color },
|
||||||
|
VertexData { position: (1.0, 0.0), uv: (1.0, 1.0), color },
|
||||||
|
VertexData { position: (1.0, 1.0), uv: (1.0, 0.0), color },
|
||||||
|
];
|
||||||
|
|
||||||
|
self.draw_arrays_tex_id(gl::TRIANGLES, vertices, surf_texture, BackendShader::Texture)?;
|
||||||
|
|
||||||
|
gl.gl.Finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some((context, _)) = self.get_context() {
|
||||||
(context.swap_buffers)(&mut context.user_data);
|
(context.swap_buffers)(&mut context.user_data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -645,11 +707,35 @@ impl BackendRenderer for OpenGLRenderer {
|
||||||
fn prepare_draw(&mut self, width: f32, height: f32) -> GameResult {
|
fn prepare_draw(&mut self, width: f32, height: f32) -> GameResult {
|
||||||
if let Some((_, gl)) = self.get_context() {
|
if let Some((_, gl)) = self.get_context() {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
let (width_u, height_u) = (width as u32, height as u32);
|
||||||
|
if self.imgui_data.last_size != (width_u, height_u) {
|
||||||
|
gl.gl.BindFramebuffer(gl::FRAMEBUFFER, 0);
|
||||||
|
gl.gl.BindTexture(gl::TEXTURE_2D, self.imgui_data.surf_texture);
|
||||||
|
|
||||||
|
gl.gl.TexImage2D(
|
||||||
|
gl::TEXTURE_2D,
|
||||||
|
0,
|
||||||
|
gl::RGBA as _,
|
||||||
|
width_u as _,
|
||||||
|
height_u as _,
|
||||||
|
0,
|
||||||
|
gl::RGBA,
|
||||||
|
gl::UNSIGNED_BYTE,
|
||||||
|
null() as _,
|
||||||
|
);
|
||||||
|
|
||||||
|
gl.gl.BindTexture(gl::TEXTURE_2D, 0 as _);
|
||||||
|
}
|
||||||
|
|
||||||
|
gl.gl.BindFramebuffer(gl::FRAMEBUFFER, self.imgui_data.surf_framebuffer);
|
||||||
|
gl.gl.ClearColor(0.0, 0.0, 0.0, 0.0);
|
||||||
|
gl.gl.Clear(gl::COLOR_BUFFER_BIT);
|
||||||
|
|
||||||
gl.gl.ActiveTexture(gl::TEXTURE0);
|
gl.gl.ActiveTexture(gl::TEXTURE0);
|
||||||
gl.gl.BlendEquation(gl::FUNC_ADD);
|
gl.gl.BlendEquation(gl::FUNC_ADD);
|
||||||
gl.gl.BlendFunc(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA);
|
gl.gl.BlendFunc(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA);
|
||||||
|
|
||||||
gl.gl.Viewport(0, 0, width as _, height as _);
|
gl.gl.Viewport(0, 0, width_u as _, height_u as _);
|
||||||
|
|
||||||
self.def_matrix = [
|
self.def_matrix = [
|
||||||
[2.0 / width, 0.0, 0.0, 0.0],
|
[2.0 / width, 0.0, 0.0, 0.0],
|
||||||
|
@ -677,7 +763,6 @@ impl BackendRenderer for OpenGLRenderer {
|
||||||
fn create_texture_mutable(&mut self, width: u16, height: u16) -> GameResult<Box<dyn BackendTexture>> {
|
fn create_texture_mutable(&mut self, width: u16, height: u16) -> GameResult<Box<dyn BackendTexture>> {
|
||||||
if let Some((_, gl)) = self.get_context() {
|
if let Some((_, gl)) = self.get_context() {
|
||||||
unsafe {
|
unsafe {
|
||||||
let data = vec![0u8; width as usize * height as usize * 4];
|
|
||||||
let current_texture_id = return_param(|x| gl.gl.GetIntegerv(gl::TEXTURE_BINDING_2D, x)) as u32;
|
let current_texture_id = return_param(|x| gl.gl.GetIntegerv(gl::TEXTURE_BINDING_2D, x)) as u32;
|
||||||
let texture_id = return_param(|x| gl.gl.GenTextures(1, x));
|
let texture_id = return_param(|x| gl.gl.GenTextures(1, x));
|
||||||
|
|
||||||
|
@ -694,7 +779,7 @@ impl BackendRenderer for OpenGLRenderer {
|
||||||
0,
|
0,
|
||||||
gl::RGBA,
|
gl::RGBA,
|
||||||
gl::UNSIGNED_BYTE,
|
gl::UNSIGNED_BYTE,
|
||||||
data.as_ptr() as _,
|
null() as _,
|
||||||
);
|
);
|
||||||
|
|
||||||
gl.gl.BindTexture(gl::TEXTURE_2D, current_texture_id);
|
gl.gl.BindTexture(gl::TEXTURE_2D, current_texture_id);
|
||||||
|
@ -707,6 +792,8 @@ impl BackendRenderer for OpenGLRenderer {
|
||||||
gl.gl.DrawBuffers(1, draw_buffers.as_ptr() as _);
|
gl.gl.DrawBuffers(1, draw_buffers.as_ptr() as _);
|
||||||
|
|
||||||
gl.gl.Viewport(0, 0, width as _, height as _);
|
gl.gl.Viewport(0, 0, width as _, height as _);
|
||||||
|
gl.gl.ClearColor(0.0, 0.0, 0.0, 0.0);
|
||||||
|
gl.gl.Clear(gl::COLOR_BUFFER_BIT);
|
||||||
gl.gl.BindFramebuffer(gl::FRAMEBUFFER, 0);
|
gl.gl.BindFramebuffer(gl::FRAMEBUFFER, 0);
|
||||||
|
|
||||||
// todo error checking: glCheckFramebufferStatus()
|
// todo error checking: glCheckFramebufferStatus()
|
||||||
|
@ -805,10 +892,20 @@ impl BackendRenderer for OpenGLRenderer {
|
||||||
];
|
];
|
||||||
|
|
||||||
gl.gl.UseProgram(self.imgui_data.program_fill);
|
gl.gl.UseProgram(self.imgui_data.program_fill);
|
||||||
gl.gl.UniformMatrix4fv(self.imgui_data.fill_locs.proj_mtx, 1, gl::FALSE, self.curr_matrix.as_ptr() as _);
|
gl.gl.UniformMatrix4fv(
|
||||||
|
self.imgui_data.fill_locs.proj_mtx,
|
||||||
|
1,
|
||||||
|
gl::FALSE,
|
||||||
|
self.curr_matrix.as_ptr() as _,
|
||||||
|
);
|
||||||
gl.gl.UseProgram(self.imgui_data.program_tex);
|
gl.gl.UseProgram(self.imgui_data.program_tex);
|
||||||
gl.gl.Uniform1i(self.imgui_data.tex_locs.texture, 0);
|
gl.gl.Uniform1i(self.imgui_data.tex_locs.texture, 0);
|
||||||
gl.gl.UniformMatrix4fv(self.imgui_data.tex_locs.proj_mtx, 1, gl::FALSE, self.curr_matrix.as_ptr() as _);
|
gl.gl.UniformMatrix4fv(
|
||||||
|
self.imgui_data.tex_locs.proj_mtx,
|
||||||
|
1,
|
||||||
|
gl::FALSE,
|
||||||
|
self.curr_matrix.as_ptr() as _,
|
||||||
|
);
|
||||||
|
|
||||||
gl.gl.BindFramebuffer(gl::FRAMEBUFFER, gl_texture.framebuffer_id);
|
gl.gl.BindFramebuffer(gl::FRAMEBUFFER, gl_texture.framebuffer_id);
|
||||||
} else {
|
} else {
|
||||||
|
@ -829,7 +926,7 @@ impl BackendRenderer for OpenGLRenderer {
|
||||||
gl::FALSE,
|
gl::FALSE,
|
||||||
self.def_matrix.as_ptr() as _,
|
self.def_matrix.as_ptr() as _,
|
||||||
);
|
);
|
||||||
gl.gl.BindFramebuffer(gl::FRAMEBUFFER, 0);
|
gl.gl.BindFramebuffer(gl::FRAMEBUFFER, self.imgui_data.surf_framebuffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1076,6 +1173,23 @@ impl OpenGLRenderer {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let texture_id = if let Some(texture) = texture {
|
||||||
|
let gl_texture: &Box<OpenGLTexture> = std::mem::transmute(texture);
|
||||||
|
gl_texture.texture_id
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
|
self.draw_arrays_tex_id(vert_type, vertices, texture_id, shader)
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn draw_arrays_tex_id(
|
||||||
|
&mut self,
|
||||||
|
vert_type: GLenum,
|
||||||
|
vertices: Vec<VertexData>,
|
||||||
|
texture: u32,
|
||||||
|
shader: BackendShader,
|
||||||
|
) -> GameResult<()> {
|
||||||
if let Some(gl) = GL_PROC.as_ref() {
|
if let Some(gl) = GL_PROC.as_ref() {
|
||||||
match shader {
|
match shader {
|
||||||
BackendShader::Fill => {
|
BackendShader::Fill => {
|
||||||
|
@ -1148,14 +1262,7 @@ impl OpenGLRenderer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let texture_id = if let Some(texture) = texture {
|
gl.gl.BindTexture(gl::TEXTURE_2D, texture);
|
||||||
let gl_texture: &Box<OpenGLTexture> = std::mem::transmute(texture);
|
|
||||||
gl_texture.texture_id
|
|
||||||
} else {
|
|
||||||
0
|
|
||||||
};
|
|
||||||
|
|
||||||
gl.gl.BindTexture(gl::TEXTURE_2D, texture_id);
|
|
||||||
gl.gl.BufferData(
|
gl.gl.BufferData(
|
||||||
gl::ARRAY_BUFFER,
|
gl::ARRAY_BUFFER,
|
||||||
(vertices.len() * mem::size_of::<VertexData>()) as _,
|
(vertices.len() * mem::size_of::<VertexData>()) as _,
|
||||||
|
|
10
src/lib.rs
10
src/lib.rs
|
@ -104,16 +104,16 @@ impl Game {
|
||||||
if let Some(scene) = self.scene.as_mut() {
|
if let Some(scene) = self.scene.as_mut() {
|
||||||
let state_ref = unsafe { &mut *self.state.get() };
|
let state_ref = unsafe { &mut *self.state.get() };
|
||||||
|
|
||||||
match state_ref.timing_mode {
|
match state_ref.settings.timing_mode {
|
||||||
TimingMode::_50Hz | TimingMode::_60Hz => {
|
TimingMode::_50Hz | TimingMode::_60Hz => {
|
||||||
let last_tick = self.next_tick;
|
let last_tick = self.next_tick;
|
||||||
|
|
||||||
while self.start_time.elapsed().as_nanos() >= self.next_tick && self.loops < 10 {
|
while self.start_time.elapsed().as_nanos() >= self.next_tick && self.loops < 10 {
|
||||||
if (state_ref.settings.speed - 1.0).abs() < 0.01 {
|
if (state_ref.settings.speed - 1.0).abs() < 0.01 {
|
||||||
self.next_tick += state_ref.timing_mode.get_delta() as u128;
|
self.next_tick += state_ref.settings.timing_mode.get_delta() as u128;
|
||||||
} else {
|
} else {
|
||||||
self.next_tick +=
|
self.next_tick +=
|
||||||
(state_ref.timing_mode.get_delta() as f64 / state_ref.settings.speed) as u128;
|
(state_ref.settings.timing_mode.get_delta() as f64 / state_ref.settings.speed) as u128;
|
||||||
}
|
}
|
||||||
self.loops += 1;
|
self.loops += 1;
|
||||||
}
|
}
|
||||||
|
@ -122,7 +122,7 @@ impl Game {
|
||||||
log::warn!("Frame skip is way too high, a long system lag occurred?");
|
log::warn!("Frame skip is way too high, a long system lag occurred?");
|
||||||
self.last_tick = self.start_time.elapsed().as_nanos();
|
self.last_tick = self.start_time.elapsed().as_nanos();
|
||||||
self.next_tick = self.last_tick
|
self.next_tick = self.last_tick
|
||||||
+ (state_ref.timing_mode.get_delta() as f64 / state_ref.settings.speed) as u128;
|
+ (state_ref.settings.timing_mode.get_delta() as f64 / state_ref.settings.speed) as u128;
|
||||||
self.loops = 0;
|
self.loops = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -152,7 +152,7 @@ impl Game {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
if state_ref.timing_mode != TimingMode::FrameSynchronized {
|
if state_ref.settings.timing_mode != TimingMode::FrameSynchronized {
|
||||||
let mut elapsed = self.start_time.elapsed().as_nanos();
|
let mut elapsed = self.start_time.elapsed().as_nanos();
|
||||||
|
|
||||||
// Even with the non-monotonic Instant mitigation at the start of the event loop, there's still a chance of it not working.
|
// Even with the non-monotonic Instant mitigation at the start of the event loop, there's still a chance of it not working.
|
||||||
|
|
|
@ -64,7 +64,7 @@ impl SettingsMenu {
|
||||||
|
|
||||||
self.main.push_entry(MenuEntry::Options(
|
self.main.push_entry(MenuEntry::Options(
|
||||||
"Game timing:".to_owned(),
|
"Game timing:".to_owned(),
|
||||||
if state.timing_mode == TimingMode::_50Hz { 0 } else { 1 },
|
if state.settings.timing_mode == TimingMode::_50Hz { 0 } else { 1 },
|
||||||
vec!["50tps (freeware)".to_owned(), "60tps (CS+)".to_owned()],
|
vec!["50tps (freeware)".to_owned(), "60tps (CS+)".to_owned()],
|
||||||
));
|
));
|
||||||
|
|
||||||
|
@ -125,13 +125,13 @@ impl SettingsMenu {
|
||||||
}
|
}
|
||||||
MenuSelectionResult::Selected(2, toggle) => {
|
MenuSelectionResult::Selected(2, toggle) => {
|
||||||
if let MenuEntry::Options(_, value, _) = toggle {
|
if let MenuEntry::Options(_, value, _) = toggle {
|
||||||
match state.timing_mode {
|
match state.settings.timing_mode {
|
||||||
TimingMode::_50Hz => {
|
TimingMode::_50Hz => {
|
||||||
state.timing_mode = TimingMode::_60Hz;
|
state.settings.timing_mode = TimingMode::_60Hz;
|
||||||
*value = 1;
|
*value = 1;
|
||||||
}
|
}
|
||||||
TimingMode::_60Hz => {
|
TimingMode::_60Hz => {
|
||||||
state.timing_mode = TimingMode::_50Hz;
|
state.settings.timing_mode = TimingMode::_50Hz;
|
||||||
*value = 0;
|
*value = 0;
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
|
|
|
@ -6,6 +6,7 @@ use crate::input::keyboard_player_controller::KeyboardController;
|
||||||
use crate::input::player_controller::PlayerController;
|
use crate::input::player_controller::PlayerController;
|
||||||
use crate::input::touch_player_controller::TouchPlayerController;
|
use crate::input::touch_player_controller::TouchPlayerController;
|
||||||
use crate::player::TargetPlayer;
|
use crate::player::TargetPlayer;
|
||||||
|
use crate::shared_game_state::TimingMode;
|
||||||
use crate::sound::InterpolationMode;
|
use crate::sound::InterpolationMode;
|
||||||
|
|
||||||
#[derive(serde::Serialize, serde::Deserialize)]
|
#[derive(serde::Serialize, serde::Deserialize)]
|
||||||
|
@ -24,6 +25,8 @@ pub struct Settings {
|
||||||
pub motion_interpolation: bool,
|
pub motion_interpolation: bool,
|
||||||
pub touch_controls: bool,
|
pub touch_controls: bool,
|
||||||
pub soundtrack: String,
|
pub soundtrack: String,
|
||||||
|
#[serde(default = "default_timing")]
|
||||||
|
pub timing_mode: TimingMode,
|
||||||
#[serde(default = "default_interpolation")]
|
#[serde(default = "default_interpolation")]
|
||||||
pub organya_interpolation: InterpolationMode,
|
pub organya_interpolation: InterpolationMode,
|
||||||
#[serde(default = "p1_default_keymap")]
|
#[serde(default = "p1_default_keymap")]
|
||||||
|
@ -43,7 +46,10 @@ pub struct Settings {
|
||||||
fn default_true() -> bool { true }
|
fn default_true() -> bool { true }
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn current_version() -> u32 { 3 }
|
fn current_version() -> u32 { 4 }
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn default_timing() -> TimingMode { TimingMode::_50Hz }
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn default_interpolation() -> InterpolationMode { InterpolationMode::Linear }
|
fn default_interpolation() -> InterpolationMode { InterpolationMode::Linear }
|
||||||
|
@ -73,6 +79,11 @@ impl Settings {
|
||||||
self.light_cone = true;
|
self.light_cone = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if self.version == 3 {
|
||||||
|
self.version = 4;
|
||||||
|
self.timing_mode = default_timing();
|
||||||
|
}
|
||||||
|
|
||||||
if self.version != initial_version {
|
if self.version != initial_version {
|
||||||
log::info!("Upgraded configuration file from version {} to {}.", initial_version, self.version);
|
log::info!("Upgraded configuration file from version {} to {}.", initial_version, self.version);
|
||||||
}
|
}
|
||||||
|
@ -112,6 +123,7 @@ impl Default for Settings {
|
||||||
motion_interpolation: true,
|
motion_interpolation: true,
|
||||||
touch_controls: cfg!(target_os = "android"),
|
touch_controls: cfg!(target_os = "android"),
|
||||||
soundtrack: "".to_string(),
|
soundtrack: "".to_string(),
|
||||||
|
timing_mode: default_timing(),
|
||||||
organya_interpolation: InterpolationMode::Linear,
|
organya_interpolation: InterpolationMode::Linear,
|
||||||
player1_key_map: p1_default_keymap(),
|
player1_key_map: p1_default_keymap(),
|
||||||
player2_key_map: p2_default_keymap(),
|
player2_key_map: p2_default_keymap(),
|
||||||
|
|
|
@ -32,7 +32,7 @@ use crate::str;
|
||||||
use crate::text_script::{ScriptMode, TextScriptExecutionState, TextScriptVM};
|
use crate::text_script::{ScriptMode, TextScriptExecutionState, TextScriptVM};
|
||||||
use crate::texture_set::TextureSet;
|
use crate::texture_set::TextureSet;
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Copy, Clone)]
|
#[derive(PartialEq, Eq, Copy, Clone, serde::Serialize, serde::Deserialize)]
|
||||||
pub enum TimingMode {
|
pub enum TimingMode {
|
||||||
_50Hz,
|
_50Hz,
|
||||||
_60Hz,
|
_60Hz,
|
||||||
|
@ -109,7 +109,6 @@ impl TileSize {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct SharedGameState {
|
pub struct SharedGameState {
|
||||||
pub timing_mode: TimingMode,
|
|
||||||
pub control_flags: ControlFlags,
|
pub control_flags: ControlFlags,
|
||||||
pub game_flags: BitVec,
|
pub game_flags: BitVec,
|
||||||
pub skip_flags: BitVec,
|
pub skip_flags: BitVec,
|
||||||
|
@ -212,7 +211,6 @@ impl SharedGameState {
|
||||||
init_hooks();
|
init_hooks();
|
||||||
|
|
||||||
Ok(SharedGameState {
|
Ok(SharedGameState {
|
||||||
timing_mode: TimingMode::_50Hz,
|
|
||||||
control_flags: ControlFlags(0),
|
control_flags: ControlFlags(0),
|
||||||
game_flags: bitvec::bitvec![0; 8000],
|
game_flags: bitvec::bitvec![0; 8000],
|
||||||
skip_flags: bitvec::bitvec![0; 64],
|
skip_flags: bitvec::bitvec![0; 64],
|
||||||
|
@ -422,7 +420,7 @@ impl SharedGameState {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn current_tps(&self) -> f64 {
|
pub fn current_tps(&self) -> f64 {
|
||||||
self.timing_mode.get_tps() as f64 * self.settings.speed
|
self.settings.timing_mode.get_tps() as f64 * self.settings.speed
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn shutdown(&mut self) {
|
pub fn shutdown(&mut self) {
|
||||||
|
|
Loading…
Reference in New Issue