1#![allow(clippy::needless_range_loop)]
4
5use crate::CacheKey;
6use crate::cache::Cache;
7use crate::color::{ColorComponents, ColorSpace};
8use crate::function::{Function, StitchingBounds, Values, interpolate};
9use crate::util::{Float32Ext, PointExt, RectExt};
10use hayro_syntax::bit_reader::BitReader;
11use hayro_syntax::object::Array;
12use hayro_syntax::object::Dict;
13use hayro_syntax::object::Object;
14use hayro_syntax::object::Rect;
15use hayro_syntax::object::Stream;
16use hayro_syntax::object::dict::keys::{
17 BACKGROUND, BBOX, BITS_PER_COMPONENT, BITS_PER_COORDINATE, BITS_PER_FLAG, COLORSPACE, COORDS,
18 DECODE, DOMAIN, EXTEND, FUNCTION, MATRIX, SHADING_TYPE, VERTICES_PER_ROW,
19};
20use kurbo::{Affine, BezPath, CubicBez, ParamCurve, Point, Shape};
21use smallvec::{SmallVec, smallvec};
22use std::sync::Arc;
23
24#[derive(Debug, Clone)]
26pub enum ShadingFunction {
27 Single(Function),
29 Multiple(SmallVec<[Function; 4]>),
31}
32
33impl ShadingFunction {
34 pub fn eval(&self, input: &Values) -> Option<Values> {
36 match self {
37 Self::Single(s) => s.eval(input.clone()),
38 Self::Multiple(m) => {
39 let mut out = smallvec![];
42
43 for func in m {
44 out.push(*func.eval(input.clone())?.first()?);
45 }
46
47 Some(out)
48 }
49 }
50 }
51
52 pub(crate) fn stitching_bounds(&self) -> StitchingBounds {
53 let mut bounds = StitchingBounds::new();
54
55 match self {
56 Self::Single(function) => bounds.extend(function.stitching_bounds()),
57 Self::Multiple(functions) => {
58 for function in functions {
59 bounds.extend(function.stitching_bounds());
60 }
61 }
62 }
63
64 bounds.sort_by(f32::total_cmp);
65 bounds.dedup_by(|a, b| (*a - *b).abs() <= f32::EPSILON);
66 bounds
67 }
68}
69
70#[derive(Debug)]
72pub enum ShadingType {
73 FunctionBased {
75 domain: [f32; 4],
77 matrix: Affine,
79 function: ShadingFunction,
81 },
82 RadialAxial {
84 coords: [f32; 6],
92 domain: [f32; 2],
94 function: ShadingFunction,
96 extend: [bool; 2],
98 axial: bool,
100 },
101 TriangleMesh {
103 triangles: Vec<Triangle>,
105 function: Option<ShadingFunction>,
107 },
108 CoonsPatchMesh {
110 patches: Vec<CoonsPatch>,
112 function: Option<ShadingFunction>,
114 },
115 TensorProductPatchMesh {
117 patches: Vec<TensorProductPatch>,
119 function: Option<ShadingFunction>,
121 },
122 Dummy,
124}
125
126#[derive(Clone, Debug)]
128pub struct Shading {
129 cache_key: u128,
130 pub shading_type: Arc<ShadingType>,
132 pub color_space: ColorSpace,
134 pub clip_path: Option<BezPath>,
136 pub background: Option<SmallVec<[f32; 4]>>,
138}
139
140impl Shading {
141 pub(crate) fn new(dict: &Dict<'_>, stream: Option<&Stream<'_>>, cache: &Cache) -> Option<Self> {
142 let cache_key = dict.cache_key();
143
144 let shading_num = dict.get::<u8>(SHADING_TYPE)?;
145
146 let color_space = ColorSpace::new(dict.get(COLORSPACE)?, cache)?;
147
148 let shading_type = match shading_num {
149 1 => {
150 let domain = dict.get::<[f32; 4]>(DOMAIN).unwrap_or([0.0, 1.0, 0.0, 1.0]);
151 let matrix = dict
152 .get::<[f64; 6]>(MATRIX)
153 .map(Affine::new)
154 .unwrap_or_default();
155 let function = read_function(dict, &color_space)?;
156
157 ShadingType::FunctionBased {
158 domain,
159 matrix,
160 function,
161 }
162 }
163 2 | 3 => {
164 let domain = dict.get::<[f32; 2]>(DOMAIN).unwrap_or([0.0, 1.0]);
165 let function = read_function(dict, &color_space)?;
166 let extend = dict.get::<[bool; 2]>(EXTEND).unwrap_or([false, false]);
167 let (coords, invalid) = if shading_num == 2 {
168 let read = dict.get::<[f32; 4]>(COORDS)?;
169 let invalid = (read[0] - read[2]).is_nearly_zero()
170 && (read[1] - read[3]).is_nearly_zero();
171 ([read[0], read[1], read[2], read[3], 0.0, 0.0], invalid)
172 } else {
173 let read = dict.get::<[f32; 6]>(COORDS)?;
174 let invalid = (read[0] - read[3]).is_nearly_zero()
175 && (read[1] - read[4]).is_nearly_zero()
176 && (read[2] - read[5]).is_nearly_zero();
177 (read, invalid)
178 };
179
180 let axial = shading_num == 2;
181
182 if invalid {
183 ShadingType::Dummy
184 } else {
185 ShadingType::RadialAxial {
186 domain,
187 function,
188 extend,
189 coords,
190 axial,
191 }
192 }
193 }
194 4 => {
195 let stream = stream?;
196 let stream_data = stream.decoded().ok()?;
197 let bp_coord = dict.get::<u8>(BITS_PER_COORDINATE)?;
198 let bp_comp = dict.get::<u8>(BITS_PER_COMPONENT)?;
199 let bpf = dict.get::<u8>(BITS_PER_FLAG)?;
200 let function = read_function(dict, &color_space);
201 let decode = dict
202 .get::<Array<'_>>(DECODE)?
203 .iter::<f32>()
204 .collect::<Vec<_>>();
205
206 let triangles = read_free_form_triangles(
207 stream_data.as_ref(),
208 bpf,
209 bp_coord,
210 bp_comp,
211 function.is_some(),
212 &decode,
213 )?;
214
215 ShadingType::TriangleMesh {
216 triangles,
217 function,
218 }
219 }
220 5 => {
221 let stream = stream?;
222 let stream_data = stream.decoded().ok()?;
223 let bp_coord = dict.get::<u8>(BITS_PER_COORDINATE)?;
224 let bp_comp = dict.get::<u8>(BITS_PER_COMPONENT)?;
225 let function = read_function(dict, &color_space);
226 let decode = dict
227 .get::<Array<'_>>(DECODE)?
228 .iter::<f32>()
229 .collect::<Vec<_>>();
230 let vertices_per_row = dict.get::<u32>(VERTICES_PER_ROW)?;
231
232 let triangles = read_lattice_triangles(
233 stream_data.as_ref(),
234 bp_coord,
235 bp_comp,
236 function.is_some(),
237 vertices_per_row,
238 &decode,
239 )?;
240
241 ShadingType::TriangleMesh {
242 triangles,
243 function,
244 }
245 }
246 6 => {
247 let stream = stream?;
248 let stream_data = stream.decoded().ok()?;
249 let bp_coord = dict.get::<u8>(BITS_PER_COORDINATE)?;
250 let bp_comp = dict.get::<u8>(BITS_PER_COMPONENT)?;
251 let bpf = dict.get::<u8>(BITS_PER_FLAG)?;
252 let function = read_function(dict, &color_space);
253 let decode = dict
254 .get::<Array<'_>>(DECODE)?
255 .iter::<f32>()
256 .collect::<Vec<_>>();
257
258 let patches = read_coons_patch_mesh(
259 stream_data.as_ref(),
260 bpf,
261 bp_coord,
262 bp_comp,
263 function.is_some(),
264 &decode,
265 )?;
266
267 ShadingType::CoonsPatchMesh { patches, function }
268 }
269 7 => {
270 let stream = stream?;
271 let stream_data = stream.decoded().ok()?;
272 let bp_coord = dict.get::<u8>(BITS_PER_COORDINATE)?;
273 let bp_comp = dict.get::<u8>(BITS_PER_COMPONENT)?;
274 let bpf = dict.get::<u8>(BITS_PER_FLAG)?;
275 let function = read_function(dict, &color_space);
276 let decode = dict
277 .get::<Array<'_>>(DECODE)?
278 .iter::<f32>()
279 .collect::<Vec<_>>();
280
281 let patches = read_tensor_product_patch_mesh(
282 stream_data.as_ref(),
283 bpf,
284 bp_coord,
285 bp_comp,
286 function.is_some(),
287 &decode,
288 )?;
289
290 ShadingType::TensorProductPatchMesh { patches, function }
291 }
292 _ => return None,
293 };
294
295 let bbox = dict.get::<Rect>(BBOX).map(|r| r.to_kurbo());
296 let background = dict
297 .get::<Array<'_>>(BACKGROUND)
298 .map(|a| a.iter::<f32>().collect::<SmallVec<_>>());
299
300 Some(Self {
301 cache_key,
302 shading_type: Arc::new(shading_type),
303 color_space,
304 clip_path: bbox.map(|r| r.to_path(0.1)),
305 background,
306 })
307 }
308}
309
310impl CacheKey for Shading {
311 fn cache_key(&self) -> u128 {
312 self.cache_key
313 }
314}
315
316#[derive(Clone, Debug)]
318pub struct Triangle {
319 pub p0: TriangleVertex,
321 pub p1: TriangleVertex,
323 pub p2: TriangleVertex,
325 kurbo_tri: kurbo::Triangle,
326 d00: f64,
327 d01: f64,
328 d11: f64,
329}
330
331impl Triangle {
332 pub fn new(p0: TriangleVertex, p1: TriangleVertex, p2: TriangleVertex) -> Self {
334 let v0 = p1.point - p0.point;
335 let v1 = p2.point - p0.point;
336
337 let d00 = v0.dot(v0);
338 let d01 = v0.dot(v1);
339 let d11 = v1.dot(v1);
340
341 let kurbo_tri = kurbo::Triangle::new(p0.point, p1.point, p2.point);
342
343 Self {
344 p0,
345 p1,
346 kurbo_tri,
347 p2,
348 d00,
349 d01,
350 d11,
351 }
352 }
353
354 pub fn interpolate(&self, pos: Point) -> ColorComponents {
358 let (u, v, w) = self.barycentric_coords(pos);
359
360 let mut result = smallvec![];
361
362 for i in 0..self.p0.colors.len() {
363 let c0 = self.p0.colors[i];
364 let c1 = self.p1.colors[i];
365 let c2 = self.p2.colors[i];
366 result.push(u * c0 + v * c1 + w * c2);
367 }
368
369 result
370 }
371
372 pub fn contains_point(&self, pos: Point) -> bool {
374 self.kurbo_tri.winding(pos) != 0
375 }
376
377 pub fn bounding_box(&self) -> kurbo::Rect {
379 self.kurbo_tri.bounding_box()
380 }
381
382 fn barycentric_coords(&self, p: Point) -> (f32, f32, f32) {
383 let (a, b, c) = (self.p0.point, self.p1.point, self.p2.point);
384 let v0 = b - a;
385 let v1 = c - a;
386 let v2 = p - a;
387
388 let d00 = self.d00;
389 let d01 = self.d01;
390 let d11 = self.d11;
391 let d20 = v2.dot(v0);
392 let d21 = v2.dot(v1);
393
394 let denom = d00 * d11 - d01 * d01;
395 let v = (d11 * d20 - d01 * d21) / denom;
396 let w = (d00 * d21 - d01 * d20) / denom;
397 let u = (1.0 - v - w) as f32;
398
399 (u, v as f32, w as f32)
400 }
401}
402
403#[derive(Clone, Debug)]
405pub struct TriangleVertex {
406 flag: u32,
407 pub point: Point,
409 pub colors: ColorComponents,
411}
412
413#[derive(Clone, Debug)]
415pub struct CoonsPatch {
416 pub control_points: [Point; 12],
418 pub colors: [ColorComponents; 4],
420}
421
422#[derive(Clone, Debug)]
424pub struct TensorProductPatch {
425 pub control_points: [Point; 16],
427 pub colors: [ColorComponents; 4],
429}
430
431impl CoonsPatch {
432 pub fn map_coordinate(&self, p: Point) -> Point {
434 let (u, v) = (p.x, p.y);
435
436 let cp = &self.control_points;
437
438 let c1 = CubicBez::new(cp[0], cp[11], cp[10], cp[9]);
439 let c2 = CubicBez::new(cp[3], cp[4], cp[5], cp[6]);
440 let d1 = CubicBez::new(cp[0], cp[1], cp[2], cp[3]);
441 let d2 = CubicBez::new(cp[9], cp[8], cp[7], cp[6]);
442
443 let sc = (1.0 - v) * c1.eval(u).to_vec2() + v * c2.eval(u).to_vec2();
444 let sd = (1.0 - u) * d1.eval(v).to_vec2() + u * d2.eval(v).to_vec2();
445 let sb = (1.0 - v) * ((1.0 - u) * c1.eval(0.0).to_vec2() + u * c1.eval(1.0).to_vec2())
446 + v * ((1.0 - u) * c2.eval(0.0).to_vec2() + u * c2.eval(1.0).to_vec2());
447
448 (sc + sd - sb).to_point()
449 }
450
451 pub fn to_triangles(&self, buffer: &mut Vec<Triangle>) {
453 generate_patch_triangles(|p| self.map_coordinate(p), |p| self.interpolate(p), buffer);
454 }
455
456 pub fn interpolate(&self, pos: Point) -> ColorComponents {
458 let (u, v) = (pos.x, pos.y);
459 let (c0, c1, c2, c3) = {
460 (
461 &self.colors[0],
462 &self.colors[1],
463 &self.colors[2],
464 &self.colors[3],
465 )
466 };
467
468 let mut result = SmallVec::new();
469 for i in 0..c0.len() {
470 let val = (1.0 - u) * (1.0 - v) * c0[i] as f64
471 + u * (1.0 - v) * c3[i] as f64
472 + u * v * c2[i] as f64
473 + (1.0 - u) * v * c1[i] as f64;
474 result.push(val as f32);
475 }
476
477 result
478 }
479}
480
481impl TensorProductPatch {
482 fn bernstein(i: usize, t: f64) -> f64 {
484 match i {
485 0 => (1.0 - t).powi(3),
486 1 => 3.0 * t * (1.0 - t).powi(2),
487 2 => 3.0 * t.powi(2) * (1.0 - t),
488 3 => t.powi(3),
489 _ => 0.0,
490 }
491 }
492
493 pub fn map_coordinate(&self, p: Point) -> Point {
495 let (u, v) = (p.x, p.y);
496
497 let mut x = 0.0;
498 let mut y = 0.0;
499
500 fn idx(i: usize, j: usize) -> usize {
501 match (i, j) {
502 (0, 0) => 0,
503 (0, 1) => 1,
504 (0, 2) => 2,
505 (0, 3) => 3,
506 (1, 0) => 11,
507 (1, 1) => 12,
508 (1, 2) => 13,
509 (1, 3) => 4,
510 (2, 0) => 10,
511 (2, 1) => 15,
512 (2, 2) => 14,
513 (2, 3) => 5,
514 (3, 0) => 9,
515 (3, 1) => 8,
516 (3, 2) => 7,
517 (3, 3) => 6,
518 _ => panic!("Invalid index"),
519 }
520 }
521
522 for i in 0..4 {
523 for j in 0..4 {
524 let control_point_idx = idx(i, j);
525 let basis = Self::bernstein(i, u) * Self::bernstein(j, v);
526
527 x += self.control_points[control_point_idx].x * basis;
528 y += self.control_points[control_point_idx].y * basis;
529 }
530 }
531
532 Point::new(x, y)
533 }
534
535 pub fn to_triangles(&self, buffer: &mut Vec<Triangle>) {
537 generate_patch_triangles(|p| self.map_coordinate(p), |p| self.interpolate(p), buffer);
538 }
539
540 pub fn interpolate(&self, pos: Point) -> ColorComponents {
542 let (u, v) = (pos.x, pos.y);
543 let (c0, c1, c2, c3) = {
544 (
545 &self.colors[0],
546 &self.colors[1],
547 &self.colors[2],
548 &self.colors[3],
549 )
550 };
551
552 let mut result = SmallVec::new();
553 for i in 0..c0.len() {
554 let val = (1.0 - u) * (1.0 - v) * c0[i] as f64
555 + u * (1.0 - v) * c3[i] as f64
556 + u * v * c2[i] as f64
557 + (1.0 - u) * v * c1[i] as f64;
558 result.push(val as f32);
559 }
560
561 result
562 }
563}
564
565fn read_free_form_triangles(
566 data: &[u8],
567 bpf: u8,
568 bp_cord: u8,
569 bp_comp: u8,
570 has_function: bool,
571 decode: &[f32],
572) -> Option<Vec<Triangle>> {
573 let mut triangles = vec![];
574
575 let ([x_min, x_max, y_min, y_max], decode) = split_decode(decode)?;
576 let mut reader = BitReader::new(data);
577 let helpers = InterpolationHelpers::new(bp_cord, bp_comp, x_min, x_max, y_min, y_max);
578
579 let read_single = |reader: &mut BitReader<'_>| -> Option<TriangleVertex> {
580 helpers.read_triangle_vertex(reader, bpf, has_function, decode)
581 };
582
583 let mut a = None;
584 let mut b = None;
585 let mut c = None;
586
587 loop {
588 let Some(first) = read_single(&mut reader) else {
589 break;
590 };
591
592 if first.flag == 0 {
593 let second = read_single(&mut reader)?;
594 let third = read_single(&mut reader)?;
595
596 a = Some(first.clone());
597 b = Some(second.clone());
598 c = Some(third.clone());
599 } else if first.flag == 1 {
600 a = Some(b.clone()?);
601 b = Some(c.clone()?);
602 c = Some(first);
603 } else if first.flag == 2 {
604 b = Some(c.clone()?);
605 c = Some(first);
606 }
607
608 let (p0, p1, p2) = (a.clone()?, b.clone()?, c.clone()?);
609
610 if p0.point.nearly_same(p1.point) || p1.point.nearly_same(p2.point) {
611 continue;
612 }
613
614 triangles.push(Triangle::new(a.clone()?, b.clone()?, c.clone()?));
615 }
616
617 Some(triangles)
618}
619
620struct InterpolationHelpers {
622 bp_coord: u8,
623 bp_comp: u8,
624 coord_max: f32,
625 comp_max: f32,
626 x_min: f32,
627 x_max: f32,
628 y_min: f32,
629 y_max: f32,
630}
631
632impl InterpolationHelpers {
633 fn new(bp_coord: u8, bp_comp: u8, x_min: f32, x_max: f32, y_min: f32, y_max: f32) -> Self {
634 let coord_max = 2.0_f32.powi(bp_coord as i32) - 1.0;
635 let comp_max = 2.0_f32.powi(bp_comp as i32) - 1.0;
636 Self {
637 bp_coord,
638 bp_comp,
639 coord_max,
640 comp_max,
641 x_min,
642 x_max,
643 y_min,
644 y_max,
645 }
646 }
647
648 fn interpolate_coord(&self, n: u32, d_min: f32, d_max: f32) -> f32 {
649 interpolate(n as f32, 0.0, self.coord_max, d_min, d_max)
650 }
651
652 fn interpolate_comp(&self, n: u32, d_min: f32, d_max: f32) -> f32 {
653 interpolate(n as f32, 0.0, self.comp_max, d_min, d_max)
654 }
655
656 fn read_point(&self, reader: &mut BitReader<'_>) -> Option<Point> {
657 let x = self.interpolate_coord(reader.read(self.bp_coord)?, self.x_min, self.x_max);
658 let y = self.interpolate_coord(reader.read(self.bp_coord)?, self.y_min, self.y_max);
659 Some(Point::new(x as f64, y as f64))
660 }
661
662 fn read_colors(
663 &self,
664 reader: &mut BitReader<'_>,
665 has_function: bool,
666 decode: &[f32],
667 ) -> Option<ColorComponents> {
668 let mut colors = smallvec![];
669 if has_function {
670 colors.push(self.interpolate_comp(
671 reader.read(self.bp_comp)?,
672 *decode.first()?,
673 *decode.get(1)?,
674 ));
675 } else {
676 let num_components = decode.len() / 2;
677 for (_, decode) in (0..num_components).zip(decode.chunks_exact(2)) {
678 colors.push(self.interpolate_comp(
679 reader.read(self.bp_comp)?,
680 decode[0],
681 decode[1],
682 ));
683 }
684 }
685 Some(colors)
686 }
687
688 fn read_triangle_vertex(
689 &self,
690 reader: &mut BitReader<'_>,
691 bpf: u8,
692 has_function: bool,
693 decode: &[f32],
694 ) -> Option<TriangleVertex> {
695 let flag = reader.read(bpf)?;
696 let point = self.read_point(reader)?;
697 let colors = self.read_colors(reader, has_function, decode)?;
698 reader.align();
699
700 Some(TriangleVertex {
701 flag,
702 point,
703 colors,
704 })
705 }
706}
707
708fn split_decode(decode: &[f32]) -> Option<([f32; 4], &[f32])> {
710 decode.split_first_chunk::<4>().map(|(a, b)| (*a, b))
711}
712
713fn generate_patch_triangles<F, I>(map_coordinate: F, interpolate: I, buffer: &mut Vec<Triangle>)
715where
716 F: Fn(Point) -> Point,
717 I: Fn(Point) -> ColorComponents,
718{
719 const GRID_SIZE: usize = 20;
720 let mut grid = vec![vec![Point::ZERO; GRID_SIZE]; GRID_SIZE];
721
722 for i in 0..GRID_SIZE {
724 for j in 0..GRID_SIZE {
725 let u = i as f64 / (GRID_SIZE - 1) as f64; let v = j as f64 / (GRID_SIZE - 1) as f64; let unit_point = Point::new(u, v);
730 grid[i][j] = map_coordinate(unit_point);
731 }
732 }
733
734 for i in 0..(GRID_SIZE - 1) {
735 for j in 0..(GRID_SIZE - 1) {
736 let p00 = grid[i][j];
737 let p10 = grid[i + 1][j];
738 let p01 = grid[i][j + 1];
739 let p11 = grid[i + 1][j + 1];
740
741 let u0 = i as f64 / (GRID_SIZE - 1) as f64;
743 let u1 = (i + 1) as f64 / (GRID_SIZE - 1) as f64;
744 let v0 = j as f64 / (GRID_SIZE - 1) as f64;
745 let v1 = (j + 1) as f64 / (GRID_SIZE - 1) as f64;
746
747 let v00 = TriangleVertex {
749 flag: 0,
750 point: p00,
751 colors: interpolate(Point::new(u0, v0)),
752 };
753 let v10 = TriangleVertex {
754 flag: 0,
755 point: p10,
756 colors: interpolate(Point::new(u1, v0)),
757 };
758 let v01 = TriangleVertex {
759 flag: 0,
760 point: p01,
761 colors: interpolate(Point::new(u0, v1)),
762 };
763 let v11 = TriangleVertex {
764 flag: 0,
765 point: p11,
766 colors: interpolate(Point::new(u1, v1)),
767 };
768
769 let inflate_point = |p: Point, mid: Point| -> Point {
770 const INFLATION_FACTOR: f64 = 1.025;
771 mid + (p - mid) * INFLATION_FACTOR
772 };
773
774 let inflate = |mut triangle: Triangle| {
777 let mid = triangle.kurbo_tri.centroid();
778 triangle.p0.point = inflate_point(triangle.p0.point, mid);
779 triangle.p1.point = inflate_point(triangle.p1.point, mid);
780 triangle.p2.point = inflate_point(triangle.p2.point, mid);
781
782 triangle
783 };
784
785 buffer.push(inflate(Triangle::new(
786 v00.clone(),
787 v10.clone(),
788 v01.clone(),
789 )));
790 buffer.push(inflate(Triangle::new(
791 v10.clone(),
792 v11.clone(),
793 v01.clone(),
794 )));
795 }
796 }
797}
798
799fn read_lattice_triangles(
800 data: &[u8],
801 bp_cord: u8,
802 bp_comp: u8,
803 has_function: bool,
804 vertices_per_row: u32,
805 decode: &[f32],
806) -> Option<Vec<Triangle>> {
807 let mut lattices = vec![];
808
809 let ([x_min, x_max, y_min, y_max], decode) = split_decode(decode)?;
810 let mut reader = BitReader::new(data);
811 let helpers = InterpolationHelpers::new(bp_cord, bp_comp, x_min, x_max, y_min, y_max);
812
813 let read_single = |reader: &mut BitReader<'_>| -> Option<TriangleVertex> {
814 let point = helpers.read_point(reader)?;
815 let colors = helpers.read_colors(reader, has_function, decode)?;
816 reader.align();
817
818 Some(TriangleVertex {
819 flag: 0,
820 point,
821 colors,
822 })
823 };
824
825 'outer: loop {
826 let mut single_row = vec![];
827
828 for _ in 0..vertices_per_row {
829 let Some(next) = read_single(&mut reader) else {
830 break 'outer;
831 };
832
833 single_row.push(next);
834 }
835
836 lattices.push(single_row);
837 }
838
839 let mut triangles = vec![];
840
841 for i in 0..lattices.len().saturating_sub(1) {
842 for j in 0..(vertices_per_row as usize).saturating_sub(1) {
843 triangles.push(Triangle::new(
844 lattices[i][j].clone(),
845 lattices[i + 1][j].clone(),
846 lattices[i][j + 1].clone(),
847 ));
848
849 triangles.push(Triangle::new(
850 lattices[i + 1][j + 1].clone(),
851 lattices[i + 1][j].clone(),
852 lattices[i][j + 1].clone(),
853 ));
854 }
855 }
856
857 Some(triangles)
858}
859
860fn read_coons_patch_mesh(
861 data: &[u8],
862 bpf: u8,
863 bp_coord: u8,
864 bp_comp: u8,
865 has_function: bool,
866 decode: &[f32],
867) -> Option<Vec<CoonsPatch>> {
868 read_patch_mesh(
869 data,
870 bpf,
871 bp_coord,
872 bp_comp,
873 has_function,
874 decode,
875 12,
876 |control_points, colors| {
877 let mut coons_points = [Point::ZERO; 12];
878 coons_points.copy_from_slice(&control_points[0..12]);
879 CoonsPatch {
880 control_points: coons_points,
881 colors,
882 }
883 },
884 )
885}
886
887#[allow(clippy::too_many_arguments)]
889fn read_patch_mesh<P, F>(
890 data: &[u8],
891 bpf: u8,
892 bp_coord: u8,
893 bp_comp: u8,
894 has_function: bool,
895 decode: &[f32],
896 control_points_count: usize,
897 create_patch: F,
898) -> Option<Vec<P>>
899where
900 F: Fn([Point; 16], [ColorComponents; 4]) -> P,
901{
902 let ([x_min, x_max, y_min, y_max], decode) = split_decode(decode)?;
903 let mut reader = BitReader::new(data);
904 let helpers = InterpolationHelpers::new(bp_coord, bp_comp, x_min, x_max, y_min, y_max);
905
906 let read_colors = |reader: &mut BitReader<'_>| -> Option<ColorComponents> {
907 helpers.read_colors(reader, has_function, decode)
908 };
909
910 let mut prev_patch_points: Option<Vec<Point>> = None;
911 let mut prev_patch_colors: Option<[ColorComponents; 4]> = None;
912 let mut patches = vec![];
913
914 while let Some(flag) = reader.read(bpf) {
915 let mut control_points = vec![Point::ZERO; 16]; let mut colors = [smallvec![], smallvec![], smallvec![], smallvec![]];
917
918 match flag {
919 0 => {
920 for i in 0..control_points_count {
921 control_points[i] = helpers.read_point(&mut reader)?;
922 }
923
924 for i in 0..4 {
925 colors[i] = read_colors(&mut reader)?;
926 }
927
928 prev_patch_points = Some(control_points.clone());
929 prev_patch_colors = Some(colors.clone());
930 }
931 1..=3 => {
932 let prev_points = prev_patch_points.as_ref()?;
933 let prev_colors = prev_patch_colors.as_ref()?;
934
935 copy_patch_control_points(flag, prev_points, &mut control_points);
936
937 match flag {
938 1 => {
939 colors[0] = prev_colors[1].clone();
940 colors[1] = prev_colors[2].clone();
941 }
942 2 => {
943 colors[0] = prev_colors[2].clone();
944 colors[1] = prev_colors[3].clone();
945 }
946 3 => {
947 colors[0] = prev_colors[3].clone();
948 colors[1] = prev_colors[0].clone();
949 }
950 _ => unreachable!(),
951 }
952
953 for i in 4..control_points_count {
954 control_points[i] = helpers.read_point(&mut reader)?;
955 }
956
957 colors[2] = read_colors(&mut reader)?;
958 colors[3] = read_colors(&mut reader)?;
959
960 prev_patch_points = Some(control_points.clone());
961 prev_patch_colors = Some(colors.clone());
962 }
963 _ => break,
964 }
965
966 let mut fixed_points = [Point::ZERO; 16];
967 for i in 0..16 {
968 if i < control_points.len() {
969 fixed_points[i] = control_points[i];
970 }
971 }
972
973 patches.push(create_patch(fixed_points, colors));
974 }
975 Some(patches)
976}
977
978fn copy_patch_control_points(
979 flag: u32,
980 prev_control_points: &[Point],
981 control_points: &mut [Point],
982) {
983 match flag {
984 1 => {
985 control_points[0] = prev_control_points[3];
986 control_points[1] = prev_control_points[4];
987 control_points[2] = prev_control_points[5];
988 control_points[3] = prev_control_points[6];
989 }
990 2 => {
991 control_points[0] = prev_control_points[6];
992 control_points[1] = prev_control_points[7];
993 control_points[2] = prev_control_points[8];
994 control_points[3] = prev_control_points[9];
995 }
996 3 => {
997 control_points[0] = prev_control_points[9];
998 control_points[1] = prev_control_points[10];
999 control_points[2] = prev_control_points[11];
1000 control_points[3] = prev_control_points[0];
1001 }
1002 _ => {}
1003 }
1004}
1005
1006fn read_tensor_product_patch_mesh(
1007 data: &[u8],
1008 bpf: u8,
1009 bp_coord: u8,
1010 bp_comp: u8,
1011 has_function: bool,
1012 decode: &[f32],
1013) -> Option<Vec<TensorProductPatch>> {
1014 read_patch_mesh(
1015 data,
1016 bpf,
1017 bp_coord,
1018 bp_comp,
1019 has_function,
1020 decode,
1021 16,
1022 |control_points, colors| TensorProductPatch {
1023 control_points,
1024 colors,
1025 },
1026 )
1027}
1028
1029fn read_function(dict: &Dict<'_>, color_space: &ColorSpace) -> Option<ShadingFunction> {
1030 if let Some(arr) = dict.get::<Array<'_>>(FUNCTION) {
1031 let arr: Option<SmallVec<_>> = arr
1032 .iter::<Object<'_>>()
1033 .map(|o| Function::new(&o))
1034 .collect();
1035 let arr = arr?;
1036
1037 if arr.len() != color_space.num_components() as usize {
1038 warn!("function array of shading has wrong size");
1039
1040 return None;
1041 }
1042
1043 Some(ShadingFunction::Multiple(arr))
1044 } else if let Some(obj) = dict.get::<Object<'_>>(FUNCTION) {
1045 Some(ShadingFunction::Single(Function::new(&obj)?))
1046 } else {
1047 None
1048 }
1049}