abhi2011 Posted April 19, 2015 Author Share Posted April 19, 2015 Hey guys, With the new DirectX8 engines, one of the functionalties that were lost from the DX7 engines was the inability to screenshot the map and/or the client screen. This meant that mappers couldn't showcase their awesome mapping talent and admins couldn't create screenshots of their games directly from the engine and has to resort to other tactics. Well, this tutorial solves that problem. You can now create as many screenshots as you possibly want. Attached to this post/topic is a module called "modAdvDX8Tex.bas", this module contains all the functions necssary to convert the game screen into a valid PNG, BMP or JPEG file. I've made sure to comment and document as much of the code as possible so that people can learn from it if they so desire. The actual module has been written for Eclipse Worlds, but it'll work with any and all DX8 engines. All that has to be changes is the usage of said module**WARNING: THIS TUTORIAL ASSUMES THAT YOU HAVE APPLIED [THIS](http://www.eclipseorigins.com/index.php?/topic/136966-bug-gdip-bug-in-dx8-engines/) BUG FIX.****Steps to add in the module to your ****project:**1. Put the module in the client src folder and open up your client project file.2. Press Ctrl+D or go to Project -> Add file.Here are a few source tutorials on how to actually use the module:>! **Taking a screenshot of the game viewport:** Find the method **Render_Graphics** in your rendering/graphics moduleAt the end of the method, ust after the call to the **Direct3D_Device.Present, **add this line of code: ```Call SaveDirectX8SurfToFile(App.Path & "\screenshot.png", Direct3D_Device.GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO), ImageFormats.PNG)```**Taking a screenshot of the entire map: **–coming soon--The provided module does not have any error handling functions. Error handling should be added in by you based upon the engine you are using. Regards,Abhi2011 Link to comment Share on other sites More sharing options...
abhi2011 Posted April 19, 2015 Author Share Posted April 19, 2015 The source code for the attached file is here, just in case it's lost during in the future due to forum conversions or some other reason. >! ```Option Explicit' This method allows you to convert your Direct3DTexture8 or Direct3DSurface8 texture into an image filePublic Enum ImageFormats ' All the image formats supported by GDIp BMP PNG JPEGEnd EnumPublic Function ConvertSurfaceToArray(Surface As Direct3DSurface8, ByRef Pixels() As Byte) As Boolean Dim SurfDesc As D3DSURFACE_DESC, LockedRect As D3DLOCKED_RECT, rc As DxVBLib.RECT Dim TempSurf As Direct3DSurface8 ' This methods converts a Direct3DSurface8 using a format ARGB with 8 bits 'per component into an array of bytes ' You can get the ARGB value in the form of a long by copying 4 bytes (starting from the first) using CopyMemory ' i.e CopyMemory Long, byte(count), 4 ' Each individual component of the ARGB can be extracted directly from the array ' For eg. starting from 0, x = 0 -> A = Arr(x + 3), R = Arr(x + 2), G = Arr(x + 1), B = Arr(x) ' Currently this method only provides support for 32bpp images. Though you can add support for 24bpp or 16bpp or 8bpp. ' Contact me if you want more help with that. Call Surface.GetDesc(SurfDesc) ' Check if it's a format that we can convert to a byte array If SurfDesc.Format = D3DFMT_A8R8G8B8 Or D3DFMT_X8R8G8B8 Then ' Set up the rect so that DX8 knows which parts of the surface we want to copy from With rc ' This will select the entire surface .Left = 0 .Right = SurfDesc.Width .Top = 0 .Bottom = SurfDesc.Height End With If SurfDesc.Pool = D3DPOOL_DEFAULT Then ' If the Texture is in the D3DPool_Default pool then we can't lock the rect ' We have make a copy of the Surface elsewhere before we attemptt lock it Set TempSurf = Direct3D_Device.CreateImageSurface(SurfDesc.Width, SurfDesc.Height, SurfDesc.Format) ' Copy the rect to the TempSurf Call Direct3D_Device.CopyRects(Surface, rc, 1, TempSurf, rc) Else ' If not in the Default pool then just set the TempSurf to the original Surf. Set TempSurf = Surface End If ' Lock the surface to get the pixel data. Call TempSurf.LockRect(LockedRect, ByVal 0, 0) ReDim Pixels((LockedRect.Pitch * SurfDesc.Height) - 1) ' Pitch = Bytes Per Pixel * width If Not DXCopyMemory(Pixels(0), ByVal LockedRect.pBits, LockedRect.Pitch * SurfDesc.Height) = D3D_OK Then ' We weren't able to copy the data ConvertSurfaceToArray = False Exit Function End If ' If you want, you can tweak the Pixels array. To put it back into the DX8 texture copy back into pbits. ' Just reverse the Dest and Source parameters in DXCopyMemory. Make sure UnLockRect is called. Else it the texture won't update Call TempSurf.UnlockRect ' This call is essential. If LockRect is called and this isn't called then it can lead to memory leaks ConvertSurfaceToArray = True End IfEnd FunctionPublic Function ConvertTextureToArray(Texture As Direct3DTexture8, Pixels() As Byte) As Boolean ConvertTextureToArray = ConvertSurfaceToArray(Texture.GetSurfaceLevel(0), Pixels)End FunctionPublic Sub SaveDirectX8SurfToMemory(Data() As Byte, Surf As Direct3DSurface8, Optional ByVal ImageType As ImageFormats = PNG) Dim GDIToken As cGDIpToken, renderer As cGDIpRenderer, Image As cGDIpImage, I As Long Dim PixelFormat As ImageColorFormatConstants, Width As Long, Height As Long, SurfDesc As D3DSURFACE_DESC Dim ImageStride As Long, DataPointer As Long, Pixels() As Byte If Not ConvertSurfaceToArray(Surf, Pixels) Then Exit Sub Call Surf.GetDesc(SurfDesc) Set GDIToken = New cGDIpToken Set renderer = New cGDIpRenderer Set Image = New cGDIpImage Call renderer.AttachTokenClass(GDIToken) I = renderer.CreateHGraphicsFromHWND(frmMain.hWnd) ' afaik the hWnd can be the hWnd of any form in the project If Image.LoadPicture_FromNothing(SurfDesc.Width, SurfDesc.Height, I, GDIToken) Then ' Set up the values for locking the image 'Image.ColorFormat PixelFormat = PixelFormat32bppPARGB Width = Image.Width: Height = Image.Height ' lock the GDIp Image DataPointer = Image.LockImageBits(ImageLockModeWrite, PixelFormat, 0, 0, Width, Height, ImageStride) If DataPointer > 0 Then ' Copy the data that we had in DirectX8 Texture to the GDIp image Call CopyMemory(ByVal DataPointer, Pixels(0), ImageStride * Height) ' Unlock the Gdip image so that the image updates, pass back the values that we used in LockImageBits Call Image.UnLockImageBits(PixelFormat, Width, Height, ImageStride, DataPointer) End If If ImageType = ImageFormats.PNG Then Call Image.SaveAsPNG(Data) ElseIf ImageType = ImageFormats.BMP Then Call Image.SaveAsBMP(Data) ElseIf ImageType = ImageFormats.JPEG Then Call Image.SaveAsJPG(Data) Else Call Image.SaveAsPNG(Data) ' Just save as a PNG End If End If Set Image = Nothing Set renderer = Nothing Set GDIToken = NothingEnd SubPublic Sub SaveDirectX8SurfToFile(ByVal Path As String, Surf As Direct3DSurface8, Optional ByVal ImageType As ImageFormats = PNG) Dim Data() As Byte, f As Long ' Convert the texture into a readable file Call SaveDirectX8SurfToMemory(Data, Surf, ImageType) ' Dump the data we got into the file at the path If FileExist(Path, True) Then Kill Path f = FreeFile Open Path For Binary As #f Put #f, , Data Close #f ' The file should now be a valid imageEnd SubPublic Sub SaveDirectX8TextureToMemory(Data() As Byte, Texture As Direct3DTexture8, Optional ByVal ImageType As ImageFormats = ImageFormats.PNG) Call SaveDirectX8SurfToMemory(Data, Texture.GetSurfaceLevel(0), ImageType)End Sub>! Public Sub SaveDirectX8TextureToFile(ByVal Path As String, Texture As Direct3DTexture8, Optional ByVal ImageType As ImageFormats = ImageFormats.PNG) Call SaveDirectX8SurfToFile(Path, Texture.GetSurfaceLevel(0), ImageType)End Sub>! ``` Link to comment Share on other sites More sharing options...
Kaymak Posted May 7, 2015 Share Posted May 7, 2015 Nice, thank you alot but how can i make more then 1 screenshot. So it saves the screenshots called 1.png , 2.png etc so the screenshot taker dont overwrite tha screenshot that i took before? Link to comment Share on other sites More sharing options...
abhi2011 Posted May 7, 2015 Author Share Posted May 7, 2015 You could do something like this: ```for i = 1 to 255if not fileexists(app.path & "\screenshot" & i & ".png") thenCall SaveDirectX8SurfToFile(App.Path & "\screenshot" & i & ".png", Direct3D_Device.GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO), ImageFormats.PNG)saved = trueend if next```If you want the date to be a part of the file name try something like this: ```Call SaveDirectX8SurfToFile(App.Path & "\screenshot" & now & ".png", Direct3D_Device.GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO), mageFormats.PNG)```That will result in a filename like this: Screenshot 07-05-2015 20:32:17.pngI haven't tested out that code so I'm not sure that'll work exactly as it's intended right off the bat. Link to comment Share on other sites More sharing options...
Kaymak Posted May 7, 2015 Share Posted May 7, 2015 ```For i``` variable not defined :( Link to comment Share on other sites More sharing options...
abhi2011 Posted May 7, 2015 Author Share Posted May 7, 2015 > ```> > For i> ```> variable not defined :(That is just some code I wrote on the spot for you to work with. Work upon that, improve it and shit.HINT: To solve that particular error declare the variable i. Link to comment Share on other sites More sharing options...
Kaymak Posted May 7, 2015 Share Posted May 7, 2015 oh wow im retarted im so sorry lol! got it thank you :P Link to comment Share on other sites More sharing options...
Politano Posted January 28, 2022 Share Posted January 28, 2022 I'm having a problem with a Public Type not declaring As IUnknown, do I need a library for that or do I need to declare it, if I need to declare how to do it? Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now