FB II Compiler

PG PRO

Debugging

Memory

System

Mathematics

Resources

Disk I/O

Windows

Controls

Menus

Mouse

Keyboard

Text

Fonts

Drawing

Sound

Clipboard

Printing

Communication

ASM

Made with FB

DRAWING

Average overlapping colours


The following code uses regions to separate the overlapping and non-overlapping parts of the circles, and unsigned arithmetic to get an average RGB colour for the overlapping region.
COMPILE ,_dimmedvarsOnly

LOCAL FN RGBAverage(src1RGBPtr&,src2RGBPtr&,destRGBPtr&)
 DIM red1&,green1&,blue1&,red2&,green2&,blue2&
 red1&=src1RGBPtr&.0%
 green1&=src1RGBPtr&.2%
 blue1&=src1RGBPtr&.4%
 red2&=src2RGBPtr&.0%
 green2&=src2RGBPtr&.2%
 blue2&=src2RGBPtr&.4%

 IF red1&<0 THEN red1&=red1&+65536' unsigned
 IF green1&<0 THEN green1&=green1&+65536
 IF blue1&<0 THEN blue1&=blue1&+65536
 IF red2&<0 THEN red2&=red2&+65536
 IF green2&<0 THEN green2&=green2&+65536
 IF blue2&<0 THEN blue2&=blue2&+65536

 destRGBPtr&.0%=(red1&+red2&)>>1' average
 destRGBPtr&.2%=(green1&+green2&)>>1
 destRGBPtr&.4%=(blue1&+blue2&)>>1
END FN

