first not-great line impl
This commit is contained in:
parent
d51a2dd5f4
commit
ba91baa302
3 changed files with 99 additions and 29 deletions
32
src/main.rs
32
src/main.rs
|
@ -2,9 +2,11 @@
|
|||
extern crate justerror;
|
||||
|
||||
mod tga;
|
||||
|
||||
use tga::*;
|
||||
|
||||
mod point;
|
||||
use point::*;
|
||||
|
||||
const WHITE: TGAColor = TGAColor {
|
||||
bgra: [255, 255, 255, 255],
|
||||
};
|
||||
|
@ -37,13 +39,31 @@ fn main() {
|
|||
let cx = 62;
|
||||
let cy = 53;
|
||||
|
||||
framebuffer.set(ax, ay, &WHITE);
|
||||
framebuffer.set(bx, by, &WHITE);
|
||||
framebuffer.set(cx, cy, &WHITE);
|
||||
framebuffer.set(ax, ay, WHITE);
|
||||
framebuffer.set(bx, by, WHITE);
|
||||
framebuffer.set(cx, cy, WHITE);
|
||||
|
||||
let a = Point::new(ax, ay);
|
||||
let b = Point::new(bx, by);
|
||||
let c = Point::new(cx, cy);
|
||||
|
||||
line(a, b, &mut framebuffer, BLUE);
|
||||
line(c, b, &mut framebuffer, GREEN);
|
||||
line(c, a, &mut framebuffer, YELLOW);
|
||||
line(a, c, &mut framebuffer, RED);
|
||||
|
||||
framebuffer
|
||||
.write_file("framebuffer.tga", true, true)
|
||||
.unwrap();
|
||||
|
||||
let new = TGAImage::from_file("framebuffer.tga").unwrap();
|
||||
}
|
||||
|
||||
fn line(a: Point, b: Point, fb: &mut TGAImage, color: TGAColor) {
|
||||
let mut t = 0.0;
|
||||
let step = 0.02;
|
||||
while t < 1.0 {
|
||||
let x = (a.x as f32 + (b.x - a.x) as f32 * t).round_ties_even() as u32;
|
||||
let y = (a.y as f32 + (b.y - a.y) as f32 * t).round_ties_even() as u32;
|
||||
fb.set(x, y, color);
|
||||
t += step;
|
||||
}
|
||||
}
|
||||
|
|
49
src/point.rs
Normal file
49
src/point.rs
Normal file
|
@ -0,0 +1,49 @@
|
|||
use std::ops::{Add, Mul, Sub};
|
||||
|
||||
#[derive(Default, Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct Point {
|
||||
pub x: i32,
|
||||
pub y: i32,
|
||||
}
|
||||
|
||||
impl Point {
|
||||
pub fn new(x: u32, y: u32) -> Self {
|
||||
Self {
|
||||
x: x as i32,
|
||||
y: y as i32,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Add for Point {
|
||||
type Output = Self;
|
||||
|
||||
fn add(self, rhs: Self) -> Self::Output {
|
||||
Self {
|
||||
x: self.x + rhs.x,
|
||||
y: self.y + rhs.y,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Sub for Point {
|
||||
type Output = Self;
|
||||
|
||||
fn sub(self, rhs: Self) -> Self::Output {
|
||||
Self {
|
||||
x: self.x.saturating_sub(rhs.x),
|
||||
y: self.y.saturating_sub(rhs.y),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul for Point {
|
||||
type Output = Self;
|
||||
|
||||
fn mul(self, rhs: Self) -> Self::Output {
|
||||
Self {
|
||||
x: self.x * rhs.x,
|
||||
y: self.y * rhs.y,
|
||||
}
|
||||
}
|
||||
}
|
47
src/tga.rs
47
src/tga.rs
|
@ -6,6 +6,8 @@ use std::{
|
|||
|
||||
const HEADER_SIZE: usize = 18;
|
||||
|
||||
pub type ColorBuf = [u8; 4];
|
||||
|
||||
#[derive(Debug, Default, Clone, PartialEq, Eq)]
|
||||
#[repr(C, packed)]
|
||||
pub struct TGAHeader {
|
||||
|
@ -48,11 +50,11 @@ impl TryFrom<u8> for TGAFormat {
|
|||
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
|
||||
#[repr(transparent)]
|
||||
pub struct TGAColor {
|
||||
pub bgra: [u8; 4],
|
||||
pub bgra: ColorBuf,
|
||||
}
|
||||
|
||||
impl Deref for TGAColor {
|
||||
type Target = [u8; 4];
|
||||
type Target = ColorBuf;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.bgra
|
||||
|
@ -65,15 +67,17 @@ impl DerefMut for TGAColor {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<[u8; 4]> for TGAColor {
|
||||
fn from(value: [u8; 4]) -> Self {
|
||||
impl From<ColorBuf> for TGAColor {
|
||||
fn from(value: ColorBuf) -> Self {
|
||||
Self { bgra: value }
|
||||
}
|
||||
}
|
||||
|
||||
impl TGAColor {
|
||||
pub fn new() -> Self {
|
||||
Self { bgra: [0; 4] }
|
||||
Self {
|
||||
bgra: ColorBuf::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn b(&mut self) -> &mut u8 {
|
||||
|
@ -96,8 +100,8 @@ impl TGAColor {
|
|||
#[derive(Debug, Default, Clone, PartialEq, Eq)]
|
||||
pub struct TGAImage {
|
||||
pub format: TGAFormat,
|
||||
pub width: u16,
|
||||
pub height: u16,
|
||||
pub width: u32,
|
||||
pub height: u32,
|
||||
data: Vec<u8>,
|
||||
}
|
||||
|
||||
|
@ -128,7 +132,7 @@ impl From<std::io::Error> for TGAError {
|
|||
}
|
||||
|
||||
impl TGAImage {
|
||||
pub fn new(width: u16, height: u16, format: TGAFormat) -> Self {
|
||||
pub fn new(width: u32, height: u32, format: TGAFormat) -> Self {
|
||||
let size = format as usize * (width * height) as usize;
|
||||
Self {
|
||||
format,
|
||||
|
@ -155,8 +159,8 @@ impl TGAImage {
|
|||
}
|
||||
self.format = (header.bits_per_pixel >> 3).try_into()?;
|
||||
|
||||
self.width = header.width;
|
||||
self.height = header.height;
|
||||
self.width = header.width as u32;
|
||||
self.height = header.height as u32;
|
||||
|
||||
let nbytes = self.format as usize * (self.width * self.height) as usize;
|
||||
let mut image_data = vec![0u8; nbytes];
|
||||
|
@ -180,8 +184,8 @@ impl TGAImage {
|
|||
|
||||
let mut header = TGAHeader::default();
|
||||
header.bits_per_pixel = self.bytes_per_pixel() << 3;
|
||||
header.width = self.width;
|
||||
header.height = self.height;
|
||||
header.width = self.width as u16;
|
||||
header.height = self.height as u16;
|
||||
|
||||
header.datatype_code = match self.format {
|
||||
TGAFormat::Grayscale if do_rle => 11,
|
||||
|
@ -204,8 +208,8 @@ impl TGAImage {
|
|||
|
||||
file.flush()?;
|
||||
|
||||
let mut developer_area = [0u8; 4];
|
||||
let mut extension_area = [0u8; 4];
|
||||
let mut developer_area = ColorBuf::default();
|
||||
let mut extension_area = ColorBuf::default();
|
||||
let mut footer: Vec<u8> = vec![
|
||||
'T', 'R', 'U', 'E', 'V', 'I', 'S', 'I', 'O', 'N', '-', 'X', 'F', 'I', 'L', 'E', '.',
|
||||
'\0',
|
||||
|
@ -231,7 +235,7 @@ impl TGAImage {
|
|||
todo!()
|
||||
}
|
||||
|
||||
pub fn set(&mut self, x: u16, y: u16, color: &TGAColor) {
|
||||
pub fn set(&mut self, x: u32, y: u32, color: TGAColor) {
|
||||
if self.data.is_empty() || x > self.width || y > self.height {
|
||||
return;
|
||||
}
|
||||
|
@ -239,12 +243,10 @@ impl TGAImage {
|
|||
let bpp = self.bytes_per_pixel() as usize;
|
||||
let start = (x + y * self.width) as usize * bpp;
|
||||
let end = start + bpp;
|
||||
for (i, b) in &mut self.data[start..end].iter_mut().enumerate() {
|
||||
*b = color[i];
|
||||
}
|
||||
self.data[start..end].copy_from_slice(&color[0..bpp]);
|
||||
}
|
||||
|
||||
pub fn get(&self, x: u16, y: u16) -> Option<TGAColor> {
|
||||
pub fn get(&self, x: u32, y: u32) -> Option<TGAColor> {
|
||||
if self.data.is_empty() || x >= self.width || y >= self.height {
|
||||
return None;
|
||||
}
|
||||
|
@ -252,12 +254,11 @@ impl TGAImage {
|
|||
let bpp = self.bytes_per_pixel() as usize;
|
||||
|
||||
let mut color = TGAColor::new();
|
||||
let start = (x + y * self.width) as usize;
|
||||
let start = bpp * (x + y * self.width) as usize;
|
||||
let end = start + bpp;
|
||||
let data = &self.data[start..end];
|
||||
for i in 0..bpp {
|
||||
color[i] = data[i];
|
||||
}
|
||||
color[0..bpp].copy_from_slice(data);
|
||||
|
||||
Some(color)
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue