Posted: 26th Sep 2013 18:16
I wrote a set of anti-aliased drawing routines that write directly to an image memblock. This is useful for creating custom graphics while preserving background transparency.

The box and circle commands can draw either an outline or filled-in. I'm still in the process of adding other commands for gradient filles, but the circle has a radial gradient function.

makeMemblockImage(memblock_num, width, height, fill_color)
mem_circle(memblock_num, centerX, centerY, radius, color, fill, preseveBackground)
mem_circle_gradient_radial(memblock_num, centerX, centerY, radius, innerColor, outerColor, gradient_centerX, gradient_centerY, gradient_radius, preseveBackground)
mem_rounded_box(memblock_num, x1, y1, x2, y2, radius, color, fill, preseveBackground)
mem_line(memblock_num, x1, y1, x2, y2, color, preseveBackground)
mem_box(memblock_num, x1, y1, x2, y2, color, fill, preseveBackground)



The preserveBackground option does just what it says. If turned off, the drawing routine will overwrite any pixel data currently in its pixels' positions. If turned on, it will use a form of alpha compositing to blend the drawing operation on top of any current data. It has a few quirks here and there, but works well in most situations.


Demo
+ Code Snippet
#include "memdraw.dba"



makeMemblockImage(1, 300, 300, E2DC_ARGB(0,0,0,0))


mem_circle(1, 180, 100, 50, E2DC_ARGB(255, 0,255,0), 0, 1)
mem_circle_gradient_radial(1, 100, 150, 50, E2DC_ARGB(255, 0,255,0), E2DC_ARGB(255, 255,255,0), 100,110,50, 1)
mem_rounded_box(1, 2,2,100,125,16, 0xFFBBBBBB, 1, 1)
mem_line(1, 5, 15, 230, 140, E2DC_ARGB(255,255,0,0), 1)
mem_box(1, 20, 1, 120, 300, E2DC_ARGB(92,0,0,255),1,1)

make image from memblock 1, 1
delete memblock 1


sync on
DO

      box 0,0,640,480,rgb(0,255,255), rgb(255,0,0),rgb(0,0,255),rgb(0,255,0)
      

      paste image 1, mousex(), mousey(), 1


      sync
LOOP




Library
+ Code Snippet
REM *****************************************************************
REM COMMANDS:
REM 
REM   makeMemblockImage(memblock_num, width, height, fill_color)
REM   mem_circle(memblock_num, centerX, centerY, radius, color, fill, preseveBackground)
REM   mem_circle_gradient_radial(memblock_num, centerX, centerY, radius, innerColor, outerColor, gradient_centerX, gradient_centerY, gradient_radius, preseveBackground)
REM   mem_rounded_box(memblock_num, x1, y1, x2, y2, radius, color, fill, preseveBackground)
REM   mem_line(memblock_num, x1, y1, x2, y2, color, preseveBackground)
REM   mem_box(memblock_num, x1, y1, x2, y2, color, fill, preseveBackground)
REM 
REM *****************************************************************



