Skip to main content

eldiron_shared/
lib.rs

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