Skip to content

Commit 717c476

Browse files
committed
render shapes on the server
1 parent d754f7a commit 717c476

File tree

5 files changed

+252
-85
lines changed

5 files changed

+252
-85
lines changed

Cargo.lock

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "draw-together"
3-
version = "2.2.1"
3+
version = "2.2.2"
44
edition = "2021"
55

66
[[bin]]

src/data.rs

+203-41
Original file line numberDiff line numberDiff line change
@@ -128,27 +128,10 @@ impl ClientMessage {
128128

129129
buf
130130
}
131-
132-
pub fn encode_internal(&self) -> u32 {
133-
let mut buf = [0; 4];
134-
135-
buf[0] = Self::encode_u3(match self.action {
136-
Action::Erase => 0,
137-
Action::DrawCubeNormal => 1,
138-
Action::DrawCubeHollow => 2,
139-
Action::DrawCircleNormal => 3,
140-
Action::DrawCircleHollow => 4,
141-
Action::DrawTriangleNormal => 5,
142-
Action::DrawTriangleHollow => 6,
143-
}) | Self::encode_u5(self.height);
144-
buf[1..4].copy_from_slice(&self.color);
145-
146-
u32::from_le_bytes(buf)
147-
}
148131
}
149132

150133
pub struct Data {
151-
pub data: Arc<Mutex<Vec<u32>>>,
134+
pub data: Arc<Mutex<Vec<u8>>>,
152135
pub listeners: Vec<tokio::sync::mpsc::Sender<Vec<u8>>>,
153136
}
154137

@@ -170,20 +153,9 @@ impl Data {
170153
None => None,
171154
};
172155

173-
let mut data: Vec<u32> = vec![0; RESOLUTION];
156+
let mut data: Vec<u8> = vec![0xff; RESOLUTION * 3];
174157
if file.is_some() {
175-
let mut file_data: Vec<u8> = Vec::with_capacity(RESOLUTION * 4);
176-
file.as_mut()
177-
.unwrap()
178-
.read_to_end(&mut file_data)
179-
.await
180-
.unwrap();
181-
182-
data.iter_mut()
183-
.zip(file_data.chunks_exact(4))
184-
.for_each(|(data, chunk)| {
185-
*data = u32::from_le_bytes([chunk[0], chunk[1], chunk[2], chunk[3]]);
186-
});
158+
file.as_mut().unwrap().read_to_end(&mut data).await.unwrap();
187159
}
188160

