Hi, I'm back again!
My application is now working fine and converting textures as it should, but I've just sent it to one of the texture guys to give it a run through and it crashes out with an error of "File or assembly name Microsoft.DirectX.Direct3D, or one of its dependecies, was not found."
As I've come to understand it, that means that the DirectX install that they have isn't enough and that the also need to install the MDX package. Considering my app is only around 25KB (zipped) when I don't include the DevIL libraries, forcing people to download a further 4.odd MB of MDX installer is just crazy.
I've tried searching for unmanaged DirectX in C#, but I'm not turning up much useful so far. If someone could give me some pointers on how to replace such a simple snippet as this:
Texture txtr = TextureLoader.FromStream(device, new MemoryStream(ddsFile, false), 0, 0, 1, Usage.None, Format.A8R8G8B8, Pool.Managed, Filter.Linear, Filter.Linear, 0);
GraphicsStream gs = TextureLoader.SaveToStream(ImageFileFormat.Tga, txtr);
tgaFile = new byte[gs.Length];
gs.Read(tgaFile, 0, (int)gs.Length);
with some unmanaged code in C# then that'd be great. In the mean time, I'll try a bit more hunting and see if I can find some tutorials burried under all of this discussion.
Thanks
[edit] So far I'm getting no where, and that's after spending a good proportion of the day searching for tutorials and articles. It doesn't help that my University started us on Java and the C#, so I don't know C++ and its exact syntax, but no-one seems to want to write tutorials on wrappers or unmanaged code in .Net that I can find.

