.X file-ok betöltése
A .x egy 3D-s modell file formátum, amit a DirectX-hez találtak ki.
Ezek DirectX alatt kényelmesen betölthetők és megjeleníthetők. Rengeteg modell található neten és a DirectX SDK-ban (<DirectX SDK könyvtár>\Samples\Media). Sok 3D-s szerkesztő program tud exportálni ilyen formátumba. Ilyen pl az ingyenes Blender.
Példa projekt, az órán használt keretredszerrel, letölthető innen.
Modellek betöltése
A következő változókra van szükség a betöltéshez és a megjelenítéshez is:
ID3DXMesh *mesh; D3DMATERIAL9 *meshMaterials; IDirect3DTexture9 **meshTextures; DWORD numMaterials;
Az első maga a modell, ami több textúrázott anyagot is tartalmazhat. Ezek számát tárolja majd a numMaterials, a többi kettő pedig a konrét adatok tömbjei lesznek.
Mindet érdemes nullára inicializálni.
A tényleges betöltő kód:
void LoadX::loadMesh() { //** Takaritas, hatha nem eloszor hivjuk ezt SAFE_RELEASE(mesh); SAFE_DELETE_ARRAY(meshMaterials); for (DWORD i=0; i<numMaterials; ++i) SAFE_RELEASE(meshTextures[i]); SAFE_DELETE_ARRAY(meshTextures); LPD3DXBUFFER materialBuffer; HRESULT hr; V( D3DXLoadMeshFromX(L"X\\airplane 2.x", D3DXMESH_MANAGED, _device, NULL, &materialBuffer, NULL, &numMaterials, &mesh) ); //** Nem ugyan az, mint a D3DMATERIAL9 ! D3DXMATERIAL* materials = (D3DXMATERIAL*)materialBuffer->GetBufferPointer(); //** Tobb anyag es textura is lehet egy mesh-ben meshMaterials = new D3DMATERIAL9[numMaterials]; meshTextures = new LPDIRECT3DTEXTURE9[numMaterials]; for (DWORD i=0; i<numMaterials; ++i) { meshMaterials[i] = materials[i].MatD3D; //** Az ambiens szint kezzel kell atallitani meshMaterials[i].Ambient = meshMaterials[i].Diffuse; //** toltsuk be a texturakat, ha vannak meshTextures[i] = 0; if (materials[i].pTextureFilename) { LPCWSTR wfilename = ConvertLPCSTRToLPWSTR(materials[i].pTextureFilename); WCHAR withpath[60]; StringCbPrintf(withpath, 60, L"X\\%s", wfilename); V( D3DXCreateTextureFromFile(_device, withpath, &meshTextures[i]) ); } } materialBuffer->Release(); }
Ez használja a következő segédfüggvényt, amire a Unicode-os és nem Unicode-es stringeketet használó függvények keveredése miatt van szükség:
LPWSTR ConvertLPCSTRToLPWSTR(char* pCstring) { LPWSTR pszOut = NULL; if (pCstring != NULL) { int nInputStrLen = (int)strlen(pCstring); int nOutputStrLen = MultiByteToWideChar(CP_ACP, 0, pCstring, nInputStrLen, NULL, 0) + 2; pszOut = new WCHAR [nOutputStrLen]; if (pszOut) { memset (pszOut, 0x00, sizeof (WCHAR)*nOutputStrLen); MultiByteToWideChar(CP_ACP, 0, pCstring, nInputStrLen, pszOut, nInputStrLen); } } return pszOut; }
Megjelenítés
A kirajzolás ennél már jóval egyszerűbb:
void LoadX::onFrameRender( double fTime, float fElapsedTime ) { _device->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(65, 105, 225), 1, 0); if ( SUCCEEDED(_device->BeginScene()) ) { for (DWORD i=0; i<numMaterials; ++i) { //** Anyagjellemzo es textura megadas _device->SetMaterial(&meshMaterials[i]); _device->SetTexture(0,meshTextures[i]); //** Al-mesh kirajzolas mesh->DrawSubset( i ); } _device->EndScene(); } }
Takarítás
A betöltött adatokak fel kell szabadítanunk, ha a program véget ér, vagy már nincs rá szükségünk:
void LoadX::onDestroyDevice() { SAFE_RELEASE(mesh); SAFE_DELETE_ARRAY(meshMaterials); for (DWORD i=0; i<numMaterials; ++i) SAFE_RELEASE(meshTextures[i]); SAFE_DELETE_ARRAY(meshTextures); }