Code archives/Graphics/Screenshot Functions

This code has been declared by its author to be Public Domain code.

Download source code

Screenshot Functions by Serpent2010
It has taken me a ridiculous amount of time to get this working, but here are working screenshot functions for Blitz3D. There are two different functions because '3D' buffers seem to be structured in memory slightly differently to '2D' buffers. A description on how to use these functions (if you can be bothered to read it) is at the start of the code.

UPDATE:
Can't believe I forgot this... .decls required:
.lib "gdi32.dll"
BitBlt%(hDestDC%,X%,Y%,nWidth%,nHeight%,hSrcDC,XSrc,YSrc,dwRop)
CreateCompatibleDC%(hdc%)
CreateCompatibleBitmap%(hdc%,Width%,Height%)
SelectObject%(obj%,selobj%)
DeleteDC(hdc%)
DeleteObject(hdc%)
GetDIBitsInt%(hDC%,hbmp%,uStartScan%,uScanLines%,lpvBits%,lpbi*,uUsage%) : "GetDIBits"

.lib "Kernel32.dll"
MoveMemoryObjInt(Destination*,Source%,Length%) : "RtlMoveMemory"

.lib "user32.dll"
GetDC%(hWnd%)
ReleaseDC%(hWnd%,hDC%)
;  WORKING SCREENSHOT FUNCTIONS
;  Author:  James (aka Serpent)
;
;  Grabs top left corner of screen.
;
;  Usage: 
;  Screenshot2DBuffer(DestinationBuffer, Width, Height)
;  Screenshot3DBuffer(DestinationBuffer, Width, Height)
;
;  DestinationBuffer - the buffer that will eventually be written to.  Can be any buffer (FrontBuffer, BackBuffer, ImageBuffer, TextureBuffer)!
;  Return Value - False if a parameter is 0, otherwise True.
;
;  Note: There is a difference between the two functions!  You must use the Screenshot2DBuffer function for '2D' buffers (i.e. ImageBuffers
;        and the FrontBuffer and BackBuffer in a 2D Graphics Mode), and you must use the Screenshot3DBuffer function for '3D' buffers
;        (i.e. TextureBuffers and the FrontBuffer and BackBuffer in a 3D Graphics Mode).  There is a slight difference regarding the structure in
;        memory of these buffers.  Although I do not know what it is I have worked around it.  3D buffers require a power of 2 size and 2D buffers
;        a width divisible by 16.  The functions take care of this - you can use any size for your buffer as long as you use the correct function.
;
;  MAKE SURE THAT YOU GIVE THE FUNCTION BUFFERS THAT ARE UNLOCKED, NOT LOCKED.  The functions lock and unlock buffers as necessary.
;  Although my testing has found that locking a buffer twice then unlocking it twice works alright, it may cause unexpected results.  If you lock
;  the buffer then the functions won't get what they expect.
;
;
;
;  Timing - For 2D buffers on my computer:
;
;  < 40 ms for a 1680 by 1050 screenshot (almost good enough for 30 screenshots per second at this resolution)
;  18-19 ms for an 800 by 600 screenshot
;
;
;
;  Note:  It is probably useful to call the GetSystemMetrics() function (user32.dll) to find the screen width and height.
;
;
;
;  e.g. - copy entire screen to BackBuffer:
;
;  Screenshot BackBuffer(), GetSystemMetrics(0), GetSystemMetrics(1)
;
;
;  .decls file (not needed for screenshot function, but useful - GetSystemMetrics):
;  ---------------------------
;  .lib "user32.dll"
;  GetSystemMetrics%(nIndex%)
;  ---------------------------
;
;
;
;  Note:  Keep Width and Height parameters positive, otherwise you might experience vertical or horizontal flipping of the
;         image - unless you want to do this for some reason.



Function Screenshot2DBuffer(DestinationBuffer,BufferWidth,BufferHeight)
	
	If DestinationBuffer = 0 Or BufferWidth = 0 Or BufferHeight = 0 Then Return False
	
	OriginalBufferWidth = BufferWidth
	BufferWidth = BufferWidth / 16
	If BufferWidth * 16 <> OriginalBufferWidth Then BufferWidth = (BufferWidth + 1) * 16 Else BufferWidth = OriginalBufferWidth
	
	hDC = GetDC(0)
	hMemDC= CreateCompatibleDC(hdc)
	hMemBmp= CreateCompatibleBitmap(hdc,BufferWidth,BufferHeight)
	
	bmi = CreateBank(48)
	PokeByte bmi,0,44
	PokeInt bmi,4,BufferWidth
	PokeInt bmi,8,-BufferHeight
	PokeByte bmi,12,1
	PokeByte bmi,14,32
	
	SelectObject hMemDC, hMemBmp
	BitBlt hMemDC, 0, 0, BufferWidth, BufferHeight, hDC, 0, 0, $00CC0020
	
	If BufferWidth = OriginalBufferWidth Then
	
		LockBuffer DestinationBuffer
		LocBnk = CreateBank(76)
		MoveMemoryObjInt(LocBnk,DestinationBuffer,76)
		Loc = PeekInt(LocBnk,72)
		FreeBank LocBnk
		GetDIBitsInt hDC,hMemBmp,0,BufferHeight,Loc,bmi,0
		UnlockBuffer DestinationBuffer
		
	Else
		
		TemporaryImage = CreateImage(BufferWidth,BufferHeight)
		TemporaryBuffer = ImageBuffer(TemporaryImage)
		LocBnk = CreateBank(76)
		LockBuffer TemporaryBuffer
		MoveMemoryObjInt(LocBnk,TemporaryBuffer,76)
		Loc = PeekInt(LocBnk,72)
		FreeBank LocBnk
		GetDIBitsInt hDC,hMemBmp,0,BufferHeight,Loc,bmi,0
		UnlockBuffer TemporaryBuffer
		CopyRect 0,0,OriginalBufferWidth,BufferHeight,0,0,TemporaryBuffer,DestinationBuffer
		
	EndIf
	
	ReleaseDC 0, hDC
	DeleteDC hMemDC
	DeleteObject hMemBmp
	
	FreeBank bmi
	Return True
	
End Function

Function Screenshot3DBuffer(DestinationBuffer,BufferWidth,BufferHeight)
	
	If DestinationBuffer = 0 Or BufferWidth = 0 Or BufferHeight = 0 Then Return False
	
	OriginalBufferWidth = BufferWidth
	Shifts = -1
	Repeat
		BufferWidth = BufferWidth Shr 1
		Shifts = Shifts + 1
	Until BufferWidth = 0
	BufferWidth = 1 Shl Shifts
	
	If BufferWidth < OriginalBufferWidth Then BufferWidth = BufferWidth Shl 1
	
	hDC = GetDC(0)
	hMemDC= CreateCompatibleDC(hdc)
	hMemBmp= CreateCompatibleBitmap(hdc,BufferWidth,BufferHeight)
	
	bmi = CreateBank(48)
	PokeByte bmi,0,44
	PokeInt bmi,4,BufferWidth
	PokeInt bmi,8,-BufferHeight
	PokeByte bmi,12,1
	PokeByte bmi,14,32
	
	SelectObject hMemDC, hMemBmp
	BitBlt hMemDC, 0, 0, BufferWidth, BufferHeight, hDC, 0, 0, $00CC0020
	
	If BufferWidth = OriginalBufferWidth Then
		
		LockBuffer DestinationBuffer
		LocBnk = CreateBank(76)
		MoveMemoryObjInt(LocBnk,DestinationBuffer,76)
		Loc = PeekInt(LocBnk,72)
		FreeBank LocBnk
		GetDIBitsInt hDC,hMemBmp,0,BufferHeight,Loc,bmi,0
		UnlockBuffer DestinationBuffer
		
	Else
		
		TemporaryImage = CreateImage(BufferWidth,BufferHeight)
		TemporaryBuffer = ImageBuffer(TemporaryImage)
		LocBnk = CreateBank(76)
		LockBuffer TemporaryBuffer
		MoveMemoryObjInt(LocBnk,TemporaryBuffer,76)
		Loc = PeekInt(LocBnk,72)
		FreeBank LocBnk
		GetDIBitsInt hDC,hMemBmp,0,BufferHeight,Loc,bmi,0
		UnlockBuffer TemporaryBuffer
		CopyRect 0,0,OriginalBufferWidth,BufferHeight,0,0,TemporaryBuffer,DestinationBuffer
		
	EndIf
	
	ReleaseDC 0, hDC
	DeleteDC hMemDC
	DeleteObject hMemBmp
	
	FreeBank bmi
	Return True
	
End Function

Comments

_PJ_2010
; .decls file (not needed for screenshot function, but useful - GetSystemMetrics):
; ---------------------------
; .lib "user32.dll"
; GetSystemMetrics%(nIndex%)
; ---------------------------


That's all well and good, but what about decls for the other functions?


Serpent2010
Oh sry - forgot about .decls for everything... I'll update it in a sec.


_PJ_2010
:) Thanks. I did find a list of GDI decls around here somewhere, but at the time I didnt know where the functions were from!


Code Archives Forum