You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

context.rs 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395
  1. // Copyright (C) 2019 Inderjit Gill
  2. // This program is free software: you can redistribute it and/or modify
  3. // it under the terms of the GNU General Public License as published by
  4. // the Free Software Foundation, either version 3 of the License, or
  5. // (at your option) any later version.
  6. // This program is distributed in the hope that it will be useful,
  7. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  8. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  9. // GNU General Public License for more details.
  10. // You should have received a copy of the GNU General Public License
  11. // along with this program. If not, see <https://www.gnu.org/licenses/>.
  12. use crate::bitmap_cache::BitmapCache;
  13. use crate::colour::Colour;
  14. use crate::ease::Easing;
  15. use crate::error::Error;
  16. use crate::geometry;
  17. use crate::matrix::MatrixStack;
  18. use crate::result::Result;
  19. use crate::rgb::Rgb;
  20. use crate::uvmapper::{BrushType, Mappings};
  21. use crate::vm::Var;
  22. use log::error;
  23. #[derive(Default)]
  24. pub struct Context {
  25. pub matrix_stack: MatrixStack,
  26. pub mappings: Mappings,
  27. pub geometry: geometry::Geometry,
  28. pub bitmap_cache: BitmapCache,
  29. pub output_linear_colour_space: bool, // derive Default sets bool to false
  30. }
  31. impl Context {
  32. pub fn reset(&mut self) {
  33. self.matrix_stack.reset();
  34. self.geometry.reset();
  35. }
  36. pub fn get_render_packet_geo_len(&self, packet_number: usize) -> usize {
  37. self.geometry.get_render_packet_geo_len(packet_number)
  38. }
  39. pub fn get_render_packet_geo_ptr(&self, packet_number: usize) -> *const f32 {
  40. self.geometry.get_render_packet_geo_ptr(packet_number)
  41. }
  42. pub fn render_line(
  43. &mut self,
  44. from: (f32, f32),
  45. to: (f32, f32),
  46. width: f32,
  47. from_col: &Colour,
  48. to_col: &Colour,
  49. brush_type: BrushType,
  50. brush_subtype: usize,
  51. ) -> Result<()> {
  52. if let Some(matrix) = self.matrix_stack.peek() {
  53. let uvm = self.mappings.get_uv_mapping(brush_type, brush_subtype);
  54. let from_col = Rgb::from_colour(from_col)?;
  55. let to_col = Rgb::from_colour(to_col)?;
  56. geometry::line::render(
  57. &mut self.geometry,
  58. matrix,
  59. from,
  60. to,
  61. width,
  62. &from_col,
  63. &to_col,
  64. uvm,
  65. )
  66. } else {
  67. error!("no matrix for render_line");
  68. Err(Error::Context)
  69. }
  70. }
  71. pub fn render_rect(
  72. &mut self,
  73. position: (f32, f32),
  74. width: f32,
  75. height: f32,
  76. colour: &Colour,
  77. ) -> Result<()> {
  78. if let Some(matrix) = self.matrix_stack.peek() {
  79. let uvm = self.mappings.get_uv_mapping(BrushType::Flat, 0);
  80. let colour = Rgb::from_colour(colour)?;
  81. geometry::rect::render(
  82. &mut self.geometry,
  83. matrix,
  84. position,
  85. width,
  86. height,
  87. &colour,
  88. uvm,
  89. )
  90. } else {
  91. error!("no matrix for render_rect");
  92. Err(Error::Context)
  93. }
  94. }
  95. pub fn render_circle(
  96. &mut self,
  97. position: (f32, f32),
  98. width: f32,
  99. height: f32,
  100. colour: &Colour,
  101. tessellation: usize,
  102. ) -> Result<()> {
  103. if let Some(matrix) = self.matrix_stack.peek() {
  104. let uvm = self.mappings.get_uv_mapping(BrushType::Flat, 0);
  105. let colour = Rgb::from_colour(colour)?;
  106. geometry::circle::render(
  107. &mut self.geometry,
  108. matrix,
  109. position,
  110. width,
  111. height,
  112. &colour,
  113. tessellation,
  114. uvm,
  115. )
  116. } else {
  117. error!("no matrix for render_circle");
  118. Err(Error::Context)
  119. }
  120. }
  121. pub fn render_circle_slice(
  122. &mut self,
  123. position: (f32, f32),
  124. width: f32,
  125. height: f32,
  126. colour: &Colour,
  127. tessellation: usize,
  128. angle_start: f32,
  129. angle_end: f32,
  130. inner_width: f32,
  131. inner_height: f32,
  132. ) -> Result<()> {
  133. if let Some(matrix) = self.matrix_stack.peek() {
  134. let uvm = self.mappings.get_uv_mapping(BrushType::Flat, 0);
  135. let colour = Rgb::from_colour(colour)?;
  136. geometry::circle_slice::render(
  137. &mut self.geometry,
  138. matrix,
  139. position,
  140. width,
  141. height,
  142. &colour,
  143. tessellation,
  144. angle_start,
  145. angle_end,
  146. inner_width,
  147. inner_height,
  148. uvm,
  149. )
  150. } else {
  151. error!("no matrix for render_circle_slice");
  152. Err(Error::Context)
  153. }
  154. }
  155. pub fn render_poly(&mut self, coords: &[Var], colours: &[Var]) -> Result<()> {
  156. let coords: Result<Vec<(f32, f32)>> =
  157. coords.into_iter().map(|c| var_to_f32_pair(c)).collect();
  158. let coords = coords?;
  159. let colours: Result<Vec<Rgb>> = colours.into_iter().map(|c| var_to_rgb(c)).collect();
  160. let colours = colours?;
  161. if let Some(matrix) = self.matrix_stack.peek() {
  162. let uvm = self.mappings.get_uv_mapping(BrushType::Flat, 0);
  163. geometry::poly::render(&mut self.geometry, matrix, &coords, &colours, uvm)
  164. } else {
  165. error!("no matrix for render_poly");
  166. Err(Error::Context)
  167. }
  168. }
  169. pub fn render_quadratic(
  170. &mut self,
  171. coords: &[f32; 6],
  172. width_start: f32,
  173. width_end: f32,
  174. width_mapping: Easing,
  175. t_start: f32,
  176. t_end: f32,
  177. colour: &Colour,
  178. tessellation: usize,
  179. brush_type: BrushType,
  180. brush_subtype: usize,
  181. ) -> Result<()> {
  182. if let Some(matrix) = self.matrix_stack.peek() {
  183. let uvm = self.mappings.get_uv_mapping(brush_type, brush_subtype);
  184. let colour = Rgb::from_colour(colour)?;
  185. geometry::quadratic::render(
  186. &mut self.geometry,
  187. matrix,
  188. coords,
  189. width_start,
  190. width_end,
  191. width_mapping,
  192. t_start,
  193. t_end,
  194. &colour,
  195. tessellation,
  196. uvm,
  197. )
  198. } else {
  199. error!("no matrix for render_quadratic");
  200. Err(Error::Context)
  201. }
  202. }
  203. pub fn render_bezier(
  204. &mut self,
  205. coords: &[f32; 8],
  206. width_start: f32,
  207. width_end: f32,
  208. width_mapping: Easing,
  209. t_start: f32,
  210. t_end: f32,
  211. colour: &Colour,
  212. tessellation: usize,
  213. brush_type: BrushType,
  214. brush_subtype: usize,
  215. ) -> Result<()> {
  216. if let Some(matrix) = self.matrix_stack.peek() {
  217. let uvm = self.mappings.get_uv_mapping(brush_type, brush_subtype);
  218. let colour = Rgb::from_colour(colour)?;
  219. geometry::bezier::render(
  220. &mut self.geometry,
  221. matrix,
  222. coords,
  223. width_start,
  224. width_end,
  225. width_mapping,
  226. t_start,
  227. t_end,
  228. &colour,
  229. tessellation,
  230. uvm,
  231. )
  232. } else {
  233. error!("no matrix for render_bezier");
  234. Err(Error::Context)
  235. }
  236. }
  237. pub fn render_bezier_bulging(
  238. &mut self,
  239. coords: &[f32; 8],
  240. line_width: f32,
  241. t_start: f32,
  242. t_end: f32,
  243. colour: &Colour,
  244. tessellation: usize,
  245. brush_type: BrushType,
  246. brush_subtype: usize,
  247. ) -> Result<()> {
  248. if let Some(matrix) = self.matrix_stack.peek() {
  249. let uvm = self.mappings.get_uv_mapping(brush_type, brush_subtype);
  250. let colour = Rgb::from_colour(colour)?;
  251. geometry::bezier_bulging::render(
  252. &mut self.geometry,
  253. matrix,
  254. coords,
  255. line_width,
  256. t_start,
  257. t_end,
  258. &colour,
  259. tessellation,
  260. uvm,
  261. )
  262. } else {
  263. error!("no matrix for render_bezier_bulging");
  264. Err(Error::Context)
  265. }
  266. }
  267. pub fn render_stroked_bezier(
  268. &mut self,
  269. tessellation: usize,
  270. coords: &[f32; 8],
  271. stroke_tessellation: usize,
  272. stroke_noise: f32,
  273. stroke_line_width_start: f32,
  274. stroke_line_width_end: f32,
  275. colour: &Colour,
  276. colour_volatility: f32,
  277. seed: f32,
  278. mapping: Easing,
  279. brush_type: BrushType,
  280. brush_subtype: usize,
  281. ) -> Result<()> {
  282. if let Some(matrix) = self.matrix_stack.peek() {
  283. let uvm = self.mappings.get_uv_mapping(brush_type, brush_subtype);
  284. let colour = Rgb::from_colour(colour)?;
  285. geometry::stroked_bezier::render(
  286. &mut self.geometry,
  287. matrix,
  288. tessellation,
  289. coords,
  290. stroke_tessellation,
  291. stroke_noise,
  292. stroke_line_width_start,
  293. stroke_line_width_end,
  294. &colour,
  295. colour_volatility,
  296. seed,
  297. mapping,
  298. uvm,
  299. )
  300. } else {
  301. error!("no matrix for render_stroked_bezier");
  302. Err(Error::Context)
  303. }
  304. }
  305. pub fn render_stroked_bezier_rect(
  306. &mut self,
  307. position: (f32, f32),
  308. width: f32,
  309. height: f32,
  310. volatility: f32,
  311. overlap: f32,
  312. iterations: f32,
  313. seed: i32,
  314. tessellation: usize,
  315. stroke_tessellation: usize,
  316. stroke_noise: f32,
  317. colour: &Colour,
  318. colour_volatility: f32,
  319. brush_type: BrushType,
  320. brush_subtype: usize,
  321. ) -> Result<()> {
  322. if let Some(matrix) = self.matrix_stack.peek() {
  323. let uvm = self.mappings.get_uv_mapping(brush_type, brush_subtype);
  324. let colour = Rgb::from_colour(colour)?;
  325. geometry::stroked_bezier_rect::render(
  326. &mut self.geometry,
  327. matrix,
  328. position,
  329. width,
  330. height,
  331. volatility,
  332. overlap,
  333. iterations,
  334. seed,
  335. tessellation,
  336. stroke_tessellation,
  337. stroke_noise,
  338. &colour,
  339. colour_volatility,
  340. uvm,
  341. )
  342. } else {
  343. error!("no matrix for render_stroked_bezier_rect");
  344. Err(Error::Context)
  345. }
  346. }
  347. }
  348. fn var_to_f32_pair(v: &Var) -> Result<(f32, f32)> {
  349. if let Var::V2D(x, y) = v {
  350. Ok((*x, *y))
  351. } else {
  352. error!("var_to_f32_pair");
  353. Err(Error::Context)
  354. }
  355. }
  356. fn var_to_rgb(v: &Var) -> Result<(Rgb)> {
  357. if let Var::Colour(col) = v {
  358. let rgb = Rgb::from_colour(&col)?;
  359. Ok(rgb)
  360. } else {
  361. error!("var_to_rgb");
  362. Err(Error::Context)
  363. }
  364. }