Merge branch 'master' into wii-usb
This commit is contained in:
commit
13bd235c11
|
@ -35,3 +35,4 @@ Source/Core/Common/Src/scmrev.h
|
|||
*.ipch
|
||||
.sconsign.dblite
|
||||
Externals/scons-local/*
|
||||
*~
|
||||
|
|
|
@ -86,7 +86,7 @@ endif()
|
|||
|
||||
# version number
|
||||
set(DOLPHIN_VERSION_MAJOR "3")
|
||||
set(DOLPHIN_VERSION_MINOR "0")
|
||||
set(DOLPHIN_VERSION_MINOR "5")
|
||||
if(DOLPHIN_IS_STABLE)
|
||||
set(DOLPHIN_VERSION_PATCH "0")
|
||||
else()
|
||||
|
@ -178,6 +178,10 @@ if(APPLE)
|
|||
# page on x86_64 is 4GB in size.
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-pagezero_size,0x1000")
|
||||
|
||||
if(NOT DISABLE_WX)
|
||||
add_definitions(-DUSE_WX -DHAVE_WX)
|
||||
set(USE_WX TRUE)
|
||||
endif()
|
||||
find_library(APPKIT_LIBRARY AppKit)
|
||||
find_library(APPSERV_LIBRARY ApplicationServices)
|
||||
find_library(ATB_LIBRARY AudioToolbox)
|
||||
|
@ -218,6 +222,15 @@ if(FASTLOG)
|
|||
add_definitions(-DDEBUGFAST)
|
||||
endif()
|
||||
|
||||
# For now GLES and EGL are tied to each other.
|
||||
# Enabling GLES also disables the OpenGL plugin.
|
||||
option(USE_GLES "Enables GLES, disables OGL" OFF)
|
||||
if(USE_GLES)
|
||||
message("GLES rendering enabled")
|
||||
add_definitions(-DUSE_GLES)
|
||||
add_definitions(-DUSE_EGL)
|
||||
set(USE_EGL True)
|
||||
endif()
|
||||
add_definitions(-D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE)
|
||||
|
||||
########################################
|
||||
|
@ -591,7 +604,6 @@ file(WRITE ${PROJECT_BINARY_DIR}/Source/Core/Common/Src/scmrev.h
|
|||
)
|
||||
include_directories("${PROJECT_BINARY_DIR}/Source/Core/Common/Src")
|
||||
|
||||
|
||||
########################################
|
||||
# Optional Targets
|
||||
# TODO: Add DSPSpy and TestSuite.
|
||||
|
@ -627,19 +639,20 @@ set(CPACK_PACKAGE_VENDOR "Dolphin Team")
|
|||
set(CPACK_PACKAGE_VERSION_MAJOR ${DOLPHIN_VERSION_MAJOR})
|
||||
set(CPACK_PACKAGE_VERSION_MINOR ${DOLPHIN_VERSION_MINOR})
|
||||
set(CPACK_PACKAGE_VERSION_PATCH ${DOLPHIN_VERSION_PATCH})
|
||||
set(CPACK_PACKAGE_DESCRIPTION_FILE ${PROJECT_SOURCE_DIR}/Data/cpack_package_description.txt)
|
||||
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "A Gamecube, Wii and Triforce emulator")
|
||||
|
||||
# TODO: CPACK_PACKAGE_DESCRIPTION_FILE
|
||||
# TODO: CPACK_PACKAGE_DESCRIPTION_SUMMARY
|
||||
set(CPACK_RPM_PACKAGE_GROUP System/Emulators/Other)
|
||||
set(CPACK_RPM_PACKAGE_LICENSE GPL-2.0)
|
||||
# TODO: CPACK_RESOURCE_FILE_README
|
||||
# TODO: CPACK_RESOURCE_FILE_WELCOME
|
||||
# TODO: CPACK_PACKAGE_EXECUTABLES
|
||||
# TODO: CPACK_PACKAGE_ICON
|
||||
# TODO: CPACK_NSIS_*
|
||||
# TODO: Use CPack components for DSPSpy, etc => cpack_add_component
|
||||
|
||||
set(CPACK_SET_DESTDIR ON)
|
||||
set(CPACK_SOURCE_GENERATOR "TGZ;TBZ2;ZIP")
|
||||
set(CPACK_SOURCE_IGNORE_FILES "\\\\.#;/#;.*~;\\\\.swp;/\\\\.svn")
|
||||
set(CPACK_SOURCE_IGNORE_FILES "\\\\.#;/#;.*~;\\\\.swp;/\\\\.git")
|
||||
list(APPEND CPACK_SOURCE_IGNORE_FILES "${CMAKE_BINARY_DIR}")
|
||||
|
||||
# CPack must be included after the CPACK_* variables are set in order for those
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Dolphin is a Gamecube, Wii and Triforce (the arcade machine based on the Gamecube) emulator which supports many extra features and abilities not present on the original consoles. Gamecube and Wii compatibility is good - one can expect "mainstream" titles to run; lesser known titles can be hit or miss. Triforce compatibility is currently limited to a couple of games - others require more of the Triforce-specific peripheral devices to be emulated.
|
1439
Languages/po/ar.po
1439
Languages/po/ar.po
File diff suppressed because it is too large
Load Diff
1449
Languages/po/ca.po
1449
Languages/po/ca.po
File diff suppressed because it is too large
Load Diff
1609
Languages/po/cs.po
1609
Languages/po/cs.po
File diff suppressed because it is too large
Load Diff
1417
Languages/po/de.po
1417
Languages/po/de.po
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
2284
Languages/po/el.po
2284
Languages/po/el.po
File diff suppressed because it is too large
Load Diff
1367
Languages/po/en.po
1367
Languages/po/en.po
File diff suppressed because it is too large
Load Diff
1482
Languages/po/es.po
1482
Languages/po/es.po
File diff suppressed because it is too large
Load Diff
3417
Languages/po/fa.po
3417
Languages/po/fa.po
File diff suppressed because it is too large
Load Diff
1460
Languages/po/fr.po
1460
Languages/po/fr.po
File diff suppressed because it is too large
Load Diff
1367
Languages/po/he.po
1367
Languages/po/he.po
File diff suppressed because it is too large
Load Diff
1451
Languages/po/hu.po
1451
Languages/po/hu.po
File diff suppressed because it is too large
Load Diff
1418
Languages/po/it.po
1418
Languages/po/it.po
File diff suppressed because it is too large
Load Diff
1651
Languages/po/ja.po
1651
Languages/po/ja.po
File diff suppressed because it is too large
Load Diff
1585
Languages/po/ko.po
1585
Languages/po/ko.po
File diff suppressed because it is too large
Load Diff
1444
Languages/po/nb.po
1444
Languages/po/nb.po
File diff suppressed because it is too large
Load Diff
1434
Languages/po/nl.po
1434
Languages/po/nl.po
File diff suppressed because it is too large
Load Diff
1506
Languages/po/pl.po
1506
Languages/po/pl.po
File diff suppressed because it is too large
Load Diff
1450
Languages/po/pt.po
1450
Languages/po/pt.po
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
1413
Languages/po/ru.po
1413
Languages/po/ru.po
File diff suppressed because it is too large
Load Diff
1392
Languages/po/sr.po
1392
Languages/po/sr.po
File diff suppressed because it is too large
Load Diff
1447
Languages/po/tr.po
1447
Languages/po/tr.po
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
21
Readme.txt
21
Readme.txt
|
@ -14,13 +14,14 @@ Team members: http://code.google.com/p/dolphin-emu/people/
|
|||
|
||||
Please read the FAQ before use:
|
||||
|
||||
http://code.google.com/p/dolphin-emu/wiki/Facts_And_Questions
|
||||
http://dolphin-emu.org/docs/faq/
|
||||
|
||||
System Requirements:
|
||||
* OS: Microsoft Windows (XP/Vista or higher) or Linux or Apple Mac OS X.
|
||||
* OS: Microsoft Windows (XP/Vista or higher) or Linux or Apple Mac OS X (10.6 or higher).
|
||||
Windows XP x64 is NOT supported.
|
||||
* Processor: Fast CPU with SSE2 supported (recommended at least 2Ghz).
|
||||
Dual Core for speed boost.
|
||||
* Graphics: Any graphics card that supports Direct3D 9 or OpenGL 2.1.
|
||||
* Graphics: Any reasonably modern graphics card (Direct3D9/OpenGL 2.1, shader model 3.0).
|
||||
|
||||
[Command line usage]
|
||||
Usage: Dolphin [-h] [-d] [-l] [-e <str>] [-b] [-V <str>] [-A <str>]
|
||||
|
@ -30,20 +31,22 @@ Usage: Dolphin [-h] [-d] [-l] [-e <str>] [-b] [-V <str>] [-A <str>]
|
|||
-e, --exec=<str> Loads the specified file (DOL,ELF,WAD,GCM,ISO)
|
||||
-b, --batch Exit Dolphin with emulator
|
||||
-V, --video_backend=<str> Specify a video plugin
|
||||
-A, --audio_emulation=<str> Low level (LLE) or high level (HLE) audio
|
||||
-A, --audio_emulation=<str> Low level (LLE) or high level (HLE) audio
|
||||
|
||||
[Libraries]
|
||||
Cg: Cg Shading API (http://developer.nvidia.com/object/cg_toolkit.html)
|
||||
*.pdb = Program Debug Database (use these symbols with a program debugger)
|
||||
|
||||
[DSP Plugins]
|
||||
Plugin_DSP_HLE: High Level DSP Emulation
|
||||
Plugin_DSP_LLE: Low Level DSP Emulation
|
||||
[DSP Emulator Engines]
|
||||
HLE: High Level DSP Emulation
|
||||
LLE: Low Level DSP Emulation (requires DSP dumps)
|
||||
Recompiler is faster than interpreter but may be buggy.
|
||||
|
||||
[Video Backends]
|
||||
Direct3D9: Render with Direct3D 9
|
||||
Direct3D11: Render with Direct3D 11
|
||||
OpenGL: Render with OpenGL + Cg Shader Language
|
||||
Software Renderer: Render using the CPU only (for devs only)
|
||||
|
||||
[Sys Files]
|
||||
totaldb.dsy: Database of symbols (for devs only)
|
||||
|
@ -54,9 +57,9 @@ setting-usa/jpn/usa.txt: config files for Wii
|
|||
Cache: used to cache the ISO list
|
||||
Config: emulator configuration files
|
||||
Dump: anything dumped from dolphin will go here
|
||||
GC: Gamecube memory cards
|
||||
GameConfig: holds the INI game config files
|
||||
Load: high resolution textures
|
||||
GC: Gamecube memory cards
|
||||
Load: custom textures
|
||||
Logs: logs go here
|
||||
Maps: symbol tables go here (dev only)
|
||||
OpenCL: OpenCL code
|
||||
|
|
|
@ -158,7 +158,7 @@ public:
|
|||
case MODE_READ: x = (wchar_t*)*ptr; break;
|
||||
case MODE_WRITE: memcpy(*ptr, x.c_str(), stringLen); break;
|
||||
case MODE_MEASURE: break;
|
||||
case MODE_VERIFY: _dbg_assert_msg_(COMMON, x == (wchar_t*)*ptr, "Savestate verification failure: \"%s\" != \"%s\" (at %p).\n", x.c_str(), (wchar_t*)*ptr, ptr); break;
|
||||
case MODE_VERIFY: _dbg_assert_msg_(COMMON, x == (wchar_t*)*ptr, "Savestate verification failure: \"%ls\" != \"%ls\" (at %p).\n", x.c_str(), (wchar_t*)*ptr, ptr); break;
|
||||
}
|
||||
(*ptr) += stringLen;
|
||||
}
|
||||
|
|
|
@ -60,11 +60,6 @@ private:
|
|||
#undef STACKALIGN
|
||||
#define STACKALIGN __attribute__((__force_align_arg_pointer__))
|
||||
#endif
|
||||
// We use wxWidgets on OS X only if it is version 2.9+ with Cocoa support.
|
||||
#ifdef __WXOSX_COCOA__
|
||||
#define HAVE_WX 1
|
||||
#define USE_WX 1 // Use wxGLCanvas
|
||||
#endif
|
||||
|
||||
#elif defined _WIN32
|
||||
|
||||
|
|
|
@ -649,8 +649,7 @@ std::string &GetUserPath(const unsigned int DirIDX, const std::string &newPath)
|
|||
if (paths[D_USER_IDX].empty())
|
||||
{
|
||||
#ifdef _WIN32
|
||||
// TODO: use GetExeDirectory() here instead of ROOT_DIR so that if the cwd is changed we still have the correct paths?
|
||||
paths[D_USER_IDX] = ROOT_DIR DIR_SEP USERDATA_DIR DIR_SEP;
|
||||
paths[D_USER_IDX] = GetExeDirectory() + DIR_SEP USERDATA_DIR DIR_SEP;
|
||||
#else
|
||||
if (File::Exists(ROOT_DIR DIR_SEP USERDATA_DIR))
|
||||
paths[D_USER_IDX] = ROOT_DIR DIR_SEP USERDATA_DIR DIR_SEP;
|
||||
|
|
|
@ -117,6 +117,8 @@ struct Rectangle
|
|||
Rectangle(T theLeft, T theTop, T theRight, T theBottom)
|
||||
: left(theLeft), top(theTop), right(theRight), bottom(theBottom)
|
||||
{ }
|
||||
|
||||
bool operator==(const Rectangle& r) { return left==r.left && top==r.top && right==r.right && bottom==r.bottom; }
|
||||
|
||||
T GetWidth() const { return abs(right - left); }
|
||||
T GetHeight() const { return abs(bottom - top); }
|
||||
|
|
|
@ -22,7 +22,9 @@
|
|||
#include "../../../Plugins/Plugin_VideoDX9/Src/VideoBackend.h"
|
||||
#include "../../../Plugins/Plugin_VideoDX11/Src/VideoBackend.h"
|
||||
#endif
|
||||
#ifndef USE_GLES
|
||||
#include "../../../Plugins/Plugin_VideoOGL/Src/VideoBackend.h"
|
||||
#endif
|
||||
#include "../../../Plugins/Plugin_VideoSoftware/Src/VideoBackend.h"
|
||||
|
||||
std::vector<VideoBackend*> g_available_video_backends;
|
||||
|
@ -52,7 +54,9 @@ void VideoBackend::PopulateList()
|
|||
if (IsGteVista())
|
||||
g_available_video_backends.push_back(new DX11::VideoBackend);
|
||||
#endif
|
||||
#ifndef USE_GLES
|
||||
g_available_video_backends.push_back(new OGL::VideoBackend);
|
||||
#endif
|
||||
g_available_video_backends.push_back(new SW::VideoSoftware);
|
||||
|
||||
g_video_backend = g_available_video_backends.front();
|
||||
|
|
|
@ -137,6 +137,8 @@ public:
|
|||
|
||||
// the implementation needs not do synchronization logic, because calls to it are surrounded by PauseAndLock now
|
||||
virtual void DoState(PointerWrap &p) = 0;
|
||||
|
||||
virtual void CheckInvalidState() = 0;
|
||||
};
|
||||
|
||||
extern std::vector<VideoBackend*> g_available_video_backends;
|
||||
|
@ -176,9 +178,15 @@ class VideoBackendHardware : public VideoBackend
|
|||
|
||||
void PauseAndLock(bool doLock, bool unpauseOnUnlock=true);
|
||||
void DoState(PointerWrap &p);
|
||||
|
||||
bool m_invalid;
|
||||
|
||||
public:
|
||||
void CheckInvalidState();
|
||||
|
||||
protected:
|
||||
void InitializeShared();
|
||||
void InvalidState();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -70,7 +70,8 @@ set(SRCS Src/ActionReplay.cpp
|
|||
Src/HW/CPU.cpp
|
||||
Src/HW/DSP.cpp
|
||||
Src/HW/DSPHLE/UCodes/UCode_AX.cpp
|
||||
Src/HW/DSPHLE/UCodes/UCode_AXWii.cpp
|
||||
Src/HW/DSPHLE/UCodes/UCode_AXWii.cpp
|
||||
Src/HW/DSPHLE/UCodes/UCode_NewAXWii.cpp
|
||||
Src/HW/DSPHLE/UCodes/UCode_CARD.cpp
|
||||
Src/HW/DSPHLE/UCodes/UCode_InitAudioSystem.cpp
|
||||
Src/HW/DSPHLE/UCodes/UCode_ROM.cpp
|
||||
|
@ -192,7 +193,11 @@ set(SRCS Src/ActionReplay.cpp
|
|||
Src/PowerPC/JitCommon/JitCache.cpp
|
||||
Src/PowerPC/JitCommon/Jit_Util.cpp)
|
||||
|
||||
set(LIBS bdisasm inputcommon videoogl videosoftware sfml-network)
|
||||
set(LIBS bdisasm inputcommon videosoftware sfml-network)
|
||||
|
||||
if(NOT USE_GLES)
|
||||
set(LIBS ${LIBS} videoogl)
|
||||
endif()
|
||||
|
||||
|
||||
if(LIBUSB_FOUND)
|
||||
|
|
|
@ -261,6 +261,7 @@
|
|||
<ClCompile Include="Src\HW\DSPHLE\UCodes\UCodes.cpp" />
|
||||
<ClCompile Include="Src\HW\DSPHLE\UCodes\UCode_AX.cpp" />
|
||||
<ClCompile Include="Src\HW\DSPHLE\UCodes\UCode_AXWii.cpp" />
|
||||
<ClCompile Include="Src\HW\DSPHLE\UCodes\UCode_NewAXWii.cpp" />
|
||||
<ClCompile Include="Src\HW\DSPHLE\UCodes\UCode_CARD.cpp" />
|
||||
<ClCompile Include="Src\HW\DSPHLE\UCodes\UCode_GBA.cpp" />
|
||||
<ClCompile Include="Src\HW\DSPHLE\UCodes\UCode_InitAudioSystem.cpp" />
|
||||
|
@ -463,9 +464,11 @@
|
|||
<ClInclude Include="Src\HW\DSPHLE\MailHandler.h" />
|
||||
<ClInclude Include="Src\HW\DSPHLE\UCodes\UCodes.h" />
|
||||
<ClInclude Include="Src\HW\DSPHLE\UCodes\UCode_AX.h" />
|
||||
<ClInclude Include="Src\HW\DSPHLE\UCodes\UCode_AXStructs.h" />
|
||||
<ClInclude Include="Src\HW\DSPHLE\UCodes\UCode_AX_Structs.h" />
|
||||
<ClInclude Include="Src\HW\DSPHLE\UCodes\UCode_AXWii.h" />
|
||||
<ClInclude Include="Src\HW\DSPHLE\UCodes\UCode_AX_ADPCM.h" />
|
||||
<ClInclude Include="Src\HW\DSPHLE\UCodes\UCode_AXWii_Structs.h" />
|
||||
<ClInclude Include="Src\HW\DSPHLE\UCodes\UCode_AXWii_Voice.h" />
|
||||
<ClInclude Include="Src\HW\DSPHLE\UCodes\UCode_NewAXWii.h" />
|
||||
<ClInclude Include="Src\HW\DSPHLE\UCodes\UCode_AX_Voice.h" />
|
||||
<ClInclude Include="Src\HW\DSPHLE\UCodes\UCode_CARD.h" />
|
||||
<ClInclude Include="Src\HW\DSPHLE\UCodes\UCode_GBA.h" />
|
||||
|
@ -597,4 +600,4 @@
|
|||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
|
|
|
@ -197,6 +197,9 @@
|
|||
<ClCompile Include="Src\HW\DSPHLE\UCodes\UCode_AXWii.cpp">
|
||||
<Filter>HW %28Flipper/Hollywood%29\DSP Interface + HLE\HLE\uCodes</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Src\HW\DSPHLE\UCodes\UCode_NewAXWii.cpp">
|
||||
<Filter>HW %28Flipper/Hollywood%29\DSP Interface + HLE\HLE\uCodes</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Src\HW\DSPHLE\UCodes\UCode_CARD.cpp">
|
||||
<Filter>HW %28Flipper/Hollywood%29\DSP Interface + HLE\HLE\uCodes</Filter>
|
||||
</ClCompile>
|
||||
|
@ -730,18 +733,24 @@
|
|||
<ClInclude Include="Src\HW\DSPHLE\UCodes\UCode_AX.h">
|
||||
<Filter>HW %28Flipper/Hollywood%29\DSP Interface + HLE\HLE\uCodes</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Src\HW\DSPHLE\UCodes\UCode_AX_ADPCM.h">
|
||||
<Filter>HW %28Flipper/Hollywood%29\DSP Interface + HLE\HLE\uCodes</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Src\HW\DSPHLE\UCodes\UCode_AX_Voice.h">
|
||||
<Filter>HW %28Flipper/Hollywood%29\DSP Interface + HLE\HLE\uCodes</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Src\HW\DSPHLE\UCodes\UCode_AXStructs.h">
|
||||
<ClInclude Include="Src\HW\DSPHLE\UCodes\UCode_AX_Structs.h">
|
||||
<Filter>HW %28Flipper/Hollywood%29\DSP Interface + HLE\HLE\uCodes</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Src\HW\DSPHLE\UCodes\UCode_AXWii.h">
|
||||
<Filter>HW %28Flipper/Hollywood%29\DSP Interface + HLE\HLE\uCodes</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Src\HW\DSPHLE\UCodes\UCode_AXWii_Structs.h">
|
||||
<Filter>HW %28Flipper/Hollywood%29\DSP Interface + HLE\HLE\uCodes</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Src\HW\DSPHLE\UCodes\UCode_AXWii_Voice.h">
|
||||
<Filter>HW %28Flipper/Hollywood%29\DSP Interface + HLE\HLE\uCodes</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Src\HW\DSPHLE\UCodes\UCode_NewAXWii.h">
|
||||
<Filter>HW %28Flipper/Hollywood%29\DSP Interface + HLE\HLE\uCodes</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Src\HW\DSPHLE\UCodes\UCode_CARD.h">
|
||||
<Filter>HW %28Flipper/Hollywood%29\DSP Interface + HLE\HLE\uCodes</Filter>
|
||||
</ClInclude>
|
||||
|
@ -1183,4 +1192,4 @@
|
|||
<UniqueIdentifier>{321a9af5-9b3d-4620-888c-fe9d02e9559e}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -12,52 +12,162 @@
|
|||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// Official Git repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#ifndef _UCODE_AX
|
||||
#define _UCODE_AX
|
||||
// High-level emulation for the AX Gamecube UCode.
|
||||
//
|
||||
// TODO:
|
||||
// * Depop support
|
||||
// * ITD support
|
||||
// * Polyphase sample interpolation support (not very useful)
|
||||
// * Dolby Pro 2 mixing with recent AX versions
|
||||
|
||||
#include <iostream>
|
||||
#include "UCode_AXStructs.h"
|
||||
#ifndef _UCODE_AX_H
|
||||
#define _UCODE_AX_H
|
||||
|
||||
enum
|
||||
#include "UCodes.h"
|
||||
#include "UCode_AX_Structs.h"
|
||||
|
||||
// We can't directly use the mixer_control field from the PB because it does
|
||||
// not mean the same in all AX versions. The AX UCode converts the
|
||||
// mixer_control value to an AXMixControl bitfield.
|
||||
enum AXMixControl
|
||||
{
|
||||
NUMBER_OF_PBS = 128
|
||||
MIX_L = 0x000001,
|
||||
MIX_L_RAMP = 0x000002,
|
||||
MIX_R = 0x000004,
|
||||
MIX_R_RAMP = 0x000008,
|
||||
MIX_S = 0x000010,
|
||||
MIX_S_RAMP = 0x000020,
|
||||
|
||||
MIX_AUXA_L = 0x000040,
|
||||
MIX_AUXA_L_RAMP = 0x000080,
|
||||
MIX_AUXA_R = 0x000100,
|
||||
MIX_AUXA_R_RAMP = 0x000200,
|
||||
MIX_AUXA_S = 0x000400,
|
||||
MIX_AUXA_S_RAMP = 0x000800,
|
||||
|
||||
MIX_AUXB_L = 0x001000,
|
||||
MIX_AUXB_L_RAMP = 0x002000,
|
||||
MIX_AUXB_R = 0x004000,
|
||||
MIX_AUXB_R_RAMP = 0x008000,
|
||||
MIX_AUXB_S = 0x010000,
|
||||
MIX_AUXB_S_RAMP = 0x020000,
|
||||
|
||||
MIX_AUXC_L = 0x040000,
|
||||
MIX_AUXC_L_RAMP = 0x080000,
|
||||
MIX_AUXC_R = 0x100000,
|
||||
MIX_AUXC_R_RAMP = 0x200000,
|
||||
MIX_AUXC_S = 0x400000,
|
||||
MIX_AUXC_S_RAMP = 0x800000
|
||||
};
|
||||
|
||||
class CUCode_AX : public IUCode
|
||||
class CUCode_AX : public IUCode
|
||||
{
|
||||
public:
|
||||
CUCode_AX(DSPHLE *dsp_hle, u32 _CRC);
|
||||
CUCode_AX(DSPHLE* dsp_hle, u32 crc);
|
||||
virtual ~CUCode_AX();
|
||||
|
||||
void HandleMail(u32 _uMail);
|
||||
void MixAdd(short* _pBuffer, int _iSize);
|
||||
void Update(int cycles);
|
||||
void DoState(PointerWrap &p);
|
||||
virtual void HandleMail(u32 mail);
|
||||
virtual void MixAdd(short* out_buffer, int nsamples);
|
||||
virtual void Update(int cycles);
|
||||
virtual void DoState(PointerWrap& p);
|
||||
|
||||
// PBs
|
||||
u8 numPBaddr;
|
||||
u32 PBaddr[8]; //2 needed for MP2
|
||||
u32 m_addressPBs;
|
||||
// Needed because StdThread.h std::thread implem does not support member
|
||||
// pointers.
|
||||
static void SpawnAXThread(CUCode_AX* self);
|
||||
|
||||
private:
|
||||
enum
|
||||
protected:
|
||||
enum MailType
|
||||
{
|
||||
MAIL_AX_ALIST = 0xBABE0000,
|
||||
AXLIST_STUDIOADDR = 0x0000,
|
||||
AXLIST_PBADDR = 0x0002,
|
||||
AXLIST_SBUFFER = 0x0007,
|
||||
AXLIST_COMPRESSORTABLE = 0x000A,
|
||||
AXLIST_END = 0x000F
|
||||
MAIL_RESUME = 0xCDD10000,
|
||||
MAIL_NEW_UCODE = 0xCDD10001,
|
||||
MAIL_RESET = 0xCDD10002,
|
||||
MAIL_CONTINUE = 0xCDD10003,
|
||||
|
||||
// CPU sends 0xBABE0000 | cmdlist_size to the DSP
|
||||
MAIL_CMDLIST = 0xBABE0000,
|
||||
MAIL_CMDLIST_MASK = 0xFFFF0000
|
||||
};
|
||||
|
||||
int *templbuffer;
|
||||
int *temprbuffer;
|
||||
// 32 * 5 because 32 samples per millisecond, for max 5 milliseconds.
|
||||
int m_samples_left[32 * 5];
|
||||
int m_samples_right[32 * 5];
|
||||
int m_samples_surround[32 * 5];
|
||||
int m_samples_auxA_left[32 * 5];
|
||||
int m_samples_auxA_right[32 * 5];
|
||||
int m_samples_auxA_surround[32 * 5];
|
||||
int m_samples_auxB_left[32 * 5];
|
||||
int m_samples_auxB_right[32 * 5];
|
||||
int m_samples_auxB_surround[32 * 5];
|
||||
|
||||
// ax task message handler
|
||||
bool AXTask(u32& _uMail);
|
||||
// Volatile because it's set by HandleMail and accessed in
|
||||
// HandleCommandList, which are running in two different threads.
|
||||
volatile u16 m_cmdlist[512];
|
||||
volatile u32 m_cmdlist_size;
|
||||
|
||||
std::thread m_axthread;
|
||||
|
||||
// Sync objects
|
||||
std::mutex m_processing;
|
||||
std::condition_variable m_cmdlist_cv;
|
||||
std::mutex m_cmdlist_mutex;
|
||||
|
||||
// Copy a command list from memory to our temp buffer
|
||||
void CopyCmdList(u32 addr, u16 size);
|
||||
|
||||
// Convert a mixer_control bitfield to our internal representation for that
|
||||
// value. Required because that bitfield has a different meaning in some
|
||||
// versions of AX.
|
||||
AXMixControl ConvertMixerControl(u32 mixer_control);
|
||||
|
||||
// Send a notification to the AX thread to tell him a new cmdlist addr is
|
||||
// available for processing.
|
||||
void NotifyAXThread();
|
||||
|
||||
void AXThread();
|
||||
|
||||
virtual void HandleCommandList();
|
||||
|
||||
void SetupProcessing(u32 init_addr);
|
||||
void DownloadAndMixWithVolume(u32 addr, u16 vol_main, u16 vol_auxa, u16 vol_auxb);
|
||||
void ProcessPBList(u32 pb_addr);
|
||||
void MixAUXSamples(int aux_id, u32 write_addr, u32 read_addr);
|
||||
void UploadLRS(u32 dst_addr);
|
||||
void SetMainLR(u32 src_addr);
|
||||
void OutputSamples(u32 out_addr, u32 surround_addr);
|
||||
void MixAUXBLR(u32 ul_addr, u32 dl_addr);
|
||||
void SendAUXAndMix(u32 main_auxa_up, u32 auxb_s_up, u32 main_l_dl,
|
||||
u32 main_r_dl, u32 auxb_l_dl, u32 auxb_r_dl);
|
||||
|
||||
// Handle save states for main AX.
|
||||
void DoAXState(PointerWrap& p);
|
||||
|
||||
private:
|
||||
enum CmdType
|
||||
{
|
||||
CMD_SETUP = 0x00,
|
||||
CMD_DL_AND_VOL_MIX = 0x01,
|
||||
CMD_PB_ADDR = 0x02,
|
||||
CMD_PROCESS = 0x03,
|
||||
CMD_MIX_AUXA = 0x04,
|
||||
CMD_MIX_AUXB = 0x05,
|
||||
CMD_UPLOAD_LRS = 0x06,
|
||||
CMD_SET_LR = 0x07,
|
||||
CMD_UNK_08 = 0x08,
|
||||
CMD_MIX_AUXB_NOWRITE = 0x09,
|
||||
CMD_COMPRESSOR_TABLE_ADDR = 0x0A,
|
||||
CMD_UNK_0B = 0x0B,
|
||||
CMD_UNK_0C = 0x0C,
|
||||
CMD_MORE = 0x0D,
|
||||
CMD_OUTPUT = 0x0E,
|
||||
CMD_END = 0x0F,
|
||||
CMD_MIX_AUXB_LR = 0x10,
|
||||
CMD_UNK_11 = 0x11,
|
||||
CMD_UNK_12 = 0x12,
|
||||
CMD_SEND_AUX_AND_MIX = 0x13,
|
||||
};
|
||||
};
|
||||
|
||||
#endif // _UCODE_AX
|
||||
#endif // !_UCODE_AX_H
|
||||
|
|
|
@ -21,10 +21,10 @@
|
|||
#include "Mixer.h"
|
||||
|
||||
#include "UCodes.h"
|
||||
#include "UCode_AXStructs.h"
|
||||
#include "UCode_AXWii_Structs.h"
|
||||
#include "UCode_AX.h" // for some functions in CUCode_AX
|
||||
#include "UCode_AXWii.h"
|
||||
#include "UCode_AX_Voice.h"
|
||||
#include "UCode_AXWii_Voice.h"
|
||||
|
||||
|
||||
CUCode_AXWii::CUCode_AXWii(DSPHLE *dsp_hle, u32 l_CRC)
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
#ifndef _UCODE_AXWII
|
||||
#define _UCODE_AXWII
|
||||
|
||||
#include "UCode_AXStructs.h"
|
||||
#include "UCode_AXWii_Structs.h"
|
||||
|
||||
#define NUMBER_OF_PBS 128
|
||||
|
||||
|
|
|
@ -0,0 +1,271 @@
|
|||
// Copyright (C) 2003 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#ifndef _UCODE_AXWII_VOICE_H
|
||||
#define _UCODE_AXWII_VOICE_H
|
||||
|
||||
#include "UCodes.h"
|
||||
#include "UCode_AXWii_ADPCM.h"
|
||||
#include "UCode_AX.h"
|
||||
#include "Mixer.h"
|
||||
#include "../../AudioInterface.h"
|
||||
|
||||
// MRAM -> ARAM for GC
|
||||
inline bool ReadPB(u32 addr, AXPB &PB)
|
||||
{
|
||||
const u16* PB_in_mram = (const u16*)Memory::GetPointer(addr);
|
||||
if (PB_in_mram == NULL)
|
||||
return false;
|
||||
u16* PB_in_aram = (u16*)&PB;
|
||||
|
||||
for (size_t p = 0; p < (sizeof(AXPB) >> 1); p++)
|
||||
{
|
||||
PB_in_aram[p] = Common::swap16(PB_in_mram[p]);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// MRAM -> ARAM for Wii
|
||||
inline bool ReadPB(u32 addr, AXPBWii &PB)
|
||||
{
|
||||
const u16* PB_in_mram = (const u16*)Memory::GetPointer(addr);
|
||||
if (PB_in_mram == NULL)
|
||||
return false;
|
||||
u16* PB_in_aram = (u16*)&PB;
|
||||
|
||||
// preswap the mixer_control
|
||||
PB.mixer_control = ((u32)PB_in_mram[7] << 16) | ((u32)PB_in_mram[6] >> 16);
|
||||
|
||||
for (size_t p = 0; p < (sizeof(AXPBWii) >> 1); p++)
|
||||
{
|
||||
PB_in_aram[p] = Common::swap16(PB_in_mram[p]);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ARAM -> MRAM for GC
|
||||
inline bool WritePB(u32 addr, AXPB &PB)
|
||||
{
|
||||
const u16* PB_in_aram = (const u16*)&PB;
|
||||
u16* PB_in_mram = (u16*)Memory::GetPointer(addr);
|
||||
if (PB_in_mram == NULL)
|
||||
return false;
|
||||
|
||||
for (size_t p = 0; p < (sizeof(AXPB) >> 1); p++)
|
||||
{
|
||||
PB_in_mram[p] = Common::swap16(PB_in_aram[p]);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ARAM -> MRAM for Wii
|
||||
inline bool WritePB(u32 addr, AXPBWii &PB)
|
||||
{
|
||||
const u16* PB_in_aram = (const u16*)&PB;
|
||||
u16* PB_in_mram = (u16*)Memory::GetPointer(addr);
|
||||
if (PB_in_mram == NULL)
|
||||
return false;
|
||||
|
||||
// preswap the mixer_control
|
||||
*(u32*)&PB_in_mram[6] = (PB.mixer_control << 16) | (PB.mixer_control >> 16);
|
||||
|
||||
for (size_t p = 0; p < (sizeof(AXPBWii) >> 1); p++)
|
||||
{
|
||||
PB_in_mram[p] = Common::swap16(PB_in_aram[p]);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// TODO: fix handling of gc/wii PB differences
|
||||
// TODO: generally fix up the mess - looks crazy and kinda wrong
|
||||
template<class ParamBlockType>
|
||||
inline void MixAddVoice(ParamBlockType &pb,
|
||||
int *templbuffer, int *temprbuffer,
|
||||
int _iSize)
|
||||
{
|
||||
if (pb.running)
|
||||
{
|
||||
const u32 ratio = (u32)(((pb.src.ratio_hi << 16) + pb.src.ratio_lo)
|
||||
* /*ratioFactor:*/((float)AudioInterface::GetAIDSampleRate() / (float)soundStream->GetMixer()->GetSampleRate()));
|
||||
u32 sampleEnd = (pb.audio_addr.end_addr_hi << 16) | pb.audio_addr.end_addr_lo;
|
||||
u32 loopPos = (pb.audio_addr.loop_addr_hi << 16) | pb.audio_addr.loop_addr_lo;
|
||||
|
||||
u32 samplePos = (pb.audio_addr.cur_addr_hi << 16) | pb.audio_addr.cur_addr_lo;
|
||||
u32 frac = pb.src.cur_addr_frac;
|
||||
|
||||
// =======================================================================================
|
||||
// Handle No-SRC streams - No src streams have pb.src_type == 2 and have pb.src.ratio_hi = 0
|
||||
// and pb.src.ratio_lo = 0. We handle that by setting the sampling ratio integer to 1. This
|
||||
// makes samplePos update in the correct way. I'm unsure how we are actually supposed to
|
||||
// detect that this setting. Updates did not fix this automatically.
|
||||
// ---------------------------------------------------------------------------------------
|
||||
// Stream settings
|
||||
// src_type = 2 (most other games have src_type = 0)
|
||||
// Affected games:
|
||||
// Baten Kaitos - Eternal Wings (2003)
|
||||
// Baten Kaitos - Origins (2006)?
|
||||
// Soul Calibur 2: The movie music use src_type 2 but it needs no adjustment, perhaps
|
||||
// the sound format plays in to, Baten use ADPCM, SC2 use PCM16
|
||||
//if (pb.src_type == 2 && (pb.src.ratio_hi == 0 && pb.src.ratio_lo == 0))
|
||||
if (pb.running && (pb.src.ratio_hi == 0 && pb.src.ratio_lo == 0))
|
||||
{
|
||||
pb.src.ratio_hi = 1;
|
||||
}
|
||||
|
||||
// =======================================================================================
|
||||
// Games that use looping to play non-looping music streams - SSBM has info in all
|
||||
// pb.adpcm_loop_info parameters but has pb.audio_addr.looping = 0. If we treat these streams
|
||||
// like any other looping streams the music works. I'm unsure how we are actually supposed to
|
||||
// detect that these kinds of blocks should be looping. It seems like pb.mixer_control == 0 may
|
||||
// identify these types of blocks. Updates did not write any looping values.
|
||||
if (
|
||||
(pb.adpcm_loop_info.pred_scale || pb.adpcm_loop_info.yn1 || pb.adpcm_loop_info.yn2)
|
||||
&& pb.mixer_control == 0 && pb.adpcm_loop_info.pred_scale <= 0x7F
|
||||
)
|
||||
{
|
||||
pb.audio_addr.looping = 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Top Spin 3 Wii
|
||||
if (pb.audio_addr.sample_format > 25)
|
||||
pb.audio_addr.sample_format = 0;
|
||||
|
||||
// =======================================================================================
|
||||
// Walk through _iSize. _iSize = numSamples. If the game goes slow _iSize will be higher to
|
||||
// compensate for that. _iSize can be as low as 100 or as high as 2000 some cases.
|
||||
for (int s = 0; s < _iSize; s++)
|
||||
{
|
||||
int sample = 0;
|
||||
u32 oldFrac = frac;
|
||||
frac += ratio;
|
||||
u32 newSamplePos = samplePos + (frac >> 16); //whole number of frac
|
||||
|
||||
// =======================================================================================
|
||||
// Process sample format
|
||||
switch (pb.audio_addr.sample_format)
|
||||
{
|
||||
case AUDIOFORMAT_PCM8:
|
||||
pb.adpcm.yn2 = ((s8)DSP::ReadARAM(samplePos)) << 8; //current sample
|
||||
pb.adpcm.yn1 = ((s8)DSP::ReadARAM(samplePos + 1)) << 8; //next sample
|
||||
|
||||
if (pb.src_type == SRCTYPE_NEAREST)
|
||||
sample = pb.adpcm.yn2;
|
||||
else // linear interpolation
|
||||
sample = (pb.adpcm.yn1 * (u16)oldFrac + pb.adpcm.yn2 * (u16)(0xFFFF - oldFrac) + pb.adpcm.yn2) >> 16;
|
||||
|
||||
samplePos = newSamplePos;
|
||||
break;
|
||||
|
||||
case AUDIOFORMAT_PCM16:
|
||||
pb.adpcm.yn2 = (s16)(u16)((DSP::ReadARAM(samplePos * 2) << 8) | (DSP::ReadARAM((samplePos * 2 + 1)))); //current sample
|
||||
pb.adpcm.yn1 = (s16)(u16)((DSP::ReadARAM((samplePos + 1) * 2) << 8) | (DSP::ReadARAM(((samplePos + 1) * 2 + 1)))); //next sample
|
||||
|
||||
if (pb.src_type == SRCTYPE_NEAREST)
|
||||
sample = pb.adpcm.yn2;
|
||||
else // linear interpolation
|
||||
sample = (pb.adpcm.yn1 * (u16)oldFrac + pb.adpcm.yn2 * (u16)(0xFFFF - oldFrac) + pb.adpcm.yn2) >> 16;
|
||||
|
||||
samplePos = newSamplePos;
|
||||
break;
|
||||
|
||||
case AUDIOFORMAT_ADPCM:
|
||||
ADPCM_Step(pb.adpcm, samplePos, newSamplePos, frac);
|
||||
|
||||
if (pb.src_type == SRCTYPE_NEAREST)
|
||||
sample = pb.adpcm.yn2;
|
||||
else // linear interpolation
|
||||
sample = (pb.adpcm.yn1 * (u16)frac + pb.adpcm.yn2 * (u16)(0xFFFF - frac) + pb.adpcm.yn2) >> 16; //adpcm moves on frac
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
// Overall volume control. In addition to this there is also separate volume settings to
|
||||
// different channels (left, right etc).
|
||||
frac &= 0xffff;
|
||||
|
||||
int vol = pb.vol_env.cur_volume >> 9;
|
||||
sample = sample * vol >> 8;
|
||||
|
||||
if (pb.mixer_control & MIXCONTROL_RAMPING)
|
||||
{
|
||||
int x = pb.vol_env.cur_volume;
|
||||
x += pb.vol_env.cur_volume_delta; // I'm not sure about this, can anybody find a game
|
||||
// that use this? Or how does it work?
|
||||
if (x < 0)
|
||||
x = 0;
|
||||
if (x >= 0x7fff)
|
||||
x = 0x7fff;
|
||||
pb.vol_env.cur_volume = x; // maybe not per sample?? :P
|
||||
}
|
||||
|
||||
int leftmix = pb.mixer.left >> 5;
|
||||
int rightmix = pb.mixer.right >> 5;
|
||||
int left = sample * leftmix >> 8;
|
||||
int right = sample * rightmix >> 8;
|
||||
// adpcm has to walk from oldSamplePos to samplePos here
|
||||
templbuffer[s] += left;
|
||||
temprbuffer[s] += right;
|
||||
|
||||
// Control the behavior when we reach the end of the sample
|
||||
if (samplePos >= sampleEnd)
|
||||
{
|
||||
if (pb.audio_addr.looping == 1)
|
||||
{
|
||||
if ((samplePos & ~0x1f) == (sampleEnd & ~0x1f) || (pb.audio_addr.sample_format != AUDIOFORMAT_ADPCM))
|
||||
samplePos = loopPos;
|
||||
if ((!pb.is_stream) && (pb.audio_addr.sample_format == AUDIOFORMAT_ADPCM))
|
||||
{
|
||||
pb.adpcm.yn1 = pb.adpcm_loop_info.yn1;
|
||||
pb.adpcm.yn2 = pb.adpcm_loop_info.yn2;
|
||||
pb.adpcm.pred_scale = pb.adpcm_loop_info.pred_scale;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pb.running = 0;
|
||||
samplePos = loopPos;
|
||||
//samplePos = samplePos - sampleEnd + loopPos;
|
||||
memset(&pb.dpop, 0, sizeof(pb.dpop));
|
||||
memset(pb.src.last_samples, 0, 8);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} // end of the _iSize loop
|
||||
|
||||
// Update volume
|
||||
pb.mixer.left = ADPCM_Vol(pb.mixer.left, pb.mixer.left_delta);
|
||||
pb.mixer.right = ADPCM_Vol(pb.mixer.right, pb.mixer.right_delta);
|
||||
|
||||
pb.src.cur_addr_frac = (u16)frac;
|
||||
pb.audio_addr.cur_addr_hi = samplePos >> 16;
|
||||
pb.audio_addr.cur_addr_lo = (u16)samplePos;
|
||||
|
||||
} // if (pb.running)
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,392 @@
|
|||
// Copyright (C) 2003 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#ifndef _UCODE_AX_STRUCTS_H
|
||||
#define _UCODE_AX_STRUCTS_H
|
||||
|
||||
struct PBMixer
|
||||
{
|
||||
u16 left;
|
||||
u16 left_delta;
|
||||
u16 right;
|
||||
u16 right_delta;
|
||||
|
||||
u16 auxA_left;
|
||||
u16 auxA_left_delta;
|
||||
u16 auxA_right;
|
||||
u16 auxA_right_delta;
|
||||
|
||||
u16 auxB_left;
|
||||
u16 auxB_left_delta;
|
||||
u16 auxB_right;
|
||||
u16 auxB_right_delta;
|
||||
|
||||
u16 auxB_surround;
|
||||
u16 auxB_surround_delta;
|
||||
u16 surround;
|
||||
u16 surround_delta;
|
||||
u16 auxA_surround;
|
||||
u16 auxA_surround_delta;
|
||||
};
|
||||
|
||||
struct PBMixerWii
|
||||
{
|
||||
// volume mixing values in .15, 0x8000 = ca. 1.0
|
||||
u16 left;
|
||||
u16 left_delta;
|
||||
u16 right;
|
||||
u16 right_delta;
|
||||
|
||||
u16 auxA_left;
|
||||
u16 auxA_left_delta;
|
||||
u16 auxA_right;
|
||||
u16 auxA_right_delta;
|
||||
|
||||
u16 auxB_left;
|
||||
u16 auxB_left_delta;
|
||||
u16 auxB_right;
|
||||
u16 auxB_right_delta;
|
||||
|
||||
// Note: the following elements usage changes a little in DPL2 mode
|
||||
// TODO: implement and comment it in the mixer
|
||||
u16 auxC_left;
|
||||
u16 auxC_left_delta;
|
||||
u16 auxC_right;
|
||||
u16 auxC_right_delta;
|
||||
|
||||
u16 surround;
|
||||
u16 surround_delta;
|
||||
u16 auxA_surround;
|
||||
u16 auxA_surround_delta;
|
||||
u16 auxB_surround;
|
||||
u16 auxB_surround_delta;
|
||||
u16 auxC_surround;
|
||||
u16 auxC_surround_delta;
|
||||
};
|
||||
|
||||
struct PBMixerWM
|
||||
{
|
||||
u16 main0;
|
||||
u16 main0_delta;
|
||||
u16 aux0;
|
||||
u16 aux0_delta;
|
||||
|
||||
u16 main1;
|
||||
u16 main1_delta;
|
||||
u16 aux1;
|
||||
u16 aux1_delta;
|
||||
|
||||
u16 main2;
|
||||
u16 main2_delta;
|
||||
u16 aux2;
|
||||
u16 aux2_delta;
|
||||
|
||||
u16 main3;
|
||||
u16 main3_delta;
|
||||
u16 aux3;
|
||||
u16 aux3_delta;
|
||||
};
|
||||
|
||||
struct PBInitialTimeDelay
|
||||
{
|
||||
u16 on;
|
||||
u16 addrMemHigh;
|
||||
u16 addrMemLow;
|
||||
u16 offsetLeft;
|
||||
u16 offsetRight;
|
||||
u16 targetLeft;
|
||||
u16 targetRight;
|
||||
};
|
||||
|
||||
// Update data - read these each 1ms subframe and use them!
|
||||
// It seems that to provide higher time precisions for MIDI events, some games
|
||||
// use this thing to update the parameter blocks per 1ms sub-block (a block is 5ms).
|
||||
// Using this data should fix games that are missing MIDI notes.
|
||||
struct PBUpdates
|
||||
{
|
||||
u16 num_updates[5];
|
||||
u16 data_hi; // These point to main RAM. Not sure about the structure of the data.
|
||||
u16 data_lo;
|
||||
};
|
||||
|
||||
// The DSP stores the final sample values for each voice after every frame of processing.
|
||||
// The values are then accumulated for all dropped voices, added to the next frame of audio,
|
||||
// and ramped down on a per-sample basis to provide a gentle "roll off."
|
||||
struct PBDpop
|
||||
{
|
||||
s16 left;
|
||||
s16 auxA_left;
|
||||
s16 auxB_left;
|
||||
|
||||
s16 right;
|
||||
s16 auxA_right;
|
||||
s16 auxB_right;
|
||||
|
||||
s16 surround;
|
||||
s16 auxA_surround;
|
||||
s16 auxB_surround;
|
||||
};
|
||||
|
||||
struct PBDpopWii
|
||||
{
|
||||
s16 left;
|
||||
s16 auxA_left;
|
||||
s16 auxB_left;
|
||||
s16 auxC_left;
|
||||
|
||||
s16 right;
|
||||
s16 auxA_right;
|
||||
s16 auxB_right;
|
||||
s16 auxC_right;
|
||||
|
||||
s16 surround;
|
||||
s16 auxA_surround;
|
||||
s16 auxB_surround;
|
||||
s16 auxC_surround;
|
||||
};
|
||||
|
||||
struct PBDpopWM
|
||||
{
|
||||
s16 aMain0;
|
||||
s16 aMain1;
|
||||
s16 aMain2;
|
||||
s16 aMain3;
|
||||
|
||||
s16 aAux0;
|
||||
s16 aAux1;
|
||||
s16 aAux2;
|
||||
s16 aAux3;
|
||||
};
|
||||
|
||||
struct PBVolumeEnvelope
|
||||
{
|
||||
u16 cur_volume; // volume at start of frame
|
||||
s16 cur_volume_delta; // signed per sample delta (96 samples per frame)
|
||||
};
|
||||
|
||||
struct PBUnknown2
|
||||
{
|
||||
u16 unknown_reserved[3];
|
||||
};
|
||||
|
||||
struct PBAudioAddr
|
||||
{
|
||||
u16 looping;
|
||||
u16 sample_format;
|
||||
u16 loop_addr_hi; // Start of loop (this will point to a shared "zero" buffer if one-shot mode is active)
|
||||
u16 loop_addr_lo;
|
||||
u16 end_addr_hi; // End of sample (and loop), inclusive
|
||||
u16 end_addr_lo;
|
||||
u16 cur_addr_hi;
|
||||
u16 cur_addr_lo;
|
||||
};
|
||||
|
||||
struct PBADPCMInfo
|
||||
{
|
||||
s16 coefs[16];
|
||||
u16 gain;
|
||||
u16 pred_scale;
|
||||
s16 yn1;
|
||||
s16 yn2;
|
||||
};
|
||||
|
||||
struct PBSampleRateConverter
|
||||
{
|
||||
// ratio = (f32)ratio * 0x10000;
|
||||
// valid range is 1/512 to 4.0000
|
||||
u16 ratio_hi; // integer part of sampling ratio
|
||||
u16 ratio_lo; // fraction part of sampling ratio
|
||||
u16 cur_addr_frac;
|
||||
u16 last_samples[4];
|
||||
};
|
||||
|
||||
struct PBSampleRateConverterWM
|
||||
{
|
||||
u16 currentAddressFrac;
|
||||
u16 last_samples[4];
|
||||
};
|
||||
|
||||
struct PBADPCMLoopInfo
|
||||
{
|
||||
u16 pred_scale;
|
||||
u16 yn1;
|
||||
u16 yn2;
|
||||
};
|
||||
|
||||
struct PBLowPassFilter
|
||||
{
|
||||
u16 enabled;
|
||||
u16 yn1;
|
||||
u16 a0;
|
||||
u16 b0;
|
||||
};
|
||||
|
||||
struct AXPB
|
||||
{
|
||||
u16 next_pb_hi;
|
||||
u16 next_pb_lo;
|
||||
u16 this_pb_hi;
|
||||
u16 this_pb_lo;
|
||||
|
||||
u16 src_type; // Type of sample rate converter (none, ?, linear)
|
||||
u16 coef_select;
|
||||
u16 mixer_control;
|
||||
|
||||
u16 running; // 1=RUN 0=STOP
|
||||
u16 is_stream; // 1 = stream, 0 = one shot
|
||||
|
||||
PBMixer mixer;
|
||||
PBInitialTimeDelay initial_time_delay;
|
||||
PBUpdates updates;
|
||||
PBDpop dpop;
|
||||
PBVolumeEnvelope vol_env;
|
||||
PBUnknown2 unknown3;
|
||||
PBAudioAddr audio_addr;
|
||||
PBADPCMInfo adpcm;
|
||||
PBSampleRateConverter src;
|
||||
PBADPCMLoopInfo adpcm_loop_info;
|
||||
PBLowPassFilter lpf;
|
||||
|
||||
u16 padding[25];
|
||||
};
|
||||
|
||||
struct PBBiquadFilter
|
||||
{
|
||||
|
||||
u16 on; // on = 2, off = 0
|
||||
u16 xn1; // History data
|
||||
u16 xn2;
|
||||
u16 yn1;
|
||||
u16 yn2;
|
||||
u16 b0; // Filter coefficients
|
||||
u16 b1;
|
||||
u16 b2;
|
||||
u16 a1;
|
||||
u16 a2;
|
||||
|
||||
};
|
||||
|
||||
union PBInfImpulseResponseWM
|
||||
{
|
||||
PBLowPassFilter lpf;
|
||||
PBBiquadFilter biquad;
|
||||
};
|
||||
|
||||
struct AXPBWii
|
||||
{
|
||||
u16 next_pb_hi;
|
||||
u16 next_pb_lo;
|
||||
u16 this_pb_hi;
|
||||
u16 this_pb_lo;
|
||||
|
||||
u16 src_type; // Type of sample rate converter (none, 4-tap, linear)
|
||||
u16 coef_select; // coef for the 4-tap src
|
||||
u16 mixer_control_hi;
|
||||
u16 mixer_control_lo;
|
||||
|
||||
u16 running; // 1=RUN 0=STOP
|
||||
u16 is_stream; // 1 = stream, 0 = one shot
|
||||
|
||||
PBMixerWii mixer;
|
||||
PBInitialTimeDelay initial_time_delay;
|
||||
PBDpopWii dpop;
|
||||
PBVolumeEnvelope vol_env;
|
||||
PBAudioAddr audio_addr;
|
||||
PBADPCMInfo adpcm;
|
||||
PBSampleRateConverter src;
|
||||
PBADPCMLoopInfo adpcm_loop_info;
|
||||
PBLowPassFilter lpf;
|
||||
PBBiquadFilter biquad;
|
||||
|
||||
// WIIMOTE :D
|
||||
u16 remote;
|
||||
u16 remote_mixer_control;
|
||||
|
||||
PBMixerWM remote_mixer;
|
||||
PBDpopWM remote_dpop;
|
||||
PBSampleRateConverterWM remote_src;
|
||||
PBInfImpulseResponseWM remote_iir;
|
||||
|
||||
u16 pad[12]; // align us, captain! (32B)
|
||||
};
|
||||
|
||||
// Seems like nintendo used an early version of AXWii and forgot to remove the update functionality ;p
|
||||
struct PBUpdatesWiiSports
|
||||
{
|
||||
u16 num_updates[3];
|
||||
u16 data_hi;
|
||||
u16 data_lo;
|
||||
};
|
||||
|
||||
struct AXPBWiiSports
|
||||
{
|
||||
u16 next_pb_hi;
|
||||
u16 next_pb_lo;
|
||||
u16 this_pb_hi;
|
||||
u16 this_pb_lo;
|
||||
|
||||
u16 src_type; // Type of sample rate converter (none, 4-tap, linear)
|
||||
u16 coef_select; // coef for the 4-tap src
|
||||
u32 mixer_control;
|
||||
|
||||
u16 running; // 1=RUN 0=STOP
|
||||
u16 is_stream; // 1 = stream, 0 = one shot
|
||||
|
||||
PBMixerWii mixer;
|
||||
PBInitialTimeDelay initial_time_delay;
|
||||
PBUpdatesWiiSports updates;
|
||||
PBDpopWii dpop;
|
||||
PBVolumeEnvelope vol_env;
|
||||
PBAudioAddr audio_addr;
|
||||
PBADPCMInfo adpcm;
|
||||
PBSampleRateConverter src;
|
||||
PBADPCMLoopInfo adpcm_loop_info;
|
||||
PBLowPassFilter lpf;
|
||||
PBBiquadFilter biquad;
|
||||
|
||||
// WIIMOTE :D
|
||||
u16 remote;
|
||||
u16 remote_mixer_control;
|
||||
|
||||
PBMixerWM remote_mixer;
|
||||
PBDpopWM remote_dpop;
|
||||
PBSampleRateConverterWM remote_src;
|
||||
PBInfImpulseResponseWM remote_iir;
|
||||
|
||||
u16 pad[7]; // align us, captain! (32B)
|
||||
};
|
||||
|
||||
// TODO: All these enums have changed a lot for wii
|
||||
enum {
|
||||
AUDIOFORMAT_ADPCM = 0,
|
||||
AUDIOFORMAT_PCM8 = 0x19,
|
||||
AUDIOFORMAT_PCM16 = 0xA,
|
||||
};
|
||||
|
||||
enum {
|
||||
SRCTYPE_POLYPHASE = 0,
|
||||
SRCTYPE_LINEAR = 1,
|
||||
SRCTYPE_NEAREST = 2,
|
||||
};
|
||||
|
||||
// Both may be used at once
|
||||
enum {
|
||||
FILTER_LOWPASS = 1,
|
||||
FILTER_BIQUAD = 2,
|
||||
};
|
||||
|
||||
#endif // _UCODE_AX_STRUCTS_H
|
|
@ -12,260 +12,389 @@
|
|||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// Official Git repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
// This file is UGLY (full of #ifdef) so that it can be used with both GC and
|
||||
// Wii version of AX. Maybe it would be better to abstract away the parts that
|
||||
// can be made common.
|
||||
|
||||
#ifndef _UCODE_AX_VOICE_H
|
||||
#define _UCODE_AX_VOICE_H
|
||||
|
||||
#include "UCodes.h"
|
||||
#include "UCode_AX_ADPCM.h"
|
||||
#include "UCode_AX.h"
|
||||
#include "Mixer.h"
|
||||
#include "../../AudioInterface.h"
|
||||
|
||||
// MRAM -> ARAM for GC
|
||||
inline bool ReadPB(u32 addr, AXPB &PB)
|
||||
{
|
||||
const u16* PB_in_mram = (const u16*)Memory::GetPointer(addr);
|
||||
if (PB_in_mram == NULL)
|
||||
return false;
|
||||
u16* PB_in_aram = (u16*)&PB;
|
||||
|
||||
for (size_t p = 0; p < (sizeof(AXPB) >> 1); p++)
|
||||
{
|
||||
PB_in_aram[p] = Common::swap16(PB_in_mram[p]);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// MRAM -> ARAM for Wii
|
||||
inline bool ReadPB(u32 addr, AXPBWii &PB)
|
||||
{
|
||||
const u16* PB_in_mram = (const u16*)Memory::GetPointer(addr);
|
||||
if (PB_in_mram == NULL)
|
||||
return false;
|
||||
u16* PB_in_aram = (u16*)&PB;
|
||||
|
||||
// preswap the mixer_control
|
||||
PB.mixer_control = ((u32)PB_in_mram[7] << 16) | ((u32)PB_in_mram[6] >> 16);
|
||||
|
||||
for (size_t p = 0; p < (sizeof(AXPBWii) >> 1); p++)
|
||||
{
|
||||
PB_in_aram[p] = Common::swap16(PB_in_mram[p]);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ARAM -> MRAM for GC
|
||||
inline bool WritePB(u32 addr, AXPB &PB)
|
||||
{
|
||||
const u16* PB_in_aram = (const u16*)&PB;
|
||||
u16* PB_in_mram = (u16*)Memory::GetPointer(addr);
|
||||
if (PB_in_mram == NULL)
|
||||
return false;
|
||||
|
||||
for (size_t p = 0; p < (sizeof(AXPB) >> 1); p++)
|
||||
{
|
||||
PB_in_mram[p] = Common::swap16(PB_in_aram[p]);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ARAM -> MRAM for Wii
|
||||
inline bool WritePB(u32 addr, AXPBWii &PB)
|
||||
{
|
||||
const u16* PB_in_aram = (const u16*)&PB;
|
||||
u16* PB_in_mram = (u16*)Memory::GetPointer(addr);
|
||||
if (PB_in_mram == NULL)
|
||||
return false;
|
||||
|
||||
// preswap the mixer_control
|
||||
*(u32*)&PB_in_mram[6] = (PB.mixer_control << 16) | (PB.mixer_control >> 16);
|
||||
|
||||
for (size_t p = 0; p < (sizeof(AXPBWii) >> 1); p++)
|
||||
{
|
||||
PB_in_mram[p] = Common::swap16(PB_in_aram[p]);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// TODO: fix handling of gc/wii PB differences
|
||||
// TODO: generally fix up the mess - looks crazy and kinda wrong
|
||||
template<class ParamBlockType>
|
||||
inline void MixAddVoice(ParamBlockType &pb,
|
||||
int *templbuffer, int *temprbuffer,
|
||||
int _iSize)
|
||||
{
|
||||
if (pb.running)
|
||||
{
|
||||
const u32 ratio = (u32)(((pb.src.ratio_hi << 16) + pb.src.ratio_lo)
|
||||
* /*ratioFactor:*/((float)AudioInterface::GetAIDSampleRate() / (float)soundStream->GetMixer()->GetSampleRate()));
|
||||
u32 sampleEnd = (pb.audio_addr.end_addr_hi << 16) | pb.audio_addr.end_addr_lo;
|
||||
u32 loopPos = (pb.audio_addr.loop_addr_hi << 16) | pb.audio_addr.loop_addr_lo;
|
||||
|
||||
u32 samplePos = (pb.audio_addr.cur_addr_hi << 16) | pb.audio_addr.cur_addr_lo;
|
||||
u32 frac = pb.src.cur_addr_frac;
|
||||
|
||||
// =======================================================================================
|
||||
// Handle No-SRC streams - No src streams have pb.src_type == 2 and have pb.src.ratio_hi = 0
|
||||
// and pb.src.ratio_lo = 0. We handle that by setting the sampling ratio integer to 1. This
|
||||
// makes samplePos update in the correct way. I'm unsure how we are actually supposed to
|
||||
// detect that this setting. Updates did not fix this automatically.
|
||||
// ---------------------------------------------------------------------------------------
|
||||
// Stream settings
|
||||
// src_type = 2 (most other games have src_type = 0)
|
||||
// Affected games:
|
||||
// Baten Kaitos - Eternal Wings (2003)
|
||||
// Baten Kaitos - Origins (2006)?
|
||||
// Soul Calibur 2: The movie music use src_type 2 but it needs no adjustment, perhaps
|
||||
// the sound format plays in to, Baten use ADPCM, SC2 use PCM16
|
||||
//if (pb.src_type == 2 && (pb.src.ratio_hi == 0 && pb.src.ratio_lo == 0))
|
||||
if (pb.running && (pb.src.ratio_hi == 0 && pb.src.ratio_lo == 0))
|
||||
{
|
||||
pb.src.ratio_hi = 1;
|
||||
}
|
||||
|
||||
// =======================================================================================
|
||||
// Games that use looping to play non-looping music streams - SSBM has info in all
|
||||
// pb.adpcm_loop_info parameters but has pb.audio_addr.looping = 0. If we treat these streams
|
||||
// like any other looping streams the music works. I'm unsure how we are actually supposed to
|
||||
// detect that these kinds of blocks should be looping. It seems like pb.mixer_control == 0 may
|
||||
// identify these types of blocks. Updates did not write any looping values.
|
||||
if (
|
||||
(pb.adpcm_loop_info.pred_scale || pb.adpcm_loop_info.yn1 || pb.adpcm_loop_info.yn2)
|
||||
&& pb.mixer_control == 0 && pb.adpcm_loop_info.pred_scale <= 0x7F
|
||||
)
|
||||
{
|
||||
pb.audio_addr.looping = 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Top Spin 3 Wii
|
||||
if (pb.audio_addr.sample_format > 25)
|
||||
pb.audio_addr.sample_format = 0;
|
||||
|
||||
// =======================================================================================
|
||||
// Walk through _iSize. _iSize = numSamples. If the game goes slow _iSize will be higher to
|
||||
// compensate for that. _iSize can be as low as 100 or as high as 2000 some cases.
|
||||
for (int s = 0; s < _iSize; s++)
|
||||
{
|
||||
int sample = 0;
|
||||
u32 oldFrac = frac;
|
||||
frac += ratio;
|
||||
u32 newSamplePos = samplePos + (frac >> 16); //whole number of frac
|
||||
|
||||
// =======================================================================================
|
||||
// Process sample format
|
||||
switch (pb.audio_addr.sample_format)
|
||||
{
|
||||
case AUDIOFORMAT_PCM8:
|
||||
pb.adpcm.yn2 = ((s8)DSP::ReadARAM(samplePos)) << 8; //current sample
|
||||
pb.adpcm.yn1 = ((s8)DSP::ReadARAM(samplePos + 1)) << 8; //next sample
|
||||
|
||||
if (pb.src_type == SRCTYPE_NEAREST)
|
||||
sample = pb.adpcm.yn2;
|
||||
else // linear interpolation
|
||||
sample = (pb.adpcm.yn1 * (u16)oldFrac + pb.adpcm.yn2 * (u16)(0xFFFF - oldFrac) + pb.adpcm.yn2) >> 16;
|
||||
|
||||
samplePos = newSamplePos;
|
||||
break;
|
||||
|
||||
case AUDIOFORMAT_PCM16:
|
||||
pb.adpcm.yn2 = (s16)(u16)((DSP::ReadARAM(samplePos * 2) << 8) | (DSP::ReadARAM((samplePos * 2 + 1)))); //current sample
|
||||
pb.adpcm.yn1 = (s16)(u16)((DSP::ReadARAM((samplePos + 1) * 2) << 8) | (DSP::ReadARAM(((samplePos + 1) * 2 + 1)))); //next sample
|
||||
|
||||
if (pb.src_type == SRCTYPE_NEAREST)
|
||||
sample = pb.adpcm.yn2;
|
||||
else // linear interpolation
|
||||
sample = (pb.adpcm.yn1 * (u16)oldFrac + pb.adpcm.yn2 * (u16)(0xFFFF - oldFrac) + pb.adpcm.yn2) >> 16;
|
||||
|
||||
samplePos = newSamplePos;
|
||||
break;
|
||||
|
||||
case AUDIOFORMAT_ADPCM:
|
||||
ADPCM_Step(pb.adpcm, samplePos, newSamplePos, frac);
|
||||
|
||||
if (pb.src_type == SRCTYPE_NEAREST)
|
||||
sample = pb.adpcm.yn2;
|
||||
else // linear interpolation
|
||||
sample = (pb.adpcm.yn1 * (u16)frac + pb.adpcm.yn2 * (u16)(0xFFFF - frac) + pb.adpcm.yn2) >> 16; //adpcm moves on frac
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
// Overall volume control. In addition to this there is also separate volume settings to
|
||||
// different channels (left, right etc).
|
||||
frac &= 0xffff;
|
||||
|
||||
int vol = pb.vol_env.cur_volume >> 9;
|
||||
sample = sample * vol >> 8;
|
||||
|
||||
if (pb.mixer_control & MIXCONTROL_RAMPING)
|
||||
{
|
||||
int x = pb.vol_env.cur_volume;
|
||||
x += pb.vol_env.cur_volume_delta; // I'm not sure about this, can anybody find a game
|
||||
// that use this? Or how does it work?
|
||||
if (x < 0)
|
||||
x = 0;
|
||||
if (x >= 0x7fff)
|
||||
x = 0x7fff;
|
||||
pb.vol_env.cur_volume = x; // maybe not per sample?? :P
|
||||
}
|
||||
|
||||
int leftmix = pb.mixer.left >> 5;
|
||||
int rightmix = pb.mixer.right >> 5;
|
||||
int left = sample * leftmix >> 8;
|
||||
int right = sample * rightmix >> 8;
|
||||
// adpcm has to walk from oldSamplePos to samplePos here
|
||||
templbuffer[s] += left;
|
||||
temprbuffer[s] += right;
|
||||
|
||||
// Control the behavior when we reach the end of the sample
|
||||
if (samplePos >= sampleEnd)
|
||||
{
|
||||
if (pb.audio_addr.looping == 1)
|
||||
{
|
||||
if ((samplePos & ~0x1f) == (sampleEnd & ~0x1f) || (pb.audio_addr.sample_format != AUDIOFORMAT_ADPCM))
|
||||
samplePos = loopPos;
|
||||
if ((!pb.is_stream) && (pb.audio_addr.sample_format == AUDIOFORMAT_ADPCM))
|
||||
{
|
||||
pb.adpcm.yn1 = pb.adpcm_loop_info.yn1;
|
||||
pb.adpcm.yn2 = pb.adpcm_loop_info.yn2;
|
||||
pb.adpcm.pred_scale = pb.adpcm_loop_info.pred_scale;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pb.running = 0;
|
||||
samplePos = loopPos;
|
||||
//samplePos = samplePos - sampleEnd + loopPos;
|
||||
memset(&pb.dpop, 0, sizeof(pb.dpop));
|
||||
memset(pb.src.last_samples, 0, 8);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} // end of the _iSize loop
|
||||
|
||||
// Update volume
|
||||
pb.mixer.left = ADPCM_Vol(pb.mixer.left, pb.mixer.left_delta);
|
||||
pb.mixer.right = ADPCM_Vol(pb.mixer.right, pb.mixer.right_delta);
|
||||
|
||||
pb.src.cur_addr_frac = (u16)frac;
|
||||
pb.audio_addr.cur_addr_hi = samplePos >> 16;
|
||||
pb.audio_addr.cur_addr_lo = (u16)samplePos;
|
||||
|
||||
} // if (pb.running)
|
||||
}
|
||||
|
||||
#if !defined(AX_GC) && !defined(AX_WII)
|
||||
#error UCode_AX_Voice.h included without specifying version
|
||||
#endif
|
||||
|
||||
#include "Common.h"
|
||||
#include "UCode_AX_Structs.h"
|
||||
#include "../../DSP.h"
|
||||
|
||||
#ifdef AX_GC
|
||||
# define PB_TYPE AXPB
|
||||
#else
|
||||
# define PB_TYPE AXPBWii
|
||||
#endif
|
||||
|
||||
// Put all of that in an anonymous namespace to avoid stupid compilers merging
|
||||
// functions from AX GC and AX Wii.
|
||||
namespace {
|
||||
|
||||
// Useful macro to convert xxx_hi + xxx_lo to xxx for 32 bits.
|
||||
#define HILO_TO_32(name) \
|
||||
((name##_hi << 16) | name##_lo)
|
||||
|
||||
// Used to pass a large amount of buffers to the mixing function.
|
||||
union AXBuffers
|
||||
{
|
||||
struct
|
||||
{
|
||||
int* left;
|
||||
int* right;
|
||||
int* surround;
|
||||
|
||||
int* auxA_left;
|
||||
int* auxA_right;
|
||||
int* auxA_surround;
|
||||
|
||||
int* auxB_left;
|
||||
int* auxB_right;
|
||||
int* auxB_surround;
|
||||
|
||||
#ifdef AX_WII
|
||||
int* auxC_left;
|
||||
int* auxC_right;
|
||||
int* auxC_surround;
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef AX_GC
|
||||
int* ptrs[9];
|
||||
#else
|
||||
int* ptrs[12];
|
||||
#endif
|
||||
};
|
||||
|
||||
// Read a PB from MRAM/ARAM
|
||||
bool ReadPB(u32 addr, PB_TYPE& pb)
|
||||
{
|
||||
u16* dst = (u16*)&pb;
|
||||
const u16* src = (const u16*)Memory::GetPointer(addr);
|
||||
if (!src)
|
||||
return false;
|
||||
|
||||
for (u32 i = 0; i < sizeof (pb) / sizeof (u16); ++i)
|
||||
dst[i] = Common::swap16(src[i]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Write a PB back to MRAM/ARAM
|
||||
bool WritePB(u32 addr, const PB_TYPE& pb)
|
||||
{
|
||||
const u16* src = (const u16*)&pb;
|
||||
u16* dst = (u16*)Memory::GetPointer(addr);
|
||||
if (!dst)
|
||||
return false;
|
||||
|
||||
for (u32 i = 0; i < sizeof (pb) / sizeof (u16); ++i)
|
||||
dst[i] = Common::swap16(src[i]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Dump the value of a PB for debugging
|
||||
#define DUMP_U16(field) WARN_LOG(DSPHLE, " %04x (%s)", pb.field, #field)
|
||||
#define DUMP_U32(field) WARN_LOG(DSPHLE, " %08x (%s)", HILO_TO_32(pb.field), #field)
|
||||
void DumpPB(const PB_TYPE& pb)
|
||||
{
|
||||
DUMP_U32(next_pb);
|
||||
DUMP_U32(this_pb);
|
||||
DUMP_U16(src_type);
|
||||
DUMP_U16(coef_select);
|
||||
#ifdef AX_GC
|
||||
DUMP_U16(mixer_control);
|
||||
#else
|
||||
DUMP_U32(mixer_control);
|
||||
#endif
|
||||
DUMP_U16(running);
|
||||
DUMP_U16(is_stream);
|
||||
|
||||
// TODO: complete as needed
|
||||
}
|
||||
|
||||
// Simulated accelerator state.
|
||||
static u32 acc_loop_addr, acc_end_addr;
|
||||
static u32* acc_cur_addr;
|
||||
static PB_TYPE* acc_pb;
|
||||
|
||||
// Sets up the simulated accelerator.
|
||||
void AcceleratorSetup(PB_TYPE* pb, u32* cur_addr)
|
||||
{
|
||||
acc_pb = pb;
|
||||
acc_loop_addr = HILO_TO_32(pb->audio_addr.loop_addr);
|
||||
acc_end_addr = HILO_TO_32(pb->audio_addr.end_addr);
|
||||
acc_cur_addr = cur_addr;
|
||||
}
|
||||
|
||||
// Reads a sample from the simulated accelerator. Also handles looping and
|
||||
// disabling streams that reached the end (this is done by an exception raised
|
||||
// by the accelerator on real hardware).
|
||||
u16 AcceleratorGetSample()
|
||||
{
|
||||
u16 ret;
|
||||
|
||||
switch (acc_pb->audio_addr.sample_format)
|
||||
{
|
||||
case 0x00: // ADPCM
|
||||
{
|
||||
// ADPCM decoding, not much to explain here.
|
||||
if ((*acc_cur_addr & 15) == 0)
|
||||
{
|
||||
acc_pb->adpcm.pred_scale = DSP::ReadARAM((*acc_cur_addr & ~15) >> 1);
|
||||
*acc_cur_addr += 2;
|
||||
}
|
||||
|
||||
int scale = 1 << (acc_pb->adpcm.pred_scale & 0xF);
|
||||
int coef_idx = (acc_pb->adpcm.pred_scale >> 4) & 0x7;
|
||||
|
||||
s32 coef1 = acc_pb->adpcm.coefs[coef_idx * 2 + 0];
|
||||
s32 coef2 = acc_pb->adpcm.coefs[coef_idx * 2 + 1];
|
||||
|
||||
int temp = (*acc_cur_addr & 1) ?
|
||||
(DSP::ReadARAM(*acc_cur_addr >> 1) & 0xF) :
|
||||
(DSP::ReadARAM(*acc_cur_addr >> 1) >> 4);
|
||||
|
||||
if (temp >= 8)
|
||||
temp -= 16;
|
||||
|
||||
int val = (scale * temp) + ((0x400 + coef1 * acc_pb->adpcm.yn1 + coef2 * acc_pb->adpcm.yn2) >> 11);
|
||||
|
||||
if (val > 0x7FFF) val = 0x7FFF;
|
||||
else if (val < -0x7FFF) val = -0x7FFF;
|
||||
|
||||
acc_pb->adpcm.yn2 = acc_pb->adpcm.yn1;
|
||||
acc_pb->adpcm.yn1 = val;
|
||||
*acc_cur_addr += 1;
|
||||
ret = val;
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x0A: // 16-bit PCM audio
|
||||
ret = (DSP::ReadARAM(*acc_cur_addr * 2) << 8) | DSP::ReadARAM(*acc_cur_addr * 2 + 1);
|
||||
acc_pb->adpcm.yn2 = acc_pb->adpcm.yn1;
|
||||
acc_pb->adpcm.yn1 = ret;
|
||||
*acc_cur_addr += 1;
|
||||
break;
|
||||
|
||||
case 0x19: // 8-bit PCM audio
|
||||
ret = DSP::ReadARAM(*acc_cur_addr) << 8;
|
||||
acc_pb->adpcm.yn2 = acc_pb->adpcm.yn1;
|
||||
acc_pb->adpcm.yn1 = ret;
|
||||
*acc_cur_addr += 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
ERROR_LOG(DSPHLE, "Unknown sample format: %d", acc_pb->audio_addr.sample_format);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Have we reached the end address?
|
||||
//
|
||||
// On real hardware, this would raise an interrupt that is handled by the
|
||||
// UCode. We simulate what this interrupt does here.
|
||||
if (*acc_cur_addr >= acc_end_addr)
|
||||
{
|
||||
// If we are really at the end (and we don't simply have cur_addr >
|
||||
// end_addr all the time), loop back to loop_addr.
|
||||
if ((*acc_cur_addr & ~0x1F) == (acc_end_addr & ~0x1F))
|
||||
*acc_cur_addr = acc_loop_addr;
|
||||
|
||||
if (acc_pb->audio_addr.looping)
|
||||
{
|
||||
// Set the ADPCM infos to continue processing at loop_addr.
|
||||
//
|
||||
// For some reason, yn1 and yn2 aren't set if the voice is not of
|
||||
// stream type. This is what the AX UCode does and I don't really
|
||||
// know why.
|
||||
acc_pb->adpcm.pred_scale = acc_pb->adpcm_loop_info.pred_scale;
|
||||
if (!acc_pb->is_stream)
|
||||
{
|
||||
acc_pb->adpcm.yn1 = acc_pb->adpcm_loop_info.yn1;
|
||||
acc_pb->adpcm.yn2 = acc_pb->adpcm_loop_info.yn2;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Non looping voice reached the end -> running = 0.
|
||||
acc_pb->running = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Read 32 input samples from ARAM, decoding and converting rate if required.
|
||||
void GetInputSamples(PB_TYPE& pb, s16* samples)
|
||||
{
|
||||
u32 cur_addr = HILO_TO_32(pb.audio_addr.cur_addr);
|
||||
AcceleratorSetup(&pb, &cur_addr);
|
||||
|
||||
// TODO: support polyphase interpolation if coefficients are available.
|
||||
if (pb.src_type == SRCTYPE_POLYPHASE || pb.src_type == SRCTYPE_LINEAR)
|
||||
{
|
||||
// Convert the input to a higher or lower sample rate using a linear
|
||||
// interpolation algorithm. The input to output ratio is set in
|
||||
// pb.src.ratio, which is a floating point num stored as a 32b integer:
|
||||
// * Upper 16 bits of the ratio are the integer part
|
||||
// * Lower 16 bits are the decimal part
|
||||
u32 ratio = HILO_TO_32(pb.src.ratio);
|
||||
|
||||
// We start getting samples not from sample 0, but 0.<cur_addr_frac>.
|
||||
// This avoids discontinuties in the audio stream, especially with very
|
||||
// low ratios which interpolate a lot of values between two "real"
|
||||
// samples.
|
||||
u32 curr_pos = pb.src.cur_addr_frac;
|
||||
|
||||
// These are the two samples between which we interpolate. The initial
|
||||
// values are stored in the PB, and we update them when resampling the
|
||||
// input data.
|
||||
s16 curr0 = pb.src.last_samples[2];
|
||||
s16 curr1 = pb.src.last_samples[3];
|
||||
|
||||
for (u32 i = 0; i < 32; ++i)
|
||||
{
|
||||
// Get our current fractional position, used to know how much of
|
||||
// curr0 and how much of curr1 the output sample should be.
|
||||
s32 curr_frac_pos = curr_pos & 0xFFFF;
|
||||
|
||||
// Linear interpolation: s1 + (s2 - s1) * pos
|
||||
s16 sample = curr0 + (s16)(((curr1 - curr0) * (s32)curr_frac_pos) >> 16);
|
||||
samples[i] = sample;
|
||||
|
||||
curr_pos += ratio;
|
||||
|
||||
// While our current position is >= 1.0, shift to the next 2
|
||||
// samples for interpolation.
|
||||
while ((curr_pos >> 16) != 0)
|
||||
{
|
||||
curr0 = curr1;
|
||||
curr1 = AcceleratorGetSample();
|
||||
curr_pos -= 0x10000;
|
||||
}
|
||||
}
|
||||
|
||||
// Update the two last_samples values in the PB as well as the current
|
||||
// position.
|
||||
pb.src.last_samples[2] = curr0;
|
||||
pb.src.last_samples[3] = curr1;
|
||||
pb.src.cur_addr_frac = curr_pos & 0xFFFF;
|
||||
}
|
||||
else // SRCTYPE_NEAREST
|
||||
{
|
||||
// No sample rate conversion here: simply read 32 samples from the
|
||||
// accelerator to the output buffer.
|
||||
for (u32 i = 0; i < 32; ++i)
|
||||
samples[i] = AcceleratorGetSample();
|
||||
|
||||
memcpy(pb.src.last_samples, samples + 28, 4 * sizeof (u16));
|
||||
}
|
||||
|
||||
// Update current position in the PB.
|
||||
pb.audio_addr.cur_addr_hi = (u16)(cur_addr >> 16);
|
||||
pb.audio_addr.cur_addr_lo = (u16)(cur_addr & 0xFFFF);
|
||||
}
|
||||
|
||||
// Add samples to an output buffer, with optional volume ramping.
|
||||
void MixAdd(int* out, const s16* input, u16* pvol, s16* dpop, bool ramp)
|
||||
{
|
||||
u16& volume = pvol[0];
|
||||
u16 volume_delta = pvol[1];
|
||||
|
||||
// If volume ramping is disabled, set volume_delta to 0. That way, the
|
||||
// mixing loop can avoid testing if volume ramping is enabled at each step,
|
||||
// and just add volume_delta.
|
||||
if (!ramp)
|
||||
volume_delta = 0;
|
||||
|
||||
for (u32 i = 0; i < 32; ++i)
|
||||
{
|
||||
s64 sample = input[i];
|
||||
sample *= volume;
|
||||
sample >>= 15;
|
||||
|
||||
out[i] += (s16)sample;
|
||||
volume += volume_delta;
|
||||
|
||||
*dpop = (s16)sample;
|
||||
}
|
||||
}
|
||||
|
||||
// Process 1ms of audio (32 samples) from a PB and mix it to the buffers.
|
||||
void Process1ms(PB_TYPE& pb, const AXBuffers& buffers, AXMixControl mctrl)
|
||||
{
|
||||
// If the voice is not running, nothing to do.
|
||||
if (!pb.running)
|
||||
return;
|
||||
|
||||
// Read input samples, performing sample rate conversion if needed.
|
||||
s16 samples[32];
|
||||
GetInputSamples(pb, samples);
|
||||
|
||||
// Apply a global volume ramp using the volume envelope parameters.
|
||||
for (u32 i = 0; i < 32; ++i)
|
||||
{
|
||||
s64 sample = 2 * (s16)samples[i] * (s16)pb.vol_env.cur_volume;
|
||||
samples[i] = (s16)(sample >> 16);
|
||||
pb.vol_env.cur_volume += pb.vol_env.cur_volume_delta;
|
||||
}
|
||||
|
||||
// Optionally, execute a low pass filter
|
||||
if (pb.lpf.enabled)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
// Mix LRS, AUXA and AUXB depending on mixer_control
|
||||
// TODO: Handle DPL2 on AUXB.
|
||||
|
||||
if (mctrl & MIX_L)
|
||||
MixAdd(buffers.left, samples, &pb.mixer.left, &pb.dpop.left, mctrl & MIX_L_RAMP);
|
||||
if (mctrl & MIX_R)
|
||||
MixAdd(buffers.right, samples, &pb.mixer.right, &pb.dpop.right, mctrl & MIX_R_RAMP);
|
||||
if (mctrl & MIX_S)
|
||||
MixAdd(buffers.surround, samples, &pb.mixer.surround, &pb.dpop.surround, mctrl & MIX_S_RAMP);
|
||||
|
||||
if (mctrl & MIX_AUXA_L)
|
||||
MixAdd(buffers.auxA_left, samples, &pb.mixer.auxA_left, &pb.dpop.auxA_left, mctrl & MIX_AUXA_L_RAMP);
|
||||
if (mctrl & MIX_AUXA_R)
|
||||
MixAdd(buffers.auxA_right, samples, &pb.mixer.auxA_right, &pb.dpop.auxA_right, mctrl & MIX_AUXA_R_RAMP);
|
||||
if (mctrl & MIX_AUXA_S)
|
||||
MixAdd(buffers.auxA_surround, samples, &pb.mixer.auxA_surround, &pb.dpop.auxA_surround, mctrl & MIX_AUXA_S_RAMP);
|
||||
|
||||
if (mctrl & MIX_AUXB_L)
|
||||
MixAdd(buffers.auxB_left, samples, &pb.mixer.auxB_left, &pb.dpop.auxB_left, mctrl & MIX_AUXB_L_RAMP);
|
||||
if (mctrl & MIX_AUXB_R)
|
||||
MixAdd(buffers.auxB_right, samples, &pb.mixer.auxB_right, &pb.dpop.auxB_right, mctrl & MIX_AUXB_R_RAMP);
|
||||
if (mctrl & MIX_AUXB_S)
|
||||
MixAdd(buffers.auxB_surround, samples, &pb.mixer.auxB_surround, &pb.dpop.auxB_surround, mctrl & MIX_AUXB_S_RAMP);
|
||||
|
||||
#ifdef AX_WII
|
||||
if (mctrl & MIX_AUXC_L)
|
||||
MixAdd(buffers.auxC_left, samples, &pb.mixer.auxC_left, &pb.dpop.auxC_left, mctrl & MIX_AUXC_L_RAMP);
|
||||
if (mctrl & MIX_AUXC_R)
|
||||
MixAdd(buffers.auxC_right, samples, &pb.mixer.auxC_right, &pb.dpop.auxC_right, mctrl & MIX_AUXC_R_RAMP);
|
||||
if (mctrl & MIX_AUXC_S)
|
||||
MixAdd(buffers.auxC_surround, samples, &pb.mixer.auxC_surround, &pb.dpop.auxC_surround, mctrl & MIX_AUXC_S_RAMP);
|
||||
#endif
|
||||
|
||||
// Optionally, phase shift left or right channel to simulate 3D sound.
|
||||
if (pb.initial_time_delay.on)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
#endif // !_UCODE_AX_VOICE_H
|
||||
|
|
|
@ -0,0 +1,383 @@
|
|||
// Copyright (C) 2003 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#include "StringUtil.h"
|
||||
|
||||
#include "../MailHandler.h"
|
||||
#include "Mixer.h"
|
||||
|
||||
#include "UCodes.h"
|
||||
#include "UCode_AX_Structs.h"
|
||||
#include "UCode_NewAXWii.h"
|
||||
|
||||
#define AX_WII
|
||||
#include "UCode_AX_Voice.h"
|
||||
|
||||
|
||||
CUCode_NewAXWii::CUCode_NewAXWii(DSPHLE *dsp_hle, u32 l_CRC)
|
||||
: CUCode_AX(dsp_hle, l_CRC)
|
||||
{
|
||||
WARN_LOG(DSPHLE, "Instantiating CUCode_NewAXWii");
|
||||
}
|
||||
|
||||
CUCode_NewAXWii::~CUCode_NewAXWii()
|
||||
{
|
||||
}
|
||||
|
||||
void CUCode_NewAXWii::HandleCommandList()
|
||||
{
|
||||
// Temp variables for addresses computation
|
||||
u16 addr_hi, addr_lo;
|
||||
u16 addr2_hi, addr2_lo;
|
||||
u16 volume;
|
||||
|
||||
// WARN_LOG(DSPHLE, "Command list:");
|
||||
// for (u32 i = 0; m_cmdlist[i] != CMD_END; ++i)
|
||||
// WARN_LOG(DSPHLE, "%04x", m_cmdlist[i]);
|
||||
// WARN_LOG(DSPHLE, "-------------");
|
||||
|
||||
u32 curr_idx = 0;
|
||||
bool end = false;
|
||||
while (!end)
|
||||
{
|
||||
u16 cmd = m_cmdlist[curr_idx++];
|
||||
|
||||
switch (cmd)
|
||||
{
|
||||
// Some of these commands are unknown, or unused in this AX HLE.
|
||||
// We still need to skip their arguments using "curr_idx += N".
|
||||
|
||||
case CMD_SETUP:
|
||||
addr_hi = m_cmdlist[curr_idx++];
|
||||
addr_lo = m_cmdlist[curr_idx++];
|
||||
SetupProcessing(HILO_TO_32(addr));
|
||||
break;
|
||||
|
||||
case CMD_UNK_01: curr_idx += 2; break;
|
||||
case CMD_UNK_02: curr_idx += 2; break;
|
||||
case CMD_UNK_03: curr_idx += 2; break;
|
||||
|
||||
case CMD_PROCESS:
|
||||
addr_hi = m_cmdlist[curr_idx++];
|
||||
addr_lo = m_cmdlist[curr_idx++];
|
||||
ProcessPBList(HILO_TO_32(addr));
|
||||
break;
|
||||
|
||||
case CMD_MIX_AUXA:
|
||||
case CMD_MIX_AUXB:
|
||||
case CMD_MIX_AUXC:
|
||||
volume = m_cmdlist[curr_idx++];
|
||||
addr_hi = m_cmdlist[curr_idx++];
|
||||
addr_lo = m_cmdlist[curr_idx++];
|
||||
addr2_hi = m_cmdlist[curr_idx++];
|
||||
addr2_lo = m_cmdlist[curr_idx++];
|
||||
MixAUXSamples(cmd - CMD_MIX_AUXA, HILO_TO_32(addr), HILO_TO_32(addr2), volume);
|
||||
break;
|
||||
|
||||
// These two go together and manipulate some AUX buffers.
|
||||
case CMD_UNK_08: curr_idx += 13; break;
|
||||
case CMD_UNK_09: curr_idx += 13; break;
|
||||
|
||||
case CMD_UNK_0A: curr_idx += 4; break;
|
||||
|
||||
case CMD_OUTPUT:
|
||||
volume = m_cmdlist[curr_idx++];
|
||||
addr_hi = m_cmdlist[curr_idx++];
|
||||
addr_lo = m_cmdlist[curr_idx++];
|
||||
addr2_hi = m_cmdlist[curr_idx++];
|
||||
addr2_lo = m_cmdlist[curr_idx++];
|
||||
OutputSamples(HILO_TO_32(addr2), HILO_TO_32(addr), volume);
|
||||
break;
|
||||
|
||||
case CMD_UNK_0C: curr_idx += 5; break;
|
||||
|
||||
case CMD_WM_OUTPUT:
|
||||
{
|
||||
u32 addresses[4] = {
|
||||
(u32)(m_cmdlist[curr_idx + 0] << 16) | m_cmdlist[curr_idx + 1],
|
||||
(u32)(m_cmdlist[curr_idx + 2] << 16) | m_cmdlist[curr_idx + 3],
|
||||
(u32)(m_cmdlist[curr_idx + 4] << 16) | m_cmdlist[curr_idx + 5],
|
||||
(u32)(m_cmdlist[curr_idx + 6] << 16) | m_cmdlist[curr_idx + 7],
|
||||
};
|
||||
curr_idx += 8;
|
||||
OutputWMSamples(addresses);
|
||||
break;
|
||||
}
|
||||
|
||||
case CMD_END:
|
||||
end = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CUCode_NewAXWii::SetupProcessing(u32 init_addr)
|
||||
{
|
||||
// TODO: should be easily factorizable with AX
|
||||
s16 init_data[60];
|
||||
|
||||
for (u32 i = 0; i < 60; ++i)
|
||||
init_data[i] = HLEMemory_Read_U16(init_addr + 2 * i);
|
||||
|
||||
// List of all buffers we have to initialize
|
||||
struct {
|
||||
int* ptr;
|
||||
u32 samples;
|
||||
} buffers[] = {
|
||||
{ m_samples_left, 32 },
|
||||
{ m_samples_right, 32 },
|
||||
{ m_samples_surround, 32 },
|
||||
{ m_samples_auxA_left, 32 },
|
||||
{ m_samples_auxA_right, 32 },
|
||||
{ m_samples_auxA_surround, 32 },
|
||||
{ m_samples_auxB_left, 32 },
|
||||
{ m_samples_auxB_right, 32 },
|
||||
{ m_samples_auxB_surround, 32 },
|
||||
{ m_samples_auxC_left, 32 },
|
||||
{ m_samples_auxC_right, 32 },
|
||||
{ m_samples_auxC_surround, 32 },
|
||||
|
||||
{ m_samples_wm0, 6 },
|
||||
{ m_samples_aux0, 6 },
|
||||
{ m_samples_wm1, 6 },
|
||||
{ m_samples_aux1, 6 },
|
||||
{ m_samples_wm2, 6 },
|
||||
{ m_samples_aux2, 6 },
|
||||
{ m_samples_wm3, 6 },
|
||||
{ m_samples_aux3, 6 }
|
||||
};
|
||||
|
||||
u32 init_idx = 0;
|
||||
for (u32 i = 0; i < sizeof (buffers) / sizeof (buffers[0]); ++i)
|
||||
{
|
||||
s32 init_val = (s32)((init_data[init_idx] << 16) | init_data[init_idx + 1]);
|
||||
s16 delta = (s16)init_data[init_idx + 2];
|
||||
|
||||
init_idx += 3;
|
||||
|
||||
if (!init_val)
|
||||
memset(buffers[i].ptr, 0, 3 * buffers[i].samples * sizeof (int));
|
||||
else
|
||||
{
|
||||
for (u32 j = 0; j < 3 * buffers[i].samples; ++j)
|
||||
{
|
||||
buffers[i].ptr[j] = init_val;
|
||||
init_val += delta;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AXMixControl CUCode_NewAXWii::ConvertMixerControl(u32 mixer_control)
|
||||
{
|
||||
u32 ret = 0;
|
||||
|
||||
if (mixer_control & 0x00000001) ret |= MIX_L;
|
||||
if (mixer_control & 0x00000002) ret |= MIX_R;
|
||||
if (mixer_control & 0x00000004) ret |= MIX_L_RAMP | MIX_R_RAMP;
|
||||
if (mixer_control & 0x00000008) ret |= MIX_S;
|
||||
if (mixer_control & 0x00000010) ret |= MIX_S_RAMP;
|
||||
if (mixer_control & 0x00010000) ret |= MIX_AUXA_L;
|
||||
if (mixer_control & 0x00020000) ret |= MIX_AUXA_R;
|
||||
if (mixer_control & 0x00040000) ret |= MIX_AUXA_L_RAMP | MIX_AUXA_R_RAMP;
|
||||
if (mixer_control & 0x00080000) ret |= MIX_AUXA_S;
|
||||
if (mixer_control & 0x00100000) ret |= MIX_AUXA_S_RAMP;
|
||||
if (mixer_control & 0x00200000) ret |= MIX_AUXB_L;
|
||||
if (mixer_control & 0x00400000) ret |= MIX_AUXB_R;
|
||||
if (mixer_control & 0x00800000) ret |= MIX_AUXB_L_RAMP | MIX_AUXB_R_RAMP;
|
||||
if (mixer_control & 0x01000000) ret |= MIX_AUXB_S;
|
||||
if (mixer_control & 0x02000000) ret |= MIX_AUXB_S_RAMP;
|
||||
if (mixer_control & 0x04000000) ret |= MIX_AUXC_L;
|
||||
if (mixer_control & 0x08000000) ret |= MIX_AUXC_R;
|
||||
if (mixer_control & 0x10000000) ret |= MIX_AUXC_L_RAMP | MIX_AUXC_R_RAMP;
|
||||
if (mixer_control & 0x20000000) ret |= MIX_AUXC_S;
|
||||
if (mixer_control & 0x40000000) ret |= MIX_AUXC_S_RAMP;
|
||||
|
||||
return (AXMixControl)ret;
|
||||
}
|
||||
|
||||
void CUCode_NewAXWii::ProcessPBList(u32 pb_addr)
|
||||
{
|
||||
const u32 spms = 32;
|
||||
|
||||
AXPBWii pb;
|
||||
|
||||
while (pb_addr)
|
||||
{
|
||||
AXBuffers buffers = {{
|
||||
m_samples_left,
|
||||
m_samples_right,
|
||||
m_samples_surround,
|
||||
m_samples_auxA_left,
|
||||
m_samples_auxA_right,
|
||||
m_samples_auxA_surround,
|
||||
m_samples_auxB_left,
|
||||
m_samples_auxB_right,
|
||||
m_samples_auxB_surround,
|
||||
m_samples_auxC_left,
|
||||
m_samples_auxC_right,
|
||||
m_samples_auxC_surround
|
||||
}};
|
||||
|
||||
if (!ReadPB(pb_addr, pb))
|
||||
break;
|
||||
|
||||
for (int curr_ms = 0; curr_ms < 3; ++curr_ms)
|
||||
{
|
||||
Process1ms(pb, buffers, ConvertMixerControl(HILO_TO_32(pb.mixer_control)));
|
||||
|
||||
// Forward the buffers
|
||||
for (u32 i = 0; i < sizeof (buffers.ptrs) / sizeof (buffers.ptrs[0]); ++i)
|
||||
buffers.ptrs[i] += spms;
|
||||
}
|
||||
|
||||
WritePB(pb_addr, pb);
|
||||
pb_addr = HILO_TO_32(pb.next_pb);
|
||||
}
|
||||
}
|
||||
|
||||
void CUCode_NewAXWii::MixAUXSamples(int aux_id, u32 write_addr, u32 read_addr, u16 volume)
|
||||
{
|
||||
int* buffers[3] = { 0 };
|
||||
int* main_buffers[3] = {
|
||||
m_samples_left,
|
||||
m_samples_right,
|
||||
m_samples_surround
|
||||
};
|
||||
|
||||
switch (aux_id)
|
||||
{
|
||||
case 0:
|
||||
buffers[0] = m_samples_auxA_left;
|
||||
buffers[1] = m_samples_auxA_right;
|
||||
buffers[2] = m_samples_auxA_surround;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
buffers[0] = m_samples_auxB_left;
|
||||
buffers[1] = m_samples_auxB_right;
|
||||
buffers[2] = m_samples_auxB_surround;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
buffers[0] = m_samples_auxC_left;
|
||||
buffers[1] = m_samples_auxC_right;
|
||||
buffers[2] = m_samples_auxC_surround;
|
||||
break;
|
||||
}
|
||||
|
||||
// Send the content of AUX buffers to the CPU
|
||||
if (write_addr)
|
||||
{
|
||||
int* ptr = (int*)HLEMemory_Get_Pointer(write_addr);
|
||||
for (u32 i = 0; i < 3; ++i)
|
||||
for (u32 j = 0; j < 3 * 32; ++j)
|
||||
*ptr++ = Common::swap32(buffers[i][j]);
|
||||
}
|
||||
|
||||
// Then read the buffers from the CPU and add to our main buffers.
|
||||
int* ptr = (int*)HLEMemory_Get_Pointer(read_addr);
|
||||
for (u32 i = 0; i < 3; ++i)
|
||||
for (u32 j = 0; j < 3 * 32; ++j)
|
||||
{
|
||||
s64 new_val = main_buffers[i][j] + Common::swap32(*ptr++);
|
||||
main_buffers[i][j] = (new_val * volume) >> 15;
|
||||
}
|
||||
}
|
||||
|
||||
void CUCode_NewAXWii::OutputSamples(u32 lr_addr, u32 surround_addr, u16 volume)
|
||||
{
|
||||
int surround_buffer[3 * 32] = { 0 };
|
||||
|
||||
for (u32 i = 0; i < 3 * 32; ++i)
|
||||
surround_buffer[i] = Common::swap32(m_samples_surround[i]);
|
||||
memcpy(HLEMemory_Get_Pointer(surround_addr), surround_buffer, sizeof (surround_buffer));
|
||||
|
||||
short buffer[3 * 32 * 2];
|
||||
|
||||
// Clamp internal buffers to 16 bits.
|
||||
for (u32 i = 0; i < 3 * 32; ++i)
|
||||
{
|
||||
int left = m_samples_left[i];
|
||||
int right = m_samples_right[i];
|
||||
|
||||
// Apply global volume. Cast to s64 to avoid overflow.
|
||||
left = ((s64)left * volume) >> 15;
|
||||
right = ((s64)right * volume) >> 15;
|
||||
|
||||
if (left < -32767) left = -32767;
|
||||
if (left > 32767) left = 32767;
|
||||
if (right < -32767) right = -32767;
|
||||
if (right > 32767) right = 32767;
|
||||
|
||||
m_samples_left[i] = left;
|
||||
m_samples_right[i] = right;
|
||||
}
|
||||
|
||||
for (u32 i = 0; i < 3 * 32; ++i)
|
||||
{
|
||||
buffer[2 * i] = Common::swap16(m_samples_left[i]);
|
||||
buffer[2 * i + 1] = Common::swap16(m_samples_right[i]);
|
||||
}
|
||||
|
||||
memcpy(HLEMemory_Get_Pointer(lr_addr), buffer, sizeof (buffer));
|
||||
}
|
||||
|
||||
void CUCode_NewAXWii::OutputWMSamples(u32* addresses)
|
||||
{
|
||||
int* buffers[] = {
|
||||
m_samples_wm0,
|
||||
m_samples_wm1,
|
||||
m_samples_wm2,
|
||||
m_samples_wm3
|
||||
};
|
||||
|
||||
for (u32 i = 0; i < 4; ++i)
|
||||
{
|
||||
int* in = buffers[i];
|
||||
u16* out = (u16*)HLEMemory_Get_Pointer(addresses[i]);
|
||||
for (u32 j = 0; j < 3 * 6; ++j)
|
||||
{
|
||||
int sample = in[j];
|
||||
if (sample < -32767) sample = -32767;
|
||||
if (sample > 32767) sample = 32767;
|
||||
out[j] = Common::swap16((u16)sample);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CUCode_NewAXWii::DoState(PointerWrap &p)
|
||||
{
|
||||
std::lock_guard<std::mutex> lk(m_processing);
|
||||
|
||||
DoStateShared(p);
|
||||
DoAXState(p);
|
||||
|
||||
p.Do(m_samples_auxC_left);
|
||||
p.Do(m_samples_auxC_right);
|
||||
p.Do(m_samples_auxC_surround);
|
||||
|
||||
p.Do(m_samples_wm0);
|
||||
p.Do(m_samples_wm1);
|
||||
p.Do(m_samples_wm2);
|
||||
p.Do(m_samples_wm3);
|
||||
|
||||
p.Do(m_samples_aux0);
|
||||
p.Do(m_samples_aux1);
|
||||
p.Do(m_samples_aux2);
|
||||
p.Do(m_samples_aux3);
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
// Copyright (C) 2003 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official Git repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#ifndef _UCODE_NEWAXWII_H
|
||||
#define _UCODE_NEWAXWII_H
|
||||
|
||||
#include "UCode_AX.h"
|
||||
|
||||
class CUCode_NewAXWii : public CUCode_AX
|
||||
{
|
||||
public:
|
||||
CUCode_NewAXWii(DSPHLE *dsp_hle, u32 _CRC);
|
||||
virtual ~CUCode_NewAXWii();
|
||||
|
||||
virtual void DoState(PointerWrap &p);
|
||||
|
||||
protected:
|
||||
int m_samples_auxC_left[32 * 3];
|
||||
int m_samples_auxC_right[32 * 3];
|
||||
int m_samples_auxC_surround[32 * 3];
|
||||
|
||||
// Wiimote buffers
|
||||
int m_samples_wm0[6 * 3];
|
||||
int m_samples_aux0[6 * 3];
|
||||
int m_samples_wm1[6 * 3];
|
||||
int m_samples_aux1[6 * 3];
|
||||
int m_samples_wm2[6 * 3];
|
||||
int m_samples_aux2[6 * 3];
|
||||
int m_samples_wm3[6 * 3];
|
||||
int m_samples_aux3[6 * 3];
|
||||
|
||||
// Convert a mixer_control bitfield to our internal representation for that
|
||||
// value. Required because that bitfield has a different meaning in some
|
||||
// versions of AX.
|
||||
AXMixControl ConvertMixerControl(u32 mixer_control);
|
||||
|
||||
virtual void HandleCommandList();
|
||||
|
||||
void SetupProcessing(u32 init_addr);
|
||||
void ProcessPBList(u32 pb_addr);
|
||||
void MixAUXSamples(int aux_id, u32 write_addr, u32 read_addr, u16 volume);
|
||||
void OutputSamples(u32 lr_addr, u32 surround_addr, u16 volume);
|
||||
void OutputWMSamples(u32* addresses); // 4 addresses
|
||||
|
||||
private:
|
||||
enum CmdType
|
||||
{
|
||||
CMD_SETUP = 0x00,
|
||||
CMD_UNK_01 = 0x01,
|
||||
CMD_UNK_02 = 0x02,
|
||||
CMD_UNK_03 = 0x03,
|
||||
CMD_PROCESS = 0x04,
|
||||
CMD_MIX_AUXA = 0x05,
|
||||
CMD_MIX_AUXB = 0x06,
|
||||
CMD_MIX_AUXC = 0x07,
|
||||
CMD_UNK_08 = 0x08,
|
||||
CMD_UNK_09 = 0x09,
|
||||
CMD_UNK_0A = 0x0A,
|
||||
CMD_OUTPUT = 0x0B,
|
||||
CMD_UNK_0C = 0x0C,
|
||||
CMD_WM_OUTPUT = 0x0D,
|
||||
CMD_END = 0x0E
|
||||
};
|
||||
};
|
||||
|
||||
#endif // _UCODE_AXWII
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
#include "UCode_AX.h"
|
||||
#include "UCode_AXWii.h"
|
||||
#include "UCode_NewAXWii.h"
|
||||
#include "UCode_Zelda.h"
|
||||
#include "UCode_ROM.h"
|
||||
#include "UCode_CARD.h"
|
||||
|
@ -26,6 +27,12 @@
|
|||
#include "UCode_GBA.h"
|
||||
#include "Hash.h"
|
||||
|
||||
#if 0
|
||||
# define AXWII CUCode_NewAXWii
|
||||
#else
|
||||
# define AXWII CUCode_AXWii
|
||||
#endif
|
||||
|
||||
IUCode* UCodeFactory(u32 _CRC, DSPHLE *dsp_hle, bool bWii)
|
||||
{
|
||||
switch (_CRC)
|
||||
|
@ -90,13 +97,13 @@ IUCode* UCodeFactory(u32 _CRC, DSPHLE *dsp_hle, bool bWii)
|
|||
case 0x4cc52064: // Bleach: Versus Crusade
|
||||
case 0xd9c4bf34: // WiiMenu
|
||||
INFO_LOG(DSPHLE, "CRC %08x: Wii - AXWii chosen", _CRC);
|
||||
return new CUCode_AXWii(dsp_hle, _CRC);
|
||||
return new AXWII(dsp_hle, _CRC);
|
||||
|
||||
default:
|
||||
if (bWii)
|
||||
{
|
||||
PanicAlert("DSPHLE: Unknown ucode (CRC = %08x) - forcing AXWii.\n\nTry LLE emulator if this is homebrew.", _CRC);
|
||||
return new CUCode_AXWii(dsp_hle, _CRC);
|
||||
return new AXWII(dsp_hle, _CRC);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -388,7 +388,7 @@ void ExecuteCommand(u32 _Address)
|
|||
|
||||
INFO_LOG(WII_IPC_FILEIO, "IOP: Open File (Device=%s, ID=%08x, Mode=%i)",
|
||||
pDevice->GetDeviceName().c_str(), DeviceID, Mode);
|
||||
if (Memory::Read_U32(_Address + 4) == DeviceID)
|
||||
if (Memory::Read_U32(_Address + 4) == (u32)DeviceID)
|
||||
{
|
||||
g_FdMap[DeviceID] = pDevice;
|
||||
}
|
||||
|
|
|
@ -789,8 +789,8 @@ bool CWII_IPC_HLE_Device_es::IOCtlV(u32 _CommandAddress)
|
|||
{
|
||||
static CWII_IPC_HLE_Device_usb_oh1_57e_305* s_Usb = GetUsbPointer();
|
||||
bool* wiiMoteConnected = new bool[s_Usb->m_WiiMotes.size()];
|
||||
for(unsigned int i = 0; i < s_Usb->m_WiiMotes.size();
|
||||
i++) wiiMoteConnected[i] = s_Usb->m_WiiMotes[i].IsConnected();
|
||||
for (unsigned int i = 0; i < s_Usb->m_WiiMotes.size(); i++)
|
||||
wiiMoteConnected[i] = s_Usb->m_WiiMotes[i].IsConnected();
|
||||
|
||||
std::string tContentFile(m_ContentFile.c_str());
|
||||
WII_IPC_HLE_Interface::Reset(true);
|
||||
|
|
|
@ -31,7 +31,7 @@ struct NANDStat
|
|||
};
|
||||
|
||||
enum {
|
||||
FS_RESULT_OK = 0,
|
||||
FS_RESULT_OK = 0,
|
||||
FS_INVALID = -4,
|
||||
FS_DIRFILE_NOT_FOUND = -6,
|
||||
FS_RESULT_FATAL = -101,
|
||||
|
|
|
@ -116,26 +116,26 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::DoState(PointerWrap &p)
|
|||
p.Do(m_EventQueue);
|
||||
m_acl_pool.DoState(p);
|
||||
|
||||
for (unsigned int i = 0; i < 4; i++)
|
||||
m_WiiMotes[i].DoState(p);
|
||||
|
||||
// Reset the connection of real and hybrid wiimotes
|
||||
if (p.GetMode() == PointerWrap::MODE_READ && SConfig::GetInstance().m_WiimoteReconnectOnLoad)
|
||||
{
|
||||
for (unsigned int i = 0; i < 4; i++)
|
||||
{
|
||||
if (WIIMOTE_SRC_EMU == g_wiimote_sources[i] || WIIMOTE_SRC_NONE == g_wiimote_sources[i])
|
||||
continue;
|
||||
// TODO: Selectively clear real wiimote messages if possible. Or create a real wiimote channel and reporting mode pre-setup to vacate the need for m_WiimoteReconnectOnLoad.
|
||||
m_EventQueue.clear();
|
||||
if (!m_WiiMotes[i].IsInactive())
|
||||
{
|
||||
m_WiiMotes[i].Activate(false);
|
||||
m_WiiMotes[i].Activate(true);
|
||||
}
|
||||
else
|
||||
m_WiiMotes[i].Activate(false);
|
||||
}
|
||||
for (unsigned int i = 0; i < 4; i++)
|
||||
m_WiiMotes[i].DoState(p);
|
||||
|
||||
// Reset the connection of real and hybrid wiimotes
|
||||
if (p.GetMode() == PointerWrap::MODE_READ && SConfig::GetInstance().m_WiimoteReconnectOnLoad)
|
||||
{
|
||||
for (unsigned int i = 0; i < 4; i++)
|
||||
{
|
||||
if (WIIMOTE_SRC_EMU == g_wiimote_sources[i] || WIIMOTE_SRC_NONE == g_wiimote_sources[i])
|
||||
continue;
|
||||
// TODO: Selectively clear real wiimote messages if possible. Or create a real wiimote channel and reporting mode pre-setup to vacate the need for m_WiimoteReconnectOnLoad.
|
||||
m_EventQueue.clear();
|
||||
if (!m_WiiMotes[i].IsInactive())
|
||||
{
|
||||
m_WiiMotes[i].Activate(false);
|
||||
m_WiiMotes[i].Activate(true);
|
||||
}
|
||||
else
|
||||
m_WiiMotes[i].Activate(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -144,7 +144,7 @@ void Init(int cpu_core)
|
|||
#ifdef _WIN32
|
||||
_control87(_PC_53, MCW_PC);
|
||||
#else
|
||||
unsigned short _mode = 0;
|
||||
unsigned short _mode;
|
||||
asm ("fstcw %0" : : "m" (_mode));
|
||||
_mode = (_mode & ~FPU_PREC_MASK) | FPU_PREC_53;
|
||||
asm ("fldcw %0" : : "m" (_mode));
|
||||
|
|
|
@ -8,7 +8,6 @@ set(LIBS core
|
|||
z
|
||||
sfml-network
|
||||
${GTK2_LIBRARIES}
|
||||
${OPENGL_LIBRARIES}
|
||||
${XRANDR_LIBRARIES}
|
||||
${X11_LIBRARIES})
|
||||
|
||||
|
@ -31,7 +30,8 @@ if(LIBAV_FOUND)
|
|||
endif()
|
||||
|
||||
if(wxWidgets_FOUND)
|
||||
set(SRCS Src/ARCodeAddEdit.cpp
|
||||
set(SRCS
|
||||
Src/ARCodeAddEdit.cpp
|
||||
Src/AboutDolphin.cpp
|
||||
Src/CheatsWindow.cpp
|
||||
Src/ConfigMain.cpp
|
||||
|
@ -79,7 +79,27 @@ if(wxWidgets_FOUND)
|
|||
|
||||
set(WXLIBS ${wxWidgets_LIBRARIES})
|
||||
else()
|
||||
set(SRCS Src/MainNoGUI.cpp)
|
||||
set(SRCS
|
||||
Src/MainNoGUI.cpp)
|
||||
endif()
|
||||
|
||||
if(USE_EGL)
|
||||
set(SRCS ${SRCS} Src/GLInterface/EGL.cpp
|
||||
Src/GLInterface/X11_Util.cpp)
|
||||
else()
|
||||
if(WIN32)
|
||||
set(SRCS ${SRCS} Src/GLInterface/GLW.cpp)
|
||||
elseif(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
||||
if(USE_WX)
|
||||
set(SRCS ${SRCS} Src/GLInterface/WX.cpp)
|
||||
else()
|
||||
set(SRCS ${SRCS} Src/GLInterface/AGL.cpp)
|
||||
endif()
|
||||
else()
|
||||
set(SRCS ${SRCS} Src/GLInterface/GLX.cpp
|
||||
Src/GLInterface/X11_Util.cpp)
|
||||
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
|
@ -196,3 +216,5 @@ if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
|||
else()
|
||||
install(TARGETS ${DOLPHIN_EXE} RUNTIME DESTINATION ${bindir})
|
||||
endif()
|
||||
|
||||
set(CPACK_PACKAGE_EXECUTABLES ${CPACK_PACKAGE_EXECUTABLES} ${DOLPHIN_EXE})
|
||||
|
|
|
@ -130,7 +130,7 @@
|
|||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>..\Common\Src;..\VideoCommon\Src;..\AudioCommon\Src;..\Core\Src;..\Core\Src\PowerPC\JitCommon;..\DebuggerWX\Src;..\..\..\Externals\Bochs_disasm;..\InputCommon\Src;..\DiscIO\Src;..\..\..\Externals\SFML\include;..\..\..\Externals\wxWidgets3;..\..\..\Externals\wxWidgets3\include;..\..\..\Externals\CLRun\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>..\..\..\Externals\GLew\include;..\Common\Src;..\VideoCommon\Src;..\AudioCommon\Src;..\Core\Src;..\Core\Src\PowerPC\JitCommon;..\DebuggerWX\Src;..\..\..\Externals\Bochs_disasm;..\InputCommon\Src;..\DiscIO\Src;..\..\..\Externals\SFML\include;..\..\..\Externals\wxWidgets3;..\..\..\Externals\wxWidgets3\include;..\..\..\Externals\CLRun\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link />
|
||||
<PostBuildEvent>
|
||||
|
@ -144,7 +144,7 @@ xcopy "$(SolutionDir)..\Externals\SDL\$(PlatformName)\*.dll" "$(TargetDir)" /e /
|
|||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>..\Common\Src;..\VideoCommon\Src;..\AudioCommon\Src;..\Core\Src;..\Core\Src\PowerPC\JitCommon;..\DebuggerWX\Src;..\..\..\Externals\Bochs_disasm;..\InputCommon\Src;..\DiscIO\Src;..\..\..\Externals\SFML\include;..\..\..\Externals\wxWidgets3;..\..\..\Externals\wxWidgets3\include;..\..\..\Externals\CLRun\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>..\..\..\Externals\GLew\include;..\Common\Src;..\VideoCommon\Src;..\AudioCommon\Src;..\Core\Src;..\Core\Src\PowerPC\JitCommon;..\DebuggerWX\Src;..\..\..\Externals\Bochs_disasm;..\InputCommon\Src;..\DiscIO\Src;..\..\..\Externals\SFML\include;..\..\..\Externals\wxWidgets3;..\..\..\Externals\wxWidgets3\include;..\..\..\Externals\CLRun\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link />
|
||||
<PostBuildEvent>
|
||||
|
@ -158,7 +158,7 @@ xcopy "$(SolutionDir)..\Externals\SDL\$(PlatformName)\*.dll" "$(TargetDir)" /e /
|
|||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>..\Common\Src;..\VideoCommon\Src;..\AudioCommon\Src;..\Core\Src;..\Core\Src\PowerPC\JitCommon;..\DebuggerWX\Src;..\..\..\Externals\Bochs_disasm;..\InputCommon\Src;..\DiscIO\Src;..\..\..\Externals\SFML\include;..\..\..\Externals\wxWidgets3;..\..\..\Externals\wxWidgets3\include;..\..\..\Externals\CLRun\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>..\..\..\Externals\GLew\include;..\Common\Src;..\VideoCommon\Src;..\AudioCommon\Src;..\Core\Src;..\Core\Src\PowerPC\JitCommon;..\DebuggerWX\Src;..\..\..\Externals\Bochs_disasm;..\InputCommon\Src;..\DiscIO\Src;..\..\..\Externals\SFML\include;..\..\..\Externals\wxWidgets3;..\..\..\Externals\wxWidgets3\include;..\..\..\Externals\CLRun\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<OpenMPSupport>
|
||||
</OpenMPSupport>
|
||||
</ClCompile>
|
||||
|
@ -174,7 +174,7 @@ xcopy "$(SolutionDir)..\Externals\SDL\$(PlatformName)\*.dll" "$(TargetDir)" /e /
|
|||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|Win32'">
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>..\Common\Src;..\VideoCommon\Src;..\AudioCommon\Src;..\Core\Src;..\Core\Src\PowerPC\JitCommon;..\DebuggerWX\Src;..\..\..\Externals\Bochs_disasm;..\InputCommon\Src;..\InputUICommon\Src;..\DiscIO\Src;..\..\..\Externals\SFML\include;..\..\..\Externals\wxWidgets3;..\..\..\Externals\wxWidgets3\include;..\..\..\Externals\CLRun\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>..\..\..\Externals\GLew\include;..\Common\Src;..\VideoCommon\Src;..\AudioCommon\Src;..\Core\Src;..\Core\Src\PowerPC\JitCommon;..\DebuggerWX\Src;..\..\..\Externals\Bochs_disasm;..\InputCommon\Src;..\InputUICommon\Src;..\DiscIO\Src;..\..\..\Externals\SFML\include;..\..\..\Externals\wxWidgets3;..\..\..\Externals\wxWidgets3\include;..\..\..\Externals\CLRun\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link />
|
||||
<PostBuildEvent>
|
||||
|
@ -188,7 +188,7 @@ xcopy "$(SolutionDir)..\Externals\SDL\$(PlatformName)\*.dll" "$(TargetDir)" /e /
|
|||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>..\Common\Src;..\VideoCommon\Src;..\AudioCommon\Src;..\Core\Src;..\Core\Src\PowerPC\JitCommon;..\DebuggerWX\Src;..\..\..\Externals\Bochs_disasm;..\InputCommon\Src;..\DiscIO\Src;..\..\..\Externals\SFML\include;..\..\..\Externals\wxWidgets3;..\..\..\Externals\wxWidgets3\include;..\..\..\Externals\CLRun\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>..\..\..\Externals\GLew\include;..\Common\Src;..\VideoCommon\Src;..\AudioCommon\Src;..\Core\Src;..\Core\Src\PowerPC\JitCommon;..\DebuggerWX\Src;..\..\..\Externals\Bochs_disasm;..\InputCommon\Src;..\DiscIO\Src;..\..\..\Externals\SFML\include;..\..\..\Externals\wxWidgets3;..\..\..\Externals\wxWidgets3\include;..\..\..\Externals\CLRun\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<OpenMPSupport>
|
||||
</OpenMPSupport>
|
||||
</ClCompile>
|
||||
|
@ -206,7 +206,7 @@ xcopy "$(SolutionDir)..\Externals\SDL\$(PlatformName)\*.dll" "$(TargetDir)" /e /
|
|||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|x64'">
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>..\Common\Src;..\VideoCommon\Src;..\AudioCommon\Src;..\Core\Src;..\Core\Src\PowerPC\JitCommon;..\DebuggerWX\Src;..\..\..\Externals\Bochs_disasm;..\InputCommon\Src;..\InputUICommon\Src;..\DiscIO\Src;..\..\..\Externals\SFML\include;..\..\..\Externals\wxWidgets3;..\..\..\Externals\wxWidgets3\include;..\..\..\Externals\CLRun\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>..\..\..\Externals\GLew\include;..\Common\Src;..\VideoCommon\Src;..\AudioCommon\Src;..\Core\Src;..\Core\Src\PowerPC\JitCommon;..\DebuggerWX\Src;..\..\..\Externals\Bochs_disasm;..\InputCommon\Src;..\InputUICommon\Src;..\DiscIO\Src;..\..\..\Externals\SFML\include;..\..\..\Externals\wxWidgets3;..\..\..\Externals\wxWidgets3\include;..\..\..\Externals\CLRun\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link />
|
||||
<PostBuildEvent>
|
||||
|
@ -267,6 +267,7 @@ xcopy "$(SolutionDir)..\Externals\SDL\$(PlatformName)\*.dll" "$(TargetDir)" /e /
|
|||
<ClCompile Include="Src\PHackSettings.cpp" />
|
||||
<ClCompile Include="Src\Debugger\RegisterView.cpp" />
|
||||
<ClCompile Include="Src\Debugger\RegisterWindow.cpp" />
|
||||
<ClCompile Include="Src\GLInterface\WGL.cpp" />
|
||||
<ClCompile Include="Src\stdafx.cpp">
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='DebugFast|Win32'">Create</PrecompiledHeader>
|
||||
|
@ -328,6 +329,9 @@ xcopy "$(SolutionDir)..\Externals\SDL\$(PlatformName)\*.dll" "$(TargetDir)" /e /
|
|||
<ClInclude Include="Src\WiimoteConfigDiag.h" />
|
||||
<ClInclude Include="Src\WXInputBase.h" />
|
||||
<ClInclude Include="Src\WxUtils.h" />
|
||||
<ClInclude Include="Src\GLInterface.h" />
|
||||
<ClInclude Include="Src\GLInterface\InterfaceBase.h" />
|
||||
<ClInclude Include="Src\GLInterface\WGL.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\..\..\Installer\Dolphin.ico" />
|
||||
|
|
|
@ -31,7 +31,7 @@ AboutDolphin::AboutDolphin(wxWindow *parent, wxWindowID id,
|
|||
wxBitmap(iDolphinLogo));
|
||||
|
||||
std::string Text = "Dolphin " SCM_DESC_STR "\n"
|
||||
"Copyright (c) 2003-2011+ Dolphin Team\n"
|
||||
"Copyright (c) 2003-2013+ Dolphin Team\n"
|
||||
"\n"
|
||||
"Branch: " SCM_BRANCH_STR "\n"
|
||||
"Revision: " SCM_REV_STR "\n"
|
||||
|
|
|
@ -365,8 +365,6 @@ CFrame::CFrame(wxFrame* parent,
|
|||
// ---------------
|
||||
|
||||
// Manager
|
||||
// wxAUI_MGR_LIVE_RESIZE does not exist in the wxWidgets 2.8.9 that comes with Ubuntu 9.04
|
||||
// Could just check for wxWidgets version if it becomes a problem.
|
||||
m_Mgr = new wxAuiManager(this, wxAUI_MGR_DEFAULT | wxAUI_MGR_LIVE_RESIZE);
|
||||
|
||||
m_Mgr->AddPane(m_Panel, wxAuiPaneInfo()
|
||||
|
|
|
@ -50,6 +50,7 @@ Core::GetWindowHandle().
|
|||
#include "LogConfigWindow.h"
|
||||
#include "FifoPlayerDlg.h"
|
||||
#include "WxUtils.h"
|
||||
#include "Host.h"
|
||||
|
||||
#include "ConfigManager.h" // Core
|
||||
#include "Core.h"
|
||||
|
@ -96,6 +97,8 @@ extern "C" {
|
|||
#include "../resources/KDE.h"
|
||||
};
|
||||
|
||||
bool confirmStop = false;
|
||||
|
||||
// Create menu items
|
||||
// ---------------------
|
||||
void CFrame::CreateMenu()
|
||||
|
@ -1070,6 +1073,9 @@ void CFrame::DoPause()
|
|||
// Stop the emulation
|
||||
void CFrame::DoStop()
|
||||
{
|
||||
if (confirmStop)
|
||||
return;
|
||||
|
||||
m_bGameLoading = false;
|
||||
if (Core::GetState() != Core::CORE_UNINITIALIZED ||
|
||||
m_RenderParent != NULL)
|
||||
|
@ -1082,17 +1088,23 @@ void CFrame::DoStop()
|
|||
// Ask for confirmation in case the user accidentally clicked Stop / Escape
|
||||
if (SConfig::GetInstance().m_LocalCoreStartupParameter.bConfirmStop)
|
||||
{
|
||||
wxMessageDialog *m_StopDlg = new wxMessageDialog(
|
||||
Core::EState state = Core::GetState();
|
||||
confirmStop = true;
|
||||
Core::SetState(Core::CORE_PAUSE);
|
||||
wxMessageDialog m_StopDlg(
|
||||
this,
|
||||
_("Do you want to stop the current emulation?"),
|
||||
_("Please confirm..."),
|
||||
wxYES_NO | wxSTAY_ON_TOP | wxICON_EXCLAMATION,
|
||||
wxDefaultPosition);
|
||||
|
||||
int Ret = m_StopDlg->ShowModal();
|
||||
m_StopDlg->Destroy();
|
||||
int Ret = m_StopDlg.ShowModal();
|
||||
confirmStop = false;
|
||||
if (Ret != wxID_YES)
|
||||
{
|
||||
Core::SetState(state);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Show the author/description dialog here
|
||||
|
@ -1142,6 +1154,9 @@ void CFrame::DoStop()
|
|||
DoFullscreen(false);
|
||||
if (!SConfig::GetInstance().m_LocalCoreStartupParameter.bRenderToMain)
|
||||
m_RenderFrame->Destroy();
|
||||
else
|
||||
// Make sure the window is not longer set to stay on top
|
||||
m_RenderFrame->SetWindowStyle(m_RenderFrame->GetWindowStyle() & ~wxSTAY_ON_TOP);
|
||||
m_RenderParent = NULL;
|
||||
|
||||
// Clean framerate indications from the status bar.
|
||||
|
@ -1454,6 +1469,7 @@ void CFrame::ConnectWiimote(int wm_idx, bool connect)
|
|||
wxString msg(wxString::Format(wxT("Wiimote %i %s"), wm_idx + 1,
|
||||
connect ? wxT("Connected") : wxT("Disconnected")));
|
||||
Core::DisplayMessage(msg.ToAscii(), 3000);
|
||||
Host_UpdateMainFrame();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,75 @@
|
|||
// Copyright (C) 2003 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
#ifndef _GLINTERFACE_H_
|
||||
#define _GLINTERFACE_H_
|
||||
|
||||
#include "Thread.h"
|
||||
|
||||
#if defined(USE_EGL) && USE_EGL
|
||||
#include "GLInterface/EGL.h"
|
||||
#elif defined(USE_WX) && USE_WX
|
||||
#include "GLInterface/WX.h"
|
||||
#elif defined(__APPLE__)
|
||||
#include "GLInterface/AGL.h"
|
||||
#elif defined(_WIN32)
|
||||
#include "GLInterface/WGL.h"
|
||||
#elif defined(HAVE_X11) && HAVE_X11
|
||||
#include "GLInterface/GLX.h"
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
#if defined(USE_EGL) && USE_EGL // This is currently a X11/EGL implementation for desktop
|
||||
int screen;
|
||||
Display *dpy;
|
||||
Display *evdpy;
|
||||
Window win;
|
||||
Window parent;
|
||||
EGLSurface egl_surf;
|
||||
EGLContext egl_ctx;
|
||||
EGLDisplay egl_dpy;
|
||||
XVisualInfo *vi;
|
||||
XSetWindowAttributes attr;
|
||||
std::thread xEventThread;
|
||||
int x, y;
|
||||
unsigned int width, height;
|
||||
#elif defined(USE_WX) && USE_WX
|
||||
wxGLCanvas *glCanvas;
|
||||
wxGLContext *glCtxt;
|
||||
wxPanel *panel;
|
||||
#elif defined(__APPLE__)
|
||||
NSWindow *cocoaWin;
|
||||
NSOpenGLContext *cocoaCtx;
|
||||
#elif defined(HAVE_X11) && HAVE_X11
|
||||
int screen;
|
||||
Window win;
|
||||
Window parent;
|
||||
// dpy used for glx stuff, evdpy for window events etc.
|
||||
// evdpy is to be used by XEventThread only
|
||||
Display *dpy, *evdpy;
|
||||
XVisualInfo *vi;
|
||||
GLXContext ctx;
|
||||
XSetWindowAttributes attr;
|
||||
std::thread xEventThread;
|
||||
int x, y;
|
||||
unsigned int width, height;
|
||||
#endif
|
||||
} GLWindow;
|
||||
|
||||
extern cInterfaceBase *GLInterface;
|
||||
extern GLWindow GLWin;
|
||||
|
||||
#endif
|
|
@ -0,0 +1,123 @@
|
|||
// Copyright (C) 2003 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#include "VideoConfig.h"
|
||||
#include "Host.h"
|
||||
#include "RenderBase.h"
|
||||
|
||||
#include "VertexShaderManager.h"
|
||||
#include "../GLInterface.h"
|
||||
#include "AGL.h"
|
||||
|
||||
void cInterfaceAGL::Swap()
|
||||
{
|
||||
[GLWin.cocoaCtx flushBuffer];
|
||||
}
|
||||
|
||||
// Show the current FPS
|
||||
void cInterfaceAGL::UpdateFPSDisplay(const char *text)
|
||||
{
|
||||
[GLWin.cocoaWin setTitle: [NSString stringWithUTF8String: text]];
|
||||
}
|
||||
|
||||
// Create rendering window.
|
||||
// Call browser: Core.cpp:EmuThread() > main.cpp:Video_Initialize()
|
||||
bool cInterfaceAGL::Create(void *&window_handle)
|
||||
{
|
||||
int _tx, _ty, _twidth, _theight;
|
||||
Host_GetRenderWindowSize(_tx, _ty, _twidth, _theight);
|
||||
|
||||
// Control window size and picture scaling
|
||||
s_backbuffer_width = _twidth;
|
||||
s_backbuffer_height = _theight;
|
||||
|
||||
NSRect size;
|
||||
NSUInteger style = NSMiniaturizableWindowMask;
|
||||
NSOpenGLPixelFormatAttribute attr[2] = { NSOpenGLPFADoubleBuffer, 0 };
|
||||
NSOpenGLPixelFormat *fmt = [[NSOpenGLPixelFormat alloc]
|
||||
initWithAttributes: attr];
|
||||
if (fmt == nil) {
|
||||
ERROR_LOG(VIDEO, "failed to create pixel format");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
GLWin.cocoaCtx = [[NSOpenGLContext alloc]
|
||||
initWithFormat: fmt shareContext: nil];
|
||||
[fmt release];
|
||||
if (GLWin.cocoaCtx == nil) {
|
||||
ERROR_LOG(VIDEO, "failed to create context");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (SConfig::GetInstance().m_LocalCoreStartupParameter.bFullscreen) {
|
||||
size = [[NSScreen mainScreen] frame];
|
||||
style |= NSBorderlessWindowMask;
|
||||
} else {
|
||||
size = NSMakeRect(_tx, _ty, _twidth, _theight);
|
||||
style |= NSResizableWindowMask | NSTitledWindowMask;
|
||||
}
|
||||
|
||||
GLWin.cocoaWin = [[NSWindow alloc] initWithContentRect: size
|
||||
styleMask: style backing: NSBackingStoreBuffered defer: NO];
|
||||
if (GLWin.cocoaWin == nil) {
|
||||
ERROR_LOG(VIDEO, "failed to create window");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (SConfig::GetInstance().m_LocalCoreStartupParameter.bFullscreen) {
|
||||
CGDisplayCapture(CGMainDisplayID());
|
||||
[GLWin.cocoaWin setLevel: CGShieldingWindowLevel()];
|
||||
}
|
||||
|
||||
[GLWin.cocoaCtx setView: [GLWin.cocoaWin contentView]];
|
||||
[GLWin.cocoaWin makeKeyAndOrderFront: nil];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cInterfaceAGL::MakeCurrent()
|
||||
{
|
||||
[GLWin.cocoaCtx makeCurrentContext];
|
||||
return true;
|
||||
}
|
||||
|
||||
// Update window width, size and etc. Called from Render.cpp
|
||||
void cInterfaceAGL::Update()
|
||||
{
|
||||
int width, height;
|
||||
|
||||
width = [[GLWin.cocoaWin contentView] frame].size.width;
|
||||
height = [[GLWin.cocoaWin contentView] frame].size.height;
|
||||
if (width == s_backbuffer_width && height == s_backbuffer_height)
|
||||
return;
|
||||
|
||||
[GLWin.cocoaCtx setView: [GLWin.cocoaWin contentView]];
|
||||
[GLWin.cocoaCtx update];
|
||||
[GLWin.cocoaCtx makeCurrentContext];
|
||||
s_backbuffer_width = width;
|
||||
s_backbuffer_height = height;
|
||||
}
|
||||
|
||||
// Close backend
|
||||
void cInterfaceAGL::Shutdown()
|
||||
{
|
||||
[GLWin.cocoaWin close];
|
||||
[GLWin.cocoaCtx clearDrawable];
|
||||
[GLWin.cocoaCtx release];
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
// Copyright (C) 2003 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
#ifndef _INTERFACEAGL_H_
|
||||
#define _INTERFACEAGL_H_
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <GL/glew.h>
|
||||
#import <AppKit/AppKit.h>
|
||||
#endif
|
||||
|
||||
#include "InterfaceBase.h"
|
||||
|
||||
class cInterfaceAGL : public cInterfaceBase
|
||||
{
|
||||
public:
|
||||
void Swap();
|
||||
void UpdateFPSDisplay(const char *Text);
|
||||
bool Create(void *&window_handle);
|
||||
bool MakeCurrent();
|
||||
void Shutdown();
|
||||
};
|
||||
#endif
|
||||
|
|
@ -0,0 +1,190 @@
|
|||
// Copyright (C) 2003 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#include "Host.h"
|
||||
#include "RenderBase.h"
|
||||
|
||||
#include "../GLInterface.h"
|
||||
#include "EGL.h"
|
||||
|
||||
// Show the current FPS
|
||||
void cInterfaceEGL::UpdateFPSDisplay(const char *text)
|
||||
{
|
||||
XStoreName(GLWin.dpy, GLWin.win, text);
|
||||
}
|
||||
void cInterfaceEGL::Swap()
|
||||
{
|
||||
eglSwapBuffers(GLWin.egl_dpy, GLWin.egl_surf);
|
||||
}
|
||||
|
||||
// Create rendering window.
|
||||
// Call browser: Core.cpp:EmuThread() > main.cpp:Video_Initialize()
|
||||
bool cInterfaceEGL::Create(void *&window_handle)
|
||||
{
|
||||
int _tx, _ty, _twidth, _theight;
|
||||
Host_GetRenderWindowSize(_tx, _ty, _twidth, _theight);
|
||||
|
||||
// Control window size and picture scaling
|
||||
s_backbuffer_width = _twidth;
|
||||
s_backbuffer_height = _theight;
|
||||
|
||||
const char *s;
|
||||
EGLint egl_major, egl_minor;
|
||||
|
||||
GLWin.dpy = XOpenDisplay(NULL);
|
||||
|
||||
if (!GLWin.dpy) {
|
||||
printf("Error: couldn't open display\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
GLWin.egl_dpy = eglGetDisplay(GLWin.dpy);
|
||||
if (!GLWin.egl_dpy) {
|
||||
printf("Error: eglGetDisplay() failed\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!eglInitialize(GLWin.egl_dpy, &egl_major, &egl_minor)) {
|
||||
printf("Error: eglInitialize() failed\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
s = eglQueryString(GLWin.egl_dpy, EGL_VERSION);
|
||||
printf("EGL_VERSION = %s\n", s);
|
||||
|
||||
s = eglQueryString(GLWin.egl_dpy, EGL_VENDOR);
|
||||
printf("EGL_VENDOR = %s\n", s);
|
||||
|
||||
s = eglQueryString(GLWin.egl_dpy, EGL_EXTENSIONS);
|
||||
printf("EGL_EXTENSIONS = %s\n", s);
|
||||
|
||||
s = eglQueryString(GLWin.egl_dpy, EGL_CLIENT_APIS);
|
||||
printf("EGL_CLIENT_APIS = %s\n", s);
|
||||
|
||||
// attributes for a visual in RGBA format with at least
|
||||
// 8 bits per color and a 24 bit depth buffer
|
||||
int attribs[] = {
|
||||
EGL_RED_SIZE, 8,
|
||||
EGL_GREEN_SIZE, 8,
|
||||
EGL_BLUE_SIZE, 8,
|
||||
EGL_DEPTH_SIZE, 24,
|
||||
#ifdef USE_GLES
|
||||
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
|
||||
#else
|
||||
EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
|
||||
#endif
|
||||
EGL_NONE };
|
||||
|
||||
static const EGLint ctx_attribs[] = {
|
||||
#ifdef USE_GLES
|
||||
EGL_CONTEXT_CLIENT_VERSION, 2,
|
||||
#endif
|
||||
EGL_NONE
|
||||
};
|
||||
|
||||
GLWin.evdpy = XOpenDisplay(NULL);
|
||||
GLWin.parent = (Window)window_handle;
|
||||
GLWin.screen = DefaultScreen(GLWin.dpy);
|
||||
if (GLWin.parent == 0)
|
||||
GLWin.parent = RootWindow(GLWin.dpy, GLWin.screen);
|
||||
|
||||
XVisualInfo visTemplate;
|
||||
int num_visuals;
|
||||
EGLConfig config;
|
||||
EGLint num_configs;
|
||||
EGLint vid;
|
||||
|
||||
if (!eglChooseConfig( GLWin.egl_dpy, attribs, &config, 1, &num_configs)) {
|
||||
printf("Error: couldn't get an EGL visual config\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!eglGetConfigAttrib(GLWin.egl_dpy, config, EGL_NATIVE_VISUAL_ID, &vid)) {
|
||||
printf("Error: eglGetConfigAttrib() failed\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* The X window visual must match the EGL config */
|
||||
visTemplate.visualid = vid;
|
||||
GLWin.vi = XGetVisualInfo(GLWin.dpy, VisualIDMask, &visTemplate, &num_visuals);
|
||||
if (!GLWin.vi) {
|
||||
printf("Error: couldn't get X visual\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
GLWin.x = _tx;
|
||||
GLWin.y = _ty;
|
||||
GLWin.width = _twidth;
|
||||
GLWin.height = _theight;
|
||||
|
||||
XWindow.CreateXWindow();
|
||||
#ifdef USE_GLES
|
||||
eglBindAPI(EGL_OPENGL_ES_API);
|
||||
#else
|
||||
eglBindAPI(EGL_OPENGL_API);
|
||||
#endif
|
||||
GLWin.egl_ctx = eglCreateContext(GLWin.egl_dpy, config, EGL_NO_CONTEXT, ctx_attribs );
|
||||
if (!GLWin.egl_ctx) {
|
||||
printf("Error: eglCreateContext failed\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
GLWin.egl_surf = eglCreateWindowSurface(GLWin.egl_dpy, config, GLWin.win, NULL);
|
||||
if (!GLWin.egl_surf) {
|
||||
printf("Error: eglCreateWindowSurface failed\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!eglMakeCurrent(GLWin.egl_dpy, GLWin.egl_surf, GLWin.egl_surf, GLWin.egl_ctx)) {
|
||||
|
||||
printf("Error: eglMakeCurrent() failed\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
printf("GL_VENDOR: %s\n", glGetString(GL_VENDOR));
|
||||
printf("GL_RENDERER: %s\n", glGetString(GL_RENDERER));
|
||||
printf("GL_VERSION: %s\n", glGetString(GL_VERSION));
|
||||
printf("GL_EXTENSIONS: %s\n", glGetString(GL_EXTENSIONS));
|
||||
/* Set initial projection/viewing transformation.
|
||||
* We can't be sure we'll get a ConfigureNotify event when the window
|
||||
* first appears.
|
||||
*/
|
||||
glViewport(0, 0, (GLint) _twidth, (GLint) _theight);
|
||||
window_handle = (void *)GLWin.win;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cInterfaceEGL::MakeCurrent()
|
||||
{
|
||||
return eglMakeCurrent(GLWin.egl_dpy, GLWin.egl_surf, GLWin.egl_surf, GLWin.egl_ctx);
|
||||
}
|
||||
// Close backend
|
||||
void cInterfaceEGL::Shutdown()
|
||||
{
|
||||
XWindow.DestroyXWindow();
|
||||
if (GLWin.egl_ctx && !eglMakeCurrent(GLWin.egl_dpy, GLWin.egl_surf, GLWin.egl_surf, GLWin.egl_ctx))
|
||||
NOTICE_LOG(VIDEO, "Could not release drawing context.");
|
||||
if (GLWin.egl_ctx)
|
||||
{
|
||||
eglDestroyContext(GLWin.egl_dpy, GLWin.egl_ctx);
|
||||
eglDestroySurface(GLWin.egl_dpy, GLWin.egl_surf);
|
||||
eglTerminate(GLWin.egl_dpy);
|
||||
GLWin.egl_ctx = NULL;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
// Copyright (C) 2003 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
#ifndef _INTERFACEGLX_H_
|
||||
#define _INTERFACEGLX_H_
|
||||
|
||||
#include <EGL/egl.h>
|
||||
#ifdef USE_GLES
|
||||
#include <GLES2/gl2.h>
|
||||
#else
|
||||
#include <GL/glxew.h>
|
||||
#include <GL/gl.h>
|
||||
#endif
|
||||
|
||||
#include "X11_Util.h"
|
||||
#include "InterfaceBase.h"
|
||||
|
||||
class cInterfaceEGL : public cInterfaceBase
|
||||
{
|
||||
private:
|
||||
cX11Window XWindow;
|
||||
public:
|
||||
friend class cX11Window;
|
||||
void Swap();
|
||||
void UpdateFPSDisplay(const char *Text);
|
||||
bool Create(void *&window_handle);
|
||||
bool MakeCurrent();
|
||||
void Shutdown();
|
||||
};
|
||||
#endif
|
||||
|
|
@ -0,0 +1,151 @@
|
|||
// Copyright (C) 2003 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#include "Host.h"
|
||||
#include "RenderBase.h"
|
||||
#include "VideoConfig.h"
|
||||
|
||||
#include "../GLInterface.h"
|
||||
#include "GLX.h"
|
||||
|
||||
// Show the current FPS
|
||||
void cInterfaceGLX::UpdateFPSDisplay(const char *text)
|
||||
{
|
||||
XStoreName(GLWin.dpy, GLWin.win, text);
|
||||
}
|
||||
void cInterfaceGLX::Swap()
|
||||
{
|
||||
glXSwapBuffers(GLWin.dpy, GLWin.win);
|
||||
}
|
||||
|
||||
// Create rendering window.
|
||||
// Call browser: Core.cpp:EmuThread() > main.cpp:Video_Initialize()
|
||||
bool cInterfaceGLX::Create(void *&window_handle)
|
||||
{
|
||||
int _tx, _ty, _twidth, _theight;
|
||||
Host_GetRenderWindowSize(_tx, _ty, _twidth, _theight);
|
||||
|
||||
// Control window size and picture scaling
|
||||
s_backbuffer_width = _twidth;
|
||||
s_backbuffer_height = _theight;
|
||||
|
||||
int glxMajorVersion, glxMinorVersion;
|
||||
|
||||
// attributes for a single buffered visual in RGBA format with at least
|
||||
// 8 bits per color and a 24 bit depth buffer
|
||||
int attrListSgl[] = {GLX_RGBA, GLX_RED_SIZE, 8,
|
||||
GLX_GREEN_SIZE, 8,
|
||||
GLX_BLUE_SIZE, 8,
|
||||
GLX_DEPTH_SIZE, 24,
|
||||
None};
|
||||
|
||||
// attributes for a double buffered visual in RGBA format with at least
|
||||
// 8 bits per color and a 24 bit depth buffer
|
||||
int attrListDbl[] = {GLX_RGBA, GLX_DOUBLEBUFFER,
|
||||
GLX_RED_SIZE, 8,
|
||||
GLX_GREEN_SIZE, 8,
|
||||
GLX_BLUE_SIZE, 8,
|
||||
GLX_DEPTH_SIZE, 24,
|
||||
GLX_SAMPLE_BUFFERS_ARB, g_Config.iMultisampleMode != MULTISAMPLE_OFF?1:0,
|
||||
GLX_SAMPLES_ARB, g_Config.iMultisampleMode != MULTISAMPLE_OFF?1:0,
|
||||
None };
|
||||
|
||||
int attrListDefault[] = {
|
||||
GLX_RGBA,
|
||||
GLX_RED_SIZE, 1,
|
||||
GLX_GREEN_SIZE, 1,
|
||||
GLX_BLUE_SIZE, 1,
|
||||
GLX_DOUBLEBUFFER,
|
||||
GLX_DEPTH_SIZE, 1,
|
||||
None };
|
||||
|
||||
GLWin.dpy = XOpenDisplay(0);
|
||||
GLWin.evdpy = XOpenDisplay(0);
|
||||
GLWin.parent = (Window)window_handle;
|
||||
GLWin.screen = DefaultScreen(GLWin.dpy);
|
||||
if (GLWin.parent == 0)
|
||||
GLWin.parent = RootWindow(GLWin.dpy, GLWin.screen);
|
||||
|
||||
glXQueryVersion(GLWin.dpy, &glxMajorVersion, &glxMinorVersion);
|
||||
NOTICE_LOG(VIDEO, "glX-Version %d.%d", glxMajorVersion, glxMinorVersion);
|
||||
|
||||
// Get an appropriate visual
|
||||
GLWin.vi = glXChooseVisual(GLWin.dpy, GLWin.screen, attrListDbl);
|
||||
if (GLWin.vi == NULL)
|
||||
{
|
||||
GLWin.vi = glXChooseVisual(GLWin.dpy, GLWin.screen, attrListSgl);
|
||||
if (GLWin.vi != NULL)
|
||||
{
|
||||
ERROR_LOG(VIDEO, "Only single buffered visual!");
|
||||
}
|
||||
else
|
||||
{
|
||||
GLWin.vi = glXChooseVisual(GLWin.dpy, GLWin.screen, attrListDefault);
|
||||
if (GLWin.vi == NULL)
|
||||
{
|
||||
ERROR_LOG(VIDEO, "Could not choose visual (glXChooseVisual)");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
NOTICE_LOG(VIDEO, "Got double buffered visual!");
|
||||
|
||||
// Create a GLX context.
|
||||
GLWin.ctx = glXCreateContext(GLWin.dpy, GLWin.vi, 0, GL_TRUE);
|
||||
if (!GLWin.ctx)
|
||||
{
|
||||
PanicAlert("Unable to create GLX context.");
|
||||
return false;
|
||||
}
|
||||
|
||||
GLWin.x = _tx;
|
||||
GLWin.y = _ty;
|
||||
GLWin.width = _twidth;
|
||||
GLWin.height = _theight;
|
||||
|
||||
XWindow.CreateXWindow();
|
||||
window_handle = (void *)GLWin.win;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cInterfaceGLX::MakeCurrent()
|
||||
{
|
||||
// connect the glx-context to the window
|
||||
#if defined(HAVE_WX) && (HAVE_WX)
|
||||
Host_GetRenderWindowSize(GLWin.x, GLWin.y,
|
||||
(int&)GLWin.width, (int&)GLWin.height);
|
||||
XMoveResizeWindow(GLWin.dpy, GLWin.win, GLWin.x, GLWin.y,
|
||||
GLWin.width, GLWin.height);
|
||||
#endif
|
||||
return glXMakeCurrent(GLWin.dpy, GLWin.win, GLWin.ctx);
|
||||
}
|
||||
// Close backend
|
||||
void cInterfaceGLX::Shutdown()
|
||||
{
|
||||
XWindow.DestroyXWindow();
|
||||
if (GLWin.ctx && !glXMakeCurrent(GLWin.dpy, None, NULL))
|
||||
NOTICE_LOG(VIDEO, "Could not release drawing context.");
|
||||
if (GLWin.ctx)
|
||||
{
|
||||
glXDestroyContext(GLWin.dpy, GLWin.ctx);
|
||||
XCloseDisplay(GLWin.dpy);
|
||||
XCloseDisplay(GLWin.evdpy);
|
||||
GLWin.ctx = NULL;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
// Copyright (C) 2003 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
#ifndef _INTERFACEGLX_H_
|
||||
#define _INTERFACEGLX_H_
|
||||
|
||||
#include <GL/glxew.h>
|
||||
#include <GL/gl.h>
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/keysym.h>
|
||||
|
||||
#include "X11_Util.h"
|
||||
#include "InterfaceBase.h"
|
||||
|
||||
class cInterfaceGLX : public cInterfaceBase
|
||||
{
|
||||
private:
|
||||
cX11Window XWindow;
|
||||
public:
|
||||
friend class cX11Window;
|
||||
void Swap();
|
||||
void UpdateFPSDisplay(const char *Text);
|
||||
bool Create(void *&window_handle);
|
||||
bool MakeCurrent();
|
||||
void Shutdown();
|
||||
};
|
||||
#endif
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
// Copyright (C) 2003 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
#ifndef _GLINTERFACEBASE_H_
|
||||
#define _GLINTERFACEBASE_H_
|
||||
class cInterfaceBase
|
||||
{
|
||||
protected:
|
||||
// Window dimensions.
|
||||
u32 s_backbuffer_width;
|
||||
u32 s_backbuffer_height;
|
||||
public:
|
||||
virtual void Swap() = 0;
|
||||
virtual void UpdateFPSDisplay(const char *Text) = 0;
|
||||
virtual bool Create(void *&window_handle) = 0;
|
||||
virtual bool MakeCurrent() = 0;
|
||||
virtual void Shutdown() = 0;
|
||||
|
||||
virtual u32 GetBackBufferWidth() { return s_backbuffer_width; }
|
||||
virtual u32 GetBackBufferHeight() { return s_backbuffer_height; }
|
||||
virtual void SetBackBufferDimensions(u32 W, u32 H) {s_backbuffer_width = W; s_backbuffer_height = H; }
|
||||
virtual void Update() { }
|
||||
virtual bool PeekMessages() { return false; }
|
||||
};
|
||||
#endif
|
|
@ -0,0 +1,179 @@
|
|||
// Copyright (C) 2003 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#include "VideoConfig.h"
|
||||
#include "Host.h"
|
||||
#include "RenderBase.h"
|
||||
|
||||
#include "VertexShaderManager.h"
|
||||
#include "../GLInterface.h"
|
||||
#include "WGL.h"
|
||||
|
||||
#include "EmuWindow.h"
|
||||
static HDC hDC = NULL; // Private GDI Device Context
|
||||
static HGLRC hRC = NULL; // Permanent Rendering Context
|
||||
|
||||
void cInterfaceWGL::Swap()
|
||||
{
|
||||
SwapBuffers(hDC);
|
||||
}
|
||||
|
||||
// Draw messages on top of the screen
|
||||
bool cInterfaceWGL::PeekMessages()
|
||||
{
|
||||
// TODO: peekmessage
|
||||
MSG msg;
|
||||
while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
|
||||
{
|
||||
if (msg.message == WM_QUIT)
|
||||
return FALSE;
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// Show the current FPS
|
||||
void cInterfaceWGL::UpdateFPSDisplay(const char *text)
|
||||
{
|
||||
TCHAR temp[512];
|
||||
swprintf_s(temp, sizeof(temp)/sizeof(TCHAR), _T("%hs"), text);
|
||||
EmuWindow::SetWindowText(temp);
|
||||
}
|
||||
|
||||
// Create rendering window.
|
||||
// Call browser: Core.cpp:EmuThread() > main.cpp:Video_Initialize()
|
||||
bool cInterfaceWGL::Create(void *&window_handle)
|
||||
{
|
||||
int _tx, _ty, _twidth, _theight;
|
||||
Host_GetRenderWindowSize(_tx, _ty, _twidth, _theight);
|
||||
|
||||
// Control window size and picture scaling
|
||||
s_backbuffer_width = _twidth;
|
||||
s_backbuffer_height = _theight;
|
||||
|
||||
window_handle = (void*)EmuWindow::Create((HWND)window_handle, GetModuleHandle(0), _T("Please wait..."));
|
||||
if (window_handle == NULL)
|
||||
{
|
||||
Host_SysMessage("failed to create window");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Show the window
|
||||
EmuWindow::Show();
|
||||
|
||||
PIXELFORMATDESCRIPTOR pfd = // pfd Tells Windows How We Want Things To Be
|
||||
{
|
||||
sizeof(PIXELFORMATDESCRIPTOR), // Size Of This Pixel Format Descriptor
|
||||
1, // Version Number
|
||||
PFD_DRAW_TO_WINDOW | // Format Must Support Window
|
||||
PFD_SUPPORT_OPENGL | // Format Must Support OpenGL
|
||||
PFD_DOUBLEBUFFER, // Must Support Double Buffering
|
||||
PFD_TYPE_RGBA, // Request An RGBA Format
|
||||
32, // Select Our Color Depth
|
||||
0, 0, 0, 0, 0, 0, // Color Bits Ignored
|
||||
0, // 8bit Alpha Buffer
|
||||
0, // Shift Bit Ignored
|
||||
0, // No Accumulation Buffer
|
||||
0, 0, 0, 0, // Accumulation Bits Ignored
|
||||
24, // 24Bit Z-Buffer (Depth Buffer)
|
||||
8, // 8bit Stencil Buffer
|
||||
0, // No Auxiliary Buffer
|
||||
PFD_MAIN_PLANE, // Main Drawing Layer
|
||||
0, // Reserved
|
||||
0, 0, 0 // Layer Masks Ignored
|
||||
};
|
||||
|
||||
GLuint PixelFormat; // Holds The Results After Searching For A Match
|
||||
|
||||
if (!(hDC=GetDC(EmuWindow::GetWnd()))) {
|
||||
PanicAlert("(1) Can't create an OpenGL Device context. Fail.");
|
||||
return false;
|
||||
}
|
||||
if (!(PixelFormat = ChoosePixelFormat(hDC, &pfd))) {
|
||||
PanicAlert("(2) Can't find a suitable PixelFormat.");
|
||||
return false;
|
||||
}
|
||||
if (!SetPixelFormat(hDC, PixelFormat, &pfd)) {
|
||||
PanicAlert("(3) Can't set the PixelFormat.");
|
||||
return false;
|
||||
}
|
||||
if (!(hRC = wglCreateContext(hDC))) {
|
||||
PanicAlert("(4) Can't create an OpenGL rendering context.");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cInterfaceWGL::MakeCurrent()
|
||||
{
|
||||
return wglMakeCurrent(hDC, hRC) ? true : false;
|
||||
}
|
||||
|
||||
// Update window width, size and etc. Called from Render.cpp
|
||||
void cInterfaceWGL::Update()
|
||||
{
|
||||
RECT rcWindow;
|
||||
if (!EmuWindow::GetParentWnd())
|
||||
{
|
||||
// We are not rendering to a child window - use client size.
|
||||
GetClientRect(EmuWindow::GetWnd(), &rcWindow);
|
||||
}
|
||||
else
|
||||
{
|
||||
// We are rendering to a child window - use parent size.
|
||||
GetWindowRect(EmuWindow::GetParentWnd(), &rcWindow);
|
||||
}
|
||||
|
||||
// Get the new window width and height
|
||||
// See below for documentation
|
||||
int width = rcWindow.right - rcWindow.left;
|
||||
int height = rcWindow.bottom - rcWindow.top;
|
||||
|
||||
// If we are rendering to a child window
|
||||
if (EmuWindow::GetParentWnd() != 0 &&
|
||||
(s_backbuffer_width != width || s_backbuffer_height != height) &&
|
||||
width >= 4 && height >= 4)
|
||||
{
|
||||
::MoveWindow(EmuWindow::GetWnd(), 0, 0, width, height, FALSE);
|
||||
s_backbuffer_width = width;
|
||||
s_backbuffer_height = height;
|
||||
}
|
||||
}
|
||||
|
||||
// Close backend
|
||||
void cInterfaceWGL::Shutdown()
|
||||
{
|
||||
if (hRC)
|
||||
{
|
||||
if (!wglMakeCurrent(NULL, NULL))
|
||||
NOTICE_LOG(VIDEO, "Could not release drawing context.");
|
||||
|
||||
if (!wglDeleteContext(hRC))
|
||||
ERROR_LOG(VIDEO, "Release Rendering Context Failed.");
|
||||
|
||||
hRC = NULL;
|
||||
}
|
||||
|
||||
if (hDC && !ReleaseDC(EmuWindow::GetWnd(), hDC))
|
||||
{
|
||||
ERROR_LOG(VIDEO, "Release Device Context Failed.");
|
||||
hDC = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
// Copyright (C) 2003 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
#ifndef _INTERFACEWGL_H_
|
||||
#define _INTERFACEWGL_H_
|
||||
|
||||
#ifdef _WIN32
|
||||
#define GLEW_STATIC
|
||||
#include <GL/glew.h>
|
||||
#include <GL/wglew.h>
|
||||
#endif
|
||||
|
||||
#include "InterfaceBase.h"
|
||||
|
||||
class cInterfaceWGL : public cInterfaceBase
|
||||
{
|
||||
public:
|
||||
void Swap();
|
||||
void UpdateFPSDisplay(const char *Text);
|
||||
bool Create(void *&window_handle);
|
||||
bool MakeCurrent();
|
||||
void Shutdown();
|
||||
|
||||
void Update();
|
||||
bool PeekMessages();
|
||||
};
|
||||
#endif
|
||||
|
|
@ -0,0 +1,82 @@
|
|||
// Copyright (C) 2003 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#include "VideoConfig.h"
|
||||
#include "Host.h"
|
||||
#include "RenderBase.h"
|
||||
|
||||
#include "VertexShaderManager.h"
|
||||
#include "../GLInterface.h"
|
||||
#include "WX.h"
|
||||
|
||||
void cInterfaceWX::Swap()
|
||||
{
|
||||
GLWin.glCanvas->SwapBuffers();
|
||||
}
|
||||
|
||||
void cInterfaceWX::UpdateFPSDisplay(const char *text)
|
||||
{
|
||||
// Handled by Host_UpdateTitle()
|
||||
}
|
||||
|
||||
// Create rendering window.
|
||||
// Call browser: Core.cpp:EmuThread() > main.cpp:Video_Initialize()
|
||||
bool cInterfaceWX::Create(void *&window_handle)
|
||||
{
|
||||
int _tx, _ty, _twidth, _theight;
|
||||
Host_GetRenderWindowSize(_tx, _ty, _twidth, _theight);
|
||||
|
||||
// Control window size and picture scaling
|
||||
s_backbuffer_width = _twidth;
|
||||
s_backbuffer_height = _theight;
|
||||
|
||||
GLWin.panel = (wxPanel *)window_handle;
|
||||
GLWin.glCanvas = new wxGLCanvas(GLWin.panel, wxID_ANY, NULL,
|
||||
wxPoint(0, 0), wxSize(_twidth, _theight));
|
||||
GLWin.glCanvas->Show(true);
|
||||
if (GLWin.glCtxt == NULL) // XXX dirty hack
|
||||
GLWin.glCtxt = new wxGLContext(GLWin.glCanvas);
|
||||
}
|
||||
|
||||
bool cInterfaceWX::MakeCurrent()
|
||||
{
|
||||
return GLWin.glCanvas->SetCurrent(*GLWin.glCtxt);
|
||||
}
|
||||
|
||||
// Update window width, size and etc. Called from Render.cpp
|
||||
void cInterfaceWX::Update()
|
||||
{
|
||||
int width, height;
|
||||
|
||||
GLWin.panel->GetSize(&width, &height);
|
||||
if (width == s_backbuffer_width && height == s_backbuffer_height)
|
||||
return;
|
||||
|
||||
GLWin.glCanvas->SetFocus();
|
||||
GLWin.glCanvas->SetSize(0, 0, width, height);
|
||||
GLWin.glCtxt->SetCurrent(*GLWin.glCanvas);
|
||||
s_backbuffer_width = width;
|
||||
s_backbuffer_height = height;
|
||||
}
|
||||
|
||||
// Close backend
|
||||
void cInterfaceWX::Shutdown()
|
||||
{
|
||||
GLWin.glCanvas->Hide();
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
// Copyright (C) 2003 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
#ifndef _INTERFACEWX_H_
|
||||
#define _INTERFACEWX_H_
|
||||
|
||||
#if defined HAVE_X11 && HAVE_X11
|
||||
#include <GL/glxew.h>
|
||||
#include <GL/gl.h>
|
||||
#elif defined __APPLE__
|
||||
#include <GL/glew.h>
|
||||
#import <AppKit/AppKit.h>
|
||||
#endif
|
||||
|
||||
#if defined USE_WX && USE_WX
|
||||
#include "wx/wx.h"
|
||||
#include "wx/glcanvas.h"
|
||||
#endif
|
||||
|
||||
#include "InterfaceBase.h"
|
||||
|
||||
class cInterfaceWX : public cInterfaceBase
|
||||
{
|
||||
public:
|
||||
void Swap();
|
||||
void UpdateFPSDisplay(const char *Text);
|
||||
bool Create(void *&window_handle);
|
||||
bool MakeCurrent();
|
||||
void Shutdown();
|
||||
|
||||
void Update();
|
||||
};
|
||||
#endif
|
||||
|
|
@ -0,0 +1,213 @@
|
|||
// Copyright (C) 2003 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#include "Host.h"
|
||||
#include "RenderBase.h"
|
||||
#include "VideoConfig.h"
|
||||
#include "../GLInterface.h"
|
||||
#include "VertexShaderManager.h"
|
||||
|
||||
void cX11Window::CreateXWindow(void)
|
||||
{
|
||||
Atom wmProtocols[1];
|
||||
|
||||
// Setup window attributes
|
||||
GLWin.attr.colormap = XCreateColormap(GLWin.evdpy,
|
||||
GLWin.parent, GLWin.vi->visual, AllocNone);
|
||||
GLWin.attr.event_mask = KeyPressMask | StructureNotifyMask | FocusChangeMask;
|
||||
GLWin.attr.background_pixel = BlackPixel(GLWin.evdpy, GLWin.screen);
|
||||
GLWin.attr.border_pixel = 0;
|
||||
|
||||
// Create the window
|
||||
GLWin.win = XCreateWindow(GLWin.evdpy, GLWin.parent,
|
||||
GLWin.x, GLWin.y, GLWin.width, GLWin.height, 0,
|
||||
GLWin.vi->depth, InputOutput, GLWin.vi->visual,
|
||||
CWBorderPixel | CWBackPixel | CWColormap | CWEventMask, &GLWin.attr);
|
||||
wmProtocols[0] = XInternAtom(GLWin.evdpy, "WM_DELETE_WINDOW", True);
|
||||
XSetWMProtocols(GLWin.evdpy, GLWin.win, wmProtocols, 1);
|
||||
XSetStandardProperties(GLWin.evdpy, GLWin.win, "GPU", "GPU", None, NULL, 0, NULL);
|
||||
XMapRaised(GLWin.evdpy, GLWin.win);
|
||||
XSync(GLWin.evdpy, True);
|
||||
|
||||
GLWin.xEventThread = std::thread(&cX11Window::XEventThread, this);
|
||||
}
|
||||
|
||||
void cX11Window::DestroyXWindow(void)
|
||||
{
|
||||
XUnmapWindow(GLWin.dpy, GLWin.win);
|
||||
GLWin.win = 0;
|
||||
if (GLWin.xEventThread.joinable())
|
||||
GLWin.xEventThread.join();
|
||||
XFreeColormap(GLWin.evdpy, GLWin.attr.colormap);
|
||||
}
|
||||
|
||||
void cX11Window::XEventThread()
|
||||
{
|
||||
// Free look variables
|
||||
static bool mouseLookEnabled = false;
|
||||
static bool mouseMoveEnabled = false;
|
||||
static float lastMouse[2];
|
||||
while (GLWin.win)
|
||||
{
|
||||
XEvent event;
|
||||
KeySym key;
|
||||
for (int num_events = XPending(GLWin.evdpy); num_events > 0; num_events--)
|
||||
{
|
||||
XNextEvent(GLWin.evdpy, &event);
|
||||
switch(event.type) {
|
||||
case KeyPress:
|
||||
key = XLookupKeysym((XKeyEvent*)&event, 0);
|
||||
switch (key)
|
||||
{
|
||||
case XK_3:
|
||||
OSDChoice = 1;
|
||||
// Toggle native resolution
|
||||
g_Config.iEFBScale = g_Config.iEFBScale + 1;
|
||||
if (g_Config.iEFBScale > 7) g_Config.iEFBScale = 0;
|
||||
break;
|
||||
case XK_4:
|
||||
OSDChoice = 2;
|
||||
// Toggle aspect ratio
|
||||
g_Config.iAspectRatio = (g_Config.iAspectRatio + 1) & 3;
|
||||
break;
|
||||
case XK_5:
|
||||
OSDChoice = 3;
|
||||
// Toggle EFB copy
|
||||
if (!g_Config.bEFBCopyEnable || g_Config.bCopyEFBToTexture)
|
||||
{
|
||||
g_Config.bEFBCopyEnable ^= true;
|
||||
g_Config.bCopyEFBToTexture = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_Config.bCopyEFBToTexture = !g_Config.bCopyEFBToTexture;
|
||||
}
|
||||
break;
|
||||
case XK_6:
|
||||
OSDChoice = 4;
|
||||
g_Config.bDisableFog = !g_Config.bDisableFog;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (g_Config.bFreeLook)
|
||||
{
|
||||
static float debugSpeed = 1.0f;
|
||||
switch (key)
|
||||
{
|
||||
case XK_parenleft:
|
||||
debugSpeed /= 2.0f;
|
||||
break;
|
||||
case XK_parenright:
|
||||
debugSpeed *= 2.0f;
|
||||
break;
|
||||
case XK_w:
|
||||
VertexShaderManager::TranslateView(0.0f, debugSpeed);
|
||||
break;
|
||||
case XK_s:
|
||||
VertexShaderManager::TranslateView(0.0f, -debugSpeed);
|
||||
break;
|
||||
case XK_a:
|
||||
VertexShaderManager::TranslateView(debugSpeed, 0.0f);
|
||||
break;
|
||||
case XK_d:
|
||||
VertexShaderManager::TranslateView(-debugSpeed, 0.0f);
|
||||
break;
|
||||
case XK_r:
|
||||
VertexShaderManager::ResetView();
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ButtonPress:
|
||||
if (g_Config.bFreeLook)
|
||||
{
|
||||
switch (event.xbutton.button)
|
||||
{
|
||||
case 2: // Middle button
|
||||
lastMouse[0] = event.xbutton.x;
|
||||
lastMouse[1] = event.xbutton.y;
|
||||
mouseMoveEnabled = true;
|
||||
break;
|
||||
case 3: // Right button
|
||||
lastMouse[0] = event.xbutton.x;
|
||||
lastMouse[1] = event.xbutton.y;
|
||||
mouseLookEnabled = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ButtonRelease:
|
||||
if (g_Config.bFreeLook)
|
||||
{
|
||||
switch (event.xbutton.button)
|
||||
{
|
||||
case 2: // Middle button
|
||||
mouseMoveEnabled = false;
|
||||
break;
|
||||
case 3: // Right button
|
||||
mouseLookEnabled = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MotionNotify:
|
||||
if (g_Config.bFreeLook)
|
||||
{
|
||||
if (mouseLookEnabled)
|
||||
{
|
||||
VertexShaderManager::RotateView((event.xmotion.x - lastMouse[0]) / 200.0f,
|
||||
(event.xmotion.y - lastMouse[1]) / 200.0f);
|
||||
lastMouse[0] = event.xmotion.x;
|
||||
lastMouse[1] = event.xmotion.y;
|
||||
}
|
||||
|
||||
if (mouseMoveEnabled)
|
||||
{
|
||||
VertexShaderManager::TranslateView((event.xmotion.x - lastMouse[0]) / 50.0f,
|
||||
(event.xmotion.y - lastMouse[1]) / 50.0f);
|
||||
lastMouse[0] = event.xmotion.x;
|
||||
lastMouse[1] = event.xmotion.y;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ConfigureNotify:
|
||||
Window winDummy;
|
||||
unsigned int borderDummy, depthDummy;
|
||||
XGetGeometry(GLWin.evdpy, GLWin.win, &winDummy, &GLWin.x, &GLWin.y,
|
||||
&GLWin.width, &GLWin.height, &borderDummy, &depthDummy);
|
||||
GLInterface->SetBackBufferDimensions(GLWin.width, GLWin.height);
|
||||
break;
|
||||
case ClientMessage:
|
||||
if ((unsigned long) event.xclient.data.l[0] ==
|
||||
XInternAtom(GLWin.evdpy, "WM_DELETE_WINDOW", False))
|
||||
Host_Message(WM_USER_STOP);
|
||||
if ((unsigned long) event.xclient.data.l[0] ==
|
||||
XInternAtom(GLWin.evdpy, "RESIZE", False))
|
||||
XMoveResizeWindow(GLWin.evdpy, GLWin.win,
|
||||
event.xclient.data.l[1], event.xclient.data.l[2],
|
||||
event.xclient.data.l[3], event.xclient.data.l[4]);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
Common::SleepCurrentThread(20);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
// Copyright (C) 2003 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
#ifndef _X11_UTIL_H_
|
||||
#define _X11_UTIL_H_
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/keysym.h>
|
||||
|
||||
class cX11Window
|
||||
{
|
||||
private:
|
||||
void XEventThread();
|
||||
public:
|
||||
void CreateXWindow(void);
|
||||
void DestroyXWindow(void);
|
||||
};
|
||||
#endif
|
|
@ -322,9 +322,11 @@ void CGameListCtrl::Update()
|
|||
}
|
||||
|
||||
// Sort items by Title
|
||||
if (!sorted)
|
||||
last_column = 0;
|
||||
sorted = false;
|
||||
wxListEvent event;
|
||||
event.m_col = SConfig::GetInstance().m_ListSort2;
|
||||
last_column = 1;
|
||||
OnColumnClick(event);
|
||||
|
||||
event.m_col = SConfig::GetInstance().m_ListSort;
|
||||
|
@ -711,20 +713,25 @@ void CGameListCtrl::OnColumnClick(wxListEvent& event)
|
|||
if(event.GetColumn() != COLUMN_BANNER)
|
||||
{
|
||||
int current_column = event.GetColumn();
|
||||
|
||||
if (last_column == current_column)
|
||||
if (sorted)
|
||||
{
|
||||
last_sort = -last_sort;
|
||||
if (last_column == current_column)
|
||||
{
|
||||
last_sort = -last_sort;
|
||||
}
|
||||
else
|
||||
{
|
||||
SConfig::GetInstance().m_ListSort2 = last_sort;
|
||||
last_column = current_column;
|
||||
last_sort = current_column;
|
||||
}
|
||||
SConfig::GetInstance().m_ListSort = last_sort;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (sorted)
|
||||
SConfig::GetInstance().m_ListSort2 = last_sort;
|
||||
last_column = current_column;
|
||||
last_sort = current_column;
|
||||
last_column = current_column;
|
||||
}
|
||||
if (sorted)
|
||||
SConfig::GetInstance().m_ListSort = last_sort;
|
||||
caller = this;
|
||||
SortItems(wxListCompare, last_sort);
|
||||
}
|
||||
|
@ -921,7 +928,8 @@ void CGameListCtrl::OnRightClick(wxMouseEvent& event)
|
|||
{
|
||||
if (selected_iso->IsCompressed())
|
||||
popupMenu->Append(IDM_COMPRESSGCM, _("Decompress ISO..."));
|
||||
else
|
||||
else if (selected_iso->GetFileName().substr(selected_iso->GetFileName().find_last_of(".")) != ".ciso"
|
||||
&& selected_iso->GetFileName().substr(selected_iso->GetFileName().find_last_of(".")) != ".wbfs")
|
||||
popupMenu->Append(IDM_COMPRESSGCM, _("Compress ISO..."));
|
||||
} else
|
||||
popupMenu->Append(IDM_LIST_INSTALLWAD, _("Install to Wii Menu"));
|
||||
|
|
|
@ -45,6 +45,15 @@
|
|||
|
||||
#include <wx/intl.h>
|
||||
|
||||
// Nvidia drivers >= v302 will check if the application exports a global
|
||||
// variable named NvOptimusEnablement to know if it should run the app in high
|
||||
// performance graphics mode or using the IGP.
|
||||
#ifdef WIN32
|
||||
extern "C" {
|
||||
__declspec(dllexport) DWORD NvOptimusEnablement = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
// ------------
|
||||
// Main window
|
||||
|
||||
|
|
|
@ -236,7 +236,7 @@ bool GetConfig(const int &type)
|
|||
case CONFIG_DISABLEFOG:
|
||||
return g_ActiveConfig.bDisableFog;
|
||||
case CONFIG_SHOWEFBREGIONS:
|
||||
return false;
|
||||
return g_ActiveConfig.bShowEFBCopyRegions;
|
||||
default:
|
||||
PanicAlert("GetConfig Error: Unknown Config Type!");
|
||||
return false;
|
||||
|
|
|
@ -34,9 +34,9 @@
|
|||
|
||||
using namespace BPFunctions;
|
||||
|
||||
u32 mapTexAddress;
|
||||
bool mapTexFound;
|
||||
int numWrites;
|
||||
static u32 mapTexAddress;
|
||||
static bool mapTexFound;
|
||||
static int numWrites;
|
||||
|
||||
extern volatile bool g_bSkipCurrentFrame;
|
||||
|
||||
|
@ -81,6 +81,9 @@ void BPWritten(const BPCmd& bp)
|
|||
just stuff geometry in them and don't put state changes there
|
||||
----------------------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
// check for invalid state, else unneeded configuration are built
|
||||
g_video_backend->CheckInvalidState();
|
||||
|
||||
// Debugging only, this lets you skip a bp update
|
||||
//static int times = 0;
|
||||
|
|
|
@ -180,6 +180,7 @@ void VideoBackendHardware::InitializeShared()
|
|||
memset((void*)&s_beginFieldArgs, 0, sizeof(s_beginFieldArgs));
|
||||
memset(&s_accessEFBArgs, 0, sizeof(s_accessEFBArgs));
|
||||
s_AccessEFBResult = 0;
|
||||
m_invalid = false;
|
||||
}
|
||||
|
||||
// Run from the CPU thread
|
||||
|
@ -198,16 +199,25 @@ void VideoBackendHardware::DoState(PointerWrap& p)
|
|||
// Refresh state.
|
||||
if (p.GetMode() == PointerWrap::MODE_READ)
|
||||
{
|
||||
BPReload();
|
||||
m_invalid = true;
|
||||
RecomputeCachedArraybases();
|
||||
|
||||
// Clear all caches that touch RAM
|
||||
// (? these don't appear to touch any emulation state that gets saved. moved to on load only.)
|
||||
TextureCache::Invalidate();
|
||||
VertexLoaderManager::MarkAllDirty();
|
||||
}
|
||||
}
|
||||
|
||||
void VideoBackendHardware::CheckInvalidState() {
|
||||
if (m_invalid)
|
||||
{
|
||||
m_invalid = false;
|
||||
|
||||
BPReload();
|
||||
TextureCache::Invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
void VideoBackendHardware::PauseAndLock(bool doLock, bool unpauseOnUnlock)
|
||||
{
|
||||
Fifo_PauseAndLock(doLock, unpauseOnUnlock);
|
||||
|
|
|
@ -377,7 +377,7 @@ TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int stage,
|
|||
//
|
||||
// TODO: Don't we need to force texture decoding to RGBA8 for dynamic EFB copies?
|
||||
// TODO: Actually, it should be enough if the internal texture format matches...
|
||||
if ((entry->type == TCET_NORMAL && width == entry->native_width && height == entry->native_height && full_format == entry->format && entry->num_mipmaps == maxlevel)
|
||||
if ((entry->type == TCET_NORMAL && width == entry->virtual_width && height == entry->virtual_height && full_format == entry->format && entry->num_mipmaps == maxlevel)
|
||||
|| (entry->type == TCET_EC_DYNAMIC && entry->native_width == width && entry->native_height == height))
|
||||
{
|
||||
// reuse the texture
|
||||
|
@ -396,14 +396,21 @@ TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int stage,
|
|||
pcfmt = LoadCustomTexture(tex_hash, texformat, 0, width, height);
|
||||
if (pcfmt != PC_TEX_FMT_NONE)
|
||||
{
|
||||
expandedWidth = width;
|
||||
expandedHeight = height;
|
||||
if (expandedWidth != width || expandedHeight != height)
|
||||
{
|
||||
expandedWidth = width;
|
||||
expandedHeight = height;
|
||||
|
||||
// If we thought we could reuse the texture before, make sure to delete it now!
|
||||
delete entry;
|
||||
entry = NULL;
|
||||
}
|
||||
using_custom_texture = true;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: RGBA8 textures are stored non-continuously in tmem, that might cause problems when preloading is enabled
|
||||
if (pcfmt == PC_TEX_FMT_NONE)
|
||||
// TODO: RGBA8 textures are stored non-continuously in tmem, that might cause problems here when preloading is enabled
|
||||
if (!using_custom_texture)
|
||||
pcfmt = TexDecoder_Decode(temp, src_data, expandedWidth,
|
||||
expandedHeight, texformat, tlutaddr, tlutfmt, g_ActiveConfig.backend_info.bUseRGBATextures);
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include "NativeVertexFormat.h"
|
||||
#include "TextureCacheBase.h"
|
||||
#include "RenderBase.h"
|
||||
#include "BPStructs.h"
|
||||
|
||||
#include "VertexManagerBase.h"
|
||||
#include "VideoConfig.h"
|
||||
|
@ -159,6 +160,9 @@ void VertexManager::AddVertices(int primitive, int numVertices)
|
|||
|
||||
void VertexManager::Flush()
|
||||
{
|
||||
// loading a state will invalidate BP, so check for it
|
||||
g_video_backend->CheckInvalidState();
|
||||
|
||||
g_vertex_manager->vFlush();
|
||||
}
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
add_subdirectory(Plugin_VideoOGL)
|
||||
if(NOT USE_GLES)
|
||||
add_subdirectory(Plugin_VideoOGL)
|
||||
endif()
|
||||
add_subdirectory(Plugin_VideoSoftware)
|
||||
# TODO: Add other backends here!
|
||||
|
|
|
@ -12,11 +12,22 @@ set(SRCS Src/FramebufferManager.cpp
|
|||
Src/VertexManager.cpp)
|
||||
|
||||
set(LIBS videocommon
|
||||
GLEW
|
||||
SOIL
|
||||
common
|
||||
${OPENGL_LIBRARIES}
|
||||
${X11_LIBRARIES})
|
||||
if(USE_EGL)
|
||||
set(LIBS ${LIBS}
|
||||
EGL)
|
||||
endif()
|
||||
|
||||
if(USE_GLES)
|
||||
set(LIBS ${LIBS}
|
||||
GLESv2)
|
||||
else()
|
||||
set(LIBS ${LIBS}
|
||||
GLEW
|
||||
${OPENGL_LIBRARIES})
|
||||
endif()
|
||||
|
||||
if(wxWidgets_FOUND)
|
||||
set(LIBS ${LIBS} ${wxWidgets_LIBRARIES})
|
||||
|
|
|
@ -247,4 +247,4 @@
|
|||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
#include "Globals.h"
|
||||
#include "FramebufferManager.h"
|
||||
#include "VertexShaderGen.h"
|
||||
|
||||
#include "TextureConverter.h"
|
||||
#include "Render.h"
|
||||
|
@ -27,6 +28,11 @@ namespace OGL
|
|||
|
||||
extern bool s_bHaveFramebufferBlit; // comes from Render.cpp. ugly.
|
||||
|
||||
static GLuint s_VBO = 0;
|
||||
static GLuint s_VAO = 0;
|
||||
static MathUtil::Rectangle<float> s_cached_sourcerc;
|
||||
static MathUtil::Rectangle<float> s_cached_drawrc;
|
||||
|
||||
int FramebufferManager::m_targetWidth;
|
||||
int FramebufferManager::m_targetHeight;
|
||||
int FramebufferManager::m_msaaSamples;
|
||||
|
@ -53,6 +59,15 @@ FramebufferManager::FramebufferManager(int targetWidth, int targetHeight, int ms
|
|||
m_resolvedDepthTexture = 0;
|
||||
m_xfbFramebuffer = 0;
|
||||
|
||||
s_cached_sourcerc.bottom = -1;
|
||||
s_cached_sourcerc.left = -1;
|
||||
s_cached_sourcerc.right = -1;
|
||||
s_cached_sourcerc.top = -1;
|
||||
s_cached_drawrc.bottom = -1;
|
||||
s_cached_drawrc.left = -1;
|
||||
s_cached_drawrc.right = -1;
|
||||
s_cached_drawrc.top = -1;
|
||||
|
||||
m_targetWidth = targetWidth;
|
||||
m_targetHeight = targetHeight;
|
||||
|
||||
|
@ -169,7 +184,28 @@ FramebufferManager::FramebufferManager(int targetWidth, int targetHeight, int ms
|
|||
// Create XFB framebuffer; targets will be created elsewhere.
|
||||
|
||||
glGenFramebuffersEXT(1, &m_xfbFramebuffer);
|
||||
|
||||
|
||||
// Generate VBO & VAO - and initialize the VAO for "Draw"
|
||||
glGenBuffers(1, &s_VBO);
|
||||
glGenVertexArrays(1, &s_VAO);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, s_VBO);
|
||||
glBindVertexArray(s_VAO);
|
||||
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
glVertexPointer(2, GL_FLOAT, 6*sizeof(GLfloat), NULL);
|
||||
|
||||
glClientActiveTexture(GL_TEXTURE0);
|
||||
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
glTexCoordPointer(2, GL_FLOAT, 6*sizeof(GLfloat), (GLfloat*)NULL+2);
|
||||
|
||||
glClientActiveTexture(GL_TEXTURE1);
|
||||
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
glTexCoordPointer(2, GL_FLOAT, 6*sizeof(GLfloat), (GLfloat*)NULL+4);
|
||||
|
||||
// TODO: this after merging with graphic_update
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
glBindVertexArray(0);
|
||||
|
||||
// EFB framebuffer is currently bound, make sure to clear its alpha value to 1.f
|
||||
glViewport(0, 0, m_targetWidth, m_targetHeight);
|
||||
glScissor(0, 0, m_targetWidth, m_targetHeight);
|
||||
|
@ -181,6 +217,8 @@ FramebufferManager::FramebufferManager(int targetWidth, int targetHeight, int ms
|
|||
FramebufferManager::~FramebufferManager()
|
||||
{
|
||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
|
||||
glDeleteBuffers(1, &s_VBO);
|
||||
glDeleteVertexArrays(1, &s_VAO);
|
||||
|
||||
GLuint glObj[3];
|
||||
|
||||
|
@ -305,24 +343,37 @@ void XFBSource::Draw(const MathUtil::Rectangle<float> &sourcerc,
|
|||
|
||||
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, texture);
|
||||
|
||||
glBegin(GL_QUADS);
|
||||
glTexCoord2f(sourcerc.left, sourcerc.bottom);
|
||||
glMultiTexCoord2fARB(GL_TEXTURE1, 0, 0);
|
||||
glVertex2f(drawrc.left, drawrc.bottom);
|
||||
|
||||
glTexCoord2f(sourcerc.left, sourcerc.top);
|
||||
glMultiTexCoord2fARB(GL_TEXTURE1, 0, 1);
|
||||
glVertex2f(drawrc.left, drawrc.top);
|
||||
|
||||
glTexCoord2f(sourcerc.right, sourcerc.top);
|
||||
glMultiTexCoord2fARB(GL_TEXTURE1, 1, 1);
|
||||
glVertex2f(drawrc.right, drawrc.top);
|
||||
|
||||
glTexCoord2f(sourcerc.right, sourcerc.bottom);
|
||||
glMultiTexCoord2fARB(GL_TEXTURE1, 1, 0);
|
||||
glVertex2f(drawrc.right, drawrc.bottom);
|
||||
glEnd();
|
||||
if(!(s_cached_sourcerc == sourcerc) || !(s_cached_drawrc == drawrc)) {
|
||||
GLfloat vertices[] = {
|
||||
drawrc.left, drawrc.bottom,
|
||||
sourcerc.left, sourcerc.bottom,
|
||||
0.0f, 0.0f,
|
||||
drawrc.left, drawrc.top,
|
||||
sourcerc.left, sourcerc.top,
|
||||
0.0f, 1.0f,
|
||||
drawrc.right, drawrc.top,
|
||||
sourcerc.right, sourcerc.top,
|
||||
1.0f, 1.0f,
|
||||
drawrc.right, drawrc.bottom,
|
||||
sourcerc.right, sourcerc.bottom,
|
||||
1.0f, 0.0f
|
||||
};
|
||||
glBindBuffer(GL_ARRAY_BUFFER, s_VBO);
|
||||
glBufferData(GL_ARRAY_BUFFER, 2*4*3*sizeof(GLfloat), vertices, GL_STREAM_DRAW);
|
||||
|
||||
// TODO: this after merging with graphic_update
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
|
||||
s_cached_sourcerc = sourcerc;
|
||||
s_cached_drawrc = drawrc;
|
||||
}
|
||||
|
||||
glBindVertexArray(s_VAO);
|
||||
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
|
||||
|
||||
// TODO: this after merging with graphic_update
|
||||
glBindVertexArray(0);
|
||||
|
||||
GL_REPORT_ERRORD();
|
||||
}
|
||||
|
||||
|
|
|
@ -28,59 +28,8 @@
|
|||
|
||||
#include "GLUtil.h"
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include "EmuWindow.h"
|
||||
static HDC hDC = NULL; // Private GDI Device Context
|
||||
static HGLRC hRC = NULL; // Permanent Rendering Context
|
||||
#else
|
||||
GLWindow GLWin;
|
||||
#endif
|
||||
|
||||
// Handles OpenGL and the window
|
||||
|
||||
// Window dimensions.
|
||||
static int s_backbuffer_width;
|
||||
static int s_backbuffer_height;
|
||||
|
||||
void OpenGL_SwapBuffers()
|
||||
{
|
||||
#if defined(USE_WX) && USE_WX
|
||||
GLWin.glCanvas->SwapBuffers();
|
||||
#elif defined(__APPLE__)
|
||||
[GLWin.cocoaCtx flushBuffer];
|
||||
#elif defined(_WIN32)
|
||||
SwapBuffers(hDC);
|
||||
#elif defined(HAVE_X11) && HAVE_X11
|
||||
glXSwapBuffers(GLWin.dpy, GLWin.win);
|
||||
#endif
|
||||
}
|
||||
|
||||
u32 OpenGL_GetBackbufferWidth()
|
||||
{
|
||||
return s_backbuffer_width;
|
||||
}
|
||||
|
||||
u32 OpenGL_GetBackbufferHeight()
|
||||
{
|
||||
return s_backbuffer_height;
|
||||
}
|
||||
|
||||
void OpenGL_SetWindowText(const char *text)
|
||||
{
|
||||
#if defined(USE_WX) && USE_WX
|
||||
// Handled by Host_UpdateTitle()
|
||||
#elif defined(__APPLE__)
|
||||
[GLWin.cocoaWin setTitle: [NSString stringWithUTF8String: text]];
|
||||
#elif defined(_WIN32)
|
||||
TCHAR temp[512];
|
||||
swprintf_s(temp, sizeof(temp)/sizeof(TCHAR), _T("%hs"), text);
|
||||
EmuWindow::SetWindowText(temp);
|
||||
#elif defined(HAVE_X11) && HAVE_X11
|
||||
// Tell X to ask the window manager to set the window title.
|
||||
// (X itself doesn't provide window title functionality.)
|
||||
XStoreName(GLWin.dpy, GLWin.win, text);
|
||||
#endif
|
||||
}
|
||||
cInterfaceBase *GLInterface;
|
||||
|
||||
namespace OGL
|
||||
{
|
||||
|
@ -88,20 +37,7 @@ namespace OGL
|
|||
// Draw messages on top of the screen
|
||||
unsigned int VideoBackend::PeekMessages()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
// TODO: peekmessage
|
||||
MSG msg;
|
||||
while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
|
||||
{
|
||||
if (msg.message == WM_QUIT)
|
||||
return FALSE;
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
return TRUE;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
return GLInterface->PeekMessages();
|
||||
}
|
||||
|
||||
// Show the current FPS
|
||||
|
@ -109,538 +45,103 @@ void VideoBackend::UpdateFPSDisplay(const char *text)
|
|||
{
|
||||
char temp[100];
|
||||
snprintf(temp, sizeof temp, "%s | OpenGL | %s", scm_rev_str, text);
|
||||
OpenGL_SetWindowText(temp);
|
||||
return GLInterface->UpdateFPSDisplay(temp);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#if defined(HAVE_X11) && HAVE_X11
|
||||
void XEventThread();
|
||||
|
||||
void CreateXWindow(void)
|
||||
void InitInterface()
|
||||
{
|
||||
Atom wmProtocols[1];
|
||||
|
||||
// Setup window attributes
|
||||
GLWin.attr.colormap = XCreateColormap(GLWin.evdpy,
|
||||
GLWin.parent, GLWin.vi->visual, AllocNone);
|
||||
GLWin.attr.event_mask = KeyPressMask | StructureNotifyMask | FocusChangeMask;
|
||||
GLWin.attr.background_pixel = BlackPixel(GLWin.evdpy, GLWin.screen);
|
||||
GLWin.attr.border_pixel = 0;
|
||||
|
||||
// Create the window
|
||||
GLWin.win = XCreateWindow(GLWin.evdpy, GLWin.parent,
|
||||
GLWin.x, GLWin.y, GLWin.width, GLWin.height, 0,
|
||||
GLWin.vi->depth, InputOutput, GLWin.vi->visual,
|
||||
CWBorderPixel | CWBackPixel | CWColormap | CWEventMask, &GLWin.attr);
|
||||
wmProtocols[0] = XInternAtom(GLWin.evdpy, "WM_DELETE_WINDOW", True);
|
||||
XSetWMProtocols(GLWin.evdpy, GLWin.win, wmProtocols, 1);
|
||||
XSetStandardProperties(GLWin.evdpy, GLWin.win, "GPU", "GPU", None, NULL, 0, NULL);
|
||||
XMapRaised(GLWin.evdpy, GLWin.win);
|
||||
XSync(GLWin.evdpy, True);
|
||||
|
||||
GLWin.xEventThread = std::thread(XEventThread);
|
||||
#if defined(USE_EGL) && USE_EGL
|
||||
GLInterface = new cInterfaceEGL;
|
||||
#elif defined(USE_WX) && USE_WX
|
||||
GLInterface = new cInterfaceWX;
|
||||
#elif defined(__APPLE__)
|
||||
GLInterface = new cInterfaceAGL;
|
||||
#elif defined(_WIN32)
|
||||
GLInterface = new cInterfaceWGL;
|
||||
#elif defined(HAVE_X11) && HAVE_X11
|
||||
GLInterface = new cInterfaceGLX;
|
||||
#endif
|
||||
}
|
||||
|
||||
void DestroyXWindow(void)
|
||||
GLuint OpenGL_CompileProgram ( const char* vertexShader, const char* fragmentShader )
|
||||
{
|
||||
XUnmapWindow(GLWin.dpy, GLWin.win);
|
||||
GLWin.win = 0;
|
||||
if (GLWin.xEventThread.joinable())
|
||||
GLWin.xEventThread.join();
|
||||
XFreeColormap(GLWin.evdpy, GLWin.attr.colormap);
|
||||
}
|
||||
|
||||
void XEventThread()
|
||||
{
|
||||
// Free look variables
|
||||
static bool mouseLookEnabled = false;
|
||||
static bool mouseMoveEnabled = false;
|
||||
static float lastMouse[2];
|
||||
while (GLWin.win)
|
||||
{
|
||||
XEvent event;
|
||||
KeySym key;
|
||||
for (int num_events = XPending(GLWin.evdpy); num_events > 0; num_events--)
|
||||
{
|
||||
XNextEvent(GLWin.evdpy, &event);
|
||||
switch(event.type) {
|
||||
case KeyPress:
|
||||
key = XLookupKeysym((XKeyEvent*)&event, 0);
|
||||
switch (key)
|
||||
{
|
||||
case XK_3:
|
||||
OSDChoice = 1;
|
||||
// Toggle native resolution
|
||||
g_Config.iEFBScale = g_Config.iEFBScale + 1;
|
||||
if (g_Config.iEFBScale > 7) g_Config.iEFBScale = 0;
|
||||
break;
|
||||
case XK_4:
|
||||
OSDChoice = 2;
|
||||
// Toggle aspect ratio
|
||||
g_Config.iAspectRatio = (g_Config.iAspectRatio + 1) & 3;
|
||||
break;
|
||||
case XK_5:
|
||||
OSDChoice = 3;
|
||||
// Toggle EFB copy
|
||||
if (!g_Config.bEFBCopyEnable || g_Config.bCopyEFBToTexture)
|
||||
{
|
||||
g_Config.bEFBCopyEnable ^= true;
|
||||
g_Config.bCopyEFBToTexture = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_Config.bCopyEFBToTexture = !g_Config.bCopyEFBToTexture;
|
||||
}
|
||||
break;
|
||||
case XK_6:
|
||||
OSDChoice = 4;
|
||||
g_Config.bDisableFog = !g_Config.bDisableFog;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (g_Config.bFreeLook)
|
||||
{
|
||||
static float debugSpeed = 1.0f;
|
||||
switch (key)
|
||||
{
|
||||
case XK_parenleft:
|
||||
debugSpeed /= 2.0f;
|
||||
break;
|
||||
case XK_parenright:
|
||||
debugSpeed *= 2.0f;
|
||||
break;
|
||||
case XK_w:
|
||||
VertexShaderManager::TranslateView(0.0f, debugSpeed);
|
||||
break;
|
||||
case XK_s:
|
||||
VertexShaderManager::TranslateView(0.0f, -debugSpeed);
|
||||
break;
|
||||
case XK_a:
|
||||
VertexShaderManager::TranslateView(debugSpeed, 0.0f);
|
||||
break;
|
||||
case XK_d:
|
||||
VertexShaderManager::TranslateView(-debugSpeed, 0.0f);
|
||||
break;
|
||||
case XK_r:
|
||||
VertexShaderManager::ResetView();
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ButtonPress:
|
||||
if (g_Config.bFreeLook)
|
||||
{
|
||||
switch (event.xbutton.button)
|
||||
{
|
||||
case 2: // Middle button
|
||||
lastMouse[0] = event.xbutton.x;
|
||||
lastMouse[1] = event.xbutton.y;
|
||||
mouseMoveEnabled = true;
|
||||
break;
|
||||
case 3: // Right button
|
||||
lastMouse[0] = event.xbutton.x;
|
||||
lastMouse[1] = event.xbutton.y;
|
||||
mouseLookEnabled = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ButtonRelease:
|
||||
if (g_Config.bFreeLook)
|
||||
{
|
||||
switch (event.xbutton.button)
|
||||
{
|
||||
case 2: // Middle button
|
||||
mouseMoveEnabled = false;
|
||||
break;
|
||||
case 3: // Right button
|
||||
mouseLookEnabled = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MotionNotify:
|
||||
if (g_Config.bFreeLook)
|
||||
{
|
||||
if (mouseLookEnabled)
|
||||
{
|
||||
VertexShaderManager::RotateView((event.xmotion.x - lastMouse[0]) / 200.0f,
|
||||
(event.xmotion.y - lastMouse[1]) / 200.0f);
|
||||
lastMouse[0] = event.xmotion.x;
|
||||
lastMouse[1] = event.xmotion.y;
|
||||
}
|
||||
|
||||
if (mouseMoveEnabled)
|
||||
{
|
||||
VertexShaderManager::TranslateView((event.xmotion.x - lastMouse[0]) / 50.0f,
|
||||
(event.xmotion.y - lastMouse[1]) / 50.0f);
|
||||
lastMouse[0] = event.xmotion.x;
|
||||
lastMouse[1] = event.xmotion.y;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ConfigureNotify:
|
||||
Window winDummy;
|
||||
unsigned int borderDummy, depthDummy;
|
||||
XGetGeometry(GLWin.evdpy, GLWin.win, &winDummy, &GLWin.x, &GLWin.y,
|
||||
&GLWin.width, &GLWin.height, &borderDummy, &depthDummy);
|
||||
s_backbuffer_width = GLWin.width;
|
||||
s_backbuffer_height = GLWin.height;
|
||||
break;
|
||||
case ClientMessage:
|
||||
if ((unsigned long) event.xclient.data.l[0] ==
|
||||
XInternAtom(GLWin.evdpy, "WM_DELETE_WINDOW", False))
|
||||
Host_Message(WM_USER_STOP);
|
||||
if ((unsigned long) event.xclient.data.l[0] ==
|
||||
XInternAtom(GLWin.evdpy, "RESIZE", False))
|
||||
XMoveResizeWindow(GLWin.evdpy, GLWin.win,
|
||||
event.xclient.data.l[1], event.xclient.data.l[2],
|
||||
event.xclient.data.l[3], event.xclient.data.l[4]);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
Common::SleepCurrentThread(20);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Create rendering window.
|
||||
// Call browser: Core.cpp:EmuThread() > main.cpp:Video_Initialize()
|
||||
bool OpenGL_Create(void *&window_handle)
|
||||
{
|
||||
int _tx, _ty, _twidth, _theight;
|
||||
Host_GetRenderWindowSize(_tx, _ty, _twidth, _theight);
|
||||
|
||||
// Control window size and picture scaling
|
||||
s_backbuffer_width = _twidth;
|
||||
s_backbuffer_height = _theight;
|
||||
|
||||
#if defined(USE_WX) && USE_WX
|
||||
GLWin.panel = (wxPanel *)window_handle;
|
||||
GLWin.glCanvas = new wxGLCanvas(GLWin.panel, wxID_ANY, NULL,
|
||||
wxPoint(0, 0), wxSize(_twidth, _theight));
|
||||
GLWin.glCanvas->Show(true);
|
||||
if (GLWin.glCtxt == NULL) // XXX dirty hack
|
||||
GLWin.glCtxt = new wxGLContext(GLWin.glCanvas);
|
||||
|
||||
#elif defined(__APPLE__)
|
||||
NSRect size;
|
||||
NSUInteger style = NSMiniaturizableWindowMask;
|
||||
NSOpenGLPixelFormatAttribute attr[2] = { NSOpenGLPFADoubleBuffer, 0 };
|
||||
NSOpenGLPixelFormat *fmt = [[NSOpenGLPixelFormat alloc]
|
||||
initWithAttributes: attr];
|
||||
if (fmt == nil) {
|
||||
ERROR_LOG(VIDEO, "failed to create pixel format");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
GLWin.cocoaCtx = [[NSOpenGLContext alloc]
|
||||
initWithFormat: fmt shareContext: nil];
|
||||
[fmt release];
|
||||
if (GLWin.cocoaCtx == nil) {
|
||||
ERROR_LOG(VIDEO, "failed to create context");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (SConfig::GetInstance().m_LocalCoreStartupParameter.bFullscreen) {
|
||||
size = [[NSScreen mainScreen] frame];
|
||||
style |= NSBorderlessWindowMask;
|
||||
} else {
|
||||
size = NSMakeRect(_tx, _ty, _twidth, _theight);
|
||||
style |= NSResizableWindowMask | NSTitledWindowMask;
|
||||
}
|
||||
|
||||
GLWin.cocoaWin = [[NSWindow alloc] initWithContentRect: size
|
||||
styleMask: style backing: NSBackingStoreBuffered defer: NO];
|
||||
if (GLWin.cocoaWin == nil) {
|
||||
ERROR_LOG(VIDEO, "failed to create window");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (SConfig::GetInstance().m_LocalCoreStartupParameter.bFullscreen) {
|
||||
CGDisplayCapture(CGMainDisplayID());
|
||||
[GLWin.cocoaWin setLevel: CGShieldingWindowLevel()];
|
||||
}
|
||||
|
||||
[GLWin.cocoaCtx setView: [GLWin.cocoaWin contentView]];
|
||||
[GLWin.cocoaWin makeKeyAndOrderFront: nil];
|
||||
|
||||
#elif defined(_WIN32)
|
||||
window_handle = (void*)EmuWindow::Create((HWND)window_handle, GetModuleHandle(0), _T("Please wait..."));
|
||||
if (window_handle == NULL)
|
||||
{
|
||||
Host_SysMessage("failed to create window");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Show the window
|
||||
EmuWindow::Show();
|
||||
|
||||
PIXELFORMATDESCRIPTOR pfd = // pfd Tells Windows How We Want Things To Be
|
||||
{
|
||||
sizeof(PIXELFORMATDESCRIPTOR), // Size Of This Pixel Format Descriptor
|
||||
1, // Version Number
|
||||
PFD_DRAW_TO_WINDOW | // Format Must Support Window
|
||||
PFD_SUPPORT_OPENGL | // Format Must Support OpenGL
|
||||
PFD_DOUBLEBUFFER, // Must Support Double Buffering
|
||||
PFD_TYPE_RGBA, // Request An RGBA Format
|
||||
32, // Select Our Color Depth
|
||||
0, 0, 0, 0, 0, 0, // Color Bits Ignored
|
||||
0, // 8bit Alpha Buffer
|
||||
0, // Shift Bit Ignored
|
||||
0, // No Accumulation Buffer
|
||||
0, 0, 0, 0, // Accumulation Bits Ignored
|
||||
24, // 24Bit Z-Buffer (Depth Buffer)
|
||||
8, // 8bit Stencil Buffer
|
||||
0, // No Auxiliary Buffer
|
||||
PFD_MAIN_PLANE, // Main Drawing Layer
|
||||
0, // Reserved
|
||||
0, 0, 0 // Layer Masks Ignored
|
||||
};
|
||||
|
||||
GLuint PixelFormat; // Holds The Results After Searching For A Match
|
||||
|
||||
if (!(hDC=GetDC(EmuWindow::GetWnd()))) {
|
||||
PanicAlert("(1) Can't create an OpenGL Device context. Fail.");
|
||||
return false;
|
||||
}
|
||||
if (!(PixelFormat = ChoosePixelFormat(hDC, &pfd))) {
|
||||
PanicAlert("(2) Can't find a suitable PixelFormat.");
|
||||
return false;
|
||||
}
|
||||
if (!SetPixelFormat(hDC, PixelFormat, &pfd)) {
|
||||
PanicAlert("(3) Can't set the PixelFormat.");
|
||||
return false;
|
||||
}
|
||||
if (!(hRC = wglCreateContext(hDC))) {
|
||||
PanicAlert("(4) Can't create an OpenGL rendering context.");
|
||||
return false;
|
||||
}
|
||||
// --------------------------------------
|
||||
|
||||
#elif defined(HAVE_X11) && HAVE_X11
|
||||
int glxMajorVersion, glxMinorVersion;
|
||||
|
||||
// attributes for a single buffered visual in RGBA format with at least
|
||||
// 8 bits per color and a 24 bit depth buffer
|
||||
int attrListSgl[] = {GLX_RGBA, GLX_RED_SIZE, 8,
|
||||
GLX_GREEN_SIZE, 8,
|
||||
GLX_BLUE_SIZE, 8,
|
||||
GLX_DEPTH_SIZE, 24,
|
||||
None};
|
||||
|
||||
// attributes for a double buffered visual in RGBA format with at least
|
||||
// 8 bits per color and a 24 bit depth buffer
|
||||
int attrListDbl[] = {GLX_RGBA, GLX_DOUBLEBUFFER,
|
||||
GLX_RED_SIZE, 8,
|
||||
GLX_GREEN_SIZE, 8,
|
||||
GLX_BLUE_SIZE, 8,
|
||||
GLX_DEPTH_SIZE, 24,
|
||||
GLX_SAMPLE_BUFFERS_ARB, g_Config.iMultisampleMode != MULTISAMPLE_OFF?1:0,
|
||||
GLX_SAMPLES_ARB, g_Config.iMultisampleMode != MULTISAMPLE_OFF?1:0,
|
||||
None };
|
||||
|
||||
int attrListDefault[] = {
|
||||
GLX_RGBA,
|
||||
GLX_RED_SIZE, 1,
|
||||
GLX_GREEN_SIZE, 1,
|
||||
GLX_BLUE_SIZE, 1,
|
||||
GLX_DOUBLEBUFFER,
|
||||
GLX_DEPTH_SIZE, 1,
|
||||
None };
|
||||
|
||||
GLWin.dpy = XOpenDisplay(0);
|
||||
GLWin.evdpy = XOpenDisplay(0);
|
||||
GLWin.parent = (Window)window_handle;
|
||||
GLWin.screen = DefaultScreen(GLWin.dpy);
|
||||
if (GLWin.parent == 0)
|
||||
GLWin.parent = RootWindow(GLWin.dpy, GLWin.screen);
|
||||
|
||||
glXQueryVersion(GLWin.dpy, &glxMajorVersion, &glxMinorVersion);
|
||||
NOTICE_LOG(VIDEO, "glX-Version %d.%d", glxMajorVersion, glxMinorVersion);
|
||||
|
||||
// Get an appropriate visual
|
||||
GLWin.vi = glXChooseVisual(GLWin.dpy, GLWin.screen, attrListDbl);
|
||||
if (GLWin.vi == NULL)
|
||||
{
|
||||
GLWin.vi = glXChooseVisual(GLWin.dpy, GLWin.screen, attrListSgl);
|
||||
if (GLWin.vi != NULL)
|
||||
{
|
||||
ERROR_LOG(VIDEO, "Only single buffered visual!");
|
||||
}
|
||||
else
|
||||
{
|
||||
GLWin.vi = glXChooseVisual(GLWin.dpy, GLWin.screen, attrListDefault);
|
||||
if (GLWin.vi == NULL)
|
||||
{
|
||||
ERROR_LOG(VIDEO, "Could not choose visual (glXChooseVisual)");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
NOTICE_LOG(VIDEO, "Got double buffered visual!");
|
||||
|
||||
// Create a GLX context.
|
||||
GLWin.ctx = glXCreateContext(GLWin.dpy, GLWin.vi, 0, GL_TRUE);
|
||||
if (!GLWin.ctx)
|
||||
{
|
||||
PanicAlert("Unable to create GLX context.");
|
||||
return false;
|
||||
}
|
||||
|
||||
GLWin.x = _tx;
|
||||
GLWin.y = _ty;
|
||||
GLWin.width = _twidth;
|
||||
GLWin.height = _theight;
|
||||
|
||||
CreateXWindow();
|
||||
window_handle = (void *)GLWin.win;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OpenGL_MakeCurrent()
|
||||
{
|
||||
// connect the glx-context to the window
|
||||
#if defined(USE_WX) && USE_WX
|
||||
return GLWin.glCanvas->SetCurrent(*GLWin.glCtxt);
|
||||
#elif defined(__APPLE__)
|
||||
[GLWin.cocoaCtx makeCurrentContext];
|
||||
#elif defined(_WIN32)
|
||||
return wglMakeCurrent(hDC, hRC) ? true : false;
|
||||
#elif defined(HAVE_X11) && HAVE_X11
|
||||
#if defined(HAVE_WX) && (HAVE_WX)
|
||||
Host_GetRenderWindowSize(GLWin.x, GLWin.y,
|
||||
(int&)GLWin.width, (int&)GLWin.height);
|
||||
XMoveResizeWindow(GLWin.dpy, GLWin.win, GLWin.x, GLWin.y,
|
||||
GLWin.width, GLWin.height);
|
||||
#endif
|
||||
return glXMakeCurrent(GLWin.dpy, GLWin.win, GLWin.ctx);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
// Update window width, size and etc. Called from Render.cpp
|
||||
void OpenGL_Update()
|
||||
{
|
||||
#if defined(USE_WX) && USE_WX
|
||||
int width, height;
|
||||
|
||||
GLWin.panel->GetSize(&width, &height);
|
||||
if (width == s_backbuffer_width && height == s_backbuffer_height)
|
||||
return;
|
||||
|
||||
GLWin.glCanvas->SetFocus();
|
||||
GLWin.glCanvas->SetSize(0, 0, width, height);
|
||||
GLWin.glCtxt->SetCurrent(*GLWin.glCanvas);
|
||||
s_backbuffer_width = width;
|
||||
s_backbuffer_height = height;
|
||||
|
||||
#elif defined(__APPLE__)
|
||||
int width, height;
|
||||
|
||||
width = [[GLWin.cocoaWin contentView] frame].size.width;
|
||||
height = [[GLWin.cocoaWin contentView] frame].size.height;
|
||||
if (width == s_backbuffer_width && height == s_backbuffer_height)
|
||||
return;
|
||||
|
||||
[GLWin.cocoaCtx setView: [GLWin.cocoaWin contentView]];
|
||||
[GLWin.cocoaCtx update];
|
||||
[GLWin.cocoaCtx makeCurrentContext];
|
||||
s_backbuffer_width = width;
|
||||
s_backbuffer_height = height;
|
||||
|
||||
#elif defined(_WIN32)
|
||||
RECT rcWindow;
|
||||
if (!EmuWindow::GetParentWnd())
|
||||
{
|
||||
// We are not rendering to a child window - use client size.
|
||||
GetClientRect(EmuWindow::GetWnd(), &rcWindow);
|
||||
}
|
||||
else
|
||||
{
|
||||
// We are rendering to a child window - use parent size.
|
||||
GetWindowRect(EmuWindow::GetParentWnd(), &rcWindow);
|
||||
}
|
||||
|
||||
// Get the new window width and height
|
||||
// See below for documentation
|
||||
int width = rcWindow.right - rcWindow.left;
|
||||
int height = rcWindow.bottom - rcWindow.top;
|
||||
|
||||
// If we are rendering to a child window
|
||||
if (EmuWindow::GetParentWnd() != 0 &&
|
||||
(s_backbuffer_width != width || s_backbuffer_height != height) &&
|
||||
width >= 4 && height >= 4)
|
||||
{
|
||||
::MoveWindow(EmuWindow::GetWnd(), 0, 0, width, height, FALSE);
|
||||
s_backbuffer_width = width;
|
||||
s_backbuffer_height = height;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// Close backend
|
||||
void OpenGL_Shutdown()
|
||||
{
|
||||
#if defined(USE_WX) && USE_WX
|
||||
GLWin.glCanvas->Hide();
|
||||
// XXX GLWin.glCanvas->Destroy();
|
||||
// XXX delete GLWin.glCtxt;
|
||||
#elif defined(__APPLE__)
|
||||
[GLWin.cocoaWin close];
|
||||
[GLWin.cocoaCtx clearDrawable];
|
||||
[GLWin.cocoaCtx release];
|
||||
#elif defined(_WIN32)
|
||||
if (hRC)
|
||||
{
|
||||
if (!wglMakeCurrent(NULL, NULL))
|
||||
NOTICE_LOG(VIDEO, "Could not release drawing context.");
|
||||
|
||||
if (!wglDeleteContext(hRC))
|
||||
ERROR_LOG(VIDEO, "Release Rendering Context Failed.");
|
||||
|
||||
hRC = NULL;
|
||||
}
|
||||
|
||||
if (hDC && !ReleaseDC(EmuWindow::GetWnd(), hDC))
|
||||
{
|
||||
ERROR_LOG(VIDEO, "Release Device Context Failed.");
|
||||
hDC = NULL;
|
||||
}
|
||||
// generate objects
|
||||
GLuint vertexShaderID = glCreateShader(GL_VERTEX_SHADER);
|
||||
GLuint fragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER);
|
||||
GLuint programID = glCreateProgram();
|
||||
GLint Result = GL_FALSE;
|
||||
char stringBuffer[1024];
|
||||
GLsizei stringBufferUsage = 0;
|
||||
|
||||
#elif defined(HAVE_X11) && HAVE_X11
|
||||
DestroyXWindow();
|
||||
if (GLWin.ctx && !glXMakeCurrent(GLWin.dpy, None, NULL))
|
||||
NOTICE_LOG(VIDEO, "Could not release drawing context.");
|
||||
if (GLWin.ctx)
|
||||
{
|
||||
glXDestroyContext(GLWin.dpy, GLWin.ctx);
|
||||
XCloseDisplay(GLWin.dpy);
|
||||
XCloseDisplay(GLWin.evdpy);
|
||||
GLWin.ctx = NULL;
|
||||
// compile vertex shader
|
||||
glShaderSource(vertexShaderID, 1, &vertexShader, NULL);
|
||||
glCompileShader(vertexShaderID);
|
||||
#if defined(_DEBUG) || defined(DEBUGFAST) || defined(DEBUG_GLSL)
|
||||
glGetShaderiv(vertexShaderID, GL_COMPILE_STATUS, &Result);
|
||||
glGetShaderInfoLog(vertexShaderID, 1024, &stringBufferUsage, stringBuffer);
|
||||
if(Result && stringBufferUsage) {
|
||||
ERROR_LOG(VIDEO, "GLSL vertex shader warnings:\n%s%s", stringBuffer, vertexShader);
|
||||
} else if(!Result) {
|
||||
ERROR_LOG(VIDEO, "GLSL vertex shader error:\n%s%s", stringBuffer, vertexShader);
|
||||
} else {
|
||||
DEBUG_LOG(VIDEO, "GLSL vertex shader compiled:\n%s", vertexShader);
|
||||
}
|
||||
bool shader_errors = !Result;
|
||||
#endif
|
||||
|
||||
// compile fragment shader
|
||||
glShaderSource(fragmentShaderID, 1, &fragmentShader, NULL);
|
||||
glCompileShader(fragmentShaderID);
|
||||
#if defined(_DEBUG) || defined(DEBUGFAST) || defined(DEBUG_GLSL)
|
||||
glGetShaderiv(fragmentShaderID, GL_COMPILE_STATUS, &Result);
|
||||
glGetShaderInfoLog(fragmentShaderID, 1024, &stringBufferUsage, stringBuffer);
|
||||
if(Result && stringBufferUsage) {
|
||||
ERROR_LOG(VIDEO, "GLSL fragment shader warnings:\n%s%s", stringBuffer, fragmentShader);
|
||||
} else if(!Result) {
|
||||
ERROR_LOG(VIDEO, "GLSL fragment shader error:\n%s%s", stringBuffer, fragmentShader);
|
||||
} else {
|
||||
DEBUG_LOG(VIDEO, "GLSL fragment shader compiled:\n%s", fragmentShader);
|
||||
}
|
||||
shader_errors |= !Result;
|
||||
#endif
|
||||
|
||||
// link them
|
||||
glAttachShader(programID, vertexShaderID);
|
||||
glAttachShader(programID, fragmentShaderID);
|
||||
glLinkProgram(programID);
|
||||
#if defined(_DEBUG) || defined(DEBUGFAST) || defined(DEBUG_GLSL)
|
||||
glGetProgramiv(programID, GL_LINK_STATUS, &Result);
|
||||
glGetProgramInfoLog(programID, 1024, &stringBufferUsage, stringBuffer);
|
||||
if(Result && stringBufferUsage) {
|
||||
ERROR_LOG(VIDEO, "GLSL linker warnings:\n%s%s%s", stringBuffer, vertexShader, fragmentShader);
|
||||
} else if(!Result && !shader_errors) {
|
||||
ERROR_LOG(VIDEO, "GLSL linker error:\n%s%s%s", stringBuffer, vertexShader, fragmentShader);
|
||||
}
|
||||
#endif
|
||||
|
||||
// cleanup
|
||||
glDeleteShader(vertexShaderID);
|
||||
glDeleteShader(fragmentShaderID);
|
||||
|
||||
return programID;
|
||||
}
|
||||
|
||||
|
||||
GLuint OpenGL_ReportGLError(const char *function, const char *file, int line)
|
||||
{
|
||||
GLint err = glGetError();
|
||||
if (err != GL_NO_ERROR)
|
||||
{
|
||||
ERROR_LOG(VIDEO, "%s:%d: (%s) OpenGL error 0x%x - %s\n",
|
||||
file, line, function, err, gluErrorString(err));
|
||||
ERROR_LOG(VIDEO, "%s:%d: (%s) OpenGL error 0x%x\n",
|
||||
file, line, function, err);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
void OpenGL_ReportARBProgramError()
|
||||
{
|
||||
#ifndef USE_GLES
|
||||
const GLubyte* pstr = glGetString(GL_PROGRAM_ERROR_STRING_ARB);
|
||||
if (pstr != NULL && pstr[0] != 0)
|
||||
{
|
||||
|
@ -650,10 +151,12 @@ void OpenGL_ReportARBProgramError()
|
|||
ERROR_LOG(VIDEO, "%s", (char*)pstr);
|
||||
ERROR_LOG(VIDEO, "\n");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool OpenGL_ReportFBOError(const char *function, const char *file, int line)
|
||||
{
|
||||
#ifndef USE_GLES
|
||||
unsigned int fbo_status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
|
||||
if (fbo_status != GL_FRAMEBUFFER_COMPLETE_EXT)
|
||||
{
|
||||
|
@ -686,6 +189,7 @@ bool OpenGL_ReportFBOError(const char *function, const char *file, int line)
|
|||
file, line, function, error);
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -20,26 +20,7 @@
|
|||
|
||||
#include "VideoConfig.h"
|
||||
#include "MathUtil.h"
|
||||
#include "Thread.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#define GLEW_STATIC
|
||||
#include <GL/glew.h>
|
||||
#include <GL/wglew.h>
|
||||
#elif defined HAVE_X11 && HAVE_X11
|
||||
#include <GL/glxew.h>
|
||||
#include <GL/gl.h>
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/keysym.h>
|
||||
#elif defined __APPLE__
|
||||
#include <GL/glew.h>
|
||||
#import <AppKit/AppKit.h>
|
||||
#endif
|
||||
|
||||
#if defined USE_WX && USE_WX
|
||||
#include "wx/wx.h"
|
||||
#include "wx/glcanvas.h"
|
||||
#endif
|
||||
#include "GLInterface.h"
|
||||
|
||||
#ifndef GL_DEPTH24_STENCIL8_EXT // allows FBOs to support stencils
|
||||
#define GL_DEPTH_STENCIL_EXT 0x84F9
|
||||
|
@ -48,53 +29,28 @@
|
|||
#define GL_TEXTURE_STENCIL_SIZE_EXT 0x88F1
|
||||
#endif
|
||||
|
||||
#ifdef USE_GLES
|
||||
#define TEX2D GL_TEXTURE_2D
|
||||
#define PREC "highp"
|
||||
#define TEXTYPE "sampler2D"
|
||||
#define TEXFUNC "texture2D"
|
||||
#else
|
||||
#define TEX2D GL_TEXTURE_RECTANGLE_ARB
|
||||
#define PREC
|
||||
#define TEXTYPE "sampler2DRect"
|
||||
#define TEXFUNC "texture2DRect"
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
typedef struct {
|
||||
#if defined(USE_WX) && USE_WX
|
||||
wxGLCanvas *glCanvas;
|
||||
wxGLContext *glCtxt;
|
||||
wxPanel *panel;
|
||||
#elif defined(__APPLE__)
|
||||
NSWindow *cocoaWin;
|
||||
NSOpenGLContext *cocoaCtx;
|
||||
#elif defined(HAVE_X11) && HAVE_X11
|
||||
int screen;
|
||||
Window win;
|
||||
Window parent;
|
||||
// dpy used for glx stuff, evdpy for window events etc.
|
||||
// evdpy is to be used by XEventThread only
|
||||
Display *dpy, *evdpy;
|
||||
XVisualInfo *vi;
|
||||
GLXContext ctx;
|
||||
XSetWindowAttributes attr;
|
||||
std::thread xEventThread;
|
||||
int x, y;
|
||||
unsigned int width, height;
|
||||
#endif
|
||||
} GLWindow;
|
||||
void InitInterface();
|
||||
|
||||
extern GLWindow GLWin;
|
||||
|
||||
#endif
|
||||
|
||||
// Public OpenGL util
|
||||
|
||||
// Initialization / upkeep
|
||||
bool OpenGL_Create(void *&);
|
||||
void OpenGL_Shutdown();
|
||||
void OpenGL_Update();
|
||||
bool OpenGL_MakeCurrent();
|
||||
void OpenGL_SwapBuffers();
|
||||
|
||||
// Get status
|
||||
u32 OpenGL_GetBackbufferWidth();
|
||||
u32 OpenGL_GetBackbufferHeight();
|
||||
|
||||
// Set things
|
||||
void OpenGL_SetWindowText(const char *text);
|
||||
// Helpers
|
||||
GLuint OpenGL_CompileProgram(const char *vertexShader, const char *fragmentShader);
|
||||
|
||||
// Error reporting - use the convenient macros.
|
||||
void OpenGL_ReportARBProgramError();
|
||||
|
@ -126,4 +82,7 @@ extern CGprofile g_cgvProf, g_cgfProf;
|
|||
// use GLSL shaders across the whole pipeline. Yikes!
|
||||
//#define USE_DUAL_SOURCE_BLEND
|
||||
|
||||
// TODO: should be removed if we use glsl a lot
|
||||
#define DEBUG_GLSL
|
||||
|
||||
#endif // _GLINIT_H_
|
||||
|
|
|
@ -27,8 +27,9 @@
|
|||
|
||||
#define COMPILED_CODE_SIZE 4096
|
||||
|
||||
// TODO: this guy is never initialized
|
||||
u32 s_prevcomponents; // previous state set
|
||||
// TODO: Use this again for performance, but without VAO we never know exactly the last configuration
|
||||
static u32 s_prevcomponents; // previous state set
|
||||
|
||||
/*
|
||||
#ifdef _WIN32
|
||||
#ifdef _M_IX86
|
||||
|
@ -64,7 +65,6 @@ public:
|
|||
|
||||
virtual void Initialize(const PortableVertexDeclaration &_vtx_decl);
|
||||
virtual void SetupVertexPointers();
|
||||
virtual void EnableComponents(u32 components);
|
||||
};
|
||||
|
||||
namespace OGL
|
||||
|
@ -187,6 +187,7 @@ void GLVertexFormat::SetupVertexPointers() {
|
|||
#ifdef USE_JIT
|
||||
((void (*)())(void*)m_compiledCode)();
|
||||
#else
|
||||
|
||||
glVertexPointer(3, GL_FLOAT, vtx_decl.stride, VertexManager::s_pBaseBufferPointer);
|
||||
if (vtx_decl.num_normals >= 1) {
|
||||
glNormalPointer(VarToGL(vtx_decl.normal_gl_type), vtx_decl.stride, (void *)(VertexManager::s_pBaseBufferPointer + vtx_decl.normal_offset[0]));
|
||||
|
@ -219,34 +220,32 @@ void GLVertexFormat::SetupVertexPointers() {
|
|||
glVertexAttribPointer(SHADER_POSMTX_ATTRIB, 4, GL_UNSIGNED_BYTE, GL_FALSE, vtx_decl.stride, (void *)(VertexManager::s_pBaseBufferPointer + vtx_decl.posmtx_offset));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void GLVertexFormat::EnableComponents(u32 components)
|
||||
{
|
||||
if (s_prevcomponents != components)
|
||||
if (s_prevcomponents != m_components)
|
||||
{
|
||||
VertexManager::Flush();
|
||||
// vertices
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
|
||||
// matrices
|
||||
if ((components & VB_HAS_POSMTXIDX) != (s_prevcomponents & VB_HAS_POSMTXIDX))
|
||||
if ((m_components & VB_HAS_POSMTXIDX) != (s_prevcomponents & VB_HAS_POSMTXIDX))
|
||||
{
|
||||
if (components & VB_HAS_POSMTXIDX)
|
||||
if (m_components & VB_HAS_POSMTXIDX)
|
||||
glEnableVertexAttribArray(SHADER_POSMTX_ATTRIB);
|
||||
else
|
||||
glDisableVertexAttribArray(SHADER_POSMTX_ATTRIB);
|
||||
}
|
||||
|
||||
// normals
|
||||
if ((components & VB_HAS_NRM0) != (s_prevcomponents & VB_HAS_NRM0))
|
||||
if ((m_components & VB_HAS_NRM0) != (s_prevcomponents & VB_HAS_NRM0))
|
||||
{
|
||||
if (components & VB_HAS_NRM0)
|
||||
if (m_components & VB_HAS_NRM0)
|
||||
glEnableClientState(GL_NORMAL_ARRAY);
|
||||
else
|
||||
glDisableClientState(GL_NORMAL_ARRAY);
|
||||
}
|
||||
if ((components & VB_HAS_NRM1) != (s_prevcomponents & VB_HAS_NRM1))
|
||||
if ((m_components & VB_HAS_NRM1) != (s_prevcomponents & VB_HAS_NRM1))
|
||||
{
|
||||
if (components & VB_HAS_NRM1) {
|
||||
if (m_components & VB_HAS_NRM1) {
|
||||
glEnableVertexAttribArray(SHADER_NORM1_ATTRIB);
|
||||
glEnableVertexAttribArray(SHADER_NORM2_ATTRIB);
|
||||
}
|
||||
|
@ -259,9 +258,9 @@ void GLVertexFormat::EnableComponents(u32 components)
|
|||
// color
|
||||
for (int i = 0; i < 2; ++i)
|
||||
{
|
||||
if ((components & (VB_HAS_COL0 << i)) != (s_prevcomponents & (VB_HAS_COL0 << i)))
|
||||
if ((m_components & (VB_HAS_COL0 << i)) != (s_prevcomponents & (VB_HAS_COL0 << i)))
|
||||
{
|
||||
if (components & (VB_HAS_COL0 << i))
|
||||
if (m_components & (VB_HAS_COL0 << i))
|
||||
glEnableClientState(i ? GL_SECONDARY_COLOR_ARRAY : GL_COLOR_ARRAY);
|
||||
else
|
||||
glDisableClientState(i ? GL_SECONDARY_COLOR_ARRAY : GL_COLOR_ARRAY);
|
||||
|
@ -271,16 +270,16 @@ void GLVertexFormat::EnableComponents(u32 components)
|
|||
// tex
|
||||
for (int i = 0; i < 8; ++i)
|
||||
{
|
||||
if ((components & (VB_HAS_UV0 << i)) != (s_prevcomponents & (VB_HAS_UV0 << i)))
|
||||
if ((m_components & (VB_HAS_UV0 << i)) != (s_prevcomponents & (VB_HAS_UV0 << i)))
|
||||
{
|
||||
glClientActiveTexture(GL_TEXTURE0 + i);
|
||||
if (components & (VB_HAS_UV0 << i))
|
||||
if (m_components & (VB_HAS_UV0 << i))
|
||||
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
else
|
||||
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
}
|
||||
}
|
||||
|
||||
s_prevcomponents = components;
|
||||
s_prevcomponents = m_components;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,12 +17,16 @@
|
|||
|
||||
#include "GLUtil.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "RasterFont.h"
|
||||
// globals
|
||||
|
||||
const GLubyte rasters[][13] = {
|
||||
|
||||
static const u32 char_width = 8;
|
||||
static const u32 char_height = 13;
|
||||
static const u32 char_offset = 32;
|
||||
static const u32 char_count = 95;
|
||||
|
||||
const u8 rasters[char_count][char_height] = {
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
|
||||
{0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18},
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36},
|
||||
|
@ -120,104 +124,160 @@ const GLubyte rasters[][13] = {
|
|||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x8f, 0xf1, 0x60, 0x00, 0x00, 0x00}
|
||||
};
|
||||
|
||||
static const char *s_vertex_shader =
|
||||
"attribute vec2 vertexPosition;\n"
|
||||
"attribute vec2 texturePosition;\n"
|
||||
"varying vec2 tpos;\n"
|
||||
"void main(void) {\n"
|
||||
" gl_Position = vec4(vertexPosition,0,1);\n"
|
||||
" tpos = texturePosition;\n"
|
||||
"}\n";
|
||||
|
||||
static const char *s_fragment_shader =
|
||||
"#extension GL_ARB_texture_rectangle : enable\n"
|
||||
"uniform sampler2DRect textureSampler;\n"
|
||||
"uniform vec4 color;\n"
|
||||
"varying vec2 tpos;\n"
|
||||
"void main(void) {\n"
|
||||
" gl_FragColor = texture2DRect(textureSampler,tpos) * color;\n"
|
||||
"}\n";
|
||||
|
||||
RasterFont::RasterFont()
|
||||
{
|
||||
// set GL modes
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
// create the raster font
|
||||
fontOffset = glGenLists(128);
|
||||
for (int i = 32; i < 127; i++) {
|
||||
glNewList(i + fontOffset, GL_COMPILE);
|
||||
glBitmap(8, 13, 0.0f, 2.0f, 10.0f, 0.0f, rasters[i - 32]);
|
||||
glEndList();
|
||||
// generate the texture
|
||||
glGenTextures(1, &texture);
|
||||
glBindTexture(GL_TEXTURE_RECTANGLE, texture);
|
||||
u32* texture_data = new u32[char_width*char_count*char_height];
|
||||
for(u32 y=0; y<char_height; y++) {
|
||||
for(u32 c=0; c<char_count; c++) {
|
||||
for(u32 x=0; x<char_width; x++) {
|
||||
bool pixel = rasters[c][y] & (1<<(char_width-x-1));
|
||||
texture_data[char_width*char_count*y+char_width*c+x] = pixel ? -1 : 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
temp_buffer = new char[TEMP_BUFFER_SIZE];
|
||||
glTexImage2D(GL_TEXTURE_RECTANGLE, 0, GL_RGBA, char_width*char_count, char_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, texture_data);
|
||||
delete [] texture_data;
|
||||
|
||||
// generate shader
|
||||
shader_program = OpenGL_CompileProgram(s_vertex_shader, s_fragment_shader);
|
||||
|
||||
// bound uniforms
|
||||
glUseProgram(shader_program);
|
||||
glUniform1i(glGetUniformLocation(shader_program,"textureSampler"), 0); // GL_TEXTURE0
|
||||
uniform_color_id = glGetUniformLocation(shader_program,"color");
|
||||
glUniform4f(uniform_color_id, 1, 1, 1, 1);
|
||||
cached_color = -1;
|
||||
glUseProgram(0);
|
||||
|
||||
// generate VBO & VAO
|
||||
glGenBuffers(1, &VBO);
|
||||
glGenVertexArrays(1, &VAO);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, VBO);
|
||||
glBindVertexArray(VAO);
|
||||
glEnableVertexAttribArray(glGetAttribLocation(shader_program, "vertexPosition"));
|
||||
glVertexAttribPointer(glGetAttribLocation(shader_program, "vertexPosition"), 2, GL_FLOAT, 0, sizeof(GLfloat)*4, NULL);
|
||||
glEnableVertexAttribArray(glGetAttribLocation(shader_program, "texturePosition"));
|
||||
glVertexAttribPointer(glGetAttribLocation(shader_program, "texturePosition"), 2, GL_FLOAT, 0, sizeof(GLfloat)*4, (GLfloat*)NULL+2);
|
||||
|
||||
// TODO: this after merging with graphic_update
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
glBindVertexArray(0);
|
||||
}
|
||||
|
||||
RasterFont::~RasterFont()
|
||||
{
|
||||
glDeleteLists(fontOffset, 128);
|
||||
delete [] temp_buffer;
|
||||
glDeleteTextures(1, &texture);
|
||||
glDeleteBuffers(1, &VBO);
|
||||
glDeleteVertexArrays(1, &VAO);
|
||||
glDeleteProgram(shader_program);
|
||||
}
|
||||
|
||||
void RasterFont::printString(const char *s, double x, double y, double z)
|
||||
void RasterFont::printMultilineText(const char *text, double start_x, double start_y, double z, int bbWidth, int bbHeight, u32 color)
|
||||
{
|
||||
int length = (int)strlen(s);
|
||||
int length = (int)strlen(text);
|
||||
if (!length)
|
||||
return;
|
||||
if (length >= TEMP_BUFFER_SIZE)
|
||||
length = TEMP_BUFFER_SIZE - 1;
|
||||
|
||||
// Sanitize string to avoid GL errors.
|
||||
char *s2 = temp_buffer;
|
||||
memcpy(s2, s, length);
|
||||
s2[length] = 0;
|
||||
for (int i = 0; i < length; i++) {
|
||||
if (s2[i] < 32 || s2[i] > 126)
|
||||
s2[i] = '!';
|
||||
}
|
||||
|
||||
// go to the right spot
|
||||
glRasterPos3d(x, y, z);
|
||||
GL_REPORT_ERRORD();
|
||||
|
||||
glPushAttrib (GL_LIST_BIT);
|
||||
glListBase(fontOffset);
|
||||
glCallLists((GLsizei)strlen(s2), GL_UNSIGNED_BYTE, (GLubyte *) s2);
|
||||
GL_REPORT_ERRORD();
|
||||
glPopAttrib();
|
||||
GL_REPORT_ERRORD();
|
||||
}
|
||||
|
||||
void RasterFont::printCenteredString(const char *s, double y, int screen_width, double z)
|
||||
{
|
||||
int length = (int)strlen(s);
|
||||
int x = (int)(screen_width/2.0 - (length/2.0)*char_width);
|
||||
printString(s, x, y, z);
|
||||
}
|
||||
|
||||
void RasterFont::printMultilineText(const char *text, double start_x, double start_y, double z, int bbWidth, int bbHeight)
|
||||
{
|
||||
double x = start_x;
|
||||
double y = start_y;
|
||||
char temp[1024];
|
||||
char *t = temp;
|
||||
while (*text)
|
||||
{
|
||||
if (*text == '\n')
|
||||
{
|
||||
*t = 0;
|
||||
printString(temp, x, y, z);
|
||||
y -= char_height * 2.0f / bbHeight;
|
||||
return; // nothing to do
|
||||
|
||||
glBindVertexArray(VAO);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, VBO);
|
||||
glBufferData(GL_ARRAY_BUFFER, length*4*6*sizeof(GLfloat), NULL, GL_STREAM_DRAW);
|
||||
GLfloat *vertices = (GLfloat*)glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
|
||||
|
||||
int usage = 0;
|
||||
GLfloat delta_x = 2*char_width/GLfloat(bbWidth);
|
||||
GLfloat delta_y = 2*char_height/GLfloat(bbHeight);
|
||||
GLfloat border_x = 1*2/GLfloat(bbWidth);
|
||||
GLfloat border_y = 2*2/GLfloat(bbHeight);
|
||||
|
||||
GLfloat x = start_x;
|
||||
GLfloat y = start_y;
|
||||
|
||||
for(int i=0; i<length; i++) {
|
||||
u8 c = text[i];
|
||||
|
||||
if(c == '\n') {
|
||||
x = start_x;
|
||||
t = temp;
|
||||
y -= delta_y + border_y;
|
||||
continue;
|
||||
}
|
||||
else if (*text == '\r')
|
||||
{
|
||||
t = temp;
|
||||
|
||||
// do not print spaces, they can be skipped easyly
|
||||
if(c == ' ') {
|
||||
x += delta_x + border_x;
|
||||
continue;
|
||||
}
|
||||
else if (*text == '\t')
|
||||
{
|
||||
//todo: add tabs every something like 4*char_width
|
||||
*t = 0;
|
||||
int cpos = (int)strlen(temp);
|
||||
int newpos = (cpos + 4) & (~3);
|
||||
printString(temp, x, y, z);
|
||||
x = start_x + (char_width*newpos) * 2.0f / bbWidth;
|
||||
t = temp;
|
||||
*t++ = ' ';
|
||||
}
|
||||
else
|
||||
*t++ = *text;
|
||||
|
||||
text++;
|
||||
|
||||
if(c < char_offset || c >= char_count+char_offset) continue;
|
||||
|
||||
vertices[usage++] = x;
|
||||
vertices[usage++] = y;
|
||||
vertices[usage++] = (c-char_offset)*char_width;
|
||||
vertices[usage++] = 0;
|
||||
|
||||
vertices[usage++] = x+delta_x;
|
||||
vertices[usage++] = y;
|
||||
vertices[usage++] = (c-char_offset+1)*char_width;
|
||||
vertices[usage++] = 0;
|
||||
|
||||
vertices[usage++] = x+delta_x;
|
||||
vertices[usage++] = y+delta_y;
|
||||
vertices[usage++] = (c-char_offset+1)*char_width;
|
||||
vertices[usage++] = char_height;
|
||||
|
||||
vertices[usage++] = x;
|
||||
vertices[usage++] = y;
|
||||
vertices[usage++] = (c-char_offset)*char_width;
|
||||
vertices[usage++] = 0;
|
||||
|
||||
vertices[usage++] = x+delta_x;
|
||||
vertices[usage++] = y+delta_y;
|
||||
vertices[usage++] = (c-char_offset+1)*char_width;
|
||||
vertices[usage++] = char_height;
|
||||
|
||||
vertices[usage++] = x;
|
||||
vertices[usage++] = y+delta_y;
|
||||
vertices[usage++] = (c-char_offset)*char_width;
|
||||
vertices[usage++] = char_height;
|
||||
|
||||
x += delta_x + border_x;
|
||||
}
|
||||
glUnmapBuffer(GL_ARRAY_BUFFER);
|
||||
|
||||
// ????
|
||||
if (t != text)
|
||||
{
|
||||
*t = 0;
|
||||
printString(temp, x, y, z);
|
||||
glUseProgram(shader_program);
|
||||
|
||||
if(color != cached_color) {
|
||||
glUniform4f(uniform_color_id, ((color>>16)&0xff)/255.f,((color>>8)&0xff)/255.f,((color>>0)&0xff)/255.f,((color>>24)&0xff)/255.f);
|
||||
cached_color = color;
|
||||
}
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_RECTANGLE, texture);
|
||||
glDrawArrays(GL_TRIANGLES, 0, usage/4);
|
||||
|
||||
// TODO: this after merging with graphic_update
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
glBindVertexArray(0);
|
||||
|
||||
glUseProgram(0);
|
||||
}
|
||||
|
|
|
@ -23,20 +23,16 @@ public:
|
|||
RasterFont();
|
||||
~RasterFont(void);
|
||||
static int debug;
|
||||
|
||||
// some useful constants
|
||||
enum {char_width = 10};
|
||||
enum {char_height = 15};
|
||||
|
||||
// and the happy helper functions
|
||||
void printString(const char *s, double x, double y, double z=0.0);
|
||||
void printCenteredString(const char *s, double y, int screen_width, double z=0.0);
|
||||
|
||||
void printMultilineText(const char *text, double x, double y, double z, int bbWidth, int bbHeight);
|
||||
void printMultilineText(const char *text, double x, double y, double z, int bbWidth, int bbHeight, u32 color);
|
||||
private:
|
||||
int fontOffset;
|
||||
char *temp_buffer;
|
||||
enum {TEMP_BUFFER_SIZE = 64 * 1024};
|
||||
|
||||
u32 VBO;
|
||||
u32 VAO;
|
||||
u32 texture;
|
||||
u32 shader_program;
|
||||
u32 uniform_color_id;
|
||||
u32 cached_color;
|
||||
};
|
||||
|
||||
#endif // _RASTERFONT_H_
|
||||
|
|
|
@ -107,10 +107,14 @@ namespace OGL
|
|||
|
||||
// Declarations and definitions
|
||||
// ----------------------------
|
||||
int s_fps=0;
|
||||
static int s_fps = 0;
|
||||
static GLuint s_ShowEFBCopyRegions_VBO = 0;
|
||||
static GLuint s_ShowEFBCopyRegions_VAO = 0;
|
||||
static GLuint s_Swap_VBO = 0;
|
||||
static GLuint s_Swap_VAO[2];
|
||||
static TargetRectangle s_cached_targetRc;
|
||||
|
||||
|
||||
RasterFont* s_pfont = NULL;
|
||||
static RasterFont* s_pfont = NULL;
|
||||
|
||||
// 1 for no MSAA. Use s_MSAASamples > 1 to check for MSAA.
|
||||
static int s_MSAASamples = 1;
|
||||
|
@ -126,9 +130,9 @@ static std::thread scrshotThread;
|
|||
#endif
|
||||
|
||||
// EFB cache related
|
||||
const u32 EFB_CACHE_RECT_SIZE = 64; // Cache 64x64 blocks.
|
||||
const u32 EFB_CACHE_WIDTH = (EFB_WIDTH + EFB_CACHE_RECT_SIZE - 1) / EFB_CACHE_RECT_SIZE; // round up
|
||||
const u32 EFB_CACHE_HEIGHT = (EFB_HEIGHT + EFB_CACHE_RECT_SIZE - 1) / EFB_CACHE_RECT_SIZE;
|
||||
static const u32 EFB_CACHE_RECT_SIZE = 64; // Cache 64x64 blocks.
|
||||
static const u32 EFB_CACHE_WIDTH = (EFB_WIDTH + EFB_CACHE_RECT_SIZE - 1) / EFB_CACHE_RECT_SIZE; // round up
|
||||
static const u32 EFB_CACHE_HEIGHT = (EFB_HEIGHT + EFB_CACHE_RECT_SIZE - 1) / EFB_CACHE_RECT_SIZE;
|
||||
static bool s_efbCacheValid[2][EFB_CACHE_WIDTH * EFB_CACHE_HEIGHT];
|
||||
static std::vector<u32> s_efbCache[2][EFB_CACHE_WIDTH * EFB_CACHE_HEIGHT]; // 2 for PEEK_Z and PEEK_COLOR
|
||||
|
||||
|
@ -251,7 +255,16 @@ Renderer::Renderer()
|
|||
OSDInternalH = 0;
|
||||
|
||||
s_fps=0;
|
||||
s_ShowEFBCopyRegions_VBO = 0;
|
||||
s_Swap_VBO = 0;
|
||||
s_blendMode = 0;
|
||||
|
||||
// should be invalid, so there will be an upload on the first call
|
||||
s_cached_targetRc.bottom = -1;
|
||||
s_cached_targetRc.top = -1;
|
||||
s_cached_targetRc.left = -1;
|
||||
s_cached_targetRc.right = -1;
|
||||
|
||||
|
||||
InitFPSCounter();
|
||||
|
||||
|
@ -312,6 +325,13 @@ Renderer::Renderer()
|
|||
bSuccess = false;
|
||||
}
|
||||
|
||||
if (!GLEW_ARB_vertex_array_object)
|
||||
{
|
||||
ERROR_LOG(VIDEO, "GPU: OGL ERROR: Need GL_ARB_vertex_array_object.\n"
|
||||
"GPU: Does your video card support OpenGL 3.0?");
|
||||
bSuccess = false;
|
||||
}
|
||||
|
||||
s_bHaveFramebufferBlit = strstr(ptoken, "GL_EXT_framebuffer_blit") != NULL;
|
||||
s_bHaveCoverageMSAA = strstr(ptoken, "GL_NV_framebuffer_multisample_coverage") != NULL;
|
||||
|
||||
|
@ -323,8 +343,8 @@ Renderer::Renderer()
|
|||
return; // TODO: fail
|
||||
|
||||
// Decide frambuffer size
|
||||
s_backbuffer_width = (int)OpenGL_GetBackbufferWidth();
|
||||
s_backbuffer_height = (int)OpenGL_GetBackbufferHeight();
|
||||
s_backbuffer_width = (int)GLInterface->GetBackBufferWidth();
|
||||
s_backbuffer_height = (int)GLInterface->GetBackBufferHeight();
|
||||
|
||||
// Handle VSync on/off
|
||||
#ifdef __APPLE__
|
||||
|
@ -451,17 +471,46 @@ Renderer::Renderer()
|
|||
cgGLSetDebugMode(GL_FALSE);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// creating buffers
|
||||
glGenBuffers(1, &s_ShowEFBCopyRegions_VBO);
|
||||
glGenVertexArrays(1, &s_ShowEFBCopyRegions_VAO);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, s_ShowEFBCopyRegions_VBO);
|
||||
glBindVertexArray( s_ShowEFBCopyRegions_VAO );
|
||||
glEnableClientState(GL_COLOR_ARRAY);
|
||||
glColorPointer (3, GL_FLOAT, sizeof(GLfloat)*5, (GLfloat*)NULL+2);
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
glVertexPointer(2, GL_FLOAT, sizeof(GLfloat)*5, NULL);
|
||||
|
||||
glGenBuffers(1, &s_Swap_VBO);
|
||||
glGenVertexArrays(2, s_Swap_VAO);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, s_Swap_VBO);
|
||||
glBindVertexArray(s_Swap_VAO[0]);
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
glVertexPointer(3, GL_FLOAT, 7*sizeof(GLfloat), NULL);
|
||||
glClientActiveTexture(GL_TEXTURE0);
|
||||
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
glTexCoordPointer(2, GL_FLOAT, 7*sizeof(GLfloat), (GLfloat*)NULL+3);
|
||||
|
||||
glBindVertexArray(s_Swap_VAO[1]);
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
glVertexPointer(3, GL_FLOAT, 7*sizeof(GLfloat), NULL);
|
||||
glClientActiveTexture(GL_TEXTURE0);
|
||||
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
glTexCoordPointer(2, GL_FLOAT, 7*sizeof(GLfloat), (GLfloat*)NULL+3);
|
||||
glClientActiveTexture(GL_TEXTURE1);
|
||||
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
glTexCoordPointer(2, GL_FLOAT, 7*sizeof(GLfloat), (GLfloat*)NULL+5);
|
||||
|
||||
// TODO: this after merging with graphic_update
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
glBindVertexArray(0);
|
||||
|
||||
glStencilFunc(GL_ALWAYS, 0, 0);
|
||||
glBlendFunc(GL_ONE, GL_ONE);
|
||||
|
||||
glViewport(0, 0, GetTargetWidth(), GetTargetHeight()); // Reset The Current Viewport
|
||||
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
|
||||
glShadeModel(GL_SMOOTH);
|
||||
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
glClearDepth(1.0f);
|
||||
|
@ -478,11 +527,6 @@ Renderer::Renderer()
|
|||
glBlendColorEXT(0, 0, 0, 0.5f);
|
||||
glClearDepth(1.0f);
|
||||
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
|
||||
// legacy multitexturing: select texture channel only.
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glClientActiveTexture(GL_TEXTURE0);
|
||||
|
@ -498,6 +542,13 @@ Renderer::~Renderer()
|
|||
{
|
||||
g_Config.bRunning = false;
|
||||
UpdateActiveConfig();
|
||||
|
||||
glDeleteBuffers(1, &s_ShowEFBCopyRegions_VBO);
|
||||
glDeleteVertexArrays(1, &s_ShowEFBCopyRegions_VAO);
|
||||
glDeleteBuffers(1, &s_Swap_VBO);
|
||||
glDeleteVertexArrays(2, s_Swap_VAO);
|
||||
s_ShowEFBCopyRegions_VBO = 0;
|
||||
|
||||
delete s_pfont;
|
||||
s_pfont = 0;
|
||||
|
||||
|
@ -521,7 +572,7 @@ Renderer::~Renderer()
|
|||
void Renderer::DrawDebugInfo()
|
||||
{
|
||||
// Reset viewport for drawing text
|
||||
glViewport(0, 0, OpenGL_GetBackbufferWidth(), OpenGL_GetBackbufferHeight());
|
||||
glViewport(0, 0, GLInterface->GetBackBufferWidth(), GLInterface->GetBackBufferHeight());
|
||||
// Draw various messages on the screen, like FPS, statistics, etc.
|
||||
char debugtext_buffer[8192];
|
||||
char *p = debugtext_buffer;
|
||||
|
@ -545,9 +596,15 @@ void Renderer::DrawDebugInfo()
|
|||
// Set Line Size
|
||||
glLineWidth(3.0f);
|
||||
|
||||
glBegin(GL_LINES);
|
||||
// 2*Coords + 3*Color
|
||||
glBindBuffer(GL_ARRAY_BUFFER, s_ShowEFBCopyRegions_VBO);
|
||||
glBufferData(GL_ARRAY_BUFFER, stats.efb_regions.size() * sizeof(GLfloat) * (2+3)*2*6, NULL, GL_STREAM_DRAW);
|
||||
GLfloat *Vertices = (GLfloat*)glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
|
||||
|
||||
// Draw EFB copy regions rectangles
|
||||
int a = 0;
|
||||
GLfloat color[3] = {0.0f, 1.0f, 1.0f};
|
||||
|
||||
for (std::vector<EFBRectangle>::const_iterator it = stats.efb_regions.begin();
|
||||
it != stats.efb_regions.end(); ++it)
|
||||
{
|
||||
|
@ -558,22 +615,97 @@ void Renderer::DrawDebugInfo()
|
|||
GLfloat x2 = (GLfloat) -1.0f + ((GLfloat)it->right / halfWidth);
|
||||
GLfloat y2 = (GLfloat) 1.0f - ((GLfloat)it->bottom / halfHeight);
|
||||
|
||||
// Draw shadow of rect
|
||||
glColor3f(0.0f, 0.0f, 0.0f);
|
||||
glVertex2f(x, y - 0.01); glVertex2f(x2, y - 0.01);
|
||||
glVertex2f(x, y2 - 0.01); glVertex2f(x2, y2 - 0.01);
|
||||
glVertex2f(x + 0.005, y); glVertex2f(x + 0.005, y2);
|
||||
glVertex2f(x2 + 0.005, y); glVertex2f(x2 + 0.005, y2);
|
||||
|
||||
// Draw rect
|
||||
glColor3f(0.0f, 1.0f, 1.0f);
|
||||
glVertex2f(x, y); glVertex2f(x2, y);
|
||||
glVertex2f(x, y2); glVertex2f(x2, y2);
|
||||
glVertex2f(x, y); glVertex2f(x, y2);
|
||||
glVertex2f(x2, y); glVertex2f(x2, y2);
|
||||
Vertices[a++] = x;
|
||||
Vertices[a++] = y;
|
||||
Vertices[a++] = color[0];
|
||||
Vertices[a++] = color[1];
|
||||
Vertices[a++] = color[2];
|
||||
|
||||
Vertices[a++] = x2;
|
||||
Vertices[a++] = y;
|
||||
Vertices[a++] = color[0];
|
||||
Vertices[a++] = color[1];
|
||||
Vertices[a++] = color[2];
|
||||
|
||||
|
||||
Vertices[a++] = x2;
|
||||
Vertices[a++] = y;
|
||||
Vertices[a++] = color[0];
|
||||
Vertices[a++] = color[1];
|
||||
Vertices[a++] = color[2];
|
||||
|
||||
Vertices[a++] = x2;
|
||||
Vertices[a++] = y2;
|
||||
Vertices[a++] = color[0];
|
||||
Vertices[a++] = color[1];
|
||||
Vertices[a++] = color[2];
|
||||
|
||||
|
||||
Vertices[a++] = x2;
|
||||
Vertices[a++] = y2;
|
||||
Vertices[a++] = color[0];
|
||||
Vertices[a++] = color[1];
|
||||
Vertices[a++] = color[2];
|
||||
|
||||
Vertices[a++] = x;
|
||||
Vertices[a++] = y2;
|
||||
Vertices[a++] = color[0];
|
||||
Vertices[a++] = color[1];
|
||||
Vertices[a++] = color[2];
|
||||
|
||||
|
||||
Vertices[a++] = x;
|
||||
Vertices[a++] = y2;
|
||||
Vertices[a++] = color[0];
|
||||
Vertices[a++] = color[1];
|
||||
Vertices[a++] = color[2];
|
||||
|
||||
Vertices[a++] = x;
|
||||
Vertices[a++] = y;
|
||||
Vertices[a++] = color[0];
|
||||
Vertices[a++] = color[1];
|
||||
Vertices[a++] = color[2];
|
||||
|
||||
|
||||
Vertices[a++] = x;
|
||||
Vertices[a++] = y;
|
||||
Vertices[a++] = color[0];
|
||||
Vertices[a++] = color[1];
|
||||
Vertices[a++] = color[2];
|
||||
|
||||
Vertices[a++] = x2;
|
||||
Vertices[a++] = y2;
|
||||
Vertices[a++] = color[0];
|
||||
Vertices[a++] = color[1];
|
||||
Vertices[a++] = color[2];
|
||||
|
||||
|
||||
Vertices[a++] = x2;
|
||||
Vertices[a++] = y;
|
||||
Vertices[a++] = color[0];
|
||||
Vertices[a++] = color[1];
|
||||
Vertices[a++] = color[2];
|
||||
|
||||
Vertices[a++] = x;
|
||||
Vertices[a++] = y2;
|
||||
Vertices[a++] = color[0];
|
||||
Vertices[a++] = color[1];
|
||||
Vertices[a++] = color[2];
|
||||
|
||||
// TO DO: build something nicer here
|
||||
GLfloat temp = color[0];
|
||||
color[0] = color[1];
|
||||
color[1] = color[2];
|
||||
color[2] = temp;
|
||||
}
|
||||
|
||||
glEnd();
|
||||
glUnmapBuffer(GL_ARRAY_BUFFER);
|
||||
|
||||
glBindVertexArray( s_ShowEFBCopyRegions_VAO );
|
||||
glDrawArrays(GL_LINES, 0, stats.efb_regions.size() * 2*6);
|
||||
|
||||
// TODO: this after merging with graphic_update
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
glBindVertexArray(0);
|
||||
|
||||
// Restore Line Size
|
||||
glLineWidth(lSize);
|
||||
|
@ -598,18 +730,20 @@ void Renderer::DrawDebugInfo()
|
|||
|
||||
void Renderer::RenderText(const char *text, int left, int top, u32 color)
|
||||
{
|
||||
const int nBackbufferWidth = (int)OpenGL_GetBackbufferWidth();
|
||||
const int nBackbufferHeight = (int)OpenGL_GetBackbufferHeight();
|
||||
const int nBackbufferWidth = (int)GLInterface->GetBackBufferWidth();
|
||||
const int nBackbufferHeight = (int)GLInterface->GetBackBufferHeight();
|
||||
|
||||
glColor4f(((color>>16) & 0xff)/255.0f, ((color>> 8) & 0xff)/255.0f,
|
||||
((color>> 0) & 0xff)/255.0f, ((color>>24) & 0xFF)/255.0f);
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
s_pfont->printMultilineText(text,
|
||||
left * 2.0f / (float)nBackbufferWidth - 1,
|
||||
1 - top * 2.0f / (float)nBackbufferHeight,
|
||||
0, nBackbufferWidth, nBackbufferHeight);
|
||||
0, nBackbufferWidth, nBackbufferHeight, color);
|
||||
|
||||
GL_REPORT_ERRORD();
|
||||
|
||||
glDisable(GL_BLEND);
|
||||
}
|
||||
|
||||
TargetRectangle Renderer::ConvertEFBRectangle(const EFBRectangle& rc)
|
||||
|
@ -1130,43 +1264,44 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,cons
|
|||
// Render to the real buffer now.
|
||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); // switch to the window backbuffer
|
||||
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, read_texture);
|
||||
if (applyShader)
|
||||
{
|
||||
glBegin(GL_QUADS);
|
||||
glTexCoord2f(targetRc.left, targetRc.bottom);
|
||||
glMultiTexCoord2fARB(GL_TEXTURE1, 0, 0);
|
||||
glVertex2f(-1, -1);
|
||||
|
||||
glTexCoord2f(targetRc.left, targetRc.top);
|
||||
glMultiTexCoord2fARB(GL_TEXTURE1, 0, 1);
|
||||
glVertex2f(-1, 1);
|
||||
if(!( s_cached_targetRc == targetRc)) {
|
||||
GLfloat vertices[] = {
|
||||
-1.0f, -1.0f, 1.0f,
|
||||
(GLfloat)targetRc.left, (GLfloat)targetRc.bottom,
|
||||
0.0f, 0.0f,
|
||||
|
||||
-1.0f, 1.0f, 1.0f,
|
||||
(GLfloat)targetRc.left, (GLfloat)targetRc.top,
|
||||
0.0f, 1.0f,
|
||||
|
||||
1.0f, 1.0f, 1.0f,
|
||||
(GLfloat)targetRc.right, (GLfloat)targetRc.top,
|
||||
1.0f, 1.0f,
|
||||
|
||||
1.0f, -1.0f, 1.0f,
|
||||
(GLfloat)targetRc.right, (GLfloat)targetRc.bottom,
|
||||
1.0f, 0.0f
|
||||
};
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, s_Swap_VBO);
|
||||
glBufferData(GL_ARRAY_BUFFER, 4*7*sizeof(GLfloat), vertices, GL_STREAM_DRAW);
|
||||
|
||||
// TODO: this after merging with graphic_update
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
|
||||
s_cached_targetRc = targetRc;
|
||||
}
|
||||
|
||||
glBindVertexArray(s_Swap_VAO[applyShader]);
|
||||
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
|
||||
|
||||
glTexCoord2f(targetRc.right, targetRc.top);
|
||||
glMultiTexCoord2fARB(GL_TEXTURE1, 1, 1);
|
||||
glVertex2f( 1, 1);
|
||||
|
||||
glTexCoord2f(targetRc.right, targetRc.bottom);
|
||||
glMultiTexCoord2fARB(GL_TEXTURE1, 1, 0);
|
||||
glVertex2f( 1, -1);
|
||||
glEnd();
|
||||
|
||||
// TODO: this after merging with graphic_update
|
||||
glBindVertexArray(0);
|
||||
|
||||
if(applyShader)
|
||||
PixelShaderCache::DisableShader();
|
||||
}
|
||||
else
|
||||
{
|
||||
glBegin(GL_QUADS);
|
||||
glTexCoord2f(targetRc.left, targetRc.bottom);
|
||||
glVertex2f(-1, -1);
|
||||
|
||||
glTexCoord2f(targetRc.left, targetRc.top);
|
||||
glVertex2f(-1, 1);
|
||||
|
||||
glTexCoord2f(targetRc.right, targetRc.top);
|
||||
glVertex2f( 1, 1);
|
||||
|
||||
glTexCoord2f(targetRc.right, targetRc.bottom);
|
||||
glVertex2f( 1, -1);
|
||||
glEnd();
|
||||
}
|
||||
}
|
||||
|
||||
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
|
||||
|
@ -1294,7 +1429,7 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,cons
|
|||
|
||||
SetWindowSize(fbWidth, fbHeight);
|
||||
|
||||
OpenGL_Update(); // just updates the render window position and the backbuffer size
|
||||
GLInterface->Update(); // just updates the render window position and the backbuffer size
|
||||
|
||||
bool xfbchanged = false;
|
||||
|
||||
|
@ -1308,8 +1443,8 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,cons
|
|||
}
|
||||
|
||||
bool WindowResized = false;
|
||||
int W = (int)OpenGL_GetBackbufferWidth();
|
||||
int H = (int)OpenGL_GetBackbufferHeight();
|
||||
int W = (int)GLInterface->GetBackBufferWidth();
|
||||
int H = (int)GLInterface->GetBackBufferHeight();
|
||||
if (W != s_backbuffer_width || H != s_backbuffer_height || s_LastEFBScale != g_ActiveConfig.iEFBScale)
|
||||
{
|
||||
WindowResized = true;
|
||||
|
@ -1354,7 +1489,7 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,cons
|
|||
GL_REPORT_ERRORD();
|
||||
|
||||
// Copy the rendered frame to the real window
|
||||
OpenGL_SwapBuffers();
|
||||
GLInterface->Swap();
|
||||
|
||||
GL_REPORT_ERRORD();
|
||||
|
||||
|
|
|
@ -56,6 +56,13 @@
|
|||
namespace OGL
|
||||
{
|
||||
|
||||
struct VBOCache {
|
||||
GLuint vbo;
|
||||
GLuint vao;
|
||||
TargetRectangle targetSource;
|
||||
};
|
||||
static std::map<u64,VBOCache> s_VBO;
|
||||
|
||||
static u32 s_TempFramebuffer = 0;
|
||||
|
||||
static const GLint c_MinLinearFilter[8] = {
|
||||
|
@ -106,6 +113,8 @@ TextureCache::TCacheEntry::~TCacheEntry()
|
|||
TextureCache::TCacheEntry::TCacheEntry()
|
||||
{
|
||||
glGenTextures(1, &texture);
|
||||
currmode.hex = 0;
|
||||
currmode1.hex = 0;
|
||||
GL_REPORT_ERRORD();
|
||||
}
|
||||
|
||||
|
@ -118,7 +127,9 @@ void TextureCache::TCacheEntry::Bind(unsigned int stage)
|
|||
// TODO: is this already done somewhere else?
|
||||
TexMode0 &tm0 = bpmem.tex[stage >> 2].texMode0[stage & 3];
|
||||
TexMode1 &tm1 = bpmem.tex[stage >> 2].texMode1[stage & 3];
|
||||
SetTextureParameters(tm0, tm1);
|
||||
|
||||
if(currmode.hex != tm0.hex || currmode1.hex != tm1.hex)
|
||||
SetTextureParameters(tm0, tm1);
|
||||
}
|
||||
|
||||
bool TextureCache::TCacheEntry::Save(const char filename[], unsigned int level)
|
||||
|
@ -304,13 +315,59 @@ void TextureCache::TCacheEntry::FromRenderTarget(u32 dstAddr, unsigned int dstFo
|
|||
GL_REPORT_ERRORD();
|
||||
|
||||
TargetRectangle targetSource = g_renderer->ConvertEFBRectangle(srcRect);
|
||||
GL_REPORT_ERRORD();
|
||||
|
||||
// should be unique enough, if not, vbo will "only" be uploaded to much
|
||||
u64 targetSourceHash = u64(targetSource.left)<<48 | u64(targetSource.top)<<32 | u64(targetSource.right)<<16 | u64(targetSource.bottom);
|
||||
std::map<u64, VBOCache>::iterator vbo_it = s_VBO.find(targetSourceHash);
|
||||
|
||||
if(vbo_it == s_VBO.end()) {
|
||||
VBOCache item;
|
||||
item.targetSource.bottom = -1;
|
||||
item.targetSource.top = -1;
|
||||
item.targetSource.left = -1;
|
||||
item.targetSource.right = -1;
|
||||
glGenBuffers(1, &item.vbo);
|
||||
glGenVertexArrays(1, &item.vao);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, item.vbo);
|
||||
glBindVertexArray(item.vao);
|
||||
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
glVertexPointer(2, GL_FLOAT, sizeof(GLfloat)*4, 0);
|
||||
|
||||
glClientActiveTexture(GL_TEXTURE0);
|
||||
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
glTexCoordPointer(2, GL_FLOAT, sizeof(GLfloat)*4, (GLfloat*)NULL + 2);
|
||||
|
||||
vbo_it = s_VBO.insert(std::pair<u64,VBOCache>(targetSourceHash, item)).first;
|
||||
}
|
||||
if(!(vbo_it->second.targetSource == targetSource)) {
|
||||
GLfloat vertices[] = {
|
||||
-1.f, 1.f,
|
||||
(GLfloat)targetSource.left, (GLfloat)targetSource.bottom,
|
||||
-1.f, -1.f,
|
||||
(GLfloat)targetSource.left, (GLfloat)targetSource.top,
|
||||
1.f, -1.f,
|
||||
(GLfloat)targetSource.right, (GLfloat)targetSource.top,
|
||||
1.f, 1.f,
|
||||
(GLfloat)targetSource.right, (GLfloat)targetSource.bottom
|
||||
};
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vbo_it->second.vbo);
|
||||
glBufferData(GL_ARRAY_BUFFER, 4*4*sizeof(GLfloat), vertices, GL_STREAM_DRAW);
|
||||
|
||||
// TODO: this after merging with graphic_update
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
|
||||
vbo_it->second.targetSource = targetSource;
|
||||
}
|
||||
|
||||
glBegin(GL_QUADS);
|
||||
glTexCoord2f((GLfloat)targetSource.left, (GLfloat)targetSource.bottom); glVertex2f(-1, 1);
|
||||
glTexCoord2f((GLfloat)targetSource.left, (GLfloat)targetSource.top ); glVertex2f(-1, -1);
|
||||
glTexCoord2f((GLfloat)targetSource.right, (GLfloat)targetSource.top ); glVertex2f( 1, -1);
|
||||
glTexCoord2f((GLfloat)targetSource.right, (GLfloat)targetSource.bottom); glVertex2f( 1, 1);
|
||||
glEnd();
|
||||
glBindVertexArray(vbo_it->second.vao);
|
||||
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
|
||||
|
||||
// TODO: this after merging with graphic_update
|
||||
glBindVertexArray(0);
|
||||
|
||||
GL_REPORT_ERRORD();
|
||||
|
||||
|
@ -357,6 +414,9 @@ void TextureCache::TCacheEntry::FromRenderTarget(u32 dstAddr, unsigned int dstFo
|
|||
|
||||
void TextureCache::TCacheEntry::SetTextureParameters(const TexMode0 &newmode, const TexMode1 &newmode1)
|
||||
{
|
||||
currmode = newmode;
|
||||
currmode1 = newmode1;
|
||||
|
||||
// TODO: not used anywhere
|
||||
TexMode0 mode = newmode;
|
||||
//mode1 = newmode1;
|
||||
|
@ -388,13 +448,24 @@ void TextureCache::TCacheEntry::SetTextureParameters(const TexMode0 &newmode, co
|
|||
(float)(1 << g_ActiveConfig.iMaxAnisotropy));
|
||||
}
|
||||
|
||||
TextureCache::TextureCache()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
TextureCache::~TextureCache()
|
||||
{
|
||||
if (s_TempFramebuffer)
|
||||
for(std::map<u64, VBOCache>::iterator it = s_VBO.begin(); it != s_VBO.end(); it++) {
|
||||
glDeleteBuffers(1, &it->second.vbo);
|
||||
glDeleteVertexArrays(1, &it->second.vao);
|
||||
}
|
||||
s_VBO.clear();
|
||||
|
||||
if (s_TempFramebuffer)
|
||||
{
|
||||
glDeleteFramebuffersEXT(1, (GLuint*)&s_TempFramebuffer);
|
||||
s_TempFramebuffer = 0;
|
||||
}
|
||||
glDeleteFramebuffersEXT(1, (GLuint*)&s_TempFramebuffer);
|
||||
s_TempFramebuffer = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void TextureCache::DisableStage(unsigned int stage)
|
||||
|
|
|
@ -32,6 +32,7 @@ namespace OGL
|
|||
class TextureCache : public ::TextureCache
|
||||
{
|
||||
public:
|
||||
TextureCache();
|
||||
static void DisableStage(unsigned int stage);
|
||||
|
||||
private:
|
||||
|
@ -66,6 +67,8 @@ private:
|
|||
|
||||
private:
|
||||
void SetTextureParameters(const TexMode0 &newmode, const TexMode1 &newmode1);
|
||||
TexMode0 currmode;
|
||||
TexMode1 currmode1;
|
||||
};
|
||||
|
||||
~TextureCache();
|
||||
|
|
|
@ -57,6 +57,14 @@ static FRAGMENTSHADER s_yuyvToRgbProgram;
|
|||
const u32 NUM_ENCODING_PROGRAMS = 64;
|
||||
static FRAGMENTSHADER s_encodingPrograms[NUM_ENCODING_PROGRAMS];
|
||||
|
||||
static GLuint s_encode_VBO = 0;
|
||||
static GLuint s_encode_VAO = 0;
|
||||
static GLuint s_decode_VBO = 0;
|
||||
static GLuint s_decode_VAO = 0;
|
||||
static TargetRectangle s_cached_sourceRc;
|
||||
static int s_cached_srcWidth = 0;
|
||||
static int s_cached_srcHeight = 0;
|
||||
|
||||
void CreateRgbToYuyvProgram()
|
||||
{
|
||||
// Output is BGRA because that is slightly faster than RGBA.
|
||||
|
@ -140,9 +148,40 @@ FRAGMENTSHADER &GetOrCreateEncodingShader(u32 format)
|
|||
void Init()
|
||||
{
|
||||
glGenFramebuffersEXT(1, &s_texConvFrameBuffer);
|
||||
|
||||
glGenBuffers(1, &s_encode_VBO );
|
||||
glGenVertexArrays(1, &s_encode_VAO );
|
||||
glBindBuffer(GL_ARRAY_BUFFER, s_encode_VBO );
|
||||
glBindVertexArray( s_encode_VAO );
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
glVertexPointer(2, GL_FLOAT, 4*sizeof(GLfloat), NULL);
|
||||
glClientActiveTexture(GL_TEXTURE0);
|
||||
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
glTexCoordPointer(2, GL_FLOAT, 4*sizeof(GLfloat), (GLfloat*)NULL + 2);
|
||||
s_cached_sourceRc.top = -1;
|
||||
s_cached_sourceRc.bottom = -1;
|
||||
s_cached_sourceRc.left = -1;
|
||||
s_cached_sourceRc.right = -1;
|
||||
|
||||
glGenBuffers(1, &s_decode_VBO );
|
||||
glGenVertexArrays(1, &s_decode_VAO );
|
||||
glBindBuffer(GL_ARRAY_BUFFER, s_decode_VBO );
|
||||
glBindVertexArray( s_decode_VAO );
|
||||
s_cached_srcWidth = -1;
|
||||
s_cached_srcHeight = -1;
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
glVertexPointer(2, GL_FLOAT, sizeof(GLfloat)*4, NULL);
|
||||
glClientActiveTexture(GL_TEXTURE0);
|
||||
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
glTexCoordPointer(2, GL_FLOAT, sizeof(GLfloat)*4, (GLfloat*)NULL+2);
|
||||
|
||||
// TODO: this after merging with graphic_update
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
glBindVertexArray(0);
|
||||
|
||||
glGenRenderbuffersEXT(1, &s_dstRenderBuffer);
|
||||
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, s_dstRenderBuffer);
|
||||
|
||||
glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_RGBA, renderBufferWidth, renderBufferHeight);
|
||||
|
||||
s_srcTextureWidth = 0;
|
||||
|
@ -162,6 +201,10 @@ void Shutdown()
|
|||
glDeleteTextures(1, &s_srcTexture);
|
||||
glDeleteRenderbuffersEXT(1, &s_dstRenderBuffer);
|
||||
glDeleteFramebuffersEXT(1, &s_texConvFrameBuffer);
|
||||
glDeleteBuffers(1, &s_encode_VBO );
|
||||
glDeleteVertexArrays(1, &s_encode_VAO );
|
||||
glDeleteBuffers(1, &s_decode_VBO );
|
||||
glDeleteVertexArrays(1, &s_decode_VAO );
|
||||
|
||||
s_rgbToYuyvProgram.Destroy();
|
||||
s_yuyvToRgbProgram.Destroy();
|
||||
|
@ -213,13 +256,33 @@ void EncodeToRamUsingShader(FRAGMENTSHADER& shader, GLuint srcTexture, const Tar
|
|||
|
||||
PixelShaderCache::SetCurrentShader(shader.glprogid);
|
||||
|
||||
// Draw...
|
||||
glBegin(GL_QUADS);
|
||||
glTexCoord2f((float)sourceRc.left, (float)sourceRc.top); glVertex2f(-1,-1);
|
||||
glTexCoord2f((float)sourceRc.left, (float)sourceRc.bottom); glVertex2f(-1,1);
|
||||
glTexCoord2f((float)sourceRc.right, (float)sourceRc.bottom); glVertex2f(1,1);
|
||||
glTexCoord2f((float)sourceRc.right, (float)sourceRc.top); glVertex2f(1,-1);
|
||||
glEnd();
|
||||
GL_REPORT_ERRORD();
|
||||
if(!(s_cached_sourceRc == sourceRc)) {
|
||||
GLfloat vertices[] = {
|
||||
-1.f, -1.f,
|
||||
(float)sourceRc.left, (float)sourceRc.top,
|
||||
-1.f, 1.f,
|
||||
(float)sourceRc.left, (float)sourceRc.bottom,
|
||||
1.f, 1.f,
|
||||
(float)sourceRc.right, (float)sourceRc.bottom,
|
||||
1.f, -1.f,
|
||||
(float)sourceRc.right, (float)sourceRc.top
|
||||
};
|
||||
glBindBuffer(GL_ARRAY_BUFFER, s_encode_VBO );
|
||||
glBufferData(GL_ARRAY_BUFFER, 4*4*sizeof(GLfloat), vertices, GL_STREAM_DRAW);
|
||||
|
||||
// TODO: this after merging with graphic_update
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
|
||||
s_cached_sourceRc = sourceRc;
|
||||
}
|
||||
|
||||
glBindVertexArray( s_encode_VAO );
|
||||
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
|
||||
|
||||
// TODO: this after merging with graphic_update
|
||||
glBindVertexArray(0);
|
||||
|
||||
GL_REPORT_ERRORD();
|
||||
|
||||
// .. and then read back the results.
|
||||
|
@ -375,18 +438,41 @@ void DecodeToTexture(u32 xfbAddr, int srcWidth, int srcHeight, GLuint destTextur
|
|||
PixelShaderCache::SetCurrentShader(s_yuyvToRgbProgram.glprogid);
|
||||
|
||||
GL_REPORT_ERRORD();
|
||||
|
||||
glBegin(GL_QUADS);
|
||||
glTexCoord2f((float)srcFmtWidth, (float)srcHeight); glVertex2f(1,-1);
|
||||
glTexCoord2f((float)srcFmtWidth, 0); glVertex2f(1,1);
|
||||
glTexCoord2f(0, 0); glVertex2f(-1,1);
|
||||
glTexCoord2f(0, (float)srcHeight); glVertex2f(-1,-1);
|
||||
glEnd();
|
||||
|
||||
if(s_cached_srcHeight != srcHeight || s_cached_srcWidth != srcWidth) {
|
||||
GLfloat vertices[] = {
|
||||
1.f, -1.f,
|
||||
(float)srcFmtWidth, (float)srcHeight,
|
||||
1.f, 1.f,
|
||||
(float)srcFmtWidth, 0.f,
|
||||
-1.f, 1.f,
|
||||
0.f, 0.f,
|
||||
-1.f, -1.f,
|
||||
0.f, (float)srcHeight
|
||||
};
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, s_decode_VBO );
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat)*4*4, vertices, GL_STREAM_DRAW);
|
||||
|
||||
// TODO: this after merging with graphic_update
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
|
||||
s_cached_srcHeight = srcHeight;
|
||||
s_cached_srcWidth = srcWidth;
|
||||
}
|
||||
|
||||
glBindVertexArray( s_decode_VAO );
|
||||
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
|
||||
|
||||
// TODO: this after merging with graphic_update
|
||||
glBindVertexArray(0);
|
||||
|
||||
GL_REPORT_ERRORD();
|
||||
|
||||
// reset state
|
||||
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
|
||||
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, 0, 0);
|
||||
TextureCache::DisableStage(0);
|
||||
TextureCache::DisableStage(0);
|
||||
|
||||
VertexShaderManager::SetViewportChanged();
|
||||
|
||||
|
|
|
@ -64,9 +64,6 @@ VertexManager::VertexManager()
|
|||
// max_Index_size = MAXIBUFFERSIZE;
|
||||
//
|
||||
//GL_REPORT_ERRORD();
|
||||
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
GL_REPORT_ERRORD();
|
||||
}
|
||||
|
||||
void VertexManager::CreateDeviceObjects()
|
||||
|
|
|
@ -165,7 +165,8 @@ bool VideoBackend::Initialize(void *&window_handle)
|
|||
g_Config.VerifyValidity();
|
||||
UpdateActiveConfig();
|
||||
|
||||
if (!OpenGL_Create(window_handle))
|
||||
InitInterface();
|
||||
if (!GLInterface->Create(window_handle))
|
||||
return false;
|
||||
|
||||
s_BackendInitialized = true;
|
||||
|
@ -177,7 +178,7 @@ bool VideoBackend::Initialize(void *&window_handle)
|
|||
// Run from the graphics thread
|
||||
void VideoBackend::Video_Prepare()
|
||||
{
|
||||
OpenGL_MakeCurrent();
|
||||
GLInterface->MakeCurrent();
|
||||
|
||||
g_renderer = new Renderer;
|
||||
|
||||
|
@ -236,7 +237,7 @@ void VideoBackend::Shutdown()
|
|||
g_renderer = NULL;
|
||||
g_texture_cache = NULL;
|
||||
}
|
||||
OpenGL_Shutdown();
|
||||
GLInterface->Shutdown();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -26,13 +26,25 @@ if(wxWidgets_FOUND)
|
|||
endif(wxWidgets_FOUND)
|
||||
|
||||
set(LIBS videocommon
|
||||
GLEW
|
||||
SOIL
|
||||
common
|
||||
${OPENGL_LIBRARIES}
|
||||
${X11_LIBRARIES}
|
||||
${wxWidgets_LIBRARIES})
|
||||
if(USE_EGL)
|
||||
set(LIBS ${LIBS}
|
||||
EGL)
|
||||
endif()
|
||||
|
||||
if(USE_GLES)
|
||||
set(SRCS ${SRCS}
|
||||
../Plugin_VideoOGL/Src/GLUtil.cpp)
|
||||
set(LIBS ${LIBS}
|
||||
GLESv2)
|
||||
else()
|
||||
set(LIBS ${LIBS}
|
||||
GLEW
|
||||
${OPENGL_LIBRARIES})
|
||||
endif()
|
||||
if(NOT (${CMAKE_SYSTEM_NAME} MATCHES "Darwin"))
|
||||
set(LIBS ${LIBS} clrun)
|
||||
endif()
|
||||
|
|
|
@ -25,7 +25,6 @@
|
|||
#include "DebugUtil.h"
|
||||
#include "HwRasterizer.h"
|
||||
#include "SWCommandProcessor.h"
|
||||
#include "../../Plugin_VideoOGL/Src/GLUtil.h"
|
||||
#include "HW/Memmap.h"
|
||||
#include "Core.h"
|
||||
|
||||
|
@ -33,7 +32,7 @@ namespace EfbCopy
|
|||
{
|
||||
void CopyToXfb()
|
||||
{
|
||||
OpenGL_Update(); // just updates the render window position and the backbuffer size
|
||||
GLInterface->Update(); // just updates the render window position and the backbuffer size
|
||||
|
||||
if (!g_SWVideoConfig.bHwRasterizer)
|
||||
{
|
||||
|
|
|
@ -29,163 +29,354 @@
|
|||
|
||||
namespace HwRasterizer
|
||||
{
|
||||
float efbHalfWidth;
|
||||
float efbHalfHeight;
|
||||
bool hasTexture;
|
||||
float efbHalfWidth;
|
||||
float efbHalfHeight;
|
||||
bool hasTexture;
|
||||
|
||||
u8 *temp;
|
||||
u8 *temp;
|
||||
|
||||
void Init()
|
||||
{
|
||||
efbHalfWidth = EFB_WIDTH / 2.0f;
|
||||
efbHalfHeight = 480 / 2.0f;
|
||||
// Programs
|
||||
static GLuint colProg, texProg, clearProg;
|
||||
|
||||
temp = (u8*)AllocateMemoryPages(TEMP_SIZE);
|
||||
}
|
||||
// Color
|
||||
static GLint col_apos = -1, col_atex = -1;
|
||||
// Tex
|
||||
static GLint tex_apos = -1, tex_atex = -1, tex_utex = -1;
|
||||
// Clear shader
|
||||
static GLint clear_apos = -1, clear_ucol = -1;
|
||||
|
||||
void LoadTexture()
|
||||
{
|
||||
FourTexUnits &texUnit = bpmem.tex[0];
|
||||
u32 imageAddr = texUnit.texImage3[0].image_base;
|
||||
void CreateShaders()
|
||||
{
|
||||
// Color Vertices
|
||||
static const char *fragcolText =
|
||||
"varying " PREC " vec4 TexCoordOut;\n"
|
||||
"void main() {\n"
|
||||
" gl_FragColor = TexCoordOut;\n"
|
||||
"}\n";
|
||||
// Texture Vertices
|
||||
static const char *fragtexText =
|
||||
"varying " PREC " vec4 TexCoordOut;\n"
|
||||
"uniform " TEXTYPE " Texture;\n"
|
||||
"void main() {\n"
|
||||
" gl_FragColor = " TEXFUNC "(Texture, TexCoordOut.xy);\n"
|
||||
"}\n";
|
||||
// Clear shader
|
||||
static const char *fragclearText =
|
||||
"uniform vec4 Color;\n"
|
||||
"void main() {\n"
|
||||
" gl_FragColor = Color;\n"
|
||||
"}\n";
|
||||
// Generic passthrough vertice shaders
|
||||
static const char *vertShaderText =
|
||||
"attribute vec4 pos;\n"
|
||||
"attribute vec4 TexCoordIn;\n "
|
||||
"varying vec4 TexCoordOut;\n "
|
||||
"void main() {\n"
|
||||
" gl_Position = pos;\n"
|
||||
" TexCoordOut = TexCoordIn;\n"
|
||||
"}\n";
|
||||
static const char *vertclearText =
|
||||
"attribute vec4 pos;\n"
|
||||
"void main() {\n"
|
||||
" gl_Position = pos;\n"
|
||||
"}\n";
|
||||
|
||||
TexCacheEntry &cacheEntry = textures[imageAddr];
|
||||
cacheEntry.Update();
|
||||
// Color Program
|
||||
colProg = OpenGL_CompileProgram(vertShaderText, fragcolText);
|
||||
|
||||
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, cacheEntry.texture);
|
||||
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, texUnit.texMode0[0].mag_filter ? GL_LINEAR : GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, (texUnit.texMode0[0].min_filter >= 4) ? GL_LINEAR : GL_NEAREST);
|
||||
}
|
||||
// Texture Program
|
||||
texProg = OpenGL_CompileProgram(vertShaderText, fragtexText);
|
||||
|
||||
void BeginTriangles()
|
||||
{
|
||||
// disabling depth test sometimes allows more things to be visible
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glEnable(GL_BLEND);
|
||||
// Clear Program
|
||||
clearProg = OpenGL_CompileProgram(vertclearText, fragclearText);
|
||||
|
||||
hasTexture = bpmem.tevorders[0].enable0;
|
||||
// Color attributes
|
||||
col_apos = glGetAttribLocation(colProg, "pos");
|
||||
col_atex = glGetAttribLocation(colProg, "TexCoordIn");
|
||||
// Texture attributes
|
||||
tex_apos = glGetAttribLocation(texProg, "pos");
|
||||
tex_atex = glGetAttribLocation(texProg, "TexCoordIn");
|
||||
tex_utex = glGetUniformLocation(texProg, "Texture");
|
||||
// Clear attributes
|
||||
clear_apos = glGetAttribLocation(clearProg, "pos");
|
||||
clear_ucol = glGetUniformLocation(clearProg, "Color");
|
||||
}
|
||||
|
||||
if (hasTexture)
|
||||
LoadTexture();
|
||||
}
|
||||
void Init()
|
||||
{
|
||||
efbHalfWidth = EFB_WIDTH / 2.0f;
|
||||
efbHalfHeight = 480 / 2.0f;
|
||||
|
||||
void EndTriangles()
|
||||
{
|
||||
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
|
||||
temp = (u8*)AllocateMemoryPages(TEMP_SIZE);
|
||||
}
|
||||
void Shutdown()
|
||||
{
|
||||
glDeleteProgram(colProg);
|
||||
glDeleteProgram(texProg);
|
||||
glDeleteProgram(clearProg);
|
||||
}
|
||||
void Prepare()
|
||||
{
|
||||
//legacy multitexturing: select texture channel only.
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 4); // 4-byte pixel alignment
|
||||
#ifndef USE_GLES
|
||||
glShadeModel(GL_SMOOTH);
|
||||
glDisable(GL_BLEND);
|
||||
glClearDepth(1.0f);
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
glDisable(GL_LIGHTING);
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glDisable(GL_BLEND);
|
||||
}
|
||||
glClientActiveTexture(GL_TEXTURE0);
|
||||
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
||||
glEnable(GL_TEXTURE_RECTANGLE_ARB);
|
||||
glStencilFunc(GL_ALWAYS, 0, 0);
|
||||
glDisable(GL_STENCIL_TEST);
|
||||
#endif
|
||||
// used by hw rasterizer if it enables blending and depth test
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glDepthFunc(GL_LEQUAL);
|
||||
|
||||
void DrawColorVertex(OutputVertexData *v)
|
||||
{
|
||||
glColor3ub(v->color[0][OutputVertexData::RED_C], v->color[0][OutputVertexData::GRN_C], v->color[0][OutputVertexData::BLU_C]);
|
||||
glVertex3f(v->screenPosition.x / efbHalfWidth - 1.0f, 1.0f - v->screenPosition.y / efbHalfHeight, v->screenPosition.z / (float)0x00ffffff);
|
||||
}
|
||||
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
|
||||
CreateShaders();
|
||||
GL_REPORT_ERRORD();
|
||||
}
|
||||
static float width, height;
|
||||
void LoadTexture()
|
||||
{
|
||||
FourTexUnits &texUnit = bpmem.tex[0];
|
||||
u32 imageAddr = texUnit.texImage3[0].image_base;
|
||||
// Texture Rectangle uses pixel coordinates
|
||||
// While GLES uses texture coordinates
|
||||
#ifdef USE_GLES
|
||||
width = texUnit.texImage0[0].width;
|
||||
height = texUnit.texImage0[0].height;
|
||||
#else
|
||||
width = 1;
|
||||
height = 1;
|
||||
#endif
|
||||
TexCacheEntry &cacheEntry = textures[imageAddr];
|
||||
cacheEntry.Update();
|
||||
|
||||
void DrawTextureVertex(OutputVertexData *v)
|
||||
{
|
||||
float s = v->texCoords[0].x;
|
||||
float t = v->texCoords[0].y;
|
||||
glTexCoord2f(s, t);
|
||||
glBindTexture(TEX2D, cacheEntry.texture);
|
||||
glTexParameteri(TEX2D, GL_TEXTURE_MAG_FILTER, texUnit.texMode0[0].mag_filter ? GL_LINEAR : GL_NEAREST);
|
||||
glTexParameteri(TEX2D, GL_TEXTURE_MIN_FILTER, (texUnit.texMode0[0].min_filter >= 4) ? GL_LINEAR : GL_NEAREST);
|
||||
GL_REPORT_ERRORD();
|
||||
}
|
||||
|
||||
float x = (v->screenPosition.x / efbHalfWidth) - 1.0f;
|
||||
float y = 1.0f - (v->screenPosition.y / efbHalfHeight);
|
||||
float z = v->screenPosition.z;
|
||||
glVertex3f(x, y, z);
|
||||
}
|
||||
void BeginTriangles()
|
||||
{
|
||||
// disabling depth test sometimes allows more things to be visible
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glEnable(GL_BLEND);
|
||||
|
||||
void DrawTriangleFrontFace(OutputVertexData *v0, OutputVertexData *v1, OutputVertexData *v2)
|
||||
{
|
||||
glBegin(GL_TRIANGLES);
|
||||
if (hasTexture)
|
||||
{
|
||||
DrawTextureVertex(v0);
|
||||
DrawTextureVertex(v1);
|
||||
DrawTextureVertex(v2);
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawColorVertex(v0);
|
||||
DrawColorVertex(v1);
|
||||
DrawColorVertex(v2);
|
||||
}
|
||||
glEnd();
|
||||
}
|
||||
hasTexture = bpmem.tevorders[0].enable0;
|
||||
|
||||
void Clear()
|
||||
{
|
||||
u8 r = (bpmem.clearcolorAR & 0x00ff);
|
||||
u8 g = (bpmem.clearcolorGB & 0xff00) >> 8;
|
||||
u8 b = (bpmem.clearcolorGB & 0x00ff);
|
||||
u8 a = (bpmem.clearcolorAR & 0xff00) >> 8;
|
||||
if (hasTexture)
|
||||
LoadTexture();
|
||||
}
|
||||
|
||||
GLfloat left = (GLfloat)bpmem.copyTexSrcXY.x / efbHalfWidth - 1.0f;
|
||||
GLfloat top = 1.0f - (GLfloat)bpmem.copyTexSrcXY.y / efbHalfHeight;
|
||||
GLfloat right = (GLfloat)(left + bpmem.copyTexSrcWH.x + 1) / efbHalfWidth - 1.0f;
|
||||
GLfloat bottom = 1.0f - (GLfloat)(top + bpmem.copyTexSrcWH.y + 1) / efbHalfHeight;
|
||||
GLfloat depth = (GLfloat)bpmem.clearZValue / (GLfloat)0x00ffffff;
|
||||
void EndTriangles()
|
||||
{
|
||||
glBindTexture(TEX2D, 0);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glDisable(GL_BLEND);
|
||||
}
|
||||
|
||||
glBegin(GL_QUADS);
|
||||
glColor4ub(r, g, b, a);
|
||||
glVertex3f(left, top, depth);
|
||||
glColor4ub(r, g, b, a);
|
||||
glVertex3f(right, top, depth);
|
||||
glColor4ub(r, g, b, a);
|
||||
glVertex3f(right, bottom, depth);
|
||||
glColor4ub(r, g, b, a);
|
||||
glVertex3f(left, bottom, depth);
|
||||
glEnd();
|
||||
}
|
||||
void DrawColorVertex(OutputVertexData *v0, OutputVertexData *v1, OutputVertexData *v2)
|
||||
{
|
||||
float x0 = (v0->screenPosition.x / efbHalfWidth) - 1.0f;
|
||||
float y0 = 1.0f - (v0->screenPosition.y / efbHalfHeight);
|
||||
float z0 = v0->screenPosition.z / (float)0x00ffffff;
|
||||
|
||||
TexCacheEntry::TexCacheEntry()
|
||||
{
|
||||
Create();
|
||||
}
|
||||
float x1 = (v1->screenPosition.x / efbHalfWidth) - 1.0f;
|
||||
float y1 = 1.0f - (v1->screenPosition.y / efbHalfHeight);
|
||||
float z1 = v1->screenPosition.z / (float)0x00ffffff;
|
||||
|
||||
void TexCacheEntry::Create()
|
||||
{
|
||||
FourTexUnits &texUnit = bpmem.tex[0];
|
||||
float x2 = (v2->screenPosition.x / efbHalfWidth) - 1.0f;
|
||||
float y2 = 1.0f - (v2->screenPosition.y / efbHalfHeight);
|
||||
float z2 = v2->screenPosition.z / (float)0x00ffffff;
|
||||
|
||||
texImage0.hex = texUnit.texImage0[0].hex;
|
||||
texImage1.hex = texUnit.texImage1[0].hex;
|
||||
texImage2.hex = texUnit.texImage2[0].hex;
|
||||
texImage3.hex = texUnit.texImage3[0].hex;
|
||||
texTlut.hex = texUnit.texTlut[0].hex;
|
||||
float r0 = v0->color[0][OutputVertexData::RED_C] / 255.0f;
|
||||
float g0 = v0->color[0][OutputVertexData::GRN_C] / 255.0f;
|
||||
float b0 = v0->color[0][OutputVertexData::BLU_C] / 255.0f;
|
||||
|
||||
int width = texImage0.width;
|
||||
int height = texImage0.height;
|
||||
float r1 = v1->color[0][OutputVertexData::RED_C] / 255.0f;
|
||||
float g1 = v1->color[0][OutputVertexData::GRN_C] / 255.0f;
|
||||
float b1 = v1->color[0][OutputVertexData::BLU_C] / 255.0f;
|
||||
|
||||
DebugUtil::GetTextureBGRA(temp, 0, 0, width, height);
|
||||
float r2 = v2->color[0][OutputVertexData::RED_C] / 255.0f;
|
||||
float g2 = v2->color[0][OutputVertexData::GRN_C] / 255.0f;
|
||||
float b2 = v2->color[0][OutputVertexData::BLU_C] / 255.0f;
|
||||
|
||||
glGenTextures(1, (GLuint *)&texture);
|
||||
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, texture);
|
||||
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA8, (GLsizei)width, (GLsizei)height, 0, GL_BGRA, GL_UNSIGNED_BYTE, temp);
|
||||
}
|
||||
static const GLfloat verts[3][3] = {
|
||||
{ x0, y0, z0 },
|
||||
{ x1, y1, z1 },
|
||||
{ x2, y2, z2 }
|
||||
};
|
||||
static const GLfloat col[3][4] = {
|
||||
{ r0, g0, b0, 1.0f },
|
||||
{ r1, g1, b1, 1.0f },
|
||||
{ r2, g2, b2, 1.0f }
|
||||
};
|
||||
{
|
||||
glUseProgram(colProg);
|
||||
glEnableVertexAttribArray(col_apos);
|
||||
glEnableVertexAttribArray(col_atex);
|
||||
|
||||
void TexCacheEntry::Destroy()
|
||||
{
|
||||
if (texture == 0)
|
||||
return;
|
||||
glVertexAttribPointer(col_apos, 3, GL_FLOAT, GL_FALSE, 0, verts);
|
||||
glVertexAttribPointer(col_atex, 4, GL_FLOAT, GL_FALSE, 0, col);
|
||||
glDrawArrays(GL_TRIANGLES, 0, 3);
|
||||
glDisableVertexAttribArray(col_atex);
|
||||
glDisableVertexAttribArray(col_apos);
|
||||
}
|
||||
GL_REPORT_ERRORD();
|
||||
}
|
||||
|
||||
glDeleteTextures(1, &texture);
|
||||
texture = 0;
|
||||
}
|
||||
void DrawTextureVertex(OutputVertexData *v0, OutputVertexData *v1, OutputVertexData *v2)
|
||||
{
|
||||
float x0 = (v0->screenPosition.x / efbHalfWidth) - 1.0f;
|
||||
float y0 = 1.0f - (v0->screenPosition.y / efbHalfHeight);
|
||||
float z0 = v0->screenPosition.z;
|
||||
|
||||
void TexCacheEntry::Update()
|
||||
{
|
||||
FourTexUnits &texUnit = bpmem.tex[0];
|
||||
float x1 = (v1->screenPosition.x / efbHalfWidth) - 1.0f;
|
||||
float y1 = 1.0f - (v1->screenPosition.y / efbHalfHeight);
|
||||
float z1 = v1->screenPosition.z;
|
||||
|
||||
// extra checks cause textures to be reloaded much more
|
||||
if (texUnit.texImage0[0].hex != texImage0.hex ||
|
||||
//texUnit.texImage1[0].hex != texImage1.hex ||
|
||||
//texUnit.texImage2[0].hex != texImage2.hex ||
|
||||
texUnit.texImage3[0].hex != texImage3.hex ||
|
||||
texUnit.texTlut[0].hex != texTlut.hex)
|
||||
{
|
||||
Destroy();
|
||||
Create();
|
||||
}
|
||||
}
|
||||
float x2 = (v2->screenPosition.x / efbHalfWidth) - 1.0f;
|
||||
float y2 = 1.0f - (v2->screenPosition.y / efbHalfHeight);
|
||||
float z2 = v2->screenPosition.z;
|
||||
|
||||
float s0 = v0->texCoords[0].x / width;
|
||||
float t0 = v0->texCoords[0].y / height;
|
||||
|
||||
float s1 = v1->texCoords[0].x / width;
|
||||
float t1 = v1->texCoords[0].y / height;
|
||||
|
||||
float s2 = v2->texCoords[0].x / width;
|
||||
float t2 = v2->texCoords[0].y / height;
|
||||
|
||||
static const GLfloat verts[3][3] = {
|
||||
{ x0, y0, z0 },
|
||||
{ x1, y1, z1 },
|
||||
{ x2, y2, z2 }
|
||||
};
|
||||
static const GLfloat tex[3][2] = {
|
||||
{ s0, t0 },
|
||||
{ s1, t1 },
|
||||
{ s2, t2 }
|
||||
};
|
||||
{
|
||||
glUseProgram(texProg);
|
||||
glEnableVertexAttribArray(tex_apos);
|
||||
glEnableVertexAttribArray(tex_atex);
|
||||
|
||||
glVertexAttribPointer(tex_apos, 3, GL_FLOAT, GL_FALSE, 0, verts);
|
||||
glVertexAttribPointer(tex_atex, 2, GL_FLOAT, GL_FALSE, 0, tex);
|
||||
glUniform1i(tex_utex, 0);
|
||||
glDrawArrays(GL_TRIANGLES, 0, 3);
|
||||
glDisableVertexAttribArray(tex_atex);
|
||||
glDisableVertexAttribArray(tex_apos);
|
||||
}
|
||||
GL_REPORT_ERRORD();
|
||||
}
|
||||
|
||||
void DrawTriangleFrontFace(OutputVertexData *v0, OutputVertexData *v1, OutputVertexData *v2)
|
||||
{
|
||||
if (hasTexture)
|
||||
DrawTextureVertex(v0, v1, v2);
|
||||
else
|
||||
DrawColorVertex(v0, v1, v2);
|
||||
}
|
||||
|
||||
void Clear()
|
||||
{
|
||||
u8 r = (bpmem.clearcolorAR & 0x00ff);
|
||||
u8 g = (bpmem.clearcolorGB & 0xff00) >> 8;
|
||||
u8 b = (bpmem.clearcolorGB & 0x00ff);
|
||||
u8 a = (bpmem.clearcolorAR & 0xff00) >> 8;
|
||||
|
||||
GLfloat left = (GLfloat)bpmem.copyTexSrcXY.x / efbHalfWidth - 1.0f;
|
||||
GLfloat top = 1.0f - (GLfloat)bpmem.copyTexSrcXY.y / efbHalfHeight;
|
||||
GLfloat right = (GLfloat)(left + bpmem.copyTexSrcWH.x + 1) / efbHalfWidth - 1.0f;
|
||||
GLfloat bottom = 1.0f - (GLfloat)(top + bpmem.copyTexSrcWH.y + 1) / efbHalfHeight;
|
||||
GLfloat depth = (GLfloat)bpmem.clearZValue / (GLfloat)0x00ffffff;
|
||||
static const GLfloat verts[4][3] = {
|
||||
{ left, top, depth },
|
||||
{ right, top, depth },
|
||||
{ right, bottom, depth },
|
||||
{ left, bottom, depth }
|
||||
};
|
||||
{
|
||||
glUseProgram(clearProg);
|
||||
glVertexAttribPointer(clear_apos, 3, GL_FLOAT, GL_FALSE, 0, verts);
|
||||
glUniform4f(clear_ucol, r, g, b, a);
|
||||
glEnableVertexAttribArray(col_apos);
|
||||
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
|
||||
glDisableVertexAttribArray(col_apos);
|
||||
}
|
||||
GL_REPORT_ERRORD();
|
||||
}
|
||||
|
||||
TexCacheEntry::TexCacheEntry()
|
||||
{
|
||||
Create();
|
||||
}
|
||||
|
||||
void TexCacheEntry::Create()
|
||||
{
|
||||
FourTexUnits &texUnit = bpmem.tex[0];
|
||||
|
||||
texImage0.hex = texUnit.texImage0[0].hex;
|
||||
texImage1.hex = texUnit.texImage1[0].hex;
|
||||
texImage2.hex = texUnit.texImage2[0].hex;
|
||||
texImage3.hex = texUnit.texImage3[0].hex;
|
||||
texTlut.hex = texUnit.texTlut[0].hex;
|
||||
|
||||
int width = texImage0.width;
|
||||
int height = texImage0.height;
|
||||
|
||||
DebugUtil::GetTextureBGRA(temp, 0, 0, width, height);
|
||||
|
||||
glGenTextures(1, (GLuint *)&texture);
|
||||
glBindTexture(TEX2D, texture);
|
||||
#ifdef USE_GLES
|
||||
glTexImage2D(TEX2D, 0, GL_RGBA, (GLsizei)width, (GLsizei)height, 0, GL_RGBA, GL_UNSIGNED_BYTE, temp);
|
||||
#else
|
||||
glTexImage2D(TEX2D, 0, GL_RGBA8, (GLsizei)width, (GLsizei)height, 0, GL_BGRA, GL_UNSIGNED_BYTE, temp);
|
||||
#endif
|
||||
GL_REPORT_ERRORD();
|
||||
}
|
||||
|
||||
void TexCacheEntry::Destroy()
|
||||
{
|
||||
if (texture == 0)
|
||||
return;
|
||||
|
||||
glDeleteTextures(1, &texture);
|
||||
texture = 0;
|
||||
}
|
||||
|
||||
void TexCacheEntry::Update()
|
||||
{
|
||||
FourTexUnits &texUnit = bpmem.tex[0];
|
||||
|
||||
// extra checks cause textures to be reloaded much more
|
||||
if (texUnit.texImage0[0].hex != texImage0.hex ||
|
||||
//texUnit.texImage1[0].hex != texImage1.hex ||
|
||||
//texUnit.texImage2[0].hex != texImage2.hex ||
|
||||
texUnit.texImage3[0].hex != texImage3.hex ||
|
||||
texUnit.texTlut[0].hex != texTlut.hex)
|
||||
{
|
||||
Destroy();
|
||||
Create();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -28,6 +28,9 @@ struct OutputVertexData;
|
|||
namespace HwRasterizer
|
||||
{
|
||||
void Init();
|
||||
void Shutdown();
|
||||
|
||||
void Prepare();
|
||||
|
||||
void BeginTriangles();
|
||||
void EndTriangles();
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue