DirectX Consultant Sought (by phone)?

Started by
18 comments, last by calidev234 18 years, 10 months ago
The D3DXLoadMeshFromX only loads your mesh into memory it doesn't actually do any rendering, you would have to then render it in the onframerender

I'm not sure of the exact code though it's been a while since I've used directx and I'm starting to get a bit rusty.
Advertisement
I suggest you read through the Samples\C++\Direct3D\Tutorials\Tut06_Meshes\ code for the very basic mesh loading and rendering code.

Now, for clarity, the tutorial code does not use the sample framework. I would recommend you use the sample framework as it does a damn good job of handling the various events/states that can occur during normal execution (primarily that of a lost device).

So, load up your EmptyProject installation - we're gonna merge the two [smile]

You seem to have worked out how you load your mesh in, but it's useful to note that your code is using D3DXMESH_MANAGED which requires less work from you, by comparison to the Tut06_Meshes code that uses D3DXMESH_SYSTEMMEM. I personally tend to use D3DXMESH_DEFAULT for my code, but that requires you pay more attention - I leave that up to you...

So, put your code in the OnCreateDevice() function.

Before we continue, you must get in the habit of writing clean code - so add the following to your OnDestroyDevice():
SAFE_DELETE_ARRAY( g_pMeshMaterials );if( g_pMeshTextures ){    for( DWORD i = 0; i < g_dwNumMaterials; i++ )    {        SAFE_RELEASE( g_pMeshTextures );    }    SAFE_DELETE_ARRAY( g_pMeshTextures );}SAFE_RELEASE( g_pMesh );

With this code, you should have cleaned up any/all resources and the world will remain happy.

Now, the important part, rendering your mesh.

EmptyProject comes with some stock rendering code - in particular the Clear() and BeginScene() / EndScene() calls. These are very important, and you should note that your drawing call should be placed between the begin/end scene calls.
for( DWORD i=0; i<g_dwNumMaterials; i++ ){    // Set the material and texture for this subset    g_pd3dDevice->SetMaterial( &g_pMeshMaterials );    g_pd3dDevice->SetTexture( 0, g_pMeshTextures );    // Draw the mesh subset    g_pMesh->DrawSubset( i );}

The above will draw your mesh.

Currently, the only difference between your code will be the matrix transforms - are you happy with those, or do you need someone to go over how they work?

hth
Jack

<hr align="left" width="25%" />
Jack Hoxley <small>[</small><small> Forum FAQ | Revised FAQ | MVP Profile | Developer Journal ]</small>

Thank you everyone for helping me understand this.

I have a question though: so far the only code I've changed from the EmptyProject is the code I included above:

WCHAR jstr[MAX_PATH] = L"test.x";
V_RETURN( D3DXLoadMeshFromX(jstr, D3DXMESH_DEFAULT, pd3dDevice, NULL, NULL, NULL, NULL, &g_pMesh) );

So in your example (between the begin/end scene) you refer to these variables:
g_dwNumMaterials
g_pMeshMaterials
g_pMeshTextures

I haven't added these to the project yet. How do I get the values for these variables when the only thing I have is a .x file?

Joshua
Alright; so I added the variables mentioned above. So now the only code I've added to the EmptyProject file is included below:

The global variables:
-----------------------
DWORD g_dwNumMaterials;
ID3DXMesh* g_pMesh = NULL;
D3DMATERIAL9* g_pMeshMaterials;
LPDIRECT3DTEXTURE9* g_pMeshTextures;


OnCreateDevice:
-----------------------
LPD3DXBUFFER matbuffer;
WCHAR jstr[MAX_PATH] = L"test.x";
HRESULT result;
result = D3DXLoadMeshFromX(jstr, D3DXMESH_SYSTEMMEM, pd3dDevice, NULL, &matbuffer, NULL, &g_dwNumMaterials, &g_pMesh);

if (result != D3D_OK) return S_FALSE;

LPD3DXMATERIAL d3dxMaterials = (LPD3DXMATERIAL)matbuffer->GetBufferPointer();
g_pMeshMaterials = new D3DMATERIAL9[g_dwNumMaterials];
g_pMeshTextures = new LPDIRECT3DTEXTURE9[g_dwNumMaterials];

for (DWORD i=0;i<g_dwNumMaterials;i++)
{
//grab the material
g_pMeshMaterials = d3dxMaterials.MatD3D;
//set ambient color for material
g_pMeshMaterials.Ambient = g_pMeshMaterials.Diffuse;
g_pMeshTextures = NULL;

if( d3dxMaterials.pTextureFilename != NULL && lstrlen((LPCWSTR)d3dxMaterials.pTextureFilename) > 0 )
{
//load texture file specified in .x file
result = D3DXCreateTextureFromFile(pd3dDevice, (LPCWSTR)d3dxMaterials.pTextureFilename, &g_pMeshTextures);

if (result != D3D_OK)
return NULL;
}

OnFrameRender:
-----------------------
for( DWORD i=0; i<g_dwNumMaterials; i++ )
{
pd3dDevice->SetMaterial( &g_pMeshMaterials );
pd3dDevice->SetTexture( 0, g_pMeshTextures );
g_pMesh->DrawSubset( i );
}


Now this looks a little better, but it is still not working. It does not crash but nor does it render anything. On a side note you'll see I've had to cast some variables (i.e. the (LPCWSTR)) because otherwise I get and error:

error C2664: cannot convert parameter 2 from 'LPSTR' to 'LPCWSTR'


I believe I'm on the right track; but I still cannot see anything? Any suggestions.

So the error I just mentioned (the casting error) is because the projects character set is set to UNICODE. I'm using DirectX 9.0c - it appears that there are big differences between 9.0b and 9.0c. What the hell?

Any ideas? Is there and EmptyProject in the 9.0b SDK - because I didn't find one.

Try running it in debug, and check the output spew. If you're having problems with filename conversion (typecasting a LPSTR to a LPCWSTR probably isn't going to work--look up the function 'mbstowcs' for a converter) it may not be able to find the file. If that's the case, the output will tell you. Of course, if you're checking the return values, you might already know that this isn't the case.

DX9 does not require unicode, but the DXUT classes (very useful things to learn if you want to do a GUI in your app) do for some reason require it. Why, I don't know. Maybe some greater mind than mind can explain it.

If it's running happily and not putting out any errors, there's a number of things that can be going wrong--the transforms could be wrong (object is drawing behind the viewpoint or something) the scale could be wrong (if the viewpoint is on the inside of a mesh, and that mesh is a simple one, all the faces could be pointing the wrong direction and being backface culled)

You set the transforms by calling the device interface, like this:

D3DMATRIX matWorld;
D3DXMatrixTranslation( &matWorld, 0.0f, 0.0f, 0.0f );
pd3dDevice->SetTransform( D3DTS_WORLD, &matWorld );

The world transform can be (kind of) considered the drawing point. If you set the world transform to a simple translation--say, a point at (0.0f, 0.0f, 0.0f) then the next thing you draw (in your example, calling g_pMesh->DrawSubset( i );) will be drawn at those coordinates in the world.

The view transform can be considered to be 'where the camera is' so you'll want to position the camera somewhere that it can see the point you're drawing D3DXVECTOR3(0.0f, 0.0f, 0.0f) in this case. Here's a handy dandy way to make a view matrix easily with:

D3DXMATRIX pView; //the output matrix
D3DXVECTOR3 vec3CameraLoc( 0.0f, 0.0f, 100.0f ); //where the camera is 'at'
D3DXVECTOR3 vec3CameraTarget( 0.0f, 0.0f, 0.0f ); //what it's looking at
D3DXVECTOR3 vec3Up( 0.0f, 1.0f, 0.0f ); //which way is 'up'

D3DXMatrixLookAtRH( &pView, &vec3CameraLoc, &vec3CameraTarget, &vec3Up ); //Make me a view matrix!

//Now, with this matrix, you can set the view:
pd3dDevice->SetTransform( D3DTS_VIEW, &pView);


My apologies if you already understand the above code, no offense is intended if you do. It's very simplified (and may not even compile, I'm beat sorry) but it should at least give you a point to start with if the issues you're having are related to the transform deal above--and if you get it to work, you can punch numbers in the stuff above to see how it all goes together.
Quote:Original post by Toraque
DX9 does not require unicode, but the DXUT classes (very useful things to learn if you want to do a GUI in your app) do for some reason require it. Why, I don't know. Maybe some greater mind than mind can explain it.

