mod.rs 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955
  1. /* This file is part of DarkFi (https://dark.fi)
  2. *
  3. * Copyright (C) 2020-2025 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::system::CondVar;
  19. use darkfi_serial::{async_trait, Decodable, Encodable, SerialDecodable, SerialEncodable};
  20. use futures::AsyncWriteExt;
  21. use log::debug;
  22. use miniquad::{
  23. conf, window, Backend, Bindings, BlendFactor, BlendState, BlendValue, BufferLayout,
  24. BufferSource, BufferType, BufferUsage, Equation, EventHandler, KeyCode, KeyMods, MouseButton,
  25. PassAction, Pipeline, PipelineParams, RenderingBackend, ShaderMeta, ShaderSource, TouchPhase,
  26. UniformDesc, UniformType, VertexAttribute, VertexFormat,
  27. };
  28. use std::{
  29. collections::HashMap,
  30. fs::File,
  31. path::PathBuf,
  32. sync::{
  33. atomic::{AtomicU32, Ordering},
  34. mpsc, Arc, Mutex as SyncMutex,
  35. },
  36. time::{Duration, Instant},
  37. };
  38. mod favico;
  39. mod linalg;
  40. pub use linalg::{Dimension, Point, Rectangle};
  41. mod shader;
  42. use crate::{
  43. app::{AppPtr, AsyncRuntime},
  44. error::{Error, Result},
  45. pubsub::{Publisher, PublisherPtr, Subscription, SubscriptionId},
  46. util::ansi_texture,
  47. };
  48. // This is very noisy so suppress output by default
  49. const DEBUG_RENDER: bool = false;
  50. const DEBUG_GFXAPI: bool = false;
  51. #[cfg(target_os = "android")]
  52. pub fn get_window_size_filename() -> PathBuf {
  53. crate::android::get_appdata_path().join("window_size")
  54. }
  55. #[cfg(not(target_os = "android"))]
  56. pub fn get_window_size_filename() -> PathBuf {
  57. dirs::cache_dir().unwrap().join("darkfi/app/window_size")
  58. }
  59. #[derive(Clone, Debug, SerialEncodable, SerialDecodable)]
  60. #[repr(C)]
  61. pub struct Vertex {
  62. pub pos: [f32; 2],
  63. pub color: [f32; 4],
  64. pub uv: [f32; 2],
  65. }
  66. impl Vertex {
  67. pub fn pos(&self) -> Point {
  68. self.pos.into()
  69. }
  70. pub fn set_pos(&mut self, pos: &Point) {
  71. self.pos = pos.as_arr();
  72. }
  73. }
  74. pub type GfxTextureId = u32;
  75. pub type GfxBufferId = u32;
  76. static NEXT_BUFFER_ID: AtomicU32 = AtomicU32::new(0);
  77. static NEXT_TEXTURE_ID: AtomicU32 = AtomicU32::new(0);
  78. pub type ManagedTexturePtr = Arc<ManagedTexture>;
  79. /// Auto-deletes texture on drop
  80. #[derive(Clone)]
  81. pub struct ManagedTexture {
  82. id: GfxTextureId,
  83. render_api: RenderApi,
  84. }
  85. impl Drop for ManagedTexture {
  86. fn drop(&mut self) {
  87. self.render_api.delete_unmanaged_texture(self.id);
  88. }
  89. }
  90. impl std::fmt::Debug for ManagedTexture {
  91. fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
  92. f.debug_struct("ManagedTexture").field("id", &self.id).finish()
  93. }
  94. }
  95. pub type ManagedBufferPtr = Arc<ManagedBuffer>;
  96. /// Auto-deletes buffer on drop
  97. #[derive(Clone)]
  98. pub struct ManagedBuffer {
  99. id: GfxBufferId,
  100. render_api: RenderApi,
  101. }
  102. impl Drop for ManagedBuffer {
  103. fn drop(&mut self) {
  104. self.render_api.delete_unmanaged_buffer(self.id);
  105. }
  106. }
  107. impl std::fmt::Debug for ManagedBuffer {
  108. fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
  109. f.debug_struct("ManagedBuffer").field("id", &self.id).finish()
  110. }
  111. }
  112. #[derive(Clone)]
  113. pub struct RenderApi {
  114. method_req: mpsc::Sender<GraphicsMethod>,
  115. }
  116. impl RenderApi {
  117. pub fn new(method_req: mpsc::Sender<GraphicsMethod>) -> Self {
  118. Self { method_req }
  119. }
  120. fn new_unmanaged_texture(&self, width: u16, height: u16, data: Vec<u8>) -> GfxTextureId {
  121. let gfx_texture_id = NEXT_TEXTURE_ID.fetch_add(1, Ordering::SeqCst);
  122. let method = GraphicsMethod::NewTexture((width, height, data, gfx_texture_id));
  123. let _ = self.method_req.send(method);
  124. gfx_texture_id
  125. }
  126. pub fn new_texture(&self, width: u16, height: u16, data: Vec<u8>) -> ManagedTexturePtr {
  127. Arc::new(ManagedTexture {
  128. id: self.new_unmanaged_texture(width, height, data),
  129. render_api: self.clone(),
  130. })
  131. }
  132. fn delete_unmanaged_texture(&self, texture: GfxTextureId) {
  133. let method = GraphicsMethod::DeleteTexture(texture);
  134. let _ = self.method_req.send(method);
  135. }
  136. fn new_unmanaged_vertex_buffer(&self, verts: Vec<Vertex>) -> GfxBufferId {
  137. let gfx_buffer_id = NEXT_BUFFER_ID.fetch_add(1, Ordering::SeqCst);
  138. let method = GraphicsMethod::NewVertexBuffer((verts, gfx_buffer_id));
  139. let _ = self.method_req.send(method);
  140. gfx_buffer_id
  141. }
  142. fn new_unmanaged_index_buffer(&self, indices: Vec<u16>) -> GfxBufferId {
  143. let gfx_buffer_id = NEXT_BUFFER_ID.fetch_add(1, Ordering::SeqCst);
  144. let method = GraphicsMethod::NewIndexBuffer((indices, gfx_buffer_id));
  145. let _ = self.method_req.send(method);
  146. gfx_buffer_id
  147. }
  148. pub fn new_vertex_buffer(&self, verts: Vec<Vertex>) -> ManagedBufferPtr {
  149. Arc::new(ManagedBuffer {
  150. id: self.new_unmanaged_vertex_buffer(verts),
  151. render_api: self.clone(),
  152. })
  153. }
  154. pub fn new_index_buffer(&self, indices: Vec<u16>) -> ManagedBufferPtr {
  155. Arc::new(ManagedBuffer {
  156. id: self.new_unmanaged_index_buffer(indices),
  157. render_api: self.clone(),
  158. })
  159. }
  160. fn delete_unmanaged_buffer(&self, buffer: GfxBufferId) {
  161. let method = GraphicsMethod::DeleteBuffer(buffer);
  162. let _ = self.method_req.send(method);
  163. }
  164. pub fn replace_draw_calls(&self, timest: u64, dcs: Vec<(u64, GfxDrawCall)>) {
  165. let method = GraphicsMethod::ReplaceDrawCalls { timest, dcs };
  166. let _ = self.method_req.send(method);
  167. }
  168. }
  169. #[derive(Clone, Debug)]
  170. pub struct GfxDrawMesh {
  171. pub vertex_buffer: ManagedBufferPtr,
  172. pub index_buffer: ManagedBufferPtr,
  173. pub texture: Option<ManagedTexturePtr>,
  174. pub num_elements: i32,
  175. }
  176. impl GfxDrawMesh {
  177. fn compile(
  178. self,
  179. textures: &HashMap<GfxTextureId, miniquad::TextureId>,
  180. buffers: &HashMap<GfxBufferId, miniquad::BufferId>,
  181. ) -> Option<DrawMesh> {
  182. let vertex_buffer_id = self.vertex_buffer.id;
  183. let index_buffer_id = self.index_buffer.id;
  184. let buffers_keep_alive = [self.vertex_buffer, self.index_buffer];
  185. let texture = match self.texture {
  186. Some(gfx_texture) => Self::try_get_texture(textures, gfx_texture),
  187. None => None,
  188. };
  189. Some(DrawMesh {
  190. vertex_buffer: Self::try_get_buffer(buffers, vertex_buffer_id)?,
  191. index_buffer: Self::try_get_buffer(buffers, index_buffer_id)?,
  192. buffers_keep_alive,
  193. texture,
  194. num_elements: self.num_elements,
  195. })
  196. }
  197. fn try_get_texture(
  198. textures: &HashMap<GfxTextureId, miniquad::TextureId>,
  199. gfx_texture: ManagedTexturePtr,
  200. ) -> Option<(ManagedTexturePtr, miniquad::TextureId)> {
  201. let gfx_texture_id = gfx_texture.id;
  202. let Some(mq_texture_id) = textures.get(&gfx_texture_id) else {
  203. error!(target: "gfx", "Serious error: missing texture ID={gfx_texture_id}");
  204. error!(target: "gfx", "Dumping textures:");
  205. for (gfx_texture_id, texture_id) in textures {
  206. error!(target: "gfx", "{gfx_texture_id} => {texture_id:?}");
  207. }
  208. panic!("Missing texture ID={gfx_texture_id}");
  209. return None
  210. };
  211. Some((gfx_texture, textures[&gfx_texture_id]))
  212. }
  213. fn try_get_buffer(
  214. buffers: &HashMap<GfxBufferId, miniquad::BufferId>,
  215. gfx_buffer_id: GfxBufferId,
  216. ) -> Option<miniquad::BufferId> {
  217. let Some(mq_buffer_id) = buffers.get(&gfx_buffer_id) else {
  218. error!(target: "gfx", "Serious error: missing buffer ID={gfx_buffer_id}");
  219. error!(target: "gfx", "Dumping buffers:");
  220. for (gfx_buffer_id, buffer_id) in buffers {
  221. error!(target: "gfx", "{gfx_buffer_id} => {buffer_id:?}");
  222. }
  223. panic!("Missing buffer ID={gfx_buffer_id}");
  224. return None
  225. };
  226. Some(*mq_buffer_id)
  227. }
  228. }
  229. #[derive(Debug, Clone)]
  230. pub enum GfxDrawInstruction {
  231. SetScale(f32),
  232. Move(Point),
  233. SetPos(Point),
  234. ApplyView(Rectangle),
  235. Draw(GfxDrawMesh),
  236. EnableDebug,
  237. }
  238. impl GfxDrawInstruction {
  239. fn compile(
  240. self,
  241. textures: &HashMap<GfxTextureId, miniquad::TextureId>,
  242. buffers: &HashMap<GfxBufferId, miniquad::BufferId>,
  243. ) -> Option<DrawInstruction> {
  244. let instr = match self {
  245. Self::SetScale(scale) => DrawInstruction::SetScale(scale),
  246. Self::Move(off) => DrawInstruction::Move(off),
  247. Self::SetPos(pos) => DrawInstruction::SetPos(pos),
  248. Self::ApplyView(view) => DrawInstruction::ApplyView(view),
  249. Self::Draw(mesh) => DrawInstruction::Draw(mesh.compile(textures, buffers)?),
  250. Self::EnableDebug => DrawInstruction::EnableDebug,
  251. };
  252. Some(instr)
  253. }
  254. }
  255. #[derive(Clone, Debug, Default)]
  256. pub struct GfxDrawCall {
  257. pub instrs: Vec<GfxDrawInstruction>,
  258. pub dcs: Vec<u64>,
  259. pub z_index: u32,
  260. }
  261. impl GfxDrawCall {
  262. fn compile(
  263. self,
  264. textures: &HashMap<GfxTextureId, miniquad::TextureId>,
  265. buffers: &HashMap<GfxBufferId, miniquad::BufferId>,
  266. timest: u64,
  267. ) -> Option<DrawCall> {
  268. Some(DrawCall {
  269. instrs: self
  270. .instrs
  271. .into_iter()
  272. .map(|i| i.compile(textures, buffers))
  273. .collect::<Option<Vec<_>>>()?,
  274. dcs: self.dcs,
  275. z_index: self.z_index,
  276. timest,
  277. })
  278. }
  279. }
  280. #[derive(Clone, Debug)]
  281. struct DrawMesh {
  282. vertex_buffer: miniquad::BufferId,
  283. index_buffer: miniquad::BufferId,
  284. /// Keeps the buffers alive for the duration of this draw call
  285. buffers_keep_alive: [ManagedBufferPtr; 2],
  286. texture: Option<(ManagedTexturePtr, miniquad::TextureId)>,
  287. num_elements: i32,
  288. }
  289. #[derive(Debug, Clone)]
  290. enum DrawInstruction {
  291. SetScale(f32),
  292. Move(Point),
  293. SetPos(Point),
  294. ApplyView(Rectangle),
  295. Draw(DrawMesh),
  296. EnableDebug,
  297. }
  298. #[derive(Debug)]
  299. struct DrawCall {
  300. instrs: Vec<DrawInstruction>,
  301. dcs: Vec<u64>,
  302. z_index: u32,
  303. timest: u64,
  304. }
  305. struct RenderContext<'a> {
  306. ctx: &'a mut Box<dyn RenderingBackend>,
  307. draw_calls: &'a HashMap<u64, DrawCall>,
  308. uniforms_data: [u8; 128],
  309. white_texture: miniquad::TextureId,
  310. scale: f32,
  311. view: Rectangle,
  312. cursor: Point,
  313. }
  314. impl<'a> RenderContext<'a> {
  315. fn draw(&mut self) {
  316. if DEBUG_RENDER {
  317. debug!(target: "gfx", "RenderContext::draw()");
  318. }
  319. let curr_pos = Point::zero();
  320. self.draw_call(&self.draw_calls[&0], 0, DEBUG_RENDER);
  321. if DEBUG_RENDER {
  322. debug!(target: "gfx", "RenderContext::draw() [DONE]");
  323. }
  324. }
  325. fn apply_view(&mut self) {
  326. let view = self.view * self.scale;
  327. let (_, screen_height) = window::screen_size();
  328. let view_x = view.x.round() as i32;
  329. let view_y = screen_height - (view.y + view.h);
  330. let view_y = view_y.round() as i32;
  331. let view_w = view.w.round() as i32;
  332. let view_h = view.h.round() as i32;
  333. // OpenGL does not like negative values here
  334. if view_w <= 0 || view_h <= 0 {
  335. return
  336. }
  337. if DEBUG_RENDER {
  338. debug!(target: "gfx", "=> viewport {view_x} {view_y} {view_w} {view_h}");
  339. }
  340. self.ctx.apply_viewport(view_x, view_y, view_w, view_h);
  341. self.ctx.apply_scissor_rect(view_x, view_y, view_w, view_h);
  342. }
  343. fn apply_model(&mut self) {
  344. let off_x = self.cursor.x / self.view.w;
  345. let off_y = self.cursor.y / self.view.h;
  346. let scale_w = 1. / self.view.w;
  347. let scale_h = 1. / self.view.h;
  348. let model = glam::Mat4::from_translation(glam::Vec3::new(off_x, off_y, 0.)) *
  349. glam::Mat4::from_scale(glam::Vec3::new(scale_w, scale_h, 1.));
  350. let data: [u8; 64] = unsafe { std::mem::transmute_copy(&model) };
  351. self.uniforms_data[64..].copy_from_slice(&data);
  352. self.ctx.apply_uniforms_from_bytes(self.uniforms_data.as_ptr(), self.uniforms_data.len());
  353. }
  354. fn draw_call(&mut self, draw_call: &DrawCall, mut indent: u32, mut is_debug: bool) {
  355. let mut ws = if is_debug { " ".repeat(indent as usize * 4) } else { String::new() };
  356. let old_scale = self.scale;
  357. let old_view = self.view;
  358. let old_cursor = self.cursor;
  359. for instr in &draw_call.instrs {
  360. match instr {
  361. DrawInstruction::SetScale(scale) => {
  362. self.scale = *scale;
  363. if is_debug {
  364. debug!(target: "gfx", "{ws}set_scale({scale})");
  365. }
  366. }
  367. DrawInstruction::Move(off) => {
  368. self.cursor += *off;
  369. if is_debug {
  370. debug!(target: "gfx",
  371. "{ws}move({off:?}) cursor={:?}, scale={}, view={:?}",
  372. self.cursor, self.scale, self.view
  373. );
  374. }
  375. self.apply_model();
  376. }
  377. DrawInstruction::SetPos(pos) => {
  378. self.cursor = old_cursor + *pos;
  379. if is_debug {
  380. debug!(target: "gfx",
  381. "{ws}set_pos({pos:?}) cursor={:?}, scale={}, view={:?}",
  382. self.cursor, self.scale, self.view
  383. );
  384. }
  385. self.apply_model();
  386. }
  387. DrawInstruction::ApplyView(view) => {
  388. // Adjust view relative to cursor
  389. self.view = *view + self.cursor;
  390. // Cursor resets within the view
  391. self.cursor = Point::zero();
  392. if is_debug {
  393. debug!(target: "gfx",
  394. "{ws}apply_view({view:?}) scale={}, view={:?}",
  395. self.scale, self.view
  396. );
  397. }
  398. self.apply_view();
  399. self.apply_model();
  400. }
  401. DrawInstruction::Draw(mesh) => {
  402. if is_debug {
  403. debug!(target: "gfx", "{ws}draw({mesh:?})");
  404. }
  405. let texture = match mesh.texture {
  406. Some((_, texture)) => texture,
  407. None => self.white_texture,
  408. };
  409. let bindings = Bindings {
  410. vertex_buffers: vec![mesh.vertex_buffer],
  411. index_buffer: mesh.index_buffer,
  412. images: vec![texture],
  413. };
  414. self.ctx.apply_bindings(&bindings);
  415. self.ctx.draw(0, mesh.num_elements, 1);
  416. }
  417. DrawInstruction::EnableDebug => {
  418. if !is_debug {
  419. indent = 0;
  420. }
  421. is_debug = true;
  422. debug!(target: "gfx", "Frame start");
  423. }
  424. }
  425. }
  426. let mut draw_calls: Vec<_> =
  427. draw_call.dcs.iter().map(|key| (key, &self.draw_calls[key])).collect();
  428. draw_calls.sort_unstable_by_key(|(_, dc)| dc.z_index);
  429. for (dc_key, dc) in draw_calls {
  430. if is_debug {
  431. debug!(target: "gfx", "{ws}drawcall {dc_key}");
  432. }
  433. self.draw_call(dc, indent + 1, is_debug);
  434. }
  435. self.scale = old_scale;
  436. if is_debug {
  437. debug!(target: "gfx", "{ws}Frame close: cursor={old_cursor:?}, view={old_view:?}");
  438. }
  439. self.view = old_view;
  440. self.apply_view();
  441. self.cursor = old_cursor;
  442. self.apply_model();
  443. }
  444. }
  445. #[derive(Clone, Debug)]
  446. pub enum GraphicsMethod {
  447. NewTexture((u16, u16, Vec<u8>, GfxTextureId)),
  448. DeleteTexture(GfxTextureId),
  449. NewVertexBuffer((Vec<Vertex>, GfxBufferId)),
  450. NewIndexBuffer((Vec<u16>, GfxBufferId)),
  451. DeleteBuffer(GfxBufferId),
  452. ReplaceDrawCalls { timest: u64, dcs: Vec<(u64, GfxDrawCall)> },
  453. }
  454. pub type GraphicsEventPublisherPtr = Arc<GraphicsEventPublisher>;
  455. pub struct GraphicsEventPublisher {
  456. resize: PublisherPtr<Dimension>,
  457. key_down: PublisherPtr<(KeyCode, KeyMods, bool)>,
  458. key_up: PublisherPtr<(KeyCode, KeyMods)>,
  459. chr: PublisherPtr<(char, KeyMods, bool)>,
  460. mouse_btn_down: PublisherPtr<(MouseButton, Point)>,
  461. mouse_btn_up: PublisherPtr<(MouseButton, Point)>,
  462. mouse_move: PublisherPtr<Point>,
  463. mouse_wheel: PublisherPtr<Point>,
  464. touch: PublisherPtr<(TouchPhase, u64, Point)>,
  465. }
  466. impl GraphicsEventPublisher {
  467. pub fn new() -> Arc<Self> {
  468. Arc::new(Self {
  469. resize: Publisher::new(),
  470. key_down: Publisher::new(),
  471. key_up: Publisher::new(),
  472. chr: Publisher::new(),
  473. mouse_btn_down: Publisher::new(),
  474. mouse_btn_up: Publisher::new(),
  475. mouse_move: Publisher::new(),
  476. mouse_wheel: Publisher::new(),
  477. touch: Publisher::new(),
  478. })
  479. }
  480. fn notify_resize(&self, screen_size: Dimension) {
  481. self.resize.notify(screen_size);
  482. }
  483. fn notify_key_down(&self, key: KeyCode, mods: KeyMods, repeat: bool) {
  484. let ev = (key, mods, repeat);
  485. self.key_down.notify(ev);
  486. }
  487. fn notify_key_up(&self, key: KeyCode, mods: KeyMods) {
  488. let ev = (key, mods);
  489. self.key_up.notify(ev);
  490. }
  491. fn notify_char(&self, chr: char, mods: KeyMods, repeat: bool) {
  492. let ev = (chr, mods, repeat);
  493. self.chr.notify(ev);
  494. }
  495. fn notify_mouse_btn_down(&self, button: MouseButton, mouse_pos: Point) {
  496. let ev = (button, mouse_pos);
  497. self.mouse_btn_down.notify(ev);
  498. }
  499. fn notify_mouse_btn_up(&self, button: MouseButton, mouse_pos: Point) {
  500. let ev = (button, mouse_pos);
  501. self.mouse_btn_up.notify(ev);
  502. }
  503. fn notify_mouse_move(&self, mouse_pos: Point) {
  504. self.mouse_move.notify(mouse_pos);
  505. }
  506. fn notify_mouse_wheel(&self, wheel_pos: Point) {
  507. self.mouse_wheel.notify(wheel_pos);
  508. }
  509. fn notify_touch(&self, phase: TouchPhase, id: u64, touch_pos: Point) {
  510. let ev = (phase, id, touch_pos);
  511. self.touch.notify(ev);
  512. }
  513. pub fn subscribe_resize(&self) -> Subscription<Dimension> {
  514. self.resize.clone().subscribe()
  515. }
  516. pub fn subscribe_key_down(&self) -> Subscription<(KeyCode, KeyMods, bool)> {
  517. self.key_down.clone().subscribe()
  518. }
  519. pub fn subscribe_key_up(&self) -> Subscription<(KeyCode, KeyMods)> {
  520. self.key_up.clone().subscribe()
  521. }
  522. pub fn subscribe_char(&self) -> Subscription<(char, KeyMods, bool)> {
  523. self.chr.clone().subscribe()
  524. }
  525. pub fn subscribe_mouse_btn_down(&self) -> Subscription<(MouseButton, Point)> {
  526. self.mouse_btn_down.clone().subscribe()
  527. }
  528. pub fn subscribe_mouse_btn_up(&self) -> Subscription<(MouseButton, Point)> {
  529. self.mouse_btn_up.clone().subscribe()
  530. }
  531. pub fn subscribe_mouse_move(&self) -> Subscription<Point> {
  532. self.mouse_move.clone().subscribe()
  533. }
  534. pub fn subscribe_mouse_wheel(&self) -> Subscription<Point> {
  535. self.mouse_wheel.clone().subscribe()
  536. }
  537. pub fn subscribe_touch(&self) -> Subscription<(TouchPhase, u64, Point)> {
  538. self.touch.clone().subscribe()
  539. }
  540. }
  541. struct Stage {
  542. #[allow(dead_code)]
  543. app: AppPtr,
  544. #[allow(dead_code)]
  545. async_runtime: AsyncRuntime,
  546. ctx: Box<dyn RenderingBackend>,
  547. pipeline: Pipeline,
  548. white_texture: miniquad::TextureId,
  549. draw_calls: HashMap<u64, DrawCall>,
  550. textures: HashMap<GfxTextureId, miniquad::TextureId>,
  551. buffers: HashMap<GfxBufferId, miniquad::BufferId>,
  552. method_rep: mpsc::Receiver<GraphicsMethod>,
  553. event_pub: GraphicsEventPublisherPtr,
  554. }
  555. impl Stage {
  556. pub fn new(
  557. app: AppPtr,
  558. async_runtime: AsyncRuntime,
  559. method_rep: mpsc::Receiver<GraphicsMethod>,
  560. event_pub: GraphicsEventPublisherPtr,
  561. cv_started: Arc<CondVar>,
  562. ) -> Self {
  563. let mut ctx: Box<dyn RenderingBackend> = window::new_rendering_backend();
  564. // This will start the app to start. Needed since we cannot get window size for init
  565. // until window is created.
  566. cv_started.notify();
  567. let white_texture = ctx.new_texture_from_rgba8(1, 1, &[255, 255, 255, 255]);
  568. let mut shader_meta: ShaderMeta = shader::meta();
  569. shader_meta.uniforms.uniforms.push(UniformDesc::new("Projection", UniformType::Mat4));
  570. shader_meta.uniforms.uniforms.push(UniformDesc::new("Model", UniformType::Mat4));
  571. let shader = ctx
  572. .new_shader(
  573. match ctx.info().backend {
  574. Backend::OpenGl => ShaderSource::Glsl {
  575. vertex: shader::GL_VERTEX,
  576. fragment: shader::GL_FRAGMENT,
  577. },
  578. Backend::Metal => ShaderSource::Msl { program: shader::METAL },
  579. },
  580. shader_meta,
  581. )
  582. .unwrap();
  583. let params = PipelineParams {
  584. color_blend: Some(BlendState::new(
  585. Equation::Add,
  586. BlendFactor::Value(BlendValue::SourceAlpha),
  587. BlendFactor::OneMinusValue(BlendValue::SourceAlpha),
  588. )),
  589. ..Default::default()
  590. };
  591. let pipeline = ctx.new_pipeline(
  592. &[BufferLayout::default()],
  593. &[
  594. VertexAttribute::new("in_pos", VertexFormat::Float2),
  595. VertexAttribute::new("in_color", VertexFormat::Float4),
  596. VertexAttribute::new("in_uv", VertexFormat::Float2),
  597. ],
  598. shader,
  599. params,
  600. );
  601. Stage {
  602. app,
  603. async_runtime,
  604. ctx,
  605. pipeline,
  606. white_texture,
  607. draw_calls: HashMap::from([(
  608. 0,
  609. DrawCall { instrs: vec![], dcs: vec![], z_index: 0, timest: 0 },
  610. )]),
  611. textures: HashMap::new(),
  612. buffers: HashMap::new(),
  613. method_rep,
  614. event_pub,
  615. }
  616. }
  617. fn process_method(&mut self, method: GraphicsMethod) {
  618. //debug!(target: "gfx", "Received method: {:?}", method);
  619. match method {
  620. GraphicsMethod::NewTexture((width, height, data, gfx_texture_id)) => {
  621. self.method_new_texture(width, height, data, gfx_texture_id)
  622. }
  623. GraphicsMethod::DeleteTexture(texture) => self.method_delete_texture(texture),
  624. GraphicsMethod::NewVertexBuffer((verts, sendr)) => {
  625. self.method_new_vertex_buffer(verts, sendr)
  626. }
  627. GraphicsMethod::NewIndexBuffer((indices, sendr)) => {
  628. self.method_new_index_buffer(indices, sendr)
  629. }
  630. GraphicsMethod::DeleteBuffer(buffer) => self.method_delete_buffer(buffer),
  631. GraphicsMethod::ReplaceDrawCalls { timest, dcs } => {
  632. self.method_replace_draw_calls(timest, dcs)
  633. }
  634. };
  635. }
  636. fn method_new_texture(
  637. &mut self,
  638. width: u16,
  639. height: u16,
  640. data: Vec<u8>,
  641. gfx_texture_id: GfxTextureId,
  642. ) {
  643. let texture = self.ctx.new_texture_from_rgba8(width, height, &data);
  644. if DEBUG_GFXAPI {
  645. debug!(target: "gfx", "Invoked method: new_texture({}, {}, ..., {}) -> {:?}",
  646. width, height, gfx_texture_id, texture);
  647. //debug!(target: "gfx", "Invoked method: new_texture({}, {}, ..., {}) -> {:?}\n{}",
  648. // width, height, gfx_texture_id, texture,
  649. // ansi_texture(width as usize, height as usize, &data));
  650. }
  651. if let Some(_) = self.textures.insert(gfx_texture_id, texture) {
  652. panic!("Duplicate texture ID={gfx_texture_id} detected!");
  653. }
  654. }
  655. fn method_delete_texture(&mut self, gfx_texture_id: GfxTextureId) {
  656. let texture = self.textures.remove(&gfx_texture_id).expect("couldn't find gfx_texture_id");
  657. if DEBUG_GFXAPI {
  658. debug!(target: "gfx", "Invoked method: delete_texture({} => {:?})",
  659. gfx_texture_id, texture);
  660. }
  661. self.ctx.delete_texture(texture);
  662. }
  663. fn method_new_vertex_buffer(&mut self, verts: Vec<Vertex>, gfx_buffer_id: GfxBufferId) {
  664. let buffer = self.ctx.new_buffer(
  665. BufferType::VertexBuffer,
  666. BufferUsage::Immutable,
  667. BufferSource::slice(&verts),
  668. );
  669. if DEBUG_GFXAPI {
  670. debug!(target: "gfx", "Invoked method: new_vertex_buffer(..., {}) -> {:?}",
  671. gfx_buffer_id, buffer);
  672. //debug!(target: "gfx", "Invoked method: new_vertex_buffer({:?}, {}) -> {:?}",
  673. // verts, gfx_buffer_id, buffer);
  674. }
  675. if let Some(_) = self.buffers.insert(gfx_buffer_id, buffer) {
  676. panic!("Duplicate vertex buffer ID={gfx_buffer_id} detected!");
  677. }
  678. }
  679. fn method_new_index_buffer(&mut self, indices: Vec<u16>, gfx_buffer_id: GfxBufferId) {
  680. let buffer = self.ctx.new_buffer(
  681. BufferType::IndexBuffer,
  682. BufferUsage::Immutable,
  683. BufferSource::slice(&indices),
  684. );
  685. if DEBUG_GFXAPI {
  686. debug!(target: "gfx", "Invoked method: new_index_buffer({}) -> {:?}",
  687. gfx_buffer_id, buffer);
  688. //debug!(target: "gfx", "Invoked method: new_index_buffer({:?}, {}) -> {:?}",
  689. // indices, gfx_buffer_id, buffer);
  690. }
  691. if let Some(_) = self.buffers.insert(gfx_buffer_id, buffer) {
  692. panic!("Duplicate index buffer ID={gfx_buffer_id} detected!");
  693. }
  694. }
  695. fn method_delete_buffer(&mut self, gfx_buffer_id: GfxBufferId) {
  696. let buffer = self.buffers.remove(&gfx_buffer_id).expect("couldn't find gfx_buffer_id");
  697. if DEBUG_GFXAPI {
  698. debug!(target: "gfx", "Invoked method: delete_buffer({} => {:?})",
  699. gfx_buffer_id, buffer);
  700. }
  701. self.ctx.delete_buffer(buffer);
  702. }
  703. fn method_replace_draw_calls(&mut self, timest: u64, dcs: Vec<(u64, GfxDrawCall)>) {
  704. if DEBUG_GFXAPI {
  705. debug!(target: "gfx", "Invoked method: replace_draw_calls({:?})", dcs);
  706. }
  707. for (key, val) in dcs {
  708. let Some(val) = val.compile(&self.textures, &self.buffers, timest) else {
  709. error!(target: "gfx", "fatal: replace_draw_calls({timest}, ...) failed with item ID={key}");
  710. continue
  711. };
  712. //self.draw_calls.insert(key, val);
  713. match self.draw_calls.get_mut(&key) {
  714. Some(old_val) => {
  715. // Only replace the draw call if it is more recent
  716. if old_val.timest < timest {
  717. *old_val = val;
  718. } else {
  719. trace!(target: "gfx", "Rejected stale draw_call {key}: {val:?}");
  720. }
  721. }
  722. None => {
  723. self.draw_calls.insert(key, val);
  724. }
  725. }
  726. }
  727. }
  728. }
  729. impl EventHandler for Stage {
  730. fn update(&mut self) {
  731. // Process as many methods as we can
  732. while let Ok(method) = self.method_rep.try_recv() {
  733. self.process_method(method);
  734. }
  735. }
  736. fn draw(&mut self) {
  737. self.ctx.begin_default_pass(PassAction::clear_color(0., 0., 0., 1.));
  738. self.ctx.apply_pipeline(&self.pipeline);
  739. // This will make the top left (0, 0) and the bottom right (1, 1)
  740. // Default is (-1, 1) -> (1, -1)
  741. let proj = glam::Mat4::from_translation(glam::Vec3::new(-1., 1., 0.)) *
  742. glam::Mat4::from_scale(glam::Vec3::new(2., -2., 1.));
  743. let mut uniforms_data = [0u8; 128];
  744. let data: [u8; 64] = unsafe { std::mem::transmute_copy(&proj) };
  745. uniforms_data[0..64].copy_from_slice(&data);
  746. //let data: [u8; 64] = unsafe { std::mem::transmute_copy(&model) };
  747. //uniforms_data[64..].copy_from_slice(&data);
  748. assert_eq!(128, 2 * UniformType::Mat4.size());
  749. let (screen_w, screen_h) = miniquad::window::screen_size();
  750. let mut render_ctx = RenderContext {
  751. ctx: &mut self.ctx,
  752. draw_calls: &self.draw_calls,
  753. uniforms_data,
  754. white_texture: self.white_texture,
  755. scale: 1.,
  756. view: Rectangle::from([0., 0., screen_w, screen_h]),
  757. cursor: Point::from([0., 0.]),
  758. };
  759. render_ctx.draw();
  760. self.ctx.commit_frame();
  761. }
  762. fn resize_event(&mut self, width: f32, height: f32) {
  763. let filename = get_window_size_filename();
  764. if let Some(parent) = filename.parent() {
  765. let _ = std::fs::create_dir_all(parent);
  766. }
  767. if let Ok(mut file) = File::create(filename) {
  768. (width as i32).encode(&mut file).unwrap();
  769. (height as i32).encode(&mut file).unwrap();
  770. }
  771. self.event_pub.notify_resize(Dimension::from([width, height]));
  772. }
  773. fn key_down_event(&mut self, keycode: KeyCode, mods: KeyMods, repeat: bool) {
  774. self.event_pub.notify_key_down(keycode, mods, repeat);
  775. }
  776. fn key_up_event(&mut self, keycode: KeyCode, mods: KeyMods) {
  777. self.event_pub.notify_key_up(keycode, mods);
  778. }
  779. fn char_event(&mut self, chr: char, mods: KeyMods, repeat: bool) {
  780. self.event_pub.notify_char(chr, mods, repeat);
  781. }
  782. fn mouse_button_down_event(&mut self, button: MouseButton, x: f32, y: f32) {
  783. let pos = Point::from([x, y]);
  784. self.event_pub.notify_mouse_btn_down(button, pos);
  785. }
  786. fn mouse_button_up_event(&mut self, button: MouseButton, x: f32, y: f32) {
  787. let pos = Point::from([x, y]);
  788. self.event_pub.notify_mouse_btn_up(button, pos);
  789. }
  790. fn mouse_motion_event(&mut self, x: f32, y: f32) {
  791. let pos = Point::from([x, y]);
  792. self.event_pub.notify_mouse_move(pos);
  793. }
  794. fn mouse_wheel_event(&mut self, x: f32, y: f32) {
  795. let pos = Point::from([x, y]);
  796. self.event_pub.notify_mouse_wheel(pos);
  797. }
  798. /// The id corresponds to multi-touch. Multiple touch events have different ids.
  799. fn touch_event(&mut self, phase: TouchPhase, id: u64, x: f32, y: f32) {
  800. let pos = Point::from([x, y]);
  801. self.event_pub.notify_touch(phase, id, pos);
  802. }
  803. fn quit_requested_event(&mut self) {
  804. debug!(target: "gfx", "quit requested");
  805. // Doesn't work
  806. //miniquad::window::cancel_quit();
  807. //self.app.stop();
  808. //self.async_runtime.stop();
  809. }
  810. }
  811. pub fn run_gui(
  812. app: AppPtr,
  813. async_runtime: AsyncRuntime,
  814. method_rep: mpsc::Receiver<GraphicsMethod>,
  815. event_pub: GraphicsEventPublisherPtr,
  816. cv_started: Arc<CondVar>,
  817. ) {
  818. let mut window_width = 1024;
  819. let mut window_height = 768;
  820. if let Ok(mut file) = File::open(get_window_size_filename()) {
  821. window_width = Decodable::decode(&mut file).unwrap();
  822. window_height = Decodable::decode(&mut file).unwrap();
  823. }
  824. debug!(target: "gfx", "Window size {window_width} x {window_height}");
  825. let mut conf = miniquad::conf::Conf {
  826. window_title: "DarkFi".to_string(),
  827. window_width,
  828. window_height,
  829. high_dpi: true,
  830. window_resizable: true,
  831. platform: miniquad::conf::Platform {
  832. linux_backend: miniquad::conf::LinuxBackend::WaylandWithX11Fallback,
  833. //blocking_event_loop: true,
  834. ..Default::default()
  835. },
  836. icon: Some(miniquad::conf::Icon {
  837. small: favico::SMALL,
  838. medium: favico::MEDIUM,
  839. big: favico::BIG,
  840. }),
  841. ..Default::default()
  842. };
  843. let metal = std::env::args().nth(1).as_deref() == Some("metal");
  844. conf.platform.apple_gfx_api =
  845. if metal { conf::AppleGfxApi::Metal } else { conf::AppleGfxApi::OpenGl };
  846. miniquad::start(conf, || {
  847. Box::new(Stage::new(app, async_runtime, method_rep, event_pub, cv_started))
  848. });
  849. }