AntiAliasing Drawling line

Share your advanced PureBasic knowledge/code with the community.
User avatar
flaith
Enthusiast
Enthusiast
Posts: 704
Joined: Mon Apr 25, 2005 9:28 pm
Location: $300:20 58 FC 60 - Rennes
Contact:

AntiAliasing Drawling line

Post by flaith »

Here is a code to make an Anti-Aliasing Line, i found the original code on blitz forum
:wink:

Code: Select all

;  Anti-aliased lines demo & routine.   
;  flaith 28/12/07
;
;  Blitz Basic version by By Mike Keith, Feb 2002
;  http://www.blitzbasic.com/codearcs/codearcs.php?code=227

InitSprite() : InitKeyboard()
#Screen_width = 800
#Screen_height = 600
#depth = 32
Global Dim AlineTable.l(64)

;==================================================

Declare DrawAALine(x1.l, y1.l, x2.l, y2.l, cr.l, cg.l, cb.l)
Declare DrawAACircle(x.l, y.l, r.l, cr.l, cg.l, cb.l)

Declare MergePixel(x,y,r,g,b,w)
Declare InitAlineTable()

;==================================================

If OpenWindow(0, 0, 0, #Screen_width, #Screen_height, "")
  If OpenWindowedScreen(WindowID(0), 0, 0, #Screen_width, #Screen_height, 0, 0, 0)
  EndIf
EndIf

InitAlineTable()

Repeat
  ExamineKeyboard()
  StartDrawing(ScreenOutput())
  
  Repeat
    Event = WindowEvent()

    Select Event 
      Case #PB_Event_Gadget
        If EventGadget() = 0
          quit = 1
        EndIf
        
      Case #PB_Event_CloseWindow
        quit = 1 
    EndSelect
  Until Event = 0
    
  If KeyboardPushed(#PB_Key_Escape) : quit = 1 : EndIf

  For y=0 To #Screen_height-1
	  z = y*255/(#Screen_height-1)
 	  LineXY(0,y,#Screen_width-1,y,RGB(z/2,z/3,0))
  Next

  t1 = ElapsedMilliseconds()
  For i=0 To 360 Step 5
	  dx = 150*Sin(i)
	  dy = 150*Cos(i)
    LineXY(160+dx,300+dy,160-dx,300-dy,RGB(255,255,255))
  Next
  t2 = ElapsedMilliseconds()

  DrawingMode(#PB_2DDrawing_Transparent)
  DrawText(50,535,"Regular lines")
  DrawText(50,550,"Took "+Str(t2-t1)+" ms")

  If 1
    t3 = ElapsedMilliseconds()
    For i=0 To 360 Step 5
	    dx = 150*Sin(i)
	    dy = 150*Cos(i)
	    DrawAALine(600+dx,300+dy,600-dx,300-dy,255,255,255)
    Next
    t4 = ElapsedMilliseconds()
  EndIf

  DrawingMode(#PB_2DDrawing_Transparent)
  DrawText(500,535,"Anti-aliased lines")
  DrawText(500,550,"Took "+Str(t4-t3)+" ms")

  DrawAACircle(#Screen_width/2,#Screen_height/2, 130, 192, 0, 0)

  StopDrawing()

  FlipBuffers()

Until quit = 1
End

;=========================================================

Procedure DrawAACircle(x.l, y.l, r.l, cr.l, cg.l, cb.l)
Protected x1.l, y1.l, x2.l, y2.l

	For theta= 0 To 359 Step 4
		x1 = r*Cos(theta*#PI/180)+x
		y1 = -r*Sin(theta*#PI/180)+y

		x2 = r*Cos((theta+4)*#PI/180)+x
		y2 = -r*Sin((theta+4)*#PI/180)+y
		
		DrawAALine(x1, y1, x2, y2, cr, cg, cb)
  Next
EndProcedure

;=========================================================
Procedure DrawAALine(x1.l, y1.l, x2.l, y2.l, r.l, g.l, b.l)

	xd = x2-x1
	yd = y2-y1
	
	If (xd = 0 Or yd = 0)
 		LineXY(x1,y1,x2,y2,RGB(r,g,b))
		ProcedureReturn
	EndIf

 	Plot(x1,y1,RGB(r,g,b))
  Plot(x2,y2,RGB(r,g,b))
	
	If (Abs(xd) > Abs(yd))
		If (x1 > x2)
			tmp = x1: x1 = x2: x2 = tmp
			tmp = y1: y1 = y2: y2 = tmp
			xd = x2-x1
			yd = y2-y1
		EndIf
		
		grad = yd*65536/xd
		yf = y1*65536
		
		For x=x1+1 To x2-1
			yf = yf + grad		
			w = (yf >> 10) & $3f
			y = yf >> 16
			
			MergePixel(x,y,r,g,b,63-w)
			MergePixel(x,y+1,r,g,b,w)
		
		Next
	Else
		If (y1 > y2)
			tmp = x1: x1 = x2: x2 = tmp
			tmp = y1: y1 = y2: y2 = tmp
			xd = x2-x1
			yd = y2-y1
		EndIf
		
		grad = xd*65536/yd
		xf = x1*65536
		
		For y=y1+1 To y2-1
			xf = xf + grad		
			w = (xf >> 10) & $3f
			x = xf >> 16
			
			MergePixel(x,y,r,g,b,63-w)
			MergePixel(x+1,y,r,g,b,w)
			
		Next
	EndIf

EndProcedure

;--------------------------------------------------------------------------
Procedure MergePixel(x.l,y.l,r.l,g.l,b.l,w.l)
Protected wf.l, pix.l, ro.l, go.l, bo.l, rnew.l, gnew.l, bnew.l

	wf = AlineTable(w)
 	pix = Point(x,y)

	ro = Red(pix)
	go = Green(pix)
	bo = Blue(pix)
	
	rnew = ro + ((wf*(r-ro)) >> 8)
	gnew = go + ((wf*(g-go)) >> 8)
	bnew = bo + ((wf*(b-bo)) >> 8)
	
 	Plot(x,y,RGB(rnew,gnew,bnew))

EndProcedure

;--------------------------------------------------------------------------
Procedure InitAlineTable()
Protected i.l

	For i=0 To 63
		ALineTable(i) = (Sqr(4*i)*16)*0.4 + (4*i)*0.6
	Next

EndProcedure
Last edited by flaith on Sat Dec 29, 2007 4:07 pm, edited 1 time in total.
“Fear is a reaction. Courage is a decision.” - WC
akj
Enthusiast
Enthusiast
Posts: 668
Joined: Mon Jun 09, 2003 10:08 pm
Location: Nottingham

Post by akj »

@flaith
Your drawing program runs MUCH faster if you remove all occurrences of StartDrawing(ScreenOutput()) and StopDrawing(), then add StartDrawing(ScreenOutput()) just after ExamineKeyboard() and add StopDrawing() just before FlipBuffers() .
Anthony Jordan
User avatar
flaith
Enthusiast
Enthusiast
Posts: 704
Joined: Mon Apr 25, 2005 9:28 pm
Location: $300:20 58 FC 60 - Rennes
Contact:

Post by flaith »

akj wrote:@flaith
Your drawing program runs MUCH faster if you remove all occurrences of StartDrawing(ScreenOutput()) and StopDrawing(), then add StartDrawing(ScreenOutput()) just after ExamineKeyboard() and add StopDrawing() just before FlipBuffers() .
Updated, thanks :D
“Fear is a reaction. Courage is a decision.” - WC
User avatar
einander
Enthusiast
Enthusiast
Posts: 744
Joined: Thu Jun 26, 2003 2:09 am
Location: Spain (Galicia)

Post by einander »

Nice example.

Here is a comparative test with GDIPlus.
Happy 2008!

Code: Select all

;  Anti-aliased lines demo & routine.   
;  flaith 28/12/07
;  Blitz Basic version by By Mike Keith, Feb 2002

;  http://www.blitzbasic.com/codearcs/codearcs.php?code=227 

; Added GDIPlus comparative by einander

Global _Img,_ImGad 
Global _QPF.Q,_GDIP,_GRAPH
Global Dim _QPF.Q(10)  ; redim to your counter needs

If QueryPerformanceFrequency_(@_QPF)=0 ;Get current performance-counter freq, in counts per second
     MessageRequester("OJO","NO hay QPF",0)
     End
EndIf 

Global _MQPF.D=_QPF/1000  
#GDIP=1

Global Dim AlineTable.l(64)
    
;<<<<<<<<<<<<<<<<<<<<<<<<<<<   from my GDIp Include file     
Structure GdiplusStartupInput
     GdiPlusVersion.l
     DebugEventCallback.l
     SuppressBackgroundThread.l
     SuppressExternalCodecs.l
EndStructure
     
Prototype GdiplusStartup(*a,*b,c=0)
    
Macro GName : GetFunction(#GDIP,Name) : EndMacro   ;- Gname
     
Prototype P1(A) : Macro M1(Name,A) : GF.P1=GName:GF(A) :EndMacro
Prototype P2(A,b) : Macro M2(Name,A,b) : GF.P2=GName:GF(A,b) :EndMacro
Prototype P1F2(A,b.f,c,d) : Macro M1F2(Name,A,b,c,d) : GF.P1f2=GName:GF(A,b,c,d) :EndMacro 
Prototype P2FFFF(A,b,c.f,d.f,E.f,F.f) : Macro  M2FFFF(Name,A,b,c,d,E,F) : GF.P2FFFF=GName:GF(A,b,c,d,E,F) :EndMacro
Prototype P6(A,b,c,d,E,F) : Macro M6(Name,A,b,c,d,E,F) : GF.P6=GName:GF(A,b,c,d,E,F) :EndMacro
     
Macro GdipDelPen :      M1("GdipDeletePen",GpPen) :EndMacro ;- GdipDelPen ;  delete solamente GpPen
Macro ARGB(RGB=0,Alpha=255)  ;- ARGB((RGB=0,Transp=255)
     RGB2ARGB(RGB,Alpha)
EndMacro 

Macro RGB2ARGB(RGB,Alpha) ;- RGB2ARGB(RGB,Alpha) - convert RGB to Alpha RGB
     Blue(RGB)|Green(RGB)<<8|Red(RGB)<<16|Alpha<<24
EndMacro
     
Macro GPen(ARGB,LineWidth,StartCap=2,EndCap=2) ;- GPen(ARGB,LineWidth,StartCap=2,EndCap=2)
     M1F2("GdipCreatePen1",ARGB,LineWidth,2,@GpPen)
     M2("GdipSetPenStartCap",GpPen,StartCap)
     M2("GdipSetPenEndCap",GpPen,EndCap)
EndMacro    
     
Macro GdipInit(Mode=2) ;- GdipInit(Mode)   ; Mode 1=Fast,2 =HiRes
     If _GDIP =0
          If OpenLibrary(#GDIP,"GDIPlus.DLL")
               Gdip.GdiplusStartupInput\GdiPlusVersion=1
               Gdip\DebugEventCallback = 0
               Gdip\SuppressBackgroundThread = 0
               Gdip\SuppressExternalCodecs = 0
               GF.GdiplusStartup = GetFunction(#GDIP, "GdiplusStartup") : GF(@_GDIP,@Gdip)
               M2("GdipCreateFromHDC",_DRAWING,@_GRAPH)
               If Mode=2 
                    M2("GdipSetSmoothingMode",_GRAPH,Mode)
               EndIf 
          Else
               MessageRequester("Error !","GDIPlus.DLL Not found",0)
          EndIf
     EndIf
EndMacro
Macro GdipClose  ;- GdipClose
     If _GDIP
          M1("GdipDeleteGraphics",_GRAPH)
          M1("GdiplusShutdown",_GDIP)
          CloseLibrary(#GDIP)
          _GDIP=0
     EndIf
EndMacro  
   
Macro IsGDIP ;- IsGDIP
     If _GDIP=0 :  GdipInit(2) :  EndIf
EndMacro

Procedure GdipLine(X.f,Y.f,X1.f,Y1.f,LineWidth.f=1,ARGB1=0,StartCap=2,EndCap=2)
     IsGDIP 
     GPen(ARGB1,LineWidth,StartCap,EndCap)
     M2FFFF("GdipDrawLine",_GRAPH,GpPen,X,Y,X1,Y1)
     GdipDelPen
EndProcedure

Procedure GdipCircle(X,Y,Radius,Rim,ARGB) ; unfilled circle
     IsGDIP  
     Radius*2
     M1F2("GdipCreatePen1",ARGB,Rim,0,@GpPen)
     M6("GdipDrawEllipseI", _GRAPH,GpPen,X-Radius/2,Y-Radius/2,Radius,Radius) 
     GdipDelPen 
EndProcedure
; <<<<<<<<<<<<<   end of GDIP section <<<<<<<<<<<<

     
Macro StartQPF(n) ;- StartQPF(n)
     QueryPerformanceCounter_(@_QPF(n))
EndMacro 
     
Procedure.D GetQPF(n) ;Ret milisegundos desde StartQPF(n)
     QueryPerformanceCounter_(@T.Q)
     ProcedureReturn(T- _QPF(n))/_MQPF
EndProcedure

Procedure MergePixel(X,Y,R,G,b,w)
     Protected wf.l, pix.l, ro.l, go.l, bo.l, rnew.l, gnew.l, bnew.l
     wf = AlineTable(w)
     pix = Point(X,Y)
     
     ro = Red(pix)
     go = Green(pix)
     bo = Blue(pix)
     
     rnew = ro + ((wf*(R-ro)) >> 8)
     gnew = go + ((wf*(G-go)) >> 8)
     bnew = bo + ((wf*(b-bo)) >> 8)
     Plot(X,Y,RGB(rnew,gnew,bnew))
EndProcedure


Procedure DrawAALine(X1, Y1, X2, Y2, R, G, b)
     xd = X2-X1 :  yd = Y2-Y1
     If (xd = 0 Or yd = 0)
          LineXY(X1,Y1,X2,Y2,RGB(R,G,b))
          ProcedureReturn
     EndIf
     Plot(X1,Y1,RGB(R,G,b))
     Plot(X2,Y2,RGB(R,G,b))
     
     If (Abs(xd) > Abs(yd))
          If (X1 > X2)
               TMP = X1: X1 = X2: X2 = TMP
               TMP = Y1: Y1 = Y2: Y2 = TMP
               xd = X2-X1
               yd = Y2-Y1
          EndIf
          
          Grad = yd*65536/xd
          yf = Y1*65536
          
          For X=X1+1 To X2-1
               yf = yf + Grad      
               w = (yf >> 10) & $3F
               Y = yf >> 16
               
               MergePixel(X,Y,R,G,b,63-w)
               MergePixel(X,Y+1,R,G,b,w)
          Next
     Else
          If (Y1 > Y2)
               TMP = X1: X1 = X2: X2 = TMP
               TMP = Y1: Y1 = Y2: Y2 = TMP
               xd = X2-X1
               yd = Y2-Y1
          EndIf
          
          Grad = xd*65536/yd
          xf = X1*65536
          
          For Y=Y1+1 To Y2-1
               xf = xf + Grad      
               w = (xf >> 10) & $3F
               X = xf >> 16
               
               MergePixel(X,Y,R,G,b,63-w)
               MergePixel(X+1,Y,R,G,b,w)
          Next
     EndIf
EndProcedure

Procedure DrawAACircle(X, Y, R, cr, cg, cb)
     Protected X1.l, Y1.l, X2.l, Y2.l
     
     For theta= 0 To 359 Step 4
          X1 = R*Cos(theta*#PI/180)+X
          Y1 = -R*Sin(theta*#PI/180)+Y
          
          X2 = R*Cos((theta+4)*#PI/180)+X
          Y2 = -R*Sin((theta+4)*#PI/180)+Y
          
          DrawAALine(X1, Y1, X2, Y2, cr, cg, cb)
     Next
EndProcedure


;--------------------------------------------------------------------------
Procedure InitAlineTable()
     Protected i.l
     For i=0 To 63
          AlineTable(i) = (Sqr(4*i)*16)*0.4 + (4*i)*0.6
     Next
EndProcedure


 ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
;==================================================
hwnd=OpenWindow(0, 100, 100,700,500 ,"",  #WS_OVERLAPPEDWINDOW | #WS_MAXIMIZE) 
CreateGadgetList(hwnd) 
Wi=WindowWidth(0):He=WindowHeight(0)
_ImGad=ImageGadget(-1,0,0,0,0,0) 
_Img=CreateImage(-1,Wi,He,32)

InitAlineTable()

_DRAWING=StartDrawing(ImageOutput(_Img))
DrawingMode( #PB_2DDrawing_Transparent | #PB_2DDrawing_Outlined)
Repeat
     Ev = WindowEvent()
     Select Ev
          Case #PB_Event_Gadget
               If EventGadget() = 0
                    QUIT = 1
               EndIf
               
          Case #PB_Event_CloseWindow
               QUIT = 1
     EndSelect
Until Ev = 0
     
     
For Y=0 To WindowHeight(0)-1
     z = Y*255/(He-1)
     LineXY(0,Y,Wi-1,Y,RGB(z/2,z/3,0))
Next

StartQPF(1)
     
T1 = ElapsedMilliseconds()
For i=0 To 360 Step 5
     dx = 150*Sin(i)
     dy = 150*Cos(i)
     LineXY(160+dx,300+dy,160-dx,300-dy,RGB(255,255,255))
Next
t2.D=GetQPF(1)
     
DrawText(50,535,"Regular lines")
DrawText(50,550,"Took "+StrD(t2,3)+" sec")
     
StartQPF(1)
For i=0 To 360 Step 5
     dx = 150*Sin(i)
     dy = 150*Cos(i)
     DrawAALine(480+dx,300+dy,480-dx,300-dy,255,255,255)
Next
t2.D=GetQPF(1)

DrawText(400,535,"Anti-aliased lines")
DrawText(400,550,"Took "+StrD(t2,3)+" sec")

GdipInit()
StartQPF(1)

For i=0 To 360 Step 5
     dx = 150*Sin(i)
     dy = 150*Cos(i)
     GdipLine(800+dx,300+dy,800-dx,300-dy,1,ARGB(#White))
Next
t2=GetQPF(1)
DrawText(700,535,"Gdip Anti-Aliased Lines")
DrawText(700,550,"Took "+StrD(t2,3)+" sec")

Circle(200,WindowHeight(0)/2,130,#Red)     
DrawAACircle(500,He/2, 130, 192, 0, 0)
GdipCircle(800,He/2,130,1,ARGB(#Red))
GdipClose

StopDrawing()

SetGadgetState(_ImGad,ImageID(_Img) )
 
Repeat 
     If GetAsyncKeyState_(#VK_ESCAPE):End:EndIf
     Ev=WaitWindowEvent() 
Until Ev=#WM_CLOSE 

User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8451
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Post by netmaestro »

@flaith, thanks for this, the quality is quite good and I know several people have been looking for such a solution without resorting to gdiplus or libs.

@einander, thx, nice comparative test! (hard to compete with the speed of gdiplus)
BERESHEIT
User avatar
einander
Enthusiast
Enthusiast
Posts: 744
Joined: Thu Jun 26, 2003 2:09 am
Location: Spain (Galicia)

Post by einander »

@Netmaestro:
thx also to you for QPF; I've found it for the first time on one of your posts, and now I'm using it daily. :)
User avatar
flaith
Enthusiast
Enthusiast
Posts: 704
Joined: Mon Apr 25, 2005 9:28 pm
Location: $300:20 58 FC 60 - Rennes
Contact:

Post by flaith »

thanks a lot guys :)
my goal was to find a function available for both Linux & Windows (may be with Mac too)
“Fear is a reaction. Courage is a decision.” - WC
User avatar
Michael Vogel
Addict
Addict
Posts: 2810
Joined: Thu Feb 09, 2006 11:27 pm
Contact:

Post by Michael Vogel »

If your code should run on different machines with different color depth, you should add different pixel routines...

For my 3D-rotation of sport courses (sudokuprogram.googlepages.com/forerunner.exe) I check the screen properties with...
DxPix=DrawingBufferPixelFormat()

...then I do different things depending which color mode is used...

Code: Select all

Macro ColRGB(r,g,b)
	( r&$ff + (g&$ff)<<8 + (b&$ff)<<16 )
EndMacro
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)
	;
	; 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 )
	;
	; nach  [w*a+(255-w)*b]/256 = [w*(a-b)+255*b]/256 ~ [w+(a-b)]/256 + b  sparen wir eine Multiplikation...
	;( (w*(r-ColRed(c)))>>8 + (w*(g-ColGreen(c)))&$ff00 + (w*(b-ColBlue(c)))<<8&$ff0000 + c)
EndMacro
Macro ColMurx(c,r,g,b,w)
	;
	; 16 Bit-Pixel:  rrrr|rggg|ggxb|bbbb    (wobei "x" bei grün verwendet wird)
	( (r*w+(c>>8&$f8)*(255-w))&$f800 + ((g*w+(c>>3&$f8)*(255-w))&$f800)>>5 + (b*w+(c<<3&$f8)*(255-w))>>11 )
	;
	; nach  [w*a+(255-w)*b]/256 = [w*(a-b)+255*b]/256 ~ [w+(a-b)]/256 + b  sparen wir eine Multiplikation...
	;( (w*(r-c>>8&$f8)+c)&$f800 + ((w*(g-c>>3&$f8))>>5+c)&$7c0 + (w*(b-c<<3&$f8))>>11 +c&$1f )
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
yrreti
Enthusiast
Enthusiast
Posts: 546
Joined: Tue Oct 31, 2006 4:34 am

Post by yrreti »

Thanks @flaith and @einander.
Those are beautiful demos and comparisons :!: :!: :!:
The difference is amazing.

Michael Vogel, your code line

Code: Select all

*DX\l=ColMix(*DX\l,b,g,r,w)
errors out: The following variable doesn't have a 'Structure': *DX
Macro Error displays:
*DX\l=( (b*w+(*DX\l&$ff)*(255-w))>>8 + (g*w+(*DX\l>>8&$ff)*(255-w))&$ff00 + (r*w+(*DX\l>>16&$ff)*(255-w))<<8&$ff0000 )
I know this is just partial code, but I would appreciate seeing more of how this could be implemented if you could.
Thanks for your input.
dell_jockey
Enthusiast
Enthusiast
Posts: 767
Joined: Sat Jan 24, 2004 6:56 pm

Puzzled by huge speed differences

Post by dell_jockey »

Flype & Einander,

thanks a lot for this piece of code, very timely that! Especially the portablitily of Flype's code is very welcome indeed....

One question: why is Flype's code in the Einander-file running so much faster that the original? The Einander test code shows the bitmap almost instantly after starting the compiled app, Flype's original takes about seven seconds. Both of course compiles without debugger info - test run on a 2.6Ghz XP-Pro box. Since it's non-threading code, I don't need to mention the number of cores my test box has, do I?
I've seen that the window gets opened a bit differently, but is there such a performance difference in doing that?
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 »

yrreti wrote:Thanks @flaith and @einander.
Michael Vogel, your code line

Code: Select all

*DX\l=ColMix(*DX\l,b,g,r,w)
errors out: The following variable doesn't have a 'Structure': *DX
I know this is just partial code, but I would appreciate seeing more of how this could be implemented if you could.
Thanks for your input.
I'll try to take out all parts for a small demo, but this will take a while...

Here's just the part with the variables and structures...

Code: Select all

Structure DxStructure
		StructureUnion
			l.l
			w.w
		EndStructureUnion
	EndStructure

	Global DxMem,DxMul,DxPix;	Plot-Beschleunigung...
	Global DxFunction
	Global *DX.DxStructure
The good thing of manipulating the memory directly is speed, of course (is around 10 times faster than using the point commands)...

The bad thing is, that there are some graphic cards I could not find the right pixel formula to to do correct lines (I just see "funny" pixels at the screen)

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

Post by Michael Vogel »

So I have collected all pieces of my code necessary to run the antialiasing lines...

And here are the good and bad things of my code:
:D it's fast - because writing directly to memory
:) it's my own code (especially the macros show how sick someone can be;)
:cry: it does not work on all graphic cards (help is absolute welcome!)

Code: Select all

; Define
	Global ScreenX=GetSystemMetrics_(#SM_CXSCREEN)
	Global ScreenY=GetSystemMetrics_(#SM_CYSCREEN)

	Global OptAntialiasing=1

	Structure DxStructure
		StructureUnion
			l.l
			w.w
		EndStructureUnion
	EndStructure

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

	Declare.l Limit(x.l)

	Global Dim AntiA(255)
	Global Dim AntiB(255)
	
	For k=0 To 255
		AntiA(k)=Limit(255-k+63)
		AntiB(k)=Limit(k+63)
	Next k

; EndDefine
Macro ColRGB(r,g,b)
	( r&$ff + (g&$ff)<<8 + (b&$ff)<<16 )
EndMacro
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)
	( (r*w+ColRed(c)*(255-w))>>8 + (g*w+ColGreen(c)*(255-w))&$ff00 + (b*w+ColBlue(c)*(255-w))<<8&$ff0000 )
EndMacro
Macro ColMurx(c,r,g,b,w)
	( (r*w+(c>>8&$f8)*(255-w))&$f800 + ((g*w+(c>>3&$f8)*(255-w))&$f800)>>5 + (b*w+(c<<3&$f8)*(255-w))>>11 )
EndMacro

Procedure.l Limit(x)
	If x<0
		ProcedureReturn 0
	ElseIf x>255
		ProcedureReturn 255
	Else
		ProcedureReturn x
	EndIf
EndProcedure

Procedure MergePixel32(x,y,r,g,b,w)
	If x>=0 And x<ScreenX And y>=0 And y<ScreenY
		*DX=DxMem+y*DxMul+x<<2
		*DX\l=ColMix(*DX\l,b,g,r,w)
	EndIf
EndProcedure
Procedure MergePixel24(x,y,r,g,b,w)
	If x>=0 And x<ScreenX And y>=0 And y<ScreenY
		*DX=DxMem+x*3+y*DxMul
		*DX\l=ColMix(*DX\l,b,g,r,w)|(*DX\l&$FF000000)
	EndIf
EndProcedure
Procedure MergePixel16(x,y,r,g,b,w)
	If x>=0 And x<ScreenX And y>=0 And y<ScreenY
		*DX=DxMem+x<<1+y*DxMul
		*DX\w=ColMurx(*DX\w,r,g,b,w)
	EndIf
EndProcedure

Procedure AntiLineXY(x1,y1,x2,y2,col)
	
	If OptAntialiasing

		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

		CallFunctionFast(DxFunction,x1,y1,r,g,b,255)
		CallFunctionFast(DxFunction,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

				CallFunctionFast(DxFunction,x,y,r,g,b,AntiA(w))
				CallFunctionFast(DxFunction,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

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

			Next
		EndIf
	Else
		LineXY(x1,y1,x2,y2,col)
	EndIf
	
EndProcedure

Procedure Main()
	InitSprite()

	win=OpenWindow(0,0,0,ScreenX,ScreenY,"",#PB_Window_ScreenCentered|#PB_Window_BorderLess)
	OpenWindowedScreen(win,0,0,ScreenX,ScreenY,0,0,0)

	ClearScreen(#Black)
	FlipBuffers()
	
	windc=StartDrawing(ScreenOutput())

	If OptAntialiasing

		DxMem=DrawingBuffer()
		DxMul=DrawingBufferPitch()
		DxPix=DrawingBufferPixelFormat(); DOES NOT WORK ON ALL NOTEBOOKS...

		If DxPix=0;												...SO I TRY SOMETHING ELSE ALSO!
			i=GetDC_(0)
			Select GetDeviceCaps_(i,#BITSPIXEL)
			Case 32
				DxPix=#PB_PixelFormat_32Bits_RGB
			Case 24
				DxPix=#PB_PixelFormat_24Bits_RGB
			Case 15,16
				DxPix=#PB_PixelFormat_16Bits
			EndSelect
			ReleaseDC_(0,i)
		EndIf


		If DxPix>=#PB_PixelFormat_32Bits_RGB
			DxFunction=@MergePixel32()
		ElseIf DxPix>=#PB_PixelFormat_24Bits_RGB
			DxFunction=@MergePixel24()
		ElseIf DxPix>=#PB_PixelFormat_15Bits
			DxFunction=@MergePixel32()
		Else
			OptAntialiasing=0
		EndIf
		
	EndIf
			
			
	For i=0 To 1000
		x=Random(ScreenX)-50
		y=Random(ScreenY)-50
		AntiLineXY(x,y,x+Random(200),y+Random(200),#White)
		;AntiLineXY(Random(ScreenX),Random(ScreenY),Random(ScreenX),Random(ScreenY),#White)
	Next i
	StopDrawing()

	FlipBuffers(0)
	Delay(2000)

EndProcedure

Main()
PS I have extracted the code parts from my sport program which shows running tracks in 3D (http://sudokuprogram.googlepages.com/GPS)...
dell_jockey
Enthusiast
Enthusiast
Posts: 767
Joined: Sat Jan 24, 2004 6:56 pm

Post by dell_jockey »

Moin Michael,

thank you very much for posting this code.

Using either PB 4.10 or PB 4.20 Beta1 on a XP Prof box with an NVIDIA Quadro FX570 graphics card (two displays attached), I get the following error on line 61 which is in MergePixel32():

Code: Select all

Invalid memory access (read error at address:  ....)
it's on the line that reads:

Code: Select all

*DX\l=ColMix(*DX\l,b,g,r,w)
Is this one of the problems that you mentioned before (those that happen on some graphics cards only?)
  • - on another XP client with PB 4.10, this one also with two displays but driven by a GeForce Ti-4200 card, it works o.k.
    - on a laptop running XP with GeForce 440 Go graphics and running the PB 4.02 compiler there's no problem.
    - on yet another laptop running XP, one with ATI Rage Mobility graphics and running PB 4.10, there's no problem either.
    - the next test will be on Ubuntu (also with a GeForce Ti-4200), I'll report back on that one
Tschüss
Last edited by dell_jockey on Mon Jan 14, 2008 10:23 pm, edited 2 times in total.
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 »

dell_jockey wrote: [...] with an NVIDEA Quadro FX570 graphics card (two displays attached), I get the following error on line 61 which is in MergePixel32():

Code: Select all

Invalid memory access (read error at address:  ....)
Hey, what a report :wink:

Your seen problem is new for me, maybe you can have a look, if the DX-values (add Debug commands for DxMem, DxMul, DxPix) will get set during the initialization...
The error I got some informations for, that instead of correct lines only "random" dots are seen on some graphic cards - but I have no more details for now.

So there are already two things to solve:
- invalid memory access (NVIDIA)
- wrong "random" pixels (???)
dell_jockey
Enthusiast
Enthusiast
Posts: 767
Joined: Sat Jan 24, 2004 6:56 pm

Post by dell_jockey »

Michael Vogel wrote: Hey, what a report :wink:
Let's just say that I'm VERY VERY VERY interested in getting this to work correctly.... ;)

Michael Vogel wrote: Your seen problem is new for me, maybe you can have a look, if the DX-values (add Debug commands for DxMem, DxMul, DxPix) will get set during the initialization...
This is how I modified your code:

Code: Select all

  If OptAntialiasing

      DxMem=DrawingBuffer()
      DxMul=DrawingBufferPitch()
      DxPix=DrawingBufferPixelFormat(); DOES NOT WORK ON ALL NOTEBOOKS...
      
      Debug(DxMem)
      Debug(DxMul)
      Debug(DxPix)

      If DxPix=0;                                    ...SO I TRY SOMETHING ELSE ALSO!
         i=GetDC_(0)
         Select GetDeviceCaps_(i,#BITSPIXEL)
         Case 32
            DxPix=#PB_PixelFormat_32Bits_RGB
         Case 24
            DxPix=#PB_PixelFormat_24Bits_RGB
         Case 15,16
            DxPix=#PB_PixelFormat_16Bits
         EndSelect
         ReleaseDC_(0,i)
      EndIf

      Debug(DxPix)

And this is what is being reported:
  • 22151168
    8192
    7
    7
Apparently, DxPix is set to 7 on the first try....
The 8K DxMul is perhaps because of the two displays that form a single desktop?

On none of the systems where your code ran o.k. I saw any wrong/random pixels...

Also please note that the invalid memory access error is NOT a generic NVIDIA problem, as it ran o.k. on the TI 4200 and on the GeForce 440 Go. Only on the Quadro FX570 equipped system I got this error.

Hope this helps...
cheers,
dell_jockey
________
http://blog.forex-trading-ideas.com
Post Reply