You can download the demo here.
Please keep in mind this is basically a one-man production. I'm quite satisfied with how the final demo turned out, given the limited amount of time I had to work on it.
class ExportFile {
public:
FILE* f;
ExportFile(const char* filename) { f = fopen(filename, "wb"); }
~ExportFile() { fclose(f); }
inline void writeU32(uint32 value) { fwrite(&value, 1, sizeof(uint32), f); }
inline void write(void* data, size_t length) { fwrite(data, 1, length, f); }
// etc.
};
void writeArray(const char* filename, unsigned int count, size_t stride, void* data)
{
ExportFile f(filename);
f.writeU32(count);
f.write(data, count*stride);
}
Here's the export function:
void exportMesh(aiMesh* mesh)
{
std::string meshName = meshNodeNames[mesh];
// vertex arrays
writeArray((meshName + std::string(".vtx")).c_str(), mesh->mNumVertices,
sizeof(aiVector3D), mesh->mVertices);
writeArray((meshName + std::string(".nrm")).c_str(), mesh->mNumVertices,
sizeof(aiVector3D), mesh->mNormals);
if (mesh->mTangents) {
writeArray((meshName + std::string(".tan")).c_str(), mesh->mNumVertices,
sizeof(aiVector3D), mesh->mTangents);
}
// texcoords
char uvFilename[256];
int numUVs = 0;
for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; i++)
{
if (mesh->mTextureCoords[i]) {
numUVs++;
unsigned int numComps = mesh->mNumUVComponents[i];
aiVector3D* uvw_array = mesh->mTextureCoords[i];
float* tex = new float[numComps * mesh->mNumVertices];
for (unsigned int v=0; v < mesh->mNumVertices; v++) {
if (numComps >= 1) tex[v*numComps+0] = uvw_array[v].x;
if (numComps >= 2) tex[v*numComps+1] = uvw_array[v].y;
if (numComps >= 3) tex[v*numComps+2] = uvw_array[v].z;
}
sprintf(uvFilename, "%s.uv%d", meshName.c_str(), i);
writeArray(uvFilename, mesh->mNumVertices, sizeof(float)*numComps, tex);
delete[] tex;
}
}
// indices
size_t idxCount = mesh->mNumFaces*3;
assert(idxCount <= 65536);
uint16* indices = new uint16[idxCount];
for (unsigned int i=0; i < mesh->mNumFaces; i++) {
assert(mesh->mFaces[i].mNumIndices == 3);
indices[i*3+0] = mesh->mFaces[i].mIndices[0];
indices[i*3+1] = mesh->mFaces[i].mIndices[1];
indices[i*3+2] = mesh->mFaces[i].mIndices[2];
}
writeArray((meshName + std::string(".idx")).c_str(), idxCount, sizeof(uint16), indices);
delete[] indices;
}
#ifndef __ID3D10Blob_FWD_DEFINED__
#define __ID3D10Blob_FWD_DEFINED__
typedef interface ID3D10Blob ID3D10Blob;
#endif
#define D3DCOMPILER_DLL_A "d3dcompiler_43.dll"
typedef struct {
LPCSTR Name;
LPCSTR Definition;
} D3D_SHADER_MACRO;
DEFINE_GUID(IID_ID3D10Blob, 0x8ba5fb08, 0x5195, 0x40e2, 0xac, 0x58,
0xd, 0x98, 0x9c, 0x3a, 0x1, 0x2);
typedef struct ID3D10BlobVtbl {
BEGIN_INTERFACE
HRESULT ( STDMETHODCALLTYPE *QueryInterface )
(ID3D10Blob * This, REFIID riid, void **ppvObject);
ULONG ( STDMETHODCALLTYPE *AddRef )(ID3D10Blob * This);
ULONG ( STDMETHODCALLTYPE *Release )(ID3D10Blob * This);
LPVOID ( STDMETHODCALLTYPE *GetBufferPointer )(ID3D10Blob * This);
SIZE_T ( STDMETHODCALLTYPE *GetBufferSize )(ID3D10Blob * This);
END_INTERFACE
} ID3D10BlobVtbl;
#define ID3D10Blob_QueryInterface(This,riid,ppvObject) \
( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
#define ID3D10Blob_AddRef(This) \
( (This)->lpVtbl -> AddRef(This) )
#define ID3D10Blob_Release(This) \
( (This)->lpVtbl -> Release(This) )
#define ID3D10Blob_GetBufferPointer(This) \
( (This)->lpVtbl -> GetBufferPointer(This) )
#define ID3D10Blob_GetBufferSize(This) \
( (This)->lpVtbl -> GetBufferSize(This) )
interface ID3D10Blob
{
CONST_VTBL struct ID3D10BlobVtbl *lpVtbl;
};
typedef ID3D10Blob ID3DBlob;
typedef HRESULT (WINAPI *pD3DCompile)
(LPCVOID pSrcData,
SIZE_T SrcDataSize,
LPCSTR pFileName,
CONST D3D_SHADER_MACRO* pDefines,
void*/*ID3DInclude* */ pInclude,
LPCSTR pEntrypoint,
LPCSTR pTarget,
UINT Flags1,
UINT Flags2,
ID3DBlob** ppCode,
ID3DBlob** ppErrorMsgs);
Now we can load the D3DCompiler DLL, import the function via GetProcAddress and then compile our shader:
HINSTANCE hD3DCompiler = LoadLibraryA(D3DCOMPILER_DLL_A);
pD3DCompile D3DCompile = NULL;
if (hD3DCompiler) {
D3DCompile = (pD3DCompile) GetProcAddress(hD3DCompiler, "D3DCompile");
}
ID3DBlob* shaderBlob = NULL;
ID3DBlob* errorMsg = NULL;
D3DCompile(vsSource, strlen(vsSource), NULL, NULL, NULL, "main", "vs_2_0",
0, 0, &shaderBlob, &errorMsg);
if (errorMsg) {
char text[1024];
sprintf(text, "D3DCompile failed:\n%s",
(char*) ID3D10Blob_GetBufferPointer(errorMsg));
MessageBoxA(NULL, text, "Error", MB_OK|MB_ICONERROR|MB_TASKMODAL);
ID3D10Blob_Release(errorMsg);
exit(-1);
}
IDirect3DVertexShader9* shader = NULL;
if (shaderBlob) {
gD3DDevice->CreateVertexShader(
(DWORD *) ID3D10Blob_GetBufferPointer(shaderBlob),
&shader
);
ID3D10Blob_Release(shaderBlob);
}