Skip to main content

eldiron_shared/
lib.rs

1pub mod asset;
2pub mod character;
3pub mod context;
4pub mod effectwrapper;
5pub mod fx;
6pub mod interaction;
7pub mod item;
8pub mod project;
9pub mod region;
10pub mod renderer_utils;
11pub mod rusterix_utils;
12pub mod screen;
13pub mod settingscontainer;
14pub mod tilemap;
15pub mod tileselection;
16
17pub mod prelude {
18    pub use ::serde::{Deserialize, Serialize};
19
20    pub use crate::asset::*;
21    pub use crate::character::Character;
22    pub use crate::context::*;
23    pub use crate::effectwrapper::*;
24    pub use crate::fx::*;
25    pub use crate::interaction::*;
26    pub use crate::item::Item;
27    pub use crate::project::{MapMode, Project};
28    pub use crate::region::Region;
29    pub use crate::renderer_utils::ray_sphere;
30    pub use crate::screen::*;
31    pub use crate::tilemap::{Tile, Tilemap};
32    pub use indexmap::IndexMap;
33}
34
35use theframework::prelude::*;
36
37/// Messages to the clients. The first argument is always the client id.
38#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
39pub enum ServerMessage {
40    /// The given player instance has joined the server in the given region.
41    /// The client will use this to know what player / region to draw / focus on.
42    PlayerJoined(Uuid, Uuid, Uuid),
43}
44
45/// Ray
46#[derive(Serialize, Deserialize, PartialEq, Debug, Copy, Clone)]
47pub struct Ray {
48    pub o: Vec3<f32>,
49    pub d: Vec3<f32>,
50}
51
52impl Ray {
53    pub fn new(o: Vec3<f32>, d: Vec3<f32>) -> Self {
54        Self { o, d }
55    }
56
57    /// Returns the position on the ray at the given distance
58    pub fn at(&self, d: f32) -> Vec3<f32> {
59        self.o + self.d * d
60    }
61}
62
63#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
64pub enum HitMode {
65    Albedo,
66    Bump,
67}
68
69#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
70pub enum HitFace {
71    XFace,
72    YFace,
73    ZFace,
74}
75
76#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
77pub enum MaterialType {
78    Off,
79    PBR,
80}
81
82#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
83pub struct Material {
84    pub base_color: Vec3<f32>,
85
86    pub roughness: f32,
87    pub metallic: f32,
88    pub ior: f32,
89
90    pub mat_type: MaterialType,
91}
92
93impl Default for Material {
94    fn default() -> Self {
95        Self::new()
96    }
97}
98
99impl Material {
100    pub fn new() -> Self {
101        Self {
102            base_color: Vec3::new(0.5, 0.5, 0.5),
103            roughness: 0.5,
104            metallic: 0.0,
105            ior: 1.45,
106
107            mat_type: MaterialType::Off,
108        }
109    }
110
111    /// Mixes two materials.
112    pub fn mix(&mut self, mat1: &Material, mat2: &Material, t: f32) {
113        self.base_color = mat1
114            .base_color
115            .map2(mat2.base_color, |a, b| a + t * (b - a));
116
117        self.metallic = f32::lerp(mat1.metallic, mat2.metallic, t);
118        self.roughness = f32::lerp(mat1.roughness, mat2.roughness, t);
119        self.ior = f32::lerp(mat1.ior, mat2.ior, t);
120    }
121}
122
123#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
124pub struct Hit {
125    pub is_valid: bool,
126
127    pub mode: HitMode,
128
129    pub node: usize,
130
131    pub eps: f32,
132
133    pub key: Vec3<f32>,
134    pub hash: f32,
135
136    pub bump: f32,
137
138    pub distance: f32,
139    pub interior_distance: f32,
140
141    pub hit_point: Vec3<f32>,
142    pub normal: Vec3<f32>,
143    pub uv: Vec2<f32>,
144    pub global_uv: Vec2<f32>,
145    pub face: HitFace,
146
147    pub pattern_pos: Vec2<f32>,
148
149    pub color: Vec4<f32>,
150
151    pub mat: Material,
152    pub noise: Option<f32>,
153    pub noise_scale: f32,
154
155    pub value: f32,
156
157    pub two_d: bool,
158}
159
160impl Default for Hit {
161    fn default() -> Self {
162        Self::new()
163    }
164}
165
166impl Hit {
167    pub fn new() -> Self {
168        Self {
169            is_valid: true,
170
171            mode: HitMode::Albedo,
172
173            node: 0,
174
175            eps: 0.001, //0.0003,
176
177            key: Vec3::zero(),
178            hash: 0.0,
179
180            bump: 0.0,
181
182            distance: f32::MAX,
183            interior_distance: f32::MAX,
184
185            hit_point: Vec3::zero(),
186            normal: Vec3::zero(),
187            uv: Vec2::zero(),
188            global_uv: Vec2::zero(),
189            face: HitFace::XFace,
190
191            pattern_pos: Vec2::zero(),
192
193            color: Vec4::zero(),
194
195            mat: Material::default(),
196            noise: None,
197            noise_scale: 1.0,
198
199            value: 1.0,
200
201            two_d: false,
202        }
203    }
204}
205
206#[derive(Debug, Clone, Copy)]
207pub struct AABB2D {
208    min: Vec2<f32>,
209    max: Vec2<f32>,
210}
211
212impl Default for AABB2D {
213    fn default() -> Self {
214        Self::zero()
215    }
216}
217
218impl AABB2D {
219    pub fn new(min: Vec2<f32>, max: Vec2<f32>) -> Self {
220        AABB2D { min, max }
221    }
222
223    pub fn zero() -> Self {
224        AABB2D {
225            min: Vec2::new(f32::MAX, f32::MAX),
226            max: Vec2::new(f32::MIN, f32::MIN),
227        }
228    }
229
230    pub fn is_empty(&self) -> bool {
231        self.min.x > self.max.x || self.min.y > self.max.y
232    }
233
234    pub fn grow(&mut self, other: AABB2D) {
235        self.min.x = self.min.x.min(other.min.x);
236        self.min.y = self.min.y.min(other.min.y);
237        self.max.x = self.max.x.max(other.max.x);
238        self.max.y = self.max.y.max(other.max.y);
239    }
240
241    pub fn to_int(&self) -> (Vec2<i32>, Vec2<i32>) {
242        let min_int = Vec2::new(self.min.x.floor() as i32, self.min.y.floor() as i32);
243        let max_int = Vec2::new(self.max.x.ceil() as i32, self.max.y.ceil() as i32);
244        (min_int, max_int)
245    }
246
247    pub fn to_tiles(&self) -> Vec<Vec2<i32>> {
248        let (min_int, max_int) = self.to_int();
249        let mut tiles = Vec::new();
250
251        for x in min_int.x..=max_int.x {
252            for y in min_int.y..=max_int.y {
253                tiles.push(Vec2::new(x, y));
254            }
255        }
256
257        tiles
258    }
259}
260
261// https://www.geeksforgeeks.org/check-if-two-given-line-segments-intersect/
262pub fn do_intersect(p1: (i32, i32), q1: (i32, i32), p2: (i32, i32), q2: (i32, i32)) -> bool {
263    // Given three collinear points p, q, r, the function checks if
264    // point q lies on line segment 'pr'
265    fn on_segment(p: (i32, i32), q: (i32, i32), r: (i32, i32)) -> bool {
266        q.0 <= std::cmp::max(p.0, r.0)
267            && q.0 >= std::cmp::min(p.0, r.0)
268            && q.1 <= std::cmp::max(p.1, r.1)
269            && q.1 >= std::cmp::min(p.1, r.1)
270    }
271
272    // To find orientation of ordered triplet (p, q, r).
273    // The function returns following values
274    // 0 --> p, q and r are collinear
275    // 1 --> Clockwise
276    // 2 --> Counterclockwise
277    fn orientation(p: (i32, i32), q: (i32, i32), r: (i32, i32)) -> i32 {
278        let val = (q.1 - p.1) * (r.0 - q.0) - (q.0 - p.0) * (r.1 - q.1);
279        if val == 0 {
280            return 0;
281        } // collinear
282        if val > 0 { 1 } else { 2 } // clock or counterclock wise
283    }
284
285    // Check if line segments 'p1q1' and 'p2q2' intersect.
286    let o1 = orientation(p1, q1, p2);
287    let o2 = orientation(p1, q1, q2);
288    let o3 = orientation(p2, q2, p1);
289    let o4 = orientation(p2, q2, q1);
290
291    // General case
292    if o1 != o2 && o3 != o4 {
293        return true;
294    }
295
296    // Special Cases
297    // p1, q1 and p2 are collinear and p2 lies on segment p1q1
298    if o1 == 0 && on_segment(p1, p2, q1) {
299        return true;
300    }
301
302    // p1, q1 and q2 are collinear and q2 lies on segment p1q1
303    if o2 == 0 && on_segment(p1, q2, q1) {
304        return true;
305    }
306
307    // p2, q2 and p1 are collinear and p1 lies on segment p2q2
308    if o3 == 0 && on_segment(p2, p1, q2) {
309        return true;
310    }
311
312    // p2, q2 and q1 are collinear and q1 lies on segment p2q2
313    if o4 == 0 && on_segment(p2, q1, q2) {
314        return true;
315    }
316
317    // Doesn't fall in any of the above cases
318    false
319}
320
321#[derive(Serialize, Deserialize, Clone, Debug)]
322pub struct RenderTile {
323    pub x: usize,
324    pub y: usize,
325    pub width: usize,
326    pub height: usize,
327}
328
329impl RenderTile {
330    pub fn new(x: usize, y: usize, width: usize, height: usize) -> Self {
331        Self {
332            x,
333            y,
334            width,
335            height,
336        }
337    }
338
339    pub fn create_tiles(
340        image_width: usize,
341        image_height: usize,
342        tile_width: usize,
343        tile_height: usize,
344    ) -> Vec<Self> {
345        // TODO: Generate the tiles in a nice spiral pattern
346
347        let mut tiles = Vec::new();
348        let mut x = 0;
349        let mut y = 0;
350        while x < image_width && y < image_height {
351            let tile = Self {
352                x,
353                y,
354                width: tile_width,
355                height: tile_height,
356            };
357            tiles.push(tile);
358            x += tile_width;
359            if x >= image_width {
360                x = 0;
361                y += tile_height;
362            }
363        }
364
365        tiles
366    }
367}