omt/gfx/
drawbuffer.rs

1
2use image::{ DynamicImage, GenericImageView };
3
4// const GRID_SIZE: u32 = 64;
5
6// :TODO: remove grid or refactor
7
8pub struct DrawBuffer {
9	width: u32,
10	height: u32,
11	data: Vec<u32>,
12	scale: f32,
13}
14
15impl DrawBuffer {
16	pub fn new( w: u32, h: u32 ) -> DrawBuffer {
17		DrawBuffer {
18			width: w,
19			height: h,
20			data: vec![0; ( w*h ) as usize],
21			scale: 1.0,
22		}
23	}
24
25	pub fn get_scale( &self ) -> f32 {
26		self.scale
27	}
28	pub fn set_scale( &mut self, scale: f32 ) {
29		self.scale = scale;
30	}
31
32	pub fn copy_from_draw_buffer( &mut self, other: &DrawBuffer ) {
33		// :TODO: verify sizes
34		self.data.copy_from_slice( other.get_data() );
35	}
36
37	pub fn fill_with_grid( &mut self, size: u32, col_a: u32, col_b: u32 ) {
38		let h = self.height; //image.dimensions().0;
39		let w = self.width; //image.dimensions().1;
40		let mut pos = 0;
41		for y in 0..h {
42			for x in 0..w {
43				if ( x/size + y/size )%2 == 0 {
44					self.data[ pos ] = col_a;
45				} else {
46					self.data[ pos ] = col_b;					
47				}
48				pos += 1;
49			}
50		}		
51	}
52
53	pub fn blit_image( &mut self, image: &DynamicImage) {
54		let mut pos = 0;
55		let h = self.height;
56		let w = self.width;
57		for y in 0..h {
58			for x in 0..w {
59				let sx = ( x as f32 * self.scale ).trunc() as u32;
60				let sy = ( y as f32 * self.scale ).trunc() as u32;
61				let pixel = image.get_pixel( sx, sy );
62				let r = pixel[ 0 ] as u32;
63				let g = pixel[ 1 ] as u32;
64				let b = pixel[ 2 ] as u32;
65				let a = pixel[ 3 ] as u32;
66				let bg = self.data[ pos ];
67				let fg: u32 = ( r << 16 )|( g << 8 )|( b << 0 );
68				let rgb = DrawBuffer::mix_rgba( fg, bg, ( a as f32 )/255.0 );
69
70				self.data[ pos ] = rgb;
71				pos += 1;
72			}
73		}
74	}
75
76	pub fn draw_hline( &mut self, sx: u32, ex: u32, y: u32, col: u32 ) {
77		// :TODO: clip line
78
79		let w = self.width as usize;
80		let h = self.height as usize;
81
82		let mut y = ( y as f32 / self.scale ) as usize;
83		let mut sx = ( sx as f32 / self.scale ) as usize;
84		let mut ex = ( ex as f32 / self.scale ) as usize;
85		if y >= h {
86			y = h-1;
87		}
88		if sx >= w {
89			sx = w-1;
90		}
91		if ex >= w {
92			ex = w-1;
93		}
94		let col = col >> 8; // :HACK: get rid of alpha
95		for x in sx..=ex {
96			let p = w * y + x;
97			self.data[ p ] = col;
98		}
99	}
100
101	#[allow(dead_code)]
102	fn draw_vline( &mut self, x: u32, sy: u32, ey: u32, col: u32 ) {
103		// :TODO: clip line
104		let w = self.width as usize;
105		let h = self.height as usize;
106
107		let mut x = ( x as f32 / self.scale ) as usize;
108		let mut sy = ( sy as f32 / self.scale ) as usize;
109		let mut ey = ( ey as f32 / self.scale ) as usize;
110		if x >= w {
111			x = w-1;
112		}
113		if sy >= h {
114			sy = h-1;
115		}
116		if ey >= h {
117			ey = h-1;
118		}
119		let col = col >> 8; // :HACK: get rid of alpha
120		for y in sy..=ey {
121			let p = w * y + x;
122			self.data[ p ] = col;
123		}
124	}
125
126	fn clamp_i32( v: i32, min: i32, max: i32 ) -> i32 {
127		if v < min {
128			min
129		} else if v > max {
130			max
131		} else {
132			v
133		}
134	}
135
136	pub fn draw_filled_rectangle( &mut self, sx: i32, sy: i32, ex: i32, ey: i32, col: u32 ) {
137		// :TODO: flip as needed
138//		println!("Drawing rect {:?}, {:?} - {:?}, {:?}", sx, sy, ex, ey);
139		let s = self.scale;
140		let sx = ( ( sx as f32 )/s ).trunc() as i32;
141		let sy = ( ( sy as f32 )/s ).trunc() as i32;
142		let ex = ( ( ex as f32 )/s ).trunc() as i32;
143		let ey = ( ( ey as f32 )/s ).trunc() as i32;
144
145		let sx = DrawBuffer::clamp_i32( sx, 0, self.width as i32 ) as u32;
146		let sy = DrawBuffer::clamp_i32( sy, 0, self.height as i32 ) as u32;
147		let ex = DrawBuffer::clamp_i32( ex, 0, self.width as i32 ) as u32;
148		let ey = DrawBuffer::clamp_i32( ey, 0, self.height as i32 ) as u32;
149
150//		println!("Drawing clamped rect {:?}, {:?} - {:?}, {:?}", sx, sy, ex, ey);
151		for y in sy..ey {
152			for x in sx..ex {
153				let offset = ( self.width * y + x ) as usize;
154				self.data[ offset ] = col;
155			}
156		}
157	}
158	pub fn draw_frame( &mut self, x: i32, y: i32, fw: u32, fh: u32, col: u32, line_width: u32 ) {
159		let hw = ( ( line_width as f32 )*0.5 ).trunc() as i32;
160		let fw = fw as i32;
161		let fh = fh as i32;
162
163		// top
164		self.draw_filled_rectangle( x-hw, y-hw, x+fw+hw, y+hw, col );
165		// bottom
166		self.draw_filled_rectangle( x-hw, y+fh-hw, x+fw+hw, y+fh+hw, col );
167		// left
168		self.draw_filled_rectangle( x-hw, y+hw, x+hw, y+fh-hw, col );
169		// right
170		self.draw_filled_rectangle( x+fw-hw, y+hw, x+fw+hw, y+fh-hw, col );
171	}
172
173	pub fn get_width( &self ) -> u32 {
174		self.width
175	}
176	pub fn get_height( &self ) -> u32 {
177		self.height
178	}
179
180	pub fn get_data( &self ) -> &Vec<u32> {
181		&self.data
182	}
183
184	/// blends a over b with f percent
185	pub fn mix_rgba( a: u32, b: u32, f: f32 ) -> u32 {
186		let ra = ( ( a >> 24 )&0x000000ff ) as u8;
187		let ga = ( ( a >> 16 )&0x000000ff ) as u8;
188		let ba = ( ( a >>  8 )&0x000000ff ) as u8;
189		let aa = ( ( a >>  0 )&0x000000ff ) as u8;
190
191		let rb = ( ( b >> 24 )&0x000000ff ) as u8;
192		let gb = ( ( b >> 16 )&0x000000ff ) as u8;
193		let bb = ( ( b >>  8 )&0x000000ff ) as u8;
194		let ab = ( ( b >>  0 )&0x000000ff ) as u8;
195
196		let r = ( ( ra as f32 ) * f + ( rb as f32 ) * ( 1.0 -f ) ) as u32;
197		let g = ( ( ga as f32 ) * f + ( gb as f32 ) * ( 1.0 -f ) ) as u32;
198		let b = ( ( ba as f32 ) * f + ( bb as f32 ) * ( 1.0 -f ) ) as u32;
199		let a = ( ( aa as f32 ) * f + ( ab as f32 ) * ( 1.0 -f ) ) as u32;
200
201		let rgba = ( r << 24 )|( g << 16 )|( b << 8 )|a;
202
203		rgba
204	}
205
206	#[allow(dead_code)]
207	fn mix_byte( a: u8, b: u8, f: u8 ) -> u8 {
208		let f = ( f as f32 )/255.0;
209		let fa = a as f32 * f;
210		let fb = b as f32 * (1.0-f);
211
212		( fa + fb ) as u8
213	}
214
215}