Skip to main content

goud_engine/sdk/components_transform2d/
builder.rs

1//! Builder pattern for constructing Transform2D via heap allocation.
2
3use crate::core::math::Vec2;
4use crate::core::types::{FfiTransform2D, FfiTransform2DBuilder};
5use crate::ecs::components::Transform2D;
6
7/// Zero-sized type for Transform2D builder operations.
8pub struct Transform2DBuilderOps;
9
10// NOTE: FFI wrappers are hand-written in ffi/component_transform2d.rs. The `#[goud_api]`
11// attribute is omitted here to avoid duplicate `#[no_mangle]` symbol conflicts.
12impl Transform2DBuilderOps {
13    /// Creates a new transform builder with default values.
14    pub fn builder_new() -> *mut FfiTransform2DBuilder {
15        let builder = FfiTransform2DBuilder {
16            transform: Transform2D::default().into(),
17        };
18        Box::into_raw(Box::new(builder))
19    }
20
21    /// Creates a new transform builder at a specific position.
22    pub fn builder_at_position(x: f32, y: f32) -> *mut FfiTransform2DBuilder {
23        let builder = FfiTransform2DBuilder {
24            transform: Transform2D::from_position(Vec2::new(x, y)).into(),
25        };
26        Box::into_raw(Box::new(builder))
27    }
28
29    /// Sets the position on the builder.
30    pub fn builder_with_position(
31        builder: *mut FfiTransform2DBuilder,
32        x: f32,
33        y: f32,
34    ) -> *mut FfiTransform2DBuilder {
35        if builder.is_null() {
36            return builder;
37        }
38        // SAFETY: Caller guarantees pointer from builder_new.
39        let t = unsafe { &mut (*builder).transform };
40        t.position_x = x;
41        t.position_y = y;
42        builder
43    }
44
45    /// Sets the rotation (radians) on the builder.
46    pub fn builder_with_rotation(
47        builder: *mut FfiTransform2DBuilder,
48        rotation: f32,
49    ) -> *mut FfiTransform2DBuilder {
50        if builder.is_null() {
51            return builder;
52        }
53        // SAFETY: Pointer checked non-null above; allocated by builder_new via Box::into_raw.
54        unsafe { (*builder).transform.rotation = rotation };
55        builder
56    }
57
58    /// Sets the rotation (degrees) on the builder.
59    pub fn builder_with_rotation_degrees(
60        builder: *mut FfiTransform2DBuilder,
61        degrees: f32,
62    ) -> *mut FfiTransform2DBuilder {
63        if builder.is_null() {
64            return builder;
65        }
66        // SAFETY: Pointer checked non-null above; allocated by builder_new via Box::into_raw.
67        unsafe { (*builder).transform.rotation = degrees.to_radians() };
68        builder
69    }
70
71    /// Sets the scale on the builder.
72    pub fn builder_with_scale(
73        builder: *mut FfiTransform2DBuilder,
74        scale_x: f32,
75        scale_y: f32,
76    ) -> *mut FfiTransform2DBuilder {
77        if builder.is_null() {
78            return builder;
79        }
80        // SAFETY: Pointer checked non-null above; allocated by builder_new via Box::into_raw.
81        let t = unsafe { &mut (*builder).transform };
82        t.scale_x = scale_x;
83        t.scale_y = scale_y;
84        builder
85    }
86
87    /// Sets uniform scale on the builder.
88    pub fn builder_with_scale_uniform(
89        builder: *mut FfiTransform2DBuilder,
90        scale: f32,
91    ) -> *mut FfiTransform2DBuilder {
92        if builder.is_null() {
93            return builder;
94        }
95        // SAFETY: Pointer checked non-null above; allocated by builder_new via Box::into_raw.
96        let t = unsafe { &mut (*builder).transform };
97        t.scale_x = scale;
98        t.scale_y = scale;
99        builder
100    }
101
102    /// Makes the builder's transform look at a target.
103    pub fn builder_looking_at(
104        builder: *mut FfiTransform2DBuilder,
105        target_x: f32,
106        target_y: f32,
107    ) -> *mut FfiTransform2DBuilder {
108        if builder.is_null() {
109            return builder;
110        }
111        // SAFETY: Pointer checked non-null above; allocated by builder_new via Box::into_raw.
112        let t = unsafe { &mut (*builder).transform };
113        let dx = target_x - t.position_x;
114        let dy = target_y - t.position_y;
115        t.rotation = dy.atan2(dx);
116        builder
117    }
118
119    /// Translates the builder's position.
120    pub fn builder_translate(
121        builder: *mut FfiTransform2DBuilder,
122        dx: f32,
123        dy: f32,
124    ) -> *mut FfiTransform2DBuilder {
125        if builder.is_null() {
126            return builder;
127        }
128        // SAFETY: Pointer checked non-null above; allocated by builder_new via Box::into_raw.
129        let t = unsafe { &mut (*builder).transform };
130        t.position_x += dx;
131        t.position_y += dy;
132        builder
133    }
134
135    /// Rotates the builder's transform.
136    pub fn builder_rotate(
137        builder: *mut FfiTransform2DBuilder,
138        angle: f32,
139    ) -> *mut FfiTransform2DBuilder {
140        if builder.is_null() {
141            return builder;
142        }
143        // SAFETY: Pointer checked non-null above; allocated by builder_new via Box::into_raw.
144        unsafe { (*builder).transform.rotation += angle };
145        builder
146    }
147
148    /// Multiplies the builder's scale.
149    pub fn builder_scale_by(
150        builder: *mut FfiTransform2DBuilder,
151        factor_x: f32,
152        factor_y: f32,
153    ) -> *mut FfiTransform2DBuilder {
154        if builder.is_null() {
155            return builder;
156        }
157        // SAFETY: Pointer checked non-null above; allocated by builder_new via Box::into_raw.
158        let t = unsafe { &mut (*builder).transform };
159        t.scale_x *= factor_x;
160        t.scale_y *= factor_y;
161        builder
162    }
163
164    /// Builds the transform, consuming and freeing the builder.
165    pub fn builder_build(builder: *mut FfiTransform2DBuilder) -> FfiTransform2D {
166        if builder.is_null() {
167            return Transform2D::default().into();
168        }
169        // SAFETY: Takes ownership from builder_new allocation.
170        let boxed = unsafe { Box::from_raw(builder) };
171        boxed.transform
172    }
173
174    /// Frees a transform builder without building.
175    pub fn builder_free(builder: *mut FfiTransform2DBuilder) {
176        if !builder.is_null() {
177            // SAFETY: Takes ownership and drops.
178            drop(unsafe { Box::from_raw(builder) });
179        }
180    }
181}