windows-nt/Source/XPSP1/NT/multimedia/directx/dxvb/dx7vb/frmsave.cpp
2020-09-26 16:20:57 +08:00

797 lines
21 KiB
C++

//**************************************************************************
//
// 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 <d3drm.h>
#include <dxfile.h>
#include <rmxftmpl.h>
#include <rmxfguid.h>
#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;
}