drawsim.rs 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671
  1. /* This file is part of DarkFi (https://dark.fi)
  2. *
  3. * Copyright (C) 2020-2026 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 async_trait::async_trait;
  19. use darkfi_serial::{SerialEncodable, SerialDecodable, serialize, Encodable, Decodable, deserialize};
  20. use std::{
  21. fs::{OpenOptions, File},
  22. collections::HashMap,
  23. sync::{mpsc, Arc, Mutex as SyncMutex},
  24. time::{Duration, Instant},
  25. ops::{Add, Mul},
  26. };
  27. use futures::AsyncWriteExt;
  28. use miniquad::{
  29. conf, window, Backend, Bindings, BlendFactor, BlendState, BlendValue, BufferLayout,
  30. BufferSource, BufferType, BufferUsage, Equation, EventHandler, KeyCode, KeyMods, MouseButton,
  31. PassAction, Pipeline, PipelineParams, RenderingBackend, ShaderMeta, ShaderSource, TouchPhase,
  32. TextureFormat, TextureKind, TextureParams, TextureWrap, UniformDesc, UniformType,
  33. VertexAttribute, VertexFormat,
  34. UniformBlockLayout,
  35. };
  36. const FILENAME: &str = "drawinstrs.dat";
  37. const DEBUG_RENDER: bool = false;
  38. const DEBUG_GFXAPI: bool = false;
  39. #[derive(Clone, Debug, SerialEncodable, SerialDecodable)]
  40. #[repr(C)]
  41. pub struct Vertex {
  42. pub pos: [f32; 2],
  43. pub color: [f32; 4],
  44. pub uv: [f32; 2],
  45. }
  46. #[derive(Clone, Copy, Debug, SerialEncodable, SerialDecodable)]
  47. pub struct Point {
  48. pub x: f32,
  49. pub y: f32,
  50. }
  51. impl Point {
  52. pub fn zero() -> Self {
  53. Self { x: 0., y: 0. }
  54. }
  55. }
  56. impl From<[f32; 2]> for Point {
  57. fn from(pos: [f32; 2]) -> Self {
  58. Self { x: pos[0], y: pos[1] }
  59. }
  60. }
  61. impl Add for Point {
  62. type Output = Self;
  63. fn add(self, other: Self) -> Self::Output {
  64. Self { x: self.x + other.x, y: self.y + other.y }
  65. }
  66. }
  67. #[derive(Debug, Clone, Copy, SerialEncodable, SerialDecodable)]
  68. pub struct Rectangle {
  69. pub x: f32,
  70. pub y: f32,
  71. pub w: f32,
  72. pub h: f32,
  73. }
  74. impl From<[f32; 4]> for Rectangle {
  75. fn from(rect: [f32; 4]) -> Self {
  76. Self { x: rect[0], y: rect[1], w: rect[2], h: rect[3] }
  77. }
  78. }
  79. impl Mul<f32> for Rectangle {
  80. type Output = Rectangle;
  81. fn mul(self, scale: f32) -> Self::Output {
  82. Self { x: self.x * scale, y: self.y * scale, w: self.w * scale, h: self.h * scale }
  83. }
  84. }
  85. pub type GfxTextureId = u32;
  86. pub type GfxBufferId = u32;
  87. #[derive(Clone, Debug, SerialEncodable, SerialDecodable)]
  88. pub struct GfxDrawCall {
  89. pub instrs: Vec<GfxDrawInstruction>,
  90. pub dcs: Vec<u64>,
  91. pub z_index: u32,
  92. }
  93. impl GfxDrawCall {
  94. fn compile(
  95. self,
  96. textures: &HashMap<GfxTextureId, miniquad::TextureId>,
  97. buffers: &HashMap<GfxBufferId, miniquad::BufferId>,
  98. ) -> DrawCall {
  99. DrawCall {
  100. instrs: self.instrs.into_iter().map(|i| i.compile(textures, buffers)).collect(),
  101. dcs: self.dcs,
  102. z_index: self.z_index,
  103. }
  104. }
  105. }
  106. #[derive(Debug, Clone, SerialEncodable, SerialDecodable)]
  107. pub enum GfxDrawInstruction {
  108. SetScale(f32),
  109. Move(Point),
  110. ApplyView(Rectangle),
  111. Draw(GfxDrawMesh),
  112. }
  113. impl GfxDrawInstruction {
  114. fn compile(
  115. self,
  116. textures: &HashMap<GfxTextureId, miniquad::TextureId>,
  117. buffers: &HashMap<GfxBufferId, miniquad::BufferId>,
  118. ) -> DrawInstruction {
  119. match self {
  120. Self::SetScale(scale) => DrawInstruction::SetScale(scale),
  121. Self::Move(off) => DrawInstruction::Move(off),
  122. Self::ApplyView(view) => DrawInstruction::ApplyView(view),
  123. Self::Draw(mesh) => DrawInstruction::Draw(mesh.compile(textures, buffers)),
  124. }
  125. }
  126. }
  127. #[derive(Clone, Debug, SerialEncodable, SerialDecodable)]
  128. pub struct GfxDrawMesh {
  129. pub vertex_buffer: GfxBufferId,
  130. pub index_buffer: GfxBufferId,
  131. pub texture: Option<GfxTextureId>,
  132. pub num_elements: i32,
  133. }
  134. impl GfxDrawMesh {
  135. fn compile(
  136. self,
  137. textures: &HashMap<GfxTextureId, miniquad::TextureId>,
  138. buffers: &HashMap<GfxBufferId, miniquad::BufferId>,
  139. ) -> DrawMesh {
  140. DrawMesh {
  141. vertex_buffer: buffers[&self.vertex_buffer],
  142. index_buffer: buffers[&self.index_buffer],
  143. texture: self.texture.map(|t| textures[&t]),
  144. num_elements: self.num_elements,
  145. }
  146. }
  147. }
  148. #[derive(Clone, Debug, SerialEncodable, SerialDecodable)]
  149. pub enum GraphicsMethod {
  150. NewTexture((u16, u16, Vec<u8>, GfxTextureId)),
  151. DeleteTexture(GfxTextureId),
  152. NewVertexBuffer((Vec<Vertex>, GfxBufferId)),
  153. NewIndexBuffer((Vec<u16>, GfxBufferId)),
  154. DeleteBuffer(GfxBufferId),
  155. ReplaceDrawCalls(Vec<(u64, GfxDrawCall)>),
  156. }
  157. #[derive(Debug, SerialEncodable, SerialDecodable)]
  158. struct Instruction {
  159. timest: u64,
  160. method: GraphicsMethod
  161. }
  162. pub fn read_instrs() -> Vec<Instruction> {
  163. let mut instrs = vec![];
  164. let mut f = File::open(FILENAME).unwrap();
  165. loop {
  166. let Ok(data) = Vec::<u8>::decode(&mut f) else { break };
  167. let instr: Instruction = deserialize(&data).unwrap();
  168. instrs.push(instr);
  169. }
  170. instrs
  171. }
  172. #[derive(Clone, Debug)]
  173. struct DrawMesh {
  174. vertex_buffer: miniquad::BufferId,
  175. index_buffer: miniquad::BufferId,
  176. texture: Option<miniquad::TextureId>,
  177. num_elements: i32,
  178. }
  179. #[derive(Debug, Clone)]
  180. enum DrawInstruction {
  181. SetScale(f32),
  182. Move(Point),
  183. ApplyView(Rectangle),
  184. Draw(DrawMesh),
  185. }
  186. #[derive(Debug)]
  187. struct DrawCall {
  188. instrs: Vec<DrawInstruction>,
  189. dcs: Vec<u64>,
  190. z_index: u32,
  191. }
  192. struct Stage {
  193. ctx: Box<dyn RenderingBackend>,
  194. pipeline: Pipeline,
  195. white_texture: miniquad::TextureId,
  196. draw_calls: HashMap<u64, DrawCall>,
  197. textures: HashMap<GfxTextureId, miniquad::TextureId>,
  198. buffers: HashMap<GfxBufferId, miniquad::BufferId>,
  199. instant: Instant,
  200. instrs: Vec<Instruction>,
  201. }
  202. impl Stage {
  203. pub fn new(
  204. ) -> Self {
  205. let mut instrs = read_instrs();
  206. instrs.reverse();
  207. println!("Loaded instrs");
  208. let mut ctx: Box<dyn RenderingBackend> = window::new_rendering_backend();
  209. let white_texture = ctx.new_texture_from_rgba8(1, 1, &[255, 255, 255, 255]);
  210. let mut shader_meta: ShaderMeta = shader::meta();
  211. shader_meta.uniforms.uniforms.push(UniformDesc::new("Projection", UniformType::Mat4));
  212. shader_meta.uniforms.uniforms.push(UniformDesc::new("Model", UniformType::Mat4));
  213. let shader = ctx
  214. .new_shader(
  215. match ctx.info().backend {
  216. Backend::OpenGl => ShaderSource::Glsl {
  217. vertex: shader::GL_VERTEX,
  218. fragment: shader::GL_FRAGMENT,
  219. },
  220. Backend::Metal => ShaderSource::Msl { program: shader::METAL },
  221. },
  222. shader_meta,
  223. )
  224. .unwrap();
  225. let params = PipelineParams {
  226. color_blend: Some(BlendState::new(
  227. Equation::Add,
  228. BlendFactor::Value(BlendValue::SourceAlpha),
  229. BlendFactor::OneMinusValue(BlendValue::SourceAlpha),
  230. )),
  231. ..Default::default()
  232. };
  233. let pipeline = ctx.new_pipeline(
  234. &[BufferLayout::default()],
  235. &[
  236. VertexAttribute::new("in_pos", VertexFormat::Float2),
  237. VertexAttribute::new("in_color", VertexFormat::Float4),
  238. VertexAttribute::new("in_uv", VertexFormat::Float2),
  239. ],
  240. shader,
  241. params,
  242. );
  243. Stage {
  244. ctx,
  245. pipeline,
  246. white_texture,
  247. draw_calls: HashMap::from([(0, DrawCall { instrs: vec![], dcs: vec![], z_index: 0 })]),
  248. textures: HashMap::new(),
  249. buffers: HashMap::new(),
  250. instant: Instant::now(),
  251. instrs,
  252. }
  253. }
  254. fn process_method(&mut self, method: GraphicsMethod) {
  255. //println!("Received method: {:?}", method);
  256. match method {
  257. GraphicsMethod::NewTexture((width, height, data, fmt, gfx_texture_id, _)) => {
  258. self.method_new_texture(width, height, data, fmt, gfx_texture_id)
  259. }
  260. GraphicsMethod::DeleteTexture(texture) => self.method_delete_texture(texture),
  261. GraphicsMethod::NewVertexBuffer((verts, sendr)) => {
  262. self.method_new_vertex_buffer(verts, sendr)
  263. }
  264. GraphicsMethod::NewIndexBuffer((indices, sendr)) => {
  265. self.method_new_index_buffer(indices, sendr)
  266. }
  267. GraphicsMethod::DeleteBuffer(buffer) => self.method_delete_buffer(buffer),
  268. GraphicsMethod::ReplaceDrawCalls(dcs) => self.method_replace_draw_calls(dcs),
  269. };
  270. }
  271. fn method_new_texture(
  272. &mut self,
  273. width: u16,
  274. height: u16,
  275. data: Vec<u8>,
  276. fmt: TextureFormat,
  277. gfx_texture_id: GfxTextureId,
  278. ) {
  279. let texture = self.ctx.new_texture_from_data_and_format(
  280. &data,
  281. TextureParams {
  282. kind: TextureKind::Texture2D,
  283. format: fmt,
  284. width: width as _,
  285. height: height as _,
  286. wrap: TextureWrap::Clamp,
  287. min_filter: miniquad::FilterMode::Linear,
  288. mag_filter: miniquad::FilterMode::Linear,
  289. mipmap_filter: miniquad::MipmapFilterMode::None,
  290. allocate_mipmaps: false,
  291. sample_count: 1,
  292. },
  293. );
  294. if DEBUG_GFXAPI {
  295. println!("Invoked method: new_texture({}, {}, ..., {}) -> {:?}",
  296. width, height, gfx_texture_id, texture);
  297. //println!("Invoked method: new_texture({}, {}, ..., {}) -> {:?}\n{}",
  298. // width, height, gfx_texture_id, texture,
  299. // ansi_texture(width as usize, height as usize, &data));
  300. }
  301. self.textures.insert(gfx_texture_id, texture);
  302. }
  303. fn method_delete_texture(&mut self, gfx_texture_id: GfxTextureId) {
  304. let texture = self.textures.remove(&gfx_texture_id).expect("couldn't find gfx_texture_id");
  305. if DEBUG_GFXAPI {
  306. println!("Invoked method: delete_texture({} => {:?})",
  307. gfx_texture_id, texture);
  308. }
  309. self.ctx.delete_texture(texture);
  310. }
  311. fn method_new_vertex_buffer(&mut self, verts: Vec<Vertex>, gfx_buffer_id: GfxBufferId) {
  312. let buffer = self.ctx.new_buffer(
  313. BufferType::VertexBuffer,
  314. BufferUsage::Immutable,
  315. BufferSource::slice(&verts),
  316. );
  317. if DEBUG_GFXAPI {
  318. println!("Invoked method: new_vertex_buffer(..., {}) -> {:?}",
  319. gfx_buffer_id, buffer);
  320. //println!("Invoked method: new_vertex_buffer({:?}, {}) -> {:?}",
  321. // verts, gfx_buffer_id, buffer);
  322. }
  323. self.buffers.insert(gfx_buffer_id, buffer);
  324. }
  325. fn method_new_index_buffer(&mut self, indices: Vec<u16>, gfx_buffer_id: GfxBufferId) {
  326. let buffer = self.ctx.new_buffer(
  327. BufferType::IndexBuffer,
  328. BufferUsage::Immutable,
  329. BufferSource::slice(&indices),
  330. );
  331. if DEBUG_GFXAPI {
  332. println!("Invoked method: new_index_buffer({}) -> {:?}",
  333. gfx_buffer_id, buffer);
  334. //println!("Invoked method: new_index_buffer({:?}, {}) -> {:?}",
  335. // indices, gfx_buffer_id, buffer);
  336. }
  337. self.buffers.insert(gfx_buffer_id, buffer);
  338. }
  339. fn method_delete_buffer(&mut self, gfx_buffer_id: GfxBufferId) {
  340. let buffer = self.buffers.remove(&gfx_buffer_id).expect("couldn't find gfx_buffer_id");
  341. if DEBUG_GFXAPI {
  342. println!("Invoked method: delete_buffer({} => {:?})",
  343. gfx_buffer_id, buffer);
  344. }
  345. self.ctx.delete_buffer(buffer);
  346. }
  347. fn method_replace_draw_calls(&mut self, dcs: Vec<(u64, GfxDrawCall)>) {
  348. if DEBUG_GFXAPI {
  349. println!("Invoked method: replace_draw_calls({:?})", dcs);
  350. }
  351. for (key, val) in dcs {
  352. let val = val.compile(&self.textures, &self.buffers);
  353. self.draw_calls.insert(key, val);
  354. }
  355. }
  356. }
  357. impl EventHandler for Stage {
  358. fn update(&mut self) {
  359. let timest = self.instant.elapsed().as_millis() as u64;
  360. while let Some(instr) = self.instrs.last() {
  361. if instr.timest > timest {
  362. break
  363. }
  364. let instr = self.instrs.pop().unwrap();
  365. self.process_method(instr.method);
  366. }
  367. }
  368. fn draw(&mut self) {
  369. self.ctx.begin_default_pass(PassAction::Nothing);
  370. self.ctx.apply_pipeline(&self.pipeline);
  371. // This will make the top left (0, 0) and the bottom right (1, 1)
  372. // Default is (-1, 1) -> (1, -1)
  373. let proj = glam::Mat4::from_translation(glam::Vec3::new(-1., 1., 0.)) *
  374. glam::Mat4::from_scale(glam::Vec3::new(2., -2., 1.));
  375. let mut uniforms_data = [0u8; 128];
  376. let data: [u8; 64] = unsafe { std::mem::transmute_copy(&proj) };
  377. uniforms_data[0..64].copy_from_slice(&data);
  378. //let data: [u8; 64] = unsafe { std::mem::transmute_copy(&model) };
  379. //uniforms_data[64..].copy_from_slice(&data);
  380. assert_eq!(128, 2 * UniformType::Mat4.size());
  381. let (screen_w, screen_h) = miniquad::window::screen_size();
  382. let mut render_ctx = RenderContext {
  383. ctx: &mut self.ctx,
  384. draw_calls: &self.draw_calls,
  385. uniforms_data,
  386. white_texture: self.white_texture,
  387. scale: 1.,
  388. view: Rectangle::from([0., 0., screen_w, screen_h]),
  389. cursor: Point::from([0., 0.]),
  390. };
  391. render_ctx.draw();
  392. self.ctx.commit_frame();
  393. }
  394. }
  395. struct RenderContext<'a> {
  396. ctx: &'a mut Box<dyn RenderingBackend>,
  397. draw_calls: &'a HashMap<u64, DrawCall>,
  398. uniforms_data: [u8; 128],
  399. white_texture: miniquad::TextureId,
  400. scale: f32,
  401. view: Rectangle,
  402. cursor: Point,
  403. }
  404. impl<'a> RenderContext<'a> {
  405. fn draw(&mut self) {
  406. if DEBUG_RENDER {
  407. println!("RenderContext::draw()");
  408. }
  409. let curr_pos = Point::zero();
  410. self.draw_call(&self.draw_calls[&0], 0);
  411. if DEBUG_RENDER {
  412. println!("RenderContext::draw() [DONE]");
  413. }
  414. }
  415. fn apply_view(&mut self) {
  416. let view = self.view * self.scale;
  417. let (_, screen_height) = window::screen_size();
  418. let view_x = view.x.round() as i32;
  419. let view_y = screen_height - (view.y + view.h);
  420. let view_y = view_y.round() as i32;
  421. let view_w = view.w.round() as i32;
  422. let view_h = view.h.round() as i32;
  423. //if DEBUG_RENDER {
  424. // println!("=> viewport {view_x} {view_y} {view_w} {view_h}");
  425. //}
  426. self.ctx.apply_viewport(view_x, view_y, view_w, view_h);
  427. self.ctx.apply_scissor_rect(view_x, view_y, view_w, view_h);
  428. }
  429. fn apply_model(&mut self) {
  430. let off_x = self.cursor.x / self.view.w;
  431. let off_y = self.cursor.y / self.view.h;
  432. let scale_w = 1. / self.view.w;
  433. let scale_h = 1. / self.view.h;
  434. let model = glam::Mat4::from_translation(glam::Vec3::new(off_x, off_y, 0.)) *
  435. glam::Mat4::from_scale(glam::Vec3::new(scale_w, scale_h, 1.));
  436. let data: [u8; 64] = unsafe { std::mem::transmute_copy(&model) };
  437. self.uniforms_data[64..].copy_from_slice(&data);
  438. self.ctx.apply_uniforms_from_bytes(self.uniforms_data.as_ptr(), self.uniforms_data.len());
  439. }
  440. fn draw_call(&mut self, draw_call: &DrawCall, indent: u32) {
  441. let ws = if DEBUG_RENDER { " ".repeat(indent as usize * 4) } else { String::new() };
  442. let old_view = self.view;
  443. let old_cursor = self.cursor;
  444. for instr in &draw_call.instrs {
  445. match instr {
  446. DrawInstruction::SetScale(scale) => {
  447. self.scale = *scale;
  448. if DEBUG_RENDER {
  449. println!("{ws}set_scale({scale})");
  450. }
  451. }
  452. DrawInstruction::Move(off) => {
  453. self.cursor = old_cursor + *off;
  454. if DEBUG_RENDER {
  455. println!(
  456. "{ws}move({off:?}) cursor={:?}, scale={}, view={:?}",
  457. self.cursor, self.scale, self.view
  458. );
  459. }
  460. self.apply_model();
  461. }
  462. DrawInstruction::ApplyView(view) => {
  463. self.view = *view;
  464. if DEBUG_RENDER {
  465. println!(
  466. "{ws}apply_view({view:?}) scale={}, view={:?}",
  467. self.scale, self.view
  468. );
  469. }
  470. self.apply_view();
  471. }
  472. DrawInstruction::Draw(mesh) => {
  473. if DEBUG_RENDER {
  474. println!("{ws}draw({mesh:?})");
  475. }
  476. let texture = match mesh.texture {
  477. Some(texture) => texture,
  478. None => self.white_texture,
  479. };
  480. let bindings = Bindings {
  481. vertex_buffers: vec![mesh.vertex_buffer],
  482. index_buffer: mesh.index_buffer,
  483. images: vec![texture],
  484. };
  485. self.ctx.apply_bindings(&bindings);
  486. self.ctx.draw(0, mesh.num_elements, 1);
  487. }
  488. }
  489. }
  490. let mut draw_calls: Vec<_> =
  491. draw_call.dcs.iter().map(|key| (key, &self.draw_calls[key])).collect();
  492. draw_calls.sort_unstable_by_key(|(_, dc)| dc.z_index);
  493. for (dc_key, dc) in draw_calls {
  494. if DEBUG_RENDER {
  495. println!("{ws}drawcall {dc_key}");
  496. }
  497. self.draw_call(dc, indent + 1);
  498. }
  499. self.cursor = old_cursor;
  500. self.apply_model();
  501. self.view = old_view;
  502. self.apply_view();
  503. }
  504. }
  505. fn main() {
  506. let mut conf = miniquad::conf::Conf {
  507. high_dpi: true,
  508. window_resizable: true,
  509. platform: miniquad::conf::Platform {
  510. linux_backend: miniquad::conf::LinuxBackend::WaylandWithX11Fallback,
  511. wayland_use_fallback_decorations: false,
  512. //blocking_event_loop: true,
  513. ..Default::default()
  514. },
  515. ..Default::default()
  516. };
  517. let metal = std::env::args().nth(1).as_deref() == Some("metal");
  518. conf.platform.apple_gfx_api =
  519. if metal { conf::AppleGfxApi::Metal } else { conf::AppleGfxApi::OpenGl };
  520. miniquad::start(conf, || Box::new(Stage::new()));
  521. }
  522. mod shader {
  523. use super::*;
  524. pub const GL_VERTEX: &str = r#"#version 100
  525. attribute vec2 in_pos;
  526. attribute vec4 in_color;
  527. attribute vec2 in_uv;
  528. varying lowp vec4 color;
  529. varying lowp vec2 uv;
  530. uniform mat4 Projection;
  531. uniform mat4 Model;
  532. void main() {
  533. gl_Position = Projection * Model * vec4(in_pos, 0, 1);
  534. color = in_color;
  535. uv = in_uv;
  536. }"#;
  537. pub const GL_FRAGMENT: &str = r#"#version 100
  538. varying lowp vec4 color;
  539. varying lowp vec2 uv;
  540. uniform sampler2D tex;
  541. void main() {
  542. gl_FragColor = color * texture2D(tex, uv);
  543. }"#;
  544. pub const METAL: &str = r#"
  545. #include <metal_stdlib>
  546. using namespace metal;
  547. struct Uniforms
  548. {
  549. float4x4 Projection;
  550. float4x4 Model;
  551. };
  552. struct Vertex
  553. {
  554. float2 in_pos [[attribute(0)]];
  555. float4 in_color [[attribute(1)]];
  556. float2 in_uv [[attribute(2)]];
  557. };
  558. struct RasterizerData
  559. {
  560. float4 position [[position]];
  561. float4 color [[user(locn0)]];
  562. float2 uv [[user(locn1)]];
  563. };
  564. vertex RasterizerData vertexShader(Vertex v [[stage_in]])
  565. {
  566. RasterizerData out;
  567. out.position = uniforms.Model * uniforms.Projection * float4(v.in_pos.xy, 0.0, 1.0);
  568. out.color = v.in_color;
  569. out.uv = v.texcoord;
  570. return out;
  571. }
  572. fragment float4 fragmentShader(RasterizerData in [[stage_in]], texture2d<float> tex [[texture(0)]], sampler texSmplr [[sampler(0)]])
  573. {
  574. return in.color * tex.sample(texSmplr, in.uv);
  575. }
  576. "#;
  577. pub fn meta() -> ShaderMeta {
  578. ShaderMeta {
  579. images: vec!["tex".to_string()],
  580. uniforms: UniformBlockLayout { uniforms: vec![] },
  581. }
  582. }
  583. }