xref: /StarryEngine/starry_client/src/base/renderer.rs (revision 731cae0674923fcc85c6e683a2eee596eb642796)
1 use std::{cell::Cell, cmp};
2 
3 use super::{
4     color::Color,
5     graphicspath::{GraphicsPath, PointType},
6 };
7 
8 static FONT_ASSET: &[u8] = include_bytes!("../font/unifont.font");
9 
10 /// 渲染模式: 混合/覆盖
11 #[derive(Clone, Copy, Debug)]
12 pub enum RenderMode {
13     /// 颜色混合
14     Blend,
15     /// 颜色覆盖
16     Overwrite,
17 }
18 
19 /// 可渲染对象需要实现的特性
20 pub trait Renderer {
21     /// 获取渲染窗口宽度
width(&self) -> u3222     fn width(&self) -> u32;
23 
24     /// 获取渲染窗口高度
height(&self) -> u3225     fn height(&self) -> u32;
26 
27     /// 获取帧缓冲数据
data(&self) -> &[Color]28     fn data(&self) -> &[Color];
29 
30     /// 获取可变帧缓存数据
data_mut(&mut self) -> &mut [Color]31     fn data_mut(&mut self) -> &mut [Color];
32 
33     /// 同步渲染数据
sync(&mut self) -> bool34     fn sync(&mut self) -> bool;
35 
36     /// 获取/设置渲染模式
mode(&self) -> &Cell<RenderMode>37     fn mode(&self) -> &Cell<RenderMode>;
38 
39     /// # 函数功能
40     /// 绘制指定位置的像素(左下角为原点)
41     ///
42     /// ## 参数
43     /// - x: 像素x坐标
44     /// - y: 像素y坐标
45     /// - color: 像素颜色值
pixel(&mut self, x: i32, y: i32, color: Color)46     fn pixel(&mut self, x: i32, y: i32, color: Color) {
47         let replace = match self.mode().get() {
48             RenderMode::Blend => false,
49             RenderMode::Overwrite => true,
50         };
51         let w = self.width();
52         let h = self.height();
53         let data = self.data_mut();
54 
55         if x >= 0 && y >= 0 && x < w as i32 && y < h as i32 {
56             let new_color = color.data;
57             let alpha = (new_color >> 24) & 0xFF;
58             let old_color = &mut data[y as usize * w as usize + x as usize].data;
59 
60             if alpha >= 255 || replace {
61                 *old_color = new_color;
62             }
63             // 颜色混合算法(效率更高的实现方法)
64             else if alpha > 0 {
65                 let n_alpha = 255 - alpha;
66                 let rb = ((n_alpha * (*old_color & 0x00FF00FF))
67                     + (alpha * (new_color & 0x00FF00FF)))
68                     >> 8;
69                 let ag = (n_alpha * ((*old_color & 0xFF00FF00) >> 8))
70                     + (alpha * (0x01000000 | ((new_color & 0x0000FF00) >> 8)));
71 
72                 *old_color = (rb & 0x00FF00FF) | (ag & 0xFF00FF00);
73             }
74         }
75     }
76 
77     /// # 函数功能
78     /// 在指定位置绘制字符
79     ///
80     /// ## 参数
81     /// - x: x坐标(局部坐标)
82     /// - y: y坐标(局部坐标)
83     /// - c: 待绘制的字符
84     /// - color: 字符颜色
char(&mut self, x: i32, y: i32, c: char, color: Color)85     fn char(&mut self, x: i32, y: i32, c: char, color: Color) {
86         let mut offset = (c as usize) * 16;
87         for row in 0..16 {
88             let row_data = if offset < FONT_ASSET.len() {
89                 FONT_ASSET[offset]
90             } else {
91                 0
92             };
93 
94             for col in 0..8 {
95                 let pixel = (row_data >> (7 - col)) & 1;
96                 if pixel > 0 {
97                     self.pixel(x + col, y + row, color);
98                 }
99             }
100             offset += 1;
101         }
102     }
103 
104     /// # 函数功能
105     /// 在指定位置绘制一幅图像至帧缓冲区
106     ///
107     /// ## 参数
108     /// - start_x: 起始x坐标(局部坐标)
109     /// - start_y: 起始y坐标(局部坐标)
110     /// - w: 图像宽度
111     /// - h: 图像高度
112     /// - data: 图像数据
image(&mut self, start_x: i32, start_y: i32, w: u32, h: u32, data: &[Color])113     fn image(&mut self, start_x: i32, start_y: i32, w: u32, h: u32, data: &[Color]) {
114         match self.mode().get() {
115             RenderMode::Blend => self.image_fast(start_x, start_y, w, h, data),
116             RenderMode::Overwrite => self.image_opaque(start_x, start_y, w, h, data),
117         }
118     }
119 
120     /// # 函数功能
121     /// 从指定行开始绘制一幅图像至帧缓冲区
122     ///
123     /// ## 参数
124     /// - start: 起始行数
125     /// - image_data: 图像帧缓冲数据
image_over(&mut self, start: i32, image_data: &[Color])126     fn image_over(&mut self, start: i32, image_data: &[Color]) {
127         let start = start as usize * self.width() as usize;
128         let window_data = self.data_mut();
129         let stop = cmp::min(start + image_data.len(), window_data.len());
130         let end = cmp::min(image_data.len(), window_data.len() - start);
131 
132         window_data[start..stop].copy_from_slice(&image_data[..end]);
133     }
134 
135     ///Display an image using non transparent method
136     /// TODO 注释补充
137     #[inline(always)]
image_opaque(&mut self, start_x: i32, start_y: i32, w: u32, h: u32, image_data: &[Color])138     fn image_opaque(&mut self, start_x: i32, start_y: i32, w: u32, h: u32, image_data: &[Color]) {
139         let w = w as usize;
140         let mut h = h as usize;
141         let width = self.width() as usize;
142         let height = self.height() as usize;
143         let start_x = start_x as usize;
144         let start_y = start_y as usize;
145 
146         //check boundaries
147         if start_x >= width || start_y >= height {
148             return;
149         }
150         if h + start_y > height {
151             h = height - start_y;
152         }
153         let window_data = self.data_mut();
154         let offset = start_y * width + start_x;
155         //copy image slices to window line by line
156         for l in 0..h {
157             let start = offset + l * width;
158             let mut stop = start + w;
159             let begin = l * w;
160             let mut end = begin + w;
161             //check boundaries
162             if start_x + w > width {
163                 stop = (start_y + l + 1) * width - 1;
164                 end = begin + stop - start;
165             }
166             window_data[start..stop].copy_from_slice(&image_data[begin..end]);
167         }
168     }
169 
170     /// Speed improved, image can be outside of window boundary
171     /// TODO 注释补充
172     #[inline(always)]
image_fast(&mut self, start_x: i32, start_y: i32, w: u32, h: u32, image_data: &[Color])173     fn image_fast(&mut self, start_x: i32, start_y: i32, w: u32, h: u32, image_data: &[Color]) {
174         let w = w as usize;
175         let h = h as usize;
176         let width = self.width() as usize;
177         let start_x = start_x as usize;
178         let start_y = start_y as usize;
179 
180         //simply return if image is outside of window
181         if start_x >= width || start_y >= self.height() as usize {
182             return;
183         }
184         let window_data = self.data_mut();
185         let offset = start_y * width + start_x;
186 
187         //copy image slices to window line by line
188         for l in 0..h {
189             let start = offset + l * width;
190             let mut stop = start + w;
191             let begin = l * w;
192             let end = begin + w;
193 
194             //check boundaries
195             if start_x + w > width {
196                 stop = (start_y + l + 1) * width;
197             }
198             let mut k = 0;
199             for i in begin..end {
200                 if i < image_data.len() {
201                     let new = image_data[i].data;
202                     let alpha = (new >> 24) & 0xFF;
203                     if alpha > 0 && (start + k) < window_data.len() && (start + k) < stop {
204                         let old = &mut window_data[start + k].data;
205                         if alpha >= 255 {
206                             *old = new;
207                         } else {
208                             let n_alpha = 255 - alpha;
209                             let rb = ((n_alpha * (*old & 0x00FF00FF))
210                                 + (alpha * (new & 0x00FF00FF)))
211                                 >> 8;
212                             let ag = (n_alpha * ((*old & 0xFF00FF00) >> 8))
213                                 + (alpha * (0x01000000 | ((new & 0x0000FF00) >> 8)));
214 
215                             *old = (rb & 0x00FF00FF) | (ag & 0xFF00FF00);
216                         }
217                     }
218                     k += 1;
219                 }
220             }
221         }
222     }
223     /// TODO 注释补充
arc(&mut self, x0: i32, y0: i32, radius: i32, parts: u8, color: Color)224     fn arc(&mut self, x0: i32, y0: i32, radius: i32, parts: u8, color: Color) {
225         let mut x = radius.abs();
226         let mut y = 0;
227         let mut err = 0;
228 
229         while x >= y {
230             if radius < 0 {
231                 if parts & 1 << 0 != 0 {
232                     self.rect(x0 - x, y0 + y, x as u32, 1, color);
233                 }
234                 if parts & 1 << 1 != 0 {
235                     self.rect(x0, y0 + y, x as u32 + 1, 1, color);
236                 }
237                 if parts & 1 << 2 != 0 {
238                     self.rect(x0 - y, y0 + x, y as u32, 1, color);
239                 }
240                 if parts & 1 << 3 != 0 {
241                     self.rect(x0, y0 + x, y as u32 + 1, 1, color);
242                 }
243                 if parts & 1 << 4 != 0 {
244                     self.rect(x0 - x, y0 - y, x as u32, 1, color);
245                 }
246                 if parts & 1 << 5 != 0 {
247                     self.rect(x0, y0 - y, x as u32 + 1, 1, color);
248                 }
249                 if parts & 1 << 6 != 0 {
250                     self.rect(x0 - y, y0 - x, y as u32, 1, color);
251                 }
252                 if parts & 1 << 7 != 0 {
253                     self.rect(x0, y0 - x, y as u32 + 1, 1, color);
254                 }
255             } else if radius == 0 {
256                 self.pixel(x0, y0, color);
257             } else {
258                 if parts & 1 << 0 != 0 {
259                     self.pixel(x0 - x, y0 + y, color);
260                 }
261                 if parts & 1 << 1 != 0 {
262                     self.pixel(x0 + x, y0 + y, color);
263                 }
264                 if parts & 1 << 2 != 0 {
265                     self.pixel(x0 - y, y0 + x, color);
266                 }
267                 if parts & 1 << 3 != 0 {
268                     self.pixel(x0 + y, y0 + x, color);
269                 }
270                 if parts & 1 << 4 != 0 {
271                     self.pixel(x0 - x, y0 - y, color);
272                 }
273                 if parts & 1 << 5 != 0 {
274                     self.pixel(x0 + x, y0 - y, color);
275                 }
276                 if parts & 1 << 6 != 0 {
277                     self.pixel(x0 - y, y0 - x, color);
278                 }
279                 if parts & 1 << 7 != 0 {
280                     self.pixel(x0 + y, y0 - x, color);
281                 }
282             }
283 
284             y += 1;
285             err += 1 + 2 * y;
286             if 2 * (err - x) + 1 > 0 {
287                 x -= 1;
288                 err += 1 - 2 * x;
289             }
290         }
291     }
292 
293     /// TODO 注释补充
circle(&mut self, x0: i32, y0: i32, radius: i32, color: Color)294     fn circle(&mut self, x0: i32, y0: i32, radius: i32, color: Color) {
295         let mut x = radius.abs();
296         let mut y = 0;
297         let mut err = -radius.abs();
298 
299         match radius {
300             radius if radius > 0 => {
301                 err = 0;
302                 while x >= y {
303                     self.pixel(x0 - x, y0 + y, color);
304                     self.pixel(x0 + x, y0 + y, color);
305                     self.pixel(x0 - y, y0 + x, color);
306                     self.pixel(x0 + y, y0 + x, color);
307                     self.pixel(x0 - x, y0 - y, color);
308                     self.pixel(x0 + x, y0 - y, color);
309                     self.pixel(x0 - y, y0 - x, color);
310                     self.pixel(x0 + y, y0 - x, color);
311 
312                     y += 1;
313                     err += 1 + 2 * y;
314                     if 2 * (err - x) + 1 > 0 {
315                         x -= 1;
316                         err += 1 - 2 * x;
317                     }
318                 }
319             }
320 
321             radius if radius < 0 => {
322                 while x >= y {
323                     let lasty = y;
324                     err += y;
325                     y += 1;
326                     err += y;
327                     self.line4points(x0, y0, x, lasty, color);
328                     if err >= 0 {
329                         if x != lasty {
330                             self.line4points(x0, y0, lasty, x, color);
331                         }
332                         err -= x;
333                         x -= 1;
334                         err -= x;
335                     }
336                 }
337             }
338             _ => {
339                 self.pixel(x0, y0, color);
340             }
341         }
342     }
343 
344     /// TODO 注释补充
line4points(&mut self, x0: i32, y0: i32, x: i32, y: i32, color: Color)345     fn line4points(&mut self, x0: i32, y0: i32, x: i32, y: i32, color: Color) {
346         //self.line(x0 - x, y0 + y, (x+x0), y0 + y, color);
347         self.rect(x0 - x, y0 + y, x as u32 * 2 + 1, 1, color);
348         if y != 0 {
349             //self.line(x0 - x, y0 - y, (x+x0), y0-y , color);
350             self.rect(x0 - x, y0 - y, x as u32 * 2 + 1, 1, color);
351         }
352     }
353 
354     /// # 函数功能
355     /// 绘制指定颜色的一条线段
356     ///
357     /// ## 参数
358     /// - argx1: 起点x坐标
359     /// - argy1: 起点y坐标
360     /// - argx2: 终点x坐标
361     /// - argy2: 终点y坐标
362     /// - color:绘制颜色
363     /// TODO
line(&mut self, argx1: i32, argy1: i32, argx2: i32, argy2: i32, color: Color)364     fn line(&mut self, argx1: i32, argy1: i32, argx2: i32, argy2: i32, color: Color) {
365         let mut x = argx1;
366         let mut y = argy1;
367 
368         let dx = if argx1 > argx2 {
369             argx1 - argx2
370         } else {
371             argx2 - argx1
372         };
373         let dy = if argy1 > argy2 {
374             argy1 - argy2
375         } else {
376             argy2 - argy1
377         };
378 
379         let sx = if argx1 < argx2 { 1 } else { -1 };
380         let sy = if argy1 < argy2 { 1 } else { -1 };
381 
382         let mut err = if dx > dy { dx } else { -dy } / 2;
383         let mut err_tolerance;
384 
385         loop {
386             self.pixel(x, y, color);
387 
388             if x == argx2 && y == argy2 {
389                 break;
390             };
391 
392             err_tolerance = 2 * err;
393 
394             if err_tolerance > -dx {
395                 err -= dy;
396                 x += sx;
397             }
398             if err_tolerance < dy {
399                 err += dx;
400                 y += sy;
401             }
402         }
403     }
404 
405     /// # 函数功能
406     /// 绘制指定颜色的若干线段(首尾相连)
407     ///
408     /// ## 参数
409     /// - points: 点集合
410     /// - color: 绘制颜色
lines(&mut self, points: &[[i32; 2]], color: Color)411     fn lines(&mut self, points: &[[i32; 2]], color: Color) {
412         if points.is_empty() {
413         } else if points.len() == 1 {
414             self.pixel(points[0][0], points[0][1], color);
415         } else {
416             for i in 0..points.len() - 1 {
417                 self.line(
418                     points[i][0],
419                     points[i][1],
420                     points[i + 1][0],
421                     points[i + 1][1],
422                     color,
423                 );
424             }
425         }
426     }
427 
428     /// # 函数功能
429     /// 绘制一条指定颜色的几何路径
430     ///
431     /// ## 参数
432     /// - graphicspath: 几何路径
433     /// - color: 绘制颜色
draw_path(&mut self, graphicspath: GraphicsPath, color: Color)434     fn draw_path(&mut self, graphicspath: GraphicsPath, color: Color) {
435         let mut x: i32 = 0;
436         let mut y: i32 = 0;
437 
438         for point in graphicspath.points {
439             if let PointType::Connect = point.2 {
440                 self.line(x, y, point.0, point.1, color);
441             }
442             x = point.0;
443             y = point.1;
444         }
445     }
446 
447     /// # 函数功能
448     /// 绘制单一颜色的矩形
449     ///
450     /// ## 参数
451     /// - x: 起始x坐标
452     /// - y: 起始y坐标
453     /// - w: 矩形宽度
454     /// - h: 矩形高度
455     /// - color: 矩形颜色
rect(&mut self, x: i32, y: i32, w: u32, h: u32, color: Color)456     fn rect(&mut self, x: i32, y: i32, w: u32, h: u32, color: Color) {
457         let replace = match self.mode().get() {
458             RenderMode::Blend => false,
459             RenderMode::Overwrite => true,
460         };
461         let self_w = self.width();
462         let self_h = self.height();
463 
464         let start_y = cmp::max(0, cmp::min(self_h as i32 - 1, y));
465         let end_y = cmp::max(start_y, cmp::min(self_h as i32, y + h as i32));
466 
467         let start_x = cmp::max(0, cmp::min(self_w as i32 - 1, x));
468         let end_x = cmp::max(start_x, cmp::min(self_w as i32, x + w as i32));
469         let len_x = end_x - start_x;
470 
471         let alpha = (color.data >> 24) & 0xFF;
472 
473         if alpha >= 255 || replace {
474             let data = self.data_mut();
475             let data_ptr = data.as_mut_ptr();
476             for y in start_y..end_y {
477                 let start = (y * self_w as i32 + start_x) as isize;
478                 let end = start + len_x as isize;
479                 for i in start..end {
480                     unsafe {
481                         *data_ptr.offset(i) = color;
482                     }
483                 }
484             }
485         } else {
486             for y in start_y..end_y {
487                 for x in start_x..end_x {
488                     self.pixel(x, y, color);
489                 }
490             }
491         }
492     }
493 
494     /// # 函数功能
495     /// 将整个窗口填充单一颜色
496     ///
497     /// ## 参数
498     /// - color: 窗口颜色
set(&mut self, color: Color)499     fn set(&mut self, color: Color) {
500         let data = self.data_mut();
501         let data_ptr = data.as_mut_ptr();
502         for i in 0..data.len() as isize {
503             unsafe {
504                 *data_ptr.offset(i) = color;
505             }
506         }
507     }
508 
509     /// # 函数功能
510     /// 将整个窗口置黑
clear(&mut self)511     fn clear(&mut self) {
512         self.set(Color::rgb(0, 0, 0));
513     }
514 
515     /// # 函数功能
516     /// 获取指定坐标的像素颜色
517     ///
518     /// ## 参数
519     /// - x: x坐标
520     /// - y: y坐标
521     ///
522     /// ## 返回值
523     /// 像素颜色
get_pixel(&self, x: i32, y: i32) -> Color524     fn get_pixel(&self, x: i32, y: i32) -> Color {
525         let p = (self.width() as i32 * y + x) as usize;
526         if p >= self.data().len() {
527             println!("[Error] Client window get pixel overflow!");
528             return Color::rgb(0, 0, 0);
529         }
530         return self.data()[p];
531     }
532 }
533