CON #1, _setup, _color, _width, _plot, _line, _arc, _vec, _vecarc, _pix, _pixarc, _text, _textarc, _textmode, _fill, _loop VAR long cog, command, bitmap_base, bitmap_longs, pixel_width, slices[8] word bases[32] PUB setup(x_tiles, y_tiles, x_origin, y_origin, base_ptr) | bases_ptr, slices_ptr '' x_tiles - number of x tiles (tiles are 16x16 pixels each) '' y_tiles - number of y tiles '' x_origin - relative-x center pixel '' y_origin - relative-y center pixel '' base_ptr - base address of bitmap cognew(@loop, @command) setcommand(_loop, 0) 'make sure last command finished repeat bases_ptr from 0 to x_tiles - 1 <# 31 'write bases bases[bases_ptr] := base_ptr + bases_ptr * y_tiles << 6 y_tiles <<= 4 'adjust arguments and do setup command y_origin := y_tiles - y_origin - 1 bases_ptr := @bases slices_ptr := @slices setcommand(_setup, @x_tiles) bitmap_base := base_ptr 'retain high-level bitmap data bitmap_longs := x_tiles * y_tiles PUB clear setcommand(_loop, 0) 'make sure last command finished longfill(bitmap_base, 0, bitmap_longs) 'clear bitmap PUB copy(dest_ptr) setcommand(_loop, 0) 'make sure last command finished longmove(dest_ptr, bitmap_base, bitmap_longs) 'copy bitmap PUB colorwidth(c, w) | pixel_passes, r, i, p '' w - 0..15 for round pixels, 16..31 for square pixels setcommand(_color, @colors[c & 3]) 'set color r := not w & $10 'determine pixel shape/width w &= $F pixel_width := w pixel_passes := w >> 1 + 1 setcommand(_width, @w) 'do width command now to avoid updating slices when busy p := w ^ $F 'update slices to new shape/width repeat i from 0 to w >> 1 slices[i] := true >> (p << 1) << (p & $E) if r and pixels[w] & |< i p += 2 if r and i == pixel_passes - 2 p += 2 PUB plot(x, y) '' Plot point '' x,y - point setcommand(_plot, @x) PUB line(x, y) '' Draw a line to point '' x,y - endpoint setcommand(_line, @x) PUB arc(x, y, xr, yr, angle, anglestep, steps, arcmode) '' Draw an arc '' x,y - center of arc '' xr,yr - radii of arc '' angle - initial angle in bits[12..0] (0..$1FFF = 0ー..359.956ー) '' anglestep - angle step in bits[12..0] '' steps - number of steps (0 just leaves (x,y) at initial arc position) '' arcmode - 0: plot point(s) '' 1: line to point(s) '' 2: line between points '' 3: line from point(s) to center setcommand(_arc, @x) PUB vec(x, y, vecscale, vecangle, vecdef_ptr) '' Draw a vector sprite '' x,y - center of vector sprite '' vecscale - scale of vector sprite ($100 = 1x) '' vecangle - rotation angle of vector sprite in bits[12..0] '' vecdef_ptr - address of vector sprite definition '' Vector sprite definition: '' word $8000|$4000+angle 'vector mode + 13-bit angle (mode: $4000=plot, $8000=line) '' word length 'vector length '' ... 'more vectors '' ... '' word 0 'end of definition setcommand(_vec, @x) PUB vecarc(x, y, xr, yr, angle, vecscale, vecangle, vecdef_ptr) '' Draw a vector sprite at an arc position '' x,y - center of arc '' xr,yr - radii of arc '' angle - angle in bits[12..0] (0..$1FFF = 0ー..359.956ー) '' vecscale - scale of vector sprite ($100 = 1x) '' vecangle - rotation angle of vector sprite in bits[12..0] '' vecdef_ptr - address of vector sprite definition setcommand(_vecarc, @x) PUB pix(x, y, pixrot, pixdef_ptr) '' Draw a pixel sprite '' x,y - center of vector sprite '' pixrot - 0: 0ー, 1: 90ー, 2: 180ー, 3: 270ー, +4: mirror '' pixdef_ptr - address of pixel sprite definition '' Pixel sprite definition: '' word 'word align, express dimensions and center, define pixels '' byte xwords, ywords, xorigin, yorigin '' word %%xxxxxxxx,%%xxxxxxxx '' word %%xxxxxxxx,%%xxxxxxxx '' word %%xxxxxxxx,%%xxxxxxxx '' ... setcommand(_pix, @x) PUB pixarc(x, y, xr, yr, angle, pixrot, pixdef_ptr) '' Draw a pixel sprite at an arc position '' x,y - center of arc '' xr,yr - radii of arc '' angle - angle in bits[12..0] (0..$1FFF = 0ー..359.956ー) '' pixrot - 0: 0ー, 1: 90ー, 2: 180ー, 3: 270ー, +4: mirror '' pixdef_ptr - address of pixel sprite definition setcommand(_pixarc, @x) PUB box(x, y, box_width, box_height) | x2, y2, pmin, pmax '' Draw a box with round/square corners, according to pixel width '' x,y - box left, box bottom if box_width > pixel_width and box_height > pixel_width pmax := pixel_width - (pmin := pixel_width >> 1) 'get pixel-half-min and pixel-half-max x += pmin 'adjust coordinates to accomodate width y += pmin x2 := x + box_width - 1 - pixel_width y2 := y + box_height - 1 - pixel_width plot(x, y) 'plot round/square corners plot(x, y2) plot(x2, y) plot(x2, y2) fill(x, y2 + pmax, 0, (x2 - x) << 16, 0, 0, pmax) 'fill gaps fill(x, y, 0, (x2 - x) << 16, 0, 0, pmin) fill(x - pmin, y2, 0, (x2 - x + pixel_width) << 16, 0, 0, y2 - y) PUB quad(x1, y1, x2, y2, x3, y3, x4, y4) '' Draw a solid quadrilateral '' vertices must be ordered clockwise or counter-clockwise tri(x1, y1, x2, y2, x3, y3) 'draw two triangle to make 4-sides polygon tri(x3, y3, x4, y4, x1, y1) PUB tri(x1, y1, x2, y2, x3, y3) | xy[2] '' Draw a solid triangle ' reorder vertices by descending y case (y1 => y2) & %100 | (y2 => y3) & %010 | (y1 => y3) & %001 %000: longmove(@xy, @x1, 2) longmove(@x1, @x3, 2) longmove(@x3, @xy, 2) %010: longmove(@xy, @x1, 2) longmove(@x1, @x2, 4) longmove(@x3, @xy, 2) %011: longmove(@xy, @x1, 2) longmove(@x1, @x2, 2) longmove(@x2, @xy, 2) %100: longmove(@xy, @x3, 2) longmove(@x2, @x1, 4) longmove(@x1, @xy, 2) %101: longmove(@xy, @x2, 2) longmove(@x2, @x3, 2) longmove(@x3, @xy, 2) ' draw triangle fill(x1, y1, (x3 - x1) << 16 / (y1 - y3 + 1), (x2 - x1) << 16 / (y1 - y2 + 1), (x3 - x2) << 16 / (y2 - y3 + 1), y1 - y2, y1 - y3) PUB finish setcommand(_loop, 0) 'make sure last command finished PRI fill(x, y, da, db, db2, linechange, lines_minus_1) setcommand(_fill, @x) PRI setcommand(cmd, argptr) command := cmd << 16 + argptr 'write command and pointer repeat while command 'wait for command to be cleared, signifying receipt DAT colors long %%0000000000000000 long %%1111111111111111 long %%2222222222222222 long %%3333333333333333 pixels byte %00000000,%00000000,%00000000,%00000000 '0,1,2,3 byte %00000000,%00000000,%00000010,%00000101 '4,5,6,7 byte %00001010,%00001010,%00011010,%00011010 '8,9,A,B byte %00110100,%00111010,%01110100,%01110100 'C,D,E,F DAT org loop rdlong t1,par wz 'wait for command if_z jmp #loop movd :arg,#arg0 'get 8 arguments mov t2,t1 mov t3,#8 :arg rdlong arg0,t2 add :arg,d0 add t2,#4 djnz t3,#:arg wrlong zero,par 'zero command to signify received call #setd 'set dx,dy from arg0,arg1 ror t1,#16+2 'lookup command address add t1,#jumps movs :table,t1 rol t1,#2 shl t1,#3 :table mov t2,0 shr t2,t1 and t2,#$FF jmp t2 'jump to command jumps byte 0 '0 byte setup_ '1 byte color_ '2 byte width_ '3 byte plot_ '4 byte line_ '5 byte arc_ '6 byte vec_ '7 byte vecarc_ '8 byte pix_ '9 byte pixarc_ 'A byte text_ 'B byte text_ 'C byte text_ 'D byte fill_ 'E byte loop 'F ' setup(x_tiles, y_tiles*16, x_origin, y_origin, base_ptr) bases_ptr, slices_ptr setup_ mov xlongs,arg0 'set xlongs, ylongs mov ylongs,arg1 mov xorigin,arg2 'set xorigin, yorigin mov yorigin,arg3 mov basesptr,arg5 'set pointers mov slicesptr,arg6 jmp #loop color_ mov pcolor,arg0 'set pixel color jmp #loop width_ mov pwidth,arg0 'set pixel width mov passes,arg1 'set pixel passes jmp #loop plot_ call #plotd jmp #loop line_ call #linepd jmp #loop arc_ and arg7,#3 'limit mode :loop call #arca 'get arc dx,dy cmp arg7,#1 wz 'if not mode 1, set px,py if_nz mov px,dx if_nz mov py,dy tjz arg6,#loop 'if no points exit with new px,py cmp arg7,#3 wz 'if mode 3, set center if_z call #setd test arg7,#1 wz 'if mode 0 or 2, plot point if_z call #plotp test arg7,#1 wz 'if mode 1 or 3, plot line if_nz call #linepd cmp arg7,#2 wz 'if mode 2, set mode 1 if_z mov arg7,#1 add arg4,arg5 'step angle djnz arg6,#:loop 'loop if more iterations jmp #loop ' vec(x, y, vecscale, vecangle, vecdef_ptr) ' vecarc(x, y, xr, yr, angle, vecscale, vecangle, vecdef_ptr) ' vecdef: word $8000/$4000+angle 'vector mode + 13-bit angle (mode: $4000=plot, $8000=line) ' word length 'vector length ' ... 'more vectors ' ... ' word 0 'end of definition vecarc_ call #arcmod vec_ tjz arg2,#loop 'if scale 0, exit :loop rdword t7,arg4 wz 'get vector mode+angle add arg4,#2 if_z jmp #loop 'if mode+angle 0, exit rdword t1,arg4 'get vector length add arg4,#2 abs t2,arg2 wc 'add/sub vector angle to/from angle mov t6,arg3 sumc t6,t7 call #multiply 'multiply length by scale add t1,#$80 'round up 1/2 lsb shr t1,#8 mov t4,t1 'get arc dx,dy mov t5,t1 call #arcd test t7,h8000 wc 'plot pixel or draw line? if_nc call #plotd test t7,h8000 wc if_c call #linepd jmp #:loop 'get next vector ' pix(x, y, pixrot, pixdef_ptr) ' pixarc(x, y, xr, yr, angle, pixrot, pixdef_ptr) ' pixdef: word ' byte xwords, ywords, xorigin, yorigin ' word %%xxxxxxxx,%%xxxxxxxx ' word %%xxxxxxxx,%%xxxxxxxx ' word %%xxxxxxxx,%%xxxxxxxx ' ... pixarc_ call #arcmod pix_ mov t6,pcolor 'save color mov px,dx 'get center into px,py mov py,dy mov sy,pwidth 'get actual pixel width add sy,#1 rdbyte dx,arg3 'get dimensions into dx,dy add arg3,#1 rdbyte dy,arg3 add arg3,#1 rdbyte t1,arg3 'get origin and adjust px,py add arg3,#1 rdbyte t2,arg3 add arg3,#1 neg t2,t2 sub t2,#1 add t2,dy mov t3,sy :adjust test arg2,#%001 wz test arg2,#%110 wc if_z sumnc px,t1 if_nz sumc py,t1 test arg2,#%010 wc if_nz sumnc px,t2 if_z sumnc py,t2 djnz t3,#:adjust :yline mov sx,#0 'plot entire pix mov t3,dx :xword rdword t4,arg3 'read next pix word add arg3,#2 shl t4,#16 mov t5,#8 :xpixel rol t4,#2 'plot pixel within word test t4,#1 wc 'set color muxc pcolor,color1 test t4,#2 wc muxc pcolor,color2 wz '(z=1 if color=0) if_nz call #plotp test arg2,#%001 wz 'update px,py for next x test arg2,#%110 wc if_z sumc px,sy if_nz sumnc py,sy add sx,sy djnz t5,#:xpixel 'another x pixel? djnz t3,#:xword 'another x word? if_z sumnc px,sx 'update px,py for next y if_nz sumc py,sx test arg2,#%010 wc if_nz sumc px,sy if_z sumc py,sy djnz dy,#:yline 'another y line? mov pcolor,t6 'restore color jmp #loop setd mov dx,xorigin 'set dx,dy from arg0,arg1 add dx,arg0 mov dy,yorigin sub dy,arg1 setd_ret ret text_ jmp #loop ' fill(x, y, da, db, db2, linechange, lines_minus_1) fill_ shl dx,#16 'get left and right fractions or dx,h8000 mov t1,dx mov t2,xlongs 'get x pixels shl t2,#4 add arg6,#1 'pre-increment line counter :yloop add dx,arg2 'adjust left and right fractions add t1,arg3 cmps dx,t1 wc 'get left and right integers if_c mov base0,dx if_c mov base1,t1 if_nc mov base0,t1 if_nc mov base1,dx sar base0,#16 sar base1,#16 cmps base0,t2 wc 'left out of range? if_c cmps hFFFFFFFF,base1 wc 'right out of range? if_c cmp dy,ylongs wc 'y out of range? if_nc jmp #:skip 'if any, skip mins base0,#0 'limit left and right maxs base1,t2 wc if_nc sub base1,#1 shl base0,#1 'make left mask neg mask0,#1 shl mask0,base0 shr base0,#5 shl base1,#1 'make right mask xor base1,#$1E neg mask1,#1 shr mask1,base1 shr base1,#5 sub base1,base0 wz 'ready long count add base1,#1 if_z and mask0,mask1 'if single long, merge masks shl base0,#1 'get long base add base0,basesptr rdword base0,base0 shl dy,#2 add base0,dy shr dy,#2 mov bits0,mask0 'ready left mask :xloop mov bits1,pcolor 'make color mask and bits1,bits0 rdlong pass,base0 'read-modify-write long andn pass,bits0 or pass,bits1 wrlong pass,base0 shl ylongs,#2 'advance to next long add base0,ylongs shr ylongs,#2 cmp base1,#2 wz 'one more? if_nz neg bits0,#1 'if not, ready full mask if_z mov bits0,mask1 'if one more, ready right mask djnz base1,#:xloop 'loop if more longs :skip sub arg5,#1 wc 'delta change? if_c mov arg3,arg4 'if so, set new deltas :same add dy,#1 'adjust y djnz arg6,#:yloop 'another y? jmp #loop ' Plot line from px,py to dx,dy linepd cmps dx,px wc, wr 'get x difference negc sx,#1 'set x direction cmps dy,py wc, wr 'get y difference negc sy,#1 'set y direction abs dx,dx 'make differences absolute abs dy,dy cmp dx,dy wc 'determine dominant axis if_nc tjz dx,#:last 'if both differences 0, plot single pixel if_nc mov count,dx 'set pixel count if_c mov count,dy mov ratio,count 'set initial ratio shr ratio,#1 if_c jmp #:yloop 'x or y dominant? :xloop call #plotp 'dominant x line add px,sx sub ratio,dy wc if_c add ratio,dx if_c add py,sy djnz count,#:xloop jmp #:last 'plot last pixel :yloop call #plotp 'dominant y line add py,sy sub ratio,dx wc if_c add ratio,dy if_c add px,sx djnz count,#:yloop :last call #plotp 'plot last pixel linepd_ret ret ' Plot pixel at px,py plotd mov px,dx 'set px,py to dx,dy mov py,dy plotp tjnz pwidth,#wplot 'if width > 0, do wide plot mov t1,px 'compute pixel mask shl t1,#1 mov mask0,#%11 shl mask0,t1 shr t1,#5 cmp t1,xlongs wc 'if x or y out of bounds, exit if_c cmp py,ylongs wc if_nc jmp #plotp_ret mov bits0,pcolor 'compute pixel bits and bits0,mask0 shl t1,#1 'get address of pixel long add t1,basesptr mov t2,py rdword t1,t1 shl t2,#2 add t1,t2 rdlong t2,t1 'write pixel andn t2,mask0 or t2,bits0 wrlong t2,t1 plotp_ret plotd_ret ret ' Plot wide pixel wplot mov t1,py 'if y out of bounds, exit add t1,#7 mov t2,ylongs add t2,#7+8 cmp t1,t2 wc if_nc jmp #plotp_ret mov t1,px 'determine x long pair sub t1,#8 sar t1,#4 cmp t1,xlongs wc muxc jumps,#%01 '(use jumps[1..0] to store writes) add t1,#1 cmp t1,xlongs wc muxc jumps,#%10 test jumps,#%11 wz 'if x out of bounds, exit if_z jmp #plotp_ret shl t1,#1 'get base pair add t1,basesptr rdword base1,t1 sub t1,#2 rdword base0,t1 mov t1,px 'determine pair shifts shl t1,#1 movs :shift1,t1 xor :shift1,#7<<1 add t1,#9<<1 movs :shift0,t1 test t1,#$F<<1 wz '(account for special case) if_z andn jumps,#%01 mov pass,#0 'ready to plot slices mov slice,slicesptr :loop rdlong mask0,slice 'get next slice mov mask1,mask0 :shift0 shl mask0,#0 'position slice :shift1 shr mask1,#0 mov bits0,pcolor 'colorize slice and bits0,mask0 mov bits1,pcolor and bits1,mask1 mov t1,py 'plot lower slice add t1,pass cmp t1,ylongs wc if_c call #wslice mov t1,py 'plot upper slice test pwidth,#1 wc subx t1,pass cmp t1,ylongs wc if_c call #wslice add slice,#4 'next slice add pass,#1 cmp pass,passes wz if_nz jmp #:loop jmp #plotp_ret ' Plot wide pixel slice wslice shl t1,#2 'ready long offset add base0,t1 'plot left slice test jumps,#%01 wc if_c rdlong t2,base0 if_c andn t2,mask0 if_c or t2,bits0 if_c wrlong t2,base0 add base1,t1 'plot right slice test jumps,#%10 wc if_c rdlong t2,base1 if_c andn t2,mask1 if_c or t2,bits1 if_c wrlong t2,base1 sub base0,t1 'restore bases sub base1,t1 wslice_ret ret ' Get arc point from args and then move args 5..7 to 2..4 arcmod call #arca 'get arc using first 5 args mov arg0,dx 'set arg0,arg1 sub arg0,xorigin mov arg1,yorigin sub arg1,dy mov arg2,arg5 'move args 5..7 to 2..4 mov arg3,arg6 mov arg4,arg7 arcmod_ret ret ' Get arc dx,dy from arg0,arg1 ' in: arg0,arg1 = center x,y ' arg2/t4 = x length ' arg3/t5 = y length ' arg4/t6 = 13-bit angle ' out: dx,dy = arc point arca mov t4,arg2 'use args mov t5,arg3 mov t6,arg4 arcd call #setd 'reset dx,dy to arg0,arg1 mov t1,t6 'get arc dx mov t2,t4 call #polarx add dx,t1 mov t1,t6 'get arc dy mov t2,t5 call #polary sub dy,t1 arcd_ret arca_ret ret ' Polar to cartesian ' in: t1 = 13-bit angle ' t2 = 16-bit length ' out: t1 = x|y polarx add t1,sine_90 'cosine, add 90ー for sine lookup polary test t1,sine_180 wz 'get sine quadrant 3|4 into nz test t1,sine_90 wc 'get sine quadrant 2|4 into c negc t1,t1 'if sine quadrant 2|4, negate table offset or t1,sine_table 'or in sine table address >> 1 shl t1,#1 'shift left to get final word address rdword t1,t1 'read sine/cosine word call #multiply 'multiply sine/cosine by length to get x|y add t1,h8000 'add 1/2 lsb to round up x|y fraction shr t1,#16 'justify x|y integer negnz t1,t1 'if sine quadrant 3|4, negate x|y polary_ret polarx_ret ret sine_90 long $0800 '90ー bit sine_180 long $1000 '180ー bit sine_table long $E000 >> 1 'sine table address shifted right ' Multiply ' in: t1 = 16-bit multiplicand (t1[31..16] must be 0) ' t2 = 16-bit multiplier ' out: t1 = 32-bit product multiply mov t3,#16 shl t2,#16 shr t1,#1 wc :loop if_c add t1,t2 wc rcr t1,#1 wc djnz t3,#:loop multiply_ret ret ' Defined data zero long 0 'constants d0 long $200 h8000 long $8000 hFFFFFFFF long $FFFFFFFF color1 long %%1111111111111111 color2 long %%2222222222222222 pcolor long %%1111111111111111 'pixel color pwidth long 0 'pixel width passes long 1 'pixel passes ' Undefined data t1 res 1 'temps t2 res 1 t3 res 1 t4 res 1 t5 res 1 t6 res 1 t7 res 1 arg0 res 1 'arguments passed from high-level arg1 res 1 arg2 res 1 arg3 res 1 arg4 res 1 arg5 res 1 arg6 res 1 arg7 res 1 basesptr res 1 'pointers slicesptr res 1 xlongs res 1 'bitmap metrics ylongs res 1 xorigin res 1 yorigin res 1 dx res 1 'line/plot coordinates dy res 1 px res 1 py res 1 sx res 1 'line sy res 1 count res 1 ratio res 1 pass res 1 'plot slice res 1 base0 res 1 base1 res 1 mask0 res 1 mask1 res 1 bits0 res 1 bits1 res 1