1 #include <iostream>
2 #include <fstream>
3 #include <iomanip>
4 #include <algorithm>
5 #include <cstdio>
6 #include <cassert>
7 #include <cstring>
8 #include <d3dx9.h>
9 
10 using namespace std;
11 
12 static IDirect3D9* g_d3d = NULL;
13 static IDirect3DDevice9* g_d3dDev = NULL;
14 static HWND g_mainWindow = NULL;
15 
16 char* D3DErrorString(HRESULT);
17 void ShowD3DErrorMessage(char* info, HRESULT hr);
18 
19 
20 struct VertexAttribute
21 {
22     enum {
23         Position = 0,
24         Color0   = 1,
25         Color1   = 2,
26         Normal   = 3,
27         Tangent  = 4,
28         Texture0 = 5,
29         Texture1 = 6,
30         Texture2 = 7,
31         Texture3 = 8,
32         MaxAttribute = 9,
33         InvalidAttribute  = -1,
34     };
35 
36     enum Format
37     {
38         Float1 = 0,
39         Float2 = 1,
40         Float3 = 2,
41         Float4 = 3,
42         UByte4 = 4,
43         InvalidFormat = -1,
44     };
45 
46     unsigned int offset;
47     Format format;
48 };
49 
50 char* AttribFormatNames[] =
51 { "f1", "f2", "f3", "f4", "ub4" };
52 
53 char* AttribNames[] = {
54     "position",
55     "color0",
56     "color1",
57     "normal",
58     "tangent",
59     "texcoord0",
60     "texcoord1",
61     "texcoord2",
62     "texcoord3"
63 };
64 
65 
operator ==(const D3DCOLORVALUE & c0,const D3DCOLORVALUE & c1)66 bool operator==(const D3DCOLORVALUE& c0, const D3DCOLORVALUE& c1)
67 {
68     return (c0.r == c1.r && c0.g == c1.g && c0.b == c1.b && c0.a == c1.a);
69 }
70 
71 
operator <(const D3DCOLORVALUE & c0,const D3DCOLORVALUE & c1)72 bool operator<(const D3DCOLORVALUE& c0, const D3DCOLORVALUE& c1)
73 {
74     if (c0.r == c1.r)
75     {
76         if (c0.g == c1.g)
77         {
78             if (c0.b == c1.b)
79                 return c0.a < c1.a;
80             else
81                 return c0.b < c1.b;
82         }
83         else
84         {
85             return c0.g < c1.g;
86         }
87     }
88     else
89     {
90         return c0.r < c1.r;
91     }
92 }
93 
94 
operator ==(const D3DXMATERIAL & mat0,const D3DXMATERIAL & mat1)95 bool operator==(const D3DXMATERIAL& mat0, const D3DXMATERIAL& mat1)
96 {
97     // Compare the texture filenames for equality, safely handling
98     // null filenames.
99     bool sameTex;
100     if (mat0.pTextureFilename == NULL)
101     {
102         sameTex = (mat1.pTextureFilename == NULL);
103     }
104     else if (mat1.pTextureFilename == NULL)
105     {
106         sameTex = false;
107     }
108     else
109     {
110         sameTex = (strcmp(mat0.pTextureFilename, mat1.pTextureFilename) == 0);
111     }
112 
113     return (mat0.MatD3D.Diffuse == mat1.MatD3D.Diffuse &&
114             mat0.MatD3D.Ambient == mat1.MatD3D.Ambient &&
115             mat0.MatD3D.Specular == mat1.MatD3D.Specular &&
116             mat0.MatD3D.Emissive == mat1.MatD3D.Emissive &&
117             mat0.MatD3D.Power == mat1.MatD3D.Power &&
118             sameTex);
119 }
120 
121 
operator <<(ostream & o,const D3DCOLORVALUE & c)122 ostream& operator<<(ostream& o, const D3DCOLORVALUE& c)
123 {
124     return (o << c.r << ' ' << c.g << ' ' << c.b);
125 }
126 
127 
render()128 static void render()
129 {
130     g_d3dDev->Clear(0, NULL,
131                     D3DCLEAR_TARGET,
132                     D3DCOLOR_ARGB(255, 0, 0, 192),  // color
133                     0.0f,                           // z
134                     0);                             // stencil value
135 }
136 
137 
checkForFan(DWORD nTris,T * indices)138 template<class T> int checkForFan(DWORD nTris, T* indices)
139 {
140     // Even number of triangles required; pairs of triangles can always
141     // be just as efficiently represented as strips, so skip them.
142     if (nTris % 2 == 1 || nTris <= 2)
143         return -1;
144 
145     DWORD i;
146     T anchor = indices[0];
147     bool isFan = true;
148     for (i = 1; i < nTris / 2 && isFan; i++)
149     {
150         if (indices[i * 2] != anchor)
151             isFan = false;
152     }
153 
154     if (isFan)
155         return 0;
156 
157     isFan = true;
158     anchor = indices[1];
159     for (i = 1; i < nTris / 2 && isFan; i++)
160     {
161         if (indices[i * 2 + 1] != anchor)
162             isFan = false;
163     }
164 
165     if (isFan)
166         cout << "fan: nTris=" << nTris << ", anchor=" << anchor << '\n';
167 
168     return isFan ? 1 : -1;
169 }
170 
171 
DumpTriStrip(DWORD nTris,T * indices,int materialIndex,ostream & meshfile)172 template<class T> int DumpTriStrip(DWORD nTris,
173                                    T* indices,
174                                    int materialIndex,
175                                    ostream& meshfile)
176 {
177     meshfile << "tristrip ";
178     meshfile << materialIndex << ' ' << (nTris + 2) << '\n';
179 
180     DWORD indexCount = nTris + 2;
181 
182     for (DWORD j = 0; j < indexCount; j++)
183     {
184         meshfile << indices[j] << ' ';
185         if (j == indexCount - 1 || j % 12 == 11)
186             meshfile << '\n';
187     }
188 }
189 
190 
191 
192 // The D3DX tristrip converter only produces strips, not fans.  It dumps
193 // fans as strips where every other triangle is degenerate.  We detect such
194 // strips and output them as fans instead, thus eliminating a bunch of
195 // degenerate triangles.
DumpTriStripAsFan(DWORD nTris,T * indices,int materialIndex,DWORD anchorOffset,ostream & meshfile)196 template<class T> void DumpTriStripAsFan(DWORD nTris,
197                                          T* indices,
198                                          int materialIndex,
199                                          DWORD anchorOffset,
200                                          ostream& meshfile)
201 {
202     meshfile << "trifan ";
203     meshfile << materialIndex << ' ' << (nTris / 2 + 3) << '\n';
204 
205     DWORD indexCount = nTris + 2;
206 
207     T anchor = indices[anchorOffset];
208     meshfile << anchor << ' ';
209 
210     if (anchorOffset == 1)
211     {
212         for (int j = (int) indexCount - 1; j >= 0; j--)
213         {
214             if (indices[j] != anchor)
215                 meshfile << indices[j] << ' ';
216             if (j == 0 || j % 12 == 11)
217                 meshfile << '\n';
218         }
219     }
220     else if (anchorOffset == 0)
221     {
222         // D3DX never seems to produce strips where the first vertex is
223         // the anchor, but we'll handle it just in case.
224         for (int j = 1; j < (int) indexCount; j++)
225         {
226             if (indices[j] != anchor)
227                 meshfile << indices[j] << ' ';
228             if (j == indexCount - 1 || j % 12 == 11)
229                 meshfile << '\n';
230         }
231     }
232 }
233 
234 
StripifyMeshSubset(ID3DXMesh * mesh,DWORD attribId,ostream & meshfile)235 bool StripifyMeshSubset(ID3DXMesh* mesh,
236                         DWORD attribId,
237                         ostream& meshfile)
238 {
239     // TODO: Fall back to tri lists if the strip size is too small
240     // TODO: Detect when a tri fan should be used instead of a tri list
241 
242     // Convert to tri strips
243     IDirect3DIndexBuffer9* indices = NULL;
244     DWORD numIndices = 0;
245     ID3DXBuffer* strips = NULL;
246     DWORD numStrips = 0;
247     HRESULT hr;
248     hr = D3DXConvertMeshSubsetToStrips(mesh,
249                                        attribId,
250                                        0,
251                                        &indices,
252                                        &numIndices,
253                                        &strips,
254                                        &numStrips);
255     if (FAILED(hr))
256     {
257         cout << "Stripify failed\n";
258         return false;
259     }
260 
261     cout << "Converted to " << numStrips << " strips\n";
262     cout << "Strip buffer size: " << strips->GetBufferSize() << '\n';
263     if (numStrips != strips->GetBufferSize() / 4)
264     {
265         cout << "Strip count is incorrect!\n";
266         return false;
267     }
268 
269     bool index32 = false;
270     {
271         D3DINDEXBUFFER_DESC desc;
272         indices->GetDesc(&desc);
273         if (desc.Format == D3DFMT_INDEX32)
274         {
275             index32 = true;
276         }
277         else if (desc.Format == D3DFMT_INDEX16)
278         {
279             index32 = false;
280         }
281         else
282         {
283             cout << "Bad index format.  Strange.\n";
284             return false;
285         }
286     }
287 
288     void* indexData = NULL;
289     hr = indices->Lock(0, 0, &indexData, D3DLOCK_READONLY);
290     if (FAILED(hr))
291     {
292         cout << "Failed to lock index buffer: " << D3DErrorString(hr) << '\n';
293         return false;
294     }
295 
296     {
297         DWORD* stripLengths = reinterpret_cast<DWORD*>(strips->GetBufferPointer());
298         int k = 0;
299         for (int i = 0; i < numStrips; i++)
300         {
301             if (stripLengths[i] == 0)
302             {
303                 cout << "Bad triangle strip (length == 0) in mesh!\n";
304                 return false;
305             }
306 
307             if (index32)
308             {
309                 DWORD* indices = reinterpret_cast<DWORD*>(indexData) + k;
310                 int fanStart = checkForFan(stripLengths[i], indices);
311                 if (fanStart != 1)
312                 {
313                     DumpTriStrip(stripLengths[i], indices, (int) attribId,
314                                  meshfile);
315                 }
316                 else
317                 {
318                     DumpTriStripAsFan(stripLengths[i], indices, (int) attribId,
319                                       fanStart, meshfile);
320                 }
321             }
322             else
323             {
324                 WORD* indices = reinterpret_cast<WORD*>(indexData) + k;
325                 int fanStart = checkForFan(stripLengths[i], indices);
326                 if (fanStart != 1)
327                 {
328                     DumpTriStrip(stripLengths[i], indices, (int) attribId,
329                                  meshfile);
330                 }
331                 else
332                 {
333                     DumpTriStripAsFan(stripLengths[i], indices, (int) attribId,
334                                       fanStart, meshfile);
335                 }
336             }
337 
338             k += stripLengths[i] + 2;
339         }
340 
341         cout << "k=" << k << ", numIndices=" << numIndices;
342         if (index32)
343             cout << ", 32-bit indices\n";
344         else
345             cout << ", 16-bit indices\n";
346     }
347 
348     return true;
349 }
350 
351 
DumpVertexDescription(VertexAttribute vertexMap[],ostream & meshfile)352 void DumpVertexDescription(VertexAttribute vertexMap[],
353                            ostream& meshfile)
354 {
355     meshfile << "vertexdesc\n";
356     for (int i = 0; i < VertexAttribute::MaxAttribute; i++)
357     {
358         if (vertexMap[i].format != VertexAttribute::InvalidFormat)
359         {
360             meshfile << AttribNames[i] << " " <<
361                 AttribFormatNames[vertexMap[i].format] << " " << '\n';
362         }
363     }
364     meshfile << "end_vertexdesc\n\n";
365 }
366 
367 
DumpMeshVertices(ID3DXMesh * mesh,VertexAttribute vertexMap[],DWORD stride,ostream & meshfile)368 bool DumpMeshVertices(ID3DXMesh* mesh,
369                       VertexAttribute vertexMap[],
370                       DWORD stride,
371                       ostream& meshfile)
372 {
373     IDirect3DVertexBuffer9* vb = NULL;
374     HRESULT hr = mesh->GetVertexBuffer(&vb);
375     if (FAILED(hr))
376     {
377         ShowD3DErrorMessage("Getting vertex buffer", hr);
378         return false;
379     }
380 
381     char* vertexData = NULL;
382     hr = vb->Lock(0, 0, reinterpret_cast<void**>(&vertexData), D3DLOCK_READONLY);
383     if (FAILED(hr) || vertexData == NULL)
384     {
385         ShowD3DErrorMessage("Locking vertex buffer", hr);
386         return false;
387     }
388 
389     DWORD numVertices = mesh->GetNumVertices();
390 
391     meshfile << "vertices " << numVertices << '\n';
392 
393     for (DWORD i = 0; i < numVertices; i++)
394     {
395         for (int attr = 0; attr < VertexAttribute::MaxAttribute; attr++)
396         {
397             if (vertexMap[attr].format != VertexAttribute::InvalidFormat)
398             {
399                 char* chardata = vertexData + i * stride + vertexMap[attr].offset;
400                 float* floatdata = reinterpret_cast<float*>(chardata);
401 
402                 switch (vertexMap[attr].format)
403                 {
404                 case VertexAttribute::Float1:
405                     meshfile << floatdata[0] << ' ';
406                     break;
407                 case VertexAttribute::Float2:
408                     meshfile << floatdata[0] << ' ' << floatdata[1] << ' ';
409                     break;
410                 case VertexAttribute::Float3:
411                     meshfile << floatdata[0] << ' ' << floatdata[1] << ' ';
412                     meshfile << floatdata[2] << ' ';
413                     break;
414                 case VertexAttribute::Float4:
415                     meshfile << floatdata[0] << ' ' << floatdata[1] << ' ';
416                     meshfile << floatdata[2] << ' ' << floatdata[3];
417                     break;
418                 case VertexAttribute::UByte4:
419                     meshfile << (unsigned int) chardata[0] << ' ' <<
420                                 (unsigned int) chardata[1] << ' ' <<
421                                 (unsigned int) chardata[2] << ' ' <<
422                                 (unsigned int) chardata[3] << ' ';
423                     break;
424                 default:
425                     break;
426                 }
427             }
428         }
429 
430         meshfile << '\n';
431     }
432 
433     vb->Unlock();
434 
435     meshfile << '\n';
436 
437     return true;
438 }
439 
440 
CreateVertexAttributeMap(D3DVERTEXELEMENT9 declElements[],VertexAttribute vertexMap[])441 bool CreateVertexAttributeMap(D3DVERTEXELEMENT9 declElements[],
442                               VertexAttribute vertexMap[])
443 {
444     int i = 0;
445     for (i = 0; i < VertexAttribute::MaxAttribute; i++)
446     {
447         vertexMap[i].offset = 0;
448         vertexMap[i].format = VertexAttribute::InvalidFormat;
449     }
450 
451     unsigned int outputOffset = 0;
452     for (i = 0; i < MAX_FVF_DECL_SIZE && declElements[i].Stream != 255; i++)
453     {
454         int attr = VertexAttribute::InvalidAttribute;
455         VertexAttribute::Format format = VertexAttribute::InvalidFormat;
456         unsigned int formatSize = 0;
457 
458         if (declElements[i].Stream == 0)
459         {
460             switch (declElements[i].Type)
461             {
462             case D3DDECLTYPE_FLOAT1:
463                 format = VertexAttribute::Float1;
464                 formatSize = 4;
465                 break;
466             case D3DDECLTYPE_FLOAT2:
467                 format = VertexAttribute::Float2;
468                 formatSize = 8;
469                 break;
470             case D3DDECLTYPE_FLOAT3:
471                 format = VertexAttribute::Float3;
472                 formatSize = 12;
473                 break;
474             case D3DDECLTYPE_FLOAT4:
475                 format = VertexAttribute::Float4;
476                 formatSize = 16;
477                 break;
478             case D3DDECLTYPE_UBYTE4:
479             case D3DDECLTYPE_UBYTE4N:
480                 format = VertexAttribute::UByte4;
481                 formatSize = 4;
482                 break;
483             }
484 
485             switch (declElements[i].Usage)
486             {
487             case D3DDECLUSAGE_POSITION:
488                 if (declElements[i].UsageIndex == 0)
489                 {
490                     attr = VertexAttribute::Position;
491                 }
492                 break;
493             case D3DDECLUSAGE_NORMAL:
494                 if (declElements[i].UsageIndex == 0)
495                 {
496                     attr = VertexAttribute::Normal;
497                 }
498                 break;
499             case D3DDECLUSAGE_TEXCOORD:
500                 if (declElements[i].UsageIndex < 4)
501                 {
502                     if (declElements[i].UsageIndex == 0)
503                         attr = VertexAttribute::Texture0;
504                     else if (declElements[i].UsageIndex == 1)
505                         attr = VertexAttribute::Texture1;
506                     else if (declElements[i].UsageIndex == 2)
507                         attr = VertexAttribute::Texture2;
508                     else
509                         attr = VertexAttribute::Texture3;
510                 }
511                 break;
512             case D3DDECLUSAGE_COLOR:
513                 if (declElements[i].UsageIndex < 2)
514                 {
515                     if (declElements[i].UsageIndex == 0)
516                         attr = VertexAttribute::Color0;
517                     else
518                         attr = VertexAttribute::Color1;
519                 }
520                 break;
521             case D3DDECLUSAGE_TANGENT:
522                 if (declElements[i].UsageIndex == 0)
523                 {
524                     attr = VertexAttribute::Tangent;
525                 }
526                 break;
527             }
528 
529             if (attr != VertexAttribute::InvalidAttribute)
530             {
531                 vertexMap[attr].offset = declElements[i].Offset;
532                 vertexMap[attr].format = format;
533             }
534         }
535     }
536 
537     return true;
538 }
539 
540 
MainWindowProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)541 static LRESULT CALLBACK MainWindowProc(HWND hWnd,
542                                        UINT uMsg,
543                                        WPARAM wParam,
544                                        LPARAM lParam)
545 {
546     switch (uMsg)
547     {
548     case WM_CREATE:
549         break;
550 
551     case WM_DESTROY:
552         PostQuitMessage(0);
553         break;
554 
555     case WM_PAINT:
556         if (g_d3dDev != NULL)
557         {
558             //render();
559             //g_d3dDev->Present(NULL, NULL, NULL, NULL);
560         }
561         break;
562 
563     default:
564         return DefWindowProc(hWnd, uMsg, wParam, lParam);
565     }
566 
567     return 0;
568 }
569 
570 
WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow)571 int APIENTRY WinMain(HINSTANCE hInstance,
572                      HINSTANCE hPrevInstance,
573                      LPSTR     lpCmdLine,
574                      int       nCmdShow)
575 {
576     WNDCLASS wc;
577 
578     wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
579     wc.lpfnWndProc = (WNDPROC) MainWindowProc;
580     wc.cbClsExtra = 0;
581     wc.cbWndExtra = 0;
582     wc.hInstance = hInstance;
583     wc.hIcon = NULL;
584     wc.hCursor = LoadCursor(NULL, MAKEINTRESOURCE(IDC_ARROW));
585     wc.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
586     wc.lpszMenuName = NULL;
587     wc.lpszClassName = "xtocmod";
588     if (RegisterClass(&wc) == 0)
589     {
590 	MessageBox(NULL,
591                    "Failed to register the window class.", "Fatal Error",
592                    MB_OK | MB_ICONERROR);
593 	return NULL;
594     }
595 
596     DWORD windowStyle = (WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU |
597                          WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX);
598     g_mainWindow = CreateWindow("xtocmod",
599                                 "xtocmod",
600                                 windowStyle,
601                                 CW_USEDEFAULT,
602                                 CW_USEDEFAULT,
603                                 300, 300,
604                                 NULL,
605                                 NULL,
606                                 hInstance,
607                                 NULL);
608     if (g_mainWindow == NULL)
609     {
610         MessageBox(NULL,
611                    "Error creating application window.", "Fatal Error",
612                    MB_OK | MB_ICONERROR);
613     }
614 
615     //ShowWindow(g_mainWindow, SW_SHOW);
616     SetForegroundWindow(g_mainWindow);
617     SetFocus(g_mainWindow);
618 
619     // Initialize D3D
620     g_d3d = Direct3DCreate9(D3D_SDK_VERSION);
621     if (g_d3d == NULL)
622     {
623         ShowD3DErrorMessage("Initializing D3D", 0);
624         return 1;
625     }
626 
627     D3DPRESENT_PARAMETERS presentParams;
628     ZeroMemory(&presentParams, sizeof(presentParams));
629     presentParams.Windowed = TRUE;
630     presentParams.SwapEffect = D3DSWAPEFFECT_COPY;
631 #if 0
632     presentParams.BackBufferWidth = 300;
633     presentParams.BackBufferHeight = 300;
634     presentParams.BackBufferCount = 1;
635     presentParams.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
636     presentParams.Windowed = TRUE;
637 #endif
638 
639     HRESULT hr = g_d3d->CreateDevice(D3DADAPTER_DEFAULT,
640                                      D3DDEVTYPE_HAL,
641                                      g_mainWindow,
642                                      D3DCREATE_HARDWARE_VERTEXPROCESSING,
643                                      &presentParams,
644                                      &g_d3dDev);
645     if (FAILED(hr))
646     {
647         ShowD3DErrorMessage("Creating D3D device", hr);
648         //return 1;
649     }
650 
651     string inputFilename(lpCmdLine);
652     string outputFilename(inputFilename, 0, inputFilename.rfind('.'));
653     outputFilename += ".cmod";
654 
655     ID3DXMesh* mesh = NULL;
656     ID3DXBuffer* adjacency = NULL;
657     ID3DXBuffer* materialBuf = NULL;
658     ID3DXBuffer* effects = NULL;
659     DWORD numMaterials;
660 
661     hr = D3DXLoadMeshFromX(inputFilename.c_str(),
662                            0,
663                            g_d3dDev,
664                            &adjacency,
665                            &materialBuf,
666                            &effects,
667                            &numMaterials,
668                            &mesh);
669     if (FAILED(hr))
670     {
671         ShowD3DErrorMessage("Loading mesh from X file", hr);
672         return 1;
673     }
674 
675 
676     DWORD numVertices = mesh->GetNumVertices();
677     DWORD numFaces = mesh->GetNumFaces();
678 
679     cout << "vertices: " << numVertices << '\n';
680     cout << "faces: " << numFaces << '\n';
681 
682     cout << "adjacency buffer size: " << adjacency->GetBufferSize() << '\n';
683 
684     ofstream meshfile(outputFilename.c_str());
685 
686     // Output the header
687     meshfile << "#celmodel__ascii\n\n";
688 
689     cout << "numMaterials=" << numMaterials << '\n';
690     D3DXMATERIAL* materials = reinterpret_cast<D3DXMATERIAL*>(materialBuf->GetBufferPointer());
691     for (DWORD mat = 0; mat < numMaterials; mat++)
692     {
693         meshfile << "material\n";
694         meshfile << "diffuse " << materials[mat].MatD3D.Diffuse << '\n';
695         //meshfile << "emissive " << materials[mat].MatD3D.Emissive << '\n';
696         meshfile << "specular " << materials[mat].MatD3D.Specular << '\n';
697         meshfile << "specpower " << materials[mat].MatD3D.Power << '\n';
698         meshfile << "opacity " << materials[mat].MatD3D.Diffuse.a << '\n';
699         meshfile << "end_material\n\n";
700     }
701 
702     // Vertex format
703     D3DVERTEXELEMENT9 declElements[MAX_FVF_DECL_SIZE];
704     hr = mesh->GetDeclaration(declElements);
705     if (FAILED(hr))
706     {
707         ShowD3DErrorMessage("Checking vertex declaration", hr);
708         return 1;
709     }
710 
711     DWORD stride = D3DXGetDeclVertexSize(declElements, 0);
712 
713     VertexAttribute vertexMap[VertexAttribute::MaxAttribute];
714     CreateVertexAttributeMap(declElements, vertexMap);
715 
716     meshfile << "mesh\n\n";
717 
718     DumpVertexDescription(vertexMap, meshfile);
719 
720     ID3DXMesh* optMesh = NULL;
721     ID3DXBuffer* vertexRemap = NULL;
722     DWORD* faceRemap = new DWORD[numFaces];
723     DWORD* optAdjacency = new DWORD[numFaces * 3];
724     hr = mesh->Optimize(D3DXMESHOPT_COMPACT | D3DXMESHOPT_STRIPREORDER,
725                         //D3DXMESHOPT_VERTEXCACHE |
726                         reinterpret_cast<DWORD*>(adjacency->GetBufferPointer()),
727                         optAdjacency,
728                         faceRemap,
729                         &vertexRemap,
730                         &optMesh);
731     if (FAILED(hr))
732     {
733         ShowD3DErrorMessage("Optimize failed: ", hr);
734         return 1;
735     }
736 
737     // Attribute table
738     DWORD attribTableSize = 0;
739     hr = optMesh->GetAttributeTable(NULL, &attribTableSize);
740     if (FAILED(hr))
741     {
742         ShowD3DErrorMessage("Querying attribute table size", hr);
743         return 1;
744     }
745 
746     D3DXATTRIBUTERANGE* attribTable = NULL;
747     if (attribTableSize > 0)
748     {
749         attribTable = new D3DXATTRIBUTERANGE[attribTableSize];
750         hr = optMesh->GetAttributeTable(attribTable, &attribTableSize);
751         if (FAILED(hr))
752         {
753             ShowD3DErrorMessage("Getting attribute table", hr);
754             return 1;
755         }
756     }
757 
758     cout << "Attribute table size: " << attribTableSize << '\n';
759     if (attribTableSize == 1)
760     {
761         cout << "Attribute id: " << attribTable[0].AttribId << '\n';
762     }
763 
764     if (!DumpMeshVertices(optMesh, vertexMap, stride, meshfile))
765         return 1;
766 
767     // output the indices
768     for (DWORD attr = 0; attr < attribTableSize; attr++)
769     {
770         StripifyMeshSubset(optMesh, attr, meshfile);
771     }
772     meshfile << "\nend_mesh\n";
773 
774 #if 0
775     IDirect3DIndexBuffer9* indices = NULL;
776     hr = mesh->GetIndexBuffer(&indices);
777 #endif
778 
779 #if 0
780     // No message loop required for this app
781     MSG msg;
782     GetMessage(&msg, NULL, 0u, 0u);
783     while (msg.message != WM_QUIT)
784     {
785         GetMessage(&msg, NULL, 0u, 0u);
786         TranslateMessage(&msg);
787         DispatchMessage(&msg);
788     }
789 #endif
790 
791     return 0;
792 }
793 
794 
main(int argc,char * argv[])795 int main(int argc, char* argv[])
796 {
797     if (argc != 2)
798     {
799         cerr << "Usage: xtocmod <meshfile.x>\n";
800         return 1;
801     }
802 
803     ID3DXMesh* mesh = NULL;
804     ID3DXBuffer* adjacency = NULL;
805     ID3DXBuffer* materials = NULL;
806     ID3DXBuffer* effects = NULL;
807 
808     return 0;
809 }
810 
811 
D3DErrorString(HRESULT hr)812 char* D3DErrorString(HRESULT hr)
813 {
814     switch (hr)
815     {
816     case D3DERR_WRONGTEXTUREFORMAT:
817         return "D3DERR_WRONGTEXTUREFORMAT";
818     case D3DERR_UNSUPPORTEDCOLOROPERATION:
819         return "D3DERR_UNSUPPORTEDCOLOROPERATION";
820     case D3DERR_UNSUPPORTEDCOLORARG:
821         return "D3DERR_UNSUPPORTEDCOLORARG";
822     case D3DERR_UNSUPPORTEDALPHAOPERATION:
823         return "D3DERR_UNSUPPORTEDALPHAOPERATION";
824     case D3DERR_UNSUPPORTEDALPHAARG:
825         return "D3DERR_UNSUPPORTEDALPHAARG";
826     case D3DERR_TOOMANYOPERATIONS:
827         return "D3DERR_TOOMANYOPERATIONS";
828     case D3DERR_CONFLICTINGTEXTUREFILTER:
829         return "D3DERR_CONFLICTINGTEXTUREFILTER";
830     case D3DERR_UNSUPPORTEDFACTORVALUE:
831         return "D3DERR_UNSUPPORTEDFACTORVALUE";
832     case D3DERR_CONFLICTINGRENDERSTATE:
833         return "D3DERR_CONFLICTINGRENDERSTATE";
834     case D3DERR_UNSUPPORTEDTEXTUREFILTER:
835         return "D3DERR_UNSUPPORTEDTEXTUREFILTER";
836     case D3DERR_CONFLICTINGTEXTUREPALETTE:
837         return "D3DERR_CONFLICTINGTEXTUREPALETTE";
838     case D3DERR_DRIVERINTERNALERROR:
839         return "D3DERR_DRIVERINTERNALERROR";
840     case D3DERR_NOTFOUND:
841         return "D3DERR_NOTFOUND";
842     case D3DERR_MOREDATA:
843         return "D3DERR_MOREDATA";
844     case D3DERR_DEVICELOST:
845         return "D3DERR_DEVICELOST";
846     case D3DERR_DEVICENOTRESET:
847         return "D3DERR_DEVICENOTRESET";
848     case D3DERR_NOTAVAILABLE:
849         return "D3DERR_NOTAVAILABLE";
850     case D3DERR_OUTOFVIDEOMEMORY:
851         return "D3DERR_OUTOFVIDEOMEMORY";
852     case D3DERR_INVALIDDEVICE:
853         return "D3DERR_INVALIDDEVICE";
854     case D3DERR_INVALIDCALL:
855         return "D3DERR_INVALIDCALL";
856     case D3DERR_DRIVERINVALIDCALL:
857         return "D3DERR_DRIVERINVALIDCALL";
858     case D3DERR_WASSTILLDRAWING:
859         return "D3DERR_WASSTILLDRAWING";
860     case D3DOK_NOAUTOGEN:
861         return "D3DOK_NOAUTOGEN";
862 
863     case D3DXERR_CANNOTMODIFYINDEXBUFFER:
864         return "D3DXERR_CANNOTMODIFYINDEXBUFFER";
865     case D3DXERR_INVALIDMESH:
866         return "D3DXERR_INVALIDMESH";
867     case D3DXERR_CANNOTATTRSORT:
868         return "D3DXERR_CANNOTATTRSORT";
869     case D3DXERR_SKINNINGNOTSUPPORTED:
870         return "D3DXERR_SKINNINGNOTSUPPORTED";
871     case D3DXERR_TOOMANYINFLUENCES:
872         return "D3DXERR_TOOMANYINFLUENCES";
873     case D3DXERR_INVALIDDATA:
874         return "D3DXERR_INVALIDDATA";
875     case D3DXERR_LOADEDMESHASNODATA:
876         return "D3DXERR_LOADEDMESHASNODATA";
877     case D3DXERR_DUPLICATENAMEDFRAGMENT:
878         return "D3DXERR_DUPLICATENAMEDFRAGMENT";
879 
880     default:
881         return "Unkown D3D Error";
882     }
883 }
884 
885 
ShowD3DErrorMessage(char * info,HRESULT hr)886 void ShowD3DErrorMessage(char* info, HRESULT hr)
887 {
888     char buf[1024];
889 
890     sprintf(buf, "%s - %s", info, D3DErrorString(hr));
891     MessageBox(g_mainWindow,
892                buf, "Fatal Error",
893                MB_OK | MB_ICONERROR);
894 }
895 
896