Poking Imagebuffers directly, it works! :)
Blitz3D Forums/Blitz3D Programming/Poking Imagebuffers directly, it works! :)
| ||
Hi, In the last 2 days I've been trying to grab an image from a window into a BB buffer. Various ways I tried didn't work, and read/writepixel is dog slow. This evening I was looking for a way to access Imagebuffers better, and I've figured it out! Note that, this is not good programming practice, it's experimental, and future BB builds may break it. The pointer to an imagebuffer is Imagebuffer + 72. By redirecting a Bank to this address, you can simply Poke directly to the image buffer! The functionality is like LockedPixels() in Blitz+ Additionaly you should be able to pass the Bank pointer to an external DLL and write direct to the buffer. There are some quirks, lock/unlockbuffer isn't needed for regular image buffers, but they ARE needed to access the frontbuffer() & backbuffer() [thanks again Andreas!], and I don't yet know if B3D uses 32bit for all images internaly, adjustments would have to be made for that. One other thing, whilst I was looking for 'access', some people who've tested it for me are telling me it's much faster than writepixelfast, so that's a bonus I guess :) Here goes! Graphics 800,600,32,2 SetBuffer BackBuffer() ; How to access an ImageBuffer directly ; ; NOTE!!!! This may not be safe to do, and future builds may break it! ; ; You'll need to add these definitions to kernel32.decls in your ; Userlibs folder. If you already have definitions from other code ; snippets, you'll have to rename these, and change references to ; them in the code. ; ;api_RtlMoveMemory%(Destination%,Source*,Length%) : "RtlMoveMemory" ;api_RtlMoveMemory2%(Destination*,Source%,Length%) : "RtlMoveMemory" ;api_RtlMoveMemory4%(Destination%,Source%,Length%) : "RtlMoveMemory" Const IMAGEBUFFER_OFFSET=72 image=CreateImage(256,256) iBuff=ImageBuffer(image) ; NEEDED! Activates the image buffer ?!?!? LockBuffer iBuff UnlockBuffer iBuff ; This Bank will be redirected & resized to point to the Imagebuffer Bank=CreateBank(4) ; This is a small check for later to show the Bank ; Pointer gets restored properly PokeInt(Bank,0,199) ; Store the old banks pointer so we can clean up properly OldBankInfo=CreateBank(8) StoreBankInfo(Bank,OldBankInfo) PointBankToImagebuffer(Bank,image) .redo t=MilliSecs() For y=0 To 255 For x=0 To 255 ; Bank, x, y, RGBA, ImageHeight PokeImageBuffer(Bank,x,y,GetRGB(x,0,y),256) Next Next time=MilliSecs() - t While Not MouseHit(1) Cls DrawImage image,MouseX(),MouseY() Text 0,0,"LMB to Exit, RMB to redraw square using Poke!" Text 0,12,"'Bank' size is: "+ BankSize(Bank) Text 0,24,"Redraw: "+ time Flip If MouseHit(2) Goto redo Wend ; Important! We must restore the old Bank so we can free it! RestoreBankInfo(Bank,OldBankInfo) ; Prove the old pointer is restored Text 0,24,"Check 'Bank' is restored (199?): "+ PeekInt(Bank,0) Text 0,36,"Bank Size is (4?): "+ BankSize(Bank) Flip WaitKey End FreeBank Bank FreeBank OldBankInfo Function GetRGB(Red,Green,Blue) Return Blue Or (Green Shl 8) Or (Red Shl 16) End Function Function PokeImageBuffer(buffer,x,y,rgba,imageH) PokeInt( buffer, (y*imageH*4) + (4*x), rgba ) End Function Function StoreBankInfo(b,info) Local temp=CreateBank(4) api_RtlMoveMemory2(temp,b+4,4) PokeInt(info,0,PeekInt(temp,0)) ; store old pointer api_RtlMoveMemory2(temp,b+8,4) PokeInt(info,4,PeekInt(temp,0)) ; store old size FreeBank temp End Function ; The clever bit, we change 'Bank' to point to the ImageBuffer! Function PointBankToImagebuffer(b,image) api_RtlMoveMemory4(b+4,ImageBuffer(image)+IMAGEBUFFER_OFFSET,4) size=ImageWidth(image) * ImageHeight(image) * 4 Local temp=CreateBank(4) PokeInt(temp,0,size) api_RtlMoveMemory(b+8,temp,4) FreeBank temp End Function Function RestoreBankInfo(b,info) Local temp=CreateBank(4) PokeInt(temp,0,PeekInt(info,0)) api_RtlMoveMemory(b+4,temp,4) ; restore old pointer PokeInt(temp,0,PeekInt(info,4)) api_RtlMoveMemory(b+8,temp,4) ; restore old size FreeBank temp End Function It's very important that you restore the bank back else you won't be able to free it properly :) If you want to do some speed tests, note that in this demo I'm calling GetRGB often, and multiplying same values in Pokebuffer, those could be tweaked [thanks Andreas for that!] Have fun! Tom |
| ||
Very interesting, Are the decls files somewhere to download? |
| ||
Nice, Tom! JFK: If you have a file in Blitz 3D -> userlibs called kernel32.decls you just add the RtlMoveMemory lines to it: api_RtlMoveMemory%(Destination%,Source*,Length%) : "RtlMoveMemory" api_RtlMoveMemory2%(Destination*,Source%,Length%) : "RtlMoveMemory" api_RtlMoveMemory4%(Destination%,Source%,Length%) : "RtlMoveMemory" If you don't have it, create a plain text file with that name, paste the above lines in, and stick this at the very top of the file: .lib "kernel32" |
| ||
But don't you also need to know lockedformat and lockedpitch? BlitzPlus supports poking directly to buffers, but the lockedformat and lockedpitch commands are there to tell you what format the color is in, (RGB 565, 555, or 888) and how wide each line of the buffer is. Because even though an image is 256x256, it might be stored in a larger buffer which means you have to skip 256 pixels at the end of each line to get back to the start of the next line. I haven't played with this so I don't know if that's the case here, but it seems like it would have to be. You can get away with just using 24bit color so you always know the color format, but you still need to know the pitch, unless maybe you blit only into individual images and not into screen buffers. Maybe. |
| ||
I fixed a typo, I forgot to change the name of the bank on one of the the freebank lines. Andreas pointed out that if you do Graphics3D 800,600,16,1 it will use 16bit for images/textures, so I'm looking for a routine to convert down from 32bit to 16bit. Texture Bit Depth can be checked like so: ; NEEDED! Activates the image buffer ?!?!? LockBuffer iBuff UnlockBuffer iBuff ; After lock/unlock infoB = CreateBank(12) api_RtlMoveMemory2(infoB,ImageBuffer(image)+92,12) ; Width=PeekInt(Bank,0) ; Height=PeekInt(Bank,4) If PeekInt(infoB,8)=16 BPP=2 ; write 2 Bytes for 16bit Else BPP=4 ; 4 bytes (Int) for 32bit End If FreeBank infoB Then adjust code accordingly It's interesting that you can point a Bank to anything... Tom |
| ||
There are _two_ 16 bit formats though. RGB 555 and RGB 565. |
| ||
; Convert from RGB24 to individual color components. R = ((RGB24 Shr 16) And 255) G = ((RGB24 Shr 8) And 255) B = (RGB24 And 255) ; Convert from individual color components to 24 bit RGB. RGB24 = ($ff000000) Or (G Shl 8) Or (R Shl 16) Or B ; Convert from individual color components to 16 bit 565 RGB. RGB565 = ((R shr 3) shl 11) Or ((G shr 2) shl 5) Or (B shr 3)) ; Convert from individual color components to 16 bit 555 RGB. RGB555 = ((R shr 3) shl 10) Or ((G shr 3) shl 5) Or (B shr 3)) |
| ||
This little article is awsome. I only wish the next version of Blitz3D would have new commands that allow handles to be interchanged. It wouldn't be hard to allow handle exchanges between image buffers, Textures, Banks, and sprites. They are all very simular data. Should also be able to transfer any of these over to an array. All this should be possible without having transfer data over from one to the other. Just change an image buffer handle into a texture handle for example. That type of functionality would make Blitz3D a lot more powerful and usefull. |
| ||
Hi, From the information we gathered, Andreas has provided us with some functions that effectively work just as they do in BlitzPlus! http://www.blitzcoder.com/cgi-bin/ubb-cgi/postdisplay.cgi?forum=Forum6&topic=001266 Additionaly, I figured out how to Blit from any window into a buffer, so a good day all round! Snippet [code] ; Assuming 32bit.. ; 'temp' is the Bank pointing to our imagebuffer() ; the color bits are copied to it :) hdcNew=api_CreateCompatibleDC(Bhdc) ; New Device Context to hold the Bitmap hBmp=api_CreateBitmap(512,512,1,32,0) ; The Bitmap we'll Blit to api_SelectObject(hdcNew,hBmp) ; Select the new Bitmap api_BitBlt(hdcNew,0,0,512,512,SOURCE_HDC,DestX,DestY,SRCCOPY) ; Blit to the new bitmap api_GetBitmapBits(hBmp,512*4*512,temp) ; Copy the Bitmap Bits (color!) from Bitmap to temp (our image buffer!) ... free up HDCs e.t.c.......... [/CODE] Cya! Tom |
| ||
So, this is VERY cool. I wonder, also, could something similar work with audio? M |
| ||
VERY COOL! But it´s not working anymore... PokeInt( buffer, (y*imageH*4) + (4*x), rgba ) ... gives me a MAV any ideas would be appreciated!!! ;) thx, chi |
| ||
This thread is six years old, so updates to Blitz3D have probably broken this method. |
| ||
Probably... but worth a try! |
| ||
buffer = TextureBuffer or ImageBuffer LockBuffer buffer BufferPtr = MemoryFastPeekInt(buffer + 72) BufferPitch = MemoryFastPeekInt(buffer + 56) MemoryFastPokeInt(BufferPtr + ( ix + iy * BufferPitch ) * 4, PixColour) ...works, but is not significantly faster than WritePixelFast. The buffer still needs to be locked for the BufferPtr to be a valid pointer, which suggests that the real slowdown nowadays is in uploading the new information to the graphics card. |
| ||
...works, but is not significantly faster than WritePixelFast. doh, I´m looking for something (much) faster than WritePixelFast! At least fast enough to transfer 60 fps without any problems ;) |
| ||
I wish I found this thread before when I was working on a screenshooting function... Either way I managed to get mine to work. It does a complete 1680x1050 screenshot on my PC in around 35ms! It's in the code archives but here it is again: and if you can be bothered to read my descriptions on how to use them: Basically, my functions make use of BitBlt for the screen capturing bit - rather than specifying the handle to a window, I use '0' to get the screen. I think '0' is considered the handle for the 'Desktop' window - the highest in the window hierachy. Either way it works. To adapt this for capturing a window, you could simply replace all of the zeros with a variable that specifies the window handle and it should still work (as far as I know). Also my functions don't quite achieve 30 FPS for a 1680 by 1050 screenshot, they are as fast I need, and I can't see a way of improving them. Note: The reason that there is a '2D' and a '3D' one is that 2D buffers seem to fail if the buffer width isn't a multiple of 16 and 3D buffers fail if the width isn't a power of 2. The functions account for these problems. Edit: Decls file (Note: may be a few unnecessary functions in here - sry) |
| ||
Hey thx! I´ll definitely check it out the next days! (afk) |