Page 1 of 2

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

Posted: Thu Mar 29, 2007 12:03 pm
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

Posted: Thu Mar 29, 2007 4:47 pm
by pjay
That's an interesting find. You should post it as a bug.

Posted: Thu Mar 29, 2007 8:25 pm
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 

Posted: Thu Mar 29, 2007 10:07 pm
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.

Posted: Fri Mar 30, 2007 6:05 am
by Kaeru Gaman
@Derek

nice tip, thanks. :D

Posted: Fri Mar 30, 2007 6:53 am
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.

Posted: Fri Mar 30, 2007 9:19 am
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

Posted: Wed Apr 11, 2007 11:41 am
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)


Posted: Thu Apr 12, 2007 8:54 am
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

Posted: Tue Apr 17, 2007 8:25 am
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

Posted: Tue Apr 17, 2007 4:06 pm
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.

Posted: Tue Apr 17, 2007 5:08 pm
by dell_jockey
Derek,

with your last snippet, I got:
- LineXY = 32
- Line = 28

Posted: Tue Apr 17, 2007 6:11 pm
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.

Posted: Tue Apr 17, 2007 6:44 pm
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.

Posted: Tue Apr 17, 2007 8:33 pm
by GeoTrail
On Derek's last example I got the following on my laptop:
Average linexy = 7
Average line = 4