LOCAL FN OverlapOvals(rect1Ptr&,rgb1Ptr&,rect2Ptr&,rgb2Ptr&)
 DIM rgn1&,rgn2&,olapRgn&,avgRGB.6
 rgn1&=FN NEWRGN
 rgn2&=FN NEWRGN
 olapRgn&=FN NEWRGN

 CALL OPENRGN
 CALL FRAMEOVAL(#rect1Ptr&)     ' oval 1
 CALL CLOSERGN(rgn1&)

 CALL OPENRGN
 CALL FRAMEOVAL(#rect2Ptr&)     ' oval 2
 CALL CLOSERGN(rgn2&)

 CALL SECTRGN(rgn1&,rgn2&,olapRgn&)' the overlap
 CALL DIFFRGN(rgn1&,olapRgn&,rgn1&)' remove overlap
 CALL DIFFRGN(rgn2&,olapRgn&,rgn2&)' remove overlap

 CALL RGBFORECOLOR(#rgb1Ptr&)
 CALL PAINTRGN(rgn1&)           ' oval 1
 CALL RGBFORECOLOR(#rgb2Ptr&)
 CALL PAINTRGN(rgn2&)           ' oval 2

 FN RGBAverage(rgb1Ptr&,rgb2Ptr&,@avgRGB)
 CALL RGBFORECOLOR(avgRGB)
 CALL PAINTRGN(olapRgn&)        ' overlap

 CALL DISPOSERGN(rgn1&)
 CALL DISPOSERGN(rgn2&)
 CALL DISPOSERGN(olapRgn&)
END FN

LOCAL FN RandomRGB(destRGBPtr&)
 destRGBPtr&.red%=RND(255)*256
 destRGBPtr&.green%=RND(255)*256
 destRGBPtr&.blue%=RND(255)*256
END FN

DIM rect1.8, rect2.8, myRGB1.6, myRGB2.6, x,y
RANDOMIZE TIMER
WINDOW 1,"Overlap",(0,0)-(630,430)
CALL SETRECT(rect1,10,10,90,90)
CALL SETRECT(rect2,50,10,130,90)
FOR x=0 TO 450 STEP 150
 FOR y=0 TO 300 STEP 150
  FN RandomRGB(@myRGB1)
  FN RandomRGB(@myRGB2)
  CALL SETORIGIN(-x,-y)
  FN OverlapOvals(@rect1,@myRGB1,@rect2,@myRGB2)
 NEXT
NEXT
CALL SETORIGIN(0,0) ' restore QuickDraw origin

DO
 HANDLEEVENTS
UNTIL FN BUTTON
Robert Purves

Don't know if this is what you're looking for, but...
'================

CLEAR LOCAL FN drawCircles
  DIM cirColor.rgbColor
  
  cirColor.Red   = 65535
  cirColor.Green = 40000
  cirColor.Blue  = 40000
  '
  
  PEN ,,,_adMin
  'Note that there are other pen settings
  'that will effect how the colors turn out,
  'here's a couple...
  '_subPin
  '_subOver
  
  CALL RGBFORECOLOR(#@cirColor)
  CIRCLE FILL 100,100,50

cirColor.Red   = 40000
  cirColor.Green = 40000
  cirColor.Blue  = 65535
  CALL RGBFORECOLOR(#@cirColor)
  CIRCLE FILL 150,150,50
  
  CALL PENNORMAL
  
END FN

WINDOW 1

FN drawCircles

DO 
  HANDLEEVENTS
UNTIL 0

'================
Al Boyd

These are 2 routines from one of my programs that blends 2 colo(u)rs where 2 colo(u)red regions overlap.
CLEAR LOCAL
LOCAL FN AvgRGB(red&, green&, blue&, rgbRed&, rgbGreen&, rgbBlue&)
  DIM redRGB, greenRGB, blueRGB
  redRGB = red&
  greenRGB = green&
  blueRGB = blue&
  LONG IF redRGB + greenRGB + blueRGB = 0
    %rgbRed&,13500
    %rgbGreen&,13500
    %rgbBlue&,13500
  XELSE
    %rgbRed&,redRGB
    %rgbGreen&,greenRGB
    %rgbBlue&,blueRGB
  END IF
END FN

CLEAR LOCAL
LOCAL FN AvgPaintRgn(face1, rgn1H&, face2, rgn2H&)
  DIM red&, green&, blue&, rgbRed, rgbGreen, rgbBlue, rgnH&
  DIM red1&, red2&, green1&, green2&, blue1&, blue2&
  rgnH& = FN NEWRGN
  CALL SECTRGN(rgn1H&, rgn2H&, rgnH&)
  red1& = VAL(UNS$(gColor.red%(face1))) : red2& = VAL(UNS$(gColor.red%(face2)))
  red& = (red1& + red2&) / 2&
  green1& = VAL(UNS$(gColor.green%(face1))) : green2& VAL(UNS$(gColor.green%(face2)))
  green& = (green1& + green2&) / 2&
  blue1& = VAL(UNS$(gColor.blue%(face1))) : blue2& VAL(UNS$(gColor.blue%(face2)))
  blue& = (blue1& + blue2&) / 2&
  FN AvgRGB(red&, green&, blue&, @rgbRed, @rgbGreen, @rgbBlue)
  LONG COLOR rgbBlue, rgbGreen, rgbRed
  CALL PAINTRGN(rgnH&)
  DEF DISPOSEH(rgnH&)
END FN
Charlie Dickman

Here is my slow attempt to mix the colours:
DIM color1.RGBColor
DIM color2.RGBColor
END GLOBALS

CLEAR LOCAL
LOCAL FN initColors
  color1.red% = 65535 : color1.green% = 0     : color1.blue% = 0
  color2.red% = 65535 : color2.green% = 65535 : color2.blue% = 0
END FN

CLEAR LOCAL
LOCAL FN drawRects
dim h,v
 DIM togglingflag,thecolor
  DIM myRect1.8
  DIM myRect2.8
  DIM myRect3.8
 
  
  CALL SETRECT(myRect1,20,20,100,100)
  CALL SETRECT(myRect2,50,20,130,100)
  CALL SETRECT(myRect3,50,20,100,100)
  
  CALL RGBFORECOLOR(#@color1) : CALL PAINTRECT(myRect1)
  CALL RGBFORECOLOR(#@color2) : CALL PAINTRECT(myRect2)
  
  FOR h = myRect3.left% TO myRect3.right%
    togglingflag = NOT(togglingflag)
    FOR v = myRect3.top% TO myRect3.bottom%
      LONG IF v MOD 2
        IF togglingflag THEN thecolor = 1 ELSE thecolor = 2
      XELSE
        IF togglingflag THEN thecolor = 2 ELSE thecolor = 1
      END IF
      IF thecolor = 1 THEN CALL SETCPIXEL(h,v,#@color1) ELSE CALL SETCPIXEL(h,v,#@color2)
    NEXT
  NEXT
END FN

WINDOW 1
FN initColors
FN drawRects

DO
UNTIL FN BUTTON OR LEN(INKEY$)
Alain

Phil Yates asked how to colour the overlapping area of two circles. The suggestion to use: PEN ,,,_adMin or other constants seems to change the orginal colours too as it combines the existing colour with the new one.

Here's an short example of a function to draw a circle and create a region for it. Then the region handles can be used to calculate the interseting area and simple averaging can determine the colour used to paint the overlapping region. See pages 297-299 in the FBII Handbook for more info re regions and their commands. - Powerful stuff.
'==================
LOCAL FN drawCircle( h,v, r )
  DIM rect;8
  CALL SETRECT( rect, h-r,v-r, h+r,v+r )
  rgn& = FN NEWRGN
  LONG IF rgn&
    CALL OPENRGN
    CALL FRAMEOVAL( rect )
    CALL CLOSERGN( rgn& )
  END IF
  CALL PAINTRGN( rgn& )
END FN = rgn&
'==================

WINDOW 1
DIM c1&, c2&, overlap&
' use your own colours
red1=64000: green1=00000: blue1=00000     ' pure red
red2=00000: green2=00000: blue2=64000     ' pure blue

red3   = (red1+red2)/2                    ' calc the average colour
green3 = (green1+green2)/2
blue3  = (blue1+blue2)/2

LONG COLOR blue1,green1,red1
c1& = FN drawCircle( 100,150, 50 )
DELAY 1000

LONG COLOR blue2,green2,red2
c2& = FN drawCircle(  90,100, 70 )
DELAY 1000

overlap& = FN NEWRGN                      ' note - need to create a region for next instruction.
CALL SECTRGN( c1&, c2&, overlap& )

LONG COLOR blue3,green3,red3
CALL PAINTRGN( overlap& )
DELAY 1000

DO
  HANDLEEVENTS
UNTIL 0
'==================
Stu

It's been a long time since I did this but here goes: There are other color modes in the Mac than just RGB, HSB for example. There are also easy toolbox calls to convert to and from!

In a similar situation i converted to HSB (Hue, Saturation, Brilliance) and averaged only the hue value, keeping Saturation and brilliance at the same levels, then converted back to RGB for display. It gave satisfactory effects.

Jonathan

I've recently started lurking on the FB listserve. I'm not much of a programmer so I'm not likely to contribute much. As a graduate student in cognitive psychology I do know a little bit about color perception.

Color averaging is a little bit tricky. Before you can figure out the algorithm for averaging, you need to decide what the result should look like. If one circle were fully saturated bright red and the other fully saturated bright green do you want the overlap to be dark brown or yellow. Brown (red = 32767, green = 32767, blue = 0) is what you would get if you mixed paints. Yellow (red = 65535, green = 65535, blue = 0) is what you would get if you shown a red and a green spot light together on a white surface.

Leaving aside the matter of mixing light for the moment, think about a standard color wheel which has the full range of bright, saturated hues around the edge with those hues becoming less saturated ("muddier") toward the center of the circle. Gray is at the center. Suppose you wanted to mix two colors on the rim of the color wheel. They are both bright and saturated. Do you want to find the mid-point between those two colors by moving to the mid-point on the rim of the circle (averaging the hues and retaining brightness and saturation) or do you want to find the midpoint of the straight line that connects the two points (averaging hue, reducing saturation, and leaving brightness unchanged). Averaging RGB values will give you a third result: average hues, reduced brightness, and saturation unchanged.

Averaging RGB values may give you exactly what you want. However, I suggest you test the results with the range of mixtures you are likely to use and make sure you are satisfied. You may be looking for a different effect such as averaging hue, saturation, and brightness (which are the dimensions of psychological "color space").

Chuck Schreiber