Vector / Oscilloscope / CRT Display ––––––––––––––––––––––––––––––––––– init(w,h) ~ ctor reset() -> default draw_frame() -> ffb set_origin set_scale set_rotation set_translation_matrix(a,b,c,d) The display is distorted like this: X = a*x + b*y Y = c*x + d*y An unscaled, undistorted image is achieved with 1,0,0,1 set_clipping set_line_color(r,g,b,a) setting set_fill_color(r,g,b,a) set_text_color(r,g,b,a) set_line_width(w) setting set_text_size(h) new_pen(r,g,b,a,w, r,g,b,a) create (static) move(x,y) move pen draw(x,y,pen=0) draw to draw(x,y,x,y,pen=0) move+draw putc(c,pen=0) draw char puts(s,pen=0) draw text putc(x,y,c,pen=0) draw char puts(x,y,s,pen=0) draw text draw_triangle(shape,linepen=0,fillpen=0) draw_polygon(shape,linepen=0,fillpen=0) draw_polygons(..) draw_triangles(array,linepen=0,fillpen=0) clip_list(..) set_var() get_var() define_proc() run_proc() stop_proc() FORTH worker machine: GVAR define GGET get GSET store LVAR define LGET get LSET store IVAL push ISTR<"text",0> NUMSTR(n--text) ADD,SUB,MUL,DIV,REM SL,SR,AND,OR,XOR EQ,NE,GT,LT,GE,LE IF(cond) ELIF(cond) ELSE ENDIF DO WAIT(frames) WHILE(cond) LOOP PROC END CALL RETURN NEW_PEN (R,G,B,A, W, R,G,B,A) USE_PEN MOVE(x,y) DRAW(x,y) DRAW(x,y,x,y) DRAW_TRIANGLE(x,y,x,y,x,y) DRAW_POLYGON(n,x,y,...) PUTC(c) PUTS(s) • Letter 'D': set hardware scaling, distortion and rotation Arguments: 4 bytes a,b,c,d = signed bytes in range -128 … 0 … +127 The image can be scaled and rotated in hardware. Scaling is intended for scaling down only. This increases the X/Y resolution while the resolution for rotation is reduced. This can be used to compensate display errors on a real device or for effects. The display is distorted like this: X = a*x/120 + b*y/120 Y = c*x/120 + d*y/120 An unscaled, undistorted image with X/Y = [-255 … +255] is achieved with: 'D',120,0,0,120 (default after reset) A double resolution, undistorted image with X/Y = [-510 … +510] is achieved with: 'D',60,0,0,60 Tips: • Store subroutines at the end of the ram. • After reset upload subroutines to draw letters and symbols. The drawing ram is never erased by the terminal. (except: reset overwrites address $0000) Take care not to overwrite the subroutines. When the status byte at the start of a frame is received, you can start overwriting the video ram with commands for the next frame. But you must be careful not to overwrite data for the current frame before it is displayed. At 19200 Baud (1920 char/sec) and 60,000 lines per sec, already 30*(1+5+1) = 210 lines are drawn before the first byte can possibly be received and stored. Actually a RS232 serial line is so slow that only (small) parts of the screen can be updated within one frame. (320 lines/frame at 60Hz) ALTERNATE ––––––––– display: 256 x 256 pixel, 8-bit DACs HW transformation for rotation and zoom effects Drawing Commands: ––––––––––––––––– Some bits are set in each command for the next command: R - 0 = absolute positioning 1 = relative positioning (or control code) C - 1 = beam on E - 1 = enable drawing clock 0 = end of frame I - 1 = raise interrupt if clock stopped There 3 kinds of commands: absolute positioning relative drawing or moving control codes A frame is started by writing the start address into the address counter register 'A'. Start of frame does: set R to 1 (relative position or control code) set C to 1 (enable beam) set E to 1 (enable drawing clock) All commands, except control codes, set the next command to: Relative position (or control code) beam on drawing clock enabled Absolute position: Used to move to the start of a new line. set the counters for the X and Y DACs to dx and dy. all values allowed. (256 x 256 pixel) Absolute positioning is 'immediate' and therefore virtually never drawing. Absolute positioning has no free bits and no free 'unused' values. Relative position: Used to draw lines or to move relative. Relative position command technically always 'draw', though the beam may be switched off. So Relative position should only be used for 'moving' short distances. (not yet required but handy for symbols when call/return implemented.) For simple hardware relative offsets are stored as sign bit + 7 bit absolute value: dx.sign = dx.bit7, dx.absvalue = dx & 0x7F dy.sign = dy.bit7, dy.absvalue = dy & 0x7F The hardware needs to know the absolute values to decide whether to draw in x or y direction, for the number of pixels to draw (in major direction) and for the calculation of side steps. The sign bits control whether the DAC counters count up or down. Control codes: Relative drawing commands have some 'unusable' values, e.g. the 'major' line length may be 0 or any of both offsets may be a negative zero. If dx contains negative zero (dx=$80) this a control code. Then dy contains a command: dy = %ff00RICE The RICE bits set the RICE flags for the next command. ff = 0 NOP: no other action ff = 1 CALL: call subroutine: the next two bytes are the subroutine address (future) ff = 2 RETN: return from subroutine ff = 3 unused If possible, the beam should be switched off during control code execution, else 'spotlights' may appear at these positions. Example: To draw a rectangle around the entire screen: (one might wish to reduce the actually used screen to 255 x 255 pixels in this case) dx dy ––––– ––––––––– CMD NOP + R + E ; select absolute address (and keep clock enabled) 0 0 ; absolute address = (0,0) = bottom left corner 127 0 ; draw 127 pixel rightwards (max. possible value) 127 0 ; draw again 1 0 ; draw a total of 255 pixels 0 127 ; draw upwards 0 127 0 1 -127 0 ; draw leftwards -127 0 -1 0 0 -127 ; draw downwards 0 -127 0 -1 CMD NOP + I ; stop clock and raise interrupt