//************************************************************************** // // Copyright (C) Microsoft Corporation, 1998 - 1999 All Rights Reserved. // // File: frmsave.cpp // // Description: Save LPDIRECT3DRMFRAME to an x file. // // History: // 011/06/98 CongpaY Created // //************************************************************************** #include #include #include #include #include "frmsave.h" extern HINSTANCE g_hInstD3DXOFDLL; #define MyD3DRMColorGetAlpha(color) ((float)((color & 0xFF000000)>>24)/(float)255) #define MyD3DRMColorGetRed(color) ((float)((color & 0x00FF0000)>>16)/(float)255) #define MyD3DRMColorGetGreen(color) ((float)((color & 0x0000FF00)>>8)/(float)255) #define MyD3DRMColorGetBlue(color) ((float)((color & 0x000000FF))/(float)255) HRESULT FrameToXFile(LPDIRECT3DRMFRAME3 pFrame, LPCSTR filename, D3DRMXOFFORMAT d3dFormat, D3DRMSAVEOPTIONS d3dSaveFlags) { Saver saver; saver.Init(filename, d3dFormat, d3dSaveFlags); saver.SaveHeaderObject(); saver.SaveFrame(pFrame); return S_OK; } Saver::Saver() { pXFile=NULL; pSave=NULL; } Saver::~Saver() { if (pSave) pSave->Release(); if (pXFile) pXFile->Release(); } HRESULT Saver::Init(LPCSTR filename, D3DRMXOFFORMAT d3dFormatArg, D3DRMSAVEOPTIONS d3dSaveFlagsArg) { HRESULT hr; d3dFormat = d3dFormatArg; d3dSaveFlags = d3dSaveFlagsArg; CREATEXFILE pCreateXFile=(CREATEXFILE)GetProcAddress( g_hInstD3DXOFDLL, "DirectXFileCreate" ); if (!pCreateXFile) return E_NOTIMPL; DXFILEFORMAT xFormat; if (d3dFormat == D3DRMXOF_BINARY) xFormat = DXFILEFORMAT_BINARY; else if (d3dFormat == D3DRMXOF_TEXT) xFormat = DXFILEFORMAT_TEXT; else xFormat = DXFILEFORMAT_COMPRESSED; //DirectXFileCreate(&pXFile); pCreateXFile(&pXFile); if (!pXFile) return E_FAIL; hr=pXFile->RegisterTemplates((LPVOID)D3DRM_XTEMPLATES, D3DRM_XTEMPLATE_BYTES); if FAILED(hr) { pXFile->Release(); pXFile=NULL; return hr; } hr=pXFile->CreateSaveObject(filename, xFormat, &pSave); if FAILED(hr) { pXFile->Release(); pXFile=NULL; pSave=NULL; return hr; } return S_OK; } HRESULT Saver::SaveHeaderObject() { LPDIRECTXFILEDATA pHeader=NULL; Header data; HRESULT hr; data.major = 1; data.minor = 0; data.flags = (d3dFormat == D3DRMXOF_TEXT)? 1 : 0; if (!pSave) return E_FAIL; hr=pSave->CreateDataObject(TID_DXFILEHeader, NULL, NULL, sizeof(Header), &data, &pHeader); if FAILED(hr) return hr; if (!pHeader) return hr; hr=pSave->SaveData(pHeader); pHeader->Release(); return hr; } HRESULT Saver::SaveFrame(LPDIRECT3DRMFRAME3 pFrame, LPDIRECT3DRMFRAME3 pRefFrame, LPDIRECTXFILEDATA pRefFrameObj) { DWORD i; HRESULT hr; LPDIRECTXFILEDATA pFrameObj=NULL; if (!pSave) return E_FAIL; if (!pFrame) return E_FAIL; hr=pSave->CreateDataObject(TID_D3DRMFrame, NULL, NULL, 0, NULL, &pFrameObj); if FAILED(hr) return hr; if (!pFrameObj) return E_FAIL; hr=SaveFrameTransform(pFrameObj, pFrame, pRefFrame); if FAILED(hr) { pFrameObj->Release(); return hr; } // Enumerate visuals. DWORD cVisuals=0; hr=pFrame->GetVisuals(&cVisuals, NULL); if FAILED(hr) { pFrameObj->Release(); return hr; } if (cVisuals) { LPUNKNOWN *ppUnk = new LPUNKNOWN[cVisuals]; hr=pFrame->GetVisuals(&cVisuals, ppUnk); if SUCCEEDED(hr) { for (i = 0; i < cVisuals; i++) { LPDIRECT3DRMFRAME3 pChildFrame; if (ppUnk[i]) { hr = ppUnk[i]->QueryInterface(IID_IDirect3DRMFrame3, (LPVOID *)&pChildFrame); if (SUCCEEDED(hr)) { SaveFrame(pChildFrame, pFrame, pFrameObj); pChildFrame->Release(); } else { LPDIRECT3DRMMESHBUILDER3 pMeshBuilder; hr = ppUnk[i]->QueryInterface(IID_IDirect3DRMMeshBuilder3, (LPVOID *)&pMeshBuilder); if (SUCCEEDED(hr)) { SaveMeshBuilder(pFrameObj, pMeshBuilder); pMeshBuilder->Release(); } } ppUnk[i]->Release(); } } delete[] ppUnk; } } //cVisuals // Enumerate child frames. LPDIRECT3DRMFRAMEARRAY pFrameArray=NULL; hr=pFrame->GetChildren(&pFrameArray); if SUCCEEDED(hr) { for (i = 0; i < pFrameArray->GetSize(); i++) { LPDIRECT3DRMFRAME pTmpFrame; LPDIRECT3DRMFRAME3 pChildFrame; pFrameArray->GetElement(i, &pTmpFrame); pTmpFrame->QueryInterface(IID_IDirect3DRMFrame3, (LPVOID *)&pChildFrame); pTmpFrame->Release(); SaveFrame(pChildFrame, pFrame, pFrameObj); pChildFrame->Release(); } pFrameArray->Release(); // Add frame object to the saved list. if (pRefFrameObj) pRefFrameObj->AddDataObject(pFrameObj); else pSave->SaveData(pFrameObj); pFrameObj->Release(); } return hr; } HRESULT Saver::SaveFrameTransform(LPDIRECTXFILEDATA pFrameObj, LPDIRECT3DRMFRAME3 pFrame, LPDIRECT3DRMFRAME3 pRefFrame) { LPDIRECTXFILEDATA pFrameTransformObj=NULL; D3DRMMATRIX4D rmMatrix; HRESULT hr; if (!pFrame) return E_INVALIDARG; pFrame->GetTransform(pRefFrame, rmMatrix); hr=pSave->CreateDataObject(TID_D3DRMFrameTransformMatrix, NULL, NULL, sizeof(D3DRMMATRIX4D), rmMatrix, &pFrameTransformObj); if FAILED(hr) return hr; hr=pFrameObj->AddDataObject(pFrameTransformObj); pFrameTransformObj->Release(); return hr; } HRESULT Saver::SaveMeshBuilder(LPDIRECTXFILEDATA pFrameObj, LPDIRECT3DRMMESHBUILDER3 pMeshBuilder) { LPDIRECTXFILEDATA pMeshObj; DWORD cVertices, cNormals, cFaces, dwFaceData, *pdwFaceData; LPDIRECT3DRMFACEARRAY pFaceArray = NULL; HRESULT hr; if (!pMeshBuilder) return E_INVALIDARG; //pFrameObj can be null hr=pMeshBuilder->GetGeometry(&cVertices, NULL, &cNormals, NULL, &dwFaceData, NULL); if FAILED(hr) return hr; cFaces = pMeshBuilder->GetFaceCount(); if (!cVertices || !cNormals || !dwFaceData || !cFaces) return S_OK; pdwFaceData = new DWORD[dwFaceData]; if FAILED(pdwFaceData) return E_OUTOFMEMORY; hr=pMeshBuilder->GetGeometry(NULL, NULL, NULL, NULL, &dwFaceData, pdwFaceData); if FAILED(hr) return hr; hr=CreateMeshObject(cVertices, cFaces, dwFaceData, pdwFaceData, pMeshBuilder, &pMeshObj); if FAILED(hr) return hr; D3DRMCOLORSOURCE clrSrc = pMeshBuilder->GetColorSource(); if (clrSrc == D3DRMCOLOR_FROMVERTEX) { CreateVertexColorsObject(pMeshObj, cVertices, pMeshBuilder); } if (d3dSaveFlags & D3DRMXOFSAVE_MATERIALS) { if (!pFaceArray) pMeshBuilder->GetFaces(&pFaceArray); CreateMaterialListObject(pMeshObj, pFaceArray); } if (d3dSaveFlags & D3DRMXOFSAVE_NORMALS) { CreateNormalsObject(pMeshObj, cNormals, cFaces, dwFaceData, pdwFaceData, pMeshBuilder); } if (d3dSaveFlags & D3DRMXOFSAVE_TEXTURETOPOLOGY) { if (!pFaceArray) pMeshBuilder->GetFaces(&pFaceArray); CreateTextureWrapsObject(pMeshObj, pFaceArray); } if (d3dSaveFlags & D3DRMXOFSAVE_TEXTURECOORDINATES) { CreateTextureCoordsObject(pMeshObj, cVertices, pMeshBuilder); } if (pFrameObj) pFrameObj->AddDataObject(pMeshObj); else pSave->SaveData(pMeshObj); pMeshObj->Release(); delete[] pdwFaceData; if (pFaceArray) pFaceArray->Release(); return S_OK; } HRESULT Saver::CreateMeshObject(DWORD cVertices, DWORD cFaces, DWORD dwFaceData, LPDWORD pdwFaceData, LPDIRECT3DRMMESHBUILDER3 pMeshBuilder, LPDIRECTXFILEDATA *ppMeshObj) { // mesh data is vertex_count + vertices + face_count + face_vertex_data; HRESULT hr; if (!pMeshBuilder) return E_INVALIDARG; if (!pSave) return E_INVALIDARG; DWORD cbSize, *data; cbSize = cVertices * sizeof(D3DVECTOR) + (1 + (dwFaceData + cFaces + 1)/2) * sizeof(DWORD); data = (LPDWORD) new BYTE[cbSize]; if (!data) return E_OUTOFMEMORY; data[0] = cVertices; LPD3DVECTOR pVertices = (LPD3DVECTOR)&data[1]; pMeshBuilder->GetGeometry(&cVertices, pVertices, NULL, NULL, NULL, NULL); LPDWORD pdwTmp = (LPDWORD)&pVertices[cVertices]; *pdwTmp++ = cFaces; while (*pdwFaceData) { DWORD cFaceVertices = *pdwFaceData++; *pdwTmp++ = cFaceVertices; for (DWORD i = 0; i < cFaceVertices; i++) { *pdwTmp++ = *pdwFaceData++; pdwFaceData++; // skip normal index. } } DWORD dwSize; pMeshBuilder->GetName(&dwSize, NULL); LPSTR szName = NULL; if (dwSize) { szName = new char[dwSize]; pMeshBuilder->GetName(&dwSize, szName); } hr=pSave->CreateDataObject(TID_D3DRMMesh, szName, NULL, cbSize, data, ppMeshObj); if (szName) lNames.Add(szName); delete[] data; return S_OK; } HRESULT Saver::CreateNormalsObject(LPDIRECTXFILEDATA pMeshObj, DWORD cNormals, DWORD cFaces, DWORD dwFaceData, LPDWORD pdwFaceData, LPDIRECT3DRMMESHBUILDER3 pMeshBuilder) { // normals data is normal_count + normals + face_count + face_normal_data; HRESULT hr; if (!pMeshObj) return E_INVALIDARG; DWORD cbSize, *data; cbSize = cNormals * sizeof(D3DVECTOR) + (1 + (dwFaceData + cFaces + 1)/2) * sizeof(DWORD); data = (LPDWORD) new BYTE[cbSize]; if (!data) return E_OUTOFMEMORY; data[0] = cNormals; LPD3DVECTOR pNormals = (LPD3DVECTOR)&data[1]; hr=pMeshBuilder->GetGeometry(NULL, NULL, &cNormals, pNormals, NULL, NULL); if FAILED(hr) return hr; LPDWORD pdwTmp = (LPDWORD)&pNormals[cNormals]; *pdwTmp++ = cFaces; while (*pdwFaceData) { DWORD cFaceVertices = *pdwFaceData++; *pdwTmp++ = cFaceVertices; for (DWORD i = 0; i < cFaceVertices; i++) { pdwFaceData++; // skip vertex index. *pdwTmp++ = *pdwFaceData++; } } LPDIRECTXFILEDATA pNormalsObj=NULL; hr=pSave->CreateDataObject(TID_D3DRMMeshNormals, NULL, NULL, cbSize, data, &pNormalsObj); if FAILED(hr) return hr; pMeshObj->AddDataObject(pNormalsObj); pNormalsObj->Release(); delete[] data; return S_OK; } HRESULT Saver::CreateVertexColorsObject(LPDIRECTXFILEDATA pMeshObj, DWORD cVertices, LPDIRECT3DRMMESHBUILDER3 pMeshBuilder) { DWORD cbSize; VertexColors *data; HRESULT hr; if (!pSave) return E_INVALIDARG; if (!pMeshBuilder) return E_INVALIDARG; cbSize = sizeof(DWORD) + cVertices * sizeof(IndexedColor); data = (VertexColors *) new BYTE[cbSize]; if (!data) return E_OUTOFMEMORY; data->cVertices = cVertices; for (DWORD i = 0; i < cVertices; i++) { D3DCOLOR color = pMeshBuilder->GetVertexColor(i); data->vertexColors[i].index = i; data->vertexColors[i].color.r = MyD3DRMColorGetRed(color); data->vertexColors[i].color.g = MyD3DRMColorGetGreen(color); data->vertexColors[i].color.b = MyD3DRMColorGetBlue(color); data->vertexColors[i].color.a = MyD3DRMColorGetAlpha(color); } LPDIRECTXFILEDATA pVertexColorsObj=NULL; hr=pSave->CreateDataObject(TID_D3DRMMeshVertexColors, NULL, NULL, cbSize, data, &pVertexColorsObj); if FAILED(hr) { delete[] data; return hr; } pMeshObj->AddDataObject(pVertexColorsObj); pVertexColorsObj->Release(); delete[] data; return S_OK; } HRESULT Saver::CreateMaterialListObject(LPDIRECTXFILEDATA pMeshObj, LPDIRECT3DRMFACEARRAY pFaceArray) { DWORD cbSize, cFaces; FaceMaterials *data; FaceMaterialList lMat; cFaces = pFaceArray->GetSize(); cbSize = (2 + cFaces) * sizeof(DWORD); data = (FaceMaterials *) new BYTE[cbSize]; if (!data) return E_OUTOFMEMORY; data->cFaceIndexes = cFaces; LPDWORD pdwIndex = data->faceIndexes; for (DWORD i = 0; i < cFaces; i++, pdwIndex++) { LPDIRECT3DRMFACE pFace; pFaceArray->GetElement(i, &pFace); D3DCOLOR faceColor; LPDIRECT3DRMMATERIAL pMaterial; LPDIRECT3DRMTEXTURE pTexture; faceColor = pFace->GetColor(); pFace->GetMaterial(&pMaterial); pFace->GetTexture(&pTexture); *pdwIndex = lMat.Find(faceColor, pMaterial, pTexture); pMaterial->Release(); if (pTexture) pTexture->Release(); pFace->Release(); } data->cMaterials = lMat.Count(); if (data->cMaterials == 1) { data->cFaceIndexes = 1; data->faceIndexes[0] = 0; cbSize = 3 * sizeof(DWORD); } LPDIRECTXFILEDATA pMatListObj; pSave->CreateDataObject(TID_D3DRMMeshMaterialList, NULL, NULL, cbSize, data, &pMatListObj); FaceMaterial *pMat; for (pMat = lMat.First(); pMat; pMat = pMat->pNext) { CreateMaterialObject(pMatListObj, pMat); } pMeshObj->AddDataObject(pMatListObj); pMatListObj->Release(); delete[] data; return S_OK; } HRESULT Saver::CreateMaterialObject(LPDIRECTXFILEDATA pMatListObj, FaceMaterial *pMat) { BaseMaterial data; data.faceColor.r = MyD3DRMColorGetRed(pMat->faceColor); data.faceColor.g = MyD3DRMColorGetGreen(pMat->faceColor); data.faceColor.b = MyD3DRMColorGetBlue(pMat->faceColor); data.faceColor.a = MyD3DRMColorGetAlpha(pMat->faceColor); data.power = pMat->pMaterial->GetPower(); pMat->pMaterial->GetSpecular(&data.specularColor.r, &data.specularColor.g, &data.specularColor.b); pMat->pMaterial->GetEmissive(&data.emissiveColor.r, &data.emissiveColor.g, &data.emissiveColor.b); LPDIRECTXFILEDATA pMaterialObj; pSave->CreateDataObject(TID_D3DRMMaterial, NULL, NULL, sizeof(BaseMaterial), &data, &pMaterialObj); if (pMat->pTexture) { IDirectXFileData *pTextureObj; DWORD dwSize; pMat->pTexture->GetName(&dwSize, NULL); if (dwSize) { LPSTR szName = new char[dwSize]; pMat->pTexture->GetName(&dwSize, szName); pSave->CreateDataObject(TID_D3DRMTextureFilename, NULL, NULL, sizeof(LPSTR), &szName, &pTextureObj); pMaterialObj->AddDataObject(pTextureObj); pTextureObj->Release(); lNames.Add(szName); } } pMatListObj->AddDataObject(pMaterialObj); pMaterialObj->Release(); return S_OK; } HRESULT Saver::CreateTextureWrapsObject(LPDIRECTXFILEDATA pMeshObj, LPDIRECT3DRMFACEARRAY pFaceArray) { DWORD cbSize, cFaces; FaceWraps *data; cFaces = pFaceArray->GetSize(); cbSize = sizeof(DWORD) + cFaces * sizeof(Boolean2d); data = (FaceWraps *) new BYTE[cbSize]; if (!data) return E_OUTOFMEMORY; data->cFaces = cFaces; Boolean2d *pWrap = data->faceWraps; for (DWORD i = 0; i < cFaces; i++, pWrap++) { LPDIRECT3DRMFACE pFace; pFaceArray->GetElement(i, &pFace); pFace->GetTextureTopology(&pWrap->u, &pWrap->v); pFace->Release(); } LPDIRECTXFILEDATA pTextureWrapsObj; pSave->CreateDataObject(TID_D3DRMMeshFaceWraps, NULL, NULL, cbSize, data, &pTextureWrapsObj); pMeshObj->AddDataObject(pTextureWrapsObj); pTextureWrapsObj->Release(); delete[] data; return S_OK; } HRESULT Saver::CreateTextureCoordsObject(LPDIRECTXFILEDATA pMeshObj, DWORD cVertices, LPDIRECT3DRMMESHBUILDER3 pMeshBuilder) { DWORD cbSize; TextureCoords *data; cbSize = sizeof(DWORD) + cVertices * sizeof(Coords2d); data = (TextureCoords *) new BYTE[cbSize]; if (!data) return E_OUTOFMEMORY; data->cVertices = cVertices; Coords2d *pCoords = data->textureCoords; for (DWORD i = 0; i < cVertices; i++, pCoords++) { pMeshBuilder->GetTextureCoordinates(i, &pCoords->u, &pCoords->v); } LPDIRECTXFILEDATA pTexCoordsObj; pSave->CreateDataObject(TID_D3DRMMeshTextureCoords, NULL, NULL, cbSize, data, &pTexCoordsObj); pMeshObj->AddDataObject(pTexCoordsObj); pTexCoordsObj->Release(); delete[] data; return S_OK; } FaceMaterialList::FaceMaterialList() : cElements(0), pFirst(NULL) { } FaceMaterialList::~FaceMaterialList() { FaceMaterial *pMat = pFirst; while (pMat) { FaceMaterial *pNext = pMat->pNext; pMat->pMaterial->Release(); if (pMat->pTexture) pMat->pTexture->Release(); delete pMat; pMat = pNext; } } DWORD FaceMaterialList::Find(D3DCOLOR faceColor, LPDIRECT3DRMMATERIAL pMaterial, LPDIRECT3DRMTEXTURE pTexture) { FaceMaterial *pTmp = pFirst; FaceMaterial **ppNew = &pFirst; for (DWORD i = 0; pTmp; i++, pTmp = pTmp->pNext) { if (pTmp->faceColor == faceColor && pTmp->pMaterial == pMaterial && pTmp->pTexture == pTexture) return i; if (!pTmp->pNext) ppNew = &pTmp->pNext; } FaceMaterial *pNew = new FaceMaterial; if (!pNew) return 0; pNew->faceColor = faceColor; pNew->pMaterial = pMaterial; pNew->pTexture = pTexture; pNew->pNext = NULL; pMaterial->AddRef(); if (pTexture) pTexture->AddRef(); *ppNew = pNew; cElements++; return i; } NameList::NameList() : pFirst(NULL), ppLast(NULL) { } NameList::~NameList() { NameEntry *pEntry = pFirst; while (pEntry) { NameEntry *pNext = pEntry->pNext; delete[] pEntry->pName; delete pEntry; pEntry = pNext; } } void NameList::Add(LPSTR pName) { NameEntry *pNew = new NameEntry; if (!pNew) return; pNew->pName = pName; pNew->pNext = NULL; if (ppLast) *ppLast = pNew; else pFirst = pNew; ppLast = &pNew->pNext; }