Compare commits
3 commits
06596a0f76
...
20325e6a75
Author | SHA1 | Date | |
---|---|---|---|
|
20325e6a75 | ||
|
9f4a8f03df | ||
|
c11bfdcc00 |
3 changed files with 238 additions and 128 deletions
142
src/main.rs
142
src/main.rs
|
@ -15,6 +15,8 @@ use point::*;
|
||||||
mod model;
|
mod model;
|
||||||
use model::*;
|
use model::*;
|
||||||
|
|
||||||
|
const BLACK: TGAColor = TGAColor { bgra: [0u8; 4] };
|
||||||
|
|
||||||
const WHITE: TGAColor = TGAColor {
|
const WHITE: TGAColor = TGAColor {
|
||||||
bgra: [255, 255, 255, 255],
|
bgra: [255, 255, 255, 255],
|
||||||
};
|
};
|
||||||
|
@ -36,44 +38,18 @@ const YELLOW: TGAColor = TGAColor {
|
||||||
};
|
};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let w = 800;
|
let w = 640;
|
||||||
let h = 800;
|
let h = 640;
|
||||||
let mut fb = TGAImage::new(w, h, TGAFormat::RGB);
|
let mut fb = TGAImage::new(w, h, TGAFormat::RGB);
|
||||||
|
|
||||||
render_head(&mut fb);
|
let a = Point2i::new(170, 40).with_color(BLUE);
|
||||||
}
|
let b = Point2i::new(550, 390).with_color(GREEN);
|
||||||
|
let c = Point2i::new(230, 590).with_color(RED);
|
||||||
|
|
||||||
fn _render_diablo(fb: &mut TGAImage) {
|
let t = Triangle2i::new(a, b, c);
|
||||||
let model = Model::from_obj("diablo3_pose.obj");
|
t.render_lines(20, BLACK, &mut fb);
|
||||||
model.render_wireframe(fb);
|
|
||||||
fb.write_file("diablo.tga", true, true).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn render_head(fb: &mut TGAImage) {
|
fb.write_file("triangle.tga", true).unwrap();
|
||||||
let model = Model::from_obj("head.obj");
|
|
||||||
model.render_triangles(fb);
|
|
||||||
fb.write_file("head.tga", true, true).unwrap();
|
|
||||||
}
|
|
||||||
fn _baseline(framebuffer: &mut TGAImage) {
|
|
||||||
let ax = 7;
|
|
||||||
let ay = 3;
|
|
||||||
let bx = 12;
|
|
||||||
let by = 37;
|
|
||||||
let cx = 62;
|
|
||||||
let cy = 53;
|
|
||||||
|
|
||||||
framebuffer.set(ax, ay, WHITE);
|
|
||||||
framebuffer.set(bx, by, WHITE);
|
|
||||||
framebuffer.set(cx, cy, WHITE);
|
|
||||||
|
|
||||||
let a = Point2i::newu(ax, ay);
|
|
||||||
let b = Point2i::newu(bx, by);
|
|
||||||
let c = Point2i::newu(cx, cy);
|
|
||||||
|
|
||||||
line(a, b, BLUE, framebuffer);
|
|
||||||
line(c, b, GREEN, framebuffer);
|
|
||||||
line(c, a, YELLOW, framebuffer);
|
|
||||||
line(a, c, RED, framebuffer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn line(mut a: Point2i, mut b: Point2i, color: TGAColor, mut fb: &mut TGAImage) {
|
fn line(mut a: Point2i, mut b: Point2i, color: TGAColor, mut fb: &mut TGAImage) {
|
||||||
|
@ -137,28 +113,96 @@ impl Triangle2i {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let it = 1.0 / total_area;
|
let it = 1.0 / total_area;
|
||||||
(bb.ymin()..=bb.ymax()).into_par_iter().for_each(|y| {
|
(bb.xmin()..=bb.xmax()).into_par_iter().for_each(|x| {
|
||||||
(bb.xmin()..bb.xmax()).into_par_iter().for_each(|x| {
|
(bb.ymin()..=bb.ymax()).into_par_iter().for_each(|y| {
|
||||||
let p = Point2i::new(x, y);
|
let p = Point2i::new(x, y);
|
||||||
let a = Triangle2i::new(p, self.a, self.b).signed_area() * it;
|
let alpha = Triangle2i::new(p, self.b, self.c).signed_area() * it;
|
||||||
let b = Triangle2i::new(p, self.b, self.c).signed_area() * it;
|
let beta = Triangle2i::new(p, self.c, self.a).signed_area() * it;
|
||||||
let c = Triangle2i::new(p, self.c, self.a).signed_area() * it;
|
let gamma = Triangle2i::new(p, self.a, self.b).signed_area() * it;
|
||||||
|
|
||||||
if a.is_sign_positive()
|
if alpha.is_sign_positive() && beta.is_sign_positive() && gamma.is_sign_positive() {
|
||||||
&& b.is_sign_positive()
|
let color = if let Some(ca) = self.a.color
|
||||||
&& c.is_sign_positive()
|
&& let Some(cb) = self.b.color
|
||||||
&& let Ok(mut fb) = fb.lock()
|
&& let Some(cc) = self.c.color
|
||||||
{
|
{
|
||||||
fb.set(x as u32, y as u32, color);
|
color + (ca * alpha) + (cb * beta) + (cc * gamma)
|
||||||
|
} else {
|
||||||
|
color
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Ok(mut fb) = fb.lock() {
|
||||||
|
fb.set(x as u32, y as u32, color);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn render_lines(&self, thickness: i32, color: TGAColor, fb: &mut TGAImage) {
|
||||||
|
let fb = Arc::new(Mutex::new(fb));
|
||||||
|
let bb = self.bb();
|
||||||
|
let total_area = self.signed_area();
|
||||||
|
if total_area < 1.0 {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let it = 1.0 / total_area;
|
||||||
|
(bb.xmin()..=bb.xmax()).into_par_iter().for_each(|x| {
|
||||||
|
(bb.ymin()..=bb.ymax()).into_par_iter().for_each(|y| {
|
||||||
|
let p = Point2i::new(x, y);
|
||||||
|
let alpha = Triangle2i::new(p, self.b, self.c).signed_area() * it;
|
||||||
|
let beta = Triangle2i::new(p, self.c, self.a).signed_area() * it;
|
||||||
|
let gamma = Triangle2i::new(p, self.a, self.b).signed_area() * it;
|
||||||
|
|
||||||
|
if alpha.is_sign_positive() && beta.is_sign_positive() && gamma.is_sign_positive() {
|
||||||
|
let ad = ((self.b.y - self.a.y) * x - (self.b.x - self.a.x) * y
|
||||||
|
+ self.b.x * self.a.y
|
||||||
|
- self.b.y * self.a.x)
|
||||||
|
.abs()
|
||||||
|
/ ((self.b.y - self.a.y).pow(2) + (self.b.x - self.a.x).pow(2)).isqrt();
|
||||||
|
let bd = ((self.c.y - self.b.y) * x - (self.c.x - self.b.x) * y
|
||||||
|
+ self.c.x * self.b.y
|
||||||
|
- self.c.y * self.b.x)
|
||||||
|
.abs()
|
||||||
|
/ ((self.c.y - self.b.y).pow(2) + (self.c.x - self.b.x).pow(2)).isqrt();
|
||||||
|
let cd = ((self.a.y - self.c.y) * x - (self.a.x - self.c.x) * y
|
||||||
|
+ self.a.x * self.c.y
|
||||||
|
- self.a.y * self.c.x)
|
||||||
|
.abs()
|
||||||
|
/ ((self.a.y - self.c.y).pow(2) + (self.a.x - self.c.x).pow(2)).isqrt();
|
||||||
|
|
||||||
|
if ad <= thickness || bd <= thickness || cd <= thickness {
|
||||||
|
let color = if let Some(ca) = self.a.color
|
||||||
|
&& let Some(cb) = self.b.color
|
||||||
|
&& let Some(cc) = self.c.color
|
||||||
|
{
|
||||||
|
color + (ca * alpha) + (cb * beta) + (cc * gamma)
|
||||||
|
} else {
|
||||||
|
color
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Ok(mut fb) = fb.lock() {
|
||||||
|
fb.set(x as u32, y as u32, color);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn render_lines(&self, color: TGAColor, fb: &mut TGAImage) {
|
pub fn centroid(&self) -> Point2i {
|
||||||
line(self.a, self.b, color, fb);
|
let x = self.a.x / 3 + self.b.x / 3 + self.c.x / 3;
|
||||||
line(self.b, self.c, color, fb);
|
let y = self.a.y / 3 + self.b.y / 3 + self.c.y / 3;
|
||||||
line(self.c, self.a, color, fb);
|
let has_color = self.a.color.is_some() || self.b.color.is_some() || self.c.color.is_some();
|
||||||
|
let denom = 1.0 / 3.0;
|
||||||
|
let color = if has_color {
|
||||||
|
let c = self.a.color.unwrap_or(BLACK) * denom
|
||||||
|
+ self.b.color.unwrap_or(BLACK) * denom
|
||||||
|
+ self.c.color.unwrap_or(BLACK) * denom;
|
||||||
|
Some(c)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
Point2i { x, y, color }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
57
src/point.rs
57
src/point.rs
|
@ -1,33 +1,60 @@
|
||||||
use std::ops::{Add, Deref, DerefMut, Div, Mul, Sub};
|
use std::{
|
||||||
|
ops::{Add, Deref, DerefMut, Div, Mul, Sub},
|
||||||
|
sync::{Arc, Mutex},
|
||||||
|
};
|
||||||
|
|
||||||
use crate::tga::TGAColor;
|
use rayon::iter::{IntoParallelIterator, ParallelIterator};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
YELLOW,
|
||||||
|
tga::{TGAColor, TGAImage},
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Default, Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(Default, Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
pub struct Point2i {
|
pub struct Point2i {
|
||||||
pub x: i32,
|
pub x: i32,
|
||||||
pub y: i32,
|
pub y: i32,
|
||||||
pub c: Option<TGAColor>,
|
pub color: Option<TGAColor>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Point2i {
|
impl Point2i {
|
||||||
pub fn new(x: i32, y: i32) -> Self {
|
pub fn new(x: i32, y: i32) -> Self {
|
||||||
Self { x, y, c: None }
|
Self { x, y, color: None }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn newu(x: u32, y: u32) -> Self {
|
pub fn newu(x: u32, y: u32) -> Self {
|
||||||
Self {
|
Self {
|
||||||
x: x as i32,
|
x: x as i32,
|
||||||
y: y as i32,
|
y: y as i32,
|
||||||
c: None,
|
color: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_color(self, color: TGAColor) -> Self {
|
pub fn with_color(self, color: TGAColor) -> Self {
|
||||||
Self {
|
Self {
|
||||||
c: Some(color),
|
color: Some(color),
|
||||||
..self
|
..self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn render(&self, radius: i32, fb: &mut TGAImage) {
|
||||||
|
let xmin = self.x - radius;
|
||||||
|
let xmax = self.x + radius;
|
||||||
|
let ymin = self.y - radius;
|
||||||
|
let ymax = self.y + radius;
|
||||||
|
let r2 = radius.pow(2);
|
||||||
|
let fb = Arc::new(Mutex::new(fb));
|
||||||
|
(ymin..=ymax).into_par_iter().for_each(|y| {
|
||||||
|
(xmin..=xmax).into_par_iter().for_each(|x| {
|
||||||
|
let d2 = (x - self.x).pow(2) + (y - self.y).pow(2);
|
||||||
|
if d2 <= r2
|
||||||
|
&& let Ok(mut fb) = fb.lock()
|
||||||
|
{
|
||||||
|
fb.set(x as u32, y as u32, self.color.unwrap_or(YELLOW));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Add for Point2i {
|
impl Add for Point2i {
|
||||||
|
@ -37,7 +64,12 @@ impl Add for Point2i {
|
||||||
Self {
|
Self {
|
||||||
x: self.x + rhs.x,
|
x: self.x + rhs.x,
|
||||||
y: self.y + rhs.y,
|
y: self.y + rhs.y,
|
||||||
c: None,
|
color: if self.color.is_none() {
|
||||||
|
rhs.color
|
||||||
|
} else {
|
||||||
|
self.color
|
||||||
|
.map(|c| if let Some(oc) = rhs.color { c + oc } else { c })
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -49,7 +81,12 @@ impl Sub for Point2i {
|
||||||
Self {
|
Self {
|
||||||
x: self.x - rhs.x,
|
x: self.x - rhs.x,
|
||||||
y: self.y - rhs.y,
|
y: self.y - rhs.y,
|
||||||
c: None,
|
color: if self.color.is_none() {
|
||||||
|
rhs.color
|
||||||
|
} else {
|
||||||
|
self.color
|
||||||
|
.map(|c| if let Some(oc) = rhs.color { c - oc } else { c })
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -61,7 +98,7 @@ impl Mul for Point2i {
|
||||||
Self {
|
Self {
|
||||||
x: self.x * rhs.x,
|
x: self.x * rhs.x,
|
||||||
y: self.y * rhs.y,
|
y: self.y * rhs.y,
|
||||||
c: None,
|
color: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -143,7 +180,7 @@ impl From<Point3f> for Point2i {
|
||||||
Self {
|
Self {
|
||||||
x: p.x().round_ties_even() as i32,
|
x: p.x().round_ties_even() as i32,
|
||||||
y: p.y().round_ties_even() as i32,
|
y: p.y().round_ties_even() as i32,
|
||||||
c: None,
|
color: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
167
src/tga.rs
167
src/tga.rs
|
@ -1,7 +1,7 @@
|
||||||
use std::{
|
use std::{
|
||||||
fs::File,
|
fs::File,
|
||||||
io::{Read, Write},
|
io::{Read, Write},
|
||||||
ops::{Deref, DerefMut},
|
ops::{Add, Deref, DerefMut, Mul, Sub},
|
||||||
};
|
};
|
||||||
|
|
||||||
const HEADER_SIZE: usize = 18;
|
const HEADER_SIZE: usize = 18;
|
||||||
|
@ -73,6 +73,49 @@ impl From<ColorBuf> for TGAColor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Add for TGAColor {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn add(self, rhs: Self) -> Self::Output {
|
||||||
|
Self {
|
||||||
|
bgra: [
|
||||||
|
self[0].saturating_add(rhs[0]),
|
||||||
|
self[1].saturating_add(rhs[1]),
|
||||||
|
self[2].saturating_add(rhs[2]),
|
||||||
|
self[3].saturating_add(rhs[3]),
|
||||||
|
],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Sub for TGAColor {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn sub(self, rhs: Self) -> Self::Output {
|
||||||
|
Self {
|
||||||
|
bgra: [
|
||||||
|
self[0].saturating_sub(rhs[0]),
|
||||||
|
self[1].saturating_sub(rhs[1]),
|
||||||
|
self[2].saturating_sub(rhs[2]),
|
||||||
|
self[3].saturating_sub(rhs[3]),
|
||||||
|
],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Mul<f32> for TGAColor {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn mul(self, rhs: f32) -> Self::Output {
|
||||||
|
let b = (self.b() as f32 * rhs).round_ties_even() as u8;
|
||||||
|
let g = (self.g() as f32 * rhs).round_ties_even() as u8;
|
||||||
|
let r = (self.r() as f32 * rhs).round_ties_even() as u8;
|
||||||
|
let a = (self.a() as f32 * rhs).round_ties_even() as u8;
|
||||||
|
|
||||||
|
Self { bgra: [b, g, r, a] }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl TGAColor {
|
impl TGAColor {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
@ -80,20 +123,20 @@ impl TGAColor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn b(&mut self) -> &mut u8 {
|
pub fn b(&self) -> u8 {
|
||||||
&mut self[0]
|
self[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn g(&mut self) -> &mut u8 {
|
pub fn g(&self) -> u8 {
|
||||||
&mut self[1]
|
self[1]
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn r(&mut self) -> &mut u8 {
|
pub fn r(&self) -> u8 {
|
||||||
&mut self[2]
|
self[2]
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn a(&mut self) -> &mut u8 {
|
pub fn a(&self) -> u8 {
|
||||||
&mut self[3]
|
self[3]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -179,7 +222,7 @@ impl TGAImage {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn write_file(&mut self, file: &str, do_vflip: bool, do_rle: bool) -> IoResult {
|
pub fn write_file(&mut self, file: &str, do_vflip: bool) -> IoResult {
|
||||||
let mut file = std::fs::File::create(file)?;
|
let mut file = std::fs::File::create(file)?;
|
||||||
|
|
||||||
let mut header = TGAHeader::default();
|
let mut header = TGAHeader::default();
|
||||||
|
@ -188,10 +231,8 @@ impl TGAImage {
|
||||||
header.height = self.height as u16;
|
header.height = self.height as u16;
|
||||||
|
|
||||||
header.datatype_code = match self.format {
|
header.datatype_code = match self.format {
|
||||||
TGAFormat::Grayscale if do_rle => 11,
|
TGAFormat::Grayscale => 11,
|
||||||
TGAFormat::Grayscale => 3,
|
_ => 10,
|
||||||
_ if do_rle => 10,
|
|
||||||
_ => 2,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
header.image_descriptor = if do_vflip { 0x00 } else { 0x20 };
|
header.image_descriptor = if do_vflip { 0x00 } else { 0x20 };
|
||||||
|
@ -200,10 +241,49 @@ impl TGAImage {
|
||||||
|
|
||||||
file.write_all(&mut header)?;
|
file.write_all(&mut header)?;
|
||||||
|
|
||||||
if do_rle {
|
let max_chunk_len = 128;
|
||||||
self.write_rle_file(&mut file)?;
|
let num_pixels = (self.width * self.height) as usize;
|
||||||
} else {
|
let mut current_pixel = 0;
|
||||||
file.write_all(&mut self.data)?;
|
|
||||||
|
let bpp = self.bytes_per_pixel() as usize;
|
||||||
|
|
||||||
|
while current_pixel < num_pixels {
|
||||||
|
let chunk_start = current_pixel * bpp;
|
||||||
|
let mut current_byte = current_pixel * bpp;
|
||||||
|
|
||||||
|
let mut run_length = 1;
|
||||||
|
let mut is_raw = true;
|
||||||
|
|
||||||
|
while (current_pixel + run_length) < num_pixels && run_length < max_chunk_len {
|
||||||
|
let mut succ_eq = true;
|
||||||
|
let mut t = 0;
|
||||||
|
while succ_eq && t < bpp {
|
||||||
|
succ_eq = self.data[current_byte + t] == self.data[current_byte + t + bpp];
|
||||||
|
t += 1;
|
||||||
|
}
|
||||||
|
current_byte += bpp;
|
||||||
|
if 1 == run_length {
|
||||||
|
is_raw = !succ_eq;
|
||||||
|
}
|
||||||
|
if is_raw && succ_eq {
|
||||||
|
run_length -= 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if !(is_raw || succ_eq) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
run_length += 1;
|
||||||
|
}
|
||||||
|
current_pixel += run_length;
|
||||||
|
let mut out = if is_raw {
|
||||||
|
[run_length as u8 - 1]
|
||||||
|
} else {
|
||||||
|
[run_length as u8 + 127]
|
||||||
|
};
|
||||||
|
|
||||||
|
file.write_all(&mut out)?;
|
||||||
|
let chunk_end = chunk_start + if is_raw { run_length * bpp } else { bpp };
|
||||||
|
file.write_all(&mut self.data[chunk_start..chunk_end])?;
|
||||||
}
|
}
|
||||||
|
|
||||||
file.flush()?;
|
file.flush()?;
|
||||||
|
@ -309,55 +389,4 @@ impl TGAImage {
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_rle_file(&mut self, file: &mut File) -> IoResult {
|
|
||||||
let max_chunk_len = 128;
|
|
||||||
let num_pixels = (self.width * self.height) as usize;
|
|
||||||
let mut current_pixel = 0;
|
|
||||||
|
|
||||||
let bpp = self.bytes_per_pixel() as usize;
|
|
||||||
|
|
||||||
while current_pixel < num_pixels {
|
|
||||||
let chunk_start = current_pixel * bpp;
|
|
||||||
let mut current_byte = current_pixel * bpp;
|
|
||||||
|
|
||||||
let mut run_length = 1;
|
|
||||||
let mut is_raw = true;
|
|
||||||
|
|
||||||
while (current_pixel + run_length) < num_pixels && run_length < max_chunk_len {
|
|
||||||
let mut succ_eq = true;
|
|
||||||
let mut t = 0;
|
|
||||||
while succ_eq && t < bpp {
|
|
||||||
succ_eq = self.data[current_byte + t] == self.data[current_byte + t + bpp];
|
|
||||||
t += 1;
|
|
||||||
}
|
|
||||||
current_byte += bpp;
|
|
||||||
if 1 == run_length {
|
|
||||||
is_raw = !succ_eq;
|
|
||||||
}
|
|
||||||
if is_raw && succ_eq {
|
|
||||||
run_length -= 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if !(is_raw || succ_eq) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
run_length += 1;
|
|
||||||
}
|
|
||||||
current_pixel += run_length;
|
|
||||||
let mut out = if is_raw {
|
|
||||||
[run_length as u8 - 1]
|
|
||||||
} else {
|
|
||||||
[run_length as u8 + 127]
|
|
||||||
};
|
|
||||||
|
|
||||||
file.write_all(&mut out)?;
|
|
||||||
let chunk_end = chunk_start + if is_raw { run_length * bpp } else { bpp };
|
|
||||||
file.write_all(&mut self.data[chunk_start..chunk_end])?;
|
|
||||||
}
|
|
||||||
|
|
||||||
file.flush()?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue