Dark Bit Factory & Gravity

PROGRAMMING => C / C++ /C# => Topic started by: Jim on October 29, 2007

Title: How to grab the desktop as a texture
Post by: Jim on October 29, 2007
Tested under Vista and XP.


#include <windows.h>

#define SCREEN_WIDTH 800
#define SCREEN_HEIGHT 600

unsigned int texture[1024*1024];
GLuint hand;

HDC hdc = GetDC(NULL);
HDC mydc = CreateCompatibleDC(hdc);
int w = GetSystemMetrics(SM_CXSCREEN);
int h = GetSystemMetrics(SM_CYSCREEN);
HBITMAP mybmp = CreateCompatibleBitmap(hdc,w,h);

SelectObject(mydc, mybmp);

StretchBlt(mydc, 0,0,1024,1024, hdc,0,0,w,h, SRCCOPY);

ReleaseDC(NULL, hdc);

static struct
{
BITMAPINFOHEADER bmiHeader;
RGBQUAD bmiColours[3];
} screen_bmi=
{
{
sizeof(BITMAPINFOHEADER),
1024,
1024,
1,
32,
BI_RGB,
0,
75,
75,
0,
0,
},
0x00,0x00,0xff,0x00,
0x00,0xff,0x00,0x00,
0xff,0x00,0x00,0x00,
};

int err = GetDIBits(mydc, mybmp, 0, 1024, texture, (BITMAPINFO *)&screen_bmi, DIB_RGB_COLORS);

glGenTextures(1, &hand);
glBindTexture(GL_TEXTURE_2D, hand);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);

//might want to do this as Windows doesn't set the alpha channel
for (int z= 0; z < 1024*1024;z++) texture[z] |= 0xff000000;
glTexImage2D(GL_TEXTURE_2D, 0, 4, 1024,1024, 0, GL_BGRA_EXT, GL_UNSIGNED_BYTE, texture);

//try it out
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, hand);

glColor4f(1,1,1,1);
glBegin(GL_QUADS);
glTexCoord2f(0.0f,1.0f);
glVertex2i(0,0);
glTexCoord2f(0.0f,0.0f);
glVertex2i(0,SCREEN_HEIGHT);
glTexCoord2f(1.0f,0.0f);
glVertex2i(SCREEN_WIDTH,SCREEN_HEIGHT);
glTexCoord2f(1.0f,1.0f);
glVertex2i(SCREEN_WIDTH,0);
glEnd();


Jim
Title: Re: How to grab the desktop as a texture
Post by: taj on October 29, 2007
karma++ Jim. I'll add this to my halloween entry once the voting is done so everyone can run it.
Chris
Title: Re: How to grab the desktop as a texture
Post by: benny! on October 29, 2007
Yeah. Nice piece of code! K++, Jim !!!
Title: Re: How to grab the desktop as a texture
Post by: Paul on October 29, 2007
Tried to make a blitzbasic version, but ended up with this...
only works in non debugmode
as you see in the screenshot, it doesn't work too well :(

Global width =api_GetSystemMetrics(0)
Global height=api_GetSystemMetrics(1)

Graphics width,height,32,1


Local hdc=api_getdc(0)
Local blitzhdc=api_getdc(SystemProperty("apphwnd"))

Local mydc = api_CreateCompatibleDC(hdc)


hidewindow
api_BitBlt(blitzhdc, 0, 0, width,height, hdc, 0,0, $CC0020)
showwindow


Local image=CreateImage(width,height)
CopyRect(0,0,width,height,0,0,FrontBuffer(),ImageBuffer(image))


SetBuffer BackBuffer()
While Not KeyHit(1)
DrawImage(image,0,0)

Text 0,0,"Done"
Flip
Cls
Wend

Function showwindow(hwnd=0)
If hwnd=0 Then hwnd=SystemProperty("apphwnd")
api_ShowWindow(hwnd,5)
End Function
Function hidewindow(hwnd=0)
If hwnd=0 Then hwnd=SystemProperty("apphwnd")
api_ShowWindow(hwnd,0)
End Function


