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