April 19, 2024, 12:08:51 PM

News:

Own IWBasic 2.x ? -----> Get your free upgrade to 3.x now.........


Capture Screen to File

Started by RG, October 14, 2009, 05:22:58 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

RG

October 14, 2009, 05:22:58 PM Last Edit: October 15, 2009, 09:10:40 AM by RG
I want to capture the direct3d window to a file for later printing. There's no function in ebasic to do so (that I can see) but I've found references on the web to a function "3dxsavesurfacetofile". I've found it in the d3dx9_29.lib in my systems folder. Anyone ever try to use this? I'm just starting to try and figure it out.

Rich

ZeroDog

You can use the SaveBitmap routine found in the SaveBitap.inc file to save bitmap images from a screen/window
SaveBitmap(filename:string,win:window,l:int,t:int,w:int,h:int)

$include "savebitmap.inc"
SaveBitmap(getstartpath+"image.bmp",screen.m_win,0,0,800,600


screen is the C3DScreen object, screen.m_win is the handle to the window when created using screen.CreateWindowed or screen.CreateFullScreen

RG

Thanks ZeroDog but doesn't seem to work for me. I tried it before and then again today and all I capture is a blank white screen (or if I size it larger, parts of other screens). Have you gotten it to work?

Rich

ZeroDog

make sure you have rendered the scene before you use SaveBitmap.

Here is a slightly modified 3D sample that comes with EBasic, that will save the 3D screen to a bitmap.  Hit F1 to take a screenshot. 

$include "savebitmap.inc"
'//Example of creating a custom primative mesh.
'//Handles ALT-TAB switching by using a restore callback
CONST DIK_UP = 0xC8 /* UpArrow on arrow keypad */
CONST DIK_PRIOR = 0xC9 /* PgUp on arrow keypad */
CONST DIK_LEFT = 0xCB /* LeftArrow on arrow keypad */
CONST DIK_RIGHT = 0xCD /* RightArrow on arrow keypad */
CONST DIK_END = 0xCF /* End on arrow keypad */
CONST DIK_DOWN = 0xD0 /* DownArrow on arrow keypad */
CONST DIK_NEXT = 0xD1 /* PgDn on arrow keypad */
CONST DIK_Z =              0x2C
CONST DIK_X =              0x2D
CONST DIK_R =              0x13
CONST DIK_ESCAPE =         0x01
CONST DIK_F1 =    0x3B

C3DScreen s
C3DCamera c
pointer m
C3DObject scene
C3DLight light

float fadjust,fTarget
'//target 60FPS for camera movement
fTarget = 1.0f / /*FPS*/60.0f * 1000.0f
fAdjust = 1.0f

s.CreateWindowed(0,0,640,480,@CAPTION,"Custom Mesh",NULL,TRUE)

c.Create(s)
c.Position(0,0,-8)
c.Orient(0,0,1,0,1,0)
c.SetBackPlane(500)

m = CreatePyramid(s,2)
'//set our callback function and a parameter that will be passed
'//when the device has been lost, such as an alt-tab switch
s.SetRestoreCallback(&restore_screen,m)

light.Create(s,LIGHT_POINT,1)
light.Position(0,20,-100)
light.SetAttenuation(0,1/200.0,0)
light.SetSpecular(.5,.5,.5,1)
light.SetAmbient(.4,.4,.4,1)

scene.CreateScene(s)
scene.AddChild(light)
scene.AddChild(m)
int fps:fps = 0
int startTime
int screenLeft,screenTop,screenWidth,screenHeight
getclientsize s.m_win, screenLeft,screenTop,screenWidth,screenHeight
do
startTime = MILLISECS()
'//check for keys and move camera accordingly

IF KeyDown(DIK_F1) then SaveBitmap(getstartpath+"image.bmp",s.m_win,0,0,screenWidth,screenHeight)
IF KeyDown(DIK_UP) then c.Move(0.0f,.25f * fAdjust)
IF KeyDown(DIK_DOWN) then c.Move(0.0f,-.25f * fAdjust)
IF KeyDown(DIK_RIGHT) then c.Rotate(1*.01745 * fAdjust,0,0)
IF KeyDown(DIK_LEFT) then c.Rotate(-1*.01745 * fAdjust,0,0)
IF KeyDown(DIK_Z) then c.Rotate(0,0,-1 *.01745 * fAdjust)
IF KeyDown(DIK_X) then c.Rotate(0,0,1 *.01745 * fAdjust)
IF KeyDown(DIK_PRIOR) then c.Rotate(0,-1 *.01745 * fAdjust,0)
IF KeyDown(DIK_NEXT) then c.Rotate(0,1 *.01745 * fAdjust,0)
IF KeyDown(DIK_R) then c.LookAt(0,0,0)
*<C3DMesh>m.Rotate(0,MILLISECS() / 1000.0f,0)
s.Clear(RGBA(0,0,0,255))
s.BeginScene(c)
scene.Draw()
s.RenderText(0,10,"ESC to exit",RGBA(255,255,0,200))
s.RenderText(0,30,"FPS:"+str$(fps),RGBA(255,255,0,255))
fps = s.RenderScene()
fAdjust = (MILLISECS() - startTime) / fTarget
until KeyDown(DIK_ESCAPE)
Scene.Free()
delete m
END

SUB CreatePyramid(pointer pScreen,float height,opt POINTER rest = NULL),POINTER
FLOAT x,y,z
POINTER pRet
if(rest = NULL)
pRet = new(C3DMesh,1)
else
pRet = rest
endif
x = height/2.0f
y = height/2.0f
z = height/2.0f
/*a pyramid has 4 sides and a bottom.  The bottom is comprised of two triangles for a total of 6
In total their are only 5 vertices and we can describe the pyramid using indices into
an array of vertices. For each triangle there are 3 entries in the index buffers.
Thats how vertex and index buffers work*/
numVertices = 5
numIndices = 3 /*vertex per triangle*/ * 6 /*triangles*/

'//create the mesh with a vertex format that allows position, a diffuse color and a normal vector.
'//if the mesh already exists then just reallocate the buffers
if(rest = NULL)
*<C3DMesh>pRet.CreateMesh(pScreen,numVertices,numIndices,D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_DIFFUSE )
else
*<C3DMesh>pRet.ReallocateMesh(numVertices,numIndices,D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_DIFFUSE)
endif
'//lock the buffers and write the vertices
POINTER pVB
POINTER pIB

pVB = *<C3DMesh>pRet.LockVertexBuffer()
pIB = *<C3DMesh>pRet.LockIndexBuffer()
'//4 points of the bottom
'//left rear
#<VERTEX0TEXTURE>pVB.position.x = -x
#<VERTEX0TEXTURE>pVB.position.y = -y
#<VERTEX0TEXTURE>pVB.position.z = z
#<VERTEX0TEXTURE>pVB.diffuseColor = RGBA(255,0,0,255)
#<VERTEX0TEXTURE>pVB.normal = Vec3Normalize(#<VERTEX0TEXTURE>pVB.position)
pVB += len(VERTEX0TEXTURE)
'//right rear
#<VERTEX0TEXTURE>pVB.position.x = x
#<VERTEX0TEXTURE>pVB.position.y = -y
#<VERTEX0TEXTURE>pVB.position.z = z
#<VERTEX0TEXTURE>pVB.diffuseColor = RGBA(0,0,255,255)
#<VERTEX0TEXTURE>pVB.normal = Vec3Normalize(#<VERTEX0TEXTURE>pVB.position)
pVB += len(VERTEX0TEXTURE)
'//right front
#<VERTEX0TEXTURE>pVB.position.x = x
#<VERTEX0TEXTURE>pVB.position.y = -y
#<VERTEX0TEXTURE>pVB.position.z = -z
#<VERTEX0TEXTURE>pVB.diffuseColor = RGBA(255,0,255,255)
#<VERTEX0TEXTURE>pVB.normal = Vec3Normalize(#<VERTEX0TEXTURE>pVB.position)
pVB += len(VERTEX0TEXTURE)
'//left front
#<VERTEX0TEXTURE>pVB.position.x = -x
#<VERTEX0TEXTURE>pVB.position.y = -y
#<VERTEX0TEXTURE>pVB.position.z = -z
#<VERTEX0TEXTURE>pVB.diffuseColor = RGBA(255,255,0,255)
#<VERTEX0TEXTURE>pVB.normal = Vec3Normalize(#<VERTEX0TEXTURE>pVB.position)
pVB += len(VERTEX0TEXTURE)
'//top point of the pyramid
#<VERTEX0TEXTURE>pVB.position.x = 0
#<VERTEX0TEXTURE>pVB.position.y = y
#<VERTEX0TEXTURE>pVB.position.z = 0
#<VERTEX0TEXTURE>pVB.diffuseColor = RGBA(255,255,255,255)
#<VERTEX0TEXTURE>pVB.normal = Vec3Normalize(#<VERTEX0TEXTURE>pVB.position)

'//write the indices.  Each index is the zero based entry of the array of vertexes. 
'//front triangle
#<WORD>pIB[0] = 3
#<WORD>pIB[1] = 4
#<WORD>pIB[2] = 2
'//left triangle
#<WORD>pIB[3] = 0
#<WORD>pIB[4] = 4
#<WORD>pIB[5] = 3
'//back triangle
#<WORD>pIB[6] = 1
#<WORD>pIB[7] = 4
#<WORD>pIB[8] = 0
'//right triangle
#<WORD>pIB[9] = 2
#<WORD>pIB[10] = 4
#<WORD>pIB[11] = 1
'//1/2 bottom
#<WORD>pIB[12] = 0
#<WORD>pIB[13] = 3
#<WORD>pIB[14] = 1
'//1/2 bottom
#<WORD>pIB[15] = 1
#<WORD>pIB[16] = 3
#<WORD>pIB[17] = 2

'//unlock the buffers
*<C3DMesh>pRet.UnlockIndexBuffer()
*<C3DMesh>pRet.UnlockVertexBuffer()

'//make it visible
*<C3DMesh>pRet.SetVisible(TRUE)

RETURN pRet
ENDSUB

/*
when the directX device is reset due to an alt-tab switch from full screen mode and back
the engine will call this function.  We need to recreate the pyramid since vertex and index
buffers will be lost. Technically we could just delete and recreate everything at this point
but that would be very inefficient in a larger program.

This only needs to be done for custom meshes and environment mapped textures
*/
SUB restore_screen(pointer pParam)

CreatePyramid(null,2,pParam)
RETURN
ENDSUB

RG

I tried your code and it saves a file but it's all white, just as I get in my program. Not sure why you can capture and I can't unless it's a video card/operating system difference.

Rich

ZeroDog

Im on winXP with an nvidia 128 meg video card...

Ionic Wind Support Team

I can just hit Alt+PrintScreen key and paste it into paint.  Works in both windowed and full screen mode.

Paul.
Ionic Wind Support Team

ZeroDog

wow.  That is probably the easiest solution to this... I dont know why I didnt think of that earlier... Sometimes it pays to think outside the box, sometimes it pays to think inside the box  ;D

RG

Paul's suggestion works for me using Zerodog's program, but it captures all the windows in my program, not just the 3D window, even if I click on it first. What I'm trying to do is have the 3D image captured to file so it can be printed using ddoc. I'm using ddoc to print the 2D design on 1-4 pages and also wanted to print the 3D design on another page so it's a complete package for the user.  I guess if worse came to worse I'd have to have the program capture the screen, pull back in the bitmap, use the window positions to clip the excess away, then save the bitmap.

Rich

RG

October 20, 2009, 09:03:14 PM #9 Last Edit: October 20, 2009, 09:06:17 PM by RG
In my last post I said I could

Quotehave the program capture the screen, pull back in the bitmap, use the window positions to clip the excess away, then save the bitmap

I decided to try this after searching the forum and finding Sapero's SaveScreenshot function (I used Sapero's 2nd reply in this thread: http://www.ionicwind.com/forums/index.php/topic,3323.0.html

Works well and gives me what I need. Here's the code I used in addition to Sapero's code.


SaveScreenshot(_GetDesktopWindow(),"3dpreview.bmp",false) :'captures the screen
getscreensize(wm,hm) :'gets the size of the screen
getsize(screen.m_win,l,t,w,h) :'gets the size and location of the 3D window
openwindow tempwin,wm,hm,w,h,0,0,"",&main :'opens a temporary window sized to the 3D image (w,h) and using the screen size (wm,hm) to locate it out of view
mybmp=loadimage(getstartpath+"3dpreview.bmp",@imgbitmap) :'loads the previously captured screenshot
showimage(tempwin,mybmp,@imgbitmap,-l,-t,w+l,h+t) :'shows the screenshot in the hidden temporary window offset to show the 3D image
SaveScreenshot(tempwin.hwnd,"3dpreview.bmp",false) :'saves the image
closewindow(tempwin) :'closes temporary window
deleteimage(mybmp,@imgbitmap) :'frees memory


Thanks to ZeroDog and Paul for the leads that got me going in the right direction. And thanks to Sapero for his function and to Larry McCaughn who's question led to sapero's response. Shows that Q&A's can have a life beyond the original need.

Rich