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 #[derive(Clone, Copy, Debug)] 11 pub enum RenderMode { 12 /// 颜色混合 13 Blend, 14 /// 颜色覆盖 15 Overwrite, 16 } 17 18 /// 用于进行渲染 19 pub trait Renderer { 20 /// 获取渲染窗口宽度 21 fn width(&self) -> u32; 22 23 /// 获取渲染窗口高度 24 fn height(&self) -> u32; 25 26 /// 获取帧缓冲数据 27 fn data(&self) -> &[Color]; 28 29 /// 获取可变帧缓存数据 30 fn data_mut(&mut self) -> &mut [Color]; 31 32 /// 同步数据 33 fn sync(&mut self) -> bool; 34 35 /// 获取/设置渲染模式 36 fn mode(&self) -> &Cell<RenderMode>; 37 38 /// # 函数功能 39 /// 绘制指定位置的像素(左下角为原点) 40 /// 41 /// ## 参数 42 /// - x: 像素x坐标 43 /// - y: 像素y坐标 44 /// - color: 像素颜色值 45 fn pixel(&mut self, x: i32, y: i32, color: Color) { 46 let replace = match self.mode().get() { 47 RenderMode::Blend => false, 48 RenderMode::Overwrite => true, 49 }; 50 let w = self.width(); 51 let h = self.height(); 52 let data = self.data_mut(); 53 54 if x >= 0 && y >= 0 && x < w as i32 && y < h as i32 { 55 let new_color = color.data; 56 let alpha = (new_color >> 24) & 0xFF; 57 let old_color = &mut data[y as usize * w as usize + x as usize].data; 58 59 if alpha >= 255 || replace { 60 *old_color = new_color; 61 } 62 // 颜色混合算法(效率更高的实现方法) 63 else if alpha > 0 { 64 let n_alpha = 255 - alpha; 65 let rb = ((n_alpha * (*old_color & 0x00FF00FF)) 66 + (alpha * (new_color & 0x00FF00FF))) 67 >> 8; 68 let ag = (n_alpha * ((*old_color & 0xFF00FF00) >> 8)) 69 + (alpha * (0x01000000 | ((new_color & 0x0000FF00) >> 8))); 70 71 *old_color = (rb & 0x00FF00FF) | (ag & 0xFF00FF00); 72 } 73 } 74 } 75 76 /// TODO 注释补充 77 fn arc(&mut self, x0: i32, y0: i32, radius: i32, parts: u8, color: Color) { 78 let mut x = radius.abs(); 79 let mut y = 0; 80 let mut err = 0; 81 82 // https://github.com/rust-lang/rust-clippy/issues/5354 83 while x >= y { 84 if radius < 0 { 85 if parts & 1 << 0 != 0 { 86 self.rect(x0 - x, y0 + y, x as u32, 1, color); 87 } 88 if parts & 1 << 1 != 0 { 89 self.rect(x0, y0 + y, x as u32 + 1, 1, color); 90 } 91 if parts & 1 << 2 != 0 { 92 self.rect(x0 - y, y0 + x, y as u32, 1, color); 93 } 94 if parts & 1 << 3 != 0 { 95 self.rect(x0, y0 + x, y as u32 + 1, 1, color); 96 } 97 if parts & 1 << 4 != 0 { 98 self.rect(x0 - x, y0 - y, x as u32, 1, color); 99 } 100 if parts & 1 << 5 != 0 { 101 self.rect(x0, y0 - y, x as u32 + 1, 1, color); 102 } 103 if parts & 1 << 6 != 0 { 104 self.rect(x0 - y, y0 - x, y as u32, 1, color); 105 } 106 if parts & 1 << 7 != 0 { 107 self.rect(x0, y0 - x, y as u32 + 1, 1, color); 108 } 109 } else if radius == 0 { 110 self.pixel(x0, y0, color); 111 } else { 112 if parts & 1 << 0 != 0 { 113 self.pixel(x0 - x, y0 + y, color); 114 } 115 if parts & 1 << 1 != 0 { 116 self.pixel(x0 + x, y0 + y, color); 117 } 118 if parts & 1 << 2 != 0 { 119 self.pixel(x0 - y, y0 + x, color); 120 } 121 if parts & 1 << 3 != 0 { 122 self.pixel(x0 + y, y0 + x, color); 123 } 124 if parts & 1 << 4 != 0 { 125 self.pixel(x0 - x, y0 - y, color); 126 } 127 if parts & 1 << 5 != 0 { 128 self.pixel(x0 + x, y0 - y, color); 129 } 130 if parts & 1 << 6 != 0 { 131 self.pixel(x0 - y, y0 - x, color); 132 } 133 if parts & 1 << 7 != 0 { 134 self.pixel(x0 + y, y0 - x, color); 135 } 136 } 137 138 y += 1; 139 err += 1 + 2 * y; 140 if 2 * (err - x) + 1 > 0 { 141 x -= 1; 142 err += 1 - 2 * x; 143 } 144 } 145 } 146 147 /// TODO 注释补充 148 fn circle(&mut self, x0: i32, y0: i32, radius: i32, color: Color) { 149 let mut x = radius.abs(); 150 let mut y = 0; 151 let mut err = -radius.abs(); 152 153 match radius { 154 radius if radius > 0 => { 155 err = 0; 156 while x >= y { 157 self.pixel(x0 - x, y0 + y, color); 158 self.pixel(x0 + x, y0 + y, color); 159 self.pixel(x0 - y, y0 + x, color); 160 self.pixel(x0 + y, y0 + x, color); 161 self.pixel(x0 - x, y0 - y, color); 162 self.pixel(x0 + x, y0 - y, color); 163 self.pixel(x0 - y, y0 - x, color); 164 self.pixel(x0 + y, y0 - x, color); 165 166 y += 1; 167 err += 1 + 2 * y; 168 if 2 * (err - x) + 1 > 0 { 169 x -= 1; 170 err += 1 - 2 * x; 171 } 172 } 173 } 174 175 radius if radius < 0 => { 176 while x >= y { 177 let lasty = y; 178 err += y; 179 y += 1; 180 err += y; 181 self.line4points(x0, y0, x, lasty, color); 182 if err >= 0 { 183 if x != lasty { 184 self.line4points(x0, y0, lasty, x, color); 185 } 186 err -= x; 187 x -= 1; 188 err -= x; 189 } 190 } 191 } 192 _ => { 193 self.pixel(x0, y0, color); 194 } 195 } 196 } 197 198 /// TODO 注释补充 199 fn line4points(&mut self, x0: i32, y0: i32, x: i32, y: i32, color: Color) { 200 //self.line(x0 - x, y0 + y, (x+x0), y0 + y, color); 201 self.rect(x0 - x, y0 + y, x as u32 * 2 + 1, 1, color); 202 if y != 0 { 203 //self.line(x0 - x, y0 - y, (x+x0), y0-y , color); 204 self.rect(x0 - x, y0 - y, x as u32 * 2 + 1, 1, color); 205 } 206 } 207 208 /// # 函数功能 209 /// 绘制指定颜色的一条线段 210 /// 211 /// ## 参数 212 /// - argx1: 起点x坐标 213 /// - argy1: 起点y坐标 214 /// - argx2: 终点x坐标 215 /// - argy2: 终点y坐标 216 /// - color:绘制颜色 217 /// TODO 218 fn line(&mut self, argx1: i32, argy1: i32, argx2: i32, argy2: i32, color: Color) { 219 let mut x = argx1; 220 let mut y = argy1; 221 222 let dx = if argx1 > argx2 { 223 argx1 - argx2 224 } else { 225 argx2 - argx1 226 }; 227 let dy = if argy1 > argy2 { 228 argy1 - argy2 229 } else { 230 argy2 - argy1 231 }; 232 233 let sx = if argx1 < argx2 { 1 } else { -1 }; 234 let sy = if argy1 < argy2 { 1 } else { -1 }; 235 236 let mut err = if dx > dy { dx } else { -dy } / 2; 237 let mut err_tolerance; 238 239 loop { 240 self.pixel(x, y, color); 241 242 if x == argx2 && y == argy2 { 243 break; 244 }; 245 246 err_tolerance = 2 * err; 247 248 if err_tolerance > -dx { 249 err -= dy; 250 x += sx; 251 } 252 if err_tolerance < dy { 253 err += dx; 254 y += sy; 255 } 256 } 257 } 258 259 /// # 函数功能 260 /// 绘制指定颜色的若干线段(首尾相连) 261 /// 262 /// ## 参数 263 /// - points: 点集合 264 /// - color: 绘制颜色 265 fn lines(&mut self, points: &[[i32; 2]], color: Color) { 266 if points.is_empty() { 267 } else if points.len() == 1 { 268 self.pixel(points[0][0], points[0][1], color); 269 } else { 270 for i in 0..points.len() - 1 { 271 self.line( 272 points[i][0], 273 points[i][1], 274 points[i + 1][0], 275 points[i + 1][1], 276 color, 277 ); 278 } 279 } 280 } 281 282 /// # 函数功能 283 /// 绘制一条指定颜色的几何路径 284 /// 285 /// ## 参数 286 /// - graphicspath: 几何路径 287 /// - color: 绘制颜色 288 fn draw_path(&mut self, graphicspath: GraphicsPath, color: Color) { 289 let mut x: i32 = 0; 290 let mut y: i32 = 0; 291 292 for point in graphicspath.points { 293 if let PointType::Connect = point.2 { 294 self.line(x, y, point.0, point.1, color); 295 } 296 x = point.0; 297 y = point.1; 298 } 299 } 300 301 /// # 函数功能 302 /// 绘制单一颜色的矩形 303 /// 304 /// ## 参数 305 /// - x: 起始x坐标 306 /// - y: 起始y坐标 307 /// - w: 矩形宽度 308 /// - h: 矩形高度 309 /// - color: 矩形颜色 310 fn rect(&mut self, x: i32, y: i32, w: u32, h: u32, color: Color) { 311 let replace = match self.mode().get() { 312 RenderMode::Blend => false, 313 RenderMode::Overwrite => true, 314 }; 315 let self_w = self.width(); 316 let self_h = self.height(); 317 318 let start_y = cmp::max(0, cmp::min(self_h as i32 - 1, y)); 319 let end_y = cmp::max(start_y, cmp::min(self_h as i32, y + h as i32)); 320 321 let start_x = cmp::max(0, cmp::min(self_w as i32 - 1, x)); 322 let end_x = cmp::max(start_x, cmp::min(self_w as i32, x + w as i32)); 323 let len_x = end_x - start_x; 324 325 let alpha = (color.data >> 24) & 0xFF; 326 327 if alpha >= 255 || replace { 328 let data = self.data_mut(); 329 let data_ptr = data.as_mut_ptr(); 330 for y in start_y..end_y { 331 let start = (y * self_w as i32 + start_x) as isize; 332 let end = start + len_x as isize; 333 for i in start..end { 334 unsafe { 335 *data_ptr.offset(i) = color; 336 } 337 } 338 } 339 } else { 340 for y in start_y..end_y { 341 for x in start_x..end_x { 342 self.pixel(x, y, color); 343 } 344 } 345 } 346 } 347 348 /// # 函数功能 349 /// 将整个窗口填充单一颜色 350 /// 351 /// ## 参数 352 /// - color: 窗口颜色 353 fn set(&mut self, color: Color) { 354 let data = self.data_mut(); 355 let data_ptr = data.as_mut_ptr(); 356 for i in 0..data.len() as isize { 357 unsafe { 358 *data_ptr.offset(i) = color; 359 } 360 } 361 } 362 363 /// # 函数功能 364 /// 将整个窗口置黑 365 fn clear(&mut self) { 366 self.set(Color::rgb(0, 0, 0)); 367 } 368 369 /// # 函数功能 370 /// 获取指定坐标的像素颜色 371 /// 372 /// ## 参数 373 /// - x: x坐标 374 /// - y: y坐标 375 /// 376 /// ## 返回值 377 /// 像素颜色 378 fn get_pixel(&self, x: i32, y: i32) -> Color { 379 let p = (self.width() as i32 * y + x) as usize; 380 if p >= self.data().len() { 381 println!("[Error] Client window get pixel overflow!"); 382 return Color::rgb(0, 0, 0); 383 } 384 return self.data()[p]; 385 } 386 387 /// # 函数功能 388 /// 在指定位置绘制字符 389 /// 390 /// ## 参数 391 /// - x: x坐标 392 /// - y: y坐标 393 /// - c: 待绘制的字符 394 /// - color: 字符颜色 395 fn char(&mut self, x: i32, y: i32, c: char, color: Color) { 396 let mut offset = (c as usize) * 16; 397 for row in 0..16 { 398 let row_data = if offset < FONT_ASSET.len() { 399 FONT_ASSET[offset] 400 } else { 401 0 402 }; 403 404 for col in 0..8 { 405 let pixel = (row_data >> (7 - col)) & 1; 406 if pixel > 0 { 407 self.pixel(x + col, y + row, color); 408 } 409 } 410 offset += 1; 411 } 412 } 413 414 /// # 函数功能 415 /// 在指定位置绘制一幅图像至帧缓冲区 416 /// 417 /// ## 参数 418 /// - start_x: 起始x坐标(左上角) 419 /// - start_y: 起始y坐标(左上角) 420 /// - w: 图像宽度 421 /// - h: 图像高度 422 /// - data: 图像数据 423 fn image(&mut self, start_x: i32, start_y: i32, w: u32, h: u32, data: &[Color]) { 424 match self.mode().get() { 425 RenderMode::Blend => self.image_fast(start_x, start_y, w, h, data), 426 RenderMode::Overwrite => self.image_opaque(start_x, start_y, w, h, data), 427 } 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 } 536