wasm32 build target #10
							
								
								
									
										6
									
								
								.cargo/config.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								.cargo/config.toml
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,6 @@
 | 
				
			|||||||
 | 
					# clipboard api is still unstable, so web-sys requires the below flag to be passed for copy (ctrl + c) to work
 | 
				
			||||||
 | 
					# https://rustwasm.github.io/docs/wasm-bindgen/web-sys/unstable-apis.html
 | 
				
			||||||
 | 
					# check status at https://developer.mozilla.org/en-US/docs/Web/API/Clipboard#browser_compatibility
 | 
				
			||||||
 | 
					# we don't use `[build]` because of rust analyzer's build cache invalidation https://github.com/emilk/eframe_template/issues/93
 | 
				
			||||||
 | 
					[target.wasm32-unknown-unknown]
 | 
				
			||||||
 | 
					rustflags = ["--cfg=web_sys_unstable_apis"]
 | 
				
			||||||
							
								
								
									
										29
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										29
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@ -1,22 +1,13 @@
 | 
				
			|||||||
 | 
					# Mac stuff:
 | 
				
			||||||
.obsidian/*
 | 
					.DS_Store
 | 
				
			||||||
.vscode/*
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# ---> Rust
 | 
					 | 
				
			||||||
# Generated by Cargo
 | 
					 | 
				
			||||||
# will have compiled files and executables
 | 
					 | 
				
			||||||
debug/
 | 
					 | 
				
			||||||
target/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
 | 
					 | 
				
			||||||
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
 | 
					 | 
				
			||||||
Cargo.lock
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# These are backup files generated by rustfmt
 | 
					 | 
				
			||||||
**/*.rs.bk
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# MSVC Windows builds of rustc generate these, which store debugging information
 | 
					 | 
				
			||||||
*.pdb
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
# trunk output folder
 | 
					# trunk output folder
 | 
				
			||||||
dist
 | 
					dist
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Rust compile target directories:
 | 
				
			||||||
 | 
					target
 | 
				
			||||||
 | 
					target_ra
 | 
				
			||||||
 | 
					target_wasm
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# https://github.com/lycheeverse/lychee
 | 
				
			||||||
 | 
					.lycheecache
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										2416
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										2416
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										21
									
								
								Cargo.toml
									
									
									
									
									
										
										
										Executable file → Normal file
									
								
							
							
						
						
									
										21
									
								
								Cargo.toml
									
									
									
									
									
										
										
										Executable file → Normal file
									
								
							@ -1,8 +1,9 @@
 | 
				
			|||||||
[package]
 | 
					[package]
 | 
				
			||||||
name = "egui-circles"
 | 
					name = "egui_circles"
 | 
				
			||||||
version = "0.2.0"
 | 
					version = "0.2.1"
 | 
				
			||||||
authors = ["Andriy Djmil <andriy@djmil.dev>"]
 | 
					authors = ["Andriy Djmil <andriy@djmil.dev>"]
 | 
				
			||||||
edition = "2021"
 | 
					edition = "2021"
 | 
				
			||||||
 | 
					include = ["LICENSE", "**/*.rs", "Cargo.toml"]
 | 
				
			||||||
rust-version = "1.76"
 | 
					rust-version = "1.76"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[package.metadata.docs.rs]
 | 
					[package.metadata.docs.rs]
 | 
				
			||||||
@ -15,13 +16,16 @@ eframe = { version = "0.28", default-features = false, features = [
 | 
				
			|||||||
#   "accesskit",     # Make egui compatible with screen readers. NOTE: adds a lot of dependencies.
 | 
					#   "accesskit",     # Make egui compatible with screen readers. NOTE: adds a lot of dependencies.
 | 
				
			||||||
    "default_fonts", # Embed the default egui fonts.
 | 
					    "default_fonts", # Embed the default egui fonts.
 | 
				
			||||||
    "glow",          # Use the glow rendering backend. Alternative: "wgpu".
 | 
					    "glow",          # Use the glow rendering backend. Alternative: "wgpu".
 | 
				
			||||||
#   "persistence",   # Enable restoring app state when restarting the app.
 | 
					    "persistence",   # Enable restoring app state when restarting the app.
 | 
				
			||||||
] }
 | 
					] }
 | 
				
			||||||
log = "0.4"
 | 
					log = "0.4"
 | 
				
			||||||
emath  = "0.28.0"
 | 
					emath  = "0.28.0"
 | 
				
			||||||
rand = "0.8"
 | 
					rand = "0.8"
 | 
				
			||||||
getrandom = { version = "0.2", features = ["js"] }
 | 
					getrandom = { version = "0.2", features = ["js"] }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# You only need serde if you want app persistence:
 | 
				
			||||||
 | 
					serde = { version = "1", features = ["derive"] }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# native:
 | 
					# native:
 | 
				
			||||||
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
 | 
					[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
 | 
				
			||||||
env_logger = "0.10"
 | 
					env_logger = "0.10"
 | 
				
			||||||
@ -40,3 +44,14 @@ opt-level = 2 # fast and small wasm
 | 
				
			|||||||
# Optimize all dependencies even in debug builds:
 | 
					# Optimize all dependencies even in debug builds:
 | 
				
			||||||
[profile.dev.package."*"]
 | 
					[profile.dev.package."*"]
 | 
				
			||||||
opt-level = 2
 | 
					opt-level = 2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[patch.crates-io]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# If you want to use the bleeding edge version of egui and eframe:
 | 
				
			||||||
 | 
					# egui = { git = "https://github.com/emilk/egui", branch = "master" }
 | 
				
			||||||
 | 
					# eframe = { git = "https://github.com/emilk/egui", branch = "master" }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# If you fork https://github.com/emilk/egui you can test with:
 | 
				
			||||||
 | 
					# egui = { path = "../egui/crates/egui" }
 | 
				
			||||||
 | 
					# eframe = { path = "../egui/crates/eframe" }
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										11
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								README.md
									
									
									
									
									
								
							@ -1,11 +1,18 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
Immediate Mode GUI app with naive visualization for elastic balls collisions.
 | 
					Immediate Mode GUI app with naive visualization for elastic balls collisions. Live [demo](https://demo.pages.djmil.dev/egui-circles).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Build & run 
 | 
					# Build & run 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```bash
 | 
					```bash
 | 
				
			||||||
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh # install rust
 | 
					curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh # install rust
 | 
				
			||||||
cargo run --package=egui-circles                               # build & run
 | 
					cargo run --package=egui_circles                               # build & run
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### wasm32 build target
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```bash
 | 
				
			||||||
 | 
					cargo install --locked trunk    # https://trunkrs.dev
 | 
				
			||||||
 | 
					trunk serve                     # visit http://127.0.0.1:8080
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Acknowledgments
 | 
					# Acknowledgments
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,6 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  "name": "eGUI Circles",
 | 
					  "name": "eGUI Circles",
 | 
				
			||||||
  "short_name": "circles",
 | 
					  "short_name": "egui-circles",
 | 
				
			||||||
  "icons": [
 | 
					  "icons": [
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
      "src": "/icon-192.png",
 | 
					      "src": "/icon-192.png",
 | 
				
			||||||
 | 
				
			|||||||
@ -1,9 +1,9 @@
 | 
				
			|||||||
var cacheName = 'egui-template-pwa';
 | 
					var cacheName = 'egui_circles';
 | 
				
			||||||
var filesToCache = [
 | 
					var filesToCache = [
 | 
				
			||||||
  './',
 | 
					  './',
 | 
				
			||||||
  './index.html',
 | 
					  './index.html',
 | 
				
			||||||
  './eframe_template.js',
 | 
					  './egui_circles.js',
 | 
				
			||||||
  './eframe_template_bg.wasm',
 | 
					  './egui_circles_bg.wasm',
 | 
				
			||||||
];
 | 
					];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Start the service worker and cache all of the app's content */
 | 
					/* Start the service worker and cache all of the app's content */
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										24
									
								
								index.html
									
									
									
									
									
								
							
							
						
						
									
										24
									
								
								index.html
									
									
									
									
									
								
							@ -1,9 +1,9 @@
 | 
				
			|||||||
<!DOCTYPE html>
 | 
					<!DOCTYPE html>
 | 
				
			||||||
<html>
 | 
					<html>
 | 
				
			||||||
<meta http-equiv="Content-Type" charset="utf-8" />
 | 
					<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<!-- Disable zooming: -->
 | 
					<!-- Disable zooming: -->
 | 
				
			||||||
<meta name="viewport" content="width=device-width, initial-scale=1.5, user-scalable=no">
 | 
					<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<head>
 | 
					<head>
 | 
				
			||||||
    <!-- change this to your project name -->
 | 
					    <!-- change this to your project name -->
 | 
				
			||||||
@ -56,15 +56,16 @@
 | 
				
			|||||||
            width: 100%;
 | 
					            width: 100%;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /* Position canvas in center-top: */
 | 
					        /* Make canvas fill entire document: */
 | 
				
			||||||
        canvas {
 | 
					        canvas {
 | 
				
			||||||
            margin-right: auto;
 | 
					            margin-right: auto;
 | 
				
			||||||
            margin-left: auto;
 | 
					            margin-left: auto;
 | 
				
			||||||
            display: block;
 | 
					            display: block;
 | 
				
			||||||
            position: absolute;
 | 
					            position: absolute;
 | 
				
			||||||
            top: 0%;
 | 
					            top: 0;
 | 
				
			||||||
            left: 50%;
 | 
					            left: 0;
 | 
				
			||||||
            transform: translate(-50%, 0%);
 | 
					            width: 100%;
 | 
				
			||||||
 | 
					            height: 100%;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        .centered {
 | 
					        .centered {
 | 
				
			||||||
@ -110,14 +111,21 @@
 | 
				
			|||||||
                transform: rotate(360deg);
 | 
					                transform: rotate(360deg);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					 | 
				
			||||||
    </style>
 | 
					    </style>
 | 
				
			||||||
</head>
 | 
					</head>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<body>
 | 
					<body>
 | 
				
			||||||
    <!-- The WASM code will resize the canvas dynamically -->
 | 
					    <!-- The WASM code will resize the canvas dynamically -->
 | 
				
			||||||
    <!-- the id is hardcoded in main.rs . so, make sure both match. -->
 | 
					    <!-- the id is hardcoded in main.rs . so, make sure both match. -->
 | 
				
			||||||
    <canvas id="the_canvas_id" width="800" height="600"></canvas>
 | 
					    <canvas id="the_canvas_id"></canvas>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <!-- the loading spinner will be removed in main.rs -->
 | 
				
			||||||
 | 
					    <div class="centered" id="loading_text">
 | 
				
			||||||
 | 
					        <p style="font-size:16px">
 | 
				
			||||||
 | 
					            Loading…
 | 
				
			||||||
 | 
					        </p>
 | 
				
			||||||
 | 
					        <div class="lds-dual-ring"></div>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <!--Register Service Worker. this will cache the wasm / js scripts for offline use (for PWA functionality). -->
 | 
					    <!--Register Service Worker. this will cache the wasm / js scripts for offline use (for PWA functionality). -->
 | 
				
			||||||
    <!-- Force refresh (Ctrl + F5) to load the latest files instead of cached files  -->
 | 
					    <!-- Force refresh (Ctrl + F5) to load the latest files instead of cached files  -->
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										136
									
								
								src/app.rs
									
									
									
									
									
								
							
							
						
						
									
										136
									
								
								src/app.rs
									
									
									
									
									
								
							@ -1,19 +1,18 @@
 | 
				
			|||||||
extern crate emath;
 | 
					use egui::{Color32, Stroke, Vec2};
 | 
				
			||||||
extern crate rand;
 | 
					use rand::Rng;
 | 
				
			||||||
extern crate eframe;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
use self::emath::Vec2;
 | 
					 | 
				
			||||||
use self::eframe::egui;
 | 
					 | 
				
			||||||
use self::egui::Color32;
 | 
					 | 
				
			||||||
use self::egui::Stroke;
 | 
					 | 
				
			||||||
use self::rand::Rng;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
use crate::circle::Circle;
 | 
					use crate::circle::Circle;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// We derive Deserialize/Serialize so we can persist app state on shutdown.
 | 
				
			||||||
 | 
					#[derive(serde::Deserialize, serde::Serialize)]
 | 
				
			||||||
 | 
					#[serde(default)] // if we add new fields, give them default values when deserializing old state
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub struct Simulation {
 | 
					pub struct Simulation {
 | 
				
			||||||
    circles: Vec<Circle>,
 | 
					 | 
				
			||||||
    circles_count: usize,
 | 
					    circles_count: usize,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[serde(skip)] // This how you opt-out of serialization of a field
 | 
				
			||||||
 | 
					    circles: Vec<Circle>,
 | 
				
			||||||
 | 
					    #[serde(skip)]
 | 
				
			||||||
    colors: Vec<egui::Color32>,
 | 
					    colors: Vec<egui::Color32>,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -27,21 +26,87 @@ impl Default for Simulation {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl eframe::App for Simulation {
 | 
					impl Simulation {
 | 
				
			||||||
    fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
 | 
					    /// Called once before the first frame.
 | 
				
			||||||
 | 
					    pub fn new(cc: &eframe::CreationContext<'_>) -> Self {
 | 
				
			||||||
 | 
					        // This is also where you can customize the look and feel of egui using
 | 
				
			||||||
 | 
					        // `cc.egui_ctx.set_visuals` and `cc.egui_ctx.set_fonts`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Looks better on 4k montior
 | 
					        // Looks better on 4k montior
 | 
				
			||||||
        ctx.set_pixels_per_point(1.5);
 | 
					        cc.egui_ctx.set_pixels_per_point(1.5);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Load previous app state (if any).
 | 
				
			||||||
 | 
					        // Note that you must enable the `persistence` feature for this to work.
 | 
				
			||||||
 | 
					        if let Some(storage) = cc.storage {
 | 
				
			||||||
 | 
					            return eframe::get_value(storage, eframe::APP_KEY).unwrap_or_default();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Default::default()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl eframe::App for Simulation {
 | 
				
			||||||
 | 
					    /// Called by the frame work to save state before shutdown.
 | 
				
			||||||
 | 
					    fn save(&mut self, storage: &mut dyn eframe::Storage) {
 | 
				
			||||||
 | 
					        eframe::set_value(storage, eframe::APP_KEY, self);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Called each time the UI needs repainting, which may be many times per second.
 | 
				
			||||||
 | 
					    fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
 | 
				
			||||||
 | 
					        // Put your widgets into a `SidePanel`, `TopBottomPanel`, `CentralPanel`, `Window` or `Area`.
 | 
				
			||||||
 | 
					        // For inspiration and more examples, go to https://emilk.github.io/egui
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        egui::TopBottomPanel::top("top_panel").show(ctx, |ui| {
 | 
				
			||||||
 | 
					            // The top panel is often a good place for a menu bar:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            egui::menu::bar(ui, |ui| {
 | 
				
			||||||
 | 
					                // NOTE: no File->Quit on web pages!
 | 
				
			||||||
 | 
					                let is_web = cfg!(target_arch = "wasm32");
 | 
				
			||||||
 | 
					                if !is_web {
 | 
				
			||||||
 | 
					                    ui.menu_button("File", |ui| {
 | 
				
			||||||
 | 
					                        if ui.button("Quit").clicked() {
 | 
				
			||||||
 | 
					                            ctx.send_viewport_cmd(egui::ViewportCommand::Close);
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    });
 | 
				
			||||||
 | 
					                    ui.add_space(16.0);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                egui::widgets::global_dark_light_mode_buttons(ui);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                ui.with_layout(egui::Layout::top_down(egui::Align::RIGHT), |ui| {
 | 
				
			||||||
 | 
					                    ui.horizontal(|ui| {
 | 
				
			||||||
 | 
					                        ui.spacing_mut().item_spacing.x = 4.0;
 | 
				
			||||||
 | 
					                        ui.hyperlink_to(
 | 
				
			||||||
 | 
					                            "source code",
 | 
				
			||||||
 | 
					                            "https://gitea.djmil.dev/djmil/egui-circles",
 | 
				
			||||||
 | 
					                        );
 | 
				
			||||||
 | 
					                        ui.label("rust");
 | 
				
			||||||
 | 
					                    });
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        egui::CentralPanel::default().show(ctx, |ui| {
 | 
					        egui::CentralPanel::default().show(ctx, |ui| {
 | 
				
			||||||
 | 
					            // The central panel the region left after adding TopPanel's and SidePanel's
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Simulatiom
 | 
				
			||||||
 | 
					            ui.horizontal(|ui| {
 | 
				
			||||||
 | 
					                ui.label("Click on circles or press");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if ui.button("push").clicked() {
 | 
				
			||||||
 | 
					                    self.circles.iter_mut().for_each(|c| (*c).v = Vec2{
 | 
				
			||||||
 | 
					                        x: rand::thread_rng().gen_range(-4.0..4.0),
 | 
				
			||||||
 | 
					                        y: rand::thread_rng().gen_range(-4.0..4.0)});
 | 
				
			||||||
 | 
					                };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                ui.label("or");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                if ui.button("halt").clicked() {
 | 
					                if ui.button("halt").clicked() {
 | 
				
			||||||
                    self.circles.iter_mut().for_each(|c| (*c).v = Vec2{x: 0.0, y: 0.0});
 | 
					                    self.circles.iter_mut().for_each(|c| (*c).v = Vec2{x: 0.0, y: 0.0});
 | 
				
			||||||
                };
 | 
					                };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if ui.button("push").clicked() {
 | 
					                ui.label("buttons");
 | 
				
			||||||
                self.circles.iter_mut().for_each(|c| (*c).v = Vec2{
 | 
					            });
 | 
				
			||||||
                    x: rand::thread_rng().gen_range(-2.0..2.0),
 | 
					 | 
				
			||||||
                    y: rand::thread_rng().gen_range(-2.0..2.0)});
 | 
					 | 
				
			||||||
            };
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            ui.add(egui::Slider::new(&mut self.circles_count, 0..=25).text("circles count"));
 | 
					            ui.add(egui::Slider::new(&mut self.circles_count, 0..=25).text("circles count"));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -53,10 +118,10 @@ impl eframe::App for Simulation {
 | 
				
			|||||||
                    self.circles.push(Circle::default());
 | 
					                    self.circles.push(Circle::default());
 | 
				
			||||||
                    self.colors.push(
 | 
					                    self.colors.push(
 | 
				
			||||||
                        egui::Color32::from_rgba_premultiplied(
 | 
					                        egui::Color32::from_rgba_premultiplied(
 | 
				
			||||||
                            rand::thread_rng().gen_range(0..255),
 | 
					                            rand::thread_rng().gen_range(64..255),
 | 
				
			||||||
                            rand::thread_rng().gen_range(0..255),
 | 
					                            rand::thread_rng().gen_range(64..255),
 | 
				
			||||||
                            rand::thread_rng().gen_range(0..255),
 | 
					                            rand::thread_rng().gen_range(64..255),
 | 
				
			||||||
                            64)
 | 
					                            128)
 | 
				
			||||||
                        );
 | 
					                        );
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
@ -92,9 +157,19 @@ impl eframe::App for Simulation {
 | 
				
			|||||||
                    self.circles[i].c, 
 | 
					                    self.circles[i].c, 
 | 
				
			||||||
                    self.circles[i].r, 
 | 
					                    self.circles[i].r, 
 | 
				
			||||||
                self.colors[i] /*Color32::TRANSPARENT*/, 
 | 
					                self.colors[i] /*Color32::TRANSPARENT*/, 
 | 
				
			||||||
                    Stroke{width: 2.0, color: Color32::from_rgb(255, 255, 255)}
 | 
					                    Stroke{width: 2.0, color: Color32::from_rgb(200, 255, 255)}
 | 
				
			||||||
                );
 | 
					                );
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					            // End simultion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            ui.separator();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            ui.with_layout(egui::Layout::bottom_up(egui::Align::LEFT), |ui| {
 | 
				
			||||||
 | 
					                powered_by_egui_and_eframe(ui);
 | 
				
			||||||
 | 
					                egui::warn_if_debug_build(ui);
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        for circle in &mut self.circles {
 | 
					        for circle in &mut self.circles {
 | 
				
			||||||
@ -121,9 +196,22 @@ impl eframe::App for Simulation {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        // This is how to go into continuous mode - uncomment this to see example of continuous mode
 | 
					        // This is how to go into continuous mode - uncomment this to see example of continuous mode
 | 
				
			||||||
        ctx.request_repaint();
 | 
					        ctx.request_repaint();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn powered_by_egui_and_eframe(ui: &mut egui::Ui) {
 | 
				
			||||||
 | 
					    ui.horizontal(|ui| {
 | 
				
			||||||
 | 
					        ui.spacing_mut().item_spacing.x = 0.0;
 | 
				
			||||||
 | 
					        ui.label("Powered by ");
 | 
				
			||||||
 | 
					        ui.hyperlink_to("egui", "https://github.com/emilk/egui");
 | 
				
			||||||
 | 
					        ui.label(" and ");
 | 
				
			||||||
 | 
					        ui.hyperlink_to(
 | 
				
			||||||
 | 
					            "eframe",
 | 
				
			||||||
 | 
					            "https://github.com/emilk/egui/tree/master/crates/eframe",
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn collision(c1: &Circle, c2: &Circle) -> (Vec2, Vec2) {
 | 
					fn collision(c1: &Circle, c2: &Circle) -> (Vec2, Vec2) {
 | 
				
			||||||
    let m1 = c1.r;
 | 
					    let m1 = c1.r;
 | 
				
			||||||
@ -168,5 +256,3 @@ fn collision(c1: &Circle, c2: &Circle) -> (Vec2, Vec2) {
 | 
				
			|||||||
        vec2n + vec2t
 | 
					        vec2n + vec2t
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
//}
 | 
					 | 
				
			||||||
 | 
				
			|||||||
@ -1,10 +1,5 @@
 | 
				
			|||||||
extern crate emath;
 | 
					use egui::{Pos2, Rect, Vec2};
 | 
				
			||||||
extern crate rand;
 | 
					use rand::Rng;
 | 
				
			||||||
 | 
					 | 
				
			||||||
use self::emath::Vec2;
 | 
					 | 
				
			||||||
use self::emath::Pos2;
 | 
					 | 
				
			||||||
use self::emath::Rect;
 | 
					 | 
				
			||||||
use self::rand::Rng;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub static FRICTION: f32 = 0.995;
 | 
					pub static FRICTION: f32 = 0.995;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										6
									
								
								src/lib.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								src/lib.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,6 @@
 | 
				
			|||||||
 | 
					#![warn(clippy::all, rust_2018_idioms)]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					mod app;
 | 
				
			||||||
 | 
					pub use app::Simulation;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					mod circle;
 | 
				
			||||||
							
								
								
									
										17
									
								
								src/main.rs
									
									
									
									
									
										
										
										Executable file → Normal file
									
								
							
							
						
						
									
										17
									
								
								src/main.rs
									
									
									
									
									
										
										
										Executable file → Normal file
									
								
							@ -1,13 +1,13 @@
 | 
				
			|||||||
mod app;
 | 
					#![warn(clippy::all, rust_2018_idioms)]
 | 
				
			||||||
mod circle;
 | 
					#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// When compiling natively:
 | 
					// When compiling natively:
 | 
				
			||||||
#[cfg(not(target_arch = "wasm32"))]
 | 
					#[cfg(not(target_arch = "wasm32"))]
 | 
				
			||||||
fn main() -> eframe::Result<()> {
 | 
					fn main() -> eframe::Result {
 | 
				
			||||||
    //env_logger::init(); // Log to stderr (if you run with `RUST_LOG=debug`).
 | 
					    env_logger::init(); // Log to stderr (if you run with `RUST_LOG=debug`).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let native_options = eframe::NativeOptions {
 | 
					    let native_options = eframe::NativeOptions {
 | 
				
			||||||
        viewport: eframe::egui::ViewportBuilder::default()
 | 
					        viewport: egui::ViewportBuilder::default()
 | 
				
			||||||
            .with_inner_size([800.0, 600.0])
 | 
					            .with_inner_size([800.0, 600.0])
 | 
				
			||||||
            .with_min_inner_size([300.0, 220.0])
 | 
					            .with_min_inner_size([300.0, 220.0])
 | 
				
			||||||
            .with_icon(
 | 
					            .with_icon(
 | 
				
			||||||
@ -19,9 +19,9 @@ fn main() -> eframe::Result<()> {
 | 
				
			|||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    eframe::run_native(
 | 
					    eframe::run_native(
 | 
				
			||||||
        "egui-circles",
 | 
					        "eGUI Circles",
 | 
				
			||||||
        native_options,
 | 
					        native_options,
 | 
				
			||||||
        Box::new(|_| Ok(Box::<crate::app::Simulation>::default())),
 | 
					        Box::new(|cc| Ok(Box::new(egui_circles::Simulation::new(cc)))),
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -38,8 +38,7 @@ fn main() {
 | 
				
			|||||||
            .start(
 | 
					            .start(
 | 
				
			||||||
                "the_canvas_id",
 | 
					                "the_canvas_id",
 | 
				
			||||||
                web_options,
 | 
					                web_options,
 | 
				
			||||||
                //Box::new(|cc| Ok(Box::new(eframe_template::TemplateApp::new(cc)))),
 | 
					                Box::new(|cc| Ok(Box::new(egui_circles::Simulation::new(cc)))),
 | 
				
			||||||
                Box::new(|_| Ok(Box::<crate::app::Simulation>::default())),
 | 
					 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
            .await;
 | 
					            .await;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										13
									
								
								wasm32/Dockerfile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								wasm32/Dockerfile
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,13 @@
 | 
				
			|||||||
 | 
					FROM rust:1.79
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					RUN rustup target add wasm32-unknown-unknown 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					RUN cargo install --locked trunk
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ENTRYPOINT ["trunk"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CMD ["serve"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					WORKDIR /egui-circles
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					EXPOSE 8080/tcp
 | 
				
			||||||
							
								
								
									
										62
									
								
								wasm32/build.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										62
									
								
								wasm32/build.sh
									
									
									
									
									
										Executable file
									
								
							@ -0,0 +1,62 @@
 | 
				
			|||||||
 | 
					#!/usr/bin/env bash
 | 
				
			||||||
 | 
					set -euo pipefail
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					NAME=egui-circles
 | 
				
			||||||
 | 
					BUILDER=$NAME-builder:wasm32
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					has_docker_image() {
 | 
				
			||||||
 | 
					   docker manifest inspect $1
 | 
				
			||||||
 | 
					} &> /dev/null
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					has_docker_container() {
 | 
				
			||||||
 | 
						docker container inspect $1
 | 
				
			||||||
 | 
					} &> /dev/null
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if ! has_docker_image $BUILDER; then
 | 
				
			||||||
 | 
						echo "Docker $BUILDER was not found"
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						read -p "Would you like to create builder image (y/N)? "
 | 
				
			||||||
 | 
						case "$REPLY" in 
 | 
				
			||||||
 | 
						y|Y )
 | 
				
			||||||
 | 
							docker build \
 | 
				
			||||||
 | 
								--file wasm32/Dockerfile \
 | 
				
			||||||
 | 
								--tag $BUILDER \
 | 
				
			||||||
 | 
								. 
 | 
				
			||||||
 | 
								;;
 | 
				
			||||||
 | 
					  	* )
 | 
				
			||||||
 | 
							exit 1 ;;
 | 
				
			||||||
 | 
						esac
 | 
				
			||||||
 | 
					fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					echo "--> Initiate WASM32 target build.."
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					docker run \
 | 
				
			||||||
 | 
						--rm \
 | 
				
			||||||
 | 
						--volume $(pwd):/$NAME \
 | 
				
			||||||
 | 
						$BUILDER \
 | 
				
			||||||
 | 
							build --release --public-url /$NAME --verbose
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					echo "--> wasm32 target can be found in dist/ folder"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					read -p "Would you like to publish (y/N)? "
 | 
				
			||||||
 | 
					case "$REPLY" in 
 | 
				
			||||||
 | 
					y|Y )
 | 
				
			||||||
 | 
						cd dist/
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						git init
 | 
				
			||||||
 | 
						git checkout -b main
 | 
				
			||||||
 | 
						git add .
 | 
				
			||||||
 | 
						git commit --message «v0.2.1»
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						# solution for "send-pack: unexpected disconnect while reading sideband packet"
 | 
				
			||||||
 | 
						git config http.postBuffer 157286400 
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						git remote add origin https://gitea.djmil.dev/demo/egui-circles.git	
 | 
				
			||||||
 | 
						git push --set-upstream origin main --force
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						echo "--> Published at https://demo.pages.djmil.dev/egui-circles"
 | 
				
			||||||
 | 
						;;
 | 
				
			||||||
 | 
					* )
 | 
				
			||||||
 | 
						exit 0 
 | 
				
			||||||
 | 
						;;
 | 
				
			||||||
 | 
					esac
 | 
				
			||||||
		Loading…
	
		Reference in New Issue
	
	Block a user