If you use gimp/photoshop or other kind of 2D software, you probably know that we can paint with a brush on our layer, with a selected blendmode.
It's almost the same as "layer blendmode", but for brush when we paint on the layer .
Here is a code (thanks to stargate, #Null, and Rashad who help me) :
Code: Select all
; blendmode for brush paint, by blendman, help by stargate, #NULL
Enumeration
; painting blendmode
#BM_PaintingDefault
#BM_PaintingNormal
#BM_PaintingNormalBorder
#BM_PaintingMultiply
#BM_PaintingADD
#BM_PaintingScreen
#BM_PaintingLast
; gadgets
#Canvas = 0
#G_BrushBlendmode
#G_brushSize
#G_brushAlpha
#G_brushPas
; images
#Img_brush = 0
#Img_Layer
EndEnumeration
;{ structures
Structure Canvas
LeftButtonDown.i
RightButtonDown.i
EndStructure
Global This.Canvas
Structure VPoint
x.f
y.f
EndStructure
Global PreviousPoint.VPoint
Global CurrentPoint.VPoint, LastPoint.VPoint
Structure sBrush
size.w
alpha.a
blendmode.a
Pas.w ; space betwen two dot
EndStructure
Global Brush.sBrush
Brush\alpha = 140
Brush\blendmode = 0
Brush\pas = 20
Brush\Size = 50
;}
Global draw
;{ procedures
; the blendmode for painting (not for the layer ;))
Procedure PaintingBMNormalBorder(X, Y, SourceColor, TargetColor)
; be carefull with this mode, it can give some weird result ^^
Protected resultColor
Protected r, g, b
Protected a
r = ( Red(sourceColor) * (Alpha(sourceColor) / 255.0) + Red(targetColor) * (1 - (Alpha(sourceColor) / 255.0)))
g = (Green(sourceColor) * (Alpha(sourceColor) / 255.0) + Green(targetColor) * (1 - (Alpha(sourceColor) / 255.0)))
b = ( Blue(sourceColor) * (Alpha(sourceColor) / 255.0) + Blue(targetColor) * (1 - (Alpha(sourceColor) / 255.0)))
If Alpha(sourceColor)=255
a = Alpha(sourceColor)
Else
a = (Alpha(sourceColor) + Alpha(targetColor)) * (1.0 - Alpha(sourceColor))
EndIf
resultColor = RGBA(r, g, b, a)
ProcedureReturn resultColor
EndProcedure
Procedure PaintingBMNormal(X, Y, SourceColor, TargetColor)
; This mode is a few better than the default #pb_2Ddrawing_alphablend, with brtush\alpha<40
Protected resultColor
Protected r, g, b
Protected a
u.d =255.0
If Alpha(targetColor)<=2
r = Red(sourceColor)
g = Green(sourceColor)
b = Blue(sourceColor)
Else
r = ( Red(sourceColor) * (Alpha(sourceColor) / u) + Red(targetColor) * (1 - (Alpha(sourceColor) / u)))
g = (Green(sourceColor) * (Alpha(sourceColor) / u) + Green(targetColor) * (1 - (Alpha(sourceColor) / u)))
b = ( Blue(sourceColor) * (Alpha(sourceColor) / u) + Blue(targetColor) * (1 - (Alpha(sourceColor) / u)))
EndIf
a = Alpha(sourceColor) + Alpha(targetColor) * (1.0 - Alpha(sourceColor)/u)
resultColor = RGBA(r, g, b, a)
ProcedureReturn resultColor
EndProcedure
Procedure PaintingBMMultiply(X,Y,SourceColor, TargetColor)
Protected resultColor
Protected.f r, g, b, a
u.d =255
c.d = (brush\alpha)/255
If Alpha(TargetColor) <5 ; And Alpha(sourceColor)<>0
r = Red(SourceColor)
g = Green(SourceColor)
b = Blue(SourceColor)
Else
r = ( Red(sourceColor) * Red(targetColor) )/ u
If r>255
r=255
EndIf
g = (Green(sourceColor) * Green(targetColor) )/ u
If g>255
g=255
EndIf
b = ( Blue(sourceColor) * Blue(targetColor) )/ u
If b>255
b= 255
EndIf
EndIf
If Alpha(targetColor)=0
a = Alpha(sourceColor)
Else
a =( Alpha(sourceColor) + Alpha(targetColor) * (1.0 - Alpha(sourceColor)/255.0))
EndIf
If a>255
a=255
EndIf
resultColor = RGBA(r, g, b, a)
ProcedureReturn resultColor
EndProcedure
Procedure PaintingBMAdd(X,Y,SourceColor, TargetColor)
Protected resultColor
Protected.f r, g, b, a
u.d = (0.1*brush\alpha)/255
If Alpha(TargetColor) <5 ;And Alpha(sourceColor)<>0
r = Red(SourceColor)
g = Green(SourceColor)
b = Blue(SourceColor)
Else
r = ( Red(sourceColor)*u + Red(targetColor) )
If r>255
r=255
EndIf
g = (Green(sourceColor)*u + Green(targetColor))
If g>255
g=255
EndIf
b = ( Blue(sourceColor)*u + Blue(targetColor))
If b>255
b=255
EndIf
EndIf
If Alpha(targetColor)=0
a = Alpha(sourceColor)
Else
a =( Alpha(sourceColor) + Alpha(targetColor) * (1.0 - Alpha(sourceColor)/255.0))
EndIf
If a>255
a=255
EndIf
resultColor = RGBA(r, g, b, a)
ProcedureReturn resultColor
EndProcedure
Procedure PaintingBMScreen(X,Y,SourceColor,TargetColor)
Protected resultColor
Protected.f r, g, b, a
u.d =(0.1*brush\alpha)/255
If Alpha(TargetColor) <5 ;And Alpha(sourceColor)<>0
r = Red(SourceColor)
g = Green(SourceColor)
b = Blue(SourceColor)
Else
r = 255 -((255-Red(SourceColor)*u)*(255-Red(TargetColor)))/255
g = 255 -((255-Green(SourceColor)*u)*(255-Green(TargetColor)))/255
b = 255 -((255-Blue(SourceColor)*u)*(255-Blue(TargetColor)))/255
EndIf
If Alpha(targetColor)=0
a = Alpha(sourceColor)
Else
a =( Alpha(sourceColor) + Alpha(targetColor) * (1.0 - Alpha(sourceColor)/255.0))
EndIf
If a>255
a=255
EndIf
resultColor = RGBA(r, g, b, a)
ProcedureReturn resultColor
EndProcedure
; for drawing
Macro distance(x1,y1,x2,y2)
Int(Sqr((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1)) )
EndMacro
Macro direction(x1,y1,x2,y2) ; get angle
ATan2((y2- y1),(x2- x1))
EndMacro
Procedure EventDraw()
; help by falsam
Protected Distance, first
Protected CountPoint, N
Protected x = GetGadgetAttribute(#Canvas, #PB_Canvas_MouseX)
Protected y = GetGadgetAttribute(#Canvas, #PB_Canvas_MouseY)
Protected NextPointX.f, NextPointY.f
Protected DeltaX.f, DeltaY.f
Define direction.d, interval.d, pas.d, distBetween2dot.d, thesize.w
Define x1.d, y1.d, x2.f, y2.f, X3.f, y3.f, nextDot.i, color.q
; define the alpha of the brush
Thealpha = Brush\Alpha
With This
Select EventType()
Case #PB_EventType_LeftButtonDown
\LeftButtonDown = #True
PreviousPoint\x = x
PreviousPoint\Y = y
If first = 0
First = 1
Draw = #True
EndIf
Case #PB_EventType_LeftButtonUp
\LeftButtonDown = #False
CurrentPoint\x = x
CurrentPoint\Y = y
Draw = #False
First = 0
Case #PB_EventType_MouseMove
Draw = #False
If \LeftButtonDown
If Thealpha >0 And Thealpha <=255
Draw = #True
EndIf
CurrentPoint\x = x
CurrentPoint\Y = y
EndIf
EndSelect
; Drawing
If Draw
; pas = to calculate the distance between two dots 100/100 => distance=TheSize
Pas = Brush\pas/100
; calcul the size
Thesize = Brush\size
If thesize >=1 And Thealpha > 0 And thealpha <=255
x1 = PreviousPoint\x
y1 = PreviousPoint\y
x2 = CurrentPoint\x
y2 = CurrentPoint\y
; the distancebetween Two dots
distBetween2dot = Thesize*Pas
;distance between two vectors
Distance = Distance(x1,y1, x2,y2)
; number of dots to draw
CountPoint = Distance/(Pas*Thesize)
; Draw !
If StartDrawing(ImageOutput(#Img_layer))
Select Brush\blendmode
Case #BM_paintingNormal ; bm painting normal
DrawingMode(#PB_2DDrawing_AlphaBlend)
Case #BM_PaintingNormalBorder ; bm normal with a strange behavior ^^
DrawingMode(#PB_2DDrawing_CustomFilter)
CustomFilterCallback(@PaintingBMNormalBorder())
Case #BM_PaintingNormal ; bm normal, but a few better with alpha <50 :)
DrawingMode(#PB_2DDrawing_CustomFilter)
CustomFilterCallback(@PaintingBMNormal())
Case #BM_PaintingMultiply
DrawingMode(#PB_2DDrawing_CustomFilter)
CustomFilterCallback(@PaintingBMMultiply())
Case #BM_PaintingScreen
DrawingMode(#PB_2DDrawing_CustomFilter)
CustomFilterCallback(@PaintingBMScreen())
Case #BM_PaintingADD
DrawingMode(#PB_2DDrawing_CustomFilter)
CustomFilterCallback(@PaintingBMAdd())
EndSelect
If distBetween2dot <= distance And CountPoint > 0 And first = 0
direction = direction(x1, y1, x2, y2)
For N = 1 To CountPoint
; then draw the dots
x3 = x1 + n * distBetween2dot * Sin(direction)
y3 = y1 + n * distBetween2dot * Cos(direction)
DrawAlphaImage(ImageID(#Img_brush), x3-Thesize/2, y3-Thesize/2, Thealpha)
Next
PreviousPoint\x = x3
PreviousPoint\y = y3
Else
If first = 1
DrawAlphaImage(ImageID(#Img_brush), x1-Thesize/2, y1-Thesize/2) ; , Thealpha)
EndIf
EndIf
StopDrawing()
EndIf
EndIf
EndIf
EndWith
EndProcedure
Procedure UpdateBrush(create=0)
s = brush\size
; we have to recreate the brush if needed
If create = 1
If IsImage(#Img_brush)
FreeImage(#Img_brush)
EndIf
If CreateImage(#Img_brush,s,s,32,#PB_Image_Transparent)
EndIf
EndIf
; Draw the brush
If StartDrawing(ImageOutput(#Img_brush))
DrawingMode(#PB_2DDrawing_AllChannels)
Select brush\blendmode
Case #BM_PaintingMultiply
Box(0,0,s,s,RGBA(255,255,255,255-brush\alpha))
DrawingMode(#PB_2DDrawing_AlphaBlend)
Case #BM_PaintingADD, #BM_PaintingScreen
Box(0,0,s,s,RGBA(0,0,0,0))
Default
Box(0,0,s,s,RGBA(0,0,0,0))
EndSelect
Circle(s/2, s/2, s/2-2, RGBA(200,150,150,brush\alpha))
StopDrawing()
EndIf
EndProcedure
Procedure UpdateCanvas(clear=0)
If StartDrawing(CanvasOutput(#canvas))
DrawingMode(#PB_2DDrawing_AllChannels)
Box(0,0,OutputWidth(), OutputHeight(),RGBA(200,200,200,255))
; draw the layers
If clear=0
DrawingMode(#PB_2DDrawing_AlphaBlend)
DrawAlphaImage(ImageID(#Img_Layer),0,0)
EndIf
StopDrawing()
EndIf
EndProcedure
Procedure Addtrackbar(gadget,x,y,w,h,min,max,tip$,state)
TrackBarGadget(gadget,x,y,w,h,min,max)
SetGadgetState(gadget,state)
GadgetToolTip(gadget,tip$)
EndProcedure
;}
w=800
h=400
If OpenWindow(0, 0, 0, w, h, "Blendmode painting.", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
CreateImage(#Img_Layer,w-200,h,32,#PB_Image_Transparent)
updateBrush(1)
blendmode$="default,normal,normalBorder,multiply,add,screen,"
nb = CountString(blendmode$, ",")-1
; gadget
Addtrackbar(#G_brushSize,10,10,150,20,1,150,"Brush size",brush\size)
Addtrackbar(#G_brushAlpha,10,40,150,20,0,255,"Brush Alpha",brush\alpha)
Addtrackbar(#G_brushPas,10,70,150,20,1,500,"Brush Pas (space between dots)",brush\pas)
ComboBoxGadget(#G_BrushBlendmode,10,100,150,20)
For i=0 To nb
AddGadgetItem(#G_BrushBlendmode,i,StringField(blendmode$,i+1,","))
Next
SetGadgetState(#G_BrushBlendmode,0)
GadgetToolTip(#G_BrushBlendmode, "painting blendmode")
CanvasGadget(#canvas,200,0,w-200,h)
updatecanvas()
Repeat
Event = WaitWindowEvent()
EventGadget =EventGadget()
If Event = #PB_Event_Gadget
Select EventGadget
Case #canvas
If EventType() = #PB_EventType_LeftButtonDown Or (EventType() = #PB_EventType_MouseMove And GetGadgetAttribute(0, #PB_Canvas_Buttons) & #PB_Canvas_LeftButton)
; draw on the layer with a brush image
Eventdraw()
; update the canvas
updatecanvas()
EndIf
Case #G_brushSize
brush\size= GetGadgetState(EventGadget)
UpdateBrush(1)
Case #G_brushAlpha
brush\alpha= GetGadgetState(EventGadget)
UpdateBrush()
Case #G_brushPas
brush\Pas = GetGadgetState(EventGadget)
Case #G_BrushBlendmode
brush\blendmode = GetGadgetState(EventGadget)
UpdateBrush()
EndSelect
EndIf
Until Event = #PB_Event_CloseWindow
EndIf
Cheers