Unmanaged DirectX to solve dependancies?
Syed Moiz
DirectXWrapper.cpp
// This is the main DLL file.
#include "stdafx.h"
#include "DirectXWrapper.h"
int DirectXWrapper::test(HWND window, byte* data){
// Create Direct3D9 Object
LPDIRECT3D9 pD3D9 = Direct3DCreate9( D3D_SDK_VERSION );
if ( !pD3D9 )
{
MessageBox( 0, "Direct3DCreate9() - Failed", 0, 0 );
return 0;
}
// Fill out the presentation parameters
D3DPRESENT_PARAMETERS D3Dpp;
ZeroMemory( &D3Dpp, sizeof(D3Dpp) );
D3Dpp.Windowed = TRUE;
D3Dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
// Create the Direct3D Device
LPDIRECT3DDEVICE9 pD3DDevice = NULL;
if ( FAILED( pD3D9->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, window, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &D3Dpp, &pD3DDevice ) ) )
{
MessageBox( 0, "CreateDevice() - Failed", 0, 0 );
SAFE_RELEASE( pD3D9 );
return 0;
}
LPDIRECT3DTEXTURE9* txtr;
D3DXIMAGE_INFO* imgInfo;
PALETTEENTRY* junkPalette;
D3DXCreateTextureFromFileInMemoryEx(pD3DDevice, data, sizeof(data), D3DX_DEFAULT, D3DX_DEFAULT, 1, D3DUSAGE_DYNAMIC, D3DFMT_DXT1, D3DPOOL_MANAGED, D3DX_FILTER_LINEAR, D3DX_FILTER_LINEAR, 0, imgInfo, junkPalette, txtr);
LPD3DXBUFFER * ppDestBuf;
D3DXSaveTextureToFileInMemory(ppDestBuf, D3DXIFF_TGA, *txtr, junkPalette);
//Texture txtr = TextureLoader.FromStream(device, stream, 0, 0, 0, Usage.None, Format.Dxt1, Pool.Managed, Filter.Linear, Filter.Linear, 0);
//GraphicsStream gs = TextureLoader.SaveToStream(ImageFileFormat.Dds, txtr);
}
and DirectXWrapper.h:
// DirectXWrapper.h
#pragma once
using namespace System;
namespace DirectXWrapper
{
int test(HWND, byte*);
}
stdafx.h:
// stdafx.h : include file for standard system include files,
// or project specific include files that are used frequently,
// but are changed infrequently
#pragma once
// Exclude rarely-used stuff from Windows headers
#define WIN32_LEAN_AND_MEAN
#define SAFE_RELEASE(x) if( x ) { (x)->Release(); (x) = NULL; }
#define SAFE_DELETE(x) if( x ) { delete(x); (x) = NULL; }
#define SAFE_DELETE_ARRAY(x) if( x ) { delete [] (x); (x) = NULL; }
// DirectX Header Files
#include <d3d9.h>
#include <d3dx9.h>
Everything is compiling so far, and as far as I understand it the ppDestBuf should either contain the same data as either the GraphicsStream or be a form of byte array full of the data like tgaFile became in the first example.
If that is the correct way of doing a DirectX wrapper than the major hole I hit is that on the CreateTextureFromFileInMemory MSDN page (http://msdn.microsoft.com/library/default.asp url=/library/en-us/directx9_c/D3DXCreateTextureFromFileInMemoryEx.asp) says:
- DestFormat
- [in] D3DXIMAGE_FILEFORMAT specifying the file format to use when saving. This function supports saving to all D3DXIMAGE_FILEFORMAT formats except Portable Pixmap (.ppm) and Targa/Truevision Graphics Adapter (.tga).
If that's still true and there's no way round it then that would be the biggest pain ever - the one time the DirectX MSDN gives definate information and it'd completely fail in the areas I need it - DDS to TGA conversion and TGA to DDS. That, plus how does it manage to handle it in the C# version of the call if the C++ can't handle TGAsAny help and pointers would be great. Thanks
shiras
>I've tried searching for unmanaged DirectX in C#, but I'm not turning up much useful
>so far.
I've not seen anything. You are pretty much asking how to create your own managed wrapper which , unless you only need a few calls, is asking for a lot of work - you are basically recreating Managed DirectX. Even if you did this you still have a dependency on DirectX which is (possibly depending on what is already there) up to a 24Mb install too.
The DirectX installer is more than capable of installing managed DirectX.
Either get your end users to run the web installer http://www.microsoft.com/downloads/details.aspx displaylang=en&FamilyID=2da43d38-db71-4c1b-bc6a-9b6652cd92a3
Or follow the instructions in the SDK http://msdn.microsoft.com/library/default.asp url=/library/en-us/directx9_c/Installing_DirectX_with_DirectSetup.asp
the extra 4M (or whatever it is) is small compared to the .Net framework which you also need to ensure is there. Yes compared to the size of your application its big, but remember the size of your appliction is small *because* all the rest of the functionality is in the other libraries.
If you really want to avoid the managed wrappers then you are better off going with native C++ and native DirectX as there is far more documentation and examples out there. Otherwise have fun and document your journey - you are breaking new ground and others may like to read about it.
buzzy
I quite literally just need wrappers for those functions I posted in the first post (TextureLoader.FromStream and TextureLoader.SaveToStream, and retrieving the bytes), plus any associated functions like creating a Device etc, so it should only be a small number of calls. I've tried some C++ in VS.Net but it didn't want to recognise the existance of the ...FileInMemory functions when I went to debug mode.
As for the DirectX dependancy, this program is a tool for the Dawn of War computer game, so people should have DirectX installed anyway. And a good proportion of people have .Net installed as part of XP/SP2 - I've only had a couple of people ignore the "Requires .Net" and then complain when it errored because the framework was missing.
But if I'm stuck with no-one having done it previously and having to use C++ then it looks like I'm going to have to learn C++ :D Not too much of a problem, I know Java and C# and I modified some Perl and PHP forums without knowing the languages at all first. If only my University had taught some C++!
Thanks
Lakshan
You can't ship the DLLs directly, however you can ship the redist CAB files and call dxsetup to install them to the correct and known places.
To be honest people worry too much about the MDX installs - like I said the April 05 MDX cab is 900k, d3dx cab is 1Mb and dxsetup is 500k. So 2.4Mb. Sure it seems a lot compared to the EXE but its 2.4Mb, not even 2 floppy discs if anyone out there even remembers floppy discs. If you package it all together in an MSI its less than 3Mb. Just to put in in perspective thats 2 photos from a modern digital camera, or about 15s of compressed 640x480 video. In other words its tiny and you would be better worrying about how good you can make the program if you have the whole API available.
Yes .Net framework is bigger but as time goes by thats will be on more and more machiens (and I assume installed by default wtih vista)
anonymoosee
My DirectXWrapper is as follows:
// This is the main DLL file.
#include "stdafx.h"
#include "DirectXWrapper.h"
using namespace System::Runtime::InteropServices;
#pragma unmanaged
void DirectXWrapper::ImageConverterUn::TGAtoDDS_un(VOID* window, unsigned char data [], LPCSTR filepath){
// Create Direct3D9 Object
LPDIRECT3D9 pD3D9 = Direct3DCreate9( D3D_SDK_VERSION );
if ( !pD3D9 )
{
MessageBox( 0, "Direct3DCreate9() - Failed", 0, 0 );
return;// 0;
}
// Fill out the presentation parameters
D3DPRESENT_PARAMETERS D3Dpp;
ZeroMemory( &D3Dpp, sizeof(D3Dpp) );
D3Dpp.Windowed = TRUE;
D3Dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
// Create the Direct3D Device
LPDIRECT3DDEVICE9 pD3DDevice = NULL;
if ( FAILED( pD3D9->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, (HWND)window, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &D3Dpp, &pD3DDevice ) ) )
{
MessageBox( 0, "CreateDevice() - Failed", 0, 0 );
SAFE_RELEASE( pD3D9 );
return;
}
LPDIRECT3DTEXTURE9* txtr;
D3DXIMAGE_INFO* imgInfo;
PALETTEENTRY* junkPalette;
D3DXCreateTextureFromFileInMemoryEx(pD3DDevice, data, sizeof(data), D3DX_DEFAULT, D3DX_DEFAULT, 1, D3DUSAGE_DYNAMIC, D3DFMT_DXT1, D3DPOOL_MANAGED, D3DX_FILTER_LINEAR, D3DX_FILTER_LINEAR, 0, imgInfo, junkPalette, txtr);
D3DXSaveTextureToFile(filepath, D3DXIFF_TGA, *txtr, junkPalette);
return;
}
#pragma managed
void DirectXWrapper::ImageConverter::TGAtoDDS(IntPtr window, System::Byte data __gc[], String* filename){
unsigned char __pin* umgd_data = new unsigned char[data->Length];
for (int i = 0; i<data->Length; i++){
umgd_data[i ] = data[i ];
}
LPCSTR umgd_filename = static_cast<char*>(Marshal::StringToHGlobalUni(filename).ToPointer());
DirectXWrapper::ImageConverterUn::TGAtoDDS_un(window.ToPointer(), umgd_data, umgd_filename);
Marshal::FreeHGlobal(static_cast<IntPtr>(const_cast<void*>(static_cast<const void*>(umgd_filename))));
delete [] umgd_data;
}
In the managed function, data is the full byte array for the TGA file, and filename is where I want it to be saved. Debugging the code, umgd_filename ends up with the value 'G' (because I'm saving it to my G drive) but I'm guessing that it's because it's an array and it's just showing me the first value. umgd_data ends up with the value '' (0), which I suspect is the problem. Is there some other way I should be copying the managed byte array to the unmanaged array
Thanks
[edit] *curses smilie conversion* I've had to add some additional spaces to the code.
[edit2] Ahah, I've tracked it down (with the help of 'return' statements to track how far it gets) to the final line of TGAtoDDS_un(). Obviously my texture isn't being created in the line before. Now to work out why, and whether it's the bit in the MSDN that says TGA isn't supported even though Managed DirectX can handle it.
[edi3] Apparently my D3DXCreateTextureFromFileInMemoryEx() call results in an D3DERR_INVALIDCALL result. I'll keep poking it to see if I can get it to work, but any ideas as to why it would return invalid call (and whether it has anything to with my managed->unmanaged data conversion, even though there's a 'D3DXERR_INVALIDDATA' return) would be great.
Raul Rodriguez
As for how good I can make the program - the part that I need DX/MDX for is quite literally nothing more than opening a TGA, converting it to a DXT1/DXT5 and saving it. That's all. Nothing particularly fancy, nothing involving 3D rendering, cameras, surfaces, vertexes or anything like that, just some simple file conversions (which DevIL.net doesn't fully support - I think it was the MipMaps it didn't create or something). Although at this rate I might be better off finding code of the DXT1 compression algorith and coding it from scratch!
[edit] I've found a solution for DDS->TGA. Thanks to a very kind person who wrote the Texture Toolkit for Unreal Editor (http://www.foogod.com/UEdTexKit/) I've had access to some C source code that was released freely (not even a GNU/MIT licence). A bit of conversion work and it's now working on DXT1 files in C#. I just need to convert the DXT3 and DXT5 code and then it's just converting back from TGA->DDS! I think that'll be slightly harder without DirectX, though.
[edit2] DDS->TGA conversion is now working fine in pure C# code. It could do with a few optimisations from an aesthetics stand-point (e.g. it checks at each texel whether it's DXT1, 3 or 5) but performance is still good. I think I'm going to try and get hold of the old December 2004 SDK and see if I have any more luck converting TGA->DDS using DirectX when I have the old static library.
[edit3] Okay, I now have the December 2004 SDK, which should mean I'll be compiling against the static lib instead of these ever-changing DLLs (which hopefully solves any dependancy issues beyond just having DirectX). Now I've just got to work out how to call the C++ wrapper functions from a C# application :\ Intellisense recognises the namespace and classes, but not the public method (declared with __gc). Most of the articles I find are saying use DllImport, but I thought that was for non-.Net DLLs not C++ in .Net compiled with /clr
Nelson Xu
It may be a bit more work, but I may end up trying to avoid using D3DX commands and just stick to the main DirectX core, that way I can be certain that the DLLs exist on the user's machine. As you say, shipping an installer with a full game is nothing special, especially with the size of modern games, but shipping it or having it as a requirement for something as small as my little Texture Tool seems completely wrong. As I once read somewhere, .Net was supposed to solve DLL Hell and instead we've just got Framework Hell (where they've got the 'wrong' version) or Package Hell (where you just add additional separate required installers).
Thanks for the suggestions.
[edit] That is, I'll avoid D3DX as long as I can find a way to convert file types without using D3DX functions. I've just looked again and the code I've found either uses D3DX or else it can't change texture types (e.g. IDirect3DDevice9::UpdateTexture requires them both to be the same format)
denish1
XP SP2 doesn't install .Net 2.0 - its on Windows update as an optional download but thats all.
Sorry can't help more with the managed wrapper - I've never had to do it. I know MDX itself is written using Managed C++ as is Ralfs 'early' MDX for D3D10 wrapper and I suspect this is because its the easiest way to merge the 2 worlds.
If you know for sure that they have the core DX then you don't need the rull redist you can just include the MDX part in your setup, its not just the managed files though you may also end up with a dependecnay on a particulr version of D3DX_nn.dll which may be different to the one Dawn of war installed so watch out for this. Also in the APril SDK if you know for sure you only need the APril SDK managed files you only have 896Kb of cab file to include (though the related d3dx_nn.dll is bigger so like I said make sure they have that).
Brian2
Almost.... if a game is written for the core directx9.0b then it should run on future versions and should run as long as the 'core' directx files are already there. At the end of the day though all application writers should consider the worst case scenario of the machine having no directx runtime.
However this doesn't apply if you have used D3DX_nn.dll fron native code, or any managed assemblies. If you use those its your responsibility as the developer to ensure that the correct version of those files is on the machine and redist them. (this catches the native deelopers out too).
Until recently this was never a big problem, most games were delivered on CD or DVD and so the extra bytes were not a big deal to include. Even with big games its not big deal becuase the game content - audio/graphics - usually dwarfs the extra bytes too. However for small tools like yours and casual games its suddenly a big deal and one that MS doesn't have a great solution for right now. Their first step in this direction is to provide the web installer which will check your machine and only download the minimum set of files to get all the d3dx_nn.dlls and all the MDX versions on your machine. If everything is there I think the total download is 50k or something for the bootstrap check. Hopefuly in the future there will be other ways too.
cybbe
I'll take a look at those D3D10 wrappers and see if they can give me any pointers. I think I already tripped over the article before but ignored it because it was about D3D10, not 9.
As for redistributables, I really am trying to avoid them at all costs. One person in the community has already released a tool (which I believe is written in VB5/6) that extracts the DDS out of a game texture file and saves it in to a TGA on the disk. If it was possible in VB without additional redistributables then there has to be some way to do it in .Net.
I thought part of the point of DirectX is that it was backwards compatible, though As long as I write for 9b (minimum requirement of the game) then I thought that it should still be fine in 9c (the minimum requirement of the expansion pack). Games that require DirectX 9b don't stop working as soon as you install 9c.
If only the documentation were more useful, and Google didn't turn up mainly MDX stuff.
[edit] I may finally have found what I was looking for! It's a little overly large for my use, since it seems to be a full wrapper, but Sunlightd.com has tutorials about and source code for his DirectX 8 wrapper that is written in Managed C++ (http://www.sunlightd.com/Windows/DirectX.NET/). From the intro to the article it's all pre-MDX, so I shouldn't be wasting my time accidentally just recoding the C# MDX code in C++!
I'll report back when I've had a chance to try it out.