Don't use LineXY(), use Line() instead.

Share your advanced PureBasic knowledge/code with the community.
Derek
Addict
Addict
Posts: 2354
Joined: Wed Apr 07, 2004 12:51 am
Location: England

Don't use LineXY(), use Line() instead.

Post by Derek »

If you are drawing a lot of graphics using the line commands then use Line() and calculate the vector yourself, seems to be twice as quick as LineXY().

Code: Select all

OpenWindow(0,0,0,800,600,"",#PB_Window_ScreenCentered|#PB_Window_SystemMenu)
InitSprite()
OpenWindowedScreen(WindowID(0),0,0,800,600,0,0,0)
ClearScreen(#White)
For c=1 To 100
  StartDrawing(ScreenOutput())
  FrontColor(RGB(c,c,c))
  t=ElapsedMilliseconds()
  For n=0 To 36000
    xto=400+250*Sin(n/100)
    yto=300+250*Cos(n/100)
    
    LineXY(400,300,xto,yto)        ;uncomment one of these lines to see the difference
    ;Line(400,300,xto-400,yto-300) ;
  
  Next
  t=ElapsedMilliseconds()-t
  a+t
  Debug t
  WindowEvent()
  StopDrawing()
  FlipBuffers()
Next
Debug "Average = "+Str(a/100)
Repeat
Until WaitWindowEvent()=#PB_Event_CloseWindow
pjay
Enthusiast
Enthusiast
Posts: 253
Joined: Thu Mar 30, 2006 11:14 am

Post by pjay »

That's an interesting find. You should post it as a bug.
Derek
Addict
Addict
Posts: 2354
Joined: Wed Apr 07, 2004 12:51 am
Location: England

Post by Derek »

It's not a bug, just a feature. There is one problem in that the endpoint is not always drawn, depending on the angle. The way around it would be to plot() the endpoint after the line() command but then the program takes exactly the time that linexy() takes, so perhaps that is what PB is actually doing.

Code: Select all

OpenWindow(0,0,0,800,600,"",#PB_Window_ScreenCentered|#PB_Window_SystemMenu) 
InitSprite() 
OpenWindowedScreen(WindowID(0),0,0,800,600,0,0,0) 
ClearScreen(#White) 
For c=1 To 100 
  StartDrawing(ScreenOutput()) 
  FrontColor(RGB(c,c,c)) 
  t=ElapsedMilliseconds() 
  For n=0 To 36000 
    xto=400+250*Sin(n/100) 
    yto=300+250*Cos(n/100) 
    
    LineXY(400,300,xto,yto)        ;uncomment one of these lines to see the difference 
    ;Line(400,300,xto-400,yto-300) : Plot(xto,yto) ; now takes as long!!!
  
  Next 
  t=ElapsedMilliseconds()-t 
  a+t 
  Debug t 
  WindowEvent() 
  StopDrawing() 
  FlipBuffers() 
Next 
Debug "Average = "+Str(a/100) 
Repeat 
Until WaitWindowEvent()=#PB_Event_CloseWindow 
User avatar
Demivec
Addict
Addict
Posts: 4270
Joined: Mon Jul 25, 2005 3:51 pm
Location: Utah, USA

Post by Demivec »

Derek wrote:There is one problem in that the endpoint is not always drawn, depending on the angle
It would seem the endpoint is almost never drawn. Here is an image at 1/4 actual size showing the diffence between a screen capture of the pattern drawn by LineXY and Line.
Image

The image was then negated to show black where there was "more" drawn for the LineXY command over what was drawn for Line(with the demo you gave). I would also add that when you used Plot to account for the time difference, doing so didn't change the image created by Line. The image was actually the same as if no Plot was used with Line. This means that Line and LineXY did not create identical images.
User avatar
Kaeru Gaman
Addict
Addict
Posts: 4826
Joined: Sun Mar 19, 2006 1:57 pm
Location: Germany

Post by Kaeru Gaman »

@Derek

nice tip, thanks. :D
oh... and have a nice day.
pjay
Enthusiast
Enthusiast
Posts: 253
Joined: Thu Mar 30, 2006 11:14 am

Post by pjay »

The extra pixel for LineXY should be expected.

For instance:

Line(0,0,10,0) draws a line from (0,0) to 10 pixels to the right, so it ends at (9,0).

LineXY(0,0,10,0) draws to (10,0), so 11 pixels in total.
Derek
Addict
Addict
Posts: 2354
Joined: Wed Apr 07, 2004 12:51 am
Location: England

Post by Derek »

Here's another (very unfinished) example of the speed increase you can get if you are willing to allow for a few pixels not being plotted.

There are a few black pixels not plotted when the lines get quite long but the overall speed increase is worth it I think.

I get 95ms average time taken when drawing with linexy() and 51ms when using line().

Code: Select all

Dim height(290,290)
Dim x(290,290)
Dim y(290,290)

Dim ylt(20)
Dim ylb(20)

For yt=1 To 290
  For xt=1 To 290
    x=xt
    y=yt
    x1=300+(x-145)+(y-145)
    y1=(300-((y+145)-(x+145))/2)
    x(xt,yt)=x1
    y(xt,yt)=y1
  Next
Next

xf=-100
xt=100
yf=-100
yt=100
peak=100

adj=-5

For y=1 To 281 Step 10
  For x=1 To 281 Step 10
    height(x,y)=(Cos(y/50)+Sin(x/50))*peak
  Next
Next

OpenWindow(0,0,0,800,600,"",#PB_Window_ScreenCentered|#PB_Window_SystemMenu)
InitSprite()
OpenWindowedScreen(WindowID(0),0,0,600,600,0,0,0)

rt=0
lo=0

Repeat

  ClearScreen(#White)
  StartDrawing(ScreenOutput())

  t=ElapsedMilliseconds()

  For y=1 To 281 Step 10
    For x=1 To 281 Step 10
      height(x,y)=(Cos(y/57)+Sin(x/57))*peak
    Next
  Next
  peak+adj
  If peak=-100 Or peak=100
    adj=-adj
  EndIf

  For yt=271 To 1 Step -10

    If WindowEvent()=#PB_Event_CloseWindow
      End
    EndIf

    For xt=1 To 271 Step 10

      x=xt
      y=yt

      x1=x(x,y)
      y1=y(x,y)-height(x,y)
      y+10

      x2=x(x,y)
      y2=y(x,y)-height(x,y)
      x+10

      x3=x(x,y)
      y3=y(x,y)-height(x,y)
      y-10

      x4=x2;x(x,y)
      y4=y(x,y)-height(x,y)

      yfrom=y2
      yto=y4
      FrontColor(RGB(0,255,0))
      If yfrom>yto
        Swap yfrom,yto
        FrontColor(RGB(255,0,0))
      EndIf

      ytp.f=y1
      ybp.f=y1
      yts.f=(yfrom-y1)/9
      ybs.f=(yto-y1)/9
      For y=1 To 9
        ytp+yts
        ybp+ybs

        ;-----------------------------------
        Line(x1+y,ytp.f,0,ybp.f-ytp.f+1)
        ;LineXY(x1+y,ytp,x1+y,ybp)
        ;-----------------------------------

      Next

      ytp=y3
      ybp=y3
      yts=(yfrom-y3)/10
      ybs=(yto-y3)/10
      For y=1 To 10
        ytp+yts
        ybp+ybs

        ;-----------------------------------
        Line(x3-y,ytp.f,0,ybp.f-ytp.f+1)
        ;LineXY(x3-y,ytp,x3-y,ybp)
        ;-----------------------------------

      Next

      FrontColor(0)

      ;-----------------------------------
      Line(x1,y1,x2-x1,y2-y1)
      Line(x2,y2,x3-x2,y3-y2)
      Line(x3,y3,x4-x3,y4-y3)
      Line(x4,y4,x1-x4,y1-y4)
      ;LineXY(x1,y1,x2,y2)
      ;LineXY(x2,y2,x3,y3)
      ;LineXY(x3,y3,x4,y4)
      ;LineXY(x4,y4,x1,y1)
      ;-----------------------------------

    Next
  Next

  t=ElapsedMilliseconds()-t

  StopDrawing()
  FlipBuffers()

  rt+t
  lo+1
  Debug "Average "+Str(rt/lo)

Until #False
User avatar
Michael Vogel
Addict
Addict
Posts: 2810
Joined: Thu Feb 09, 2006 11:27 pm
Contact:

Post by Michael Vogel »

Played a little bit around and found no speed increase when using Line instead of LineXY - I'll get also nearly same times for Windows API Lineto...

O also added am old routine I've done for antialiasing...

Code: Select all

; Simple Line
Procedure FastlineInit(Window,Width,Color)
	Global FastLineDC=GetDC_(WindowID(Window))
	Global FastLinePen=CreatePen_(#PS_SOLID,Width,Color)
	Global FastLineOld=SelectObject_(FastLineDC,FastLinePen)
EndProcedure
Procedure FastLine(x,y,x1,y1)
	MoveToEx_(FastLineDC,x,y,0)
	LineTo_(FastLineDC,x1,y1)
EndProcedure
Procedure FastlineStop()
	DeleteObject_(FastLinePen)
	DeleteObject_(FastLineOld)
EndProcedure

; Antialiased Line
Procedure.l Limit(x)
	If x<0
		ProcedureReturn 0
	ElseIf x>255
		ProcedureReturn 255
	Else
		ProcedureReturn x
	EndIf
EndProcedure
Procedure AntiLineInit(Window)
	Structure DxStructure
		StructureUnion
			l.l
			w.w
		EndStructureUnion
	EndStructure

	Global DxMem,DxMul,DxPix;	Plot-Beschleunigung...
	Global *DX.DxStructure

	windc=StartDrawing(ScreenOutput())

	DxMem=DrawingBuffer()
	DxMul=DrawingBufferPitch()
	DxPix=DrawingBufferPixelFormat()

	Global Dim AntiA(255)
	Global Dim AntiB(255)

	#AntiStrength=5

	Dummy=(#AntiStrength-5)<<4
	For k=0 To 255
		AntiA(k)=Limit(255-k+Dummy)
		AntiB(k)=Limit(k+Dummy)
	Next k

EndProcedure
Macro ColRed(col)
	(col&$ff)
EndMacro
Macro ColGreen(col)
	(col>>8&$ff)
EndMacro
Macro ColBlue(col)
	(col>>16&$ff)
EndMacro
Macro ColMix(c,r,g,b,w)
	; (c) Michael Vogel
	; 24/32 Bit-Pixel: bbbbbbbb|gggggggg|rrrrrrrr
	( (r*w+ColRed(c)*(255-w))>>8 + (g*w+ColGreen(c)*(255-w))&$ff00 + (b*w+ColBlue(c)*(255-w))<<8&$ff0000 )
EndMacro
Procedure MergePixel(x,y,r,g,b,w)
	If x>=0 And x<screenx And y>=0 And y<ScreenY
		If DxPix>=#PB_PixelFormat_32Bits_RGB
			*DX=DxMem+x<<2+y*DxMul
			*DX\l=ColMix(*DX\l,b,g,r,w)
		ElseIf DxPix>=#PB_PixelFormat_24Bits_RGB
			*DX=DxMem+x*3+y*DxMul
			*DX\l=ColMix(*DX\l,b,g,r,w)|(*DX\l&$FF000000)
		ElseIf DxPix>=#PB_PixelFormat_16Bits
			*DX=DxMem+x<<1+y*DxMul
			*DX\w=ColMurx(*DX\w,r,g,b,w)
			;Plot(x,y,ColMix(Point(x,y),r,g,b,w))
			;SetPixel_(hdc,x,y,col)
		EndIf
	EndIf
EndProcedure
Procedure AntiLineXY(x1,y1,x2,y2,col)
	Protected r = ColRed(col)
	Protected g = ColGreen(col)
	Protected b = ColBlue(col)
	Protected xd=x2-x1
	Protected yd=y2-y1
	Protected x,y,xf,yf
	Protected grad,w

	MergePixel(x1,y1,r,g,b,255)
	MergePixel(x2,y2,r,g,b,255)
	If xd=0 Or yd=0
		LineXY(x1,y1,x2,y2,col)
		ProcedureReturn
	EndIf

	If Abs(xd)>Abs(yd)
		If (x1>x2)
			Swap x1,x2
			Swap y1,y2
			xd=-xd
			yd=-yd
		EndIf

		grad=yd<<16/xd
		yf=y1<<16

		For x=x1+1 To x2-1
			yf+grad
			w=(yf>>8)&$FF
			y=yf>>16

			MergePixel(x,y,r,g,b,AntiA(w))
			MergePixel(x,y+1,r,g,b,AntiB(w))

		Next
	Else
		If (y1>y2)
			Swap x1,x2
			Swap y1,y2
			xd=-xd
			yd=-yd
		EndIf
		grad=xd<<16/yd
		xf=x1<<16
		For y=y1+1 To y2-1
			xf+grad
			w=(xf>>8)&$FF
			x=xf>>16

			MergePixel(x,y,r,g,b,AntiA(w))
			MergePixel(x+1,y,r,g,b,AntiB(w))

		Next
	EndIf
EndProcedure


_X=GetSystemMetrics_(#SM_CXSCREEN)-8
_Y=GetSystemMetrics_(#SM_CYSCREEN)-68

InitSprite() 
	
OpenWindow(0,0,0,_X,_Y,"")
;OpenWindowedScreen(WindowID(Window),0,0,_X,_Y,0,0,0)
	
StartDrawing(WindowOutput(0))
;FastlineInit(0,1,#Blue)
;AntiLineInit(0)

Zeit=GetTickCount_()
For i=0 To _X Step 8
	For j=0 To _X Step 8
		LineXY(i,0,j,_Y)
		;Line(i,0,j-i,_Y+1)
		;FastLine(i,0,j,_Y)
		;AntiLineXY(i,0,j,_Y,#Red)
	Next j
Next i
Zeit-GetTickCount_()

FastLineStop()
StopDrawing()

MessageRequester("Fertig","Zeit: "+Str(-Zeit)+"ms",0)

dell_jockey
Enthusiast
Enthusiast
Posts: 767
Joined: Sat Jan 24, 2004 6:56 pm

Post by dell_jockey »

Moin Michael,

- ColMurx() on line 79 should perhaps be ColMix() ?
- the AA routines only seem to draw horizontal and vertical lines.

I'd really appreciate to see an example that shows how to use your set of antialiassed line functions
cheers,
dell_jockey
________
http://blog.forex-trading-ideas.com
User avatar
Michael Vogel
Addict
Addict
Posts: 2810
Joined: Thu Feb 09, 2006 11:27 pm
Contact:

Post by Michael Vogel »

The routine is changing the screen memory, so I wrote different versions for 16 bit and 24 bit screens (16 bit is not very common, so I did not post the ColMurx routine - just ignore it;)...

Maybe I forgot some other procedure also? I'll check it as soon as possible...

If horizontal or vertical lines have to be drawn, the routine did not work very fine, so I use the standard Line routine from Purebasic...

Michael
Derek
Addict
Addict
Posts: 2354
Joined: Wed Apr 07, 2004 12:51 am
Location: England

Post by Derek »

Don't you get any increase at all?

Try this example,

Code: Select all

DisableDebugger
OpenWindow(0,0,0,800,600,"",#PB_Window_ScreenCentered|#PB_Window_SystemMenu)
InitSprite()
OpenWindowedScreen(WindowID(0),0,0,800,600,0,0,0)
ClearScreen(#White)
For c=1 To 100
  StartDrawing(ScreenOutput())
  FrontColor(RGB(c,c,c))
  t=ElapsedMilliseconds()
  For n=0 To 3600
    xto=400+250*Sin(n/100)
    yto=300+250*Cos(n/100)
    Line(400,300,xto-400,yto-300) ;
  Next
  t=ElapsedMilliseconds()-t
  a+t
  Debug t
  WindowEvent()
  StopDrawing()
  FlipBuffers()
Next
a=a/100
axy=0
ClearScreen(#White)
For c=1 To 100
  StartDrawing(ScreenOutput())
  FrontColor(RGB(c,c,c))
  t=ElapsedMilliseconds()
  For n=0 To 3600
    xto=400+250*Sin(n/100)
    yto=300+250*Cos(n/100)
    Linexy(400,300,xto,yto)
  Next
  t=ElapsedMilliseconds()-t
  axy+t
  Debug t
  WindowEvent()
  StopDrawing()
  FlipBuffers()
Next
axy=axy/100
MessageRequester("","Average linexy= "+Str(axy)+Chr(13)+Chr(10)+"Average line= "+Str(a))
Repeat
Until WaitWindowEvent()=#PB_Event_CloseWindow
On mine I get 8ms and 18ms, the more lines I draw the bigger the difference becomes. There is a small problem with the end points not being drawn but if you code around it then there does appear to be a good bit of speed to be had.

I did try your code and I admit that I did get the same times for the first two examples which is a bit strange.
dell_jockey
Enthusiast
Enthusiast
Posts: 767
Joined: Sat Jan 24, 2004 6:56 pm

Post by dell_jockey »

Derek,

with your last snippet, I got:
- LineXY = 32
- Line = 28
cheers,
dell_jockey
________
http://blog.forex-trading-ideas.com
Derek
Addict
Addict
Posts: 2354
Joined: Wed Apr 07, 2004 12:51 am
Location: England

Post by Derek »

@dell_jockey, seems like it might be an OS or CPU thing again because your results wouldn't be a conclusive result, some people could argue that there is other things happening on your computer and that 4ms isn't a big deal.

On mine the difference from 18 ms to 8ms is obviously alot more conclusive but if the results can't be maintained across all computers then it becomes a bit of a pointless exercise and so basically unless you are coding for a specific machine and you can test your results you may as well use linexy() if it is easier to.
Last edited by Derek on Wed Apr 18, 2007 9:14 am, edited 1 time in total.
MrMat
Enthusiast
Enthusiast
Posts: 762
Joined: Sun Sep 05, 2004 6:27 am
Location: England

Post by MrMat »

I briefly debugged it and LineXY seems to be wrapping something else which adds an extra Call (compared to Line) but the main slowdown is probably because LineXY is doing an extra SetPixelV after drawing the line.
Mat
User avatar
GeoTrail
Addict
Addict
Posts: 2794
Joined: Fri Feb 13, 2004 12:45 am
Location: Bergen, Norway
Contact:

Post by GeoTrail »

On Derek's last example I got the following on my laptop:
Average linexy = 7
Average line = 4
I Stepped On A Cornflake!!! Now I'm A Cereal Killer!
Post Reply