My understanding for this is quite simply a case of internationalization... regular 7/8bit ASCII text is a bit of a dinosaur now, and fairly useless at representing a lot of human languages - thus it wouldn't make much sense to develop a new library that is inherantly limited by an old(er) technology...

Jack

<hr align="left" width="25%" />
Jack Hoxley <small>[</small><small> Forum FAQ | Revised FAQ | MVP Profile | Developer Journal ]</small>

Ok, so because I have to incorporate this DirectX code into an existing project that is not Unicode; does this mean I cannot use the 9.0c and must revert back to the 9.0b. Because when I choose to goto to multi-single this messes everything up (in the 9.0c EmptyProject).

????
hi,

this is simply a problem of unicode / standard ascii. When switching to a newer version of DirectX SDK (don't remember which one ... should be the one with their new GUI system) I had this problem a lot. So I simply took an emptyproject, and remove ALL occurences of UNICODE to have a ASCII emptyproject ^^ But that's quite long.

So, I would advice creating 2 functions

LPSTR unicode2ascii(LPSTR textAscii, LPCWSTR text){   for (int i = 0; i < wstrlen(text); i++)      textAscii = (unsigned char)text;   return(textAscii)}LPCWSTR ascii2unicode(LPCWSTR textUnicode, LPSTR text){   for (int i = 0; i < strlen(text); i++)      textUnicode = (unsigned short)text;   return(textUnicode)}


That's from memory, the function / types might be incorrect. But that's the idea.

so when the "error C2664: cannot convert parameter 2 from 'LPSTR' to 'LPCWSTR'" error occures, replace the parameter "the_LPSTR_Parameter" by "ascii2unicode(a_LPCWSTR_string, the_LPSTR_Parameter)"
Thank you very much - that if very helpful. It seems like a major change to have between releases which are not even the main version releases (i.e. 9.0b to 9.0c) - it seems a bit silly. But anyway...thank you.

Joshua

This topic is closed to new replies.

Advertisement