Page 1 of 2

AntiAliasing Drawling line

Posted: Sat Dec 29, 2007 10:49 am
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

Posted: Sat Dec 29, 2007 1:45 pm
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() .

Posted: Sat Dec 29, 2007 4:08 pm
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

Posted: Sat Dec 29, 2007 5:17 pm
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 


Posted: Sat Dec 29, 2007 7:52 pm
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)

Posted: Sat Dec 29, 2007 8:41 pm
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. :)

Posted: Sat Dec 29, 2007 9:42 pm
by flaith
thanks a lot guys :)
my goal was to find a function available for both Linux & Windows (may be with Mac too)

Posted: Tue Jan 01, 2008 9:50 pm
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

Posted: Wed Jan 02, 2008 4:13 pm
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.

Puzzled by huge speed differences

Posted: Sat Jan 12, 2008 3:59 pm
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?

Posted: Sat Jan 12, 2008 8:47 pm
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

Posted: Sun Jan 13, 2008 9:26 pm
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)...

Posted: Mon Jan 14, 2008 11:49 am
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

Posted: Mon Jan 14, 2008 5:18 pm
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 (???)

Posted: Mon Jan 14, 2008 10:20 pm
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...