drawsim.rs 20 KB

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