189161
let data = Arc::new(Mutex::new(data));
@@ -236,21 +208,211 @@ impl Data {
236208
let mut self_data = self_data.lock().await;
237209

238210
for message in data {
239-
let index = (message.y as usize * RESOLUTION_WIDTH) + message.x as usize;
240-
self_data[index] = message.encode_internal();
211+
match message.action {
212+
Action::Erase => {
213+
let height = (message.height as f64) * 1.5 * 4.0;
214+
215+
let start_x = message.x.saturating_sub(height as u16) as usize;
216+
let end_x =
217+
((message.x + height as u16).min(RESOLUTION_WIDTH as u16 - 1)) as usize;
218+
let start_y = message.y.saturating_sub(height as u16) as usize;
219+
let end_y =
220+
((message.y + height as u16).min(RESOLUTION_HEIGHT as u16 - 1)) as usize;
221+
222+
for y in start_y..=end_y {
223+
let row_start = y * RESOLUTION_WIDTH * 3;
224+
for x in start_x..=end_x {
225+
let index = row_start + x * 3;
226+
self_data[index] = 0xff;
227+
self_data[index + 1] = 0xff;
228+
self_data[index + 2] = 0xff;
229+
}
230+
}
231+
}
232+
Action::DrawCubeNormal => {
233+
let height = message.height as usize * 4;
234+
println!("height: {}", height);
235+
let start_x = message.x as usize;
236+
let end_x =
237+
((message.x + height as u16).min(RESOLUTION_WIDTH as u16 - 1)) as usize;
238+
let start_y = message.y as usize;
239+
let end_y =
240+
((message.y + height as u16).min(RESOLUTION_HEIGHT as u16 - 1)) as usize;
241+
242+
for y in start_y..=end_y {
243+
let row_start = y * RESOLUTION_WIDTH * 3;
244+
for x in start_x..=end_x {
245+
let index = row_start + x * 3;
246+
self_data[index..index + 3].copy_from_slice(&message.color);
247+
}
248+
}
249+
}
250+
Action::DrawCubeHollow => {
251+
let height = message.height as usize * 4;
252+
let start_x = message.x as usize;
253+
let end_x =
254+
((message.x + height as u16).min(RESOLUTION_WIDTH as u16 - 1)) as usize;
255+
let start_y = message.y as usize;
256+
let end_y =
257+
((message.y + height as u16).min(RESOLUTION_HEIGHT as u16 - 1)) as usize;
258+
259+
for x in start_x..=end_x {
260+
let top_index = start_y * RESOLUTION_WIDTH * 3 + x * 3;
261+
let bottom_index = end_y * RESOLUTION_WIDTH * 3 + x * 3;
262+
self_data[top_index..top_index + 3].copy_from_slice(&message.color);
263+
self_data[bottom_index..bottom_index + 3].copy_from_slice(&message.color);
264+
}
265+
266+
for y in start_y..=end_y {
267+
let left_index = y * RESOLUTION_WIDTH * 3 + start_x * 3;
268+
let right_index = y * RESOLUTION_WIDTH * 3 + end_x * 3;
269+
self_data[left_index..left_index + 3].copy_from_slice(&message.color);
270+
self_data[right_index..right_index + 3].copy_from_slice(&message.color);
271+
}
272+
}
273+
Action::DrawCircleNormal | Action::DrawCircleHollow => {
274+
let radius = message.height as usize * 4;
275+
let is_hollow = matches!(message.action, Action::DrawCircleHollow);
276+
277+
let start_x = message.x.saturating_sub(radius as u16) as usize;
278+
let end_x =
279+
((message.x + radius as u16).min(RESOLUTION_WIDTH as u16 - 1)) as usize;
280+
let start_y = message.y.saturating_sub(radius as u16) as usize;
281+
let end_y =
282+
((message.y + radius as u16).min(RESOLUTION_HEIGHT as u16 - 1)) as usize;
283+
284+
let center_x = message.x as f32;
285+
let center_y = message.y as f32;
286+
let radius_sq = (radius * radius) as f32;
287+
let inner_radius_sq = ((radius - 1) * (radius - 1)) as f32;
288+
289+
for y in start_y..=end_y {
290+
let dy = y as f32 - center_y;
291+
let dy_sq = dy * dy;
292+
let row_start = y * RESOLUTION_WIDTH * 3;
293+
294+
for x in start_x..=end_x {
295+
let dx = x as f32 - center_x;
296+
let dist_sq = dx * dx + dy_sq;
297+
298+
if (!is_hollow && dist_sq <= radius_sq)
299+
|| (is_hollow && dist_sq <= radius_sq && dist_sq >= inner_radius_sq)
300+
{
301+
let index = row_start + x * 3;
302+
self_data[index..index + 3].copy_from_slice(&message.color);
303+
}
304+
}
305+
}
306+
}
307+
Action::DrawTriangleNormal | Action::DrawTriangleHollow => {
308+
let height = message.height as usize * 4;
309+
let is_hollow = matches!(message.action, Action::DrawTriangleHollow);
310+
311+
let x1 = message.x as i32;
312+
let y1 = message.y as i32;
313+
let x2 = (message.x as i32) - (height as i32);
314+
let y2 = message.y as i32 + (height as i32 * 2);
315+
let x3 = message.x as i32 + height as i32;
316+
let y3 = y2;
317+
318+
if is_hollow {
319+
draw_line_fast(&mut self_data, x1, y1, x2, y2, &message.color);
320+
draw_line_fast(&mut self_data, x2, y2, x3, y3, &message.color);
321+
draw_line_fast(&mut self_data, x3, y3, x1, y1, &message.color);
322+
} else {
323+
let min_x = x2.min(x3).min(x1).max(0) as usize;
324+
let max_x = x2.max(x3).max(x1).min(RESOLUTION_WIDTH as i32 - 1) as usize;
325+
let min_y = y1.min(y2).min(y3).max(0) as usize;
326+
let max_y = y1.max(y2).max(y3).min(RESOLUTION_HEIGHT as i32 - 1) as usize;
327+
328+
for y in min_y..=max_y {
329+
let row_start = y * RESOLUTION_WIDTH * 3;
330+
for x in min_x..=max_x {
331+
if point_in_triangle_fast(
332+
x as i32, y as i32, x1, y1, x2, y2, x3, y3,
333+
) {
334+
let index = row_start + x * 3;
335+
self_data[index..index + 3].copy_from_slice(&message.color);
336+
}
337+
}
338+
}
339+
}
340+
}
341+
}
241342
}
242343

243-
let mut encoded = Vec::with_capacity(7 * data.len());
244-
for message in data {
245-
encoded.extend_from_slice(&message.encode());
246-
}
344+
if !self.listeners.is_empty() {
345+
let mut encoded = Vec::with_capacity(7 * data.len());
346+
encoded.extend(data.iter().flat_map(|msg| msg.encode()));
347+
348+
self.listeners.retain(|listener| !listener.is_closed());
247349

248-
for listener in &self.listeners {
249-
if listener.is_closed() {
250-
continue;
350+
for listener in &self.listeners {
351+
listener.send(encoded.clone()).await.unwrap();
251352
}
353+
}
354+
}
355+
}
252356

253-
listener.send(encoded.to_vec()).await.unwrap();
357+
#[inline(always)]
358+
fn draw_line_fast(data: &mut Vec<u8>, x1: i32, y1: i32, x2: i32, y2: i32, color: &[u8; 3]) {
359+
draw_single_line(data, x1, y1, x2, y2, color);
360+
draw_single_line(data, x1 + 1, y1, x2 + 1, y2, color);
361+
draw_single_line(data, x1, y1 + 1, x2, y2 + 1, color);
362+
draw_single_line(data, x1 + 1, y1 + 1, x2 + 1, y2 + 1, color);
363+
}
364+
365+
#[inline(always)]
366+
fn draw_single_line(
367+
data: &mut Vec<u8>,
368+
mut x1: i32,
369+
mut y1: i32,
370+
x2: i32,
371+
y2: i32,
372+
color: &[u8; 3],
373+
) {
374+
let dx = (x2 - x1).abs();
375+
let dy = -(y2 - y1).abs();
376+
let sx = if x1 < x2 { 1 } else { -1 };
377+
let sy = if y1 < y2 { 1 } else { -1 };
378+
let mut err = dx + dy;
379+
380+
loop {
381+
if x1 >= 0 && x1 < RESOLUTION_WIDTH as i32 && y1 >= 0 && y1 < RESOLUTION_HEIGHT as i32 {
382+
let index = (y1 as usize * RESOLUTION_WIDTH + x1 as usize) * 3;
383+
data[index..index + 3].copy_from_slice(color);
384+
}
385+
386+
if x1 == x2 && y1 == y2 {
387+
break;
388+
}
389+
390+
let e2 = err * 2;
391+
if e2 >= dy {
392+
err += dy;
393+
x1 += sx;
394+
}
395+
if e2 <= dx {
396+
err += dx;
397+
y1 += sy;
254398
}
255399
}
256400
}
401+
402+
#[inline(always)]
403+
fn point_in_triangle_fast(
404+
px: i32,
405+
py: i32,
406+
x1: i32,
407+
y1: i32,
408+
x2: i32,
409+
y2: i32,
410+
x3: i32,
411+
y3: i32,
412+
) -> bool {
413+
let edge1 = (px - x1) * (y2 - y1) - (py - y1) * (x2 - x1);
414+
let edge2 = (px - x2) * (y3 - y2) - (py - y2) * (x3 - x2);
415+
let edge3 = (px - x3) * (y1 - y3) - (py - y3) * (x1 - x3);
416+
417+
(edge1 >= 0 && edge2 >= 0 && edge3 >= 0) || (edge1 <= 0 && edge2 <= 0 && edge3 <= 0)
418+
}

src/main.rs

+1-6
Original file line numberDiff line numberDiff line change
@@ -51,12 +51,7 @@ async fn main() {
5151
headers.insert("Content-Type", "robert/history-2".parse().unwrap());
5252

5353
let data = data.data.as_ref().lock().await;
54-
let body = Body::from(
55-
data.clone()
56-
.iter()
57-
.flat_map(|x| x.to_le_bytes().to_vec())
58-
.collect::<Vec<u8>>(),
59-
);
54+
let body = Body::from(data.clone());
6055

6156
(headers, body)
6257
}),

0 commit comments

Comments
 (0)