microcad_lang/render/
context.rs

1// Copyright © 2025 The µcad authors <info@ucad.xyz>
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
4//! Render context
5
6use microcad_core::RenderResolution;
7
8use crate::{model::Model, render::*};
9
10/// The render context.
11///
12/// Keeps a stack of model nodes and the render cache.
13#[derive(Default)]
14pub struct RenderContext {
15    /// Model stack.
16    pub model_stack: Vec<Model>,
17
18    /// Render cache.
19    pub cache: RenderCache,
20}
21
22impl RenderContext {
23    /// Create default context.
24    pub fn new() -> Self {
25        Self::default()
26    }
27
28    /// Initialize context with current model and prerender model.
29    pub fn init(model: &Model, resolution: RenderResolution) -> RenderResult<Self> {
30        model.prerender(resolution)?;
31
32        Ok(Self {
33            model_stack: vec![model.clone()],
34            ..Default::default()
35        })
36    }
37
38    /// The current model (panics if it is none).
39    pub fn model(&self) -> Model {
40        self.model_stack.last().expect("A model").clone()
41    }
42
43    /// Run the closure `f` within the given `model`.
44    pub fn with_model<T>(&mut self, model: Model, f: impl FnOnce(&mut RenderContext) -> T) -> T {
45        self.model_stack.push(model);
46        let result = f(self);
47        self.model_stack.pop();
48        result
49    }
50
51    /// Update a 2D geometry if it is not in cache.
52    ///
53    /// TODO Add cache look up functionality.
54    pub fn update_2d(
55        &mut self,
56        f: impl FnOnce(&mut RenderContext, Model, RenderResolution) -> RenderResult<Geometry2DOutput>,
57    ) -> RenderResult<Geometry2DOutput> {
58        let model = self.model();
59        let resolution = self.current_resolution();
60        f(self, model, resolution)
61    }
62
63    /// Update a 3D geometry if it is not in cache.
64    ///
65    /// TODO Add cache look up functionality.
66    pub fn update_3d(
67        &mut self,
68        f: impl FnOnce(&mut RenderContext, Model, RenderResolution) -> RenderResult<Geometry3DOutput>,
69    ) -> RenderResult<Geometry3DOutput> {
70        let model = self.model();
71        let resolution = self.current_resolution();
72        f(self, model, resolution)
73    }
74
75    /// Return current render resolution.
76    pub fn current_resolution(&self) -> RenderResolution {
77        self.model().borrow().resolution()
78    }
79}