REM *****************************************************************
REM
REM Draws a filled in circle with AA edges and a radial gradient
REM 
REM 
REM        -= Parameters =-
REM  mem                - memblock number to draw to
REM  [cx,cy]            - circle's center coordinates
REM  r                  - circle radius
REM  color1             - Inner color for gradient
REM  color2             - Outer color for gradient 
REM  [sx,sy]            - Center coordinates for gradient fill
REM  r2#                - Radius of radial gradient
REM  preserveBackground - TRUE keeps current memblock pixels, 
REM                           using alpha-compositing to draw on top of them
REM                     - FALSE replaces current memblock pixels.
REM *****************************************************************
function mem_circle_gradient_radial(mem, cx as integer, cy as integer, r as integer, color1 as dword, color2 as dword, sx, sy, r2#, preserveBackground as boolean )
      local alpha1 as dword
      local alpha2 as dword
      
      red1   = rgbr(color1)
      green1 = rgbg(color1)
      blue1  = rgbb(color1)
      red2   = rgbr(color2)
      green2 = rgbg(color2)
      blue2  = rgbb(color2)
      a1# = (color1 >> 24) / 255.0
      a2# = (color2 >> 24) / 255.0
      
      x = r
      y = -1
      t# = 0
      gr# = r2#*r2#
      
      while x > y
            inc y
            cur_dist# = E2DC_Distance#(r, y)
            if cur_dist# < t# then dec x
            
            
            if x <> y
                  rem anit-aliased pixels outside the circle
                  c = 127 - (127*cur_dist#)
                  alpha1 = E2DC_ARGB(c*a1#, red1, green1, blue1)
                  alpha2 = E2DC_ARGB(c*a2#, red2, green2, blue2)
                  
                  rem Fill the circle with the gradient
                  for gx = cx-x to cx+x
                        gy = cy-y
                        gy2 = cy+y
                        t1# = (gr#-((gx - sx)^2 + (gy - sy)^2)) / gr#
                        t2# = (gr#-((gx - sx)^2 + (gy2 - sy)^2)) / gr#
                        rem octant 2,7
                        mem_dot(mem, gx, gy, E2DC_Get_LO_Color(color2, color1, t1#), preserveBackground)
                        rem octant 3,6
                        mem_dot(mem, gx, gy2, E2DC_Get_LO_Color(color2, color1, t2#), preserveBackground)
                  next gx
                  for gx = cx-y to cx+y
                        gy = cy-x
                        gy2 = cy+x
                        t1# = (gr#-((gx - sx)^2 + (gy - sy)^2)) / gr#
                        t2# = (gr#-((gx - sx)^2 + (gy2 - sy)^2)) / gr#
                        rem octant 1,8
                        mem_dot(mem, gx, gy, E2DC_Get_LO_Color(color2, color1, t1#), preserveBackground)
                        rem octant 4,5
                        mem_dot(mem, gx, gy2, E2DC_Get_LO_Color(color2, color1, t2#), preserveBackground)
                  next gx
                  
                  
                  rem octant 1
                  t1# = (gr#-(((cx-y) - sx)^2 + ((cy-x-1) - sy)^2)) / gr#
                  mem_dot(mem, cx-y,   cy-x-1, E2DC_Get_LO_Color(alpha2, alpha1, t1#), preserveBackground)
                  rem octant 2
                  t1# = (gr#-(((cx-x-1) - sx)^2 + ((cy-y) - sy)^2)) / gr#
                  mem_dot(mem, cx-x-1, cy-y, E2DC_Get_LO_Color(alpha2, alpha1, t1#), preserveBackground)
                  rem octant 3
                  t1# = (gr#-(((cx-x-1) - sx)^2 + ((cy+y) - sy)^2)) / gr#
                  mem_dot(mem, cx-x-1, cy+y, E2DC_Get_LO_Color(alpha2, alpha1, t1#), preserveBackground)
                  rem octant 4
                  t1# = (gr#-(((cx-y) - sx)^2 + ((cy+x+1) - sy)^2)) / gr#
                  mem_dot(mem, cx-y,   cy+x+1, E2DC_Get_LO_Color(alpha2, alpha1, t1#), preserveBackground)
                  rem octant 5
                  t1# = (gr#-(((cx+y) - sx)^2 + ((cy+x+1) - sy)^2)) / gr#
                  mem_dot(mem, cx+y,   cy+x+1, E2DC_Get_LO_Color(alpha2, alpha1, t1#), preserveBackground)
                  rem octant 6
                  t1# = (gr#-(((cx+x+1) - sx)^2 + ((cy+y) - sy)^2)) / gr#
                  mem_dot(mem, cx+x+1, cy+y, E2DC_Get_LO_Color(alpha2, alpha1, t1#), preserveBackground)
                  rem octant 7
                  t1# = (gr#-(((cx+x+1) - sx)^2 + ((cy-y) - sy)^2)) / gr#
                  mem_dot(mem, cx+x+1, cy-y, E2DC_Get_LO_Color(alpha2, alpha1, t1#), preserveBackground)
                  rem octant 8
                  t1# = (gr#-(((cx+y) - sx)^2 + ((cy-x-1) - sy)^2)) / gr#
                  mem_dot(mem, cx+y,   cy-x-1, E2DC_Get_LO_Color(alpha2, alpha1, t1#), preserveBackground)
            endif     
            t# = cur_dist#
      endwhile
endfunction








REM *****************************************************************
REM
REM Draws a box with rounded corners
REM 
REM 
REM        -= Parameters =-
REM  mem                - memblock number to draw to
REM  [x1,y1]            - upper-left coordinates of box
REM  [x2,y2]            - lower-right coordinates of box
REM  radius             - radius of corners
REM  color              - Box color
REM  solid              - TRUE filled-in box, FALSE outline
REM  preserveBackground - TRUE keeps current memblock pixels, 
REM                           using alpha-compositing to draw on top of them
REM                     - FALSE replaces current memblock pixels.
REM *****************************************************************
function mem_rounded_box(mem, x1, y1, x2, y2, radius, color as dword, solid as boolean, preserveBackground as boolean)
      mem_line(mem, x1+radius+2, y1, x2-radius-2, y1, color, preserveBackground)
      if solid = 0
            mem_line(mem, x1+radius+2, y2, x2-radius-2, y2, color, preserveBackground)
            mem_line(mem, x1, y1+radius+2, x1, y2-radius-2, color, preserveBackground)
            mem_line(mem, x2, y1+radius+2, x2, y2-radius-2, color, preserveBackground)
      else
            mem_box(mem, x1, y1+radius, x2, y2-radius, color, 1, preserveBackground)
            `mem_line(mem, x1+radius, y1, x2-radius, y1, color, preserveBackground)
            mem_line(mem, x1+radius, y2, x2-radius, y2, color, preserveBackground)
      endif
      

      local alpha1 as dword
      local alpha2 as dword
      
      red = rgbr(color)
      green = rgbg(color)
      blue = rgbb(color)
      
      h = y2 - y1
      w = x2 - x1
      cx = x1
      cy = y1

      x = radius
      y = -1
      t# = 0
      r = radius
      
      while x > y
            inc y
            cur_dist# = E2DC_Distance#(r, y)
            if cur_dist# < t# then dec x
            
            
            if x <> y
                  rem anti-aliased pixels inside the circle
                  c = 127*cur_dist#       : alpha1 = E2DC_ARGB(c, red, green, blue)
                  rem anit-aliased pixels outside the circle
                  c = 127 - c             : alpha2 = E2DC_ARGB(c, red, green, blue)      
                  
                  rem Either fill in the middle or draw inside AA pixels
                  if solid = 1
                        mem_box(mem, cx-y+r,   cy-x+1+r, cx+y+w-r,   cy-x+1+r, color, 1, preserveBackground)
                        mem_box(mem, cx-x+1+r, cy-y+r,   cx+x-1+w-r, cy-y+r,   color, 1, preserveBackground)
                        mem_box(mem, cx-x+1+r+1, cy+y+h-r-1, cx+x-1+w-r-1, cy+y+h-r-1, color, 1, preserveBackground)
                        mem_box(mem, cx-y+r+1,   cy+x+h-r-1, cx+y+w-r-1,   cy+x+h-r-1, color, 1, preserveBackground)
                  else
                        mem_dot(mem, cx-y+r,   cy-x+1+r,   alpha1, preserveBackground)
                        mem_dot(mem, cx-x+1+r, cy-y+r,     alpha1, preserveBackground)
                        mem_dot(mem, cx-x+1+r, cy+y+h-r,   alpha1, preserveBackground)
                        mem_dot(mem, cx-y+r,   cy+x-1+h-r, alpha1, preserveBackground)
                        
                        mem_dot(mem, cx+y+w-r,   cy+x-1+h-r, alpha1, preserveBackground)
                        mem_dot(mem, cx+x-1+w-r, cy+y+h-r,   alpha1, preserveBackground)
                        mem_dot(mem, cx+x-1+w-r, cy-y+r,     alpha1, preserveBackground)
                        mem_dot(mem, cx+y+w-r,   cy-x+1+r,   alpha1, preserveBackground)
                        
                  endif
                  
                  rem octant 1
                  mem_dot(mem, cx-y+r+1,   cy-x+r+1,   color,  preserveBackground)
                  mem_dot(mem, cx-y+r+1,   cy-x-1+r+1, alpha2, preserveBackground)
                  rem octant 2
                  mem_dot(mem, cx-x+r+1,   cy-y+r+1, color,  preserveBackground)
                  mem_dot(mem, cx-x-1+r+1, cy-y+r+1, alpha2, preserveBackground)
                  
                  rem octant 3
                  mem_dot(mem, cx-x+r+1,   (cy+y+h-r)-1, color,  preserveBackground)
                  mem_dot(mem, cx-x-1+r+1, (cy+y+h-r)-1, alpha2, preserveBackground)
                  rem octant 4
                  mem_dot(mem, cx-y+r+1,   (cy+x+h-r)-1,   color,  preserveBackground)
                  mem_dot(mem, cx-y+r+1,   (cy+x+1+h-r)-1, alpha2, preserveBackground)
                  rem octant 5
                  mem_dot(mem, cx+y+w-r-1,   cy+x+h-r-1,   color,  preserveBackground)
                  mem_dot(mem, cx+y+w-r-1,   cy+x+1+h-r-1, alpha2, preserveBackground)
                  rem octant 6
                  mem_dot(mem, cx+x+w-r-1,   cy+y+h-r-1, color,  preserveBackground)
                  mem_dot(mem, cx+x+1+w-r-1, cy+y+h-r-1, alpha2, preserveBackground)
                  rem octant 7
                  mem_dot(mem, cx+x+w-r-1,   cy-y+r+1, color,  preserveBackground)
                  mem_dot(mem, cx+x+1+w-r-1, cy-y+r+1, alpha2, preserveBackground)
                  rem octant 8
                  mem_dot(mem, cx+y+w-r-1,   cy-x+r+1,   color,  preserveBackground)
                  mem_dot(mem, cx+y+w-r-1,   cy-x-1+r+1, alpha2, preserveBackground)
                  
            endif     
            t# = cur_dist#
      endwhile
endfunction







REM *****************************************************************
REM
REM Draws a box
REM 
REM 
REM        -= Parameters =-
REM  mem                - memblock number to draw to
REM  [x1,y1]            - upper-left coordinates of box
REM  [x2,y2]            - lower-right coordinates of box
REM  color              - Box color
REM  solid              - TRUE filled-in box, FALSE outline
REM  preserveBackground - TRUE keeps current memblock pixels, 
REM                           using alpha-compositing to draw on top of them
REM                     - FALSE replaces current memblock pixels.
REM *****************************************************************
function mem_box(mem, x1, y1, x2, y2, color as dword, solid as boolean, preserveBackground as boolean)
      if solid = 0
            for x = x1 to x2
                  mem_dot(mem, x, y1, color, preserveBackground)
                  mem_dot(mem, x, y2, color, preserveBackground)
            next x
            for y = y1 to y2
                  mem_dot(mem, x1, y, color, preserveBackground)
                  mem_dot(mem, x2, y, color, preserveBackground)
            next y
      else
            for y = y1 to y2
                  for x = x1 to x2
                        mem_dot(mem, x, y, color, preserveBackground)
                  next x
            next y
      endif
endfunction





REM *****************************************************************
REM
REM Draws a circle with AA edges
REM 
REM 
REM        -= Parameters =-
REM  mem                - memblock number to draw to
REM  [cx,cy]            - circle's center coordinates
REM  r                  - circle radius
REM  color              - Color of circle
REM  solid              - TRUE filled-in box, FALSE outline
REM  preserveBackground - TRUE keeps current memblock pixels, 
REM                           using alpha-compositing to draw on top of them
REM                     - FALSE replaces current memblock pixels.
REM *****************************************************************
function mem_circle(mem, cx as integer, cy as integer, r as integer, color as dword, solid as boolean, preserveBackground as boolean )
      local alpha1 as dword
      local alpha2 as dword
      
      red = rgbr(color)
      green = rgbg(color)
      blue = rgbb(color)
      a# = (color >> 24) / 255.0
      `a# = 1
      x = r
      y = -1
      t# = 0
      
      while x > y
            inc y
            cur_dist# = E2DC_Distance#(r, y)
            if cur_dist# < t# then dec x
            
            
            if x <> y
                  rem anti-aliased pixels inside the circle
                  c = 127*cur_dist#       : alpha1 = E2DC_ARGB(c*a#, red, green, blue)
                  rem anit-aliased pixels outside the circle
                  c = 127 - c             : alpha2 = E2DC_ARGB(c*a#, red, green, blue)      
            
                  rem Either fill in the middle or draw inside AA pixels
                  if solid = 1
                        mem_box(mem, cx-y,   cy-x+1, cx+y,   cy-x+1, color, 1, preserveBackground)
                        mem_box(mem, cx-x+1, cy-y,   cx+x-1, cy-y,   color, 1, preserveBackground)
                        mem_box(mem, cx-x+1, cy+y,   cx+x-1, cy+y,   color, 1, preserveBackground)
                        mem_box(mem, cx-y,   cy+x,   cx+y,   cy+x,   color, 1, preserveBackground)
                  else
                        mem_dot(mem, cx-y,   cy-x+1, alpha1, preserveBackground)
                        mem_dot(mem, cx-x+1, cy-y,   alpha1, preserveBackground)
                        mem_dot(mem, cx-x+1, cy+y,   alpha1, preserveBackground)
                        mem_dot(mem, cx-y,   cy+x-1, alpha1, preserveBackground)
                        mem_dot(mem, cx+y,   cy+x-1, alpha1, preserveBackground)
                        mem_dot(mem, cx+x-1, cy+y,   alpha1, preserveBackground)
                        mem_dot(mem, cx+x-1, cy-y,   alpha1, preserveBackground)
                        mem_dot(mem, cx+y,   cy-x+1, alpha1, preserveBackground)
                  endif
                  
                  rem octant 1
                  mem_dot(mem, cx-y,   cy-x,   color,  preserveBackground)
                  mem_dot(mem, cx-y,   cy-x-1, alpha2, preserveBackground)
                  rem octant 2
                  mem_dot(mem, cx-x,   cy-y, color,  preserveBackground)
                  mem_dot(mem, cx-x-1, cy-y, alpha2, preserveBackground)
                  rem octant 3
                  mem_dot(mem, cx-x,   cy+y, color,  preserveBackground)
                  mem_dot(mem, cx-x-1, cy+y, alpha2, preserveBackground)
                  rem octant 4
                  mem_dot(mem, cx-y,   cy+x,   color,  preserveBackground)
                  mem_dot(mem, cx-y,   cy+x+1, alpha2, preserveBackground)
                  rem octant 5
                  mem_dot(mem, cx+y,   cy+x,   color,  preserveBackground)
                  mem_dot(mem, cx+y,   cy+x+1, alpha2, preserveBackground)
                  rem octant 6
                  mem_dot(mem, cx+x,   cy+y, color,  preserveBackground)
                  mem_dot(mem, cx+x+1, cy+y, alpha2, preserveBackground)
                  rem octant 7
                  mem_dot(mem, cx+x,   cy-y, color,  preserveBackground)
                  mem_dot(mem, cx+x+1, cy-y, alpha2, preserveBackground)
                  rem octant 8
                  mem_dot(mem, cx+y,   cy-x,   color,  preserveBackground)
                  mem_dot(mem, cx+y,   cy-x-1, alpha2, preserveBackground)
            endif     
            t# = cur_dist#
      endwhile
endfunction






REM *****************************************************************
REM
REM Draws an AA line using Xialon Wu's algorithm
REM 
REM 
REM        -= Parameters =-
REM  mem                - memblock number to draw to
REM  [x1,y1]            - Starting coordinate of line
REM  [x2,y2]            - Ending coordinate of line
REM  color              - Color of circle
REM  preserveBackground - TRUE keeps current memblock pixels, 
REM                           using alpha-compositing to draw on top of them
REM                     - FALSE replaces current memblock pixels.
REM *****************************************************************
function mem_line(mem, x1, y1, x2, y2, color as dword, preserveBackground as boolean )
    local dx as float
    local dy as float
    local xend as float
    local yend as float
    local xgap as float
    local ygap as float
    local xpxl1 as float
    local ypxl1 as float
    local xpxl2 as float
    local ypxl2 as float
    local intery as float
    local interx as float
    
    width  = memblock dword(mem, 0)
    height = memblock dword(mem, 4)
        
    red   = rgbr(color)
    green = rgbg(color)
    blue  = rgbb(color)
    
    dx = x2-x1
    dy = y2-y1
        
    if abs(dx) > abs(dy)
        rem handle horizontal lines
        if x2 < x1
            ax = x1                 
            x1 = x2
            x2 = ax
            ay = y1
            y1 = y2
            y2 = ay
        endif
        gradient# = dy / dx
                
        rem handle first endpoint
        xend = ceil(x1)
        yend = y1 + gradient# * (xend-x1)
        xgap = 1.0 - fract#(x1 + 0.5)
        xpxl1 = xend : `used in main loop
        ypxl1 = int(yend)
        f# = 1-fract#(yend)*xgap : `brightness
        alpha = 255*f#
        c = E2DC_ARGB(alpha, red, green, blue)
        mem_dot(mem, xpxl1, ypxl1, c, preserveBackground)
        rem brightness: fract#(yend)*xgap
        f# = fract#(yend)*xgap : `brightness
        alpha = 255*f#
        c = E2DC_ARGB(alpha, red, green, blue)
        mem_dot(mem, xpxl1, ypxl1+1, c, preserveBackground)
        intery = yend + gradient# : `first y-intersection for main loop

        rem handle second endpoint
        xend = ceil(x2)
        yend = y2 + gradient# * (xend-x2)
        xgap = 1.0 - fract#(x2 + 0.5)
        xpxl2 = xend : `used in main loop
        ypxl2 = int(yend)
        f# = 1-fract#(yend)*xgap : `brightness
        alpha = 255*f#
        c = E2DC_ARGB(alpha, red, green, blue)
        mem_dot(mem, xpxl2, ypxl2, c, preserveBackground)
        f# = fract#(yend)*xgap : `brightness
        alpha = 255*f#
        c = E2DC_ARGB(alpha, red, green, blue)
        mem_dot(mem, xpxl2, ypxl2+1, c, preserveBackground)
        
        rem main loop
        a = xpxl1+1
        b = xpxl2-1
        for x = a to b
            f# = 1-fract#(intery) : `brightness
            alpha = 255*f#
            c = E2DC_ARGB(alpha, red, green, blue)
            mem_dot(mem, x, intery, c, preserveBackground)
            f# = fract#(intery) : `brightness
            alpha = 255*f#
            c = E2DC_ARGB(alpha, red, green, blue)
            mem_dot(mem, x, intery+1, c, preserveBackground)
            intery = intery + gradient#
        next x
                
    else
        rem handle vertical lines
        if y2 < y1
            ax = x1
            x1 = x2
            x2 = ax
            ay = y1
            y1 = y2
            y2 = ay
        endif
        
        gradient# = dx / dy
        
        rem handle first endpoint
        yend = ceil(y1)
        xend = x1 + gradient# * (yend-y1)
        ygap = 1.0 - fract#(y1 + 0.5)
        xpxl1 = int(xend)
        ypxl1 = yend            
        f# = 1-fract#(xend)*ygap : `brightness
        alpha = 255*f#
        c = E2DC_ARGB(alpha, red, green, blue)
        mem_dot(mem, xpxl1, ypxl1, c, preserveBackground)
        intery = intery + gradient#
        f# = fract#(xend)*ygap : `brightness
        alpha = 255*f#
        c = E2DC_ARGB(alpha, red, green, blue)
        mem_dot(mem, xpxl1, ypxl1+1, c, preserveBackground)
        interx = xend + gradient# : `first y-intersection for main loop

        rem handle second endpoint
        yend = ceil(y2)
        xend = x2 + gradient# * (yend-y2)
        ygap = fract#(y2 + 0.5)
        xpxl2 = int(xend)
        ypxl2 = yend
        f# = 1-fract#(xend)*ygap : `brightness
        alpha = 255*f#
        c = E2DC_ARGB(alpha, red, green, blue)
        mem_dot(mem, xpxl2, ypxl2, c, preserveBackground)
        f# = fract#(xend)*ygap : `brightness
        alpha = 255*f#
        c = E2DC_ARGB(alpha, red, green, blue)
        mem_dot(mem, xpxl2, ypxl2+1, c, preserveBackground)
        
        rem main loop
        a = ypxl1+1
        b = ypxl2-1
        for y = a to b                  
            f# = 1-fract#(interx) : `brightness
            alpha = 255*f#
            c = E2DC_ARGB(alpha, red, green, blue)
            mem_dot(mem, interx, y, c, preserveBackground)
            f# = fract#(interx) : `brightness
            alpha = 255*f#
            c = E2DC_ARGB(alpha, red, green, blue)
            mem_dot(mem, interx+1, y, c, preserveBackground)
            interx = interx + gradient#
        next y
    endif
endfunction






REM *****************************************************************
REM
REM Creates a memblock with a 32-bit image structure.
REM 
REM 
REM        -= Parameters =-
REM  mem                - memblock number to create
REM  width              - Width of image
REM  height             - height of image
REM  color              - Fill color (0 to leave blank/transparent)
REM *****************************************************************
function makeMemblockImage(mem, width, height, color as dword)
      make memblock mem, width*height*4+12
      write memblock dword mem, 0, width
      write memblock dword mem, 4, height
      write memblock dword mem, 8, 32
      
      if color <> 0
            for y = 0 to height-1
                  for x = 0 to width-1
                        pos = (y*width + x)*4 + 12
                        write memblock dword mem, pos, color
                  next x
            next y
      endif
endfunction








REM *****************************************************************
REM
REM Returns new color using alpha compositing
REM 
REM 
REM    -= Parameters =-
REM  base   - Color of base layer
REM  above  - Color above base layer 
REM           (what you're trying to merge on top of the base)
REM *****************************************************************
function getAlphaComposite(base as dword, above as dword)
      c as dword
      ab = base >> 24
      rb = rgbr(base)
      gb = rgbg(base)
      bb = rgbb(base)
      ab# = ab / 255.0
      
      aa = above >> 24
      ra = rgbr(above)
      ga = rgbg(above)
      ba = rgbb(above)
      aa# = aa / 255.0
      
      red   = ra*aa# + rb*ab#*(1-aa#)
      green = ga*aa# + gb*ab#*(1-aa#)
      blue  = ba*aa# + bb*ab#*(1-aa#)
      alpha = (aa# + ab#*(1-aa#)) * 255
      
      c = E2DC_ARGB(alpha, red, green, blue)
      
endfunction c





REM *****************************************************************
REM
REM Draws a dot to the memblock image
REM 
REM 
REM        -= Parameters =-
REM  mem                - memblock number to draw to
REM  [x,y]              - Coordinates of dot
REM  color              - Color of dot
REM  preserveBackground - TRUE keeps current memblock pixels, 
REM                           using alpha-compositing to draw on top of them
REM                     - FALSE replaces current memblock pixels.
REM *****************************************************************
function mem_dot(mem, x, y, color as dword, preserveBackground as boolean)
      pos = ((y-1)*memblock dword(mem, 0) + (x-1))*4 + 12
      if preserveBackground
            c as dword
            c = memblock dword(mem, pos)
            if c >> 24 > 0 then color = getAlphaComposite(c, color)
      endif
      write memblock dword mem, pos, color
endfunction




REM *****************************************************************
REM
REM Returns a color from the memblock image
REM 
REM 
REM   -= Parameters =-
REM  mem    - memblock number to retrieve color from
REM  [x,y]  - Point in image to retrieve
REM *****************************************************************
function mem_pick(mem, x, y) as dword
      c as dword
      pos = ((y-1)*memblock dword(mem, 0) + (x-1))*4 + 12
      c = memblock dword(mem, pos)
endfunction c




REM **************************************************
REM Truncates the integer part of a float and returns
REM just the decimal value
REM **************************************************
function fract#(x as float)
    a# = x - int(x)
endfunction a#


REM **************************************************
REM Returns a color with an alpha value
REM **************************************************
function E2DC_ARGB(a,r,g,b)
    local c as dword
    c = (a*16777216)+(r*65536)+(g*256)+b
endfunction c




REM **************************************************
REM Returns fractional part of distance
REM   * Needed for Xiaolin Wu functions
REM **************************************************
function E2DC_Distance#(a, b)
    real# = sqrt(a^2 - b^2)
    d# = ceil(real#) - real#
endfunction d#




REM **************************************************
REM Returns a linear interpolated color between base
REM color and target color. Percent ranges from 0 to 1
REM **************************************************
function E2DC_Get_LO_Color(base as dword, target as dword, percent# as float)
      if percent# > 1 then percent# = 1
      if percent# < 0 then percent# = 0
      
      color as dword
      
      br = rgbr(base)
      bg = rgbg(base)
      bb = rgbb(base)
      ba = base >> 24
      
      tr = rgbr(target)
      tg = rgbg(target)
      tb = rgbb(target)
      ta = target >> 24
      
      tr = br + (tr-br)*percent#
      tg = bg + (tg-bg)*percent#
      tb = bb + (tb-bb)*percent#
      ta = ba + (ta-ba)*percent#
      
      color = E2DC_ARGB(ta,tr,tg,tb)
endfunction color




The shapes in the screenshot were all drawn to a single image.