Math and vector graphics

Just starting out? Need help? Post your questions and find answers here.
User avatar
Michael Vogel
Addict
Addict
Posts: 2677
Joined: Thu Feb 09, 2006 11:27 pm
Contact:

Math and vector graphics

Post by Michael Vogel »

Would need some help again, I'd like to do rounded rectangles with light and shadow effect which works fine under simple conditions. But when using narrow boxes, everything gets scrambled... (I also want to implement a drop shadow which is even more complicate)

Here's an example which uses extra a large radius and wide light/shadow stripes to demonstrate the issues. Anyone good in math do create an universally working solution?

Code: Select all

Procedure Min(a,b)
	If a<b
		ProcedureReturn a
	Else
		ProcedureReturn b
	EndIf
EndProcedure

Procedure AddPathRoundBox(x.d,y.d,w.d,h.d,radius.d,flags=#PB_Path_Default)

	If radius>h/2 : radius=h/2 : EndIf
	If radius>w/2 : radius=w/2 : EndIf

	If radius<0
		radius=0
	EndIf

	MovePathCursor(x+radius,y,flags)

	AddPathArc(w-radius,0,w-radius,radius,radius,#PB_Path_Relative)
	AddPathArc(0,h-radius,-radius,h-radius,radius,#PB_Path_Relative)
	AddPathArc(-w+radius,0,-w+radius,-radius,radius,#PB_Path_Relative)
	AddPathArc(0,-h+radius,radius,-h+radius,radius,#PB_Path_Relative)

	ClosePath()

	MovePathCursor(-radius,0,#PB_Path_Relative)

EndProcedure
Procedure AddPathHighlight(x.d,y.d,w.d,h.d,r.d,angle.d,flags=#PB_Path_Default)

	Protected t1.d,t2.d,t3.d,t4.d,t5.d

	t1=Cos(angle*#PI/180);	1-89°
	t2=Sin(angle*#PI/180)
	t3=r*t1
	t4=r*t2
	t5=2*r-t4

	MovePathCursor(x,y+r,flags)
	AddPathCircle(r,0,r,180,270,#PB_Path_Relative)
	AddPathLine(w-r*2,0,#PB_Path_Relative)
	AddPathCircle(0,r,r,270,270+angle,#PB_Path_Relative|#PB_Path_Connected)
	AddPathLine(-w+t5,0,#PB_Path_Relative)
	AddPathCircle(0,t3,t3,270,180,#PB_Path_Relative|#PB_Path_Connected|#PB_Path_CounterClockwise)
	AddPathLine(0,h-t5,#PB_Path_Relative)
	AddPathCircle(t3,-t4,r,180-angle,180,#PB_Path_Relative|#PB_Path_Connected)

	ClosePath()

EndProcedure
Procedure AddPathShadow(x.d,y.d,w.d,h.d,r.d,angle.d,flags=#PB_Path_Default)

	Protected ro.d
	Protected t1.d,t2.d,t3.d,t4.d,t5.d

	ro=Min(Min(r,h/2),w/2)

	t1=Cos(angle*#PI/180);	1-89°
	t2=Sin(angle*#PI/180)
	t3=r*t1
	t4=r*t2
	t5=2*r-t4

	r=ro
	Debug ro

	MovePathCursor(x+w,y+h-r,flags)
	AddPathCircle(-r,0,r,0,90,#PB_Path_Relative)
	AddPathLine(-w+r*2,0,#PB_Path_Relative)
	AddPathCircle(0,-r,r,90,90+angle,#PB_Path_Relative|#PB_Path_Connected)
	AddPathLine(w-t5,0,#PB_Path_Relative)
	AddPathCircle(0,-t3,t3,90,0,#PB_Path_Relative|#PB_Path_Connected|#PB_Path_CounterClockwise)
	AddPathLine(0,-h+t5,#PB_Path_Relative)
	AddPathCircle(-t3,t4,r,360-angle,360,#PB_Path_Relative|#PB_Path_Connected)

	ClosePath()

EndProcedure

Procedure boxs(x,y,w,h,radius,col,extra=8)


	AddPathRoundBox(x,y,w,h,radius)
	VectorSourceColor($a0000000|col)
	FillPath(#PB_Path_Preserve)
	VectorSourceColor($60000000)
	StrokePath(1)

	VectorSourceColor($40ffffff)
	AddPathHighlight(x,y,w,h,radius,extra*2)
	FillPath()
	AddPathHighlight(x,y,w,h,radius,extra*3)
	FillPath()
	VectorSourceColor($20000000)
	AddPathShadow(x,y,w,h,radius,extra*2)
	FillPath()
	AddPathShadow(x,y,w,h,radius,extra*3)
	FillPath()


	; Debug "Data.i "+Str(boxnr)+", "+Str(x)+","+Str(y)+", "+Str(w)+","+Str(h)+"; "+Str(size)

EndProcedure
Procedure show()

	Protected i

	StartVectorDrawing(CanvasVectorOutput(0))
	AddPathBox(0,0,VectorOutputWidth(),VectorOutputHeight())
	VectorSourceColor($Ff000000|#White)
	FillPath()

	boxs(50,50,300,200,90,$F3D1AD)
	boxs(50,350,300,100,40,$F3D1AD,20);		smaller radius
	boxs(400,100,300,100,90,$9AF0B8)
	boxs(500,250,100,300,90,$9AF0B8,20)

	StopVectorDrawing()

EndProcedure

Procedure main()

	#X=800
	#Y=600

	OpenWindow(0,0,0,#X,#Y,"")
	CanvasGadget(0,0,0,#X,#Y)

	show()

	Repeat
		Select WaitWindowEvent()
		Case #PB_Event_CloseWindow
			End
		Case #WM_CHAR
			End
		EndSelect
	ForEver

EndProcedure
main()
User avatar
pf shadoko
Enthusiast
Enthusiast
Posts: 291
Joined: Thu Jul 09, 2015 9:07 am

Re: Math and vector graphics

Post by pf shadoko »

Hi,

my brush functions can also be used with a vectordrawing path
Doesn't that suit you?
https://www.purebasic.fr/french/viewtop ... =6&t=16385
User avatar
Michael Vogel
Addict
Addict
Posts: 2677
Joined: Thu Feb 09, 2006 11:27 pm
Contact:

Re: Math and vector graphics

Post by Michael Vogel »

I like your routines, but I believe the functions are only producing perfect results when drawing an opaque layer at the top. Give me a hint if this is correct (I only made a quick test replacing all occurrences of $FF by $80...

I need transparent shapes, maybe the following example makes this a little bit clearer:

Code: Select all

Procedure Min(a,b)
	If a<b
		ProcedureReturn a
	Else
		ProcedureReturn b
	EndIf
EndProcedure

Procedure AddPathRoundBox(x.d,y.d,w.d,h.d,radius.d,flags=#PB_Path_Default)

	If radius>h/2 : radius=h/2 : EndIf
	If radius>w/2 : radius=w/2 : EndIf

	If radius<0
		radius=0
	EndIf

	MovePathCursor(x+radius,y,flags)

	AddPathArc(w-radius,0,w-radius,radius,radius,#PB_Path_Relative)
	AddPathArc(0,h-radius,-radius,h-radius,radius,#PB_Path_Relative)
	AddPathArc(-w+radius,0,-w+radius,-radius,radius,#PB_Path_Relative)
	AddPathArc(0,-h+radius,radius,-h+radius,radius,#PB_Path_Relative)

	ClosePath()

	MovePathCursor(-radius,0,#PB_Path_Relative)

EndProcedure
Procedure AddPathHighlight(x.d,y.d,w.d,h.d,r.d,angle.d,flags=#PB_Path_Default)

	Protected t1.d,t2.d,t3.d,t4.d,t5.d

	t1=Cos(angle*#PI/180);	1-89°
	t2=Sin(angle*#PI/180)
	t3=r*t1
	t4=r*t2
	t5=2*r-t4

	MovePathCursor(x,y+r,flags)
	AddPathCircle(r,0,r,180,270,#PB_Path_Relative)
	AddPathLine(w-r*2,0,#PB_Path_Relative)
	AddPathCircle(0,r,r,270,270+angle,#PB_Path_Relative|#PB_Path_Connected)
	AddPathLine(-w+t5,0,#PB_Path_Relative)
	AddPathCircle(0,t3,t3,270,180,#PB_Path_Relative|#PB_Path_Connected|#PB_Path_CounterClockwise)
	AddPathLine(0,h-t5,#PB_Path_Relative)
	AddPathCircle(t3,-t4,r,180-angle,180,#PB_Path_Relative|#PB_Path_Connected)

	ClosePath()

EndProcedure
Procedure AddPathShadow(x.d,y.d,w.d,h.d,r.d,angle.d,flags=#PB_Path_Default)

	Protected ro.d
	Protected t1.d,t2.d,t3.d,t4.d,t5.d

	ro=Min(Min(r,h/2),w/2)

	t1=Cos(angle*#PI/180);	1-89°
	t2=Sin(angle*#PI/180)
	t3=r*t1
	t4=r*t2
	t5=2*r-t4

	r=ro
	Debug ro

	MovePathCursor(x+w,y+h-r,flags)
	AddPathCircle(-r,0,r,0,90,#PB_Path_Relative)
	AddPathLine(-w+r*2,0,#PB_Path_Relative)
	AddPathCircle(0,-r,r,90,90+angle,#PB_Path_Relative|#PB_Path_Connected)
	AddPathLine(w-t5,0,#PB_Path_Relative)
	AddPathCircle(0,-t3,t3,90,0,#PB_Path_Relative|#PB_Path_Connected|#PB_Path_CounterClockwise)
	AddPathLine(0,-h+t5,#PB_Path_Relative)
	AddPathCircle(-t3,t4,r,360-angle,360,#PB_Path_Relative|#PB_Path_Connected)

	ClosePath()

EndProcedure

Procedure boxs(x,y,w,h,radius,col,extra=8)


	AddPathRoundBox(x,y,w,h,radius)
	VectorSourceColor($a0000000|col)
	FillPath(#PB_Path_Preserve)
	VectorSourceColor($60000000)
	StrokePath(1)

	VectorSourceColor($40ffffff)
	AddPathHighlight(x,y,w,h,radius,extra*2)
	FillPath()
	AddPathHighlight(x,y,w,h,radius,extra*3)
	FillPath()
	VectorSourceColor($20000000)
	AddPathShadow(x,y,w,h,radius,extra*2)
	FillPath()
	AddPathShadow(x,y,w,h,radius,extra*3)
	FillPath()


	; Debug "Data.i "+Str(boxnr)+", "+Str(x)+","+Str(y)+", "+Str(w)+","+Str(h)+"; "+Str(size)

EndProcedure
Procedure show()

	Protected i

	StartVectorDrawing(CanvasVectorOutput(0))
	AddPathBox(0,0,VectorOutputWidth(),VectorOutputHeight())
	VectorSourceColor($Ff000000|#White)
	FillPath()
	
	AddPathBox(100,150,450,250)
	VectorSourceColor($400000f0)
	FillPath()
	
	boxs(50,50,300,200,90,$F3D1AD)
	boxs(50,350,300,100,40,$F3D1AD,20);		smaller radius
	boxs(400,100,300,100,90,$9AF0B8)
	boxs(500,250,100,300,90,$9AF0B8,20)

	StopVectorDrawing()

EndProcedure

Procedure main()

	#X=800
	#Y=600

	OpenWindow(0,0,0,#X,#Y,"")
	CanvasGadget(0,0,0,#X,#Y)

	show()

	Repeat
		Select WaitWindowEvent()
		Case #PB_Event_CloseWindow
			End
		Case #WM_CHAR
			End
		EndSelect
	ForEver

EndProcedure
main()
And that's what I am able to produce with your code:

Code: Select all

Macro doevents
	Repeat:Until WaitWindowEvent() = #PB_Event_CloseWindow
EndMacro
Macro VFill(c,flag=#PB_Path_Default)
	VectorSourceColor($20000000|(c&$FFFFFF))
	FillPath(flag)
EndMacro
Macro vcolor(c)
	VectorSourceColor(c)
EndMacro

Procedure SortIdx(Array t.l(1),Array idx.l(1),deb=0, fin=-1) ;<= met dans le tableau idx() la position des element trié du tableau t()

	Protected min,i,j,v,idmin
	If fin=-1: fin=ArraySize(t()):EndIf
	Dim idx(fin)
	For i=deb To fin:idx(i)=i:Next
	For i=deb To fin
		min=$7fffffff
		For j=i To fin
			v=t(idx(j))
			If v<min:min=v:idmin=j:EndIf
		Next
		Swap idx(i),idx(idmin)
	Next
EndProcedure
Procedure initIF(image,centerX.w=-1,centerY.w=-1)
	;image : numero de l'image
	;centerx/y : definit le centre de l'image
	Structure IFsij
		i.b
		j.b
	EndStructure

	Protected i,j,n,di,dj
	Protected idx=ImageWidth (image)
	Protected idy=ImageHeight(image)
	Protected Dim IFdis.l(idx * idy-1)
	Global IFcenterx
	If centerX=-1:IFcenterx=idx/2:Else:IFcenterx=centerx:EndIf
	Global IFcenterY
	If centery=-1:IFcentery=idy/2:Else:IFcentery=centery:EndIf
	Global Dim IFidx.l(idx * idy-1)
	Global Dim IFbmp.l(idx-1,idy-1)
	Global Dim IFpos.IFsij(idx * idy-1)

	StartDrawing(ImageOutput(image))
	DrawingMode(#PB_2DDrawing_AllChannels)
	For j=0 To idy-1
		For i=0 To idx-1
			IFbmp(i,j)=Point(i,j)
			IFpos(n)\i=i:di=i-IFcenterx
			IFpos(n)\j=j:dj=j-IFcentery
			;IFdis(n)=di*di+dj*dj
			IFdis(n)=Abs(di)+Abs(dj)
			n+1
		Next
	Next
	StopDrawing()
	sortidx(IFdis(),IFidx())
EndProcedure
Procedure FillPathBrush(image,centerX.w=-1,centerY.w=-1)
	initIF(image,centerX,centerY)
	Protected s.s=PathSegments()
	Protected n,nn=ArraySize(IFidx())
	ResetPath()
	For n=0 To nn
		With IFpos(IFidx(nn-n))
			If Alpha(IFbmp(\i,\j))
				MovePathCursor(\i-ifcenterX+1,\j-ifcentery+1)
				AddPathSegments(s,#PB_Path_Relative)
				Vfill(IFbmp(\i,\j))
			EndIf
		EndWith
	Next
EndProcedure

Procedure exemple()
	EnableExplicit
	Protected i,j,n, a.f,y, idx=800,idy=600
	For n=0 To 7
		CreateImage(10+n,16,16,32,#PB_Image_Transparent)
		StartVectorDrawing(ImageVectorOutput(10+n))
		Select n
		Case 0
			VectorSourceCircularGradient(8-3,8-3,10)
			VectorSourceGradientColor($ffffffff, 0.0)
			VectorSourceGradientColor($ffffaaaa, 0.4)
			VectorSourceGradientColor($ff886666, 1.0)
			VectorSourceGradientColor($00886666, 1.0)
			AddPathCircle(8,8,7):FillPath()
		EndSelect
		StopVectorDrawing()
	Next

	CreateImage(0,idx,idy,32,#White)

	StartVectorDrawing(ImageVectorOutput(0))
	AddPathBox(480,100,100,260)
	VectorSourceColor($6000ff00)
	FillPath()

	y=i*72+10
	MovePathCursor(0,30+y)
	;DrawVectorImage(ImageID(10+i))
	AddPathBox(380,200,200,60)
	FillPathBrush(10+i)

	StopVectorDrawing()

	OpenWindow(0, 0, 0, idx, idy, "VectorDrawing-Brush", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
	ImageGadget(0, 0, 0, idx, idy,ImageID(0))
	doevents
EndProcedure

exemple()
#NULL
Addict
Addict
Posts: 1440
Joined: Thu Aug 30, 2007 11:54 pm
Location: right here

Re: Math and vector graphics

Post by #NULL »

I played a bit with this.

Code: Select all

Procedure show()
   [...]
   ; some random background
   For i=0 To 1000
     AddPathBox(Random(VectorOutputWidth())-50,Random(VectorOutputHeight())-50, 50+Random(50), 50+Random(50))
     VectorSourceColor(RGBA(Random(255),Random(255),Random(255),Random(20)))
     FillPath()
   Next
   [...]

Code: Select all

Procedure boxs(x,y,w,h,radius,col,extra=8)
  
  Protected alpha.f = 20
  Protected size = 20
  Protected offset.f = 5
  Protected color = $60000000
  
  For i=1 To size
     AddPathRoundBox( (x-(offset*(i/size))), (y-(offset*(i/size))), (w+i), (h+i), ((w+i)*radius/w) )
     VectorSourceColor(RGBA(Red(color), Green(color), Blue(color), alpha*((size-i)/size)))
     StrokePath(1)
  Next

  [...]
I'm drawing the round-box outline multiple times with increasing size and decreasing alpha. I used an offset so the shadow is larger on the bottom-right than it is on the top-left. Unfortunately it becomes also denser/darker in the top-left, which looks counterintuitive. If you use an offset of size/2 it looks ok though. Maybe that's a start :)

Code: Select all

Procedure Min(a,b)
   If a<b
      ProcedureReturn a
   Else
      ProcedureReturn b
   EndIf
EndProcedure

Procedure AddPathRoundBox(x.d,y.d,w.d,h.d,radius.d,flags=#PB_Path_Default)

   If radius>h/2 : radius=h/2 : EndIf
   If radius>w/2 : radius=w/2 : EndIf

   If radius<0
      radius=0
   EndIf

   MovePathCursor(x+radius,y,flags)

   AddPathArc(w-radius,0,w-radius,radius,radius,#PB_Path_Relative)
   AddPathArc(0,h-radius,-radius,h-radius,radius,#PB_Path_Relative)
   AddPathArc(-w+radius,0,-w+radius,-radius,radius,#PB_Path_Relative)
   AddPathArc(0,-h+radius,radius,-h+radius,radius,#PB_Path_Relative)

   ClosePath()

   MovePathCursor(-radius,0,#PB_Path_Relative)

EndProcedure
Procedure AddPathHighlight(x.d,y.d,w.d,h.d,r.d,angle.d,flags=#PB_Path_Default)

   Protected t1.d,t2.d,t3.d,t4.d,t5.d

   t1=Cos(angle*#PI/180);   1-89°
   t2=Sin(angle*#PI/180)
   t3=r*t1
   t4=r*t2
   t5=2*r-t4

   MovePathCursor(x,y+r,flags)
   AddPathCircle(r,0,r,180,270,#PB_Path_Relative)
   AddPathLine(w-r*2,0,#PB_Path_Relative)
   AddPathCircle(0,r,r,270,270+angle,#PB_Path_Relative|#PB_Path_Connected)
   AddPathLine(-w+t5,0,#PB_Path_Relative)
   AddPathCircle(0,t3,t3,270,180,#PB_Path_Relative|#PB_Path_Connected|#PB_Path_CounterClockwise)
   AddPathLine(0,h-t5,#PB_Path_Relative)
   AddPathCircle(t3,-t4,r,180-angle,180,#PB_Path_Relative|#PB_Path_Connected)

   ClosePath()

EndProcedure
Procedure AddPathShadow(x.d,y.d,w.d,h.d,r.d,angle.d,flags=#PB_Path_Default)

   Protected ro.d
   Protected t1.d,t2.d,t3.d,t4.d,t5.d

   ro=Min(Min(r,h/2),w/2)

   t1=Cos(angle*#PI/180);   1-89°
   t2=Sin(angle*#PI/180)
   t3=r*t1
   t4=r*t2
   t5=2*r-t4

   r=ro
   Debug ro

   MovePathCursor(x+w,y+h-r,flags)
   AddPathCircle(-r,0,r,0,90,#PB_Path_Relative)
   AddPathLine(-w+r*2,0,#PB_Path_Relative)
   AddPathCircle(0,-r,r,90,90+angle,#PB_Path_Relative|#PB_Path_Connected)
   AddPathLine(w-t5,0,#PB_Path_Relative)
   AddPathCircle(0,-t3,t3,90,0,#PB_Path_Relative|#PB_Path_Connected|#PB_Path_CounterClockwise)
   AddPathLine(0,-h+t5,#PB_Path_Relative)
   AddPathCircle(-t3,t4,r,360-angle,360,#PB_Path_Relative|#PB_Path_Connected)

   ClosePath()

EndProcedure

Procedure boxs(x,y,w,h,radius,col,extra=8)
  
  Protected alpha.f = 20
  Protected size = 20
  Protected offset.f = 5
  Protected color = $60000000
  
  For i=1 To size
     AddPathRoundBox( (x-(offset*(i/size))), (y-(offset*(i/size))), (w+i), (h+i), ((w+i)*radius/w) )
     VectorSourceColor(RGBA(Red(color), Green(color), Blue(color), alpha*((size-i)/size)))
     StrokePath(1)
  Next
  
   AddPathRoundBox(x,y,w,h,radius)
   VectorSourceColor($a0000000|col)
   FillPath(#PB_Path_Preserve)
   VectorSourceColor($60000000)
   StrokePath(1)

   VectorSourceColor($40ffffff)
   AddPathHighlight(x,y,w,h,radius,extra*2)
   FillPath()
   AddPathHighlight(x,y,w,h,radius,extra*3)
   FillPath()
   VectorSourceColor($20000000)
   AddPathShadow(x,y,w,h,radius,extra*2)
   FillPath()
   AddPathShadow(x,y,w,h,radius,extra*3)
   FillPath()


   ; Debug "Data.i "+Str(boxnr)+", "+Str(x)+","+Str(y)+", "+Str(w)+","+Str(h)+"; "+Str(size)

EndProcedure
Procedure show()

   Protected i

   StartVectorDrawing(CanvasVectorOutput(0))
   AddPathBox(0,0,VectorOutputWidth(),VectorOutputHeight())
   VectorSourceColor($Ff000000|#White)
   FillPath()
   
   ; some random background
   For i=0 To 1000
     AddPathBox(Random(VectorOutputWidth())-50,Random(VectorOutputHeight())-50, 50+Random(50), 50+Random(50))
     VectorSourceColor(RGBA(Random(255),Random(255),Random(255),Random(20)))
     FillPath()
   Next
   
   boxs(50,50,300,200,90,$F3D1AD)
   boxs(50,350,300,100,40,$F3D1AD,20);      smaller radius
   boxs(400,100,300,100,90,$9AF0B8)
   boxs(500,250,100,300,90,$9AF0B8,20)

   StopVectorDrawing()

EndProcedure

Procedure main()

   #X=800
   #Y=600

   OpenWindow(0,0,0,#X,#Y,"")
   CanvasGadget(0,0,0,#X,#Y)

   show()

   Repeat
      Select WaitWindowEvent()
      Case #PB_Event_CloseWindow
         End
;       Case #WM_CHAR
;          End
      EndSelect
   ForEver

EndProcedure
main()
User avatar
Michael Vogel
Addict
Addict
Posts: 2677
Joined: Thu Feb 09, 2006 11:27 pm
Contact:

Re: Math and vector graphics

Post by Michael Vogel »

#Null, interestng approach, will also play around with your code now...

Tried to do clipping but that's not the best function in PB because it does not do alpha or antialiazing...

Code: Select all

Procedure Min(a,b)
	If a<b
		ProcedureReturn a
	Else
		ProcedureReturn b
	EndIf
EndProcedure
Macro StartClipping()
	SaveVectorState()
	ClipPath()
EndMacro
Macro StopClipping()
	RestoreVectorState()
EndMacro

Procedure AddPathRoundBox(x.d,y.d,w.d,h.d,radius.d,flags=#PB_Path_Default)

	If radius>h/2 : radius=h/2 : EndIf
	If radius>w/2 : radius=w/2 : EndIf

	If radius<0
		radius=0
	EndIf

	MovePathCursor(x+radius,y,flags)

	AddPathArc(w-radius,0,w-radius,radius,radius,#PB_Path_Relative)
	AddPathArc(0,h-radius,-radius,h-radius,radius,#PB_Path_Relative)
	AddPathArc(-w+radius,0,-w+radius,-radius,radius,#PB_Path_Relative)
	AddPathArc(0,-h+radius,radius,-h+radius,radius,#PB_Path_Relative)

	ClosePath()

	MovePathCursor(-radius,0,#PB_Path_Relative)

EndProcedure
Procedure AddPathHighlight(x.d,y.d,w.d,h.d,r.d,angle.d,flags=#PB_Path_Default)

	Protected t1.d,t2.d,t3.d,t4.d,t5.d

	t1=Cos(angle*#PI/180);   1-89°
	t2=Sin(angle*#PI/180)
	t3=r*t1
	t4=r*t2
	t5=2*r-t4

	MovePathCursor(x,y+r,flags)
	AddPathCircle(r,0,r,180,270,#PB_Path_Relative)
	AddPathLine(w-r*2,0,#PB_Path_Relative)
	AddPathCircle(0,r,r,270,270+angle,#PB_Path_Relative|#PB_Path_Connected)
	AddPathLine(-w+t5,0,#PB_Path_Relative)
	AddPathCircle(0,t3,t3,270,180,#PB_Path_Relative|#PB_Path_Connected|#PB_Path_CounterClockwise)
	AddPathLine(0,h-t5,#PB_Path_Relative)
	AddPathCircle(t3,-t4,r,180-angle,180,#PB_Path_Relative|#PB_Path_Connected)

	ClosePath()

EndProcedure
Procedure AddPathShadow(x.d,y.d,w.d,h.d,r.d,angle.d,flags=#PB_Path_Default)

	Protected ro.d
	Protected t1.d,t2.d,t3.d,t4.d,t5.d

	ro=Min(Min(r,h/2),w/2)

	t1=Cos(angle*#PI/180);   1-89°
	t2=Sin(angle*#PI/180)
	t3=r*t1
	t4=r*t2
	t5=2*r-t4

	r=ro
	Debug ro

	MovePathCursor(x+w,y+h-r,flags)
	AddPathCircle(-r,0,r,0,90,#PB_Path_Relative)
	AddPathLine(-w+r*2,0,#PB_Path_Relative)
	AddPathCircle(0,-r,r,90,90+angle,#PB_Path_Relative|#PB_Path_Connected)
	AddPathLine(w-t5,0,#PB_Path_Relative)
	AddPathCircle(0,-t3,t3,90,0,#PB_Path_Relative|#PB_Path_Connected|#PB_Path_CounterClockwise)
	AddPathLine(0,-h+t5,#PB_Path_Relative)
	AddPathCircle(-t3,t4,r,360-angle,360,#PB_Path_Relative|#PB_Path_Connected)

	ClosePath()

EndProcedure
Procedure DrawVectorShadow(x.d,y.d,w.d,h.d,radius.d,size.d=20,offset.d=5,alpha.d=20,color=#Black,flags=#PB_Path_Default)

	Protected i
	AddPathBox(0,0,VectorOutputWidth(),VectorOutputHeight())
	AddPathRoundBox(x,y,w,h,radius)
	StartClipping()

	For i=1 To size
		AddPathRoundBox(x+offset-i,y+offset-i,w+i*2,h+i*2,((w+i)*radius/w) )
		VectorSourceColor(RGBA(Red(color), Green(color), Blue(color), alpha*((size-i)/size)))
		;StrokePath(1)
		FillPath()
	Next
	StopClipping()

EndProcedure
Procedure boxs(x,y,w,h,radius,col,extra=8)

	DrawVectorShadow(x,y,w,h,radius,10,10,20)

	AddPathRoundBox(x,y,w,h,radius)
	VectorSourceColor($a0000000|col)
	FillPath(#PB_Path_Preserve)
	VectorSourceColor($60000000)
	StrokePath(1)

	If 0
		VectorSourceColor($40ffffff)
		AddPathHighlight(x,y,w,h,radius,extra*2)
		FillPath()
		AddPathHighlight(x,y,w,h,radius,extra*3)
		FillPath()
		VectorSourceColor($20000000)
		AddPathShadow(x,y,w,h,radius,extra*2)
		FillPath()
		AddPathShadow(x,y,w,h,radius,extra*3)
		FillPath()
	EndIf

	; Debug "Data.i "+Str(boxnr)+", "+Str(x)+","+Str(y)+", "+Str(w)+","+Str(h)+"; "+Str(size)

EndProcedure
Procedure show()

	Protected i

	StartVectorDrawing(CanvasVectorOutput(0))
	AddPathBox(0,0,VectorOutputWidth(),VectorOutputHeight())
	VectorSourceColor($Ff000000|#White)
	FillPath()

	; some random background
	If 0
		For i=0 To 1000
			AddPathBox(Random(VectorOutputWidth())-50,Random(VectorOutputHeight())-50, 50+Random(50), 50+Random(50))
			VectorSourceColor(RGBA(Random(255),Random(255),Random(255),Random(20)))
			FillPath()
		Next
	EndIf

	boxs(50,50,300,200,90,$F3D1AD)
	boxs(50,350,300,100,40,$F3D1AD,20);      smaller radius
	boxs(400,100,300,100,90,$9AF0B8)
	boxs(500,250,100,300,90,$9AF0B8,20)

	StopVectorDrawing()

EndProcedure

Procedure main()

	#X=800
	#Y=600

	OpenWindow(0,0,0,#X,#Y,"")
	CanvasGadget(0,0,0,#X,#Y)

	show()

	Repeat
		Select WaitWindowEvent()
		Case #PB_Event_CloseWindow
			End
			;       Case #WM_CHAR
			;          End
		EndSelect
	ForEver

EndProcedure
main()
#NULL
Addict
Addict
Posts: 1440
Joined: Thu Aug 30, 2007 11:54 pm
Location: right here

Re: Math and vector graphics

Post by #NULL »

Looks pretty good :)
I think you could also use layers (BeginVectorLayer()). Overdrawing the shadow with the actual button by drawing the button completely opaque on top of the shadow, but both within a layer with its own transparency to blend everything with the background.

<edit>That would probably be more difficult if your buttons are drawn with multiple transparent parts on top of each other. But you could partially clear the shadow by drawing a opaque button background first. That would clear only the shadow within the layer and can be blended with the underlying background later.
But with the clipping it already looks fine anyway.
#NULL
Addict
Addict
Posts: 1440
Joined: Thu Aug 30, 2007 11:54 pm
Location: right here

Re: Math and vector graphics

Post by #NULL »

As for the scrambled glow. If I add the radius correction from AddPathRoundBox() also to AddPathHighlight()..

Code: Select all

   If r>h/2 : r=h/2 : EndIf
   If r>w/2 : r=w/2 : EndIf
..that seems to solve some of the issues.

<edit>
..and the same added for AddPathShadow() solves the other issue too?
User avatar
Michael Vogel
Addict
Addict
Posts: 2677
Joined: Thu Feb 09, 2006 11:27 pm
Contact:

Re: Math and vector graphics

Post by Michael Vogel »

Some moments later...

Good idea about layers, which would be even more useful when an UnfillPath (Unstroke) function would also exist to allow erasing content from the layer (as said, clipping is not ideal because it's border are calculated pixel wise).

There's still a kind of light aura arround the buttons (could be seen best on the lower blue box), but the result is not that bad...

Code: Select all

Procedure Min(a,b)
	If a<b
		ProcedureReturn a
	Else
		ProcedureReturn b
	EndIf
EndProcedure
Macro StartClipping()
	SaveVectorState()
	ClipPath()
EndMacro
Macro StopClipping()
	RestoreVectorState()
EndMacro

Procedure AddPathRoundBox(x.d,y.d,w.d,h.d,radius.d,flags=#PB_Path_Default)

	If radius>h/2 : radius=h/2 : EndIf
	If radius>w/2 : radius=w/2 : EndIf

	If radius<0
		radius=0
	EndIf

	MovePathCursor(x+radius,y,flags)

	AddPathArc(w-radius,0,w-radius,radius,radius,#PB_Path_Relative)
	AddPathArc(0,h-radius,-radius,h-radius,radius,#PB_Path_Relative)
	AddPathArc(-w+radius,0,-w+radius,-radius,radius,#PB_Path_Relative)
	AddPathArc(0,-h+radius,radius,-h+radius,radius,#PB_Path_Relative)

	ClosePath()

	MovePathCursor(-radius,0,#PB_Path_Relative)

EndProcedure
Procedure AddPathHighlight(x.d,y.d,w.d,h.d,r.d,angle.d,flags=#PB_Path_Default)

	Protected t1.d,t2.d,t3.d,t4.d,t5.d

	t1=Cos(angle*#PI/180);   1-89°
	t2=Sin(angle*#PI/180)
	t3=r*t1
	t4=r*t2
	t5=2*r-t4

	MovePathCursor(x,y+r,flags)
	AddPathCircle(r,0,r,180,270,#PB_Path_Relative)
	AddPathLine(w-r*2,0,#PB_Path_Relative)
	AddPathCircle(0,r,r,270,270+angle,#PB_Path_Relative|#PB_Path_Connected)
	AddPathLine(-w+t5,0,#PB_Path_Relative)
	AddPathCircle(0,t3,t3,270,180,#PB_Path_Relative|#PB_Path_Connected|#PB_Path_CounterClockwise)
	AddPathLine(0,h-t5,#PB_Path_Relative)
	AddPathCircle(t3,-t4,r,180-angle,180,#PB_Path_Relative|#PB_Path_Connected)

	ClosePath()

EndProcedure
Procedure AddPathShadow(x.d,y.d,w.d,h.d,r.d,angle.d,flags=#PB_Path_Default)

	Protected ro.d
	Protected t1.d,t2.d,t3.d,t4.d,t5.d

	ro=Min(Min(r,h/2),w/2)

	t1=Cos(angle*#PI/180);   1-89°
	t2=Sin(angle*#PI/180)
	t3=r*t1
	t4=r*t2
	t5=2*r-t4

	r=ro
	Debug ro

	MovePathCursor(x+w,y+h-r,flags)
	AddPathCircle(-r,0,r,0,90,#PB_Path_Relative)
	AddPathLine(-w+r*2,0,#PB_Path_Relative)
	AddPathCircle(0,-r,r,90,90+angle,#PB_Path_Relative|#PB_Path_Connected)
	AddPathLine(w-t5,0,#PB_Path_Relative)
	AddPathCircle(0,-t3,t3,90,0,#PB_Path_Relative|#PB_Path_Connected|#PB_Path_CounterClockwise)
	AddPathLine(0,-h+t5,#PB_Path_Relative)
	AddPathCircle(-t3,t4,r,360-angle,360,#PB_Path_Relative|#PB_Path_Connected)

	ClosePath()

EndProcedure
Procedure DrawVectorShadow(x.d,y.d,w.d,h.d,radius.d,size.d=20,offset.d=5,alpha.d=20,color=#Black,flags=#PB_Path_Default)

	Protected i
	AddPathBox(0,0,VectorOutputWidth(),VectorOutputHeight())
	AddPathRoundBox(x,y,w,h,radius)
	StartClipping()

	For i=1 To size
		AddPathRoundBox(x+offset-i,y+offset-i,w+i*2,h+i*2,((w+i)*radius/w) )
		VectorSourceColor(RGBA(Red(color), Green(color), Blue(color), Alpha/size))
		FillPath()
	Next
	StopClipping()

EndProcedure

Procedure boxs(x.f,y.f,w.f,h.f,radius.f,col,alpha=255,button.f=8,shadow.f=20,darkness=100,offset.f=15)

	Protected shadowcount=20

	radius=min(min(radius,h/2),w/2)

	BeginVectorLayer(min(alpha,255))
	
	; Shadow
	shadow/shadowcount
	darkness=darkness/shadowcount+1
	For i=0 To shadowcount
		AddPathRoundBox(x+offset+shadow*i/2,y+offset+shadow*i/2,w-shadow*i,h-shadow*i,radius-shadow*(i-shadowcount/2)/2)
		VectorSourceColor(darkness<<24)
		FillPath()
	Next i

	; Filled Button
	AddPathRoundBox(x,y,w,h,radius)
	VectorSourceColor($ff000000|col)
	FillPath()
	
	; Erasing area...
	;AddPathBox(x+50,y+50,150,50)
	;VectorSourceColor($fffffffff)
	;FillPath()
	
	; Highlight and Shadow
	VectorSourceColor($40ffffff)
	AddPathHighlight(x,y,w,h,radius,button*2)
	FillPath()
	AddPathHighlight(x,y,w,h,radius,button*3)
	FillPath()
	VectorSourceColor($20000000)
	AddPathShadow(x,y,w,h,radius,button*2)
	FillPath()
	AddPathShadow(x,y,w,h,radius,button*3)
	FillPath()
	
	; Button Border
	AddPathRoundBox(x,y,w,h,radius)
	VectorSourceColor($60000000)
	StrokePath(1)

	EndVectorLayer()

EndProcedure
Procedure show()

	Protected i

	StartVectorDrawing(CanvasVectorOutput(0))
	AddPathBox(0,0,VectorOutputWidth(),VectorOutputHeight())
	VectorSourceColor($Ff000000|#White)
	FillPath()

	; some random background
	For i=0 To 100
		AddPathBox(Random(VectorOutputWidth())-50,Random(VectorOutputHeight())-50, 50+Random(50), 50+Random(50))
		VectorSourceColor(RGBA(Random(255),Random(255),Random(255),Random(40)))
		FillPath()
	Next

	boxs(50,50,300,200,90,$F3D1AD,160,5,50,170)
	boxs(50,350,300,100,40,$F3D1AD,200,8,20,50);      smaller radius
	boxs(400,100,300,100,90,$9AF0B8,120,10)
	boxs(500,250,100,300,90,$9AF0B8,180,20)

	StopVectorDrawing()

EndProcedure

Procedure main()

	#X=800
	#Y=600

	OpenWindow(0,0,0,#X,#Y,"")
	CanvasGadget(0,0,0,#X,#Y)

	show()

	Repeat
		Select WaitWindowEvent()
		Case #PB_Event_CloseWindow
			End
			;       Case #WM_CHAR
			;          End
		EndSelect
	ForEver

EndProcedure
main()
Post Reply