mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
631 lines
17 KiB
631 lines
17 KiB
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
#include "cpmesh.h"
|
|
#include "pmerrors.h"
|
|
#include "fileio.h"
|
|
|
|
|
|
float (* vdata)[3];
|
|
|
|
static GLuint LoadTexture (char* file)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
|
|
const short PM_MAX_TEX_STRING_LEN = 1024; // Enforced by the spec.
|
|
|
|
/*
|
|
* This function currently only works on external files, not on URLs.
|
|
* It can only load .pmx files and not PM records embedded in X files.
|
|
* Hence the "pmname" argument is ignored.
|
|
* It only supports synchronous loads so pPMeshLoadCB is ignored
|
|
* !!Currently no memory cleanup occurs on error. Must add code to do so.
|
|
* Could use a local win32 heap!!
|
|
* See \\anujg\docs\"Progressive Mesh file format.doc" for details on the
|
|
* file format
|
|
*/
|
|
|
|
|
|
/*
|
|
* The concept of Materials:
|
|
* 1) Materials can be "looked up", i.e. textures
|
|
* 2) Computed using a API specific lighting equation. (pure mat)
|
|
* 3) Both of above combined. (Modulated/Lit textures)
|
|
*/
|
|
|
|
STDMETHODIMP CPMeshGL::Load(const TCHAR* const url,
|
|
const TCHAR* const pmname,
|
|
DWORD* const minvert,
|
|
DWORD* const maxvert,
|
|
LPPMESHLOADCB pPMeshLoadCB)
|
|
{
|
|
DWORD i, k;
|
|
WORD j, ftCurveSize, fmCurveSize;
|
|
DWORD vAttr, wAttr, fAttr, mAttr, sAttr;
|
|
DWORD mOffset, vOffset, wOffset, fOffset;
|
|
DWORD& maxVert = *maxvert;
|
|
DWORD& minVert = *minvert;
|
|
HRESULT hr;
|
|
DWORD vsplit_offset, bmesh_offset;
|
|
|
|
// Estimated number of faces and wedges in the mesh with maxvert vertices
|
|
DWORD nFacePredict=0, nWedgePredict=0;
|
|
|
|
// A curve is approximated by an array of pairs {(x,y), (x,y),...}
|
|
typedef struct crvpnt{
|
|
DWORD x;
|
|
float y;
|
|
} *CURVE;
|
|
CURVE *ftcurves, *fmcurves; // An array of curves
|
|
|
|
ifstream is(url);
|
|
if (!is)
|
|
return PM_E_FOPENERROR;
|
|
is.setmode(filebuf::binary);
|
|
|
|
#ifdef __DUMP_DATA
|
|
ofstream dump("dump.pmx");
|
|
if (!dump)
|
|
return PM_E_FOPENERROR;
|
|
dump.setmode(filebuf::text);
|
|
#endif //__DUMP_DATA
|
|
|
|
/*
|
|
* Read PMesh Header
|
|
*/
|
|
read_DWORD(is, m_maxVertices);
|
|
#ifdef __MAT_PREALLOC_OPTIMIZATION
|
|
maxVert = min(maxVert, m_maxVertices);
|
|
#else
|
|
maxVert = m_maxVertices;
|
|
#endif //__MAT_PREALLOC_OPTIMIZATION
|
|
*maxvert = maxVert;
|
|
|
|
read_DWORD(is, m_maxWedges);
|
|
read_DWORD(is, m_maxFaces);
|
|
read_DWORD(is, m_maxMaterials);
|
|
read_DWORD(is, m_maxTextures);
|
|
|
|
#ifdef __DUMP_DATA
|
|
dump << "\nMaxVert = " << m_maxVertices;
|
|
dump << "\nMaxWedges = " << m_maxWedges;
|
|
dump << "\nMaxFaces = " << m_maxFaces;
|
|
dump << "\nMaxMat = " << m_maxMaterials;
|
|
dump << "\nMaxTex = " << m_maxTextures;
|
|
#endif //__DUMP_DATA
|
|
|
|
/*
|
|
* Max Valence
|
|
*/
|
|
read_DWORD(is, i);
|
|
if (i > 65535)
|
|
return PM_E_BADVALENCE;
|
|
#ifdef __DUMP_DATA
|
|
dump << "\nMaxValence = " << i;
|
|
#endif //__DUMP_DATA
|
|
|
|
/*
|
|
* Normal Encoding
|
|
*/
|
|
read_WORD(is, j);
|
|
if (((j & NORM_MASK) != NORM_EXPLICIT) || ((j & TEX_MASK) != TEX_EXPLICIT))
|
|
return PM_E_BADWEDGEDATA;
|
|
#ifdef __DUMP_DATA
|
|
dump << "\nNormal Encoding = " << j;
|
|
#endif //__DUMP_DATA
|
|
|
|
/*
|
|
* Integer Encoding
|
|
*/
|
|
read_WORD(is, j); // integer encoding type
|
|
if (j != INTC_MAX)
|
|
return PM_E_BADINTCODE;
|
|
#ifdef __DUMP_DATA
|
|
dump << "\nInteger Encoding = " << j;
|
|
#endif //__DUMP_DATA
|
|
|
|
/*
|
|
* Sizes of various user defined attributes
|
|
*/
|
|
read_DWORD(is, vAttr); // Vertex attributes
|
|
read_DWORD(is, wAttr); // Wedge attributes
|
|
read_DWORD(is, fAttr); // Face attributes
|
|
read_DWORD(is, mAttr); // Material attributes
|
|
read_DWORD(is, sAttr); // VSplit attributes
|
|
#ifdef __DUMP_DATA
|
|
dump << "\n\nUser defined attribute sizes:";
|
|
dump << "\nVertex: " << vAttr;
|
|
dump << "\nWedge: " << wAttr;
|
|
dump << "\nFace: " << fAttr;
|
|
dump << "\nMaterial: " << mAttr;
|
|
dump << "\nVSplit: " << sAttr;
|
|
#endif //__DUMP_DATA
|
|
|
|
/*
|
|
* Allocate material and texture related tables
|
|
*/
|
|
WORD *matcnt = new WORD [m_maxMaterials];
|
|
#ifdef __MATPOS_IS_A_PTR
|
|
GLface **matpos = new GLface* [m_maxMaterials];
|
|
#else
|
|
WORD *matpos = new WORD [m_maxMaterials];
|
|
#endif
|
|
GLmaterial *matArray = new GLmaterial [m_maxMaterials];
|
|
if (!matArray || !matcnt || !matpos)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
else
|
|
{
|
|
m_matArray = matArray;
|
|
m_matcnt = matcnt;
|
|
m_matpos = matpos;
|
|
}
|
|
|
|
#ifdef __MATPOS_IS_A_PTR
|
|
/*
|
|
* Allocate the vertex and normal arrays.
|
|
*/
|
|
|
|
GLvertex *varray = new GLvertex [m_maxWedges];
|
|
GLnormal *narray = new GLnormal [m_maxWedges];
|
|
GLtexCoord *tarray = new GLtexCoord [m_maxWedges];
|
|
WORD *wedgelist = new WORD [m_maxWedges];
|
|
WORD (*fnei)[3] = new WORD [m_maxFaces][3];
|
|
GLface *farray = new GLface [m_maxFaces];
|
|
|
|
if (!farray || !varray || !narray || !tarray || !wedgelist || !fnei)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
else
|
|
{
|
|
m_varray = varray;
|
|
m_narray = narray;
|
|
m_tarray = tarray;
|
|
m_farray = farray;
|
|
m_wedgelist = wedgelist;
|
|
m_fnei = fnei;
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
* Read face-texture curve
|
|
*/
|
|
read_WORD(is, ftCurveSize); // Size of face-texture curve
|
|
#ifdef __DUMP_DATA
|
|
dump << "\n\nFace-texture curve:";
|
|
dump << "\nFT-curve size: " << ftCurveSize;
|
|
#endif //__DUMP_DATA
|
|
ftcurves = new CURVE[m_maxTextures]; // A curve for each texture
|
|
DWORD* ftmax = new DWORD[m_maxTextures];
|
|
if (!ftcurves || !ftmax)
|
|
return E_OUTOFMEMORY;
|
|
for (k=0; k<m_maxTextures; ++k)
|
|
{
|
|
ftcurves[k] = new crvpnt[ftCurveSize];
|
|
if (!ftcurves[k])
|
|
return E_OUTOFMEMORY;
|
|
|
|
read_DWORD(is,ftmax[k]); // Total faces of tex k in fully detailed
|
|
// mesh
|
|
#ifdef __DUMP_DATA
|
|
dump << "\n\nTotal faces of tex " << k << " in fully detailed mesh: ";
|
|
dump << ftmax[k];
|
|
#endif //__DUMP_DATA
|
|
for (i=0; i<ftCurveSize; ++i)
|
|
{
|
|
|
|
read_DWORD(is, ftcurves[k][i].x); // vertex(i) of ftcurve of
|
|
// texture k.
|
|
read_float(is, ftcurves[k][i].y); // faces of tex k when total
|
|
// vert in mesh = vertex(i).
|
|
#ifdef __DUMP_DATA
|
|
dump << "\n (" << ftcurves[k][i].x << ", " << ftcurves[k][i].y << ")";
|
|
#endif //__DUMP_DATA
|
|
}
|
|
}
|
|
|
|
#ifdef __TEX_PREALLOC_OPTIMIZATION
|
|
for (k=0; k<m_maxTextures; ++k)
|
|
{
|
|
for (i=0; i<ftCurveSize; ++i)
|
|
{
|
|
if (ftcurves[k][i].x == maxVert)
|
|
{
|
|
m_texcnt[k] = WORD(ftcurves[k][i].y + 0.5);
|
|
m_texcnt[k] = WORD(min(m_texcnt[k], ftmax[k]));
|
|
break;
|
|
}
|
|
else if (ftcurves[k][i].x > maxVert)
|
|
{
|
|
m_texcnt[k] = WORD(ftcurves[k][i-1].y +
|
|
(maxVert - ftcurves[k][i-1].x) *
|
|
(ftcurves[k][i].y - ftcurves[k][i-1].y) /
|
|
(ftcurves[k][i].x - ftcurves[k][i-1].x));
|
|
m_texcnt[k] = WORD(min(m_texcnt[k], ftmax[k]));
|
|
break;
|
|
}
|
|
}
|
|
nFacePredict += m_texcnt[k];
|
|
delete [] ftcurves[k];
|
|
}
|
|
delete [] ftcurves;
|
|
delete [] ftmax;
|
|
|
|
/*
|
|
* Convert m_texcnt to array of offsets into the prim buf where faces of
|
|
* that texture need to be stored.
|
|
*/
|
|
m_texpos[0] = 0;
|
|
for (i=1; i<m_maxTextures; ++i)
|
|
m_texpos[i] = WORD(m_texpos[i-1] + m_texcnt[i-1] +
|
|
TEXTUREGAP/sizeof(D3DTRIANGLE));
|
|
#else
|
|
delete [] ftcurves;
|
|
delete [] ftmax;
|
|
#endif __TEX_PREALLOC_OPTIMIZATION
|
|
|
|
/*
|
|
* Read face-material curve
|
|
*/
|
|
|
|
read_WORD(is,fmCurveSize); // Size of face-material curve
|
|
#ifdef __DUMP_DATA
|
|
dump << "\n\nFace-material curve:";
|
|
dump << "\nFM-curve size: " << fmCurveSize;
|
|
#endif //__DUMP_DATA
|
|
fmcurves = new CURVE[m_maxMaterials];
|
|
DWORD* fmmax = new DWORD[m_maxMaterials];
|
|
if (!fmcurves || !fmmax)
|
|
return E_OUTOFMEMORY;
|
|
|
|
for (k=0; k<m_maxMaterials; ++k)
|
|
{
|
|
fmcurves[k] = new crvpnt [fmCurveSize];
|
|
if (!fmcurves[k])
|
|
return E_OUTOFMEMORY;
|
|
|
|
read_DWORD(is,fmmax[k]); // Total faces of material k in fully
|
|
// detailed mesh
|
|
#ifdef __DUMP_DATA
|
|
dump << "\n\nTotal faces of mat " << k << " in fully detailed mesh: ";
|
|
dump << fmmax[k];
|
|
#endif //__DUMP_DATA
|
|
for (i=0; i<fmCurveSize; ++i)
|
|
{
|
|
read_DWORD(is,fmcurves[k][i].x); // vertex(i) of fmcurve of
|
|
// material k
|
|
read_float(is,fmcurves[k][i].y); // faces of mat k when total
|
|
// vert in mesh = vertex(i)
|
|
#ifdef __DUMP_DATA
|
|
dump << "\n (" << fmcurves[k][i].x << ", " << fmcurves[k][i].y << ")";
|
|
#endif //__DUMP_DATA
|
|
}
|
|
}
|
|
|
|
#ifdef __MAT_PREALLOC_OPTIMIZATION
|
|
for (k=0; k<m_maxMaterials; ++k)
|
|
{
|
|
for (i=0; i<fmCurveSize; ++i)
|
|
{
|
|
if (fmcurves[k][i].x == maxVert)
|
|
{
|
|
matcnt[k] = WORD(fmcurves[k][i].y + 0.5);
|
|
matcnt[k] = WORD(min(matcnt[k], fmmax[k]));
|
|
break;
|
|
}
|
|
else if (fmcurves[k][i].x > maxVert)
|
|
{
|
|
matcnt[k] = WORD(fmcurves[k][i-1].y + (maxVert -
|
|
fmcurves[k][i-1].x) *
|
|
(fmcurves[k][i].y - fmcurves[k][i-1].y) /
|
|
(fmcurves[k][i].x - fmcurves[k][i-1].x));
|
|
matcnt[k] = WORD(min(matcnt[k], fmmax[k]));
|
|
break;
|
|
}
|
|
}
|
|
nFacePredict += matcnt[k];
|
|
delete [] fmcurves[k];
|
|
}
|
|
delete [] fmcurves;
|
|
delete [] fmmax;
|
|
|
|
#else //__MAT_PREALLOC_OPTIMIZATION
|
|
/*
|
|
* Convert m_matcnt to array of offsets into the face buf where faces of
|
|
* that material need to be stored.
|
|
*/
|
|
#ifdef __MATPOS_IS_A_PTR
|
|
matpos[0] = farray;
|
|
int cnt = 0;
|
|
for (i=1; i<m_maxMaterials; ++i)
|
|
{
|
|
matpos[i] = &(farray[cnt + fmmax[i-1]]);
|
|
cnt += fmmax[i-1];
|
|
}
|
|
#else
|
|
matpos[0] = 0;
|
|
for (i=1; i<m_maxMaterials; ++i)
|
|
{
|
|
matpos[i] = matpos[i-1] + fmmax[i-1];
|
|
}
|
|
#endif
|
|
|
|
delete [] fmcurves;
|
|
delete [] fmmax;
|
|
#endif //__MAT_PREALLOC_OPTIMIZATION
|
|
|
|
read_DWORD(is,vsplit_offset); // offset to vsplit array from end of
|
|
// the Base mesh
|
|
read_DWORD(is,bmesh_offset); // offset from here to start of base mesh
|
|
|
|
#ifdef __DUMP_DATA
|
|
dump << "\n\nVSplit offset from BaseMesh: " << vsplit_offset;
|
|
dump << "\n\nBaseMesh offset from here: " << bmesh_offset;
|
|
#endif //__DUMP_DATA
|
|
|
|
#ifndef __MATPOS_IS_A_PTR
|
|
/*
|
|
* Allocate the vertex and normal arrays.
|
|
*/
|
|
|
|
GLvertex *varray = new GLvertex [m_maxWedges];
|
|
GLnormal *narray = new GLnormal [m_maxWedges];
|
|
GLtexCoord *tarray = new GLtexCoord [m_maxWedges];
|
|
WORD *wedgelist = new WORD [m_maxWedges];
|
|
WORD (*fnei)[3] = new WORD [m_maxFaces][3];
|
|
GLface *farray = new GLface [m_maxFaces];
|
|
WORD *facemap = new WORD [m_maxFaces];
|
|
|
|
if (!farray || !varray || !narray || !tarray || !wedgelist || !fnei
|
|
|| !facemap)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
else
|
|
{
|
|
m_varray = varray;
|
|
m_narray = narray;
|
|
m_tarray = tarray;
|
|
m_farray = farray;
|
|
m_wedgelist = wedgelist;
|
|
m_fnei = fnei;
|
|
m_facemap = facemap;
|
|
}
|
|
#endif
|
|
/*
|
|
* Read Base Mesh Header
|
|
*/
|
|
|
|
if (bmesh_offset)
|
|
skip_bytes(is,bmesh_offset); // jump to start of base mesh.
|
|
|
|
read_DWORD(is,m_baseVertices);
|
|
#ifdef __MAT_PREALLOC_OPTIMIZATION
|
|
minVert = max(minVert, m_baseVertices);
|
|
#else
|
|
minVert = m_baseVertices;
|
|
#endif //__MAT_PREALLOC_OPTIMIZATION
|
|
*minvert = minVert;
|
|
m_numVerts = m_baseVertices;
|
|
|
|
read_DWORD(is,m_baseWedges);
|
|
m_numWedges = m_baseWedges;
|
|
|
|
read_DWORD(is,m_baseFaces);
|
|
m_numFaces = m_baseFaces;
|
|
|
|
read_DWORD(is,i); // max materials
|
|
if (i != m_maxMaterials)
|
|
return PM_E_MATCNT_MISMATCH;
|
|
else
|
|
m_numMaterials = i;
|
|
|
|
read_DWORD(is,mOffset); // Offset to mat array
|
|
read_DWORD(is,vOffset); // Offset to vertex array
|
|
read_DWORD(is,wOffset); // Offset to wedge array
|
|
read_DWORD(is,fOffset); // Offset to face array
|
|
|
|
#ifdef __DUMP_DATA
|
|
dump << "\n\n# of baseVerts: " << m_baseVertices;
|
|
dump << "\n# of baseWedges: " << m_baseWedges;
|
|
dump << "\n# of baseFaces: " << m_baseFaces;
|
|
|
|
dump << "\n\nOffset to MatArray: " << mOffset;
|
|
dump << "\nOffset to Vertex Array: " << vOffset;
|
|
dump << "\nOffset to Wedge Array: " << wOffset;
|
|
dump << "\nOffset to Face Array: " << fOffset;
|
|
#endif //__DUMP_DATA
|
|
|
|
/*
|
|
* Read Materials
|
|
*/
|
|
j = 0; // texture count
|
|
if (mOffset)
|
|
skip_bytes(is, mOffset);
|
|
|
|
for (i=0; i<m_maxMaterials; ++i)
|
|
{
|
|
char texname[PM_MAX_TEX_STRING_LEN];
|
|
|
|
matArray[i].ambient.r =
|
|
matArray[i].ambient.g =
|
|
matArray[i].ambient.b =
|
|
matArray[i].ambient.a = 0.0f;
|
|
|
|
matcnt[i] = (WORD) 0;
|
|
|
|
read_float(is, matArray[i].diffuse.r);
|
|
read_float(is, matArray[i].diffuse.g);
|
|
read_float(is, matArray[i].diffuse.b);
|
|
read_float(is, matArray[i].diffuse.a);
|
|
|
|
read_float(is, matArray[i].shininess);
|
|
|
|
read_float(is, matArray[i].specular.r);
|
|
read_float(is, matArray[i].specular.g);
|
|
read_float(is, matArray[i].specular.b);
|
|
read_float(is, matArray[i].specular.a);
|
|
|
|
read_float(is, matArray[i].emissive.r);
|
|
read_float(is, matArray[i].emissive.g);
|
|
read_float(is, matArray[i].emissive.b);
|
|
read_float(is, matArray[i].emissive.a);
|
|
|
|
is.getline(texname, 1024, '\0');
|
|
if (texname[0])
|
|
{
|
|
j++;
|
|
matArray[i].texObj = LoadTexture (texname);
|
|
}
|
|
else
|
|
{
|
|
matArray[i].texObj = 0;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Read base-mesh faces
|
|
*/
|
|
|
|
if (fOffset)
|
|
skip_bytes(is, fOffset);
|
|
|
|
for (i=0; i<m_baseFaces; ++i)
|
|
{
|
|
DWORD w;
|
|
WORD matid;
|
|
|
|
read_WORD(is, matid);
|
|
for (int j=0; j<3; ++j)
|
|
{
|
|
read_DWORD(is, w);
|
|
#ifdef __MATPOS_IS_A_PTR
|
|
(matpos[matid][matcnt[matid]]).w[j] = (WORD)w;
|
|
#else
|
|
(farray[matpos[matid] + matcnt[matid]]).w[j] = (WORD)w;
|
|
#endif
|
|
facemap[i] = matpos[matid] + matcnt[matid];
|
|
}
|
|
matcnt[matid]++;
|
|
}
|
|
|
|
/*
|
|
* Read base-mesh wedges
|
|
*/
|
|
if (wOffset)
|
|
skip_bytes(is, wOffset);
|
|
long* vidx_arr = new long[m_baseVertices];
|
|
if (!vidx_arr)
|
|
return E_OUTOFMEMORY;
|
|
memset(vidx_arr, -1, sizeof(long) * m_baseVertices);
|
|
|
|
for (i=0; i<m_baseWedges; ++i)
|
|
{
|
|
DWORD vidx;
|
|
read_DWORD(is, vidx);
|
|
#ifdef _DEBUG
|
|
if (vidx >= m_baseVertices)
|
|
return -1;
|
|
#endif
|
|
if (vidx_arr[vidx] < 0)
|
|
{
|
|
/*
|
|
* New vertex, create entry and initialize the wedge list
|
|
*/
|
|
|
|
vidx_arr[vidx] = i;
|
|
wedgelist[i] = WORD(i); // create circular list with one entry
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* Another wedge uses existing vertex, add new wedge to the
|
|
* existing wedge list.
|
|
*/
|
|
|
|
wedgelist[i] = wedgelist[vidx_arr[vidx]];
|
|
wedgelist[vidx_arr[vidx]] = WORD(i);
|
|
}
|
|
read_float(is, narray[i].x);
|
|
read_float(is, narray[i].y);
|
|
read_float(is, narray[i].z);
|
|
|
|
read_float(is, tarray[i].s);
|
|
read_float(is, tarray[i].t);
|
|
}
|
|
|
|
/*
|
|
* Read base-mesh vertices
|
|
*/
|
|
|
|
if (vOffset)
|
|
skip_bytes(is, vOffset);
|
|
for (i=0; i<m_baseVertices; ++i)
|
|
{
|
|
float x, y, z;
|
|
read_float(is, x);
|
|
read_float(is, y);
|
|
read_float(is, z);
|
|
|
|
/*
|
|
* Loop thru all wedges that share the vertex
|
|
* and fill in coordinates.
|
|
*/
|
|
WORD start = j = WORD(vidx_arr[i]);
|
|
do
|
|
{
|
|
varray[j].x = x;
|
|
varray[j].y = y;
|
|
varray[j].z = z;
|
|
}
|
|
while ((j=wedgelist[j]) != start);
|
|
}
|
|
delete [] vidx_arr;
|
|
|
|
|
|
#ifdef __DUMP_DATA
|
|
Print (dump);
|
|
#endif //__DUMP_DATA
|
|
|
|
/*
|
|
* Compute adjacency before we apply any vsplits
|
|
*/
|
|
ComputeAdjacency();
|
|
|
|
/*
|
|
* Read Vsplit records
|
|
*/
|
|
m_vsarr = new VsplitArray(maxVert - minVert);
|
|
for (i=0; i<maxVert-m_baseVertices; ++i)
|
|
{
|
|
/*
|
|
* Keep applying vsplits till base mesh is refined to have
|
|
* minVert vertices.
|
|
*/
|
|
|
|
if (i + m_baseVertices < minVert)
|
|
{
|
|
Vsplit vs;
|
|
vs.read(is);
|
|
apply_vsplit(vs);
|
|
// Update m_base* members
|
|
}
|
|
else // Read the rest in the Vsplit array
|
|
{
|
|
m_vsarr->elem(i + m_baseVertices - minVert).read(is);
|
|
}
|
|
}
|
|
|
|
#ifdef __DUMP_DATA
|
|
m_vsarr->write(dump);
|
|
#endif //__DUMP_DATA
|
|
m_currPos = 0;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|