[EXPERIMENTAL] Add Rust support
This commit is contained in:
parent
68adb14b07
commit
f4dcd55f98
|
@ -11,6 +11,9 @@ jobs:
|
|||
runs-on: macos-latest
|
||||
|
||||
steps:
|
||||
- name: Install Rust toolchain
|
||||
uses: actions-rust-lang/setup-rust-toolchain@v1
|
||||
|
||||
- name: Checkout the code
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
|
|
|
@ -15,6 +15,9 @@ jobs:
|
|||
shell: msys2 {0}
|
||||
|
||||
steps:
|
||||
- name: Install Rust toolchain
|
||||
uses: actions-rust-lang/setup-rust-toolchain@v1
|
||||
|
||||
- name: Checkout the code
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
|
|
|
@ -10,6 +10,9 @@ jobs:
|
|||
cmake_options: ['', '-DENABLE_LINK=OFF', '-DENABLE_SDL=ON']
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Install Rust toolchain
|
||||
uses: actions-rust-lang/setup-rust-toolchain@v1
|
||||
|
||||
- name: Checkout the code
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
|
|
|
@ -12,6 +12,9 @@ jobs:
|
|||
cmake_options: ['', '-DENABLE_LINK=OFF', '-DENABLE_SDL=ON']
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- name: Install Rust toolchain
|
||||
uses: actions-rust-lang/setup-rust-toolchain@v1
|
||||
|
||||
- name: Checkout the code
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
|
|
|
@ -17,3 +17,7 @@ compile_commands.json
|
|||
|
||||
# mac finder crap
|
||||
*.DS_Store
|
||||
|
||||
# Rust build files
|
||||
src/core/rust/target/
|
||||
src/core/rust/Cargo.lock
|
||||
|
|
|
@ -74,6 +74,15 @@ set(CMAKE_CXX_STANDARD_REQUIRED True)
|
|||
set(CMAKE_C_STANDARD 11)
|
||||
set(CMAKE_C_STANDARD_REQUIRED True)
|
||||
|
||||
# Rust library dependency
|
||||
include(FetchContent)
|
||||
FetchContent_Declare(
|
||||
Corrosion
|
||||
GIT_REPOSITORY https://github.com/corrosion-rs/corrosion.git
|
||||
GIT_TAG v0.4
|
||||
)
|
||||
FetchContent_MakeAvailable(Corrosion)
|
||||
|
||||
project(VBA-M C CXX)
|
||||
|
||||
find_package(PkgConfig)
|
||||
|
@ -263,15 +272,6 @@ add_compile_definitions(PKGDATADIR="${CMAKE_INSTALL_FULL_DATADIR}/vbam")
|
|||
add_compile_definitions(__STDC_FORMAT_MACROS)
|
||||
|
||||
if(ENABLE_LINK)
|
||||
# IPC linking code needs sem_timedwait which can be either in librt or pthreads
|
||||
if(NOT WIN32)
|
||||
find_library(RT_LIB rt)
|
||||
if(RT_LIB)
|
||||
set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} ${RT_LIB})
|
||||
set(VBAMCORE_LIBS ${VBAMCORE_LIBS} ${RT_LIB})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
include(CheckFunctionExists)
|
||||
check_function_exists(sem_timedwait SEM_TIMEDWAIT)
|
||||
if(SEM_TIMEDWAIT)
|
||||
|
|
|
@ -218,7 +218,6 @@ Here is the complete list:
|
|||
| ENABLE_GBA_LOGGING | Enable extended GBA logging | ON |
|
||||
| ENABLE_DIRECT3D | Direct3D rendering for wxWidgets (Windows, **NOT IMPLEMENTED!!!**) | ON |
|
||||
| ENABLE_XAUDIO2 | Enable xaudio2 sound output for wxWidgets (Windows only) | ON |
|
||||
| ENABLE_OPENAL | Enable OpenAL for the wxWidgets port | AUTO |
|
||||
| ENABLE_ASAN | Enable libasan sanitizers (by default address, only in debug mode) | OFF |
|
||||
| UPSTREAM_RELEASE | Do some release tasks, like codesigning, making zip and gpg sigs. | OFF |
|
||||
| BUILD_TESTING | Build the tests and enable ctest support. | ON |
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
# Compiler stuff
|
||||
include(ProcessorCount)
|
||||
ProcessorCount(num_cpus)
|
||||
|
||||
if(CMAKE_C_COMPILER_ID STREQUAL Clang AND CMAKE_CXX_COMPILER_ID STREQUAL Clang AND NOT MSVC)
|
||||
# TODO: This should also be done for clang-cl.
|
||||
include(LLVMToolchain)
|
||||
endif()
|
||||
|
||||
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID STREQUAL Clang AND NOT MSVC)
|
||||
include(Toolchain-gcc-clang)
|
||||
elseif(MSVC)
|
||||
include(Toolchain-msvc)
|
||||
elseif(MINGW)
|
||||
include(Toolchain-mingw)
|
||||
endif()
|
||||
|
||||
# Assembler flags
|
||||
if(ASM_ENABLED)
|
||||
string(REGEX REPLACE "<FLAGS>" "-I${CMAKE_SOURCE_DIR}/src/filters/hq/asm/ -O1 -w-orphan-labels" CMAKE_ASM_NASM_COMPILE_OBJECT ${CMAKE_ASM_NASM_COMPILE_OBJECT})
|
||||
endif()
|
|
@ -0,0 +1,44 @@
|
|||
#Do not use this file directly. Always use the top level CMakeLists.txt file
|
||||
#File extractors so the user doesn't have to extract the rom before playing it
|
||||
|
||||
# Source files definition
|
||||
SET(SRC_FEX
|
||||
7z_C/7zAlloc.c
|
||||
7z_C/7zBuf.c
|
||||
7z_C/7zCrc.c
|
||||
7z_C/7zCrcOpt.c
|
||||
7z_C/7zDec.c
|
||||
7z_C/7zIn.c
|
||||
7z_C/7zStream.c
|
||||
7z_C/Bcj2.c
|
||||
7z_C/Bra86.c
|
||||
7z_C/Bra.c
|
||||
7z_C/CpuArch.c
|
||||
7z_C/Lzma2Dec.c
|
||||
7z_C/LzmaDec.c
|
||||
7z_C/Ppmd7.c
|
||||
7z_C/Ppmd7Dec.c
|
||||
fex/Binary_Extractor.cpp
|
||||
fex/blargg_common.cpp
|
||||
fex/blargg_errors.cpp
|
||||
fex/Data_Reader.cpp
|
||||
fex/fex.cpp
|
||||
fex/File_Extractor.cpp
|
||||
fex/Gzip_Extractor.cpp
|
||||
fex/Gzip_Reader.cpp
|
||||
fex/Rar_Extractor.cpp
|
||||
fex/Zip7_Extractor.cpp
|
||||
fex/Zip_Extractor.cpp
|
||||
fex/Zlib_Inflater.cpp
|
||||
)
|
||||
|
||||
ADD_LIBRARY(
|
||||
fex
|
||||
STATIC
|
||||
${SRC_FEX}
|
||||
)
|
||||
|
||||
add_dependencies(fex generate)
|
||||
|
||||
target_include_directories(fex PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}")
|
||||
target_link_libraries(fex PUBLIC ZLIB::ZLIB)
|
54
installdeps
54
installdeps
|
@ -1,7 +1,6 @@
|
|||
#!/bin/sh
|
||||
|
||||
CMAKE=cmake
|
||||
ENABLE_OPENAL=1
|
||||
ENABLE_FFMPEG=1
|
||||
|
||||
main() {
|
||||
|
@ -25,10 +24,6 @@ check_command_line_args() {
|
|||
usage
|
||||
quit 0
|
||||
;;
|
||||
--no-openal)
|
||||
ENABLE_OPENAL=
|
||||
shift
|
||||
;;
|
||||
--no-ffmpeg)
|
||||
ENABLE_FFMPEG=
|
||||
shift
|
||||
|
@ -355,9 +350,8 @@ debian_installdeps() {
|
|||
;;
|
||||
esac
|
||||
|
||||
pkgs="build-essential g++ nasm cmake ccache gettext zlib1g-dev libgl1-mesa-dev libgettextpo-dev libsdl2-dev $sdl_lib libglu1-mesa-dev libglu1-mesa libgles2-mesa-dev libsfml-dev $sfml_libs $glew_lib $wx_libs libgtk2.0-dev libgtk-3-dev ccache zip ninja-build"
|
||||
pkgs="build-essential g++ nasm cmake ccache gettext zlib1g-dev libgl1-mesa-dev libgettextpo-dev libsdl2-dev $sdl_lib libglu1-mesa-dev libglu1-mesa libgles2-mesa-dev libsfml-dev $sfml_libs $glew_lib $wx_libs libgtk2.0-dev libgtk-3-dev ccache zip ninja-build libopenal-dev"
|
||||
|
||||
[ -n "$ENABLE_OPENAL" ] && pkgs="$pkgs libopenal-dev"
|
||||
[ -n "$ENABLE_FFMPEG" ] && pkgs="$pkgs libavcodec-dev libavformat-dev libswscale-dev libavutil-dev $libswresample_dev"
|
||||
|
||||
check sudo apt-get -qy install $pkgs
|
||||
|
@ -407,8 +401,7 @@ debian_installdeps() {
|
|||
fi
|
||||
fi
|
||||
|
||||
deps="gcc zlib ffmpeg gettext sdl2 sfml openal wxwidgets"
|
||||
[ -n "$ENABLE_OPENAL" ] && deps="$deps openal"
|
||||
deps="gcc zlib ffmpeg gettext sdl2 sfml openal wxwidgets openal"
|
||||
[ -n "$ENABLE_FFMPEG" ] && deps="$deps ffmpeg"
|
||||
|
||||
set --
|
||||
|
@ -510,9 +503,6 @@ fedora_installdeps() {
|
|||
*ffmpeg*)
|
||||
[ -z "$ENABLE_FFMPEG" ] && continue
|
||||
;;
|
||||
*openal*)
|
||||
[ -z "$ENABLE_OPENAL" ] && continue
|
||||
;;
|
||||
esac
|
||||
|
||||
pkg_arch=
|
||||
|
@ -601,15 +591,9 @@ fedora_installdeps() {
|
|||
;;
|
||||
esac
|
||||
# install static deps
|
||||
for pkg in zlib gettext SDL2 wxWidgets3; do
|
||||
for pkg in zlib gettext SDL2 wxWidgets3 openal-soft; do
|
||||
set -- "$@" "${target}-${pkg}-static"
|
||||
done
|
||||
# install deps that are not available as static
|
||||
if [ -n "$ENABLE_OPENAL" ]; then
|
||||
for pkg in openal-soft; do
|
||||
set -- "$@" "${target}-${pkg}"
|
||||
done
|
||||
fi
|
||||
|
||||
# get the necessary win32 headers
|
||||
git submodule update --init --remote --recursive
|
||||
|
@ -707,9 +691,6 @@ rhel_installdeps() {
|
|||
*ffmpeg*)
|
||||
[ -z "$ENABLE_FFMPEG" ] && continue
|
||||
;;
|
||||
*openal*)
|
||||
[ -z "$ENABLE_OPENAL" ] && continue
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ -n "$amd64" ]; then
|
||||
|
@ -790,15 +771,9 @@ rhel_installdeps() {
|
|||
;;
|
||||
esac
|
||||
# install static deps
|
||||
for pkg in zlib gettext SDL2 wxWidgets; do
|
||||
for pkg in zlib gettext SDL2 wxWidgets openal-soft; do
|
||||
set -- "$@" "${target}-${pkg}-static"
|
||||
done
|
||||
# install deps that are not available as static
|
||||
if [ -n "$ENABLE_OPENAL" ]; then
|
||||
for pkg in openal-soft; do
|
||||
set -- "$@" "${target}-${pkg}"
|
||||
done
|
||||
fi
|
||||
|
||||
# get the necessary win32 headers
|
||||
git submodule update --init --remote --recursive
|
||||
|
@ -824,11 +799,9 @@ suse_installdeps() {
|
|||
|
||||
tools="make cmake ccache nasm gettext-tools pkg-config ccache zip sfml2-devel ninja"
|
||||
|
||||
libs="gcc gcc-c++ libSDL2-devel wxWidgets-3_0-devel" # ffmpeg-devel
|
||||
libs="gcc gcc-c++ libSDL2-devel wxWidgets-3_0-devel openal-soft-devel" # ffmpeg-devel
|
||||
|
||||
[ -n "$ENABLE_OPENAL" ] && libs="$libs openal-soft-devel"
|
||||
# ffmpeg requires packman repos
|
||||
|
||||
if [ "$target" = m32 ]; then
|
||||
libs=$(echo "$libs" | sed -E 's/([^ ]) ([^ ])/\1-32bit \2/g; s/$/-32bit/;')
|
||||
fi
|
||||
|
@ -894,9 +867,8 @@ archlinux_installdeps() {
|
|||
|
||||
$pacman -Q gtk3-classic >/dev/null 2>&1 && gtk=gtk3-classic
|
||||
|
||||
libs="zlib mesa gettext sdl2 wxgtk3 $gtk sfml"
|
||||
libs="zlib mesa gettext sdl2 wxgtk3 $gtk sfml openal"
|
||||
|
||||
[ -n "$ENABLE_OPENAL" ] && libs="$libs openal"
|
||||
[ -n "$ENABLE_FFMPEG" ] && libs="$libs ffmpeg"
|
||||
|
||||
if [ -z "$target" -o "$target" = m32 ]; then
|
||||
|
@ -991,9 +963,7 @@ EOF
|
|||
fi
|
||||
done
|
||||
|
||||
deps="zlib gettext pkg-config sdl2 wxmsw"
|
||||
|
||||
[ -n "$ENABLE_OPENAL" ] && deps="$deps openal"
|
||||
deps="zlib gettext pkg-config sdl2 wxmsw openal"
|
||||
|
||||
# and the actual deps
|
||||
for p in $deps; do
|
||||
|
@ -1024,9 +994,7 @@ solus_installdeps() {
|
|||
check sudo eopkg -y install -c system.devel
|
||||
check sudo eopkg -y install git ccache ninja
|
||||
|
||||
set -- sdl2-devel wxwidgets-devel libgtk-2-devel libgtk-3-devel libglu-devel
|
||||
|
||||
[ -n "$ENABLE_OPENAL" ] && set -- "$@" openal-soft-devel
|
||||
set -- sdl2-devel wxwidgets-devel libgtk-2-devel libgtk-3-devel libglu-devel openal-soft-devel
|
||||
|
||||
if [ -n "$amd64" -a "$target" = m32 ]; then
|
||||
info_msg 'Calculating dependencies, this will take a while..'
|
||||
|
@ -1102,14 +1070,13 @@ gentoo_installdeps() {
|
|||
sys-devel/binutils \
|
||||
media-libs/libsdl2 \
|
||||
media-libs/libsfml \
|
||||
media-libs/openal \
|
||||
x11-libs/wxGTK:$wx_slot \
|
||||
sys-libs/zlib \
|
||||
dev-util/pkgconf \
|
||||
dev-lang/nasm \
|
||||
dev-build/ninja"
|
||||
|
||||
[ -n "$ENABLE_OPENAL" ] && ebuilds="$ebuilds media-libs/openal"
|
||||
|
||||
[ -n "$ENABLE_FFMPEG" ] && ebuilds="$ebuilds media-video/ffmpeg"
|
||||
|
||||
check sudo emerge -vna $ebuilds
|
||||
|
@ -1152,9 +1119,8 @@ windows_installdeps() {
|
|||
;;
|
||||
esac
|
||||
|
||||
pkgs="$pkgs SDL2 sfml wxWidgets3.2 zlib binutils cmake crt-git extra-cmake-modules headers-git make pkgconf tools-git windows-default-manifest libmangle-git ninja gdb ccache"
|
||||
pkgs="$pkgs SDL2 sfml wxWidgets3.2 zlib binutils cmake crt-git extra-cmake-modules headers-git make pkgconf tools-git windows-default-manifest libmangle-git ninja gdb ccache openal"
|
||||
|
||||
[ -n "$ENABLE_OPENAL" ] && pkgs="$pkgs openal"
|
||||
[ -n "$ENABLE_FFMPEG" ] && pkgs="$pkgs ffmpeg"
|
||||
|
||||
set --
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
[toolchain]
|
||||
channel = "stable"
|
||||
profile = "minimal"
|
|
@ -51,7 +51,6 @@ parts:
|
|||
- libopenal-dev
|
||||
- libwxgtk3.0-gtk3-dev
|
||||
cmake-parameters:
|
||||
- -DENABLE_OPENAL=ON
|
||||
- -DENABLE_SDL=OFF
|
||||
- -DCMAKE_INSTALL_PREFIX=/usr
|
||||
|
||||
|
|
|
@ -2,6 +2,9 @@ add_subdirectory(apu)
|
|||
add_subdirectory(base)
|
||||
add_subdirectory(fex)
|
||||
|
||||
# Set up "vbam_rust" library.
|
||||
corrosion_import_crate(MANIFEST_PATH ${CMAKE_CURRENT_LIST_DIR}/rust/Cargo.toml NO_STD)
|
||||
|
||||
# The vbam-core target contains both the Game Boy and Game Boy Advance
|
||||
# emulators. These should be broken down into 2 separate targets. The issue lies
|
||||
# with the Link and Sound emulation, which are tangled together between the two
|
||||
|
@ -94,7 +97,7 @@ target_include_directories(vbam-core
|
|||
|
||||
target_link_libraries(vbam-core
|
||||
PRIVATE vbam-core-apu vbam-fex
|
||||
PUBLIC vbam-core-base ${ZLIB_LIBRARY}
|
||||
PUBLIC vbam-core-base ${ZLIB_LIBRARY} vbam_rust
|
||||
)
|
||||
|
||||
if(ENABLE_DEBUGGER)
|
||||
|
|
|
@ -6,8 +6,11 @@
|
|||
#include "core/base/file_util.h"
|
||||
#include "core/base/message.h"
|
||||
#include "core/gba/gba.h"
|
||||
#include "core/gba/gbaInline.h"
|
||||
#include "core/gba/gbaGlobals.h"
|
||||
#include "core/gba/gbaInline.h"
|
||||
#include "core/rust/bindings.hpp"
|
||||
|
||||
using namespace core;
|
||||
|
||||
/**
|
||||
* Gameshark code types: (based on AR v1.0)
|
||||
|
@ -672,7 +675,7 @@ int cheatsCheckKeys(uint32_t keys, uint32_t extended)
|
|||
case GSA_16_BIT_ROM_PATCH:
|
||||
if ((cheatsList[i].status & 1) == 0) {
|
||||
if (CPUReadHalfWord(cheatsList[i].address) != cheatsList[i].value) {
|
||||
cheatsList[i].oldValue = CPUReadHalfWord(cheatsList[i].address);
|
||||
cheatsList[i].old_value = CPUReadHalfWord(cheatsList[i].address);
|
||||
cheatsList[i].status |= 1;
|
||||
CHEAT_PATCH_ROM_16BIT(cheatsList[i].address, cheatsList[i].value);
|
||||
}
|
||||
|
@ -1280,6 +1283,33 @@ int cheatsCheckKeys(uint32_t keys, uint32_t extended)
|
|||
return ticks;
|
||||
}
|
||||
|
||||
void cheatsAdd(CheatsData data) {
|
||||
if (cheatsNumber == MAX_CHEATS) {
|
||||
return;
|
||||
}
|
||||
|
||||
int x = cheatsNumber;
|
||||
cheatsList[x] = std::move(data);
|
||||
switch (cheatsList[x].size) {
|
||||
case INT_8_BIT_WRITE:
|
||||
cheatsList[x].old_value = CPUReadByte(cheatsList[x].address);
|
||||
break;
|
||||
case INT_16_BIT_WRITE:
|
||||
cheatsList[x].old_value = CPUReadHalfWord(cheatsList[x].address);
|
||||
break;
|
||||
case INT_32_BIT_WRITE:
|
||||
cheatsList[x].old_value = CPUReadMemory(cheatsList[x].address);
|
||||
break;
|
||||
case CHEATS_16_BIT_WRITE:
|
||||
cheatsList[x].old_value = CPUReadHalfWord(cheatsList[x].address);
|
||||
break;
|
||||
case CHEATS_32_BIT_WRITE:
|
||||
cheatsList[x].old_value = CPUReadMemory(cheatsList[x].address);
|
||||
break;
|
||||
}
|
||||
cheatsNumber++;
|
||||
}
|
||||
|
||||
void cheatsAdd(const char* codeStr,
|
||||
const char* desc,
|
||||
uint32_t rawaddress,
|
||||
|
@ -1304,19 +1334,19 @@ void cheatsAdd(const char* codeStr,
|
|||
// is taken care when it actually patches the ROM
|
||||
switch (cheatsList[x].size) {
|
||||
case INT_8_BIT_WRITE:
|
||||
cheatsList[x].oldValue = CPUReadByte(address);
|
||||
cheatsList[x].old_value = CPUReadByte(address);
|
||||
break;
|
||||
case INT_16_BIT_WRITE:
|
||||
cheatsList[x].oldValue = CPUReadHalfWord(address);
|
||||
cheatsList[x].old_value = CPUReadHalfWord(address);
|
||||
break;
|
||||
case INT_32_BIT_WRITE:
|
||||
cheatsList[x].oldValue = CPUReadMemory(address);
|
||||
cheatsList[x].old_value = CPUReadMemory(address);
|
||||
break;
|
||||
case CHEATS_16_BIT_WRITE:
|
||||
cheatsList[x].oldValue = CPUReadHalfWord(address);
|
||||
cheatsList[x].old_value = CPUReadHalfWord(address);
|
||||
break;
|
||||
case CHEATS_32_BIT_WRITE:
|
||||
cheatsList[x].oldValue = CPUReadMemory(address);
|
||||
cheatsList[x].old_value = CPUReadMemory(address);
|
||||
break;
|
||||
}
|
||||
cheatsNumber++;
|
||||
|
@ -1331,33 +1361,33 @@ void cheatsDelete(int number, bool restore)
|
|||
if (restore) {
|
||||
switch (cheatsList[x].size) {
|
||||
case INT_8_BIT_WRITE:
|
||||
CPUWriteByte(cheatsList[x].address, (uint8_t)cheatsList[x].oldValue);
|
||||
CPUWriteByte(cheatsList[x].address, (uint8_t)cheatsList[x].old_value);
|
||||
break;
|
||||
case INT_16_BIT_WRITE:
|
||||
CPUWriteHalfWord(cheatsList[x].address, (uint16_t)cheatsList[x].oldValue);
|
||||
CPUWriteHalfWord(cheatsList[x].address, (uint16_t)cheatsList[x].old_value);
|
||||
break;
|
||||
case INT_32_BIT_WRITE:
|
||||
CPUWriteMemory(cheatsList[x].address, cheatsList[x].oldValue);
|
||||
CPUWriteMemory(cheatsList[x].address, cheatsList[x].old_value);
|
||||
break;
|
||||
case CHEATS_16_BIT_WRITE:
|
||||
if ((cheatsList[x].address >> 24) >= 0x08) {
|
||||
CHEAT_PATCH_ROM_16BIT(cheatsList[x].address, cheatsList[x].oldValue);
|
||||
CHEAT_PATCH_ROM_16BIT(cheatsList[x].address, cheatsList[x].old_value);
|
||||
} else {
|
||||
CPUWriteHalfWord(cheatsList[x].address, cheatsList[x].oldValue);
|
||||
CPUWriteHalfWord(cheatsList[x].address, cheatsList[x].old_value);
|
||||
}
|
||||
break;
|
||||
case CHEATS_32_BIT_WRITE:
|
||||
if ((cheatsList[x].address >> 24) >= 0x08) {
|
||||
CHEAT_PATCH_ROM_32BIT(cheatsList[x].address, cheatsList[x].oldValue);
|
||||
CHEAT_PATCH_ROM_32BIT(cheatsList[x].address, cheatsList[x].old_value);
|
||||
} else {
|
||||
CPUWriteMemory(cheatsList[x].address, cheatsList[x].oldValue);
|
||||
CPUWriteMemory(cheatsList[x].address, cheatsList[x].old_value);
|
||||
}
|
||||
/* fallthrough */
|
||||
case GSA_16_BIT_ROM_PATCH:
|
||||
if (cheatsList[x].status & 1) {
|
||||
cheatsList[x].status &= ~1;
|
||||
CHEAT_PATCH_ROM_16BIT(cheatsList[x].address,
|
||||
cheatsList[x].oldValue);
|
||||
cheatsList[x].old_value);
|
||||
}
|
||||
break;
|
||||
case GSA_16_BIT_ROM_PATCH2C:
|
||||
|
@ -1403,7 +1433,7 @@ void cheatsDisable(int i)
|
|||
if (cheatsList[i].status & 1) {
|
||||
cheatsList[i].status &= ~1;
|
||||
CHEAT_PATCH_ROM_16BIT(cheatsList[i].address,
|
||||
cheatsList[i].oldValue);
|
||||
cheatsList[i].old_value);
|
||||
}
|
||||
break;
|
||||
case GSA_16_BIT_ROM_PATCH2C:
|
||||
|
@ -1424,72 +1454,15 @@ void cheatsDisable(int i)
|
|||
|
||||
bool cheatsVerifyCheatCode(const char* code, const char* desc)
|
||||
{
|
||||
size_t len = strlen(code);
|
||||
if (len != 11 && len != 13 && len != 17) {
|
||||
systemMessage(MSG_INVALID_CHEAT_CODE, N_("Invalid cheat code '%s': wrong length"), code);
|
||||
auto converted = core::decode_code(core::GbaCheatsType::Generic, code, desc);
|
||||
if (converted.tag ==
|
||||
core::Result_CheatsData__CheatsDecodeError_Tag::Err_CheatsData__CheatsDecodeError) {
|
||||
systemMessage(MSG_INVALID_CHEAT_CODE, N_("Invalid cheat code '%s': %s"), code,
|
||||
converted.err);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (code[8] != ':') {
|
||||
systemMessage(MSG_INVALID_CHEAT_CODE, N_("Invalid cheat code '%s': no colon"), code);
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t i;
|
||||
for (i = 0; i < 8; i++) {
|
||||
if (!CHEAT_IS_HEX(code[i])) {
|
||||
// wrong cheat
|
||||
systemMessage(MSG_INVALID_CHEAT_CODE,
|
||||
N_("Invalid cheat code '%s': first part is not hex"), code);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
for (i = 9; i < len; i++) {
|
||||
if (!CHEAT_IS_HEX(code[i])) {
|
||||
// wrong cheat
|
||||
systemMessage(MSG_INVALID_CHEAT_CODE,
|
||||
N_("Invalid cheat code '%s' second part is not hex"), code);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t address = 0;
|
||||
uint32_t value = 0;
|
||||
|
||||
char buffer[10];
|
||||
strncpy(buffer, code, 8);
|
||||
buffer[8] = 0;
|
||||
sscanf(buffer, "%x", &address);
|
||||
|
||||
switch (address >> 24) {
|
||||
case 0x02:
|
||||
case 0x03:
|
||||
case 0x04:
|
||||
case 0x05:
|
||||
case 0x06:
|
||||
case 0x07:
|
||||
case 0x08:
|
||||
case 0x09:
|
||||
case 0x0A:
|
||||
case 0x0B:
|
||||
case 0x0C:
|
||||
case 0x0D:
|
||||
break;
|
||||
default:
|
||||
systemMessage(MSG_INVALID_CHEAT_CODE_ADDRESS,
|
||||
N_("Invalid cheat code address: %08x"),
|
||||
address);
|
||||
return false;
|
||||
}
|
||||
|
||||
strncpy(buffer, &code[9], 8);
|
||||
sscanf(buffer, "%x", &value);
|
||||
int type = 0;
|
||||
if (len == 13)
|
||||
type = 114;
|
||||
if (len == 17)
|
||||
type = 115;
|
||||
cheatsAdd(code, desc, address, address, value, type, type);
|
||||
cheatsAdd(std::move(converted.ok));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -2606,7 +2579,7 @@ void cheatsReadGame(gzFile file, int version)
|
|||
utilGzRead(file, &cheatsList[i].address, sizeof(uint32_t));
|
||||
cheatsList[i].rawaddress = cheatsList[i].address;
|
||||
utilGzRead(file, &cheatsList[i].value, sizeof(uint32_t));
|
||||
utilGzRead(file, &cheatsList[i].oldValue, sizeof(uint32_t));
|
||||
utilGzRead(file, &cheatsList[i].old_value, sizeof(uint32_t));
|
||||
utilGzRead(file, &cheatsList[i].codestring, 20 * sizeof(char));
|
||||
utilGzRead(file, &cheatsList[i].desc, 32 * sizeof(char));
|
||||
}
|
||||
|
@ -2743,7 +2716,7 @@ bool cheatsLoadCheatList(const char* file)
|
|||
FREAD_UNCHECKED(&cheatsList[i].address, 1, sizeof(uint32_t), f);
|
||||
cheatsList[i].rawaddress = cheatsList[i].address;
|
||||
FREAD_UNCHECKED(&cheatsList[i].value, 1, sizeof(uint32_t), f);
|
||||
FREAD_UNCHECKED(&cheatsList[i].oldValue, 1, sizeof(uint32_t), f);
|
||||
FREAD_UNCHECKED(&cheatsList[i].old_value, 1, sizeof(uint32_t), f);
|
||||
FREAD_UNCHECKED(&cheatsList[i].codestring, 1, 20 * sizeof(char), f);
|
||||
if (fread(&cheatsList[i].desc, 1, 32 * sizeof(char), f) != 32 * sizeof(char)) {
|
||||
fclose(f);
|
||||
|
@ -2829,9 +2802,9 @@ void cheatsWriteMemory(uint32_t address, uint32_t value)
|
|||
{
|
||||
if (cheatsNumber == 0) {
|
||||
int type = cheatsGetType(address);
|
||||
uint32_t oldValue = debuggerReadMemory(address);
|
||||
if (type == 1 || (type == 2 && oldValue != value)) {
|
||||
debuggerBreakOnWrite(address, oldValue, value, 2, type);
|
||||
uint32_t old_value = debuggerReadMemory(address);
|
||||
if (type == 1 || (type == 2 && old_value != value)) {
|
||||
debuggerBreakOnWrite(address, old_value, value, 2, type);
|
||||
cpuNextEvent = 0;
|
||||
}
|
||||
debuggerWriteMemory(address, value);
|
||||
|
@ -2842,9 +2815,9 @@ void cheatsWriteHalfWord(uint32_t address, uint16_t value)
|
|||
{
|
||||
if (cheatsNumber == 0) {
|
||||
int type = cheatsGetType(address);
|
||||
uint16_t oldValue = debuggerReadHalfWord(address);
|
||||
if (type == 1 || (type == 2 && oldValue != value)) {
|
||||
debuggerBreakOnWrite(address, oldValue, value, 1, type);
|
||||
uint16_t old_value = debuggerReadHalfWord(address);
|
||||
if (type == 1 || (type == 2 && old_value != value)) {
|
||||
debuggerBreakOnWrite(address, old_value, value, 1, type);
|
||||
cpuNextEvent = 0;
|
||||
}
|
||||
debuggerWriteHalfWord(address, value);
|
||||
|
@ -2855,9 +2828,9 @@ void cheatsWriteByte(uint32_t address, uint8_t value)
|
|||
{
|
||||
if (cheatsNumber == 0) {
|
||||
int type = cheatsGetType(address);
|
||||
uint8_t oldValue = debuggerReadByte(address);
|
||||
if (type == 1 || (type == 2 && oldValue != value)) {
|
||||
debuggerBreakOnWrite(address, oldValue, value, 0, type);
|
||||
uint8_t old_value = debuggerReadByte(address);
|
||||
if (type == 1 || (type == 2 && old_value != value)) {
|
||||
debuggerBreakOnWrite(address, old_value, value, 0, type);
|
||||
cpuNextEvent = 0;
|
||||
}
|
||||
debuggerWriteByte(address, value);
|
||||
|
|
|
@ -9,18 +9,7 @@
|
|||
#include <zlib.h>
|
||||
#endif // defined(__LIBRETRO__)
|
||||
|
||||
struct CheatsData {
|
||||
int code;
|
||||
int size;
|
||||
int status;
|
||||
bool enabled;
|
||||
uint32_t rawaddress;
|
||||
uint32_t address;
|
||||
uint32_t value;
|
||||
uint32_t oldValue;
|
||||
char codestring[20];
|
||||
char desc[32];
|
||||
};
|
||||
#include "core/rust/bindings.hpp"
|
||||
|
||||
void cheatsAdd(const char* codeStr, const char* desc, uint32_t rawaddress, uint32_t address, uint32_t value,
|
||||
int code, int size);
|
||||
|
@ -47,6 +36,6 @@ void cheatsWriteByte(uint32_t address, uint8_t value);
|
|||
int cheatsCheckKeys(uint32_t keys, uint32_t extended);
|
||||
|
||||
extern int cheatsNumber;
|
||||
extern CheatsData cheatsList[MAX_CHEATS];
|
||||
extern core::CheatsData cheatsList[MAX_CHEATS];
|
||||
|
||||
#endif // VBAM_CORE_GBA_GBACHEATS_H_
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
[package]
|
||||
name = "vbam_rust"
|
||||
version = "0.1.0"
|
||||
|
||||
[lib]
|
||||
name = "vbam_rust"
|
||||
crate-type = ["staticlib"]
|
||||
|
||||
[profile.dev]
|
||||
panic = "abort"
|
||||
|
||||
[profile.release]
|
||||
panic = "abort"
|
||||
|
||||
[build-dependencies]
|
||||
cbindgen = "0.26.0"
|
|
@ -0,0 +1,76 @@
|
|||
#ifndef VBAM_CORE_RUST_H_
|
||||
#define VBAM_CORE_RUST_H_
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
namespace core {
|
||||
#endif // __cplusplus
|
||||
|
||||
typedef enum CheatsDecodeError {
|
||||
UnsupportedType,
|
||||
InvalidLength,
|
||||
InvalidCharacter,
|
||||
AddressNotHex,
|
||||
ValueNotHex,
|
||||
} CheatsDecodeError;
|
||||
|
||||
typedef enum GbaCheatsType {
|
||||
Generic,
|
||||
GameSharkV2,
|
||||
CodeBreaker,
|
||||
ActionReplay,
|
||||
} GbaCheatsType;
|
||||
|
||||
typedef struct CheatsData {
|
||||
int code;
|
||||
int size;
|
||||
int status;
|
||||
bool enabled;
|
||||
uint32_t rawaddress;
|
||||
uint32_t address;
|
||||
uint32_t value;
|
||||
uint32_t old_value;
|
||||
char codestring[20];
|
||||
char desc[32];
|
||||
} CheatsData;
|
||||
|
||||
typedef enum Result_CheatsData__CheatsDecodeError_Tag {
|
||||
Ok_CheatsData__CheatsDecodeError,
|
||||
Err_CheatsData__CheatsDecodeError,
|
||||
} Result_CheatsData__CheatsDecodeError_Tag;
|
||||
|
||||
typedef struct Result_CheatsData__CheatsDecodeError {
|
||||
Result_CheatsData__CheatsDecodeError_Tag tag;
|
||||
union {
|
||||
struct {
|
||||
struct CheatsData ok;
|
||||
};
|
||||
struct {
|
||||
enum CheatsDecodeError err;
|
||||
};
|
||||
};
|
||||
} Result_CheatsData__CheatsDecodeError;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
enum GbaCheatsType some_type(void);
|
||||
|
||||
struct Result_CheatsData__CheatsDecodeError decode_code(enum GbaCheatsType cheat_type,
|
||||
const char *code_string,
|
||||
const char *description);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif // __cplusplus
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // namespace core
|
||||
#endif // __cplusplus
|
||||
|
||||
#endif /* VBAM_CORE_RUST_H_ */
|
|
@ -0,0 +1,17 @@
|
|||
extern crate cbindgen;
|
||||
|
||||
use std::env;
|
||||
|
||||
fn main() {
|
||||
let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
|
||||
|
||||
cbindgen::Builder::new()
|
||||
.with_crate(crate_dir)
|
||||
.with_language(cbindgen::Language::C)
|
||||
.with_cpp_compat(true)
|
||||
.with_include_guard("VBAM_CORE_RUST_H_")
|
||||
.with_namespace("core")
|
||||
.generate()
|
||||
.expect("Unable to generate bindings")
|
||||
.write_to_file("bindings.hpp");
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
mod panic;
|
||||
|
||||
mod result;
|
||||
pub use crate::base::result::Result;
|
||||
|
||||
mod string;
|
||||
pub(crate) use crate::base::string::StrLike;
|
|
@ -0,0 +1,6 @@
|
|||
#[panic_handler]
|
||||
#[cfg(not(test))]
|
||||
/// Panic handler, called on panic. Does nothing.
|
||||
fn panic(_info: &core::panic::PanicInfo) -> ! {
|
||||
loop {}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
#[repr(C)]
|
||||
pub enum Result<T, E> {
|
||||
Ok(T),
|
||||
Err(E),
|
||||
}
|
|
@ -0,0 +1,100 @@
|
|||
use core::ffi::c_char;
|
||||
use core::ffi::CStr;
|
||||
|
||||
pub(crate) trait CharLike {
|
||||
fn to_hex(&self) -> Option<u8>;
|
||||
fn is_hex(&self) -> bool {
|
||||
self.to_hex().is_some()
|
||||
}
|
||||
}
|
||||
|
||||
impl CharLike for u8 {
|
||||
fn to_hex(&self) -> Option<u8> {
|
||||
if *self >= b'0' && *self <= b'9' {
|
||||
Some(*self - b'0')
|
||||
} else if *self >= b'A' && *self <= b'F' {
|
||||
Some(*self - b'A' + 10)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) trait StrLike {
|
||||
fn to_hex(&self) -> Option<u32>;
|
||||
fn clone_buffer<const LEN: usize>(&self) -> [c_char; LEN];
|
||||
}
|
||||
|
||||
impl StrLike for [u8] {
|
||||
fn to_hex(&self) -> Option<u32> {
|
||||
let mut result: u32 = 0;
|
||||
for byte in self.iter() {
|
||||
if let Some(value) = byte.to_hex() {
|
||||
result = result.wrapping_mul(16).wrapping_add(value as u32);
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
Some(result)
|
||||
}
|
||||
|
||||
fn clone_buffer<const LEN: usize>(&self) -> [c_char; LEN] {
|
||||
let mut buffer = [0; LEN];
|
||||
let mut i: usize = 0;
|
||||
for byte in self.iter() {
|
||||
if i == LEN {
|
||||
break;
|
||||
}
|
||||
buffer[i] = *byte as c_char;
|
||||
i += 1;
|
||||
}
|
||||
if i == LEN {
|
||||
buffer[LEN - 1] = 0;
|
||||
} else {
|
||||
buffer[i] = 0;
|
||||
}
|
||||
buffer
|
||||
}
|
||||
}
|
||||
|
||||
impl StrLike for CStr {
|
||||
fn to_hex(&self) -> Option<u32> {
|
||||
self.to_bytes().to_hex()
|
||||
}
|
||||
|
||||
fn clone_buffer<const LEN: usize>(&self) -> [c_char; LEN] {
|
||||
self.to_bytes().clone_buffer()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_char_to_hex() {
|
||||
assert_eq!(b'0'.to_hex(), Some(0));
|
||||
assert_eq!(b'9'.to_hex(), Some(9));
|
||||
assert_eq!(b'A'.to_hex(), Some(10));
|
||||
assert_eq!(b'F'.to_hex(), Some(15));
|
||||
assert_eq!(b'G'.to_hex(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_str_to_hex() {
|
||||
assert_eq!([].to_hex(), Some(0));
|
||||
assert_eq!([b'0'].to_hex(), Some(0));
|
||||
assert_eq!([b'1', b'0'].to_hex(), Some(16));
|
||||
assert_eq!([b'F', b'F'].to_hex(), Some(255));
|
||||
assert_eq!([b'G'].to_hex(), None);
|
||||
assert_eq!(b"ABCDEF".to_hex(), Some(11259375));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_str_clone_buffer() {
|
||||
assert_eq!(b"test".clone_buffer(), [116, 101, 115, 116, 0]);
|
||||
assert_eq!(b"test".clone_buffer(), [116, 101, 0]);
|
||||
assert_eq!(b"test".clone_buffer(), [0]);
|
||||
assert_eq!(b"".clone_buffer(), [0]);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
mod cheats;
|
||||
pub use crate::gba::cheats::GbaCheatsType;
|
|
@ -0,0 +1,108 @@
|
|||
use core::ffi::c_char;
|
||||
use core::ffi::c_int;
|
||||
use core::ffi::CStr;
|
||||
|
||||
use crate::base::StrLike;
|
||||
use crate::prelude::*;
|
||||
|
||||
#[repr(C)]
|
||||
pub enum GbaCheatsType {
|
||||
Generic,
|
||||
GameSharkV2,
|
||||
CodeBreaker,
|
||||
ActionReplay,
|
||||
}
|
||||
|
||||
impl GbaCheatsType {
|
||||
#[no_mangle]
|
||||
pub extern "C" fn some_type() -> GbaCheatsType {
|
||||
GbaCheatsType::Generic
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct CheatsData {
|
||||
code: c_int,
|
||||
size: c_int,
|
||||
status: c_int,
|
||||
enabled: bool,
|
||||
rawaddress: u32,
|
||||
address: u32,
|
||||
value: u32,
|
||||
old_value: u32,
|
||||
codestring: [c_char; 20],
|
||||
desc: [c_char; 32],
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub enum CheatsDecodeError {
|
||||
UnsupportedType,
|
||||
InvalidLength,
|
||||
InvalidCharacter,
|
||||
AddressNotHex,
|
||||
ValueNotHex,
|
||||
}
|
||||
|
||||
impl CheatsData {
|
||||
fn decode_generic(code_string: &CStr, description: &CStr) -> Result<CheatsData, CheatsDecodeError> {
|
||||
let code_length = code_string.to_bytes().len();
|
||||
if code_length != 11 && code_length != 13 && code_length != 17 {
|
||||
return Err(CheatsDecodeError::InvalidLength);
|
||||
}
|
||||
|
||||
if code_string.to_bytes()[8] != b':' {
|
||||
return Err(CheatsDecodeError::InvalidCharacter);
|
||||
}
|
||||
|
||||
let address =
|
||||
match code_string.to_bytes()[..8].to_hex() {
|
||||
Some(address) => address,
|
||||
None => {
|
||||
return Err(CheatsDecodeError::AddressNotHex);
|
||||
}
|
||||
};
|
||||
|
||||
let value =
|
||||
match code_string.to_bytes()[9..].to_hex() {
|
||||
Some(value) => value,
|
||||
None => {
|
||||
return Err(CheatsDecodeError::ValueNotHex);
|
||||
}
|
||||
};
|
||||
|
||||
let code = if code_length == 1 {
|
||||
0
|
||||
} else if code_length == 13 {
|
||||
114
|
||||
} else {
|
||||
115
|
||||
};
|
||||
|
||||
Ok(CheatsData {
|
||||
code,
|
||||
size: code,
|
||||
status: 0,
|
||||
enabled: true,
|
||||
rawaddress: address,
|
||||
address,
|
||||
value,
|
||||
old_value: 0,
|
||||
codestring: code_string.clone_buffer(),
|
||||
desc: description.clone_buffer(),
|
||||
})
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn decode_code(
|
||||
cheat_type: GbaCheatsType,
|
||||
code_string: *const c_char,
|
||||
description: *const c_char,
|
||||
) -> Result<CheatsData, CheatsDecodeError> {
|
||||
let code = unsafe { CStr::from_ptr(code_string) };
|
||||
let description = unsafe { CStr::from_ptr(description) };
|
||||
match cheat_type {
|
||||
GbaCheatsType::Generic => CheatsData::decode_generic(code, description),
|
||||
_ => Err(CheatsDecodeError::UnsupportedType),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
//! A crate implementing part of the VBA-M core in Rust. This is meant to be
|
||||
//! used as a library in the VBA-M core.
|
||||
//!
|
||||
//! Guidelines:
|
||||
//! * `no_std`. In particular, this means no I/O and no file I/O. It's fine to
|
||||
//! pass buffers of memory to and from the Rust code, but the Rust code itself
|
||||
//! should not perform any I/O.
|
||||
//! * Core code only. We may want to use Rust in other parts of the codebase but
|
||||
//! let's leave it at the core for now.
|
||||
//! * Exported types must be `#[repr(C)]`. Exported functions must be `extern
|
||||
//! "C"` with `[no_mangle]`.
|
||||
|
||||
#![no_std]
|
||||
|
||||
pub mod base;
|
||||
pub mod gba;
|
||||
|
||||
mod prelude {
|
||||
pub use crate::base::Result;
|
||||
pub use crate::base::Result::Err;
|
||||
pub use crate::base::Result::Ok;
|
||||
}
|
|
@ -34,10 +34,6 @@ if(MSVC)
|
|||
)
|
||||
endif()
|
||||
|
||||
if(ENABLE_LIRC)
|
||||
set(LIRC_CLIENT_LIBRARY lirc_client)
|
||||
endif()
|
||||
|
||||
target_link_libraries(vbam
|
||||
vbam-core
|
||||
vbam-components-audio-sdl
|
||||
|
|
|
@ -427,7 +427,7 @@ host_compile(${CMAKE_CURRENT_SOURCE_DIR}/bin2c.c ${BIN2C})
|
|||
|
||||
# Override wxrc when cross-compiling.
|
||||
if(CMAKE_HOST_WIN32 AND CMAKE_CROSSCOMPILING)
|
||||
set(WXRC ${CMAKE_SOURCE_DIR}/dependencies/wxrc/wxrc.exe)
|
||||
find_program(WXRC NAMES wxrc)
|
||||
endif()
|
||||
|
||||
# Configure wxrc.
|
||||
|
|
|
@ -8,6 +8,6 @@
|
|||
#define DOCTEST_THREAD_LOCAL // Avoid MinGW thread_local bug.
|
||||
#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN
|
||||
|
||||
#include "doctest.h"
|
||||
#include <doctest.h>
|
||||
|
||||
#endif
|
||||
|
|
|
@ -524,7 +524,6 @@ setup() {
|
|||
# binary smaller.
|
||||
if [ "$target_os" = windows ] && [ "$target_bits" -eq 32 ]; then
|
||||
BUILD_FFMPEG=
|
||||
PROJECT_ARGS="$PROJECT_ARGS -DENABLE_OPENAL=NO"
|
||||
fi
|
||||
|
||||
if [ -z "$BUILD_FFMPEG" ]; then
|
||||
|
|
Loading…
Reference in New Issue