UI: Massive revamp, new features and improvements

This commit is contained in:
Connor McLaughlin 2022-07-11 23:03:29 +10:00
parent 3fb61865e5
commit b42b5501f6
425 changed files with 39701 additions and 29487 deletions

View file

@ -89,12 +89,12 @@ if(WIN32 AND USE_SDL2)
set(SDL2_LIBRARIES "${CMAKE_CURRENT_SOURCE_DIR}/dep/msvc/sdl2/lib64/SDL2.lib")
set(SDL2MAIN_LIBRARIES "${CMAKE_CURRENT_SOURCE_DIR}/dep/msvc/sdl2/lib64/SDL2main.lib")
set(SDL2_DLL_PATH "${CMAKE_CURRENT_SOURCE_DIR}/dep/msvc/sdl2/bin64/SDL2.dll")
set(Qt5_DIR "${CMAKE_CURRENT_SOURCE_DIR}/dep/msvc/qt/5.15.0/msvc2017_64/lib/cmake/Qt5")
set(Qt6_DIR "${CMAKE_CURRENT_SOURCE_DIR}/dep/msvc/qt/6.1.0/msvc2019_64/lib/cmake/Qt6")
else()
set(SDL2_LIBRARIES "${CMAKE_CURRENT_SOURCE_DIR}/dep/msvc/sdl2/lib32/SDL2.lib")
set(SDL2MAIN_LIBRARIES "${CMAKE_CURRENT_SOURCE_DIR}/dep/msvc/sdl2/lib32/SDL2main.lib")
set(SDL2_DLL_PATH "${CMAKE_CURRENT_SOURCE_DIR}/dep/msvc/sdl2/bin32/SDL2.dll")
set(Qt5_DIR "${CMAKE_CURRENT_SOURCE_DIR}/dep/msvc/qt/5.15.0/msvc2017_32/lib/cmake/Qt5")
set(Qt6_DIR "${CMAKE_CURRENT_SOURCE_DIR}/dep/msvc/qt/6.1.0/msvc2019_32/lib/cmake/Qt6")
endif()
endif()
@ -105,7 +105,7 @@ if(NOT ANDROID)
find_package(SDL2 REQUIRED)
endif()
if(BUILD_QT_FRONTEND)
find_package(Qt5 COMPONENTS Core Gui Widgets Network LinguistTools REQUIRED)
find_package(Qt6 COMPONENTS Core Gui Widgets Network LinguistTools REQUIRED)
endif()
endif()

View file

