diff --git a/Source/Core/Common/Src/MathUtil.cpp b/Source/Core/Common/Src/MathUtil.cpp index 65446cec0c..e2dbaa0640 100644 --- a/Source/Core/Common/Src/MathUtil.cpp +++ b/Source/Core/Common/Src/MathUtil.cpp @@ -20,6 +20,8 @@ #include "Common.h" #include "MathUtil.h" +#include + static u32 saved_sse_state = _mm_getcsr(); static const u32 default_sse_state = _mm_getcsr(); @@ -40,3 +42,106 @@ void SaveSSEState() { saved_sse_state = _mm_getcsr(); } + +void MatrixMul(int n, const float *a, const float *b, float *result) +{ + for(int i = 0; i < n; ++i) { + for(int j= 0; j < n; ++j) { + float temp = 0; + for(int k = 0; k < n; ++k) { + temp += a[i * n + k] * b[k * n + j]; + } + result[i * n + j] = temp; + } + } +} + +void Matrix33::LoadIdentity(Matrix33 &mtx) +{ + memset(mtx.data, 0, sizeof(mtx.data)); + mtx.data[0] = 1.0f; + mtx.data[4] = 1.0f; + mtx.data[8] = 1.0f; +} + +void Matrix33::RotateX(Matrix33 &mtx, float rad) +{ + float s = sin(rad); + float c = cos(rad); + memset(mtx.data, 0, sizeof(mtx.data)); + mtx.data[0] = 1; + mtx.data[4] = c; + mtx.data[5] = -s; + mtx.data[7] = s; + mtx.data[8] = c; +} +void Matrix33::RotateY(Matrix33 &mtx, float rad) +{ + float s = sin(rad); + float c = cos(rad); + memset(mtx.data, 0, sizeof(mtx.data)); + mtx.data[0] = c; + mtx.data[2] = s; + mtx.data[4] = 1; + mtx.data[6] = -s; + mtx.data[8] = c; +} + +void Matrix33::Multiply(const Matrix33 &a, const Matrix33 &b, Matrix33 &result) +{ + MatrixMul(3, a.data, b.data, result.data); +} + +void Matrix33::Multiply(const Matrix33 &a, const float vec[3], float result[3]) +{ + for(int i = 0; i < 3; ++i) { + result[i] = 0; + for(int k = 0; k < 3; ++k) { + result[i] += a.data[i * 3 + k] * vec[k]; + } + } +} + +void Matrix44::LoadIdentity(Matrix44 &mtx) +{ + memset(mtx.data, 0, sizeof(mtx.data)); + mtx.data[0] = 1.0f; + mtx.data[5] = 1.0f; + mtx.data[10] = 1.0f; + mtx.data[15] = 1.0f; +} + +void Matrix44::LoadMatrix33(Matrix44 &mtx, const Matrix33 &m33) +{ + for(int i = 0; i < 3; ++i) { + for(int j = 0; j < 3; ++j) { + mtx.data[i * 4 + j] = m33.data[i * 3 + j]; + } + } + + for(int i = 0; i < 3; ++i) { + mtx.data[i * 4 + 3] = 0; + mtx.data[i + 12] = 0; + } + mtx.data[15] = 1.0f; +} + +void Matrix44::Set(Matrix44 &mtx, const float mtxArray[16]) +{ + for(int i = 0; i < 16; ++i) { + mtx.data[i] = mtxArray[i]; + } +} + +void Matrix44::Translate(Matrix44 &mtx, const float vec[3]) +{ + LoadIdentity(mtx); + mtx.data[3] = vec[0]; + mtx.data[7] = vec[1]; + mtx.data[11] = vec[2]; +} + +void Matrix44::Multiply(const Matrix44 &a, const Matrix44 &b, Matrix44 &result) +{ + MatrixMul(4, a.data, b.data, result.data); +} diff --git a/Source/Core/Common/Src/MathUtil.h b/Source/Core/Common/Src/MathUtil.h index cbf24bcd35..72c0eca29a 100644 --- a/Source/Core/Common/Src/MathUtil.h +++ b/Source/Core/Common/Src/MathUtil.h @@ -36,4 +36,36 @@ void LoadDefaultSSEState(); #define ROUND_UP(x, a) (((x) + (a) - 1) & ~((a) - 1)) +// ugly matrix implementation +class Matrix33 +{ +public: + static void LoadIdentity(Matrix33 &mtx); + + // set mtx to be a rotation matrix around the x axis + static void RotateX(Matrix33 &mtx, float rad); + // set mtx to be a rotation matrix around the y axis + static void RotateY(Matrix33 &mtx, float rad); + + // set result = a x b + static void Multiply(const Matrix33 &a, const Matrix33 &b, Matrix33 &result); + static void Multiply(const Matrix33 &a, const float vec[3], float result[3]); + + float data[9]; +}; + +class Matrix44 +{ +public: + static void LoadIdentity(Matrix44 &mtx); + static void LoadMatrix33(Matrix44 &mtx, const Matrix33 &m33); + static void Set(Matrix44 &mtx, const float mtxArray[16]); + + static void Translate(Matrix44 &mtx, const float vec[3]); + + static void Multiply(const Matrix44 &a, const Matrix44 &b, Matrix44 &result); + + float data[16]; +}; + #endif // _MATH_UTIL_H_ diff --git a/Source/Core/VideoCommon/Src/VertexShaderManager.cpp b/Source/Core/VideoCommon/Src/VertexShaderManager.cpp index 6e37e7b44b..3e6db1acbf 100644 --- a/Source/Core/VideoCommon/Src/VertexShaderManager.cpp +++ b/Source/Core/VideoCommon/Src/VertexShaderManager.cpp @@ -16,6 +16,7 @@ // http://code.google.com/p/dolphin-emu/ #include "Common.h" +#include "MathUtil.h" #include "Profiler.h" #include @@ -45,6 +46,11 @@ static int nNormalMatricesChanged[2]; // min,max static int nPostTransformMatricesChanged[2]; // min,max static int nLightsChanged[2]; // min,max +static Matrix33 s_viewRotationMatrix; +static Matrix33 s_viewInvRotationMatrix; +static float s_fViewTranslationVector[3]; +static float s_fViewRotation[2]; + void UpdateViewport(); void VertexShaderManager::Init() @@ -59,6 +65,8 @@ void VertexShaderManager::Init() memset(&xfregs, 0, sizeof(xfregs)); memset(xfmem, 0, sizeof(xfmem)); + + ResetView(); } void VertexShaderManager::Shutdown() @@ -69,7 +77,7 @@ void VertexShaderManager::Shutdown() // ======================================================================================= // Syncs the shader constant buffers with xfmem // ---------------- -void VertexShaderManager::SetConstants(bool proj_hax_1,bool SMG_hack) +void VertexShaderManager::SetConstants(bool proj_hax_1,bool SMG_hack, bool freeLook) { //nTransformMatricesChanged[0] = 0; nTransformMatricesChanged[1] = 256; //nNormalMatricesChanged[0] = 0; nNormalMatricesChanged[1] = 96; @@ -293,10 +301,29 @@ void VertexShaderManager::SetConstants(bool proj_hax_1,bool SMG_hack) } PRIM_LOG("Projection: %f %f %f %f %f %f\n", xfregs.rawProjection[0], xfregs.rawProjection[1], xfregs.rawProjection[2], xfregs.rawProjection[3], xfregs.rawProjection[4], xfregs.rawProjection[5]); - SetVSConstant4fv(C_PROJECTION, &g_fProjectionMatrix[0]); - SetVSConstant4fv(C_PROJECTION+1, &g_fProjectionMatrix[4]); - SetVSConstant4fv(C_PROJECTION+2, &g_fProjectionMatrix[8]); - SetVSConstant4fv(C_PROJECTION+3, &g_fProjectionMatrix[12]); + + if (freeLook) { + Matrix44 mtxA; + Matrix44 mtxB; + Matrix44 viewMtx; + + Matrix44::Translate(mtxA, s_fViewTranslationVector); + Matrix44::LoadMatrix33(mtxB, s_viewRotationMatrix); + Matrix44::Multiply(mtxB, mtxA, viewMtx); // view = rotation x translation + Matrix44::Set(mtxB, g_fProjectionMatrix); + Matrix44::Multiply(mtxB, viewMtx, mtxA); // mtxA = projection x view + + SetVSConstant4fv(C_PROJECTION, &mtxA.data[0]); + SetVSConstant4fv(C_PROJECTION+1, &mtxA.data[4]); + SetVSConstant4fv(C_PROJECTION+2, &mtxA.data[8]); + SetVSConstant4fv(C_PROJECTION+3, &mtxA.data[12]); + } + else { + SetVSConstant4fv(C_PROJECTION, &g_fProjectionMatrix[0]); + SetVSConstant4fv(C_PROJECTION+1, &g_fProjectionMatrix[4]); + SetVSConstant4fv(C_PROJECTION+2, &g_fProjectionMatrix[8]); + SetVSConstant4fv(C_PROJECTION+3, &g_fProjectionMatrix[12]); + } } } @@ -430,3 +457,46 @@ void VertexShaderManager::SetMaterialColor(int index, u32 data) s_fMaterials[ind++] = ((data>>8)&0xFF)/255.0f; s_fMaterials[ind] = ((data)&0xFF)/255.0f; } + +void VertexShaderManager::TranslateView(float x, float y) +{ + float result[3]; + float vector[3] = { x,0,y }; + + Matrix33::Multiply(s_viewInvRotationMatrix, vector, result); + + for(int i = 0; i < 3; i++) { + s_fViewTranslationVector[i] += result[i]; + } + + bProjectionChanged = true; +} + +void VertexShaderManager::RotateView(float x, float y) +{ + s_fViewRotation[0] += x; + s_fViewRotation[1] += y; + + Matrix33 mx; + Matrix33 my; + Matrix33::RotateX(mx, s_fViewRotation[1]); + Matrix33::RotateY(my, s_fViewRotation[0]); + Matrix33::Multiply(mx, my, s_viewRotationMatrix); + + // reverse rotation + Matrix33::RotateX(mx, -s_fViewRotation[1]); + Matrix33::RotateY(my, -s_fViewRotation[0]); + Matrix33::Multiply(my, mx, s_viewInvRotationMatrix); + + bProjectionChanged = true; +} + +void VertexShaderManager::ResetView() +{ + memset(s_fViewTranslationVector, 0, sizeof(s_fViewTranslationVector)); + Matrix33::LoadIdentity(s_viewRotationMatrix); + Matrix33::LoadIdentity(s_viewInvRotationMatrix); + s_fViewRotation[0] = s_fViewRotation[1] = 0.0f; + + bProjectionChanged = true; +} diff --git a/Source/Core/VideoCommon/Src/VertexShaderManager.h b/Source/Core/VideoCommon/Src/VertexShaderManager.h index dc7ecd2706..8bb3f3d455 100644 --- a/Source/Core/VideoCommon/Src/VertexShaderManager.h +++ b/Source/Core/VideoCommon/Src/VertexShaderManager.h @@ -28,7 +28,7 @@ public: static void Shutdown(); // constant management - static void SetConstants(bool proj_hax_1, bool SMG_hack); + static void SetConstants(bool proj_hax_1, bool SMG_hack, bool freeLook); static void SetViewport(float* _Viewport); static void SetViewportChanged(); @@ -37,6 +37,10 @@ public: static void SetTexMatrixChangedA(u32 Value); static void SetTexMatrixChangedB(u32 Value); static void SetMaterialColor(int index, u32 data); + + static void TranslateView(float x, float y); + static void RotateView(float x, float y); + static void ResetView(); }; void SetVSConstant4f(int const_number, float f1, float f2, float f3, float f4); diff --git a/Source/Plugins/Plugin_VideoDX9/Src/VertexManager.cpp b/Source/Plugins/Plugin_VideoDX9/Src/VertexManager.cpp index 394a02e3d5..d0b2b97618 100644 --- a/Source/Plugins/Plugin_VideoDX9/Src/VertexManager.cpp +++ b/Source/Plugins/Plugin_VideoDX9/Src/VertexManager.cpp @@ -235,7 +235,7 @@ void Flush() if (numVertices) { // set global constants - VertexShaderManager::SetConstants(false, false); + VertexShaderManager::SetConstants(false, false, false); PixelShaderManager::SetConstants(); PixelShaderCache::SetShader(); diff --git a/Source/Plugins/Plugin_VideoOGL/Src/Config.cpp b/Source/Plugins/Plugin_VideoOGL/Src/Config.cpp index 9843215724..7f038a3d58 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/Config.cpp +++ b/Source/Plugins/Plugin_VideoOGL/Src/Config.cpp @@ -62,6 +62,7 @@ void Config::Load() iniFile.Get("Settings", "DumpTextures", &bDumpTextures, 0); iniFile.Get("Settings", "DumpEFBTarget", &bDumpEFBTarget, 0); iniFile.Get("Settings", "DumpFrames", &bDumpFrames, 0); + iniFile.Get("Settings", "FreeLook", &bFreeLook, 0); iniFile.Get("Settings", "ShowShaderErrors", &bShowShaderErrors, 0); iniFile.Get("Settings", "MSAA", &iMultisampleMode, 0); iniFile.Get("Settings", "DstAlphaPass", &bDstAlphaPass, false); @@ -147,6 +148,7 @@ void Config::Save() iniFile.Set("Settings", "DumpTextures", bDumpTextures); iniFile.Set("Settings", "DumpEFBTarget", bDumpEFBTarget); iniFile.Set("Settings", "DumpFrames", bDumpFrames); + iniFile.Set("Settings", "FreeLook", bFreeLook); iniFile.Set("Settings", "ShowEFBCopyRegions", bShowEFBCopyRegions); iniFile.Set("Settings", "ShowShaderErrors", bShowShaderErrors); iniFile.Set("Settings", "MSAA", iMultisampleMode); diff --git a/Source/Plugins/Plugin_VideoOGL/Src/Config.h b/Source/Plugins/Plugin_VideoOGL/Src/Config.h index 2b7450934b..5910adf5a0 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/Config.h +++ b/Source/Plugins/Plugin_VideoOGL/Src/Config.h @@ -86,6 +86,7 @@ struct Config bool bDumpTextures; bool bDumpEFBTarget; bool bDumpFrames; + bool bFreeLook; // Hacks bool bEFBCopyDisable; diff --git a/Source/Plugins/Plugin_VideoOGL/Src/GUI/ConfigDlg.cpp b/Source/Plugins/Plugin_VideoOGL/Src/GUI/ConfigDlg.cpp index 66a055fa40..9b2cc92011 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/GUI/ConfigDlg.cpp +++ b/Source/Plugins/Plugin_VideoOGL/Src/GUI/ConfigDlg.cpp @@ -21,6 +21,7 @@ #include "../Config.h" #include "../TextureMngr.h" +#include "VertexShaderManager.h" BEGIN_EVENT_TABLE(ConfigDialog,wxDialog) EVT_CLOSE(ConfigDialog::OnClose) @@ -54,7 +55,8 @@ BEGIN_EVENT_TABLE(ConfigDialog,wxDialog) EVT_CHECKBOX(ID_TEXFMTCENTER, ConfigDialog::AdvancedSettingsChanged) EVT_CHECKBOX(ID_DUMPTEXTURES, ConfigDialog::AdvancedSettingsChanged) EVT_CHECKBOX(ID_DUMPEFBTARGET, ConfigDialog::AdvancedSettingsChanged) - EVT_CHECKBOX(ID_DUMPFRAMES, ConfigDialog::AdvancedSettingsChanged) + EVT_CHECKBOX(ID_DUMPFRAMES, ConfigDialog::AdvancedSettingsChanged) + EVT_CHECKBOX(ID_FREELOOK, ConfigDialog::AdvancedSettingsChanged) EVT_CHECKBOX(ID_DISABLELIGHTING, ConfigDialog::AdvancedSettingsChanged) EVT_CHECKBOX(ID_DISABLETEXTURING, ConfigDialog::AdvancedSettingsChanged) EVT_CHECKBOX(ID_DISABLEFOG, ConfigDialog::AdvancedSettingsChanged) @@ -350,6 +352,8 @@ void ConfigDialog::CreateGUIControls() " set up for the dump or several gigabytes of space available.")); #endif m_DumpFrames->SetValue(g_Config.bDumpFrames); + m_FreeLook = new wxCheckBox(m_PageAdvanced, ID_FREELOOK, wxT("Free Look"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator); + m_FreeLook->SetValue(g_Config.bFreeLook); // Hacks controls m_SafeTextureCache = new wxCheckBox(m_PageAdvanced, ID_SAFETEXTURECACHE, wxT("Use Safe texture cache"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator); @@ -415,10 +419,12 @@ void ConfigDialog::CreateGUIControls() sRenderBoxRow1->Add(sSBox, 0, wxALL|wxEXPAND, 5); sbRendering->Add(sRenderBoxRow1); - sUtilities = new wxBoxSizer(wxHORIZONTAL); - sUtilities->Add(m_DumpTextures, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5); - sUtilities->Add(m_DumpEFBTarget, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5); - sUtilities->Add(m_DumpFrames, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5); + //sUtilities = new wxBoxSizer(wxHORIZONTAL); + sUtilities = new wxGridBagSizer(0, 0); + sUtilities->Add(m_DumpTextures, wxGBPosition(0, 0), wxGBSpan(1, 1), wxALIGN_CENTER_VERTICAL|wxALL, 5); + sUtilities->Add(m_DumpEFBTarget, wxGBPosition(0, 1), wxGBSpan(1, 1), wxALIGN_CENTER_VERTICAL|wxALL, 5); + sUtilities->Add(m_DumpFrames, wxGBPosition(1, 0), wxGBSpan(1, 1), wxALIGN_CENTER_VERTICAL|wxALL, 5); + sUtilities->Add(m_FreeLook, wxGBPosition(1, 1), wxGBSpan(1, 1), wxALIGN_CENTER_VERTICAL|wxALL, 5); sbUtilities->Add(sUtilities, 1, wxEXPAND); // Sizers @@ -558,6 +564,9 @@ void ConfigDialog::AdvancedSettingsChanged(wxCommandEvent& event) case ID_DUMPFRAMES: g_Config.bDumpFrames = m_DumpFrames->IsChecked(); break; + case ID_FREELOOK: + g_Config.bFreeLook = m_FreeLook->IsChecked(); + break; case ID_TEXTUREPATH: break; case ID_CHECKBOX_DISABLECOPYEFB: diff --git a/Source/Plugins/Plugin_VideoOGL/Src/GUI/ConfigDlg.h b/Source/Plugins/Plugin_VideoOGL/Src/GUI/ConfigDlg.h index de3fc248fa..0b4ed94bd0 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/GUI/ConfigDlg.h +++ b/Source/Plugins/Plugin_VideoOGL/Src/GUI/ConfigDlg.h @@ -64,7 +64,7 @@ class ConfigDialog : public wxDialog wxStaticBoxSizer* sbRendering; wxGridBagSizer* sRendering; wxStaticBoxSizer* sbUtilities; - wxBoxSizer* sUtilities; + wxGridBagSizer* sUtilities; wxStaticBoxSizer* sbHacks; wxGridBagSizer* sHacks; @@ -108,6 +108,7 @@ class ConfigDialog : public wxDialog wxCheckBox *m_DumpTextures; wxCheckBox *m_DumpEFBTarget; wxCheckBox *m_DumpFrames; + wxCheckBox *m_FreeLook; wxStaticBox * m_StaticBox_EFB; wxCheckBox *m_CheckBox_DisableCopyEFB; wxRadioButton *m_Radio_CopyEFBToRAM, *m_Radio_CopyEFBToGL; @@ -167,6 +168,7 @@ class ConfigDialog : public wxDialog ID_DUMPTEXTURES, ID_DUMPEFBTARGET, ID_DUMPFRAMES, + ID_FREELOOK, ID_TEXTUREPATH, ID_CHECKBOX_DISABLECOPYEFB, diff --git a/Source/Plugins/Plugin_VideoOGL/Src/OS/Win32.cpp b/Source/Plugins/Plugin_VideoOGL/Src/OS/Win32.cpp index 4c76c8b807..260651154e 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/OS/Win32.cpp +++ b/Source/Plugins/Plugin_VideoOGL/Src/OS/Win32.cpp @@ -28,6 +28,7 @@ #include "main.h" #include "Win32.h" #include "OnScreenDisplay.h" +#include "VertexShaderManager.h" #include "StringUtil.h" @@ -138,6 +139,65 @@ HWND GetChildParentWnd() return m_hMain; } +void FreeLookInput( UINT iMsg, WPARAM wParam ) +{ + static float debugSpeed = 1.0f; + static bool mouseLookEnabled = false; + static float lastMouse[2]; + + switch( iMsg ) + { + + case WM_KEYDOWN: + switch( LOWORD( wParam )) + { + case '9': + debugSpeed /= 2.0f; + break; + case '0': + debugSpeed *= 2.0f; + break; + case 'W': + VertexShaderManager::TranslateView(0.0f, debugSpeed); + break; + case 'S': + VertexShaderManager::TranslateView(0.0f, -debugSpeed); + break; + case 'A': + VertexShaderManager::TranslateView(debugSpeed, 0.0f); + break; + case 'D': + VertexShaderManager::TranslateView(-debugSpeed, 0.0f); + break; + case 'R': + VertexShaderManager::ResetView(); + break; + } + break; + + case WM_MOUSEMOVE: + if (mouseLookEnabled) { + POINT point; + GetCursorPos(&point); + VertexShaderManager::RotateView((point.x - lastMouse[0]) / 200.0f, (point.y - lastMouse[1]) / 200.0f); + lastMouse[0] = point.x; + lastMouse[1] = point.y; + } + break; + + case WM_RBUTTONDOWN: + POINT point; + GetCursorPos(&point); + lastMouse[0] = point.x; + lastMouse[1] = point.y; + mouseLookEnabled= true; + break; + case WM_RBUTTONUP: + mouseLookEnabled = false; + break; + } +} + LRESULT CALLBACK WndProc( HWND hWnd, UINT iMsg, WPARAM wParam, LPARAM lParam ) { HDC hdc; @@ -298,6 +358,10 @@ LRESULT CALLBACK WndProc( HWND hWnd, UINT iMsg, WPARAM wParam, LPARAM lParam ) break; } + if (g_Config.bFreeLook) { + FreeLookInput( iMsg, wParam ); + } + return DefWindowProc(hWnd, iMsg, wParam, lParam); } diff --git a/Source/Plugins/Plugin_VideoOGL/Src/VertexManager.cpp b/Source/Plugins/Plugin_VideoOGL/Src/VertexManager.cpp index d313d70f8e..a5c920c64a 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/VertexManager.cpp +++ b/Source/Plugins/Plugin_VideoOGL/Src/VertexManager.cpp @@ -278,7 +278,7 @@ void Flush() Renderer::SetRenderMode(Renderer::RM_Normal); // set global constants - VertexShaderManager::SetConstants(g_Config.bProjectionHax1, g_Config.bSMGhack); + VertexShaderManager::SetConstants(g_Config.bProjectionHax1, g_Config.bSMGhack, g_Config.bFreeLook); PixelShaderManager::SetConstants(); // finally bind