gfx2.rs 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892
  1. /* This file is part of DarkFi (https://dark.fi)
  2. *
  3. * Copyright (C) 2020-2024 Dyne.org foundation
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU Affero General Public License as
  7. * published by the Free Software Foundation, either version 3 of the
  8. * License, or (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU Affero General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU Affero General Public License
  16. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  17. */
  18. use darkfi_serial::{SerialDecodable, SerialEncodable};
  19. use log::debug;
  20. use miniquad::{
  21. conf, window, Backend, Bindings, BlendFactor, BlendState, BlendValue, BufferId, BufferLayout,
  22. BufferSource, BufferType, BufferUsage, Equation, EventHandler, KeyCode, KeyMods, MouseButton,
  23. PassAction, Pipeline, PipelineParams, RenderingBackend, ShaderMeta, ShaderSource, TextureId,
  24. TouchPhase, UniformDesc, UniformType, VertexAttribute, VertexFormat,
  25. };
  26. use std::{
  27. collections::HashMap,
  28. sync::{mpsc, Arc, Mutex as SyncMutex},
  29. time::{Duration, Instant},
  30. };
  31. use crate::{
  32. app::AsyncRuntime,
  33. error::{Error, Result},
  34. pubsub::{Publisher, PublisherPtr, Subscription, SubscriptionId},
  35. shader,
  36. util::ansi_texture,
  37. };
  38. // This is very noisy so suppress output by default
  39. const DEBUG_RENDER: bool = false;
  40. #[derive(Debug, SerialEncodable, SerialDecodable)]
  41. #[repr(C)]
  42. pub struct Vertex {
  43. pub pos: [f32; 2],
  44. pub color: [f32; 4],
  45. pub uv: [f32; 2],
  46. }
  47. impl Vertex {
  48. pub fn pos(&self) -> Point {
  49. self.pos.into()
  50. }
  51. pub fn set_pos(&mut self, pos: &Point) {
  52. self.pos = pos.as_arr();
  53. }
  54. }
  55. #[derive(Debug)]
  56. pub struct Point {
  57. pub x: f32,
  58. pub y: f32,
  59. }
  60. impl Point {
  61. pub fn unpack(&self) -> (f32, f32) {
  62. (self.x, self.y)
  63. }
  64. pub fn as_arr(&self) -> [f32; 2] {
  65. [self.x, self.y]
  66. }
  67. pub fn offset(&self, off_x: f32, off_y: f32) -> Self {
  68. Self { x: self.x + off_x, y: self.y + off_y }
  69. }
  70. pub fn to_rect(&self, w: f32, h: f32) -> Rectangle {
  71. Rectangle { x: self.x, y: self.y, w, h }
  72. }
  73. }
  74. impl From<[f32; 2]> for Point {
  75. fn from(pos: [f32; 2]) -> Self {
  76. Self { x: pos[0], y: pos[1] }
  77. }
  78. }
  79. #[derive(Debug, Clone)]
  80. pub struct Rectangle {
  81. pub x: f32,
  82. pub y: f32,
  83. pub w: f32,
  84. pub h: f32,
  85. }
  86. impl Rectangle {
  87. pub fn new(x: f32, y: f32, w: f32, h: f32) -> Self {
  88. Self { x, y, w, h }
  89. }
  90. pub fn zero() -> Self {
  91. Self { x: 0., y: 0., w: 0., h: 0. }
  92. }
  93. pub fn from_array(arr: [f32; 4]) -> Self {
  94. Self { x: arr[0], y: arr[1], w: arr[2], h: arr[3] }
  95. }
  96. pub fn clip(&self, other: &Self) -> Option<Self> {
  97. if other.x + other.w < self.x ||
  98. other.x > self.x + self.w ||
  99. other.y + other.h < self.y ||
  100. other.y > self.y + self.h
  101. {
  102. return None
  103. }
  104. let mut clipped = other.clone();
  105. if clipped.x < self.x {
  106. clipped.x = self.x;
  107. clipped.w = other.x + other.w - clipped.x;
  108. }
  109. if clipped.y < self.y {
  110. clipped.y = self.y;
  111. clipped.h = other.y + other.h - clipped.y;
  112. }
  113. if clipped.x + clipped.w > self.x + self.w {
  114. clipped.w = self.x + self.w - clipped.x;
  115. }
  116. if clipped.y + clipped.h > self.y + self.h {
  117. clipped.h = self.y + self.h - clipped.y;
  118. }
  119. Some(clipped)
  120. }
  121. pub fn clip_point(&self, point: &mut Point) {
  122. if point.x < self.x {
  123. point.x = self.x;
  124. }
  125. if point.y < self.y {
  126. point.y = self.y;
  127. }
  128. if point.x > self.x + self.w {
  129. point.x = self.x + self.w;
  130. }
  131. if point.y > self.y + self.h {
  132. point.y = self.y + self.h;
  133. }
  134. }
  135. pub fn contains(&self, point: &Point) -> bool {
  136. self.x <= point.x &&
  137. point.x <= self.x + self.w &&
  138. self.y <= point.y &&
  139. point.y <= self.y + self.h
  140. }
  141. pub fn rhs(&self) -> f32 {
  142. self.x + self.w
  143. }
  144. pub fn bhs(&self) -> f32 {
  145. self.y + self.h
  146. }
  147. pub fn top_left(&self) -> Point {
  148. Point { x: self.x, y: self.y }
  149. }
  150. pub fn bottom_right(&self) -> Point {
  151. Point { x: self.x + self.w, y: self.y + self.h }
  152. }
  153. pub fn includes(&self, child: &Self) -> bool {
  154. self.contains(&child.top_left()) && self.contains(&child.bottom_right())
  155. }
  156. }
  157. pub type RenderApiPtr = Arc<RenderApi>;
  158. pub struct RenderApi {
  159. method_req: mpsc::Sender<GraphicsMethod>,
  160. }
  161. impl RenderApi {
  162. pub fn new(method_req: mpsc::Sender<GraphicsMethod>) -> Arc<Self> {
  163. Arc::new(Self { method_req })
  164. }
  165. pub async fn new_texture(&self, width: u16, height: u16, data: Vec<u8>) -> Result<TextureId> {
  166. let (sendr, recvr) = async_channel::bounded(1);
  167. let method = GraphicsMethod::NewTexture((width, height, data, sendr));
  168. self.method_req.send(method).map_err(|_| Error::GfxWindowClosed)?;
  169. let texture_id = recvr.recv().await.map_err(|_| Error::GfxWindowClosed)?;
  170. Ok(texture_id)
  171. }
  172. pub fn delete_texture(&self, texture: TextureId) {
  173. let method = GraphicsMethod::DeleteTexture(texture);
  174. // Ignore any error
  175. let _ = self.method_req.send(method);
  176. }
  177. pub async fn new_vertex_buffer(&self, verts: Vec<Vertex>) -> Result<BufferId> {
  178. let (sendr, recvr) = async_channel::bounded(1);
  179. let method = GraphicsMethod::NewVertexBuffer((verts, sendr));
  180. self.method_req.send(method).map_err(|_| Error::GfxWindowClosed)?;
  181. let buffer = recvr.recv().await.map_err(|_| Error::GfxWindowClosed)?;
  182. Ok(buffer)
  183. }
  184. pub async fn new_index_buffer(&self, indices: Vec<u16>) -> Result<BufferId> {
  185. let (sendr, recvr) = async_channel::bounded(1);
  186. let method = GraphicsMethod::NewIndexBuffer((indices, sendr));
  187. self.method_req.send(method).map_err(|_| Error::GfxWindowClosed)?;
  188. let buffer = recvr.recv().await.map_err(|_| Error::GfxWindowClosed)?;
  189. Ok(buffer)
  190. }
  191. pub fn delete_buffer(&self, buffer: BufferId) {
  192. let method = GraphicsMethod::DeleteBuffer(buffer);
  193. // Ignore any error
  194. let _ = self.method_req.send(method);
  195. }
  196. pub async fn replace_draw_calls(&self, dcs: Vec<(u64, DrawCall)>) {
  197. let method = GraphicsMethod::ReplaceDrawCalls(dcs);
  198. // Ignore any error
  199. let _ = self.method_req.send(method);
  200. }
  201. }
  202. #[derive(Clone, Debug)]
  203. pub struct DrawMesh {
  204. pub vertex_buffer: BufferId,
  205. pub index_buffer: BufferId,
  206. pub texture: Option<TextureId>,
  207. pub num_elements: i32,
  208. }
  209. #[derive(Debug, Clone)]
  210. pub enum DrawInstruction {
  211. ApplyViewport(Rectangle),
  212. ApplyMatrix(glam::Mat4),
  213. Draw(DrawMesh),
  214. }
  215. #[derive(Debug)]
  216. pub struct DrawCall {
  217. pub instrs: Vec<DrawInstruction>,
  218. pub dcs: Vec<u64>,
  219. pub z_index: u32,
  220. }
  221. struct RenderContext<'a> {
  222. ctx: &'a mut Box<dyn RenderingBackend>,
  223. draw_calls: &'a HashMap<u64, DrawCall>,
  224. uniforms_data: [u8; 128],
  225. white_texture: TextureId,
  226. // Used for implementing a push/pop for viewport
  227. current_view: Rectangle,
  228. }
  229. impl<'a> RenderContext<'a> {
  230. fn draw(&mut self) {
  231. if DEBUG_RENDER {
  232. debug!(target: "gfx", "RenderContext::draw()");
  233. }
  234. self.draw_call(&self.draw_calls[&0], 0);
  235. if DEBUG_RENDER {
  236. debug!(target: "gfx", "RenderContext::draw() [DONE]");
  237. }
  238. }
  239. fn apply_view(&mut self, view: &Rectangle) {
  240. let (_, screen_height) = window::screen_size();
  241. let view_x = view.x.round() as i32;
  242. let view_y = screen_height - (view.y + view.h);
  243. let view_y = view_y.round() as i32;
  244. let view_w = view.w.round() as i32;
  245. let view_h = view.h.round() as i32;
  246. self.ctx.apply_viewport(view_x, view_y, view_w, view_h);
  247. self.ctx.apply_scissor_rect(view_x, view_y, view_w, view_h);
  248. }
  249. fn draw_call(&mut self, draw_call: &DrawCall, indent: u32) {
  250. let ws = if DEBUG_RENDER { " ".repeat(indent as usize * 4) } else { String::new() };
  251. let mut prev_view = None;
  252. for instr in &draw_call.instrs {
  253. match instr {
  254. DrawInstruction::ApplyViewport(view) => {
  255. if DEBUG_RENDER {
  256. debug!(target: "gfx", "{}apply_viewport({:?})", ws, view);
  257. }
  258. prev_view = Some(view.clone());
  259. self.current_view = view.clone();
  260. self.apply_view(view);
  261. }
  262. DrawInstruction::ApplyMatrix(model) => {
  263. if DEBUG_RENDER {
  264. debug!(target: "gfx", "{}apply_matrix(", ws);
  265. debug!(target: "gfx", "{} {:?}", ws, model.row(0).to_array());
  266. debug!(target: "gfx", "{} {:?}", ws, model.row(1).to_array());
  267. debug!(target: "gfx", "{} {:?}", ws, model.row(2).to_array());
  268. debug!(target: "gfx", "{} {:?}", ws, model.row(3).to_array());
  269. debug!(target: "gfx", "{})", ws);
  270. }
  271. let data: [u8; 64] = unsafe { std::mem::transmute_copy(model) };
  272. self.uniforms_data[64..].copy_from_slice(&data);
  273. self.ctx.apply_uniforms_from_bytes(
  274. self.uniforms_data.as_ptr(),
  275. self.uniforms_data.len(),
  276. );
  277. }
  278. DrawInstruction::Draw(mesh) => {
  279. if DEBUG_RENDER {
  280. debug!(target: "gfx", "{}draw({:?})", ws, mesh);
  281. }
  282. let texture = match mesh.texture {
  283. Some(texture) => texture,
  284. None => self.white_texture,
  285. };
  286. let bindings = Bindings {
  287. vertex_buffers: vec![mesh.vertex_buffer],
  288. index_buffer: mesh.index_buffer,
  289. images: vec![texture],
  290. };
  291. self.ctx.apply_bindings(&bindings);
  292. self.ctx.draw(0, mesh.num_elements, 1);
  293. }
  294. }
  295. }
  296. let mut draw_calls: Vec<_> =
  297. draw_call.dcs.iter().map(|key| &self.draw_calls[key]).collect();
  298. draw_calls.sort_unstable_by_key(|dc| dc.z_index);
  299. for dc in draw_calls {
  300. self.draw_call(dc, indent + 1);
  301. }
  302. // Reset view back again
  303. if let Some(view) = prev_view {
  304. self.apply_view(&view);
  305. self.current_view = view;
  306. }
  307. }
  308. }
  309. #[derive(Debug)]
  310. pub enum GraphicsMethod {
  311. NewTexture((u16, u16, Vec<u8>, async_channel::Sender<TextureId>)),
  312. DeleteTexture(TextureId),
  313. NewVertexBuffer((Vec<Vertex>, async_channel::Sender<BufferId>)),
  314. NewIndexBuffer((Vec<u16>, async_channel::Sender<BufferId>)),
  315. DeleteBuffer(BufferId),
  316. ReplaceDrawCalls(Vec<(u64, DrawCall)>),
  317. }
  318. pub type GraphicsEventPublisherPtr = Arc<GraphicsEventPublisher>;
  319. pub struct GraphicsEventPublisher {
  320. lock_resize: SyncMutex<Option<SubscriptionId>>,
  321. resize: PublisherPtr<(f32, f32)>,
  322. lock_mouse_move: SyncMutex<Option<SubscriptionId>>,
  323. mouse_move: PublisherPtr<(f32, f32)>,
  324. lock_mouse_wheel: SyncMutex<Option<SubscriptionId>>,
  325. mouse_wheel: PublisherPtr<(f32, f32)>,
  326. lock_mouse_btn_down: SyncMutex<Option<SubscriptionId>>,
  327. mouse_btn_down: PublisherPtr<(MouseButton, f32, f32)>,
  328. lock_mouse_btn_up: SyncMutex<Option<SubscriptionId>>,
  329. mouse_btn_up: PublisherPtr<(MouseButton, f32, f32)>,
  330. lock_char: SyncMutex<Option<SubscriptionId>>,
  331. chr: PublisherPtr<(char, KeyMods, bool)>,
  332. lock_key_down: SyncMutex<Option<SubscriptionId>>,
  333. key_down: PublisherPtr<(KeyCode, KeyMods, bool)>,
  334. lock_key_up: SyncMutex<Option<SubscriptionId>>,
  335. key_up: PublisherPtr<(KeyCode, KeyMods)>,
  336. lock_touch: SyncMutex<Option<SubscriptionId>>,
  337. touch: PublisherPtr<(TouchPhase, u64, f32, f32)>,
  338. }
  339. impl GraphicsEventPublisher {
  340. pub fn new() -> Arc<Self> {
  341. Arc::new(Self {
  342. lock_resize: SyncMutex::new(None),
  343. resize: Publisher::new(),
  344. lock_mouse_move: SyncMutex::new(None),
  345. mouse_move: Publisher::new(),
  346. lock_mouse_wheel: SyncMutex::new(None),
  347. mouse_wheel: Publisher::new(),
  348. lock_mouse_btn_down: SyncMutex::new(None),
  349. mouse_btn_down: Publisher::new(),
  350. lock_mouse_btn_up: SyncMutex::new(None),
  351. mouse_btn_up: Publisher::new(),
  352. lock_char: SyncMutex::new(None),
  353. chr: Publisher::new(),
  354. lock_key_down: SyncMutex::new(None),
  355. key_down: Publisher::new(),
  356. lock_key_up: SyncMutex::new(None),
  357. key_up: Publisher::new(),
  358. lock_touch: SyncMutex::new(None),
  359. touch: Publisher::new(),
  360. })
  361. }
  362. fn lock_resize(&self, sub_id: SubscriptionId) {
  363. *self.lock_resize.lock().unwrap() = Some(sub_id);
  364. }
  365. fn unlock_resize(&self) {
  366. *self.lock_resize.lock().unwrap() = None;
  367. }
  368. fn lock_mouse_move(&self, sub_id: SubscriptionId) {
  369. *self.lock_mouse_move.lock().unwrap() = Some(sub_id);
  370. }
  371. fn unlock_mouse_move(&self) {
  372. *self.lock_mouse_move.lock().unwrap() = None;
  373. }
  374. fn lock_mouse_wheel(&self, sub_id: SubscriptionId) {
  375. *self.lock_mouse_wheel.lock().unwrap() = Some(sub_id);
  376. }
  377. fn unlock_mouse_wheel(&self) {
  378. *self.lock_mouse_wheel.lock().unwrap() = None;
  379. }
  380. fn lock_mouse_btn_down(&self, sub_id: SubscriptionId) {
  381. *self.lock_mouse_btn_down.lock().unwrap() = Some(sub_id);
  382. }
  383. fn unlock_mouse_btn_down(&self) {
  384. *self.lock_mouse_btn_down.lock().unwrap() = None;
  385. }
  386. fn lock_mouse_btn_up(&self, sub_id: SubscriptionId) {
  387. *self.lock_mouse_btn_up.lock().unwrap() = Some(sub_id);
  388. }
  389. fn unlock_mouse_btn_up(&self) {
  390. *self.lock_mouse_btn_up.lock().unwrap() = None;
  391. }
  392. fn lock_char(&self, sub_id: SubscriptionId) {
  393. *self.lock_char.lock().unwrap() = Some(sub_id);
  394. }
  395. fn unlock_char(&self) {
  396. *self.lock_char.lock().unwrap() = None;
  397. }
  398. fn lock_key_down(&self, sub_id: SubscriptionId) {
  399. *self.lock_key_down.lock().unwrap() = Some(sub_id);
  400. }
  401. fn unlock_key_down(&self) {
  402. *self.lock_key_down.lock().unwrap() = None;
  403. }
  404. fn lock_key_up(&self, sub_id: SubscriptionId) {
  405. *self.lock_key_up.lock().unwrap() = Some(sub_id);
  406. }
  407. fn unlock_key_up(&self) {
  408. *self.lock_key_up.lock().unwrap() = None;
  409. }
  410. fn lock_touch(&self, sub_id: SubscriptionId) {
  411. *self.lock_touch.lock().unwrap() = Some(sub_id);
  412. }
  413. fn unlock_touch(&self) {
  414. *self.lock_touch.lock().unwrap() = None;
  415. }
  416. fn notify_resize(&self, w: f32, h: f32) {
  417. let ev = (w, h);
  418. let locked = self.lock_resize.lock().unwrap().clone();
  419. if let Some(locked) = locked {
  420. self.resize.notify_with_include(ev, &[locked]);
  421. } else {
  422. self.resize.notify(ev);
  423. }
  424. }
  425. fn notify_mouse_move(&self, x: f32, y: f32) {
  426. let ev = (x, y);
  427. let locked = self.lock_mouse_move.lock().unwrap().clone();
  428. if let Some(locked) = locked {
  429. self.mouse_move.notify_with_include(ev, &[locked]);
  430. } else {
  431. self.mouse_move.notify(ev);
  432. }
  433. }
  434. fn notify_mouse_wheel(&self, x: f32, y: f32) {
  435. let ev = (x, y);
  436. let locked = self.lock_mouse_wheel.lock().unwrap().clone();
  437. if let Some(locked) = locked {
  438. self.mouse_wheel.notify_with_include(ev, &[locked]);
  439. } else {
  440. self.mouse_wheel.notify(ev);
  441. }
  442. }
  443. fn notify_mouse_btn_down(&self, button: MouseButton, x: f32, y: f32) {
  444. let ev = (button, x, y);
  445. let locked = self.lock_mouse_btn_down.lock().unwrap().clone();
  446. if let Some(locked) = locked {
  447. self.mouse_btn_down.notify_with_include(ev, &[locked]);
  448. } else {
  449. self.mouse_btn_down.notify(ev);
  450. }
  451. }
  452. fn notify_mouse_btn_up(&self, button: MouseButton, x: f32, y: f32) {
  453. let ev = (button, x, y);
  454. let locked = self.lock_mouse_btn_up.lock().unwrap().clone();
  455. if let Some(locked) = locked {
  456. self.mouse_btn_up.notify_with_include(ev, &[locked]);
  457. } else {
  458. self.mouse_btn_up.notify(ev);
  459. }
  460. }
  461. fn notify_char(&self, chr: char, mods: KeyMods, repeat: bool) {
  462. let ev = (chr, mods, repeat);
  463. let locked = self.lock_char.lock().unwrap().clone();
  464. if let Some(locked) = locked {
  465. self.chr.notify_with_include(ev, &[locked]);
  466. } else {
  467. self.chr.notify(ev);
  468. }
  469. }
  470. fn notify_key_down(&self, key: KeyCode, mods: KeyMods, repeat: bool) {
  471. let ev = (key, mods, repeat);
  472. let locked = self.lock_key_down.lock().unwrap().clone();
  473. if let Some(locked) = locked {
  474. self.key_down.notify_with_include(ev, &[locked]);
  475. } else {
  476. self.key_down.notify(ev);
  477. }
  478. }
  479. fn notify_key_up(&self, key: KeyCode, mods: KeyMods) {
  480. let ev = (key, mods);
  481. let locked = self.lock_key_up.lock().unwrap().clone();
  482. if let Some(locked) = locked {
  483. self.key_up.notify_with_include(ev, &[locked]);
  484. } else {
  485. self.key_up.notify(ev);
  486. }
  487. }
  488. fn notify_touch(&self, phase: TouchPhase, id: u64, x: f32, y: f32) {
  489. let ev = (phase, id, x, y);
  490. let locked = self.lock_touch.lock().unwrap().clone();
  491. if let Some(locked) = locked {
  492. self.touch.notify_with_include(ev, &[locked]);
  493. } else {
  494. self.touch.notify(ev);
  495. }
  496. }
  497. pub fn subscribe_resize(&self) -> Subscription<(f32, f32)> {
  498. self.resize.clone().subscribe()
  499. }
  500. pub fn subscribe_mouse_move(&self) -> Subscription<(f32, f32)> {
  501. self.mouse_move.clone().subscribe()
  502. }
  503. pub fn subscribe_mouse_wheel(&self) -> Subscription<(f32, f32)> {
  504. self.mouse_wheel.clone().subscribe()
  505. }
  506. pub fn subscribe_mouse_btn_down(&self) -> Subscription<(MouseButton, f32, f32)> {
  507. self.mouse_btn_down.clone().subscribe()
  508. }
  509. pub fn subscribe_mouse_btn_up(&self) -> Subscription<(MouseButton, f32, f32)> {
  510. self.mouse_btn_up.clone().subscribe()
  511. }
  512. pub fn subscribe_char(&self) -> Subscription<(char, KeyMods, bool)> {
  513. self.chr.clone().subscribe()
  514. }
  515. pub fn subscribe_key_down(&self) -> Subscription<(KeyCode, KeyMods, bool)> {
  516. self.key_down.clone().subscribe()
  517. }
  518. pub fn subscribe_key_up(&self) -> Subscription<(KeyCode, KeyMods)> {
  519. self.key_up.clone().subscribe()
  520. }
  521. pub fn subscribe_touch(&self) -> Subscription<(TouchPhase, u64, f32, f32)> {
  522. self.touch.clone().subscribe()
  523. }
  524. }
  525. struct Stage {
  526. async_runtime: AsyncRuntime,
  527. ctx: Box<dyn RenderingBackend>,
  528. pipeline: Pipeline,
  529. white_texture: TextureId,
  530. draw_calls: HashMap<u64, DrawCall>,
  531. last_draw_time: Option<Instant>,
  532. method_rep: mpsc::Receiver<GraphicsMethod>,
  533. event_pub: GraphicsEventPublisherPtr,
  534. }
  535. impl Stage {
  536. pub fn new(
  537. async_runtime: AsyncRuntime,
  538. method_rep: mpsc::Receiver<GraphicsMethod>,
  539. event_pub: GraphicsEventPublisherPtr,
  540. ) -> Self {
  541. let mut ctx: Box<dyn RenderingBackend> = window::new_rendering_backend();
  542. // Maybe should be patched upstream since inconsistent behaviour
  543. // Needs testing on other platforms too.
  544. #[cfg(target_os = "android")]
  545. {
  546. let (screen_width, screen_height) = window::screen_size();
  547. event_pub.notify_resize(screen_width, screen_height);
  548. }
  549. let white_texture = ctx.new_texture_from_rgba8(1, 1, &[255, 255, 255, 255]);
  550. let mut shader_meta: ShaderMeta = shader::meta();
  551. shader_meta.uniforms.uniforms.push(UniformDesc::new("Projection", UniformType::Mat4));
  552. shader_meta.uniforms.uniforms.push(UniformDesc::new("Model", UniformType::Mat4));
  553. let shader = ctx
  554. .new_shader(
  555. match ctx.info().backend {
  556. Backend::OpenGl => ShaderSource::Glsl {
  557. vertex: shader::GL_VERTEX,
  558. fragment: shader::GL_FRAGMENT,
  559. },
  560. Backend::Metal => ShaderSource::Msl { program: shader::METAL },
  561. },
  562. shader_meta,
  563. )
  564. .unwrap();
  565. let params = PipelineParams {
  566. color_blend: Some(BlendState::new(
  567. Equation::Add,
  568. BlendFactor::Value(BlendValue::SourceAlpha),
  569. BlendFactor::OneMinusValue(BlendValue::SourceAlpha),
  570. )),
  571. ..Default::default()
  572. };
  573. let pipeline = ctx.new_pipeline(
  574. &[BufferLayout::default()],
  575. &[
  576. VertexAttribute::new("in_pos", VertexFormat::Float2),
  577. VertexAttribute::new("in_color", VertexFormat::Float4),
  578. VertexAttribute::new("in_uv", VertexFormat::Float2),
  579. ],
  580. shader,
  581. params,
  582. );
  583. Stage {
  584. async_runtime,
  585. ctx,
  586. pipeline,
  587. white_texture,
  588. draw_calls: HashMap::from([(0, DrawCall { instrs: vec![], dcs: vec![], z_index: 0 })]),
  589. last_draw_time: None,
  590. method_rep,
  591. event_pub,
  592. }
  593. }
  594. fn method_new_texture(
  595. &mut self,
  596. width: u16,
  597. height: u16,
  598. data: Vec<u8>,
  599. sendr: async_channel::Sender<TextureId>,
  600. ) {
  601. let texture = self.ctx.new_texture_from_rgba8(width, height, &data);
  602. //debug!(target: "gfx2", "Invoked method: new_texture({}, {}, ...) -> {:?}",
  603. // width, height, texture);
  604. //debug!(target: "gfx2", "Invoked method: new_texture({}, {}, ...) -> {:?}\n{}",
  605. // width, height, texture,
  606. // ansi_texture(width as usize, height as usize, &data));
  607. sendr.try_send(texture).unwrap();
  608. }
  609. fn method_delete_texture(&mut self, texture: TextureId) {
  610. //debug!(target: "gfx2", "Invoked method: delete_texture({:?})", texture);
  611. self.ctx.delete_texture(texture);
  612. }
  613. fn method_new_vertex_buffer(
  614. &mut self,
  615. verts: Vec<Vertex>,
  616. sendr: async_channel::Sender<BufferId>,
  617. ) {
  618. let buffer = self.ctx.new_buffer(
  619. BufferType::VertexBuffer,
  620. BufferUsage::Immutable,
  621. BufferSource::slice(&verts),
  622. );
  623. //debug!(target: "gfx2", "Invoked method: new_vertex_buffer({:?}) -> {:?}", verts, buffer);
  624. sendr.try_send(buffer).unwrap();
  625. }
  626. fn method_new_index_buffer(
  627. &mut self,
  628. indices: Vec<u16>,
  629. sendr: async_channel::Sender<BufferId>,
  630. ) {
  631. let buffer = self.ctx.new_buffer(
  632. BufferType::IndexBuffer,
  633. BufferUsage::Immutable,
  634. BufferSource::slice(&indices),
  635. );
  636. //debug!(target: "gfx2", "Invoked method: new_index_buffer({:?}) -> {:?}", indices, buffer);
  637. sendr.try_send(buffer).unwrap();
  638. }
  639. fn method_delete_buffer(&mut self, buffer: BufferId) {
  640. //debug!(target: "gfx2", "Invoked method: delete_buffer({:?})", buffer);
  641. self.ctx.delete_buffer(buffer);
  642. }
  643. fn method_replace_draw_calls(&mut self, dcs: Vec<(u64, DrawCall)>) {
  644. //debug!(target: "gfx2", "Invoked method: replace_draw_calls({:?})", dcs);
  645. for (key, val) in dcs {
  646. self.draw_calls.insert(key, val);
  647. }
  648. }
  649. }
  650. impl EventHandler for Stage {
  651. fn update(&mut self) {
  652. if self.last_draw_time.is_none() {
  653. return
  654. }
  655. // Only allow 20 ms, process as much as we can during that time
  656. let elapsed_since_draw = self.last_draw_time.unwrap().elapsed();
  657. // We're long overdue a redraw. Exit for now
  658. if elapsed_since_draw > Duration::from_millis(20) {
  659. return
  660. }
  661. // The next redraw must happen 20ms since its last one.
  662. // Calculate how much time is remaining until then.
  663. let allowed_time = Duration::from_millis(20) - elapsed_since_draw;
  664. let deadline = Instant::now() + allowed_time;
  665. loop {
  666. let Ok(method) = self.method_rep.recv_deadline(deadline) else { break };
  667. //debug!(target: "gfx", "Received method: {:?}", method);
  668. match method {
  669. GraphicsMethod::NewTexture((width, height, data, sendr)) => {
  670. self.method_new_texture(width, height, data, sendr)
  671. }
  672. GraphicsMethod::DeleteTexture(texture) => self.method_delete_texture(texture),
  673. GraphicsMethod::NewVertexBuffer((verts, sendr)) => {
  674. self.method_new_vertex_buffer(verts, sendr)
  675. }
  676. GraphicsMethod::NewIndexBuffer((indices, sendr)) => {
  677. self.method_new_index_buffer(indices, sendr)
  678. }
  679. GraphicsMethod::DeleteBuffer(buffer) => self.method_delete_buffer(buffer),
  680. GraphicsMethod::ReplaceDrawCalls(dcs) => self.method_replace_draw_calls(dcs),
  681. };
  682. }
  683. }
  684. fn draw(&mut self) {
  685. self.last_draw_time = Some(Instant::now());
  686. self.ctx.begin_default_pass(PassAction::Nothing);
  687. self.ctx.apply_pipeline(&self.pipeline);
  688. // This will make the top left (0, 0) and the bottom right (1, 1)
  689. // Default is (-1, 1) -> (1, -1)
  690. let proj = glam::Mat4::from_translation(glam::Vec3::new(-1., 1., 0.)) *
  691. glam::Mat4::from_scale(glam::Vec3::new(2., -2., 1.));
  692. let mut uniforms_data = [0u8; 128];
  693. let data: [u8; 64] = unsafe { std::mem::transmute_copy(&proj) };
  694. uniforms_data[0..64].copy_from_slice(&data);
  695. //let data: [u8; 64] = unsafe { std::mem::transmute_copy(&model) };
  696. //uniforms_data[64..].copy_from_slice(&data);
  697. assert_eq!(128, 2 * UniformType::Mat4.size());
  698. let (screen_width, screen_height) = window::screen_size();
  699. let default_view = Rectangle { x: 0., y: 0., w: screen_width, h: screen_height };
  700. let mut render_ctx = RenderContext {
  701. ctx: &mut self.ctx,
  702. draw_calls: &self.draw_calls,
  703. uniforms_data,
  704. white_texture: self.white_texture,
  705. current_view: default_view,
  706. };
  707. render_ctx.draw();
  708. self.ctx.commit_frame();
  709. }
  710. fn resize_event(&mut self, width: f32, height: f32) {
  711. self.event_pub.notify_resize(width, height);
  712. }
  713. fn mouse_motion_event(&mut self, x: f32, y: f32) {
  714. self.event_pub.notify_mouse_move(x, y);
  715. }
  716. fn mouse_wheel_event(&mut self, x: f32, y: f32) {
  717. self.event_pub.notify_mouse_wheel(x, y);
  718. }
  719. fn mouse_button_down_event(&mut self, button: MouseButton, x: f32, y: f32) {
  720. self.event_pub.notify_mouse_btn_down(button, x, y);
  721. }
  722. fn mouse_button_up_event(&mut self, button: MouseButton, x: f32, y: f32) {
  723. self.event_pub.notify_mouse_btn_up(button, x, y);
  724. }
  725. fn char_event(&mut self, chr: char, mods: KeyMods, repeat: bool) {
  726. self.event_pub.notify_char(chr, mods, repeat);
  727. }
  728. fn key_down_event(&mut self, keycode: KeyCode, mods: KeyMods, repeat: bool) {
  729. self.event_pub.notify_key_down(keycode, mods, repeat);
  730. }
  731. fn key_up_event(&mut self, keycode: KeyCode, mods: KeyMods) {
  732. self.event_pub.notify_key_up(keycode, mods);
  733. }
  734. /// The id corresponds to multi-touch. Multiple touch events have different ids.
  735. fn touch_event(&mut self, phase: TouchPhase, id: u64, x: f32, y: f32) {
  736. self.event_pub.notify_touch(phase, id, x, y);
  737. }
  738. fn quit_requested_event(&mut self) {
  739. self.async_runtime.stop();
  740. }
  741. }
  742. pub fn run_gui(
  743. async_runtime: AsyncRuntime,
  744. method_rep: mpsc::Receiver<GraphicsMethod>,
  745. event_pub: GraphicsEventPublisherPtr,
  746. ) {
  747. let mut conf = miniquad::conf::Conf {
  748. high_dpi: true,
  749. window_resizable: true,
  750. platform: miniquad::conf::Platform {
  751. linux_backend: miniquad::conf::LinuxBackend::WaylandWithX11Fallback,
  752. wayland_use_fallback_decorations: false,
  753. ..Default::default()
  754. },
  755. ..Default::default()
  756. };
  757. let metal = std::env::args().nth(1).as_deref() == Some("metal");
  758. conf.platform.apple_gfx_api =
  759. if metal { conf::AppleGfxApi::Metal } else { conf::AppleGfxApi::OpenGl };
  760. miniquad::start(conf, || Box::new(Stage::new(async_runtime, method_rep, event_pub)));
  761. }