From fcc024f4b4e5c02356f926c8a62be31d8a37e205 Mon Sep 17 00:00:00 2001 From: Barnacle <> Date: Tue, 11 Dec 2018 03:07:56 +0700 Subject: [PATCH] Upload. --- .gitignore | 8 + D3D/D3D.cpp | 291 +++++++ D3D/D3D.h | 83 ++ D3D/D3D.rc | Bin 0 -> 4472 bytes D3D/D3D.vcxproj | 93 +++ D3D/D3D.vcxproj.filters | 14 + D3D/D3D.vcxproj.user | 10 + D3D/Ema.h | 1516 +++++++++++++++++++++++++++++++++++++ D3D/resource.h | 14 + README.md | 11 + USF4ce.sln | 57 ++ main/AboutBox.cpp | 2 + main/AboutBox.h | 99 +++ main/AboutBox.resx | 120 +++ main/Reader.h | 423 +++++++++++ main/USF4ce.rc | Bin 0 -> 4524 bytes main/Wrapper.h | 114 +++ main/main.cpp | 13 + main/main.h | 1296 +++++++++++++++++++++++++++++++ main/main.resx | 132 ++++ main/main.vcxproj | 130 ++++ main/main.vcxproj.filters | 36 + main/main.vcxproj.user | 4 + main/resource.h | 14 + 24 files changed, 4480 insertions(+) create mode 100644 .gitignore create mode 100644 D3D/D3D.cpp create mode 100644 D3D/D3D.h create mode 100644 D3D/D3D.rc create mode 100644 D3D/D3D.vcxproj create mode 100644 D3D/D3D.vcxproj.filters create mode 100644 D3D/D3D.vcxproj.user create mode 100644 D3D/Ema.h create mode 100644 D3D/resource.h create mode 100644 README.md create mode 100644 USF4ce.sln create mode 100644 main/AboutBox.cpp create mode 100644 main/AboutBox.h create mode 100644 main/AboutBox.resx create mode 100644 main/Reader.h create mode 100644 main/USF4ce.rc create mode 100644 main/Wrapper.h create mode 100644 main/main.cpp create mode 100644 main/main.h create mode 100644 main/main.resx create mode 100644 main/main.vcxproj create mode 100644 main/main.vcxproj.filters create mode 100644 main/main.vcxproj.user create mode 100644 main/resource.h diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..dac3658 --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +Debug/ +Release/ +D3D/Debug/ +D3D/Release/ +main/Debug/ +main/Release/ +# Visual Studio 2015 cache/options directory +.vs/ \ No newline at end of file diff --git a/D3D/D3D.cpp b/D3D/D3D.cpp new file mode 100644 index 0000000..a22193c --- /dev/null +++ b/D3D/D3D.cpp @@ -0,0 +1,291 @@ +#include "D3D.h" + +CD3DRender::CD3DRender() +{ + m_emaRenderer = new EMARenderer; +} + +CD3DRender::~CD3DRender() +{} + +struct Vertex +{ + D3DXVECTOR3 p; + D3DXVECTOR3 n; + float u, v; + + enum FVF + { + FVF_Flags = D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1 + }; +}; + +HRESULT CD3DRender::init(HWND hwnd, int Width, int Height) +{ + // Create the D3D object. + if (NULL == (g_D3D = Direct3DCreate9(D3D_SDK_VERSION))) + return E_FAIL; + + g_D3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &d3ddm); + + ZeroMemory(&d3dpp, sizeof(d3dpp)); + d3dpp.Windowed = TRUE; + d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; + d3dpp.BackBufferFormat = d3ddm.Format; + d3dpp.EnableAutoDepthStencil = TRUE; + d3dpp.AutoDepthStencilFormat = D3DFMT_D16; + d3dpp.BackBufferWidth = Width; + d3dpp.BackBufferHeight = Height; + d3dpp.MultiSampleType = D3DMULTISAMPLE_8_SAMPLES; + + // Create the D3DDevice + if (FAILED(g_D3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd, + D3DCREATE_SOFTWARE_VERTEXPROCESSING, + &d3dpp, &g_d3dDevice))) + { + return E_FAIL; + } + + g_d3dDevice->SetRenderState(D3DRS_LIGHTING, FALSE); + g_d3dDevice->SetRenderState(D3DRS_ZENABLE, TRUE); + g_d3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); + + D3DXMATRIX matProj; + D3DXMatrixPerspectiveFovLH(&matProj, D3DXToRadian(45.0f), + (float)Width / (float)Height, 0.1f, 100.0f); + g_d3dDevice->SetTransform(D3DTS_PROJECTION, &matProj); + + + + return S_OK; +} + +// Функция предварительного создания буферов. +HRESULT CD3DRender::CreateBuffers(ushort EMGcount) +{ + g_pIndexBuffer = new LPDIRECT3DINDEXBUFFER9*[EMGcount]; + g_pVertexBuffer = new LPDIRECT3DVERTEXBUFFER9[EMGcount]; + + CD3DRender::EMGcount = EMGcount; + EMGsubmodels = new ushort[EMGcount]; + + IndexCount = new ushort*[EMGcount]; + VertexCount = new ushort[EMGcount]; + VertexSize = new ushort[EMGcount]; + + DDSid = new Byte*[EMGcount]; + + return S_OK; +} + +// Функция заполнения массива буферов. +HRESULT CD3DRender::LoadEMG(ushort CurrentEMG, ushort EMGsubmodels, Byte* DDSid, ushort* IndexCount, + ushort VertexCount, ushort VertexSize, ushort** IndiceArray, Byte* VertexArray) +{ + // Заполнение массивов для использования в ProcessFrame(). + CD3DRender::IndexCount[CurrentEMG] = new ushort[EMGsubmodels]; + CD3DRender::VertexCount[CurrentEMG] = VertexCount; + CD3DRender::VertexSize[CurrentEMG] = VertexSize; + CD3DRender::EMGsubmodels[CurrentEMG] = EMGsubmodels; + + CD3DRender::DDSid[CurrentEMG] = new Byte[EMGsubmodels]; + + g_pIndexBuffer[CurrentEMG] = new LPDIRECT3DINDEXBUFFER9[EMGsubmodels]; + + for (ushort i = 0; i < EMGsubmodels; i++) + { + CD3DRender::IndexCount[CurrentEMG][i] = IndexCount[i]; + CD3DRender::DDSid[CurrentEMG][i] = DDSid[i]; + + // Create an index buffer to use with our indexed vertex buffer... + g_d3dDevice->CreateIndexBuffer(IndexCount[i] * sizeof(WORD), + D3DUSAGE_WRITEONLY, + D3DFMT_INDEX16, + D3DPOOL_MANAGED, + &(g_pIndexBuffer[CurrentEMG][i]), + NULL); + WORD *pIndices = NULL; + + g_pIndexBuffer[CurrentEMG][i]->Lock(0, IndexCount[i] * sizeof(WORD), (void**)&pIndices, 0); + memcpy(pIndices, IndiceArray[i], IndexCount[i] * sizeof(WORD)); + g_pIndexBuffer[CurrentEMG][i]->Unlock(); + } + + // Create a vertex buffer... + g_d3dDevice->CreateVertexBuffer(VertexCount * VertexSize, + D3DUSAGE_WRITEONLY, + Vertex::FVF_Flags, + D3DPOOL_MANAGED, + &(g_pVertexBuffer[CurrentEMG]), + NULL); + void *pVertices = NULL; + + g_pVertexBuffer[CurrentEMG]->Lock(0, VertexCount * VertexSize, (void**)&pVertices, 0); + memcpy(pVertices, VertexArray, VertexCount * VertexSize); + g_pVertexBuffer[CurrentEMG]->Unlock(); + + return S_OK; +} + +HRESULT CD3DRender::LoadDDS(ushort DDScount, unsigned long* DDSsize, Byte** DDScontent) +{ + g_Texture = new LPDIRECT3DTEXTURE9[DDScount]; + CD3DRender::DDScount = DDScount; + for (ushort i = 0; i < DDScount; i++) + D3DXCreateTextureFromFileInMemory(g_d3dDevice, DDScontent[i], DDSsize[i], &g_Texture[i]); + + + return S_OK; +} + +HRESULT CD3DRender::Shutdown() +{ + for (ushort i = 0; i < EMGcount; i++) + { + for (ushort a = 0; a < EMGsubmodels[i]; a++) + { + if (g_pIndexBuffer != NULL) + g_pIndexBuffer[i][a]->Release(); + } + + if (g_pVertexBuffer != NULL) + g_pVertexBuffer[i]->Release(); + } + + for (ushort i = 0; i < DDScount; i++) + { + if (g_Texture != NULL) + g_Texture[i]->Release(); + } + + if( g_d3dDevice != NULL ) + g_d3dDevice->Release(); + + if( g_D3D != NULL ) + g_D3D->Release(); + + return S_OK; +} + +HRESULT CD3DRender::OnMouseMove(short x, short y, bool RMousing) +{ + ptCurrentMousePosit.x = x; + ptCurrentMousePosit.y = y; + + if (bMousing) + { + if (bRMousing != RMousing) + { + m_zoom += (ptCurrentMousePosit.y - ptLastMousePosit.y) / (float)1000; + } + else + { + g_fSpinX -= (ptCurrentMousePosit.x - ptLastMousePosit.x); + g_fSpinY -= (ptCurrentMousePosit.y - ptLastMousePosit.y); + } + } + + ptLastMousePosit.x = ptCurrentMousePosit.x; + ptLastMousePosit.y = ptCurrentMousePosit.y; + + return S_OK; +} + +HRESULT CD3DRender::OnMouseButtonUp() +{ + bMousing = false; + bRMousing = false; + + return S_OK; +} + +HRESULT CD3DRender::OnMouseButtonDown(short x, short y) +{ + ptLastMousePosit.x = ptCurrentMousePosit.x = x; + ptLastMousePosit.y = ptCurrentMousePosit.y = y; + bMousing = true; + bRMousing = false; + + return S_OK; +} + +HRESULT CD3DRender::Reset() +{ + return S_OK; +} + +HRESULT CD3DRender::ProcessFrame() +{ + // Clear the backbuffer and the zbuffer + g_d3dDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, + D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0); + + D3DXMATRIX matTrans; + D3DXMATRIX matRot; + D3DXMATRIX matWorld; + + D3DXMatrixTranslation(&matTrans, 0.0f, 0.0f, m_zoom); + + D3DXMatrixRotationYawPitchRoll( &matRot, + D3DXToRadian(g_fSpinX), + D3DXToRadian(g_fSpinY), + 0.0f); + matWorld = matRot * matTrans; + g_d3dDevice->SetTransform(D3DTS_WORLD, &matWorld); + + // Begin the scene + if (SUCCEEDED(g_d3dDevice->BeginScene())) + { + if (g_pIndexBuffer != 0 && g_pVertexBuffer != 0) + { + for (int i = 0; i < EMGcount; i++) + { + g_d3dDevice->SetStreamSource(0, g_pVertexBuffer[i], 0, VertexSize[i]); + g_d3dDevice->SetFVF(Vertex::FVF_Flags); + + for (ushort a = 0; a < EMGsubmodels[i]; a++) + { + if (g_Texture != NULL) + { + g_d3dDevice->SetTexture(0, g_Texture[DDSid[i][a]]); + + g_d3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_ANISOTROPIC); + g_d3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_ANISOTROPIC); + g_d3dDevice->SetSamplerState(0, D3DSAMP_MAXANISOTROPY, 4); + + } + + g_d3dDevice->SetIndices(g_pIndexBuffer[i][a]); + g_d3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLESTRIP, 0, 0, VertexCount[i], 0, IndexCount[i][a] - 2); + } + } + } + // End the scene + g_d3dDevice->EndScene(); + } + + // Present the backbuffer contents to the display + g_d3dDevice->Present(NULL, NULL, NULL, NULL); + + return S_OK; +} + +HRESULT CD3DRender::Resize(int Width, int Height) +{ + d3dpp.BackBufferWidth = Width; + d3dpp.BackBufferHeight = Height; + + g_d3dDevice->Reset(&d3dpp); + + g_d3dDevice->SetRenderState(D3DRS_LIGHTING, FALSE); + g_d3dDevice->SetRenderState(D3DRS_ZENABLE, TRUE); + g_d3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); + + D3DXMATRIX matProj; + D3DXMatrixPerspectiveFovLH(&matProj, D3DXToRadian(45.0f), + (float)Width / (float)Height, 0.1f, 100.0f); + g_d3dDevice->SetTransform(D3DTS_PROJECTION, &matProj); + + return S_OK; +} + diff --git a/D3D/D3D.h b/D3D/D3D.h new file mode 100644 index 0000000..f3498c3 --- /dev/null +++ b/D3D/D3D.h @@ -0,0 +1,83 @@ +#pragma once + +#ifdef _EXPORTING +#define CLASS_DECLSPEC __declspec(dllexport) +#else +#define CLASS_DECLSPEC __declspec(dllimport) +#endif + +#include +#include +#include "Ema.h" + +#pragma comment( lib, "d3d9.lib" ) +#pragma comment( lib, "d3dx9d.lib" ) +#pragma comment( lib, "winmm.lib" ) + +typedef unsigned short ushort; +typedef unsigned char Byte; + +class CLASS_DECLSPEC CD3DRender +{ +public: + CD3DRender(); + ~CD3DRender(); + + LPDIRECT3D9 g_D3D = NULL; // Used to create the D3DDevice + LPDIRECT3DDEVICE9 g_d3dDevice = NULL; // Our rendering device + + LPDIRECT3DINDEXBUFFER9** g_pIndexBuffer = NULL; // Буфер индексов + LPDIRECT3DVERTEXBUFFER9* g_pVertexBuffer = NULL; // Буфер вертексов + LPDIRECT3DTEXTURE9* g_Texture = NULL; + + D3DDISPLAYMODE d3ddm; + D3DPRESENT_PARAMETERS d3dpp; + + POINT ptLastMousePosit; + POINT ptCurrentMousePosit; + + bool bMousing = false; + float g_fSpinX = 0.0f; + float g_fSpinY = 0.0f; + + bool bRMousing = false; + float m_zoom = 2.5f; + + unsigned short EMGcount; + unsigned short* EMGsubmodels = NULL; + unsigned short**IndexCount = NULL; + unsigned short* VertexCount = NULL; + unsigned short* VertexSize = NULL; + + ushort DDScount; + Byte** DDSid = NULL; + + HRESULT init(HWND hwnd, int Width, int Height); + HRESULT CreateBuffers(ushort EMGcount); + HRESULT LoadEMG(ushort CurrentEMG, ushort EMGsubmodels, Byte* DDSid, ushort* IndexCount, + ushort VertexCount, ushort VertexSize, + ushort** IndiceArray, Byte* VertexArray); + HRESULT LoadDDS(ushort DDScount, unsigned long* DDSsize, Byte** DDScontent); + HRESULT Shutdown(); + HRESULT Reset(); + HRESULT ProcessFrame(); + HRESULT Resize(int Width, int Height); + HRESULT OnMouseMove(short x, short y, bool RMousing); + HRESULT OnMouseButtonUp(); + HRESULT OnMouseButtonDown(short x, short y); + + EMARenderer* m_emaRenderer; + HRESULT Setup(std::string emaFileName, unsigned long emaBlockOffset) + { + m_emaRenderer->setup(emaFileName, emaBlockOffset); + + return S_OK; + } + + HRESULT Update(float(&structure)[500][6], std::string(&names)[500], std::string AnimationName, int frame) + { + m_emaRenderer->updateDeviceObjects(AnimationName, (float)frame, structure, names); + + return S_OK; + } +}; \ No newline at end of file diff --git a/D3D/D3D.rc b/D3D/D3D.rc new file mode 100644 index 0000000000000000000000000000000000000000..61f99ca43dbebbf1dd3819707ca9090a45a8d74f GIT binary patch literal 4472 zcmd6r+in^$5QgWvQr}@qZW=X8LXw+ahHy|+5>Pm(l_H@u9EwCC;-I!tpS|t(+c@m9 zke2NYS{ZxCp7G2-2YdPb>%>khvKt%PqfKpMGg{x~(Av;uwy*~q@pfhJcp@8E&&ISV z^f`SO+LT^=3r3HOBiT3Q($y!~W7?|DK>-=p(Cu%R0t=P@33R z?4N^L*J-Y*GQl5#u3oK8W_I{3k=x2wov|GkU1i4Nj?V}Y(Zv}t zx+Z%|YilAR_=va*&9AK^zeWVMs6EYp;t0~qu4+`!?uL5NAonArf46fySaq5xDpys* z*Omf1Ro3)eN%9i%&-^{^D>HCP+O@v^G`3!6l6FmU)X>k%zCcGk7fYTMT21aQbx`x` z&QkNfQYKf0oj2#c>S_&Kg-i|&=J;E;umK(#Vp$JAjnQ?omW`XGg{(+Ql_hz5?=1Sv zZ!)h}Jez7$m<@d!Kk7as407nLd(V?Q^L`Lt54`oD>(t0m?H;gZ%&+d0qI<-HtYn{* z9IP+G7r(LkOb9y^IUOU1&Xiu~TNzt*&&{$|GTXu)d2Y$4&utgE@|^DB9)nQ|pCWls zL~<8&MmuR-Md|=tN6rIJ_QOTZfZOLBIUfBpw9bRZE*jUCauk7*9=xEpxM#C#UT231 z7BBG9JcUSB4<@B%_v7lM4Y8S~By+0`GSg?AvgB$q?wd%{4RQwh`ihIkyDF#8WO+Ex zO+ZyDo>MDrS0l}DKRL7BTleeajB6u%W%(0Nq>K){Vqv=074E4DgXcg literal 0 HcmV?d00001 diff --git a/D3D/D3D.vcxproj b/D3D/D3D.vcxproj new file mode 100644 index 0000000..ad0cfff --- /dev/null +++ b/D3D/D3D.vcxproj @@ -0,0 +1,93 @@ +п»ї + + + + Debug + Win32 + + + Release + Win32 + + + + {01A3003A-08FD-4A54-8EB2-32F4BD558E28} + D3D + 8.1 + + + + DynamicLibrary + true + v141 + MultiByte + + + DynamicLibrary + false + v141 + true + MultiByte + + + + + + + + + + + + + + + Level3 + Disabled + true + _EXPORTING;%(PreprocessorDefinitions) + $(DXSDK_DIR)\include + true + + + true + + $(DXSDK_DIR)\lib\x86 + + + true + + + + + Level3 + MaxSpeed + true + true + true + $(DXSDK_DIR)\include + _EXPORTING;%(PreprocessorDefinitions) + + + true + true + true + $(DXSDK_DIR)\lib\x86 + Windows + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/D3D/D3D.vcxproj.filters b/D3D/D3D.vcxproj.filters new file mode 100644 index 0000000..bd84d5d --- /dev/null +++ b/D3D/D3D.vcxproj.filters @@ -0,0 +1,14 @@ +п»ї + + + + + + + + + + + + + \ No newline at end of file diff --git a/D3D/D3D.vcxproj.user b/D3D/D3D.vcxproj.user new file mode 100644 index 0000000..a6bdedb --- /dev/null +++ b/D3D/D3D.vcxproj.user @@ -0,0 +1,10 @@ +п»ї + + + + + WindowsLocalDebugger + $(TargetDir)\SSF4mv.exe + false + + \ No newline at end of file diff --git a/D3D/Ema.h b/D3D/Ema.h new file mode 100644 index 0000000..fc78b0a --- /dev/null +++ b/D3D/Ema.h @@ -0,0 +1,1516 @@ +// https://sourceforge.net/projects/sf4viewer/ + +#pragma once + +#include +#include +#include +#include +#include +#include + +#define M_PI 3.141592653589793238462643 + +template +void leftHandToEulerAnglesXYZ(const Real m[16], Real& rfXAngle, Real& rfYAngle, Real& rfZAngle) +{ + // +- -+ +- -+ + // | r00 r01 r02 | | cy*cz cz*sx*sy-cx*sz cx*cz*sy+sx*sz | + // | r10 r11 r12 | = | cy*sz cx*cz+sx*sy*sz -cz*sx+cx*sy*sz | + // | r20 r21 r22 | | -sy cy*sx cx*cy | + // +- -+ +- -+ + + if (m[8] < (Real)1.0) + { + if (m[8] > -(Real)1.0) + { + // y_angle = asin(-r20) + // z_angle = atan2(r10,r00) + // x_angle = atan2(r21,r22) + rfYAngle = (Real)asin(-(double)m[8]); + rfZAngle = atan2(m[4], m[0]); + rfXAngle = atan2(m[9], m[10]); + return;//EA_UNIQUE + } + else + { + // y_angle = +pi/2 + // x_angle - z_angle = atan2(r01,r02) + // WARNING. The solution is not unique. Choosing x_angle = 0. + rfYAngle = (Real)(0.5*M_PI); + rfZAngle = -atan2(m[1], m[2]); + rfXAngle = (Real)0.0; + return;//EA_NOT_UNIQUE_DIF + } + } + else + { + // y_angle = -pi/2 + // x_angle + z_angle = atan2(-r01,-r02) + // WARNING. The solution is not unique. Choosing x_angle = 0; + rfYAngle = -(Real)(0.5*M_PI); + rfZAngle = atan2(-m[1], -m[2]); + rfXAngle = (Real)0.0; + return;//EA_NOT_UNIQUE_SUM + } +} +void decomposeMatrix(float rotation[3], float scale[3], float translation[3], const float matrix[16], float rotationQuaternion[4]) +{ + if (matrix == NULL) + { + return; + } + D3DXMATRIX originalMatrix(matrix); + D3DXQUATERNION q; + D3DXVECTOR3 originalScale; + D3DXVECTOR3 originalTrans; + D3DXMatrixDecompose(&originalScale, &q, &originalTrans, &originalMatrix); + + memcpy(translation, (float*)originalTrans, 3 * sizeof(float)); + memcpy(scale, (float*)originalScale, 3 * sizeof(float)); + memcpy(rotationQuaternion, (float*)q, 4 * sizeof(float)); + + D3DXMATRIX m; + D3DXMatrixTranspose(&m, &originalMatrix); + leftHandToEulerAnglesXYZ(m, rotation[0], rotation[1], rotation[2]); + + rotation[0] *= (float)(180. / M_PI); + rotation[1] *= (float)(180. / M_PI); + rotation[2] *= (float)(180. / M_PI); +} +void composeMatrixQuat(const D3DXQUATERNION & rotation, float scale[3], float translation[3], float matrix[16]) +{ + if (matrix == NULL) + { + return; + } + + D3DXMATRIX translationMatrix, scalingMatrix, rotationMatrix; + D3DXMatrixTranslation(&translationMatrix, translation[0], translation[1], translation[2]); + D3DXMatrixScaling(&scalingMatrix, scale[0], scale[1], scale[2]); + D3DXMatrixRotationQuaternion(&rotationMatrix, &rotation); + + //store result + D3DXMATRIX fullMatrix = scalingMatrix * rotationMatrix * translationMatrix; + memcpy(matrix, (float*)fullMatrix, 16 * sizeof(float)); +} +//Pitch->X axis, Yaw->Y axis, Roll->Z axis +void eulerToQuaternionXYZ(float fPitch, float fYaw, float fRoll, float quaternion[4]) +{ + const float fSinPitch(sin(fPitch*0.5F)); + const float fCosPitch(cos(fPitch*0.5F)); + const float fSinYaw(sin(fYaw*0.5F)); + const float fCosYaw(cos(fYaw*0.5F)); + const float fSinRoll(sin(fRoll*0.5F)); + const float fCosRoll(cos(fRoll*0.5F)); + const float fCosPitchCosYaw(fCosPitch*fCosYaw); + const float fSinPitchSinYaw(fSinPitch*fSinYaw); + quaternion[0] = fSinRoll * fCosPitchCosYaw - fCosRoll * fSinPitchSinYaw; + quaternion[1] = fCosRoll * fSinPitch * fCosYaw + fSinRoll * fCosPitch * fSinYaw; + quaternion[2] = fCosRoll * fCosPitch * fSinYaw - fSinRoll * fSinPitch * fCosYaw; + quaternion[3] = fCosRoll * fCosPitchCosYaw + fSinRoll * fSinPitchSinYaw; +} + +struct EMAAnimationHeader{ + unsigned short duration; + unsigned short cmdOffsetCount; + unsigned long valueCount; + unsigned long zero; + unsigned long nameOffset; + unsigned long valuesOffset; +}; +struct EMAAnimationCommandHeader{ + unsigned short boneIndex; + unsigned char transformType;//0 -> translation, 1 -> rotation, 2->scale + unsigned char flags;//4bits : ? / 2bits: transform component ( a record has 0, the next 1, then 2 ) + unsigned short stepCount; + unsigned short indicesOffset; +}; +struct EMASkelettonHeader{ + unsigned short nodeCount; + unsigned short unknown0x02; + unsigned short ikDataCount;//small number + unsigned short unknown0x06;//0 + unsigned long skeletonStartOffset; + unsigned long skeletonNameAddressOffset; + // 0x10 + unsigned long unknown0x10; + unsigned long unknown0x14;//0 + unsigned long unknown0x18;//address for bunch of FF's + unsigned long matrixOffset; + // 0x20 + unsigned long ikDataOffset; +}; +struct EMASkelettonNodeTemp{ + unsigned short parent;//FFFF if root + unsigned short child1; + unsigned short child2;//FFFF if none + unsigned short child3;//FFFF if none + unsigned short child4;//FFFF if none + unsigned short flags; + float unknown4;//0 + float matrix[16]; +}; +struct EMASkelettonNode{ + unsigned short parent;//FFFF if root + unsigned short child1; + unsigned short sibling;//FFFF if none + unsigned short flags; + + float unknownScale; + + unsigned short number; + + unsigned long update_flags; + + float matrix[16]; + float translation[3]; + float scale[3]; + float rotation[3]; + float rotationQuaternion[4]; + + //runtime values (filled after a EAMData::setupFrame() call) + float animatedMatrix[16]; + float animatedTranslation[3]; + float animatedScale[3]; + float animatedRotation[3]; + float animatedRotationQuaternion[4]; + + bool animatedAbsoluteRotationFlag; + bool animatedAbsoluteScaleFlag; + bool animatedAbsoluteTranslationFlag; + + bool animationProcessingDone; +}; +struct EMASkeletonIKData{ + unsigned short method; + unsigned short dataSize; + unsigned char data[0x20]; +}; + +struct EMAData +{ + struct EMAAnimationCommandStep + { + unsigned short timing; + unsigned int index; + unsigned int tangentIndex; + }; + enum ETransformType + { + E_TRANSLATION = 0 + , E_ROTATION + , E_SCALING + , E_NOP = -1 + }; + typedef std::vector CommandSequence; + struct Commands + { + CommandSequence steps; + bool absolute; + }; + typedef std::map CommandsPerComponent; + typedef std::map CommandsPerComponentPerType; + typedef std::map CommandsPerComponentPerTypePerBone; + struct EMAAnimation + { + std::string name; + unsigned short duration; + std::vector values; + CommandsPerComponentPerTypePerBone commandsPerComponentPerTypePerBone; + }; +public: + typedef std::map SkelettonNodePerNumberMap; + typedef std::vector SkeletonIKData; + EMAAnimationHeader m_animationHeader; + unsigned long m_nodeCount; + SkelettonNodePerNumberMap m_skelettonNodes; + std::map m_skelettonNodeNames; + float m_matrix[16]; + + SkeletonIKData m_ikData; + std::vector m_animations; + std::map m_animationIndexPerName; + std::vector m_animationNames; + + ~EMAData() + { + freeData(); + } + + void freeData() + { + m_nodeCount = 0; + m_skelettonNodes.clear(); + m_skelettonNodeNames.clear(); + m_animations.clear(); + m_animationIndexPerName.clear(); + m_animationNames.clear(); + } + + std::vector const& getAnimationNames() const + { + return m_animationNames; + } + + unsigned short getAnimationDuration(std::string const& name) const + { + std::map::const_iterator it = m_animationIndexPerName.find(name); + return (m_animationIndexPerName.end() != it) ? (it->secondsecond].duration : 0 : 0; + } + void setupPaletteNames(std::map & matrixNames) + { + for (std::map::iterator itNode = m_skelettonNodeNames.begin(); + itNode != m_skelettonNodeNames.end(); itNode++) + { + matrixNames.insert(std::map::value_type(itNode->second, itNode->first)); + } + } + + void setupFrame(std::string const& name, float frame) + { + std::map::const_iterator it = m_animationIndexPerName.find(name); + + unsigned int animationIndex = (m_animationIndexPerName.end() != it) ? it->second : ~0; + + EMAAnimation *currentAnimation = (animationIndexduration) - (integerFrame - frame); + for (EMAData::SkelettonNodePerNumberMap::iterator itNode = m_skelettonNodes.begin(); + itNode != m_skelettonNodes.end(); itNode++) + { + EMASkelettonNode & node = itNode->second; + + decomposeMatrix(node.rotation, node.scale, node.translation, node.matrix, node.rotationQuaternion); + + node.animationProcessingDone = false; + node.animatedAbsoluteRotationFlag = false; + node.animatedAbsoluteScaleFlag = false; + node.animatedAbsoluteTranslationFlag = false; + memset(node.animatedRotation, 0, 3 * sizeof(float)); + memset(node.animatedScale, 0, 3 * sizeof(float)); + memset(node.animatedTranslation, 0, 3 * sizeof(float)); + memset(node.animatedRotationQuaternion, 0, 4 * sizeof(float)); + memset(node.animatedMatrix, 0, 16 * sizeof(float)); + + // rotation + node.animatedRotationQuaternion[3] = 1.0; + // scale + node.animatedScale[0] = 1.0; + node.animatedScale[1] = 1.0; + node.animatedScale[2] = 1.0; + // matrix + node.animatedMatrix[0] = 1.0; + node.animatedMatrix[5] = 1.0; + node.animatedMatrix[10] = 1.0; + node.animatedMatrix[15] = 1.0; + // flags + node.update_flags = 0; + + if (currentAnimation != 0) + { + CommandsPerComponentPerTypePerBone::const_iterator boneCommandsIt = currentAnimation->commandsPerComponentPerTypePerBone.find(node.number); + if (currentAnimation->commandsPerComponentPerTypePerBone.end() != boneCommandsIt) + { + CommandsPerComponentPerType const& commandsPerComponentPerType = boneCommandsIt->second; + + // translation + if (getTransform(*currentAnimation, boneCommandsIt->second, EMAData::E_TRANSLATION, frameFixed, node.animatedTranslation, node.animatedAbsoluteTranslationFlag)) + { + if (node.animatedAbsoluteTranslationFlag) + node.update_flags |= 0x00010000; + else + node.update_flags |= 0x00000001; + } + + // rotation + if (getTransform(*currentAnimation, boneCommandsIt->second, EMAData::E_ROTATION, frameFixed, node.animatedRotation, node.animatedAbsoluteRotationFlag)) + { + eulerToQuaternionXYZ( + node.animatedRotation[1] * (float)(M_PI / 180.), + node.animatedRotation[2] * (float)(M_PI / 180.), + node.animatedRotation[0] * (float)(M_PI / 180.), + node.animatedRotationQuaternion); + + if (node.animatedAbsoluteRotationFlag) + node.update_flags |= 0x00020000; + else + node.update_flags |= 0x00000002; + } + + // scale + if (getTransform(*currentAnimation, boneCommandsIt->second, EMAData::E_SCALING, frameFixed, node.animatedScale, node.animatedAbsoluteScaleFlag)) + { + if (node.animatedAbsoluteScaleFlag) + node.update_flags |= 0x00040000; + else + node.update_flags |= 0x00000004; + } + } + } + + // translation + if (node.update_flags & 0x00010001) + { + memcpy(node.translation, node.animatedTranslation, 3 * sizeof(float)); + } + else + { + memcpy(node.animatedTranslation, node.translation, 3 * sizeof(float)); + } + + // rotation + if (node.update_flags & 0x00020002) + { + memcpy(node.rotation, node.animatedRotation, 3 * sizeof(float)); + memcpy(node.rotationQuaternion, node.animatedRotationQuaternion, 4 * sizeof(float)); + } + else + { + memcpy(node.animatedRotation, node.rotation, 3 * sizeof(float)); + memcpy(node.animatedRotationQuaternion, node.rotationQuaternion, 4 * sizeof(float)); + } + + // scale + if (node.update_flags & 0x00040004) + { + memcpy(node.scale, node.animatedScale, 3 * sizeof(float)); + } + else + { + memcpy(node.animatedScale, node.scale, 3 * sizeof(float)); + } + + // transform matrix + composeMatrixQuat(D3DXQUATERNION(node.animatedRotationQuaternion), node.animatedScale, node.animatedTranslation, node.animatedMatrix); + memcpy(node.matrix, node.animatedMatrix, 16 * sizeof(float)); + } + } + + template + F hermiteInterpolation(F P1, F T1, F P2, F T2, F s) + { + F s2 = s*s; + F s3 = s*s*s; + F h1 = 2 * s3 - 3 * s2 + 1; // calculate basis function 1 + F h2 = -2 * s3 + 3 * s2; // calculate basis function 2 + F h3 = s3 - 2 * s2 + s; // calculate basis function 3 + F h4 = s3 - s2; // calculate basis function 4 + return h1*P1 + // multiply and sum all funtions + h2*P2 + // together to build the interpolated + h3*T1 + // point along the curve. + h4*T2; + } + + bool getTransform(EMAAnimation const& currentAnimation, CommandsPerComponentPerType const& commandsPerComponentPerType, EMAData::ETransformType type, float frame, float values[3], bool& globalValueFlag) + { + bool animated = false; + CommandsPerComponentPerType::const_iterator itCommandsPerType = commandsPerComponentPerType.find(type); + if (itCommandsPerType != commandsPerComponentPerType.end()) + { + CommandsPerComponent const& commandsPerComponent(itCommandsPerType->second); + for (CommandsPerComponent::const_iterator itCommandsPerComponent = commandsPerComponent.begin(); + itCommandsPerComponent != commandsPerComponent.end(); + ++itCommandsPerComponent) + { + if (itCommandsPerComponent->first >= 3) + { + continue; + } + Commands const& commands(itCommandsPerComponent->second); + CommandSequence const& commandSequence(commands.steps); + //there is always a step 0 at first (so we have a new step 0 when there is no animation) + std::vector::const_iterator itStep = commandSequence.begin(); + std::vector::const_iterator itPrevStep = itStep; + ++itStep; + for (; itStep != commandSequence.end(); itPrevStep = itStep, ++itStep) + { + if (((float)itStep->timing) >= frame) + { + float s = (frame - (float)itPrevStep->timing) / (float)(itStep->timing - itPrevStep->timing); // scale goes from 0 to 1 + float P1 = currentAnimation.values[itPrevStep->index]; + float P2 = currentAnimation.values[itStep->index]; + float T1 = (itPrevStep->tangentIndex == ~0) ? 0.f : currentAnimation.values[itPrevStep->tangentIndex]; + float T2 = (itStep->tangentIndex == ~0) ? 0.f : currentAnimation.values[itStep->tangentIndex]; + values[itCommandsPerComponent->first] = hermiteInterpolation(P1, T1, P2, T2, s); + globalValueFlag |= commands.absolute; + animated = true; + break; + } + } + } + } + return animated; + } + static std::string readZeroTerminatedString(std::istream& file) + { + std::string s; + char c; + for (;;) + { + file.read(reinterpret_cast(&c), sizeof (char)); + if (c) + { + s.push_back(c); + } + else + { + break; + } + } + return s; + } + bool readAnimation(EMAAnimation& currentAnimation, std::istream& file, unsigned long animationBlockOffset) + { + currentAnimation.commandsPerComponentPerTypePerBone.clear(); + currentAnimation.values.clear(); + + file.seekg(animationBlockOffset, std::ios::beg); + file.read(reinterpret_cast(&m_animationHeader), sizeof (EMAAnimationHeader)); + + std::vector cmdOffsets; + cmdOffsets.resize(m_animationHeader.cmdOffsetCount); + file.read(reinterpret_cast(&cmdOffsets.front()), sizeof (unsigned long)* m_animationHeader.cmdOffsetCount); + + //second half of the animation (float values) + file.seekg(animationBlockOffset + m_animationHeader.valuesOffset, std::ios::beg); + currentAnimation.values.resize(m_animationHeader.valueCount); + file.read(reinterpret_cast(¤tAnimation.values.front()), sizeof (float)* m_animationHeader.valueCount); + + currentAnimation.duration = m_animationHeader.duration; + + //animation name + file.seekg(animationBlockOffset + m_animationHeader.nameOffset + 10, std::ios::beg); + + unsigned char stringLen; + file.read(reinterpret_cast(&stringLen), sizeof (unsigned char)); + + char* str = new char[stringLen + 1]; + str[stringLen] = 0; + file.read(reinterpret_cast(str), sizeof (char)* stringLen); + currentAnimation.name = str; + + for (unsigned long i = 0; i(&commandHeader), sizeof (EMAAnimationCommandHeader)); + + EMAData::ETransformType transformType = + commandHeader.transformType == 0 ? EMAData::E_TRANSLATION + : commandHeader.transformType == 1 ? EMAData::E_ROTATION + : commandHeader.transformType == 2 ? EMAData::E_SCALING + : EMAData::E_NOP; + unsigned char transformComponent = commandHeader.flags & 0x03; + CommandsPerComponentPerType &commandsPerComponentPerType = currentAnimation.commandsPerComponentPerTypePerBone[commandHeader.boneIndex]; + CommandsPerComponent &commandsPerComponent = commandsPerComponentPerType[transformType]; + Commands& commands = commandsPerComponent[transformComponent]; + CommandSequence& commandSequence(commands.steps); + commands.absolute = (commandHeader.flags & 0x10) != 0; + + commands.steps.resize(commandHeader.stepCount); + + unsigned int readBytes = 0; + if (commandHeader.flags & 0x20) + { + for (CommandSequence::iterator itStep = commandSequence.begin(); itStep != commandSequence.end(); ++itStep) + { + unsigned short timing16; + file.read(reinterpret_cast(&timing16), sizeof (unsigned short)); + readBytes += sizeof (unsigned short); + itStep->timing = timing16; + } + } + else + { + for (CommandSequence::iterator itStep = commandSequence.begin(); itStep != commandSequence.end(); ++itStep) + { + unsigned char timing8; + file.read(reinterpret_cast(&timing8), sizeof (unsigned char)); + readBytes += sizeof (unsigned char); + itStep->timing = timing8; + } + } + if (readBytes(&index), sizeof (unsigned long)); + itStep->index = (index & 0x3FFFFFFF); + unsigned char highOrderBits = ((index >> 30) & 0x03); + itStep->tangentIndex = highOrderBits == 0 ? ~0 : (itStep->index + highOrderBits); + } + } + else + { + for (CommandSequence::iterator itStep = commandSequence.begin(); itStep != commandSequence.end(); ++itStep) + { + unsigned short index16; + file.read(reinterpret_cast(&index16), sizeof (unsigned short)); + itStep->index = (index16 & 0x3FFF); + unsigned char highOrderBits = ((index16 >> 14) & 0x03); + itStep->tangentIndex = highOrderBits == 0 ? ~0 : (itStep->index + highOrderBits); + } + } + } + return true; + } + + bool load(std::string emaFileName, unsigned long emaBlockOffset) + { + freeData(); + + std::ifstream file(emaFileName.c_str(), std::ios::in | std::ios::binary); + if (file.bad()) + { + return false; + } + char tokenEMA[5]; + tokenEMA[4] = 0; + file.seekg(emaBlockOffset, std::ios::beg); + file.read(reinterpret_cast(reinterpret_cast(tokenEMA)), sizeof (unsigned char)* 4); + if (strcmp("#EMA", tokenEMA) != 0) + { + file.close(); + return false; + } + + //#EMA -> base skeleton pose + + file.seekg(emaBlockOffset + 6, std::ios::beg); + unsigned short headerSize; + file.read(reinterpret_cast(&headerSize), sizeof (unsigned short)); + + file.seekg(emaBlockOffset + 12, std::ios::beg); + unsigned long skeletonOffset; + file.read(reinterpret_cast(&skeletonOffset), sizeof (unsigned long)); + + file.seekg(emaBlockOffset + 16, std::ios::beg); + unsigned short animationCount; + file.read(reinterpret_cast(&animationCount), sizeof (unsigned short)); + + std::vector animationDataAddresses; + animationDataAddresses.resize(animationCount); + file.seekg(emaBlockOffset + headerSize, std::ios::beg); + file.read(reinterpret_cast(&animationDataAddresses.front()), sizeof (unsigned long)*animationCount); + + unsigned long skeletonAdress = emaBlockOffset + skeletonOffset; + + file.seekg(skeletonAdress, std::ios::beg); + EMASkelettonHeader skelettonHeader; + file.read(reinterpret_cast(&skelettonHeader), sizeof (EMASkelettonHeader)); + + m_nodeCount = skelettonHeader.nodeCount; + + std::vector skeletonNameAddresses; + skeletonNameAddresses.resize(m_nodeCount); + file.seekg(skeletonAdress + skelettonHeader.skeletonNameAddressOffset, std::ios::beg); + file.read(reinterpret_cast(&skeletonNameAddresses.front()), sizeof (unsigned long)*m_nodeCount); + + for (unsigned int i = 0; i::value_type(i, readZeroTerminatedString(file))); + } + + //Nodes + file.seekg(skeletonAdress + skelettonHeader.skeletonStartOffset, std::ios::beg); + for (unsigned int i = 0; i(&skelettonNodeTemp), sizeof (EMASkelettonNodeTemp)); + + EMASkelettonNode skelettonNode; + skelettonNode.number = i; + skelettonNode.parent = skelettonNodeTemp.parent; + skelettonNode.child1 = skelettonNodeTemp.child1; + skelettonNode.sibling = skelettonNodeTemp.child2; + skelettonNode.flags = skelettonNodeTemp.flags; + skelettonNode.unknownScale = skelettonNodeTemp.unknown4; + memcpy(skelettonNode.matrix, skelettonNodeTemp.matrix, 16 * sizeof(float)); + + decomposeMatrix(skelettonNode.rotation, skelettonNode.scale, skelettonNode.translation, skelettonNode.matrix, skelettonNode.rotationQuaternion); + + m_skelettonNodes.insert(SkelettonNodePerNumberMap::value_type(i, skelettonNode)); + } + + //Matrix + if (skelettonHeader.matrixOffset != 0) + { + file.seekg(skeletonAdress + skelettonHeader.matrixOffset, std::ios::beg); + file.read(reinterpret_cast(m_matrix), sizeof (float)* 16); + // [m00 m01 m02] + // [m10 m11 m12] + // [m20 m21 m22] + // heading = Math.atan2(-m.m20,m.m00); + // bank = Math.atan2(-m.m12,m.m11); + // attitude = Math.asin(m.m10); + float translation[] = { -m_matrix[12], m_matrix[14], m_matrix[13] }; + float rx = atan2(-m_matrix[2], m_matrix[0]); + float ry = atan2(-m_matrix[9], m_matrix[5]); + float rz = asin(m_matrix[1]); + } + else + { + memset(m_matrix, 0, 16 * sizeof (float)); + m_matrix[0] = m_matrix[5] = m_matrix[10] = m_matrix[15] = 1.f; + } + + // read ik information + if (0 < skelettonHeader.ikDataCount && + 0 != skelettonHeader.ikDataOffset) + { + file.seekg(skeletonAdress + skelettonHeader.ikDataOffset, std::ios::beg); + + m_ikData.resize(skelettonHeader.ikDataCount); + + for (unsigned int i = 0; i(&m_ikData[i].method), sizeof (unsigned short)); + file.read(reinterpret_cast(&m_ikData[i].dataSize), sizeof (unsigned short)); + memset(m_ikData[i].data, 0, 0x20); + file.read(reinterpret_cast(m_ikData[i].data), sizeof (unsigned char)*min((m_ikData[i].dataSize - 4), 0x20)); + } + } + + // read animations + m_animations.resize(animationCount); + for (unsigned int i = 0; i < animationCount; ++i) + { + unsigned long animationBlockOffset = emaBlockOffset + animationDataAddresses[i]; + readAnimation(m_animations[i], file, animationBlockOffset); + m_animationIndexPerName.insert(std::map::value_type(m_animations[i].name, i)); + m_animationNames.push_back(m_animations[i].name); + } + + file.close(); + + return true; + } +}; + +class EMARenderer +{ + EMAData emaData; +public: + EMARenderer() + { + } + + bool setup(std::string emaFileName, unsigned long emaBlockOffset) + { + bool ok = emaData.load(emaFileName, emaBlockOffset); + return ok; + } + + std::vector const& getAnimationNames() const + { + return emaData.getAnimationNames(); + } + unsigned short getAnimationDuration(std::string const& name) const + { + return emaData.getAnimationDuration(name); + } + void setupPaletteNames(std::map & matrixNames) + { + emaData.setupPaletteNames(matrixNames); + } + + void updateDeviceObjects(std::string const& animationName, float frame, float(&structure)[500][6], std::string(&names)[500]) + { + std::map matrixPalette; + setupMatrixPalette(animationName, frame, matrixPalette); + EMAData::SkelettonNodePerNumberMap &skelettonNodes = emaData.m_skelettonNodes; + + for (EMAData::SkelettonNodePerNumberMap::const_iterator it = skelettonNodes.begin(); + it != skelettonNodes.end(); it++) + { + EMASkelettonNode const& node = it->second; + + std::map::const_iterator itNodeMatrix = matrixPalette.find(node.number); + std::map::const_iterator itParentNodeMatrix = matrixPalette.find(node.parent); + + int id = itNodeMatrix->first; + + if (itNodeMatrix == matrixPalette.end() || itParentNodeMatrix == matrixPalette.end()) + { + continue; + } + + D3DXMATRIX MatrixWorld(itNodeMatrix->second); + D3DXMATRIX MatrixParent(itParentNodeMatrix->second); + + D3DXMATRIX MatrixParentInverse; + D3DXMatrixInverse(&MatrixParentInverse, 0, &MatrixParent); + + D3DXMATRIX LocalMatrix = MatrixWorld * MatrixParentInverse; + + D3DXVECTOR3 translation, rotation, scale; + D3DXQUATERNION rotation_quaternion; + decomposeMatrix(rotation, scale, translation, LocalMatrix, rotation_quaternion); + + structure[id][0] = translation.x; + structure[id][1] = translation.y; + structure[id][2] = translation.z; + structure[id][3] = rotation.x * (float)(M_PI / 180.); + structure[id][4] = rotation.y * (float)(M_PI / 180.); + structure[id][5] = rotation.z * (float)(M_PI / 180.); + + std::map::const_iterator itRefSkeletonNodeName = emaData.m_skelettonNodeNames.find(node.number); + names[id] = itRefSkeletonNodeName->second; + }; + } + + void setupMatrixPalette(std::string const& name, float frame, std::map & matrixPalette) + { + EMAData::SkelettonNodePerNumberMap &skelettonNodes = emaData.m_skelettonNodes; + + emaData.setupFrame(name, frame); + + for (EMAData::SkelettonNodePerNumberMap::iterator it = skelettonNodes.begin(); it != skelettonNodes.end(); it++) + { + EMASkelettonNode & node = it->second; + update_node(node.number); + } + + for (unsigned long i = 0; i < emaData.m_ikData.size(); ++i) + { + updateIKData(i); + } + + for (EMAData::SkelettonNodePerNumberMap::iterator it = skelettonNodes.begin(); + it != skelettonNodes.end(); it++) + { + EMASkelettonNode & node = it->second; + update_node(node.number); + + matrixPalette.insert(std::map::value_type(node.number, D3DXMATRIX(node.animatedMatrix))); + }; + } + + template + bool update_node(unsigned short nodeNumber) + { + EMAData::SkelettonNodePerNumberMap &skelettonNodes = emaData.m_skelettonNodes; + EMAData::SkelettonNodePerNumberMap::iterator nodeIt = skelettonNodes.find(nodeNumber); + if (skelettonNodes.end() != nodeIt) + { + EMASkelettonNode & node = nodeIt->second; + unsigned short parentNumber = node.parent; + + const EMASkelettonNode * parent_node = NULL; + EMAData::SkelettonNodePerNumberMap::const_iterator parentIt = skelettonNodes.find(parentNumber); + if (skelettonNodes.end() != parentIt) + { + parent_node = &parentIt->second; + } + + if (update_parent && parent_node) + { + update_node(parent_node->number); + } + + bool update = false; + + if (initialize) + { + update = (update_parent || (node.flags & 0x00008004) == 0); + update = update && ((node.update_flags & 0x80000000) == 0); + update = update && ((parentNumber == 0xFFFF) || (parent_node && (parent_node->update_flags & 0x80000000)) != 0); + } + else + { + update = (parentNumber != 0xFFFF) && ((node.update_flags & 0x70000000) == 0); + } + + if (!update) + { + if (!initialize) + { + update_node(node.sibling); + } + + return ((node.update_flags & 0x80000000) != 0); + } + + D3DXMATRIX matrix(node.matrix); + + D3DXVECTOR3 translation, rotation, scale; + D3DXQUATERNION rotation_quaternion; + + decomposeMatrix(rotation, scale, translation, matrix, rotation_quaternion); + + // translation + { + if ((node.update_flags & 0x00010001) != 0) + translation = node.translation; + else + translation = translation; + + if (parent_node && (node.update_flags & 0x00010000) == 0) + { + D3DXVec3TransformCoord(&translation, &translation, &D3DXMATRIX(parent_node->animatedMatrix)); + } + } + + // rotation + { + if ((node.update_flags & 0x00020002) != 0) + rotation_quaternion = D3DXQUATERNION(node.rotationQuaternion); + else + rotation_quaternion = rotation_quaternion; + + if (parent_node && (node.update_flags & 0x00020000) == 0) + { + rotation_quaternion *= D3DXQUATERNION(parent_node->animatedRotationQuaternion); + } + } + + // scale + { + if ((node.update_flags & 0x00040004) != 0) + scale = D3DXVECTOR3(node.scale); + else + scale = D3DXVECTOR3(1, 1, 1); + + if (parent_node && (node.update_flags & 0x00040000) == 0) + { + scale.x *= parent_node->animatedScale[0]; + scale.y *= parent_node->animatedScale[1]; + scale.z *= parent_node->animatedScale[2]; + } + } + + // matrix + composeMatrixQuat(rotation_quaternion, scale, translation, matrix); + + memcpy(node.animatedScale, (float*)scale, 3 * sizeof(float)); + memcpy(node.animatedTranslation, (float*)translation, 3 * sizeof(float)); + memcpy(node.animatedRotationQuaternion, (float*)rotation_quaternion, 4 * sizeof(float)); + memcpy(node.animatedMatrix, (float*)matrix, 16 * sizeof(float)); + + node.animationProcessingDone = true; + node.update_flags |= 0x80000000; + + if (!initialize) + { + update_node(node.child1); + update_node(node.sibling); + } + + return true; + } + + return false; + } + + template + T lerp(T const& _in1, T const& _in2, const float& _a) + { + return _in1 + (_in2 - _in1) * _a; + } + + D3DXVECTOR4 var_xmm0; + D3DXVECTOR4 var_xmm1; + D3DXVECTOR4 var_xmm2; + D3DXVECTOR4 var_xmm3; + D3DXVECTOR4 var_xmm4; + + D3DXMATRIX * D3DXMatrixCreate(D3DXMATRIX * pM, D3DXVECTOR4 const* pV1, D3DXVECTOR4 const* pV2, D3DXVECTOR4 const* pV3, D3DXVECTOR4 const* pV4) + { + // + pM->_11 = pV1->x; + pM->_12 = pV1->y; + pM->_13 = pV1->z; + pM->_14 = pV1->w; + + // + pM->_21 = pV2->x; + pM->_22 = pV2->y; + pM->_23 = pV2->z; + pM->_24 = pV2->w; + + // + pM->_31 = pV3->x; + pM->_32 = pV3->y; + pM->_33 = pV3->z; + pM->_34 = pV3->w; + + // + pM->_41 = pV4->x; + pM->_42 = pV4->y; + pM->_43 = pV4->z; + pM->_44 = pV4->w; + + return pM; + } + + D3DXVECTOR4* D3DXVec4Multiply(D3DXVECTOR4* pOut, D3DXVECTOR4 const* pVec1, D3DXVECTOR4 const* pVec2) + { + pOut->x = pVec1->x * pVec2->x; + pOut->y = pVec1->y * pVec2->y; + pOut->z = pVec1->z * pVec2->z; + pOut->w = pVec1->w * pVec2->w; + + return pOut; + } + + D3DXMATRIX * sub_504330(D3DXMATRIX * pM_ECX, D3DXVECTOR4 const* pV1_ESI, D3DXVECTOR4 const* pV2) + { + D3DXVECTOR4 var_60 = D3DXVECTOR4(0, 0, 0, 0); + D3DXVECTOR4 var_50 = D3DXVECTOR4(0, 0, 0, 0); + D3DXVECTOR4 var_40 = D3DXVECTOR4(0, 0, 0, 0); + D3DXVECTOR4 var_30 = D3DXVECTOR4(0, 0, 0, 0); + D3DXVECTOR4 var_20 = D3DXVECTOR4(0, 0, 0, 0); + D3DXVECTOR4 var_10 = D3DXVECTOR4(0, 0, 0, 0); + + // + // var_xmm0 = D3DXVECTOR4(pV1_ESI->y, 0, 0, 0); + // float var_74 = 0.0f; + // float var_78 = pV1_ESI->x; + // float var_7C = pV1_ESI->z; + + var_60 = D3DXVECTOR4(pV1_ESI->y, pV1_ESI->z, pV1_ESI->x, 0); + + // + // var_xmm0 = D3DXVECTOR4(pV1_ESI->z, 0, 0, 0); + // float var_74 = 0.0f; + // float var_78 = pV1_ESI->y; + // float var_7C = pV1_ESI->x; + + var_30 = D3DXVECTOR4(pV1_ESI->z, pV1_ESI->x, pV1_ESI->y, 0); + + // + var_50.z = 1.0f - pV2->y; + // var_xmm0 = D3DXVECTOR4(pV2->x, 0, 0, 0); + // float var_74 = pV2->x; + // float var_78 = pV2->x; + // float var_7C = pV2->x; + + var_10 = D3DXVECTOR4(pV2->x, pV2->x, pV2->x, pV2->x); + + // + // var_xmm0 = D3DXVECTOR4(pV2->y, 0, 0, 0); + // float var_74 = pV2->y; + // float var_78 = pV2->y; + // float var_7C = pV2->y; + + var_20 = D3DXVECTOR4(pV2->y, pV2->y, pV2->y, pV2->y); + + // + // var_xmm0 = D3DXVECTOR4(var_50.z, 0, 0, 0); + // float var_74 = var_50.z; + // float var_78 = var_50.z; + // float var_7C = var_50.z; + + var_50 = D3DXVECTOR4(var_50.z, var_50.z, var_50.z, var_50.z); + + // + // var_xmm0 = D3DXVECTOR4(pV2->x, 0, 0, 0); + // float var_74 = pV2->x; + // float var_78 = pV2->x; + // float var_7C = pV2->x; + + var_40 = D3DXVECTOR4(pV2->x, pV2->x, pV2->x, pV2->x); + + // var_xmm1 = var_50; + // var_xmm2 = var_60; + + D3DXVec4Multiply(&var_xmm0, &var_50, &var_60); + + // var_xmm2 = *pV1_ESI; + + D3DXVec4Multiply(&var_xmm2, &var_50, pV1_ESI); + + // var_xmm1 = var_30; + + D3DXVec4Multiply(&var_xmm0, &var_xmm0, &var_30); + + D3DXVec4Multiply(&var_xmm1, pV1_ESI, &var_xmm2); + + D3DXVec4Add(&var_xmm1, &var_xmm1, &var_20); + + // var_xmm2 = var_40; + + var_50 = var_xmm1; + var_30 = var_xmm0; + + D3DXVec4Multiply(&var_xmm1, pV1_ESI, &var_40); + D3DXVec4Add(&var_xmm1, &var_xmm1, &var_xmm0); + + var_40 = var_xmm1; + + D3DXVec4Multiply(&var_xmm0, pV1_ESI, &var_10); + + D3DXVec4Subtract(&var_60, &var_xmm0, &var_30); + + var_60 = -var_60; + + // + pM_ECX->_11 = var_50.x; + pM_ECX->_12 = var_40.z; + pM_ECX->_13 = var_60.y; + pM_ECX->_14 = 0.0f; + + // + pM_ECX->_21 = var_60.z; + pM_ECX->_22 = var_50.y; + pM_ECX->_23 = var_40.x; + pM_ECX->_24 = 0.0f; + + // + pM_ECX->_31 = var_40.y; + pM_ECX->_32 = var_60.x; + pM_ECX->_33 = var_50.z; + pM_ECX->_34 = 0.0f; + + // + pM_ECX->_41 = 0.0f; + pM_ECX->_42 = 0.0f; + pM_ECX->_43 = 0.0f; + pM_ECX->_44 = 1.0f; + + return pM_ECX; + } + + bool updateIKData(unsigned long const& ikNumber) + { + bool bResult = false; + if (ikNumber < emaData.m_ikData.size()) + { + EMASkeletonIKData const& ikData = emaData.m_ikData.at(ikNumber); + + switch (ikData.method) + { + case 0x00: + { + switch (ikData.data[0]) + { + case 0x02: + { + processIKData0x00_02(ikData); + bResult = true; + } break; + } + } break; + case 0x01: + { + processIKData0x01_00(ikData); + bResult = true; + } break; + } + } + + return bResult; + } + void processIKData0x00_02(EMASkeletonIKData const& ikData) + { + EMAData::SkelettonNodePerNumberMap &skelettonNodes = emaData.m_skelettonNodes; + WORD index0 = *((WORD*)(ikData.data + 0x02)); + EMAData::SkelettonNodePerNumberMap::iterator nodeIt = skelettonNodes.find(index0); + EMASkelettonNode * nodeP = NULL; + EMASkelettonNode * node0 = NULL; + if (skelettonNodes.end() != nodeIt) + { + node0 = &(nodeIt->second); + + // get parent node + nodeIt = skelettonNodes.find(node0->parent); + if (skelettonNodes.end() != nodeIt) + { + nodeP = &(nodeIt->second); + } + } + WORD index1 = *((WORD*)(ikData.data + 0x04)); + nodeIt = skelettonNodes.find(index1); + EMASkelettonNode * node1 = NULL; + if (skelettonNodes.end() != nodeIt) + { + node1 = &(nodeIt->second); + } + WORD index2 = *((WORD*)(ikData.data + 0x06)); + nodeIt = skelettonNodes.find(index2); + EMASkelettonNode * node2 = NULL; + if (skelettonNodes.end() != nodeIt) + { + node2 = &(nodeIt->second); + } + WORD index3 = *((WORD*)(ikData.data + 0x08)); + nodeIt = skelettonNodes.find(index3); + EMASkelettonNode * node3 = NULL; + if (skelettonNodes.end() != nodeIt) + { + node3 = &(nodeIt->second); + } + WORD index4 = *((WORD*)(ikData.data + 0x0A)); + nodeIt = skelettonNodes.find(index4); + EMASkelettonNode * node4 = NULL; + if (skelettonNodes.end() != nodeIt) + { + node4 = &(nodeIt->second); + } + + if (!nodeP || !node0 || !node1 || !node2 || !node3 || !node4) + { + return; + } + + node3->update_flags |= 0x10000000; + node4->update_flags |= 0x20000000; + + // sub_524390 + { + D3DXVECTOR4 var_F0 = D3DXVECTOR4(0, 0, 0, 0); + D3DXVECTOR4 var_D0 = D3DXVECTOR4(0, 0, 0, 0); + D3DXVECTOR4 var_C0 = D3DXVECTOR4(0, 0, 0, 0); + D3DXVECTOR4 var_B0 = D3DXVECTOR4(0, 0, 0, 0); + D3DXVECTOR4 var_A0 = D3DXVECTOR4(0, 0, 0, 1); + + D3DXVECTOR4 var_140 = D3DXVECTOR4(0, 0, 0, 0); + D3DXVECTOR4 var_120 = D3DXVECTOR4(0, 0, 0, 0); + D3DXVECTOR4 var_100 = D3DXVECTOR4(0, 0, 0, 0); + D3DXVECTOR4 var_90 = D3DXVECTOR4(0, 0, 0, 0); + + // update bone index unknown0x08 + update_node(node1->number); + // update bone index unknown0x0A + update_node(node2->number); + + var_100 = D3DXVECTOR4(D3DXVECTOR3(node0->animatedTranslation), 1); // position unknown0x06 + var_120 = D3DXVECTOR4(D3DXVECTOR3(node3->animatedTranslation), 1); // position unknown0x0C + var_140 = D3DXVECTOR4(D3DXVECTOR3(node4->animatedTranslation), 1); // position unknown0x0E + + D3DXVec4Subtract(&var_120, &var_120, &var_100); + D3DXVec4Subtract(&var_140, &var_140, &var_100); + + D3DXVec3Cross((D3DXVECTOR3*)&var_F0, (D3DXVECTOR3*)&var_140, (D3DXVECTOR3*)&var_120); + D3DXVec3Cross((D3DXVECTOR3*)&var_140, (D3DXVECTOR3*)&var_F0, (D3DXVECTOR3*)&var_120); + + if (ikData.data[1] & 0x01) + { + var_F0 = -var_F0; + var_140 = -var_140; + } + + D3DXVec4Normalize(&var_D0, &var_120); + D3DXVec4Normalize(&var_C0, &var_140); + D3DXVec4Normalize(&var_B0, &var_F0); + + var_A0 = var_100; + + var_xmm4 = D3DXVECTOR4(D3DXVec4Length(&var_120), 0, 0, 0); + + D3DXVECTOR4 scale0x08 = D3DXVECTOR4(D3DXVECTOR3(node1->animatedScale), 1); + D3DXVECTOR4 scale0x0A = D3DXVECTOR4(D3DXVECTOR3(node2->animatedScale), 1); + + const float xScale0x08 = scale0x08.x, unkScale0x08 = node1->unknownScale; // 1.0f; + const float xScale0x0A = scale0x0A.x, unkScale0x0A = node2->unknownScale; // 1.0f; + + var_xmm1 = D3DXVECTOR4((xScale0x08 * unkScale0x08), 0, 0, 0); + var_xmm3 = D3DXVECTOR4(var_xmm4.x, var_xmm1.x, 0, 0); + var_xmm2 = D3DXVECTOR4((xScale0x0A * unkScale0x0A), 0, 0, 0); + + float var_104 = var_xmm1.x; + var_xmm1 = D3DXVECTOR4(var_xmm1.x, var_xmm2.x, 0, 0); + var_xmm2 = D3DXVECTOR4(var_xmm2.x, var_xmm4.x, 0, 0); + + // movaps var_100, xmm1 + var_100 = var_xmm1; + + // movaps xmm4, xmm3 + var_xmm4 = var_xmm3; + + // mulps xmm1, xmm1 + D3DXVec4Multiply(&var_xmm1, &var_xmm1, &var_xmm1); + // mulps xmm4, xmm3 + D3DXVec4Multiply(&var_xmm4, &var_xmm4, &var_xmm3); + // movaps var_90, xmm3 + var_90 = var_xmm3; + // mulps xmm2, xmm2 + D3DXVec4Multiply(&var_xmm2, &var_xmm2, &var_xmm2); + // addps xmm4, xmm1 + D3DXVec4Add(&var_xmm4, &var_xmm4, &var_xmm1); + // movss xmm1, 0.5 + var_xmm1 = D3DXVECTOR4(0.5, 0, 0, 0); + + // movss xmm3, var_100.y + var_xmm3 = D3DXVECTOR4(var_100.y, 0, 0, 0); + var_xmm3.x *= var_90.y; + // subps xmm4, xmm2 + D3DXVec4Subtract(&var_xmm4, &var_xmm4, &var_xmm2); + // movss xmm2, var_100.x + var_xmm2 = D3DXVECTOR4(var_100.x, 0, 0, 0); + var_xmm2.x *= var_90.x; + // shufps xmm1, xmm1, 0 + var_xmm1 = D3DXVECTOR4(0.5, 0.5, 0.5, 0.5); + // mulps xmm4, xmm1 + D3DXVec4Multiply(&var_xmm4, &var_xmm4, &var_xmm1); + // movaps var_120, xmm4 + var_120 = var_xmm4; + // movss xmm1, var_120.x + var_xmm1 = D3DXVECTOR4(var_120.x, 0, 0, 0); + // movss xxm4, 1 + var_xmm4 = D3DXVECTOR4(1, 0, 0, 0); + // divss xmm1, xmm2 + var_xmm1.x /= var_xmm2.x; + // movss xmm2, var_120.y + var_xmm2 = D3DXVECTOR4(var_120.y, 0, 0, 0); + // divss xmm2, xmm3 + var_xmm2.x /= var_xmm3.x; + // movss xxm3, -1 + var_xmm3 = D3DXVECTOR4(-1, 0, 0, 0); + // movss var_120.x, xmm1 + var_120.x = var_xmm1.x; + // movss var_120.y, xmm2 + var_120.y = var_xmm2.x; + + if (var_xmm3.x > var_xmm1.x) + { + var_120.x = var_xmm3.x; + } + else if (var_xmm4.x < var_xmm1.x) + { + var_120.x = var_xmm4.x; + } + + if (var_xmm3.x > var_xmm2.x) + { + var_120.y = var_xmm3.x; + } + else if (var_xmm4.x < var_xmm2.x) + { + var_120.y = var_xmm4.x; + } + // movaps xmm1, var_120 + var_xmm1 = var_120; + + var_xmm0 = D3DXVECTOR4(1, 1, 0, 0); // D3DXVECTOR4(var_xmm4.x, var_xmm4.x); + // mulps xmm1, xmm1 + D3DXVec4Multiply(&var_xmm1, &var_xmm1, &var_xmm1); + // subps xmm0, xmm1 + D3DXVec4Subtract(&var_xmm0, &var_xmm0, &var_xmm1); + // + var_140 = D3DXVECTOR4(sqrtf(var_xmm0.x), sqrtf(var_xmm0.y), 0, 0); + + var_xmm0 = D3DXVECTOR4(0, 0, 0, 0); + + var_F0 = D3DXVECTOR4(0, 0, -1, 0); + + D3DXMATRIX var_80, var_40; + // lea esi, var_F0 + // lea ecx, var_80 + sub_504330(&var_80, &var_F0, &D3DXVECTOR4(var_140.x, var_120.x, 0, 0)); + + // lea esi, var_F0 + // lea ecx, var_40 + sub_504330(&var_40, &var_F0, &D3DXVECTOR4(-var_140.y, -var_120.y, 0, 0)); + + D3DXMATRIX mat_D0; + D3DXMatrixCreate(&mat_D0, &var_D0, &var_C0, &var_B0, &var_A0); + D3DXMatrixMultiply(&var_80, &var_80, &mat_D0); + + D3DXMATRIX mat_bone0x08; + + // bone matrix = bone scale matrix * mat_80 + + D3DXMatrixScaling(&mat_bone0x08, scale0x08.x, scale0x08.y, scale0x08.z); + D3DXMatrixMultiply(&mat_bone0x08, &mat_bone0x08, &var_80); + + mat_D0 = var_80; + + var_100 = D3DXVECTOR4(var_104, 0, 0, 1); + // + // mat_D0 position = bone matrix position + mat_D0._41 = mat_bone0x08._41; + mat_D0._42 = mat_bone0x08._42; + mat_D0._43 = mat_bone0x08._43; + mat_D0._44 = mat_bone0x08._44; + + D3DXVec4Transform(&var_100, &var_100, &mat_D0); + // mat_D0 position = var_100 + mat_D0._41 = var_100.x; + mat_D0._42 = var_100.y; + mat_D0._43 = var_100.z; + mat_D0._44 = var_100.w; + + D3DXMatrixMultiply(&var_40, &var_40, &mat_D0); + + D3DXMATRIX mat_bone0x0A; + + // bone matrix = bone scale matrix * mat_80 + + D3DXMatrixScaling(&mat_bone0x0A, scale0x0A.x, scale0x0A.y, scale0x0A.z); + D3DXMatrixMultiply(&mat_bone0x0A, &mat_bone0x0A, &var_40); + + var_100 = D3DXVECTOR4(unkScale0x0A, 0, 0, 1); + + D3DXVec4Transform(&var_100, &var_100, &mat_bone0x0A); + + D3DXQUATERNION rotation; + + // update position and quaternion information for bone index 0x08 + D3DXQuaternionRotationMatrix(&rotation, &var_80); + + leftHandToEulerAnglesXYZ((float*)var_80, node1->animatedRotation[0], node1->animatedRotation[1], node1->animatedRotation[2]); + + memcpy(node1->animatedTranslation, (float*)(mat_bone0x08.m[3]), 3 * sizeof(float)); + memcpy(node1->animatedRotationQuaternion, (float*)rotation, 4 * sizeof(float)); + memcpy(node1->animatedMatrix, (float*)mat_bone0x08, 16 * sizeof(float)); + // set flags for absolute translation and rotation + node1->animationProcessingDone = true; + node1->animatedAbsoluteRotationFlag = true; + node1->animatedAbsoluteTranslationFlag = true; + node1->update_flags &= 0xFFFFFFFC; + node1->update_flags |= 0xC0003000; + + // update position and quaternion information for bone index 0x0A + D3DXQuaternionRotationMatrix(&rotation, &var_40); + + leftHandToEulerAnglesXYZ((float*)var_40, node2->animatedRotation[0], node2->animatedRotation[1], node2->animatedRotation[2]); + + memcpy(node2->animatedTranslation, (float*)(mat_bone0x0A.m[3]), 3 * sizeof(float)); + memcpy(node2->animatedRotationQuaternion, (float*)rotation, 4 * sizeof(float)); + memcpy(node2->animatedMatrix, (float*)mat_bone0x0A, 16 * sizeof(float)); + // set flags for absolute translation and rotation + node2->animationProcessingDone = true; + node2->animatedAbsoluteRotationFlag = true; + node2->animatedAbsoluteTranslationFlag = true; + node2->update_flags &= 0xFFFFFFFC; + node2->update_flags |= 0xC0003000; + + // update position for bone index 0x0C + memcpy(node3->animatedTranslation, (float*)var_100, 3 * sizeof(float)); + memcpy((node3->animatedMatrix + 0x0C), (float*)var_100, 3 * sizeof(float)); + // set flags for absolute translation + node3->animatedAbsoluteTranslationFlag = true; + node3->update_flags &= 0xFFFFFFFE; + node3->update_flags |= 0x00001000; + memcpy(node3->translation, node3->animatedTranslation, 3 * sizeof(float)); + + // update children of bone index 0x08 + update_node(node1->child1); + // update children of bone index 0x0A + update_node(node2->child1); + } + } + void processIKData0x01_00(EMASkeletonIKData const& ikData) + { + // sub_525270 + { + EMAData::SkelettonNodePerNumberMap &skelettonNodes = emaData.m_skelettonNodes; + EMAData::SkelettonNodePerNumberMap::iterator nodeIt = skelettonNodes.find(*((WORD*)(ikData.data + 0x02))); + EMASkelettonNode * nodeP = NULL; + EMASkelettonNode * node0 = NULL; + if (skelettonNodes.end() != nodeIt) + { + node0 = &(nodeIt->second); + + // get parent node + nodeIt = skelettonNodes.find(node0->parent); + if (skelettonNodes.end() != nodeIt) + { + nodeP = &(nodeIt->second); + } + } + nodeIt = skelettonNodes.find(*((WORD*)(ikData.data + 0x04))); + EMASkelettonNode * node1 = NULL; + if (skelettonNodes.end() != nodeIt) + { + node1 = &(nodeIt->second); + } + nodeIt = skelettonNodes.find(*((WORD*)(ikData.data + 0x06))); + EMASkelettonNode * node2 = NULL; + if (skelettonNodes.end() != nodeIt) + { + node2 = &(nodeIt->second); + } + + if (!nodeP || !node0 || !node1 || !node2) + { + return; + } + + // update bone index unknown0x08 + update_node(node1->number); + // update bone index unknown0x0A + update_node(node2->number); + // update bone index unknown0x06 parent + update_node(nodeP->number); + + D3DXVECTOR3 translation; + // if flags & 0x01 + if (ikData.data[1] & 0x01) + { + // - boneTransform0x06.position = lerp(boneTransform0x08.position, boneTransform0x0A.position, float0x0C); + translation = lerp(D3DXVECTOR3(node2->animatedTranslation), D3DXVECTOR3(node1->animatedTranslation), *((float*)(ikData.data + 0x0C))); + } + else + { + // - boneTransform0x06.position = boneTransform0x06.position * boneTransform0x06.parentTransform; + D3DXVec3TransformCoord(&translation, &D3DXVECTOR3(node0->translation), &D3DXMATRIX(nodeP->animatedMatrix)); + } + + D3DXQUATERNION rotation; + // if flags & 0x02 + if (ikData.data[1] & 0x02) + { + // - boneTransform0x06.rotation = slerp(boneTransform0x08.rotation, boneTransform0x0A.rotation, float0x10); + rotation = lerp(D3DXQUATERNION(node1->animatedRotationQuaternion), D3DXQUATERNION(node2->animatedRotationQuaternion), *((float*)(ikData.data + 0x10))); + } + else + { + // - boneTransform0x06.rotation = boneTransform0x06.roation * boneTransform0x06.parent.rotation + rotation = D3DXQUATERNION(node0->animatedRotationQuaternion) * D3DXQUATERNION(nodeP->animatedRotationQuaternion); + } + D3DXQuaternionNormalize(&rotation, &rotation); + + D3DXVECTOR3 scale; + // if flags & 0x04 + if (ikData.data[1] & 0x04) + { + // - boneTransform0x06.scale = lerp(boneTransform0x08.scale, boneTransform0x0A.scale, float0x14); + scale = lerp(D3DXVECTOR3(node2->animatedScale), D3DXVECTOR3(node1->animatedScale), *((float*)(ikData.data + 0x14))); + } + else + { + // - boneTransform0x06.scale = boneTransform0x06.parent.scale + scale = D3DXVECTOR3(nodeP->animatedScale); + } + + D3DXMATRIX matrix; + // update translation, rotation, and scale information for bone index 0x06 + composeMatrixQuat(rotation, scale, translation, matrix); + + leftHandToEulerAnglesXYZ((float*)matrix, node0->animatedRotation[0], node0->animatedRotation[1], node0->animatedRotation[2]); + + memcpy(node0->animatedScale, (float*)scale, 3 * sizeof(float)); + memcpy(node0->animatedTranslation, (float*)translation, 3 * sizeof(float)); + memcpy(node0->animatedRotationQuaternion, (float*)rotation, 4 * sizeof(float)); + memcpy(node0->animatedMatrix, (float*)matrix, 16 * sizeof(float)); + + // set flags for absolute translation, rotation, and scale + node0->animationProcessingDone = true; + node0->animatedAbsoluteRotationFlag = true; + node0->animatedAbsoluteTranslationFlag = true; + node0->animatedAbsoluteScaleFlag = true; + node0->update_flags &= 0xFFFFFFF8; + node0->update_flags |= 0x80007000; + memcpy(node0->rotation, node0->animatedRotation, 3 * sizeof(float)); + memcpy(node0->scale, node0->animatedScale, 3 * sizeof(float)); + memcpy(node0->translation, node0->animatedTranslation, 3 * sizeof(float)); + memcpy(node0->rotationQuaternion, node0->animatedRotationQuaternion, 4 * sizeof(float)); + + // update children of bone index 0x06 + update_node(node0->child1); + } + } +}; \ No newline at end of file diff --git a/D3D/resource.h b/D3D/resource.h new file mode 100644 index 0000000..413a836 --- /dev/null +++ b/D3D/resource.h @@ -0,0 +1,14 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by D3D.rc + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/README.md b/README.md new file mode 100644 index 0000000..a4318b7 --- /dev/null +++ b/README.md @@ -0,0 +1,11 @@ +# README # + +Super\Ultra Street Fighter 4 character model viewer and exporter. + +### Features ### + +* Character models and textures preview. +* Export models and animations to Studiomdl Data (SMD) file format. +* Export textures to DDS. + +31.10.2014 diff --git a/USF4ce.sln b/USF4ce.sln new file mode 100644 index 0000000..a593de0 --- /dev/null +++ b/USF4ce.sln @@ -0,0 +1,57 @@ +п»ї +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.26730.3 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "D3D", "D3D\D3D.vcxproj", "{01A3003A-08FD-4A54-8EB2-32F4BD558E28}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "USF4ce", "main\main.vcxproj", "{62CE09EC-B4BA-4E35-BBD7-112EC13BCCC4}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|Mixed Platforms = Debug|Mixed Platforms + Debug|Win32 = Debug|Win32 + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|Mixed Platforms = Release|Mixed Platforms + Release|Win32 = Release|Win32 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {01A3003A-08FD-4A54-8EB2-32F4BD558E28}.Debug|Any CPU.ActiveCfg = Debug|Win32 + {01A3003A-08FD-4A54-8EB2-32F4BD558E28}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 + {01A3003A-08FD-4A54-8EB2-32F4BD558E28}.Debug|Mixed Platforms.Build.0 = Debug|Win32 + {01A3003A-08FD-4A54-8EB2-32F4BD558E28}.Debug|Win32.ActiveCfg = Debug|Win32 + {01A3003A-08FD-4A54-8EB2-32F4BD558E28}.Debug|Win32.Build.0 = Debug|Win32 + {01A3003A-08FD-4A54-8EB2-32F4BD558E28}.Debug|x86.ActiveCfg = Debug|Win32 + {01A3003A-08FD-4A54-8EB2-32F4BD558E28}.Debug|x86.Build.0 = Debug|Win32 + {01A3003A-08FD-4A54-8EB2-32F4BD558E28}.Release|Any CPU.ActiveCfg = Release|Win32 + {01A3003A-08FD-4A54-8EB2-32F4BD558E28}.Release|Mixed Platforms.ActiveCfg = Release|Win32 + {01A3003A-08FD-4A54-8EB2-32F4BD558E28}.Release|Mixed Platforms.Build.0 = Release|Win32 + {01A3003A-08FD-4A54-8EB2-32F4BD558E28}.Release|Win32.ActiveCfg = Release|Win32 + {01A3003A-08FD-4A54-8EB2-32F4BD558E28}.Release|Win32.Build.0 = Release|Win32 + {01A3003A-08FD-4A54-8EB2-32F4BD558E28}.Release|x86.ActiveCfg = Release|Win32 + {01A3003A-08FD-4A54-8EB2-32F4BD558E28}.Release|x86.Build.0 = Release|Win32 + {62CE09EC-B4BA-4E35-BBD7-112EC13BCCC4}.Debug|Any CPU.ActiveCfg = Debug|Win32 + {62CE09EC-B4BA-4E35-BBD7-112EC13BCCC4}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 + {62CE09EC-B4BA-4E35-BBD7-112EC13BCCC4}.Debug|Mixed Platforms.Build.0 = Debug|Win32 + {62CE09EC-B4BA-4E35-BBD7-112EC13BCCC4}.Debug|Win32.ActiveCfg = Debug|Win32 + {62CE09EC-B4BA-4E35-BBD7-112EC13BCCC4}.Debug|Win32.Build.0 = Debug|Win32 + {62CE09EC-B4BA-4E35-BBD7-112EC13BCCC4}.Debug|x86.ActiveCfg = Debug|Win32 + {62CE09EC-B4BA-4E35-BBD7-112EC13BCCC4}.Debug|x86.Build.0 = Debug|Win32 + {62CE09EC-B4BA-4E35-BBD7-112EC13BCCC4}.Release|Any CPU.ActiveCfg = Release|Win32 + {62CE09EC-B4BA-4E35-BBD7-112EC13BCCC4}.Release|Mixed Platforms.ActiveCfg = Release|Win32 + {62CE09EC-B4BA-4E35-BBD7-112EC13BCCC4}.Release|Mixed Platforms.Build.0 = Release|Win32 + {62CE09EC-B4BA-4E35-BBD7-112EC13BCCC4}.Release|Win32.ActiveCfg = Release|Win32 + {62CE09EC-B4BA-4E35-BBD7-112EC13BCCC4}.Release|Win32.Build.0 = Release|Win32 + {62CE09EC-B4BA-4E35-BBD7-112EC13BCCC4}.Release|x86.ActiveCfg = Release|Win32 + {62CE09EC-B4BA-4E35-BBD7-112EC13BCCC4}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {B789573D-5118-4967-B3F2-4E94FB7AE4C8} + EndGlobalSection +EndGlobal diff --git a/main/AboutBox.cpp b/main/AboutBox.cpp new file mode 100644 index 0000000..53e2d46 --- /dev/null +++ b/main/AboutBox.cpp @@ -0,0 +1,2 @@ +#include "AboutBox.h" + diff --git a/main/AboutBox.h b/main/AboutBox.h new file mode 100644 index 0000000..8a19226 --- /dev/null +++ b/main/AboutBox.h @@ -0,0 +1,99 @@ +#pragma once + +namespace SSF4ce { + + using namespace System; + using namespace System::ComponentModel; + using namespace System::Collections; + using namespace System::Windows::Forms; + using namespace System::Data; + using namespace System::Drawing; + + /// + /// Summary for AboutBox + /// + public ref class AboutBox : public System::Windows::Forms::Form + { + public: + AboutBox(void) + { + InitializeComponent(); + // + //TODO: Add the constructor code here + // + } + + protected: + /// + /// Clean up any resources being used. + /// + ~AboutBox() + { + if (components) + { + delete components; + } + } + private: System::Windows::Forms::Button^ button1; + private: System::Windows::Forms::Label^ label1; + protected: + + private: + /// + /// Required designer variable. + /// + System::ComponentModel::Container ^components; + +#pragma region Windows Form Designer generated code + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + void InitializeComponent(void) + { + this->button1 = (gcnew System::Windows::Forms::Button()); + this->label1 = (gcnew System::Windows::Forms::Label()); + this->SuspendLayout(); + // + // button1 + // + this->button1->Location = System::Drawing::Point(100, 100); + this->button1->Name = L"button1"; + this->button1->Size = System::Drawing::Size(100, 25); + this->button1->TabIndex = 0; + this->button1->Text = L"OK"; + this->button1->UseVisualStyleBackColor = true; + this->button1->Click += gcnew System::EventHandler(this, &AboutBox::button1_Click); + // + // label1 + // + this->label1->AutoSize = true; + this->label1->Location = System::Drawing::Point(32, 20); + this->label1->Name = L"label1"; + this->label1->Size = System::Drawing::Size(109, 65); + this->label1->TabIndex = 1; + this->label1->Text = L"Barnacle 31.10.2014 \r\n\r\nUSF4 Character Extractor 0.2\r\n\r\n2014-2018"; + // + // AboutBox + // + this->AutoScaleDimensions = System::Drawing::SizeF(6, 13); + this->AutoScaleMode = System::Windows::Forms::AutoScaleMode::Font; + this->ClientSize = System::Drawing::Size(284, 142); + this->Controls->Add(this->label1); + this->Controls->Add(this->button1); + this->FormBorderStyle = System::Windows::Forms::FormBorderStyle::FixedDialog; + this->MaximizeBox = false; + this->MinimizeBox = false; + this->Name = L"AboutBox"; + this->StartPosition = System::Windows::Forms::FormStartPosition::CenterScreen; + this->Text = L"About"; + this->ResumeLayout(false); + this->PerformLayout(); + + } +#pragma endregion + private: System::Void button1_Click(System::Object^ sender, System::EventArgs^ e) { + AboutBox::Close(); + } + }; +} diff --git a/main/AboutBox.resx b/main/AboutBox.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/main/AboutBox.resx @@ -0,0 +1,120 @@ +п»ї + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/main/Reader.h b/main/Reader.h new file mode 100644 index 0000000..f0ed884 --- /dev/null +++ b/main/Reader.h @@ -0,0 +1,423 @@ +#pragma once + +namespace SSF4ce { + using namespace System; + using namespace System::IO; + + typedef unsigned short ushort; + typedef unsigned long ulong; + typedef unsigned char Byte; + + value struct EMGReturn + { + Byte* DDSid; // Массив id прикреплённых текстур к подмешам. + ushort SubmodelCount; // Кол-во подмешей в EMG. + ushort* IndexCount; // Массив кол-в индексов каждого подмеша. + ushort* NodesCount; // Массив кол-в костей каждого подмеша. + ushort VertexCount; // Кол-во вертексов. + ushort VertexSize; // Размер блока вертексов. + ushort** IndiceArray; // Массив лент треугольников. + ushort** NodesArray; // Массив костей. + Byte* VertexArray; // Массив блоков вертексов. + }; + + EMGReturn ReadEMG(String^ FileName, int EMGposition) // Входящие данные: имя файла, позиция EMG в EMO + { + EMGReturn retval; + + FileStream^ fs = File::OpenRead(FileName); + BinaryReader^ br = gcnew BinaryReader(fs); + + fs->Position = EMGposition + 16; // 16 - Сдвиг на заголовок EMG. + + fs->Position = fs->Position + 4; //EMGHeader1->Number711 = (ushort)br->ReadUInt32(); + ushort TextureCount = (ushort)br->ReadUInt32(); // Кол-во привязанных текстур к подмоделям. + fs->Position = fs->Position + 4; //EMGHeader1->Something = (ushort)br->ReadUInt32(); + ushort TextureOffset = (ushort)br->ReadUInt32(); // Позиция списка сдвигов текстур. + + ushort VertexCount = (ushort)br->ReadUInt16(); // Кол-во вертексов. + ushort VertexSize = (ushort)br->ReadUInt16(); // Размер блока вертексов. + ulong VertexOffset = (ulong)br->ReadUInt32(); // Позиция вертексов в файле. + fs->Position = fs->Position + 2; //EMGHeader1->Empty = (ushort)br->ReadUInt16(); // Пустые 2 байта. (strips?) + ushort SubmodelCount = (ushort)br->ReadUInt16(); // Кол-во подмешей в EMG. + ushort SubMesheListOffset = (ushort)br->ReadUInt16(); // Сдвиг на список адресов подмешей. + + //================================================================== + // Текстуры. + //================================================================== + fs->Position = EMGposition + 16 + TextureOffset; + + ushort* Offsets = new ushort[TextureCount]; + for (ushort i = 0; i < TextureCount; i++) + Offsets[i] = (ushort)br->ReadUInt32(); + + Byte* id = new Byte[TextureCount]; + for (ushort i = 0; i < TextureCount; i++) + { + fs->Position = EMGposition + 16 + Offsets[i] + 5; + id[i] = (Byte)br->ReadChar(); + } + + Byte* DDSid = new Byte[SubmodelCount]; + + //================================================================== + // Индексы и кости + //================================================================== + ushort *IndexCount = new ushort[SubmodelCount]; // Массив кол-в индексов подмешей. + ushort **IndiceArray = new ushort*[SubmodelCount]; // + + ushort *NodesCount = new ushort[SubmodelCount]; + ushort **NodesArray = new ushort*[SubmodelCount]; + + for (ushort i = 0; i < SubmodelCount; i++) + { + fs->Position = EMGposition + 16 + SubMesheListOffset + i * 4; // Ищется адрес подмеша из строки списка подмешей. + fs->Position = EMGposition + 16 + br->ReadUInt32() + 16; // 16 байт #EMG + читается сдвиг подмеша + 16 байт хрени + DDSid[i] = id[(Byte)br->ReadUInt16()]; // ID текстуры. + IndexCount[i] = (ushort)br->ReadUInt16(); // Кол-во индексов. + NodesCount[i] = (ushort)br->ReadUInt16(); // Кол-во костей. + + fs->Position = fs->Position + 32; // пропуск названия из 32-х байтов. + + IndiceArray[i] = new ushort[IndexCount[i]]; + + // Заполнение массива индексами подмеша. + for (int a = 0; a < IndexCount[i]; a++) + { + IndiceArray[i][a] = (ushort)br->ReadUInt16(); + } + + NodesArray[i] = new ushort[NodesCount[i]]; + + // Заполнение массива костями. + for (Byte a = 0; a < NodesCount[i]; a++) + { + NodesArray[i][a] = (ushort)br->ReadUInt16(); + } + } + + //================================================================== + // Вертексы + //================================================================== + fs->Position = EMGposition + 16 + VertexOffset; // Адрес вертексов + Byte* VertexArray = new Byte[VertexCount * VertexSize]; // Массив данных о вертексах + for (int i = 0; i < VertexCount * VertexSize; i++) + { + VertexArray[i] = (Byte)br->ReadByte(); + } + + br->Close(); + fs->Close(); + + retval.DDSid = DDSid; + retval.SubmodelCount = SubmodelCount; + retval.IndexCount = IndexCount; + retval.NodesCount = NodesCount; + retval.VertexCount = VertexCount; + retval.VertexSize = VertexSize; + retval.IndiceArray = IndiceArray; + retval.NodesArray = NodesArray; + retval.VertexArray = VertexArray; + return retval; + } + + //================================================================== + + value struct EMBReturn + { + ushort DDScount; // Кол-во dds в EMB. + ulong* DDSsize; // Размеры каждого dds. + Byte** DDSArray; // Сами dds. + }; + + EMBReturn ReadEMB(String^ FileName) + { + EMBReturn retval; + + FileStream^ fs = File::OpenRead(FileName); + BinaryReader^ br = gcnew BinaryReader(fs); + + // Кол-во DDS. + fs->Position = 12; + ushort DDScount = br->ReadInt16(); + + // + ulong *DDSoffset = new ulong[DDScount]; + ulong *DDSsize = new ulong[DDScount]; + Byte **DDSArray = new Byte*[DDScount]; + + // Список сдвигов на DDS и их размеры. + fs->Position = 32; + for (ulong i = 0; i < DDScount; i++) + { + DDSoffset[i] = br->ReadInt32() + (i * 2 * 4); // + учёт DDSsize + DDSsize[i] = br->ReadInt32(); + } + + // + for (ulong i = 0; i < DDScount; i++) + { + DDSArray[i] = new Byte[DDSsize[i]]; + + fs->Position = 32 + DDSoffset[i]; + + for (ulong a = 0; a < DDSsize[i]; a++) + { + DDSArray[i][a] = (Byte)br->ReadByte(); + } + } + + br->Close(); + fs->Close(); + + retval.DDScount = DDScount; + retval.DDSsize = DDSsize; + retval.DDSArray = DDSArray; + return retval; + } + + //================================================================== + + value struct SkeletonReturn + { + ushort NodesCount; + char** NodeName; + short* ParentNodeArray; + Byte** Matrix4x4; + }; + + SkeletonReturn ReadSkeleton(String^ FileName, Byte offset) // EMO - 16, EMA - 12 + { + SkeletonReturn retval; + + FileStream^ fs = File::OpenRead(FileName); + BinaryReader^ br = gcnew BinaryReader(fs); + + fs->Position = offset; // Пропуск на позицию о костях. + unsigned int SkeletalInfoOffset = br->ReadUInt32(); + + fs->Position = SkeletalInfoOffset; // Переход на позицию данных о костях. + ushort NodesCount = br->ReadUInt16(); // Кол-во нодов. + + fs->Position = fs->Position + 6; // Пропуск 4 байт. + ushort StartOffset = br->ReadUInt32(); // Размер заголовка блока. + ushort NamesOffsetsOffset = br->ReadUInt32(); // Сдвиг на список сдвигов о названиях нодов. + + //================================================================== + + fs->Position = SkeletalInfoOffset + NamesOffsetsOffset; // Сдвиги на названия. + unsigned int* NodesNamesOffsets = new unsigned int[NodesCount]; // Чтение. + for (ushort i = 0; i < NodesCount; i++) + NodesNamesOffsets[i] = br->ReadUInt32(); + + char** NodeName = new char*[NodesCount]; + + for (ushort i = 0; i < NodesCount; i++) + { + fs->Position = SkeletalInfoOffset + NodesNamesOffsets[i]; + + ushort size = 1; // Длинна названия для создания массива. + while (br->ReadChar() != 0) + size++; + + NodeName[i] = new char[size]; + + fs->Position = fs->Position - size; // Возврат позиции. + + for (ushort a = 0; a < size; a++) // Чтение в массив. + NodeName[i][a] = (char)br->ReadChar(); + } + + //================================================================== + + fs->Position = SkeletalInfoOffset + StartOffset; // Кости. + + short* ParentNodeArray = new short[NodesCount]; + Byte** Matrix4x4 = new Byte*[NodesCount]; + + for (ushort i = 0; i < NodesCount; i++) + { + ushort temp = br->ReadUInt16(); + if (temp == 65535) // FFFF - коренной. + ParentNodeArray[i] = -1; + else + ParentNodeArray[i] = temp; + + fs->Position = fs->Position + 14; // Пропуск на позицию о матрице. + + Matrix4x4[i] = new Byte[64]; + for (ushort a = 0; a < 64; a++) + Matrix4x4[i][a] = br->ReadByte(); + } + + br->Close(); + fs->Close(); + + retval.NodesCount = NodesCount; + retval.NodeName = NodeName; + retval.ParentNodeArray = ParentNodeArray; + retval.Matrix4x4 = Matrix4x4; + return retval; + } + + //================================================================== + + value struct EMAReturn + { + ushort AnimationCount; + char** AnimationName; + + ushort* Duration; + ushort** NodeIndex; + Byte** NodeTransformType; + Byte** TransformFlag; + ushort** NodeStepCount; + ushort* cmdOffsetCount; + ushort*** Frame; + float*** NodeValue; + float*** NodeTangentValue; + }; + + EMAReturn ReadEMA(String^ FileName) + { + EMAReturn retval; + + FileStream^ fs = File::OpenRead(FileName); + BinaryReader^ br = gcnew BinaryReader(fs); + + fs->Position = 6; // Заголовок. + ushort HeaderSize = br->ReadUInt16(); + + fs->Position = 16; // кол-во анимаций. + ushort AnimationCount = br->ReadUInt16(); + + fs->Position = HeaderSize; // сдвиги на анимации + ulong* AnimationOffsets = new ulong[AnimationCount]; + for (ushort i = 0; i < AnimationCount; i++) + AnimationOffsets[i] = br->ReadUInt32(); // + + char** AnimationName = new char*[AnimationCount]; + + ushort* Duration = new ushort[AnimationCount]; + ushort** NodeIndex = new ushort*[AnimationCount]; + ushort* cmdOffsetCount = new ushort[AnimationCount]; + ushort** NodeStepCount = new ushort*[AnimationCount]; + ushort*** Frame = new ushort**[AnimationCount]; + Byte** NodeTransformType = new Byte*[AnimationCount]; + float*** NodeValue = new float**[AnimationCount]; + float*** NodeTangentValue = new float**[AnimationCount]; + Byte** TransformFlag = new Byte*[AnimationCount]; + + for (ushort i = 0; i < AnimationCount; i++) + { + fs->Position = AnimationOffsets[i]; + + Duration[i] = br->ReadUInt16(); // Длительность анимации. + cmdOffsetCount[i] = br->ReadUInt16(); // cmdOffsetCount + ulong ValueCount = br->ReadUInt32(); // valueCount + ulong temp4 = br->ReadUInt32(); // zero + ulong NameOffset = br->ReadUInt32(); // Сдвиг на название. + ulong ValuesOffset = br->ReadUInt32(); // valuesOffset + + //================================================================== + fs->Position = AnimationOffsets[i] + NameOffset + 11; // 11 - хлам. + ushort size = 1; // Длинна названия для создания массива. + while (br->ReadChar() != 0) + size++; + AnimationName[i] = new char[size]; + fs->Position = fs->Position - size; // Возврат позиции. + for (ushort a = 0; a < size; a++) // Чтение в массив. + AnimationName[i][a] = (char)br->ReadChar(); + //================================================================== + + fs->Position = AnimationOffsets[i] + ValuesOffset; + float* Values = new float[ValueCount]; + for (ulong Value = 0; Value < ValueCount; Value++) + Values[Value] = br->ReadSingle(); + + //================================================================== + + fs->Position = AnimationOffsets[i] + 20; + ulong* cmdOffsets = new ulong[cmdOffsetCount[i]]; + for (ulong cmdOffset = 0; cmdOffset < cmdOffsetCount[i]; cmdOffset++) + cmdOffsets[cmdOffset] = br->ReadUInt32(); + + NodeIndex[i] = new ushort[cmdOffsetCount[i]]; + NodeStepCount[i] = new ushort[cmdOffsetCount[i]]; + Frame[i] = new ushort*[cmdOffsetCount[i]]; + NodeTransformType[i] = new Byte[cmdOffsetCount[i]]; + NodeValue[i] = new float*[cmdOffsetCount[i]]; + NodeTangentValue[i] = new float*[cmdOffsetCount[i]]; + TransformFlag[i] = new Byte[cmdOffsetCount[i]]; + + for (ulong cmdOffset = 0; cmdOffset < cmdOffsetCount[i]; cmdOffset++) + { + fs->Position = AnimationOffsets[i] + cmdOffsets[cmdOffset]; + + NodeIndex[i][cmdOffset] = br->ReadUInt16(); // индекс кости. + NodeTransformType[i][cmdOffset] = (char)br->ReadChar(); // 0 -> translation, 1 -> rotation, 2->scale + TransformFlag[i][cmdOffset] = (char)br->ReadChar(); // 0 - x, 1 - y, 2 - z + NodeStepCount[i][cmdOffset] = br->ReadUInt16(); //(stepCount)) + ushort IndicesOffset = br->ReadUInt16(); //(indicesOffset)); + + Frame[i][cmdOffset] = new ushort[NodeStepCount[i][cmdOffset]]; + NodeValue[i][cmdOffset] = new float[NodeStepCount[i][cmdOffset]]; + NodeTangentValue[i][cmdOffset] = new float[NodeStepCount[i][cmdOffset]]; + + for (ushort a = 0; a < NodeStepCount[i][cmdOffset]; a++) + { + if (TransformFlag[i][cmdOffset] & 0x20) + Frame[i][cmdOffset][a] = br->ReadUInt16(); + else + Frame[i][cmdOffset][a] = (ushort)br->ReadByte(); + } + + fs->Position = AnimationOffsets[i] + cmdOffsets[cmdOffset] + IndicesOffset; + + for (ushort a = 0; a < NodeStepCount[i][cmdOffset]; a++) + { + if (TransformFlag[i][cmdOffset] & 0x40) + { + ulong index = br->ReadUInt32(); + unsigned int valueindex = (index & 0x3FFFFFFF); + NodeValue[i][cmdOffset][a] = Values[valueindex]; + + unsigned char highOrderBits = ((index >> 30) & 0x03); + unsigned int tangentIndex = highOrderBits == 0 ? ~0 : (valueindex + highOrderBits); + if (tangentIndex != ~0) + NodeTangentValue[i][cmdOffset][a] = Values[tangentIndex]; + } + else + { + ushort index = br->ReadUInt16(); + unsigned int valueindex = (index & 0x3FFF); + NodeValue[i][cmdOffset][a] = Values[valueindex]; + + unsigned char highOrderBits = ((index >> 14) & 0x03); + unsigned int tangentIndex = highOrderBits == 0 ? ~0 : (valueindex + highOrderBits); + if (tangentIndex != ~0) + NodeTangentValue[i][cmdOffset][a] = Values[tangentIndex]; + } + } + } + } + + br->Close(); + fs->Close(); + + retval.AnimationCount = AnimationCount; + retval.AnimationName = AnimationName; + + retval.Duration = Duration; + retval.NodeIndex = NodeIndex; + retval.NodeTransformType = NodeTransformType; + retval.TransformFlag = TransformFlag; + retval.NodeStepCount = NodeStepCount; + retval.cmdOffsetCount = cmdOffsetCount; + retval.Frame = Frame; + retval.NodeValue = NodeValue; + retval.NodeTangentValue = NodeTangentValue; + + return retval; + } +} \ No newline at end of file diff --git a/main/USF4ce.rc b/main/USF4ce.rc new file mode 100644 index 0000000000000000000000000000000000000000..1c867785267d215a7e7e032ec8f3ea634ee51b89 GIT binary patch literal 4524 zcmd6rTTfa+5Xa}aNx#D>CQVI^g8I@&kxNWbh+NVpCWHzoi3P(Ytw}$7+uwhe^_;`S z7JMNm%kG)onVtF1W%uys_mLf0WS2IuTN~TRCbYgyp|zk*Y-SyM;O*Q#@j(C%_fjzS3(B9e`b~$qW9@HVT53KIGwV5UUL%X+(TP@B#x32H_ zB>T*2R=0*VtzZ{cwYFVb5o&?)l~wF3lsdncmWNVd9QKzEyY~d`LLXTfToy6zgVM;p zWB(L%ghKR@wZA5xV46@H&2vS{ECdY8(kE;7!nL>&1ns*^EIq@EK=ZQ`lI zBe}nLqP3h2WLy)qlF=mJ_T8=(s8>*%^ko;BffCl$iCwKZKz5yVd3N(W+PjEeXHYA| zxG?bEmKE#0tz2kf!)Le)j$^lcnbaouHT3H;I?StA%YoLq+}C^_+sm#h=q;K*tE=pd zW#^T)2yz}VajAxEv&X9Hp0VZHlCc|V)D2PW>wK)`I*m@Y)M(Rv_FV1ll4GhT{*l*K z)t2RG6LxAzKkwE!Xcu~&^E%B{RYv$D(ABH8$jmmsMRHsDsx!9jqN~JM+{qasBDy#u zMi*pnabZnF%pDM62d>Y~*Vd3?xIUX$uQN%zra7wU=VhOwqn^__PmETByGsq! z(mKTRzEY-Fg`HRDzUpcfT!l;q4W{^8x3D`rG{CYRej1|dXdxR{OAA?%mMTkf_Q_fF zjo)-$$2_ZQQwnPp9x_HooFSj(;fKU?WVnS_Z>siExAX9^Kb8=6p1|{>{pE#ZKG22MhrQ0i>R}1TV5RQwhqRxxP4up?{?193zaH%gy9ZG2*)?c?jLtcb z+(d45E=Tbyy@Sv6mW+ef>R)4@5ji_^zP)-u`X<_^rEc%j_;e25U8bb-v4sWWXSBA- z?{xe$kfvMb1Rv yU6$_`NqM_9mSxf?^soJj)qU^fuh@X)ZsCyBMjEb<@FDd^|FbNAvo8BxlKui%M-vSI literal 0 HcmV?d00001 diff --git a/main/Wrapper.h b/main/Wrapper.h new file mode 100644 index 0000000..e34fce1 --- /dev/null +++ b/main/Wrapper.h @@ -0,0 +1,114 @@ +#pragma once + +#include "..\D3D\D3D.h" + +class CD3DRender; + +public ref class Wrapper +{ +public: + Wrapper(); + ~Wrapper(); + + HRESULT WrapInit(int hWnd, int Width, int Height); + HRESULT WrapClose(); + HRESULT WrapRender(); + HRESULT WrapResize(int Width, int Height); + HRESULT WrapOnMouseButtonUp(); + HRESULT WrapOnMouseMove(short x, short y, bool RMousing); + HRESULT WrapOnMouseButtonDown(short x, short y); + HRESULT WrapCreateBuffers(ushort EMGcount); + HRESULT WrapLoadEMG(ushort CurrentEMG, ushort EMGsubmodels, unsigned char* DDSid, ushort* IndexCount, + ushort VertexCount, ushort VertexSize, + ushort** IndiceArray, unsigned char* VertexArray); + HRESULT WrapLoadDDS(ushort DDScount, unsigned long* DDSsize, unsigned char** DDScontent); + + HRESULT WrapSetup(System::String^ emaFileName, unsigned long emaBlockOffset); + HRESULT WrapUpdate(float(&structure)[500][6], std::string(&names)[500], System::String^ AnimationName, int frame); + + std::string managedStrToNative(System::String^ sysstr) + { + using System::IntPtr; + using System::Runtime::InteropServices::Marshal; + + IntPtr ip = Marshal::StringToHGlobalAnsi(sysstr); + std::string outString = static_cast(ip.ToPointer()); + Marshal::FreeHGlobal(ip); + return outString; + } + +protected: + CD3DRender* m_pRenderer; +}; + +Wrapper::Wrapper() +{ + m_pRenderer = new CD3DRender; +} + +Wrapper::~Wrapper() +{ + delete m_pRenderer; +} + +HRESULT Wrapper::WrapInit(int hWnd, int Width, int Height) +{ + return m_pRenderer->init((HWND)hWnd, Width, Height); +} + +HRESULT Wrapper::WrapClose() +{ + return m_pRenderer->Shutdown(); +} + +HRESULT Wrapper::WrapRender() +{ + return m_pRenderer->ProcessFrame(); +} + +HRESULT Wrapper::WrapResize(int Width, int Height) +{ + return m_pRenderer->Resize(Width, Height); +} + +HRESULT Wrapper::WrapOnMouseButtonUp() +{ + return m_pRenderer->OnMouseButtonUp(); +} + +HRESULT Wrapper::WrapOnMouseMove(short x, short y, bool RMousing) +{ + return m_pRenderer->OnMouseMove(x, y, RMousing); +} + +HRESULT Wrapper::WrapOnMouseButtonDown(short x, short y) +{ + return m_pRenderer->OnMouseButtonDown(x, y); +} + +HRESULT Wrapper::WrapCreateBuffers(ushort EMGcount) +{ + return m_pRenderer->CreateBuffers(EMGcount); +} + +HRESULT Wrapper::WrapLoadEMG(ushort CurrentEMG, ushort EMGsubmodels, unsigned char* DDSid, ushort* IndexCount, ushort VertexSize, ushort VerteSize, ushort** IndiceArray, unsigned char* VertexArray) +{ + return m_pRenderer->LoadEMG(CurrentEMG, EMGsubmodels, DDSid, IndexCount, VertexSize, VerteSize, IndiceArray, VertexArray); +} + +HRESULT Wrapper::WrapLoadDDS(ushort DDScount, unsigned long* DDSsize, unsigned char** DDScontent) +{ + return m_pRenderer->LoadDDS(DDScount, DDSsize, DDScontent); +} + +HRESULT Wrapper::WrapSetup(System::String^ emaFileName, unsigned long emaBlockOffset) +{ + std::string emaFileName1 = managedStrToNative(emaFileName); + return m_pRenderer->Setup(emaFileName1, emaBlockOffset); +} + +HRESULT Wrapper::WrapUpdate(float(&structure)[500][6], std::string(&names)[500], System::String^ AnimationName, int frame) +{ + std::string AnimationName1 = managedStrToNative(AnimationName); + return m_pRenderer->Update(structure, names, AnimationName1, frame); +} diff --git a/main/main.cpp b/main/main.cpp new file mode 100644 index 0000000..b7badd1 --- /dev/null +++ b/main/main.cpp @@ -0,0 +1,13 @@ +#include "main.h" + +using namespace SSF4ce; //the project name in your header file + +[STAThreadAttribute] +int main(array ^args) +{ + Application::EnableVisualStyles(); + Application::SetCompatibleTextRenderingDefault(false); + + Application::Run(gcnew MainForm()); + return 0; +} diff --git a/main/main.h b/main/main.h new file mode 100644 index 0000000..abfd56c --- /dev/null +++ b/main/main.h @@ -0,0 +1,1296 @@ +#pragma once + +#include "AboutBox.h" +#include "Wrapper.h" +#include "Reader.h" + +namespace SSF4ce { + + using namespace System; + using namespace System::ComponentModel; + using namespace System::Collections; + using namespace System::Windows::Forms; + using namespace System::Data; + using namespace System::Drawing; + // + using namespace System::IO; + using namespace System::Text; + using namespace System::Globalization; + using namespace Microsoft::Win32; + + // Фикс двойного клика. + // Uncomment this before final release and replace TreeView^ with NewTreeView^. + /*public ref class NewTreeView : public TreeView + { + protected: + virtual void WndProc(Message% m) override + { + if (m.Msg == WM_LBUTTONDBLCLK) + return; + else + TreeView::WndProc(m); + } + };*/ + + /// + /// Summary for main + /// + public ref class MainForm : public System::Windows::Forms::Form + { + private: System::Windows::Forms::ToolStripDropDownButton^ toolStripDropDownButton3; + private: System::Windows::Forms::ToolStripMenuItem^ steamToolStripMenuItem; + private: System::Windows::Forms::ToolStripMenuItem^ originStoreToolStripMenuItem; + private: System::Windows::Forms::ToolStripMenuItem^ MergeSubmodelsToolStripMenuItem; + private: System::Windows::Forms::ToolStripTextBox^ toolStripTextBox1; + private: System::Windows::Forms::ToolStripMenuItem^ replaceSkelToolStripMenuItem; + private: System::Windows::Forms::ToolStripMenuItem^ starPoseFixToolStripMenuItem; + private: System::Windows::Forms::SplitContainer^ BaseSplitContainer; + private: System::Windows::Forms::SplitContainer^ TopSplitContainer; + private: System::Windows::Forms::SplitContainer^ BottomSplitContainer; + + + private: System::Windows::Forms::TrackBar^ trackBar1; + + public: + Wrapper^ m_D3DWrap; + OpenFileDialog^ openFileDialog1 = gcnew OpenFileDialog(); + + MainForm(void) + { + InitializeComponent(); + // + //TODO: Add the constructor code here + // + m_D3DWrap = gcnew Wrapper(); + m_D3DWrap->WrapInit(TopSplitContainer->Panel2->Handle.ToInt32(), TopSplitContainer->Panel2->Width, TopSplitContainer->Panel2->Height); + } + + protected: + /// + /// Clean up any resources being used. + /// + ~MainForm() + { + if (components) + { + delete components; + } + } + private: System::Windows::Forms::StatusStrip^ statusStrip1; + protected: + private: System::Windows::Forms::ToolStrip^ toolStrip1; + private: System::Windows::Forms::ToolStripDropDownButton^ toolStripDropDownButton1; + private: System::Windows::Forms::ToolStripDropDownButton^ toolStripDropDownButton2; + private: System::Windows::Forms::ToolStripMenuItem^ aboutToolStripMenuItem; + private: System::Windows::Forms::ToolStripMenuItem^ openToolStripMenuItem; + private: System::Windows::Forms::ToolStripMenuItem^ exitToolStripMenuItem; + + + + private: System::Windows::Forms::Timer^ timer1; + private: System::Windows::Forms::Button^ button1; + private: System::Windows::Forms::ToolStripStatusLabel^ toolStripStatusLabel1; + private: System::ComponentModel::IContainer^ components; + + + // Фикс двойного нажатия. + private: System::Windows::Forms::TreeView^ treeView1; // Comment this. + //private: NewTreeView^ treeView1; + + private: + /// + /// Required designer variable. + /// +#pragma region Windows Form Designer generated code + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + void InitializeComponent(void) + { + this->components = (gcnew System::ComponentModel::Container()); + System::Windows::Forms::TreeNode^ treeNode1 = (gcnew System::Windows::Forms::TreeNode(L"Mesh")); + System::Windows::Forms::TreeNode^ treeNode2 = (gcnew System::Windows::Forms::TreeNode(L"Skins")); + System::Windows::Forms::TreeNode^ treeNode3 = (gcnew System::Windows::Forms::TreeNode(L"Animations")); + this->statusStrip1 = (gcnew System::Windows::Forms::StatusStrip()); + this->toolStripStatusLabel1 = (gcnew System::Windows::Forms::ToolStripStatusLabel()); + this->toolStrip1 = (gcnew System::Windows::Forms::ToolStrip()); + this->toolStripDropDownButton1 = (gcnew System::Windows::Forms::ToolStripDropDownButton()); + this->openToolStripMenuItem = (gcnew System::Windows::Forms::ToolStripMenuItem()); + this->exitToolStripMenuItem = (gcnew System::Windows::Forms::ToolStripMenuItem()); + this->toolStripDropDownButton3 = (gcnew System::Windows::Forms::ToolStripDropDownButton()); + this->steamToolStripMenuItem = (gcnew System::Windows::Forms::ToolStripMenuItem()); + this->originStoreToolStripMenuItem = (gcnew System::Windows::Forms::ToolStripMenuItem()); + this->MergeSubmodelsToolStripMenuItem = (gcnew System::Windows::Forms::ToolStripMenuItem()); + this->replaceSkelToolStripMenuItem = (gcnew System::Windows::Forms::ToolStripMenuItem()); + this->toolStripTextBox1 = (gcnew System::Windows::Forms::ToolStripTextBox()); + this->starPoseFixToolStripMenuItem = (gcnew System::Windows::Forms::ToolStripMenuItem()); + this->toolStripDropDownButton2 = (gcnew System::Windows::Forms::ToolStripDropDownButton()); + this->aboutToolStripMenuItem = (gcnew System::Windows::Forms::ToolStripMenuItem()); + this->treeView1 = (gcnew System::Windows::Forms::TreeView()); + this->button1 = (gcnew System::Windows::Forms::Button()); + this->timer1 = (gcnew System::Windows::Forms::Timer(this->components)); + this->BaseSplitContainer = (gcnew System::Windows::Forms::SplitContainer()); + this->TopSplitContainer = (gcnew System::Windows::Forms::SplitContainer()); + this->BottomSplitContainer = (gcnew System::Windows::Forms::SplitContainer()); + this->trackBar1 = (gcnew System::Windows::Forms::TrackBar()); + this->statusStrip1->SuspendLayout(); + this->toolStrip1->SuspendLayout(); + (cli::safe_cast(this->BaseSplitContainer))->BeginInit(); + this->BaseSplitContainer->Panel1->SuspendLayout(); + this->BaseSplitContainer->Panel2->SuspendLayout(); + this->BaseSplitContainer->SuspendLayout(); + (cli::safe_cast(this->TopSplitContainer))->BeginInit(); + this->TopSplitContainer->Panel1->SuspendLayout(); + this->TopSplitContainer->SuspendLayout(); + (cli::safe_cast(this->BottomSplitContainer))->BeginInit(); + this->BottomSplitContainer->Panel1->SuspendLayout(); + this->BottomSplitContainer->Panel2->SuspendLayout(); + this->BottomSplitContainer->SuspendLayout(); + (cli::safe_cast(this->trackBar1))->BeginInit(); + this->SuspendLayout(); + // + // statusStrip1 + // + this->statusStrip1->Items->AddRange(gcnew cli::array< System::Windows::Forms::ToolStripItem^ >(1) { this->toolStripStatusLabel1 }); + this->statusStrip1->Location = System::Drawing::Point(0, 540); + this->statusStrip1->Name = L"statusStrip1"; + this->statusStrip1->Size = System::Drawing::Size(784, 22); + this->statusStrip1->TabIndex = 0; + this->statusStrip1->Text = L"statusStrip1"; + // + // toolStripStatusLabel1 + // + this->toolStripStatusLabel1->Name = L"toolStripStatusLabel1"; + this->toolStripStatusLabel1->Size = System::Drawing::Size(39, 17); + this->toolStripStatusLabel1->Text = L"Ready"; + this->toolStripStatusLabel1->Visible = false; + // + // toolStrip1 + // + this->toolStrip1->GripStyle = System::Windows::Forms::ToolStripGripStyle::Hidden; + this->toolStrip1->Items->AddRange(gcnew cli::array< System::Windows::Forms::ToolStripItem^ >(3) { + this->toolStripDropDownButton1, + this->toolStripDropDownButton3, this->toolStripDropDownButton2 + }); + this->toolStrip1->Location = System::Drawing::Point(0, 0); + this->toolStrip1->Name = L"toolStrip1"; + this->toolStrip1->Size = System::Drawing::Size(784, 25); + this->toolStrip1->Stretch = true; + this->toolStrip1->TabIndex = 1; + this->toolStrip1->Text = L"toolStrip1"; + // + // toolStripDropDownButton1 + // + this->toolStripDropDownButton1->DisplayStyle = System::Windows::Forms::ToolStripItemDisplayStyle::Text; + this->toolStripDropDownButton1->DropDownItems->AddRange(gcnew cli::array< System::Windows::Forms::ToolStripItem^ >(2) { + this->openToolStripMenuItem, + this->exitToolStripMenuItem + }); + this->toolStripDropDownButton1->Name = L"toolStripDropDownButton1"; + this->toolStripDropDownButton1->ShowDropDownArrow = false; + this->toolStripDropDownButton1->Size = System::Drawing::Size(29, 22); + this->toolStripDropDownButton1->Text = L"File"; + // + // openToolStripMenuItem + // + this->openToolStripMenuItem->Name = L"openToolStripMenuItem"; + this->openToolStripMenuItem->Size = System::Drawing::Size(103, 22); + this->openToolStripMenuItem->Text = L"Open"; + this->openToolStripMenuItem->Click += gcnew System::EventHandler(this, &MainForm::openToolStripMenuItem_Click); + // + // exitToolStripMenuItem + // + this->exitToolStripMenuItem->Name = L"exitToolStripMenuItem"; + this->exitToolStripMenuItem->Size = System::Drawing::Size(103, 22); + this->exitToolStripMenuItem->Text = L"Exit"; + this->exitToolStripMenuItem->Click += gcnew System::EventHandler(this, &MainForm::exitToolStripMenuItem_Click); + // + // toolStripDropDownButton3 + // + this->toolStripDropDownButton3->DisplayStyle = System::Windows::Forms::ToolStripItemDisplayStyle::Text; + this->toolStripDropDownButton3->DropDownItems->AddRange(gcnew cli::array< System::Windows::Forms::ToolStripItem^ >(6) { + this->steamToolStripMenuItem, + this->originStoreToolStripMenuItem, this->MergeSubmodelsToolStripMenuItem, this->replaceSkelToolStripMenuItem, this->toolStripTextBox1, + this->starPoseFixToolStripMenuItem + }); + this->toolStripDropDownButton3->Name = L"toolStripDropDownButton3"; + this->toolStripDropDownButton3->ShowDropDownArrow = false; + this->toolStripDropDownButton3->Size = System::Drawing::Size(53, 22); + this->toolStripDropDownButton3->Text = L"Settings"; + // + // steamToolStripMenuItem + // + this->steamToolStripMenuItem->Checked = true; + this->steamToolStripMenuItem->CheckState = System::Windows::Forms::CheckState::Checked; + this->steamToolStripMenuItem->Name = L"steamToolStripMenuItem"; + this->steamToolStripMenuItem->Size = System::Drawing::Size(173, 22); + this->steamToolStripMenuItem->Text = L"Steam folder"; + this->steamToolStripMenuItem->Click += gcnew System::EventHandler(this, &MainForm::steamToolStripMenuItem_Click); + // + // originStoreToolStripMenuItem + // + this->originStoreToolStripMenuItem->Checked = true; + this->originStoreToolStripMenuItem->CheckState = System::Windows::Forms::CheckState::Checked; + this->originStoreToolStripMenuItem->Name = L"originStoreToolStripMenuItem"; + this->originStoreToolStripMenuItem->Size = System::Drawing::Size(173, 22); + this->originStoreToolStripMenuItem->Text = L"Origin coord. store"; + this->originStoreToolStripMenuItem->Visible = false; + this->originStoreToolStripMenuItem->Click += gcnew System::EventHandler(this, &MainForm::originStoreToolStripMenuItem_Click); + // + // MergeSubmodelsToolStripMenuItem + // + this->MergeSubmodelsToolStripMenuItem->Name = L"MergeSubmodelsToolStripMenuItem"; + this->MergeSubmodelsToolStripMenuItem->Size = System::Drawing::Size(173, 22); + this->MergeSubmodelsToolStripMenuItem->Text = L"Merge submodels"; + this->MergeSubmodelsToolStripMenuItem->ToolTipText = L"By texture id"; + this->MergeSubmodelsToolStripMenuItem->Click += gcnew System::EventHandler(this, &MainForm::MergeSubmodelsToolStripMenuItem_Click); + // + // replaceSkelToolStripMenuItem + // + this->replaceSkelToolStripMenuItem->Name = L"replaceSkelToolStripMenuItem"; + this->replaceSkelToolStripMenuItem->Size = System::Drawing::Size(173, 22); + this->replaceSkelToolStripMenuItem->Text = L"Replace skeleton"; + this->replaceSkelToolStripMenuItem->ToolTipText = L"Quick fix for a T-Pose chars, not for a Star-Pose ones"; + this->replaceSkelToolStripMenuItem->Click += gcnew System::EventHandler(this, &MainForm::replaceSkelToolStripMenuItem_Click); + // + // toolStripTextBox1 + // + this->toolStripTextBox1->Name = L"toolStripTextBox1"; + this->toolStripTextBox1->Size = System::Drawing::Size(100, 23); + this->toolStripTextBox1->Text = L"72"; + this->toolStripTextBox1->TextBoxTextAlign = System::Windows::Forms::HorizontalAlignment::Right; + this->toolStripTextBox1->ToolTipText = L"Scale"; + // + // starPoseFixToolStripMenuItem + // + this->starPoseFixToolStripMenuItem->Name = L"starPoseFixToolStripMenuItem"; + this->starPoseFixToolStripMenuItem->Size = System::Drawing::Size(173, 22); + this->starPoseFixToolStripMenuItem->Text = L"Star-Pose Fix"; + this->starPoseFixToolStripMenuItem->Click += gcnew System::EventHandler(this, &MainForm::starPoseFixToolStripMenuItem_Click); + // + // toolStripDropDownButton2 + // + this->toolStripDropDownButton2->DisplayStyle = System::Windows::Forms::ToolStripItemDisplayStyle::Text; + this->toolStripDropDownButton2->DropDownItems->AddRange(gcnew cli::array< System::Windows::Forms::ToolStripItem^ >(1) { this->aboutToolStripMenuItem }); + this->toolStripDropDownButton2->Name = L"toolStripDropDownButton2"; + this->toolStripDropDownButton2->ShowDropDownArrow = false; + this->toolStripDropDownButton2->Size = System::Drawing::Size(36, 22); + this->toolStripDropDownButton2->Text = L"Help"; + // + // aboutToolStripMenuItem + // + this->aboutToolStripMenuItem->Name = L"aboutToolStripMenuItem"; + this->aboutToolStripMenuItem->Size = System::Drawing::Size(107, 22); + this->aboutToolStripMenuItem->Text = L"About"; + this->aboutToolStripMenuItem->Click += gcnew System::EventHandler(this, &MainForm::aboutToolStripMenuItem_Click); + // + // treeView1 + // + this->treeView1->CheckBoxes = true; + this->treeView1->Dock = System::Windows::Forms::DockStyle::Fill; + this->treeView1->Enabled = false; + this->treeView1->Location = System::Drawing::Point(0, 0); + this->treeView1->Name = L"treeView1"; + treeNode1->Name = L"Node0"; + treeNode1->Text = L"Mesh"; + treeNode2->Name = L"Node1"; + treeNode2->Text = L"Skins"; + treeNode3->Name = L"Node2"; + treeNode3->Text = L"Animations"; + this->treeView1->Nodes->AddRange(gcnew cli::array< System::Windows::Forms::TreeNode^ >(3) { treeNode1, treeNode2, treeNode3 }); + this->treeView1->Size = System::Drawing::Size(187, 466); + this->treeView1->TabIndex = 0; + this->treeView1->AfterCheck += gcnew System::Windows::Forms::TreeViewEventHandler(this, &MainForm::treeView1_AfterCheck); + this->treeView1->AfterSelect += gcnew System::Windows::Forms::TreeViewEventHandler(this, &MainForm::treeView1_AfterSelect); + // + // button1 + // + this->button1->Enabled = false; + this->button1->FlatStyle = System::Windows::Forms::FlatStyle::Flat; + this->button1->Location = System::Drawing::Point(0, 0); + this->button1->Name = L"button1"; + this->button1->Size = System::Drawing::Size(186, 43); + this->button1->TabIndex = 0; + this->button1->Text = L"Extract"; + this->button1->UseVisualStyleBackColor = true; + this->button1->Click += gcnew System::EventHandler(this, &MainForm::button1_Click); + // + // timer1 + // + this->timer1->Enabled = true; + this->timer1->Interval = 30; + this->timer1->Tick += gcnew System::EventHandler(this, &MainForm::timer1_Tick); + // + // BaseSplitContainer + // + this->BaseSplitContainer->Dock = System::Windows::Forms::DockStyle::Fill; + this->BaseSplitContainer->FixedPanel = System::Windows::Forms::FixedPanel::Panel2; + this->BaseSplitContainer->IsSplitterFixed = true; + this->BaseSplitContainer->Location = System::Drawing::Point(0, 25); + this->BaseSplitContainer->Name = L"BaseSplitContainer"; + this->BaseSplitContainer->Orientation = System::Windows::Forms::Orientation::Horizontal; + // + // BaseSplitContainer.Panel1 + // + this->BaseSplitContainer->Panel1->Controls->Add(this->TopSplitContainer); + // + // BaseSplitContainer.Panel2 + // + this->BaseSplitContainer->Panel2->Controls->Add(this->BottomSplitContainer); + this->BaseSplitContainer->Size = System::Drawing::Size(784, 515); + this->BaseSplitContainer->SplitterDistance = 466; + this->BaseSplitContainer->TabIndex = 3; + // + // TopSplitContainer + // + this->TopSplitContainer->Dock = System::Windows::Forms::DockStyle::Fill; + this->TopSplitContainer->Location = System::Drawing::Point(0, 0); + this->TopSplitContainer->Name = L"TopSplitContainer"; + // + // TopSplitContainer.Panel1 + // + this->TopSplitContainer->Panel1->Controls->Add(this->treeView1); + // + // TopSplitContainer.Panel2 + // + this->TopSplitContainer->Panel2->MouseDown += gcnew System::Windows::Forms::MouseEventHandler(this, &MainForm::TopSplitContainer_Panel2_MouseDown); + this->TopSplitContainer->Panel2->MouseMove += gcnew System::Windows::Forms::MouseEventHandler(this, &MainForm::TopSplitContainer_Panel2_MouseMove); + this->TopSplitContainer->Panel2->MouseUp += gcnew System::Windows::Forms::MouseEventHandler(this, &MainForm::TopSplitContainer_Panel2_MouseUp); + this->TopSplitContainer->Size = System::Drawing::Size(784, 466); + this->TopSplitContainer->SplitterDistance = 187; + this->TopSplitContainer->TabIndex = 0; + this->TopSplitContainer->SplitterMoved += gcnew System::Windows::Forms::SplitterEventHandler(this, &MainForm::TopSplitContainer_SplitterMoved); + // + // BottomSplitContainer + // + this->BottomSplitContainer->Dock = System::Windows::Forms::DockStyle::Fill; + this->BottomSplitContainer->FixedPanel = System::Windows::Forms::FixedPanel::Panel1; + this->BottomSplitContainer->IsSplitterFixed = true; + this->BottomSplitContainer->Location = System::Drawing::Point(0, 0); + this->BottomSplitContainer->Name = L"BottomSplitContainer"; + // + // BottomSplitContainer.Panel1 + // + this->BottomSplitContainer->Panel1->Controls->Add(this->button1); + // + // BottomSplitContainer.Panel2 + // + this->BottomSplitContainer->Panel2->Controls->Add(this->trackBar1); + this->BottomSplitContainer->Size = System::Drawing::Size(784, 45); + this->BottomSplitContainer->SplitterDistance = 187; + this->BottomSplitContainer->TabIndex = 0; + // + // trackBar1 + // + this->trackBar1->Dock = System::Windows::Forms::DockStyle::Fill; + this->trackBar1->Enabled = false; + this->trackBar1->Location = System::Drawing::Point(0, 0); + this->trackBar1->Name = L"trackBar1"; + this->trackBar1->Size = System::Drawing::Size(593, 45); + this->trackBar1->TabIndex = 1; + this->trackBar1->Visible = false; + // + // MainForm + // + this->AutoScaleDimensions = System::Drawing::SizeF(6, 13); + this->AutoScaleMode = System::Windows::Forms::AutoScaleMode::Font; + this->ClientSize = System::Drawing::Size(784, 562); + this->Controls->Add(this->BaseSplitContainer); + this->Controls->Add(this->toolStrip1); + this->Controls->Add(this->statusStrip1); + this->MinimumSize = System::Drawing::Size(800, 600); + this->Name = L"MainForm"; + this->StartPosition = System::Windows::Forms::FormStartPosition::CenterScreen; + this->Text = L"USF4 Character Extractor PC"; + this->SizeChanged += gcnew System::EventHandler(this, &MainForm::MainForm_SizeChanged); + this->statusStrip1->ResumeLayout(false); + this->statusStrip1->PerformLayout(); + this->toolStrip1->ResumeLayout(false); + this->toolStrip1->PerformLayout(); + this->BaseSplitContainer->Panel1->ResumeLayout(false); + this->BaseSplitContainer->Panel2->ResumeLayout(false); + (cli::safe_cast(this->BaseSplitContainer))->EndInit(); + this->BaseSplitContainer->ResumeLayout(false); + this->TopSplitContainer->Panel1->ResumeLayout(false); + (cli::safe_cast(this->TopSplitContainer))->EndInit(); + this->TopSplitContainer->ResumeLayout(false); + this->BottomSplitContainer->Panel1->ResumeLayout(false); + this->BottomSplitContainer->Panel2->ResumeLayout(false); + this->BottomSplitContainer->Panel2->PerformLayout(); + (cli::safe_cast(this->BottomSplitContainer))->EndInit(); + this->BottomSplitContainer->ResumeLayout(false); + (cli::safe_cast(this->trackBar1))->EndInit(); + this->ResumeLayout(false); + this->PerformLayout(); + + } +#pragma endregion +private: System::Void exitToolStripMenuItem_Click(System::Object^ sender, System::EventArgs^ e) { + Application::Exit(); +} +private: System::Void aboutToolStripMenuItem_Click(System::Object^ sender, System::EventArgs^ e) { + AboutBox^ AboutBox1 = gcnew AboutBox; + AboutBox1->ShowDialog(); +} +private: System::Void timer1_Tick(System::Object^ sender, System::EventArgs^ e) { + m_D3DWrap->WrapRender(); +} +private: System::Void TopSplitContainer_Panel2_MouseMove(System::Object^ sender, System::Windows::Forms::MouseEventArgs^ e) { + m_D3DWrap->WrapOnMouseMove((short)Control::MousePosition.X, (short)Control::MousePosition.Y, e->Button == System::Windows::Forms::MouseButtons::Right); +} +private: System::Void TopSplitContainer_Panel2_MouseUp(System::Object^ sender, System::Windows::Forms::MouseEventArgs^ e) { + m_D3DWrap->WrapOnMouseButtonUp(); +} +private: System::Void TopSplitContainer_Panel2_MouseDown(System::Object^ sender, System::Windows::Forms::MouseEventArgs^ e) { + m_D3DWrap->WrapOnMouseButtonDown((short)Control::MousePosition.X, (short)Control::MousePosition.Y); +} +private: System::Void openToolStripMenuItem_Click(System::Object^ sender, System::EventArgs^ e) { + + String^ SteamPath; + if (steamToolStripMenuItem->Checked) + { + try{ + RegistryKey^ rk = Registry::CurrentUser->OpenSubKey("Software\\Valve\\Steam", false); + SteamPath = rk->GetValue("SteamPath")->ToString(); + rk->Close(); + + if (SteamPath) + { + SteamPath = SteamPath->Replace("/", "\\"); + SteamPath += "\\SteamApps\\common\\Super Street Fighter IV - Arcade Edition\\resource\\battle\\chara"; + openFileDialog1->InitialDirectory = SteamPath; + } + } + catch(...){} + } + openFileDialog1->Filter = "SF4 model|*obj.emo"; + openFileDialog1->Title = "Select model"; + + if (openFileDialog1->ShowDialog() == System::Windows::Forms::DialogResult::OK) + { + treeView1->Nodes[0]->Nodes->Clear(); + treeView1->Nodes[1]->Nodes->Clear(); + treeView1->Nodes[2]->Nodes->Clear(); + + FileStream^ fs = File::OpenRead(openFileDialog1->FileName); + BinaryReader^ br = gcnew BinaryReader(fs); + + // Эта часть кода читает первые 4 байта, что является идентификатором #EMO + if (String::Compare(Encoding::UTF8->GetString(br->ReadBytes(4)), "#EMO", true) == 0) // Если равно, то продолжаем чтение. + { + //================================================================== + // Mesh + //================================================================== + + SkeletonReturn SkeletonReturn1 = ReadSkeleton(openFileDialog1->FileName, 16); + + // Данные о костях, отправка в dx. + + //================================================================== + + fs->Position = 32; // Пропуск 32 байт на позицию о кол-ве EMG. + ushort EMGcount = br->ReadInt16(); + + //================================================================== + + fs->Position = 32 + 4; // Позиция списка сдвигов на сдвиги названий EMG. + unsigned int EMGnamesOffsetsOffset = br->ReadInt32(); // Чтение. + fs->Position = 32 + EMGnamesOffsetsOffset; // Позиция списка сдвигов на названия EMG. + array^ EMGnamesOffsets = gcnew array(EMGcount); // Чтение. + for (ushort i = 0; i < EMGcount; i++) + { + EMGnamesOffsets[i] = br->ReadUInt32(); + } + + array^ EMGnames = gcnew array(EMGcount); + for (ushort i = 0; i < EMGcount; i++) + { + fs->Position = 32 + EMGnamesOffsets[i]; + + StringBuilder^ sb = gcnew StringBuilder; + while (br->ReadChar() != 0) + { + fs->Position--; + sb->Append(br->ReadChar()); + } + + EMGnames[i] = sb->ToString(); + } + + //================================================================== + + fs->Position = 32 + 8; // Позиция списка сдвигов на все EMG. + + array^ EMGoffsets = gcnew array(EMGcount); + array^ EMGReturn1 = gcnew array(EMGcount); + + m_D3DWrap->WrapCreateBuffers(EMGcount); // Предварительное создание массива буферов. + + for (ushort i = 0; i < EMGcount; i++) + { + EMGoffsets[i] = br->ReadInt32(); // Заполнение массива списком. + EMGReturn1[i] = ReadEMG(openFileDialog1->FileName, 32 + EMGoffsets[i] + 16); // Заполнение массива данными о каждом EMG. + + m_D3DWrap->WrapLoadEMG(i, EMGReturn1[i].SubmodelCount, EMGReturn1[i].DDSid, EMGReturn1[i].IndexCount, + EMGReturn1[i].VertexCount, EMGReturn1[i].VertexSize, + EMGReturn1[i].IndiceArray, EMGReturn1[i].VertexArray); + + treeView1->Nodes[0]->Nodes->Add(gcnew TreeNode((i + 1) + ". " + EMGnames[i])); + treeView1->Nodes[0]->Nodes[i]->Checked = true; + } + + button1->Enabled = true; + treeView1->Enabled = true; + treeView1->Nodes[0]->Checked = true; + treeView1->Nodes[0]->Expand(); + + //================================================================== + // Textures + //================================================================== + + array^ TrimChars = { 'o', 'b', 'e', 'm', 'j', '.' }; + String^ Path = Path::GetDirectoryName(openFileDialog1->FileName); + String^ Name = Path::GetFileName(openFileDialog1->FileName)->TrimEnd(TrimChars); + + if (!File::Exists(Path + "\\" + Name + "_01.col.emb")) + { + //m_D3DWrap->WrapLoadDDS(0, 0, 0); + } + else + { + fs = File::OpenRead(Path + "\\" + Name + "_01.col.emb"); + BinaryReader^ br = gcnew BinaryReader(fs); + + if (String::Compare(Encoding::UTF8->GetString(br->ReadBytes(4)), "#EMB", true) == 0) // Если равно, то продолжаем чтение. + { + treeView1->Nodes[1]->Checked = true; + + for (char i = 0; i < 22; i++) + { + String^ NodeName; + if (i < 9) + NodeName = Name + "_0" + (i + 1) + ".col.emb"; + else + NodeName = Name + "_" + (i + 1) + ".col.emb"; + + if (File::Exists(Path + "\\" + NodeName)) + { + treeView1->Nodes[1]->Nodes->Add(gcnew TreeNode(NodeName)); + treeView1->Nodes[1]->Nodes[treeView1->Nodes[1]->LastNode->Index]->Checked = true; + } + } + + EMBReturn result = ReadEMB(Path + "\\" + Name + "_01.col.emb"); + + m_D3DWrap->WrapLoadDDS(result.DDScount, result.DDSsize, result.DDSArray); + + treeView1->Nodes[1]->Expand(); + } + } + + // Normal map + if (!File::Exists(Path + "\\" + Name + ".nml.emb")) + { + // + } + else + { + fs = File::OpenRead(Path + "\\" + Name + ".nml.emb"); + BinaryReader^ br = gcnew BinaryReader(fs); + + if (String::Compare(Encoding::UTF8->GetString(br->ReadBytes(4)), "#EMB", true) == 0) // Если равно, то продолжаем чтение. + { + treeView1->Nodes[1]->Nodes->Add(gcnew TreeNode("Normal map")); + treeView1->Nodes[1]->Nodes[treeView1->Nodes[1]->LastNode->Index]->Checked = true; + } + } + + //================================================================== + // Animations + //================================================================== + + array^ TrimChars2 = { '_', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' }; + String^ Name2 = Name->TrimEnd(TrimChars2); + + if (!File::Exists(Path + "\\" + Name2 + ".obj.ema")) + { + // + } + else + { + fs = File::OpenRead(Path + "\\" + Name2 + ".obj.ema"); + BinaryReader^ br = gcnew BinaryReader(fs); + + if (String::Compare(Encoding::UTF8->GetString(br->ReadBytes(4)), "#EMA", true) == 0) // Если равно, то продолжаем чтение. + { + treeView1->Nodes[2]->Checked = true; + + EMAReturn result = ReadEMA(Path + "\\" + Name2 + ".obj.ema"); + + for (ushort i = 0; i < result.AnimationCount; i++) + { + String^ AnimationName = gcnew String(result.AnimationName[i]); + treeView1->Nodes[2]->Nodes->Add(gcnew TreeNode(i+1 + ". " + AnimationName)); + treeView1->Nodes[2]->Nodes[i]->Checked = true; + } + + treeView1->Nodes[2]->Expand(); + } + } + } + else + { + MessageBox::Show("Not a EMO", "Error", MessageBoxButtons::OK, MessageBoxIcon::Exclamation); + } + + br->Close(); + fs->Close(); + } +} +private: System::Void button1_Click(System::Object^ sender, System::EventArgs^ e) { + treeView1->Enabled = false; + + array^ TrimChars = { 'o', 'b', 'e', 'm', 'j', '.' }; + String^ Path = Path::GetDirectoryName(openFileDialog1->FileName); + String^ Name = Path::GetFileName(openFileDialog1->FileName)->TrimEnd(TrimChars); + + if (treeView1->Nodes[0]->Checked == true) // меш + { + // Код экспорта меша в SMD + SaveFileDialog^ saveFileDialog1 = gcnew SaveFileDialog(); + saveFileDialog1->FileName = Name; + saveFileDialog1->Filter = "SMD model|*.smd"; + saveFileDialog1->RestoreDirectory = true; + + if (saveFileDialog1->ShowDialog() == System::Windows::Forms::DialogResult::OK) + { + FileStream^ fs = File::OpenRead(openFileDialog1->FileName); + BinaryReader^ br = gcnew BinaryReader(fs); + StreamWriter^ sw = gcnew StreamWriter(saveFileDialog1->FileName); + + ushort Scale = ushort::Parse(toolStripTextBox1->Text); + + sw->WriteLine("version 1"); + + //================================================================== + // Иерархия костей. + //================================================================== + + SkeletonReturn SkeletonReturn1 = ReadSkeleton(openFileDialog1->FileName, 16); + + sw->WriteLine("nodes"); + + for (ushort i = 0; i < SkeletonReturn1.NodesCount; i++) // + { + String^ NodeName = gcnew String(SkeletonReturn1.NodeName[i]); + sw->WriteLine(i + " " + "\"" + NodeName + "\"" + " " + SkeletonReturn1.ParentNodeArray[i]); //" \"root\" child+1 + } + + sw->WriteLine("end"); + + //================================================================== + // Позиция костей. + //================================================================== + sw->WriteLine("skeleton"); + sw->WriteLine("time 0"); + + float structure[500][6]; + std::string names[500]; + if (replaceSkelToolStripMenuItem->Checked == true) // Если не отмечена анимация, экспортируется оригинальный скелет. + { + array^ TrimChars2 = { '_', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' }; + String^ Name2 = Name->TrimEnd(TrimChars2); + + String^ AnimName = gcnew String(Path + "\\" + Name2 + ".obj.ema"); + m_D3DWrap->WrapSetup(AnimName, 0); + m_D3DWrap->WrapUpdate(structure, names, "NONE", 0); + } + + for (ushort i = 0; i < SkeletonReturn1.NodesCount; i++) // + { + CultureInfo^ enUS = gcnew CultureInfo("en-US"); + + float tx = *((float*)(SkeletonReturn1.Matrix4x4[i] + 48)); // 12 + float ty = *((float*)(SkeletonReturn1.Matrix4x4[i] + 56)); // 14 + float tz = -*((float*)(SkeletonReturn1.Matrix4x4[i] + 52)); // 13 + + float rx = atan2(-*((float*)(SkeletonReturn1.Matrix4x4[i] + 36)), *((float*)(SkeletonReturn1.Matrix4x4[i] + 20))); // 9, 5 + float ry = -atan2(-*((float*)(SkeletonReturn1.Matrix4x4[i] + 8)), *((float*)(SkeletonReturn1.Matrix4x4[i]))); // 2, 0 + float rz = asin(*((float*)(SkeletonReturn1.Matrix4x4[i] + 4))); // 1 + + if (replaceSkelToolStripMenuItem->Checked == true) // Если не отмечена, экспортируется оригинальный скелет. + { + String^ NodeName = gcnew String(SkeletonReturn1.NodeName[i]);// Имя текущего нода. + + array^ TrimChars2 = { '_', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' }; + String^ Name2 = Name->TrimEnd(TrimChars2); + SkeletonReturn SkeletonReturn2 = ReadSkeleton(Path + "\\" + Name2 + ".obj.ema", 12); + + for (ushort Nodes = 0; Nodes < SkeletonReturn2.NodesCount; Nodes++) // Замена значений текущего нода значениями из реф. скелета анимации. + { + std::string name(names[Nodes]); + String^ nameclr = gcnew String(name.c_str()); + + if (nameclr == NodeName) + { + tx = structure[Nodes][0]; + ty = structure[Nodes][1]; + tz = structure[Nodes][2]; + rx = structure[Nodes][3]; + rz = structure[Nodes][4]; + + if (starPoseFixToolStripMenuItem->Checked == true) + { + if (nameclr == "RLegRoot") + ry = -(float)0.610842; + else if (nameclr == "LLegRoot") + ry = (float)0.610842; + else + ry = structure[Nodes][5]; + } + else + ry = structure[Nodes][5]; + } + } + } + else + { + if (i == 0) // Нужно наклонить. + rx = (float)1.570796; + } + + sw->WriteLine(i + " " + + (-tx * Scale).ToString("F6", enUS) + " " + + (ty * Scale).ToString("F6", enUS) + " " + + (tz * Scale).ToString("F6", enUS) + " " + + + rx.ToString("F6", enUS) + " " + + (-rz).ToString("F6", enUS) + " " + + (-ry).ToString("F6", enUS) ); + } + sw->WriteLine("end"); + + //================================================================== + // Треугольники + //================================================================== + fs->Position = 32; // Пропуск 32 байт на позицию о кол-ве EMG. + ushort EMGcount = br->ReadInt16(); + fs->Position = 32 + 8; // Позиция списка сдвигов на все EMG. + + array^ EMGoffsets = gcnew array(EMGcount); + array^ result = gcnew array(EMGcount); + + sw->WriteLine("triangles"); + + for (Byte CurrentEMG = 0; CurrentEMG < EMGcount; CurrentEMG++) + { + EMGoffsets[CurrentEMG] = br->ReadInt32(); // Заполнение массива списком. + result[CurrentEMG] = ReadEMG(openFileDialog1->FileName, 32 + EMGoffsets[CurrentEMG] + 16); // Заполнение массива данными о каждом EMG. + + if (treeView1->Nodes[0]->Nodes[CurrentEMG]->Checked) + { + for (Byte CurrentSubmodel = 0; CurrentSubmodel < result[CurrentEMG].SubmodelCount; CurrentSubmodel++) + { + for (ushort i = 0; i < result[CurrentEMG].IndexCount[CurrentSubmodel] - 2; i++) + { + CultureInfo^ enUS = gcnew CultureInfo("en-US"); + + int a, b, c; + + String^ Texture; + if (MergeSubmodelsToolStripMenuItem->Checked) + Texture = Name + "_" + (result[CurrentEMG].DDSid[CurrentSubmodel] + 1) + ".dds"; + else + Texture = CurrentEMG + "_" + Name + "_" + (result[CurrentEMG].DDSid[CurrentSubmodel] + 1) + ".dds"; + + if (i % 2 == 0) + { + a = result[CurrentEMG].IndiceArray[CurrentSubmodel][i + 0]; + b = result[CurrentEMG].IndiceArray[CurrentSubmodel][i + 1]; + c = result[CurrentEMG].IndiceArray[CurrentSubmodel][i + 2]; + + if (a != b && b != c) // пропуск дегенеративных + { + sw->WriteLine(Texture); + + for (char x = 2; x > -1; x--) + { + int index = result[CurrentEMG].IndiceArray[CurrentSubmodel][i + x]; + sw->Write("0 " + // PosX PosY PosZ + + (-*((float*)(index * result[CurrentEMG].VertexSize + result[CurrentEMG].VertexArray)) * Scale).ToString("F6", enUS) + " " + + (*((float*)(index * result[CurrentEMG].VertexSize + result[CurrentEMG].VertexArray + 4)) * Scale).ToString("F6", enUS) + " " + + (*((float*)(index * result[CurrentEMG].VertexSize + result[CurrentEMG].VertexArray + 8)) * Scale).ToString("F6", enUS) + " " + // NormX NormY NormZ + + (*((float*)(index * result[CurrentEMG].VertexSize + result[CurrentEMG].VertexArray + 12))).ToString("F6", enUS) + " " + + (*((float*)(index * result[CurrentEMG].VertexSize + result[CurrentEMG].VertexArray + 16))).ToString("F6", enUS) + " " + + (*((float*)(index * result[CurrentEMG].VertexSize + result[CurrentEMG].VertexArray + 20))).ToString("F6", enUS) + " " + // U V + + (*((float*)(index * result[CurrentEMG].VertexSize + result[CurrentEMG].VertexArray + 24))).ToString("F6", enUS) + " " + + (-*((float*)(index * result[CurrentEMG].VertexSize + result[CurrentEMG].VertexArray + 28))).ToString("F6", enUS) + " "); + + Byte BoneID[4]; + for (Byte Num = 0; Num < 4; Num++) + BoneID[Num] = *((Byte*)(index * result[CurrentEMG].VertexSize + result[CurrentEMG].VertexArray + 48 + Num)); + float Weight[3]; + for (Byte Num = 0; Num < 3; Num++) + Weight[Num] = *((float*)(index * result[CurrentEMG].VertexSize + result[CurrentEMG].VertexArray + 52 + (Num*4))); + + if (Weight[0] != 0 && Weight[1] == 0) // if 1 + sw->WriteLine("1 " + result[CurrentEMG].NodesArray[CurrentSubmodel][BoneID[0]].ToString() + " 1"); + else if (Weight[0] != 0 && Weight[1] != 0 && Weight[2] == 0) // if 2 + sw->WriteLine("2 " + result[CurrentEMG].NodesArray[CurrentSubmodel][BoneID[0]].ToString() + " " + + Weight[0].ToString("F6", enUS) + " " + + result[CurrentEMG].NodesArray[CurrentSubmodel][BoneID[1]].ToString() + " " + + Weight[1].ToString("F6", enUS)); + else if (Weight[0] + Weight[1] + Weight[2] > 0.999) // if 3 + sw->WriteLine("3 " + result[CurrentEMG].NodesArray[CurrentSubmodel][BoneID[0]].ToString() + " " + + Weight[0].ToString("F6", enUS) + " " + + result[CurrentEMG].NodesArray[CurrentSubmodel][BoneID[1]].ToString() + " " + + Weight[1].ToString("F6", enUS) + " " + + result[CurrentEMG].NodesArray[CurrentSubmodel][BoneID[2]].ToString() + " " + + Weight[2].ToString("F6", enUS)); + else // if 4 + sw->WriteLine("4 " + result[CurrentEMG].NodesArray[CurrentSubmodel][BoneID[0]].ToString() + " " + + Weight[0].ToString("F6", enUS) + " " + + result[CurrentEMG].NodesArray[CurrentSubmodel][BoneID[1]].ToString() + " " + + Weight[1].ToString("F6", enUS) + " " + + result[CurrentEMG].NodesArray[CurrentSubmodel][BoneID[2]].ToString() + " " + + Weight[2].ToString("F6", enUS) + " " + + result[CurrentEMG].NodesArray[CurrentSubmodel][BoneID[3]].ToString() + " " + + (1 - (Weight[0] + Weight[1] + Weight[2])).ToString("F6", enUS)); + } + } + } + else + { + a = result[CurrentEMG].IndiceArray[CurrentSubmodel][i + 2]; + b = result[CurrentEMG].IndiceArray[CurrentSubmodel][i + 1]; + c = result[CurrentEMG].IndiceArray[CurrentSubmodel][i + 0]; + + if (a != b && b != c) + { + sw->WriteLine(Texture); + + for (char x = 0; x < 3; x++) + { + int index = result[CurrentEMG].IndiceArray[CurrentSubmodel][i + x]; + sw->Write("0 " + // PosX PosY PosZ + + (-*((float*)(index * result[CurrentEMG].VertexSize + result[CurrentEMG].VertexArray)) * Scale).ToString("F6", enUS) + " " + + (*((float*)(index * result[CurrentEMG].VertexSize + result[CurrentEMG].VertexArray + 4)) * Scale).ToString("F6", enUS) + " " + + (*((float*)(index * result[CurrentEMG].VertexSize + result[CurrentEMG].VertexArray + 8)) * Scale).ToString("F6", enUS) + " " + // NormX NormY NormZ + + (*((float*)(index * result[CurrentEMG].VertexSize + result[CurrentEMG].VertexArray + 12))).ToString("F6", enUS) + " " + + (*((float*)(index * result[CurrentEMG].VertexSize + result[CurrentEMG].VertexArray + 16))).ToString("F6", enUS) + " " + + (*((float*)(index * result[CurrentEMG].VertexSize + result[CurrentEMG].VertexArray + 20))).ToString("F6", enUS) + " " + // U V + + (*((float*)(index * result[CurrentEMG].VertexSize + result[CurrentEMG].VertexArray + 24))).ToString("F6", enUS) + " " + + (-*((float*)(index * result[CurrentEMG].VertexSize + result[CurrentEMG].VertexArray + 28))).ToString("F6", enUS) + " "); + + Byte BoneID[4]; + for (Byte Num = 0; Num < 4; Num++) + BoneID[Num] = *((Byte*)(index * result[CurrentEMG].VertexSize + result[CurrentEMG].VertexArray + 48 + Num)); + float Weight[3]; + for (Byte Num = 0; Num < 3; Num++) + Weight[Num] = *((float*)(index * result[CurrentEMG].VertexSize + result[CurrentEMG].VertexArray + 52 + (Num * 4))); + + if (Weight[0] != 0 && Weight[1] == 0) + sw->WriteLine("1 " + result[CurrentEMG].NodesArray[CurrentSubmodel][BoneID[0]].ToString() + " 1"); + else if (Weight[0] != 0 && Weight[1] != 0 && Weight[2] == 0) + sw->WriteLine("2 " + result[CurrentEMG].NodesArray[CurrentSubmodel][BoneID[0]].ToString() + " " + + Weight[0].ToString("F6", enUS) + " " + + result[CurrentEMG].NodesArray[CurrentSubmodel][BoneID[1]].ToString() + " " + + Weight[1].ToString("F6", enUS)); + else if (Weight[0] + Weight[1] + Weight[2] > 0.999) + sw->WriteLine("3 " + result[CurrentEMG].NodesArray[CurrentSubmodel][BoneID[0]].ToString() + " " + + Weight[0].ToString("F6", enUS) + " " + + result[CurrentEMG].NodesArray[CurrentSubmodel][BoneID[1]].ToString() + " " + + Weight[1].ToString("F6", enUS) + " " + + result[CurrentEMG].NodesArray[CurrentSubmodel][BoneID[2]].ToString() + " " + + Weight[2].ToString("F6", enUS)); + else + sw->WriteLine("4 " + result[CurrentEMG].NodesArray[CurrentSubmodel][BoneID[0]].ToString() + " " + + Weight[0].ToString("F6", enUS) + " " + + result[CurrentEMG].NodesArray[CurrentSubmodel][BoneID[1]].ToString() + " " + + Weight[1].ToString("F6", enUS) + " " + + result[CurrentEMG].NodesArray[CurrentSubmodel][BoneID[2]].ToString() + " " + + Weight[2].ToString("F6", enUS) + " " + + result[CurrentEMG].NodesArray[CurrentSubmodel][BoneID[3]].ToString() + " " + + (1 - (Weight[0] + Weight[1] + Weight[2])).ToString("F6", enUS)); + } + } + } + } + } + } + } + + sw->Write("end"); + + sw->Close(); + br->Close(); + fs->Close(); + + MessageBox::Show("Mesh extracted", "Done", MessageBoxButtons::OK); + } + } + + if(treeView1->Nodes[1]->Checked == true) // текстуры + { + SaveFileDialog^ saveFileDialog1 = gcnew SaveFileDialog(); + saveFileDialog1->FileName = Name; + saveFileDialog1->Filter = "DDS Texture|*.dds"; + saveFileDialog1->RestoreDirectory = true; + + if (saveFileDialog1->ShowDialog() == System::Windows::Forms::DialogResult::OK) + { + for (Byte Node = 0; Node < treeView1->Nodes[1]->LastNode->Index; Node++) + { + if (treeView1->Nodes[1]->Nodes[Node]->Checked) + { + EMBReturn result; + String^ Temp = Path + "\\" + treeView1->Nodes[1]->Nodes[Node]->Text; + result = ReadEMB(Temp); + + String^ tempName = treeView1->Nodes[1]->Nodes[Node]->Text; + array^ name = tempName->Split('.'); + array^ nameArr = name[0]->Split('_'); + + for (Byte i = 0; i < result.DDScount; i++) + { + String^ OutputPath = Path::GetDirectoryName(saveFileDialog1->FileName); + FileStream^ fs = gcnew FileStream(OutputPath + "\\" + nameArr[0] + "_" + nameArr[1] + "_" + (i+1) + "_" + nameArr[2] + ".dds", FileMode::Create, FileAccess::ReadWrite); + BinaryWriter^ br = gcnew BinaryWriter(fs); + + for (ulong a = 0; a < result.DDSsize[i]; a++) + br->Write(result.DDSArray[i][a]); + + br->Close(); + fs->Close(); + } + } + } + + // Normal map. + if (treeView1->Nodes[1]->Nodes[treeView1->Nodes[1]->LastNode->Index]->Checked) + { + EMBReturn result; + result = ReadEMB(Path + "\\" + Name + ".nml.emb"); + + for (Byte i = 0; i < result.DDScount; i++) + { + String^ OutputPath = Path::GetDirectoryName(saveFileDialog1->FileName); + FileStream^ fs = gcnew FileStream(OutputPath + "\\" + Name + "_" + i + ".nml.dds", FileMode::Create, FileAccess::ReadWrite); + BinaryWriter^ br = gcnew BinaryWriter(fs); + + for (ulong a = 0; a < result.DDSsize[i]; a++) + br->Write(result.DDSArray[i][a]); + + br->Close(); + fs->Close(); + } + } + MessageBox::Show("Textures extracted", "Done", MessageBoxButtons::OK); + } + } + + if(treeView1->Nodes[2]->Checked == true) // анимации + { + SaveFileDialog^ saveFileDialog1 = gcnew SaveFileDialog(); + array^ TrimChars2 = { '_', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' }; + String^ Name2 = Name->TrimEnd(TrimChars2); + saveFileDialog1->FileName = Name2 + "_anim"; + saveFileDialog1->Filter = "SMD animation|*.smd"; + saveFileDialog1->RestoreDirectory = true; + + if (saveFileDialog1->ShowDialog() == System::Windows::Forms::DialogResult::OK) + { + ushort AnimationID; + IEnumerator^ myEnum = treeView1->Nodes[2]->Nodes->GetEnumerator(); + + String^ AnimName = gcnew String(Path + "\\" + Name2 + ".obj.ema"); + m_D3DWrap->WrapSetup(AnimName, 0); + + while (myEnum->MoveNext()) + { + TreeNode^ node = safe_cast(myEnum->Current); + if (node->Checked) + { + AnimationID = node->Index; + + String^ OutputPath = Path::GetDirectoryName(saveFileDialog1->FileName); + + StreamWriter^ sw = gcnew StreamWriter(OutputPath + "\\" + node->Text + ".smd"); + + CultureInfo^ enUS = gcnew CultureInfo("en-US"); + + ushort Scale = ushort::Parse(toolStripTextBox1->Text); + + sw->WriteLine("version 1"); + + //================================================================== + // Иерархия костей. + //================================================================== + + SkeletonReturn SkeletonReturn1 = ReadSkeleton(Path + "\\" + Name2 + ".obj.ema", 12); + + sw->WriteLine("nodes"); + + for (ushort i = 0; i < SkeletonReturn1.NodesCount; i++) // + { + String^ NodeName = gcnew String(SkeletonReturn1.NodeName[i]); + sw->WriteLine(i + " " + "\"" + NodeName + "\"" + " " + SkeletonReturn1.ParentNodeArray[i]); //" \"root\" child+1 + } + + sw->WriteLine("end"); + + //================================================================== + // Позиция костей. + //================================================================== + + sw->WriteLine("skeleton"); + + EMAReturn result = ReadEMA(Path + "\\" + Name2 + ".obj.ema"); + + String^ AnimationName = gcnew String(result.AnimationName[AnimationID]); + int Duration = result.Duration[AnimationID]; + + float structure[500][6]; + std::string names[500]; + + sw->WriteLine("time 0"); + m_D3DWrap->WrapUpdate(structure, names, "ref", 0); + for (int i = 0; i < SkeletonReturn1.NodesCount; i++) + { + if (i == 0 ) + sw->WriteLine("0 0 0 0 0 0 0"); //1.570796 3.141592 + else if (i != 0) + { + sw->Write(i + " " + (-structure[i][0] * Scale).ToString("F6", enUS) + " " + (structure[i][1] * Scale).ToString("F6", enUS) + " " + (structure[i][2] * Scale).ToString("F6", enUS) + " "); + sw->WriteLine(structure[i][3].ToString("F6", enUS) + " " + (-structure[i][4]).ToString("F6", enUS) + " " + (-structure[i][5]).ToString("F6", enUS)); + } + } + + for (ushort time = 0; time < Duration; time++) + { + sw->WriteLine("time " + (time + 1)); + m_D3DWrap->WrapUpdate(structure, names, AnimationName, time); + for (int i = 0; i < SkeletonReturn1.NodesCount; i++) + { + if (i == 0 && time == 0) + sw->WriteLine("0 0 0 0 0 0 0"); //1.570796 3.141592 + else if (i != 0) + { + std::string name(names[i]); + String^ nameclr = gcnew String(name.c_str()); + + if (nameclr == "RLegRoot" || nameclr == "LLegRoot" || nameclr == "LArmRoot" || nameclr == "RArmRoot") + { + } + else + { + sw->Write(i + " " + (-structure[i][0] * Scale).ToString("F6", enUS) + " " + (structure[i][1] * Scale).ToString("F6", enUS) + " " + (structure[i][2] * Scale).ToString("F6", enUS) + " "); + sw->WriteLine(structure[i][3].ToString("F6", enUS) + " " + (-structure[i][4]).ToString("F6", enUS) + " " + (-structure[i][5]).ToString("F6", enUS)); + } + } + } + } + + sw->WriteLine("end"); + sw->Close(); + } + } + + MessageBox::Show("Animations extracted", "Done", MessageBoxButtons::OK); + } + } + + treeView1->Enabled = true; +} +private: System::Void treeView1_AfterCheck(System::Object^ sender, System::Windows::Forms::TreeViewEventArgs^ e) { + //================================================================== + // Блок взаимодейсвия нодов. + treeView1->BeginUpdate(); + if (e->Action != TreeViewAction::Unknown) + { + // Выделение или снятие выделения членов, если отмечен коренной нод. + if (e->Node->Nodes->Count > 0) + { + IEnumerator^ myEnum = e->Node->Nodes->GetEnumerator(); + while (myEnum->MoveNext()) + { + TreeNode^ node = safe_cast(myEnum->Current); + node->Checked = e->Node->Checked; + } + } + // Влияние членов на отметку коренного нода. + if (e->Node->Parent != nullptr && e->Node->Checked) + e->Node->Parent->Checked = true; + else if (e->Node->Parent != nullptr && !e->Node->Checked) + { + ushort i = 0; // Подсчёт отмеченных нодов. + IEnumerator^ myEnum = e->Node->Parent->Nodes->GetEnumerator(); + while (myEnum->MoveNext()) + { + TreeNode^ node = safe_cast(myEnum->Current); + if (node->Checked) + i++; + } + if (i == 0) // Если 0, то снимаем галочку с родительского. + e->Node->Parent->Checked = false; + } + } + treeView1->EndUpdate(); + //================================================================== + + if (e->Action != TreeViewAction::Unknown) + { + if (e->Node->Name == "Node0") // Если отмечен галочкой нод "Mesh". + { + if (e->Node->Checked) // Полное отображение модели. + { + FileStream^ fs = File::OpenRead(openFileDialog1->FileName); + BinaryReader^ br = gcnew BinaryReader(fs); + + fs->Position = 32; // Пропуск 32 байт на позицию о кол-ве EMG. + ushort EMGcount = br->ReadInt16(); + fs->Position = 32 + 8; // Позиция списка сдвигов на все EMG. + + array^ EMGoffsets = gcnew array(EMGcount); + array^ result = gcnew array(EMGcount); + + m_D3DWrap->WrapCreateBuffers(EMGcount); // Предварительное создание массива буферов. + + for (Byte i = 0; i < EMGcount; i++) + { + EMGoffsets[i] = br->ReadInt32(); // Заполнение массива списком. + result[i] = ReadEMG(openFileDialog1->FileName, 32 + EMGoffsets[i] + 16); // Заполнение массива данными о каждом EMG. + m_D3DWrap->WrapLoadEMG(i, result[i].SubmodelCount, result[i].DDSid, result[i].IndexCount, + result[i].VertexCount, result[i].VertexSize, + result[i].IndiceArray, result[i].VertexArray); + } + } + else // В обратном случае убрать полностью. + { + m_D3DWrap->WrapCreateBuffers(0); + } + } + + // Частичное отображение модели. + if (e->Node->Parent != nullptr && e->Node->Parent->Name == "Node0") + { + FileStream^ fs = File::OpenRead(openFileDialog1->FileName); + BinaryReader^ br = gcnew BinaryReader(fs); + + fs->Position = 32; // Пропуск 32 байт на позицию о кол-ве EMG. + ushort EMGcount = br->ReadInt16(); + fs->Position = 32 + 8; // Позиция списка сдвигов на все EMG. + + array^ EMGoffsets = gcnew array(EMGcount); + array^ result = gcnew array(EMGcount); + + // Вычисление необходимого числа буферов и создание массива отметок. + ushort BufferCount = 0; + array^ Arr = gcnew array(EMGcount); + IEnumerator^ myEnum = e->Node->Parent->Nodes->GetEnumerator(); + while (myEnum->MoveNext()) + { + TreeNode^ node = safe_cast(myEnum->Current); + if (node->Checked) + { + BufferCount++; + Arr[node->Index] = true; + } + else + Arr[node->Index] = false; + } + + m_D3DWrap->WrapCreateBuffers(BufferCount); // Предварительное создание массива буферов. + + // Заполнение буферов с учётом отметок. + int sendcount = 0; + for (Byte i = 0; i < EMGcount; i++) + { + EMGoffsets[i] = br->ReadInt32(); // Заполнение массива списком. + + if (Arr[i] == true) + { + result[i] = ReadEMG(openFileDialog1->FileName, 32 + EMGoffsets[i] + 16); // Заполнение массива данными о каждом EMG. + m_D3DWrap->WrapLoadEMG(sendcount, result[i].SubmodelCount, result[i].DDSid, result[i].IndexCount, + result[i].VertexCount, result[i].VertexSize, + result[i].IndiceArray, result[i].VertexArray); + sendcount++; + } + } + } + } + + // Кнопка "Extract". + if (!treeView1->Nodes[0]->Checked && !treeView1->Nodes[1]->Checked + && !treeView1->Nodes[2]->Checked) + button1->Enabled = false; + else + button1->Enabled = true; +} +private: System::Void treeView1_AfterSelect(System::Object^ sender, System::Windows::Forms::TreeViewEventArgs^ e) { + if (e->Action != TreeViewAction::Unknown) + { + if (e->Node->Name == "Node1") + { + + } + + if (e->Node->Parent != nullptr && e->Node->Parent->Name == "Node1") + { + if (e->Node->Index != e->Node->Parent->LastNode->Index) + { + String^ Path = Path::GetDirectoryName(openFileDialog1->FileName); + Path += "\\" + e->Node->Text; + + EMBReturn result; + result = ReadEMB(Path); + m_D3DWrap->WrapLoadDDS(result.DDScount, result.DDSsize, result.DDSArray); + } + } + } +} +private: System::Void steamToolStripMenuItem_Click(System::Object^ sender, System::EventArgs^ e) { + if (steamToolStripMenuItem->Checked) + steamToolStripMenuItem->Checked = false; + else + steamToolStripMenuItem->Checked = true; +} +private: System::Void originStoreToolStripMenuItem_Click(System::Object^ sender, System::EventArgs^ e) { + if (originStoreToolStripMenuItem->Checked) + originStoreToolStripMenuItem->Checked = false; + else + originStoreToolStripMenuItem->Checked = true; +} +private: System::Void MergeSubmodelsToolStripMenuItem_Click(System::Object^ sender, System::EventArgs^ e) { + if (MergeSubmodelsToolStripMenuItem->Checked) + MergeSubmodelsToolStripMenuItem->Checked = false; + else + MergeSubmodelsToolStripMenuItem->Checked = true; +} +private: System::Void replaceSkelToolStripMenuItem_Click(System::Object^ sender, System::EventArgs^ e) { + if (replaceSkelToolStripMenuItem->Checked) + replaceSkelToolStripMenuItem->Checked = false; + else + replaceSkelToolStripMenuItem->Checked = true; +} +private: System::Void starPoseFixToolStripMenuItem_Click(System::Object^ sender, System::EventArgs^ e) { + if (starPoseFixToolStripMenuItem->Checked) + starPoseFixToolStripMenuItem->Checked = false; + else + starPoseFixToolStripMenuItem->Checked = true; +} +private: System::Void TopSplitContainer_SplitterMoved(System::Object^ sender, System::Windows::Forms::SplitterEventArgs^ e) { + m_D3DWrap->WrapResize(TopSplitContainer->Panel2->Width, TopSplitContainer->Panel2->Height); +} +private: System::Void MainForm_SizeChanged(System::Object^ sender, System::EventArgs^ e) { + m_D3DWrap->WrapResize(TopSplitContainer->Panel2->Width, TopSplitContainer->Panel2->Height); +} +}; +} \ No newline at end of file diff --git a/main/main.resx b/main/main.resx new file mode 100644 index 0000000..e9286c2 --- /dev/null +++ b/main/main.resx @@ -0,0 +1,132 @@ +п»ї + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + + 133, 17 + + + 238, 17 + + + 57 + + \ No newline at end of file diff --git a/main/main.vcxproj b/main/main.vcxproj new file mode 100644 index 0000000..8e6d1a6 --- /dev/null +++ b/main/main.vcxproj @@ -0,0 +1,130 @@ +п»ї + + + + Debug + Win32 + + + Release + Win32 + + + + {62CE09EC-B4BA-4E35-BBD7-112EC13BCCC4} + v4.5 + ManagedCProj + main + USF4ce + 8.1 + + + + Application + true + v141 + true + Unicode + + + Application + false + v141 + true + Unicode + + + + + + + + + + + + + false + $(ProjectName) + + + false + + + + Level3 + Disabled + WIN32;_DEBUG;%(PreprocessorDefinitions) + $(DXSDK_DIR)\include + true + + + true + + Windows + main + $(DXSDK_DIR)\lib\x86 + + + true + + + + + Level3 + WIN32;NDEBUG;%(PreprocessorDefinitions) + $(DXSDK_DIR)\include + + + true + + $(DXSDK_DIR)\lib\x86 + Windows + main + + + + + + + + + + + + + + + CppForm + + + CppForm + + + + + + + + AboutBox.h + Designer + + + main.h + Designer + + + + + + + {01a3003a-08fd-4a54-8eb2-32f4bd558e28} + + + + + + + + + \ No newline at end of file diff --git a/main/main.vcxproj.filters b/main/main.vcxproj.filters new file mode 100644 index 0000000..40c0abd --- /dev/null +++ b/main/main.vcxproj.filters @@ -0,0 +1,36 @@ +п»ї + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + + + Source Files + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + + + + + + + \ No newline at end of file diff --git a/main/main.vcxproj.user b/main/main.vcxproj.user new file mode 100644 index 0000000..ef5ff2a --- /dev/null +++ b/main/main.vcxproj.user @@ -0,0 +1,4 @@ +п»ї + + + \ No newline at end of file diff --git a/main/resource.h b/main/resource.h new file mode 100644 index 0000000..0126807 --- /dev/null +++ b/main/resource.h @@ -0,0 +1,14 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by USF4ce.rc + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif