@@ -11,17 +11,18 @@ use num_traits::float::FloatCore;
1111use widestring:: { U16Str , u16str} ;
1212
1313use super :: {
14- BuildingData , Content , LObject , LString , LValue , LVar , LogicVM , ProcessorState , VMLoadError ,
15- VMLoadResult ,
14+ BuildingData , Content , DrawCommand , LObject , LString , LValue , LVar , LogicVM , ProcessorState ,
15+ TextAlignment , VMLoadError , VMLoadResult ,
1616 buildings:: borrow_data,
17- processor:: MAX_TEXT_BUFFER ,
17+ draw:: SCALE_STEP ,
18+ processor:: { MAX_DRAW_BUFFER , MAX_TEXT_BUFFER } ,
1819 variables:: { Constants , F64_DEG_RAD , F64_RAD_DEG , RAD_DEG } ,
1920} ;
2021use crate :: {
21- parser:: ast:: { self , ConditionOp , LogicOp , TileLayer } ,
22+ parser:: ast:: { self , ConditionOp , DrawOp , LogicOp , TileLayer } ,
2223 types:: {
2324 ContentType , LAccess , PackedPoint2 , Team ,
24- colors:: { self , f32_to_double_bits, f64_from_double_bits} ,
25+ colors:: { self , f32_to_double_bits, f64_from_double_bits, from_double_bits } ,
2526 content,
2627 } ,
2728 utils:: { RapidHashMap , u16format} ,
@@ -68,10 +69,12 @@ pub enum Instruction {
6869 // input/output
6970 Read ,
7071 Write ,
72+ Draw ,
7173 Print ,
7274 PrintChar ,
7375 Format ,
7476 // block control
77+ DrawFlush ,
7578 PrintFlush ,
7679 GetLink ,
7780 Control ,
@@ -192,31 +195,32 @@ impl InstructionBuilder {
192195 . into ( ) ,
193196 // TODO: implement draw?
194197 ast:: Instruction :: Draw {
195- op : _ ,
198+ op,
196199 x,
197200 y,
198201 p1,
199202 p2,
200203 p3,
201204 p4,
202- } => {
203- lvar ( x ) ;
204- lvar ( y ) ;
205- lvar ( p1 ) ;
206- lvar ( p2 ) ;
207- lvar ( p3 ) ;
208- lvar ( p4 ) ;
209- Noop . into ( )
205+ } => Draw {
206+ op ,
207+ p1 : lvar ( x ) ,
208+ p2 : lvar ( y ) ,
209+ p3 : lvar ( p1 ) ,
210+ p4 : lvar ( p2 ) ,
211+ p5 : lvar ( p3 ) ,
212+ p6 : lvar ( p4 ) ,
210213 }
214+ . into ( ) ,
211215 ast:: Instruction :: Print { value } => Print { value : lvar ( value) } . into ( ) ,
212216 ast:: Instruction :: PrintChar { value } => PrintChar { value : lvar ( value) } . into ( ) ,
213217 ast:: Instruction :: Format { value } => Format { value : lvar ( value) } . into ( ) ,
214218
215219 // block control
216- ast:: Instruction :: DrawFlush { target } => {
217- lvar ( target) ;
218- Noop . into ( )
220+ ast:: Instruction :: DrawFlush { target } => DrawFlush {
221+ target : lvar ( target) ,
219222 }
223+ . into ( ) ,
220224 ast:: Instruction :: PrintFlush { target } => PrintFlush {
221225 target : lvar ( target) ,
222226 }
@@ -498,6 +502,128 @@ impl InstructionTrait for Write {
498502 }
499503}
500504
505+ #[ derive( Debug ) ]
506+ #[ non_exhaustive]
507+ pub struct Draw {
508+ pub op : DrawOp ,
509+ pub p1 : LVar ,
510+ pub p2 : LVar ,
511+ pub p3 : LVar ,
512+ pub p4 : LVar ,
513+ pub p5 : LVar ,
514+ pub p6 : LVar ,
515+ }
516+
517+ impl SimpleInstructionTrait for Draw {
518+ fn execute ( & self , state : & mut ProcessorState , _: & LogicVM ) {
519+ if state. drawbuffer_len >= MAX_DRAW_BUFFER {
520+ return ;
521+ }
522+
523+ let p1 = self . p1 . get_inner ( state, & state. variables ) ;
524+ let p2 = self . p2 . get_inner ( state, & state. variables ) ;
525+ let p3 = self . p3 . get_inner ( state, & state. variables ) ;
526+ let p4 = self . p4 . get_inner ( state, & state. variables ) ;
527+ let p5 = self . p5 . get_inner ( state, & state. variables ) ;
528+ let p6 = self . p6 . get_inner ( state, & state. variables ) ;
529+
530+ let mut size = 1 ;
531+ state. drawbuffer . push ( match self . op {
532+ DrawOp :: Clear => DrawCommand :: Clear {
533+ r : p1. numi ( ) as u8 ,
534+ g : p2. numi ( ) as u8 ,
535+ b : p3. numi ( ) as u8 ,
536+ } ,
537+ DrawOp :: Color => DrawCommand :: Color {
538+ r : p1. numi ( ) as u8 ,
539+ g : p2. numi ( ) as u8 ,
540+ b : p3. numi ( ) as u8 ,
541+ a : p4. numi ( ) as u8 ,
542+ } ,
543+ DrawOp :: Col => {
544+ let ( r, g, b, a) = from_double_bits ( p1. num ( ) ) ;
545+ DrawCommand :: Color { r, g, b, a }
546+ }
547+ DrawOp :: Stroke => DrawCommand :: Stroke {
548+ width : p1. numi ( ) as i16 ,
549+ } ,
550+ DrawOp :: Line => DrawCommand :: Line {
551+ x1 : p1. numi ( ) as i16 ,
552+ y1 : p2. numi ( ) as i16 ,
553+ x2 : p3. numi ( ) as i16 ,
554+ y2 : p4. numi ( ) as i16 ,
555+ } ,
556+ DrawOp :: Rect | DrawOp :: LineRect => DrawCommand :: Rect {
557+ x : p1. numi ( ) as i16 ,
558+ y : p2. numi ( ) as i16 ,
559+ width : p3. numi ( ) as i16 ,
560+ height : p4. numi ( ) as i16 ,
561+ fill : self . op == DrawOp :: Rect ,
562+ } ,
563+ DrawOp :: Poly | DrawOp :: LinePoly => DrawCommand :: Poly {
564+ x : p1. numi ( ) as i16 ,
565+ y : p2. numi ( ) as i16 ,
566+ sides : p3. numi ( ) as i16 ,
567+ radius : p4. numi ( ) as i16 ,
568+ rotation : p5. numi ( ) as i16 ,
569+ fill : self . op == DrawOp :: Poly ,
570+ } ,
571+ DrawOp :: Triangle => DrawCommand :: Triangle {
572+ x1 : p1. numi ( ) as i16 ,
573+ y1 : p2. numi ( ) as i16 ,
574+ x2 : p3. numi ( ) as i16 ,
575+ y2 : p4. numi ( ) as i16 ,
576+ x3 : p5. numi ( ) as i16 ,
577+ y3 : p6. numi ( ) as i16 ,
578+ } ,
579+ DrawOp :: Image => DrawCommand :: Image {
580+ x : p1. numi ( ) as i16 ,
581+ y : p2. numi ( ) as i16 ,
582+ image : match p3. obj ( ) {
583+ Some ( LObject :: Content ( content) ) => Some ( * content) ,
584+ _ => None ,
585+ } ,
586+ size : p4. numi ( ) as i16 ,
587+ rotation : p5. numi ( ) as i16 ,
588+ } ,
589+ DrawOp :: Print => {
590+ if state. printbuffer . is_empty ( ) {
591+ return ;
592+ }
593+
594+ // newlines don't count toward the length limit
595+ size = state
596+ . printbuffer
597+ . as_slice ( )
598+ . iter ( )
599+ . filter ( |v| * * v != b'\n' as u16 )
600+ . count ( ) ;
601+
602+ DrawCommand :: Print {
603+ x : p1. numi ( ) as i16 ,
604+ y : p2. numi ( ) as i16 ,
605+ alignment : TextAlignment :: from_bits_truncate ( p3. numi ( ) as u8 ) ,
606+ // FIXME: lazy
607+ text : core:: mem:: take ( & mut state. printbuffer ) ,
608+ }
609+ }
610+ DrawOp :: Translate => DrawCommand :: Translate {
611+ x : p1. numi ( ) as i16 ,
612+ y : p2. numi ( ) as i16 ,
613+ } ,
614+ DrawOp :: Scale => DrawCommand :: Scale {
615+ x : ( p1. numf ( ) / SCALE_STEP ) as i16 ,
616+ y : ( p2. numf ( ) / SCALE_STEP ) as i16 ,
617+ } ,
618+ DrawOp :: Rotate => DrawCommand :: Rotate {
619+ degrees : p1. numi ( ) as i16 ,
620+ } ,
621+ DrawOp :: Reset => DrawCommand :: Reset ,
622+ } ) ;
623+ state. drawbuffer_len += size;
624+ }
625+ }
626+
501627#[ derive( Debug ) ]
502628#[ non_exhaustive]
503629pub struct Print {
@@ -601,6 +727,27 @@ impl SimpleInstructionTrait for Format {
601727
602728// block control
603729
730+ #[ derive( Debug ) ]
731+ #[ non_exhaustive]
732+ pub struct DrawFlush {
733+ pub target : LVar ,
734+ }
735+
736+ impl InstructionTrait for DrawFlush {
737+ fn execute ( & self , state : & mut ProcessorState , vm : & LogicVM ) -> InstructionResult {
738+ let result = if let Some ( LObject :: Building ( target) ) = self . target . get ( state) . obj ( )
739+ && let Ok ( mut data) = target. data . clone ( ) . try_borrow_mut ( )
740+ && let BuildingData :: Custom ( custom) = & mut * data
741+ {
742+ custom. drawflush ( state, vm)
743+ } else {
744+ InstructionResult :: Ok
745+ } ;
746+ state. drawbuffer . clear ( ) ;
747+ result
748+ }
749+ }
750+
604751#[ derive( Debug ) ]
605752#[ non_exhaustive]
606753pub struct PrintFlush {
0 commit comments