mirror of https://github.com/mgba-emu/mgba.git
Merge branch 'master' into port/psp2
This commit is contained in:
commit
abcc83f68c
16
CHANGES
16
CHANGES
|
@ -27,8 +27,11 @@ Features:
|
|||
- Undo-able savestate loading and saving
|
||||
- Controller profiles now store shortcut settings
|
||||
- Default controller profiles for several common controllers
|
||||
- Libretro now supports BIOS and rumble
|
||||
- Libretro now supports BIOS, rumble and solar sensor
|
||||
- Implement BIOS call Stop, for sleep mode
|
||||
- Automatically load patches, if found
|
||||
- Improved video synchronization
|
||||
- Configurable audio output sample rate
|
||||
Bugfixes:
|
||||
- ARM7: Fix SWI and IRQ timings
|
||||
- GBA Audio: Force audio FIFOs to 32-bit
|
||||
|
@ -64,6 +67,11 @@ Bugfixes:
|
|||
- Qt: Fix a missing va_end call in the log handler lambda within the GameController constructor
|
||||
- GBA Cheats: Fix Pro Action Replay and GameShark issues when used together
|
||||
- Qt: Fix analog buttons not getting unmapped
|
||||
- GBA Video: Prevent tiles < 512 from being used in modes 3 - 5
|
||||
- Qt: Fix passing command line options
|
||||
- Qt: Fix crashes on Windows by using using QMetaObject to do cross-thread calls
|
||||
- GBA Video: Fix timing on first scanline
|
||||
- GBA: Ensure cycles never go negative
|
||||
Misc:
|
||||
- Qt: Handle saving input settings better
|
||||
- Debugger: Free watchpoints in addition to breakpoints
|
||||
|
@ -109,6 +117,12 @@ Misc:
|
|||
- GBA Input: Allow axes and buttons to be mapped to the same key
|
||||
- GBA BIOS: Stub out SoundBias
|
||||
- Qt: Gamepads can now have both buttons and analog axes mapped to the same key
|
||||
- Qt: Increase usability of key mapper
|
||||
- Qt: Show checkmark for window sizes
|
||||
- Qt: Set window path to loaded ROM
|
||||
- GBA Memory: Run multiple DMAs in a tight loop if they all occur before present
|
||||
- GBA Audio: Process multiple audio events at once, if necessary
|
||||
- GBA: Process multiple timer events at once, if necessary
|
||||
|
||||
0.2.1: (2015-05-13)
|
||||
Bugfixes:
|
||||
|
|
|
@ -21,6 +21,7 @@ set(BUILD_PERF OFF CACHE BOOL "Build performance profiling tool")
|
|||
set(BUILD_STATIC OFF CACHE BOOL "Build a static library")
|
||||
set(BUILD_SHARED ON CACHE BOOL "Build a shared library")
|
||||
set(BUILD_GL ON CACHE STRING "Build with OpenGL")
|
||||
set(BUILD_GLES2 OFF CACHE STRING "Build with OpenGL|ES 2")
|
||||
file(GLOB ARM_SRC ${CMAKE_SOURCE_DIR}/src/arm/*.c)
|
||||
file(GLOB GBA_SRC ${CMAKE_SOURCE_DIR}/src/gba/*.c)
|
||||
file(GLOB GBA_CHEATS_SRC ${CMAKE_SOURCE_DIR}/src/gba/cheats/*.c)
|
||||
|
@ -44,13 +45,17 @@ if(NOT CMAKE_BUILD_TYPE)
|
|||
set(CMAKE_BUILD_TYPE Release CACHE STRING "Build type (e.g. Release or Debug)" FORCE)
|
||||
endif()
|
||||
|
||||
set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${LIBDIR}")
|
||||
|
||||
include(GNUInstallDirs)
|
||||
|
||||
if (NOT DEFINED LIBDIR)
|
||||
set(LIBDIR "lib")
|
||||
endif()
|
||||
|
||||
set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${LIBDIR}")
|
||||
|
||||
include(GNUInstallDirs)
|
||||
if (NOT DEFINED MANDIR)
|
||||
set(MANDIR ${CMAKE_INSTALL_MANDIR})
|
||||
endif()
|
||||
|
||||
# Function definitions
|
||||
include(FindPkgConfig)
|
||||
|
@ -126,7 +131,14 @@ endif()
|
|||
if(BUILD_GL)
|
||||
find_package(OpenGL QUIET)
|
||||
if(NOT OPENGL_FOUND)
|
||||
set(BUILD_GL OFF)
|
||||
set(BUILD_GL OFF CACHE BOOL "OpenGL not found" FORCE)
|
||||
endif()
|
||||
endif()
|
||||
if(BUILD_GLES2 AND NOT BUILD_RASPI)
|
||||
find_path(OPENGLES2_INCLUDE_DIR NAMES GLES2/gl2.h)
|
||||
find_library(OPENGLES2_LIBRARY NAMES GLESv2 GLESv2_CM)
|
||||
if(NOT OPENGLES2_INCLUDE_DIR OR NOT OPENGLES2_LIBRARY)
|
||||
set(BUILD_GLES2 OFF CACHE BOOL "OpenGL|ES 2 not found" FORCE)
|
||||
endif()
|
||||
endif()
|
||||
find_feature(USE_FFMPEG "libavcodec;libavformat;libavresample;libavutil;libswscale")
|
||||
|
@ -177,6 +189,10 @@ if(BUILD_BBB OR BUILD_RASPI OR BUILD_PANDORA)
|
|||
endif()
|
||||
endif()
|
||||
|
||||
if(BUILD_RASPI)
|
||||
set(BUILD_GL OFF CACHE BOOL "OpenGL not supported" FORCE)
|
||||
endif()
|
||||
|
||||
if(BUILD_PANDORA)
|
||||
add_definitions(-DBUILD_PANDORA)
|
||||
endif()
|
||||
|
@ -371,6 +387,7 @@ endif()
|
|||
|
||||
if(BUILD_SHARED)
|
||||
add_library(${BINARY_NAME} SHARED ${SRC})
|
||||
set_target_properties(${BINARY_NAME} PROPERTIES SOVERSION ${LIB_VERSION_ABI})
|
||||
if(BUILD_STATIC)
|
||||
add_library(${BINARY_NAME}-static STATIC ${SRC})
|
||||
set_target_properties(${BINARY_NAME}-static PROPERTIES COMPILE_DEFINITIONS "${FEATURE_DEFINES}")
|
||||
|
@ -384,7 +401,7 @@ endif()
|
|||
add_dependencies(${BINARY_NAME} version-info)
|
||||
|
||||
target_link_libraries(${BINARY_NAME} ${DEBUGGER_LIB} ${DEPENDENCY_LIB} ${OS_LIB})
|
||||
install(TARGETS ${BINARY_NAME} DESTINATION ${LIBDIR} COMPONENT lib${BINARY_NAME})
|
||||
install(TARGETS ${BINARY_NAME} LIBRARY DESTINATION ${LIBDIR} COMPONENT lib${BINARY_NAME} NAMELINK_SKIP ARCHIVE DESTINATION ${LIBDIR} RUNTIME DESTINATION ${LIBDIR} COMPONENT lib${BINARY_NAME})
|
||||
if(UNIX AND NOT APPLE)
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/res/mgba-16.png DESTINATION share/icons/hicolor/16x16/apps RENAME mgba.png COMPONENT lib${BINARY_NAME})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/res/mgba-24.png DESTINATION share/icons/hicolor/24x24/apps RENAME mgba.png COMPONENT lib${BINARY_NAME})
|
||||
|
@ -402,6 +419,10 @@ if(BUILD_GL)
|
|||
add_definitions(-DBUILD_GL)
|
||||
endif()
|
||||
|
||||
if(BUILD_GLES2)
|
||||
add_definitions(-DBUILD_GLES2)
|
||||
endif()
|
||||
|
||||
if(BUILD_LIBRETRO)
|
||||
file(GLOB RETRO_SRC ${CMAKE_SOURCE_DIR}/src/platform/libretro/*.c)
|
||||
add_library(${BINARY_NAME}_libretro SHARED ${CORE_SRC} ${RETRO_SRC})
|
||||
|
|
|
@ -30,13 +30,12 @@ The ports are vaguely usable, but by no means should be considered stable.
|
|||
|
||||
### PS Vita (port/psp2)
|
||||
* Add menu
|
||||
* Add audio
|
||||
* Fix audio
|
||||
* Make it faster
|
||||
* Threaded renderer shim
|
||||
* Hardware acceleration
|
||||
|
||||
### Wii (port/wii)
|
||||
* Add menu
|
||||
* Add audio
|
||||
* Thread support
|
||||
* Clean up video detection
|
||||
|
|
|
@ -126,8 +126,6 @@ Footnotes
|
|||
- OBJ window for modes 3, 4 and 5 ([Bug #5](http://mgba.io/b/5))
|
||||
- Mosaic for transformed OBJs ([Bug #9](http://mgba.io/b/9))
|
||||
- BIOS call RegisterRamReset is partially stubbed out ([Bug #141](http://mgba.io/b/141))
|
||||
- Game Pak prefetch ([Bug #195](http://mgba.io/b/195))
|
||||
- BIOS call Stop, for entering sleep mode ([Bug #199](http://mgba.io/b/199))
|
||||
|
||||
<a name="flashdetect">[2]</a> Flash memory size detection does not work in some cases. These can be configured at runtime, but filing a bug is recommended if such a case is encountered.
|
||||
|
||||
|
|
|
@ -0,0 +1,118 @@
|
|||
.\" Copyright (c) 2015 Anthony J. Bentley <anthony@anjbe.name>
|
||||
.\"
|
||||
.\" This Source Code Form is subject to the terms of the Mozilla Public
|
||||
.\" License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
.\" file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
.Dd July 29, 2015
|
||||
.Dt MGBA-QT 6
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm mgba-qt
|
||||
.Nd Game Boy Advance emulator
|
||||
.Sh SYNOPSIS
|
||||
.Nm mgba-qt
|
||||
.Op Fl b Ar biosfile
|
||||
.Op Fl l Ar loglevel
|
||||
.Op Fl p Ar patchfile
|
||||
.Op Fl s Ar n
|
||||
.Ar file
|
||||
.Sh DESCRIPTION
|
||||
.Nm
|
||||
is a Game Boy Advance emulator.
|
||||
The options are as follows:
|
||||
.Bl -tag -width Ds
|
||||
.It Fl b Ar biosfile , Fl -bios Ar biosfile
|
||||
Specify a BIOS file to use during boot.
|
||||
If this flag is omitted,
|
||||
.Nm
|
||||
will use the BIOS specified in the configuration file,
|
||||
or a high\(hylevel emulated BIOS if none is specified.
|
||||
.It Fl l Ar loglevel
|
||||
Log messages during emulation.
|
||||
.Ar loglevel
|
||||
is a bitmask defining which types of messages to log:
|
||||
.Bl -bullet -compact
|
||||
.It
|
||||
1 \(en fatal errors
|
||||
.It
|
||||
2 \(en errors
|
||||
.It
|
||||
4 \(en warnings
|
||||
.It
|
||||
8 \(en informative messages
|
||||
.It
|
||||
16 \(en debugging messages
|
||||
.It
|
||||
32 \(en stub messages for unimplemented features
|
||||
.It
|
||||
256 \(en in\(hygame errors
|
||||
.It
|
||||
512 \(en software interrupts
|
||||
.It
|
||||
1024 \(en emulator status messages
|
||||
.It
|
||||
2048 \(en serial I/O messages
|
||||
.El
|
||||
The default is to log warnings, errors, fatal errors, and status messages.
|
||||
.It Fl p Ar patchfile , Fl -patch Ar patchfile
|
||||
Specify a patch file in BPS, IPS, or UPS format.
|
||||
.It Fl s Ar n , Fl -frameskip Ar n
|
||||
Skip every
|
||||
.Ar n
|
||||
frames.
|
||||
.El
|
||||
.Sh CONTROLS
|
||||
The default controls are as follows:
|
||||
.Bl -hang -width "Frame advance" -compact
|
||||
.It A
|
||||
.Cm x
|
||||
.It B
|
||||
.Cm z
|
||||
.It L
|
||||
.Cm a
|
||||
.It R
|
||||
.Cm s
|
||||
.It Start
|
||||
.Aq Cm Enter
|
||||
.It Select
|
||||
.Aq Cm Backspace
|
||||
.It Load state
|
||||
.Cm F1 Ns \(en Ns Cm F9
|
||||
.It Save state
|
||||
.Ao Cm Shift Ac Ns \(hy Ns Cm F1 Ns \(en Ns Cm F9
|
||||
.It Frame advance
|
||||
.Ao Cm Ctrl Ac Ns \(hy Ns Cm n
|
||||
.El
|
||||
.Sh FILES
|
||||
.Bl -tag -width ~/.config/mgba/config.ini -compact
|
||||
.It Pa ~/.config/mgba/config.ini
|
||||
Default
|
||||
.Xr mgba 6
|
||||
configuration file.
|
||||
.It Pa ~/.config/mgba/qt.ini
|
||||
Default
|
||||
.Nm mgba-qt
|
||||
configuration file.
|
||||
.It Pa portable.ini
|
||||
If this file exists in the current directory,
|
||||
.Nm
|
||||
will read
|
||||
.Pa config.ini
|
||||
and
|
||||
.Pa qt.ini
|
||||
from the current directory instead of
|
||||
.Pa ~/.config/mgba .
|
||||
.El
|
||||
.Sh AUTHORS
|
||||
.An Jeffrey Pfau Aq Mt jeffrey@endrift.com
|
||||
.Sh HOMEPAGE
|
||||
.Bl -bullet
|
||||
.It
|
||||
.Lk https://mgba.io/ "mGBA homepage"
|
||||
.It
|
||||
.Lk https://github.com/mgba-emu/mgba "Development repository"
|
||||
.It
|
||||
.Lk https://github.com/mgba-emu/mgba/issues "Bug tracker"
|
||||
.It
|
||||
.Lk https://forums.mgba.io/ "Message board"
|
||||
.El
|
|
@ -0,0 +1,259 @@
|
|||
.\" Copyright (c) 2015 Anthony J. Bentley <anthony@anjbe.name>
|
||||
.\"
|
||||
.\" This Source Code Form is subject to the terms of the Mozilla Public
|
||||
.\" License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
.\" file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
.Dd July 29, 2015
|
||||
.Dt MGBA 6
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm mgba
|
||||
.Nd Game Boy Advance emulator
|
||||
.Sh SYNOPSIS
|
||||
.Nm mgba
|
||||
.Op Fl 123456dfg
|
||||
.Op Fl b Ar biosfile
|
||||
.Op Fl c Ar cheatfile
|
||||
.Op Fl l Ar loglevel
|
||||
.Op Fl p Ar patchfile
|
||||
.Op Fl s Ar n
|
||||
.Op Fl v Ar moviefile
|
||||
.Ar file
|
||||
.Sh DESCRIPTION
|
||||
.Nm
|
||||
is a Game Boy Advance emulator.
|
||||
The options are as follows:
|
||||
.Bl -tag -width Ds
|
||||
.It Fl 1
|
||||
Scale the window 1\(mu.
|
||||
.It Fl 2
|
||||
Scale the window 2\(mu.
|
||||
.It Fl 3
|
||||
Scale the window 3\(mu.
|
||||
.It Fl 4
|
||||
Scale the window 4\(mu.
|
||||
.It Fl 5
|
||||
Scale the window 5\(mu.
|
||||
.It Fl 6
|
||||
Scale the window 6\(mu.
|
||||
.It Fl b Ar biosfile , Fl -bios Ar biosfile
|
||||
Specify a BIOS file to use during boot.
|
||||
If this flag is omitted,
|
||||
.Nm
|
||||
will use the BIOS specified in the configuration file,
|
||||
or a high\(hylevel emulated BIOS if none is specified.
|
||||
.It Fl c Ar cheatfile , Fl -cheats Ar cheatfile
|
||||
Apply cheat codes from
|
||||
.Ar cheatfile .
|
||||
.It Fl d
|
||||
Start emulating via the command\(hyline debugger.
|
||||
.It Fl f
|
||||
Start the emulator full\(hyscreen.
|
||||
.It Fl g
|
||||
Start a
|
||||
.Xr gdb 1
|
||||
session.
|
||||
By default the session starts on port 2345.
|
||||
.It Fl l Ar loglevel
|
||||
Log messages during emulation to
|
||||
.Dv stdout .
|
||||
.Ar loglevel
|
||||
is a bitmask defining which types of messages to log:
|
||||
.Bl -bullet -compact
|
||||
.It
|
||||
1 \(en fatal errors
|
||||
.It
|
||||
2 \(en errors
|
||||
.It
|
||||
4 \(en warnings
|
||||
.It
|
||||
8 \(en informative messages
|
||||
.It
|
||||
16 \(en debugging messages
|
||||
.It
|
||||
32 \(en stub messages for unimplemented features
|
||||
.It
|
||||
256 \(en in\(hygame errors
|
||||
.It
|
||||
512 \(en software interrupts
|
||||
.It
|
||||
1024 \(en emulator status messages
|
||||
.It
|
||||
2048 \(en serial I/O messages
|
||||
.El
|
||||
The default is to log warnings, errors, fatal errors, and status messages.
|
||||
.It Fl p Ar patchfile , Fl -patch Ar patchfile
|
||||
Specify a patch file in BPS, IPS, or UPS format.
|
||||
.It Fl s Ar n , Fl -frameskip Ar n
|
||||
Skip every
|
||||
.Ar n
|
||||
frames.
|
||||
.It Fl v Ar moviefile , Fl -movie Ar moviefile
|
||||
Play back a movie of recording input from
|
||||
.Ar moviefile .
|
||||
.El
|
||||
.Sh CONTROLS
|
||||
The default controls are as follows:
|
||||
.Bl -hang -width "Frame advance" -compact
|
||||
.It A
|
||||
.Cm x
|
||||
.It B
|
||||
.Cm z
|
||||
.It L
|
||||
.Cm a
|
||||
.It R
|
||||
.Cm s
|
||||
.It Start
|
||||
.Aq Cm Enter
|
||||
.It Select
|
||||
.Aq Cm Backspace
|
||||
.It Load state
|
||||
.Cm F1 Ns \(en Ns Cm F9
|
||||
.It Save state
|
||||
.Ao Cm Shift Ac Ns \(hy Ns Cm F1 Ns \(en Ns Cm F9
|
||||
.It Frame advance
|
||||
.Ao Cm Ctrl Ac Ns \(hy Ns Cm n
|
||||
.El
|
||||
.Sh DEBUGGER
|
||||
When
|
||||
.Nm
|
||||
is run with the
|
||||
.Fl d
|
||||
option, the command\(hyline debugger is enabled.
|
||||
It supports the following commands:
|
||||
.Pp
|
||||
.Bl -tag -compact -width 1
|
||||
.It Cm b Ns Oo Cm reak Oc Ar address
|
||||
.It Cm b Ns Oo Cm reak Oc Ns Cm /a Ar address
|
||||
.It Cm b Ns Oo Cm reak Oc Ns Cm /t Ar address
|
||||
Set a breakpoint \(en ARM
|
||||
.Pq Ql /a ,
|
||||
Thumb
|
||||
.Pq Ql /t ,
|
||||
or the current CPU mode \(en at
|
||||
.Ar address .
|
||||
.It Cm c Ns Op Cm ontinue
|
||||
Continue execution.
|
||||
.It Cm d Ns Oo Cm elete Oc Ar address
|
||||
Delete a breakpoint at
|
||||
.Ar address .
|
||||
.It Cm dis Ns Oo Cm asm Oc Op Ar address Op Ar count
|
||||
.It Cm dis Ns Oo Cm asm Oc Ns Cm /a Op Ar address Op Ar count
|
||||
.It Cm dis Ns Oo Cm asm Oc Ns Cm /t Op Ar address Op Ar count
|
||||
.It Cm dis Ns Oo Cm assemble Oc Op Ar address Op Ar count
|
||||
.It Cm dis Ns Oo Cm assemble Oc Ns Cm /a Op Ar address Op Ar count
|
||||
.It Cm dis Ns Oo Cm assemble Oc Ns Cm /t Op Ar address Op Ar count
|
||||
Disassemble
|
||||
.Ar count
|
||||
instructions starting at
|
||||
.Ar address ,
|
||||
as ARM
|
||||
.Pq Ql /a ,
|
||||
Thumb
|
||||
.Pq Ql /t ,
|
||||
or the current CPU mode.
|
||||
If
|
||||
.Ar count
|
||||
is not specified, only disassemble the instruction at
|
||||
.Ar address .
|
||||
If
|
||||
.Ar address
|
||||
is not specified, only disassemble the current address.
|
||||
.It Cm h Ns Op Cm elp
|
||||
Print help.
|
||||
.It Cm i Ns Op Cm nfo
|
||||
.It Cm status
|
||||
Print the current contents of general\(hypurpose registers and the current
|
||||
program state register, and disassemble the current instruction.
|
||||
.It Cm n Ns Op Cm ext
|
||||
Execute the next instruction.
|
||||
.It Cm p Ns Oo Cm rint Oc Ar value ...
|
||||
.It Cm p Ns Oo Cm rint Oc Ns Cm /t Ar value ...
|
||||
.It Cm p Ns Oo Cm rint Oc Ns Cm /x Ar value ...
|
||||
Print one or more
|
||||
.Ar value Ns s
|
||||
as binary
|
||||
.Pq Ql /t ,
|
||||
hexadecimal
|
||||
.Pq Ql /x ,
|
||||
or decimal.
|
||||
.It Cm q Ns Op Cm uit
|
||||
Quit the emulator.
|
||||
.It Cm reset
|
||||
Reset the emulation.
|
||||
.It Cm r/1 Ar address
|
||||
.It Cm r/2 Ar address
|
||||
.It Cm r/4 Ar address
|
||||
Read a byte
|
||||
.Pq Ql /1 ,
|
||||
halfword
|
||||
.Pq Ql /2 ,
|
||||
or word
|
||||
.Pq Ql /4
|
||||
from
|
||||
.Ar address .
|
||||
.It Cm w Ns Oo Cm atch Oc Ar address
|
||||
Set a watchpoint at
|
||||
.Ar address .
|
||||
.It Cm w/1 Ar address data
|
||||
.It Cm w/2 Ar address data
|
||||
.It Cm w/4 Ar address data
|
||||
Write
|
||||
.Ar data
|
||||
as a byte
|
||||
.Pq Ql /1 ,
|
||||
halfword
|
||||
.Pq Ql /2 ,
|
||||
or word
|
||||
.Pq Ql /4
|
||||
to
|
||||
.Ar address .
|
||||
.It Cm w/r Ar register data
|
||||
Write
|
||||
.Ar data
|
||||
as a word to
|
||||
.Ar register .
|
||||
.It Cm x/1 Ar address Op Ar count
|
||||
.It Cm x/2 Ar address Op Ar count
|
||||
.It Cm x/4 Ar address Op Ar count
|
||||
Examine
|
||||
.Ar count
|
||||
bytes
|
||||
.Pq Ql /1 ,
|
||||
halfwords
|
||||
.Pq Ql /2 ,
|
||||
or words
|
||||
.Pq Ql /4
|
||||
from
|
||||
.Ar address .
|
||||
If
|
||||
.Ar count
|
||||
is not specified, examine 16 bytes, 8 halfwords, or 4 words.
|
||||
.El
|
||||
.Sh FILES
|
||||
.Bl -tag -width ~/.config/mgba/config.ini -compact
|
||||
.It Pa ~/.config/mgba/config.ini
|
||||
Default
|
||||
.Nm
|
||||
configuration file.
|
||||
.It Pa portable.ini
|
||||
If this file exists in the current directory,
|
||||
.Nm
|
||||
will read
|
||||
.Pa config.ini
|
||||
from the current directory instead of
|
||||
.Pa ~/.config/mgba .
|
||||
.El
|
||||
.Sh AUTHORS
|
||||
.An Jeffrey Pfau Aq Mt jeffrey@endrift.com
|
||||
.Sh HOMEPAGE
|
||||
.Bl -bullet
|
||||
.It
|
||||
.Lk https://mgba.io/ "mGBA homepage"
|
||||
.It
|
||||
.Lk https://github.com/mgba-emu/mgba "Development repository"
|
||||
.It
|
||||
.Lk https://github.com/mgba-emu/mgba/issues "Bug tracker"
|
||||
.It
|
||||
.Lk https://forums.mgba.io/ "Message board"
|
||||
.El
|
BIN
res/keymap.qpic
BIN
res/keymap.qpic
Binary file not shown.
268
res/keymap.svg
268
res/keymap.svg
|
@ -7,130 +7,266 @@
|
|||
<stop offset="0" style="stop-color:#7A65F5"/>
|
||||
<stop offset="1" style="stop-color:#302575"/>
|
||||
</linearGradient>
|
||||
<path fill="url(#SVGID_1_)" d="M480,450c0,16.5684-13.4316,30-30,30H30c-16.5684,0-30-13.4316-30-30V30C0,13.4316,13.4316,0,30,0
|
||||
h420c16.5684,0,30,13.4316,30,30V450z"/>
|
||||
<linearGradient id="SVGID_2_" gradientUnits="userSpaceOnUse" x1="239.9995" y1="-479" x2="239.9994" y2="1159.0004">
|
||||
<stop offset="0" style="stop-color:#7A65F5"/>
|
||||
<path fill="url(#SVGID_1_)" d="M480,450c0,16.568-13.432,30-30,30H30c-16.568,0-30-13.432-30-30V30C0,13.432,13.432,0,30,0h420
|
||||
c16.568,0,30,13.432,30,30V450z"/>
|
||||
<linearGradient id="SVGID_2_" gradientUnits="userSpaceOnUse" x1="239.9995" y1="-479.0015" x2="239.9994" y2="1158.9995">
|
||||
<stop offset="0" style="stop-color:#7762F5"/>
|
||||
<stop offset="1" style="stop-color:#372E75"/>
|
||||
</linearGradient>
|
||||
<path fill="url(#SVGID_2_)" d="M30,473c-12.682,0-23-10.317-23-23V30C7,17.318,17.318,7,30,7h420c12.683,0,23,10.318,23,23v420
|
||||
c0,12.683-10.317,23-23,23H30z"/>
|
||||
<linearGradient id="SVGID_3_" gradientUnits="userSpaceOnUse" x1="118.3335" y1="291.667" x2="118.3335" y2="47.9995">
|
||||
<stop offset="0" style="stop-color:#7466CF"/>
|
||||
<stop offset="1" style="stop-color:#302575"/>
|
||||
</linearGradient>
|
||||
<path fill="url(#SVGID_2_)" d="M30,473c-12.6821,0-23-10.3174-23-23V30C7,17.3179,17.3179,7,30,7h420c12.6826,0,23,10.3179,23,23
|
||||
v420c0,12.6826-10.3174,23-23,23H30z"/>
|
||||
<linearGradient id="SVGID_3_" gradientUnits="userSpaceOnUse" x1="118.3335" y1="291.667" x2="118.3335" y2="47.9991">
|
||||
<stop offset="0" style="stop-color:#7A65F5"/>
|
||||
<stop offset="1" style="stop-color:#302575"/>
|
||||
</linearGradient>
|
||||
<path fill="url(#SVGID_3_)" d="M118.3335,122.333c-46.7603,0-84.667,37.9067-84.667,84.667c0,46.7607,37.9067,84.667,84.667,84.667
|
||||
s84.667-37.9062,84.667-84.667C203.0005,160.2397,165.0938,122.333,118.3335,122.333z M118.334,278.7344
|
||||
c-39.6172,0-71.7339-32.1172-71.7339-71.7344c0-39.6177,32.1167-71.7339,71.7339-71.7339S190.0679,167.3823,190.0679,207
|
||||
C190.0679,246.6172,157.9512,278.7344,118.334,278.7344z"/>
|
||||
<path fill="url(#SVGID_3_)" d="M118.333,122.333c-46.76,0-84.667,37.907-84.667,84.667c0,46.761,37.907,84.667,84.667,84.667
|
||||
S203,253.761,203,207C203,160.24,165.094,122.333,118.333,122.333z M118.334,278.734C78.717,278.734,46.6,246.617,46.6,207
|
||||
c0-39.618,32.117-71.734,71.734-71.734s71.734,32.116,71.734,71.734C190.068,246.617,157.951,278.734,118.334,278.734z"/>
|
||||
<g>
|
||||
|
||||
<radialGradient id="SVGID_4_" cx="118.8335" cy="138.167" r="103.2725" fx="165.1467" fy="138.167" gradientTransform="matrix(-4.371139e-08 1 -1.42 -6.206884e-08 315.0264 19.3335)" gradientUnits="userSpaceOnUse">
|
||||
<radialGradient id="SVGID_4_" cx="118.8335" cy="138.167" r="103.2721" fx="165.1465" fy="138.167" gradientTransform="matrix(-4.371139e-08 1 -1.42 -6.206886e-08 315.0265 19.3335)" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" style="stop-color:#9C9CB3"/>
|
||||
<stop offset="1" style="stop-color:#333045"/>
|
||||
</radialGradient>
|
||||
<path fill="url(#SVGID_4_)" d="M172.1973,207c0-9.667-3.0029-17.333-3.0029-17.333H135.667v-33.5283
|
||||
c0,0-7.667-3.0029-17.3335-3.0029s-17.333,3.0029-17.333,3.0029v33.5283H67.4727c0,0-3.0029,7.666-3.0029,17.333
|
||||
c0,9.666,3.0029,17.333,3.0029,17.333h33.5278v33.5273c0,0,7.6665,3.0039,17.333,3.0039s17.3335-3.0039,17.3335-3.0039V224.333
|
||||
h33.5273C169.1943,224.333,172.1973,216.666,172.1973,207z"/>
|
||||
<path fill="#5C567D" d="M118.3335,258.8643c-6.9185,0-12.833-1.625-15.333-2.4287V222.333h-34.103
|
||||
c-0.8027-2.5-2.4277-8.4146-2.4277-15.333s1.6245-12.833,2.4277-15.333h34.103v-34.1035c2.5-0.8027,8.4146-2.4277,15.333-2.4277
|
||||
c6.9453,0,12.8408,1.6226,15.3335,2.4258v34.1055h34.1025c0.8032,2.5,2.4277,8.4146,2.4277,15.333
|
||||
c0,6.9448-1.6226,12.8403-2.4258,15.333H133.667v34.1025C131.167,257.2393,125.252,258.8643,118.3335,258.8643z"/>
|
||||
<radialGradient id="SVGID_5_" cx="118.333" cy="220.397" r="69.7522" gradientUnits="userSpaceOnUse">
|
||||
<path fill="url(#SVGID_4_)" d="M172.197,207c0-9.667-3.003-17.333-3.003-17.333h-33.527v-33.528c0,0-7.667-3.003-17.333-3.003
|
||||
S101,156.139,101,156.139v33.528H67.473c0,0-3.003,7.666-3.003,17.333c0,9.666,3.003,17.333,3.003,17.333H101v33.527
|
||||
c0,0,7.667,3.004,17.333,3.004s17.333-3.004,17.333-3.004v-33.527h33.527C169.194,224.333,172.197,216.666,172.197,207z"/>
|
||||
<path fill="#5C567D" d="M118.333,258.864c-6.918,0-12.833-1.625-15.333-2.429v-34.103H68.897c-0.803-2.5-2.428-8.415-2.428-15.333
|
||||
s1.625-12.833,2.428-15.333H103v-34.104c2.5-0.803,8.415-2.428,15.333-2.428c6.945,0,12.841,1.623,15.333,2.426v34.105h34.103
|
||||
c0.803,2.5,2.428,8.415,2.428,15.333c0,6.945-1.623,12.84-2.426,15.333h-34.104v34.103
|
||||
C131.167,257.239,125.252,258.864,118.333,258.864z"/>
|
||||
<radialGradient id="SVGID_5_" cx="118.333" cy="220.397" r="69.7523" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" style="stop-color:#706F8A"/>
|
||||
<stop offset="0.9951" style="stop-color:#2D2842"/>
|
||||
</radialGradient>
|
||||
<circle fill="url(#SVGID_5_)" cx="118.333" cy="207" r="21.2749"/>
|
||||
<circle fill="url(#SVGID_5_)" cx="118.333" cy="207" r="21.275"/>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<linearGradient id="SVGID_6_" gradientUnits="userSpaceOnUse" x1="198.9673" y1="490" x2="198.9673" y2="384.981">
|
||||
<linearGradient id="SVGID_6_" gradientUnits="userSpaceOnUse" x1="198.9673" y1="490" x2="198.9673" y2="384.9809">
|
||||
<stop offset="0" style="stop-color:#7A65F5"/>
|
||||
<stop offset="1" style="stop-color:#302575"/>
|
||||
</linearGradient>
|
||||
<path fill="url(#SVGID_6_)" d="M198.9678,387.0303c-18.8418,0-34.1162,15.2734-34.1162,34.1162
|
||||
c0,18.8418,15.2744,34.1152,34.1162,34.1152c18.8408,0,34.1152-15.2734,34.1152-34.1152
|
||||
C233.083,402.3037,217.8086,387.0303,198.9678,387.0303z M198.9678,445.7871c-13.6089,0-24.6401-11.0332-24.6401-24.6406
|
||||
c0-13.6094,11.0312-24.6406,24.6401-24.6406c13.6074,0,24.6396,11.0312,24.6396,24.6406
|
||||
C223.6074,434.7539,212.5752,445.7871,198.9678,445.7871z"/>
|
||||
<path fill="url(#SVGID_6_)" d="M198.968,387.03c-18.842,0-34.116,15.273-34.116,34.116c0,18.842,15.274,34.115,34.116,34.115
|
||||
c18.841,0,34.115-15.273,34.115-34.115C233.083,402.304,217.809,387.03,198.968,387.03z M198.968,445.787
|
||||
c-13.609,0-24.64-11.033-24.64-24.641c0-13.609,11.031-24.641,24.64-24.641c13.607,0,24.64,11.031,24.64,24.641
|
||||
C223.607,434.754,212.575,445.787,198.968,445.787z"/>
|
||||
<g>
|
||||
<linearGradient id="SVGID_7_" gradientUnits="userSpaceOnUse" x1="198.9673" y1="437.4414" x2="198.9673" y2="404.8516">
|
||||
<stop offset="0" style="stop-color:#333045"/>
|
||||
<stop offset="1" style="stop-color:#9C9CB3"/>
|
||||
</linearGradient>
|
||||
<circle fill="url(#SVGID_7_)" cx="198.9673" cy="421.1465" r="16.2949"/>
|
||||
<circle fill="#5C567D" cx="198.9673" cy="421.1465" r="15.0737"/>
|
||||
<circle fill="url(#SVGID_7_)" cx="198.967" cy="421.146" r="16.295"/>
|
||||
<circle fill="#5C567D" cx="198.967" cy="421.146" r="15.074"/>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<linearGradient id="SVGID_8_" gradientUnits="userSpaceOnUse" x1="281.0312" y1="490" x2="281.0312" y2="384.981">
|
||||
<linearGradient id="SVGID_8_" gradientUnits="userSpaceOnUse" x1="281.0312" y1="490" x2="281.0312" y2="384.9809">
|
||||
<stop offset="0" style="stop-color:#7A65F5"/>
|
||||
<stop offset="1" style="stop-color:#302575"/>
|
||||
</linearGradient>
|
||||
<path fill="url(#SVGID_8_)" d="M281.0322,387.0303c-18.8418,0-34.1162,15.2734-34.1162,34.1162
|
||||
c0,18.8418,15.2744,34.1152,34.1162,34.1152c18.8408,0,34.1152-15.2734,34.1152-34.1152
|
||||
C315.1475,402.3037,299.873,387.0303,281.0322,387.0303z M281.0322,445.7871c-13.6084,0-24.6396-11.0332-24.6396-24.6406
|
||||
c0-13.6094,11.0312-24.6406,24.6396-24.6406c13.6074,0,24.6396,11.0312,24.6396,24.6406
|
||||
C305.6719,434.7539,294.6396,445.7871,281.0322,445.7871z"/>
|
||||
<path fill="url(#SVGID_8_)" d="M281.032,387.03c-18.842,0-34.116,15.273-34.116,34.116c0,18.842,15.274,34.115,34.116,34.115
|
||||
c18.841,0,34.115-15.273,34.115-34.115C315.147,402.304,299.873,387.03,281.032,387.03z M281.032,445.787
|
||||
c-13.608,0-24.64-11.033-24.64-24.641c0-13.609,11.031-24.641,24.64-24.641c13.607,0,24.64,11.031,24.64,24.641
|
||||
C305.672,434.754,294.64,445.787,281.032,445.787z"/>
|
||||
<g>
|
||||
<linearGradient id="SVGID_9_" gradientUnits="userSpaceOnUse" x1="281.0322" y1="437.4414" x2="281.0322" y2="404.8516">
|
||||
<stop offset="0" style="stop-color:#333045"/>
|
||||
<stop offset="1" style="stop-color:#9C9CB3"/>
|
||||
</linearGradient>
|
||||
<circle fill="url(#SVGID_9_)" cx="281.0322" cy="421.1465" r="16.2949"/>
|
||||
<circle fill="#5C567D" cx="281.0317" cy="421.1465" r="15.0737"/>
|
||||
<circle fill="url(#SVGID_9_)" cx="281.032" cy="421.146" r="16.295"/>
|
||||
<circle fill="#5C567D" cx="281.032" cy="421.146" r="15.074"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<linearGradient id="SVGID_10_" gradientUnits="userSpaceOnUse" x1="356.1787" y1="280.2178" x2="356.1787" y2="134.9952">
|
||||
<stop offset="0" style="stop-color:#7A65F5"/>
|
||||
<linearGradient id="SVGID_10_" gradientUnits="userSpaceOnUse" x1="356.1787" y1="280.2178" x2="356.1787" y2="134.9951">
|
||||
<stop offset="0" style="stop-color:#7466CF"/>
|
||||
<stop offset="1" style="stop-color:#302575"/>
|
||||
</linearGradient>
|
||||
<path fill="url(#SVGID_10_)" d="M437.9521,179.5503c-7.0088-23.9434-32.0986-37.6724-56.043-30.6646l-76.8369,22.4912
|
||||
c-23.9453,7.0073-37.6748,32.0991-30.666,56.043c7.0088,23.9443,32.0996,37.6719,56.0449,30.6621l76.8369-22.4902
|
||||
C431.2314,228.585,444.96,203.4946,437.9521,179.5503z M426.3311,209.6025c-4.6377,8.4756-12.2979,14.6382-21.5703,17.3516
|
||||
l-76.8379,22.4902c-3.3301,0.9746-6.7559,1.4688-10.1816,1.4688c-0.001,0-0.001,0-0.002,0
|
||||
c-15.9443-0.001-30.2109-10.7012-34.6953-26.0215c-2.7148-9.2729-1.6553-19.0479,2.9824-27.5244
|
||||
c4.6387-8.4761,12.2998-14.6387,21.5732-17.3525l76.8379-22.4912c3.3281-0.9741,6.7539-1.4683,10.1807-1.4683
|
||||
c15.9434,0,30.2109,10.7012,34.6963,26.0234C432.0283,191.3516,430.9688,201.1265,426.3311,209.6025z"/>
|
||||
<path fill="url(#SVGID_10_)" d="M437.952,179.55c-7.009-23.943-32.099-37.672-56.043-30.665l-76.837,22.491
|
||||
c-23.945,7.007-37.675,32.099-30.666,56.043c7.009,23.944,32.1,37.672,56.045,30.662l76.837-22.49
|
||||
C431.231,228.585,444.96,203.495,437.952,179.55z M426.331,209.603c-4.638,8.476-12.298,14.638-21.57,17.352l-76.838,22.49
|
||||
c-3.33,0.975-6.756,1.469-10.182,1.469c-0.001,0-0.001,0-0.001,0c-15.945-0.001-30.212-10.701-34.696-26.021
|
||||
c-2.715-9.273-1.655-19.048,2.982-27.524c4.639-8.476,12.3-14.639,21.573-17.353l76.838-22.491
|
||||
c3.328-0.974,6.754-1.468,10.181-1.468c15.943,0,30.211,10.701,34.696,26.023C432.028,191.352,430.969,201.126,426.331,209.603z"/>
|
||||
<g>
|
||||
<linearGradient id="SVGID_11_" gradientUnits="userSpaceOnUse" x1="395.9062" y1="217.8188" x2="395.9062" y2="166.6519">
|
||||
<stop offset="0" style="stop-color:#333045"/>
|
||||
<stop offset="1" style="stop-color:#9C9CB3"/>
|
||||
</linearGradient>
|
||||
<circle fill="url(#SVGID_11_)" cx="395.9062" cy="192.2358" r="25.584"/>
|
||||
<circle fill="#5C567D" cx="395.9072" cy="192.2358" r="23.666"/>
|
||||
<circle fill="url(#SVGID_11_)" cx="395.906" cy="192.236" r="25.584"/>
|
||||
<circle fill="#5C567D" cx="395.907" cy="192.236" r="23.666"/>
|
||||
</g>
|
||||
<g>
|
||||
<linearGradient id="SVGID_12_" gradientUnits="userSpaceOnUse" x1="318.9785" y1="239.6406" x2="318.9785" y2="188.4722">
|
||||
<stop offset="0" style="stop-color:#333045"/>
|
||||
<stop offset="1" style="stop-color:#9C9CB3"/>
|
||||
</linearGradient>
|
||||
<circle fill="url(#SVGID_12_)" cx="318.979" cy="214.0571" r="25.5835"/>
|
||||
<circle fill="#5C567D" cx="318.98" cy="214.0571" r="23.6665"/>
|
||||
<circle fill="url(#SVGID_12_)" cx="318.979" cy="214.057" r="25.583"/>
|
||||
<circle fill="#5C567D" cx="318.98" cy="214.057" r="23.667"/>
|
||||
</g>
|
||||
<g>
|
||||
<linearGradient id="SVGID_13_" gradientUnits="userSpaceOnUse" x1="-15.0425" y1="77.9346" x2="55.6245" y2="-5.3989">
|
||||
<linearGradient id="SVGID_13_" gradientUnits="userSpaceOnUse" x1="-15.0435" y1="77.9331" x2="55.6236" y2="-5.4006">
|
||||
<stop offset="0" style="stop-color:#333045"/>
|
||||
<stop offset="1" style="stop-color:#9C9CB3"/>
|
||||
</linearGradient>
|
||||
<path fill="url(#SVGID_13_)" d="M33.6665,0H61.5c2.9697,1.0112,2.3306,7,2.3306,7l0.0581,8.4844
|
||||
C63.8887,31.3535,48.9922,50,27.9922,50H7.0068c0,0-5.2197,2.312-7.0068-8.0029V30C0,11.5,12.333,0,33.6665,0z"/>
|
||||
<path fill="#5C567D" d="M9.7783,49.1743c-0.2793-0.251-1.166-1.2764-1.7744-4.5308V33.0029c0-16.5234,10.813-26,29.6665-26h26.0854
|
||||
c0.1318,0.709,0.1821,1.7549,0.0996,2.5908L63.835,9.8032l0.0576,8.7114c0,14.3774-13.6406,30.4883-31.8965,30.4883H10.1646
|
||||
L9.7783,49.1743z"/>
|
||||
<path fill="url(#SVGID_13_)" d="M33.667,0H61.5c2.97,1.011,2.331,7,2.331,7l0.058,8.484C63.889,31.354,48.992,50,27.992,50H7.007
|
||||
c0,0-5.22,2.312-7.007-8.003V30C0,11.5,12.333,0,33.667,0z"/>
|
||||
<path fill="#5C567D" d="M9.778,49.174c-0.279-0.251-1.166-1.276-1.774-4.531V33.003c0-16.523,10.813-26,29.667-26h26.085
|
||||
c0.132,0.709,0.182,1.755,0.1,2.591l-0.021,0.209l0.058,8.711c0,14.377-13.641,30.488-31.896,30.488H10.165L9.778,49.174z"/>
|
||||
</g>
|
||||
<g>
|
||||
|
||||
<linearGradient id="SVGID_14_" gradientUnits="userSpaceOnUse" x1="401.0615" y1="77.9336" x2="471.7285" y2="-5.3999" gradientTransform="matrix(-1 0 0 1 896.1055 0)">
|
||||
<linearGradient id="SVGID_14_" gradientUnits="userSpaceOnUse" x1="401.0605" y1="77.9331" x2="471.7277" y2="-5.4007" gradientTransform="matrix(-1 0 0 1 896.1055 0)">
|
||||
<stop offset="0" style="stop-color:#333045"/>
|
||||
<stop offset="1" style="stop-color:#9C9CB3"/>
|
||||
</linearGradient>
|
||||
<path fill="url(#SVGID_14_)" d="M446.334,0h-27.833c-2.9697,1.0112-2.3311,7-2.3311,7l-0.0576,8.4844
|
||||
C416.1123,31.3535,431.0088,50,452.0088,50h20.9854c0,0,5.2197,2.312,7.0068-8.0029V30C480.001,11.5,467.668,0,446.334,0z"/>
|
||||
<path fill="#5C567D" d="M470.2227,49.1743c0.2793-0.251,1.166-1.2764,1.7744-4.5308V33.0029c0-16.5234-10.8135-26-29.667-26
|
||||
h-26.085c-0.1318,0.709-0.1826,1.7549-0.0996,2.5908l0.0205,0.2095l-0.0576,8.7114c0,14.3774,13.6406,30.4883,31.8965,30.4883
|
||||
h21.8311L470.2227,49.1743z"/>
|
||||
<path fill="url(#SVGID_14_)" d="M446.334,0h-27.833c-2.97,1.011-2.331,7-2.331,7l-0.058,8.484
|
||||
c0,15.869,14.896,34.516,35.896,34.516h20.985c0,0,5.22,2.312,7.007-8.003V30C480.001,11.5,467.668,0,446.334,0z"/>
|
||||
<path fill="#5C567D" d="M470.223,49.174c0.279-0.251,1.166-1.276,1.774-4.531V33.003c0-16.523-10.813-26-29.667-26h-26.085
|
||||
c-0.132,0.709-0.183,1.755-0.1,2.591l0.021,0.209l-0.058,8.711c0,14.377,13.641,30.488,31.896,30.488h21.831L470.223,49.174z"/>
|
||||
</g>
|
||||
<g opacity="0.5">
|
||||
<path fill="#9C9CB3" stroke="#9C9CB3" stroke-miterlimit="10" d="M312.197,226v-21.475h8.057c1.641,0,2.956,0.217,3.947,0.652
|
||||
s1.768,1.104,2.33,2.007c0.561,0.903,0.842,1.848,0.842,2.834c0,0.918-0.249,1.782-0.747,2.593s-1.25,1.465-2.256,1.963
|
||||
c1.299,0.381,2.297,1.03,2.995,1.948s1.048,2.002,1.048,3.252c0,1.006-0.212,1.941-0.638,2.805c-0.424,0.864-0.949,1.531-1.574,2
|
||||
s-1.409,0.823-2.352,1.062S321.753,226,320.386,226H312.197z M315.039,213.549h4.644c1.26,0,2.163-0.083,2.71-0.249
|
||||
c0.723-0.215,1.268-0.571,1.633-1.069c0.367-0.498,0.55-1.123,0.55-1.875c0-0.713-0.171-1.34-0.513-1.882s-0.83-0.913-1.465-1.113
|
||||
s-1.724-0.3-3.267-0.3h-4.292V213.549z M315.039,223.466h5.347c0.918,0,1.562-0.034,1.934-0.103
|
||||
c0.654-0.117,1.201-0.312,1.641-0.586s0.801-0.671,1.084-1.194s0.425-1.125,0.425-1.809c0-0.801-0.205-1.497-0.615-2.087
|
||||
s-0.979-1.006-1.707-1.245s-1.774-0.359-3.142-0.359h-4.966V223.466z"/>
|
||||
</g>
|
||||
<g opacity="0.5">
|
||||
<path fill="#9C9CB3" stroke="#9C9CB3" stroke-miterlimit="10" d="M385.956,203l8.247-21.475h3.062L406.054,203h-3.237l-2.505-6.504
|
||||
h-8.979L388.974,203H385.956z M392.152,194.182h7.28l-2.241-5.947c-0.684-1.807-1.191-3.291-1.523-4.453
|
||||
c-0.273,1.377-0.659,2.744-1.157,4.102L392.152,194.182z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path fill="#333045" d="M312.197,224v-21.475h8.057c1.641,0,2.956,0.217,3.947,0.652s1.768,1.104,2.33,2.007
|
||||
c0.561,0.903,0.842,1.848,0.842,2.834c0,0.918-0.249,1.782-0.747,2.593s-1.25,1.465-2.256,1.963
|
||||
c1.299,0.381,2.297,1.03,2.995,1.948s1.048,2.002,1.048,3.252c0,1.006-0.212,1.941-0.638,2.805c-0.424,0.864-0.949,1.531-1.574,2
|
||||
s-1.409,0.823-2.352,1.062S321.753,224,320.386,224H312.197z M315.039,211.549h4.644c1.26,0,2.163-0.083,2.71-0.249
|
||||
c0.723-0.215,1.268-0.571,1.633-1.069c0.367-0.498,0.55-1.123,0.55-1.875c0-0.713-0.171-1.34-0.513-1.882s-0.83-0.913-1.465-1.113
|
||||
s-1.724-0.3-3.267-0.3h-4.292V211.549z M315.039,221.466h5.347c0.918,0,1.562-0.034,1.934-0.103
|
||||
c0.654-0.117,1.201-0.312,1.641-0.586s0.801-0.671,1.084-1.194s0.425-1.125,0.425-1.809c0-0.801-0.205-1.497-0.615-2.087
|
||||
s-0.979-1.006-1.707-1.245s-1.774-0.359-3.142-0.359h-4.966V221.466z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path fill="#333045" d="M385.956,201l8.247-21.475h3.062L406.054,201h-3.237l-2.505-6.504h-8.979L388.974,201H385.956z
|
||||
M392.152,192.182h7.28l-2.241-5.947c-0.684-1.807-1.191-3.291-1.523-4.453c-0.273,1.377-0.659,2.744-1.157,4.102L392.152,192.182z
|
||||
"/>
|
||||
</g>
|
||||
<g opacity="0.5">
|
||||
<g>
|
||||
<path fill="#1B0942" stroke="#1B0942" stroke-width="2" stroke-miterlimit="10" d="M320.35,425.264l2.658-0.258
|
||||
c0.16,0.893,0.484,1.547,0.974,1.967c0.489,0.418,1.148,0.627,1.979,0.627c0.88,0,1.543-0.186,1.988-0.559
|
||||
c0.446-0.373,0.669-0.807,0.669-1.307c0-0.318-0.094-0.592-0.281-0.816s-0.515-0.42-0.982-0.586
|
||||
c-0.32-0.111-1.049-0.307-2.188-0.59c-1.464-0.363-2.491-0.809-3.082-1.338c-0.831-0.744-1.246-1.652-1.246-2.723
|
||||
c0-0.689,0.195-1.334,0.586-1.934s0.954-1.057,1.689-1.371c0.734-0.312,1.622-0.471,2.662-0.471c1.698,0,2.977,0.373,3.834,1.117
|
||||
c0.858,0.744,1.31,1.738,1.353,2.98l-2.731,0.121c-0.117-0.695-0.368-1.195-0.753-1.5c-0.384-0.305-0.961-0.457-1.729-0.457
|
||||
c-0.794,0-1.416,0.162-1.864,0.488c-0.29,0.209-0.435,0.49-0.435,0.84c0,0.32,0.136,0.594,0.406,0.822
|
||||
c0.345,0.289,1.182,0.59,2.511,0.904s2.312,0.639,2.948,0.973c0.637,0.336,1.135,0.795,1.495,1.375
|
||||
c0.359,0.582,0.54,1.301,0.54,2.156c0,0.775-0.216,1.5-0.646,2.178c-0.431,0.676-1.04,1.18-1.827,1.508
|
||||
c-0.787,0.33-1.769,0.494-2.943,0.494c-1.711,0-3.024-0.395-3.941-1.186C321.076,427.93,320.528,426.777,320.35,425.264z"/>
|
||||
<path fill="#1B0942" stroke="#1B0942" stroke-width="2" stroke-miterlimit="10" d="M336.694,429.666v-11.24h-4.015v-2.289h10.751
|
||||
v2.289h-4.005v11.24H336.694z"/>
|
||||
<path fill="#1B0942" stroke="#1B0942" stroke-width="2" stroke-miterlimit="10" d="M355.99,429.666h-2.972l-1.182-3.072h-5.407
|
||||
l-1.117,3.072h-2.897l5.27-13.529h2.889L355.99,429.666z M350.961,424.314l-1.864-5.021l-1.827,5.021H350.961z"/>
|
||||
<path fill="#1B0942" stroke="#1B0942" stroke-width="2" stroke-miterlimit="10" d="M357.449,429.666v-13.529h5.749
|
||||
c1.445,0,2.496,0.123,3.151,0.365c0.655,0.244,1.18,0.676,1.573,1.297s0.591,1.332,0.591,2.131c0,1.016-0.299,1.854-0.896,2.516
|
||||
s-1.488,1.078-2.676,1.25c0.591,0.346,1.078,0.723,1.463,1.135c0.384,0.412,0.902,1.145,1.555,2.197l1.652,2.639h-3.268
|
||||
l-1.975-2.943c-0.701-1.053-1.182-1.715-1.439-1.988c-0.259-0.273-0.532-0.463-0.821-0.562c-0.289-0.102-0.748-0.152-1.375-0.152
|
||||
h-0.554v5.646H357.449z M360.181,421.859h2.021c1.311,0,2.129-0.055,2.455-0.166s0.581-0.301,0.766-0.572s0.277-0.609,0.277-1.016
|
||||
c0-0.455-0.122-0.822-0.364-1.102c-0.243-0.281-0.587-0.457-1.029-0.531c-0.222-0.031-0.886-0.047-1.993-0.047h-2.132V421.859z"/>
|
||||
<path fill="#1B0942" stroke="#1B0942" stroke-width="2" stroke-miterlimit="10" d="M374.134,429.666v-11.24h-4.015v-2.289h10.751
|
||||
v2.289h-4.005v11.24H374.134z"/>
|
||||
</g>
|
||||
</g>
|
||||
<g opacity="0.5">
|
||||
<g>
|
||||
<path fill="#1B0942" stroke="#1B0942" stroke-width="2" stroke-miterlimit="10" d="M87.35,425.264l2.658-0.258
|
||||
c0.16,0.893,0.484,1.547,0.974,1.967c0.489,0.418,1.148,0.627,1.979,0.627c0.88,0,1.543-0.186,1.988-0.559
|
||||
c0.446-0.373,0.669-0.807,0.669-1.307c0-0.318-0.094-0.592-0.281-0.816s-0.515-0.42-0.982-0.586
|
||||
c-0.32-0.111-1.049-0.307-2.188-0.59c-1.464-0.363-2.491-0.809-3.082-1.338c-0.831-0.744-1.246-1.652-1.246-2.723
|
||||
c0-0.689,0.195-1.334,0.586-1.934s0.954-1.057,1.689-1.371c0.734-0.312,1.622-0.471,2.662-0.471c1.698,0,2.977,0.373,3.834,1.117
|
||||
c0.858,0.744,1.31,1.738,1.353,2.98l-2.731,0.121c-0.117-0.695-0.368-1.195-0.753-1.5c-0.384-0.305-0.961-0.457-1.729-0.457
|
||||
c-0.794,0-1.416,0.162-1.864,0.488c-0.29,0.209-0.435,0.49-0.435,0.84c0,0.32,0.136,0.594,0.406,0.822
|
||||
c0.345,0.289,1.182,0.59,2.511,0.904s2.312,0.639,2.948,0.973c0.637,0.336,1.135,0.795,1.495,1.375
|
||||
c0.359,0.582,0.54,1.301,0.54,2.156c0,0.775-0.216,1.5-0.646,2.178c-0.431,0.676-1.04,1.18-1.827,1.508
|
||||
c-0.787,0.33-1.769,0.494-2.943,0.494c-1.711,0-3.024-0.395-3.941-1.186C88.076,427.93,87.528,426.777,87.35,425.264z"/>
|
||||
<path fill="#1B0942" stroke="#1B0942" stroke-width="2" stroke-miterlimit="10" d="M100.648,429.666v-13.529h10.031v2.289h-7.3v3
|
||||
h6.792v2.279h-6.792v3.682h7.559v2.279H100.648z"/>
|
||||
<path fill="#1B0942" stroke="#1B0942" stroke-width="2" stroke-miterlimit="10" d="M113.328,429.666v-13.418h2.731v11.139h6.792
|
||||
v2.279H113.328z"/>
|
||||
<path fill="#1B0942" stroke="#1B0942" stroke-width="2" stroke-miterlimit="10" d="M124.799,429.666v-13.529h10.031v2.289h-7.3v3
|
||||
h6.792v2.279h-6.792v3.682h7.559v2.279H124.799z"/>
|
||||
<path fill="#1B0942" stroke="#1B0942" stroke-width="2" stroke-miterlimit="10" d="M146.062,424.691l2.648,0.84
|
||||
c-0.406,1.477-1.081,2.574-2.025,3.291s-2.143,1.074-3.595,1.074c-1.796,0-3.272-0.613-4.43-1.84
|
||||
c-1.156-1.229-1.734-2.906-1.734-5.035c0-2.252,0.581-4,1.744-5.246c1.162-1.246,2.691-1.869,4.586-1.869
|
||||
c1.655,0,3,0.49,4.033,1.469c0.615,0.578,1.076,1.408,1.384,2.49l-2.703,0.646c-0.16-0.701-0.494-1.256-1.002-1.66
|
||||
c-0.507-0.406-1.124-0.609-1.85-0.609c-1.003,0-1.817,0.359-2.441,1.08c-0.624,0.719-0.937,1.885-0.937,3.496
|
||||
c0,1.711,0.308,2.93,0.923,3.654c0.615,0.727,1.415,1.09,2.399,1.09c0.726,0,1.351-0.23,1.873-0.691
|
||||
C145.459,426.408,145.834,425.684,146.062,424.691z"/>
|
||||
<path fill="#1B0942" stroke="#1B0942" stroke-width="2" stroke-miterlimit="10" d="M154.101,429.666v-11.24h-4.015v-2.289h10.751
|
||||
v2.289h-4.005v11.24H154.101z"/>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<path fill="#7A65F5" d="M320.35,423.264l2.658-0.258c0.16,0.893,0.484,1.547,0.974,1.967c0.489,0.418,1.148,0.627,1.979,0.627
|
||||
c0.88,0,1.543-0.186,1.988-0.559c0.446-0.373,0.669-0.807,0.669-1.307c0-0.318-0.094-0.592-0.281-0.816s-0.515-0.42-0.982-0.586
|
||||
c-0.32-0.111-1.049-0.307-2.188-0.59c-1.464-0.363-2.491-0.809-3.082-1.338c-0.831-0.744-1.246-1.652-1.246-2.723
|
||||
c0-0.689,0.195-1.334,0.586-1.934s0.954-1.057,1.689-1.371c0.734-0.312,1.622-0.471,2.662-0.471c1.698,0,2.977,0.373,3.834,1.117
|
||||
c0.858,0.744,1.31,1.738,1.353,2.98l-2.731,0.121c-0.117-0.695-0.368-1.195-0.753-1.5c-0.384-0.305-0.961-0.457-1.729-0.457
|
||||
c-0.794,0-1.416,0.162-1.864,0.488c-0.29,0.209-0.435,0.49-0.435,0.84c0,0.32,0.136,0.594,0.406,0.822
|
||||
c0.345,0.289,1.182,0.59,2.511,0.904s2.312,0.639,2.948,0.973c0.637,0.336,1.135,0.795,1.495,1.375
|
||||
c0.359,0.582,0.54,1.301,0.54,2.156c0,0.775-0.216,1.5-0.646,2.178c-0.431,0.676-1.04,1.18-1.827,1.508
|
||||
c-0.787,0.33-1.769,0.494-2.943,0.494c-1.711,0-3.024-0.395-3.941-1.186C321.076,425.93,320.528,424.777,320.35,423.264z"/>
|
||||
<path fill="#7A65F5" d="M336.694,427.666v-11.24h-4.015v-2.289h10.751v2.289h-4.005v11.24H336.694z"/>
|
||||
<path fill="#7A65F5" d="M355.99,427.666h-2.972l-1.182-3.072h-5.407l-1.117,3.072h-2.897l5.27-13.529h2.889L355.99,427.666z
|
||||
M350.961,422.314l-1.864-5.021l-1.827,5.021H350.961z"/>
|
||||
<path fill="#7A65F5" d="M357.449,427.666v-13.529h5.749c1.445,0,2.496,0.123,3.151,0.365c0.655,0.244,1.18,0.676,1.573,1.297
|
||||
s0.591,1.332,0.591,2.131c0,1.016-0.299,1.854-0.896,2.516s-1.488,1.078-2.676,1.25c0.591,0.346,1.078,0.723,1.463,1.135
|
||||
c0.384,0.412,0.902,1.145,1.555,2.197l1.652,2.639h-3.268l-1.975-2.943c-0.701-1.053-1.182-1.715-1.439-1.988
|
||||
c-0.259-0.273-0.532-0.463-0.821-0.562c-0.289-0.102-0.748-0.152-1.375-0.152h-0.554v5.646H357.449z M360.181,419.859h2.021
|
||||
c1.311,0,2.129-0.055,2.455-0.166s0.581-0.301,0.766-0.572s0.277-0.609,0.277-1.016c0-0.455-0.122-0.822-0.364-1.102
|
||||
c-0.243-0.281-0.587-0.457-1.029-0.531c-0.222-0.031-0.886-0.047-1.993-0.047h-2.132V419.859z"/>
|
||||
<path fill="#7A65F5" d="M374.134,427.666v-11.24h-4.015v-2.289h10.751v2.289h-4.005v11.24H374.134z"/>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<path fill="#7A65F5" d="M87.35,423.264l2.658-0.258c0.16,0.893,0.484,1.547,0.974,1.967c0.489,0.418,1.148,0.627,1.979,0.627
|
||||
c0.88,0,1.543-0.186,1.988-0.559c0.446-0.373,0.669-0.807,0.669-1.307c0-0.318-0.094-0.592-0.281-0.816s-0.515-0.42-0.982-0.586
|
||||
c-0.32-0.111-1.049-0.307-2.188-0.59c-1.464-0.363-2.491-0.809-3.082-1.338c-0.831-0.744-1.246-1.652-1.246-2.723
|
||||
c0-0.689,0.195-1.334,0.586-1.934s0.954-1.057,1.689-1.371c0.734-0.312,1.622-0.471,2.662-0.471c1.698,0,2.977,0.373,3.834,1.117
|
||||
c0.858,0.744,1.31,1.738,1.353,2.98l-2.731,0.121c-0.117-0.695-0.368-1.195-0.753-1.5c-0.384-0.305-0.961-0.457-1.729-0.457
|
||||
c-0.794,0-1.416,0.162-1.864,0.488c-0.29,0.209-0.435,0.49-0.435,0.84c0,0.32,0.136,0.594,0.406,0.822
|
||||
c0.345,0.289,1.182,0.59,2.511,0.904s2.312,0.639,2.948,0.973c0.637,0.336,1.135,0.795,1.495,1.375
|
||||
c0.359,0.582,0.54,1.301,0.54,2.156c0,0.775-0.216,1.5-0.646,2.178c-0.431,0.676-1.04,1.18-1.827,1.508
|
||||
c-0.787,0.33-1.769,0.494-2.943,0.494c-1.711,0-3.024-0.395-3.941-1.186C88.076,425.93,87.528,424.777,87.35,423.264z"/>
|
||||
<path fill="#7A65F5" d="M100.648,427.666v-13.529h10.031v2.289h-7.3v3h6.792v2.279h-6.792v3.682h7.559v2.279H100.648z"/>
|
||||
<path fill="#7A65F5" d="M113.328,427.666v-13.418h2.731v11.139h6.792v2.279H113.328z"/>
|
||||
<path fill="#7A65F5" d="M124.799,427.666v-13.529h10.031v2.289h-7.3v3h6.792v2.279h-6.792v3.682h7.559v2.279H124.799z"/>
|
||||
<path fill="#7A65F5" d="M146.062,422.691l2.648,0.84c-0.406,1.477-1.081,2.574-2.025,3.291s-2.143,1.074-3.595,1.074
|
||||
c-1.796,0-3.272-0.613-4.43-1.84c-1.156-1.229-1.734-2.906-1.734-5.035c0-2.252,0.581-4,1.744-5.246
|
||||
c1.162-1.246,2.691-1.869,4.586-1.869c1.655,0,3,0.49,4.033,1.469c0.615,0.578,1.076,1.408,1.384,2.49l-2.703,0.646
|
||||
c-0.16-0.701-0.494-1.256-1.002-1.66c-0.507-0.406-1.124-0.609-1.85-0.609c-1.003,0-1.817,0.359-2.441,1.08
|
||||
c-0.624,0.719-0.937,1.885-0.937,3.496c0,1.711,0.308,2.93,0.923,3.654c0.615,0.727,1.415,1.09,2.399,1.09
|
||||
c0.726,0,1.351-0.23,1.873-0.691C145.459,424.408,145.834,423.684,146.062,422.691z"/>
|
||||
<path fill="#7A65F5" d="M154.101,427.666v-11.24h-4.015v-2.289h10.751v2.289h-4.005v11.24H154.101z"/>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
</svg>
|
||||
|
|
Before Width: | Height: | Size: 8.7 KiB After Width: | Height: | Size: 20 KiB |
Binary file not shown.
Before Width: | Height: | Size: 525 KiB After Width: | Height: | Size: 518 KiB |
|
@ -18,7 +18,9 @@ static const char* ERROR_OVERFLOW = "Arguments overflow";
|
|||
|
||||
static struct CLIDebugger* _activeDebugger;
|
||||
|
||||
#ifndef NDEBUG
|
||||
static void _breakInto(struct CLIDebugger*, struct CLIDebugVector*);
|
||||
#endif
|
||||
static void _continue(struct CLIDebugger*, struct CLIDebugVector*);
|
||||
static void _disassemble(struct CLIDebugger*, struct CLIDebugVector*);
|
||||
static void _disassembleArm(struct CLIDebugger*, struct CLIDebugVector*);
|
||||
|
@ -56,6 +58,8 @@ static struct CLIDebuggerCommandSummary _debuggerCommands[] = {
|
|||
{ "b/a", _setBreakpointARM, CLIDVParse, "Set a software breakpoint as ARM" },
|
||||
{ "b/t", _setBreakpointThumb, CLIDVParse, "Set a software breakpoint as Thumb" },
|
||||
{ "break", _setBreakpoint, CLIDVParse, "Set a breakpoint" },
|
||||
{ "break/a", _setBreakpointARM, CLIDVParse, "Set a software breakpoint as ARM" },
|
||||
{ "break/t", _setBreakpointThumb, CLIDVParse, "Set a software breakpoint as Thumb" },
|
||||
{ "c", _continue, 0, "Continue execution" },
|
||||
{ "continue", _continue, 0, "Continue execution" },
|
||||
{ "d", _clearBreakpoint, CLIDVParse, "Delete a breakpoint" },
|
||||
|
@ -97,7 +101,9 @@ static struct CLIDebuggerCommandSummary _debuggerCommands[] = {
|
|||
{ "x/1", _dumpByte, CLIDVParse, "Examine bytes at a specified offset" },
|
||||
{ "x/2", _dumpHalfword, CLIDVParse, "Examine halfwords at a specified offset" },
|
||||
{ "x/4", _dumpWord, CLIDVParse, "Examine words at a specified offset" },
|
||||
#ifndef NDEBUG
|
||||
{ "!", _breakInto, 0, "Break into attached debugger (for developers)" },
|
||||
#endif
|
||||
{ 0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
|
@ -112,6 +118,7 @@ static inline void _printPSR(union PSR psr) {
|
|||
psr.t ? 'T' : '-');
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
static void _handleDeath(int sig) {
|
||||
UNUSED(sig);
|
||||
printf("No debugger attached!\n");
|
||||
|
@ -133,6 +140,7 @@ static void _breakInto(struct CLIDebugger* debugger, struct CLIDebugVector* dv)
|
|||
#endif
|
||||
sigaction(SIGTRAP, &osa, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void _continue(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
|
||||
UNUSED(dv);
|
||||
|
|
|
@ -167,7 +167,7 @@ void GBAAudioResizeBuffer(struct GBAAudio* audio, size_t samples) {
|
|||
int32_t GBAAudioProcessEvents(struct GBAAudio* audio, int32_t cycles) {
|
||||
audio->nextEvent -= cycles;
|
||||
audio->eventDiff += cycles;
|
||||
if (audio->nextEvent <= 0) {
|
||||
while (audio->nextEvent <= 0) {
|
||||
audio->nextEvent = INT_MAX;
|
||||
if (audio->enable) {
|
||||
if (audio->playingCh1 && !audio->ch1.envelope.dead) {
|
||||
|
|
|
@ -94,6 +94,7 @@ static void GBAInit(struct ARMCore* cpu, struct ARMComponent* component) {
|
|||
gba->idleDetectionFailures = 0;
|
||||
|
||||
gba->realisticTiming = true;
|
||||
gba->hardCrash = true;
|
||||
|
||||
gba->performingDMA = false;
|
||||
}
|
||||
|
@ -183,6 +184,11 @@ static void GBAProcessEvents(struct ARMCore* cpu) {
|
|||
int32_t cycles = cpu->nextEvent;
|
||||
int32_t nextEvent = INT_MAX;
|
||||
int32_t testEvent;
|
||||
#ifndef NDEBUG
|
||||
if (cycles < 0) {
|
||||
GBALog(gba, GBA_LOG_FATAL, "Negative cycles passed: %i", cycles);
|
||||
}
|
||||
#endif
|
||||
|
||||
gba->bus = cpu->prefetch[1];
|
||||
if (cpu->executionMode == MODE_THUMB) {
|
||||
|
@ -238,7 +244,7 @@ static int32_t GBATimersProcessEvents(struct GBA* gba, int32_t cycles) {
|
|||
if (timer->enable) {
|
||||
timer->nextEvent -= cycles;
|
||||
timer->lastEvent -= cycles;
|
||||
if (timer->nextEvent <= 0) {
|
||||
while (timer->nextEvent <= 0) {
|
||||
timer->lastEvent = timer->nextEvent;
|
||||
timer->nextEvent += timer->overflowInterval;
|
||||
gba->memory.io[REG_TM0CNT_LO >> 1] = timer->reload;
|
||||
|
|
|
@ -124,6 +124,7 @@ struct GBA {
|
|||
bool taintedRegisters[16];
|
||||
|
||||
bool realisticTiming;
|
||||
bool hardCrash;
|
||||
};
|
||||
|
||||
struct GBACartridge {
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
#include "gba/serialize.h"
|
||||
#include "util/hash.h"
|
||||
|
||||
const int GBA_LUX_LEVELS[10] = { 5, 11, 18, 27, 42, 62, 84, 109, 139, 183 };
|
||||
|
||||
static void _readPins(struct GBACartridgeHardware* hw);
|
||||
static void _outputPins(struct GBACartridgeHardware* hw, unsigned pins);
|
||||
|
||||
|
@ -610,6 +612,7 @@ void GBAHardwareDeserialize(struct GBACartridgeHardware* hw, const struct GBASer
|
|||
hw->readWrite = state->hw.readWrite;
|
||||
hw->pinState = state->hw.pinState;
|
||||
hw->direction = state->hw.pinDirection;
|
||||
hw->devices = state->hw.devices;
|
||||
hw->rtc = state->hw.rtc;
|
||||
hw->gyroSample = state->hw.gyroSample;
|
||||
hw->gyroEdge = state->hw.gyroEdge;
|
||||
|
@ -622,4 +625,7 @@ void GBAHardwareDeserialize(struct GBACartridgeHardware* hw, const struct GBASer
|
|||
hw->gbpInputsPosted = state->hw.gbpInputsPosted;
|
||||
hw->gbpTxPosition = state->hw.gbpTxPosition;
|
||||
hw->gbpNextEvent = state->hw.gbpNextEvent;
|
||||
if (hw->devices & HW_GB_PLAYER) {
|
||||
GBASIOSetDriver(&hw->p->sio, &hw->gbpDriver.d, SIO_NORMAL_32);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -433,8 +433,9 @@ int GBAInputClearAxis(const struct GBAInputMap* map, uint32_t type, int axis, in
|
|||
|
||||
void GBAInputBindAxis(struct GBAInputMap* map, uint32_t type, int axis, const struct GBAAxis* description) {
|
||||
struct GBAInputMapImpl* impl = _guaranteeMap(map, type);
|
||||
TableEnumerate(&impl->axes, _unbindAxis, &description->highDirection);
|
||||
TableEnumerate(&impl->axes, _unbindAxis, &description->lowDirection);
|
||||
struct GBAAxis d2 = *description;
|
||||
TableEnumerate(&impl->axes, _unbindAxis, &d2.highDirection);
|
||||
TableEnumerate(&impl->axes, _unbindAxis, &d2.lowDirection);
|
||||
struct GBAAxis* dup = malloc(sizeof(struct GBAAxis));
|
||||
*dup = *description;
|
||||
TableInsert(&impl->axes, axis, dup);
|
||||
|
|
|
@ -79,6 +79,8 @@ struct GBARotationSource {
|
|||
int32_t (*readGyroZ)(struct GBARotationSource*);
|
||||
};
|
||||
|
||||
extern const int GBA_LUX_LEVELS[10];
|
||||
|
||||
struct GBALuminanceSource {
|
||||
void (*sample)(struct GBALuminanceSource*);
|
||||
|
||||
|
|
|
@ -278,9 +278,11 @@ static void GBASetActiveRegion(struct ARMCore* cpu, uint32_t address) {
|
|||
memory->activeRegion = -1;
|
||||
cpu->memory.activeRegion = _deadbeef;
|
||||
cpu->memory.activeMask = 0;
|
||||
if (!gba->yankedRomSize) {
|
||||
GBALog(gba, GBA_LOG_FATAL, "Jumped to invalid address");
|
||||
enum GBALogLevel errorLevel = GBA_LOG_FATAL;
|
||||
if (gba->yankedRomSize || !gba->hardCrash) {
|
||||
errorLevel = GBA_LOG_GAME_ERROR;
|
||||
}
|
||||
GBALog(gba, errorLevel, "Jumped to invalid address: %08X", address);
|
||||
return;
|
||||
}
|
||||
cpu->memory.activeSeqCycles32 = memory->waitstatesSeq32[memory->activeRegion];
|
||||
|
@ -634,8 +636,12 @@ uint32_t GBALoad8(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
|
|||
#define STORE_VRAM \
|
||||
if ((address & 0x0001FFFF) < SIZE_VRAM) { \
|
||||
STORE_32(value, address & 0x0001FFFC, gba->video.renderer->vram); \
|
||||
gba->video.renderer->writeVRAM(gba->video.renderer, (address & 0x0001FFFC) + 2); \
|
||||
gba->video.renderer->writeVRAM(gba->video.renderer, (address & 0x0001FFFC)); \
|
||||
} else { \
|
||||
STORE_32(value, address & 0x00017FFC, gba->video.renderer->vram); \
|
||||
gba->video.renderer->writeVRAM(gba->video.renderer, (address & 0x00017FFC) + 2); \
|
||||
gba->video.renderer->writeVRAM(gba->video.renderer, (address & 0x00017FFC)); \
|
||||
} \
|
||||
wait += waitstatesRegion[REGION_VRAM];
|
||||
|
||||
|
@ -728,8 +734,10 @@ void GBAStore16(struct ARMCore* cpu, uint32_t address, int16_t value, int* cycle
|
|||
case REGION_VRAM:
|
||||
if ((address & 0x0001FFFF) < SIZE_VRAM) {
|
||||
STORE_16(value, address & 0x0001FFFE, gba->video.renderer->vram);
|
||||
gba->video.renderer->writeVRAM(gba->video.renderer, address & 0x0001FFFE);
|
||||
} else {
|
||||
STORE_16(value, address & 0x00017FFE, gba->video.renderer->vram);
|
||||
gba->video.renderer->writeVRAM(gba->video.renderer, address & 0x00017FFE);
|
||||
}
|
||||
break;
|
||||
case REGION_OAM:
|
||||
|
@ -794,8 +802,8 @@ void GBAStore8(struct ARMCore* cpu, uint32_t address, int8_t value, int* cycleCo
|
|||
GBALog(gba, GBA_LOG_GAME_ERROR, "Cannot Store8 to OBJ: 0x%08X", address);
|
||||
break;
|
||||
}
|
||||
((int8_t*) gba->video.renderer->vram)[address & 0x1FFFE] = value;
|
||||
((int8_t*) gba->video.renderer->vram)[(address & 0x1FFFE) | 1] = value;
|
||||
gba->video.renderer->vram[(address & 0x1FFFE) >> 1] = ((uint8_t) value) | (value << 8);
|
||||
gba->video.renderer->writeVRAM(gba->video.renderer, address & 0x0001FFFE);
|
||||
break;
|
||||
case REGION_OAM:
|
||||
GBALog(gba, GBA_LOG_GAME_ERROR, "Cannot Store8 to OAM: 0x%08X", address);
|
||||
|
@ -1397,7 +1405,7 @@ int32_t GBAMemoryRunDMAs(struct GBA* gba, int32_t cycles) {
|
|||
}
|
||||
memory->nextDMA -= cycles;
|
||||
memory->eventDiff += cycles;
|
||||
if (memory->nextDMA <= 0) {
|
||||
while (memory->nextDMA <= 0) {
|
||||
struct GBADMA* dma = &memory->dma[memory->activeDMA];
|
||||
GBAMemoryServiceDMA(gba, memory->activeDMA, dma);
|
||||
GBAMemoryUpdateDMAs(gba, memory->eventDiff);
|
||||
|
|
|
@ -116,6 +116,9 @@ int GBAVideoSoftwareRendererPreprocessSprite(struct GBAVideoSoftwareRenderer* re
|
|||
x >>= 23;
|
||||
uint16_t* vramBase = &renderer->d.vram[BASE_TILE >> 1];
|
||||
unsigned charBase = GBAObjAttributesCGetTile(sprite->c) * 0x20;
|
||||
if (GBARegisterDISPCNTGetMode(renderer->dispcnt) >= 3 && GBAObjAttributesCGetTile(sprite->c) < 512) {
|
||||
return 0;
|
||||
}
|
||||
int variant = renderer->target1Obj && GBAWindowControlIsBlendEnable(renderer->currentWindow.packed) && (renderer->blendEffect == BLEND_BRIGHTEN || renderer->blendEffect == BLEND_DARKEN);
|
||||
if (GBAObjAttributesAGetMode(sprite->a) == OBJ_MODE_SEMITRANSPARENT) {
|
||||
int target2 = renderer->target2Bd << 4;
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
static void GBAVideoSoftwareRendererInit(struct GBAVideoRenderer* renderer);
|
||||
static void GBAVideoSoftwareRendererDeinit(struct GBAVideoRenderer* renderer);
|
||||
static void GBAVideoSoftwareRendererReset(struct GBAVideoRenderer* renderer);
|
||||
static void GBAVideoSoftwareRendererWriteVRAM(struct GBAVideoRenderer* renderer, uint32_t address);
|
||||
static void GBAVideoSoftwareRendererWriteOAM(struct GBAVideoRenderer* renderer, uint32_t oam);
|
||||
static void GBAVideoSoftwareRendererWritePalette(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value);
|
||||
static uint16_t GBAVideoSoftwareRendererWriteVideoRegister(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value);
|
||||
|
@ -46,6 +47,7 @@ void GBAVideoSoftwareRendererCreate(struct GBAVideoSoftwareRenderer* renderer) {
|
|||
renderer->d.reset = GBAVideoSoftwareRendererReset;
|
||||
renderer->d.deinit = GBAVideoSoftwareRendererDeinit;
|
||||
renderer->d.writeVideoRegister = GBAVideoSoftwareRendererWriteVideoRegister;
|
||||
renderer->d.writeVRAM = GBAVideoSoftwareRendererWriteVRAM;
|
||||
renderer->d.writeOAM = GBAVideoSoftwareRendererWriteOAM;
|
||||
renderer->d.writePalette = GBAVideoSoftwareRendererWritePalette;
|
||||
renderer->d.drawScanline = GBAVideoSoftwareRendererDrawScanline;
|
||||
|
@ -327,6 +329,11 @@ static uint16_t GBAVideoSoftwareRendererWriteVideoRegister(struct GBAVideoRender
|
|||
return value;
|
||||
}
|
||||
|
||||
static void GBAVideoSoftwareRendererWriteVRAM(struct GBAVideoRenderer* renderer, uint32_t address) {
|
||||
UNUSED(renderer);
|
||||
UNUSED(address);
|
||||
}
|
||||
|
||||
static void GBAVideoSoftwareRendererWriteOAM(struct GBAVideoRenderer* renderer, uint32_t oam) {
|
||||
struct GBAVideoSoftwareRenderer* softwareRenderer = (struct GBAVideoSoftwareRenderer*) renderer;
|
||||
softwareRenderer->oamDirty = 1;
|
||||
|
|
|
@ -87,6 +87,10 @@ bool GBADeserialize(struct GBA* gba, const struct GBASerializedState* state) {
|
|||
GBALog(gba, GBA_LOG_WARN, "Savestate is corrupted: CPU cycles are negative");
|
||||
error = true;
|
||||
}
|
||||
if (state->cpu.nextEvent < 0) {
|
||||
GBALog(gba, GBA_LOG_WARN, "Savestate is corrupted: Next event is negative");
|
||||
error = true;
|
||||
}
|
||||
if (state->video.eventDiff < 0) {
|
||||
GBALog(gba, GBA_LOG_WARN, "Savestate is corrupted: video eventDiff is negative");
|
||||
error = true;
|
||||
|
@ -99,6 +103,10 @@ bool GBADeserialize(struct GBA* gba, const struct GBASerializedState* state) {
|
|||
GBALog(gba, GBA_LOG_WARN, "Savestate is corrupted: overflowInterval is negative");
|
||||
error = true;
|
||||
}
|
||||
if (state->timers[0].nextEvent < 0 || state->timers[1].nextEvent < 0 || state->timers[2].nextEvent < 0 || state->timers[3].nextEvent < 0) {
|
||||
GBALog(gba, GBA_LOG_WARN, "Savestate is corrupted: timer nextEvent is negative");
|
||||
error = true;
|
||||
}
|
||||
if (state->audio.eventDiff < 0) {
|
||||
GBALog(gba, GBA_LOG_WARN, "Savestate is corrupted: audio eventDiff is negative");
|
||||
error = true;
|
||||
|
|
|
@ -247,6 +247,7 @@ void GBAConfigMap(const struct GBAConfig* config, struct GBAOptions* opts) {
|
|||
if (_lookupUIntValue(config, "audioBuffers", &audioBuffers)) {
|
||||
opts->audioBuffers = audioBuffers;
|
||||
}
|
||||
_lookupUIntValue(config, "sampleRate", &opts->sampleRate);
|
||||
|
||||
int fakeBool;
|
||||
if (_lookupIntValue(config, "useBios", &fakeBool)) {
|
||||
|
@ -305,6 +306,7 @@ void GBAConfigLoadDefaults(struct GBAConfig* config, const struct GBAOptions* op
|
|||
ConfigurationSetIntValue(&config->defaultsTable, 0, "rewindBufferInterval", opts->rewindBufferInterval);
|
||||
ConfigurationSetFloatValue(&config->defaultsTable, 0, "fpsTarget", opts->fpsTarget);
|
||||
ConfigurationSetUIntValue(&config->defaultsTable, 0, "audioBuffers", opts->audioBuffers);
|
||||
ConfigurationSetUIntValue(&config->defaultsTable, 0, "sampleRate", opts->sampleRate);
|
||||
ConfigurationSetIntValue(&config->defaultsTable, 0, "audioSync", opts->audioSync);
|
||||
ConfigurationSetIntValue(&config->defaultsTable, 0, "videoSync", opts->videoSync);
|
||||
ConfigurationSetIntValue(&config->defaultsTable, 0, "fullscreen", opts->fullscreen);
|
||||
|
|
|
@ -29,6 +29,7 @@ struct GBAOptions {
|
|||
int rewindBufferInterval;
|
||||
float fpsTarget;
|
||||
size_t audioBuffers;
|
||||
unsigned sampleRate;
|
||||
|
||||
int fullscreen;
|
||||
int width;
|
||||
|
|
|
@ -419,6 +419,16 @@ bool GBAThreadStart(struct GBAThread* threadContext) {
|
|||
|
||||
threadContext->save = VDirOptionalOpenFile(threadContext->stateDir, threadContext->fname, "sram", ".sav", O_CREAT | O_RDWR);
|
||||
|
||||
if (!threadContext->patch) {
|
||||
threadContext->patch = VDirOptionalOpenFile(threadContext->stateDir, threadContext->fname, "patch", ".ups", O_RDONLY);
|
||||
}
|
||||
if (!threadContext->patch) {
|
||||
threadContext->patch = VDirOptionalOpenFile(threadContext->stateDir, threadContext->fname, "patch", ".ips", O_RDONLY);
|
||||
}
|
||||
if (!threadContext->patch) {
|
||||
threadContext->patch = VDirOptionalOpenFile(threadContext->stateDir, threadContext->fname, "patch", ".bps", O_RDONLY);
|
||||
}
|
||||
|
||||
MutexInit(&threadContext->stateMutex);
|
||||
ConditionInit(&threadContext->stateCond);
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@ static void GBAVideoDummyRendererInit(struct GBAVideoRenderer* renderer);
|
|||
static void GBAVideoDummyRendererReset(struct GBAVideoRenderer* renderer);
|
||||
static void GBAVideoDummyRendererDeinit(struct GBAVideoRenderer* renderer);
|
||||
static uint16_t GBAVideoDummyRendererWriteVideoRegister(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value);
|
||||
static void GBAVideoDummyRendererWriteVRAM(struct GBAVideoRenderer* renderer, uint32_t address);
|
||||
static void GBAVideoDummyRendererWritePalette(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value);
|
||||
static void GBAVideoDummyRendererWriteOAM(struct GBAVideoRenderer* renderer, uint32_t oam);
|
||||
static void GBAVideoDummyRendererDrawScanline(struct GBAVideoRenderer* renderer, int y);
|
||||
|
@ -47,6 +48,7 @@ static struct GBAVideoRenderer dummyRenderer = {
|
|||
.reset = GBAVideoDummyRendererReset,
|
||||
.deinit = GBAVideoDummyRendererDeinit,
|
||||
.writeVideoRegister = GBAVideoDummyRendererWriteVideoRegister,
|
||||
.writeVRAM = GBAVideoDummyRendererWriteVRAM,
|
||||
.writePalette = GBAVideoDummyRendererWritePalette,
|
||||
.writeOAM = GBAVideoDummyRendererWriteOAM,
|
||||
.drawScanline = GBAVideoDummyRendererDrawScanline,
|
||||
|
@ -65,7 +67,7 @@ void GBAVideoReset(struct GBAVideo* video) {
|
|||
video->lastHblank = 0;
|
||||
video->nextHblank = VIDEO_HDRAW_LENGTH;
|
||||
video->nextEvent = video->nextHblank;
|
||||
video->eventDiff = video->nextEvent;
|
||||
video->eventDiff = 0;
|
||||
|
||||
video->nextHblankIRQ = 0;
|
||||
video->nextVblankIRQ = 0;
|
||||
|
@ -222,6 +224,12 @@ static uint16_t GBAVideoDummyRendererWriteVideoRegister(struct GBAVideoRenderer*
|
|||
return value;
|
||||
}
|
||||
|
||||
static void GBAVideoDummyRendererWriteVRAM(struct GBAVideoRenderer* renderer, uint32_t address) {
|
||||
UNUSED(renderer);
|
||||
UNUSED(address);
|
||||
// Nothing to do
|
||||
}
|
||||
|
||||
static void GBAVideoDummyRendererWritePalette(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value) {
|
||||
UNUSED(renderer);
|
||||
UNUSED(address);
|
||||
|
|
|
@ -161,6 +161,7 @@ struct GBAVideoRenderer {
|
|||
void (*deinit)(struct GBAVideoRenderer* renderer);
|
||||
|
||||
uint16_t (*writeVideoRegister)(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value);
|
||||
void (*writeVRAM)(struct GBAVideoRenderer* renderer, uint32_t address);
|
||||
void (*writePalette)(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value);
|
||||
void (*writeOAM)(struct GBAVideoRenderer* renderer, uint32_t oam);
|
||||
void (*drawScanline)(struct GBAVideoRenderer* renderer, int y);
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "util/common.h"
|
||||
|
||||
#include "gba/gba.h"
|
||||
#include "gba/interface.h"
|
||||
#include "gba/renderers/video-software.h"
|
||||
#include "gba/serialize.h"
|
||||
#include "gba/supervisor/overrides.h"
|
||||
|
@ -18,6 +19,8 @@
|
|||
#define SAMPLES 1024
|
||||
#define RUMBLE_PWM 35
|
||||
|
||||
#define SOLAR_SENSOR_LEVEL "mgba_solar_sensor_level"
|
||||
|
||||
static retro_environment_t environCallback;
|
||||
static retro_video_refresh_t videoCallback;
|
||||
static retro_audio_sample_batch_t audioCallback;
|
||||
|
@ -31,6 +34,8 @@ static void GBARetroLog(struct GBAThread* thread, enum GBALogLevel level, const
|
|||
static void _postAudioBuffer(struct GBAAVStream*, struct GBAAudio* audio);
|
||||
static void _postVideoFrame(struct GBAAVStream*, struct GBAVideoRenderer* renderer);
|
||||
static void _setRumble(struct GBARumble* rumble, int enable);
|
||||
static uint8_t _readLux(struct GBALuminanceSource* lux);
|
||||
static void _updateLux(struct GBALuminanceSource* lux);
|
||||
|
||||
static struct GBA gba;
|
||||
static struct ARMCore cpu;
|
||||
|
@ -44,6 +49,8 @@ static struct GBAAVStream stream;
|
|||
static int rumbleLevel;
|
||||
static struct CircleBuffer rumbleHistory;
|
||||
static struct GBARumble rumble;
|
||||
static struct GBALuminanceSource lux;
|
||||
static int luxLevel;
|
||||
|
||||
unsigned retro_api_version(void) {
|
||||
return RETRO_API_VERSION;
|
||||
|
@ -51,6 +58,13 @@ unsigned retro_api_version(void) {
|
|||
|
||||
void retro_set_environment(retro_environment_t env) {
|
||||
environCallback = env;
|
||||
|
||||
struct retro_variable vars[] = {
|
||||
{ SOLAR_SENSOR_LEVEL, "Solar sensor level; 0|1|2|3|4|5|6|7|8|9|10" },
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
environCallback(RETRO_ENVIRONMENT_SET_VARIABLES, vars);
|
||||
}
|
||||
|
||||
void retro_set_video_refresh(retro_video_refresh_t video) {
|
||||
|
@ -115,7 +129,9 @@ void retro_init(void) {
|
|||
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP, "Up" },
|
||||
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN, "Down" },
|
||||
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R, "R" },
|
||||
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L, "L" }
|
||||
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L, "L" },
|
||||
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R3, "Brighten Solar Sensor" },
|
||||
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L3, "Darken Solar Sensor" }
|
||||
};
|
||||
environCallback(RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS, &inputDescriptors);
|
||||
|
||||
|
@ -130,6 +146,11 @@ void retro_init(void) {
|
|||
rumbleCallback = 0;
|
||||
}
|
||||
|
||||
luxLevel = 0;
|
||||
lux.readLuminance = _readLux;
|
||||
lux.sample = _updateLux;
|
||||
_updateLux(&lux);
|
||||
|
||||
struct retro_log_callback log;
|
||||
if (environCallback(RETRO_ENVIRONMENT_GET_LOG_INTERFACE, &log)) {
|
||||
logCallback = log.log;
|
||||
|
@ -151,6 +172,7 @@ void retro_init(void) {
|
|||
if (rumbleCallback) {
|
||||
gba.rumble = &rumble;
|
||||
}
|
||||
gba.luminanceSource = &lux;
|
||||
rom = 0;
|
||||
|
||||
const char* sysDir = 0;
|
||||
|
@ -201,6 +223,26 @@ void retro_run(void) {
|
|||
keys |= (!!inputCallback(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R)) << 8;
|
||||
keys |= (!!inputCallback(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L)) << 9;
|
||||
|
||||
static bool wasAdjustingLux = false;
|
||||
if (wasAdjustingLux) {
|
||||
wasAdjustingLux = inputCallback(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R3) ||
|
||||
inputCallback(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L3);
|
||||
} else {
|
||||
if (inputCallback(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R3)) {
|
||||
++luxLevel;
|
||||
if (luxLevel > 10) {
|
||||
luxLevel = 10;
|
||||
}
|
||||
wasAdjustingLux = true;
|
||||
} else if (inputCallback(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L3)) {
|
||||
--luxLevel;
|
||||
if (luxLevel < 0) {
|
||||
luxLevel = 0;
|
||||
}
|
||||
wasAdjustingLux = true;
|
||||
}
|
||||
}
|
||||
|
||||
int frameCount = gba.video.frameCounter;
|
||||
while (gba.video.frameCounter == frameCount) {
|
||||
ARMRunLoop(&cpu);
|
||||
|
@ -401,3 +443,40 @@ static void _setRumble(struct GBARumble* rumble, int enable) {
|
|||
CircleBufferWrite8(&rumbleHistory, enable);
|
||||
rumbleCallback(0, RETRO_RUMBLE_STRONG, rumbleLevel * 0xFFFF / RUMBLE_PWM);
|
||||
}
|
||||
|
||||
static void _updateLux(struct GBALuminanceSource* lux) {
|
||||
UNUSED(lux);
|
||||
struct retro_variable var = {
|
||||
.key = SOLAR_SENSOR_LEVEL,
|
||||
.value = 0
|
||||
};
|
||||
|
||||
bool updated = false;
|
||||
if (!environCallback(RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE, &updated) || !updated) {
|
||||
return;
|
||||
}
|
||||
if (!environCallback(RETRO_ENVIRONMENT_GET_VARIABLE, &var) || !var.value) {
|
||||
return;
|
||||
}
|
||||
|
||||
char* end;
|
||||
int newLuxLevel = strtol(var.value, &end, 10);
|
||||
if (!*end) {
|
||||
if (newLuxLevel > 10) {
|
||||
luxLevel = 10;
|
||||
} else if (newLuxLevel < 0) {
|
||||
luxLevel = 0;
|
||||
} else {
|
||||
luxLevel = newLuxLevel;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t _readLux(struct GBALuminanceSource* lux) {
|
||||
UNUSED(lux);
|
||||
int value = 0x16;
|
||||
if (luxLevel > 0) {
|
||||
value += GBA_LUX_LEVELS[luxLevel - 1];
|
||||
}
|
||||
return 0xFF - value;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,136 @@
|
|||
/* Copyright (c) 2013-2015 Jeffrey Pfau
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#include "gles2.h"
|
||||
|
||||
#include "gba/video.h"
|
||||
|
||||
static const char* const _vertexShader =
|
||||
"attribute vec4 position;\n"
|
||||
"varying vec2 texCoord;\n"
|
||||
|
||||
"void main() {\n"
|
||||
" gl_Position = position;\n"
|
||||
" texCoord = (position.st + vec2(1.0, -1.0)) * vec2(0.46875, -0.3125);\n"
|
||||
"}";
|
||||
|
||||
static const char* const _fragmentShader =
|
||||
"varying vec2 texCoord;\n"
|
||||
"uniform sampler2D tex;\n"
|
||||
|
||||
"void main() {\n"
|
||||
" vec4 color = texture2D(tex, texCoord);\n"
|
||||
" color.a = 1.;\n"
|
||||
" gl_FragColor = color;"
|
||||
"}";
|
||||
|
||||
static const GLfloat _vertices[] = {
|
||||
-1.f, -1.f,
|
||||
-1.f, 1.f,
|
||||
1.f, 1.f,
|
||||
1.f, -1.f,
|
||||
};
|
||||
|
||||
static void GBAGLES2ContextInit(struct VideoBackend* v, WHandle handle) {
|
||||
UNUSED(handle);
|
||||
struct GBAGLES2Context* context = (struct GBAGLES2Context*) v;
|
||||
glGenTextures(1, &context->tex);
|
||||
glBindTexture(GL_TEXTURE_2D, context->tex);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
|
||||
#ifdef COLOR_16_BIT
|
||||
#ifdef COLOR_5_6_5
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, 0);
|
||||
#else
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, 0);
|
||||
#endif
|
||||
#else
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
|
||||
#endif
|
||||
|
||||
glShaderSource(context->fragmentShader, 1, (const GLchar**) &_fragmentShader, 0);
|
||||
glShaderSource(context->vertexShader, 1, (const GLchar**) &_vertexShader, 0);
|
||||
glAttachShader(context->program, context->vertexShader);
|
||||
glAttachShader(context->program, context->fragmentShader);
|
||||
char log[1024];
|
||||
glCompileShader(context->fragmentShader);
|
||||
glCompileShader(context->vertexShader);
|
||||
glGetShaderInfoLog(context->fragmentShader, 1024, 0, log);
|
||||
glGetShaderInfoLog(context->vertexShader, 1024, 0, log);
|
||||
glLinkProgram(context->program);
|
||||
glGetProgramInfoLog(context->program, 1024, 0, log);
|
||||
printf("%s\n", log);
|
||||
context->texLocation = glGetUniformLocation(context->program, "tex");
|
||||
context->positionLocation = glGetAttribLocation(context->program, "position");
|
||||
glClearColor(0.f, 0.f, 0.f, 1.f);
|
||||
}
|
||||
|
||||
static void GBAGLES2ContextDeinit(struct VideoBackend* v) {
|
||||
struct GBAGLES2Context* context = (struct GBAGLES2Context*) v;
|
||||
glDeleteTextures(1, &context->tex);
|
||||
}
|
||||
|
||||
static void GBAGLES2ContextResized(struct VideoBackend* v, int w, int h) {
|
||||
int drawW = w;
|
||||
int drawH = h;
|
||||
if (v->lockAspectRatio) {
|
||||
if (w * 2 > h * 3) {
|
||||
drawW = h * 3 / 2;
|
||||
} else if (w * 2 < h * 3) {
|
||||
drawH = w * 2 / 3;
|
||||
}
|
||||
}
|
||||
glViewport(0, 0, 240, 160);
|
||||
glClearColor(0.f, 0.f, 0.f, 1.f);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
glViewport((w - drawW) / 2, (h - drawH) / 2, drawW, drawH);
|
||||
}
|
||||
|
||||
static void GBAGLES2ContextClear(struct VideoBackend* v) {
|
||||
UNUSED(v);
|
||||
glClearColor(0.f, 0.f, 0.f, 1.f);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
}
|
||||
|
||||
void GBAGLES2ContextDrawFrame(struct VideoBackend* v) {
|
||||
struct GBAGLES2Context* context = (struct GBAGLES2Context*) v;
|
||||
glUseProgram(context->program);
|
||||
glUniform1i(context->texLocation, 0);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, context->tex);
|
||||
glVertexAttribPointer(context->positionLocation, 2, GL_FLOAT, GL_FALSE, 0, _vertices);
|
||||
glEnableVertexAttribArray(context->positionLocation);
|
||||
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
|
||||
glUseProgram(0);
|
||||
}
|
||||
|
||||
void GBAGLES2ContextPostFrame(struct VideoBackend* v, const void* frame) {
|
||||
struct GBAGLES2Context* context = (struct GBAGLES2Context*) v;
|
||||
glBindTexture(GL_TEXTURE_2D, context->tex);
|
||||
#ifdef COLOR_16_BIT
|
||||
#ifdef COLOR_5_6_5
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, frame);
|
||||
#else
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, frame);
|
||||
#endif
|
||||
#else
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, frame);
|
||||
#endif
|
||||
}
|
||||
|
||||
void GBAGLES2ContextCreate(struct GBAGLES2Context* context) {
|
||||
context->d.init = GBAGLES2ContextInit;
|
||||
context->d.deinit = GBAGLES2ContextDeinit;
|
||||
context->d.resized = GBAGLES2ContextResized;
|
||||
context->d.swap = 0;
|
||||
context->d.clear = GBAGLES2ContextClear;
|
||||
context->d.postFrame = GBAGLES2ContextPostFrame;
|
||||
context->d.drawFrame = GBAGLES2ContextDrawFrame;
|
||||
context->d.setMessage = 0;
|
||||
context->d.clearMessage = 0;
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
/* Copyright (c) 2013-2015 Jeffrey Pfau
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#ifndef GLES2_H
|
||||
#define GLES2_H
|
||||
|
||||
#include <GLES2/gl2.h>
|
||||
|
||||
#include "platform/video-backend.h"
|
||||
|
||||
struct GBAGLES2Context {
|
||||
struct VideoBackend d;
|
||||
|
||||
GLuint tex;
|
||||
GLuint fragmentShader;
|
||||
GLuint vertexShader;
|
||||
GLuint program;
|
||||
GLuint bufferObject;
|
||||
GLuint texLocation;
|
||||
GLuint positionLocation;
|
||||
};
|
||||
|
||||
void GBAGLES2ContextCreate(struct GBAGLES2Context*);
|
||||
|
||||
#endif
|
|
@ -186,7 +186,7 @@ static void _GBAPerfRunloop(struct GBAThread* context, int* frames, bool quiet)
|
|||
}
|
||||
}
|
||||
GBASyncWaitFrameEnd(&context->sync);
|
||||
if (*frames == duration) {
|
||||
if (duration > 0 && *frames == duration) {
|
||||
_GBAPerfShutdown(0);
|
||||
}
|
||||
if (_dispatchExiting) {
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
#include <pthread.h>
|
||||
#include <sys/time.h>
|
||||
#ifdef __FreeBSD__
|
||||
#if defined(__FreeBSD__) || defined(__OpenBSD__)
|
||||
#include <pthread_np.h>
|
||||
#endif
|
||||
|
||||
|
@ -79,7 +79,7 @@ static inline int ThreadJoin(Thread thread) {
|
|||
static inline int ThreadSetName(const char* name) {
|
||||
#ifdef __APPLE__
|
||||
return pthread_setname_np(name);
|
||||
#elif defined(__FreeBSD__)
|
||||
#elif defined(__FreeBSD__) || defined(__OpenBSD__)
|
||||
pthread_set_name_np(pthread_self(), name);
|
||||
return 0;
|
||||
#else
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
/* Copyright (c) 2013-2015 Jeffrey Pfau
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#include "AboutScreen.h"
|
||||
|
||||
#include "util/version.h"
|
||||
|
||||
#include <QPixmap>
|
||||
|
||||
using namespace QGBA;
|
||||
|
||||
AboutScreen::AboutScreen(QWidget* parent)
|
||||
: QDialog(parent)
|
||||
{
|
||||
m_ui.setupUi(this);
|
||||
|
||||
QPixmap logo(":/res/mgba-1024.png");
|
||||
logo = logo.scaled(m_ui.logo->minimumSize() * devicePixelRatio(), Qt::KeepAspectRatio, Qt::SmoothTransformation);
|
||||
logo.setDevicePixelRatio(devicePixelRatio());
|
||||
m_ui.logo->setPixmap(logo);
|
||||
|
||||
m_ui.projectName->setText(QLatin1String(projectName));
|
||||
m_ui.projectVersion->setText(QLatin1String(projectVersion));
|
||||
QString gitInfo = m_ui.gitInfo->text();
|
||||
gitInfo.replace("{gitBranch}", QLatin1String(gitBranch));
|
||||
gitInfo.replace("{gitCommit}", QLatin1String(gitCommit));
|
||||
m_ui.gitInfo->setText(gitInfo);
|
||||
QString description = m_ui.description->text();
|
||||
description.replace("{projectName}", QLatin1String(projectName));
|
||||
m_ui.description->setText(description);
|
||||
QString extraLinks = m_ui.extraLinks->text();
|
||||
extraLinks.replace("{gitBranch}", QLatin1String(gitBranch));
|
||||
m_ui.extraLinks->setText(extraLinks);
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
/* Copyright (c) 2013-2014 Jeffrey Pfau
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#ifndef QGBA_ABOUT_SCREEN
|
||||
#define QGBA_ABOUT_SCREEN
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
#include "ui_AboutScreen.h"
|
||||
|
||||
namespace QGBA {
|
||||
|
||||
class AboutScreen : public QDialog {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
AboutScreen(QWidget* parent = nullptr);
|
||||
|
||||
private:
|
||||
Ui::AboutScreen m_ui;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,177 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>AboutScreen</class>
|
||||
<widget class="QWidget" name="AboutScreen">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>565</width>
|
||||
<height>268</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>About</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<property name="sizeConstraint">
|
||||
<enum>QLayout::SetFixedSize</enum>
|
||||
</property>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLabel" name="projectName">
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>36</pointsize>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>{projectName}</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0" colspan="4">
|
||||
<widget class="QLabel" name="copyright">
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>10</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>© 2013 – 2015 Jeffrey Pfau — Game Boy Advance is a registered trademark of Nintendo Co., Ltd.</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLabel" name="projectVersion">
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>{projectVersion}</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft</set>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0" rowspan="6">
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="leftMargin">
|
||||
<number>8</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>16</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>12</number>
|
||||
</property>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="logo">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>256</width>
|
||||
<height>192</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>{logo}</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QLabel" name="description">
|
||||
<property name="text">
|
||||
<string>{projectName} is an open-source Game Boy Advance emulator</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QLabel" name="extraLinks">
|
||||
<property name="text">
|
||||
<string><a href="http://mgba.io/">Website</a> • <a href="https://forums.mgba.io/">Forums / Support</a> • <a href="https://github.com/mgba-emu/mgba/tree/{gitBranch}">Source</a> • <a href="https://github.com/mgba-emu/mgba/blob/{gitBranch}/LICENSE">License</a></string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
<property name="openExternalLinks">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QLabel" name="gitInfo">
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>10</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Branch: <tt>{gitBranch}</tt><br/>Revision: <tt>{gitCommit}</tt></string>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
|
@ -38,10 +38,10 @@ AudioProcessor* AudioProcessor::create() {
|
|||
#endif
|
||||
|
||||
default:
|
||||
#ifdef BUILD_QT_MULTIMEDIA
|
||||
return new AudioProcessorQt();
|
||||
#else
|
||||
#ifdef BUILD_SDL
|
||||
return new AudioProcessorSDL();
|
||||
#else
|
||||
return new AudioProcessorQt();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@ public:
|
|||
|
||||
virtual void setInput(GBAThread* input);
|
||||
int getBufferSamples() const { return m_samples; }
|
||||
virtual unsigned sampleRate() const = 0;
|
||||
|
||||
public slots:
|
||||
virtual void start() = 0;
|
||||
|
@ -39,7 +40,7 @@ public slots:
|
|||
virtual void setBufferSamples(int samples) = 0;
|
||||
virtual void inputParametersChanged() = 0;
|
||||
|
||||
virtual unsigned sampleRate() const = 0;
|
||||
virtual void requestSampleRate(unsigned) = 0;
|
||||
|
||||
protected:
|
||||
GBAThread* input() { return m_context; }
|
||||
|
|
|
@ -20,6 +20,7 @@ AudioProcessorQt::AudioProcessorQt(QObject* parent)
|
|||
: AudioProcessor(parent)
|
||||
, m_audioOutput(nullptr)
|
||||
, m_device(nullptr)
|
||||
, m_sampleRate(44100)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -45,7 +46,7 @@ void AudioProcessorQt::start() {
|
|||
|
||||
if (!m_audioOutput) {
|
||||
QAudioFormat format;
|
||||
format.setSampleRate(44100);
|
||||
format.setSampleRate(m_sampleRate);
|
||||
format.setChannelCount(2);
|
||||
format.setSampleSize(16);
|
||||
format.setCodec("audio/pcm");
|
||||
|
@ -84,6 +85,15 @@ void AudioProcessorQt::inputParametersChanged() {
|
|||
}
|
||||
}
|
||||
|
||||
void AudioProcessorQt::requestSampleRate(unsigned rate) {
|
||||
m_sampleRate = rate;
|
||||
if (m_device) {
|
||||
QAudioFormat format(m_audioOutput->format());
|
||||
format.setSampleRate(rate);
|
||||
m_device->setFormat(format);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned AudioProcessorQt::sampleRate() const {
|
||||
if (!m_audioOutput) {
|
||||
return 0;
|
||||
|
|
|
@ -20,6 +20,7 @@ public:
|
|||
AudioProcessorQt(QObject* parent = nullptr);
|
||||
|
||||
virtual void setInput(GBAThread* input);
|
||||
virtual unsigned sampleRate() const override;
|
||||
|
||||
public slots:
|
||||
virtual void start();
|
||||
|
@ -28,11 +29,12 @@ public slots:
|
|||
virtual void setBufferSamples(int samples);
|
||||
virtual void inputParametersChanged();
|
||||
|
||||
virtual unsigned sampleRate() const override;
|
||||
virtual void requestSampleRate(unsigned) override;
|
||||
|
||||
private:
|
||||
QAudioOutput* m_audioOutput;
|
||||
AudioDevice* m_device;
|
||||
unsigned m_sampleRate;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ using namespace QGBA;
|
|||
|
||||
AudioProcessorSDL::AudioProcessorSDL(QObject* parent)
|
||||
: AudioProcessor(parent)
|
||||
, m_audio()
|
||||
, m_audio{ 2048, 44100 }
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -55,6 +55,18 @@ void AudioProcessorSDL::setBufferSamples(int samples) {
|
|||
void AudioProcessorSDL::inputParametersChanged() {
|
||||
}
|
||||
|
||||
unsigned AudioProcessorSDL::sampleRate() const {
|
||||
return m_audio.obtainedSpec.freq;
|
||||
void AudioProcessorSDL::requestSampleRate(unsigned rate) {
|
||||
m_audio.sampleRate = rate;
|
||||
if (m_audio.thread) {
|
||||
GBASDLDeinitAudio(&m_audio);
|
||||
GBASDLInitAudio(&m_audio, input());
|
||||
}
|
||||
}
|
||||
|
||||
unsigned AudioProcessorSDL::sampleRate() const {
|
||||
if (m_audio.thread) {
|
||||
return m_audio.obtainedSpec.freq;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,6 +22,8 @@ public:
|
|||
AudioProcessorSDL(QObject* parent = nullptr);
|
||||
~AudioProcessorSDL();
|
||||
|
||||
virtual unsigned sampleRate() const override;
|
||||
|
||||
public slots:
|
||||
virtual void start();
|
||||
virtual void pause();
|
||||
|
@ -29,7 +31,7 @@ public slots:
|
|||
virtual void setBufferSamples(int samples);
|
||||
virtual void inputParametersChanged();
|
||||
|
||||
virtual unsigned sampleRate() const override;
|
||||
virtual void requestSampleRate(unsigned) override;
|
||||
|
||||
private:
|
||||
GBASDLAudio m_audio;
|
||||
|
|
|
@ -28,17 +28,31 @@ endif()
|
|||
set(CMAKE_AUTOMOC ON)
|
||||
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||
|
||||
if(NOT WIN32 OR NOT BUILD_SDL)
|
||||
find_package(Qt5Multimedia)
|
||||
endif()
|
||||
find_package(Qt5OpenGL)
|
||||
find_package(Qt5Widgets)
|
||||
|
||||
if(NOT Qt5OpenGL_FOUND OR NOT Qt5Widgets_FOUND OR NOT OPENGL_FOUND)
|
||||
if(NOT BUILD_GL AND NOT BUILD_GLES2)
|
||||
message(WARNING "OpenGL is required to build the Qt port")
|
||||
set(BUILD_QT OFF PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
|
||||
if(NOT Qt5OpenGL_FOUND OR NOT Qt5Widgets_FOUND)
|
||||
message(WARNING "Cannot find Qt modules")
|
||||
set(BUILD_QT OFF PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
|
||||
if(BUILD_GL)
|
||||
list(APPEND PLATFORM_SRC ${PLATFORM_SRC} ${CMAKE_SOURCE_DIR}/src/platform/opengl/gl.c)
|
||||
endif()
|
||||
|
||||
if(BUILD_GLES2)
|
||||
list(APPEND PLATFORM_SRC ${PLATFORM_SRC} ${CMAKE_SOURCE_DIR}/src/platform/opengl/gles2.c)
|
||||
endif()
|
||||
|
||||
get_target_property(QT_TYPE Qt5::Core TYPE)
|
||||
if(QT_TYPE STREQUAL STATIC_LIBRARY)
|
||||
|
@ -47,6 +61,7 @@ if(QT_TYPE STREQUAL STATIC_LIBRARY)
|
|||
endif()
|
||||
|
||||
set(SOURCE_FILES
|
||||
AboutScreen.cpp
|
||||
AudioProcessor.cpp
|
||||
CheatsModel.cpp
|
||||
CheatsView.cpp
|
||||
|
@ -83,6 +98,7 @@ set(SOURCE_FILES
|
|||
VideoView.cpp)
|
||||
|
||||
qt5_wrap_ui(UI_FILES
|
||||
AboutScreen.ui
|
||||
CheatsView.ui
|
||||
GIFView.ui
|
||||
LoadSaveState.ui
|
||||
|
@ -142,7 +158,7 @@ add_executable(${BINARY_NAME}-qt WIN32 MACOSX_BUNDLE main.cpp ${CMAKE_SOURCE_DIR
|
|||
set_target_properties(${BINARY_NAME}-qt PROPERTIES MACOSX_BUNDLE_INFO_PLIST ${CMAKE_SOURCE_DIR}/res/info.plist.in COMPILE_DEFINITIONS "${FEATURE_DEFINES}")
|
||||
|
||||
list(APPEND QT_LIBRARIES Qt5::Widgets Qt5::OpenGL)
|
||||
target_link_libraries(${BINARY_NAME}-qt ${PLATFORM_LIBRARY} ${OPENGL_LIBRARY} ${BINARY_NAME} ${QT_LIBRARIES})
|
||||
target_link_libraries(${BINARY_NAME}-qt ${PLATFORM_LIBRARY} ${BINARY_NAME} ${QT_LIBRARIES} ${OPENGL_LIBRARY} ${OPENGLES2_LIBRARY})
|
||||
set(CPACK_DEBIAN_PACKAGE_DEPENDS "${CPACK_DEBIAN_PACKAGE_DEPENDS}" PARENT_SCOPE)
|
||||
|
||||
install(TARGETS ${BINARY_NAME}-qt
|
||||
|
@ -154,6 +170,9 @@ if(UNIX AND NOT APPLE)
|
|||
install(CODE "execute_process(COMMAND ${DESKTOP_FILE_INSTALL} \"${CMAKE_SOURCE_DIR}/res/mgba-qt.desktop\" --dir \"$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/share/applications/\")")
|
||||
endif()
|
||||
endif()
|
||||
if(UNIX)
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/doc/mgba-qt.6 DESTINATION ${MANDIR}/man6 COMPONENT ${BINARY_NAME}-qt)
|
||||
endif()
|
||||
if(APPLE OR WIN32)
|
||||
set_target_properties(${BINARY_NAME}-qt PROPERTIES OUTPUT_NAME ${PROJECT_NAME})
|
||||
endif()
|
||||
|
|
|
@ -99,19 +99,29 @@ void CheatsView::removeSet() {
|
|||
}
|
||||
|
||||
void CheatsView::enterCheat(std::function<bool(GBACheatSet*, const char*)> callback) {
|
||||
GBACheatSet* set;
|
||||
GBACheatSet* set = nullptr;
|
||||
QModelIndexList selection = m_ui.cheatList->selectionModel()->selectedIndexes();
|
||||
if (selection.count() != 1) {
|
||||
return;
|
||||
QModelIndex index;
|
||||
if (selection.count() == 0) {
|
||||
set = new GBACheatSet;
|
||||
GBACheatSetInit(set, nullptr);
|
||||
} else if (selection.count() == 1) {
|
||||
index = selection[0];
|
||||
set = m_model.itemAt(index);
|
||||
}
|
||||
set = m_model.itemAt(selection[0]);
|
||||
|
||||
if (!set) {
|
||||
return;
|
||||
}
|
||||
m_controller->threadInterrupt();
|
||||
if (selection.count() == 0) {
|
||||
m_model.addSet(set);
|
||||
index = m_model.index(m_model.rowCount() - 1, 0, QModelIndex());
|
||||
m_ui.cheatList->selectionModel()->select(index, QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows);
|
||||
}
|
||||
QStringList cheats = m_ui.codeEntry->toPlainText().split('\n', QString::SkipEmptyParts);
|
||||
for (const QString& string : cheats) {
|
||||
m_model.beginAppendRow(selection[0]);
|
||||
m_model.beginAppendRow(index);
|
||||
callback(set, string.toUtf8().constData());
|
||||
m_model.endAppendRow();
|
||||
}
|
||||
|
|
|
@ -107,7 +107,7 @@ ConfigController::ConfigController(QObject* parent)
|
|||
m_opts.audioSync = GameController::AUDIO_SYNC;
|
||||
m_opts.videoSync = GameController::VIDEO_SYNC;
|
||||
m_opts.fpsTarget = 60;
|
||||
m_opts.audioBuffers = 2048;
|
||||
m_opts.audioBuffers = 1536;
|
||||
m_opts.volume = GBA_AUDIO_VOLUME_MAX;
|
||||
m_opts.logLevel = GBA_LOG_WARN | GBA_LOG_ERROR | GBA_LOG_FATAL | GBA_LOG_STATUS;
|
||||
m_opts.rewindEnable = false;
|
||||
|
@ -115,8 +115,8 @@ ConfigController::ConfigController(QObject* parent)
|
|||
m_opts.rewindBufferCapacity = 0;
|
||||
m_opts.useBios = true;
|
||||
m_opts.suspendScreensaver = true;
|
||||
GBAConfigLoadDefaults(&m_config, &m_opts);
|
||||
GBAConfigLoad(&m_config);
|
||||
GBAConfigLoadDefaults(&m_config, &m_opts);
|
||||
GBAConfigMap(&m_config, &m_opts);
|
||||
}
|
||||
|
||||
|
@ -126,7 +126,11 @@ ConfigController::~ConfigController() {
|
|||
}
|
||||
|
||||
bool ConfigController::parseArguments(GBAArguments* args, int argc, char* argv[]) {
|
||||
return ::parseArguments(args, &m_config, argc, argv, 0);
|
||||
if (::parseArguments(args, &m_config, argc, argv, 0)) {
|
||||
GBAConfigMap(&m_config, &m_opts);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
ConfigOption* ConfigController::addOption(const char* key) {
|
||||
|
|
|
@ -22,7 +22,7 @@ Display::Driver Display::s_driver = Display::Driver::QT;
|
|||
|
||||
Display* Display::create(QWidget* parent) {
|
||||
#ifdef BUILD_GL
|
||||
QGLFormat format(QGLFormat(QGL::Rgba | QGL::DoubleBuffer));
|
||||
QGLFormat format(QGLFormat(QGL::Rgba | QGL::SingleBuffer));
|
||||
format.setSwapInterval(1);
|
||||
#endif
|
||||
|
||||
|
@ -72,6 +72,9 @@ void Display::filter(bool filter) {
|
|||
|
||||
void Display::showMessage(const QString& message) {
|
||||
m_messagePainter.showMessage(message);
|
||||
if (!isDrawing()) {
|
||||
forceDraw();
|
||||
}
|
||||
}
|
||||
|
||||
void Display::mouseMoveEvent(QMouseEvent*) {
|
||||
|
|
|
@ -33,6 +33,8 @@ public:
|
|||
bool isAspectRatioLocked() const { return m_lockAspectRatio; }
|
||||
bool isFiltered() const { return m_filter; }
|
||||
|
||||
virtual bool isDrawing() const = 0;
|
||||
|
||||
signals:
|
||||
void showCursor();
|
||||
void hideCursor();
|
||||
|
|
|
@ -16,6 +16,7 @@ using namespace QGBA;
|
|||
|
||||
DisplayGL::DisplayGL(const QGLFormat& format, QWidget* parent)
|
||||
: Display(parent)
|
||||
, m_isDrawing(false)
|
||||
, m_gl(new EmptyGLWidget(format, this))
|
||||
, m_painter(new PainterGL(m_gl))
|
||||
, m_drawThread(nullptr)
|
||||
|
@ -33,6 +34,7 @@ void DisplayGL::startDrawing(GBAThread* thread) {
|
|||
if (m_drawThread) {
|
||||
return;
|
||||
}
|
||||
m_isDrawing = true;
|
||||
m_painter->setContext(thread);
|
||||
m_painter->setMessagePainter(messagePainter());
|
||||
m_context = thread;
|
||||
|
@ -55,6 +57,7 @@ void DisplayGL::startDrawing(GBAThread* thread) {
|
|||
|
||||
void DisplayGL::stopDrawing() {
|
||||
if (m_drawThread) {
|
||||
m_isDrawing = false;
|
||||
if (GBAThreadIsActive(m_context)) {
|
||||
GBAThreadInterrupt(m_context);
|
||||
}
|
||||
|
@ -69,6 +72,7 @@ void DisplayGL::stopDrawing() {
|
|||
|
||||
void DisplayGL::pauseDrawing() {
|
||||
if (m_drawThread) {
|
||||
m_isDrawing = false;
|
||||
if (GBAThreadIsActive(m_context)) {
|
||||
GBAThreadInterrupt(m_context);
|
||||
}
|
||||
|
@ -81,6 +85,7 @@ void DisplayGL::pauseDrawing() {
|
|||
|
||||
void DisplayGL::unpauseDrawing() {
|
||||
if (m_drawThread) {
|
||||
m_isDrawing = true;
|
||||
if (GBAThreadIsActive(m_context)) {
|
||||
GBAThreadInterrupt(m_context);
|
||||
}
|
||||
|
@ -113,7 +118,8 @@ void DisplayGL::filter(bool filter) {
|
|||
|
||||
void DisplayGL::framePosted(const uint32_t* buffer) {
|
||||
if (m_drawThread && buffer) {
|
||||
QMetaObject::invokeMethod(m_painter, "setBacking", Q_ARG(const uint32_t*, buffer));
|
||||
m_painter->enqueue(buffer);
|
||||
QMetaObject::invokeMethod(m_painter, "draw");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -135,7 +141,11 @@ PainterGL::PainterGL(QGLWidget* parent)
|
|||
, m_context(nullptr)
|
||||
, m_messagePainter(nullptr)
|
||||
{
|
||||
#ifdef BUILD_GL
|
||||
GBAGLContextCreate(&m_backend);
|
||||
#elif defined(BUILD_GLES2)
|
||||
GBAGLES2ContextCreate(&m_backend);
|
||||
#endif
|
||||
m_backend.d.swap = [](VideoBackend* v) {
|
||||
PainterGL* painter = static_cast<PainterGL*>(v->user);
|
||||
painter->m_gl->swapBuffers();
|
||||
|
@ -143,6 +153,19 @@ PainterGL::PainterGL(QGLWidget* parent)
|
|||
m_backend.d.user = this;
|
||||
m_backend.d.filter = false;
|
||||
m_backend.d.lockAspectRatio = false;
|
||||
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
m_free.append(new uint32_t[256 * 256]);
|
||||
}
|
||||
}
|
||||
|
||||
PainterGL::~PainterGL() {
|
||||
while (!m_queue.isEmpty()) {
|
||||
delete[] m_queue.dequeue();
|
||||
}
|
||||
for (auto item : m_free) {
|
||||
delete[] item;
|
||||
}
|
||||
}
|
||||
|
||||
void PainterGL::setContext(GBAThread* context) {
|
||||
|
@ -153,15 +176,6 @@ void PainterGL::setMessagePainter(MessagePainter* messagePainter) {
|
|||
m_messagePainter = messagePainter;
|
||||
}
|
||||
|
||||
void PainterGL::setBacking(const uint32_t* backing) {
|
||||
m_gl->makeCurrent();
|
||||
m_backend.d.postFrame(&m_backend.d, backing);
|
||||
if (m_active) {
|
||||
draw();
|
||||
}
|
||||
m_gl->doneCurrent();
|
||||
}
|
||||
|
||||
void PainterGL::resize(const QSize& size) {
|
||||
m_size = size;
|
||||
if (m_active) {
|
||||
|
@ -191,7 +205,11 @@ void PainterGL::start() {
|
|||
}
|
||||
|
||||
void PainterGL::draw() {
|
||||
if (GBASyncWaitFrameStart(&m_context->sync, m_context->frameskip)) {
|
||||
if (m_queue.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
if (GBASyncWaitFrameStart(&m_context->sync, m_context->frameskip) || !m_queue.isEmpty()) {
|
||||
dequeue();
|
||||
m_painter.begin(m_gl->context()->device());
|
||||
performDraw();
|
||||
m_painter.end();
|
||||
|
@ -200,6 +218,9 @@ void PainterGL::draw() {
|
|||
} else {
|
||||
GBASyncWaitFrameEnd(&m_context->sync);
|
||||
}
|
||||
if (!m_queue.isEmpty()) {
|
||||
QMetaObject::invokeMethod(this, "draw", Qt::QueuedConnection);
|
||||
}
|
||||
}
|
||||
|
||||
void PainterGL::forceDraw() {
|
||||
|
@ -212,6 +233,7 @@ void PainterGL::forceDraw() {
|
|||
void PainterGL::stop() {
|
||||
m_active = false;
|
||||
m_gl->makeCurrent();
|
||||
dequeueAll();
|
||||
m_backend.d.clear(&m_backend.d);
|
||||
m_backend.d.swap(&m_backend.d);
|
||||
m_backend.d.deinit(&m_backend.d);
|
||||
|
@ -222,9 +244,6 @@ void PainterGL::stop() {
|
|||
|
||||
void PainterGL::pause() {
|
||||
m_active = false;
|
||||
// Make sure both buffers are filled
|
||||
forceDraw();
|
||||
forceDraw();
|
||||
}
|
||||
|
||||
void PainterGL::unpause() {
|
||||
|
@ -241,3 +260,41 @@ void PainterGL::performDraw() {
|
|||
m_messagePainter->paint(&m_painter);
|
||||
}
|
||||
}
|
||||
|
||||
void PainterGL::enqueue(const uint32_t* backing) {
|
||||
m_mutex.lock();
|
||||
uint32_t* buffer;
|
||||
if (m_free.isEmpty()) {
|
||||
buffer = m_queue.dequeue();
|
||||
} else {
|
||||
buffer = m_free.takeLast();
|
||||
}
|
||||
memcpy(buffer, backing, 256 * VIDEO_VERTICAL_PIXELS * BYTES_PER_PIXEL);
|
||||
m_queue.enqueue(buffer);
|
||||
m_mutex.unlock();
|
||||
}
|
||||
|
||||
void PainterGL::dequeue() {
|
||||
m_mutex.lock();
|
||||
if (m_queue.isEmpty()) {
|
||||
m_mutex.unlock();
|
||||
return;
|
||||
}
|
||||
uint32_t* buffer = m_queue.dequeue();
|
||||
m_backend.d.postFrame(&m_backend.d, buffer);
|
||||
m_free.append(buffer);
|
||||
m_mutex.unlock();
|
||||
}
|
||||
|
||||
void PainterGL::dequeueAll() {
|
||||
uint32_t* buffer = 0;
|
||||
m_mutex.lock();
|
||||
while (!m_queue.isEmpty()) {
|
||||
buffer = m_queue.dequeue();
|
||||
m_free.append(buffer);
|
||||
}
|
||||
if (buffer) {
|
||||
m_backend.d.postFrame(&m_backend.d, buffer);
|
||||
}
|
||||
m_mutex.unlock();
|
||||
}
|
||||
|
|
|
@ -9,12 +9,18 @@
|
|||
#include "Display.h"
|
||||
|
||||
#include <QGLWidget>
|
||||
#include <QList>
|
||||
#include <QMouseEvent>
|
||||
#include <QQueue>
|
||||
#include <QThread>
|
||||
#include <QTimer>
|
||||
|
||||
extern "C" {
|
||||
#ifdef BUILD_GL
|
||||
#include "platform/opengl/gl.h"
|
||||
#elif defined(BUILD_GLES2)
|
||||
#include "platform/opengl/gles2.h"
|
||||
#endif
|
||||
}
|
||||
|
||||
struct GBAThread;
|
||||
|
@ -39,6 +45,8 @@ public:
|
|||
DisplayGL(const QGLFormat& format, QWidget* parent = nullptr);
|
||||
~DisplayGL();
|
||||
|
||||
bool isDrawing() const override { return m_isDrawing; }
|
||||
|
||||
public slots:
|
||||
void startDrawing(GBAThread* context) override;
|
||||
void stopDrawing() override;
|
||||
|
@ -56,6 +64,7 @@ protected:
|
|||
private:
|
||||
void resizePainter();
|
||||
|
||||
bool m_isDrawing;
|
||||
QGLWidget* m_gl;
|
||||
PainterGL* m_painter;
|
||||
QThread* m_drawThread;
|
||||
|
@ -67,12 +76,13 @@ Q_OBJECT
|
|||
|
||||
public:
|
||||
PainterGL(QGLWidget* parent);
|
||||
~PainterGL();
|
||||
|
||||
void setContext(GBAThread*);
|
||||
void setMessagePainter(MessagePainter*);
|
||||
void enqueue(const uint32_t* backing);
|
||||
|
||||
public slots:
|
||||
void setBacking(const uint32_t*);
|
||||
void forceDraw();
|
||||
void draw();
|
||||
void start();
|
||||
|
@ -85,12 +95,21 @@ public slots:
|
|||
|
||||
private:
|
||||
void performDraw();
|
||||
void dequeue();
|
||||
void dequeueAll();
|
||||
|
||||
QList<uint32_t*> m_free;
|
||||
QQueue<uint32_t*> m_queue;
|
||||
QPainter m_painter;
|
||||
QMutex m_mutex;
|
||||
QGLWidget* m_gl;
|
||||
bool m_active;
|
||||
GBAThread* m_context;
|
||||
#ifdef BUILD_GL
|
||||
GBAGLContext m_backend;
|
||||
#elif defined(BUILD_GLES2)
|
||||
GBAGLES2Context m_backend;
|
||||
#endif
|
||||
QSize m_size;
|
||||
MessagePainter* m_messagePainter;
|
||||
};
|
||||
|
|
|
@ -15,11 +15,13 @@ using namespace QGBA;
|
|||
|
||||
DisplayQt::DisplayQt(QWidget* parent)
|
||||
: Display(parent)
|
||||
, m_isDrawing(false)
|
||||
, m_backing(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
void DisplayQt::startDrawing(GBAThread*) {
|
||||
m_isDrawing = true;
|
||||
}
|
||||
|
||||
void DisplayQt::lockAspectRatio(bool lock) {
|
||||
|
|
|
@ -21,11 +21,13 @@ Q_OBJECT
|
|||
public:
|
||||
DisplayQt(QWidget* parent = nullptr);
|
||||
|
||||
bool isDrawing() const override { return m_isDrawing; }
|
||||
|
||||
public slots:
|
||||
void startDrawing(GBAThread* context) override;
|
||||
void stopDrawing() override {}
|
||||
void pauseDrawing() override {}
|
||||
void unpauseDrawing() override {}
|
||||
void stopDrawing() override { m_isDrawing = false; }
|
||||
void pauseDrawing() override { m_isDrawing = false; }
|
||||
void unpauseDrawing() override { m_isDrawing = true; }
|
||||
void forceDraw() override { update(); }
|
||||
void lockAspectRatio(bool lock) override;
|
||||
void filter(bool filter) override;
|
||||
|
@ -35,6 +37,7 @@ protected:
|
|||
virtual void paintEvent(QPaintEvent*) override;
|
||||
|
||||
private:
|
||||
bool m_isDrawing;
|
||||
QImage m_backing;
|
||||
};
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include <QIcon>
|
||||
|
||||
extern "C" {
|
||||
#include "gba/supervisor/thread.h"
|
||||
#include "platform/commandline.h"
|
||||
#include "util/socket.h"
|
||||
}
|
||||
|
@ -33,10 +34,13 @@ GBAApp::GBAApp(int& argc, char* argv[])
|
|||
SDL_Init(SDL_INIT_NOPARACHUTE);
|
||||
#endif
|
||||
|
||||
#ifndef Q_OS_MAC
|
||||
setWindowIcon(QIcon(":/res/mgba-1024.png"));
|
||||
#endif
|
||||
|
||||
SocketSubsystemInit();
|
||||
qRegisterMetaType<const uint32_t*>("const uint32_t*");
|
||||
qRegisterMetaType<GBAThread*>("GBAThread*");
|
||||
|
||||
QApplication::setApplicationName(projectName);
|
||||
QApplication::setApplicationVersion(projectVersion);
|
||||
|
@ -45,31 +49,30 @@ GBAApp::GBAApp(int& argc, char* argv[])
|
|||
Display::setDriver(static_cast<Display::Driver>(m_configController.getQtOption("displayDriver").toInt()));
|
||||
}
|
||||
|
||||
GBAArguments args;
|
||||
bool loaded = m_configController.parseArguments(&args, argc, argv);
|
||||
if (loaded && args.showHelp) {
|
||||
usage(argv[0], 0);
|
||||
::exit(0);
|
||||
return;
|
||||
}
|
||||
|
||||
AudioProcessor::setDriver(static_cast<AudioProcessor::Driver>(m_configController.getQtOption("audioDriver").toInt()));
|
||||
Window* w = new Window(&m_configController);
|
||||
connect(w, &Window::destroyed, [this]() {
|
||||
m_windows[0] = nullptr;
|
||||
});
|
||||
m_windows[0] = w;
|
||||
|
||||
#ifndef Q_OS_MAC
|
||||
w->show();
|
||||
#endif
|
||||
|
||||
GBAArguments args;
|
||||
if (m_configController.parseArguments(&args, argc, argv)) {
|
||||
if (loaded) {
|
||||
w->argumentsPassed(&args);
|
||||
} else {
|
||||
w->loadConfig();
|
||||
}
|
||||
freeArguments(&args);
|
||||
|
||||
AudioProcessor::setDriver(static_cast<AudioProcessor::Driver>(m_configController.getQtOption("audioDriver").toInt()));
|
||||
w->controller()->reloadAudioDriver();
|
||||
w->show();
|
||||
|
||||
w->controller()->setMultiplayerController(&m_multiplayer);
|
||||
#ifdef Q_OS_MAC
|
||||
w->show();
|
||||
#endif
|
||||
}
|
||||
|
||||
bool GBAApp::event(QEvent* event) {
|
||||
|
@ -91,14 +94,9 @@ Window* GBAApp::newWindow() {
|
|||
});
|
||||
m_windows[windowId] = w;
|
||||
w->setAttribute(Qt::WA_DeleteOnClose);
|
||||
#ifndef Q_OS_MAC
|
||||
w->show();
|
||||
#endif
|
||||
w->loadConfig();
|
||||
w->controller()->setMultiplayerController(&m_multiplayer);
|
||||
#ifdef Q_OS_MAC
|
||||
w->show();
|
||||
#endif
|
||||
w->controller()->setMultiplayerController(&m_multiplayer);
|
||||
return w;
|
||||
}
|
||||
|
||||
|
|
|
@ -18,9 +18,9 @@
|
|||
using namespace QGBA;
|
||||
|
||||
const qreal GBAKeyEditor::DPAD_CENTER_X = 0.247;
|
||||
const qreal GBAKeyEditor::DPAD_CENTER_Y = 0.431;
|
||||
const qreal GBAKeyEditor::DPAD_WIDTH = 0.1;
|
||||
const qreal GBAKeyEditor::DPAD_HEIGHT = 0.1;
|
||||
const qreal GBAKeyEditor::DPAD_CENTER_Y = 0.432;
|
||||
const qreal GBAKeyEditor::DPAD_WIDTH = 0.12;
|
||||
const qreal GBAKeyEditor::DPAD_HEIGHT = 0.12;
|
||||
|
||||
GBAKeyEditor::GBAKeyEditor(InputController* controller, int type, const QString& profile, QWidget* parent)
|
||||
: QWidget(parent)
|
||||
|
@ -148,8 +148,8 @@ void GBAKeyEditor::resizeEvent(QResizeEvent* event) {
|
|||
setLocation(m_keyDR, DPAD_CENTER_X + DPAD_WIDTH, DPAD_CENTER_Y);
|
||||
setLocation(m_keySelect, 0.415, 0.93);
|
||||
setLocation(m_keyStart, 0.585, 0.93);
|
||||
setLocation(m_keyA, 0.826, 0.451);
|
||||
setLocation(m_keyB, 0.667, 0.490);
|
||||
setLocation(m_keyA, 0.826, 0.475);
|
||||
setLocation(m_keyB, 0.667, 0.514);
|
||||
setLocation(m_keyL, 0.1, 0.1);
|
||||
setLocation(m_keyR, 0.9, 0.1);
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
using namespace QGBA;
|
||||
|
||||
GDBWindow::GDBWindow(GDBController* controller, QWidget* parent)
|
||||
: QWidget(parent)
|
||||
: QDialog(parent)
|
||||
, m_gdbController(controller)
|
||||
{
|
||||
setWindowFlags(windowFlags() & ~Qt::WindowFullscreenButtonHint);
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
#ifndef QGBA_GDB_WINDOW
|
||||
#define QGBA_GDB_WINDOW
|
||||
|
||||
#include <QWidget>
|
||||
#include <QDialog>
|
||||
|
||||
class QLineEdit;
|
||||
class QPushButton;
|
||||
|
@ -15,7 +15,7 @@ namespace QGBA {
|
|||
|
||||
class GDBController;
|
||||
|
||||
class GDBWindow : public QWidget {
|
||||
class GDBWindow : public QDialog {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
|
|
@ -29,11 +29,10 @@ extern "C" {
|
|||
using namespace QGBA;
|
||||
using namespace std;
|
||||
|
||||
const int GameController::LUX_LEVELS[10] = { 5, 11, 18, 27, 42, 62, 84, 109, 139, 183 };
|
||||
|
||||
GameController::GameController(QObject* parent)
|
||||
: QObject(parent)
|
||||
, m_drawContext(new uint32_t[256 * 256])
|
||||
, m_drawContext(new uint32_t[256 * VIDEO_HORIZONTAL_PIXELS])
|
||||
, m_frontBuffer(new uint32_t[256 * 256])
|
||||
, m_threadContext()
|
||||
, m_activeKeys(0)
|
||||
, m_inactiveKeys(0)
|
||||
|
@ -49,6 +48,8 @@ GameController::GameController(QObject* parent)
|
|||
, m_turboForced(false)
|
||||
, m_turboSpeed(-1)
|
||||
, m_wasPaused(false)
|
||||
, m_audioChannels{ true, true, true, true, true, true }
|
||||
, m_videoLayers{ true, true, true, true, true }
|
||||
, m_inputController(nullptr)
|
||||
, m_multiplayer(nullptr)
|
||||
, m_stateSlot(1)
|
||||
|
@ -86,12 +87,25 @@ GameController::GameController(QObject* parent)
|
|||
|
||||
m_threadContext.startCallback = [](GBAThread* context) {
|
||||
GameController* controller = static_cast<GameController*>(context->userData);
|
||||
if (controller->m_audioProcessor) {
|
||||
controller->m_audioProcessor->setInput(context);
|
||||
}
|
||||
context->gba->luminanceSource = &controller->m_lux;
|
||||
GBARTCGenericSourceInit(&controller->m_rtc, context->gba);
|
||||
context->gba->rtcSource = &controller->m_rtc.d;
|
||||
context->gba->rumble = controller->m_inputController->rumble();
|
||||
context->gba->rotationSource = controller->m_inputController->rotationSource();
|
||||
context->gba->audio.forceDisableCh[0] = !controller->m_audioChannels[0];
|
||||
context->gba->audio.forceDisableCh[1] = !controller->m_audioChannels[1];
|
||||
context->gba->audio.forceDisableCh[2] = !controller->m_audioChannels[2];
|
||||
context->gba->audio.forceDisableCh[3] = !controller->m_audioChannels[3];
|
||||
context->gba->audio.forceDisableChA = !controller->m_audioChannels[4];
|
||||
context->gba->audio.forceDisableChB = !controller->m_audioChannels[5];
|
||||
context->gba->video.renderer->disableBG[0] = !controller->m_videoLayers[0];
|
||||
context->gba->video.renderer->disableBG[1] = !controller->m_videoLayers[1];
|
||||
context->gba->video.renderer->disableBG[2] = !controller->m_videoLayers[2];
|
||||
context->gba->video.renderer->disableBG[3] = !controller->m_videoLayers[3];
|
||||
context->gba->video.renderer->disableOBJ = !controller->m_videoLayers[4];
|
||||
controller->m_fpsTarget = context->fpsTarget;
|
||||
|
||||
if (GBALoadState(context, context->stateDir, 0)) {
|
||||
|
@ -100,24 +114,25 @@ GameController::GameController(QObject* parent)
|
|||
vf->truncate(vf, 0);
|
||||
}
|
||||
}
|
||||
controller->gameStarted(context);
|
||||
QMetaObject::invokeMethod(controller, "gameStarted", Q_ARG(GBAThread*, context));
|
||||
};
|
||||
|
||||
m_threadContext.cleanCallback = [](GBAThread* context) {
|
||||
GameController* controller = static_cast<GameController*>(context->userData);
|
||||
controller->gameStopped(context);
|
||||
QMetaObject::invokeMethod(controller, "gameStopped", Q_ARG(GBAThread*, context));
|
||||
};
|
||||
|
||||
m_threadContext.frameCallback = [](GBAThread* context) {
|
||||
GameController* controller = static_cast<GameController*>(context->userData);
|
||||
if (GBASyncDrawingFrame(&controller->m_threadContext.sync)) {
|
||||
memcpy(controller->m_frontBuffer, controller->m_drawContext, 256 * VIDEO_HORIZONTAL_PIXELS * BYTES_PER_PIXEL);
|
||||
QMetaObject::invokeMethod(controller, "frameAvailable", Q_ARG(const uint32_t*, controller->m_frontBuffer));
|
||||
} else {
|
||||
QMetaObject::invokeMethod(controller, "frameAvailable", Q_ARG(const uint32_t*, nullptr));
|
||||
}
|
||||
if (controller->m_pauseAfterFrame.testAndSetAcquire(true, false)) {
|
||||
GBAThreadPauseFromThread(context);
|
||||
controller->gamePaused(&controller->m_threadContext);
|
||||
}
|
||||
if (GBASyncDrawingFrame(&controller->m_threadContext.sync)) {
|
||||
controller->frameAvailable(controller->m_drawContext);
|
||||
} else {
|
||||
controller->frameAvailable(nullptr);
|
||||
QMetaObject::invokeMethod(controller, "gamePaused", Q_ARG(GBAThread*, context));
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -146,7 +161,7 @@ GameController::GameController(QObject* parent)
|
|||
va_copy(argc, args);
|
||||
int immediate = va_arg(argc, int);
|
||||
va_end(argc);
|
||||
controller->unimplementedBiosCall(immediate);
|
||||
QMetaObject::invokeMethod(controller, "unimplementedBiosCall", Q_ARG(int, immediate));
|
||||
} else if (level == GBA_LOG_STATUS) {
|
||||
// Slot 0 is reserved for suspend points
|
||||
if (strncmp(savestateMessage, format, strlen(savestateMessage)) == 0) {
|
||||
|
@ -174,9 +189,9 @@ GameController::GameController(QObject* parent)
|
|||
}
|
||||
QString message(QString().vsprintf(format, args));
|
||||
if (level == GBA_LOG_STATUS) {
|
||||
controller->statusPosted(message);
|
||||
QMetaObject::invokeMethod(controller, "statusPosted", Q_ARG(const QString&, message));
|
||||
}
|
||||
controller->postLog(level, message);
|
||||
QMetaObject::invokeMethod(controller, "postLog", Q_ARG(int, level), Q_ARG(const QString&, message));
|
||||
};
|
||||
|
||||
connect(&m_rewindTimer, &QTimer::timeout, [this]() {
|
||||
|
@ -205,6 +220,7 @@ GameController::~GameController() {
|
|||
GBACheatDeviceDestroy(&m_cheatDevice);
|
||||
delete m_renderer;
|
||||
delete[] m_drawContext;
|
||||
delete[] m_frontBuffer;
|
||||
delete m_backupLoadState;
|
||||
}
|
||||
|
||||
|
@ -328,6 +344,7 @@ void GameController::openGame(bool biosOnly) {
|
|||
}
|
||||
|
||||
m_inputController->recalibrateAxes();
|
||||
memset(m_drawContext, 0xF8, 1024 * VIDEO_HORIZONTAL_PIXELS);
|
||||
|
||||
if (!GBAThreadStart(&m_threadContext)) {
|
||||
m_gameOpen = false;
|
||||
|
@ -453,8 +470,7 @@ void GameController::setPaused(bool paused) {
|
|||
return;
|
||||
}
|
||||
if (paused) {
|
||||
GBAThreadPause(&m_threadContext);
|
||||
emit gamePaused(&m_threadContext);
|
||||
m_pauseAfterFrame.testAndSetRelaxed(false, true);
|
||||
} else {
|
||||
GBAThreadUnpause(&m_threadContext);
|
||||
emit gameUnpaused(&m_threadContext);
|
||||
|
@ -519,9 +535,9 @@ void GameController::startRewinding() {
|
|||
return;
|
||||
}
|
||||
m_wasPaused = isPaused();
|
||||
bool signalsBlocked = blockSignals(true);
|
||||
setPaused(true);
|
||||
blockSignals(signalsBlocked);
|
||||
if (!GBAThreadIsPaused(&m_threadContext)) {
|
||||
GBAThreadPause(&m_threadContext);
|
||||
}
|
||||
m_rewindTimer.start();
|
||||
}
|
||||
|
||||
|
@ -574,11 +590,65 @@ void GameController::clearKeys() {
|
|||
}
|
||||
|
||||
void GameController::setAudioBufferSamples(int samples) {
|
||||
if (m_audioProcessor) {
|
||||
threadInterrupt();
|
||||
redoSamples(samples);
|
||||
threadContinue();
|
||||
QMetaObject::invokeMethod(m_audioProcessor, "setBufferSamples", Q_ARG(int, samples));
|
||||
}
|
||||
}
|
||||
|
||||
void GameController::setAudioSampleRate(unsigned rate) {
|
||||
if (m_audioProcessor) {
|
||||
threadInterrupt();
|
||||
redoSamples(m_audioProcessor->getBufferSamples());
|
||||
threadContinue();
|
||||
QMetaObject::invokeMethod(m_audioProcessor, "requestSampleRate", Q_ARG(unsigned, rate));
|
||||
}
|
||||
}
|
||||
|
||||
void GameController::setAudioChannelEnabled(int channel, bool enable) {
|
||||
if (channel > 5 || channel < 0) {
|
||||
return;
|
||||
}
|
||||
m_audioChannels[channel] = enable;
|
||||
if (m_gameOpen) {
|
||||
switch (channel) {
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
m_threadContext.gba->audio.forceDisableCh[channel] = !enable;
|
||||
break;
|
||||
case 4:
|
||||
m_threadContext.gba->audio.forceDisableChA = !enable;
|
||||
break;
|
||||
case 5:
|
||||
m_threadContext.gba->audio.forceDisableChB = !enable;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GameController::setVideoLayerEnabled(int layer, bool enable) {
|
||||
if (layer > 4 || layer < 0) {
|
||||
return;
|
||||
}
|
||||
m_videoLayers[layer] = enable;
|
||||
if (m_gameOpen) {
|
||||
switch (layer) {
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
m_threadContext.gba->video.renderer->disableBG[layer] = !enable;
|
||||
break;
|
||||
case 4:
|
||||
m_threadContext.gba->video.renderer->disableOBJ = !enable;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GameController::setFPSTarget(float fps) {
|
||||
threadInterrupt();
|
||||
|
@ -587,7 +657,9 @@ void GameController::setFPSTarget(float fps) {
|
|||
if (m_turbo && m_turboSpeed > 0) {
|
||||
m_threadContext.fpsTarget *= m_turboSpeed;
|
||||
}
|
||||
if (m_audioProcessor) {
|
||||
redoSamples(m_audioProcessor->getBufferSamples());
|
||||
}
|
||||
threadContinue();
|
||||
}
|
||||
|
||||
|
@ -598,9 +670,14 @@ void GameController::setSkipBIOS(bool set) {
|
|||
}
|
||||
|
||||
void GameController::setUseBIOS(bool use) {
|
||||
threadInterrupt();
|
||||
if (use == m_useBios) {
|
||||
return;
|
||||
}
|
||||
m_useBios = use;
|
||||
threadContinue();
|
||||
if (m_gameOpen) {
|
||||
closeGame();
|
||||
openGame();
|
||||
}
|
||||
}
|
||||
|
||||
void GameController::loadState(int slot) {
|
||||
|
@ -744,7 +821,9 @@ void GameController::enableTurbo() {
|
|||
m_threadContext.sync.audioWait = true;
|
||||
m_threadContext.sync.videoFrameWait = false;
|
||||
}
|
||||
if (m_audioProcessor) {
|
||||
redoSamples(m_audioProcessor->getBufferSamples());
|
||||
}
|
||||
threadContinue();
|
||||
}
|
||||
|
||||
|
@ -773,11 +852,21 @@ void GameController::screenshot() {
|
|||
#endif
|
||||
|
||||
void GameController::reloadAudioDriver() {
|
||||
int samples = 0;
|
||||
unsigned sampleRate = 0;
|
||||
if (m_audioProcessor) {
|
||||
QMetaObject::invokeMethod(m_audioProcessor, "pause", Qt::BlockingQueuedConnection);
|
||||
int samples = m_audioProcessor->getBufferSamples();
|
||||
samples = m_audioProcessor->getBufferSamples();
|
||||
sampleRate = m_audioProcessor->sampleRate();
|
||||
delete m_audioProcessor;
|
||||
}
|
||||
m_audioProcessor = AudioProcessor::create();
|
||||
if (samples) {
|
||||
m_audioProcessor->setBufferSamples(samples);
|
||||
}
|
||||
if (sampleRate) {
|
||||
m_audioProcessor->requestSampleRate(sampleRate);
|
||||
}
|
||||
m_audioProcessor->moveToThread(m_audioThread);
|
||||
connect(this, SIGNAL(gameStarted(GBAThread*)), m_audioProcessor, SLOT(start()));
|
||||
connect(this, SIGNAL(gameStopped(GBAThread*)), m_audioProcessor, SLOT(pause()));
|
||||
|
@ -794,7 +883,7 @@ void GameController::setLuminanceValue(uint8_t value) {
|
|||
value = std::max<int>(value - 0x16, 0);
|
||||
m_luxLevel = 10;
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
if (value < LUX_LEVELS[i]) {
|
||||
if (value < GBA_LUX_LEVELS[i]) {
|
||||
m_luxLevel = i;
|
||||
break;
|
||||
}
|
||||
|
@ -806,7 +895,7 @@ void GameController::setLuminanceLevel(int level) {
|
|||
int value = 0x16;
|
||||
level = std::max(0, std::min(10, level));
|
||||
if (level > 0) {
|
||||
value += LUX_LEVELS[level - 1];
|
||||
value += GBA_LUX_LEVELS[level - 1];
|
||||
}
|
||||
setLuminanceValue(value);
|
||||
}
|
||||
|
|
|
@ -72,6 +72,8 @@ public:
|
|||
|
||||
void setOptions(const GBAOptions*);
|
||||
|
||||
int stateSlot() const { return m_stateSlot; }
|
||||
|
||||
#ifdef USE_GDB_STUB
|
||||
ARMDebugger* debugger();
|
||||
void setDebugger(ARMDebugger*);
|
||||
|
@ -117,6 +119,9 @@ public slots:
|
|||
void keyReleased(int key);
|
||||
void clearKeys();
|
||||
void setAudioBufferSamples(int samples);
|
||||
void setAudioSampleRate(unsigned rate);
|
||||
void setAudioChannelEnabled(int channel, bool enable = true);
|
||||
void setVideoLayerEnabled(int layer, bool enable = true);
|
||||
void setFPSTarget(float fps);
|
||||
void loadState(int slot = 0);
|
||||
void saveState(int slot = 0);
|
||||
|
@ -163,6 +168,7 @@ private:
|
|||
void enableTurbo();
|
||||
|
||||
uint32_t* m_drawContext;
|
||||
uint32_t* m_frontBuffer;
|
||||
GBAThread m_threadContext;
|
||||
GBAVideoSoftwareRenderer* m_renderer;
|
||||
GBACheatDevice m_cheatDevice;
|
||||
|
@ -193,6 +199,9 @@ private:
|
|||
QTimer m_rewindTimer;
|
||||
bool m_wasPaused;
|
||||
|
||||
bool m_audioChannels[6];
|
||||
bool m_videoLayers[5];
|
||||
|
||||
int m_stateSlot;
|
||||
GBASerializedState* m_backupLoadState;
|
||||
QByteArray m_backupSaveState;
|
||||
|
@ -207,8 +216,6 @@ private:
|
|||
uint8_t m_luxValue;
|
||||
int m_luxLevel;
|
||||
|
||||
static const int LUX_LEVELS[10];
|
||||
|
||||
GBARTCGenericSource m_rtc;
|
||||
};
|
||||
|
||||
|
|
|
@ -208,9 +208,11 @@ void InputController::setPreferredGamepad(uint32_t type, const QString& device)
|
|||
|
||||
GBARumble* InputController::rumble() {
|
||||
#ifdef BUILD_SDL
|
||||
#if SDL_VERSION_ATLEAST(2, 0, 0)
|
||||
if (m_playerAttached) {
|
||||
return &m_sdlPlayer.rumble.d;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -497,19 +499,29 @@ bool InputController::hasPendingEvent(GBAKey key) const {
|
|||
return m_pendingEvents.contains(key);
|
||||
}
|
||||
|
||||
#if defined(BUILD_SDL) && SDL_VERSION_ATLEAST(2, 0, 0)
|
||||
void InputController::suspendScreensaver() {
|
||||
#ifdef BUILD_SDL
|
||||
#if SDL_VERSION_ATLEAST(2, 0, 0)
|
||||
GBASDLSuspendScreensaver(&s_sdlEvents);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
void InputController::resumeScreensaver() {
|
||||
#ifdef BUILD_SDL
|
||||
#if SDL_VERSION_ATLEAST(2, 0, 0)
|
||||
GBASDLResumeScreensaver(&s_sdlEvents);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
void InputController::setScreensaverSuspendable(bool suspendable) {
|
||||
#ifdef BUILD_SDL
|
||||
#if SDL_VERSION_ATLEAST(2, 0, 0)
|
||||
GBASDLSetScreensaverSuspendable(&s_sdlEvents, suspendable);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
void InputController::stealFocus(QWidget* focus) {
|
||||
m_focusParent = focus;
|
||||
|
|
|
@ -87,12 +87,10 @@ signals:
|
|||
public slots:
|
||||
void testGamepad(int type);
|
||||
|
||||
#if defined(BUILD_SDL) && SDL_VERSION_ATLEAST(2, 0, 0)
|
||||
// TODO: Move these to somewhere that makes sense
|
||||
void suspendScreensaver();
|
||||
void resumeScreensaver();
|
||||
void setScreensaverSuspendable(bool);
|
||||
#endif
|
||||
|
||||
private:
|
||||
void postPendingEvent(GBAKey);
|
||||
|
|
|
@ -23,9 +23,10 @@ using namespace QGBA;
|
|||
LoadSaveState::LoadSaveState(GameController* controller, QWidget* parent)
|
||||
: QWidget(parent)
|
||||
, m_controller(controller)
|
||||
, m_currentFocus(0)
|
||||
, m_currentFocus(controller->stateSlot() - 1)
|
||||
, m_mode(LoadSave::LOAD)
|
||||
{
|
||||
setAttribute(Qt::WA_TranslucentBackground);
|
||||
m_ui.setupUi(this);
|
||||
|
||||
m_slots[0] = m_ui.state1;
|
||||
|
@ -45,6 +46,13 @@ LoadSaveState::LoadSaveState(GameController* controller, QWidget* parent)
|
|||
connect(m_slots[i], &QAbstractButton::clicked, this, [this, i]() { triggerState(i + 1); });
|
||||
}
|
||||
|
||||
if (m_currentFocus >= 9) {
|
||||
m_currentFocus = 0;
|
||||
}
|
||||
if (m_currentFocus < 0) {
|
||||
m_currentFocus = 0;
|
||||
}
|
||||
|
||||
QAction* escape = new QAction(this);
|
||||
escape->connect(escape, SIGNAL(triggered()), this, SLOT(close()));
|
||||
escape->setShortcut(QKeySequence("Esc"));
|
||||
|
@ -201,6 +209,5 @@ void LoadSaveState::showEvent(QShowEvent* event) {
|
|||
void LoadSaveState::paintEvent(QPaintEvent*) {
|
||||
QPainter painter(this);
|
||||
QRect full(QPoint(), size());
|
||||
painter.drawPixmap(full, m_currentImage);
|
||||
painter.fillRect(full, QColor(0, 0, 0, 128));
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ extern "C" {
|
|||
using namespace QGBA;
|
||||
|
||||
OverrideView::OverrideView(GameController* controller, ConfigController* config, QWidget* parent)
|
||||
: QWidget(parent)
|
||||
: QDialog(parent)
|
||||
, m_controller(controller)
|
||||
, m_config(config)
|
||||
{
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
#ifndef QGBA_OVERRIDE_VIEW
|
||||
#define QGBA_OVERRIDE_VIEW
|
||||
|
||||
#include <QWidget>
|
||||
#include <QDialog>
|
||||
|
||||
#include "ui_OverrideView.h"
|
||||
|
||||
|
@ -21,7 +21,7 @@ namespace QGBA {
|
|||
class ConfigController;
|
||||
class GameController;
|
||||
|
||||
class OverrideView : public QWidget {
|
||||
class OverrideView : public QDialog {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
|
|
@ -13,7 +13,7 @@ using namespace QGBA;
|
|||
SavestateButton::SavestateButton(QWidget* parent)
|
||||
: QAbstractButton(parent)
|
||||
{
|
||||
// Nothing to do
|
||||
setAttribute(Qt::WA_TranslucentBackground);
|
||||
}
|
||||
|
||||
void SavestateButton::paintEvent(QPaintEvent*) {
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
using namespace QGBA;
|
||||
|
||||
SensorView::SensorView(GameController* controller, InputController* input, QWidget* parent)
|
||||
: QWidget(parent)
|
||||
: QDialog(parent)
|
||||
, m_controller(controller)
|
||||
, m_input(input)
|
||||
, m_rotation(input->rotationSource())
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
#define QGBA_SENSOR_VIEW
|
||||
|
||||
#include <QTimer>
|
||||
#include <QWidget>
|
||||
#include <QDialog>
|
||||
|
||||
#include <functional>
|
||||
|
||||
|
@ -22,7 +22,7 @@ class GameController;
|
|||
class GamepadAxisEvent;
|
||||
class InputController;
|
||||
|
||||
class SensorView : public QWidget {
|
||||
class SensorView : public QDialog {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
using namespace QGBA;
|
||||
|
||||
SettingsView::SettingsView(ConfigController* controller, QWidget* parent)
|
||||
: QWidget(parent)
|
||||
: QDialog(parent)
|
||||
, m_controller(controller)
|
||||
{
|
||||
m_ui.setupUi(this);
|
||||
|
@ -22,6 +22,7 @@ SettingsView::SettingsView(ConfigController* controller, QWidget* parent)
|
|||
loadSetting("useBios", m_ui.useBios);
|
||||
loadSetting("skipBios", m_ui.skipBios);
|
||||
loadSetting("audioBuffers", m_ui.audioBufferSize);
|
||||
loadSetting("sampleRate", m_ui.sampleRate);
|
||||
loadSetting("videoSync", m_ui.videoSync);
|
||||
loadSetting("audioSync", m_ui.audioSync);
|
||||
loadSetting("frameskip", m_ui.frameskip);
|
||||
|
@ -102,6 +103,7 @@ void SettingsView::updateConfig() {
|
|||
saveSetting("useBios", m_ui.useBios);
|
||||
saveSetting("skipBios", m_ui.skipBios);
|
||||
saveSetting("audioBuffers", m_ui.audioBufferSize);
|
||||
saveSetting("sampleRate", m_ui.sampleRate);
|
||||
saveSetting("videoSync", m_ui.videoSync);
|
||||
saveSetting("audioSync", m_ui.audioSync);
|
||||
saveSetting("frameskip", m_ui.frameskip);
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
#ifndef QGBA_SETTINGS_VIEW
|
||||
#define QGBA_SETTINGS_VIEW
|
||||
|
||||
#include <QWidget>
|
||||
#include <QDialog>
|
||||
|
||||
#include "ui_SettingsView.h"
|
||||
|
||||
|
@ -14,7 +14,7 @@ namespace QGBA {
|
|||
|
||||
class ConfigController;
|
||||
|
||||
class SettingsView : public QWidget {
|
||||
class SettingsView : public QDialog {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
|
|
@ -62,26 +62,41 @@
|
|||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="currentText">
|
||||
<string>2048</string>
|
||||
<string>1536</string>
|
||||
</property>
|
||||
<property name="currentIndex">
|
||||
<number>2</number>
|
||||
<number>3</number>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>512</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>768</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>1024</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>1536</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>2048</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>3072</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>4096</string>
|
||||
|
@ -99,13 +114,20 @@
|
|||
</layout>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_19">
|
||||
<property name="text">
|
||||
<string>Sample rate:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_17">
|
||||
<property name="text">
|
||||
<string>Volume:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<item row="3" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_6">
|
||||
<item>
|
||||
<widget class="QSlider" name="volume">
|
||||
|
@ -132,28 +154,38 @@
|
|||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="3" column="0" colspan="2">
|
||||
<item row="4" column="0" colspan="2">
|
||||
<widget class="Line" name="line">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="label_10">
|
||||
<property name="text">
|
||||
<string>Display driver:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<item row="5" column="1">
|
||||
<widget class="QComboBox" name="displayDriver">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<widget class="QLabel" name="label_9">
|
||||
<property name="text">
|
||||
<string>Frameskip:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<item row="6" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_16">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_12">
|
||||
|
@ -174,14 +206,14 @@
|
|||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<item row="7" column="0">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>FPS target:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="1">
|
||||
<item row="7" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QDoubleSpinBox" name="fpsTarget">
|
||||
|
@ -205,21 +237,21 @@
|
|||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="7" column="0" colspan="2">
|
||||
<item row="8" column="0" colspan="2">
|
||||
<widget class="Line" name="line_4">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="0">
|
||||
<item row="9" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Sync:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="1">
|
||||
<item row="9" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_10">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="videoSync">
|
||||
|
@ -237,32 +269,66 @@
|
|||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="9" column="1">
|
||||
<item row="10" column="1">
|
||||
<widget class="QCheckBox" name="lockAspectRatio">
|
||||
<property name="text">
|
||||
<string>Lock aspect ratio</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="10" column="1">
|
||||
<item row="11" column="1">
|
||||
<widget class="QCheckBox" name="resampleVideo">
|
||||
<property name="text">
|
||||
<string>Resample video</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QComboBox" name="displayDriver">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
<item row="2" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_14">
|
||||
<item>
|
||||
<widget class="QComboBox" name="sampleRate">
|
||||
<property name="editable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="currentText">
|
||||
<string>44100</string>
|
||||
</property>
|
||||
<property name="currentIndex">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>22050</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>32000</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>44100</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>48000</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_20">
|
||||
<property name="text">
|
||||
<string>Hz</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="line_5">
|
||||
<property name="orientation">
|
||||
|
|
|
@ -103,6 +103,8 @@ public:
|
|||
const QKeySequence& shortcut, const QString& visibleName, const QString& name);
|
||||
void addMenu(QMenu* menu, QMenu* parent = nullptr);
|
||||
|
||||
QAction* getAction(const QString& name);
|
||||
|
||||
QKeySequence shortcutAt(const QModelIndex& index) const;
|
||||
bool isMenuAt(const QModelIndex& index) const;
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include <QPainter>
|
||||
#include <QStackedLayout>
|
||||
|
||||
#include "AboutScreen.h"
|
||||
#include "CheatsView.h"
|
||||
#include "ConfigController.h"
|
||||
#include "Display.h"
|
||||
|
@ -40,8 +41,8 @@ extern "C" {
|
|||
|
||||
using namespace QGBA;
|
||||
|
||||
#ifdef __WIN32
|
||||
// This is a macro everywhere except MinGW, it seems
|
||||
#if defined(__WIN32) || defined(__OpenBSD__)
|
||||
// This is a macro everywhere except MinGW and OpenBSD, it seems
|
||||
using std::isnan;
|
||||
#endif
|
||||
|
||||
|
@ -99,6 +100,14 @@ Window::Window(ConfigController* config, int playerId, QWidget* parent)
|
|||
connect(m_controller, SIGNAL(gameStopped(GBAThread*)), &m_inputController, SLOT(resumeScreensaver()));
|
||||
connect(m_controller, SIGNAL(stateLoaded(GBAThread*)), m_display, SLOT(forceDraw()));
|
||||
connect(m_controller, SIGNAL(rewound(GBAThread*)), m_display, SLOT(forceDraw()));
|
||||
connect(m_controller, &GameController::gamePaused, [this]() {
|
||||
QImage currentImage(reinterpret_cast<const uchar*>(m_controller->drawContext()), VIDEO_HORIZONTAL_PIXELS,
|
||||
VIDEO_VERTICAL_PIXELS, 1024, QImage::Format_RGBX8888);
|
||||
QPixmap pixmap;
|
||||
pixmap.convertFromImage(currentImage);
|
||||
m_screenWidget->setPixmap(pixmap);
|
||||
m_screenWidget->setLockAspectRatio(3, 2);
|
||||
});
|
||||
connect(m_controller, SIGNAL(gamePaused(GBAThread*)), m_display, SLOT(pauseDrawing()));
|
||||
#ifndef Q_OS_MAC
|
||||
connect(m_controller, SIGNAL(gamePaused(GBAThread*)), menuBar(), SLOT(show()));
|
||||
|
@ -126,15 +135,16 @@ Window::Window(ConfigController* config, int playerId, QWidget* parent)
|
|||
connect(this, SIGNAL(shutdown()), m_controller, SLOT(closeGame()));
|
||||
connect(this, SIGNAL(shutdown()), m_logView, SLOT(hide()));
|
||||
connect(this, SIGNAL(audioBufferSamplesChanged(int)), m_controller, SLOT(setAudioBufferSamples(int)));
|
||||
connect(this, SIGNAL(sampleRateChanged(unsigned)), m_controller, SLOT(setAudioSampleRate(unsigned)));
|
||||
connect(this, SIGNAL(fpsTargetChanged(float)), m_controller, SLOT(setFPSTarget(float)));
|
||||
connect(&m_fpsTimer, SIGNAL(timeout()), this, SLOT(showFPS()));
|
||||
connect(m_display, &Display::hideCursor, [this]() {
|
||||
if (static_cast<QStackedLayout*>(m_screenWidget->layout())->currentWidget() == m_display) {
|
||||
setCursor(Qt::BlankCursor);
|
||||
m_screenWidget->setCursor(Qt::BlankCursor);
|
||||
}
|
||||
});
|
||||
connect(m_display, &Display::showCursor, [this]() {
|
||||
unsetCursor();
|
||||
m_screenWidget->unsetCursor();
|
||||
});
|
||||
connect(&m_inputController, SIGNAL(profileLoaded(const QString&)), m_shortcutController, SLOT(loadProfile(const QString&)));
|
||||
|
||||
|
@ -171,6 +181,7 @@ void Window::argumentsPassed(GBAArguments* args) {
|
|||
|
||||
void Window::resizeFrame(int width, int height) {
|
||||
QSize newSize(width, height);
|
||||
m_screenWidget->setSizeHint(newSize);
|
||||
newSize -= m_screenWidget->size();
|
||||
newSize += size();
|
||||
resize(newSize);
|
||||
|
@ -193,6 +204,7 @@ void Window::loadConfig() {
|
|||
m_controller->loadBIOS(opts->bios);
|
||||
}
|
||||
|
||||
// TODO: Move these to ConfigController
|
||||
if (opts->fpsTarget) {
|
||||
emit fpsTargetChanged(opts->fpsTarget);
|
||||
}
|
||||
|
@ -201,6 +213,10 @@ void Window::loadConfig() {
|
|||
emit audioBufferSamplesChanged(opts->audioBuffers);
|
||||
}
|
||||
|
||||
if (opts->sampleRate) {
|
||||
emit sampleRateChanged(opts->sampleRate);
|
||||
}
|
||||
|
||||
if (opts->width && opts->height) {
|
||||
resizeFrame(opts->width, opts->height);
|
||||
}
|
||||
|
@ -344,6 +360,11 @@ void Window::openMemoryWindow() {
|
|||
openView(memoryWindow);
|
||||
}
|
||||
|
||||
void Window::openAboutScreen() {
|
||||
AboutScreen* about = new AboutScreen();
|
||||
openView(about);
|
||||
}
|
||||
|
||||
#ifdef BUILD_SDL
|
||||
void Window::openGamepadWindow() {
|
||||
const char* profile = m_inputController.profileForType(SDL_BINDING_BUTTON);
|
||||
|
@ -386,9 +407,7 @@ void Window::gdbOpen() {
|
|||
m_gdbController = new GDBController(m_controller, this);
|
||||
}
|
||||
GDBWindow* window = new GDBWindow(m_gdbController);
|
||||
connect(this, SIGNAL(shutdown()), window, SLOT(close()));
|
||||
window->setAttribute(Qt::WA_DeleteOnClose);
|
||||
window->show();
|
||||
openView(window);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -420,14 +439,34 @@ void Window::keyReleaseEvent(QKeyEvent* event) {
|
|||
event->accept();
|
||||
}
|
||||
|
||||
void Window::resizeEvent(QResizeEvent*) {
|
||||
void Window::resizeEvent(QResizeEvent* event) {
|
||||
if (!isFullScreen()) {
|
||||
m_config->setOption("height", m_screenWidget->height());
|
||||
m_config->setOption("width", m_screenWidget->width());
|
||||
}
|
||||
|
||||
int factor = 0;
|
||||
if (event->size().width() % VIDEO_HORIZONTAL_PIXELS == 0 && event->size().height() % VIDEO_VERTICAL_PIXELS == 0 &&
|
||||
event->size().width() / VIDEO_HORIZONTAL_PIXELS == event->size().height() / VIDEO_VERTICAL_PIXELS) {
|
||||
factor = event->size().width() / VIDEO_HORIZONTAL_PIXELS;
|
||||
}
|
||||
for (QMap<int, QAction*>::iterator iter = m_frameSizes.begin(); iter != m_frameSizes.end(); ++iter) {
|
||||
bool enableSignals = iter.value()->blockSignals(true);
|
||||
if (iter.key() == factor) {
|
||||
iter.value()->setChecked(true);
|
||||
} else {
|
||||
iter.value()->setChecked(false);
|
||||
}
|
||||
iter.value()->blockSignals(enableSignals);
|
||||
}
|
||||
|
||||
m_config->setOption("fullscreen", isFullScreen());
|
||||
}
|
||||
|
||||
void Window::showEvent(QShowEvent* event) {
|
||||
resizeFrame(m_screenWidget->sizeHint().width(), m_screenWidget->sizeHint().height());
|
||||
}
|
||||
|
||||
void Window::closeEvent(QCloseEvent* event) {
|
||||
emit shutdown();
|
||||
m_config->setQtOption("windowPos", pos());
|
||||
|
@ -435,6 +474,10 @@ void Window::closeEvent(QCloseEvent* event) {
|
|||
QMainWindow::closeEvent(event);
|
||||
}
|
||||
|
||||
void Window::focusInEvent(QFocusEvent*) {
|
||||
m_display->forceDraw();
|
||||
}
|
||||
|
||||
void Window::focusOutEvent(QFocusEvent*) {
|
||||
m_controller->setTurbo(false, false);
|
||||
m_controller->stopRewinding();
|
||||
|
@ -475,7 +518,6 @@ void Window::enterFullScreen() {
|
|||
return;
|
||||
}
|
||||
showFullScreen();
|
||||
setCursor(Qt::BlankCursor);
|
||||
#ifndef Q_OS_MAC
|
||||
if (m_controller->isLoaded() && !m_controller->isPaused()) {
|
||||
menuBar()->hide();
|
||||
|
@ -487,7 +529,7 @@ void Window::exitFullScreen() {
|
|||
if (!isFullScreen()) {
|
||||
return;
|
||||
}
|
||||
unsetCursor();
|
||||
m_screenWidget->unsetCursor();
|
||||
menuBar()->show();
|
||||
showNormal();
|
||||
}
|
||||
|
@ -515,6 +557,7 @@ void Window::gameStarted(GBAThread* context) {
|
|||
action->setDisabled(false);
|
||||
}
|
||||
if (context->fname) {
|
||||
setWindowFilePath(context->fname);
|
||||
appendMRU(context->fname);
|
||||
}
|
||||
updateTitle();
|
||||
|
@ -534,10 +577,12 @@ void Window::gameStopped() {
|
|||
foreach (QAction* action, m_gameActions) {
|
||||
action->setDisabled(true);
|
||||
}
|
||||
setWindowFilePath(QString());
|
||||
updateTitle();
|
||||
detachWidget(m_display);
|
||||
m_screenWidget->setLockAspectRatio(m_logo.width(), m_logo.height());
|
||||
m_screenWidget->setPixmap(m_logo);
|
||||
m_screenWidget->unsetCursor();
|
||||
|
||||
m_fpsTimer.stop();
|
||||
}
|
||||
|
@ -640,7 +685,7 @@ void Window::openStateWindow(LoadSave ls) {
|
|||
connect(this, SIGNAL(shutdown()), m_stateWindow, SLOT(close()));
|
||||
connect(m_controller, SIGNAL(gameStopped(GBAThread*)), m_stateWindow, SLOT(close()));
|
||||
connect(m_stateWindow, &LoadSaveState::closed, [this]() {
|
||||
m_screenWidget->layout()->removeWidget(m_stateWindow);
|
||||
detachWidget(m_stateWindow);
|
||||
m_stateWindow = nullptr;
|
||||
QMetaObject::invokeMethod(this, "setFocus", Qt::QueuedConnection);
|
||||
});
|
||||
|
@ -752,6 +797,14 @@ void Window::setupMenu(QMenuBar* menubar) {
|
|||
});
|
||||
addControlledAction(fileMenu, multiWindow, "multiWindow");
|
||||
|
||||
#ifndef Q_OS_MAC
|
||||
fileMenu->addSeparator();
|
||||
#endif
|
||||
|
||||
QAction* about = new QAction(tr("About"), fileMenu);
|
||||
connect(about, SIGNAL(triggered()), this, SLOT(openAboutScreen()));
|
||||
fileMenu->addAction(about);
|
||||
|
||||
#ifndef Q_OS_MAC
|
||||
addControlledAction(fileMenu, fileMenu->addAction(tr("E&xit"), this, SLOT(close()), QKeySequence::Quit), "quit");
|
||||
#endif
|
||||
|
@ -782,13 +835,6 @@ void Window::setupMenu(QMenuBar* menubar) {
|
|||
connect(pause, SIGNAL(triggered(bool)), m_controller, SLOT(setPaused(bool)));
|
||||
connect(m_controller, &GameController::gamePaused, [this, pause]() {
|
||||
pause->setChecked(true);
|
||||
|
||||
QImage currentImage(reinterpret_cast<const uchar*>(m_controller->drawContext()), VIDEO_HORIZONTAL_PIXELS,
|
||||
VIDEO_VERTICAL_PIXELS, 1024, QImage::Format_RGB32);
|
||||
QPixmap pixmap;
|
||||
pixmap.convertFromImage(currentImage.rgbSwapped());
|
||||
m_screenWidget->setPixmap(pixmap);
|
||||
m_screenWidget->setLockAspectRatio(3, 2);
|
||||
});
|
||||
connect(m_controller, &GameController::gameUnpaused, [pause]() { pause->setChecked(false); });
|
||||
m_gameActions.append(pause);
|
||||
|
@ -897,10 +943,15 @@ void Window::setupMenu(QMenuBar* menubar) {
|
|||
m_shortcutController->addMenu(frameMenu, avMenu);
|
||||
for (int i = 1; i <= 6; ++i) {
|
||||
QAction* setSize = new QAction(tr("%1x").arg(QString::number(i)), avMenu);
|
||||
connect(setSize, &QAction::triggered, [this, i]() {
|
||||
setSize->setCheckable(true);
|
||||
connect(setSize, &QAction::triggered, [this, i, setSize]() {
|
||||
showNormal();
|
||||
resizeFrame(VIDEO_HORIZONTAL_PIXELS * i, VIDEO_VERTICAL_PIXELS * i);
|
||||
bool enableSignals = setSize->blockSignals(true);
|
||||
setSize->setChecked(true);
|
||||
setSize->blockSignals(enableSignals);
|
||||
});
|
||||
m_frameSizes[i] = setSize;
|
||||
addControlledAction(frameMenu, setSize, QString("frame%1x").arg(QString::number(i)));
|
||||
}
|
||||
QKeySequence fullscreenKeys;
|
||||
|
@ -937,20 +988,6 @@ void Window::setupMenu(QMenuBar* menubar) {
|
|||
|
||||
avMenu->addSeparator();
|
||||
|
||||
QMenu* buffersMenu = avMenu->addMenu(tr("Audio buffer &size"));
|
||||
ConfigOption* buffers = m_config->addOption("audioBuffers");
|
||||
buffers->connect([this](const QVariant& value) {
|
||||
emit audioBufferSamplesChanged(value.toInt());
|
||||
}, this);
|
||||
buffers->addValue(tr("512"), 512, buffersMenu);
|
||||
buffers->addValue(tr("768"), 768, buffersMenu);
|
||||
buffers->addValue(tr("1024"), 1024, buffersMenu);
|
||||
buffers->addValue(tr("2048"), 2048, buffersMenu);
|
||||
buffers->addValue(tr("4096"), 4096, buffersMenu);
|
||||
m_config->updateOption("audioBuffers");
|
||||
|
||||
avMenu->addSeparator();
|
||||
|
||||
QMenu* target = avMenu->addMenu(tr("FPS target"));
|
||||
ConfigOption* fpsTargetOption = m_config->addOption("fpsTarget");
|
||||
fpsTargetOption->connect([this](const QVariant& value) {
|
||||
|
@ -997,16 +1034,14 @@ void Window::setupMenu(QMenuBar* menubar) {
|
|||
QAction* enableBg = new QAction(tr("Background %0").arg(i), videoLayers);
|
||||
enableBg->setCheckable(true);
|
||||
enableBg->setChecked(true);
|
||||
connect(enableBg, &QAction::triggered, [this, i](bool enable) { m_controller->thread()->gba->video.renderer->disableBG[i] = !enable; });
|
||||
m_gameActions.append(enableBg);
|
||||
connect(enableBg, &QAction::triggered, [this, i](bool enable) { m_controller->setVideoLayerEnabled(i, enable); });
|
||||
addControlledAction(videoLayers, enableBg, QString("enableBG%0").arg(i));
|
||||
}
|
||||
|
||||
QAction* enableObj = new QAction(tr("OBJ (sprites)"), videoLayers);
|
||||
enableObj->setCheckable(true);
|
||||
enableObj->setChecked(true);
|
||||
connect(enableObj, &QAction::triggered, [this](bool enable) { m_controller->thread()->gba->video.renderer->disableOBJ = !enable; });
|
||||
m_gameActions.append(enableObj);
|
||||
connect(enableObj, &QAction::triggered, [this](bool enable) { m_controller->setVideoLayerEnabled(4, enable); });
|
||||
addControlledAction(videoLayers, enableObj, "enableOBJ");
|
||||
|
||||
QMenu* audioChannels = avMenu->addMenu(tr("Audio channels"));
|
||||
|
@ -1015,23 +1050,20 @@ void Window::setupMenu(QMenuBar* menubar) {
|
|||
QAction* enableCh = new QAction(tr("Channel %0").arg(i + 1), audioChannels);
|
||||
enableCh->setCheckable(true);
|
||||
enableCh->setChecked(true);
|
||||
connect(enableCh, &QAction::triggered, [this, i](bool enable) { m_controller->thread()->gba->audio.forceDisableCh[i] = !enable; });
|
||||
m_gameActions.append(enableCh);
|
||||
connect(enableCh, &QAction::triggered, [this, i](bool enable) { m_controller->setAudioChannelEnabled(i, enable); });
|
||||
addControlledAction(audioChannels, enableCh, QString("enableCh%0").arg(i + 1));
|
||||
}
|
||||
|
||||
QAction* enableChA = new QAction(tr("Channel A"), audioChannels);
|
||||
enableChA->setCheckable(true);
|
||||
enableChA->setChecked(true);
|
||||
connect(enableChA, &QAction::triggered, [this, i](bool enable) { m_controller->thread()->gba->audio.forceDisableChA = !enable; });
|
||||
m_gameActions.append(enableChA);
|
||||
connect(enableChA, &QAction::triggered, [this, i](bool enable) { m_controller->setAudioChannelEnabled(4, enable); });
|
||||
addControlledAction(audioChannels, enableChA, QString("enableChA"));
|
||||
|
||||
QAction* enableChB = new QAction(tr("Channel B"), audioChannels);
|
||||
enableChB->setCheckable(true);
|
||||
enableChB->setChecked(true);
|
||||
connect(enableChB, &QAction::triggered, [this, i](bool enable) { m_controller->thread()->gba->audio.forceDisableChB = !enable; });
|
||||
m_gameActions.append(enableChB);
|
||||
connect(enableChB, &QAction::triggered, [this, i](bool enable) { m_controller->setAudioChannelEnabled(5, enable); });
|
||||
addControlledAction(audioChannels, enableChB, QString("enableChB"));
|
||||
|
||||
QMenu* toolsMenu = menubar->addMenu(tr("&Tools"));
|
||||
|
@ -1091,6 +1123,21 @@ void Window::setupMenu(QMenuBar* menubar) {
|
|||
m_controller->setSkipBIOS(value.toBool());
|
||||
}, this);
|
||||
|
||||
ConfigOption* useBios = m_config->addOption("useBios");
|
||||
useBios->connect([this](const QVariant& value) {
|
||||
m_controller->setUseBIOS(value.toBool());
|
||||
}, this);
|
||||
|
||||
ConfigOption* buffers = m_config->addOption("audioBuffers");
|
||||
buffers->connect([this](const QVariant& value) {
|
||||
emit audioBufferSamplesChanged(value.toInt());
|
||||
}, this);
|
||||
|
||||
ConfigOption* sampleRate = m_config->addOption("sampleRate");
|
||||
sampleRate->connect([this](const QVariant& value) {
|
||||
emit sampleRateChanged(value.toUInt());
|
||||
}, this);
|
||||
|
||||
ConfigOption* volume = m_config->addOption("volume");
|
||||
volume->connect([this](const QVariant& value) {
|
||||
m_controller->setVolume(value.toInt());
|
||||
|
@ -1133,7 +1180,7 @@ void Window::setupMenu(QMenuBar* menubar) {
|
|||
|
||||
void Window::attachWidget(QWidget* widget) {
|
||||
m_screenWidget->layout()->addWidget(widget);
|
||||
unsetCursor();
|
||||
m_screenWidget->unsetCursor();
|
||||
static_cast<QStackedLayout*>(m_screenWidget->layout())->setCurrentWidget(widget);
|
||||
}
|
||||
|
||||
|
@ -1215,10 +1262,10 @@ void WindowBackground::paintEvent(QPaintEvent*) {
|
|||
painter.fillRect(QRect(QPoint(), size()), Qt::black);
|
||||
QSize s = size();
|
||||
QSize ds = s;
|
||||
if (s.width() * m_aspectHeight > s.height() * m_aspectWidth) {
|
||||
ds.setWidth(s.height() * m_aspectWidth / m_aspectHeight);
|
||||
} else if (s.width() * m_aspectHeight < s.height() * m_aspectWidth) {
|
||||
ds.setHeight(s.width() * m_aspectHeight / m_aspectWidth);
|
||||
if (ds.width() * m_aspectHeight > ds.height() * m_aspectWidth) {
|
||||
ds.setWidth(ds.height() * m_aspectWidth / m_aspectHeight);
|
||||
} else if (ds.width() * m_aspectHeight < ds.height() * m_aspectWidth) {
|
||||
ds.setHeight(ds.width() * m_aspectHeight / m_aspectWidth);
|
||||
}
|
||||
QPoint origin = QPoint((s.width() - ds.width()) / 2, (s.height() - ds.height()) / 2);
|
||||
QRect full(origin, ds);
|
||||
|
|
|
@ -54,6 +54,7 @@ signals:
|
|||
void startDrawing(GBAThread*);
|
||||
void shutdown();
|
||||
void audioBufferSamplesChanged(int samples);
|
||||
void sampleRateChanged(unsigned samples);
|
||||
void fpsTargetChanged(float target);
|
||||
|
||||
public slots:
|
||||
|
@ -82,6 +83,8 @@ public slots:
|
|||
void openPaletteWindow();
|
||||
void openMemoryWindow();
|
||||
|
||||
void openAboutScreen();
|
||||
|
||||
#ifdef BUILD_SDL
|
||||
void openGamepadWindow();
|
||||
#endif
|
||||
|
@ -102,7 +105,9 @@ protected:
|
|||
virtual void keyPressEvent(QKeyEvent* event) override;
|
||||
virtual void keyReleaseEvent(QKeyEvent* event) override;
|
||||
virtual void resizeEvent(QResizeEvent*) override;
|
||||
virtual void showEvent(QShowEvent*) override;
|
||||
virtual void closeEvent(QCloseEvent*) override;
|
||||
virtual void focusInEvent(QFocusEvent*) override;
|
||||
virtual void focusOutEvent(QFocusEvent*) override;
|
||||
virtual void dragEnterEvent(QDragEnterEvent*) override;
|
||||
virtual void dropEvent(QDropEvent*) override;
|
||||
|
@ -144,6 +149,7 @@ private:
|
|||
GameController* m_controller;
|
||||
Display* m_display;
|
||||
QList<QAction*> m_gameActions;
|
||||
QMap<int, QAction*> m_frameSizes;
|
||||
LogController m_log;
|
||||
LogView* m_logView;
|
||||
LoadSaveState* m_stateWindow;
|
||||
|
|
|
@ -10,9 +10,11 @@
|
|||
#include <QtPlugin>
|
||||
#ifdef _WIN32
|
||||
Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin);
|
||||
#ifdef BUILD_QT_MULTIMEDIA
|
||||
Q_IMPORT_PLUGIN(QWindowsAudioPlugin);
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
QGBA::GBAApp application(argc, argv);
|
||||
|
|
|
@ -51,13 +51,16 @@ set(MAIN_SRC ${CMAKE_SOURCE_DIR}/src/platform/sdl/main.c)
|
|||
|
||||
if(BUILD_RASPI)
|
||||
add_definitions(-DBUILD_RASPI)
|
||||
set(EGL_MAIN_SRC ${CMAKE_SOURCE_DIR}/src/platform/sdl/egl-sdl.c)
|
||||
set(EGL_LIBRARY "-lEGL -lGLESv2 -lbcm_host")
|
||||
list(APPEND PLATFORM_SRC ${CMAKE_SOURCE_DIR}/src/platform/opengl/gles2.c ${CMAKE_SOURCE_DIR}/src/platform/sdl/gl-common.c)
|
||||
list(APPEND MAIN_SRC ${CMAKE_SOURCE_DIR}/src/platform/sdl/gles2-sdl.c)
|
||||
set(OPENGLES2_LIBRARY "-lEGL -lGLESv2 -lbcm_host")
|
||||
set(BUILD_GLES2 ON CACHE BOOL "Using OpenGL|ES 2" FORCE)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fgnu89-inline")
|
||||
add_executable(${BINARY_NAME}-rpi ${PLATFORM_SRC} ${MAIN_SRC} ${EGL_MAIN_SRC})
|
||||
add_executable(${BINARY_NAME}-rpi ${PLATFORM_SRC} ${MAIN_SRC})
|
||||
set_target_properties(${BINARY_NAME}-rpi PROPERTIES COMPILE_DEFINITIONS "${FEATURE_DEFINES}")
|
||||
target_link_libraries(${BINARY_NAME}-rpi ${BINARY_NAME} ${PLATFORM_LIBRARY} ${EGL_LIBRARY})
|
||||
target_link_libraries(${BINARY_NAME}-rpi ${BINARY_NAME} ${PLATFORM_LIBRARY} ${OPENGLES2_LIBRARY})
|
||||
install(TARGETS ${BINARY_NAME}-rpi DESTINATION bin COMPONENT ${BINARY_NAME}-rpi)
|
||||
unset(OPENGLES2_INCLUDE_DIR} CACHE) # Clear NOTFOUND
|
||||
endif()
|
||||
|
||||
if(BUILD_PANDORA)
|
||||
|
@ -66,13 +69,21 @@ else()
|
|||
list(APPEND MAIN_SRC ${CMAKE_SOURCE_DIR}/src/platform/sdl/sw-sdl.c)
|
||||
if(BUILD_GL)
|
||||
list(APPEND MAIN_SRC ${CMAKE_SOURCE_DIR}/src/platform/sdl/gl-sdl.c)
|
||||
list(APPEND PLATFORM_SRC ${CMAKE_SOURCE_DIR}/src/platform/opengl/gl.c)
|
||||
list(APPEND PLATFORM_SRC ${CMAKE_SOURCE_DIR}/src/platform/opengl/gl.c ${CMAKE_SOURCE_DIR}/src/platform/sdl/gl-common.c)
|
||||
include_directories(${OPENGL_INCLUDE_DIR})
|
||||
endif()
|
||||
if(BUILD_GLES2)
|
||||
list(APPEND MAIN_SRC ${CMAKE_SOURCE_DIR}/src/platform/sdl/gles2-sdl.c)
|
||||
list(APPEND PLATFORM_SRC ${CMAKE_SOURCE_DIR}/src/platform/opengl/gles2.c ${CMAKE_SOURCE_DIR}/src/platform/sdl/gl-common.c)
|
||||
include_directories(${OPENGLES2_INCLUDE_DIR})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
add_executable(${BINARY_NAME}-sdl WIN32 ${PLATFORM_SRC} ${MAIN_SRC})
|
||||
set_target_properties(${BINARY_NAME}-sdl PROPERTIES COMPILE_DEFINITIONS "${FEATURE_DEFINES}")
|
||||
target_link_libraries(${BINARY_NAME}-sdl ${BINARY_NAME} ${PLATFORM_LIBRARY} ${OPENGL_LIBRARY})
|
||||
target_link_libraries(${BINARY_NAME}-sdl ${BINARY_NAME} ${PLATFORM_LIBRARY} ${OPENGL_LIBRARY} ${OPENGLES2_LIBRARY})
|
||||
set_target_properties(${BINARY_NAME}-sdl PROPERTIES OUTPUT_NAME ${BINARY_NAME})
|
||||
install(TARGETS ${BINARY_NAME}-sdl DESTINATION bin COMPONENT ${BINARY_NAME}-sdl)
|
||||
if(UNIX)
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/doc/mgba.6 DESTINATION ${MANDIR}/man6 COMPONENT ${BINARY_NAME}-sdl)
|
||||
endif()
|
||||
|
|
|
@ -1,166 +0,0 @@
|
|||
/* Copyright (c) 2013-2014 Jeffrey Pfau
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#include "main.h"
|
||||
|
||||
static const char* _vertexShader =
|
||||
"attribute vec4 position;\n"
|
||||
"varying vec2 texCoord;\n"
|
||||
|
||||
"void main() {\n"
|
||||
" gl_Position = position;\n"
|
||||
" texCoord = (position.st + vec2(1.0, -1.0)) * vec2(0.46875, -0.3125);\n"
|
||||
"}";
|
||||
|
||||
static const char* _fragmentShader =
|
||||
"varying vec2 texCoord;\n"
|
||||
"uniform sampler2D tex;\n"
|
||||
|
||||
"void main() {\n"
|
||||
" vec4 color = texture2D(tex, texCoord);\n"
|
||||
" color.a = 1.;\n"
|
||||
" gl_FragColor = color;"
|
||||
"}";
|
||||
|
||||
static const GLfloat _vertices[] = {
|
||||
-1.f, -1.f,
|
||||
-1.f, 1.f,
|
||||
1.f, 1.f,
|
||||
1.f, -1.f,
|
||||
};
|
||||
|
||||
bool GBASDLInit(struct SDLSoftwareRenderer* renderer) {
|
||||
bcm_host_init();
|
||||
renderer->display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
|
||||
int major, minor;
|
||||
if (EGL_FALSE == eglInitialize(renderer->display, &major, &minor)) {
|
||||
printf("Failed to initialize EGL");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (EGL_FALSE == eglBindAPI(EGL_OPENGL_ES_API)) {
|
||||
printf("Failed to get GLES API");
|
||||
return false;
|
||||
}
|
||||
|
||||
const EGLint requestConfig[] = {
|
||||
EGL_RED_SIZE, 5,
|
||||
EGL_GREEN_SIZE, 5,
|
||||
EGL_BLUE_SIZE, 5,
|
||||
EGL_ALPHA_SIZE, 1,
|
||||
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
|
||||
EGL_NONE
|
||||
};
|
||||
|
||||
EGLConfig config;
|
||||
EGLint numConfigs;
|
||||
|
||||
if (EGL_FALSE == eglChooseConfig(renderer->display, requestConfig, &config, 1, &numConfigs)) {
|
||||
printf("Failed to choose EGL config\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
const EGLint contextAttributes[] = {
|
||||
EGL_CONTEXT_CLIENT_VERSION, 2,
|
||||
EGL_NONE
|
||||
};
|
||||
|
||||
int dispWidth = 240, dispHeight = 160, adjWidth;
|
||||
renderer->context = eglCreateContext(renderer->display, config, EGL_NO_CONTEXT, contextAttributes);
|
||||
graphics_get_display_size(0, &dispWidth, &dispHeight);
|
||||
adjWidth = dispHeight / 2 * 3;
|
||||
|
||||
DISPMANX_DISPLAY_HANDLE_T display = vc_dispmanx_display_open(0);
|
||||
DISPMANX_UPDATE_HANDLE_T update = vc_dispmanx_update_start(0);
|
||||
|
||||
VC_RECT_T destRect = {
|
||||
.x = (dispWidth - adjWidth) / 2,
|
||||
.y = 0,
|
||||
.width = adjWidth,
|
||||
.height = dispHeight
|
||||
};
|
||||
|
||||
VC_RECT_T srcRect = {
|
||||
.x = 0,
|
||||
.y = 0,
|
||||
.width = 240 << 16,
|
||||
.height = 160 << 16
|
||||
};
|
||||
|
||||
DISPMANX_ELEMENT_HANDLE_T element = vc_dispmanx_element_add(update, display, 0, &destRect, 0, &srcRect, DISPMANX_PROTECTION_NONE, 0, 0, 0);
|
||||
vc_dispmanx_update_submit_sync(update);
|
||||
|
||||
renderer->window.element = element;
|
||||
renderer->window.width = dispWidth;
|
||||
renderer->window.height = dispHeight;
|
||||
|
||||
renderer->surface = eglCreateWindowSurface(renderer->display, config, &renderer->window, 0);
|
||||
if (EGL_FALSE == eglMakeCurrent(renderer->display, renderer->surface, renderer->surface, renderer->context)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
renderer->d.outputBuffer = memalign(16, 256 * 256 * 4);
|
||||
renderer->d.outputBufferStride = 256;
|
||||
glGenTextures(1, &renderer->tex);
|
||||
glBindTexture(GL_TEXTURE_2D, renderer->tex);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
|
||||
renderer->fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
|
||||
renderer->vertexShader = glCreateShader(GL_VERTEX_SHADER);
|
||||
renderer->program = glCreateProgram();
|
||||
|
||||
glShaderSource(renderer->fragmentShader, 1, (const GLchar**) &_fragmentShader, 0);
|
||||
glShaderSource(renderer->vertexShader, 1, (const GLchar**) &_vertexShader, 0);
|
||||
glAttachShader(renderer->program, renderer->vertexShader);
|
||||
glAttachShader(renderer->program, renderer->fragmentShader);
|
||||
char log[1024];
|
||||
glCompileShader(renderer->fragmentShader);
|
||||
glCompileShader(renderer->vertexShader);
|
||||
glGetShaderInfoLog(renderer->fragmentShader, 1024, 0, log);
|
||||
glGetShaderInfoLog(renderer->vertexShader, 1024, 0, log);
|
||||
glLinkProgram(renderer->program);
|
||||
glGetProgramInfoLog(renderer->program, 1024, 0, log);
|
||||
printf("%s\n", log);
|
||||
renderer->texLocation = glGetUniformLocation(renderer->program, "tex");
|
||||
renderer->positionLocation = glGetAttribLocation(renderer->program, "position");
|
||||
glClearColor(1.f, 0.f, 0.f, 1.f);
|
||||
}
|
||||
|
||||
void GBASDLRunloop(struct GBAThread* context, struct SDLSoftwareRenderer* renderer) {
|
||||
SDL_Event event;
|
||||
|
||||
while (context->state < THREAD_EXITING) {
|
||||
while (SDL_PollEvent(&event)) {
|
||||
GBASDLHandleEvent(context, &renderer->player, &event);
|
||||
}
|
||||
|
||||
if (GBASyncWaitFrameStart(&context->sync, context->frameskip)) {
|
||||
glViewport(0, 0, 240, 160);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
glUseProgram(renderer->program);
|
||||
glUniform1i(renderer->texLocation, 0);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, renderer->tex);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, renderer->d.outputBuffer);
|
||||
glVertexAttribPointer(renderer->positionLocation, 2, GL_FLOAT, GL_FALSE, 0, _vertices);
|
||||
glEnableVertexAttribArray(renderer->positionLocation);
|
||||
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
|
||||
glUseProgram(0);
|
||||
eglSwapBuffers(renderer->display, renderer->surface);
|
||||
}
|
||||
GBASyncWaitFrameEnd(&context->sync);
|
||||
}
|
||||
}
|
||||
|
||||
void GBASDLDeinit(struct SDLSoftwareRenderer* renderer) {
|
||||
eglMakeCurrent(renderer->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
|
||||
eglDestroySurface(renderer->display, renderer->surface);
|
||||
eglDestroyContext(renderer->display, renderer->context);
|
||||
eglTerminate(renderer->display);
|
||||
bcm_host_deinit();
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
/* Copyright (c) 2013-2015 Jeffrey Pfau
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#include "main.h"
|
||||
|
||||
void GBASDLGLCommonSwap(struct VideoBackend* context) {
|
||||
struct SDLSoftwareRenderer* renderer = (struct SDLSoftwareRenderer*) context->user;
|
||||
#if SDL_VERSION_ATLEAST(2, 0, 0)
|
||||
SDL_GL_SwapWindow(renderer->window);
|
||||
#else
|
||||
UNUSED(renderer);
|
||||
SDL_GL_SwapBuffers();
|
||||
#endif
|
||||
}
|
||||
|
||||
void GBASDLGLCommonInit(struct SDLSoftwareRenderer* renderer) {
|
||||
#ifndef COLOR_16_BIT
|
||||
SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
|
||||
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
|
||||
SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
|
||||
#else
|
||||
SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5);
|
||||
#ifdef COLOR_5_6_5
|
||||
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 6);
|
||||
#else
|
||||
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 5);
|
||||
#endif
|
||||
SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5);
|
||||
#endif
|
||||
|
||||
#if SDL_VERSION_ATLEAST(2, 0, 0)
|
||||
renderer->window = SDL_CreateWindow(projectName, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, renderer->viewportWidth, renderer->viewportHeight, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | (SDL_WINDOW_FULLSCREEN_DESKTOP * renderer->player.fullscreen));
|
||||
renderer->glCtx = SDL_GL_CreateContext(renderer->window);
|
||||
SDL_GL_SetSwapInterval(1);
|
||||
SDL_GetWindowSize(renderer->window, &renderer->viewportWidth, &renderer->viewportHeight);
|
||||
renderer->player.window = renderer->window;
|
||||
#else
|
||||
SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, 1);
|
||||
#ifdef COLOR_16_BIT
|
||||
SDL_SetVideoMode(renderer->viewportWidth, renderer->viewportHeight, 16, SDL_OPENGL);
|
||||
#else
|
||||
SDL_SetVideoMode(renderer->viewportWidth, renderer->viewportHeight, 32, SDL_OPENGL);
|
||||
#endif
|
||||
#endif
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
/* Copyright (c) 2013-2015 Jeffrey Pfau
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#ifndef SDL_GL_COMMON_H
|
||||
#define SDL_GL_COMMON_H
|
||||
#include "main.h"
|
||||
|
||||
void GBASDLGLCommonSwap(struct VideoBackend* context);
|
||||
void GBASDLGLCommonInit(struct SDLSoftwareRenderer* renderer);
|
||||
|
||||
#endif
|
|
@ -5,18 +5,11 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#include "main.h"
|
||||
|
||||
#include "gl-common.h"
|
||||
|
||||
#include "gba/supervisor/thread.h"
|
||||
#include "platform/opengl/gl.h"
|
||||
|
||||
static void _sdlSwap(struct VideoBackend* context) {
|
||||
struct SDLSoftwareRenderer* renderer = (struct SDLSoftwareRenderer*) context->user;
|
||||
#if SDL_VERSION_ATLEAST(2, 0, 0)
|
||||
SDL_GL_SwapWindow(renderer->window);
|
||||
#else
|
||||
SDL_GL_SwapBuffers();
|
||||
#endif
|
||||
}
|
||||
|
||||
static void _doViewport(int w, int h, struct VideoBackend* v) {
|
||||
v->resized(v, w, h);
|
||||
v->clear(v);
|
||||
|
@ -35,34 +28,7 @@ void GBASDLGLCreate(struct SDLSoftwareRenderer* renderer) {
|
|||
}
|
||||
|
||||
bool GBASDLGLInit(struct SDLSoftwareRenderer* renderer) {
|
||||
#ifndef COLOR_16_BIT
|
||||
SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
|
||||
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
|
||||
SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
|
||||
#else
|
||||
SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5);
|
||||
#ifdef COLOR_5_6_5
|
||||
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 6);
|
||||
#else
|
||||
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 5);
|
||||
#endif
|
||||
SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5);
|
||||
#endif
|
||||
|
||||
#if SDL_VERSION_ATLEAST(2, 0, 0)
|
||||
renderer->window = SDL_CreateWindow(projectName, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, renderer->viewportWidth, renderer->viewportHeight, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | (SDL_WINDOW_FULLSCREEN_DESKTOP * renderer->player.fullscreen));
|
||||
renderer->glCtx = SDL_GL_CreateContext(renderer->window);
|
||||
SDL_GL_SetSwapInterval(1);
|
||||
SDL_GetWindowSize(renderer->window, &renderer->viewportWidth, &renderer->viewportHeight);
|
||||
renderer->player.window = renderer->window;
|
||||
#else
|
||||
SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, 1);
|
||||
#ifdef COLOR_16_BIT
|
||||
SDL_SetVideoMode(renderer->viewportWidth, renderer->viewportHeight, 16, SDL_OPENGL);
|
||||
#else
|
||||
SDL_SetVideoMode(renderer->viewportWidth, renderer->viewportHeight, 32, SDL_OPENGL);
|
||||
#endif
|
||||
#endif
|
||||
GBASDLGLCommonInit(renderer);
|
||||
|
||||
renderer->d.outputBuffer = malloc(256 * 256 * BYTES_PER_PIXEL);
|
||||
renderer->d.outputBufferStride = 256;
|
||||
|
@ -71,7 +37,7 @@ bool GBASDLGLInit(struct SDLSoftwareRenderer* renderer) {
|
|||
renderer->gl.d.user = renderer;
|
||||
renderer->gl.d.lockAspectRatio = renderer->lockAspectRatio;
|
||||
renderer->gl.d.filter = renderer->filter;
|
||||
renderer->gl.d.swap = _sdlSwap;
|
||||
renderer->gl.d.swap = GBASDLGLCommonSwap;
|
||||
renderer->gl.d.init(&renderer->gl.d, 0);
|
||||
|
||||
_doViewport(renderer->viewportWidth, renderer->viewportHeight, &renderer->gl.d);
|
||||
|
|
|
@ -0,0 +1,144 @@
|
|||
/* Copyright (c) 2013-2015 Jeffrey Pfau
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#include "main.h"
|
||||
|
||||
#include "gl-common.h"
|
||||
|
||||
#include <malloc.h>
|
||||
|
||||
static bool GBASDLGLES2Init(struct SDLSoftwareRenderer* renderer);
|
||||
static void GBASDLGLES2Runloop(struct GBAThread* context, struct SDLSoftwareRenderer* renderer);
|
||||
static void GBASDLGLES2Deinit(struct SDLSoftwareRenderer* renderer);
|
||||
|
||||
void GBASDLGLES2Create(struct SDLSoftwareRenderer* renderer) {
|
||||
renderer->init = GBASDLGLES2Init;
|
||||
renderer->deinit = GBASDLGLES2Deinit;
|
||||
renderer->runloop = GBASDLGLES2Runloop;
|
||||
}
|
||||
|
||||
bool GBASDLGLES2Init(struct SDLSoftwareRenderer* renderer) {
|
||||
#ifdef BUILD_RASPI
|
||||
bcm_host_init();
|
||||
renderer->display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
|
||||
int major, minor;
|
||||
if (EGL_FALSE == eglInitialize(renderer->display, &major, &minor)) {
|
||||
printf("Failed to initialize EGL");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (EGL_FALSE == eglBindAPI(EGL_OPENGL_ES_API)) {
|
||||
printf("Failed to get GLES API");
|
||||
return false;
|
||||
}
|
||||
|
||||
const EGLint requestConfig[] = {
|
||||
EGL_RED_SIZE, 5,
|
||||
EGL_GREEN_SIZE, 5,
|
||||
EGL_BLUE_SIZE, 5,
|
||||
EGL_ALPHA_SIZE, 1,
|
||||
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
|
||||
EGL_NONE
|
||||
};
|
||||
|
||||
EGLConfig config;
|
||||
EGLint numConfigs;
|
||||
|
||||
if (EGL_FALSE == eglChooseConfig(renderer->display, requestConfig, &config, 1, &numConfigs)) {
|
||||
printf("Failed to choose EGL config\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
const EGLint contextAttributes[] = {
|
||||
EGL_CONTEXT_CLIENT_VERSION, 2,
|
||||
EGL_NONE
|
||||
};
|
||||
|
||||
int dispWidth = 240, dispHeight = 160, adjWidth;
|
||||
renderer->context = eglCreateContext(renderer->display, config, EGL_NO_CONTEXT, contextAttributes);
|
||||
graphics_get_display_size(0, &dispWidth, &dispHeight);
|
||||
adjWidth = dispHeight / 2 * 3;
|
||||
|
||||
DISPMANX_DISPLAY_HANDLE_T display = vc_dispmanx_display_open(0);
|
||||
DISPMANX_UPDATE_HANDLE_T update = vc_dispmanx_update_start(0);
|
||||
|
||||
VC_RECT_T destRect = {
|
||||
.x = (dispWidth - adjWidth) / 2,
|
||||
.y = 0,
|
||||
.width = adjWidth,
|
||||
.height = dispHeight
|
||||
};
|
||||
|
||||
VC_RECT_T srcRect = {
|
||||
.x = 0,
|
||||
.y = 0,
|
||||
.width = 240 << 16,
|
||||
.height = 160 << 16
|
||||
};
|
||||
|
||||
DISPMANX_ELEMENT_HANDLE_T element = vc_dispmanx_element_add(update, display, 0, &destRect, 0, &srcRect, DISPMANX_PROTECTION_NONE, 0, 0, 0);
|
||||
vc_dispmanx_update_submit_sync(update);
|
||||
|
||||
renderer->window.element = element;
|
||||
renderer->window.width = dispWidth;
|
||||
renderer->window.height = dispHeight;
|
||||
|
||||
renderer->surface = eglCreateWindowSurface(renderer->display, config, &renderer->window, 0);
|
||||
if (EGL_FALSE == eglMakeCurrent(renderer->display, renderer->surface, renderer->surface, renderer->context)) {
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
GBASDLGLCommonInit(renderer);
|
||||
#endif
|
||||
|
||||
renderer->d.outputBuffer = memalign(16, 256 * 256 * 4);
|
||||
renderer->d.outputBufferStride = 256;
|
||||
|
||||
GBAGLES2ContextCreate(&renderer->gl);
|
||||
renderer->gl.d.user = renderer;
|
||||
renderer->gl.d.lockAspectRatio = renderer->lockAspectRatio;
|
||||
renderer->gl.d.filter = renderer->filter;
|
||||
renderer->gl.d.swap = GBASDLGLCommonSwap;
|
||||
renderer->gl.d.init(&renderer->gl.d, 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
void GBASDLGLES2Runloop(struct GBAThread* context, struct SDLSoftwareRenderer* renderer) {
|
||||
SDL_Event event;
|
||||
struct VideoBackend* v = &renderer->gl.d;
|
||||
|
||||
while (context->state < THREAD_EXITING) {
|
||||
while (SDL_PollEvent(&event)) {
|
||||
GBASDLHandleEvent(context, &renderer->player, &event);
|
||||
}
|
||||
|
||||
if (GBASyncWaitFrameStart(&context->sync, context->frameskip)) {
|
||||
v->postFrame(v, renderer->d.outputBuffer);
|
||||
}
|
||||
v->drawFrame(v);
|
||||
GBASyncWaitFrameEnd(&context->sync);
|
||||
#ifdef BUILD_RASPI
|
||||
eglSwapBuffers(renderer->display, renderer->surface);
|
||||
#else
|
||||
v->swap(v);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void GBASDLGLES2Deinit(struct SDLSoftwareRenderer* renderer) {
|
||||
if (renderer->gl.d.deinit) {
|
||||
renderer->gl.d.deinit(&renderer->gl.d);
|
||||
}
|
||||
#ifdef BUILD_RASPI
|
||||
eglMakeCurrent(renderer->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
|
||||
eglDestroySurface(renderer->display, renderer->surface);
|
||||
eglDestroyContext(renderer->display, renderer->context);
|
||||
eglTerminate(renderer->display);
|
||||
bcm_host_deinit();
|
||||
#elif SDL_VERSION_ATLEAST(2, 0, 0)
|
||||
SDL_GL_DeleteContext(renderer->glCtx);
|
||||
#endif
|
||||
free(renderer->d.outputBuffer);
|
||||
}
|
|
@ -86,6 +86,8 @@ int main(int argc, char** argv) {
|
|||
|
||||
#ifdef BUILD_GL
|
||||
GBASDLGLCreate(&renderer);
|
||||
#elif defined(BUILD_GLES2)
|
||||
GBASDLGLES2Create(&renderer);
|
||||
#else
|
||||
GBASDLSWCreate(&renderer);
|
||||
#endif
|
||||
|
@ -110,6 +112,10 @@ int main(int argc, char** argv) {
|
|||
bool didFail = false;
|
||||
|
||||
renderer.audio.samples = context.audioBuffers;
|
||||
renderer.audio.sampleRate = 44100;
|
||||
if (opts.sampleRate) {
|
||||
renderer.audio.sampleRate = opts.sampleRate;
|
||||
}
|
||||
if (!GBASDLInitAudio(&renderer.audio, &context)) {
|
||||
didFail = true;
|
||||
}
|
||||
|
|
|
@ -20,13 +20,16 @@
|
|||
#pragma GCC diagnostic ignored "-Wunused-function"
|
||||
#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
|
||||
#include <SDL/SDL.h>
|
||||
#include <GLES2/gl2.h>
|
||||
#include <EGL/egl.h>
|
||||
|
||||
#include <bcm_host.h>
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
#ifdef BUILD_GLES2
|
||||
#include "platform/opengl/gles2.h"
|
||||
#endif
|
||||
|
||||
#ifdef USE_PIXMAN
|
||||
#include <pixman.h>
|
||||
#endif
|
||||
|
@ -57,6 +60,8 @@ struct SDLSoftwareRenderer {
|
|||
|
||||
#ifdef BUILD_GL
|
||||
struct GBAGLContext gl;
|
||||
#elif BUILD_GLES2
|
||||
struct GBAGLES2Context gl;
|
||||
#endif
|
||||
|
||||
#ifdef USE_PIXMAN
|
||||
|
@ -69,13 +74,6 @@ struct SDLSoftwareRenderer {
|
|||
EGLSurface surface;
|
||||
EGLContext context;
|
||||
EGL_DISPMANX_WINDOW_T window;
|
||||
GLuint tex;
|
||||
GLuint fragmentShader;
|
||||
GLuint vertexShader;
|
||||
GLuint program;
|
||||
GLuint bufferObject;
|
||||
GLuint texLocation;
|
||||
GLuint positionLocation;
|
||||
#endif
|
||||
|
||||
#ifdef BUILD_PANDORA
|
||||
|
@ -90,4 +88,8 @@ void GBASDLSWCreate(struct SDLSoftwareRenderer* renderer);
|
|||
#ifdef BUILD_GL
|
||||
void GBASDLGLCreate(struct SDLSoftwareRenderer* renderer);
|
||||
#endif
|
||||
|
||||
#ifdef BUILD_GLES2
|
||||
void GBASDLGLES2Create(struct SDLSoftwareRenderer* renderer);
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
@ -22,7 +22,7 @@ bool GBASDLInitAudio(struct GBASDLAudio* context, struct GBAThread* threadContex
|
|||
return false;
|
||||
}
|
||||
|
||||
context->desiredSpec.freq = 44100;
|
||||
context->desiredSpec.freq = context->sampleRate;
|
||||
context->desiredSpec.format = AUDIO_S16SYS;
|
||||
context->desiredSpec.channels = 2;
|
||||
context->desiredSpec.samples = context->samples;
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
struct GBASDLAudio {
|
||||
// Input
|
||||
size_t samples;
|
||||
unsigned sampleRate;
|
||||
|
||||
// State
|
||||
SDL_AudioSpec desiredSpec;
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
#endif
|
||||
|
||||
#define GYRO_STEPS 100
|
||||
#define RUMBLE_PWM 35
|
||||
#define RUMBLE_PWM 20
|
||||
|
||||
#if SDL_VERSION_ATLEAST(2, 0, 0)
|
||||
static void _GBASDLSetRumble(struct GBARumble* rumble, int enable);
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
mgba (0.3.0-1) UNRELEASED; urgency=low
|
||||
|
||||
* Initial release (closes: Bug#787470).
|
||||
|
||||
-- Sérgio Benjamim <sergio_br2@yahoo.com.br> Mon, 17 Aug 2015 18:40:00 -0300
|
|
@ -0,0 +1,2 @@
|
|||
debian/libmgba.install
|
||||
debian/libretro-mgba.install
|
|
@ -0,0 +1 @@
|
|||
9
|
|
@ -0,0 +1,78 @@
|
|||
Source: mgba
|
||||
Section: otherosfs
|
||||
Priority: extra
|
||||
Maintainer: Sérgio Benjamim <sergio_br2@yahoo.com.br>
|
||||
Build-Depends: cmake (>= 2.8.11),
|
||||
debhelper (>= 9),
|
||||
libavcodec-dev,
|
||||
libavformat-dev,
|
||||
libavresample-dev,
|
||||
libavutil-dev,
|
||||
libedit-dev,
|
||||
libmagickwand-dev,
|
||||
libpng-dev,
|
||||
libqt5opengl5-dev,
|
||||
libsdl2-dev,
|
||||
libswscale-dev,
|
||||
libzip-dev,
|
||||
pkg-config,
|
||||
qtbase5-dev,
|
||||
qtmultimedia5-dev,
|
||||
zlib1g-dev
|
||||
Standards-Version: 3.9.6
|
||||
Homepage: http://mgba.io/
|
||||
|
||||
Package: libmgba
|
||||
Architecture: any
|
||||
Multi-Arch: same
|
||||
Depends: ${misc:Depends}, ${shlibs:Depends}
|
||||
Description: Game Boy Advance emulator (common library for mGBA)
|
||||
mGBA is a new emulator for running Game Boy Advance games. It aims to be faster
|
||||
and more accurate than many existing Game Boy Advance emulators, as well as
|
||||
adding features that other emulators lack.
|
||||
.
|
||||
This package provides the common library for mGBA.
|
||||
.
|
||||
Game Boy Advance is a registered trademark of Nintendo of America Inc. mGBA is
|
||||
not affiliated with or endorsed by any of the companies mentioned.
|
||||
|
||||
Package: mgba-qt
|
||||
Architecture: any
|
||||
Depends: ${misc:Depends}, ${shlibs:Depends}
|
||||
Description: Game Boy Advance emulator (Qt frontend for mGBA)
|
||||
mGBA is a new emulator for running Game Boy Advance games. It aims to be faster
|
||||
and more accurate than many existing Game Boy Advance emulators, as well as
|
||||
adding features that other emulators lack.
|
||||
.
|
||||
This package provides the Qt GUI frontend for mGBA.
|
||||
.
|
||||
Game Boy Advance is a registered trademark of Nintendo of America Inc. mGBA is
|
||||
not affiliated with or endorsed by any of the companies mentioned.
|
||||
|
||||
Package: mgba-sdl
|
||||
Architecture: any
|
||||
Depends: ${misc:Depends}, ${shlibs:Depends}
|
||||
Description: Game Boy Advance emulator (SDL frontend for mGBA)
|
||||
mGBA is a new emulator for running Game Boy Advance games. It aims to be faster
|
||||
and more accurate than many existing Game Boy Advance emulators, as well as
|
||||
adding features that other emulators lack.
|
||||
.
|
||||
This package provides the SDL UI console for mGBA.
|
||||
.
|
||||
Game Boy Advance is a registered trademark of Nintendo of America Inc. mGBA is
|
||||
not affiliated with or endorsed by any of the companies mentioned.
|
||||
|
||||
Package: libretro-mgba
|
||||
Architecture: any
|
||||
Multi-Arch: same
|
||||
Depends: ${misc:Depends}, ${shlibs:Depends}
|
||||
Description: Libretro wrapper for mGBA
|
||||
This wrapper makes mGBA API compatible with libretro, thus allowing its use
|
||||
with libretro frontends, such as RetroArch.
|
||||
.
|
||||
mGBA is a new emulator for running Game Boy Advance games. It aims to be faster
|
||||
and more accurate than many existing Game Boy Advance emulators, as well as
|
||||
adding features that other emulators lack.
|
||||
.
|
||||
Game Boy Advance is a registered trademark of Nintendo of America Inc. mGBA is
|
||||
not affiliated with or endorsed by any of the companies mentioned.
|
|
@ -0,0 +1,472 @@
|
|||
Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
|
||||
Upstream-Name: mGBA
|
||||
Upstream-Contact: Jeffrey Pfau (aka endrift) <jeffrey@endrift.com>
|
||||
Source: https://github.com/mgba-emu/mgba
|
||||
Comment: This package was debianized by
|
||||
Sergio Benjamim (sergio-br2) <sergio_br2@yahoo.com.br> on Mon, 01 Jun 2015 18:40:00 -0300
|
||||
|
||||
|
||||
Files: *
|
||||
Copyright: 2013-2015 Jeffrey Pfau
|
||||
License: MPL-2.0
|
||||
|
||||
Files: src/third-party/blip_buf/*
|
||||
Copyright: 2003-2009 Shay Green
|
||||
License: LGPL-2.1+
|
||||
|
||||
Files: src/third-party/inih/*
|
||||
Copyright: 2009 Brush Technology. All rights reserved.
|
||||
License: BSD-3-clause-Brush-Technology
|
||||
|
||||
Files: src/third-party/lzma/*
|
||||
Copyright: 2008-2015 Igor Pavlov
|
||||
License: public-domain
|
||||
These files have been put in the public domain by their author
|
||||
|
||||
Files: src/platform/libretro/libretro.h
|
||||
Copyright: 2010-2015 The RetroArch Team
|
||||
License: Expat
|
||||
|
||||
Files: debian/*
|
||||
Copyright: 2015 Sergio Benjamim (sergio-br2) <sergio_br2@yahoo.com.br>
|
||||
License: MPL-2.0
|
||||
|
||||
|
||||
License: MPL-2.0
|
||||
Mozilla Public License Version 2.0
|
||||
==================================
|
||||
.
|
||||
1. Definitions
|
||||
--------------
|
||||
.
|
||||
1.1. "Contributor"
|
||||
means each individual or legal entity that creates, contributes to
|
||||
the creation of, or owns Covered Software.
|
||||
.
|
||||
1.2. "Contributor Version"
|
||||
means the combination of the Contributions of others (if any) used
|
||||
by a Contributor and that particular Contributor's Contribution.
|
||||
.
|
||||
1.3. "Contribution"
|
||||
means Covered Software of a particular Contributor.
|
||||
.
|
||||
1.4. "Covered Software"
|
||||
means Source Code Form to which the initial Contributor has attached
|
||||
the notice in Exhibit A, the Executable Form of such Source Code
|
||||
Form, and Modifications of such Source Code Form, in each case
|
||||
including portions thereof.
|
||||
.
|
||||
1.5. "Incompatible With Secondary Licenses"
|
||||
means
|
||||
.
|
||||
(a) that the initial Contributor has attached the notice described
|
||||
in Exhibit B to the Covered Software; or
|
||||
.
|
||||
(b) that the Covered Software was made available under the terms of
|
||||
version 1.1 or earlier of the License, but not also under the
|
||||
terms of a Secondary License.
|
||||
.
|
||||
1.6. "Executable Form"
|
||||
means any form of the work other than Source Code Form.
|
||||
.
|
||||
1.7. "Larger Work"
|
||||
means a work that combines Covered Software with other material, in
|
||||
a separate file or files, that is not Covered Software.
|
||||
.
|
||||
1.8. "License"
|
||||
means this document.
|
||||
.
|
||||
1.9. "Licensable"
|
||||
means having the right to grant, to the maximum extent possible,
|
||||
whether at the time of the initial grant or subsequently, any and
|
||||
all of the rights conveyed by this License.
|
||||
.
|
||||
1.10. "Modifications"
|
||||
means any of the following:
|
||||
.
|
||||
(a) any file in Source Code Form that results from an addition to,
|
||||
deletion from, or modification of the contents of Covered
|
||||
Software; or
|
||||
.
|
||||
(b) any new file in Source Code Form that contains any Covered
|
||||
Software.
|
||||
.
|
||||
1.11. "Patent Claims" of a Contributor
|
||||
means any patent claim(s), including without limitation, method,
|
||||
process, and apparatus claims, in any patent Licensable by such
|
||||
Contributor that would be infringed, but for the grant of the
|
||||
License, by the making, using, selling, offering for sale, having
|
||||
made, import, or transfer of either its Contributions or its
|
||||
Contributor Version.
|
||||
.
|
||||
1.12. "Secondary License"
|
||||
means either the GNU General Public License, Version 2.0, the GNU
|
||||
Lesser General Public License, Version 2.1, the GNU Affero General
|
||||
Public License, Version 3.0, or any later versions of those
|
||||
licenses.
|
||||
.
|
||||
1.13. "Source Code Form"
|
||||
means the form of the work preferred for making modifications.
|
||||
.
|
||||
1.14. "You" (or "Your")
|
||||
means an individual or a legal entity exercising rights under this
|
||||
License. For legal entities, "You" includes any entity that
|
||||
controls, is controlled by, or is under common control with You. For
|
||||
purposes of this definition, "control" means (a) the power, direct
|
||||
or indirect, to cause the direction or management of such entity,
|
||||
whether by contract or otherwise, or (b) ownership of more than
|
||||
fifty percent (50%) of the outstanding shares or beneficial
|
||||
ownership of such entity.
|
||||
.
|
||||
2. License Grants and Conditions
|
||||
--------------------------------
|
||||
.
|
||||
2.1. Grants
|
||||
.
|
||||
Each Contributor hereby grants You a world-wide, royalty-free,
|
||||
non-exclusive license:
|
||||
.
|
||||
(a) under intellectual property rights (other than patent or trademark)
|
||||
Licensable by such Contributor to use, reproduce, make available,
|
||||
modify, display, perform, distribute, and otherwise exploit its
|
||||
Contributions, either on an unmodified basis, with Modifications, or
|
||||
as part of a Larger Work; and
|
||||
.
|
||||
(b) under Patent Claims of such Contributor to make, use, sell, offer
|
||||
for sale, have made, import, and otherwise transfer either its
|
||||
Contributions or its Contributor Version.
|
||||
.
|
||||
2.2. Effective Date
|
||||
.
|
||||
The licenses granted in Section 2.1 with respect to any Contribution
|
||||
become effective for each Contribution on the date the Contributor first
|
||||
distributes such Contribution.
|
||||
.
|
||||
2.3. Limitations on Grant Scope
|
||||
.
|
||||
The licenses granted in this Section 2 are the only rights granted under
|
||||
this License. No additional rights or licenses will be implied from the
|
||||
distribution or licensing of Covered Software under this License.
|
||||
Notwithstanding Section 2.1(b) above, no patent license is granted by a
|
||||
Contributor:
|
||||
.
|
||||
(a) for any code that a Contributor has removed from Covered Software;
|
||||
or
|
||||
.
|
||||
(b) for infringements caused by: (i) Your and any other third party's
|
||||
modifications of Covered Software, or (ii) the combination of its
|
||||
Contributions with other software (except as part of its Contributor
|
||||
Version); or
|
||||
.
|
||||
(c) under Patent Claims infringed by Covered Software in the absence of
|
||||
its Contributions.
|
||||
.
|
||||
This License does not grant any rights in the trademarks, service marks,
|
||||
or logos of any Contributor (except as may be necessary to comply with
|
||||
the notice requirements in Section 3.4).
|
||||
.
|
||||
2.4. Subsequent Licenses
|
||||
.
|
||||
No Contributor makes additional grants as a result of Your choice to
|
||||
distribute the Covered Software under a subsequent version of this
|
||||
License (see Section 10.2) or under the terms of a Secondary License (if
|
||||
permitted under the terms of Section 3.3).
|
||||
.
|
||||
2.5. Representation
|
||||
.
|
||||
Each Contributor represents that the Contributor believes its
|
||||
Contributions are its original creation(s) or it has sufficient rights
|
||||
to grant the rights to its Contributions conveyed by this License.
|
||||
.
|
||||
2.6. Fair Use
|
||||
.
|
||||
This License is not intended to limit any rights You have under
|
||||
applicable copyright doctrines of fair use, fair dealing, or other
|
||||
equivalents.
|
||||
.
|
||||
2.7. Conditions
|
||||
.
|
||||
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
|
||||
in Section 2.1.
|
||||
.
|
||||
3. Responsibilities
|
||||
-------------------
|
||||
.
|
||||
3.1. Distribution of Source Form
|
||||
.
|
||||
All distribution of Covered Software in Source Code Form, including any
|
||||
Modifications that You create or to which You contribute, must be under
|
||||
the terms of this License. You must inform recipients that the Source
|
||||
Code Form of the Covered Software is governed by the terms of this
|
||||
License, and how they can obtain a copy of this License. You may not
|
||||
attempt to alter or restrict the recipients' rights in the Source Code
|
||||
Form.
|
||||
.
|
||||
3.2. Distribution of Executable Form
|
||||
.
|
||||
If You distribute Covered Software in Executable Form then:
|
||||
.
|
||||
(a) such Covered Software must also be made available in Source Code
|
||||
Form, as described in Section 3.1, and You must inform recipients of
|
||||
the Executable Form how they can obtain a copy of such Source Code
|
||||
Form by reasonable means in a timely manner, at a charge no more
|
||||
than the cost of distribution to the recipient; and
|
||||
.
|
||||
(b) You may distribute such Executable Form under the terms of this
|
||||
License, or sublicense it under different terms, provided that the
|
||||
license for the Executable Form does not attempt to limit or alter
|
||||
the recipients' rights in the Source Code Form under this License.
|
||||
.
|
||||
3.3. Distribution of a Larger Work
|
||||
.
|
||||
You may create and distribute a Larger Work under terms of Your choice,
|
||||
provided that You also comply with the requirements of this License for
|
||||
the Covered Software. If the Larger Work is a combination of Covered
|
||||
Software with a work governed by one or more Secondary Licenses, and the
|
||||
Covered Software is not Incompatible With Secondary Licenses, this
|
||||
License permits You to additionally distribute such Covered Software
|
||||
under the terms of such Secondary License(s), so that the recipient of
|
||||
the Larger Work may, at their option, further distribute the Covered
|
||||
Software under the terms of either this License or such Secondary
|
||||
License(s).
|
||||
.
|
||||
3.4. Notices
|
||||
.
|
||||
You may not remove or alter the substance of any license notices
|
||||
(including copyright notices, patent notices, disclaimers of warranty,
|
||||
or limitations of liability) contained within the Source Code Form of
|
||||
the Covered Software, except that You may alter any license notices to
|
||||
the extent required to remedy known factual inaccuracies.
|
||||
.
|
||||
3.5. Application of Additional Terms
|
||||
.
|
||||
You may choose to offer, and to charge a fee for, warranty, support,
|
||||
indemnity or liability obligations to one or more recipients of Covered
|
||||
Software. However, You may do so only on Your own behalf, and not on
|
||||
behalf of any Contributor. You must make it absolutely clear that any
|
||||
such warranty, support, indemnity, or liability obligation is offered by
|
||||
You alone, and You hereby agree to indemnify every Contributor for any
|
||||
liability incurred by such Contributor as a result of warranty, support,
|
||||
indemnity or liability terms You offer. You may include additional
|
||||
disclaimers of warranty and limitations of liability specific to any
|
||||
jurisdiction.
|
||||
.
|
||||
4. Inability to Comply Due to Statute or Regulation
|
||||
---------------------------------------------------
|
||||
.
|
||||
If it is impossible for You to comply with any of the terms of this
|
||||
License with respect to some or all of the Covered Software due to
|
||||
statute, judicial order, or regulation then You must: (a) comply with
|
||||
the terms of this License to the maximum extent possible; and (b)
|
||||
describe the limitations and the code they affect. Such description must
|
||||
be placed in a text file included with all distributions of the Covered
|
||||
Software under this License. Except to the extent prohibited by statute
|
||||
or regulation, such description must be sufficiently detailed for a
|
||||
recipient of ordinary skill to be able to understand it.
|
||||
.
|
||||
5. Termination
|
||||
--------------
|
||||
.
|
||||
5.1. The rights granted under this License will terminate automatically
|
||||
if You fail to comply with any of its terms. However, if You become
|
||||
compliant, then the rights granted under this License from a particular
|
||||
Contributor are reinstated (a) provisionally, unless and until such
|
||||
Contributor explicitly and finally terminates Your grants, and (b) on an
|
||||
ongoing basis, if such Contributor fails to notify You of the
|
||||
non-compliance by some reasonable means prior to 60 days after You have
|
||||
come back into compliance. Moreover, Your grants from a particular
|
||||
Contributor are reinstated on an ongoing basis if such Contributor
|
||||
notifies You of the non-compliance by some reasonable means, this is the
|
||||
first time You have received notice of non-compliance with this License
|
||||
from such Contributor, and You become compliant prior to 30 days after
|
||||
Your receipt of the notice.
|
||||
.
|
||||
5.2. If You initiate litigation against any entity by asserting a patent
|
||||
infringement claim (excluding declaratory judgment actions,
|
||||
counter-claims, and cross-claims) alleging that a Contributor Version
|
||||
directly or indirectly infringes any patent, then the rights granted to
|
||||
You by any and all Contributors for the Covered Software under Section
|
||||
2.1 of this License shall terminate.
|
||||
.
|
||||
5.3. In the event of termination under Sections 5.1 or 5.2 above, all
|
||||
end user license agreements (excluding distributors and resellers) which
|
||||
have been validly granted by You or Your distributors under this License
|
||||
prior to termination shall survive termination.
|
||||
.
|
||||
************************************************************************
|
||||
* *
|
||||
* 6. Disclaimer of Warranty *
|
||||
* ------------------------- *
|
||||
* *
|
||||
* Covered Software is provided under this License on an "as is" *
|
||||
* basis, without warranty of any kind, either expressed, implied, or *
|
||||
* statutory, including, without limitation, warranties that the *
|
||||
* Covered Software is free of defects, merchantable, fit for a *
|
||||
* particular purpose or non-infringing. The entire risk as to the *
|
||||
* quality and performance of the Covered Software is with You. *
|
||||
* Should any Covered Software prove defective in any respect, You *
|
||||
* (not any Contributor) assume the cost of any necessary servicing, *
|
||||
* repair, or correction. This disclaimer of warranty constitutes an *
|
||||
* essential part of this License. No use of any Covered Software is *
|
||||
* authorized under this License except under this disclaimer. *
|
||||
* *
|
||||
************************************************************************
|
||||
.
|
||||
************************************************************************
|
||||
* *
|
||||
* 7. Limitation of Liability *
|
||||
* -------------------------- *
|
||||
* *
|
||||
* Under no circumstances and under no legal theory, whether tort *
|
||||
* (including negligence), contract, or otherwise, shall any *
|
||||
* Contributor, or anyone who distributes Covered Software as *
|
||||
* permitted above, be liable to You for any direct, indirect, *
|
||||
* special, incidental, or consequential damages of any character *
|
||||
* including, without limitation, damages for lost profits, loss of *
|
||||
* goodwill, work stoppage, computer failure or malfunction, or any *
|
||||
* and all other commercial damages or losses, even if such party *
|
||||
* shall have been informed of the possibility of such damages. This *
|
||||
* limitation of liability shall not apply to liability for death or *
|
||||
* personal injury resulting from such party's negligence to the *
|
||||
* extent applicable law prohibits such limitation. Some *
|
||||
* jurisdictions do not allow the exclusion or limitation of *
|
||||
* incidental or consequential damages, so this exclusion and *
|
||||
* limitation may not apply to You. *
|
||||
* *
|
||||
************************************************************************
|
||||
.
|
||||
8. Litigation
|
||||
-------------
|
||||
.
|
||||
Any litigation relating to this License may be brought only in the
|
||||
courts of a jurisdiction where the defendant maintains its principal
|
||||
place of business and such litigation shall be governed by laws of that
|
||||
jurisdiction, without reference to its conflict-of-law provisions.
|
||||
Nothing in this Section shall prevent a party's ability to bring
|
||||
cross-claims or counter-claims.
|
||||
.
|
||||
9. Miscellaneous
|
||||
----------------
|
||||
.
|
||||
This License represents the complete agreement concerning the subject
|
||||
matter hereof. If any provision of this License is held to be
|
||||
unenforceable, such provision shall be reformed only to the extent
|
||||
necessary to make it enforceable. Any law or regulation which provides
|
||||
that the language of a contract shall be construed against the drafter
|
||||
shall not be used to construe this License against a Contributor.
|
||||
.
|
||||
10. Versions of the License
|
||||
---------------------------
|
||||
.
|
||||
10.1. New Versions
|
||||
.
|
||||
Mozilla Foundation is the license steward. Except as provided in Section
|
||||
10.3, no one other than the license steward has the right to modify or
|
||||
publish new versions of this License. Each version will be given a
|
||||
distinguishing version number.
|
||||
.
|
||||
10.2. Effect of New Versions
|
||||
.
|
||||
You may distribute the Covered Software under the terms of the version
|
||||
of the License under which You originally received the Covered Software,
|
||||
or under the terms of any subsequent version published by the license
|
||||
steward.
|
||||
.
|
||||
10.3. Modified Versions
|
||||
.
|
||||
If you create software not governed by this License, and you want to
|
||||
create a new license for such software, you may create and use a
|
||||
modified version of this License if you rename the license and remove
|
||||
any references to the name of the license steward (except to note that
|
||||
such modified license differs from this License).
|
||||
.
|
||||
10.4. Distributing Source Code Form that is Incompatible With Secondary
|
||||
Licenses
|
||||
.
|
||||
If You choose to distribute Source Code Form that is Incompatible With
|
||||
Secondary Licenses under the terms of this version of the License, the
|
||||
notice described in Exhibit B of this License must be attached.
|
||||
.
|
||||
Exhibit A - Source Code Form License Notice
|
||||
-------------------------------------------
|
||||
.
|
||||
This Source Code Form is subject to the terms of the Mozilla Public
|
||||
License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
.
|
||||
If it is not possible or desirable to put the notice in a particular
|
||||
file, then You may include the notice in a location (such as a LICENSE
|
||||
file in a relevant directory) where a recipient would be likely to look
|
||||
for such a notice.
|
||||
.
|
||||
You may add additional accurate notices of copyright ownership.
|
||||
.
|
||||
Exhibit B - "Incompatible With Secondary Licenses" Notice
|
||||
---------------------------------------------------------
|
||||
.
|
||||
This Source Code Form is "Incompatible With Secondary Licenses", as
|
||||
defined by the Mozilla Public License, v. 2.0.
|
||||
|
||||
|
||||
License: BSD-3-clause-Brush-Technology
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of Brush Technology nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
.
|
||||
THIS SOFTWARE IS PROVIDED BY BRUSH TECHNOLOGY ''AS IS'' AND ANY
|
||||
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL BRUSH TECHNOLOGY BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
|
||||
License: Expat
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
.
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
|
||||
License: LGPL-2.1+
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
.
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
.
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA
|
||||
.
|
||||
On Debian systems, the full text of the GNU Lesser General Public
|
||||
License version 2.1 can be found in the file
|
||||
`/usr/share/common-licenses/LGPL-2.1'.
|
|
@ -0,0 +1,2 @@
|
|||
README.md
|
||||
CHANGES
|
|
@ -0,0 +1 @@
|
|||
obj/libmgba.so* usr/lib/@DEB_HOST_MULTIARCH@/
|
|
@ -0,0 +1 @@
|
|||
obj/mgba_libretro.so usr/lib/@DEB_HOST_MULTIARCH@/libretro
|
|
@ -0,0 +1,3 @@
|
|||
usr/bin/mgba-qt
|
||||
res/mgba-qt.desktop usr/share/applications
|
||||
usr/share/icons
|
|
@ -0,0 +1 @@
|
|||
doc/mgba-qt.6
|
|
@ -0,0 +1 @@
|
|||
usr/bin/mgba
|
|
@ -0,0 +1 @@
|
|||
doc/mgba.6
|
|
@ -0,0 +1,27 @@
|
|||
#!/usr/bin/make -f
|
||||
|
||||
# Copyright (C) 2015 Sergio Benjamim
|
||||
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
DEB_HOST_MULTIARCH ?= $(shell dpkg-architecture -qDEB_HOST_MULTIARCH)
|
||||
ARCH=$(shell dpkg-architecture -qDEB_HOST_ARCH)
|
||||
|
||||
ifeq ($(ARCH),armhf)
|
||||
ARM=-DBUILD_GL=OFF -DBUILD_GLES2=ON
|
||||
endif
|
||||
|
||||
%:
|
||||
dh $@ --buildsystem=cmake --builddirectory=obj --parallel
|
||||
|
||||
override_dh_auto_configure:
|
||||
dh_auto_configure -- -DCMAKE_INSTALL_PREFIX:PATH=/usr -DCMAKE_SKIP_RPATH=ON -DBUILD_LIBRETRO=ON $(ARM)
|
||||
sed 's/@DEB_HOST_MULTIARCH@/$(DEB_HOST_MULTIARCH)/g' \
|
||||
debian/libretro-mgba.install.in > debian/libretro-mgba.install
|
||||
sed 's/@DEB_HOST_MULTIARCH@/$(DEB_HOST_MULTIARCH)/g' \
|
||||
debian/libmgba.install.in > debian/libmgba.install
|
||||
|
||||
override_dh_installchangelogs:
|
||||
dh_installchangelogs -k CHANGES
|
|
@ -0,0 +1 @@
|
|||
3.0 (quilt)
|
|
@ -0,0 +1,3 @@
|
|||
version=3
|
||||
opts=filenamemangle=s/.+\/v?(\d\S*)\.tar\.gz/mgba-$1\.tar\.gz/ \
|
||||
https://github.com/mgba-emu/mgba/tags .*/v?(\d\S*)\.tar\.gz
|
|
@ -56,8 +56,8 @@ while [ $# -gt 0 ]; do
|
|||
sed -i~ "s/,$//g" deb-temp/DEBIAN/control
|
||||
sed -i~ "/^[^:]*: $/d" deb-temp/DEBIAN/control
|
||||
rm deb-temp/DEBIAN/control~
|
||||
chown -R 0:0 deb-temp
|
||||
chmod 600 deb-temp/DEBIAN/md5sums
|
||||
chmod 644 deb-temp/DEBIAN/md5sums
|
||||
chown -R root:root deb-temp
|
||||
dpkg-deb -b deb-temp $DEB
|
||||
rm -rf deb-temp
|
||||
shift
|
||||
|
|
Loading…
Reference in New Issue