xref: /StarryEngine/starry_client/src/window.rs (revision 1bee64b64bc410ee78964a11a40a0fff69945480)
1 use std::{
2     cell::Cell,
3     cmp::min,
4     fs::File,
5     io::{Seek, SeekFrom, Write},
6 };
7 
8 use crate::base::{
9     color::Color,
10     renderer::{RenderMode, Renderer},
11 };
12 
13 // TODO: 读帧缓冲设备属性
14 /// 屏幕宽度
15 const SCREEN_WIDTH: usize = 1440;
16 /// 屏幕高度
17 #[allow(dead_code)]
18 const SCREEN_HEIGHT: usize = 900;
19 
20 const FB_FILE_PATH: &str = "/dev/fb0";
21 
22 /// 客户端的窗口类,与服务端的窗口对象一一对应
23 /// 一般来说客户端应用程序不直接使用该类,而通过Toolkit库间接使用
24 #[allow(dead_code)]
25 pub struct Window {
26     /// 窗口左上角的x坐标
27     x: i32,
28     /// 窗口左上角的y坐标
29     y: i32,
30     /// 窗口的宽度
31     w: u32,
32     /// 窗口的高度
33     h: u32,
34     /// 窗口的标题
35     title: String,
36     /// TODO
37     // window_async: bool,
38     /// 窗口是否大小可变
39     resizable: bool,
40     /// 窗口的渲染模式
41     mode: Cell<RenderMode>,
42     // TODO
43     // file_opt: Option<File>,
44     // TODO: 改定长数组
45     // data_opt: Option<& 'static mut [Color]>,
46     /// 窗口的渲染数据
47     data_opt: Option<Box<[Color]>>,
48     /// 帧缓冲文件
49     fb_file: File,
50 }
51 
52 impl Renderer for Window {
53     fn width(&self) -> u32 {
54         self.w
55     }
56 
57     fn height(&self) -> u32 {
58         self.h
59     }
60 
61     fn data(&self) -> &[Color] {
62         self.data_opt.as_ref().unwrap()
63     }
64 
65     fn data_mut(&mut self) -> &mut [Color] {
66         self.data_opt.as_mut().unwrap()
67     }
68 
69     fn sync(&mut self) -> bool {
70         // 处理窗口大小超限的情况
71         let width = min(self.width() as i32, SCREEN_WIDTH as i32 - self.x);
72         let height = min(self.height() as i32, SCREEN_HEIGHT as i32 - self.y);
73 
74         for y in 0..height as i32 {
75             for x in 0..width as i32 {
76                 let pixel = self.get_pixel(x, y);
77                 let offset = (((y + self.y()) * SCREEN_WIDTH as i32) + x + self.x()) * 4;
78                 // 写缓冲区
79                 self.fb_file
80                     .seek(SeekFrom::Start(offset as u64))
81                     .expect("Unable to seek framebuffer");
82                 self.fb_file
83                     .write_all(&pixel.to_bgra_bytes())
84                     .expect("Unable to write framebuffer");
85             }
86         }
87         true
88     }
89 
90     fn mode(&self) -> &Cell<RenderMode> {
91         &self.mode
92     }
93 }
94 
95 #[allow(dead_code)]
96 impl Window {
97     /// TODO: 接收flags
98     pub fn new(x: i32, y: i32, w: u32, h: u32, title: &str, color: Color) -> Self {
99         Window {
100             x: x,
101             y: y,
102             w: w,
103             h: h,
104             title: title.to_string(),
105             // window_async: false,
106             resizable: false,
107             mode: Cell::new(RenderMode::Blend),
108             // file_opt: None,
109             data_opt: Some(vec![color; (w * h) as usize].into_boxed_slice()),
110             fb_file: File::open(FB_FILE_PATH).expect("[Error] Window failed to open fb file"),
111         }
112 
113         // TODO: 与服务器通信
114     }
115 
116     /// 返回窗口x坐标
117     pub fn x(&self) -> i32 {
118         self.x
119     }
120 
121     /// 返回窗口y坐标
122     pub fn y(&self) -> i32 {
123         self.y
124     }
125 
126     /// 返回窗口标题
127     pub fn title(&self) -> String {
128         self.title.clone()
129     }
130 
131     /// 改变窗口的位置
132     pub fn set_pos(&mut self, x: i32, y: i32) {
133         self.x = x;
134         self.y = y;
135     }
136 
137     /// 改变窗口的大小
138     pub fn set_size(&mut self, width: u32, height: u32) {
139         self.w = width;
140         self.h = height;
141     }
142 
143     /// 改变窗口标题
144     pub fn set_title(&mut self, title: &str) {
145         self.title = title.to_string();
146     }
147 }
148