Title: Re: How to grab the desktop as a texture
Post by: Rbz on October 29, 2007
@Paul: try to initialize your graphics screen "Graphics width,height,32,1" after "CopyRect(0,0,width,height,0,0,FrontBuffer(),ImageBuffer(image))" command.
Title: Re: How to grab the desktop as a texture
Post by: Paul on October 30, 2007
It seems as if the code hasto be run in fullscreen for it to work at all, so thats not an option :(
any other ideas?
Title: Re: How to grab the desktop as a texture
Post by: Jim on October 30, 2007
I'm not much of a bb programmer, but it looks like you missed out a bit - where do you create and copy to the compatible bitmap?

Jim
Title: Re: How to grab the desktop as a texture
Post by: Paul on October 30, 2007
sry, here somes the code again but with coments:


Global width =api_GetSystemMetrics(0)
Global height=api_GetSystemMetrics(1)

Graphics width,height,32,1


Local blitzhdc=api_GetDC(SystemProperty("apphwnd")) ;get the blitzwindows device context

Local deskhdc=api_GetDC(api_GetDesktopWindow()) ;same for desktop

hidewindow
api_BitBlt(blitzhdc, 0, 0, width,height, deskhdc, 0,0, $CC0020);copy the desktop device context to the blitz frontbuffer(i think and it seems to work)
showwindow


Local image=CreateImage(width,height) ;create an empty iamge

CopyRect(0,0,width,height,0,0,FrontBuffer(),ImageBuffer(image)) ;copy the frontbuffer to our image. only problem is that it far too often doesn't get the whole screen


SetBuffer BackBuffer()
While Not KeyHit(1)
DrawImage(image,0,0)

Text 0,0,"Done"
Flip
Cls
Wend

Function showwindow(hwnd=0)
If hwnd=0 Then hwnd=SystemProperty("apphwnd")
api_ShowWindow(hwnd,5)
End Function
Function hidewindow(hwnd=0)
If hwnd=0 Then hwnd=SystemProperty("apphwnd")
api_ShowWindow(hwnd,0)
End Function


I don't realy understand the compatible bitmap but i think that's the way to go.
Title: Re: How to grab the desktop as a texture
Post by: zawran on October 30, 2007
Not really wanting to go off topic, since the topic is in the C/C++ section, but I did a search on the blitzresearch forum, and found this one in the code archieves. It should work for both images and textures. But I have not tested it though since I only have blitzmax installed at the moment.

Example usage:

tex = GetDesktop() ; creates a texture
image = GetDesktop(1) ; creates an image
GetDesktop(0,tex) ; updates a texture
GetDesktop(1,image) ; updates an image


Const SRCCOPY = $CC0020
Const CF_BITMAP = 2
Const SW_HIDE = 0
Const SW_SHOW = 5

Function GetDesktop(flag=0,update=0)

; ADAmor ZILTCH 2003
;
; This command must come after your GRAPHICS(3D) x,y command.
;
;  flag 0 = create texture
;       1 = create image
;
; if update is not 0 then it is the tex/image to update.

   DeskHwnd = GetDesktopWindow()

   ; Get screen coordinates
   fwidth  = GetSystemMetrics%(0)  ;RectWin\rightR  - RectWin\leftR
   fheight = GetSystemMetrics%(1)  ;RectWin\bottomR - RectWin\topR

   BlitzHwnd = GetActiveWindow()
   ShowWindow(BlitzHwnd,SW_HIDE)

   ; Get the device context of Desktop and allocate memory
   hdc = GetDC(DeskHwnd)
   Blitzhdc = GetDC(BlitzHwnd)

   ; Copy data
   BitBlt(Blitzhdc, 0, 0, fwidth, fheight, hdc, 0,0, SRCCOPY)

   ; Clean up handles
   ReleaseDC(DeskHwnd, hdc)
   ReleaseDC(BlitzHwnd, Blitzhdc)
   ShowWindow(BlitzHwnd,SW_SHOW)

   ; Create/update texture or image
   Select flag
     Case 0
       If update = 0 Then
         tex=CreateTexture(fwidth,fheight)
       Else
         tex=update
       End If
       CopyRect 0,0,fwidth,fheight,0,0,FrontBuffer(),TextureBuffer(tex)
       Return tex
     Case 1
       If update = 0 Then
         image=CreateImage(fwidth,fheight)
       Else
         image=update
       End If
       CopyRect 0,0,fwidth,fheight,0,0,FrontBuffer(),ImageBuffer(image)
       Return image
   End Select

End Function
;---------------- end code


It needs some user.decls definitions:


Lines needed in Userlib: User32.decls

FindWindow%( class$,Text$ ):"FindWindowA"
ShowWindow(hwnd%,nCmdShow%)
GetActiveWindow%()
GetDC%(hWnd% )
ReleaseDC%(hWnd%,hDC%)
GetDesktopWindow%()
GetSystemMetrics%(nIndext%)

Lines needed in Userlib: Gdi32.decls
BitBlt%(hDestDC%,X%,Y%,nWidth%,nHeight%,hSrcDC,XSrc,YSrc,dwRop)


I hope its of use, and sorry for the somewhat off topic.
Title: Re: How to grab the desktop as a texture
Post by: Jim on October 30, 2007
I *think* the problem is when you do the BitBlt there is no bitmap selected in to the blitzhdc so it doesn't work.
You need to do

bmp=CreateCompatibleBitmap(deskhdc, width, height)
SelectObject(blitzhdc, bmp);

before the bitblt.
But then there's no real reason why CopyRect will work, since it's not obvious what the source for the copy is. :-\

Jim
Title: Re: How to grab the desktop as a texture
Post by: Paul on October 30, 2007
@ zawran, that code has the exact same problem as mine. It looks lite the desktop was updating hen i ran the code so i got some black areas.
@jim, the problem is probably there, but ihave tried waht you say(i think) and it doesn't work, same prolem. could you compile an exe of youre c++ program so i can check if that works on my pc? thx, and sry for the offtopic.
Title: Re: How to grab the desktop as a texture
Post by: Paul on November 03, 2007
OK... found a solution. use the api_keybd_event(44,0,0,0) function to "press" the print screen button. then paste the image to an imagebuffer using the PasteImageFromClipboard() function from here:   http://www.blitzbasic.com/codearcs/codearcs.php?code=1767
Title: Re: How to grab the desktop as a texture
Post by: madsravn on November 23, 2007
Cool effect :) I've gotta try it out . Thanks man ;)
Title: Re: How to grab the desktop as a texture
Post by: Jim on November 23, 2007
No probs - great to see you here!

Jim
Title: Re: How to grab the desktop as a texture
Post by: Jim on December 13, 2007
Just spotted a slight error.
correction:

int err = GetDIBits(mydc, mybmp, 0, h, texture, (BITMAPINFO *)&screen_bmi, DIB_RGB_COLORS);

should be

int err = GetDIBits(mydc, mybmp, 0, 1024, texture, (BITMAPINFO *)&screen_bmi, DIB_RGB_COLORS);

Corrected in original post.

Jim