almost done with tga stuff

This commit is contained in:
Joe Ardent 2025-09-04 16:27:13 -07:00
commit 7d190cec88
6 changed files with 172 additions and 0 deletions

1
.gitignore vendored Normal file
View file

@ -0,0 +1 @@
/target

4
.rustfmt.toml Normal file
View file

@ -0,0 +1,4 @@
imports_granularity = "Crate"
group_imports = "StdExternalCrate"
wrap_comments = true
edition = "2024"

7
Cargo.lock generated Normal file
View file

@ -0,0 +1,7 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "tinyrender"
version = "0.1.0"

6
Cargo.toml Normal file
View file

@ -0,0 +1,6 @@
[package]
name = "tinyrender"
version = "0.1.0"
edition = "2024"
[dependencies]

3
src/main.rs Normal file
View file

@ -0,0 +1,3 @@
fn main() {
println!("Hello, world!");
}

151
src/tga.rs Normal file
View file

@ -0,0 +1,151 @@
use std::{
fs::File,
io::Read,
ops::{Deref, DerefMut},
};
#[derive(Debug, Default, Clone, PartialEq, Eq)]
#[repr(C, packed)]
pub struct TGAHeader {
pub id_length: u8,
pub colormap_type: u8,
pub datatype_code: u8,
pub colormap_origin: u16,
pub colormap_length: u16,
pub colormap_depth: u8,
pub x_origin: u16,
pub y_origin: u16,
pub width: u16,
pub height: u16,
pub bits_per_pixel: u8,
pub image_descriptor: u8,
}
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum Format {
Grayscale = 1,
RGB = 3,
#[default]
RGBA = 4,
}
impl TryFrom<u8> for Format {
type Error = String;
fn try_from(value: u8) -> Result<Self, Self::Error> {
match value {
1 => Ok(Self::Grayscale),
3 => Ok(Self::RGB),
4 => Ok(Self::RGBA),
_ => Err(format!("could not convert {value} into a Format")),
}
}
}
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
#[repr(transparent)]
pub struct TGAColor {
pub bgra: [u8; 4],
}
impl Deref for TGAColor {
type Target = [u8; 4];
fn deref(&self) -> &Self::Target {
&self.bgra
}
}
impl DerefMut for TGAColor {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.bgra
}
}
impl TGAColor {
pub fn new() -> Self {
Self { bgra: [0; 4] }
}
}
#[derive(Debug, Default, Clone, PartialEq, Eq)]
struct TGAImage {
pub format: Format,
pub width: u32,
pub height: u32,
data: Vec<u8>,
}
pub type IoResult = std::io::Result<()>;
impl TGAImage {
pub fn new(width: u32, height: u32, format: Format) -> Self {
Self {
format,
width,
height,
data: Vec::with_capacity((format as usize) * (width * height) as usize),
}
}
pub fn bytes_per_pixel(&self) -> u8 {
self.format as u8
}
pub fn read_file(&mut self, file: &str) -> IoResult {
let mut file = std::fs::File::open(file)?;
let header_size = size_of::<TGAHeader>();
assert_eq!(header_size, 18);
let mut bytes = [0u8; header_size];
file.read_exact(&mut bytes)?;
let header: TGAHeader = unsafe { std::mem::transmute(bytes) };
if header.width < 1 || header.height < 1 {
return Err("bad image metadata".into());
}
self.format = (header.bits_per_pixel >> 3).try_into()?;
self.width = header.width;
self.height = header.height;
let nbytes = self.format as usize * (self.width * self.height) as usize;
let mut image_data = Vec::with_capacity(nbytes);
match header.datatype_code {
2 | 3 => {
file.read_to_end(&mut image_data)?;
self.data = image_data;
}
10 | 11 => {
self.read_rle_file(&mut file)?;
}
_ => {
return Err("invalid TGA file".into());
}
}
}
pub fn write_file(&self, file: &str) -> IoResult {
todo!()
}
pub fn flip_horizontal(&mut self) {
todo!()
}
pub fn flip_vertical(&mut self) {
todo!()
}
pub fn set(&mut self, x: u32, y: u32, color: &TGAColor) {
todo!()
}
pub fn get(&self, x: u32, y: u32) -> Option<TGAColor> {
todo!()
}
fn read_rle_file(&mut self, file: &mut File) -> IoResult {
todo!()
}
}