Dark Bit Factory & Gravity
PROGRAMMING => General coding questions => Topic started by: emook on January 10, 2014
-
As you can tell by the title, I'm not sure what I am on about.
Well I saw the UDG demos posted for the UDG compo and really enjoyed the creativeness that was employed by some of you very clever people. I've also been playing with tinyptc for Purebasic and have come to the realisation that to do funky stuff you need to ditch those inbuilt easy command and start poking with your frame buffer. The more complex source codes I check out, the more the frame buffer is being abused and manipulated to gain great effects with speed.
So, I would like to create something UDG-y. using 8x8 pixel blocks. I thought about drawing my routines to a backbuffer then peeking the results and then using a workaround of x*8,y*8 then drawing blocks 8x8 to achieve the results. However, this is where I get back to the framebuffer - my testing seems very slow and I can only imagine once I start getting more funky stuff flopping around the screen, my way of doing things is gonna slow down way too much. And i don't want that.
Here is the code I have put together (purebasic) :
InitMouse():InitKeyboard() : InitSprite()
OpenWindow(0,0,0,800,600,"")
OpenWindowedScreen(WindowID(0),0,0,800,600)
; 800 = 100
; 640 = 80
Global spx=CreateSprite(#PB_Any,100,80)
StartDrawing(SpriteOutput((spx)))
For Radius = 25 To 0 Step -1
Circle(25, 25, Radius, RGB(Random(255), Random(255), Random(255)))
Next
StopDrawing()
Global Dim pos(100,80)
ExamineMouse()
Procedure MakeScreen()
Static.f angle,sS,Cs,zoom=5
sS=Sin(angle.f*0.5)*10
cS=(Cos(angle.f*0.5))
angle.f+0.51
ClearScreen(0)
StartDrawing(SpriteOutput(spx))
Box(0,0,100,80,#Black)
For Radius = 25 To 0 Step -1
Circle(25, 25, Radius-zoom, RGB(Random(255), Random(255), Random(255)))
Next
zoom-1
If zoom<0
zoom=25
EndIf
StopDrawing()
DisplayTransparentSprite(spx,50+ss,cS,255)
StartDrawing(ScreenOutput())
zoom+1
For x=1 To 100
For y=1 To 80
col=Point(x,y)
If col>0
pos(x,y)=(col)
Else
pos(x,y)=0
EndIf
Next
Next
StopDrawing()
ClearScreen(0)
EndProcedure
Procedure ToUDG()
StartDrawing(ScreenOutput())
For x=1 To 100
For y=1 To 80
;StartDrawing(SpriteOutput(0))
col=pos(x,y)
;StopDrawing()
If col>0
; FlipBuffers()
Box(x*8,y*8,8,8,col)
; FlipBuffers()
EndIf
Next
Next
StopDrawing()
EndProcedure
Repeat
ClearScreen(0)
MakeScreen()
ToUDG()
FlipBuffers()
ExamineKeyboard()
WindowEvent()
Until KeyboardPushed(#PB_Key_Escape)
Now as you can see, I am trying to carry out brain surgery using a plunger and a hacksaw - I need to be guided how I can do this sort of stuff with the framebuffer, possibly tinyptc because it seems so quick!
I've attached an exe for you to see if your not a Pb-er..
Thanks in advance!
:)
-
hi mate i can see what you are doing here but using pb like that will always be really slow.. there is a ton of extra steps too be done that don't have too if you just grab an area of ram and flush it too the gpu each frame.
ive coded a little freebasic app too show you how with low level pure pixel pushing you can get this done.
its now just a two step process
step 1:
i render the animated udg into its own array.
step 2:
blit the udg too the framebuffer much the same way as a bmp.
doing it this way is pretty much as fast as you can get. and indeed much much faster. now i don't know if pb has a means of working on raw buffers the same way as freebasic but if it does this freebasic example should run roughly the same in pb.
ive added a few little comment's too the source too hopefully help you out but if there is any technical bits you don't understand just fire some questions my way.
-
i forgot too add the little 8x8 resize in my example but even with this coded in it would still be really really fast.
-edit i have put the re-size in this version it now is the same size as your ver.. i also added a fps counter in the console window when run in windowed mode. with vertical sync on it runs 100% 60fps with vsync off its too fast too see runs at about 200 fps here.
-
Wow, thanks man!
This'll be really helpful, so it looks like I am correct that if I want to make more impressive quick effects, I need to learn how to blit to the frame buffer. I've never done stuff like that before - but I am doing a lot of things recently that I have never achieved before so this is good!
The example is really healpful, very grateful for that. I have been converting some tintptc FB sources to tinyptc PB, so I should be able to convert this and hopefully I will feel that *plonk* click in my head when you suddenly grasp a concept.
Gonna have a play and see what I do.
Again, tip top! thanks!
;D
-
yeah framebuffer's are like that they look cryptic at first but all of a sudden things click and you just start thrashing stuff around (anything is possible when pushing individual pixels.. the mind is the limit)
i will try too explain how a 1d array works because that's probably the toughest part too grasp.
basically with framebuffers you will work with arrays like this.
Dim Shared As Integer BackBuffer(Width*height)
rather than
Dim Shared As Integer BackBuffer(Width,Height)
now when i comes time too put an rgb point at say... 100x by 200y how would we do that with a 1d array. thats where this little formula comes in.
xpos+ypos*ScreenWidth
that formula will always point too the correct element in the array so
BackBuffer(100+200*screenWidth) = rgb(255,0,0)
would store a red dot in the back buffer array at 100,200. :)
then with ptc its just
Ptc_Update( BackBuffer )
what that does is map each element of the backbuffer directly too screen pixels so it would light a red dot up at 100,200
now im sorry if you already knew this. its just that for some folks this is the part that when they get over it things just click!
while your having a mess around if there is anything your not sure of just ask away mate.
-
That's really helpful, no I didn't know this, thanks!
Really going to hammer this out this weekend :)
:updance:
-
how is your framebuffer adventures coming along emook?
-
Unfortunately due to certain things, likes kids and missus!, I did not get the chance I wanted. Going to see if I can give it a whirl today :)
-
excellent! well i still have pb installed here so if there is anything i can help with just give me a shout :cheers:
-
Hello again!
Ok, I didnt have a lot of time last weekend and have come back to this. (spent a while playing with the old basic routine to try and come up with some ideas!)
So last night I began converting, I managed to get the circle to display but it looks like I am only reading 1bitplane, or 2bytes from memory rather than the expected 4 giving strange results.
I had to stop after many hours of tweaking, could you have a look for me?
:carrot:
In the archive is your example, my PB version & compiled exe (I am not bothered about movement at the moment) with the tinyptc library this needs to go into your PB folder PureLibraries\UserLibraries.
Once I figure this out I want to be able to load an image into memory and do the same thing....
Thanks in advance!
https://dl.dropboxusercontent.com/u/2940985/framebuffer_ptc.rar (https://dl.dropboxusercontent.com/u/2940985/framebuffer_ptc.rar)
-
hi mate yes i will have a proper look a little later for you. just had a quick skim over and one thing jumps out...
Global *udgptr=AllocateMemory(WidthX*HeightY)
Global *Buffer=AllocateMemory(WidthX*HeightY)
now i am not sure how pb works but with ever other language i have worked in, when allocating memory you have too multiply the number of elements by the number of bytes required for each element.
so those two would be.
Global *udgptr=AllocateMemory((WidthX*HeightY)*4)
Global *Buffer=AllocateMemory((WidthX*HeightY)*4)
as its 32 bits(r/g/b/a) or 4 bytes per pixel.
thats just a stab atm though ill have a proper look in a bit
-
Ahh yes! I should have remembered the *4 - I've added that in but still having the same issue - i think its someting to do with converting the colour into the correct rgba component.
Look forward to your reply! :)
-
i am on the trial version of pb emook so it wont let me use the tiny ptc lib :(
however i think i have found your error have a look in here..
Procedure RenderCircle(*Buffer,Xpos,Ypos,Radi.f,WdthX,HghtY,Colour)
Radi2.f
; Z
; Dim W As Double
; Dim X As Integer
If Radi>0
Radi2 = ( Radi * Radi )
For Z=-Radi To Radi
W = Sqr( Radi2 - Z * Z )
If ( Z + Ypos ) < HghtY - 1 And ( Z + Ypos ) > 1
For X = Xpos - W To Xpos + W
If X < WdthX - 1 And X > 1
; Buffer[ ( Z + Ypos ) * WdthX + X ] = Colour
pos=(Z+Ypos)*WdthX+X
PokeB(*Buffer+pos,Colour)
; Debug Colour
EndIf
Next
EndIf
Next
EndIf
EndProcedure
Procedure RenderIntoUdgBuffer()
Protected.I sS,Cs
Protected.I x,Y,Radius
sS=(Sin(Angle*0.5)*10.0)
cS=(Cos(Angle*0.5))
Angle+0.51
For Radius = 25 To 0 Step -1
; RenderCircle(@UdgBuffer(0), 35, 35, Radius-zoom,UdgWidth,UdgHeight, RGB(Random(255,1), Random(255,1), Random(255,1)))
RenderCircle(@UdgBuffer(0), 35, 35, Radius-zoom,UdgWidth,UdgHeight, RGB(Random(255,1), Random(255,1), Random(255,1)))
; RenderCircle(@UdgBuffer(0), 35, 35, Radius-zoom,UdgWidth,UdgHeight,RGB(255,255,255))
Next
zoom-1
If zoom<0
zoom=25
EndIf
EndProcedure
first this.
Procedure RenderCircle(*Buffer,Xpos,Ypos,Radi.f,WdthX,HghtY,Colour)
should be
Procedure RenderCircle(*Buffer,Xpos,Ypos,Radi.f,WdthX,HghtY,ColourR,ColourG,ColourB)
and then here.
PokeB(*Buffer+pos,Colour)
should be.
PokeInt(*Buffer+pos,(ColourR shl 16) Or (ColourG shl 8) Or (ColourB) )
now i dont know how pb does arithmatic shift lefts so just change the shl too the proper symbol/word your language expects. and then i am pretty sure it will work! :cheers:
-
Oh my god! this is driving me mad! :) Thanks for the help again -
I have made the changes, but get the same results. When I am poking integers the circle ends up torn like so :
(http://i.imgur.com/ODD8RHE.png)
When I poke bytes I get :
(http://i.imgur.com/B9ID1t3.png)
as you can see there is a shadow of around four pixels underneath.
I also tried to change to this part in the rendercircle proc :
IPokeB(*Buffer+pos,RGB(ColourR,Colourg,Colourr))
to this :
BackBuffer(pos)=(ColourR << 16) | (Colourg << 8) | (Colourb)
The colour appears correct, for example I have set r to 255 but then I get this :
(http://i.imgur.com/EsuFmBP.png)
Colour is correct but the place of the image isn't! My poor brain!
:crutches: :crutches: :crutches:
-
i like this line much better.
BackBuffer(pos)=(ColourR << 16) | (Colourg << 8) | (Colourb)
and the fact you are getting your specified color means you probably have fixed that part of your code.
i think you are having trouble from here too.
BackBuffer( (Xpos+X+Rx)+(Y+Ypos+Ry)*WidthX ) = PeekB(*UdgPtr+X+Y*WdthX)
its most definitely int's you want too write too the back buffer i would just change it too something like..
BackBuffer( (Xpos+X+Rx)+(Y+Ypos+Ry)*WidthX ) = UdgPtr[X+Y*WdthX]
have you added the *4 too you allocs as well because now you are writting and reading int's is when that would show up.
-
Yes I have added the *4 for the memory allocation. I'm totally stumped with this now.
There must be something quite fundamental regarding Purebasic that I am not doing here.
I don't understand why I use Ints everything seems to go wrong.
What I am planning to do this evening is painstakingly sit and add a load of break points and compare the memory address contents. Maybe that will shed some light on what I am not doing correctly.
I went to sleep at 4 am last night after trying to figure out how to fix this, and then lay in bed coming up with all sorts of potential fixes. Looks like tonight will be the same.
No doubt I will kick myself when someone finally shows me the way! :)
:inspired:
-
after a quick mess around here is it working.
; Structure Type
; Type.TimerType
;
; Frequency As LARGE_INTEGER
; LiStart As LARGE_INTEGER
; LiStop As LARGE_INTEGER
; LlTimeDiff As LONGLONG
; MDuration As Double
;
; End Type
Declare RenderLine(StartX,StartY,EndX,EndY,Col)
Declare RenderIntoUdgBuffer()
Declare RenderUdg(Xpos,Ypos,WdthX,HghtY)
Declare OpenPtcWindow()
Declare RenderCircle(Xpos,Ypos,Radi.f,WdthX,HghtY,ColourR,ColourG,ColourB)
Global Dim Buffer.l(800*640)
ptc_setdialog(1,"",1,0)
ptc_allowclose(1)
ptc_open("TinyPTCExt",800,640)
Global WidthX = 800
Global HeightY = 640
Global Dim BackBuffer.l(WidthX*HeightY)
For i=0 To WidthX*HeightY
BackBuffer(i)=$402020
Next
Global UdgWidth = 100
Global UdgHeight = 80
Global Dim UdgBuffer.l(UdgWidth*UdgHeight)
Global Angle, Zoom = 5
Global Dim udgptr.l(WidthX*HeightY)
Global Dim Buffer.l(WidthX*HeightY)
;OpenPtcWindow()
Xpos=1
XAngle.f = 0.1
; Global StepY
; Global YPos
;While ( GetAsyncKeyState( VK_ESCAPE ) <> -32767 )
Repeat
;Dim Y,X
;this draws into an object udg buffer of size x=100 y=80
RenderIntoUdgBuffer()
; Xpos+(Sin(XAngle*0.8)*13.0)
; XAngle + 0.1
;this does a blit of our just generated udg into the back buffer at 300,200
RenderUdg(Xpos, 0, UdgWidth, UdgHeight )
;this flips the back buffer
; ptc_update( ;@BackBuffer(0) )
ptc_update( @BackBuffer(0) )
;this clears the back buffer
For x = 0 To (WidthX-1)*(HeightY-1)
BackBuffer(X) = RGB( 60, 0, 0 )
Next
ForEver
Procedure RenderUdg(Xpos,Ypos,WdthX,HghtY)
; ; GetObject_(ImageID(img), SizeOf(BITMAP), @bmp.BITMAP)
; ; Protected imagesize = bmp\bmWidthBytes * bmp\bmHeight
; ; Protected *bits = bmp\bmBits
; blit and upscale udg into back buffer
StepY=Ypos
For Y = 0 To HghtY-1
For Ry = StepY To StepY+4
For X = 0 To WdthX-1
For Rx = StepX To StepX+4
If UdgPtr(X+Y*WdthX)<>$0
; If PeekI(*bits+X+Y*WdthX)<>$0
;Debug "hit"
;BackBuffer( (Xpos+X+Rx)+(Y+Ypos+Ry)*WidthX ) = PeekB(*bits+X+Y*WdthX)
BackBuffer( (Xpos+X+Rx)+(Y+Ypos+Ry)*WidthX ) = UdgPtr(X+Y*WdthX)
EndIf
Next
StepX+4
Next
StepX=0
Next
StepY+4
Next
EndProcedure
Procedure OpenPtcWindow()
ptc_allowclose(0)
ptc_setdialog(1,"udg test"+"FullScreen",1,0)
ptc_setflip(0)
ptc_open("udg", WidthX, HeightY)
; End - 1
;EndIf
EndProcedure
Procedure RenderCircle(Xpos,Ypos,Radi.f,WdthX,HghtY,ColourR,ColourG,ColourB)
Radi2.f
; Z
; Dim W As Double
; Dim X As Integer
If Radi>0
Radi2 = ( Radi * Radi )
For Z=-Radi To Radi
W = Sqr( Radi2 - Z * Z )
If ( Z + Ypos ) < HghtY - 1 And ( Z + Ypos ) > 1
For X = Xpos - W To Xpos + W
If X < WdthX - 1 And X > 1
; Buffer[ ( Z + Ypos ) * WdthX + X ] = Colour
pos=(Z+Ypos)*WdthX+X
Udgptr(pos) = (ColourR << 16) | (ColourG << 8) | (ColourB)
; Debug Colour
EndIf
Next
EndIf
Next
EndIf
EndProcedure
Procedure RenderIntoUdgBuffer()
Protected.I sS,Cs
Protected.I x,Y,Radius
sS=(Sin(Angle*0.5)*10.0)
cS=(Cos(Angle*0.5))
Angle+0.51
For Radius = 25 To 0 Step -1
; RenderCircle(@UdgBuffer(0), 35, 35, Radius-zoom,UdgWidth,UdgHeight, RGB(Random(255,1), Random(255,1), Random(255,1)))
RenderCircle( 35, 35, Radius-zoom,UdgWidth,UdgHeight, Random(255,1), Random(255,1), Random(255,1))
; RenderCircle(@UdgBuffer(0), 35, 35, Radius-zoom,UdgWidth,UdgHeight,RGB(255,255,255))
Next
zoom-1
If zoom<0
zoom=25
EndIf
EndProcedure
now i have stripped it back too a basic level as you can see so if you very carefully take it from here it will work the way you had it.
one thing too note is that your pointers were getting messed up while being passed through the functions.
if you have an allocated pointer such as udgptr you dont pass this through as @someptr(0) you just pass it through as someptr, in your function decleration you will probably want too let it know that a ptr is going too be coming so something like
function thisfunction( someptr as ptr,width,height,x,y)
the too call this you would just do thisfunction( someptr,200,100,0,0);
-
Is there an icon the has a bott kicking my own ass?!
Thank you very much, I was going way too complex for what was needed it seems. Hmm!
:sunny: :sunny: :sunny: :sunny:
I think I may have done something like that early on but abandoned when I had issues with the correct colour (the (ColourR << 16) | (ColourG << 8) | (ColourB) bit). Anyway well done and thanks again.
My next task would be to read an image and then put that into the buffer to be displayed!...
:)
-
:) i think your doing great stuff emook keep at it!!
i have a basic little bmp ptc image loader in freebasic i can post tomorrow if you like..
-
Thanks!
However I have managed to sort out displaying a image from memory. Turns out it was quite easy :)