Compare commits

..
10 Commits
8 changed files with 249 additions and 222 deletions
Generated
+181 -184
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -4,7 +4,7 @@ description = "An emulator for the Virtual Boy."
repository = "https://git.virtual-boy.com/PVB/lemur" repository = "https://git.virtual-boy.com/PVB/lemur"
publish = false publish = false
license = "MIT" license = "MIT"
version = "0.12.0" version = "0.12.3"
edition = "2024" edition = "2024"
[dependencies] [dependencies]
+11 -11
View File
@@ -13,12 +13,12 @@ COPY install-llvm.sh .
RUN apt-get update && \ RUN apt-get update && \
./install-llvm.sh && \ ./install-llvm.sh && \
apt-get install -y bash bzip2 git make patch xz-utils && \ apt-get install -y bash bzip2 git make patch xz-utils && \
ln -s $(which clang-21) /usr/bin/clang && \ ln -s $(which clang-22) /usr/bin/clang && \
ln -s $(which clang++-21) /usr/bin/clang++ && \ ln -s $(which clang++-22) /usr/bin/clang++ && \
ln -s $(which ld64.lld-21) /usr/bin/ld64.lld && \ ln -s $(which ld64.lld-22) /usr/bin/ld64.lld && \
SDK_VERSION=14.5 UNATTENDED=1 ENABLE_COMPILER_RT_INSTALL=1 TARGET_DIR=/osxcross ./build.sh SDK_VERSION=14.5 UNATTENDED=1 ENABLE_COMPILER_RT_INSTALL=1 TARGET_DIR=/osxcross ./build.sh
FROM rust:1.94-bookworm FROM rust:1.95-bookworm
ADD --chmod=644 "https://apt.llvm.org/llvm-snapshot.gpg.key" /etc/apt/trusted.gpg.d/apt.llvm.org.asc ADD --chmod=644 "https://apt.llvm.org/llvm-snapshot.gpg.key" /etc/apt/trusted.gpg.d/apt.llvm.org.asc
COPY llvm.sources /etc/apt/sources.list.d/llvm.sources COPY llvm.sources /etc/apt/sources.list.d/llvm.sources
COPY install-llvm.sh . COPY install-llvm.sh .
@@ -31,13 +31,13 @@ RUN rustup target add x86_64-pc-windows-msvc && \
cargo install cargo-bundle xwin && \ cargo install cargo-bundle xwin && \
xwin --accept-license splat --output xwin && \ xwin --accept-license splat --output xwin && \
rm -rf .xwin-cache && \ rm -rf .xwin-cache && \
ln -s $(which clang-21) /usr/bin/clang && \ ln -s $(which clang-22) /usr/bin/clang && \
ln -s $(which clang++-21) /usr/bin/clang++ ln -s $(which clang++-22) /usr/bin/clang++
COPY --from=osxcross /osxcross /osxcross COPY --from=osxcross /osxcross /osxcross
ENV PATH="/osxcross/bin:$PATH" \ ENV PATH="/osxcross/bin:$PATH" \
LD_LIBRARY_PATH="/osxcross/lib" \ LD_LIBRARY_PATH="/osxcross/lib" \
CC="clang-21" CXX="clang++-21" AR="llvm-ar-21" \ CC="clang-22" CXX="clang++-22" AR="llvm-ar-22" \
CC_x86_64-apple-darwin="o64-clang" \ CC_x86_64-apple-darwin="o64-clang" \
CXX_x86_64-apple-darwin="o64-clang++" \ CXX_x86_64-apple-darwin="o64-clang++" \
CC_aarch64-apple-darwin="oa64-clang" \ CC_aarch64-apple-darwin="oa64-clang" \
@@ -47,11 +47,11 @@ ENV PATH="/osxcross/bin:$PATH" \
SHROOMS_CFLAGS_x86_64-pc-windows-msvc="-flto" \ SHROOMS_CFLAGS_x86_64-pc-windows-msvc="-flto" \
CFLAGS_x86_64-pc-windows-msvc="-I/xwin/crt/include -I/xwin/sdk/include/ucrt -I/xwin/sdk/include/um -I/xwin/sdk/include/shared" \ CFLAGS_x86_64-pc-windows-msvc="-I/xwin/crt/include -I/xwin/sdk/include/ucrt -I/xwin/sdk/include/um -I/xwin/sdk/include/shared" \
CARGO_TARGET_X86_64_PC_WINDOWS_MSVC_RUSTFLAGS="-Lnative=/xwin/crt/lib/x86_64 -Lnative=/xwin/sdk/lib/um/x86_64 -Lnative=/xwin/sdk/lib/ucrt/x86_64 -Clinker-plugin-lto -Clink-arg=-fuse-ld=lld" \ CARGO_TARGET_X86_64_PC_WINDOWS_MSVC_RUSTFLAGS="-Lnative=/xwin/crt/lib/x86_64 -Lnative=/xwin/sdk/lib/um/x86_64 -Lnative=/xwin/sdk/lib/ucrt/x86_64 -Clinker-plugin-lto -Clink-arg=-fuse-ld=lld" \
CARGO_TARGET_X86_64_PC_WINDOWS_MSVC_LINKER="lld-link-21" \ CARGO_TARGET_X86_64_PC_WINDOWS_MSVC_LINKER="lld-link-22" \
CARGO_TARGET_X86_64_APPLE_DARWIN_LINKER="o64-clang" \ CARGO_TARGET_X86_64_APPLE_DARWIN_LINKER="o64-clang" \
CARGO_TARGET_X86_64_APPLE_DARWIN_AR="llvm-ar-21" \ CARGO_TARGET_X86_64_APPLE_DARWIN_AR="llvm-ar-22" \
CARGO_TARGET_AARCH64_APPLE_DARWIN_LINKER="oa64-clang" \ CARGO_TARGET_AARCH64_APPLE_DARWIN_LINKER="oa64-clang" \
CARGO_TARGET_AARCH64_APPLE_DARWIN_AR="llvm-ar-21" \ CARGO_TARGET_AARCH64_APPLE_DARWIN_AR="llvm-ar-22" \
RC_PATH="llvm-rc-21" \ RC_PATH="llvm-rc-22" \
MACOSX_DEPLOYMENT_TARGET="14.5" MACOSX_DEPLOYMENT_TARGET="14.5"
ENTRYPOINT ["bash"] ENTRYPOINT ["bash"]
+4 -4
View File
@@ -4,11 +4,11 @@
# The apt index for these is broken in bookworm, and upgrading to trixie # The apt index for these is broken in bookworm, and upgrading to trixie
# would make them depend on too new of a libc version. # would make them depend on too new of a libc version.
# https://apt.llvm.org/bookworm/pool/main/l/llvm-toolchain-21/clang-21_21.1.5~%2B%2B20251023083151%2B45afac62e373-1~exp1~20251023083333.51_amd64.deb # https://apt.llvm.org/bookworm/pool/main/l/llvm-toolchain-22/clang-22_22.1.0~%2B%2B20260223093050%2Bcd5897175d0d-1~exp1~20260223093246.28_amd64.deb
PACKAGES=('clang-21' 'clang-tools-21' 'libclang-common-21-dev' 'libclang-cpp21' 'libclang-rt-21-dev' 'libclang1-21' 'libllvm21' 'lld-21' 'llvm-21' 'llvm-21-dev' 'llvm-21-linker-tools' 'llvm-21-runtime' 'llvm-21-tools') PACKAGES=('clang-22' 'clang-tools-22' 'libclang-common-22-dev' 'libclang-cpp22' 'libclang-rt-22-dev' 'libclang1-22' 'libllvm22' 'lld-22' 'llvm-22' 'llvm-22-dev' 'llvm-22-linker-tools' 'llvm-22-runtime' 'llvm-22-tools')
FILES=() FILES=()
URL='https://apt.llvm.org/bookworm/pool/main/l/llvm-toolchain-21' URL='https://apt.llvm.org/bookworm/pool/main/l/llvm-toolchain-22'
VERSION='21.1.5~%2B%2B20251023083151%2B45afac62e373-1~exp1~20251023083333.51_amd64.deb' VERSION='22.1.0~%2B%2B20260223093050%2Bcd5897175d0d-1~exp1~20260223093246.28_amd64.deb'
apt-get install -y curl python3 apt-get install -y curl python3
for package in "${PACKAGES[@]}"; do for package in "${PACKAGES[@]}"; do
+1 -1
View File
@@ -1,4 +1,4 @@
Types: deb deb-src Types: deb deb-src
URIs: http://apt.llvm.org/bookworm/ URIs: http://apt.llvm.org/bookworm/
Suites: llvm-toolchain-bookworm-21 Suites: llvm-toolchain-bookworm-22
Components: main Components: main
+10 -7
View File
@@ -288,6 +288,7 @@ impl Application {
} }
} }
let clipped_primitives = self.ctx.tessellate(output.shapes, output.pixels_per_point); let clipped_primitives = self.ctx.tessellate(output.shapes, output.pixels_per_point);
viewport.window.pre_present_notify();
self.shared.painter.paint_and_update_textures( self.shared.painter.paint_and_update_textures(
viewport.id, viewport.id,
output.pixels_per_point, output.pixels_per_point,
@@ -296,7 +297,6 @@ impl Application {
&output.textures_delta, &output.textures_delta,
vec![], vec![],
); );
viewport.window.pre_present_notify();
} }
let mut active_viewports = ViewportIdSet::default(); let mut active_viewports = ViewportIdSet::default();
for (id, update) in updates { for (id, update) in updates {
@@ -398,22 +398,25 @@ impl ApplicationHandler<UserEvent> for Application {
if close_requested && viewport_id == ViewportId::ROOT { if close_requested && viewport_id == ViewportId::ROOT {
event_loop.exit(); event_loop.exit();
} }
if response.repaint {
viewport.window.request_redraw();
}
if !response.consumed { if !response.consumed {
match event { match event {
WindowEvent::KeyboardInput { event, .. } => { WindowEvent::KeyboardInput { event, .. }
if !self.app.handle_key_event(viewport_id, &event) { if !self.app.handle_key_event(viewport_id, &event) =>
{
self.controllers.handle_key_event(&event); self.controllers.handle_key_event(&event);
} }
}
WindowEvent::Focused(new_focused) => { WindowEvent::Focused(new_focused) => {
self.focused = new_focused.then_some(viewport_id); self.focused = new_focused.then_some(viewport_id);
} }
WindowEvent::RedrawRequested => {
self.repaint_all(event_loop);
}
_ => {} _ => {}
} }
} }
if response.repaint {
self.repaint_all(event_loop);
}
self.check_repaint(event_loop); self.check_repaint(event_loop);
} }
+4 -1
View File
@@ -1,6 +1,6 @@
use anyhow::Result; use anyhow::Result;
use clap::Parser; use clap::Parser;
use egui::{Color32, Vec2}; use egui::{Color32, Pos2, Vec2};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::{emulator::SimId, persistence::Persistence, window::DisplayMode}; use crate::{emulator::SimId, persistence::Persistence, window::DisplayMode};
@@ -75,6 +75,8 @@ pub struct SimConfig {
pub dimensions: Vec2, pub dimensions: Vec2,
#[serde(default = "default_audio_enabled")] #[serde(default = "default_audio_enabled")]
pub audio_enabled: bool, pub audio_enabled: bool,
#[serde(default)]
pub position: Option<Pos2>,
} }
impl SimConfig { impl SimConfig {
@@ -87,6 +89,7 @@ impl SimConfig {
colors: COLOR_PRESETS[0], colors: COLOR_PRESETS[0],
dimensions: DisplayMode::Anaglyph.proportions() + Vec2::new(0.0, 22.0), dimensions: DisplayMode::Anaglyph.proportions() + Vec2::new(0.0, 22.0),
audio_enabled: true, audio_enabled: true,
position: None,
} }
} }
+36 -12
View File
@@ -20,10 +20,11 @@ use crate::{
}; };
use anyhow::Context as _; use anyhow::Context as _;
use egui::{ use egui::{
Align2, Button, CentralPanel, Color32, Context, Frame, MenuBar, Panel, Ui, Vec2, Align2, Button, CentralPanel, Color32, Context, Frame, MenuBar, Panel, Pos2, Ui, Vec2,
ViewportBuilder, ViewportCommand, ViewportId, ViewportIdMap, Window, ViewportBuilder, ViewportCommand, ViewportId, ViewportIdMap, Window,
}; };
use egui_notify::{Anchor, Toast, Toasts}; use egui_notify::{Anchor, Toast, Toasts};
use serde::{Deserialize, Serialize};
use winit::{event::KeyEvent, event_loop::EventLoopProxy}; use winit::{event::KeyEvent, event_loop::EventLoopProxy};
use super::{ use super::{
@@ -50,7 +51,7 @@ pub struct GameWindow {
images: Arc<ImageTextureLoader>, images: Arc<ImageTextureLoader>,
mappings: MappingProvider, mappings: MappingProvider,
children: ViewportIdMap<ChildWindowWrapper>, children: ViewportIdMap<ChildWindowWrapper>,
child_sizes: UiData<ViewportIdMap<Vec2>>, child_states: UiData<ViewportIdMap<ChildState>>,
queued_children: Vec<ChildWindow>, queued_children: Vec<ChildWindow>,
} }
@@ -91,7 +92,7 @@ impl GameWindow {
images: images.clone(), images: images.clone(),
mappings: mappings.clone(), mappings: mappings.clone(),
children: ViewportIdMap::default(), children: ViewportIdMap::default(),
child_sizes: UiData::new(), child_states: UiData::new(),
queued_children: vec![], queued_children: vec![],
} }
} }
@@ -175,8 +176,9 @@ impl GameWindow {
}; };
let mut viewport = child.initial_viewport(); let mut viewport = child.initial_viewport();
if let Some(size) = self.child_sizes.get(&viewport_id) { if let Some(state) = self.child_states.get(&viewport_id) {
viewport.inner_size = Some(*size); viewport.position = Some(state.position);
viewport.inner_size = Some(state.size);
} }
self.children.insert( self.children.insert(
viewport_id, viewport_id,
@@ -626,18 +628,27 @@ impl AppWindow for GameWindow {
} }
fn initial_viewport(&self) -> ViewportBuilder { fn initial_viewport(&self) -> ViewportBuilder {
ViewportBuilder::default() let builder = ViewportBuilder::default()
.with_title("Lemur") .with_title("Lemur")
.with_inner_size(self.config.dimensions) .with_inner_size(self.config.dimensions);
if let Some(position) = self.config.position {
builder.with_position(position)
} else {
builder
}
} }
fn show(&mut self, ui: &mut Ui) { fn show(&mut self, ui: &mut Ui) {
self.child_sizes.load(ui); self.child_states.load(ui);
let dimensions = { let dimensions = {
let bounds = ui.content_rect(); let bounds = ui.content_rect();
bounds.max - bounds.min bounds.max - bounds.min
}; };
self.update_config(|c| c.dimensions = dimensions); let position = ui.input(|i| i.viewport().outer_rect.map(|r| r.min));
self.update_config(|c| {
c.dimensions = dimensions;
c.position = position;
});
while let Ok(toast) = self.messages.try_recv() { while let Ok(toast) = self.messages.try_recv() {
self.toasts.add(toast); self.toasts.add(toast);
@@ -679,8 +690,15 @@ impl AppWindow for GameWindow {
let app = child.app.clone(); let app = child.app.clone();
let viewport_builder = child.updates.take().unwrap_or_default(); let viewport_builder = child.updates.take().unwrap_or_default();
let close_requested = child.close_requested.clone(); let close_requested = child.close_requested.clone();
let size = ui.input_for(*id, |v| v.viewport_rect().size()); if let Some(rect) = ui.input_for(*id, |inp| inp.viewport().outer_rect) {
self.child_sizes.insert(*id, size); self.child_states.insert(
*id,
ChildState {
position: rect.min,
size: rect.size(),
},
);
}
ui.show_viewport_deferred(*id, viewport_builder, move |ui, _| { ui.show_viewport_deferred(*id, viewport_builder, move |ui, _| {
app.lock().unwrap().show(ui); app.lock().unwrap().show(ui);
if ui.input(|s| s.viewport().close_requested()) { if ui.input(|s| s.viewport().close_requested()) {
@@ -689,7 +707,7 @@ impl AppWindow for GameWindow {
}); });
true true
}); });
self.child_sizes.save(ui); self.child_states.save(ui);
ui.request_repaint_after(Duration::from_millis(10)); ui.request_repaint_after(Duration::from_millis(10));
} }
@@ -795,3 +813,9 @@ impl ChildWindow {
} }
} }
} }
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
struct ChildState {
position: Pos2,
size: Vec2,
}