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