Directdraw Library - Antialiasing; Restore Background; etc..
Posted: Sun May 17, 2009 4:39 pm
please use this if you like. i've gotten so much support from this forum that i am really happy to give something. i hope it is at all useful to someone.
please give any feedback for optimization or additions. (this is just a start)
please give any feedback for optimization or additions. (this is just a start)
Code: Select all
;=========================================;
; ;
; C I N T A M A N I ;
; ;
; Directdraw Graphics Library ;
; ;
;_________________________________________;
; ;
; jayagopal.das -- May 15, 2009 ;
; ;
;=========================================;
;-Constants
;#screenW =1280: #screenH = 800
;#screenW =1024: #screenH = 768
#screenW = 800: #screenH = 600
;#screenW = 640: #screenH = 480
;#screenW = 320: #screenH = 240
#RD=0
#GR=1
#BL=2
#Background=-2
#Foreground=-1
;-Procedure Declarations
;Graphics
Declare redraw() ; draw the virtual-screen on the real one
Declare clear(x1=0,y1=0,x2=#screenW-1,y2=#screenH-1) ; restore the background (or a portion of it)
Declare addPage() ; add a screen page
Declare deletePage(pageNumber) ;NOT TESTED YET!!!
Declare copyPageFore(pageNumber) ; copy a screen page to the foreground
Declare copyPageBack(pageNumber) ; copy a screen page to the background
Declare.c virtualScreen(x,y,channel,intensity=-1) ; read/write the appropriate screen page
Declare mLine(x1,y1,x2,y2,r=255,g=255,b=255,a=255,antialias=0) ; manual line drawing routine
Declare mCircle(x,y,rad,r=255,g=255,b=255,a=255,antialias=0) ; manual circle drawing routine
Declare pixel(x,y,r,g,b,a=255) ; write a pixel to the virtual screen
;Calculation
Declare.f frac(num.f) ; return the fractional part of a number
Declare.f radius(dx,dy) ; return a value from the radius table
Declare sign(n) ; return the sign of a number
;-Global arrays and variables
Global Dim radiusTable.f(#screenW,#screenH) ; to speed up distance calculations
Global *foreground=AllocateMemory(#screenW*#screenH*4) ; the foreground screen page
Global *background=AllocateMemory(#screenW*#screenH*4) ; the background screen page
Global Dim *page(0) ; used for storing additional screen pages
Global pageCount=0
Global Buffer ; starting address for screen memory
Global Pitch ; bytes in one screen-line
Global drawPage ; the page to draw to
;==========STARTING FROM HERE, this can be in another file==================
;-Initialization
If InitSprite()=0 Or InitKeyboard()=0 Or InitMouse()=0: End: EndIf
If OpenScreen(#screenW, #screenH, 32, "PB DirectGraphics Library Example")
;- Main Loop
;{ contains examples of drawing using these procedures
;draw some static on a gradient on 4 different pages
For i=1 To 4
addPage()
drawPage=i ;this is the page-number to draw to (index starts from 1)
For y=0 To #screenH-1: For x=0 To #screenW-1
pixel(x,y,Int(x/#screenW*255),Int(y/#screenH*255),Int((x+y)/(#screenW+#screenH)*255)): pixel(x,y,Random(64),Random(64),Random(64),128)
Next: Next
Next
;some variables for drawing the thingy
rad=#screenH*0.14: circumference=rad*2*#PI: t.f: ti.f
Repeat
ExamineKeyboard()
ExamineMouse()
drawPage=#Foreground
;draw a weird thingy that spins And follows the mouse
;mx=MouseX(): my=MouseY()
mx=DesktopMouseX(): my=DesktopMouseY()
mLine(#screenW/2,#screenH/2,mx,my,255,255,255,155,1)
t=ti: ti+0.05
For i=0 To 23
t+(#PI/12): px=mx+rad*Cos(t): py=my+rad*Sin(t)
mLine(mx,my,px,py,255,255,255,155,1)
mCircle(px,py,#screenH*0.02,255,255,255,155,1)
Next
;draw some random lines, circles and pixels
For i=1 To 3000: pixel(Random(#screenW),Random(#screenH), Random(255),Random(255),Random(255), Random(155)): Next
For i=1 To 10
mLine(Random(#screenW),Random(#screenH), Random(#screenW),Random(#screenH), Random(255),Random(255),Random(255), Random(55),1)
mCircle(Random(#screenW),Random(#screenH), Random(#screenW), Random(255),Random(255),Random(255), Random(55),1)
Next
mCircle(#screenW/2,#screenH/2,#screenH*0.3, 255,255,255,155,0) ;standing circle
mCircle(#screenW/2,#screenH/2,#screenH*0.4, 255,255,255,155,1) ;standing antialiased circle
mLine(#screenW*0.375,#screenH,#screenW,#screenH*0.375, 255,255,255,155,0) ;standing line
mLine(0,#screenH/2,#screenW/2,0, 255,255,255,155,1) ;standing antialiased line
;cycle the background through all the extra pages (this will not effect the foreground, but WILL overwrite the background)
If q=pageCount: q=1: EndIf: copyPageBack(q): q+1
drawPage=#Background
;draw directly onto the background (even after the foreground is drawn) -- this will be updated after clear() is called
For r =1 To 50: mCircle(100,100, r, Random(255),Random(255),Random(255), Random(55),1): Next
redraw()
clear() ;full clear
;halfDim=rad+#screenH*0.02+1: clear(mx-halfDim,my-halfDim,mx+halfDim,my+halfDim) ;example of clearing just a portion
Until KeyboardPushed(#PB_Key_Escape) ;}
Else
MessageRequester("Error","Sorry, some problem drawing the screen?",0)
EndIf
End
;==========AND ENDING HERE, this can be in another file==================
;-Graphics procedures
Procedure redraw()
restoredrawPage=drawPage
drawPage=#Foreground
If StartDrawing(ScreenOutput())
Buffer = DrawingBuffer() ; Get the start address of the screen buffer.
Pitch = DrawingBufferPitch() ; Get the length (in bytes) of one horizontal line.
For y=0 To #screenH-1
*Line.l = Buffer+Pitch*y
For x=0 To #screenW-1
PokeC(*Line, virtualScreen(x,y,#BL)): *Line+1
PokeC(*Line, virtualScreen(x,y,#GR)): *Line+1
PokeC(*Line, virtualScreen(x,y,#RD)): *Line+2
Next
Next
StopDrawing()
FlipBuffers() ; Page flipping
EndIf
drawPage=restoredrawPage
EndProcedure
Procedure clear(x1=0,y1=0,x2=#screenW-1,y2=#screenH-1)
If x1=0 And y1=0 And x2=#screenW-1 And y2=#screenH-1
CopyMemory(*background,*foreground,#screenW*#screenH*4)
Else
;restore the specified portion
If x1>x2: Swap x1, x2: EndIf
If y1>y2: Swap y1, y2: EndIf
If x1<0: x1=0: EndIf: If x2>#screenW-1: x2=#screenW-1: EndIf
If y1<0: y1=0: EndIf: If y2>#screenH-1: y2=#screenH-1: EndIf
width=(x2-x1)*4
For y=y1 To y2
offset=y*#screenW*4+x1*4
CopyMemory(*background+offset,*foreground+offset,width)
Next
EndIf
EndProcedure
Procedure addPage()
pageCount=ArraySize(*page())+1
ReDim *page(pageCount)
*page(pageCount)=AllocateMemory(#screenW*#screenH*4)
EndProcedure
Procedure deletePage(pageNumber)
FreeMemory(*page(pageNumber))
For i=pageNumber To pageCount: *page(i)=*page(i+1): Next
pageCount-1
EndProcedure
Procedure copyPageFore(pageNumber)
If pageNumber>0 And pageNumber<=pageCount
CopyMemory(*page(pageNumber),*foreground,#screenW*#screenH*4)
EndIf
EndProcedure
Procedure copyPageBack(pageNumber)
If pageNumber>0 And pageNumber<=pageCount
CopyMemory(*page(pageNumber),*background,#screenW*#screenH*4)
EndIf
EndProcedure
Procedure.c virtualScreen(x,y,channel,intensity=-1)
Select drawPage
Case #Foreground: *pageAddress=*foreground
Case #Background: *pageAddress=*background
Default: *pageAddress=*page(drawPage)
EndSelect
If intensity=-1
intensity=PeekC(*pageAddress+y*#screenW*4+x*4+channel)
ProcedureReturn intensity
Else
PokeC(*pageAddress+y*#screenW*4+x*4+channel,intensity)
ProcedureReturn 1
EndIf
EndProcedure
Procedure mLine(x1,y1,x2,y2,r=255,g=255,b=255,a=255,antialias=0)
If antialias: gradient.f: y.f: C1.f: C2.f: xend.f: yend.f: xgap.f: deltax.f: deltay.f: EndIf ;initialize floats
If Abs(y2-y1) > Abs(x2-x1): steep=1: EndIf ;detect slopes>.5
If steep: Swap x1, y1: Swap x2, y2: EndIf
If x1>x2: Swap x1, x2: Swap y1, y2: EndIf
;ix1=x1:ix2=x2
deltax=x2-x1
deltay=Abs(y2-y1)
error=deltax/2
y=y1
If antialias And deltax<>0
gradient=deltay/deltax+0.0010001 ;get slope
;generate antialiased endpoints
xend=Int(x1+0.5)
yend=y1+gradient*(xend-x1)
xgap=1-frac(x1)
ix1=Int(xend)
iy1=Int(yend)
C2=frac(yend+0.5)*xgap
C1=1-C2
;If steep: pixel(iy1,ix1,r,g,b,a*C1): pixel(iy1+1,ix1,r,g,b,a*C2)
;Else: pixel(ix1,iy1,r,g,b,a*C1): pixel(ix1,iy1+1,r,g,b,a*C2): EndIf
;y=yend+gradient
xend=Int(x2+0.5)
yend=y2+gradient*(xend-x2)
xgap=1-frac(x2)
ix2=Int(xend)
iy2=Int(yend)
C2=frac(yend+0.5)*xgap
C1=1-C2
;If steep: pixel(iy2,ix2,r,g,b,a*C1): pixel(iy2+1,ix2,r,g,b,a*C2)
;Else: pixel(ix2,iy2,r,g,b,a*C1): pixel(ix2,iy2+1,r,g,b,a*C2): EndIf
EndIf
If y1<y2: ystep = 1: Else: ystep = -1: gradient*-1: EndIf
For x=x1 To x2
If Not antialias ;bresenham's algorithm
If steep: pixel(y,x,r,g,b,a): Else: pixel(x,y,r,g,b,a): EndIf
error-deltay
If error<0: y+ystep: error+deltax: EndIf
Else ;wu's algorithm
C2=frac(y+0.5)
C1=1-C2
If steep: pixel(y+0,x,r,g,b,a*C1): Else: pixel(x,y+0,r,g,b,a*C1): EndIf
If steep: pixel(y+1,x,r,g,b,a*C2): Else: pixel(x,y+1,r,g,b,a*C2): EndIf
y+gradient
EndIf
Next
EndProcedure
Procedure mCircle(x,y,rad,r=255,g=255,b=255,a=255,antialias=0)
If rad>0
ys.f
If antialias: C1.f: C2.f: Else: C1=1: EndIf
For xs = -rad*0.7071 To -1
ys=Sqr(rad*rad-xs*xs)
If antialias: C2=frac(ys+0.5): C1=1-C2: EndIf
pixel(x+xs,y+ys,r,g,b,a*C1)
pixel(x-xs,y+ys,r,g,b,a*C1)
pixel(x+xs,y-ys,r,g,b,a*C1)
pixel(x-xs,y-ys,r,g,b,a*C1)
pixel(x+ys,y+xs,r,g,b,a*C1)
pixel(x-ys,y+xs,r,g,b,a*C1)
pixel(x+ys,y-xs,r,g,b,a*C1)
pixel(x-ys,y-xs,r,g,b,a*C1)
If antialias
pixel(x+xs,y+ys+1,r,g,b,a*C2)
pixel(x-xs,y+ys+1,r,g,b,a*C2)
pixel(x+xs,y-ys-1,r,g,b,a*C2)
pixel(x-xs,y-ys-1,r,g,b,a*C2)
pixel(x+ys+1,y+xs,r,g,b,a*C2)
pixel(x-ys-1,y+xs,r,g,b,a*C2)
pixel(x+ys+1,y-xs,r,g,b,a*C2)
pixel(x-ys-1,y-xs,r,g,b,a*C2)
EndIf
Next
If antialias: C2=frac(rad+0.5): C1=1-C2: Else: C1=1: EndIf
pixel(x,y+rad,r,g,b,a*C1)
pixel(x,y-rad,r,g,b,a*C1)
pixel(x+rad,y,r,g,b,a*C1)
pixel(x-rad,y,r,g,b,a*C1)
If antialias
pixel(x,y+rad+1,r,g,b,a*C2)
pixel(x,y-rad-1,r,g,b,a*C2)
pixel(x+rad+1,y,r,g,b,a*C2)
pixel(x-rad-1,y,r,g,b,a*C2)
EndIf
;circumference=rad*2*#PI
;;generic calculation:
;t.f
;For i = 1 To circumference
; t+2*#PI/circumference
; pixel(x+rad*Cos(t), y+rad*Sin(t), r,g,b,a)
;Next
EndIf
EndProcedure
Procedure pixel(x,y,r=255,g=255,b=255,a=255)
If r<0 : r=0 : EndIf
If g<0 : g=0 : EndIf
If b<0 : b=0 : EndIf
If a<0 : a=0 : EndIf
If r>255 : r=255 : EndIf
If g>255 : g=255 : EndIf
If b>255 : b=255 : EndIf
If a>255 : a=255 : EndIf
If x>=0 And x<#screenW And y>=0 And y<#screenH
If a<255
ar=255-a
r=virtualScreen(x,y,#RD)*ar/255+b*a/255
g=virtualScreen(x,y,#GR)*ar/255+g*a/255
b=virtualScreen(x,y,#BL)*ar/255+r*a/255
EndIf
virtualScreen(x,y,#RD,r)
virtualScreen(x,y,#GR,g)
virtualScreen(x,y,#BL,b)
EndIf
EndProcedure
;-Calculation procedures
Procedure.f frac(num.f)
num=num-Int(num)
ProcedureReturn num
EndProcedure
Procedure.f radius(dx,dy)
ProcedureReturn radiusTable(Int(Abs(dx)),Int(Abs(dy)))
EndProcedure
Procedure sign(n)
ProcedureReturn n/Abs(n)
EndProcedure