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