@ -36683,7 +36683,7 @@
"controllers": [
"AnalogController",
"DigitalController",
"NamcoGuncon"
"GunCon"
],
"track_data": [
{
@ -94490,7 +94490,7 @@
"AnalogController",
"DigitalController",
"PlayStationMouse",
"NamcoGuncon",
"GunCon",
"KonamiJustifier"
],
"track_data": [
@ -94528,7 +94528,7 @@
"AnalogController",
"DigitalController",
"PlayStationMouse",
"NamcoGuncon",
"GunCon",
"KonamiJustifier"
],
"track_data": [
@ -94566,7 +94566,7 @@
"AnalogController",
"DigitalController",
"PlayStationMouse",
"NamcoGuncon",
"GunCon",
"KonamiJustifier"
],
"track_data": [
@ -94604,7 +94604,7 @@
"AnalogController",
"DigitalController",
"PlayStationMouse",
"NamcoGuncon",
"GunCon",
"KonamiJustifier"
],
"track_data": [
@ -94642,7 +94642,7 @@
"AnalogController",
"DigitalController",
"PlayStationMouse",
"NamcoGuncon",
"GunCon",
"KonamiJustifier"
],
"track_data": [
@ -118156,7 +118156,7 @@
"controllers": [
"AnalogController",
"DigitalController",
"NamcoGuncon",
"GunCon",
"KonamiJustifier",
"PlayStationMouse"
],
@ -131024,7 +131024,7 @@
"controllers": [
"AnalogController",
"DigitalController",
"NamcoGuncon"
"GunCon"
],
"track_data": [
{
@ -159741,7 +159741,7 @@
"controllers": [
"AnalogController",
"DigitalController",
"NamcoGuncon",
"GunCon",
"KonamiJustifier",
"PlayStationMouse"
],
@ -161094,7 +161094,7 @@
"AnalogController",
"DigitalController",
"PlayStationMouse",
"NamcoGuncon"
"GunCon"
],
"track_data": [
{
@ -168086,7 +168086,7 @@
"linkCable": false,
"controllers": [
"DigitalController",
"NamcoGuncon"
"GunCon"
],
"track_data": [
{
@ -168130,7 +168130,7 @@
"linkCable": false,
"controllers": [
"DigitalController",
"NamcoGuncon"
"GunCon"
],
"track_data": [
{
@ -168166,7 +168166,7 @@
"controllers": [
"AnalogController",
"DigitalController",
"NamcoGuncon"
"GunCon"
],
"track_data": [
{
@ -168202,7 +168202,7 @@
"controllers": [
"AnalogController",
"DigitalController",
"NamcoGuncon"
"GunCon"
],
"track_data": [
{
@ -168264,7 +168264,7 @@
"controllers": [
"AnalogController",
"DigitalController",
"NamcoGuncon"
"GunCon"
],
"track_data": [
{
@ -168300,7 +168300,7 @@
"controllers": [
"AnalogController",
"DigitalController",
"NamcoGuncon"
"GunCon"
]
},
{
@ -169280,7 +169280,7 @@
"controllers": [
"AnalogController",
"DigitalController",
"NamcoGuncon"
"GunCon"
],
"track_data": [
{
@ -169316,7 +169316,7 @@
"controllers": [
"AnalogController",
"DigitalController",
"NamcoGuncon"
"GunCon"
],
"track_data": [
{
@ -169792,7 +169792,7 @@
"linkCable": false,
"controllers": [
"DigitalController",
"NamcoGuncon"
"GunCon"
],
"track_data": [
{
@ -200165,7 +200165,7 @@
"linkCable": false,
"controllers": [
"DigitalController",
"NamcoGuncon",
"GunCon",
"KonamiJustifier"
],
"track_data": [
@ -200201,7 +200201,7 @@
"linkCable": false,
"controllers": [
"DigitalController",
"NamcoGuncon",
"GunCon",
"KonamiJustifier"
],
"track_data": [
@ -201057,7 +201057,7 @@
"controllers": [
"AnalogController",
"DigitalController",
"NamcoGuncon"
"GunCon"
],
"track_data": [
{
@ -243440,7 +243440,7 @@
"controllers": [
"AnalogController",
"DigitalController",
"NamcoGuncon",
"GunCon",
"KonamiJustifier"
],
"track_data": [
@ -243477,7 +243477,7 @@
"controllers": [
"AnalogController",
"DigitalController",
"NamcoGuncon",
"GunCon",
"KonamiJustifier"
],
"track_data": [
@ -250279,7 +250279,7 @@
"controllers": [
"AnalogController",
"DigitalController",
"NamcoGuncon",
"GunCon",
"KonamiJustifier"
],
"track_data": [
@ -250316,7 +250316,7 @@
"controllers": [
"AnalogController",
"DigitalController",
"NamcoGuncon",
"GunCon",
"KonamiJustifier"
],
"track_data": [
@ -257141,7 +257141,7 @@
"controllers": [
"AnalogController",
"DigitalController",
"NamcoGuncon"
"GunCon"
],
"track_data": [
{
@ -257262,7 +257262,7 @@
"controllers": [
"AnalogController",
"DigitalController",
"NamcoGuncon"
"GunCon"
],
"track_data": [
{
@ -290498,7 +290498,7 @@
"controllers": [
"AnalogController",
"DigitalController",
"NamcoGuncon"
"GunCon"
]
},
{
@ -313576,7 +313576,7 @@
"linkCable": false,
"controllers": [
"DigitalController",
"NamcoGuncon"
"GunCon"
],
"track_data": [
{
@ -313620,7 +313620,7 @@
"linkCable": false,
"controllers": [
"DigitalController",
"NamcoGuncon"
"GunCon"
],
"track_data": [
{
@ -313660,7 +313660,7 @@
"controllers": [
"AnalogController",
"DigitalController",
"NamcoGuncon"
"GunCon"
],
"track_data": [
{
@ -313696,7 +313696,7 @@
"controllers": [
"AnalogController",
"DigitalController",
"NamcoGuncon"
"GunCon"
],
"track_data": [
{
@ -313736,7 +313736,7 @@
"controllers": [
"AnalogController",
"DigitalController",
"NamcoGuncon"
"GunCon"
],
"track_data": [
{
@ -313772,7 +313772,7 @@
"controllers": [
"AnalogController",
"DigitalController",
"NamcoGuncon"
"GunCon"
],
"track_data": [
{
@ -313808,7 +313808,7 @@
"controllers": [
"AnalogController",
"DigitalController",
"NamcoGuncon"
"GunCon"
]
},
{
@ -323119,7 +323119,7 @@
"linkCable": false,
"controllers": [
"DigitalController",
"NamcoGuncon"
"GunCon"
],
"track_data": [
{
@ -336352,7 +336352,7 @@
"controllers": [
"AnalogController",
"DigitalController",
"NamcoGuncon",
"GunCon",
"PlayStationMouse"
],
"track_data": [
@ -336389,7 +336389,7 @@
"controllers": [
"AnalogController",
"DigitalController",
"NamcoGuncon",
"GunCon",
"PlayStationMouse"
]
},
@ -336437,7 +336437,7 @@
"controllers": [
"AnalogController",
"DigitalController",
"NamcoGuncon",
"GunCon",
"PlayStationMouse"
],
"track_data": [
@ -336837,7 +336837,7 @@
"controllers": [
"AnalogController",
"DigitalController",
"NamcoGuncon"
"GunCon"
],
"track_data": [
{
@ -336874,7 +336874,7 @@
"controllers": [
"AnalogController",
"DigitalController",
"NamcoGuncon"
"GunCon"
],
"track_data": [
{
@ -336910,7 +336910,7 @@
"controllers": [
"AnalogController",
"DigitalController",
"NamcoGuncon"
"GunCon"
],
"track_data": [
{
@ -338230,7 +338230,7 @@
"linkCable": false,
"controllers": [
"DigitalController",
"NamcoGuncon"
"GunCon"
],
"track_data": [
{
@ -338333,7 +338333,7 @@
"linkCable": false,
"controllers": [
"DigitalController",
"NamcoGuncon"
"GunCon"
],
"track_data": [
{
@ -338436,7 +338436,7 @@
"linkCable": false,
"controllers": [
"DigitalController",
"NamcoGuncon"
"GunCon"
],
"track_data": [
{
@ -338539,7 +338539,7 @@
"linkCable": false,
"controllers": [
"DigitalController",
"NamcoGuncon"
"GunCon"
],
"track_data": [
{
@ -370386,7 +370386,7 @@
"controllers": [
"AnalogController",
"DigitalController",
"NamcoGuncon"
"GunCon"
],
"track_data": [
{
@ -372433,7 +372433,7 @@
"controllers": [
"AnalogController",
"DigitalController",
"NamcoGuncon"
"GunCon"
],
"track_data": [
{
@ -430122,7 +430122,7 @@
"linkCable": false,
"controllers": [
"DigitalController",
"NamcoGuncon",
"GunCon",
"PlayStationMouse"
],
"track_data": [
@ -430287,7 +430287,7 @@
"linkCable": false,
"controllers": [
"DigitalController",
"NamcoGuncon",
"GunCon",
"PlayStationMouse"
],
"track_data": [
@ -430451,7 +430451,7 @@
"linkCable": false,
"controllers": [
"DigitalController",
"NamcoGuncon",
"GunCon",
"PlayStationMouse"
],
"track_data": [
@ -430615,7 +430615,7 @@
"linkCable": false,
"controllers": [
"DigitalController",
"NamcoGuncon",
"GunCon",
"PlayStationMouse"
],
"track_data": [
@ -430780,7 +430780,7 @@
"controllers": [
"AnalogController",
"DigitalController",
"NamcoGuncon"
"GunCon"
]
},
{
@ -430810,7 +430810,7 @@
"controllers": [
"AnalogController",
"DigitalController",
"NamcoGuncon"
"GunCon"
],
"track_data": [
{
@ -431114,7 +431114,7 @@
"controllers": [
"AnalogController",
"DigitalController",
"NamcoGuncon"
"GunCon"
],
"track_data": [
{
@ -431234,7 +431234,7 @@
"controllers": [
"AnalogController",
"DigitalController",
"NamcoGuncon"
"GunCon"
],
"track_data": [
{
@ -431353,7 +431353,7 @@
"linkCable": false,
"controllers": [
"DigitalController",
"NamcoGuncon",
"GunCon",
"PlayStationMouse"
]
},

View file

@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

Binary file not shown.

View file

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

View file

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 10 KiB

View file

Before

Width:  |  Height:  |  Size: 4.8 KiB

After

Width:  |  Height:  |  Size: 4.8 KiB

View file

Before

Width:  |  Height:  |  Size: 120 KiB

After

Width:  |  Height:  |  Size: 120 KiB

View file

Before

Width:  |  Height:  |  Size: 117 KiB

After

Width:  |  Height:  |  Size: 117 KiB

View file

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 48 KiB

View file

Before

Width:  |  Height:  |  Size: 202 KiB

After

Width:  |  Height:  |  Size: 202 KiB

View file

Before

Width:  |  Height:  |  Size: 72 KiB

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

View file

Before

Width:  |  Height:  |  Size: 5.4 KiB

After

Width:  |  Height:  |  Size: 5.4 KiB

View file

Before

Width:  |  Height:  |  Size: 6 KiB

After

Width:  |  Height:  |  Size: 6 KiB

View file

Before

Width:  |  Height:  |  Size: 6.2 KiB

After

Width:  |  Height:  |  Size: 6.2 KiB

View file

Before

Width:  |  Height:  |  Size: 6.4 KiB

After

Width:  |  Height:  |  Size: 6.4 KiB

View file

Before

Width:  |  Height:  |  Size: 6.2 KiB

After

Width:  |  Height:  |  Size: 6.2 KiB

View file

Before

Width:  |  Height:  |  Size: 5.8 KiB

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 209 KiB

@ -1 +1 @@
Subproject commit fb9018121818293b72e9f5064b2cb202e713c501
Subproject commit f44f99baad9c52e6e98831f95dde283b3c3d7993

View file

@ -2,36 +2,38 @@
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Label="UserMacros">
<BinaryOutputDir>$(SolutionDir)bin\$(Platform)\</BinaryOutputDir>
<QTDIRDefault Condition="'$(Platform)'=='x64'">$(SolutionDir)dep\msvc\qt\6.1.0\msvc2019_64\</QTDIRDefault>
<QTDIRDefault Condition="'$(Platform)'=='ARM64'">$(SolutionDir)dep\msvc\qt\6.1.0\msvc2019_arm64\</QTDIRDefault>
<QTDIR Condition="Exists('$(QTDIRDefault)') And ('$(QTDIR)'=='' Or !Exists('$(QTDIR)'))">$(QTDIRDefault)</QTDIR>
<QTDIR Condition="Exists('$(QTDIR)') And !HasTrailingSlash('$(QTDIR)')">$(QTDIR)\</QTDIR>
<QTDIRHost>$(SolutionDir)dep\msvc\qt\6.1.0\msvc2019_64\</QTDIRHost>
<QtDirValid>false</QtDirValid>
<QtDirValid Condition="Exists('$(QTDIR)')">true</QtDirValid>
<QtIncludeDir>$(QTDIR)include\</QtIncludeDir>
<QtLibDir>$(QTDIR)lib\</QtLibDir>
<QtBinDir>$(QTDIR)bin\</QtBinDir>
<QtHostBinDir>$(QTDIRHost)bin\</QtHostBinDir>
<QtPluginsDir>$(QTDIR)plugins\</QtPluginsDir>
<QtTranslationsDir>$(QTDIR)translations\</QtTranslationsDir>
<QtToolOutDir>$(SolutionDir)build\$(ProjectName)-$(Platform)-$(Configuration)\</QtToolOutDir>
<DSQTDIRDefault Condition="'$(Platform)'=='x64'">$(SolutionDir)dep\msvc\qt\6.1.0\msvc2019_64\</DSQTDIRDefault>
<DSQTDIRDefault Condition="'$(Platform)'=='ARM64'">$(SolutionDir)dep\msvc\qt\6.3.1\msvc2022_arm64\</DSQTDIRDefault>
<DSQTDIR Condition="Exists('$(DSQTDIRDefault)') And ('$(DSQTDIR)'=='' Or !Exists('$(DSQTDIR)'))">$(DSQTDIRDefault)</DSQTDIR>
<DSQTDIR Condition="Exists('$(DSQTDIR)') And !HasTrailingSlash('$(DSQTDIR)')">$(DSQTDIR)\</DSQTDIR>
<DSQTDIRHost Condition="'$(Platform)'!='ARM64'">$(SolutionDir)dep\msvc\qt\6.1.0\msvc2019_64\</DSQTDIRHost>
<DSQTDIRHost Condition="'$(Platform)'=='ARM64'">$(SolutionDir)dep\msvc\qt\6.3.1\msvc2022_64\</DSQTDIRHost>
<DSQTDIRValid>false</DSQTDIRValid>
<DSQTDIRValid Condition="Exists('$(DSQTDIR)')">true</DSQTDIRValid>
<QtIncludeDir>$(DSQTDIR)include\</QtIncludeDir>
<QtLibDir>$(DSQTDIR)lib\</QtLibDir>
<QtBinDir>$(DSQTDIR)bin\</QtBinDir>
<QtHostBinDir>$(DSQTDIRHost)bin\</QtHostBinDir>
<QtPluginsDir>$(DSQTDIR)plugins\</QtPluginsDir>
<QtTranslationsDir>$(DSQTDIR)translations\</QtTranslationsDir>
<QtToolOutDir>$(IntDir)</QtToolOutDir>
<QtMocOutPrefix>$(QtToolOutDir)moc_</QtMocOutPrefix>
<QtTsOutDir>$(BinaryOutputDir)translations\</QtTsOutDir>
<QtDebugSuffix>d</QtDebugSuffix>
<QtLibSuffix Condition="'$(Configuration)'=='Debug' Or '$(Configuration)'=='DebugFast'">$(QtDebugSuffix)</QtLibSuffix>
<QtLibSuffix Condition="$(Configuration.Contains(Debug))">$(QtDebugSuffix)</QtLibSuffix>
<QtPluginFolder>QtPlugins</QtPluginFolder>
<QtEntryPointLib>$(QtLibDir)Qt6EntryPoint$(QtLibSuffix).lib</QtEntryPointLib>
</PropertyGroup>
<ItemDefinitionGroup>
<ClCompile>
<PreprocessorDefinitions Condition="'$(Configuration)'=='Release' Or '$(Configuration)'=='ReleaseLTCG'">QT_NO_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="!$(Configuration.Contains(Debug))">QT_NO_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(ProjectDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(QtToolOutDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(QtIncludeDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<AdditionalLibraryDirectories>$(QtLibDir);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>Qt6Core$(QtLibSuffix).lib;Qt6Gui$(QtLibSuffix).lib;Qt6Widgets$(QtLibSuffix).lib;Qt6Network$(QtLibSuffix).lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>Qt6Core$(QtLibSuffix).lib;Qt6Gui$(QtLibSuffix).lib;Qt6Widgets$(QtLibSuffix).lib;Qt6Network$(QtLibSuffix).lib;Qt6Concurrent$(QtLibSuffix).lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
@ -45,7 +47,7 @@
Condition="'@(QtResource)'!=''"
Outputs="@(ResFiles->'$(QtToolOutDir)qrc_%(Filename).cpp')">
<Message Text="rcc %(ResFiles.Filename)" Importance="High" />
<Error Condition="!$(QtDirValid)" Text="QTDIR not set or non-existent (pull the submodule?)" />
<Error Condition="!$(DSQTDIRValid)" Text="Qt directory non-existent (pull the submodule?)" />
<MakeDir Directories="$(QtToolOutDir)" />
<Exec Command="&quot;$(QtHostBinDir)rcc.exe&quot; &quot;%(ResFiles.FullPath)&quot; -o &quot;$(QtToolOutDir)qrc_%(ResFiles.Filename).cpp&quot;" />
</Target>
@ -64,7 +66,7 @@
Condition="'@(QtUi)'!=''"
Outputs="@(UiFiles->'$(QtToolOutDir)ui_%(Filename).h')">
<Message Text="uic %(UiFiles.Filename)" Importance="High" />
<Error Condition="!$(QtDirValid)" Text="QTDIR not set or non-existent (pull the submodule?)" />
<Error Condition="!$(DSQTDIRValid)" Text="Qt directory non-existent (pull the submodule?)" />
<MakeDir Directories="$(QtToolOutDir)" />
<Exec Command="&quot;$(QtHostBinDir)uic.exe&quot; &quot;%(UiFiles.FullPath)&quot; -o &quot;$(QtToolOutDir)ui_%(UiFiles.Filename).h&quot;" />
</Target>
@ -77,26 +79,18 @@
<!--TODO find a way to autocreate from ClCompile settings-->
<PropertyGroup>
<MocDefines></MocDefines>
<MocDefines Condition="'$(Configuration)'=='Release' Or '$(Configuration)'=='ReleaseLTCG'">-DQT_NO_DEBUG -DNDEBUG $(MocDefines)</MocDefines>
<!-- !!!HOLY UGLY BATMAN!!!
Be very careful here when adding include directories. Each path must have the whole arg surrounded by doublequotes - HOWEVER,
the ending doublequote cannot be directly preceeded by a directory seperator. In other words, you must use:
"-I$(SomeDir) "
instead of
"-I$(SomeDir)"
in order to prevent the trailing slash from escaping the doublequote after value replacement.
-->
<MocIncludes>"-I$(QtIncludeDir)" "-I$(SolutionDir)src" -I.</MocIncludes>
<MocDefines Condition="!$(Configuration.Contains(Debug))">-DQT_NO_DEBUG -DNDEBUG $(MocDefines)</MocDefines>
<MocIncludes>-I"$(QtIncludeDir)." -I"$(SolutionDir)pcsx2" "-I$(SolutionDir)." -I.</MocIncludes>
</PropertyGroup>
<Target Name="QtMoc"
BeforeTargets="ClCompile"
Condition="'@(QtMoc)'!=''"
Inputs="%(QtMoc.Identity);%(QtMoc.AdditionalDependencies);$(MSBuildProjectFile)"
Outputs="$(QtToolOutDir)moc_%(QtMoc.Filename).cpp">
<Message Text="moc %(QtMoc.Filename) $(QtToolOutDir)moc_%(QtMoc.Filename).cpp" Importance="High" />
<Error Condition="!$(QtDirValid)" Text="QTDIR not set or non-existent (pull the submodule?)" />
Outputs="$(QtToolOutDir)%(QtMoc.RelativeDir)moc_%(QtMoc.Filename).cpp">
<Message Text="moc %(QtMoc.Filename) $(QtToolOutDir)%(QtMoc.RelativeDir)moc_%(QtMoc.Filename).cpp" Importance="High" />
<Error Condition="!$(DSQTDIRValid)" Text="Qt directory non-existent (pull the submodule?)" />
<MakeDir Directories="$(QtToolOutDir)" />
<Exec Command="&quot;$(QtHostBinDir)moc.exe&quot; &quot;%(QtMoc.FullPath)&quot; -o &quot;$(QtToolOutDir)moc_%(QtMoc.Filename).cpp&quot; -f%(QtMoc.Filename)%(QtMoc.Extension) $(MocDefines) $(MocIncludes)" />
<Exec Command="&quot;$(QtHostBinDir)moc.exe&quot; &quot;%(QtMoc.FullPath)&quot; -o &quot;$(QtToolOutDir)%(QtMoc.RelativeDir)moc_%(QtMoc.Filename).cpp&quot; -f%(QtMoc.Filename)%(QtMoc.Extension) $(MocDefines) $(MocIncludes)" />
</Target>
<ItemGroup>
@ -125,21 +119,24 @@
<!--Copy the needed dlls-->
<ItemGroup>
<QtLibNames Include="Qt6Core$(QtLibSuffix);Qt6Gui$(QtLibSuffix);Qt6Widgets$(QtLibSuffix);Qt6Network$(QtLibSuffix);Qt6Svg$(QtLibSuffix)" />
<QtLibNames Include="Qt6Core$(QtLibSuffix);Qt6Gui$(QtLibSuffix);Qt6Widgets$(QtLibSuffix);Qt6Network$(QtLibSuffix);Qt6Svg$(QtLibSuffix);Qt6Concurrent$(QtLibSuffix)" />
<QtDlls Include="@(QtLibNames -> '$(QtBinDir)%(Identity).dll')" />
<!--Filter plugins to copy based on the observation that all debug versions end in "d"-->
<QtAllPlugins Include="$(QtPluginsDir)**\*$(QtLibSuffix).dll" />
<QtPlugins Condition="'$(Configuration)'=='Debug' Or '$(Configuration)'=='DebugFast'" Include="@(QtAllPlugins)" />
<QtPlugins Condition="'$(Configuration)'=='Release' Or '$(Configuration)'=='ReleaseLTCG'" Exclude="$(QtPluginsDir)**\*$(QtDebugSuffix).dll" Include="@(QtAllPlugins)" />
<QtPlugins Condition="$(Configuration.Contains(Debug))" Include="@(QtAllPlugins)" />
<QtPlugins Condition="!$(Configuration.Contains(Debug))" Exclude="$(QtPluginsDir)**\*$(QtDebugSuffix).dll" Include="@(QtAllPlugins)" />
<QtPluginsDest Include="@(QtPlugins -> '$(BinaryOutputDir)$(QtPluginFolder)\%(RecursiveDir)%(Filename)%(Extension)')" />
<!--Our normal *d filter fails for the TLS DLLs, because backend ends in d. -->
<!--<QtTLSDlls Include="$(QtPluginsDir)tls\qcertonlybackend$(QtLibSuffix).dll;$(QtPluginsDir)tls\qschannelbackend$(QtLibSuffix).dll" />-->
<QtTLSDllsDest Include="@(QtTLSDlls -> '$(BinaryOutputDir)$(QtPluginFolder)\tls\%(Filename)%(Extension)')" />
</ItemGroup>
<PropertyGroup>
<QtConfFile>$(BinaryOutputDir)qt.conf</QtConfFile>
</PropertyGroup>
<Target Name="QtCopyBinaries"
AfterTargets="Build"
Inputs="@(QtDlls);@(QtPlugins)"
Outputs="@(QtDlls -> '$(BinaryOutputDir)%(RecursiveDir)%(Filename)%(Extension)');@(QtPlugins -> '$(BinaryOutputDir)$(QtPluginFolder)\%(RecursiveDir)%(Filename)%(Extension)')">
Inputs="@(QtDlls);@(QtPlugins);@(QtTLSDlls)"
Outputs="@(QtDlls -> '$(BinaryOutputDir)%(RecursiveDir)%(Filename)%(Extension)');@(QtPluginsDest);@(QtTLSDllsDest)">
<Message Text="Copying Qt .dlls" Importance="High" />
<Copy
SourceFiles="@(QtDlls)"
@ -151,6 +148,11 @@
DestinationFiles="@(QtPluginsDest)"
SkipUnchangedFiles="true"
/>
<Copy
SourceFiles="@(QtTLSDlls)"
DestinationFiles="@(QtTLSDllsDest)"
SkipUnchangedFiles="true"
/>
</Target>
<Target Name="QtCreateConf"
BeforeTargets="QtCopyBinaries"
@ -192,7 +194,7 @@
Condition="'@(QtTs)'!=''"
Outputs="@(TsFiles->'$(QtTsOutDir)%(Filename).qm')">
<Message Text="lrelease %(TsFiles.Filename)" Importance="High" />
<Error Condition="!$(QtDirValid)" Text="QTDIR not set or non-existent (pull the submodule?)" />
<Error Condition="!$(DSQTDIRValid)" Text="Qt directory non-existent (pull the submodule?)" />
<MakeDir Directories="$(QtTsOutDir)" />
<Exec Command="&quot;$(QtHostBinDir)lrelease.exe&quot; &quot;%(TsFiles.FullPath)&quot; -qm &quot;$(QtTsOutDir)%(TsFiles.Filename).qm&quot;" />
</Target>

View file

@ -16,6 +16,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "common", "src\common\common
{ED601289-AC1A-46B8-A8ED-17DB9EB73423} = {ED601289-AC1A-46B8-A8ED-17DB9EB73423}
{8BDA439C-6358-45FB-9994-2FF083BABE06} = {8BDA439C-6358-45FB-9994-2FF083BABE06}
{7FF9FDB9-D504-47DB-A16A-B08071999620} = {7FF9FDB9-D504-47DB-A16A-B08071999620}
{8BE398E6-B882-4248-9065-FECC8728E038} = {8BE398E6-B882-4248-9065-FECC8728E038}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "core", "src\core\core.vcxproj", "{868B98C8-65A1-494B-8346-250A73A48C0A}"
@ -811,30 +812,22 @@ Global
{39F0ADFF-3A84-470D-9CF0-CA49E164F2F3}.ReleaseUWP|x64.ActiveCfg = ReleaseUWP|x64
{39F0ADFF-3A84-470D-9CF0-CA49E164F2F3}.ReleaseUWP|x86.ActiveCfg = ReleaseUWP|Win32
{0A172B2E-DC67-49FC-A4C1-975F93C586C4}.Debug|ARM64.ActiveCfg = Debug|ARM64
{0A172B2E-DC67-49FC-A4C1-975F93C586C4}.Debug|ARM64.Build.0 = Debug|ARM64
{0A172B2E-DC67-49FC-A4C1-975F93C586C4}.Debug|x64.ActiveCfg = Debug|x64
{0A172B2E-DC67-49FC-A4C1-975F93C586C4}.Debug|x64.Build.0 = Debug|x64
{0A172B2E-DC67-49FC-A4C1-975F93C586C4}.Debug|x86.ActiveCfg = Debug|Win32
{0A172B2E-DC67-49FC-A4C1-975F93C586C4}.Debug|x86.Build.0 = Debug|Win32
{0A172B2E-DC67-49FC-A4C1-975F93C586C4}.DebugFast|ARM64.ActiveCfg = DebugFast|ARM64
{0A172B2E-DC67-49FC-A4C1-975F93C586C4}.DebugFast|ARM64.Build.0 = DebugFast|ARM64
{0A172B2E-DC67-49FC-A4C1-975F93C586C4}.DebugFast|x64.ActiveCfg = DebugFast|x64
{0A172B2E-DC67-49FC-A4C1-975F93C586C4}.DebugFast|x64.Build.0 = DebugFast|x64
{0A172B2E-DC67-49FC-A4C1-975F93C586C4}.DebugFast|x86.ActiveCfg = DebugFast|Win32
{0A172B2E-DC67-49FC-A4C1-975F93C586C4}.DebugFast|x86.Build.0 = DebugFast|Win32
{0A172B2E-DC67-49FC-A4C1-975F93C586C4}.DebugUWP|ARM64.ActiveCfg = DebugUWP|ARM64
{0A172B2E-DC67-49FC-A4C1-975F93C586C4}.DebugUWP|x64.ActiveCfg = DebugUWP|x64
{0A172B2E-DC67-49FC-A4C1-975F93C586C4}.DebugUWP|x86.ActiveCfg = DebugUWP|Win32
{0A172B2E-DC67-49FC-A4C1-975F93C586C4}.Release|ARM64.ActiveCfg = Release|ARM64
{0A172B2E-DC67-49FC-A4C1-975F93C586C4}.Release|ARM64.Build.0 = Release|ARM64
{0A172B2E-DC67-49FC-A4C1-975F93C586C4}.Release|x64.ActiveCfg = Release|x64
{0A172B2E-DC67-49FC-A4C1-975F93C586C4}.Release|x64.Build.0 = Release|x64
{0A172B2E-DC67-49FC-A4C1-975F93C586C4}.Release|x86.ActiveCfg = Release|Win32
{0A172B2E-DC67-49FC-A4C1-975F93C586C4}.Release|x86.Build.0 = Release|Win32
{0A172B2E-DC67-49FC-A4C1-975F93C586C4}.ReleaseLTCG|ARM64.ActiveCfg = ReleaseLTCG|ARM64
{0A172B2E-DC67-49FC-A4C1-975F93C586C4}.ReleaseLTCG|ARM64.Build.0 = ReleaseLTCG|ARM64
{0A172B2E-DC67-49FC-A4C1-975F93C586C4}.ReleaseLTCG|x64.ActiveCfg = ReleaseLTCG|x64
{0A172B2E-DC67-49FC-A4C1-975F93C586C4}.ReleaseLTCG|x64.Build.0 = ReleaseLTCG|x64
{0A172B2E-DC67-49FC-A4C1-975F93C586C4}.ReleaseLTCG|x86.ActiveCfg = ReleaseLTCG|Win32
{0A172B2E-DC67-49FC-A4C1-975F93C586C4}.ReleaseLTCG|x86.Build.0 = ReleaseLTCG|Win32
{0A172B2E-DC67-49FC-A4C1-975F93C586C4}.ReleaseUWP|ARM64.ActiveCfg = ReleaseUWP|ARM64

View file

@ -896,6 +896,105 @@ void GrowableMemoryByteStream::Grow(u32 MinimumGrowth)
ResizeMemory(NewSize);
}
bool ByteStream::ReadU8(u8* dest)
{
return Read2(dest, sizeof(u8));
}
bool ByteStream::ReadU16(u16* dest)
{
return Read2(dest, sizeof(u16));
}
bool ByteStream::ReadU32(u32* dest)
{
return Read2(dest, sizeof(u32));
}
bool ByteStream::ReadU64(u64* dest)
{
return Read2(dest, sizeof(u64));
}
bool ByteStream::ReadS8(s8* dest)
{
return Read2(dest, sizeof(s8));
}
bool ByteStream::ReadS16(s16* dest)
{
return Read2(dest, sizeof(s16));
}
bool ByteStream::ReadS32(s32* dest)
{
return Read2(dest, sizeof(s32));
}
bool ByteStream::ReadS64(s64* dest)
{
return Read2(dest, sizeof(s64));
}
bool ByteStream::ReadSizePrefixedString(std::string* dest)
{
u32 size;
if (!Read2(&size, sizeof(size)))
return false;
dest->resize(size);
if (!Read2(dest->data(), size))
return false;
return true;
}
bool ByteStream::WriteU8(u8 dest)
{
return Write2(&dest, sizeof(u8));
}
bool ByteStream::WriteU16(u16 dest)
{
return Write2(&dest, sizeof(u16));
}
bool ByteStream::WriteU32(u32 dest)
{
return Write2(&dest, sizeof(u32));
}
bool ByteStream::WriteU64(u64 dest)
{
return Write2(&dest, sizeof(u64));
}
bool ByteStream::WriteS8(s8 dest)
{
return Write2(&dest, sizeof(s8));
}
bool ByteStream::WriteS16(s16 dest)
{
return Write2(&dest, sizeof(s16));
}
bool ByteStream::WriteS32(s32 dest)
{
return Write2(&dest, sizeof(s32));
}
bool ByteStream::WriteS64(s64 dest)
{
return Write2(&dest, sizeof(s64));
}
bool ByteStream::WriteSizePrefixedString(const std::string_view& str)
{
const u32 size = static_cast<u32>(str.size());
return (Write2(&size, sizeof(size)) && (size == 0 || Write2(str.data(), size)));
}
std::unique_ptr<ByteStream> ByteStream::OpenFile(const char* fileName, u32 openMode)
{
if ((openMode & (BYTESTREAM_OPEN_CREATE | BYTESTREAM_OPEN_WRITE)) == BYTESTREAM_OPEN_WRITE)

View file

@ -2,6 +2,7 @@
#include "types.h"
#include <memory>
#include <string>
#include <string_view>
#include <vector>
// base byte stream creation functions
@ -76,6 +77,26 @@ public:
inline void SetErrorState() { m_errorState = true; }
inline void ClearErrorState() { m_errorState = false; }
bool ReadU8(u8* dest);
bool ReadU16(u16* dest);
bool ReadU32(u32* dest);
bool ReadU64(u64* dest);
bool ReadS8(s8* dest);
bool ReadS16(s16* dest);
bool ReadS32(s32* dest);
bool ReadS64(s64* dest);
bool ReadSizePrefixedString(std::string* dest);
bool WriteU8(u8 dest);
bool WriteU16(u16 dest);
bool WriteU32(u32 dest);
bool WriteU64(u64 dest);
bool WriteS8(s8 dest);
bool WriteS16(s16 dest);
bool WriteS32(s32 dest);
bool WriteS64(s64 dest);
bool WriteSizePrefixedString(const std::string_view& str);
// base byte stream creation functions
// opens a local file-based stream. fills in error if passed, and returns false if the file cannot be opened.
static std::unique_ptr<ByteStream> OpenFile(const char* FileName, u32 OpenMode);

View file

@ -167,7 +167,7 @@ std::string ShaderCache::GetCacheBaseFileName(const std::string_view& base_path,
bool debug)
{
std::string base_filename(base_path);
base_filename += "d3d_shaders_";
base_filename += FS_OSPATH_SEPARATOR_STR "d3d_shaders_";
switch (feature_level)
{

View file

@ -226,7 +226,7 @@ std::string ShaderCache::GetCacheBaseFileName(const std::string_view& base_path,
D3D_FEATURE_LEVEL feature_level, bool debug)
{
std::string base_filename(base_path);
base_filename += "d3d12_";
base_filename += FS_OSPATH_SEPARATOR_STR "d3d12_";
base_filename += type;
base_filename += "_";

View file

@ -2,6 +2,7 @@
#include "../file_system.h"
#include "../log.h"
#include "../md5_digest.h"
#include "../path.h"
#include "../string_util.h"
Log_SetChannel(GL::ShaderCache);
@ -251,12 +252,12 @@ ShaderCache::CacheIndexKey ShaderCache::GetCacheKey(const std::string_view& vert
std::string ShaderCache::GetIndexFileName() const
{
return StringUtil::StdStringFromFormat("%sgl_programs.idx", m_base_path.c_str());
return Path::Combine(m_base_path, "gl_programs.idx");
}
std::string ShaderCache::GetBlobFileName() const
{
return StringUtil::StdStringFromFormat("%sgl_programs.bin", m_base_path.c_str());
return Path::Combine(m_base_path, "gl_programs.bin");
}
std::optional<Program> ShaderCache::GetProgram(const std::string_view vertex_shader,

View file

@ -7,7 +7,7 @@ Log_SetChannel(HTTPDownloader);
static constexpr float DEFAULT_TIMEOUT_IN_SECONDS = 30;
static constexpr u32 DEFAULT_MAX_ACTIVE_REQUESTS = 4;
namespace FrontendCommon {
namespace Common {
const char HTTPDownloader::DEFAULT_USER_AGENT[] =
"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:85.0) Gecko/20100101 Firefox/85.0";

View file

@ -7,7 +7,7 @@
#include <string>
#include <vector>
namespace FrontendCommon {
namespace Common {
class HTTPDownloader
{

View file

@ -9,7 +9,7 @@
#include <signal.h>
Log_SetChannel(HTTPDownloaderCurl);
namespace FrontendCommon {
namespace Common {
HTTPDownloaderCurl::HTTPDownloaderCurl() : HTTPDownloader() {}

View file

@ -6,7 +6,7 @@
#include <mutex>
#include <curl/curl.h>
namespace FrontendCommon {
namespace Common {
class HTTPDownloaderCurl final : public HTTPDownloader
{

View file

@ -13,7 +13,7 @@ Log_SetChannel(HTTPDownloaderWinHttp);
using namespace winrt::Windows::Foundation;
using namespace winrt::Windows::Web::Http;
namespace FrontendCommon {
namespace Common {
HTTPDownloaderUWP::HTTPDownloaderUWP(std::string user_agent) : HTTPDownloader(), m_user_agent(std::move(user_agent)) {}

View file

@ -6,7 +6,7 @@
#include <winrt/windows.Web.Http.h>
namespace FrontendCommon {
namespace Common {
class HTTPDownloaderUWP final : public HTTPDownloader
{

View file

@ -9,7 +9,7 @@ Log_SetChannel(HTTPDownloaderWinHttp);
#pragma comment(lib, "winhttp.lib")
namespace FrontendCommon {
namespace Common {
HTTPDownloaderWinHttp::HTTPDownloaderWinHttp() : HTTPDownloader() {}

View file

@ -5,7 +5,7 @@
#include <winhttp.h>
namespace FrontendCommon {
namespace Common {
class HTTPDownloaderWinHttp final : public HTTPDownloader
{

View file

@ -1,4 +1,5 @@
#pragma once
#include "heterogeneous_containers.h"
#include <cstdint>
#include <map>
@ -13,7 +14,7 @@ class LRUCache
CounterType last_access;
};
using MapType = std::map<K, Item>;
using MapType = std::conditional_t<std::is_same_v<K, std::string>, StringMap<Item>, std::map<K, Item>>;
public:
LRUCache(std::size_t max_capacity = 16, bool manual_evict = false)

View file

@ -24,15 +24,18 @@
#include <sys/syscall.h>
#define gettid() syscall(SYS_gettid)
#endif
#else
#elif defined(__APPLE__)
#include <mach/mach.h>
#include <mach/mach_error.h>
#include <mach/mach_time.h>
#include <mach/semaphore.h>
#include <mach/task.h>
#include <pthread_np.h>
#endif
#endif
#ifdef _WIN32
// This hacky union would probably fail on some cpu platforms if the contents of FILETIME aren't
// packed (but for any x86 CPU and microsoft compiler, they will be).
union FileTimeSucks
union FileTimeU64Union
{
FILETIME filetime;
u64 u64time;
@ -208,18 +211,16 @@ Threading::ThreadHandle& Threading::ThreadHandle::operator=(const ThreadHandle&
u64 Threading::ThreadHandle::GetCPUTime() const
{
#if defined(_WIN32)
#if 0
#if defined(_WIN32) && !defined(_UWP) && !defined(_M_ARM64)
u64 ret = 0;
if (m_native_handle)
QueryThreadCycleTime((HANDLE)m_native_handle, &ret);
return ret;
#else
FileTimeSucks user = {}, kernel = {};
#elif defined(_WIN32)
FileTimeU64Union user = {}, kernel = {};
FILETIME dummy;
GetThreadTimes((HANDLE)m_native_handle, &dummy, &dummy, &kernel.filetime, &user.filetime);
return user.u64time + kernel.u64time;
#endif
#elif defined(__APPLE__)
return getthreadtime(pthread_mach_thread_np((pthread_t)m_native_handle));
#elif defined(__linux__)
@ -457,17 +458,15 @@ Threading::ThreadHandle& Threading::Thread::operator=(Thread&& thread)
u64 Threading::GetThreadCpuTime()
{
#if defined(_WIN32)
#if 0
#if defined(_WIN32) && !defined(_UWP) && !defined(_M_ARM64)
u64 ret = 0;
QueryThreadCycleTime(GetCurrentThread(), &ret);
return ret;
#else
FileTimeSucks user = {}, kernel = {};
#elif defined(_WIN32)
FileTimeU64Union user = {}, kernel = {};
FILETIME dummy;
GetThreadTimes(GetCurrentThread(), &dummy, &dummy, &kernel.filetime, &user.filetime);
return user.u64time + kernel.u64time;
#endif
#elif defined(__APPLE__)
return getthreadtime(pthread_mach_thread_np(pthread_self()));
#else
@ -477,17 +476,33 @@ u64 Threading::GetThreadCpuTime()
u64 Threading::GetThreadTicksPerSecond()
{
#if defined(_WIN32)
#if 0
#if defined(_WIN32) && !defined(_UWP) && !defined(_M_ARM64)
// On x86, despite what the MS documentation says, this basically appears to be rdtsc.
// So, the frequency is our base clock speed (and stable regardless of power management).
static u64 frequency = 0;
if (unlikely(frequency == 0))
frequency = x86caps.CachedMHz() * u64(1000000);
if (UNLIKELY(frequency == 0))
{
frequency = 1000000;
HKEY hKey;
if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", 0, KEY_READ, &hKey) ==
ERROR_SUCCESS)
{
DWORD value;
DWORD value_size = sizeof(value);
if (RegQueryValueExW(hKey, L"~MHz", 0, nullptr, reinterpret_cast<LPBYTE>(&value), &value_size) == ERROR_SUCCESS)
{
// value is in mhz, convert to hz
frequency *= value;
}
RegCloseKey(hKey);
}
}
return frequency;
#else
#elif defined(_WIN32)
return 10000000;
#endif
#elif defined(__APPLE__)
return 1000000;
@ -539,3 +554,60 @@ void Threading::SetNameOfCurrentThread(const char* name)
pthread_set_name_np(pthread_self(), name);
#endif
}
Threading::KernelSemaphore::KernelSemaphore()
{
#ifdef _WIN32
m_sema = CreateSemaphore(nullptr, 0, LONG_MAX, nullptr);
#elif defined(__APPLE__)
semaphore_create(mach_task_self(), &m_sema, SYNC_POLICY_FIFO, 0);
#else
sem_init(&m_sema, false, 0);
#endif
}
Threading::KernelSemaphore::~KernelSemaphore()
{
#ifdef _WIN32
CloseHandle(m_sema);
#elif defined(__APPLE__)
semaphore_destroy(mach_task_self(), m_sema);
#else
sem_destroy(&m_sema);
#endif
}
void Threading::KernelSemaphore::Post()
{
#ifdef _WIN32
ReleaseSemaphore(m_sema, 1, nullptr);
#elif defined(__APPLE__)
semaphore_signal(m_sema);
#else
sem_post(&m_sema);
#endif
}
void Threading::KernelSemaphore::Wait()
{
#ifdef _WIN32
WaitForSingleObject(m_sema, INFINITE);
#elif defined(__APPLE__)
semaphore_wait(m_sema);
#else
sem_wait(&m_sema);
#endif
}
bool Threading::KernelSemaphore::TryWait()
{
#ifdef _WIN32
return WaitForSingleObject(m_sema, 0) == WAIT_OBJECT_0;
#elif defined(__APPLE__)
mach_timespec_t time = {};
kern_return_t res = semaphore_timedwait(m_sema, time);
return (res != KERN_OPERATION_TIMED_OUT);
#else
return sem_trywait(&m_sema) == 0;
#endif
}

View file

@ -55,6 +55,16 @@ char (&__countof_ArraySizeHelper(T (&array)[N]))[N];
#define printflike(n,m)
#endif
#ifdef _MSC_VER
// TODO: Use C++20 [[likely]] when available.
#define LIKELY(x) (!!(x))
#define UNLIKELY(x) (!!(x))
#else
#define LIKELY(x) __builtin_expect(!!(x), 1)
#define UNLIKELY(x) __builtin_expect(!!(x), 0)
#endif
// disable warnings that show up at warning level 4
// TODO: Move to build system instead
#ifdef _MSC_VER

View file

@ -386,7 +386,7 @@ void ShaderCache::ClosePipelineCache()
std::string ShaderCache::GetShaderCacheBaseFileName(const std::string_view& base_path, bool debug)
{
std::string base_filename(base_path);
base_filename += "vulkan_shaders";
base_filename += FS_OSPATH_SEPARATOR_STR "vulkan_shaders";
if (debug)
base_filename += "_debug";
@ -397,7 +397,7 @@ std::string ShaderCache::GetShaderCacheBaseFileName(const std::string_view& base
std::string ShaderCache::GetPipelineCacheBaseFileName(const std::string_view& base_path, bool debug)
{
std::string base_filename(base_path);
base_filename += "vulkan_pipelines";
base_filename += FS_OSPATH_SEPARATOR_STR "vulkan_pipelines";
if (debug)
base_filename += "_debug";

View file

@ -1,4 +1,5 @@
add_library(core
achievements.h
analog_controller.cpp
analog_controller.h
analog_joystick.cpp
@ -28,6 +29,8 @@ add_library(core
digital_controller.h
dma.cpp
dma.h
game_database.cpp
game_database.h
gdb_protocol.cpp
gdb_protocol.h
gpu.cpp
@ -48,21 +51,18 @@ add_library(core
gpu_sw_backend.cpp
gpu_sw_backend.h
gpu_types.h
guncon.cpp
guncon.h
gte.cpp
gte.h
gte_types.h
host.cpp
host.h
host_display.cpp
host_display.h
host_interface.cpp
host_interface.h
host_interface_progress_callback.cpp
host_interface_progress_callback.h
host_settings.h
imgui_styles.cpp
imgui_styles.h
imgui_fullscreen.cpp
imgui_fullscreen.h
interrupt_controller.cpp
interrupt_controller.h
libcrypt_game_codes.cpp
@ -75,8 +75,6 @@ add_library(core
memory_card_image.h
multitap.cpp
multitap.h
namco_guncon.cpp
namco_guncon.h
negcon.cpp
negcon.h
pad.cpp
@ -123,7 +121,7 @@ set(RECOMPILER_SRCS
target_include_directories(core PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/..")
target_include_directories(core PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/..")
target_link_libraries(core PUBLIC Threads::Threads common util zlib)
target_link_libraries(core PRIVATE glad stb xxhash imgui)
target_link_libraries(core PRIVATE glad stb xxhash imgui rapidjson tinyxml2)
if(WIN32)
target_sources(core PRIVATE
@ -161,10 +159,5 @@ else()
endif()
if(ENABLE_CHEEVOS)
target_sources(core PRIVATE
cheevos.cpp
cheevos.h
)
target_compile_definitions(core PUBLIC -DWITH_CHEEVOS=1)
target_link_libraries(core PRIVATE rcheevos rapidjson)
target_compile_definitions(core PRIVATE -DWITH_CHEEVOS=1)
endif()

55
src/core/achievements.h Normal file
View file

@ -0,0 +1,55 @@
#pragma once
#include "common/types.h"
class StateWrapper;
class CDImage;
namespace Achievements {
#ifdef WITH_CHEEVOS
// Implemented in Host.
extern bool Reset();
extern bool DoState(StateWrapper& sw);
extern void GameChanged(const std::string& path, CDImage* image);
/// Re-enables hardcode mode if it is enabled in the settings.
extern void ResetChallengeMode();
/// Forces hardcore mode off until next reset.
extern void DisableChallengeMode();
/// Prompts the user to disable hardcore mode, if they agree, returns true.
extern bool ConfirmChallengeModeDisable(const char* trigger);
/// Returns true if features such as save states should be disabled.
extern bool ChallengeModeActive();
#else
// Make noops when compiling without cheevos.
static inline bool Reset()
{
return true;
}
static inline bool DoState(StateWrapper& sw)
{
return true;
}
static constexpr inline bool ChallengeModeActive()
{
return false;
}
static inline void ResetChallengeMode() {}
static inline void DisableChallengeMode() {}
static inline bool ConfirmChallengeModeDisable(const char* trigger)
{
return true;
}
#endif
} // namespace Achievements

View file

@ -1,14 +1,14 @@
#include "analog_controller.h"
#include "common/log.h"
#include "common/string_util.h"
#include "host_interface.h"
#include "host.h"
#include "settings.h"
#include "system.h"
#include "util/state_wrapper.h"
#include <cmath>
Log_SetChannel(AnalogController);
AnalogController::AnalogController(u32 index) : m_index(index)
AnalogController::AnalogController(u32 index) : Controller(index)
{
m_axis_state.fill(0x80);
Reset();
@ -29,7 +29,12 @@ void AnalogController::Reset()
m_tx_buffer.fill(0x00);
m_analog_mode = false;
m_configuration_mode = false;
m_motor_state.fill(0);
for (u32 i = 0; i < NUM_MOTORS; i++)
{
if (m_motor_state[i] != 0)
SetMotorState(i, 0);
}
m_dualshock_enabled = false;
ResetRumbleConfig();
@ -40,8 +45,8 @@ void AnalogController::Reset()
{
if (g_settings.controller_disable_analog_mode_forcing)
{
g_host_interface->AddOSDMessage(
g_host_interface->TranslateStdString(
Host::AddOSDMessage(
Host::TranslateStdString(
"OSDMessage", "Analog mode forcing is disabled by game settings. Controller will start in digital mode."),
10.0f);
}
@ -88,72 +93,42 @@ bool AnalogController::DoState(StateWrapper& sw, bool apply_input_state)
if (old_analog_mode != m_analog_mode)
{
g_host_interface->AddFormattedOSDMessage(
Host::AddFormattedOSDMessage(
5.0f,
m_analog_mode ?
g_host_interface->TranslateString("AnalogController", "Controller %u switched to analog mode.") :
g_host_interface->TranslateString("AnalogController", "Controller %u switched to digital mode."),
m_analog_mode ? Host::TranslateString("AnalogController", "Controller %u switched to analog mode.") :
Host::TranslateString("AnalogController", "Controller %u switched to digital mode."),
m_index + 1u);
}
}
return true;
}
std::optional<s32> AnalogController::GetAxisCodeByName(std::string_view axis_name) const
float AnalogController::GetBindState(u32 index) const
{
return StaticGetAxisCodeByName(axis_name);
}
if (index >= static_cast<u32>(Button::Count))
{
const u32 sub_index = index - static_cast<u32>(Button::Count);
if (sub_index >= static_cast<u32>(m_half_axis_state.size()))
return 0.0f;
std::optional<s32> AnalogController::GetButtonCodeByName(std::string_view button_name) const
{
return StaticGetButtonCodeByName(button_name);
}
float AnalogController::GetAxisState(s32 axis_code) const
{
if (axis_code < 0 || axis_code >= static_cast<s32>(Axis::Count))
return static_cast<float>(m_half_axis_state[sub_index]) * (1.0f / 255.0f);
}
else if (index < static_cast<u32>(Button::Analog))
{
return static_cast<float>(((m_button_state >> index) & 1u) ^ 1u);
}
else
{
return 0.0f;
// 0..255 -> -1..1
const float value = (((static_cast<float>(m_axis_state[static_cast<s32>(axis_code)]) / 255.0f) * 2.0f) - 1.0f);
return std::clamp(value / m_axis_scale, -1.0f, 1.0f);
}
}
void AnalogController::SetAxisState(s32 axis_code, float value)
void AnalogController::SetBindState(u32 index, float value)
{
if (axis_code < 0 || axis_code >= static_cast<s32>(Axis::Count))
return;
// -1..1 -> 0..255
const float scaled_value = std::clamp(value * m_axis_scale, -1.0f, 1.0f);
const u8 u8_value = static_cast<u8>(std::clamp(std::round(((scaled_value + 1.0f) / 2.0f) * 255.0f), 0.0f, 255.0f));
SetAxisState(static_cast<Axis>(axis_code), u8_value);
}
void AnalogController::SetAxisState(Axis axis, u8 value)
{
if (value != m_axis_state[static_cast<u8>(axis)])
System::SetRunaheadReplayFlag();
m_axis_state[static_cast<u8>(axis)] = value;
}
bool AnalogController::GetButtonState(s32 button_code) const
{
if (button_code < 0 || button_code >= static_cast<s32>(Button::Analog))
return false;
const u16 bit = u16(1) << static_cast<u8>(button_code);
return ((m_button_state & bit) == 0);
}
void AnalogController::SetButtonState(Button button, bool pressed)
{
if (button == Button::Analog)
if (index == static_cast<s32>(Button::Analog))
{
// analog toggle
if (pressed)
if (value >= 0.5f)
{
if (m_command == Command::Idle)
ProcessAnalogModeToggle();
@ -163,10 +138,58 @@ void AnalogController::SetButtonState(Button button, bool pressed)
return;
}
else if (index >= static_cast<u32>(Button::Count))
{
const u32 sub_index = index - static_cast<u32>(Button::Count);
if (sub_index >= static_cast<u32>(m_half_axis_state.size()))
return;
const u16 bit = u16(1) << static_cast<u8>(button);
value = ApplyAnalogDeadzoneSensitivity(m_analog_deadzone, m_analog_sensitivity, value);
const u8 u8_value = static_cast<u8>(std::clamp(value * 255.0f, 0.0f, 255.0f));
if (u8_value == m_half_axis_state[sub_index])
return;
if (pressed)
m_half_axis_state[sub_index] = u8_value;
System::SetRunaheadReplayFlag();
#define MERGE(pos, neg) \
((m_half_axis_state[static_cast<u32>(pos)] != 0) ? (127u + ((m_half_axis_state[static_cast<u32>(pos)] + 1u) / 2u)) : \
(127u - (m_half_axis_state[static_cast<u32>(neg)] / 2u)))
switch (static_cast<HalfAxis>(sub_index))
{
case HalfAxis::LLeft:
case HalfAxis::LRight:
m_axis_state[static_cast<u8>(Axis::LeftX)] = MERGE(HalfAxis::LRight, HalfAxis::LLeft);
break;
case HalfAxis::LDown:
case HalfAxis::LUp:
m_axis_state[static_cast<u8>(Axis::LeftY)] = MERGE(HalfAxis::LDown, HalfAxis::LUp);
break;
case HalfAxis::RLeft:
case HalfAxis::RRight:
m_axis_state[static_cast<u8>(Axis::RightX)] = MERGE(HalfAxis::RRight, HalfAxis::RLeft);
break;
case HalfAxis::RDown:
case HalfAxis::RUp:
m_axis_state[static_cast<u8>(Axis::RightY)] = MERGE(HalfAxis::RDown, HalfAxis::RUp);
break;
default:
break;
}
#undef MERGE
return;
}
const u16 bit = u16(1) << static_cast<u8>(index);
if (value >= 0.5f)
{
if (m_button_state & bit)
System::SetRunaheadReplayFlag();
@ -182,14 +205,6 @@ void AnalogController::SetButtonState(Button button, bool pressed)
}
}
void AnalogController::SetButtonState(s32 button_code, bool pressed)
{
if (button_code < 0 || button_code >= static_cast<s32>(Button::Count))
return;
SetButtonState(static_cast<Button>(button_code), pressed);
}
u32 AnalogController::GetButtonStateBits() const
{
// flip bits, native data is active low
@ -202,26 +217,6 @@ std::optional<u32> AnalogController::GetAnalogInputBytes() const
m_axis_state[static_cast<size_t>(Axis::RightY)] << 8 | m_axis_state[static_cast<size_t>(Axis::RightX)];
}
u32 AnalogController::GetVibrationMotorCount() const
{
return NUM_MOTORS;
}
float AnalogController::GetVibrationMotorStrength(u32 motor)
{
DebugAssert(motor < NUM_MOTORS);
if (m_motor_state[motor] == 0)
return 0.0f;
// Curve from https://github.com/KrossX/Pokopom/blob/master/Pokopom/Input_XInput.cpp#L210
const double x =
static_cast<double>(std::min<u32>(static_cast<u32>(m_motor_state[motor]) + static_cast<u32>(m_rumble_bias), 255));
const double strength = 0.006474549734772402 * std::pow(x, 3.0) - 1.258165252213538 * std::pow(x, 2.0) +
156.82454281087692 * x + 3.637978807091713e-11;
return static_cast<float>(strength / 65535.0);
}
void AnalogController::ResetTransferState()
{
if (m_analog_toggle_queued)
@ -240,11 +235,11 @@ void AnalogController::SetAnalogMode(bool enabled)
return;
Log_InfoPrintf("Controller %u switched to %s mode.", m_index + 1u, enabled ? "analog" : "digital");
g_host_interface->AddFormattedOSDMessage(
5.0f,
enabled ? g_host_interface->TranslateString("AnalogController", "Controller %u switched to analog mode.") :
g_host_interface->TranslateString("AnalogController", "Controller %u switched to digital mode."),
m_index + 1u);
Host::AddFormattedOSDMessage(5.0f,
enabled ?
Host::TranslateString("AnalogController", "Controller %u switched to analog mode.") :
Host::TranslateString("AnalogController", "Controller %u switched to digital mode."),
m_index + 1u);
m_analog_mode = enabled;
}
@ -252,11 +247,10 @@ void AnalogController::ProcessAnalogModeToggle()
{
if (m_analog_locked)
{
g_host_interface->AddFormattedOSDMessage(
Host::AddFormattedOSDMessage(
5.0f,
m_analog_mode ?
g_host_interface->TranslateString("AnalogController", "Controller %u is locked to analog mode by the game.") :
g_host_interface->TranslateString("AnalogController", "Controller %u is locked to digital mode by the game."),
m_analog_mode ? Host::TranslateString("AnalogController", "Controller %u is locked to analog mode by the game.") :
Host::TranslateString("AnalogController", "Controller %u is locked to digital mode by the game."),
m_index + 1u);
}
else
@ -269,10 +263,32 @@ void AnalogController::ProcessAnalogModeToggle()
}
}
void AnalogController::SetMotorState(u8 motor, u8 value)
void AnalogController::SetMotorState(u32 motor, u8 value)
{
DebugAssert(motor < NUM_MOTORS);
m_motor_state[motor] = value;
if (m_motor_state[motor] != value)
{
m_motor_state[motor] = value;
UpdateHostVibration();
}
}
void AnalogController::UpdateHostVibration()
{
std::array<float, NUM_MOTORS> hvalues;
for (u32 motor = 0; motor < NUM_MOTORS; motor++)
{
// Curve from https://github.com/KrossX/Pokopom/blob/master/Pokopom/Input_XInput.cpp#L210
const u8 state = m_motor_state[motor];
const double x =
static_cast<double>(std::min<u32>(state + static_cast<u32>(m_rumble_bias), 255));
const double strength = 0.006474549734772402 * std::pow(x, 3.0) - 1.258165252213538 * std::pow(x, 2.0) +
156.82454281087692 * x + 3.637978807091713e-11;
hvalues[motor] = (state != 0) ? static_cast<float>(strength / 65535.0) : 0.0f;
}
Host::SetPadVibrationIntensity(m_index, hvalues[0], hvalues[1]);
}
u8 AnalogController::GetExtraButtonMaskLSB() const
@ -350,7 +366,7 @@ bool AnalogController::Transfer(const u8 data_in, u8* data_out)
if (data_in == 0x01)
{
Log_DevPrintf("ACK controller access");
Log_DebugPrintf("ACK controller access");
m_command = Command::Ready;
return true;
}
@ -689,10 +705,10 @@ bool AnalogController::Transfer(const u8 data_in, u8* data_out)
{
m_command = Command::Idle;
Log_DevPrintf("Rx: %02x %02x %02x %02x %02x %02x %02x %02x", m_rx_buffer[0], m_rx_buffer[1], m_rx_buffer[2],
m_rx_buffer[3], m_rx_buffer[4], m_rx_buffer[5], m_rx_buffer[6], m_rx_buffer[7]);
Log_DevPrintf("Tx: %02x %02x %02x %02x %02x %02x %02x %02x", m_tx_buffer[0], m_tx_buffer[1], m_tx_buffer[2],
m_tx_buffer[3], m_tx_buffer[4], m_tx_buffer[5], m_tx_buffer[6], m_tx_buffer[7]);
Log_DebugPrintf("Rx: %02x %02x %02x %02x %02x %02x %02x %02x", m_rx_buffer[0], m_rx_buffer[1], m_rx_buffer[2],
m_rx_buffer[3], m_rx_buffer[4], m_rx_buffer[5], m_rx_buffer[6], m_rx_buffer[7]);
Log_DebugPrintf("Tx: %02x %02x %02x %02x %02x %02x %02x %02x", m_tx_buffer[0], m_tx_buffer[1], m_tx_buffer[2],
m_tx_buffer[3], m_tx_buffer[4], m_tx_buffer[5], m_tx_buffer[6], m_tx_buffer[7]);
m_rx_buffer.fill(0x00);
m_tx_buffer.fill(0x00);
@ -706,122 +722,89 @@ std::unique_ptr<AnalogController> AnalogController::Create(u32 index)
return std::make_unique<AnalogController>(index);
}
std::optional<s32> AnalogController::StaticGetAxisCodeByName(std::string_view axis_name)
{
#define AXIS(name) \
if (axis_name == #name) \
static const Controller::ControllerBindingInfo s_binding_info[] = {
#define BUTTON(name, display_name, button, genb) \
{ \
return static_cast<s32>(ZeroExtend32(static_cast<u8>(Axis::name))); \
name, display_name, static_cast<u32>(button), Controller::ControllerBindingType::Button, genb \
}
#define AXIS(name, display_name, halfaxis, genb) \
{ \
name, display_name, static_cast<u32>(AnalogController::Button::Count) + static_cast<u32>(halfaxis), \
Controller::ControllerBindingType::HalfAxis, genb \
}
AXIS(LeftX);
AXIS(LeftY);
AXIS(RightX);
AXIS(RightY);
BUTTON("Up", "D-Pad Up", AnalogController::Button::Up, GenericInputBinding::DPadUp),
BUTTON("Right", "D-Pad Right", AnalogController::Button::Right, GenericInputBinding::DPadRight),
BUTTON("Down", "D-Pad Down", AnalogController::Button::Down, GenericInputBinding::DPadDown),
BUTTON("Left", "D-Pad Left", AnalogController::Button::Left, GenericInputBinding::DPadLeft),
BUTTON("Triangle", "Triangle", AnalogController::Button::Triangle, GenericInputBinding::Triangle),
BUTTON("Circle", "Circle", AnalogController::Button::Circle, GenericInputBinding::Circle),
BUTTON("Cross", "Cross", AnalogController::Button::Cross, GenericInputBinding::Cross),
BUTTON("Square", "Square", AnalogController::Button::Square, GenericInputBinding::Square),
BUTTON("Select", "Select", AnalogController::Button::Select, GenericInputBinding::Select),
BUTTON("Start", "Start", AnalogController::Button::Start, GenericInputBinding::Start),
BUTTON("Analog", "Analog Toggle", AnalogController::Button::Analog, GenericInputBinding::System),
BUTTON("L1", "L1", AnalogController::Button::L1, GenericInputBinding::L1),
BUTTON("R1", "R1", AnalogController::Button::R1, GenericInputBinding::R1),
BUTTON("L2", "L2", AnalogController::Button::L2, GenericInputBinding::L2),
BUTTON("R2", "R2", AnalogController::Button::R2, GenericInputBinding::R2),
BUTTON("L3", "L3", AnalogController::Button::L3, GenericInputBinding::L3),
BUTTON("R3", "R3", AnalogController::Button::R3, GenericInputBinding::R3),
return std::nullopt;
AXIS("LLeft", "Left Stick Left", AnalogController::HalfAxis::LLeft, GenericInputBinding::LeftStickLeft),
AXIS("LRight", "Left Stick Right", AnalogController::HalfAxis::LRight, GenericInputBinding::LeftStickRight),
AXIS("LDown", "Left Stick Down", AnalogController::HalfAxis::LDown, GenericInputBinding::LeftStickDown),
AXIS("LUp", "Left Stick Up", AnalogController::HalfAxis::LUp, GenericInputBinding::LeftStickUp),
AXIS("RLeft", "Right Stick Left", AnalogController::HalfAxis::RLeft, GenericInputBinding::RightStickLeft),
AXIS("RRight", "Right Stick Right", AnalogController::HalfAxis::RRight, GenericInputBinding::RightStickRight),
AXIS("RDown", "Right Stick Down", AnalogController::HalfAxis::RDown, GenericInputBinding::RightStickDown),
AXIS("RUp", "Right Stick Up", AnalogController::HalfAxis::RUp, GenericInputBinding::RightStickUp),
#undef AXIS
}
std::optional<s32> AnalogController::StaticGetButtonCodeByName(std::string_view button_name)
{
#define BUTTON(name) \
if (button_name == #name) \
{ \
return static_cast<s32>(ZeroExtend32(static_cast<u8>(Button::name))); \
}
BUTTON(Select);
BUTTON(L3);
BUTTON(R3);
BUTTON(Start);
BUTTON(Up);
BUTTON(Right);
BUTTON(Down);
BUTTON(Left);
BUTTON(L2);
BUTTON(R2);
BUTTON(L1);
BUTTON(R1);
BUTTON(Triangle);
BUTTON(Circle);
BUTTON(Cross);
BUTTON(Square);
BUTTON(Analog);
return std::nullopt;
#undef BUTTON
}
};
Controller::AxisList AnalogController::StaticGetAxisNames()
static const SettingInfo s_settings[] = {
{SettingInfo::Type::Boolean, "ForceAnalogOnReset", TRANSLATABLE("AnalogController", "Force Analog Mode on Reset"),
TRANSLATABLE("AnalogController", "Forces the controller to analog mode when the console is reset/powered on. May "
"cause issues with games, so it is recommended to leave this option off."),
"true"},
{SettingInfo::Type::Boolean, "AnalogDPadInDigitalMode",
TRANSLATABLE("AnalogController", "Use Analog Sticks for D-Pad in Digital Mode"),
TRANSLATABLE("AnalogController",
"Allows you to use the analog sticks to control the d-pad in digital mode, as well as the buttons."),
"true"},
{SettingInfo::Type::Float, "AnalogDeadzone", TRANSLATABLE("AnalogController", "Analog Deadzone"),
TRANSLATABLE("AnalogController",
"Sets the analog stick deadzone, i.e. the fraction of the stick movement which will be ignored."),
"0.00f", "0.00f", "1.00f", "0.01f"},
{SettingInfo::Type::Float, "AnalogSensitivity", TRANSLATABLE("AnalogController", "Analog Sensitivity"),
TRANSLATABLE(
"AnalogController",
"Sets the analog stick axis scaling factor. A value between 1.30 and 1.40 is recommended when using recent "
"controllers, e.g. DualShock 4, Xbox One Controller."),
"1.33f", "0.01f", "2.00f", "0.01f"},
{SettingInfo::Type::Integer, "VibrationBias", TRANSLATABLE("AnalogController", "Vibration Bias"),
TRANSLATABLE("AnalogController", "Sets the rumble bias value. If rumble in some games is too weak or not "
"functioning, try increasing this value."),
"8", "0", "255", "1"}};
const Controller::ControllerInfo AnalogController::INFO = {ControllerType::AnalogController,
"AnalogController",
TRANSLATABLE("ControllerType", "Analog Controller"),
s_binding_info,
countof(s_binding_info),
s_settings,
countof(s_settings),
Controller::VibrationCapabilities::LargeSmallMotors};
void AnalogController::LoadSettings(SettingsInterface& si, const char* section)
{
return {{TRANSLATABLE("AnalogController", "LeftX"), static_cast<s32>(Axis::LeftX), AxisType::Full},
{TRANSLATABLE("AnalogController", "LeftY"), static_cast<s32>(Axis::LeftY), AxisType::Full},
{TRANSLATABLE("AnalogController", "RightX"), static_cast<s32>(Axis::RightX), AxisType::Full},
{TRANSLATABLE("AnalogController", "RightY"), static_cast<s32>(Axis::RightY), AxisType::Full}};
}
Controller::ButtonList AnalogController::StaticGetButtonNames()
{
return {{TRANSLATABLE("AnalogController", "Up"), static_cast<s32>(Button::Up)},
{TRANSLATABLE("AnalogController", "Down"), static_cast<s32>(Button::Down)},
{TRANSLATABLE("AnalogController", "Left"), static_cast<s32>(Button::Left)},
{TRANSLATABLE("AnalogController", "Right"), static_cast<s32>(Button::Right)},
{TRANSLATABLE("AnalogController", "Select"), static_cast<s32>(Button::Select)},
{TRANSLATABLE("AnalogController", "Start"), static_cast<s32>(Button::Start)},
{TRANSLATABLE("AnalogController", "Triangle"), static_cast<s32>(Button::Triangle)},
{TRANSLATABLE("AnalogController", "Cross"), static_cast<s32>(Button::Cross)},
{TRANSLATABLE("AnalogController", "Circle"), static_cast<s32>(Button::Circle)},
{TRANSLATABLE("AnalogController", "Square"), static_cast<s32>(Button::Square)},
{TRANSLATABLE("AnalogController", "L1"), static_cast<s32>(Button::L1)},
{TRANSLATABLE("AnalogController", "L2"), static_cast<s32>(Button::L2)},
{TRANSLATABLE("AnalogController", "R1"), static_cast<s32>(Button::R1)},
{TRANSLATABLE("AnalogController", "R2"), static_cast<s32>(Button::R2)},
{TRANSLATABLE("AnalogController", "L3"), static_cast<s32>(Button::L3)},
{TRANSLATABLE("AnalogController", "R3"), static_cast<s32>(Button::R3)},
{TRANSLATABLE("AnalogController", "Analog"), static_cast<s32>(Button::Analog)}};
}
u32 AnalogController::StaticGetVibrationMotorCount()
{
return NUM_MOTORS;
}
Controller::SettingList AnalogController::StaticGetSettings()
{
static constexpr std::array<SettingInfo, 4> settings = {
{{SettingInfo::Type::Boolean, "ForceAnalogOnReset", TRANSLATABLE("AnalogController", "Force Analog Mode on Reset"),
TRANSLATABLE("AnalogController", "Forces the controller to analog mode when the console is reset/powered on. May "
"cause issues with games, so it is recommended to leave this option off."),
"false"},
{SettingInfo::Type::Boolean, "AnalogDPadInDigitalMode",
TRANSLATABLE("AnalogController", "Use Analog Sticks for D-Pad in Digital Mode"),
TRANSLATABLE("AnalogController",
"Allows you to use the analog sticks to control the d-pad in digital mode, as well as the buttons."),
"false"},
{SettingInfo::Type::Float, "AxisScale", TRANSLATABLE("AnalogController", "Analog Axis Scale"),
TRANSLATABLE(
"AnalogController",
"Sets the analog stick axis scaling factor. A value between 1.30 and 1.40 is recommended when using recent "
"controllers, e.g. DualShock 4, Xbox One Controller."),
"1.00f", "0.01f", "1.50f", "0.01f"},
{SettingInfo::Type::Integer, "VibrationBias", TRANSLATABLE("AnalogController", "Vibration Bias"),
TRANSLATABLE("AnalogController", "Sets the rumble bias value. If rumble in some games is too weak or not "
"functioning, try increasing this value."),
"8", "0", "255", "1"}}};
return SettingList(settings.begin(), settings.end());
}
void AnalogController::LoadSettings(const char* section)
{
Controller::LoadSettings(section);
m_force_analog_on_reset = g_host_interface->GetBoolSettingValue(section, "ForceAnalogOnReset", false);
m_analog_dpad_in_digital_mode = g_host_interface->GetBoolSettingValue(section, "AnalogDPadInDigitalMode", false);
m_axis_scale =
std::clamp(std::abs(g_host_interface->GetFloatSettingValue(section, "AxisScale", 1.00f)), 0.01f, 1.50f);
m_rumble_bias =
static_cast<u8>(std::min<u32>(g_host_interface->GetIntSettingValue(section, "VibrationBias", 8), 255));
Controller::LoadSettings(si, section);
m_force_analog_on_reset = si.GetBoolValue(section, "ForceAnalogOnReset", true);
m_analog_dpad_in_digital_mode = si.GetBoolValue(section, "AnalogDPadInDigitalMode", true);
m_analog_deadzone = std::clamp(si.GetFloatValue(section, "AnalogDeadzone", DEFAULT_STICK_DEADZONE), 0.0f, 1.0f);
m_analog_sensitivity =
std::clamp(si.GetFloatValue(section, "AnalogSensitivity", DEFAULT_STICK_SENSITIVITY), 0.01f, 3.0f);
m_rumble_bias = static_cast<u8>(std::min<u32>(si.GetIntValue(section, "VibrationBias", 8), 255));
}

View file

@ -39,43 +39,42 @@ public:
Count
};
enum class HalfAxis : u8
{
LLeft,
LRight,
LDown,
LUp,
RLeft,
RRight,
RDown,
RUp,
Count
};
static constexpr u8 NUM_MOTORS = 2;
static const Controller::ControllerInfo INFO;
AnalogController(u32 index);
~AnalogController() override;
static std::unique_ptr<AnalogController> Create(u32 index);
static std::optional<s32> StaticGetAxisCodeByName(std::string_view axis_name);
static std::optional<s32> StaticGetButtonCodeByName(std::string_view button_name);
static AxisList StaticGetAxisNames();
static ButtonList StaticGetButtonNames();
static u32 StaticGetVibrationMotorCount();
static SettingList StaticGetSettings();
ControllerType GetType() const override;
std::optional<s32> GetAxisCodeByName(std::string_view axis_name) const override;
std::optional<s32> GetButtonCodeByName(std::string_view button_name) const override;
void Reset() override;
bool DoState(StateWrapper& sw, bool ignore_input_state) override;
float GetAxisState(s32 axis_code) const override;
void SetAxisState(s32 axis_code, float value) override;
bool GetButtonState(s32 button_code) const override;
void SetButtonState(s32 button_code, bool pressed) override;
float GetBindState(u32 index) const override;
void SetBindState(u32 index, float value) override;
u32 GetButtonStateBits() const override;
std::optional<u32> GetAnalogInputBytes() const override;
void ResetTransferState() override;
bool Transfer(const u8 data_in, u8* data_out) override;
void SetAxisState(Axis axis, u8 value);
void SetButtonState(Button button, bool pressed);
u32 GetVibrationMotorCount() const override;
float GetVibrationMotorStrength(u32 motor) override;
void LoadSettings(const char* section) override;
void LoadSettings(SettingsInterface& si, const char* section) override;
private:
using MotorState = std::array<u8, NUM_MOTORS>;
@ -111,16 +110,16 @@ private:
void SetAnalogMode(bool enabled);
void ProcessAnalogModeToggle();
void SetMotorState(u8 motor, u8 value);
void SetMotorState(u32 motor, u8 value);
void UpdateHostVibration();
u8 GetExtraButtonMaskLSB() const;
void ResetRumbleConfig();
void SetMotorStateForConfigIndex(int index, u8 value);
u32 m_index;
bool m_force_analog_on_reset = false;
bool m_analog_dpad_in_digital_mode = false;
float m_axis_scale = 1.00f;
float m_analog_deadzone = 0.0f;
float m_analog_sensitivity = 1.33f;
u8 m_rumble_bias = 8;
bool m_analog_mode = false;
@ -151,6 +150,9 @@ private:
MotorState m_motor_state{};
// both directions of axis state, merged to m_axis_state
std::array<u8, static_cast<u32>(HalfAxis::Count)> m_half_axis_state{};
// Member variables that are no longer used, but kept and serialized for compatibility with older save states
u8 m_command_param = 0;
bool m_legacy_rumble_unlocked = false;

View file

@ -1,15 +1,14 @@
#include "analog_joystick.h"
#include "common/log.h"
#include "common/string_util.h"
#include "host_interface.h"
#include "host.h"
#include "system.h"
#include "util/state_wrapper.h"
#include <cmath>
Log_SetChannel(AnalogJoystick);
AnalogJoystick::AnalogJoystick(u32 index)
AnalogJoystick::AnalogJoystick(u32 index) : Controller(index)
{
m_index = index;
m_axis_state.fill(0x80);
Reset();
}
@ -50,82 +49,101 @@ bool AnalogJoystick::DoState(StateWrapper& sw, bool apply_input_state)
if (sw.IsReading() && (old_analog_mode != m_analog_mode))
{
g_host_interface->AddFormattedOSDMessage(
5.0f,
m_analog_mode ? g_host_interface->TranslateString("AnalogJoystick", "Controller %u switched to analog mode.") :
g_host_interface->TranslateString("AnalogJoystick", "Controller %u switched to digital mode."),
m_index + 1u);
Host::AddFormattedOSDMessage(5.0f,
m_analog_mode ?
Host::TranslateString("AnalogJoystick", "Controller %u switched to analog mode.") :
Host::TranslateString("AnalogJoystick", "Controller %u switched to digital mode."),
m_index + 1u);
}
return true;
}
std::optional<s32> AnalogJoystick::GetAxisCodeByName(std::string_view axis_name) const
float AnalogJoystick::GetBindState(u32 index) const
{
return StaticGetAxisCodeByName(axis_name);
}
std::optional<s32> AnalogJoystick::GetButtonCodeByName(std::string_view button_name) const
{
return StaticGetButtonCodeByName(button_name);
}
float AnalogJoystick::GetAxisState(s32 axis_code) const
{
if (axis_code < 0 || axis_code >= static_cast<s32>(Axis::Count))
return 0.0f;
// 0..255 -> -1..1
const float value = (((static_cast<float>(m_axis_state[static_cast<s32>(axis_code)]) / 255.0f) * 2.0f) - 1.0f);
return std::clamp(value / m_axis_scale, -1.0f, 1.0f);
}
void AnalogJoystick::SetAxisState(s32 axis_code, float value)
{
if (axis_code < 0 || axis_code >= static_cast<s32>(Axis::Count))
return;
// -1..1 -> 0..255
const float scaled_value = std::clamp(value * m_axis_scale, -1.0f, 1.0f);
const u8 u8_value = static_cast<u8>(std::clamp(std::round(((scaled_value + 1.0f) / 2.0f) * 255.0f), 0.0f, 255.0f));
SetAxisState(static_cast<Axis>(axis_code), u8_value);
}
void AnalogJoystick::SetAxisState(Axis axis, u8 value)
{
if (m_axis_state[static_cast<u8>(axis)] != value)
System::SetRunaheadReplayFlag();
m_axis_state[static_cast<u8>(axis)] = value;
}
bool AnalogJoystick::GetButtonState(s32 button_code) const
{
if (button_code < 0 || button_code >= static_cast<s32>(Button::Count))
return false;
const u16 bit = u16(1) << static_cast<u8>(button_code);
return ((m_button_state & bit) == 0);
}
void AnalogJoystick::SetButtonState(Button button, bool pressed)
{
if (button == Button::Mode)
if (index >= static_cast<u32>(Button::Count))
{
if (pressed)
const u32 sub_index = index - static_cast<u32>(Button::Count);
if (sub_index >= static_cast<u32>(m_half_axis_state.size()))
return 0.0f;
return static_cast<float>(m_half_axis_state[sub_index]) * (1.0f / 255.0f);
}
else if (index < static_cast<u32>(Button::Mode))
{
return static_cast<float>(((m_button_state >> index) & 1u) ^ 1u);
}
else
{
return 0.0f;
}
}
void AnalogJoystick::SetBindState(u32 index, float value)
{
if (index == static_cast<s32>(Button::Mode))
{
// analog toggle
if (value >= 0.5f)
ToggleAnalogMode();
return;
}
else if (index >= static_cast<u32>(Button::Count))
{
const u32 sub_index = index - static_cast<u32>(Button::Count);
if (sub_index >= static_cast<u32>(m_half_axis_state.size()))
return;
const u16 bit = u16(1) << static_cast<u8>(button);
value = ApplyAnalogDeadzoneSensitivity(m_analog_deadzone, m_analog_sensitivity, value);
const u8 u8_value = static_cast<u8>(std::clamp(value * 255.0f, 0.0f, 255.0f));
if (u8_value != m_half_axis_state[sub_index])
System::SetRunaheadReplayFlag();
if (pressed)
m_half_axis_state[sub_index] = u8_value;
#define MERGE(pos, neg) \
((m_half_axis_state[static_cast<u32>(pos)] != 0) ? (127u + ((m_half_axis_state[static_cast<u32>(pos)] + 1u) / 2u)) : \
(127u - (m_half_axis_state[static_cast<u32>(neg)] / 2u)))
switch (static_cast<HalfAxis>(sub_index))
{
case HalfAxis::LLeft:
case HalfAxis::LRight:
m_axis_state[static_cast<u8>(Axis::LeftX)] = MERGE(HalfAxis::LRight, HalfAxis::LLeft);
break;
case HalfAxis::LDown:
case HalfAxis::LUp:
m_axis_state[static_cast<u8>(Axis::LeftY)] = MERGE(HalfAxis::LDown, HalfAxis::LUp);
break;
case HalfAxis::RLeft:
case HalfAxis::RRight:
m_axis_state[static_cast<u8>(Axis::RightX)] = MERGE(HalfAxis::RRight, HalfAxis::RLeft);
break;
case HalfAxis::RDown:
case HalfAxis::RUp:
m_axis_state[static_cast<u8>(Axis::RightY)] = MERGE(HalfAxis::RDown, HalfAxis::RUp);
break;
default:
break;
}
#undef MERGE
return;
}
const u16 bit = u16(1) << static_cast<u8>(index);
if (value >= 0.5f)
{
if (m_button_state & bit)
System::SetRunaheadReplayFlag();
m_button_state &= ~bit;
m_button_state &= ~(bit);
}
else
{
@ -136,14 +154,6 @@ void AnalogJoystick::SetButtonState(Button button, bool pressed)
}
}
void AnalogJoystick::SetButtonState(s32 button_code, bool pressed)
{
if (button_code < 0 || button_code >= static_cast<s32>(Button::Count))
return;
SetButtonState(static_cast<Button>(button_code), pressed);
}
u32 AnalogJoystick::GetButtonStateBits() const
{
return m_button_state ^ 0xFFFF;
@ -173,11 +183,11 @@ void AnalogJoystick::ToggleAnalogMode()
m_analog_mode = !m_analog_mode;
Log_InfoPrintf("Joystick %u switched to %s mode.", m_index + 1u, m_analog_mode ? "analog" : "digital");
g_host_interface->AddFormattedOSDMessage(
5.0f,
m_analog_mode ? g_host_interface->TranslateString("AnalogJoystick", "Controller %u switched to analog mode.") :
g_host_interface->TranslateString("AnalogJoystick", "Controller %u switched to digital mode."),
m_index + 1u);
Host::AddFormattedOSDMessage(5.0f,
m_analog_mode ?
Host::TranslateString("AnalogJoystick", "Controller %u switched to analog mode.") :
Host::TranslateString("AnalogJoystick", "Controller %u switched to digital mode."),
m_index + 1u);
}
bool AnalogJoystick::Transfer(const u8 data_in, u8* data_out)
@ -272,104 +282,73 @@ std::unique_ptr<AnalogJoystick> AnalogJoystick::Create(u32 index)
return std::make_unique<AnalogJoystick>(index);
}
std::optional<s32> AnalogJoystick::StaticGetAxisCodeByName(std::string_view axis_name)
{
#define AXIS(name) \
if (axis_name == #name) \
static const Controller::ControllerBindingInfo s_binding_info[] = {
#define BUTTON(name, display_name, button, genb) \
{ \
return static_cast<s32>(ZeroExtend32(static_cast<u8>(Axis::name))); \
name, display_name, static_cast<u32>(button), Controller::ControllerBindingType::Button, genb \
}
#define AXIS(name, display_name, halfaxis, genb) \
{ \
name, display_name, static_cast<u32>(AnalogJoystick::Button::Count) + static_cast<u32>(halfaxis), \
Controller::ControllerBindingType::HalfAxis, genb \
}
AXIS(LeftX);
AXIS(LeftY);
AXIS(RightX);
AXIS(RightY);
BUTTON("Up", "D-Pad Up", AnalogJoystick::Button::Up, GenericInputBinding::DPadUp),
BUTTON("Right", "D-Pad Right", AnalogJoystick::Button::Right, GenericInputBinding::DPadRight),
BUTTON("Down", "D-Pad Down", AnalogJoystick::Button::Down, GenericInputBinding::DPadDown),
BUTTON("Left", "D-Pad Left", AnalogJoystick::Button::Left, GenericInputBinding::DPadLeft),
BUTTON("Triangle", "Triangle", AnalogJoystick::Button::Triangle, GenericInputBinding::Triangle),
BUTTON("Circle", "Circle", AnalogJoystick::Button::Circle, GenericInputBinding::Circle),
BUTTON("Cross", "Cross", AnalogJoystick::Button::Cross, GenericInputBinding::Cross),
BUTTON("Square", "Square", AnalogJoystick::Button::Square, GenericInputBinding::Square),
BUTTON("Select", "Select", AnalogJoystick::Button::Select, GenericInputBinding::Select),
BUTTON("Start", "Start", AnalogJoystick::Button::Start, GenericInputBinding::Start),
BUTTON("Mode", "Mode Toggle", AnalogJoystick::Button::Mode, GenericInputBinding::System),
BUTTON("L1", "L1", AnalogJoystick::Button::L1, GenericInputBinding::L1),
BUTTON("R1", "R1", AnalogJoystick::Button::R1, GenericInputBinding::R1),
BUTTON("L2", "L2", AnalogJoystick::Button::L2, GenericInputBinding::L2),
BUTTON("R2", "R2", AnalogJoystick::Button::R2, GenericInputBinding::R2),
BUTTON("L3", "L3", AnalogJoystick::Button::L3, GenericInputBinding::L3),
BUTTON("R3", "R3", AnalogJoystick::Button::R3, GenericInputBinding::R3),
return std::nullopt;
AXIS("LLeft", "Left Stick Left", AnalogJoystick::HalfAxis::LLeft, GenericInputBinding::LeftStickLeft),
AXIS("LRight", "Left Stick Right", AnalogJoystick::HalfAxis::LRight, GenericInputBinding::LeftStickRight),
AXIS("LDown", "Left Stick Down", AnalogJoystick::HalfAxis::LDown, GenericInputBinding::LeftStickDown),
AXIS("LUp", "Left Stick Up", AnalogJoystick::HalfAxis::LUp, GenericInputBinding::LeftStickUp),
AXIS("RLeft", "Right Stick Left", AnalogJoystick::HalfAxis::RLeft, GenericInputBinding::RightStickLeft),
AXIS("RRight", "Right Stick Right", AnalogJoystick::HalfAxis::RRight, GenericInputBinding::RightStickRight),
AXIS("RDown", "Right Stick Down", AnalogJoystick::HalfAxis::RDown, GenericInputBinding::RightStickDown),
AXIS("RUp", "Right Stick Up", AnalogJoystick::HalfAxis::RUp, GenericInputBinding::RightStickUp),
#undef AXIS
}
std::optional<s32> AnalogJoystick::StaticGetButtonCodeByName(std::string_view button_name)
{
#define BUTTON(name) \
if (button_name == #name) \
{ \
return static_cast<s32>(ZeroExtend32(static_cast<u8>(Button::name))); \
}
BUTTON(Select);
BUTTON(L3);
BUTTON(R3);
BUTTON(Start);
BUTTON(Up);
BUTTON(Right);
BUTTON(Down);
BUTTON(Left);
BUTTON(L2);
BUTTON(R2);
BUTTON(L1);
BUTTON(R1);
BUTTON(Triangle);
BUTTON(Circle);
BUTTON(Cross);
BUTTON(Square);
BUTTON(Mode);
return std::nullopt;
#undef BUTTON
}
};
Controller::AxisList AnalogJoystick::StaticGetAxisNames()
static const SettingInfo s_settings[] = {
{SettingInfo::Type::Float, "AnalogDeadzone", TRANSLATABLE("AnalogController", "Analog Deadzone"),
TRANSLATABLE("AnalogController",
"Sets the analog stick deadzone, i.e. the fraction of the stick movement which will be ignored.s"),
"1.00f", "0.00f", "1.00f", "0.01f"},
{SettingInfo::Type::Float, "AnalogSensitivity", TRANSLATABLE("AnalogController", "Analog Sensitivity"),
TRANSLATABLE(
"AnalogController",
"Sets the analog stick axis scaling factor. A value between 1.30 and 1.40 is recommended when using recent "
"controllers, e.g. DualShock 4, Xbox One Controller."),
"1.33f", "0.01f", "2.00f", "0.01f"}};
const Controller::ControllerInfo AnalogJoystick::INFO = {ControllerType::AnalogJoystick,
"AnalogJoystick",
TRANSLATABLE("ControllerType", "Analog Joystick"),
s_binding_info,
countof(s_binding_info),
s_settings,
countof(s_settings),
Controller::VibrationCapabilities::NoVibration};
void AnalogJoystick::LoadSettings(SettingsInterface& si, const char* section)
{
return {{TRANSLATABLE("AnalogJoystick", "LeftX"), static_cast<s32>(Axis::LeftX), AxisType::Full},
{TRANSLATABLE("AnalogJoystick", "LeftY"), static_cast<s32>(Axis::LeftY), AxisType::Full},
{TRANSLATABLE("AnalogJoystick", "RightX"), static_cast<s32>(Axis::RightX), AxisType::Full},
{TRANSLATABLE("AnalogJoystick", "RightY"), static_cast<s32>(Axis::RightY), AxisType::Full}};
}
Controller::ButtonList AnalogJoystick::StaticGetButtonNames()
{
return {{TRANSLATABLE("AnalogJoystick", "Up"), static_cast<s32>(Button::Up)},
{TRANSLATABLE("AnalogJoystick", "Down"), static_cast<s32>(Button::Down)},
{TRANSLATABLE("AnalogJoystick", "Left"), static_cast<s32>(Button::Left)},
{TRANSLATABLE("AnalogJoystick", "Right"), static_cast<s32>(Button::Right)},
{TRANSLATABLE("AnalogJoystick", "Select"), static_cast<s32>(Button::Select)},
{TRANSLATABLE("AnalogJoystick", "Start"), static_cast<s32>(Button::Start)},
{TRANSLATABLE("AnalogJoystick", "Triangle"), static_cast<s32>(Button::Triangle)},
{TRANSLATABLE("AnalogJoystick", "Cross"), static_cast<s32>(Button::Cross)},
{TRANSLATABLE("AnalogJoystick", "Circle"), static_cast<s32>(Button::Circle)},
{TRANSLATABLE("AnalogJoystick", "Square"), static_cast<s32>(Button::Square)},
{TRANSLATABLE("AnalogJoystick", "L1"), static_cast<s32>(Button::L1)},
{TRANSLATABLE("AnalogJoystick", "L2"), static_cast<s32>(Button::L2)},
{TRANSLATABLE("AnalogJoystick", "R1"), static_cast<s32>(Button::R1)},
{TRANSLATABLE("AnalogJoystick", "R2"), static_cast<s32>(Button::R2)},
{TRANSLATABLE("AnalogJoystick", "L3"), static_cast<s32>(Button::L3)},
{TRANSLATABLE("AnalogJoystick", "R3"), static_cast<s32>(Button::R3)},
{TRANSLATABLE("AnalogJoystick", "Analog"), static_cast<s32>(Button::Mode)}};
}
u32 AnalogJoystick::StaticGetVibrationMotorCount()
{
return 0;
}
Controller::SettingList AnalogJoystick::StaticGetSettings()
{
static constexpr std::array<SettingInfo, 1> settings = {
{{SettingInfo::Type::Float, "AxisScale", TRANSLATABLE("AnalogJoystick", "Analog Axis Scale"),
TRANSLATABLE(
"AnalogJoystick",
"Sets the analog stick axis scaling factor. A value between 1.30 and 1.40 is recommended when using recent "
"controllers, e.g. DualShock 4, Xbox One Controller."),
"1.00f", "0.01f", "1.50f", "0.01f"}}};
return SettingList(settings.begin(), settings.end());
}
void AnalogJoystick::LoadSettings(const char* section)
{
Controller::LoadSettings(section);
m_axis_scale = std::clamp(g_host_interface->GetFloatSettingValue(section, "AxisScale", 1.00f), 0.01f, 1.50f);
Controller::LoadSettings(si, section);
m_analog_deadzone = std::clamp(si.GetFloatValue(section, "AnalogDeadzone", DEFAULT_STICK_DEADZONE), 0.0f, 1.0f);
m_analog_sensitivity =
std::clamp(si.GetFloatValue(section, "AnalogSensitivity", DEFAULT_STICK_SENSITIVITY), 0.01f, 3.0f);
}

View file

@ -39,38 +39,40 @@ public:
Count
};
enum class HalfAxis : u8
{
LLeft,
LRight,
LDown,
LUp,
RLeft,
RRight,
RDown,
RUp,
Count
};
static const Controller::ControllerInfo INFO;
AnalogJoystick(u32 index);
~AnalogJoystick() override;
static std::unique_ptr<AnalogJoystick> Create(u32 index);
static std::optional<s32> StaticGetAxisCodeByName(std::string_view axis_name);
static std::optional<s32> StaticGetButtonCodeByName(std::string_view button_name);
static AxisList StaticGetAxisNames();
static ButtonList StaticGetButtonNames();
static u32 StaticGetVibrationMotorCount();
static SettingList StaticGetSettings();
ControllerType GetType() const override;
std::optional<s32> GetAxisCodeByName(std::string_view axis_name) const override;
std::optional<s32> GetButtonCodeByName(std::string_view button_name) const override;
void Reset() override;
bool DoState(StateWrapper& sw, bool apply_input_state) override;
float GetAxisState(s32 axis_code) const override;
void SetAxisState(s32 axis_code, float value) override;
bool GetButtonState(s32 button_code) const override;
void SetButtonState(s32 button_code, bool pressed) override;
float GetBindState(u32 index) const override;
void SetBindState(u32 index, float value) override;
u32 GetButtonStateBits() const override;
std::optional<u32> GetAnalogInputBytes() const override;
void ResetTransferState() override;
bool Transfer(const u8 data_in, u8* data_out) override;
void LoadSettings(const char* section) override;
void SetAxisState(Axis axis, u8 value);
void SetButtonState(Button button, bool pressed);
void LoadSettings(SettingsInterface& si, const char* section) override;
private:
enum class TransferState : u8
@ -89,9 +91,8 @@ private:
u16 GetID() const;
void ToggleAnalogMode();
u32 m_index;
float m_axis_scale = 1.00f;
float m_analog_deadzone = 0.0f;
float m_analog_sensitivity = 1.33f;
// On original hardware, the mode toggle is a switch rather than a button, so we'll enable Analog Mode by default
bool m_analog_mode = true;
@ -101,5 +102,8 @@ private:
std::array<u8, static_cast<u8>(Axis::Count)> m_axis_state{};
// both directions of axis state, merged to m_axis_state
std::array<u8, static_cast<u32>(HalfAxis::Count)> m_half_axis_state{};
TransferState m_transfer_state = TransferState::Idle;
};

View file

@ -3,7 +3,11 @@
#include "common/file_system.h"
#include "common/log.h"
#include "common/md5_digest.h"
#include "common/path.h"
#include "cpu_disasm.h"
#include "host.h"
#include "host_settings.h"
#include "settings.h"
#include <array>
#include <cerrno>
Log_SetChannel(BIOS);
@ -272,3 +276,143 @@ DiscRegion GetPSExeDiscRegion(const PSEXEHeader& header)
}
} // namespace BIOS
std::optional<std::vector<u8>> BIOS::GetBIOSImage(ConsoleRegion region)
{
std::string bios_name;
switch (region)
{
case ConsoleRegion::NTSC_J:
bios_name = Host::GetStringSettingValue("BIOS", "PathNTSCJ", "");
break;
case ConsoleRegion::PAL:
bios_name = Host::GetStringSettingValue("BIOS", "PathPAL", "");
break;
case ConsoleRegion::NTSC_U:
default:
bios_name = Host::GetStringSettingValue("BIOS", "PathNTSCU", "");
break;
}
if (bios_name.empty())
{
// auto-detect
return FindBIOSImageInDirectory(region, EmuFolders::Bios.c_str());
}
// try the configured path
std::optional<Image> image = LoadImageFromFile(Path::Combine(EmuFolders::Bios, bios_name).c_str());
if (!image.has_value())
{
Host::ReportFormattedErrorAsync(
"Error", Host::TranslateString("HostInterface", "Failed to load configured BIOS file '%s'"), bios_name.c_str());
return std::nullopt;
}
Hash found_hash = GetHash(*image);
Log_DevPrintf("Hash for BIOS '%s': %s", bios_name.c_str(), found_hash.ToString().c_str());
if (!IsValidHashForRegion(region, found_hash))
Log_WarningPrintf("Hash for BIOS '%s' does not match region. This may cause issues.", bios_name.c_str());
return image;
}
std::optional<std::vector<u8>> BIOS::FindBIOSImageInDirectory(ConsoleRegion region, const char* directory)
{
Log_InfoPrintf("Searching for a %s BIOS in '%s'...", Settings::GetConsoleRegionDisplayName(region), directory);
FileSystem::FindResultsArray results;
FileSystem::FindFiles(
directory, "*", FILESYSTEM_FIND_FILES | FILESYSTEM_FIND_HIDDEN_FILES | FILESYSTEM_FIND_RELATIVE_PATHS, &results);
std::string fallback_path;
std::optional<Image> fallback_image;
const ImageInfo* fallback_info = nullptr;
for (const FILESYSTEM_FIND_DATA& fd : results)
{
if (fd.Size != BIOS_SIZE && fd.Size != BIOS_SIZE_PS2 && fd.Size != BIOS_SIZE_PS3)
{
Log_WarningPrintf("Skipping '%s': incorrect size", fd.FileName.c_str());
continue;
}
std::string full_path(Path::Combine(directory, fd.FileName));
std::optional<Image> found_image = LoadImageFromFile(full_path.c_str());
if (!found_image)
continue;
Hash found_hash = GetHash(*found_image);
Log_DevPrintf("Hash for BIOS '%s': %s", fd.FileName.c_str(), found_hash.ToString().c_str());
const ImageInfo* ii = GetImageInfoForHash(found_hash);
if (IsValidHashForRegion(region, found_hash))
{
Log_InfoPrintf("Using BIOS '%s': %s", fd.FileName.c_str(), ii ? ii->description : "");
return found_image;
}
// don't let an unknown bios take precedence over a known one
if (!fallback_path.empty() && (fallback_info || !ii))
continue;
fallback_path = std::move(full_path);
fallback_image = std::move(found_image);
fallback_info = ii;
}
if (!fallback_image.has_value())
{
Host::ReportFormattedErrorAsync("Error",
Host::TranslateString("HostInterface", "No BIOS image found for %s region"),
Settings::GetConsoleRegionDisplayName(region));
return std::nullopt;
}
if (!fallback_info)
{
Log_WarningPrintf("Using unknown BIOS '%s'. This may crash.", fallback_path.c_str());
}
else
{
Log_WarningPrintf("Falling back to possibly-incompatible image '%s': %s", fallback_path.c_str(),
fallback_info->description);
}
return fallback_image;
}
std::vector<std::pair<std::string, const BIOS::ImageInfo*>> BIOS::FindBIOSImagesInDirectory(const char* directory)
{
std::vector<std::pair<std::string, const ImageInfo*>> results;
FileSystem::FindResultsArray files;
FileSystem::FindFiles(directory, "*",
FILESYSTEM_FIND_FILES | FILESYSTEM_FIND_HIDDEN_FILES | FILESYSTEM_FIND_RELATIVE_PATHS, &files);
for (FILESYSTEM_FIND_DATA& fd : files)
{
if (fd.Size != BIOS_SIZE && fd.Size != BIOS_SIZE_PS2 && fd.Size != BIOS_SIZE_PS3)
continue;
std::string full_path(Path::Combine(directory, fd.FileName));
std::optional<Image> found_image = LoadImageFromFile(full_path.c_str());
if (!found_image)
continue;
Hash found_hash = GetHash(*found_image);
const ImageInfo* ii = GetImageInfoForHash(found_hash);
results.emplace_back(std::move(fd.FileName), ii);
}
return results;
}
bool BIOS::HasAnyBIOSImages()
{
return FindBIOSImageInDirectory(ConsoleRegion::Auto, EmuFolders::Bios.c_str()).has_value();
}

View file

@ -70,4 +70,17 @@ bool PatchBIOSForEXE(u8* image, u32 image_size, u32 r_pc, u32 r_gp, u32 r_sp, u3
bool IsValidPSExeHeader(const PSEXEHeader& header, u32 file_size);
DiscRegion GetPSExeDiscRegion(const PSEXEHeader& header);
/// Loads the BIOS image for the specified region.
std::optional<std::vector<u8>> GetBIOSImage(ConsoleRegion region);
/// Searches for a BIOS image for the specified region in the specified directory. If no match is found, the first
/// BIOS image within 512KB and 4MB will be used.
std::optional<std::vector<u8>> FindBIOSImageInDirectory(ConsoleRegion region, const char* directory);
/// Returns a list of filenames and descriptions for BIOS images in a directory.
std::vector<std::pair<std::string, const BIOS::ImageInfo*>> FindBIOSImagesInDirectory(const char* directory);
/// Returns true if any BIOS images are found in the configured BIOS directory.
bool HasAnyBIOSImages();
} // namespace BIOS

View file

@ -10,7 +10,7 @@
#include "cpu_disasm.h"
#include "dma.h"
#include "gpu.h"
#include "host_interface.h"
#include "host.h"
#include "interrupt_controller.h"
#include "mdec.h"
#include "pad.h"
@ -130,7 +130,7 @@ bool Initialize()
{
if (!AllocateMemory(g_settings.enable_8mb_ram))
{
g_host_interface->ReportError("Failed to allocate memory");
Host::ReportErrorAsync("Error", "Failed to allocate memory");
return false;
}

View file

@ -3,6 +3,7 @@
#include "common/log.h"
#include "common/platform.h"
#include "dma.h"
#include "host.h"
#include "imgui.h"
#include "interrupt_controller.h"
#include "settings.h"
@ -2722,7 +2723,7 @@ void CDROM::DrawDebugWindow()
{
static const ImVec4 active_color{1.0f, 1.0f, 1.0f, 1.0f};
static const ImVec4 inactive_color{0.4f, 0.4f, 0.4f, 1.0f};
const float framebuffer_scale = ImGui::GetIO().DisplayFramebufferScale.x;
const float framebuffer_scale = Host::GetOSDScale();
ImGui::SetNextWindowSize(ImVec2(800.0f * framebuffer_scale, 550.0f * framebuffer_scale), ImGuiCond_FirstUseEver);
if (!ImGui::Begin("CDROM State", nullptr))

View file

@ -29,6 +29,7 @@ public:
bool HasMedia() const { return m_reader.HasMedia(); }
const std::string& GetMediaFileName() const { return m_reader.GetMediaFileName(); }
const CDImage* GetMedia() const { return m_reader.GetMedia(); }
DiscRegion GetDiscRegion() const { return m_disc_region; }
bool IsMediaPS1Disc() const;
bool DoesMediaRegionMatchConsole() const;

View file

@ -9,7 +9,7 @@
#include "controller.h"
#include "cpu_code_cache.h"
#include "cpu_core.h"
#include "host_interface.h"
#include "host.h"
#include "system.h"
#include <cctype>
#include <iomanip>
@ -686,17 +686,11 @@ bool CheatList::SaveToPCSXRFile(const char* filename)
bool CheatList::LoadFromPackage(const std::string& game_code)
{
std::unique_ptr<ByteStream> stream =
g_host_interface->OpenPackageFile("database/chtdb.txt", BYTESTREAM_OPEN_READ | BYTESTREAM_OPEN_STREAMED);
if (!stream)
const std::optional<std::string> db_string(Host::ReadResourceFileToString("chtdb.txt"));
if (!db_string.has_value())
return false;
std::string db_string = ByteStream::ReadStreamToString(stream.get());
stream.reset();
if (db_string.empty())
return false;
std::istringstream iss(db_string);
std::istringstream iss(db_string.value());
std::string line;
while (std::getline(iss, line))
{

File diff suppressed because it is too large Load diff

View file

@ -2,12 +2,27 @@
#include "analog_controller.h"
#include "analog_joystick.h"
#include "digital_controller.h"
#include "namco_guncon.h"
#include "fmt/format.h"
#include "guncon.h"
#include "negcon.h"
#include "playstation_mouse.h"
#include "util/state_wrapper.h"
Controller::Controller() = default;
static const Controller::ControllerInfo s_none_info = {ControllerType::None,
"None",
"Not Connected",
nullptr,
0,
nullptr,
0,
Controller::VibrationCapabilities::NoVibration};
static const Controller::ControllerInfo* s_controller_info[] = {
&s_none_info, &DigitalController::INFO, &AnalogController::INFO, &AnalogJoystick::INFO, &NeGcon::INFO,
&GunCon::INFO, &PlayStationMouse::INFO,
};
Controller::Controller(u32 index) : m_index(index) {}
Controller::~Controller() = default;
@ -26,19 +41,12 @@ bool Controller::Transfer(const u8 data_in, u8* data_out)
return false;
}
float Controller::GetAxisState(s32 axis_code) const
float Controller::GetBindState(u32 index) const
{
return 0.0f;
}
void Controller::SetAxisState(s32 axis_code, float value) {}
bool Controller::GetButtonState(s32 button_code) const
{
return false;
}
void Controller::SetButtonState(s32 button_code, bool pressed) {}
void Controller::SetBindState(u32 index, float value) {}
u32 Controller::GetButtonStateBits() const
{
@ -50,17 +58,7 @@ std::optional<u32> Controller::GetAnalogInputBytes() const
return std::nullopt;
}
u32 Controller::GetVibrationMotorCount() const
{
return 0;
}
float Controller::GetVibrationMotorStrength(u32 motor)
{
return 0.0f;
}
void Controller::LoadSettings(const char* section) {}
void Controller::LoadSettings(SettingsInterface& si, const char* section) {}
bool Controller::GetSoftwareCursor(const Common::RGBA8Image** image, float* image_scale, bool* relative_mode)
{
@ -72,7 +70,7 @@ std::unique_ptr<Controller> Controller::Create(ControllerType type, u32 index)
switch (type)
{
case ControllerType::DigitalController:
return DigitalController::Create();
return DigitalController::Create(index);
case ControllerType::AnalogController:
return AnalogController::Create(index);
@ -80,14 +78,14 @@ std::unique_ptr<Controller> Controller::Create(ControllerType type, u32 index)
case ControllerType::AnalogJoystick:
return AnalogJoystick::Create(index);
case ControllerType::NamcoGunCon:
return NamcoGunCon::Create();
case ControllerType::GunCon:
return GunCon::Create(index);
case ControllerType::PlayStationMouse:
return PlayStationMouse::Create();
return PlayStationMouse::Create(index);
case ControllerType::NeGcon:
return NeGcon::Create();
return NeGcon::Create(index);
case ControllerType::None:
default:
@ -95,179 +93,134 @@ std::unique_ptr<Controller> Controller::Create(ControllerType type, u32 index)
}
}
std::optional<s32> Controller::GetAxisCodeByName(std::string_view button_name) const
const char* Controller::GetDefaultPadType(u32 pad)
{
return (pad == 0) ? "DigitalController" : "None";
}
const Controller::ControllerInfo* Controller::GetControllerInfo(ControllerType type)
{
for (const ControllerInfo* info : s_controller_info)
{
if (type == info->type)
return info;
}
return nullptr;
}
const Controller::ControllerInfo* Controller::GetControllerInfo(const std::string_view& name)
{
for (const ControllerInfo* info : s_controller_info)
{
if (name == info->name)
return info;
}
return nullptr;
}
std::vector<std::pair<std::string, std::string>> Controller::GetControllerTypeNames()
{
std::vector<std::pair<std::string, std::string>> ret;
for (const ControllerInfo* info : s_controller_info)
ret.emplace_back(info->name, info->display_name);
return ret;
}
std::vector<std::string> Controller::GetControllerBinds(const std::string_view& type)
{
std::vector<std::string> ret;
const ControllerInfo* info = GetControllerInfo(type);
if (info)
{
for (u32 i = 0; i < info->num_bindings; i++)
{
const ControllerBindingInfo& bi = info->bindings[i];
if (bi.type == ControllerBindingType::Unknown || bi.type == ControllerBindingType::Motor)
continue;
ret.emplace_back(info->bindings[i].name);
}
}
return ret;
}
std::vector<std::string> Controller::GetControllerBinds(ControllerType type)
{
std::vector<std::string> ret;
const ControllerInfo* info = GetControllerInfo(type);
if (info)
{
for (u32 i = 0; i < info->num_bindings; i++)
{
const ControllerBindingInfo& bi = info->bindings[i];
if (bi.type == ControllerBindingType::Unknown || bi.type == ControllerBindingType::Motor)
continue;
ret.emplace_back(info->bindings[i].name);
}
}
return ret;
}
std::optional<u32> Controller::GetBindIndex(ControllerType type, const std::string_view& bind_name)
{
const ControllerInfo* info = GetControllerInfo(type);
if (!info)
return std::nullopt;
for (u32 i = 0; i < info->num_bindings; i++)
{
if (bind_name == info->bindings[i].name)
return i;
}
return std::nullopt;
}
std::optional<s32> Controller::GetButtonCodeByName(std::string_view button_name) const
Controller::VibrationCapabilities Controller::GetControllerVibrationCapabilities(const std::string_view& type)
{
return std::nullopt;
const ControllerInfo* info = GetControllerInfo(type);
return info ? info->vibration_caps : VibrationCapabilities::NoVibration;
}
Controller::AxisList Controller::GetAxisNames(ControllerType type)
std::tuple<u32, u32> Controller::ConvertPadToPortAndSlot(u32 index)
{
switch (type)
{
case ControllerType::DigitalController:
return DigitalController::StaticGetAxisNames();
case ControllerType::AnalogController:
return AnalogController::StaticGetAxisNames();
case ControllerType::AnalogJoystick:
return AnalogJoystick::StaticGetAxisNames();
case ControllerType::NamcoGunCon:
return NamcoGunCon::StaticGetAxisNames();
case ControllerType::PlayStationMouse:
return PlayStationMouse::StaticGetAxisNames();
case ControllerType::NeGcon:
return NeGcon::StaticGetAxisNames();
case ControllerType::None:
default:
return {};
}
if (index > 4) // [5,6,7]
return std::make_tuple(1, index - 4); // 2B,2C,2D
else if (index > 1) // [2,3,4]
return std::make_tuple(0, index - 1); // 1B,1C,1D
else // [0,1]
return std::make_tuple(index, 0); // 1A,2A
}
Controller::ButtonList Controller::GetButtonNames(ControllerType type)
u32 Controller::ConvertPortAndSlotToPad(u32 port, u32 slot)
{
switch (type)
{
case ControllerType::DigitalController:
return DigitalController::StaticGetButtonNames();
case ControllerType::AnalogController:
return AnalogController::StaticGetButtonNames();
case ControllerType::AnalogJoystick:
return AnalogJoystick::StaticGetButtonNames();
case ControllerType::NamcoGunCon:
return NamcoGunCon::StaticGetButtonNames();
case ControllerType::PlayStationMouse:
return PlayStationMouse::StaticGetButtonNames();
case ControllerType::NeGcon:
return NeGcon::StaticGetButtonNames();
case ControllerType::None:
default:
return {};
}
if (slot == 0)
return port;
else if (port == 0) // slot=[0,1]
return slot + 1; // 2,3,4
else
return slot + 4; // 5,6,7
}
u32 Controller::GetVibrationMotorCount(ControllerType type)
bool Controller::PadIsMultitapSlot(u32 index)
{
switch (type)
{
case ControllerType::DigitalController:
return DigitalController::StaticGetVibrationMotorCount();
case ControllerType::AnalogController:
return AnalogController::StaticGetVibrationMotorCount();
case ControllerType::AnalogJoystick:
return AnalogJoystick::StaticGetVibrationMotorCount();
case ControllerType::NamcoGunCon:
return NamcoGunCon::StaticGetVibrationMotorCount();
case ControllerType::PlayStationMouse:
return PlayStationMouse::StaticGetVibrationMotorCount();
case ControllerType::NeGcon:
return NeGcon::StaticGetVibrationMotorCount();
case ControllerType::None:
default:
return 0;
}
return (index >= 2);
}
std::optional<s32> Controller::GetAxisCodeByName(ControllerType type, std::string_view axis_name)
bool Controller::PortAndSlotIsMultitap(u32 port, u32 slot)
{
switch (type)
{
case ControllerType::DigitalController:
return DigitalController::StaticGetAxisCodeByName(axis_name);
case ControllerType::AnalogController:
return AnalogController::StaticGetAxisCodeByName(axis_name);
case ControllerType::AnalogJoystick:
return AnalogJoystick::StaticGetAxisCodeByName(axis_name);
case ControllerType::NamcoGunCon:
return NamcoGunCon::StaticGetAxisCodeByName(axis_name);
case ControllerType::PlayStationMouse:
return PlayStationMouse::StaticGetAxisCodeByName(axis_name);
case ControllerType::NeGcon:
return NeGcon::StaticGetAxisCodeByName(axis_name);
case ControllerType::None:
default:
return std::nullopt;
}
return (slot != 0);
}
std::optional<s32> Controller::GetButtonCodeByName(ControllerType type, std::string_view button_name)
std::string Controller::GetSettingsSection(u32 pad)
{
switch (type)
{
case ControllerType::DigitalController:
return DigitalController::StaticGetButtonCodeByName(button_name);
case ControllerType::AnalogController:
return AnalogController::StaticGetButtonCodeByName(button_name);
case ControllerType::AnalogJoystick:
return AnalogJoystick::StaticGetButtonCodeByName(button_name);
case ControllerType::NamcoGunCon:
return NamcoGunCon::StaticGetButtonCodeByName(button_name);
case ControllerType::PlayStationMouse:
return PlayStationMouse::StaticGetButtonCodeByName(button_name);
case ControllerType::NeGcon:
return NeGcon::StaticGetButtonCodeByName(button_name);
case ControllerType::None:
default:
return std::nullopt;
}
}
Controller::SettingList Controller::GetSettings(ControllerType type)
{
switch (type)
{
case ControllerType::DigitalController:
return DigitalController::StaticGetSettings();
case ControllerType::AnalogController:
return AnalogController::StaticGetSettings();
case ControllerType::AnalogJoystick:
return AnalogJoystick::StaticGetSettings();
case ControllerType::NamcoGunCon:
return NamcoGunCon::StaticGetSettings();
case ControllerType::NeGcon:
return NeGcon::StaticGetSettings();
case ControllerType::PlayStationMouse:
return PlayStationMouse::StaticGetSettings();
default:
return {};
}
return fmt::format("Pad{}", pad + 1u);
}

View file

@ -6,36 +6,67 @@
#include <optional>
#include <string>
#include <string_view>
#include <tuple>
#include <vector>
class SettingsInterface;
class StateWrapper;
class HostInterface;
enum class GenericInputBinding : u8;
class Controller
{
public:
enum class AxisType : u8
enum class ControllerBindingType : u8
{
Full,
Half
Unknown,
Button,
Axis,
HalfAxis,
Motor,
Macro
};
using ButtonList = std::vector<std::pair<std::string, s32>>;
using AxisList = std::vector<std::tuple<std::string, s32, AxisType>>;
using SettingList = std::vector<SettingInfo>;
enum class VibrationCapabilities : u8
{
NoVibration,
LargeSmallMotors,
SingleMotor,
Count
};
Controller();
struct ControllerBindingInfo
{
const char* name;
const char* display_name;
u32 bind_index;
ControllerBindingType type;
GenericInputBinding generic_mapping;
};
struct ControllerInfo
{
ControllerType type;
const char* name;
const char* display_name;
const ControllerBindingInfo* bindings;
u32 num_bindings;
const SettingInfo* settings;
u32 num_settings;
VibrationCapabilities vibration_caps;
};
/// Default stick deadzone/sensitivity.
static constexpr float DEFAULT_STICK_DEADZONE = 0.0f;
static constexpr float DEFAULT_STICK_SENSITIVITY = 1.33f;
Controller(u32 index);
virtual ~Controller();
/// Returns the type of controller.
virtual ControllerType GetType() const = 0;
/// Gets the integer code for an axis in the specified controller type.
virtual std::optional<s32> GetAxisCodeByName(std::string_view axis_name) const;
/// Gets the integer code for a button in the specified controller type.
virtual std::optional<s32> GetButtonCodeByName(std::string_view button_name) const;
virtual void Reset();
virtual bool DoState(StateWrapper& sw, bool apply_input_state);
@ -46,16 +77,10 @@ public:
virtual bool Transfer(const u8 data_in, u8* data_out);
/// Changes the specified axis state. Values are normalized from -1..1.
virtual float GetAxisState(s32 axis_code) const;
virtual float GetBindState(u32 index) const;
/// Changes the specified axis state. Values are normalized from -1..1.
virtual void SetAxisState(s32 axis_code, float value);
/// Returns the specified button state.
virtual bool GetButtonState(s32 button_code) const;
/// Changes the specified button state.
virtual void SetButtonState(s32 button_code, bool pressed);
/// Changes the specified bind state. Values are normalized from -1..1.
virtual void SetBindState(u32 index, float value);
/// Returns a bitmask of the current button states, 1 = on.
virtual u32 GetButtonStateBits() const;
@ -63,14 +88,8 @@ public:
/// Returns analog input bytes packed as a u32. Values are specific to controller type.
virtual std::optional<u32> GetAnalogInputBytes() const;
/// Returns the number of vibration motors.
virtual u32 GetVibrationMotorCount() const;
/// Queries the state of the specified vibration motor. Values are normalized from 0..1.
virtual float GetVibrationMotorStrength(u32 motor);
/// Loads/refreshes any per-controller settings.
virtual void LoadSettings(const char* section);
virtual void LoadSettings(SettingsInterface& si, const char* section);
/// Returns the software cursor to use for this controller, if any.
virtual bool GetSoftwareCursor(const Common::RGBA8Image** image, float* image_scale, bool* relative_mode);
@ -78,21 +97,45 @@ public:
/// Creates a new controller of the specified type.
static std::unique_ptr<Controller> Create(ControllerType type, u32 index);
/// Returns the default type for the specified port.
static const char* GetDefaultPadType(u32 pad);
/// Returns a list of controller type names. Pair of [name, display name].
static std::vector<std::pair<std::string, std::string>> GetControllerTypeNames();
/// Returns the list of binds for the specified controller type.
static std::vector<std::string> GetControllerBinds(const std::string_view& type);
static std::vector<std::string> GetControllerBinds(ControllerType type);
/// Gets the integer code for an axis in the specified controller type.
static std::optional<s32> GetAxisCodeByName(ControllerType type, std::string_view axis_name);
static std::optional<u32> GetBindIndex(ControllerType type, const std::string_view& bind_name);
/// Gets the integer code for a button in the specified controller type.
static std::optional<s32> GetButtonCodeByName(ControllerType type, std::string_view button_name);
/// Returns the vibration configuration for the specified controller type.
static VibrationCapabilities GetControllerVibrationCapabilities(const std::string_view& type);
/// Returns a list of axises for the specified controller type.
static AxisList GetAxisNames(ControllerType type);
/// Returns general information for the specified controller type.
static const ControllerInfo* GetControllerInfo(ControllerType type);
static const ControllerInfo* GetControllerInfo(const std::string_view& name);
/// Returns a list of buttons for the specified controller type.
static ButtonList GetButtonNames(ControllerType type);
/// Converts a global pad index to a multitap port and slot.
static std::tuple<u32, u32> ConvertPadToPortAndSlot(u32 index);
/// Returns the number of vibration motors.
static u32 GetVibrationMotorCount(ControllerType type);
/// Converts a multitap port and slot to a global pad index.
static u32 ConvertPortAndSlotToPad(u32 port, u32 slot);
/// Returns settings for the controller.
static SettingList GetSettings(ControllerType type);
/// Returns true if the given pad index is a multitap slot.
static bool PadIsMultitapSlot(u32 index);
static bool PortAndSlotIsMultitap(u32 port, u32 slot);
/// Returns the configuration section for the specified gamepad.
static std::string GetSettingsSection(u32 pad);
/// Applies an analog deadzone/sensitivity.
static float ApplyAnalogDeadzoneSensitivity(float deadzone, float sensitivity, float value)
{
return (value < deadzone) ? 0.0f : ((value - deadzone) / (1.0f - deadzone) * sensitivity);
}
protected:
u32 m_index;
};

View file

@ -9,7 +9,7 @@
<PreprocessorDefinitions Condition="('$(Platform)'=='x64' Or '$(Platform)'=='ARM' Or '$(Platform)'=='ARM64')">WITH_RECOMPILER=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="('$(Platform)'=='x64' Or '$(Platform)'=='ARM64') And ('$(BuildingForUWP)'!='true')">WITH_MMAP_FASTMEM=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(SolutionDir)dep\glad\include;$(SolutionDir)dep\stb\include;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\xxhash\include;$(SolutionDir)dep\zlib\include;$(SolutionDir)dep\rcheevos\include;$(SolutionDir)dep\rapidjson\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(SolutionDir)dep\tinyxml2\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\stb\include;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\xxhash\include;$(SolutionDir)dep\zlib\include;$(SolutionDir)dep\rcheevos\include;$(SolutionDir)dep\rapidjson\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories Condition="('$(BuildingForUWP)'!='true' And '$(Platform)'!='ARM64')">$(SolutionDir)dep\rainterface;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories Condition="'$(Platform)'=='x64'">$(SolutionDir)dep\xbyak\xbyak;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
@ -19,7 +19,7 @@
<ItemDefinitionGroup>
<Lib>
<AdditionalDependencies>$(RootBuildDir)rcheevos\rcheevos.lib;$(RootBuildDir)imgui\imgui.lib;$(RootBuildDir)stb\stb.lib;$(RootBuildDir)xxhash\xxhash.lib;$(RootBuildDir)zlib\zlib.lib;$(RootBuildDir)util\util.lib;$(RootBuildDir)common\common.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>$(RootBuildDir)tinyxml2\tinyxml2.lib;$(RootBuildDir)rcheevos\rcheevos.lib;$(RootBuildDir)imgui\imgui.lib;$(RootBuildDir)stb\stb.lib;$(RootBuildDir)xxhash\xxhash.lib;$(RootBuildDir)zlib\zlib.lib;$(RootBuildDir)util\util.lib;$(RootBuildDir)common\common.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies Condition="('$(BuildingForUWP)'!='true' And '$(Platform)'!='ARM64')">$(RootBuildDir)rainterface\rainterface.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies Condition="'$(Platform)'=='ARM64'">$(RootBuildDir)vixl\vixl.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Lib>

View file

@ -9,7 +9,6 @@
<ClCompile Include="cdrom.cpp" />
<ClCompile Include="cdrom_async_reader.cpp" />
<ClCompile Include="cheats.cpp" />
<ClCompile Include="cheevos.cpp" />
<ClCompile Include="cpu_core.cpp" />
<ClCompile Include="cpu_disasm.cpp" />
<ClCompile Include="cpu_code_cache.cpp" />
@ -33,6 +32,7 @@
</ClCompile>
<ClCompile Include="cpu_types.cpp" />
<ClCompile Include="digital_controller.cpp" />
<ClCompile Include="game_database.cpp" />
<ClCompile Include="gpu_backend.cpp" />
<ClCompile Include="gpu_commands.cpp" />
<ClCompile Include="gpu_hw_d3d11.cpp" />
@ -47,18 +47,16 @@
<ClCompile Include="gpu.cpp" />
<ClCompile Include="gpu_hw.cpp" />
<ClCompile Include="gpu_hw_opengl.cpp" />
<ClCompile Include="host.cpp" />
<ClCompile Include="host_display.cpp" />
<ClCompile Include="host_interface.cpp" />
<ClCompile Include="host_interface_progress_callback.cpp" />
<ClCompile Include="imgui_fullscreen.cpp" />
<ClCompile Include="imgui_styles.cpp" />
<ClCompile Include="interrupt_controller.cpp" />
<ClCompile Include="libcrypt_game_codes.cpp" />
<ClCompile Include="mdec.cpp" />
<ClCompile Include="memory_card.cpp" />
<ClCompile Include="memory_card_image.cpp" />
<ClCompile Include="multitap.cpp" />
<ClCompile Include="namco_guncon.cpp" />
<ClCompile Include="guncon.cpp" />
<ClCompile Include="negcon.cpp" />
<ClCompile Include="pad.cpp" />
<ClCompile Include="controller.cpp" />
@ -83,7 +81,7 @@
<ClInclude Include="cdrom.h" />
<ClInclude Include="cdrom_async_reader.h" />
<ClInclude Include="cheats.h" />
<ClInclude Include="cheevos.h" />
<ClInclude Include="achievements.h" />
<ClInclude Include="cpu_core.h" />
<ClInclude Include="cpu_core_private.h" />
<ClInclude Include="cpu_disasm.h" />
@ -101,6 +99,7 @@
<ExcludedFromBuild Condition="'$(Platform)'=='Win32'">true</ExcludedFromBuild>
</ClInclude>
<ClInclude Include="digital_controller.h" />
<ClInclude Include="game_database.h" />
<ClInclude Include="gpu_backend.h" />
<ClInclude Include="gpu_hw_d3d11.h" />
<ClInclude Include="gpu_hw_d3d12.h" />
@ -119,18 +118,15 @@
<ClInclude Include="gte_types.h" />
<ClInclude Include="host.h" />
<ClInclude Include="host_display.h" />
<ClInclude Include="host_interface.h" />
<ClInclude Include="host_interface_progress_callback.h" />
<ClInclude Include="host_settings.h" />
<ClInclude Include="imgui_fullscreen.h" />
<ClInclude Include="imgui_styles.h" />
<ClInclude Include="interrupt_controller.h" />
<ClInclude Include="libcrypt_game_codes.h" />
<ClInclude Include="mdec.h" />
<ClInclude Include="memory_card.h" />
<ClInclude Include="memory_card_image.h" />
<ClInclude Include="multitap.h" />
<ClInclude Include="namco_guncon.h" />
<ClInclude Include="guncon.h" />
<ClInclude Include="negcon.h" />
<ClInclude Include="pad.h" />
<ClInclude Include="controller.h" />

View file

@ -10,7 +10,6 @@
<ClCompile Include="gpu.cpp" />
<ClCompile Include="gpu_hw_opengl.cpp" />
<ClCompile Include="gpu_hw.cpp" />
<ClCompile Include="host_interface.cpp" />
<ClCompile Include="interrupt_controller.cpp" />
<ClCompile Include="cdrom.cpp" />
<ClCompile Include="gte.cpp" />
@ -40,7 +39,7 @@
<ClCompile Include="timing_event.cpp" />
<ClCompile Include="cdrom_async_reader.cpp" />
<ClCompile Include="psf_loader.cpp" />
<ClCompile Include="namco_guncon.cpp" />
<ClCompile Include="guncon.cpp" />
<ClCompile Include="playstation_mouse.cpp" />
<ClCompile Include="negcon.cpp" />
<ClCompile Include="gpu_hw_vulkan.cpp" />
@ -58,9 +57,8 @@
<ClCompile Include="texture_replacements.cpp" />
<ClCompile Include="multitap.cpp" />
<ClCompile Include="gpu_hw_d3d12.cpp" />
<ClCompile Include="imgui_fullscreen.cpp" />
<ClCompile Include="imgui_styles.cpp" />
<ClCompile Include="cheevos.cpp" />
<ClCompile Include="host.cpp" />
<ClCompile Include="game_database.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="types.h" />
@ -74,7 +72,6 @@
<ClInclude Include="gpu.h" />
<ClInclude Include="gpu_hw_opengl.h" />
<ClInclude Include="gpu_hw.h" />
<ClInclude Include="host_interface.h" />
<ClInclude Include="interrupt_controller.h" />
<ClInclude Include="cdrom.h" />
<ClInclude Include="gte.h" />
@ -101,7 +98,7 @@
<ClInclude Include="timing_event.h" />
<ClInclude Include="cdrom_async_reader.h" />
<ClInclude Include="psf_loader.h" />
<ClInclude Include="namco_guncon.h" />
<ClInclude Include="guncon.h" />
<ClInclude Include="playstation_mouse.h" />
<ClInclude Include="negcon.h" />
<ClInclude Include="gpu_hw_vulkan.h" />
@ -123,10 +120,9 @@
<ClInclude Include="multitap.h" />
<ClInclude Include="gpu_hw_d3d12.h" />
<ClInclude Include="gdb_protocol.h" />
<ClInclude Include="imgui_fullscreen.h" />
<ClInclude Include="imgui_styles.h" />
<ClInclude Include="cheevos.h" />
<ClInclude Include="host.h" />
<ClInclude Include="host_settings.h" />
<ClInclude Include="achievements.h" />
<ClInclude Include="game_database.h" />
</ItemGroup>
</Project>

View file

@ -7,7 +7,7 @@
#include "cpu_disasm.h"
#include "cpu_recompiler_thunks.h"
#include "gte.h"
#include "host_interface.h"
#include "host.h"
#include "pgxp.h"
#include "settings.h"
#include "system.h"
@ -1691,8 +1691,8 @@ bool AddBreakpoint(VirtualMemoryAddress address, bool auto_clear, bool enabled)
if (!auto_clear)
{
g_host_interface->ReportFormattedDebuggerMessage(
g_host_interface->TranslateString("DebuggerMessage", "Added breakpoint at 0x%08X."), address);
Host::ReportFormattedDebuggerMessage(Host::TranslateString("DebuggerMessage", "Added breakpoint at 0x%08X."),
address);
}
return true;
@ -1718,8 +1718,8 @@ bool RemoveBreakpoint(VirtualMemoryAddress address)
if (it == s_breakpoints.end())
return false;
g_host_interface->ReportFormattedDebuggerMessage(
g_host_interface->TranslateString("DebuggerMessage", "Removed breakpoint at 0x%08X."), address);
Host::ReportFormattedDebuggerMessage(Host::TranslateString("DebuggerMessage", "Removed breakpoint at 0x%08X."),
address);
s_breakpoints.erase(it);
UpdateDebugDispatcherFlag();
@ -1750,8 +1750,8 @@ bool AddStepOverBreakpoint()
if (!IsCallInstruction(inst))
{
g_host_interface->ReportFormattedDebuggerMessage(
g_host_interface->TranslateString("DebuggerMessage", "0x%08X is not a call instruction."), g_state.regs.pc);
Host::ReportFormattedDebuggerMessage(Host::TranslateString("DebuggerMessage", "0x%08X is not a call instruction."),
g_state.regs.pc);
return false;
}
@ -1760,16 +1760,15 @@ bool AddStepOverBreakpoint()
if (IsBranchInstruction(inst))
{
g_host_interface->ReportFormattedDebuggerMessage(
g_host_interface->TranslateString("DebuggerMessage", "Can't step over double branch at 0x%08X"), g_state.regs.pc);
Host::ReportFormattedDebuggerMessage(
Host::TranslateString("DebuggerMessage", "Can't step over double branch at 0x%08X"), g_state.regs.pc);
return false;
}
// skip the delay slot
bp_pc += sizeof(Instruction);
g_host_interface->ReportFormattedDebuggerMessage(
g_host_interface->TranslateString("DebuggerMessage", "Stepping over to 0x%08X."), bp_pc);
Host::ReportFormattedDebuggerMessage(Host::TranslateString("DebuggerMessage", "Stepping over to 0x%08X."), bp_pc);
return AddBreakpoint(bp_pc, true);
}
@ -1785,25 +1784,22 @@ bool AddStepOutBreakpoint(u32 max_instructions_to_search)
Instruction inst;
if (!SafeReadInstruction(ret_pc, &inst.bits))
{
g_host_interface->ReportFormattedDebuggerMessage(
g_host_interface->TranslateString("DebuggerMessage",
"Instruction read failed at %08X while searching for function end."),
Host::ReportFormattedDebuggerMessage(
Host::TranslateString("DebuggerMessage", "Instruction read failed at %08X while searching for function end."),
ret_pc);
return false;
}
if (IsReturnInstruction(inst))
{
g_host_interface->ReportFormattedDebuggerMessage(
g_host_interface->TranslateString("DebuggerMessage", "Stepping out to 0x%08X."), ret_pc);
Host::ReportFormattedDebuggerMessage(Host::TranslateString("DebuggerMessage", "Stepping out to 0x%08X."), ret_pc);
return AddBreakpoint(ret_pc, true);
}
}
g_host_interface->ReportFormattedDebuggerMessage(
g_host_interface->TranslateString("DebuggerMessage",
"No return instruction found after %u instructions for step-out at %08X."),
Host::ReportFormattedDebuggerMessage(
Host::TranslateString("DebuggerMessage", "No return instruction found after %u instructions for step-out at %08X."),
max_instructions_to_search, g_state.regs.pc);
return false;
@ -1857,18 +1853,18 @@ ALWAYS_INLINE_RELEASE static bool BreakpointCheck()
}
else
{
g_host_interface->PauseSystem(true);
System::PauseSystem(true);
if (bp.auto_clear)
{
g_host_interface->ReportFormattedDebuggerMessage("Stopped execution at 0x%08X.", pc);
Host::ReportFormattedDebuggerMessage("Stopped execution at 0x%08X.", pc);
s_breakpoints.erase(s_breakpoints.begin() + i);
count--;
UpdateDebugDispatcherFlag();
}
else
{
g_host_interface->ReportFormattedDebuggerMessage("Hit breakpoint %u at 0x%08X.", bp.number, pc);
Host::ReportFormattedDebuggerMessage("Hit breakpoint %u at 0x%08X.", bp.number, pc);
i++;
}
}
@ -1979,7 +1975,7 @@ void SingleStep()
{
s_single_step = true;
ExecuteDebug();
g_host_interface->ReportFormattedDebuggerMessage("Stepped to 0x%08X.", g_state.regs.pc);
Host::ReportFormattedDebuggerMessage("Stepped to 0x%08X.", g_state.regs.pc);
}
namespace CodeCache {

View file

@ -1,10 +1,10 @@
#include "digital_controller.h"
#include "common/assert.h"
#include "host_interface.h"
#include "host.h"
#include "system.h"
#include "util/state_wrapper.h"
DigitalController::DigitalController() = default;
DigitalController::DigitalController(u32 index) : Controller(index) {}
DigitalController::~DigitalController() = default;
@ -13,16 +13,6 @@ ControllerType DigitalController::GetType() const
return ControllerType::DigitalController;
}
std::optional<s32> DigitalController::GetAxisCodeByName(std::string_view axis_name) const
{
return StaticGetAxisCodeByName(axis_name);
}
std::optional<s32> DigitalController::GetButtonCodeByName(std::string_view button_name) const
{
return StaticGetButtonCodeByName(button_name);
}
void DigitalController::Reset()
{
m_transfer_state = TransferState::Idle;
@ -42,18 +32,25 @@ bool DigitalController::DoState(StateWrapper& sw, bool apply_input_state)
return true;
}
bool DigitalController::GetButtonState(s32 button_code) const
float DigitalController::GetBindState(u32 index) const
{
if (button_code < 0 || button_code >= static_cast<s32>(Button::Count))
return false;
const u16 bit = u16(1) << static_cast<u8>(button_code);
return ((m_button_state & bit) == 0);
if (index < static_cast<u32>(Button::Count))
{
return static_cast<float>(((m_button_state >> index) & 1u) ^ 1u);
}
else
{
return 0.0f;
}
}
void DigitalController::SetButtonState(Button button, bool pressed)
void DigitalController::SetBindState(u32 index, float value)
{
const u16 bit = u16(1) << static_cast<u8>(button);
if (index >= static_cast<u32>(Button::Count))
return;
const bool pressed = (value >= 0.5f);
const u16 bit = u16(1) << static_cast<u8>(index);
if (pressed)
{
if (m_button_state & bit)
@ -70,14 +67,6 @@ void DigitalController::SetButtonState(Button button, bool pressed)
}
}
void DigitalController::SetButtonState(s32 button_code, bool pressed)
{
if (button_code < 0 || button_code >= static_cast<s32>(Button::Count))
return;
SetButtonState(static_cast<Button>(button_code), pressed);
}
u32 DigitalController::GetButtonStateBits() const
{
return m_button_state ^ 0xFFFF;
@ -146,87 +135,53 @@ bool DigitalController::Transfer(const u8 data_in, u8* data_out)
}
}
std::unique_ptr<DigitalController> DigitalController::Create()
std::unique_ptr<DigitalController> DigitalController::Create(u32 index)
{
return std::make_unique<DigitalController>();
return std::make_unique<DigitalController>(index);
}
std::optional<s32> DigitalController::StaticGetAxisCodeByName(std::string_view button_name)
{
return std::nullopt;
}
std::optional<s32> DigitalController::StaticGetButtonCodeByName(std::string_view button_name)
{
#define BUTTON(name) \
if (button_name == #name) \
static const Controller::ControllerBindingInfo s_binding_info[] = {
#define BUTTON(name, display_name, button, genb) \
{ \
return static_cast<s32>(ZeroExtend32(static_cast<u8>(Button::name))); \
name, display_name, static_cast<u32>(button), Controller::ControllerBindingType::Button, genb \
}
BUTTON(Select);
BUTTON(L3);
BUTTON(R3);
BUTTON(Start);
BUTTON(Up);
BUTTON(Right);
BUTTON(Down);
BUTTON(Left);
BUTTON(L2);
BUTTON(R2);
BUTTON(L1);
BUTTON(R1);
BUTTON(Triangle);
BUTTON(Circle);
BUTTON(Cross);
BUTTON(Square);
return std::nullopt;
BUTTON("Up", "D-Pad Up", DigitalController::Button::Up, GenericInputBinding::DPadUp),
BUTTON("Right", "D-Pad Right", DigitalController::Button::Right, GenericInputBinding::DPadRight),
BUTTON("Down", "D-Pad Down", DigitalController::Button::Down, GenericInputBinding::DPadDown),
BUTTON("Left", "D-Pad Left", DigitalController::Button::Left, GenericInputBinding::DPadLeft),
BUTTON("Triangle", "Triangle", DigitalController::Button::Triangle, GenericInputBinding::Triangle),
BUTTON("Circle", "Circle", DigitalController::Button::Circle, GenericInputBinding::Circle),
BUTTON("Cross", "Cross", DigitalController::Button::Cross, GenericInputBinding::Cross),
BUTTON("Square", "Square", DigitalController::Button::Square, GenericInputBinding::Square),
BUTTON("Select", "Select", DigitalController::Button::Select, GenericInputBinding::Select),
BUTTON("Start", "Start", DigitalController::Button::Start, GenericInputBinding::Start),
BUTTON("L1", "L1", DigitalController::Button::L1, GenericInputBinding::L1),
BUTTON("R1", "R1", DigitalController::Button::R1, GenericInputBinding::R1),
BUTTON("L2", "L2", DigitalController::Button::L2, GenericInputBinding::L2),
BUTTON("R2", "R2", DigitalController::Button::R2, GenericInputBinding::R2),
#undef BUTTON
}
};
Controller::AxisList DigitalController::StaticGetAxisNames()
{
return {};
}
static const SettingInfo s_settings[] = {
{SettingInfo::Type::Boolean, "ForcePopnControllerMode",
TRANSLATABLE("DigitalController", "Force Pop'n Controller Mode"),
TRANSLATABLE("DigitalController", "Forces the Digital Controller to act as a Pop'n Controller."), "false"}};
Controller::ButtonList DigitalController::StaticGetButtonNames()
{
return {{TRANSLATABLE("DigitalController", "Up"), static_cast<s32>(Button::Up)},
{TRANSLATABLE("DigitalController", "Down"), static_cast<s32>(Button::Down)},
{TRANSLATABLE("DigitalController", "Left"), static_cast<s32>(Button::Left)},
{TRANSLATABLE("DigitalController", "Right"), static_cast<s32>(Button::Right)},
{TRANSLATABLE("DigitalController", "Select"), static_cast<s32>(Button::Select)},
{TRANSLATABLE("DigitalController", "Start"), static_cast<s32>(Button::Start)},
{TRANSLATABLE("DigitalController", "Triangle"), static_cast<s32>(Button::Triangle)},
{TRANSLATABLE("DigitalController", "Cross"), static_cast<s32>(Button::Cross)},
{TRANSLATABLE("DigitalController", "Circle"), static_cast<s32>(Button::Circle)},
{TRANSLATABLE("DigitalController", "Square"), static_cast<s32>(Button::Square)},
{TRANSLATABLE("DigitalController", "L1"), static_cast<s32>(Button::L1)},
{TRANSLATABLE("DigitalController", "L2"), static_cast<s32>(Button::L2)},
{TRANSLATABLE("DigitalController", "R1"), static_cast<s32>(Button::R1)},
{TRANSLATABLE("DigitalController", "R2"), static_cast<s32>(Button::R2)}};
}
const Controller::ControllerInfo DigitalController::INFO = {ControllerType::DigitalController,
"DigitalController",
TRANSLATABLE("ControllerType", "Digital Controller"),
s_binding_info,
countof(s_binding_info),
s_settings,
countof(s_settings),
Controller::VibrationCapabilities::NoVibration};
u32 DigitalController::StaticGetVibrationMotorCount()
void DigitalController::LoadSettings(SettingsInterface& si, const char* section)
{
return 0;
}
Controller::SettingList DigitalController::StaticGetSettings()
{
static constexpr std::array<SettingInfo, 1> settings = {
{{SettingInfo::Type::Boolean, "ForcePopnControllerMode",
TRANSLATABLE("DigitalController", "Force Pop'n Controller Mode"),
TRANSLATABLE("DigitalController", "Forces the Digital Controller to act as a Pop'n Controller."), "false"}}};
return SettingList(settings.begin(), settings.end());
}
void DigitalController::LoadSettings(const char* section)
{
Controller::LoadSettings(section);
m_popn_controller_mode = g_host_interface->GetBoolSettingValue(section, "ForcePopnControllerMode", false);
Controller::LoadSettings(si, section);
m_popn_controller_mode = si.GetBoolValue(section, "ForcePopnControllerMode", false);
}
u8 DigitalController::GetButtonsLSBMask() const

View file

@ -28,34 +28,26 @@ public:
Count
};
DigitalController();
static const Controller::ControllerInfo INFO;
DigitalController(u32 index);
~DigitalController() override;
static std::unique_ptr<DigitalController> Create();
static std::optional<s32> StaticGetAxisCodeByName(std::string_view button_name);
static std::optional<s32> StaticGetButtonCodeByName(std::string_view button_name);
static AxisList StaticGetAxisNames();
static ButtonList StaticGetButtonNames();
static u32 StaticGetVibrationMotorCount();
static SettingList StaticGetSettings();
static std::unique_ptr<DigitalController> Create(u32 index);
ControllerType GetType() const override;
std::optional<s32> GetAxisCodeByName(std::string_view axis_name) const override;
std::optional<s32> GetButtonCodeByName(std::string_view button_name) const override;
void Reset() override;
bool DoState(StateWrapper& sw, bool apply_input_state) override;
bool GetButtonState(s32 button_code) const override;
void SetButtonState(s32 button_code, bool pressed) override;
float GetBindState(u32 index) const override;
void SetBindState(u32 index, float value) override;
u32 GetButtonStateBits() const override;
void ResetTransferState() override;
bool Transfer(const u8 data_in, u8* data_out) override;
void SetButtonState(Button button, bool pressed);
void LoadSettings(const char* section) override;
void LoadSettings(SettingsInterface& si, const char* section) override;
private:
enum class TransferState : u8

View file

@ -6,6 +6,7 @@
#include "cpu_code_cache.h"
#include "cpu_core.h"
#include "gpu.h"
#include "host.h"
#include "imgui.h"
#include "interrupt_controller.h"
#include "mdec.h"
@ -626,7 +627,7 @@ void DMA::DrawDebugStateWindow()
{"MDECin", "MDECout", "GPU", "CDROM", "SPU", "PIO", "OTC"}};
static constexpr std::array<const char*, 4> sync_mode_names = {{"Manual", "Request", "LinkedList", "Reserved"}};
const float framebuffer_scale = ImGui::GetIO().DisplayFramebufferScale.x;
const float framebuffer_scale = Host::GetOSDScale();
ImGui::SetNextWindowSize(ImVec2(850.0f * framebuffer_scale, 250.0f * framebuffer_scale), ImGuiCond_FirstUseEver);
if (!ImGui::Begin("DMA State", nullptr))

1137
src/core/game_database.cpp Normal file

File diff suppressed because it is too large Load diff

122
src/core/game_database.h Normal file
View file

@ -0,0 +1,122 @@
#pragma once
#include "core/types.h"
#include "util/cd_image_hasher.h"
#include <bitset>
#include <map>
#include <string>
#include <string_view>
#include <vector>
class CDImage;
struct Settings;
namespace GameDatabase {
enum class CompatibilityRating : u32
{
Unknown = 0,
DoesntBoot = 1,
CrashesInIntro = 2,
CrashesInGame = 3,
GraphicalAudioIssues = 4,
NoIssues = 5,
Count,
};
enum class Trait : u32
{
ForceInterpreter,
ForceSoftwareRenderer,
ForceSoftwareRendererForReadbacks,
ForceInterlacing,
DisableTrueColor,
DisableUpscaling,
DisableScaledDithering,
DisableForceNTSCTimings,
DisableWidescreen,
DisablePGXP,
DisablePGXPCulling,
DisablePGXPTextureCorrection,
DisablePGXPDepthBuffer,
ForcePGXPVertexCache,
ForcePGXPCPUMode,
ForceRecompilerMemoryExceptions,
ForceRecompilerICache,
ForceRecompilerLUTFastmem,
Count
};
struct Entry
{
// TODO: Make string_view.
std::string serial;
std::string title;
std::string genre;
std::string developer;
std::string publisher;
u64 release_date;
u8 min_players;
u8 max_players;
u8 min_blocks;
u8 max_blocks;
u32 supported_controllers;
CompatibilityRating compatibility;
std::bitset<static_cast<int>(Trait::Count)> traits{};
std::optional<s16> display_active_start_offset;
std::optional<s16> display_active_end_offset;
std::optional<s8> display_line_start_offset;
std::optional<s8> display_line_end_offset;
std::optional<u32> dma_max_slice_ticks;
std::optional<u32> dma_halt_ticks;
std::optional<u32> gpu_fifo_size;
std::optional<u32> gpu_max_run_ahead;
std::optional<float> gpu_pgxp_tolerance;
std::optional<float> gpu_pgxp_depth_threshold;
ALWAYS_INLINE bool HasTrait(Trait trait) const { return traits[static_cast<int>(trait)]; }
void ApplySettings(Settings& settings, bool display_osd_messages) const;
};
void EnsureLoaded();
void Unload();
const Entry* GetEntryForDisc(CDImage* image);
const Entry* GetEntryForSerial(const std::string_view& serial);
const Entry* GetEntryForCode(const std::string_view& code);
std::string GetSerialForDisc(CDImage* image);
std::string GetSerialForPath(const char* path);
const char* GetTraitName(Trait trait);
const char* GetTraitDisplayName(Trait trait);
const char* GetCompatibilityRatingName(CompatibilityRating rating);
const char* GetCompatibilityRatingDisplayName(CompatibilityRating rating);
/// Map of track hashes for image verification
struct TrackData
{
TrackData(std::vector<std::string> codes, std::string revisionString, uint32_t revision)
: codes(std::move(codes)), revisionString(revisionString), revision(revision)
{
}
friend bool operator==(const TrackData& left, const TrackData& right)
{
// 'revisionString' is deliberately ignored in comparisons as it's redundant with comparing 'revision'! Do not
// change!
return left.codes == right.codes && left.revision == right.revision;
}
std::vector<std::string> codes;
std::string revisionString;
uint32_t revision;
};
using TrackHashesMap = std::multimap<CDImageHasher::Hash, TrackData>;
const TrackHashesMap& GetTrackHashesMap();
void EnsureTrackHashesMapLoaded();
} // namespace GameDatabase

View file

@ -4,7 +4,7 @@
#include "common/log.h"
#include "common/string_util.h"
#include "cpu_core.h"
#include "frontend-common/common_host_interface.h"
#include "frontend-common/common_host.h"
#include "system.h"
#include <functional>
#include <iomanip>

View file

@ -4,8 +4,8 @@
#include "common/log.h"
#include "common/string_util.h"
#include "dma.h"
#include "host.h"
#include "host_display.h"
#include "host_interface.h"
#include "imgui.h"
#include "interrupt_controller.h"
#include "settings.h"
@ -24,9 +24,8 @@ GPU::GPU() = default;
GPU::~GPU() = default;
bool GPU::Initialize(HostDisplay* host_display)
bool GPU::Initialize()
{
m_host_display = host_display;
m_force_progressive_scan = g_settings.gpu_disable_interlacing;
m_force_ntsc_timings = g_settings.gpu_force_ntsc_timings;
m_crtc_tick_event = TimingEvents::CreateTimingEvent(
@ -41,6 +40,16 @@ bool GPU::Initialize(HostDisplay* host_display)
m_max_run_ahead = g_settings.gpu_max_run_ahead;
m_console_is_pal = System::IsPALRegion();
UpdateCRTCConfig();
g_host_display->SetDisplayLinearFiltering(g_settings.display_linear_filtering);
g_host_display->SetDisplayIntegerScaling(g_settings.display_integer_scaling);
g_host_display->SetDisplayStretch(g_settings.display_stretch);
if (g_settings.display_post_processing &&
!g_host_display->SetPostProcessingChain(g_settings.display_post_process_chain))
{
Host::AddOSDMessage(Host::TranslateStdString("OSDMessage", "Failed to load post processing shader chain."), 20.0f);
}
return true;
}
@ -59,6 +68,10 @@ void GPU::UpdateSettings()
// Crop mode calls this, so recalculate the display area
UpdateCRTCDisplayParameters();
g_host_display->SetDisplayLinearFiltering(g_settings.display_linear_filtering);
g_host_display->SetDisplayIntegerScaling(g_settings.display_integer_scaling);
g_host_display->SetDisplayStretch(g_settings.display_stretch);
}
bool GPU::IsHardwareRenderer()
@ -962,9 +975,9 @@ void GPU::UpdateCommandTickEvent()
bool GPU::ConvertScreenCoordinatesToBeamTicksAndLines(s32 window_x, s32 window_y, float x_scale, u32* out_tick,
u32* out_line) const
{
auto [display_x, display_y] = m_host_display->ConvertWindowCoordinatesToDisplayCoordinates(
window_x, window_y, m_host_display->GetWindowWidth(), m_host_display->GetWindowHeight(),
m_host_display->GetDisplayTopMargin());
auto [display_x, display_y] = g_host_display->ConvertWindowCoordinatesToDisplayCoordinates(
window_x, window_y, g_host_display->GetWindowWidth(), g_host_display->GetWindowHeight(),
g_host_display->GetDisplayTopMargin());
if (x_scale != 1.0f)
{
@ -1551,7 +1564,7 @@ bool GPU::DumpVRAMToFile(const char* filename, u32 width, u32 height, u32 stride
void GPU::DrawDebugStateWindow()
{
const float framebuffer_scale = ImGui::GetIO().DisplayFramebufferScale.x;
const float framebuffer_scale = Host::GetOSDScale();
ImGui::SetNextWindowSize(ImVec2(450.0f * framebuffer_scale, 550.0f * framebuffer_scale), ImGuiCond_FirstUseEver);
if (!ImGui::Begin("GPU", nullptr))

View file

@ -75,7 +75,7 @@ public:
virtual GPURenderer GetRendererType() const = 0;
virtual bool Initialize(HostDisplay* host_display);
virtual bool Initialize();
virtual void Reset(bool clear_vram);
virtual bool DoState(StateWrapper& sw, HostDisplayTexture** save_to_texture, bool update_display);
@ -319,8 +319,6 @@ protected:
AddCommandTicks(std::max(width, height));
}
HostDisplay* m_host_display = nullptr;
std::unique_ptr<TimingEvent> m_crtc_tick_event;
std::unique_ptr<TimingEvent> m_command_tick_event;

View file

@ -173,7 +173,7 @@ void GPUBackend::StartGPUThread()
{
m_gpu_loop_done.store(false);
m_use_gpu_thread = true;
m_gpu_thread = std::thread(&GPUBackend::RunGPULoop, this);
m_gpu_thread.Start([this]() { RunGPULoop(); });
Log_InfoPrint("GPU thread started.");
}
@ -184,7 +184,7 @@ void GPUBackend::StopGPUThread()
m_gpu_loop_done.store(true);
WakeGPUThread();
m_gpu_thread.join();
m_gpu_thread.Join();
m_use_gpu_thread = false;
Log_InfoPrint("GPU thread stopped.");
}

View file

@ -1,6 +1,7 @@
#pragma once
#include "common/event.h"
#include "common/heap_array.h"
#include "common/threading.h"
#include "gpu_types.h"
#include <atomic>
#include <condition_variable>
@ -20,6 +21,7 @@ public:
virtual ~GPUBackend();
ALWAYS_INLINE u16* GetVRAM() const { return m_vram_ptr; }
ALWAYS_INLINE const Threading::Thread* GetThread() const { return m_use_gpu_thread ? &m_gpu_thread : nullptr; }
virtual bool Initialize(bool force_thread);
virtual void UpdateSettings();
@ -67,7 +69,7 @@ protected:
Common::Event m_sync_event;
std::atomic_bool m_gpu_thread_sleeping{false};
std::atomic_bool m_gpu_loop_done{false};
std::thread m_gpu_thread;
Threading::Thread m_gpu_thread;
bool m_use_gpu_thread = false;
std::mutex m_sync_mutex;

View file

@ -4,6 +4,7 @@
#include "common/log.h"
#include "cpu_core.h"
#include "gpu_sw_backend.h"
#include "host.h"
#include "imgui.h"
#include "pgxp.h"
#include "settings.h"
@ -43,14 +44,14 @@ GPU_HW::~GPU_HW()
}
}
bool GPU_HW::Initialize(HostDisplay* host_display)
bool GPU_HW::Initialize()
{
if (!GPU::Initialize(host_display))
if (!GPU::Initialize())
return false;
m_resolution_scale = CalculateResolutionScale();
m_multisamples = std::min(g_settings.gpu_multisamples, m_max_multisamples);
m_render_api = host_display->GetRenderAPI();
m_render_api = g_host_display->GetRenderAPI();
m_per_sample_shading = g_settings.gpu_per_sample_shading && m_supports_per_sample_shading;
m_true_color = g_settings.gpu_true_color;
m_scaled_dithering = g_settings.gpu_scaled_dithering;
@ -61,29 +62,26 @@ bool GPU_HW::Initialize(HostDisplay* host_display)
if (m_multisamples != g_settings.gpu_multisamples)
{
g_host_interface->AddFormattedOSDMessage(
20.0f, g_host_interface->TranslateString("OSDMessage", "%ux MSAA is not supported, using %ux instead."),
g_settings.gpu_multisamples, m_multisamples);
Host::AddFormattedOSDMessage(20.0f,
Host::TranslateString("OSDMessage", "%ux MSAA is not supported, using %ux instead."),
g_settings.gpu_multisamples, m_multisamples);
}
if (!m_per_sample_shading && g_settings.gpu_per_sample_shading)
{
g_host_interface->AddOSDMessage(
g_host_interface->TranslateStdString("OSDMessage", "SSAA is not supported, using MSAA instead."), 20.0f);
Host::AddOSDMessage(Host::TranslateStdString("OSDMessage", "SSAA is not supported, using MSAA instead."), 20.0f);
}
if (!m_supports_dual_source_blend && TextureFilterRequiresDualSourceBlend(m_texture_filtering))
{
g_host_interface->AddFormattedOSDMessage(
20.0f,
g_host_interface->TranslateString("OSDMessage",
"Texture filter '%s' is not supported with the current renderer."),
Host::AddFormattedOSDMessage(
20.0f, Host::TranslateString("OSDMessage", "Texture filter '%s' is not supported with the current renderer."),
Settings::GetTextureFilterDisplayName(m_texture_filtering));
m_texture_filtering = GPUTextureFilter::Nearest;
}
if (!m_supports_adaptive_downsampling && g_settings.gpu_resolution_scale > 1 &&
g_settings.gpu_downsample_mode == GPUDownsampleMode::Adaptive)
{
g_host_interface->AddOSDMessage(
g_host_interface->TranslateStdString(
Host::AddOSDMessage(
Host::TranslateStdString(
"OSDMessage", "Adaptive downsampling is not supported with the current renderer, using box filter instead."),
20.0f);
}
@ -149,27 +147,26 @@ void GPU_HW::UpdateHWSettings(bool* framebuffer_changed, bool* shaders_changed)
if (m_resolution_scale != resolution_scale)
{
g_host_interface->AddKeyedFormattedOSDMessage(
Host::AddKeyedFormattedOSDMessage(
"ResolutionScale", 10.0f,
g_host_interface->TranslateString("OSDMessage", "Resolution scale set to %ux (display %ux%u, VRAM %ux%u)"),
resolution_scale, m_crtc_state.display_vram_width * resolution_scale,
resolution_scale * m_crtc_state.display_vram_height, VRAM_WIDTH * resolution_scale,
VRAM_HEIGHT * resolution_scale);
Host::TranslateString("OSDMessage", "Resolution scale set to %ux (display %ux%u, VRAM %ux%u)"), resolution_scale,
m_crtc_state.display_vram_width * resolution_scale, resolution_scale * m_crtc_state.display_vram_height,
VRAM_WIDTH * resolution_scale, VRAM_HEIGHT * resolution_scale);
}
if (m_multisamples != multisamples || m_per_sample_shading != per_sample_shading)
{
if (per_sample_shading)
{
g_host_interface->AddKeyedFormattedOSDMessage(
"Multisampling", 10.0f,
g_host_interface->TranslateString("OSDMessage", "Multisample anti-aliasing set to %ux (SSAA)."), multisamples);
Host::AddKeyedFormattedOSDMessage(
"Multisampling", 10.0f, Host::TranslateString("OSDMessage", "Multisample anti-aliasing set to %ux (SSAA)."),
multisamples);
}
else
{
g_host_interface->AddKeyedFormattedOSDMessage(
"Multisampling", 10.0f,
g_host_interface->TranslateString("OSDMessage", "Multisample anti-aliasing set to %ux."), multisamples);
Host::AddKeyedFormattedOSDMessage("Multisampling", 10.0f,
Host::TranslateString("OSDMessage", "Multisample anti-aliasing set to %ux."),
multisamples);
}
}
@ -215,7 +212,7 @@ u32 GPU_HW::CalculateResolutionScale() const
(m_console_is_pal ? (PAL_VERTICAL_ACTIVE_END - PAL_VERTICAL_ACTIVE_START) :
(NTSC_VERTICAL_ACTIVE_END - NTSC_VERTICAL_ACTIVE_START));
const s32 preferred_scale =
static_cast<s32>(std::ceil(static_cast<float>(m_host_display->GetWindowHeight()) / height));
static_cast<s32>(std::ceil(static_cast<float>(g_host_display->GetWindowHeight()) / height));
Log_InfoPrintf("Height = %d, preferred scale = %d", height, preferred_scale);
scale = static_cast<u32>(std::clamp<s32>(preferred_scale, 1, m_max_resolution_scale));
@ -229,10 +226,9 @@ u32 GPU_HW::CalculateResolutionScale() const
if (g_settings.gpu_resolution_scale != 0)
{
g_host_interface->AddFormattedOSDMessage(
Host::AddFormattedOSDMessage(
10.0f,
g_host_interface->TranslateString("OSDMessage",
"Resolution scale %ux not supported for adaptive smoothing, using %ux."),
Host::TranslateString("OSDMessage", "Resolution scale %ux not supported for adaptive smoothing, using %ux."),
scale, new_scale);
}
@ -1410,7 +1406,7 @@ void GPU_HW::DrawRendererStats(bool is_idle_frame)
const auto& stats = m_last_renderer_stats;
ImGui::Columns(2);
ImGui::SetColumnWidth(0, 200.0f * ImGui::GetIO().DisplayFramebufferScale.x);
ImGui::SetColumnWidth(0, 200.0f * Host::GetOSDScale());
ImGui::TextUnformatted("Resolution Scale:");
ImGui::NextColumn();
@ -1487,7 +1483,7 @@ void GPU_HW::ShaderCompileProgressTracker::Increment()
const u64 tv = Common::Timer::GetCurrentValue();
if ((tv - m_start_time) >= m_min_time && (tv - m_last_update_time) >= m_update_interval)
{
g_host_interface->DisplayLoadingScreen(m_title.c_str(), 0, static_cast<int>(m_total), static_cast<int>(m_progress));
Host::DisplayLoadingScreen(m_title.c_str(), 0, static_cast<int>(m_total), static_cast<int>(m_progress));
m_last_update_time = tv;
}
}

View file

@ -33,7 +33,7 @@ public:
GPU_HW();
virtual ~GPU_HW();
virtual bool Initialize(HostDisplay* host_display) override;
virtual bool Initialize() override;
virtual void Reset(bool clear_vram) override;
virtual bool DoState(StateWrapper& sw, HostDisplayTexture** host_texture, bool update_display) override;

View file

@ -6,7 +6,6 @@
#include "gpu_hw_shadergen.h"
#include "gpu_sw_backend.h"
#include "host_display.h"
#include "host_interface.h"
#include "shader_cache_version.h"
#include "system.h"
#include "util/state_wrapper.h"
@ -16,8 +15,11 @@ GPU_HW_D3D11::GPU_HW_D3D11() = default;
GPU_HW_D3D11::~GPU_HW_D3D11()
{
if (m_host_display)
m_host_display->ClearDisplayTexture();
if (g_host_display)
{
g_host_display->ClearDisplayTexture();
ResetGraphicsAPIState();
}
if (m_context)
m_context->ClearState();
@ -31,22 +33,22 @@ GPURenderer GPU_HW_D3D11::GetRendererType() const
return GPURenderer::HardwareD3D11;
}
bool GPU_HW_D3D11::Initialize(HostDisplay* host_display)
bool GPU_HW_D3D11::Initialize()
{
if (host_display->GetRenderAPI() != HostDisplay::RenderAPI::D3D11)
if (!Host::AcquireHostDisplay(HostDisplay::RenderAPI::D3D11))
{
Log_ErrorPrintf("Host render API is incompatible");
return false;
}
m_device = static_cast<ID3D11Device*>(host_display->GetRenderDevice());
m_context = static_cast<ID3D11DeviceContext*>(host_display->GetRenderContext());
m_device = static_cast<ID3D11Device*>(g_host_display->GetRenderDevice());
m_context = static_cast<ID3D11DeviceContext*>(g_host_display->GetRenderContext());
if (!m_device || !m_context)
return false;
SetCapabilities();
if (!GPU_HW::Initialize(host_display))
if (!GPU_HW::Initialize())
return false;
if (!CreateFramebuffer())
@ -122,7 +124,7 @@ bool GPU_HW_D3D11::DoState(StateWrapper& sw, HostDisplayTexture** host_texture,
{
delete tex;
tex = m_host_display
tex = g_host_display
->CreateTexture(m_vram_texture.GetWidth(), m_vram_texture.GetHeight(), 1, 1,
m_vram_texture.GetSamples(), HostDisplayPixelFormat::RGBA8, nullptr, 0, false)
.release();
@ -178,7 +180,7 @@ void GPU_HW_D3D11::UpdateSettings()
RestoreGraphicsAPIState();
ReadVRAM(0, 0, VRAM_WIDTH, VRAM_HEIGHT);
ResetGraphicsAPIState();
m_host_display->ClearDisplayTexture();
g_host_display->ClearDisplayTexture();
CreateFramebuffer();
}
@ -501,10 +503,10 @@ void GPU_HW_D3D11::DestroyStateObjects()
bool GPU_HW_D3D11::CompileShaders()
{
D3D11::ShaderCache shader_cache;
shader_cache.Open(g_host_interface->GetShaderCacheBasePath(), m_device->GetFeatureLevel(), SHADER_CACHE_VERSION,
shader_cache.Open(EmuFolders::Cache, m_device->GetFeatureLevel(), SHADER_CACHE_VERSION,
g_settings.gpu_use_debug_device);
GPU_HW_ShaderGen shadergen(m_host_display->GetRenderAPI(), m_resolution_scale, m_multisamples, m_per_sample_shading,
GPU_HW_ShaderGen shadergen(g_host_display->GetRenderAPI(), m_resolution_scale, m_multisamples, m_per_sample_shading,
m_true_color, m_scaled_dithering, m_texture_filtering, m_using_uv_limits,
m_pgxp_depth_buffer, m_supports_dual_source_blend);
@ -826,7 +828,7 @@ void GPU_HW_D3D11::ClearDisplay()
{
GPU_HW::ClearDisplay();
m_host_display->ClearDisplayTexture();
g_host_display->ClearDisplayTexture();
static constexpr std::array<float, 4> clear_color = {0.0f, 0.0f, 0.0f, 1.0f};
m_context->ClearRenderTargetView(m_display_texture.GetD3DRTV(), clear_color.data());
@ -841,23 +843,23 @@ void GPU_HW_D3D11::UpdateDisplay()
if (IsUsingMultisampling())
{
UpdateVRAMReadTexture();
m_host_display->SetDisplayTexture(m_vram_read_texture.GetD3DSRV(), HostDisplayPixelFormat::RGBA8,
g_host_display->SetDisplayTexture(m_vram_read_texture.GetD3DSRV(), HostDisplayPixelFormat::RGBA8,
m_vram_read_texture.GetWidth(), m_vram_read_texture.GetHeight(), 0, 0,
m_vram_read_texture.GetWidth(), m_vram_read_texture.GetHeight());
}
else
{
m_host_display->SetDisplayTexture(m_vram_texture.GetD3DSRV(), HostDisplayPixelFormat::RGBA8,
g_host_display->SetDisplayTexture(m_vram_texture.GetD3DSRV(), HostDisplayPixelFormat::RGBA8,
m_vram_texture.GetWidth(), m_vram_texture.GetHeight(), 0, 0,
m_vram_texture.GetWidth(), m_vram_texture.GetHeight());
}
m_host_display->SetDisplayParameters(VRAM_WIDTH, VRAM_HEIGHT, 0, 0, VRAM_WIDTH, VRAM_HEIGHT,
g_host_display->SetDisplayParameters(VRAM_WIDTH, VRAM_HEIGHT, 0, 0, VRAM_WIDTH, VRAM_HEIGHT,
static_cast<float>(VRAM_WIDTH) / static_cast<float>(VRAM_HEIGHT));
}
else
{
m_host_display->SetDisplayParameters(m_crtc_state.display_width, m_crtc_state.display_height,
g_host_display->SetDisplayParameters(m_crtc_state.display_width, m_crtc_state.display_height,
m_crtc_state.display_origin_left, m_crtc_state.display_origin_top,
m_crtc_state.display_vram_width, m_crtc_state.display_vram_height,
GetDisplayAspectRatio());
@ -875,7 +877,7 @@ void GPU_HW_D3D11::UpdateDisplay()
if (IsDisplayDisabled())
{
m_host_display->ClearDisplayTexture();
g_host_display->ClearDisplayTexture();
}
else if (!m_GPUSTAT.display_area_color_depth_24 && interlaced == InterlacedRenderMode::None &&
!IsUsingMultisampling() && (scaled_vram_offset_x + scaled_display_width) <= m_vram_texture.GetWidth() &&
@ -889,7 +891,7 @@ void GPU_HW_D3D11::UpdateDisplay()
}
else
{
m_host_display->SetDisplayTexture(m_vram_texture.GetD3DSRV(), HostDisplayPixelFormat::RGBA8,
g_host_display->SetDisplayTexture(m_vram_texture.GetD3DSRV(), HostDisplayPixelFormat::RGBA8,
m_vram_texture.GetWidth(), m_vram_texture.GetHeight(), scaled_vram_offset_x,
scaled_vram_offset_y, scaled_display_width, scaled_display_height);
}
@ -921,7 +923,7 @@ void GPU_HW_D3D11::UpdateDisplay()
}
else
{
m_host_display->SetDisplayTexture(m_display_texture.GetD3DSRV(), HostDisplayPixelFormat::RGBA8,
g_host_display->SetDisplayTexture(m_display_texture.GetD3DSRV(), HostDisplayPixelFormat::RGBA8,
m_display_texture.GetWidth(), m_display_texture.GetHeight(), 0, 0,
scaled_display_width, scaled_display_height);
}
@ -1202,7 +1204,7 @@ void GPU_HW_D3D11::DownsampleFramebufferAdaptive(D3D11::Texture& source, u32 lef
RestoreGraphicsAPIState();
m_host_display->SetDisplayTexture(m_display_texture.GetD3DSRV(), HostDisplayPixelFormat::RGBA8,
g_host_display->SetDisplayTexture(m_display_texture.GetD3DSRV(), HostDisplayPixelFormat::RGBA8,
m_display_texture.GetWidth(), m_display_texture.GetHeight(), left, top, width,
height);
}
@ -1227,7 +1229,7 @@ void GPU_HW_D3D11::DownsampleFramebufferBoxFilter(D3D11::Texture& source, u32 le
RestoreGraphicsAPIState();
m_host_display->SetDisplayTexture(m_downsample_texture.GetD3DSRV(), HostDisplayPixelFormat::RGBA8,
g_host_display->SetDisplayTexture(m_downsample_texture.GetD3DSRV(), HostDisplayPixelFormat::RGBA8,
m_downsample_texture.GetWidth(), m_downsample_texture.GetHeight(), ds_left, ds_top,
ds_width, ds_height);
}

View file

@ -22,7 +22,7 @@ public:
GPURenderer GetRendererType() const override;
bool Initialize(HostDisplay* host_display) override;
bool Initialize() override;
void Reset(bool clear_vram) override;
bool DoState(StateWrapper& sw, HostDisplayTexture** host_texture, bool update_display) override;

View file

@ -11,7 +11,6 @@
#include "common/timer.h"
#include "gpu_hw_shadergen.h"
#include "host_display.h"
#include "host_interface.h"
#include "system.h"
Log_SetChannel(GPU_HW_D3D12);
@ -19,9 +18,9 @@ GPU_HW_D3D12::GPU_HW_D3D12() = default;
GPU_HW_D3D12::~GPU_HW_D3D12()
{
if (m_host_display)
if (g_host_display)
{
m_host_display->ClearDisplayTexture();
g_host_display->ClearDisplayTexture();
ResetGraphicsAPIState();
}
@ -33,9 +32,9 @@ GPURenderer GPU_HW_D3D12::GetRendererType() const
return GPURenderer::HardwareD3D12;
}
bool GPU_HW_D3D12::Initialize(HostDisplay* host_display)
bool GPU_HW_D3D12::Initialize()
{
if (host_display->GetRenderAPI() != HostDisplay::RenderAPI::D3D12)
if (!Host::AcquireHostDisplay(HostDisplay::RenderAPI::D3D12))
{
Log_ErrorPrintf("Host render API is incompatible");
return false;
@ -43,7 +42,7 @@ bool GPU_HW_D3D12::Initialize(HostDisplay* host_display)
SetCapabilities();
if (!GPU_HW::Initialize(host_display))
if (!GPU_HW::Initialize())
return false;
if (!CreateRootSignatures())
@ -144,7 +143,7 @@ void GPU_HW_D3D12::UpdateSettings()
}
// Everything should be finished executing before recreating resources.
m_host_display->ClearDisplayTexture();
g_host_display->ClearDisplayTexture();
g_d3d12_context->ExecuteCommandList(true);
if (framebuffer_changed)
@ -413,10 +412,9 @@ bool GPU_HW_D3D12::CreateTextureBuffer()
bool GPU_HW_D3D12::CompilePipelines()
{
D3D12::ShaderCache shader_cache;
shader_cache.Open(g_host_interface->GetShaderCacheBasePath(), g_d3d12_context->GetFeatureLevel(),
g_settings.gpu_use_debug_device);
shader_cache.Open(EmuFolders::Cache, g_d3d12_context->GetFeatureLevel(), g_settings.gpu_use_debug_device);
GPU_HW_ShaderGen shadergen(m_host_display->GetRenderAPI(), m_resolution_scale, m_multisamples, m_per_sample_shading,
GPU_HW_ShaderGen shadergen(g_host_display->GetRenderAPI(), m_resolution_scale, m_multisamples, m_per_sample_shading,
m_true_color, m_scaled_dithering, m_texture_filtering, m_using_uv_limits,
m_pgxp_depth_buffer, m_supports_dual_source_blend);
@ -852,7 +850,7 @@ void GPU_HW_D3D12::ClearDisplay()
{
GPU_HW::ClearDisplay();
m_host_display->ClearDisplayTexture();
g_host_display->ClearDisplayTexture();
static constexpr float clear_color[4] = {0.0f, 0.0f, 0.0f, 1.0f};
m_display_texture.TransitionToState(D3D12_RESOURCE_STATE_RENDER_TARGET);
@ -869,23 +867,23 @@ void GPU_HW_D3D12::UpdateDisplay()
if (IsUsingMultisampling())
{
UpdateVRAMReadTexture();
m_host_display->SetDisplayTexture(&m_vram_read_texture, HostDisplayPixelFormat::RGBA8,
g_host_display->SetDisplayTexture(&m_vram_read_texture, HostDisplayPixelFormat::RGBA8,
m_vram_read_texture.GetWidth(), m_vram_read_texture.GetHeight(), 0, 0,
m_vram_read_texture.GetWidth(), m_vram_read_texture.GetHeight());
}
else
{
m_vram_texture.TransitionToState(D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
m_host_display->SetDisplayTexture(&m_vram_texture, HostDisplayPixelFormat::RGBA8, m_vram_texture.GetWidth(),
g_host_display->SetDisplayTexture(&m_vram_texture, HostDisplayPixelFormat::RGBA8, m_vram_texture.GetWidth(),
m_vram_texture.GetHeight(), 0, 0, m_vram_texture.GetWidth(),
m_vram_texture.GetHeight());
}
m_host_display->SetDisplayParameters(VRAM_WIDTH, VRAM_HEIGHT, 0, 0, VRAM_WIDTH, VRAM_HEIGHT,
g_host_display->SetDisplayParameters(VRAM_WIDTH, VRAM_HEIGHT, 0, 0, VRAM_WIDTH, VRAM_HEIGHT,
static_cast<float>(VRAM_WIDTH) / static_cast<float>(VRAM_HEIGHT));
}
else
{
m_host_display->SetDisplayParameters(m_crtc_state.display_width, m_crtc_state.display_height,
g_host_display->SetDisplayParameters(m_crtc_state.display_width, m_crtc_state.display_height,
m_crtc_state.display_origin_left, m_crtc_state.display_origin_top,
m_crtc_state.display_vram_width, m_crtc_state.display_vram_height,
GetDisplayAspectRatio());
@ -903,14 +901,14 @@ void GPU_HW_D3D12::UpdateDisplay()
if (IsDisplayDisabled())
{
m_host_display->ClearDisplayTexture();
g_host_display->ClearDisplayTexture();
}
else if (!m_GPUSTAT.display_area_color_depth_24 && interlaced == InterlacedRenderMode::None &&
!IsUsingMultisampling() && (scaled_vram_offset_x + scaled_display_width) <= m_vram_texture.GetWidth() &&
(scaled_vram_offset_y + scaled_display_height) <= m_vram_texture.GetHeight())
{
m_vram_texture.TransitionToState(D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
m_host_display->SetDisplayTexture(&m_vram_texture, HostDisplayPixelFormat::RGBA8, m_vram_texture.GetWidth(),
g_host_display->SetDisplayTexture(&m_vram_texture, HostDisplayPixelFormat::RGBA8, m_vram_texture.GetWidth(),
m_vram_texture.GetHeight(), scaled_vram_offset_x, scaled_vram_offset_y,
scaled_display_width, scaled_display_height);
}
@ -938,7 +936,7 @@ void GPU_HW_D3D12::UpdateDisplay()
m_display_texture.TransitionToState(D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
m_vram_texture.TransitionToState(D3D12_RESOURCE_STATE_RENDER_TARGET);
m_host_display->SetDisplayTexture(&m_display_texture, HostDisplayPixelFormat::RGBA8, m_display_texture.GetWidth(),
g_host_display->SetDisplayTexture(&m_display_texture, HostDisplayPixelFormat::RGBA8, m_display_texture.GetWidth(),
m_display_texture.GetHeight(), 0, 0, scaled_display_width,
scaled_display_height);

View file

@ -20,7 +20,7 @@ public:
GPURenderer GetRendererType() const override;
bool Initialize(HostDisplay* host_display) override;
bool Initialize() override;
void Reset(bool clear_vram) override;
void ResetGraphicsAPIState() override;

View file

@ -3,6 +3,7 @@
#include "common/log.h"
#include "common/timer.h"
#include "gpu_hw_shadergen.h"
#include "host.h"
#include "host_display.h"
#include "shader_cache_version.h"
#include "system.h"
@ -24,9 +25,9 @@ GPU_HW_OpenGL::~GPU_HW_OpenGL()
if (m_texture_buffer_r16ui_texture != 0)
glDeleteTextures(1, &m_texture_buffer_r16ui_texture);
if (m_host_display)
if (g_host_display)
{
m_host_display->ClearDisplayTexture();
g_host_display->ClearDisplayTexture();
ResetGraphicsAPIState();
}
@ -40,31 +41,30 @@ GPURenderer GPU_HW_OpenGL::GetRendererType() const
return GPURenderer::HardwareOpenGL;
}
bool GPU_HW_OpenGL::Initialize(HostDisplay* host_display)
bool GPU_HW_OpenGL::Initialize()
{
if (host_display->GetRenderAPI() != HostDisplay::RenderAPI::OpenGL &&
host_display->GetRenderAPI() != HostDisplay::RenderAPI::OpenGLES)
if (!Host::AcquireHostDisplay(HostDisplay::RenderAPI::OpenGL))
{
Log_ErrorPrintf("Host render API type is incompatible");
return false;
}
const bool opengl_is_available =
((host_display->GetRenderAPI() == HostDisplay::RenderAPI::OpenGL &&
((g_host_display->GetRenderAPI() == HostDisplay::RenderAPI::OpenGL &&
(GLAD_GL_VERSION_3_0 || GLAD_GL_ARB_uniform_buffer_object)) ||
(host_display->GetRenderAPI() == HostDisplay::RenderAPI::OpenGLES && GLAD_GL_ES_VERSION_3_0));
(g_host_display->GetRenderAPI() == HostDisplay::RenderAPI::OpenGLES && GLAD_GL_ES_VERSION_3_0));
if (!opengl_is_available)
{
g_host_interface->AddOSDMessage(
g_host_interface->TranslateStdString("OSDMessage", "OpenGL renderer unavailable, your driver or hardware is not "
"recent enough. OpenGL 3.1 or OpenGL ES 3.0 is required."),
20.0f);
Host::AddOSDMessage(Host::TranslateStdString("OSDMessage",
"OpenGL renderer unavailable, your driver or hardware is not "
"recent enough. OpenGL 3.1 or OpenGL ES 3.0 is required."),
20.0f);
return false;
}
SetCapabilities(host_display);
SetCapabilities();
if (!GPU_HW::Initialize(host_display))
if (!GPU_HW::Initialize())
return false;
if (!CreateFramebuffer())
@ -133,7 +133,7 @@ bool GPU_HW_OpenGL::DoState(StateWrapper& sw, HostDisplayTexture** host_texture,
{
delete tex;
tex = m_host_display
tex = g_host_display
->CreateTexture(m_vram_texture.GetWidth(), m_vram_texture.GetHeight(), 1, 1,
m_vram_texture.GetSamples(), HostDisplayPixelFormat::RGBA8, nullptr, 0, false)
.release();
@ -252,7 +252,7 @@ void GPU_HW_OpenGL::UpdateSettings()
RestoreGraphicsAPIState();
ReadVRAM(0, 0, VRAM_WIDTH, VRAM_HEIGHT);
ResetGraphicsAPIState();
m_host_display->ClearDisplayTexture();
g_host_display->ClearDisplayTexture();
CreateFramebuffer();
}
if (shaders_changed)
@ -297,7 +297,7 @@ std::tuple<s32, s32> GPU_HW_OpenGL::ConvertToFramebufferCoordinates(s32 x, s32 y
return std::make_tuple(x, static_cast<s32>(static_cast<s32>(VRAM_HEIGHT) - y));
}
void GPU_HW_OpenGL::SetCapabilities(HostDisplay* host_display)
void GPU_HW_OpenGL::SetCapabilities()
{
GLint max_texture_size = VRAM_WIDTH;
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size);
@ -510,10 +510,10 @@ bool GPU_HW_OpenGL::CreateTextureBuffer()
bool GPU_HW_OpenGL::CompilePrograms()
{
GL::ShaderCache shader_cache;
shader_cache.Open(IsGLES(), g_host_interface->GetShaderCacheBasePath(), SHADER_CACHE_VERSION);
shader_cache.Open(IsGLES(), EmuFolders::Cache, SHADER_CACHE_VERSION);
const bool use_binding_layout = GPU_HW_ShaderGen::UseGLSLBindingLayout();
GPU_HW_ShaderGen shadergen(m_host_display->GetRenderAPI(), m_resolution_scale, m_multisamples, m_per_sample_shading,
GPU_HW_ShaderGen shadergen(g_host_display->GetRenderAPI(), m_resolution_scale, m_multisamples, m_per_sample_shading,
m_true_color, m_scaled_dithering, m_texture_filtering, m_using_uv_limits,
m_pgxp_depth_buffer, m_supports_dual_source_blend);
@ -844,7 +844,7 @@ void GPU_HW_OpenGL::ClearDisplay()
{
GPU_HW::ClearDisplay();
m_host_display->ClearDisplayTexture();
g_host_display->ClearDisplayTexture();
m_display_texture.BindFramebuffer(GL_DRAW_FRAMEBUFFER);
glDisable(GL_SCISSOR_TEST);
@ -864,7 +864,7 @@ void GPU_HW_OpenGL::UpdateDisplay()
{
UpdateVRAMReadTexture();
m_host_display->SetDisplayTexture(reinterpret_cast<void*>(static_cast<uintptr_t>(m_vram_read_texture.GetGLId())),
g_host_display->SetDisplayTexture(reinterpret_cast<void*>(static_cast<uintptr_t>(m_vram_read_texture.GetGLId())),
HostDisplayPixelFormat::RGBA8, m_vram_read_texture.GetWidth(),
static_cast<s32>(m_vram_read_texture.GetHeight()), 0,
m_vram_read_texture.GetHeight(), m_vram_read_texture.GetWidth(),
@ -872,17 +872,17 @@ void GPU_HW_OpenGL::UpdateDisplay()
}
else
{
m_host_display->SetDisplayTexture(reinterpret_cast<void*>(static_cast<uintptr_t>(m_vram_texture.GetGLId())),
g_host_display->SetDisplayTexture(reinterpret_cast<void*>(static_cast<uintptr_t>(m_vram_texture.GetGLId())),
HostDisplayPixelFormat::RGBA8, m_vram_texture.GetWidth(),
static_cast<s32>(m_vram_texture.GetHeight()), 0, m_vram_texture.GetHeight(),
m_vram_texture.GetWidth(), -static_cast<s32>(m_vram_texture.GetHeight()));
}
m_host_display->SetDisplayParameters(VRAM_WIDTH, VRAM_HEIGHT, 0, 0, VRAM_WIDTH, VRAM_HEIGHT,
g_host_display->SetDisplayParameters(VRAM_WIDTH, VRAM_HEIGHT, 0, 0, VRAM_WIDTH, VRAM_HEIGHT,
static_cast<float>(VRAM_WIDTH) / static_cast<float>(VRAM_HEIGHT));
}
else
{
m_host_display->SetDisplayParameters(m_crtc_state.display_width, m_crtc_state.display_height,
g_host_display->SetDisplayParameters(m_crtc_state.display_width, m_crtc_state.display_height,
m_crtc_state.display_origin_left, m_crtc_state.display_origin_top,
m_crtc_state.display_vram_width, m_crtc_state.display_vram_height,
GetDisplayAspectRatio());
@ -900,7 +900,7 @@ void GPU_HW_OpenGL::UpdateDisplay()
if (IsDisplayDisabled())
{
m_host_display->ClearDisplayTexture();
g_host_display->ClearDisplayTexture();
}
else if (!m_GPUSTAT.display_area_color_depth_24 && interlaced == GPU_HW::InterlacedRenderMode::None &&
!IsUsingMultisampling() && (scaled_vram_offset_x + scaled_display_width) <= m_vram_texture.GetWidth() &&
@ -913,7 +913,7 @@ void GPU_HW_OpenGL::UpdateDisplay()
}
else
{
m_host_display->SetDisplayTexture(reinterpret_cast<void*>(static_cast<uintptr_t>(m_vram_texture.GetGLId())),
g_host_display->SetDisplayTexture(reinterpret_cast<void*>(static_cast<uintptr_t>(m_vram_texture.GetGLId())),
HostDisplayPixelFormat::RGBA8, m_vram_texture.GetWidth(),
m_vram_texture.GetHeight(), scaled_vram_offset_x,
m_vram_texture.GetHeight() - scaled_vram_offset_y, scaled_display_width,
@ -960,7 +960,7 @@ void GPU_HW_OpenGL::UpdateDisplay()
}
else
{
m_host_display->SetDisplayTexture(reinterpret_cast<void*>(static_cast<uintptr_t>(m_display_texture.GetGLId())),
g_host_display->SetDisplayTexture(reinterpret_cast<void*>(static_cast<uintptr_t>(m_display_texture.GetGLId())),
HostDisplayPixelFormat::RGBA8, m_display_texture.GetWidth(),
m_display_texture.GetHeight(), 0, scaled_display_height, scaled_display_width,
-static_cast<s32>(scaled_display_height));
@ -1353,7 +1353,7 @@ void GPU_HW_OpenGL::DownsampleFramebufferBoxFilter(GL::Texture& source, u32 left
RestoreGraphicsAPIState();
m_host_display->SetDisplayTexture(reinterpret_cast<void*>(static_cast<uintptr_t>(m_downsample_texture.GetGLId())),
g_host_display->SetDisplayTexture(reinterpret_cast<void*>(static_cast<uintptr_t>(m_downsample_texture.GetGLId())),
HostDisplayPixelFormat::RGBA8, m_downsample_texture.GetWidth(),
m_downsample_texture.GetHeight(), ds_left,
m_downsample_texture.GetHeight() - ds_top, ds_width, -static_cast<s32>(ds_height));

View file

@ -18,7 +18,7 @@ public:
GPURenderer GetRendererType() const override;
bool Initialize(HostDisplay* host_display) override;
bool Initialize() override;
void Reset(bool clear_vram) override;
bool DoState(StateWrapper& sw, HostDisplayTexture** host_texture, bool update_display) override;
@ -57,7 +57,7 @@ private:
std::tuple<s32, s32> ConvertToFramebufferCoordinates(s32 x, s32 y);
void SetCapabilities(HostDisplay* host_display);
void SetCapabilities();
bool CreateFramebuffer();
void ClearFramebuffer();
void CopyFramebufferForState(GLenum target, GLuint src_texture, u32 src_fbo, u32 src_x, u32 src_y, GLuint dst_texture,

View file

@ -9,7 +9,6 @@
#include "common/vulkan/util.h"
#include "gpu_hw_shadergen.h"
#include "host_display.h"
#include "host_interface.h"
#include "system.h"
#include "util/state_wrapper.h"
Log_SetChannel(GPU_HW_Vulkan);
@ -18,9 +17,9 @@ GPU_HW_Vulkan::GPU_HW_Vulkan() = default;
GPU_HW_Vulkan::~GPU_HW_Vulkan()
{
if (m_host_display)
if (g_host_display)
{
m_host_display->ClearDisplayTexture();
g_host_display->ClearDisplayTexture();
ResetGraphicsAPIState();
}
@ -32,9 +31,9 @@ GPURenderer GPU_HW_Vulkan::GetRendererType() const
return GPURenderer::HardwareVulkan;
}
bool GPU_HW_Vulkan::Initialize(HostDisplay* host_display)
bool GPU_HW_Vulkan::Initialize()
{
if (host_display->GetRenderAPI() != HostDisplay::RenderAPI::Vulkan)
if (!Host::AcquireHostDisplay(HostDisplay::RenderAPI::Vulkan))
{
Log_ErrorPrintf("Host render API is incompatible");
return false;
@ -43,7 +42,7 @@ bool GPU_HW_Vulkan::Initialize(HostDisplay* host_display)
Assert(g_vulkan_shader_cache);
SetCapabilities();
if (!GPU_HW::Initialize(host_display))
if (!GPU_HW::Initialize())
return false;
if (!CreatePipelineLayouts())
@ -144,7 +143,7 @@ bool GPU_HW_Vulkan::DoState(StateWrapper& sw, HostDisplayTexture** host_texture,
{
delete htex;
htex = m_host_display
htex = g_host_display
->CreateTexture(m_vram_texture.GetWidth(), m_vram_texture.GetHeight(), 1, 1,
m_vram_texture.GetSamples(), HostDisplayPixelFormat::RGBA8, nullptr, 0, false)
.release();
@ -179,7 +178,7 @@ void GPU_HW_Vulkan::ResetGraphicsAPIState()
EndRenderPass();
if (m_host_display->GetDisplayTextureHandle() == &m_vram_texture)
if (g_host_display->GetDisplayTextureHandle() == &m_vram_texture)
{
m_vram_texture.TransitionToLayout(g_vulkan_context->GetCurrentCommandBuffer(),
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
@ -218,7 +217,7 @@ void GPU_HW_Vulkan::UpdateSettings()
}
// Everything should be finished executing before recreating resources.
m_host_display->ClearDisplayTexture();
g_host_display->ClearDisplayTexture();
g_vulkan_context->ExecuteCommandBuffer(true);
if (framebuffer_changed)
@ -923,7 +922,7 @@ bool GPU_HW_Vulkan::CompilePipelines()
VkDevice device = g_vulkan_context->GetDevice();
VkPipelineCache pipeline_cache = g_vulkan_shader_cache->GetPipelineCache();
GPU_HW_ShaderGen shadergen(m_host_display->GetRenderAPI(), m_resolution_scale, m_multisamples, m_per_sample_shading,
GPU_HW_ShaderGen shadergen(g_host_display->GetRenderAPI(), m_resolution_scale, m_multisamples, m_per_sample_shading,
m_true_color, m_scaled_dithering, m_texture_filtering, m_using_uv_limits,
m_pgxp_depth_buffer, m_supports_dual_source_blend);
@ -1405,7 +1404,7 @@ void GPU_HW_Vulkan::ClearDisplay()
GPU_HW::ClearDisplay();
EndRenderPass();
m_host_display->ClearDisplayTexture();
g_host_display->ClearDisplayTexture();
VkCommandBuffer cmdbuf = g_vulkan_context->GetCurrentCommandBuffer();
const Vulkan::Util::DebugScope debugScope(cmdbuf, "GPU_HW_Vulkan::ClearDisplay");
@ -1435,22 +1434,22 @@ void GPU_HW_Vulkan::UpdateDisplay()
UpdateVRAMReadTexture();
}
m_host_display->SetDisplayTexture(&m_vram_read_texture, HostDisplayPixelFormat::RGBA8,
g_host_display->SetDisplayTexture(&m_vram_read_texture, HostDisplayPixelFormat::RGBA8,
m_vram_read_texture.GetWidth(), m_vram_read_texture.GetHeight(), 0, 0,
m_vram_read_texture.GetWidth(), m_vram_read_texture.GetHeight());
}
else
{
m_host_display->SetDisplayTexture(&m_vram_texture, HostDisplayPixelFormat::RGBA8, m_vram_texture.GetWidth(),
g_host_display->SetDisplayTexture(&m_vram_texture, HostDisplayPixelFormat::RGBA8, m_vram_texture.GetWidth(),
m_vram_texture.GetHeight(), 0, 0, m_vram_texture.GetWidth(),
m_vram_texture.GetHeight());
}
m_host_display->SetDisplayParameters(VRAM_WIDTH, VRAM_HEIGHT, 0, 0, VRAM_WIDTH, VRAM_HEIGHT,
g_host_display->SetDisplayParameters(VRAM_WIDTH, VRAM_HEIGHT, 0, 0, VRAM_WIDTH, VRAM_HEIGHT,
static_cast<float>(VRAM_WIDTH) / static_cast<float>(VRAM_HEIGHT));
}
else
{
m_host_display->SetDisplayParameters(m_crtc_state.display_width, m_crtc_state.display_height,
g_host_display->SetDisplayParameters(m_crtc_state.display_width, m_crtc_state.display_height,
m_crtc_state.display_origin_left, m_crtc_state.display_origin_top,
m_crtc_state.display_vram_width, m_crtc_state.display_vram_height,
GetDisplayAspectRatio());
@ -1468,7 +1467,7 @@ void GPU_HW_Vulkan::UpdateDisplay()
if (IsDisplayDisabled())
{
m_host_display->ClearDisplayTexture();
g_host_display->ClearDisplayTexture();
}
else if (!m_GPUSTAT.display_area_color_depth_24 && interlaced == InterlacedRenderMode::None &&
!IsUsingMultisampling() && (scaled_vram_offset_x + scaled_display_width) <= m_vram_texture.GetWidth() &&
@ -1481,7 +1480,7 @@ void GPU_HW_Vulkan::UpdateDisplay()
}
else
{
m_host_display->SetDisplayTexture(&m_vram_texture, HostDisplayPixelFormat::RGBA8, m_vram_texture.GetWidth(),
g_host_display->SetDisplayTexture(&m_vram_texture, HostDisplayPixelFormat::RGBA8, m_vram_texture.GetWidth(),
m_vram_texture.GetHeight(), scaled_vram_offset_x, scaled_vram_offset_y,
scaled_display_width, scaled_display_height);
}
@ -1528,7 +1527,7 @@ void GPU_HW_Vulkan::UpdateDisplay()
}
else
{
m_host_display->SetDisplayTexture(&m_display_texture, HostDisplayPixelFormat::RGBA8,
g_host_display->SetDisplayTexture(&m_display_texture, HostDisplayPixelFormat::RGBA8,
m_display_texture.GetWidth(), m_display_texture.GetHeight(), 0, 0,
scaled_display_width, scaled_display_height);
RestoreGraphicsAPIState();
@ -1938,7 +1937,7 @@ void GPU_HW_Vulkan::DownsampleFramebufferBoxFilter(Vulkan::Texture& source, u32
RestoreGraphicsAPIState();
m_host_display->SetDisplayTexture(&m_downsample_texture, HostDisplayPixelFormat::RGBA8,
g_host_display->SetDisplayTexture(&m_downsample_texture, HostDisplayPixelFormat::RGBA8,
m_downsample_texture.GetWidth(), m_downsample_texture.GetHeight(), ds_left, ds_top,
ds_width, ds_height);
}
@ -2037,7 +2036,7 @@ void GPU_HW_Vulkan::DownsampleFramebufferAdaptive(Vulkan::Texture& source, u32 l
}
RestoreGraphicsAPIState();
m_host_display->SetDisplayTexture(&m_display_texture, HostDisplayPixelFormat::RGBA8, m_display_texture.GetWidth(),
g_host_display->SetDisplayTexture(&m_display_texture, HostDisplayPixelFormat::RGBA8, m_display_texture.GetWidth(),
m_display_texture.GetHeight(), left, top, width, height);
}

View file

@ -17,7 +17,7 @@ public:
GPURenderer GetRendererType() const override;
bool Initialize(HostDisplay* host_display) override;
bool Initialize() override;
void Reset(bool clear_vram) override;
bool DoState(StateWrapper& sw, HostDisplayTexture** host_texture, bool update_display) override;

View file

@ -36,8 +36,8 @@ GPU_SW::GPU_SW()
GPU_SW::~GPU_SW()
{
m_backend.Shutdown();
if (m_host_display)
m_host_display->ClearDisplayTexture();
if (g_host_display)
g_host_display->ClearDisplayTexture();
}
GPURenderer GPU_SW::GetRendererType() const
@ -45,9 +45,13 @@ GPURenderer GPU_SW::GetRendererType() const
return GPURenderer::Software;
}
bool GPU_SW::Initialize(HostDisplay* host_display)
bool GPU_SW::Initialize()
{
if (!GPU::Initialize(host_display) || !m_backend.Initialize(false))
// we need something to draw in.. but keep the current api if we have one
if (!g_host_display && !Host::AcquireHostDisplay(HostDisplay::GetPreferredAPI()))
return false;
if (!GPU::Initialize() || !m_backend.Initialize(false))
return false;
static constexpr auto formats_for_16bit = make_array(HostDisplayPixelFormat::RGB565, HostDisplayPixelFormat::RGBA5551,
@ -57,7 +61,7 @@ bool GPU_SW::Initialize(HostDisplay* host_display)
HostDisplayPixelFormat::RGBA5551);
for (const HostDisplayPixelFormat format : formats_for_16bit)
{
if (m_host_display->SupportsDisplayPixelFormat(format))
if (g_host_display->SupportsDisplayPixelFormat(format))
{
m_16bit_display_format = format;
break;
@ -65,7 +69,7 @@ bool GPU_SW::Initialize(HostDisplay* host_display)
}
for (const HostDisplayPixelFormat format : formats_for_24bit)
{
if (m_host_display->SupportsDisplayPixelFormat(format))
if (g_host_display->SupportsDisplayPixelFormat(format))
{
m_24bit_display_format = format;
break;
@ -233,7 +237,7 @@ void GPU_SW::CopyOut15Bit(u32 src_x, u32 src_y, u32 width, u32 height, u32 field
if (!interlaced)
{
if (!m_host_display->BeginSetDisplayPixels(display_format, width, height, reinterpret_cast<void**>(&dst_ptr),
if (!g_host_display->BeginSetDisplayPixels(display_format, width, height, reinterpret_cast<void**>(&dst_ptr),
&dst_stride))
{
return;
@ -285,11 +289,11 @@ void GPU_SW::CopyOut15Bit(u32 src_x, u32 src_y, u32 width, u32 height, u32 field
if (!interlaced)
{
m_host_display->EndSetDisplayPixels();
g_host_display->EndSetDisplayPixels();
}
else
{
m_host_display->SetDisplayPixels(display_format, width, height, m_display_texture_buffer.data(), output_stride);
g_host_display->SetDisplayPixels(display_format, width, height, m_display_texture_buffer.data(), output_stride);
}
}
@ -327,7 +331,7 @@ void GPU_SW::CopyOut24Bit(u32 src_x, u32 src_y, u32 skip_x, u32 width, u32 heigh
if (!interlaced)
{
if (!m_host_display->BeginSetDisplayPixels(display_format, width, height, reinterpret_cast<void**>(&dst_ptr),
if (!g_host_display->BeginSetDisplayPixels(display_format, width, height, reinterpret_cast<void**>(&dst_ptr),
&dst_stride))
{
return;
@ -443,11 +447,11 @@ void GPU_SW::CopyOut24Bit(u32 src_x, u32 src_y, u32 skip_x, u32 width, u32 heigh
if (!interlaced)
{
m_host_display->EndSetDisplayPixels();
g_host_display->EndSetDisplayPixels();
}
else
{
m_host_display->SetDisplayPixels(display_format, width, height, m_display_texture_buffer.data(), output_stride);
g_host_display->SetDisplayPixels(display_format, width, height, m_display_texture_buffer.data(), output_stride);
}
}
@ -486,14 +490,14 @@ void GPU_SW::UpdateDisplay()
if (!g_settings.debugging.show_vram)
{
m_host_display->SetDisplayParameters(m_crtc_state.display_width, m_crtc_state.display_height,
g_host_display->SetDisplayParameters(m_crtc_state.display_width, m_crtc_state.display_height,
m_crtc_state.display_origin_left, m_crtc_state.display_origin_top,
m_crtc_state.display_vram_width, m_crtc_state.display_vram_height,
GetDisplayAspectRatio());
if (IsDisplayDisabled())
{
m_host_display->ClearDisplayTexture();
g_host_display->ClearDisplayTexture();
return;
}
@ -534,7 +538,7 @@ void GPU_SW::UpdateDisplay()
else
{
CopyOut15Bit(m_16bit_display_format, 0, 0, VRAM_WIDTH, VRAM_HEIGHT, 0, false, false);
m_host_display->SetDisplayParameters(VRAM_WIDTH, VRAM_HEIGHT, 0, 0, VRAM_WIDTH, VRAM_HEIGHT,
g_host_display->SetDisplayParameters(VRAM_WIDTH, VRAM_HEIGHT, 0, 0, VRAM_WIDTH, VRAM_HEIGHT,
static_cast<float>(VRAM_WIDTH) / static_cast<float>(VRAM_HEIGHT));
}
}

View file

@ -7,6 +7,11 @@
#include <memory>
#include <vector>
namespace Threading
{
class Thread;
}
class HostDisplayTexture;
class GPU_SW final : public GPU
@ -15,9 +20,11 @@ public:
GPU_SW();
~GPU_SW() override;
ALWAYS_INLINE const GPU_SW_Backend& GetBackend() const { return m_backend; }
GPURenderer GetRendererType() const override;
bool Initialize(HostDisplay* host_display) override;
bool Initialize() override;
bool DoState(StateWrapper& sw, HostDisplayTexture** host_texture, bool update_display) override;
void Reset(bool clear_vram) override;
void UpdateSettings() override;

View file

@ -5,7 +5,6 @@
#include "cpu_core.h"
#include "cpu_core_private.h"
#include "host_display.h"
#include "host_interface.h"
#include "pgxp.h"
#include "settings.h"
#include "timing_event.h"
@ -188,15 +187,14 @@ void UpdateAspectRatio()
{
case DisplayAspectRatio::MatchWindow:
{
const HostDisplay* display = g_host_interface->GetDisplay();
if (!display)
if (!g_host_display)
{
s_aspect_ratio = DisplayAspectRatio::R4_3;
return;
}
num = display->GetWindowWidth();
denom = display->GetWindowHeight();
num = g_host_display->GetWindowWidth();
denom = g_host_display->GetWindowHeight();
}
break;

273
src/core/guncon.cpp Normal file
View file

@ -0,0 +1,273 @@
#include "guncon.h"
#include "common/assert.h"
#include "common/log.h"
#include "gpu.h"
#include "host.h"
#include "host_display.h"
#include "resources.h"
#include "system.h"
#include "util/state_wrapper.h"
#include <array>
Log_SetChannel(GunCon);
static constexpr std::array<u8, static_cast<size_t>(GunCon::Button::Count)> s_button_indices = {{13, 3, 14}};
GunCon::GunCon(u32 index) : Controller(index) {}
GunCon::~GunCon() = default;
ControllerType GunCon::GetType() const
{
return ControllerType::GunCon;
}
void GunCon::Reset()
{
m_transfer_state = TransferState::Idle;
}
bool GunCon::DoState(StateWrapper& sw, bool apply_input_state)
{
if (!Controller::DoState(sw, apply_input_state))
return false;
u16 button_state = m_button_state;
u16 position_x = m_position_x;
u16 position_y = m_position_y;
sw.Do(&button_state);
sw.Do(&position_x);
sw.Do(&position_y);
if (apply_input_state)
{
m_button_state = button_state;
m_position_x = position_x;
m_position_y = position_y;
}
sw.Do(&m_transfer_state);
return true;
}
float GunCon::GetBindState(u32 index) const
{
if (index >= s_button_indices.size())
return 0.0f;
const u32 bit = s_button_indices[index];
return static_cast<float>(((m_button_state >> bit) & 1u) ^ 1u);
}
void GunCon::SetBindState(u32 index, float value)
{
const bool pressed = (value >= 0.5f);
if (index == static_cast<u32>(Button::ShootOffscreen))
{
if (m_shoot_offscreen != pressed)
{
m_shoot_offscreen = pressed;
SetBindState(static_cast<u32>(Button::Trigger), pressed);
}
return;
}
if (pressed)
m_button_state &= ~(u16(1) << s_button_indices[static_cast<u8>(index)]);
else
m_button_state |= u16(1) << s_button_indices[static_cast<u8>(index)];
}
void GunCon::ResetTransferState()
{
m_transfer_state = TransferState::Idle;
}
bool GunCon::Transfer(const u8 data_in, u8* data_out)
{
static constexpr u16 ID = 0x5A63;
switch (m_transfer_state)
{
case TransferState::Idle:
{
*data_out = 0xFF;
if (data_in == 0x01)
{
m_transfer_state = TransferState::Ready;
return true;
}
return false;
}
case TransferState::Ready:
{
if (data_in == 0x42)
{
*data_out = Truncate8(ID);
m_transfer_state = TransferState::IDMSB;
return true;
}
*data_out = 0xFF;
return false;
}
case TransferState::IDMSB:
{
*data_out = Truncate8(ID >> 8);
m_transfer_state = TransferState::ButtonsLSB;
return true;
}
case TransferState::ButtonsLSB:
{
*data_out = Truncate8(m_button_state);
m_transfer_state = TransferState::ButtonsMSB;
return true;
}
case TransferState::ButtonsMSB:
{
*data_out = Truncate8(m_button_state >> 8);
m_transfer_state = TransferState::XLSB;
return true;
}
case TransferState::XLSB:
{
UpdatePosition();
*data_out = Truncate8(m_position_x);
m_transfer_state = TransferState::XMSB;
return true;
}
case TransferState::XMSB:
{
*data_out = Truncate8(m_position_x >> 8);
m_transfer_state = TransferState::YLSB;
return true;
}
case TransferState::YLSB:
{
*data_out = Truncate8(m_position_y);
m_transfer_state = TransferState::YMSB;
return true;
}
case TransferState::YMSB:
{
*data_out = Truncate8(m_position_y >> 8);
m_transfer_state = TransferState::Idle;
return false;
}
default:
{
UnreachableCode();
return false;
}
}
}
void GunCon::UpdatePosition()
{
// get screen coordinates
const s32 mouse_x = g_host_display->GetMousePositionX();
const s32 mouse_y = g_host_display->GetMousePositionY();
// are we within the active display area?
u32 tick, line;
if (mouse_x < 0 || mouse_y < 0 ||
!g_gpu->ConvertScreenCoordinatesToBeamTicksAndLines(mouse_x, mouse_y, m_x_scale, &tick, &line) ||
m_shoot_offscreen)
{
Log_DebugPrintf("Lightgun out of range for window coordinates %d,%d", mouse_x, mouse_y);
m_position_x = 0x01;
m_position_y = 0x0A;
return;
}
// 8MHz units for X = 44100*768*11/7 = 53222400 / 8000000 = 6.6528
const double divider = static_cast<double>(g_gpu->GetCRTCFrequency()) / 8000000.0;
m_position_x = static_cast<u16>(static_cast<float>(tick) / static_cast<float>(divider));
m_position_y = static_cast<u16>(line);
Log_DebugPrintf("Lightgun window coordinates %d,%d -> tick %u line %u 8mhz ticks %u", mouse_x, mouse_y, tick, line,
m_position_x);
}
std::unique_ptr<GunCon> GunCon::Create(u32 index)
{
return std::make_unique<GunCon>(index);
}
static const Controller::ControllerBindingInfo s_binding_info[] = {
#define BUTTON(name, display_name, button, genb) \
{ \
name, display_name, static_cast<u32>(button), Controller::ControllerBindingType::Button, genb \
}
BUTTON("Trigger", "Trigger", GunCon::Button::Trigger, GenericInputBinding::R2),
BUTTON("ShootOffscreen", "ShootOffscreen", GunCon::Button::ShootOffscreen, GenericInputBinding::L2),
BUTTON("A", "A", GunCon::Button::A, GenericInputBinding::Cross),
BUTTON("B", "B", GunCon::Button::B, GenericInputBinding::Circle),
#undef BUTTON
};
static const SettingInfo s_settings[] = {
{SettingInfo::Type::Path, "CrosshairImagePath", TRANSLATABLE("NamcoGunCon", "Crosshair Image Path"),
TRANSLATABLE("NamcoGunCon", "Path to an image to use as a crosshair/cursor.")},
{SettingInfo::Type::Float, "CrosshairScale", TRANSLATABLE("NamcoGunCon", "Crosshair Image Scale"),
TRANSLATABLE("NamcoGunCon", "Scale of crosshair image on screen."), "1.0", "0.0001", "100.0", "0.10"},
{SettingInfo::Type::Float, "XScale", TRANSLATABLE("NamcoGunCon", "X Scale"),
TRANSLATABLE("NamcoGunCon", "Scales X coordinates relative to the center of the screen."), "1.0", "0.01", "2.0",
"0.01"}};
const Controller::ControllerInfo GunCon::INFO = {ControllerType::GunCon,
"GunCon",
TRANSLATABLE("ControllerType", "GunCon"),
s_binding_info,
countof(s_binding_info),
s_settings,
countof(s_settings),
Controller::VibrationCapabilities::NoVibration};
void GunCon::LoadSettings(SettingsInterface& si, const char* section)
{
Controller::LoadSettings(si, section);
std::string path = si.GetStringValue(section, "CrosshairImagePath");
if (path != m_crosshair_image_path)
{
m_crosshair_image_path = std::move(path);
if (m_crosshair_image_path.empty() || !m_crosshair_image.LoadFromFile(m_crosshair_image_path.c_str()))
{
m_crosshair_image.Invalidate();
}
}
#ifndef __ANDROID__
if (!m_crosshair_image.IsValid())
{
m_crosshair_image.SetPixels(Resources::CROSSHAIR_IMAGE_WIDTH, Resources::CROSSHAIR_IMAGE_HEIGHT,
Resources::CROSSHAIR_IMAGE_DATA.data());
}
#endif
m_crosshair_image_scale = si.GetFloatValue(section, "CrosshairScale", 1.0f);
m_x_scale = si.GetFloatValue(section, "XScale", 1.0f);
}
bool GunCon::GetSoftwareCursor(const Common::RGBA8Image** image, float* image_scale, bool* relative_mode)
{
if (!m_crosshair_image.IsValid())
return false;
*image = &m_crosshair_image;
*image_scale = m_crosshair_image_scale;
*relative_mode = false;
return true;
}

View file

@ -4,7 +4,7 @@
#include <optional>
#include <string_view>
class NamcoGunCon final : public Controller
class GunCon final : public Controller
{
public:
enum class Button : u8
@ -16,34 +16,27 @@ public:
Count
};
NamcoGunCon();
~NamcoGunCon() override;
static const Controller::ControllerInfo INFO;
static std::unique_ptr<NamcoGunCon> Create();
static std::optional<s32> StaticGetAxisCodeByName(std::string_view button_name);
static std::optional<s32> StaticGetButtonCodeByName(std::string_view button_name);
static AxisList StaticGetAxisNames();
static ButtonList StaticGetButtonNames();
static u32 StaticGetVibrationMotorCount();
static SettingList StaticGetSettings();
GunCon(u32 index);
~GunCon() override;
static std::unique_ptr<GunCon> Create(u32 index);
ControllerType GetType() const override;
std::optional<s32> GetAxisCodeByName(std::string_view axis_name) const override;
std::optional<s32> GetButtonCodeByName(std::string_view button_name) const override;
void Reset() override;
bool DoState(StateWrapper& sw, bool apply_input_state) override;
void LoadSettings(const char* section) override;
void LoadSettings(SettingsInterface& si, const char* section) override;
bool GetSoftwareCursor(const Common::RGBA8Image** image, float* image_scale, bool* relative_mode) override;
bool GetButtonState(s32 button_code) const override;
void SetButtonState(s32 button_code, bool pressed) override;
float GetBindState(u32 index) const override;
void SetBindState(u32 index, float value) override;
void ResetTransferState() override;
bool Transfer(const u8 data_in, u8* data_out) override;
void SetButtonState(Button button, bool pressed);
private:
void UpdatePosition();

32
src/core/host.cpp Normal file
View file

@ -0,0 +1,32 @@
#include "host.h"
#include "common/string_util.h"
#include <cstdarg>
void Host::ReportFormattedErrorAsync(const std::string_view& title, const char* format, ...)
{
std::va_list ap;
va_start(ap, format);
std::string message(StringUtil::StdStringFromFormatV(format, ap));
va_end(ap);
ReportErrorAsync(title, message);
}
bool Host::ConfirmFormattedMessage(const std::string_view& title, const char* format, ...)
{
std::va_list ap;
va_start(ap, format);
std::string message = StringUtil::StdStringFromFormatV(format, ap);
va_end(ap);
return ConfirmMessage(title, message);
}
void Host::ReportFormattedDebuggerMessage(const char* format, ...)
{
std::va_list ap;
va_start(ap, format);
std::string message = StringUtil::StdStringFromFormatV(format, ap);
va_end(ap);
ReportDebuggerMessage(message);
}

View file

@ -1,12 +1,67 @@
#pragma once
#include "common/string.h"
#include "common/types.h"
#include <ctime>
#include <functional>
#include <memory>
#include <optional>
#include <string>
#include <string_view>
#include <vector>
struct WindowInfo;
enum class AudioBackend : u8;
class AudioStream;
class CDImage;
/// Marks a core string as being translatable.
#define TRANSLATABLE(context, str) str
/// Generic input bindings. These roughly match a DualShock 4 or XBox One controller.
/// They are used for automatic binding to PS2 controller types, and for big picture mode navigation.
enum class GenericInputBinding : u8
{
Unknown,
DPadUp,
DPadRight,
DPadLeft,
DPadDown,
LeftStickUp,
LeftStickRight,
LeftStickDown,
LeftStickLeft,
L3,
RightStickUp,
RightStickRight,
RightStickDown,
RightStickLeft,
R3,
Triangle, // Y on XBox pads.
Circle, // B on XBox pads.
Cross, // A on XBox pads.
Square, // X on XBox pads.
Select, // Share on DS4, View on XBox pads.
Start, // Options on DS4, Menu on XBox pads.
System, // PS button on DS4, Guide button on XBox pads.
L1, // LB on Xbox pads.
L2, // Left trigger on XBox pads.
R1, // RB on XBox pads.
R2, // Right trigger on Xbox pads.
SmallMotor, // High frequency vibration.
LargeMotor, // Low frequency vibration.
Count,
};
namespace Host {
/// Reads a file from the resources directory of the application.
/// This may be outside of the "normal" filesystem on platforms such as Mac.
@ -15,6 +70,18 @@ std::optional<std::vector<u8>> ReadResourceFile(const char* filename);
/// Reads a resource file file from the resources directory as a string.
std::optional<std::string> ReadResourceFileToString(const char* filename);
/// Returns the modified time of a resource.
std::optional<std::time_t> GetResourceFileTimestamp(const char* filename);
/// Translates a string to the current language.
TinyString TranslateString(const char* context, const char* str, const char* disambiguation = nullptr, int n = -1);
std::string TranslateStdString(const char* context, const char* str, const char* disambiguation = nullptr, int n = -1);
std::unique_ptr<AudioStream> CreateAudioStream(AudioBackend backend);
/// Returns the scale of OSD elements.
float GetOSDScale();
/// Adds OSD messages, duration is in seconds.
void AddOSDMessage(std::string message, float duration = 2.0f);
void AddKeyedOSDMessage(std::string key, std::string message, float duration = 2.0f);
@ -26,4 +93,26 @@ void ClearOSDMessages();
/// Displays an asynchronous error on the UI thread, i.e. doesn't block the caller.
void ReportErrorAsync(const std::string_view& title, const std::string_view& message);
void ReportFormattedErrorAsync(const std::string_view& title, const char* format, ...);
/// Displays a synchronous confirmation on the UI thread, i.e. blocks the caller.
bool ConfirmMessage(const std::string_view& title, const std::string_view& message);
bool ConfirmFormattedMessage(const std::string_view& title, const char* format, ...);
/// Debugger feedback.
void ReportDebuggerMessage(const std::string_view& message);
void ReportFormattedDebuggerMessage(const char* format, ...);
/// Displays a loading screen with the logo, rendered with ImGui. Use when executing possibly-time-consuming tasks
/// such as compiling shaders when starting up.
void DisplayLoadingScreen(const char* message, int progress_min = -1, int progress_max = -1, int progress_value = -1);
/// Internal method used by pads to dispatch vibration updates to input sources.
/// Intensity is normalized from 0 to 1.
void SetPadVibrationIntensity(u32 pad_index, float large_or_single_motor_intensity, float small_motor_intensity);
/// Enables "relative" mouse mode, locking the cursor position and returning relative coordinates.
void SetMouseMode(bool relative, bool hide_cursor);
/// Safely executes a function on the VM thread.
void RunOnCPUThread(std::function<void()> function, bool block = false);
} // namespace Host

View file

@ -5,7 +5,6 @@
#include "common/log.h"
#include "common/string_util.h"
#include "common/timer.h"
#include "host_interface.h"
#include "stb_image.h"
#include "stb_image_resize.h"
#include "stb_image_write.h"
@ -16,10 +15,72 @@
#include <vector>
Log_SetChannel(HostDisplay);
std::unique_ptr<HostDisplay> g_host_display;
HostDisplayTexture::~HostDisplayTexture() = default;
HostDisplay::~HostDisplay() = default;
HostDisplay::RenderAPI HostDisplay::GetPreferredAPI()
{
#ifdef _WIN32
return RenderAPI::D3D11;
#else
return RenderAPI::OpenGL;
#endif
}
bool HostDisplay::ParseFullscreenMode(const std::string_view& mode, u32* width, u32* height, float* refresh_rate)
{
if (!mode.empty())
{
std::string_view::size_type sep1 = mode.find('x');
if (sep1 != std::string_view::npos)
{
std::optional<u32> owidth = StringUtil::FromChars<u32>(mode.substr(0, sep1));
sep1++;
while (sep1 < mode.length() && std::isspace(mode[sep1]))
sep1++;
if (owidth.has_value() && sep1 < mode.length())
{
std::string_view::size_type sep2 = mode.find('@', sep1);
if (sep2 != std::string_view::npos)
{
std::optional<u32> oheight = StringUtil::FromChars<u32>(mode.substr(sep1, sep2 - sep1));
sep2++;
while (sep2 < mode.length() && std::isspace(mode[sep2]))
sep2++;
if (oheight.has_value() && sep2 < mode.length())
{
std::optional<float> orefresh_rate = StringUtil::FromChars<float>(mode.substr(sep2));
if (orefresh_rate.has_value())
{
*width = owidth.value();
*height = oheight.value();
*refresh_rate = orefresh_rate.value();
return true;
}
}
}
}
}
}
*width = 0;
*height = 0;
*refresh_rate = 0;
return false;
}
std::string HostDisplay::GetFullscreenModeString(u32 width, u32 height, float refresh_rate)
{
return StringUtil::StdStringFromFormat("%u x %u @ %f hz", width, height, refresh_rate);
}
bool HostDisplay::UsesLowerLeftOrigin() const
{
const RenderAPI api = GetRenderAPI();

View file

@ -62,6 +62,15 @@ public:
virtual ~HostDisplay();
/// Returns the default/preferred API for the system.
static RenderAPI GetPreferredAPI();
/// Parses a fullscreen mode into its components (width * height @ refresh hz)
static bool ParseFullscreenMode(const std::string_view& mode, u32* width, u32* height, float* refresh_rate);
/// Converts a fullscreen mode to a string.
static std::string GetFullscreenModeString(u32 width, u32 height, float refresh_rate);
ALWAYS_INLINE const WindowInfo& GetWindowInfo() const { return m_window_info; }
ALWAYS_INLINE s32 GetWindowWidth() const { return static_cast<s32>(m_window_info.surface_width); }
ALWAYS_INLINE s32 GetWindowHeight() const { return static_cast<s32>(m_window_info.surface_height); }
@ -290,3 +299,25 @@ protected:
bool m_display_integer_scaling = false;
bool m_display_stretch = false;
};
/// Returns a pointer to the current host display abstraction. Assumes AcquireHostDisplay() has been caled.
extern std::unique_ptr<HostDisplay> g_host_display;
namespace Host {
/// Creates the host display. This may create a new window. The API used depends on the current configuration.
bool AcquireHostDisplay(HostDisplay::RenderAPI api);
/// Destroys the host display. This may close the display window.
void ReleaseHostDisplay();
/// Returns false if the window was completely occluded. If frame_skip is set, the frame won't be
/// displayed, but the GPU command queue will still be flushed.
//bool BeginPresentFrame(bool frame_skip);
/// Presents the frame to the display, and renders OSD elements.
//void EndPresentFrame();
/// Provided by the host; renders the display.
void RenderDisplay();
void InvalidateDisplay();
} // namespace Host

File diff suppressed because it is too large Load diff

View file

@ -1,225 +0,0 @@
#pragma once
#include "common/string.h"
#include "common/timer.h"
#include "settings.h"
#include "types.h"
#include <chrono>
#include <deque>
#include <functional>
#include <memory>
#include <mutex>
#include <optional>
#include <string>
#include <vector>
enum LOGLEVEL;
class AudioStream;
class ByteStream;
class CDImage;
class HostDisplay;
class GameList;
struct SystemBootParameters;
namespace BIOS {
struct ImageInfo;
}
class HostInterface
{
public:
enum : u32
{
AUDIO_SAMPLE_RATE = 44100,
AUDIO_CHANNELS = 2,
DEFAULT_AUDIO_BUFFER_SIZE = 2048
};
HostInterface();
virtual ~HostInterface();
/// Access to host display.
ALWAYS_INLINE HostDisplay* GetDisplay() const { return m_display.get(); }
ALWAYS_INLINE bool HasDisplay() const { return static_cast<bool>(m_display.get()); }
/// Access to host audio stream.
ALWAYS_INLINE AudioStream* GetAudioStream() const { return m_audio_stream.get(); }
/// Initializes the emulator frontend.
virtual bool Initialize();
/// Shuts down the emulator frontend.
virtual void Shutdown();
virtual bool BootSystem(std::shared_ptr<SystemBootParameters> parameters);
virtual void PauseSystem(bool paused);
virtual void ResetSystem();
virtual void DestroySystem();
/// Loads state from the specified filename.
bool LoadState(const char* filename);
virtual void ReportError(const char* message);
virtual void ReportMessage(const char* message);
virtual void ReportDebuggerMessage(const char* message);
virtual bool ConfirmMessage(const char* message);
void ReportFormattedError(const char* format, ...) printflike(2, 3);
void ReportFormattedMessage(const char* format, ...) printflike(2, 3);
void ReportFormattedDebuggerMessage(const char* format, ...) printflike(2, 3);
bool ConfirmFormattedMessage(const char* format, ...) printflike(2, 3);
/// Adds OSD messages, duration is in seconds.
virtual void AddOSDMessage(std::string message, float duration = 2.0f) = 0;
virtual void AddKeyedOSDMessage(std::string key, std::string message, float duration = 2.0f) = 0;
virtual void RemoveKeyedOSDMessage(std::string key) = 0;
void AddFormattedOSDMessage(float duration, const char* format, ...) printflike(3, 4);
void AddKeyedFormattedOSDMessage(std::string key, float duration, const char* format, ...) printflike(4, 5);
/// Returns the base user directory path.
ALWAYS_INLINE const std::string& GetUserDirectory() const { return m_user_directory; }
/// Returns a path relative to the user directory.
std::string GetUserDirectoryRelativePath(const char* format, ...) const printflike(2, 3);
/// Returns a path relative to the application directory (for system files).
std::string GetProgramDirectoryRelativePath(const char* format, ...) const printflike(2, 3);
/// Returns a string which can be used as part of a filename, based on the current date/time.
static TinyString GetTimestampStringForFileName();
/// Displays a loading screen with the logo, rendered with ImGui. Use when executing possibly-time-consuming tasks
/// such as compiling shaders when starting up.
virtual void DisplayLoadingScreen(const char* message, int progress_min = -1, int progress_max = -1,
int progress_value = -1) = 0;
/// Retrieves information about specified game from game list.
virtual void GetGameInfo(const char* path, CDImage* image, std::string* code, std::string* title) = 0;
/// Returns the directory where per-game memory cards will be saved.
virtual std::string GetMemoryCardDirectory() const;
/// Returns the default path to a memory card.
virtual std::string GetSharedMemoryCardPath(u32 slot) const;
/// Returns the default path to a memory card for a specific game.
virtual std::string GetGameMemoryCardPath(const char* game_code, u32 slot) const;
/// Returns the path to the shader cache directory.
virtual std::string GetShaderCacheBasePath() const;
/// Returns a setting value from the configuration.
virtual std::string GetStringSettingValue(const char* section, const char* key, const char* default_value = "") = 0;
/// Returns a boolean setting from the configuration.
virtual bool GetBoolSettingValue(const char* section, const char* key, bool default_value = false);
/// Returns an integer setting from the configuration.
virtual int GetIntSettingValue(const char* section, const char* key, int default_value = 0);
/// Returns a float setting from the configuration.
virtual float GetFloatSettingValue(const char* section, const char* key, float default_value = 0.0f);
/// Returns a string list from the configuration.
virtual std::vector<std::string> GetSettingStringList(const char* section, const char* key) = 0;
/// Returns the settings interface.
virtual SettingsInterface* GetSettingsInterface() = 0;
virtual std::lock_guard<std::recursive_mutex> GetSettingsLock() = 0;
/// Translates a string to the current language.
virtual TinyString TranslateString(const char* context, const char* str, const char* disambiguation = nullptr,
int n = -1) const;
virtual std::string TranslateStdString(const char* context, const char* str, const char* disambiguation = nullptr,
int n = -1) const;
/// Returns the path to the directory to search for BIOS images.
virtual std::string GetBIOSDirectory();
/// Loads the BIOS image for the specified region.
std::optional<std::vector<u8>> GetBIOSImage(ConsoleRegion region);
/// Searches for a BIOS image for the specified region in the specified directory. If no match is found, the first
/// BIOS image within 512KB and 4MB will be used.
std::optional<std::vector<u8>> FindBIOSImageInDirectory(ConsoleRegion region, const char* directory);
/// Returns a list of filenames and descriptions for BIOS images in a directory.
std::vector<std::pair<std::string, const BIOS::ImageInfo*>> FindBIOSImagesInDirectory(const char* directory);
/// Returns true if any BIOS images are found in the configured BIOS directory.
bool HasAnyBIOSImages();
/// Opens a file in the DuckStation "package".
/// This is the APK for Android builds, or the program directory for standalone builds.
virtual std::unique_ptr<ByteStream> OpenPackageFile(const char* path, u32 flags) = 0;
virtual void OnRunningGameChanged(const std::string& path, CDImage* image, const std::string& game_code,
const std::string& game_title) = 0;
virtual void OnSystemPerformanceCountersUpdated() = 0;
/// Called when the display is invalidated (e.g. a state is loaded).
virtual void OnDisplayInvalidated() = 0;
/// Called when achievements data is loaded.
virtual void OnAchievementsRefreshed() = 0;
protected:
virtual bool AcquireHostDisplay() = 0;
virtual void ReleaseHostDisplay() = 0;
virtual std::unique_ptr<AudioStream> CreateAudioStream(AudioBackend backend) = 0;
virtual s32 GetAudioOutputVolume() const;
virtual void OnSystemCreated() = 0;
virtual void OnSystemPaused(bool paused) = 0;
virtual void OnSystemDestroyed() = 0;
virtual void OnControllerTypeChanged(u32 slot) = 0;
/// Restores all settings to defaults.
virtual void SetDefaultSettings(SettingsInterface& si);
/// Loads settings to m_settings and any frontend-specific parameters.
virtual void LoadSettings(SettingsInterface& si);
/// Saves current settings variables to ini.
virtual void SaveSettings(SettingsInterface& si);
/// Checks and fixes up any incompatible settings.
virtual void FixIncompatibleSettings(bool display_osd_messages);
/// Checks for settings changes, std::move() the old settings away for comparing beforehand.
virtual void CheckForSettingsChanges(const Settings& old_settings);
/// Switches the GPU renderer by saving state, recreating the display window, and restoring state (if needed).
virtual void RecreateSystem();
/// Enables "relative" mouse mode, locking the cursor position and returning relative coordinates.
virtual void SetMouseMode(bool relative, bool hide_cursor) = 0;
/// Call when host display size changes, use with "match display" aspect ratio setting.
virtual void OnHostDisplayResized();
/// Sets the user directory to the program directory, i.e. "portable mode".
void SetUserDirectoryToProgramDirectory();
/// Quick switch between software and hardware rendering.
void ToggleSoftwareRendering();
/// Adjusts the internal (render) resolution of the hardware backends.
void ModifyResolutionScale(s32 increment);
/// Updates software cursor state, based on controllers.
void UpdateSoftwareCursor();
bool SaveState(const char* filename);
void CreateAudioStream();
std::unique_ptr<HostDisplay> m_display;
std::unique_ptr<AudioStream> m_audio_stream;
std::string m_program_directory;
std::string m_user_directory;
};
#define TRANSLATABLE(context, str) str
extern HostInterface* g_host_interface;

View file

@ -1,10 +1,14 @@
#include "host_interface_progress_callback.h"
#include "common/log.h"
#include "host.h"
Log_SetChannel(HostInterfaceProgressCallback);
HostInterfaceProgressCallback::HostInterfaceProgressCallback() : BaseProgressCallback() {}
void HostInterfaceProgressCallback::PushState() { BaseProgressCallback::PushState(); }
void HostInterfaceProgressCallback::PushState()
{
BaseProgressCallback::PushState();
}
void HostInterfaceProgressCallback::PopState()
{
@ -57,32 +61,42 @@ void HostInterfaceProgressCallback::Redraw(bool force)
return;
m_last_progress_percent = percent;
g_host_interface->DisplayLoadingScreen(m_status_text, 0, static_cast<int>(m_progress_range),
static_cast<int>(m_progress_value));
Host::DisplayLoadingScreen(m_status_text, 0, static_cast<int>(m_progress_range), static_cast<int>(m_progress_value));
}
void HostInterfaceProgressCallback::DisplayError(const char* message) { Log_ErrorPrint(message); }
void HostInterfaceProgressCallback::DisplayError(const char* message)
{
Log_ErrorPrint(message);
}
void HostInterfaceProgressCallback::DisplayWarning(const char* message) { Log_WarningPrint(message); }
void HostInterfaceProgressCallback::DisplayWarning(const char* message)
{
Log_WarningPrint(message);
}
void HostInterfaceProgressCallback::DisplayInformation(const char* message) { Log_InfoPrint(message); }
void HostInterfaceProgressCallback::DisplayInformation(const char* message)
{
Log_InfoPrint(message);
}
void HostInterfaceProgressCallback::DisplayDebugMessage(const char* message) { Log_DevPrint(message); }
void HostInterfaceProgressCallback::DisplayDebugMessage(const char* message)
{
Log_DevPrint(message);
}
void HostInterfaceProgressCallback::ModalError(const char* message)
{
Log_ErrorPrint(message);
g_host_interface->ReportError(message);
Host::ReportErrorAsync("Error", message);
}
bool HostInterfaceProgressCallback::ModalConfirmation(const char* message)
{
Log_InfoPrint(message);
return g_host_interface->ConfirmMessage(message);
return Host::ConfirmMessage("Confirm", message);
}
void HostInterfaceProgressCallback::ModalInformation(const char* message)
{
Log_InfoPrint(message);
g_host_interface->ReportMessage(message);
}

View file

@ -1,6 +1,5 @@
#pragma once
#include "common/progress_callback.h"
#include "host_interface.h"
class HostInterfaceProgressCallback final : public BaseProgressCallback
{

View file

@ -18,13 +18,16 @@ double GetBaseDoubleSettingValue(const char* section, const char* key, double de
std::vector<std::string> GetBaseStringListSetting(const char* section, const char* key);
// Allows the emucore to write settings back to the frontend. Use with care.
// You should call CommitBaseSettingChanges() after finishing writing, or it may not be written to disk.
// You should call CommitBaseSettingChanges() if you directly write to the layer (i.e. not these functions), or it may
// not be written to disk.
void SetBaseBoolSettingValue(const char* section, const char* key, bool value);
void SetBaseIntSettingValue(const char* section, const char* key, s32 value);
void SetBaseUIntSettingValue(const char* section, const char* key, u32 value);
void SetBaseFloatSettingValue(const char* section, const char* key, float value);
void SetBaseStringSettingValue(const char* section, const char* key, const char* value);
void SetBaseStringListSettingValue(const char* section, const char* key, const std::vector<std::string>& values);
bool AddValueToBaseStringListSetting(const char* section, const char* key, const char* value);
bool RemoveValueFromBaseStringListSetting(const char* section, const char* key, const char* value);
void DeleteBaseSettingValue(const char* section, const char* key);
void CommitBaseSettingChanges();

View file

@ -1,56 +0,0 @@
#include "imgui_styles.h"
void ImGui::StyleColorsDarker(ImGuiStyle* dst)
{
ImGuiStyle* style = dst ? dst : &ImGui::GetStyle();
ImVec4* colors = style->Colors;
colors[ImGuiCol_Text] = ImVec4(0.95f, 0.96f, 0.98f, 1.00f);
colors[ImGuiCol_TextDisabled] = ImVec4(0.36f, 0.42f, 0.47f, 1.00f);
colors[ImGuiCol_WindowBg] = ImVec4(0.11f, 0.15f, 0.17f, 1.00f);
colors[ImGuiCol_ChildBg] = ImVec4(0.15f, 0.18f, 0.22f, 1.00f);
colors[ImGuiCol_PopupBg] = ImVec4(0.08f, 0.08f, 0.08f, 0.94f);
colors[ImGuiCol_Border] = ImVec4(0.08f, 0.10f, 0.12f, 1.00f);
colors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
colors[ImGuiCol_FrameBg] = ImVec4(0.20f, 0.25f, 0.29f, 1.00f);
colors[ImGuiCol_FrameBgHovered] = ImVec4(0.12f, 0.20f, 0.28f, 1.00f);
colors[ImGuiCol_FrameBgActive] = ImVec4(0.09f, 0.12f, 0.14f, 1.00f);
colors[ImGuiCol_TitleBg] = ImVec4(0.09f, 0.12f, 0.14f, 0.65f);
colors[ImGuiCol_TitleBgActive] = ImVec4(0.08f, 0.10f, 0.12f, 1.00f);
colors[ImGuiCol_TitleBgCollapsed] = ImVec4(0.00f, 0.00f, 0.00f, 0.51f);
colors[ImGuiCol_MenuBarBg] = ImVec4(0.15f, 0.18f, 0.22f, 1.00f);
colors[ImGuiCol_ScrollbarBg] = ImVec4(0.02f, 0.02f, 0.02f, 0.39f);
colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.20f, 0.25f, 0.29f, 1.00f);
colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.18f, 0.22f, 0.25f, 1.00f);
colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.09f, 0.21f, 0.31f, 1.00f);
colors[ImGuiCol_CheckMark] = ImVec4(0.28f, 0.56f, 1.00f, 1.00f);
colors[ImGuiCol_SliderGrab] = ImVec4(0.28f, 0.56f, 1.00f, 1.00f);
colors[ImGuiCol_SliderGrabActive] = ImVec4(0.37f, 0.61f, 1.00f, 1.00f);
colors[ImGuiCol_Button] = ImVec4(0.20f, 0.25f, 0.29f, 1.00f);
colors[ImGuiCol_ButtonHovered] = ImVec4(0.33f, 0.38f, 0.46f, 1.00f);
colors[ImGuiCol_ButtonActive] = ImVec4(0.27f, 0.32f, 0.38f, 1.00f);
colors[ImGuiCol_Header] = ImVec4(0.20f, 0.25f, 0.29f, 0.55f);
colors[ImGuiCol_HeaderHovered] = ImVec4(0.33f, 0.38f, 0.46f, 1.00f);
colors[ImGuiCol_HeaderActive] = ImVec4(0.27f, 0.32f, 0.38f, 1.00f);
colors[ImGuiCol_Separator] = ImVec4(0.20f, 0.25f, 0.29f, 1.00f);
colors[ImGuiCol_SeparatorHovered] = ImVec4(0.33f, 0.38f, 0.46f, 1.00f);
colors[ImGuiCol_SeparatorActive] = ImVec4(0.27f, 0.32f, 0.38f, 1.00f);
colors[ImGuiCol_ResizeGrip] = ImVec4(0.26f, 0.59f, 0.98f, 0.25f);
colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.33f, 0.38f, 0.46f, 1.00f);
colors[ImGuiCol_ResizeGripActive] = ImVec4(0.27f, 0.32f, 0.38f, 1.00f);
colors[ImGuiCol_Tab] = ImVec4(0.11f, 0.15f, 0.17f, 1.00f);
colors[ImGuiCol_TabHovered] = ImVec4(0.33f, 0.38f, 0.46f, 1.00f);
colors[ImGuiCol_TabActive] = ImVec4(0.27f, 0.32f, 0.38f, 1.00f);
colors[ImGuiCol_TabUnfocused] = ImVec4(0.11f, 0.15f, 0.17f, 1.00f);
colors[ImGuiCol_TabUnfocusedActive] = ImVec4(0.11f, 0.15f, 0.17f, 1.00f);
colors[ImGuiCol_PlotLines] = ImVec4(0.61f, 0.61f, 0.61f, 1.00f);
colors[ImGuiCol_PlotLinesHovered] = ImVec4(1.00f, 0.43f, 0.35f, 1.00f);
colors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f);
colors[ImGuiCol_PlotHistogramHovered] = ImVec4(1.00f, 0.60f, 0.00f, 1.00f);
colors[ImGuiCol_TextSelectedBg] = ImVec4(0.26f, 0.59f, 0.98f, 0.35f);
colors[ImGuiCol_DragDropTarget] = ImVec4(1.00f, 1.00f, 0.00f, 0.90f);
colors[ImGuiCol_NavHighlight] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);
colors[ImGuiCol_NavWindowingHighlight] = ImVec4(1.00f, 1.00f, 1.00f, 0.70f);
colors[ImGuiCol_NavWindowingDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.20f);
colors[ImGuiCol_ModalWindowDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.35f);
}

Some files were not shown because too many files have changed in this diff Show more