Merge pull request #1 from Dima353/miami-psp2
Add PlayStation Vita (PSP2) port
@@ -0,0 +1,82 @@
|
||||
name: reVC makefile VitaSDK (PlayStation Vita)
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
pull_request:
|
||||
push:
|
||||
branches: [ miami ]
|
||||
release:
|
||||
types: [ published ]
|
||||
|
||||
jobs:
|
||||
build-ps-vita:
|
||||
runs-on: ubuntu-latest
|
||||
container: vitasdk/vitasdk:latest
|
||||
|
||||
steps:
|
||||
- name: Install CI prerequisites
|
||||
# build-base gives the HOST gcc/g++: several deps (OpenAL, mpg123) build a
|
||||
# native codegen helper, and the image only ships the arm-vita-eabi cross tools.
|
||||
run: apk add --no-cache build-base git make cmake bash wget tar bzip2 patch
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Build vitaShaRK
|
||||
run: |
|
||||
git clone --depth 1 https://github.com/Rinnegatamante/vitaShaRK.git
|
||||
make -C vitaShaRK -j"$(nproc)" install
|
||||
|
||||
- name: Build math-neon
|
||||
run: |
|
||||
git clone --depth 1 https://github.com/Rinnegatamante/math-neon.git
|
||||
make -C math-neon -j"$(nproc)" install
|
||||
|
||||
- name: Build vitaGL
|
||||
run: |
|
||||
git clone --depth 1 https://github.com/Rinnegatamante/vitaGL.git
|
||||
make -C vitaGL NO_DEBUG=1 PHYCONT_ON_DEMAND=1 ENABLE_LEGACY_PIPELINE=1 -j"$(nproc)" install
|
||||
|
||||
- name: Build librw-vita (fork, kept building against current vitaGL)
|
||||
run: |
|
||||
git clone --depth 1 https://github.com/Dima353/librw-vita.git
|
||||
make -C librw-vita -j"$(nproc)" install
|
||||
|
||||
- name: Build OpenAL-Soft (Vita fork)
|
||||
run: |
|
||||
git clone --depth 1 -b vita-1.19.1 https://github.com/Dima353/openal-soft.git
|
||||
mkdir -p openal-soft/build && cd openal-soft/build
|
||||
cmake -DCMAKE_TOOLCHAIN_FILE=${VITASDK}/share/vita.toolchain.cmake -DCMAKE_BUILD_TYPE=Release \
|
||||
-DCMAKE_C_FLAGS="-D_GNU_SOURCE -Wno-error=implicit-function-declaration -Wno-error=int-conversion" ..
|
||||
make -j"$(nproc)" install
|
||||
|
||||
- name: Build mpg123
|
||||
run: |
|
||||
wget -q https://www.mpg123.de/download/mpg123-1.33.5.tar.bz2
|
||||
tar -xjf mpg123-1.33.5.tar.bz2
|
||||
wget -q -O mpg123-1.33.5/mpg123.patch https://raw.githubusercontent.com/vitasdk/packages/master/mpg123/mpg123.patch
|
||||
cd mpg123-1.33.5
|
||||
patch -p1 -i mpg123.patch
|
||||
mkdir _build && cd _build
|
||||
cmake ../ports/cmake \
|
||||
-DCMAKE_TOOLCHAIN_FILE=${VITASDK}/share/vita.toolchain.cmake -DCMAKE_BUILD_TYPE=Release \
|
||||
-DCMAKE_C_FLAGS='-DDONT_CATCH_SIGNALS' -DACCURATE_ROUNDING=OFF -DHAVE_IPV6=0 -DHAVE_NETWORK=0
|
||||
make -j"$(nproc)" install
|
||||
|
||||
- name: Build SDL2 (VGL backend)
|
||||
run: |
|
||||
git clone --depth 1 https://github.com/Northfear/SDL.git
|
||||
cd SDL
|
||||
cmake -S. -Bbuild -DCMAKE_TOOLCHAIN_FILE=${VITASDK}/share/vita.toolchain.cmake -DCMAKE_BUILD_TYPE=Release -DVIDEO_VITA_VGL=ON -DCMAKE_POLICY_VERSION_MINIMUM=3.5
|
||||
cmake --build build -- -j"$(nproc)"
|
||||
cmake --install build
|
||||
|
||||
- name: Build reVC (GTAVC.vpk)
|
||||
run: make -j"$(nproc)"
|
||||
|
||||
- name: Upload VPK artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: vita-gtavc-vpk
|
||||
path: GTAVC.vpk
|
||||
if-no-files-found: error
|
||||
@@ -0,0 +1,70 @@
|
||||
TITLE := "Grand Theft Auto: Vice City"
|
||||
TITLE_ID := GTAVCRT00
|
||||
TARGET := GTAVC
|
||||
|
||||
SOURCES := src src/animation src/audio src/audio/oal src/audio/eax src/buildings src/control src/collision src/core src/entities src/math src/modelinfo src/objects src/peds src/renderer src/rw src/save src/skel src/skel/glfw src/text src/vehicles src/weapons src/extras src/fakerw
|
||||
INCLUDES := src src/animation src/audio src/audio/oal src/audio/eax src/buildings src/control src/collision src/core src/entities src/math src/modelinfo src/objects src/peds src/renderer src/rw src/save src/skel src/skel/glfw src/text src/vehicles src/weapons src/extras src/fakerw librw
|
||||
|
||||
CFILES := $(foreach dir,$(SOURCES), $(wildcard $(dir)/*.c))
|
||||
CPPFILES := $(foreach dir,$(SOURCES), $(wildcard $(dir)/*.cpp))
|
||||
BINFILES := $(foreach dir,$(DATA), $(wildcard $(dir)/*.bin))
|
||||
OBJS := $(addsuffix .o,$(BINFILES)) $(CFILES:.c=.o) $(CPPFILES:.cpp=.o)
|
||||
|
||||
INCLUDE := $(foreach dir,$(INCLUDES),-I$(dir))
|
||||
|
||||
PREFIX = arm-vita-eabi
|
||||
CC = $(PREFIX)-gcc
|
||||
CXX = $(PREFIX)-g++
|
||||
ARCH := -mtune=cortex-a9 -march=armv7-a -mfpu=neon
|
||||
CFLAGS := -g -Wl,-q,--no-enum-size-warning -fno-short-enums -fno-optimize-sibling-calls -O2 -ftree-vectorize -mfloat-abi=hard -fno-builtin-memcpy $(ARCH) $(DEFINES)
|
||||
CFLAGS += $(INCLUDE) -DPSP2 -DNDEBUG -DMASTER -DLIBRW -DRW_GL3 -DAUDIO_OAL -DLIBRW_GLAD
|
||||
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions
|
||||
ASFLAGS := -g $(ARCH)
|
||||
LDFLAGS = -g $(ARCH) -Wl,-Map,$(notdir $*.map)
|
||||
LIBS := -lrw -lopenal -lSDL2 -lvita2d -lvitaGL -lSceAppMgr_stub -lSceDisplay_stub -lSceCommonDialog_stub -lSceLibKernel_stub \
|
||||
-lSceSysmodule_stub -lvitashark -lSceShaccCg_stub -lSceShaccCgExt -lvitaGL -lmathneon -lSceGxm_stub -lScePower_stub \
|
||||
-lSceCtrl_stub -lSceHid_stub -lSceAudio_stub -lSceAudioIn_stub -lSceTouch_stub -lm -lpthread -lmpg123 -lSceMotion_stub \
|
||||
-lSceSysmodule_stub -lSceAvPlayer_stub -lSceKernelDmacMgr_stub -ltaihen_stub
|
||||
|
||||
all: $(TARGET).vpk
|
||||
|
||||
%.vpk: eboot.bin
|
||||
vita-mksfoex -s APP_VER=01.20 -s TITLE_ID=$(TITLE_ID) -d ATTRIBUTE2=12 $(TITLE) param.sfo
|
||||
vita-pack-vpk -s param.sfo -b eboot.bin \
|
||||
--add sce_sys/icon0.png=sce_sys/icon0.png \
|
||||
--add sce_sys/livearea/contents/bg.png=sce_sys/livearea/contents/bg.png \
|
||||
--add sce_sys/livearea/contents/startup.png=sce_sys/livearea/contents/startup.png \
|
||||
--add sce_sys/livearea/contents/template.xml=sce_sys/livearea/contents/template.xml \
|
||||
--add sce_sys/manual/001.png=sce_sys/manual/001.png \
|
||||
--add sce_sys/manual/002.png=sce_sys/manual/002.png \
|
||||
--add sce_sys/manual/003.png=sce_sys/manual/003.png \
|
||||
--add sce_sys/manual/004.png=sce_sys/manual/004.png \
|
||||
--add sce_sys/manual/005.png=sce_sys/manual/005.png \
|
||||
--add sce_sys/manual/006.png=sce_sys/manual/006.png \
|
||||
--add sce_sys/manual/007.png=sce_sys/manual/007.png \
|
||||
--add sce_sys/manual/008.png=sce_sys/manual/008.png \
|
||||
--add sce_sys/manual/009.png=sce_sys/manual/009.png \
|
||||
--add sce_sys/manual/010.png=sce_sys/manual/010.png \
|
||||
--add sce_sys/manual/011.png=sce_sys/manual/011.png \
|
||||
--add sce_sys/manual/012.png=sce_sys/manual/012.png \
|
||||
--add sce_sys/manual/013.png=sce_sys/manual/013.png \
|
||||
--add sce_sys/manual/014.png=sce_sys/manual/014.png \
|
||||
--add sce_sys/manual/015.png=sce_sys/manual/015.png \
|
||||
--add sce_sys/manual/016.png=sce_sys/manual/016.png \
|
||||
--add sce_sys/manual/017.png=sce_sys/manual/017.png \
|
||||
--add sce_sys/manual/018.png=sce_sys/manual/018.png \
|
||||
--add sce_sys/manual/019.png=sce_sys/manual/019.png \
|
||||
--add sce_sys/manual/020.png=sce_sys/manual/020.png \
|
||||
$(TARGET).vpk
|
||||
|
||||
eboot.bin: $(TARGET).velf
|
||||
vita-make-fself -c -s $< $@
|
||||
|
||||
%.velf: %.elf
|
||||
vita-elf-create $< $@
|
||||
|
||||
$(TARGET).elf: $(OBJS)
|
||||
$(CXX) $(CXXFLAGS) $^ $(LIBS) -o $@
|
||||
|
||||
clean:
|
||||
@rm -rf $(TARGET).vpk $(TARGET).velf $(TARGET).elf $(OBJS) eboot.bin param.sfo
|
||||
|
After Width: | Height: | Size: 7.0 KiB |
|
After Width: | Height: | Size: 241 KiB |
|
After Width: | Height: | Size: 24 KiB |
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<livearea style="psmobile" format-ver="01.00" content-rev="1">
|
||||
<livearea-background>
|
||||
<image>bg.png</image>
|
||||
</livearea-background>
|
||||
|
||||
<gate>
|
||||
<startup-image>startup.png</startup-image>
|
||||
</gate>
|
||||
</livearea>
|
||||
|
After Width: | Height: | Size: 536 KiB |
|
After Width: | Height: | Size: 405 KiB |
|
After Width: | Height: | Size: 347 KiB |
|
After Width: | Height: | Size: 387 KiB |
|
After Width: | Height: | Size: 525 KiB |
|
After Width: | Height: | Size: 514 KiB |
|
After Width: | Height: | Size: 453 KiB |
|
After Width: | Height: | Size: 391 KiB |
|
After Width: | Height: | Size: 463 KiB |
|
After Width: | Height: | Size: 436 KiB |
|
After Width: | Height: | Size: 509 KiB |
|
After Width: | Height: | Size: 473 KiB |
|
After Width: | Height: | Size: 493 KiB |
|
After Width: | Height: | Size: 417 KiB |
|
After Width: | Height: | Size: 367 KiB |
|
After Width: | Height: | Size: 630 KiB |
|
After Width: | Height: | Size: 363 KiB |
|
After Width: | Height: | Size: 297 KiB |
|
After Width: | Height: | Size: 455 KiB |
|
After Width: | Height: | Size: 432 KiB |
@@ -51,6 +51,7 @@ using namespace re3_openal;
|
||||
|
||||
void EFXInit()
|
||||
{
|
||||
#ifndef PSP2
|
||||
/* Define a macro to help load the function pointers. */
|
||||
#define LOAD_PROC(T, x) ((x) = (T)alGetProcAddress(#x))
|
||||
LOAD_PROC(LPALGENEFFECTS, alGenEffects);
|
||||
@@ -89,6 +90,7 @@ void EFXInit()
|
||||
LOAD_PROC(LPALGETAUXILIARYEFFECTSLOTF, alGetAuxiliaryEffectSlotf);
|
||||
LOAD_PROC(LPALGETAUXILIARYEFFECTSLOTFV, alGetAuxiliaryEffectSlotfv);
|
||||
#undef LOAD_PROC
|
||||
#endif
|
||||
}
|
||||
|
||||
void SetEffectsLevel(ALuint uiFilter, float level)
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
#include <direct.h>
|
||||
#include <shlobj.h>
|
||||
#include <shlguid.h>
|
||||
#else
|
||||
#elif !defined(PSP2)
|
||||
#define _getcwd getcwd
|
||||
#endif
|
||||
|
||||
@@ -261,7 +261,9 @@ set_new_provider(int index)
|
||||
usingEAX3 = 0;
|
||||
_usingEFX = false;
|
||||
|
||||
if ( !strcmp(&providers[index].name[strlen(providers[index].name) - strlen(" EAX3")], " EAX3")
|
||||
// The Vita openal-soft has no EFX, so there is no EAX provider to detect.
|
||||
#if !defined(PSP2)
|
||||
if ( !strcmp(&providers[index].name[strlen(providers[index].name) - strlen(" EAX3")], " EAX3")
|
||||
&& alcIsExtensionPresent(ALDevice, (ALCchar*)ALC_EXT_EFX_NAME) )
|
||||
{
|
||||
|
||||
@@ -288,7 +290,8 @@ set_new_provider(int index)
|
||||
alAuxiliaryEffectSloti(ALEffectSlot, AL_EFFECTSLOT_EFFECT, ALEffect);
|
||||
EAX_SetAll(&EAX30_ORIGINAL_PRESETS[EAX_ENVIRONMENT_CAVE]);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
//SampleManager.SetSpeakerConfig(speaker_type);
|
||||
|
||||
if ( IsFXSupported() )
|
||||
@@ -451,7 +454,7 @@ _ResolveLink(char const *path, char *out)
|
||||
#else
|
||||
struct stat sb;
|
||||
|
||||
if (lstat(path, &sb) == -1) {
|
||||
if (_lstat(path, &sb) == -1) {
|
||||
perror("lstat: ");
|
||||
return FALSE;
|
||||
}
|
||||
@@ -488,7 +491,8 @@ _FindMP3s(void)
|
||||
WIN32_FIND_DATA fd;
|
||||
char filepath[MAX_PATH + sizeof(fd.cFileName)];
|
||||
|
||||
if (getcwd(_mp3DirectoryPath, MAX_PATH) == NULL) {
|
||||
// _getcwd on PSP2 returns the data directory; elsewhere it is the real one.
|
||||
if (_getcwd(_mp3DirectoryPath, MAX_PATH) == NULL) {
|
||||
perror("getcwd: ");
|
||||
return;
|
||||
}
|
||||
@@ -540,6 +544,8 @@ _FindMP3s(void)
|
||||
{
|
||||
if (filepathlen > 0)
|
||||
{
|
||||
// No symlinks on this filesystem, and readlink is a stub here.
|
||||
#ifndef PSP2
|
||||
if (_ResolveLink(filepath, filepath))
|
||||
{
|
||||
OutputDebugString("Resolving Link");
|
||||
@@ -547,6 +553,7 @@ _FindMP3s(void)
|
||||
bShortcut = TRUE;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
bShortcut = FALSE;
|
||||
if (filepathlen > MAX_PATH) {
|
||||
@@ -599,6 +606,7 @@ _FindMP3s(void)
|
||||
{
|
||||
if ( filepathlen > 0 )
|
||||
{
|
||||
#ifndef PSP2
|
||||
if ( _ResolveLink(filepath, filepath) )
|
||||
{
|
||||
OutputDebugString("Resolving Link");
|
||||
@@ -606,6 +614,7 @@ _FindMP3s(void)
|
||||
bShortcut = TRUE;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
bShortcut = FALSE;
|
||||
|
||||
if (aStream[0] && aStream[0]->Open(filepath))
|
||||
@@ -869,13 +878,17 @@ cSampleManager::Initialise(void)
|
||||
alListenerfv(AL_ORIENTATION, orientation);
|
||||
|
||||
alDistanceModel(AL_INVERSE_DISTANCE_CLAMPED);
|
||||
|
||||
|
||||
// The Vita openal-soft is built without EFX, so EFXInit never resolved these
|
||||
// and the pointers are still null - calling them lands on address zero.
|
||||
#ifndef PSP2
|
||||
if ( alcIsExtensionPresent(ALDevice, (ALCchar*)ALC_EXT_EFX_NAME) )
|
||||
{
|
||||
{
|
||||
_effectsSupported = providers[index].bSupportsFx;
|
||||
alGenAuxiliaryEffectSlots(1, &ALEffectSlot);
|
||||
alGenEffects(1, &ALEffect);
|
||||
}
|
||||
#endif
|
||||
|
||||
alGenSources(MAX_STREAMS*2, ALStreamSources[0]);
|
||||
for ( int32 i = 0; i < MAX_STREAMS; i++ )
|
||||
|
||||
@@ -7,7 +7,9 @@
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/time.h>
|
||||
#ifndef PSP2
|
||||
#include <sys/statvfs.h>
|
||||
#endif
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
@@ -26,6 +28,12 @@
|
||||
#define CDDEBUG(f, ...) debug ("%s: " f "\n", "cdvd_stream", ## __VA_ARGS__)
|
||||
#define CDTRACE(f, ...) printf("%s: " f "\n", "cdvd_stream", ## __VA_ARGS__)
|
||||
|
||||
#ifdef PSP2
|
||||
// Named semaphores do not exist here, and newlib does not declare SEM_FAILED.
|
||||
#define USE_UNNAMED_SEM
|
||||
#define SEM_FAILED ((sem_t *) 0)
|
||||
#endif
|
||||
|
||||
#ifdef FLUSHABLE_STREAMING
|
||||
bool flushStream[MAX_CDCHANNELS];
|
||||
#endif
|
||||
@@ -198,6 +206,7 @@ CdStreamInitThread(void)
|
||||
void
|
||||
CdStreamInit(int32 numChannels)
|
||||
{
|
||||
#ifndef PSP2
|
||||
struct statvfs fsInfo;
|
||||
|
||||
if((statvfs("models/gta3.img", &fsInfo)) < 0)
|
||||
@@ -206,6 +215,7 @@ CdStreamInit(int32 numChannels)
|
||||
ASSERT(0);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
#ifdef __linux__
|
||||
_gdwCdStreamFlags = O_RDONLY | O_NOATIME;
|
||||
#else
|
||||
@@ -219,7 +229,11 @@ CdStreamInit(int32 numChannels)
|
||||
debug("Using no buffered loading for streaming\n");
|
||||
}
|
||||
*/
|
||||
#ifndef PSP2
|
||||
void *pBuffer = (void *)RwMallocAlign(CDSTREAM_SECTOR_SIZE, (RwUInt32)fsInfo.f_bsize);
|
||||
#else
|
||||
void *pBuffer = (void *)RwMallocAlign(CDSTREAM_SECTOR_SIZE, CDSTREAM_SECTOR_SIZE);
|
||||
#endif
|
||||
ASSERT( pBuffer != nil );
|
||||
|
||||
gNumImages = 0;
|
||||
@@ -245,13 +259,14 @@ GetGTA3ImgSize(void)
|
||||
struct stat statbuf;
|
||||
|
||||
char path[PATH_MAX];
|
||||
realpath(gImgNames[0], path);
|
||||
// _realpath is the Vita shim, plain realpath everywhere else - see crossplatform.h
|
||||
_realpath(gImgNames[0], path);
|
||||
if (stat(path, &statbuf) == -1) {
|
||||
// Try case-insensitivity
|
||||
char* real = casepath(gImgNames[0], false);
|
||||
if (real)
|
||||
{
|
||||
realpath(real, path);
|
||||
_realpath(real, path);
|
||||
free(real);
|
||||
if (stat(path, &statbuf) != -1)
|
||||
goto ok;
|
||||
|
||||
@@ -32,14 +32,16 @@ static myFILE myfiles[NUMFILES];
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#if !defined(PSP2)
|
||||
#define _getcwd getcwd
|
||||
#endif
|
||||
|
||||
// Case-insensitivity on linux (from https://github.com/OneSadCookie/fcaseopen)
|
||||
void mychdir(char const *path)
|
||||
{
|
||||
char* r = casepath(path, false);
|
||||
if (r) {
|
||||
chdir(r);
|
||||
_chdir(r);
|
||||
free(r);
|
||||
} else {
|
||||
errno = ENOENT;
|
||||
|
||||
@@ -36,6 +36,10 @@
|
||||
#include "User.h"
|
||||
#include "sampman.h"
|
||||
|
||||
#ifdef PSP2
|
||||
extern bool useRearpad; // touch input: front panel or rear, see crossplatform.cpp
|
||||
#endif
|
||||
|
||||
// Similar story to Hud.cpp:
|
||||
// Game has colors inlined in code.
|
||||
// For easier modification we collect them here:
|
||||
@@ -506,7 +510,11 @@ CMenuManager::CMenuManager()
|
||||
DisplayComboButtonErrMsg = false;
|
||||
m_PrefsDMA = 1;
|
||||
OS_Language = LANG_ENGLISH;
|
||||
#ifdef GTA_HANDHELD
|
||||
m_ControlMethod = CONTROL_CLASSIC; // handhelds default to classic controls
|
||||
#else
|
||||
m_ControlMethod = CONTROL_STANDARD;
|
||||
#endif
|
||||
#ifdef PC_PLAYER_CONTROLS
|
||||
CCamera::m_bUseMouse3rdPerson = true;
|
||||
#else
|
||||
@@ -543,11 +551,7 @@ CMenuManager::CMenuManager()
|
||||
#endif
|
||||
|
||||
#ifdef GAMEPAD_MENU
|
||||
#ifdef __SWITCH__
|
||||
m_PrefsControllerType = CONTROLLER_NINTENDO_SWITCH;
|
||||
#else
|
||||
m_PrefsControllerType = CONTROLLER_XBOXONE;
|
||||
#endif
|
||||
m_PrefsControllerType = DEFAULT_CONTROLLER_TYPE;
|
||||
#endif
|
||||
|
||||
#ifdef MISSION_REPLAY
|
||||
@@ -1390,6 +1394,15 @@ CMenuManager::DrawStandardMenus(bool activeScreen)
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef PSP2
|
||||
// The rear-panel toggle is labelled from the "PSP2" GXT key rather than a
|
||||
// CFO name, so that the entry reads properly in every localisation.
|
||||
if (!strncmp(aScreens[m_nCurrScreen].m_aEntries[i].m_EntryName, "PSP2", 4)) {
|
||||
leftText = TheText.Get("PSP2");
|
||||
rightText = TheText.Get(useRearpad ? "FEM_ON" : "FEM_OFF");
|
||||
}
|
||||
#endif
|
||||
|
||||
// Highlight trapezoid
|
||||
if (activeScreen && i == m_nCurrOption && itemsAreSelectable && section == 0) {
|
||||
|
||||
@@ -5984,7 +5997,7 @@ const char* controllerTypesPaths[] = {
|
||||
"MODELS/FRONTEND_DS2.TXD",
|
||||
"MODELS/FRONTEND_DS3.TXD",
|
||||
"MODELS/FRONTEND_DS4.TXD",
|
||||
#ifndef RT
|
||||
#ifndef RT_CONTROLLERS
|
||||
"MODELS/FRONTEND_X360.TXD",
|
||||
#endif
|
||||
"MODELS/FRONTEND_XONE.TXD",
|
||||
@@ -5994,7 +6007,697 @@ const char* controllerTypesPaths[] = {
|
||||
void
|
||||
CMenuManager::PrintController(void)
|
||||
{
|
||||
#ifdef RT
|
||||
#ifdef PSP2
|
||||
// Don't print anything if controller texture is missing
|
||||
if (!m_aFrontEndSprites[MENUSPRITE_CONTROLLER].m_pTexture) return;
|
||||
|
||||
const float scale = 0.9f;
|
||||
const float CONTROLLER_SIZE_X = 384.0f;
|
||||
const float CONTROLLER_SIZE_Y = 384.2f;
|
||||
const float CONTROLLER_POS_X = (DEFAULT_SCREEN_WIDTH - CONTROLLER_SIZE_X) / 2.0f;
|
||||
const float CONTROLLER_POS_Y = 220.0f;
|
||||
|
||||
float centerX = CONTROLLER_POS_X + CONTROLLER_SIZE_X / 2;
|
||||
float centerY = CONTROLLER_POS_Y + CONTROLLER_SIZE_Y / 2;
|
||||
|
||||
#define X(f) ((f)*scale + centerX)
|
||||
#define Y(f) ((f)*scale + centerY)
|
||||
|
||||
m_aFrontEndSprites[MENUSPRITE_CONTROLLER].Draw(MENU_X_LEFT_ALIGNED(X(-CONTROLLER_SIZE_X / 2)), MENU_Y(Y(-CONTROLLER_SIZE_Y / 2)), MENU_X(CONTROLLER_SIZE_X * scale), MENU_Y(CONTROLLER_SIZE_Y * scale), CRGBA(255, 255, 255, FadeIn(255)));
|
||||
if (m_DisplayControllerOnFoot) {
|
||||
if ((int)CTimer::GetTimeInMillisecondsPauseMode() & 0x400)
|
||||
m_aFrontEndSprites[MENUSPRITE_ARROWS1].Draw(MENU_X_LEFT_ALIGNED(X(-CONTROLLER_SIZE_X / 2)), MENU_Y(Y(-CONTROLLER_SIZE_Y / 2)), MENU_X(CONTROLLER_SIZE_X * scale), MENU_Y(CONTROLLER_SIZE_Y * scale), CRGBA(255, 255, 255, FadeIn(255)));
|
||||
else
|
||||
m_aFrontEndSprites[MENUSPRITE_ARROWS3].Draw(MENU_X_LEFT_ALIGNED(X(-CONTROLLER_SIZE_X / 2)), MENU_Y(Y(-CONTROLLER_SIZE_Y / 2)), MENU_X(CONTROLLER_SIZE_X * scale), MENU_Y(CONTROLLER_SIZE_Y * scale), CRGBA(255, 255, 255, FadeIn(255)));
|
||||
}
|
||||
else {
|
||||
if ((int)CTimer::GetTimeInMillisecondsPauseMode() & 0x400)
|
||||
m_aFrontEndSprites[MENUSPRITE_ARROWS2].Draw(MENU_X_LEFT_ALIGNED(X(-CONTROLLER_SIZE_X / 2)), MENU_Y(Y(-CONTROLLER_SIZE_Y / 2)), MENU_X(CONTROLLER_SIZE_X * scale), MENU_Y(CONTROLLER_SIZE_Y * scale), CRGBA(255, 255, 255, FadeIn(255)));
|
||||
else
|
||||
m_aFrontEndSprites[MENUSPRITE_ARROWS4].Draw(MENU_X_LEFT_ALIGNED(X(-CONTROLLER_SIZE_X / 2)), MENU_Y(Y(-CONTROLLER_SIZE_Y / 2)), MENU_X(CONTROLLER_SIZE_X * scale), MENU_Y(CONTROLLER_SIZE_Y * scale), CRGBA(255, 255, 255, FadeIn(255)));
|
||||
}
|
||||
|
||||
CFont::SetFontStyle(FONT_LOCALE(FONT_STANDARD));
|
||||
|
||||
CFont::SetScale(MENU_X(SMALLESTTEXT_X_SCALE * 2 * scale * 0.9f), MENU_Y(SMALLESTTEXT_Y_SCALE * scale * 0.9f)); // X
|
||||
|
||||
CFont::SetDropColor(CRGBA(0, 0, 0, FadeIn(255)));
|
||||
CFont::SetDropShadowPosition(0);
|
||||
CFont::SetColor(CRGBA(255, 255, 255, FadeIn(255)));
|
||||
CFont::SetWrapx(SCREEN_WIDTH);
|
||||
|
||||
float TEXT_L2_X = 106.0f + CONTROLLER_POS_X - centerX, TEXT_L2_Y = -7.0f + CONTROLLER_POS_Y - centerY;
|
||||
float TEXT_L1_X = 2.0f + CONTROLLER_POS_X - centerX, TEXT_L1_Y = 25.0f + CONTROLLER_POS_Y - centerY, TEXT_L1_Y_VEH = 3.0f + TEXT_L1_Y;
|
||||
float TEXT_DPAD_X = 2.0f + CONTROLLER_POS_X - centerX, TEXT_DPAD_Y = 65.0f + CONTROLLER_POS_Y - centerY;
|
||||
float TEXT_LSTICK_X = 2.0f + CONTROLLER_POS_X - centerX, TEXT_LSTICK_Y = 101.0f + CONTROLLER_POS_Y - centerY;
|
||||
float TEXT_SELECT_X = 382.0f + CONTROLLER_POS_X - centerX, TEXT_SELECT_Y = 141.0f + CONTROLLER_POS_Y - centerY;
|
||||
float TEXT_START_X = 382.0f + CONTROLLER_POS_X - centerX, TEXT_START_Y = 124.0f + CONTROLLER_POS_Y - centerY;
|
||||
float TEXT_R2_X = 274.0F + CONTROLLER_POS_X - centerX, TEXT_R2_Y = -7.0f + CONTROLLER_POS_Y - centerY;
|
||||
float TEXT_R1_X = 382.0f + CONTROLLER_POS_X - centerX, TEXT_R1_Y = 25.0f + CONTROLLER_POS_Y - centerY;
|
||||
|
||||
float TEXT_SQUARE_X = 382.0f + CONTROLLER_POS_X - centerX, TEXT_SQUARE_Y = 48.0f + CONTROLLER_POS_Y - centerY;
|
||||
float TEXT_TRIANGLE_X = 382.0f + CONTROLLER_POS_X - centerX, TEXT_TRIANGLE_Y = 52.0f + CONTROLLER_POS_Y - centerY;
|
||||
float TEXT_CIRCLE_X = 382.0f + CONTROLLER_POS_X - centerX, TEXT_CIRCLE_Y = 65.0f + CONTROLLER_POS_Y - centerY;
|
||||
float TEXT_CROSS_X = 382.0f + CONTROLLER_POS_X - centerX, TEXT_CROSS_Y = 78.0f + CONTROLLER_POS_Y - centerY;
|
||||
float TEXT_RSTICK_X = 382.0f + CONTROLLER_POS_X - centerX, TEXT_RSTICK_Y = 102.0f + CONTROLLER_POS_Y - centerY;
|
||||
float TEXT_R3_X = 382.0f + CONTROLLER_POS_X - centerX, TEXT_R3_Y = 158.0f + CONTROLLER_POS_Y - centerY;
|
||||
float TEXT_L3_X = 2.0f + CONTROLLER_POS_X - centerX, TEXT_L3_Y = 158.0f + CONTROLLER_POS_Y - centerY;
|
||||
float TEXT_L2R2_X = 192.0f + CONTROLLER_POS_X - centerX, TEXT_L2R2_Y = 6.0f + CONTROLLER_POS_Y - centerY;
|
||||
|
||||
switch (m_PrefsControllerType)
|
||||
{
|
||||
case CONTROLLER_DUALSHOCK4:
|
||||
TEXT_L1_Y -= 2.0f;
|
||||
TEXT_R1_Y -= 2.0f;
|
||||
TEXT_L1_Y_VEH = TEXT_L1_Y;
|
||||
TEXT_TRIANGLE_Y += 0.0f;
|
||||
TEXT_CIRCLE_Y += 4.0f;
|
||||
TEXT_CROSS_Y += 7.0f;
|
||||
TEXT_SQUARE_Y -= 3.0f;
|
||||
TEXT_RSTICK_Y += 3.0f;
|
||||
TEXT_R3_Y -= 30.0f;
|
||||
TEXT_DPAD_Y -= 3.0f;
|
||||
TEXT_LSTICK_Y += 3.0f;
|
||||
TEXT_L3_Y -= 30.0f;
|
||||
TEXT_SELECT_X -= 260.0f;
|
||||
TEXT_SELECT_Y += 13.0f;
|
||||
TEXT_START_X -= 198.0f;
|
||||
TEXT_START_Y += 12.0f;
|
||||
break;
|
||||
case CONTROLLER_DUALSHOCK3:
|
||||
TEXT_L1_Y += 4.0f;
|
||||
TEXT_L1_Y_VEH = TEXT_L1_Y;
|
||||
TEXT_TRIANGLE_Y += 5.0f;
|
||||
TEXT_CIRCLE_Y += 9.0f;
|
||||
TEXT_CROSS_Y += 15.0f;
|
||||
TEXT_RSTICK_Y += 17.0f;
|
||||
TEXT_R3_Y -= 17.0f;
|
||||
TEXT_DPAD_Y += 11.0f;
|
||||
TEXT_LSTICK_Y += 17.0f;
|
||||
TEXT_L3_Y -= 17.0f;
|
||||
TEXT_SELECT_X -= 248.0f;
|
||||
TEXT_SELECT_Y -= 112.0f;
|
||||
TEXT_START_X -= 214.0f;
|
||||
TEXT_START_Y += 28.0f;
|
||||
break;
|
||||
case CONTROLLER_XBOX360:
|
||||
TEXT_L2_X += 8.0f;
|
||||
TEXT_R2_X -= 8.0f;
|
||||
TEXT_L1_Y += 15.0f;
|
||||
TEXT_L1_Y_VEH = TEXT_L1_Y;
|
||||
TEXT_R1_Y += 15.0f;
|
||||
TEXT_TRIANGLE_Y += 4.0f;
|
||||
TEXT_CIRCLE_Y += 4.0f;
|
||||
TEXT_CROSS_Y += 4.0f;
|
||||
TEXT_RSTICK_Y += 4.0f;
|
||||
TEXT_R3_Y += 4.0f;
|
||||
TEXT_DPAD_Y += 30.0f;
|
||||
TEXT_LSTICK_Y -= 19.0f;
|
||||
TEXT_L3_X -= 36.0f;
|
||||
TEXT_L2R2_Y += 5.0f;
|
||||
TEXT_SELECT_X += 3.0f;
|
||||
break;
|
||||
};
|
||||
|
||||
if (m_DisplayControllerOnFoot) {
|
||||
switch (CPad::GetPad(0)->Mode) {
|
||||
case 0:
|
||||
CFont::SetRightJustifyOn();
|
||||
switch (m_PrefsLanguage)
|
||||
{
|
||||
case LANGUAGE_FRENCH:
|
||||
case LANGUAGE_SPANISH:
|
||||
TEXT_L2_X -= 45.0f;
|
||||
CFont::SetRightJustifyWrap(MENU_X_LEFT_ALIGNED(X(TEXT_L1_X)) - SCREEN_SCALE_X(85));
|
||||
break;
|
||||
default:
|
||||
CFont::SetRightJustifyWrap(0);
|
||||
break;
|
||||
}
|
||||
CFont::SetRightJustifyWrap(0);
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_L1_X)), MENU_Y(Y(TEXT_L1_Y)), TheText.Get("FEC_LOF"));
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_DPAD_X)), MENU_Y(Y(TEXT_DPAD_Y)), TheText.Get("FEC_MOV"));
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_LSTICK_X)), MENU_Y(Y(TEXT_LSTICK_Y)), TheText.Get("FEC_MOV"));
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_LSTICK_X)), MENU_Y(Y(TEXT_R3_Y)), TheText.Get("FEC_CR3"));
|
||||
CFont::SetRightJustifyOn();
|
||||
CFont::SetCentreOn();
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_R2_X)), MENU_Y(Y(TEXT_R2_Y)), TheText.Get("FEC_CWR"));
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_L2_X)), MENU_Y(Y(TEXT_L2_Y)), TheText.Get("FEC_CWL"));
|
||||
switch (m_PrefsLanguage)
|
||||
{
|
||||
case LANGUAGE_GERMAN:
|
||||
TEXT_SELECT_X += 20.0f;
|
||||
break;
|
||||
case LANGUAGE_SPANISH:
|
||||
TEXT_SELECT_X += 15.0f;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
CFont::SetJustifyOn();
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_SELECT_X)), MENU_Y(Y(TEXT_SELECT_Y)), TheText.Get("FEC_CAM"));
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_START_X)), MENU_Y(Y(TEXT_START_Y)), TheText.Get("FEC_PAU"));
|
||||
switch (m_PrefsLanguage)
|
||||
{
|
||||
case LANGUAGE_FRENCH:
|
||||
case LANGUAGE_SPANISH:
|
||||
TEXT_R2_X += 30.0f;
|
||||
CFont::SetJustifyOff();
|
||||
CFont::SetWrapx(MENU_X_LEFT_ALIGNED(X(TEXT_R2_X)) + SCREEN_SCALE_X(120));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
CFont::SetJustifyOn();
|
||||
CFont::SetWrapx(SCREEN_WIDTH);
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_R1_X)), MENU_Y(Y(TEXT_R1_Y)), TheText.Get("FEC_TAR"));
|
||||
CFont::SetRightJustifyOn();
|
||||
CFont::SetJustifyOn();
|
||||
CFont::PrintStringFromBottom(MENU_X_LEFT_ALIGNED(X(TEXT_SQUARE_X)), MENU_Y(Y(TEXT_SQUARE_Y)), TheText.Get("FEC_JUM"));
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_TRIANGLE_X)), MENU_Y(Y(TEXT_TRIANGLE_Y)), TheText.Get("FEC_ENV"));
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_CIRCLE_X)), MENU_Y(Y(TEXT_CIRCLE_Y)), TheText.Get("FEC_ATT"));
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_CROSS_X)), MENU_Y(Y(TEXT_CROSS_Y)), TheText.Get("FEC_RUN"));
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_RSTICK_X)), MENU_Y(Y(TEXT_RSTICK_Y)), TheText.Get("FEC_FPC"));
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_R3_X)), MENU_Y(Y(TEXT_R3_Y)), TheText.Get("FEC_LB3"));
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_R3_X)), MENU_Y(Y(TEXT_R3_Y + 13.0f)), TheText.Get("FEC_R3"));
|
||||
break;
|
||||
case 1:
|
||||
CFont::SetRightJustifyOn();
|
||||
switch (m_PrefsLanguage)
|
||||
{
|
||||
case LANGUAGE_FRENCH:
|
||||
case LANGUAGE_SPANISH:
|
||||
TEXT_L2_X -= 45.0f;
|
||||
CFont::SetRightJustifyWrap(MENU_X_LEFT_ALIGNED(X(TEXT_L1_X)) - SCREEN_SCALE_X(85));
|
||||
break;
|
||||
default:
|
||||
CFont::SetRightJustifyWrap(0);
|
||||
break;
|
||||
}
|
||||
CFont::SetRightJustifyWrap(0);
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_L1_X)), MENU_Y(Y(TEXT_L1_Y)), TheText.Get("FEC_LOF"));
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_DPAD_X)), MENU_Y(Y(TEXT_DPAD_Y)), TheText.Get("FEC_CAM"));
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_LSTICK_X)), MENU_Y(Y(TEXT_LSTICK_Y)), TheText.Get("FEC_MOV"));
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_LSTICK_X)), MENU_Y(Y(TEXT_R3_Y)), TheText.Get("FEC_CR3"));
|
||||
CFont::SetCentreOn();
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_R2_X)), MENU_Y(Y(TEXT_R2_Y)), TheText.Get("FEC_CWR"));
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_L2_X)), MENU_Y(Y(TEXT_L2_Y)), TheText.Get("FEC_CWL"));
|
||||
switch (m_PrefsLanguage)
|
||||
{
|
||||
case LANGUAGE_GERMAN:
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_SELECT_X)), MENU_Y(Y(TEXT_SELECT_Y)), TheText.Get("FEC_NA"));
|
||||
break;
|
||||
default:
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_SELECT_X += 10.0f)), MENU_Y(Y(TEXT_SELECT_Y)), TheText.Get("FEC_NA"));
|
||||
break;
|
||||
}
|
||||
CFont::SetJustifyOn();
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_START_X)), MENU_Y(Y(TEXT_START_Y)), TheText.Get("FEC_PAU"));
|
||||
switch (m_PrefsLanguage)
|
||||
{
|
||||
case LANGUAGE_FRENCH:
|
||||
case LANGUAGE_SPANISH:
|
||||
TEXT_R2_X += 30.0f;
|
||||
CFont::SetJustifyOff();
|
||||
CFont::SetWrapx(MENU_X_LEFT_ALIGNED(X(TEXT_R2_X)) + SCREEN_SCALE_X(120));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
CFont::SetJustifyOn();
|
||||
CFont::SetWrapx(SCREEN_WIDTH);
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_R1_X)), MENU_Y(Y(TEXT_R1_Y)), TheText.Get("FEC_TAR"));
|
||||
CFont::SetRightJustifyOn();
|
||||
CFont::SetJustifyOn();
|
||||
CFont::PrintStringFromBottom(MENU_X_LEFT_ALIGNED(X(TEXT_SQUARE_X)), MENU_Y(Y(TEXT_SQUARE_Y)), TheText.Get("FEC_JUM"));
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_TRIANGLE_X)), MENU_Y(Y(TEXT_TRIANGLE_Y)), TheText.Get("FEC_ENV"));
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_CIRCLE_X)), MENU_Y(Y(TEXT_CIRCLE_Y)), TheText.Get("FEC_ATT"));
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_CROSS_X)), MENU_Y(Y(TEXT_CROSS_Y)), TheText.Get("FEC_RUN"));
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_RSTICK_X)), MENU_Y(Y(TEXT_RSTICK_Y)), TheText.Get("FEC_FPC"));
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_R3_X)), MENU_Y(Y(TEXT_R3_Y)), TheText.Get("FEC_LB3"));
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_R3_X)), MENU_Y(Y(TEXT_R3_Y + 13.0f)), TheText.Get("FEC_R3"));
|
||||
break;
|
||||
case 2:
|
||||
CFont::SetRightJustifyOn();
|
||||
switch (m_PrefsLanguage)
|
||||
{
|
||||
case LANGUAGE_FRENCH:
|
||||
case LANGUAGE_SPANISH:
|
||||
TEXT_L2_X -= 45.0f;
|
||||
CFont::SetRightJustifyWrap(MENU_X_LEFT_ALIGNED(X(TEXT_L1_X)) - SCREEN_SCALE_X(85));
|
||||
break;
|
||||
default:
|
||||
CFont::SetRightJustifyWrap(0);
|
||||
break;
|
||||
}
|
||||
CFont::SetRightJustifyWrap(0);
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_L1_X)), MENU_Y(Y(TEXT_L1_Y)), TheText.Get("FEC_ENV"));
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_DPAD_X)), MENU_Y(Y(TEXT_DPAD_Y)), TheText.Get("FEC_MOV"));
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_LSTICK_X)), MENU_Y(Y(TEXT_LSTICK_Y)), TheText.Get("FEC_MOV"));
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_LSTICK_X)), MENU_Y(Y(TEXT_R3_Y)), TheText.Get("FEC_CR3"));
|
||||
CFont::SetRightJustifyOn();
|
||||
CFont::SetCentreOn();
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_R2_X)), MENU_Y(Y(TEXT_R2_Y)), TheText.Get("FEC_CWR"));
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_L2_X)), MENU_Y(Y(TEXT_L2_Y)), TheText.Get("FEC_CWL"));
|
||||
switch (m_PrefsLanguage)
|
||||
{
|
||||
case LANGUAGE_GERMAN:
|
||||
TEXT_SELECT_X += 20.0f;
|
||||
break;
|
||||
case LANGUAGE_SPANISH:
|
||||
TEXT_SELECT_X += 15.0f;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
CFont::SetJustifyOn();
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_SELECT_X)), MENU_Y(Y(TEXT_SELECT_Y)), TheText.Get("FEC_CAM"));
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_START_X)), MENU_Y(Y(TEXT_START_Y)), TheText.Get("FEC_PAU"));
|
||||
switch (m_PrefsLanguage)
|
||||
{
|
||||
case LANGUAGE_FRENCH:
|
||||
case LANGUAGE_SPANISH:
|
||||
TEXT_R2_X += 30.0f;
|
||||
CFont::SetJustifyOff();
|
||||
CFont::SetWrapx(MENU_X_LEFT_ALIGNED(X(TEXT_R2_X)) + SCREEN_SCALE_X(120));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
CFont::SetJustifyOn();
|
||||
CFont::SetWrapx(SCREEN_WIDTH);
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_R1_X)), MENU_Y(Y(TEXT_R1_Y)), TheText.Get("FEC_TAR"));
|
||||
CFont::SetRightJustifyOn();
|
||||
CFont::SetJustifyOn();
|
||||
CFont::PrintStringFromBottom(MENU_X_LEFT_ALIGNED(X(TEXT_SQUARE_X)), MENU_Y(Y(TEXT_SQUARE_Y)), TheText.Get("FEC_JUM"));
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_TRIANGLE_X)), MENU_Y(Y(TEXT_TRIANGLE_Y)), TheText.Get("FEC_LOF"));
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_CIRCLE_X)), MENU_Y(Y(TEXT_CIRCLE_Y)), TheText.Get("FEC_RUN"));
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_CROSS_X)), MENU_Y(Y(TEXT_CROSS_Y)), TheText.Get("FEC_ATT"));
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_RSTICK_X)), MENU_Y(Y(TEXT_RSTICK_Y)), TheText.Get("FEC_FPC"));
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_R3_X)), MENU_Y(Y(TEXT_R3_Y)), TheText.Get("FEC_LB3"));
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_R3_X)), MENU_Y(Y(TEXT_R3_Y + 13.0f)), TheText.Get("FEC_R3"));
|
||||
break;
|
||||
case 3:
|
||||
CFont::SetRightJustifyOn();
|
||||
switch (m_PrefsLanguage)
|
||||
{
|
||||
case LANGUAGE_FRENCH:
|
||||
case LANGUAGE_SPANISH:
|
||||
TEXT_L2_X -= 45.0f;
|
||||
CFont::SetRightJustifyWrap(MENU_X_LEFT_ALIGNED(X(TEXT_L1_X)) - SCREEN_SCALE_X(85));
|
||||
break;
|
||||
default:
|
||||
CFont::SetRightJustifyWrap(0);
|
||||
break;
|
||||
}
|
||||
CFont::SetRightJustifyWrap(0);
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_L1_X)), MENU_Y(Y(TEXT_L1_Y)), TheText.Get("FEC_TAR"));
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_DPAD_X)), MENU_Y(Y(TEXT_DPAD_Y)), TheText.Get("FEC_NA"));
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_LSTICK_X)), MENU_Y(Y(TEXT_LSTICK_Y)), TheText.Get("FEC_MOV"));
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_LSTICK_X)), MENU_Y(Y(TEXT_R3_Y)), TheText.Get("FEC_CR3"));
|
||||
CFont::SetRightJustifyOn();
|
||||
CFont::SetCentreOn();
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_R2_X)), MENU_Y(Y(TEXT_R2_Y)), TheText.Get("FEC_CWR"));
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_L2_X)), MENU_Y(Y(TEXT_L2_Y)), TheText.Get("FEC_CWL"));
|
||||
switch (m_PrefsLanguage)
|
||||
{
|
||||
case LANGUAGE_GERMAN:
|
||||
TEXT_SELECT_X += 20.0f;
|
||||
break;
|
||||
case LANGUAGE_SPANISH:
|
||||
TEXT_SELECT_X += 15.0f;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
CFont::SetJustifyOn();
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_SELECT_X)), MENU_Y(Y(TEXT_SELECT_Y)), TheText.Get("FEC_CAM"));
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_START_X)), MENU_Y(Y(TEXT_START_Y)), TheText.Get("FEC_PAU"));
|
||||
switch (m_PrefsLanguage)
|
||||
{
|
||||
case LANGUAGE_FRENCH:
|
||||
case LANGUAGE_SPANISH:
|
||||
TEXT_R2_X += 30.0f;
|
||||
CFont::SetJustifyOff();
|
||||
CFont::SetWrapx(MENU_X_LEFT_ALIGNED(X(TEXT_R2_X)) + SCREEN_SCALE_X(120));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
CFont::SetJustifyOn();
|
||||
CFont::SetWrapx(SCREEN_WIDTH);
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_R1_X)), MENU_Y(Y(TEXT_R1_Y)), TheText.Get("FEC_ATT"));
|
||||
CFont::SetRightJustifyOn();
|
||||
CFont::SetJustifyOn();
|
||||
CFont::PrintStringFromBottom(MENU_X_LEFT_ALIGNED(X(TEXT_SQUARE_X)), MENU_Y(Y(TEXT_SQUARE_Y)), TheText.Get("FEC_JUM"));
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_TRIANGLE_X)), MENU_Y(Y(TEXT_TRIANGLE_Y)), TheText.Get("FEC_ENV"));
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_CIRCLE_X)), MENU_Y(Y(TEXT_CIRCLE_Y)), TheText.Get("FEC_LOF"));
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_CROSS_X)), MENU_Y(Y(TEXT_CROSS_Y)), TheText.Get("FEC_RUN"));
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_RSTICK_X)), MENU_Y(Y(TEXT_RSTICK_Y)), TheText.Get("FEC_FPC"));
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_R3_X)), MENU_Y(Y(TEXT_R3_Y)), TheText.Get("FEC_LB3"));
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_R3_X)), MENU_Y(Y(TEXT_R3_Y + 13.0f)), TheText.Get("FEC_R3"));
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
CFont::SetCentreOn();
|
||||
switch (m_PrefsLanguage)
|
||||
{
|
||||
case LANGUAGE_ITALIAN:
|
||||
if (m_PrefsControllerType != CONTROLLER_XBOX360)
|
||||
break;
|
||||
case LANGUAGE_FRENCH:
|
||||
case LANGUAGE_GERMAN:
|
||||
CFont::SetScale(MENU_X(SMALLESTTEXT_X_SCALE * 2 * scale * 0.65f), MENU_Y(SMALLESTTEXT_Y_SCALE * scale * 0.65f));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(0.0f)), MENU_Y(Y(TEXT_L2R2_Y)), TheText.Get("FEC_LB"));
|
||||
CFont::SetScale(MENU_X(SMALLESTTEXT_X_SCALE * 2 * scale * 0.9f), MENU_Y(SMALLESTTEXT_Y_SCALE* scale * 0.9f));
|
||||
switch (CPad::GetPad(0)->Mode) {
|
||||
case 0:
|
||||
CFont::SetRightJustifyOn();
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_L1_X)), MENU_Y(Y(TEXT_L1_Y_VEH)), TheText.Get("FEC_RSC"));
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_DPAD_X)), MENU_Y(Y(TEXT_DPAD_Y)), TheText.Get("FEC_VES"));
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_LSTICK_X)), MENU_Y(Y(TEXT_LSTICK_Y)), TheText.Get("FEC_VES"));
|
||||
CFont::SetRightJustifyOn();
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_L3_X)), MENU_Y(Y(TEXT_L3_Y)), TheText.Get("FEC_HO3"));
|
||||
CFont::SetCentreOn();
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_L2_X)), MENU_Y(Y(TEXT_L2_Y)), TheText.Get("FEC_LL"));
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_R2_X)), MENU_Y(Y(TEXT_R2_Y)), TheText.Get("FEC_LR"));
|
||||
switch (m_PrefsLanguage)
|
||||
{
|
||||
case LANGUAGE_FRENCH:
|
||||
TEXT_SELECT_X -= 5.0f;
|
||||
break;
|
||||
case LANGUAGE_GERMAN:
|
||||
TEXT_SELECT_X += 20.0f;
|
||||
break;
|
||||
case LANGUAGE_SPANISH:
|
||||
TEXT_SELECT_X += 15.0f;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
CFont::SetRightJustifyWrap(MENU_X_LEFT_ALIGNED(X(TEXT_SELECT_X)) - SCREEN_SCALE_X(80));
|
||||
CFont::SetJustifyOn();
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_SELECT_X)), MENU_Y(Y(TEXT_SELECT_Y)), TheText.Get("FEC_CAM"));
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_START_X)), MENU_Y(Y(TEXT_START_Y)), TheText.Get("FEC_PAU"));
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_R1_X)), MENU_Y(Y(TEXT_R1_Y)), TheText.Get("FEC_HAB"));
|
||||
CFont::SetJustifyOn();
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_TRIANGLE_X)), MENU_Y(Y(TEXT_TRIANGLE_Y)), TheText.Get("FEC_EXV"));
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_CIRCLE_X)), MENU_Y(Y(TEXT_CIRCLE_Y)), TheText.Get("FEC_CAW"));
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_CROSS_X)), MENU_Y(Y(TEXT_CROSS_Y)), TheText.Get("FEC_ACC"));
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_RSTICK_X)), MENU_Y(Y(TEXT_RSTICK_Y)), TheText.Get("FEC_TUC"));
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_R3_X)), MENU_Y(Y(TEXT_R3_Y)), TheText.Get("FEC_SM3"));
|
||||
CFont::SetJustifyOn();
|
||||
switch (m_PrefsControllerType)
|
||||
{
|
||||
case CONTROLLER_XBOXONE:
|
||||
case CONTROLLER_XBOX360:
|
||||
CFont::SetScale(MENU_X(SMALLESTTEXT_X_SCALE * 2 * scale * 0.65f), MENU_Y(SMALLESTTEXT_Y_SCALE * scale * 0.65f));
|
||||
switch (m_PrefsLanguage)
|
||||
{
|
||||
case LANGUAGE_FRENCH:
|
||||
TEXT_SQUARE_X += 3.0f;
|
||||
CFont::SetRightJustifyWrap(MENU_X_LEFT_ALIGNED(X(TEXT_SQUARE_X)) - SCREEN_SCALE_X(90));
|
||||
break;
|
||||
case LANGUAGE_GERMAN:
|
||||
case LANGUAGE_SPANISH:
|
||||
TEXT_SQUARE_X += 18.0f;
|
||||
CFont::SetRightJustifyWrap(MENU_X_LEFT_ALIGNED(X(TEXT_SQUARE_X)) - SCREEN_SCALE_X(90));
|
||||
break;
|
||||
default:
|
||||
CFont::SetRightJustifyWrap(MENU_X_LEFT_ALIGNED(X(TEXT_SQUARE_X)) - SCREEN_SCALE_X(60));
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
switch (m_PrefsLanguage)
|
||||
{
|
||||
case LANGUAGE_FRENCH:
|
||||
TEXT_SQUARE_X -= 15.0f;
|
||||
TEXT_SQUARE_Y += 5.0f;
|
||||
CFont::SetScale(MENU_X(SMALLESTTEXT_X_SCALE * 2 * scale * 0.65f), MENU_Y(SMALLESTTEXT_Y_SCALE * scale * 0.65f));
|
||||
CFont::SetRightJustifyWrap(MENU_X_LEFT_ALIGNED(X(TEXT_SQUARE_X)) - SCREEN_SCALE_X(60));
|
||||
break;
|
||||
case LANGUAGE_GERMAN:
|
||||
TEXT_SQUARE_X -= 15.0f;
|
||||
TEXT_SQUARE_Y += 10.0f;
|
||||
CFont::SetScale(MENU_X(SMALLESTTEXT_X_SCALE * 2 * scale * 0.65f), MENU_Y(SMALLESTTEXT_Y_SCALE* scale * 0.65f));
|
||||
CFont::SetRightJustifyWrap(MENU_X_LEFT_ALIGNED(X(TEXT_SQUARE_X)) - SCREEN_SCALE_X(60));
|
||||
break;
|
||||
case LANGUAGE_SPANISH:
|
||||
TEXT_SQUARE_X += 15.0f;
|
||||
case LANGUAGE_ITALIAN:
|
||||
CFont::SetScale(MENU_X(SMALLESTTEXT_X_SCALE * 2 * scale * 0.65f), MENU_Y(SMALLESTTEXT_Y_SCALE * scale * 0.65f));
|
||||
default:
|
||||
CFont::SetRightJustifyWrap(MENU_X_LEFT_ALIGNED(X(TEXT_SQUARE_X)) - SCREEN_SCALE_X(100));
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
CFont::PrintStringFromBottom(MENU_X_LEFT_ALIGNED(X(TEXT_SQUARE_X)), MENU_Y(Y(TEXT_SQUARE_Y)), TheText.Get("FEC_BRA"));
|
||||
break;
|
||||
case 1:
|
||||
CFont::SetRightJustifyOn();
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_L1_X)), MENU_Y(Y(TEXT_L1_Y_VEH)), TheText.Get("FEC_HOR"));
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_DPAD_X)), MENU_Y(Y(TEXT_DPAD_Y)), TheText.Get("FEC_CAM"));
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_LSTICK_X)), MENU_Y(Y(TEXT_LSTICK_Y)), TheText.Get("FEC_VES"));
|
||||
CFont::SetRightJustifyOn();
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_L3_X)), MENU_Y(Y(TEXT_L3_Y)), TheText.Get("FEC_NA"));
|
||||
CFont::SetCentreOn();
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_L2_X)), MENU_Y(Y(TEXT_L2_Y)), TheText.Get("FEC_LL"));
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_R2_X)), MENU_Y(Y(TEXT_R2_Y)), TheText.Get("FEC_LR"));
|
||||
switch (m_PrefsLanguage)
|
||||
{
|
||||
case LANGUAGE_GERMAN:
|
||||
TEXT_SELECT_X += 20.0f;
|
||||
break;
|
||||
case LANGUAGE_SPANISH:
|
||||
TEXT_SELECT_X += 12.0f;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
CFont::SetRightJustifyWrap(MENU_X_LEFT_ALIGNED(X(TEXT_SELECT_X)) - SCREEN_SCALE_X(80));
|
||||
CFont::SetJustifyOn();
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_SELECT_X)), MENU_Y(Y(TEXT_SELECT_Y)), TheText.Get("FEC_RSC"));
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_START_X)), MENU_Y(Y(TEXT_START_Y)), TheText.Get("FEC_PAU"));
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_R1_X)), MENU_Y(Y(TEXT_R1_Y)), TheText.Get("FEC_HAB"));
|
||||
CFont::SetJustifyOn();
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_TRIANGLE_X)), MENU_Y(Y(TEXT_TRIANGLE_Y)), TheText.Get("FEC_EXV"));
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_CIRCLE_X)), MENU_Y(Y(TEXT_CIRCLE_Y)), TheText.Get("FEC_CAW"));
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_CROSS_X)), MENU_Y(Y(TEXT_CROSS_Y)), TheText.Get("FEC_ACC"));
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_RSTICK_X)), MENU_Y(Y(TEXT_RSTICK_Y)), TheText.Get("FEC_TUC"));
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_R3_X)), MENU_Y(Y(TEXT_R3_Y)), TheText.Get("FEC_SM3"));
|
||||
CFont::SetJustifyOn();
|
||||
switch (m_PrefsControllerType)
|
||||
{
|
||||
case CONTROLLER_XBOXONE:
|
||||
case CONTROLLER_XBOX360:
|
||||
CFont::SetScale(MENU_X(SMALLESTTEXT_X_SCALE * 2 * scale * 0.65f), MENU_Y(SMALLESTTEXT_Y_SCALE * scale * 0.65f));
|
||||
switch (m_PrefsLanguage)
|
||||
{
|
||||
case LANGUAGE_FRENCH:
|
||||
TEXT_SQUARE_X += 3.0f;
|
||||
CFont::SetRightJustifyWrap(MENU_X_LEFT_ALIGNED(X(TEXT_SQUARE_X)) - SCREEN_SCALE_X(90));
|
||||
break;
|
||||
case LANGUAGE_GERMAN:
|
||||
case LANGUAGE_SPANISH:
|
||||
TEXT_SQUARE_X += 18.0f;
|
||||
CFont::SetRightJustifyWrap(MENU_X_LEFT_ALIGNED(X(TEXT_SQUARE_X)) - SCREEN_SCALE_X(90));
|
||||
break;
|
||||
default:
|
||||
CFont::SetRightJustifyWrap(MENU_X_LEFT_ALIGNED(X(TEXT_SQUARE_X)) - SCREEN_SCALE_X(60));
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
switch (m_PrefsLanguage)
|
||||
{
|
||||
case LANGUAGE_FRENCH:
|
||||
TEXT_SQUARE_X -= 15.0f;
|
||||
TEXT_SQUARE_Y += 5.0f;
|
||||
CFont::SetScale(MENU_X(SMALLESTTEXT_X_SCALE * 2 * scale * 0.65f), MENU_Y(SMALLESTTEXT_Y_SCALE * scale * 0.65f));
|
||||
CFont::SetRightJustifyWrap(MENU_X_LEFT_ALIGNED(X(TEXT_SQUARE_X)) - SCREEN_SCALE_X(60));
|
||||
break;
|
||||
case LANGUAGE_GERMAN:
|
||||
TEXT_SQUARE_X -= 15.0f;
|
||||
TEXT_SQUARE_Y += 10.0f;
|
||||
CFont::SetScale(MENU_X(SMALLESTTEXT_X_SCALE * 2 * scale * 0.65f), MENU_Y(SMALLESTTEXT_Y_SCALE * scale * 0.65f));
|
||||
CFont::SetRightJustifyWrap(MENU_X_LEFT_ALIGNED(X(TEXT_SQUARE_X)) - SCREEN_SCALE_X(60));
|
||||
break;
|
||||
case LANGUAGE_SPANISH:
|
||||
TEXT_SQUARE_X += 15.0f;
|
||||
case LANGUAGE_ITALIAN:
|
||||
CFont::SetScale(MENU_X(SMALLESTTEXT_X_SCALE * 2 * scale * 0.65f), MENU_Y(SMALLESTTEXT_Y_SCALE * scale * 0.65f));
|
||||
default:
|
||||
CFont::SetRightJustifyWrap(MENU_X_LEFT_ALIGNED(X(TEXT_SQUARE_X)) - SCREEN_SCALE_X(100));
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
CFont::PrintStringFromBottom(MENU_X_LEFT_ALIGNED(X(TEXT_SQUARE_X)), MENU_Y(Y(TEXT_SQUARE_Y)), TheText.Get("FEC_BRA"));
|
||||
break;
|
||||
case 2:
|
||||
CFont::SetRightJustifyOn();
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_L1_X)), MENU_Y(Y(TEXT_L1_Y_VEH)), TheText.Get("FEC_EXV"));
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_DPAD_X)), MENU_Y(Y(TEXT_DPAD_Y)), TheText.Get("FEC_VES"));
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_LSTICK_X)), MENU_Y(Y(TEXT_LSTICK_Y)), TheText.Get("FEC_VES"));
|
||||
CFont::SetRightJustifyOn();
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_L3_X)), MENU_Y(Y(TEXT_L3_Y)), TheText.Get("FEC_RS3"));
|
||||
CFont::SetCentreOn();
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_L2_X)), MENU_Y(Y(TEXT_L2_Y)), TheText.Get("FEC_LL"));
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_R2_X)), MENU_Y(Y(TEXT_R2_Y)), TheText.Get("FEC_LR"));
|
||||
switch (m_PrefsLanguage)
|
||||
{
|
||||
case LANGUAGE_FRENCH:
|
||||
TEXT_SELECT_X -= 5.0f;
|
||||
break;
|
||||
case LANGUAGE_GERMAN:
|
||||
TEXT_SELECT_X += 20.0f;
|
||||
break;
|
||||
case LANGUAGE_SPANISH:
|
||||
TEXT_SELECT_X += 15.0f;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
CFont::SetRightJustifyWrap(MENU_X_LEFT_ALIGNED(X(TEXT_SELECT_X)) - SCREEN_SCALE_X(80));
|
||||
CFont::SetJustifyOn();
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_SELECT_X)), MENU_Y(Y(TEXT_SELECT_Y)), TheText.Get("FEC_CAM"));
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_START_X)), MENU_Y(Y(TEXT_START_Y)), TheText.Get("FEC_PAU"));
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_R1_X)), MENU_Y(Y(TEXT_R1_Y)), TheText.Get("FEC_HOR"));
|
||||
CFont::SetJustifyOn();
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_TRIANGLE_X)), MENU_Y(Y(TEXT_TRIANGLE_Y)), TheText.Get("FEC_HAB"));
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_CIRCLE_X)), MENU_Y(Y(TEXT_CIRCLE_Y)), TheText.Get("FEC_CAW"));
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_CROSS_X)), MENU_Y(Y(TEXT_CROSS_Y)), TheText.Get("FEC_ACC"));
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_RSTICK_X)), MENU_Y(Y(TEXT_RSTICK_Y)), TheText.Get("FEC_TUC"));
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_R3_X)), MENU_Y(Y(TEXT_R3_Y)), TheText.Get("FEC_SM3"));
|
||||
CFont::SetJustifyOn();
|
||||
switch (m_PrefsControllerType)
|
||||
{
|
||||
case CONTROLLER_XBOXONE:
|
||||
case CONTROLLER_XBOX360:
|
||||
CFont::SetScale(MENU_X(SMALLESTTEXT_X_SCALE * 2 * scale * 0.65f), MENU_Y(SMALLESTTEXT_Y_SCALE * scale * 0.65f));
|
||||
switch (m_PrefsLanguage)
|
||||
{
|
||||
case LANGUAGE_FRENCH:
|
||||
TEXT_SQUARE_X += 3.0f;
|
||||
CFont::SetRightJustifyWrap(MENU_X_LEFT_ALIGNED(X(TEXT_SQUARE_X)) - SCREEN_SCALE_X(90));
|
||||
break;
|
||||
case LANGUAGE_GERMAN:
|
||||
case LANGUAGE_SPANISH:
|
||||
TEXT_SQUARE_X += 18.0f;
|
||||
CFont::SetRightJustifyWrap(MENU_X_LEFT_ALIGNED(X(TEXT_SQUARE_X)) - SCREEN_SCALE_X(90));
|
||||
break;
|
||||
default:
|
||||
CFont::SetRightJustifyWrap(MENU_X_LEFT_ALIGNED(X(TEXT_SQUARE_X)) - SCREEN_SCALE_X(60));
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
switch (m_PrefsLanguage)
|
||||
{
|
||||
case LANGUAGE_FRENCH:
|
||||
TEXT_SQUARE_X -= 15.0f;
|
||||
TEXT_SQUARE_Y += 5.0f;
|
||||
CFont::SetScale(MENU_X(SMALLESTTEXT_X_SCALE * 2 * scale * 0.65f), MENU_Y(SMALLESTTEXT_Y_SCALE * scale * 0.65f));
|
||||
CFont::SetRightJustifyWrap(MENU_X_LEFT_ALIGNED(X(TEXT_SQUARE_X)) - SCREEN_SCALE_X(60));
|
||||
break;
|
||||
case LANGUAGE_GERMAN:
|
||||
TEXT_SQUARE_X -= 15.0f;
|
||||
TEXT_SQUARE_Y += 10.0f;
|
||||
CFont::SetScale(MENU_X(SMALLESTTEXT_X_SCALE * 2 * scale * 0.65f), MENU_Y(SMALLESTTEXT_Y_SCALE * scale * 0.65f));
|
||||
CFont::SetRightJustifyWrap(MENU_X_LEFT_ALIGNED(X(TEXT_SQUARE_X)) - SCREEN_SCALE_X(60));
|
||||
break;
|
||||
case LANGUAGE_SPANISH:
|
||||
TEXT_SQUARE_X += 15.0f;
|
||||
case LANGUAGE_ITALIAN:
|
||||
CFont::SetScale(MENU_X(SMALLESTTEXT_X_SCALE * 2 * scale * 0.65f), MENU_Y(SMALLESTTEXT_Y_SCALE * scale * 0.65f));
|
||||
default:
|
||||
CFont::SetRightJustifyWrap(MENU_X_LEFT_ALIGNED(X(TEXT_SQUARE_X)) - SCREEN_SCALE_X(100));
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
CFont::PrintStringFromBottom(MENU_X_LEFT_ALIGNED(X(TEXT_SQUARE_X)), MENU_Y(Y(TEXT_SQUARE_Y)), TheText.Get("FEC_BRA"));
|
||||
break;
|
||||
case 3:
|
||||
CFont::SetRightJustifyOn();
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_L1_X)), MENU_Y(Y(TEXT_L1_Y_VEH)), TheText.Get("FEC_HAB"));
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_DPAD_X)), MENU_Y(Y(TEXT_DPAD_Y)), TheText.Get("FEC_TUC"));
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_LSTICK_X)), MENU_Y(Y(TEXT_LSTICK_Y)), TheText.Get("FEC_VES"));
|
||||
CFont::SetRightJustifyOn();
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_L3_X)), MENU_Y(Y(TEXT_L3_Y)), TheText.Get("FEC_HO3"));
|
||||
CFont::SetCentreOn();
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_L2_X)), MENU_Y(Y(TEXT_L2_Y)), TheText.Get("FEC_LL"));
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_R2_X)), MENU_Y(Y(TEXT_R2_Y)), TheText.Get("FEC_LR"));
|
||||
switch (m_PrefsLanguage)
|
||||
{
|
||||
case LANGUAGE_FRENCH:
|
||||
TEXT_SELECT_X -= 5.0f;
|
||||
break;
|
||||
case LANGUAGE_GERMAN:
|
||||
TEXT_SELECT_X += 20.0f;
|
||||
break;
|
||||
case LANGUAGE_SPANISH:
|
||||
TEXT_SELECT_X += 15.0f;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
CFont::SetRightJustifyWrap(MENU_X_LEFT_ALIGNED(X(TEXT_SELECT_X)) - SCREEN_SCALE_X(80));
|
||||
CFont::SetJustifyOn();
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_SELECT_X)), MENU_Y(Y(TEXT_SELECT_Y)), TheText.Get("FEC_CAM"));
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_START_X)), MENU_Y(Y(TEXT_START_Y)), TheText.Get("FEC_PAU"));
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_R1_X)), MENU_Y(Y(TEXT_R1_Y)), TheText.Get("FEC_CAW"));
|
||||
CFont::SetJustifyOn();
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_TRIANGLE_X)), MENU_Y(Y(TEXT_TRIANGLE_Y)), TheText.Get("FEC_EXV"));
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_CIRCLE_X)), MENU_Y(Y(TEXT_CIRCLE_Y)), TheText.Get("FEC_RSC"));
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_CROSS_X)), MENU_Y(Y(TEXT_CROSS_Y)), TheText.Get("FEC_NA"));
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_RSTICK_X)), MENU_Y(Y(TEXT_RSTICK_Y)), TheText.Get("FEC_ACC"));
|
||||
CFont::PrintString(MENU_X_LEFT_ALIGNED(X(TEXT_R3_X)), MENU_Y(Y(TEXT_R3_Y)), TheText.Get("FEC_BRA"));
|
||||
CFont::SetJustifyOn();
|
||||
CFont::SetRightJustifyWrap(0);
|
||||
switch (m_PrefsControllerType)
|
||||
{
|
||||
case CONTROLLER_XBOXONE:
|
||||
case CONTROLLER_XBOX360:
|
||||
CFont::SetScale(MENU_X(SMALLESTTEXT_X_SCALE * 2 * scale * 0.65f), MENU_Y(SMALLESTTEXT_Y_SCALE * scale * 0.65f));
|
||||
CFont::PrintStringFromBottom(MENU_X_LEFT_ALIGNED(X(TEXT_SQUARE_X)), MENU_Y(Y(TEXT_SQUARE_Y)), TheText.Get("FEC_SMT"));
|
||||
break;
|
||||
default:
|
||||
switch (m_PrefsLanguage)
|
||||
{
|
||||
case LANGUAGE_GERMAN:
|
||||
TEXT_SQUARE_X += 5.0f;
|
||||
case LANGUAGE_FRENCH:
|
||||
case LANGUAGE_ITALIAN:
|
||||
CFont::SetScale(MENU_X(SMALLESTTEXT_X_SCALE * 2 * scale * 0.65f), MENU_Y(SMALLESTTEXT_Y_SCALE * scale * 0.65f));
|
||||
CFont::PrintStringFromBottom(MENU_X_LEFT_ALIGNED(X(TEXT_SQUARE_X)), MENU_Y(Y(TEXT_SQUARE_Y)), TheText.Get("FEC_SMT"));
|
||||
break;
|
||||
default:
|
||||
CFont::PrintStringFromBottom(MENU_X_LEFT_ALIGNED(X(TEXT_SQUARE_X)), MENU_Y(Y(TEXT_SQUARE_Y)), TheText.Get("FEC_SMT"));
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
CFont::SetDropShadowPosition(0); // X
|
||||
|
||||
#undef X
|
||||
#undef Y
|
||||
#elif defined RT
|
||||
// Don't print anything if controller texture is missing
|
||||
if (!m_aFrontEndSprites[MENUSPRITE_CONTROLLER].m_pTexture) return;
|
||||
|
||||
@@ -7386,12 +8089,14 @@ CMenuManager::PrintController(void)
|
||||
void
|
||||
CMenuManager::LoadController(int8 type)
|
||||
{
|
||||
// A controller type saved by the other build variant can be out of range here:
|
||||
// the RT and vanilla controller enums differ in size (vanilla keeps CONTROLLER_XBOX360),
|
||||
// so e.g. Nintendo Switch is index 5 in vanilla but 4 under RT. An out-of-range value
|
||||
// would index controllerTypesPaths/controllerTypes out of bounds -> crash. Clamp it.
|
||||
if (type < 0 || type >= (int8)ARRAY_SIZE(controllerTypesPaths)) {
|
||||
type = CONTROLLER_NINTENDO_SWITCH;
|
||||
// A controller type saved by another build variant can be out of range here, in two
|
||||
// ways: the RT and vanilla enums differ in size (vanilla keeps CONTROLLER_XBOX360),
|
||||
// so e.g. Nintendo Switch is index 5 in vanilla but 4 under RT; and the handhelds
|
||||
// offer fewer types than the .ini may hold. Out of range means controllerTypes read
|
||||
// out of bounds, a pad the menu can no longer select away from, and with it the wrong
|
||||
// button labels and the wrong menu confirm/cancel layout. Clamp it.
|
||||
if (type < 0 || type >= (int8)NUM_MENU_CONTROLLER_TYPES) {
|
||||
type = DEFAULT_CONTROLLER_TYPE;
|
||||
m_PrefsControllerType = type;
|
||||
}
|
||||
|
||||
@@ -7399,12 +8104,12 @@ CMenuManager::LoadController(int8 type)
|
||||
{
|
||||
case CONTROLLER_DUALSHOCK3:
|
||||
case CONTROLLER_DUALSHOCK4:
|
||||
#ifndef RT
|
||||
#ifndef RT_CONTROLLERS
|
||||
case CONTROLLER_DUALSHOCK2: // real DualShock2 uses PlayStation buttons
|
||||
#endif
|
||||
CFont::LoadButtons("MODELS/PS3BTNS.TXD");
|
||||
break;
|
||||
#ifdef RT
|
||||
#ifdef RT_CONTROLLERS
|
||||
case CONTROLLER_DUALSHOCK2: // RT: the DS2 slot is a Switch Pro Controller
|
||||
#endif
|
||||
case CONTROLLER_NINTENDO_SWITCH:
|
||||
|
||||
@@ -729,13 +729,25 @@ public:
|
||||
CONTROLLER_DUALSHOCK2 = 0,
|
||||
CONTROLLER_DUALSHOCK3,
|
||||
CONTROLLER_DUALSHOCK4,
|
||||
#ifndef RT
|
||||
#ifndef RT_CONTROLLERS
|
||||
CONTROLLER_XBOX360,
|
||||
#endif
|
||||
CONTROLLER_XBOXONE,
|
||||
CONTROLLER_NINTENDO_SWITCH,
|
||||
NUM_CONTROLLER_TYPES,
|
||||
};
|
||||
|
||||
#ifdef PSP2
|
||||
#define NUM_MENU_CONTROLLER_TYPES (CMenuManager::CONTROLLER_DUALSHOCK4 + 1) // the Vita itself, plus the DS3/DS4 a PSTV can pair with
|
||||
#define DEFAULT_CONTROLLER_TYPE CMenuManager::CONTROLLER_DUALSHOCK2
|
||||
#elif defined __SWITCH__
|
||||
#define NUM_MENU_CONTROLLER_TYPES CMenuManager::NUM_CONTROLLER_TYPES
|
||||
#define DEFAULT_CONTROLLER_TYPE CMenuManager::CONTROLLER_NINTENDO_SWITCH
|
||||
#else
|
||||
#define NUM_MENU_CONTROLLER_TYPES CMenuManager::NUM_CONTROLLER_TYPES
|
||||
#define DEFAULT_CONTROLLER_TYPE CMenuManager::CONTROLLER_XBOXONE
|
||||
#endif
|
||||
|
||||
int8 m_PrefsControllerType;
|
||||
#endif
|
||||
enum LANGUAGE
|
||||
|
||||
@@ -244,6 +244,14 @@ CGame::InitialiseRenderWare(void)
|
||||
CreateDebugFont();
|
||||
|
||||
#ifdef LIBRW
|
||||
// librw-vita predates the envMap* knobs and only exposes modulateEnvMap.
|
||||
#ifdef PSP2
|
||||
#ifdef PS2_MATFX
|
||||
rw::MatFX::modulateEnvMap = true;
|
||||
#else
|
||||
rw::MatFX::modulateEnvMap = false;
|
||||
#endif
|
||||
#else
|
||||
#ifdef PS2_MATFX
|
||||
rw::MatFX::envMapApplyLight = true;
|
||||
rw::MatFX::envMapUseMatColor = true;
|
||||
@@ -255,6 +263,7 @@ CGame::InitialiseRenderWare(void)
|
||||
#endif
|
||||
rw::RGBA envcol = { 64, 64, 64, 255 };
|
||||
rw::MatFX::envMapColor = envcol;
|
||||
#endif
|
||||
#else
|
||||
#ifdef PS2_MATFX
|
||||
ReplaceMatFxCallback();
|
||||
|
||||
@@ -33,6 +33,10 @@
|
||||
|
||||
// Menu screens array is at the bottom of the file.
|
||||
|
||||
#ifdef PSP2
|
||||
extern bool useRearpad; // touch input: front panel or rear, see crossplatform.cpp
|
||||
#endif
|
||||
|
||||
#ifdef PC_MENU
|
||||
|
||||
#ifdef CUSTOM_FRONTEND_OPTIONS
|
||||
@@ -43,7 +47,9 @@
|
||||
#define VIDEOMODE_SELECTOR
|
||||
#endif
|
||||
|
||||
#ifdef MULTISAMPLING
|
||||
// Not on PSP2: vglInitExtended fixes the level at 4x, so the entry could never
|
||||
// change anything, and stepping through it used to hang the game.
|
||||
#if defined(MULTISAMPLING) && !defined(PSP2)
|
||||
#define MULTISAMPLING_SELECTOR MENUACTION_CFO_DYNAMIC, "FED_AAS", { new CCFODynamic((int8*)&FrontEndMenuManager.m_nPrefsMSAALevel, "Graphics", "MultiSampling", MultiSamplingDraw, MultiSamplingButtonPress) }, 0, 0, MENUALIGN_LEFT,
|
||||
#else
|
||||
#define MULTISAMPLING_SELECTOR
|
||||
@@ -97,7 +103,7 @@
|
||||
#endif
|
||||
|
||||
#ifdef GAMEPAD_MENU
|
||||
#define SELECT_CONTROLLER_TYPE MENUACTION_CFO_SELECT, "FEC_TYP", { new CCFOSelect((int8*)&FrontEndMenuManager.m_PrefsControllerType, "Controller", "Type", controllerTypes, ARRAY_SIZE(controllerTypes), false, ControllerTypeAfterChange) }, 0, 0, MENUALIGN_LEFT,
|
||||
#define SELECT_CONTROLLER_TYPE MENUACTION_CFO_SELECT, "FEC_TYP", { new CCFOSelect((int8*)&FrontEndMenuManager.m_PrefsControllerType, "Controller", "Type", controllerTypes, NUM_MENU_CONTROLLER_TYPES, false, ControllerTypeAfterChange) }, 0, 0, MENUALIGN_LEFT,
|
||||
#else
|
||||
#define SELECT_CONTROLLER_TYPE
|
||||
#endif
|
||||
@@ -232,7 +238,9 @@ void MultiSamplingButtonPress(int8 action) {
|
||||
|
||||
int i = 0;
|
||||
int maxAA = RwD3D8EngineGetMaxMultiSamplingLevels();
|
||||
while (maxAA != 1) {
|
||||
// > 1, not != 1: the PSP2 stub reports 0 levels, and 0 >> 1 stays 0,
|
||||
// so the original condition never terminates and hangs the game.
|
||||
while (maxAA > 1) {
|
||||
i++;
|
||||
maxAA >>= 1;
|
||||
}
|
||||
@@ -380,8 +388,10 @@ void DetectJoystickGoBack() {
|
||||
#endif
|
||||
|
||||
#ifdef GAMEPAD_MENU
|
||||
// Stays parallel to the controller enum in Frontend.h - it is indexed by type, not
|
||||
// iterated. The menu offers only the first NUM_MENU_CONTROLLER_TYPES of them.
|
||||
const char* controllerTypes[] = { "FEC_DS2", "FEC_DS3", "FEC_DS4",
|
||||
#ifndef RT
|
||||
#ifndef RT_CONTROLLERS
|
||||
"FEC_360",
|
||||
#endif
|
||||
"FEC_ONE", "FEC_NSW" };
|
||||
@@ -712,6 +722,12 @@ CMenuScreenCustom aScreens[] = {
|
||||
MENUACTION_CTRLCONFIG, "FEC_CCF", { nil, SAVESLOT_NONE, MENUPAGE_CONTROLLER_SETTINGS }, 40, 76, MENUALIGN_LEFT,
|
||||
MENUACTION_CTRLDISPLAY, "FEC_CDP", { nil, SAVESLOT_NONE, MENUPAGE_CONTROLLER_SETTINGS }, 0, 0, MENUALIGN_LEFT,
|
||||
INVERT_PAD_SELECTOR
|
||||
#ifdef PSP2
|
||||
// The Vita's only extra control option: front touch panel or rear. Placed here
|
||||
// (after invert-look, before vibration) to match the reVC-vita layout. Labelled
|
||||
// from the "PSP2" GXT key in Frontend.cpp::Draw so it reads right in every language.
|
||||
MENUACTION_CFO_SELECT, "PSP2", { new CCFOSelect((int8*)&useRearpad, "Controller", "Rearpad", off_on, 2, false) }, 0, 0, MENUALIGN_LEFT,
|
||||
#endif
|
||||
MENUACTION_CTRLVIBRATION, "FEC_VIB", { nil, SAVESLOT_NONE, MENUPAGE_CONTROLLER_SETTINGS }, 0, 0, MENUALIGN_LEFT,
|
||||
SELECT_CONTROLLER_TYPE
|
||||
MENUACTION_GOBACK, "FEDS_TB", { nil, SAVESLOT_NONE, MENUPAGE_NONE }, 0, 0, MENUALIGN_LEFT,
|
||||
|
||||
@@ -1105,7 +1105,7 @@ void CPad::StartShake_Train(float fX, float fY)
|
||||
static bool MenuUsesNintendoLayout()
|
||||
{
|
||||
return FrontEndMenuManager.m_PrefsControllerType == CMenuManager::CONTROLLER_NINTENDO_SWITCH
|
||||
#ifdef RT
|
||||
#ifdef RT_CONTROLLERS
|
||||
|| FrontEndMenuManager.m_PrefsControllerType == CMenuManager::CONTROLLER_DUALSHOCK2 // RT: DS2 slot is a Switch Pro Controller
|
||||
#endif
|
||||
;
|
||||
@@ -1851,6 +1851,18 @@ void CPad::Update(int16 pad)
|
||||
{
|
||||
OldState = NewState;
|
||||
|
||||
#ifdef PSP2
|
||||
if ( ShakeDur )
|
||||
{
|
||||
ShakeDur = Max((int32_t)ShakeDur - (int32_t)CTimer::GetTimeStepInMilliseconds(), 0);
|
||||
|
||||
SceCtrlActuator handle;
|
||||
handle.small = 0;
|
||||
handle.large = ShakeDur == 0 ? 0 : (unsigned char)ShakeFreq;
|
||||
sceCtrlSetActuator(pad + 1, &handle);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef GTA_PS2
|
||||
bObsoleteControllerMessage = false;
|
||||
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef PSP2
|
||||
extern "C"{
|
||||
#include <math_neon.h>
|
||||
};
|
||||
#endif
|
||||
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
#define _USE_MATH_DEFINES
|
||||
#pragma warning(disable: 4244) // int to float
|
||||
|
||||
@@ -220,10 +220,20 @@ enum Config {
|
||||
// Every other platform builds vanilla. Platform necessities (audio/loading tweaks)
|
||||
// are gated on __SWITCH__ separately, so a vanilla NX build still keeps those.
|
||||
// Kept above VANILLA_DEFINES so the tunables below exist in every configuration.
|
||||
#if defined(__SWITCH__) && !defined(NO_RT)
|
||||
// The Vita ships the same 10thAE resources, and its menu layout is drawn against
|
||||
// them, so it is an RT build too. The controller half of RT stays Switch-only -
|
||||
// see the RT && __SWITCH__ gates around the pad slots.
|
||||
#if (defined(__SWITCH__) || defined(PSP2)) && !defined(NO_RT)
|
||||
#define RT
|
||||
#endif
|
||||
|
||||
// The controller half of RT - dropping the X360 slot and repurposing DS2 as a
|
||||
// Switch Pro Controller - only makes sense on the Switch. The Vita has its own
|
||||
// three pads (DS2 is the console itself) and keeps the upstream slots.
|
||||
#if defined(RT) && defined(__SWITCH__)
|
||||
#define RT_CONTROLLERS
|
||||
#endif
|
||||
|
||||
// RT tunables, centralized so shared code stays readable. RT off = upstream values.
|
||||
#ifdef RT
|
||||
#define RT_RADAR_SCALE 1.3f // enlarge the minimap by 30%
|
||||
@@ -329,18 +339,25 @@ enum Config {
|
||||
#define USE_TXD_CDIMAGE // generate and load textures from txd.img
|
||||
#define PS2_ALPHA_TEST // emulate ps2 alpha test
|
||||
#define IMPROVED_VIDEOMODE // save and load videomode parameters instead of a magic number
|
||||
#ifndef __SWITCH__
|
||||
#define DISABLE_LOADING_SCREEN // disable the loading screen which vastly improves the loading time (kept on Switch to show it)
|
||||
#if !defined(__SWITCH__) && !defined(PSP2)
|
||||
#define DISABLE_LOADING_SCREEN // disable the loading screen which vastly improves the loading time (both handhelds keep it, to show it)
|
||||
#endif
|
||||
#define DISABLE_VSYNC_ON_TEXTURE_CONVERSION // make texture conversion work faster by disabling vsync
|
||||
#ifndef PSP2
|
||||
#define ANISOTROPIC_FILTERING // set all textures to max anisotropic filtering
|
||||
#endif
|
||||
//#define USE_TEXTURE_POOL
|
||||
#ifdef LIBRW
|
||||
#define EXTENDED_COLOURFILTER // more options for colour filter (replaces mblur)
|
||||
// Not on PSP2: librw-vita is an old fork with no setupVertexInput, no three-argument
|
||||
// Shader::create and no UNIFORM_VEC4, so the Neo pipelines and the droplets cannot
|
||||
// build against it. They would also need Cg versions of every shader.
|
||||
#ifndef PSP2
|
||||
#define EXTENDED_PIPELINES // custom render pipelines (includes Neo)
|
||||
#define SCREEN_DROPLETS // neo water droplets
|
||||
#define NEW_RENDERER // leeds-like world rendering, needs librw
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define FIX_SPRITES // fix sprites aspect ratio(moon, coronas, particle etc)
|
||||
|
||||
@@ -472,7 +489,11 @@ static_assert(false, "SUPPORT_XBOX_SCRIPT and SUPPORT_MOBILE_SCRIPT are mutually
|
||||
#define PAUSE_RADIO_IN_FRONTEND // pause radio when game is paused
|
||||
#define ATTACH_RELEASING_SOUNDS_TO_ENTITIES // sounds would follow ped and vehicles coordinates if not being queued otherwise
|
||||
#define USE_TIME_SCALE_FOR_AUDIO // slow down/speed up sounds according to the speed of the game
|
||||
// Not on PSP2: std::thread cannot start here, and with -fno-exceptions the
|
||||
// system_error it throws goes straight to terminate().
|
||||
#ifndef PSP2
|
||||
#define MULTITHREADED_AUDIO // for streams. requires C++11 or later
|
||||
#endif
|
||||
|
||||
#ifdef AUDIO_OPUS
|
||||
#define AUDIO_OAL_USE_OPUS // enable support of opus files
|
||||
|
||||
@@ -355,6 +355,11 @@ RwGrabScreen(RwCamera *camera, RwChar *filename)
|
||||
#define TILE_WIDTH 576
|
||||
#define TILE_HEIGHT 432
|
||||
|
||||
#ifdef PSP2
|
||||
extern GLuint fxfb;
|
||||
bool using_fbo = false;
|
||||
#endif
|
||||
|
||||
void
|
||||
DoRWStuffEndOfFrame(void)
|
||||
{
|
||||
@@ -362,6 +367,19 @@ DoRWStuffEndOfFrame(void)
|
||||
CDebug::DebugDisplayTextBuffer();
|
||||
FlushObrsPrintfs();
|
||||
RwCameraEndUpdate(Scene.camera);
|
||||
|
||||
#if defined(PSP2) && defined(EXTENDED_COLOURFILTER)
|
||||
// Arm the next frame's capture: bind our FBO once CPostFX has asked for it, so
|
||||
// the scene renders into fxraster and the colour filter can sample it.
|
||||
if(CPostFX::NeedBackBuffer()){
|
||||
if (using_fbo) {
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, fxfb);
|
||||
using_fbo = false;
|
||||
} else
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
RsCameraShowRaster(Scene.camera);
|
||||
#ifndef MASTER
|
||||
char s[48];
|
||||
|
||||
@@ -194,7 +194,14 @@ CustomFrontendOptionsPopulate(void)
|
||||
#define MINI_CASE_SENSITIVE
|
||||
#include "ini.h"
|
||||
|
||||
#ifdef PSP2
|
||||
// mINI opens the file with std::ifstream/ofstream, which bypasses the fcaseopen/
|
||||
// casepath shims that resolve relative paths against the data dir, so a bare
|
||||
// "reVC.ini" never opens here and settings would not persist.
|
||||
mINI::INIFile ini(PSP2_DATA_PATH "/reVC.ini");
|
||||
#else
|
||||
mINI::INIFile ini("reVC.ini");
|
||||
#endif
|
||||
mINI::INIStructure cfg;
|
||||
|
||||
bool ReadIniIfExists(const char *cat, const char *key, uint32 *out)
|
||||
|
||||
@@ -13,6 +13,13 @@
|
||||
#include "MBlur.h"
|
||||
#include "postfx.h"
|
||||
|
||||
#ifdef PSP2
|
||||
// The Vita captures the scene into its own FBO instead of reading the backbuffer:
|
||||
// see DoRWStuffEndOfFrame, which flips the binding a frame ahead.
|
||||
GLuint fxraster = 0xDEADBEEF, fxfb;
|
||||
extern bool using_fbo;
|
||||
#endif
|
||||
|
||||
RwRaster *CPostFX::pFrontBuffer;
|
||||
RwRaster *CPostFX::pBackBuffer;
|
||||
bool CPostFX::bJustInitialised;
|
||||
@@ -55,6 +62,16 @@ CPostFX::Open(RwCamera *cam)
|
||||
uint32 width = Pow(2.0f, int32(log2(RwRasterGetWidth (RwCameraGetRaster(cam))))+1);
|
||||
uint32 height = Pow(2.0f, int32(log2(RwRasterGetHeight(RwCameraGetRaster(cam))))+1);
|
||||
uint32 depth = RwRasterGetDepth(RwCameraGetRaster(cam));
|
||||
#ifdef PSP2
|
||||
// Screen-sized rather than a POT block. Elsewhere the captured scene sits in the
|
||||
// top-left corner of the POT raster at 1:1 texel-to-pixel and the overhang falls
|
||||
// off screen; here nothing lines up that way, because librw's rasterRenderFast
|
||||
// copies a fixed 960x544 out of the display buffer and addresses the destination
|
||||
// by its own height/stride, while the fullscreen quad samples the whole raster
|
||||
// over 0..1. The two only agree when the raster matches the screen.
|
||||
width = RwRasterGetWidth(RwCameraGetRaster(cam));
|
||||
height = RwRasterGetHeight(RwCameraGetRaster(cam));
|
||||
#endif
|
||||
pFrontBuffer = RwRasterCreate(width, height, depth, rwRASTERTYPECAMERATEXTURE);
|
||||
pBackBuffer = RwRasterCreate(width, height, depth, rwRASTERTYPECAMERATEXTURE);
|
||||
bJustInitialised = true;
|
||||
@@ -152,23 +169,43 @@ CPostFX::Open(RwCamera *cam)
|
||||
contrast_PS = rw::d3d::createPixelShader(contrastPS_cso);
|
||||
#endif
|
||||
#ifdef RW_OPENGL
|
||||
#ifdef PSP2
|
||||
// Cg source, not the precompiled GXP blobs: librw-vita is built with
|
||||
// PSP2_USE_SHADER_COMPILER, so Shader::create expects source strings, and
|
||||
// glShaderBinary would now be handed a blob it cannot parse.
|
||||
#include "shaders/im2d_v_cg.inc"
|
||||
#endif
|
||||
using namespace rw::gl3;
|
||||
|
||||
{
|
||||
#ifdef PSP2
|
||||
#include "shaders/colourfilterVC_f_cg.inc"
|
||||
const char *vs[] = { im2d_v_cg_src, nil };
|
||||
const char *fs[] = { colourfilterVC_f_cg_src, nil };
|
||||
colourFilterVC = Shader::create(vs, fs, true);
|
||||
#else
|
||||
#include "shaders/obj/im2d_vert.inc"
|
||||
#include "shaders/obj/colourfilterVC_frag.inc"
|
||||
const char *vs[] = { shaderDecl, header_vert_src, im2d_vert_src, nil };
|
||||
const char *fs[] = { shaderDecl, header_frag_src, colourfilterVC_frag_src, nil };
|
||||
colourFilterVC = Shader::create(vs, fs);
|
||||
#endif
|
||||
assert(colourFilterVC);
|
||||
}
|
||||
|
||||
{
|
||||
#ifdef PSP2
|
||||
#include "shaders/contrast_f_cg.inc"
|
||||
const char *vs[] = { im2d_v_cg_src, nil };
|
||||
const char *fs[] = { contrast_f_cg_src, nil };
|
||||
contrast = Shader::create(vs, fs, true);
|
||||
#else
|
||||
#include "shaders/obj/im2d_vert.inc"
|
||||
#include "shaders/obj/contrast_frag.inc"
|
||||
const char *vs[] = { shaderDecl, header_vert_src, im2d_vert_src, nil };
|
||||
const char *fs[] = { shaderDecl, header_frag_src, contrast_frag_src, nil };
|
||||
contrast = Shader::create(vs, fs);
|
||||
#endif
|
||||
assert(contrast);
|
||||
}
|
||||
|
||||
@@ -305,6 +342,14 @@ CPostFX::RenderOverlayShader(RwCamera *cam, int32 r, int32 g, int32 b, int32 a)
|
||||
glUniform4fv(colourFilterVC->uniformLocations[u_blurcolor], 1, blurcolors);
|
||||
#endif
|
||||
}
|
||||
#ifdef PSP2
|
||||
// The scene lives in our own FBO texture here, not in pBackBuffer.
|
||||
glBindTexture(GL_TEXTURE_2D, fxraster);
|
||||
RwIm2DVertexSetIntRGBA(&Vertex[0], 255, 255, 255, 255);
|
||||
RwIm2DVertexSetIntRGBA(&Vertex[1], 255, 255, 255, 255);
|
||||
RwIm2DVertexSetIntRGBA(&Vertex[2], 255, 255, 255, 255);
|
||||
RwIm2DVertexSetIntRGBA(&Vertex[3], 255, 255, 255, 255);
|
||||
#endif
|
||||
RwIm2DRenderIndexedPrimitive(rwPRIMTYPETRILIST, Vertex, 4, Index, 6);
|
||||
#ifdef RW_D3D9
|
||||
rw::d3d::im2dOverridePS = nil;
|
||||
@@ -418,8 +463,11 @@ CPostFX::Render(RwCamera *cam, uint32 red, uint32 green, uint32 blue, uint32 blu
|
||||
blur = AvgAlpha;
|
||||
}
|
||||
|
||||
// PSP2 captures the scene through its own FBO a frame ahead instead.
|
||||
#ifndef PSP2
|
||||
if(NeedBackBuffer())
|
||||
GetBackBuffer(cam);
|
||||
#endif
|
||||
|
||||
DefinedState();
|
||||
|
||||
@@ -431,22 +479,43 @@ CPostFX::Render(RwCamera *cam, uint32 red, uint32 green, uint32 blue, uint32 blu
|
||||
if(type == MOTION_BLUR_SNIPER){
|
||||
if(!bJustInitialised)
|
||||
RenderOverlaySniper(cam, red, green, blue, blur);
|
||||
}else switch(EffectSwitch){
|
||||
case POSTFX_OFF:
|
||||
case POSTFX_SIMPLE:
|
||||
// no actual rendering here
|
||||
break;
|
||||
case POSTFX_NORMAL:
|
||||
if(MotionBlurOn){
|
||||
if(!bJustInitialised)
|
||||
RenderOverlayBlur(cam, red, green, blue, blur);
|
||||
}else{
|
||||
RenderOverlayShader(cam, red, green, blue, blur);
|
||||
}else{
|
||||
#if defined(PSP2) && defined(EXTENDED_COLOURFILTER)
|
||||
// Arm the capture for the next frame: DoRWStuffEndOfFrame binds fxfb once
|
||||
// using_fbo is set, so the scene lands in fxraster and this pass samples it.
|
||||
if (NeedBackBuffer()) {
|
||||
if(fxraster == 0xDEADBEEF){
|
||||
glGenTextures(1, &fxraster);
|
||||
glBindTexture(GL_TEXTURE_2D, fxraster);
|
||||
// Screen-sized, not a POT block: the fullscreen quad samples this
|
||||
// over 0..1, so anything bigger leaves the scene in a sub-rect and
|
||||
// the remainder reads as black.
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 960, 544, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
|
||||
glGenFramebuffers(1, &fxfb);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, fxfb);
|
||||
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, fxraster, 0);
|
||||
}
|
||||
using_fbo = true;
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
}
|
||||
#endif
|
||||
switch(EffectSwitch){
|
||||
case POSTFX_OFF:
|
||||
case POSTFX_SIMPLE:
|
||||
// no actual rendering here
|
||||
break;
|
||||
case POSTFX_NORMAL:
|
||||
if(MotionBlurOn){
|
||||
if(!bJustInitialised)
|
||||
RenderOverlayBlur(cam, red, green, blue, blur);
|
||||
}else{
|
||||
RenderOverlayShader(cam, red, green, blue, blur);
|
||||
}
|
||||
break;
|
||||
case POSTFX_MOBILE:
|
||||
RenderOverlayShader(cam, red, green, blue, blur);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case POSTFX_MOBILE:
|
||||
RenderOverlayShader(cam, red, green, blue, blur);
|
||||
break;
|
||||
}
|
||||
|
||||
if(!bJustInitialised)
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
#define u_fogStart (u_fogData.x)
|
||||
#define u_fogEnd (u_fogData.y)
|
||||
#define u_fogRange (u_fogData.z)
|
||||
#define u_fogDisable (u_fogData.w)
|
||||
|
||||
void DoAlphaTest(float a, half2 u_alphaRef)
|
||||
{
|
||||
if(a < u_alphaRef.x || a >= u_alphaRef.y)
|
||||
discard;
|
||||
}
|
||||
|
||||
float4 main(
|
||||
half4 v_color : COLOR0,
|
||||
half2 v_tex0 : TEXCOORD0,
|
||||
fixed v_fog : FOG,
|
||||
uniform half4 u_fogColor,
|
||||
uniform half2 u_alphaRef,
|
||||
uniform half4 u_blurcolor,
|
||||
uniform sampler2D tex0
|
||||
) {
|
||||
half a = u_blurcolor.a;
|
||||
half4 doublec = clamp(u_blurcolor*2.0, 0.0, 1.0);
|
||||
half4 dst = v_color*tex2D(tex0, half2(v_tex0.x, 1.0-v_tex0.y));
|
||||
dst.rgb = lerp(u_fogColor.rgb, dst.rgb, v_fog);
|
||||
DoAlphaTest(dst.a, u_alphaRef);
|
||||
|
||||
half4 prev = dst;
|
||||
for (int i = 0; i < 5; i++){
|
||||
half4 tmp = dst*(1.0-a) + prev*doublec*a;
|
||||
tmp += prev*u_blurcolor;
|
||||
tmp += prev*u_blurcolor;
|
||||
prev = clamp(tmp, 0.0, 1.0);
|
||||
}
|
||||
half4 color;
|
||||
color.rgb = prev.rgb;
|
||||
color.a = 1.0f;
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
const char *colourfilterVC_f_cg_src =
|
||||
"#define u_fogStart (u_fogData.x)\n"
|
||||
"#define u_fogEnd (u_fogData.y)\n"
|
||||
"#define u_fogRange (u_fogData.z)\n"
|
||||
"#define u_fogDisable (u_fogData.w)\n"
|
||||
|
||||
"void DoAlphaTest(float a, half2 u_alphaRef)\n"
|
||||
"{\n"
|
||||
" if(a < u_alphaRef.x || a >= u_alphaRef.y)\n"
|
||||
" discard;\n"
|
||||
"}\n"
|
||||
|
||||
"float4 main(\n"
|
||||
" half4 v_color : COLOR0,\n"
|
||||
" half2 v_tex0 : TEXCOORD0,\n"
|
||||
" fixed v_fog : FOG,\n"
|
||||
" uniform half4 u_fogColor,\n"
|
||||
" uniform half2 u_alphaRef,\n"
|
||||
" uniform half4 u_blurcolor,\n"
|
||||
" uniform sampler2D tex0\n"
|
||||
") {\n"
|
||||
" half a = u_blurcolor.a;\n"
|
||||
" half4 doublec = clamp(u_blurcolor*2.0, 0.0, 1.0);\n"
|
||||
" half4 dst = v_color*tex2D(tex0, half2(v_tex0.x, 1.0-v_tex0.y));\n"
|
||||
" dst.rgb = lerp(u_fogColor.rgb, dst.rgb, v_fog);\n"
|
||||
" DoAlphaTest(dst.a, u_alphaRef);\n"
|
||||
|
||||
" half4 prev = dst;\n"
|
||||
" for (int i = 0; i < 5; i++){\n"
|
||||
" half4 tmp = dst*(1.0-a) + prev*doublec*a;\n"
|
||||
" tmp += prev*u_blurcolor;\n"
|
||||
" tmp += prev*u_blurcolor;\n"
|
||||
" prev = clamp(tmp, 0.0, 1.0);\n"
|
||||
" }\n"
|
||||
" half4 color;\n"
|
||||
" color.rgb = prev.rgb;\n"
|
||||
" color.a = 1.0f;\n"
|
||||
|
||||
" return color;\n"
|
||||
"}\n"
|
||||
|
||||
|
||||
;
|
||||
@@ -0,0 +1,33 @@
|
||||
#define u_fogStart (u_fogData.x)
|
||||
#define u_fogEnd (u_fogData.y)
|
||||
#define u_fogRange (u_fogData.z)
|
||||
#define u_fogDisable (u_fogData.w)
|
||||
|
||||
void DoAlphaTest(float a, half2 u_alphaRef)
|
||||
{
|
||||
if(a < u_alphaRef.x || a >= u_alphaRef.y)
|
||||
discard;
|
||||
}
|
||||
|
||||
float4 main(
|
||||
half4 v_color : COLOR0,
|
||||
half2 v_tex0 : TEXCOORD0,
|
||||
fixed v_fog : FOG,
|
||||
uniform half4 u_fogColor,
|
||||
uniform half2 u_alphaRef,
|
||||
uniform float3 u_contrastAdd,
|
||||
uniform float3 u_contrastMult,
|
||||
uniform sampler2D tex0
|
||||
) {
|
||||
half4 dst = v_color*tex2D(tex0, half2(v_tex0.x, 1.0-v_tex0.y));
|
||||
dst.rgb = lerp(u_fogColor.rgb, dst.rgb, v_fog);
|
||||
DoAlphaTest(dst.a, u_alphaRef);
|
||||
|
||||
half4 color;
|
||||
color.rgb = dst.rgb*u_contrastMult + u_contrastAdd;
|
||||
color.a = 1.0f;
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
const char *contrast_f_cg_src =
|
||||
"#define u_fogStart (u_fogData.x)\n"
|
||||
"#define u_fogEnd (u_fogData.y)\n"
|
||||
"#define u_fogRange (u_fogData.z)\n"
|
||||
"#define u_fogDisable (u_fogData.w)\n"
|
||||
|
||||
"void DoAlphaTest(float a, half2 u_alphaRef)\n"
|
||||
"{\n"
|
||||
" if(a < u_alphaRef.x || a >= u_alphaRef.y)\n"
|
||||
" discard;\n"
|
||||
"}\n"
|
||||
|
||||
"float4 main(\n"
|
||||
" half4 v_color : COLOR0,\n"
|
||||
" half2 v_tex0 : TEXCOORD0,\n"
|
||||
" fixed v_fog : FOG,\n"
|
||||
" uniform half4 u_fogColor,\n"
|
||||
" uniform half2 u_alphaRef,\n"
|
||||
" uniform float3 u_contrastAdd,\n"
|
||||
" uniform float3 u_contrastMult,\n"
|
||||
" uniform sampler2D tex0\n"
|
||||
") {\n"
|
||||
" half4 dst = v_color*tex2D(tex0, half2(v_tex0.x, 1.0-v_tex0.y));\n"
|
||||
" dst.rgb = lerp(u_fogColor.rgb, dst.rgb, v_fog);\n"
|
||||
" DoAlphaTest(dst.a, u_alphaRef);\n"
|
||||
|
||||
" half4 color;\n"
|
||||
" color.rgb = dst.rgb*u_contrastMult + u_contrastAdd;\n"
|
||||
" color.a = 1.0f;\n"
|
||||
|
||||
" return color;\n"
|
||||
"}\n"
|
||||
|
||||
|
||||
;
|
||||
@@ -0,0 +1,35 @@
|
||||
#define u_fogStart (u_fogData.x)
|
||||
#define u_fogEnd (u_fogData.y)
|
||||
#define u_fogRange (u_fogData.z)
|
||||
#define u_fogDisable (u_fogData.w)
|
||||
|
||||
#define MAX_LIGHTS 8
|
||||
|
||||
#define surfAmbient (u_surfProps.x)
|
||||
#define surfSpecular (u_surfProps.y)
|
||||
#define surfDiffuse (u_surfProps.z)
|
||||
|
||||
fixed DoFog(float w, half4 u_fogData)
|
||||
{
|
||||
return clamp((w - u_fogEnd)*u_fogRange, u_fogDisable, 1.0);
|
||||
}
|
||||
|
||||
void main(
|
||||
float4 in_pos,
|
||||
half4 in_color,
|
||||
half2 in_tex0,
|
||||
uniform half4 u_fogData,
|
||||
uniform float4 u_xform,
|
||||
half4 out v_color : COLOR0,
|
||||
half2 out v_tex0 : TEXCOORD0,
|
||||
fixed out v_fog : FOG,
|
||||
float4 out gl_Position : POSITION
|
||||
) {
|
||||
gl_Position = in_pos;
|
||||
gl_Position.w = 1.0;
|
||||
gl_Position.xy = gl_Position.xy * u_xform.xy + u_xform.zw;
|
||||
v_fog = DoFog(gl_Position.z, u_fogData);
|
||||
gl_Position.xyz *= gl_Position.w;
|
||||
v_color = in_color;
|
||||
v_tex0 = in_tex0;
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
const char *im2d_v_cg_src =
|
||||
"#define u_fogStart (u_fogData.x)\n"
|
||||
"#define u_fogEnd (u_fogData.y)\n"
|
||||
"#define u_fogRange (u_fogData.z)\n"
|
||||
"#define u_fogDisable (u_fogData.w)\n"
|
||||
|
||||
"#define MAX_LIGHTS 8\n"
|
||||
|
||||
"#define surfAmbient (u_surfProps.x)\n"
|
||||
"#define surfSpecular (u_surfProps.y)\n"
|
||||
"#define surfDiffuse (u_surfProps.z)\n"
|
||||
|
||||
"fixed DoFog(float w, half4 u_fogData)\n"
|
||||
"{\n"
|
||||
" return clamp((w - u_fogEnd)*u_fogRange, u_fogDisable, 1.0);\n"
|
||||
"}\n"
|
||||
|
||||
"void main(\n"
|
||||
" float4 in_pos,\n"
|
||||
" half4 in_color,\n"
|
||||
" half2 in_tex0,\n"
|
||||
" uniform half4 u_fogData,\n"
|
||||
" uniform float4 u_xform,\n"
|
||||
" half4 out v_color : COLOR0,\n"
|
||||
" half2 out v_tex0 : TEXCOORD0,\n"
|
||||
" fixed out v_fog : FOG,\n"
|
||||
" float4 out gl_Position : POSITION\n"
|
||||
") {\n"
|
||||
" gl_Position = in_pos;\n"
|
||||
" gl_Position.w = 1.0;\n"
|
||||
" gl_Position.xy = gl_Position.xy * u_xform.xy + u_xform.zw;\n"
|
||||
" v_fog = DoFog(gl_Position.z, u_fogData);\n"
|
||||
" gl_Position.xyz *= gl_Position.w;\n"
|
||||
" v_color = in_color;\n"
|
||||
" v_tex0 = in_tex0;\n"
|
||||
"}\n"
|
||||
;
|
||||
@@ -299,13 +299,40 @@ RwTextureAddressMode RwTextureGetAddressingV(const RwTexture *texture);
|
||||
// TODO
|
||||
void _rwD3D8TexDictionaryEnableRasterFormatConversion(bool enable) { }
|
||||
|
||||
#ifdef PSP2
|
||||
// librw-vita predates Raster::convertTexToCurrentPlatform, so do it by hand:
|
||||
// round-trip through an Image, which also drops the palette the Vita cannot use.
|
||||
static rw::Raster*
|
||||
ConvertTexRaster(rw::Raster *ras)
|
||||
{
|
||||
using namespace rw;
|
||||
|
||||
if(ras->platform == rw::platform)
|
||||
return ras;
|
||||
// compatible platforms
|
||||
if(ras->platform == PLATFORM_D3D8 && rw::platform == PLATFORM_D3D9 ||
|
||||
ras->platform == PLATFORM_D3D9 && rw::platform == PLATFORM_D3D8)
|
||||
return ras;
|
||||
|
||||
Image *img = ras->toImage();
|
||||
ras->destroy();
|
||||
img->unpalettize();
|
||||
ras = Raster::createFromImage(img);
|
||||
img->destroy();
|
||||
return ras;
|
||||
}
|
||||
#endif
|
||||
|
||||
// hack for reading native textures
|
||||
RwBool rwNativeTextureHackRead(RwStream *stream, RwTexture **tex, RwInt32 size)
|
||||
{
|
||||
*tex = Texture::streamReadNative(stream);
|
||||
#ifdef LIBRW
|
||||
#ifdef PSP2
|
||||
(*tex)->raster = ConvertTexRaster((*tex)->raster);
|
||||
#else
|
||||
(*tex)->raster = rw::Raster::convertTexToCurrentPlatform((*tex)->raster);
|
||||
#endif
|
||||
#endif
|
||||
return *tex != nil;
|
||||
}
|
||||
@@ -551,6 +578,7 @@ static void *reallocWrap(void *p, size_t sz, uint32 hint) { return real_realloc(
|
||||
|
||||
// WARNING: unused parameters
|
||||
RwBool RwEngineInit(RwMemoryFunctions *memFuncs, RwUInt32 initFlags, RwUInt32 resArenaSize) {
|
||||
#ifndef PSP2
|
||||
if(memFuncs){
|
||||
real_malloc = memFuncs->rwmalloc;
|
||||
real_realloc = memFuncs->rwrealloc;
|
||||
@@ -561,6 +589,10 @@ RwBool RwEngineInit(RwMemoryFunctions *memFuncs, RwUInt32 initFlags, RwUInt32 re
|
||||
}else{
|
||||
Engine::init(nil);
|
||||
}
|
||||
#else
|
||||
// librw-vita's Engine::init takes no memory functions.
|
||||
Engine::init();
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
// TODO: this is platform dependent
|
||||
@@ -602,8 +634,20 @@ void RwD3D8EngineSetRefreshRate(RwUInt32 refreshRate) {}
|
||||
RwBool RwD3D8DeviceSupportsDXTTexture(void) { return true; }
|
||||
|
||||
|
||||
void RwD3D8EngineSetMultiSamplingLevels(RwUInt32 level) { Engine::setMultiSamplingLevels(level); }
|
||||
RwUInt32 RwD3D8EngineGetMaxMultiSamplingLevels(void) { return Engine::getMaxMultiSamplingLevels(); }
|
||||
// librw-vita has no multisampling controls - the level is fixed when vitaGL starts.
|
||||
// Reporting 0 levels is what keeps the menu entry out; see MenuScreensCustom.
|
||||
void RwD3D8EngineSetMultiSamplingLevels(RwUInt32 level) {
|
||||
#ifndef PSP2
|
||||
Engine::setMultiSamplingLevels(level);
|
||||
#endif
|
||||
}
|
||||
RwUInt32 RwD3D8EngineGetMaxMultiSamplingLevels(void) {
|
||||
#ifndef PSP2
|
||||
return Engine::getMaxMultiSamplingLevels();
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
RpMaterial *RpMaterialCreate(void) { return Material::create(); }
|
||||
@@ -1005,7 +1049,15 @@ RwBool RtCharsetDestroy(RtCharset * charSet) { charSet->destroy(); return
|
||||
|
||||
#include <rpanisot.h>
|
||||
|
||||
#ifdef PSP2
|
||||
// librw-vita has no anisotropy plugin. Reporting zero keeps callers away from it.
|
||||
RwInt8 RpAnisotGetMaxSupportedMaxAnisotropy(void) { return 0; }
|
||||
RwTexture *RpAnisotTextureSetMaxAnisotropy(RwTexture *tex, RwInt8 val) { return tex; }
|
||||
RwInt8 RpAnisotTextureGetMaxAnisotropy(RwTexture *tex) { return 0; }
|
||||
RwBool RpAnisotPluginAttach(void) { return false; }
|
||||
#else
|
||||
RwInt8 RpAnisotGetMaxSupportedMaxAnisotropy(void) { return rw::getMaxSupportedMaxAnisotropy(); }
|
||||
RwTexture *RpAnisotTextureSetMaxAnisotropy(RwTexture *tex, RwInt8 val) { tex->setMaxAnisotropy(val); return tex; }
|
||||
RwInt8 RpAnisotTextureGetMaxAnisotropy(RwTexture *tex) { return tex->getMaxAnisotropy(); }
|
||||
RwBool RpAnisotPluginAttach(void) { rw::registerAnisotropyPlugin(); return true; }
|
||||
#endif
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
void
|
||||
CVector::Normalise(void)
|
||||
{
|
||||
#ifdef PSP2
|
||||
normalize3_neon(&this->x, &this->x);
|
||||
#else
|
||||
float sq = MagnitudeSqr();
|
||||
if (sq > 0.0f) {
|
||||
float invsqrt = RecipSqrt(sq);
|
||||
@@ -11,6 +14,7 @@ CVector::Normalise(void)
|
||||
z *= invsqrt;
|
||||
} else
|
||||
x = 1.0f;
|
||||
#endif
|
||||
}
|
||||
|
||||
CVector
|
||||
|
||||
@@ -185,7 +185,8 @@ GetGPUcaps(GPUcaps *caps)
|
||||
caps->subplatform = 0;
|
||||
caps->dxtSupport = 0;
|
||||
// TODO: more later
|
||||
#ifdef RW_GL3
|
||||
// librw-vita has no gl3Caps.
|
||||
#if defined(RW_GL3) && !defined(PSP2)
|
||||
caps->subplatform = rw::gl3::gl3Caps.gles;
|
||||
caps->dxtSupport = rw::gl3::gl3Caps.dxtSupported;
|
||||
#endif
|
||||
@@ -366,9 +367,49 @@ DealWithTxdWriteError(uint32 num, uint32 count, const char *text)
|
||||
#define STREAMTELL(str) filesys->rwftell((str)->Type.file.fpFile)
|
||||
#endif
|
||||
|
||||
#ifdef PSP2
|
||||
static void
|
||||
ConvertNativeTXD(const char *filename)
|
||||
{
|
||||
RwStream *stream = RwStreamOpen(rwSTREAMFILENAME, rwSTREAMREAD, filename);
|
||||
if(stream == nil)
|
||||
return;
|
||||
RwTexDictionary *txd = nil;
|
||||
if(RwStreamFindChunk(stream, rwID_TEXDICTIONARY, nil, nil))
|
||||
txd = RwTexDictionaryGtaStreamRead(stream);
|
||||
RwStreamClose(stream, nil);
|
||||
if(txd == nil)
|
||||
return;
|
||||
|
||||
stream = RwStreamOpen(rwSTREAMFILENAME, rwSTREAMWRITE, filename);
|
||||
if(stream){
|
||||
RwTexDictionaryStreamWrite(txd, stream);
|
||||
RwStreamClose(stream, nil);
|
||||
}
|
||||
RwTexDictionaryDestroy(txd);
|
||||
}
|
||||
#endif
|
||||
|
||||
bool
|
||||
CreateTxdImageForVideoCard()
|
||||
{
|
||||
#ifdef PSP2
|
||||
// Loose TXDs outside gta3.img are still in their original platform format, and
|
||||
// librw-vita cannot read those at load time. Rewrite them in place once, on the
|
||||
// same pass that builds the video-card image.
|
||||
static const char *looseTxds[] = {
|
||||
"models\\menu.txd", "models\\fonts.txd", "models\\fonts_j.txd",
|
||||
"models\\fonts_p.txd", "models\\fonts_r.txd", "models\\frontend.txd",
|
||||
"models\\generic.txd", "models\\hud.txd", "models\\MISC.TXD",
|
||||
"models\\particle.txd", "models\\x360btns.txd",
|
||||
"txd\\mainsc1.txd", "txd\\mainsc2.txd", "txd\\NEWS.TXD",
|
||||
"txd\\SPLASH1.TXD", "txd\\SPLASH2.TXD", "txd\\SPLASH3.TXD",
|
||||
};
|
||||
for(uint32 i = 0; i < ARRAY_SIZE(looseTxds); i++){
|
||||
ConvertNativeTXD(looseTxds[i]);
|
||||
}
|
||||
#endif
|
||||
|
||||
uint8 *buf = new uint8[CDSTREAM_SECTOR_SIZE];
|
||||
CDirectory *pDir = new CDirectory(TXDSTORESIZE);
|
||||
CDirectory::DirectoryInfo dirInfo;
|
||||
@@ -391,7 +432,8 @@ CreateTxdImageForVideoCard()
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef RW_GL3
|
||||
// librw-vita has no needToReadBackTextures - it always keeps texture data around.
|
||||
#if defined(RW_GL3) && !defined(PSP2)
|
||||
// so we can read back DXT with GLES
|
||||
// only works for textures that are not yet loaded
|
||||
// so let's hope that is the case for all
|
||||
@@ -434,7 +476,7 @@ CreateTxdImageForVideoCard()
|
||||
delete []buf;
|
||||
delete pDir;
|
||||
CStreaming::RemoveTxd(i);
|
||||
#ifdef RW_GL3
|
||||
#if defined(RW_GL3) && !defined(PSP2)
|
||||
rw::gl3::needToReadBackTextures = false;
|
||||
#endif
|
||||
return false;
|
||||
@@ -469,7 +511,7 @@ CreateTxdImageForVideoCard()
|
||||
RwStreamClose(img, nil);
|
||||
delete []buf;
|
||||
|
||||
#ifdef RW_GL3
|
||||
#if defined(RW_GL3) && !defined(PSP2)
|
||||
rw::gl3::needToReadBackTextures = false;
|
||||
#endif
|
||||
|
||||
|
||||
@@ -32,7 +32,12 @@ template<typename T>
|
||||
inline void
|
||||
ReadSaveBuf(T *out, uint8 *&buf)
|
||||
{
|
||||
// Save buffers are not aligned, and the Vita traps unaligned wide loads.
|
||||
#if !defined(PSP2)
|
||||
*out = *(T *)buf;
|
||||
#else
|
||||
sceClibMemcpy(out, buf, sizeof(T));
|
||||
#endif
|
||||
SkipSaveBuf(buf, sizeof(T));
|
||||
}
|
||||
|
||||
@@ -40,7 +45,11 @@ template<typename T>
|
||||
inline void
|
||||
ReadSaveBuf(T *out, uint8 *&buf, uint32 &length)
|
||||
{
|
||||
#if !defined(PSP2)
|
||||
*out = *(T *)buf;
|
||||
#else
|
||||
sceClibMemcpy(out, buf, sizeof(T));
|
||||
#endif
|
||||
SkipSaveBuf(buf, length, sizeof(T));
|
||||
}
|
||||
|
||||
@@ -49,7 +58,11 @@ inline T *
|
||||
WriteSaveBuf(uint8 *&buf, const T &value)
|
||||
{
|
||||
T *p = (T*)buf;
|
||||
#if !defined(PSP2)
|
||||
*p = value;
|
||||
#else
|
||||
sceClibMemcpy(p, &value, sizeof(T));
|
||||
#endif
|
||||
SkipSaveBuf(buf, sizeof(T));
|
||||
return p;
|
||||
}
|
||||
@@ -59,7 +72,11 @@ inline T *
|
||||
WriteSaveBuf(uint8 *&buf, uint32 &length, const T &value)
|
||||
{
|
||||
T *p = (T*)buf;
|
||||
#if !defined(PSP2)
|
||||
*p = value;
|
||||
#else
|
||||
sceClibMemcpy(p, &value, sizeof(T));
|
||||
#endif
|
||||
SkipSaveBuf(buf, length, sizeof(T));
|
||||
return p;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,322 @@
|
||||
#include "common.h"
|
||||
#include "crossplatform.h"
|
||||
|
||||
|
||||
#ifdef PSP2
|
||||
extern SceTouchPanelInfo panelInfo[2];
|
||||
bool useRearpad = false;
|
||||
|
||||
void *memcpy(void *dest, const void *src, size_t n)
|
||||
{
|
||||
return sceClibMemcpy(dest, src, n);
|
||||
}
|
||||
|
||||
static unsigned char gButtons[GLFW_GAMEPAD_BUTTON_LAST+1];
|
||||
static float gAxes[GLFW_GAMEPAD_AXIS_LAST+1];
|
||||
|
||||
unsigned char* glfwGetJoystickButtons(int jid, int* count)
|
||||
{
|
||||
int port_id = useRearpad ? 1 : 0;
|
||||
SceCtrlData pad;
|
||||
SceTouchData touch;
|
||||
sceCtrlPeekBufferPositiveExt2(0, &pad, 1);
|
||||
sceTouchPeek(port_id, &touch, 1);
|
||||
gButtons[GLFW_GAMEPAD_BUTTON_CROSS] = pad.buttons & SCE_CTRL_CROSS ? GLFW_PRESS : GLFW_RELEASE;
|
||||
gButtons[GLFW_GAMEPAD_BUTTON_CIRCLE] = pad.buttons & SCE_CTRL_CIRCLE ? GLFW_PRESS : GLFW_RELEASE;
|
||||
gButtons[GLFW_GAMEPAD_BUTTON_SQUARE] = pad.buttons & SCE_CTRL_SQUARE ? GLFW_PRESS : GLFW_RELEASE;
|
||||
gButtons[GLFW_GAMEPAD_BUTTON_TRIANGLE] = pad.buttons & SCE_CTRL_TRIANGLE ? GLFW_PRESS : GLFW_RELEASE;
|
||||
gButtons[GLFW_GAMEPAD_BUTTON_LEFT_BUMPER] = pad.buttons & SCE_CTRL_L1 ? GLFW_PRESS : GLFW_RELEASE;
|
||||
gButtons[GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER] = pad.buttons & SCE_CTRL_R1 ? GLFW_PRESS : GLFW_RELEASE;
|
||||
gButtons[GLFW_GAMEPAD_BUTTON_BACK] = pad.buttons & SCE_CTRL_SELECT ? GLFW_PRESS : GLFW_RELEASE;
|
||||
gButtons[GLFW_GAMEPAD_BUTTON_START] = pad.buttons & SCE_CTRL_START ? GLFW_PRESS : GLFW_RELEASE;
|
||||
gButtons[GLFW_GAMEPAD_BUTTON_GUIDE] = GLFW_RELEASE;
|
||||
gButtons[GLFW_GAMEPAD_BUTTON_LEFT_THUMB] = pad.buttons & SCE_CTRL_L3 ? GLFW_PRESS : GLFW_RELEASE;
|
||||
gButtons[GLFW_GAMEPAD_BUTTON_RIGHT_THUMB] = pad.buttons & SCE_CTRL_R3 ? GLFW_PRESS : GLFW_RELEASE;
|
||||
for (int i = 0; i < touch.reportNum; i++) {
|
||||
if (touch.report[i].y >= (panelInfo[port_id].minAaY + panelInfo[port_id].maxAaY) / 2) {
|
||||
if (touch.report[i].x < (panelInfo[port_id].minAaX + panelInfo[port_id].maxAaX) / 2)
|
||||
gButtons[GLFW_GAMEPAD_BUTTON_LEFT_THUMB] = GLFW_PRESS;
|
||||
else
|
||||
gButtons[GLFW_GAMEPAD_BUTTON_RIGHT_THUMB] = GLFW_PRESS;
|
||||
}
|
||||
}
|
||||
gButtons[GLFW_GAMEPAD_BUTTON_DPAD_UP] = pad.buttons & SCE_CTRL_UP ? GLFW_PRESS : GLFW_RELEASE;
|
||||
gButtons[GLFW_GAMEPAD_BUTTON_DPAD_RIGHT] = pad.buttons & SCE_CTRL_RIGHT ? GLFW_PRESS : GLFW_RELEASE;
|
||||
gButtons[GLFW_GAMEPAD_BUTTON_DPAD_DOWN] = pad.buttons & SCE_CTRL_DOWN ? GLFW_PRESS : GLFW_RELEASE;
|
||||
gButtons[GLFW_GAMEPAD_BUTTON_DPAD_LEFT] = pad.buttons & SCE_CTRL_LEFT ? GLFW_PRESS : GLFW_RELEASE;
|
||||
if (count)
|
||||
*count = GLFW_GAMEPAD_BUTTON_LAST+1;
|
||||
return gButtons;
|
||||
}
|
||||
|
||||
float* glfwGetJoystickAxes(int jid, int* count)
|
||||
{
|
||||
int port_id = useRearpad ? 1 : 0;
|
||||
SceCtrlData pad;
|
||||
SceTouchData touch;
|
||||
sceCtrlPeekBufferPositiveExt2(0, &pad, 1);
|
||||
sceTouchPeek(port_id, &touch, 1);
|
||||
gAxes[GLFW_GAMEPAD_AXIS_LEFT_X] = ((float)pad.lx - 128.0f) / 128.0f;
|
||||
gAxes[GLFW_GAMEPAD_AXIS_LEFT_Y] = ((float)pad.ly - 128.0f) / 128.0f;
|
||||
gAxes[GLFW_GAMEPAD_AXIS_RIGHT_X] = ((float)pad.rx - 128.0f) / 128.0f;
|
||||
gAxes[GLFW_GAMEPAD_AXIS_RIGHT_Y] = ((float)pad.ry - 128.0f) / 128.0f;
|
||||
gAxes[GLFW_GAMEPAD_AXIS_LEFT_TRIGGER] = pad.buttons & SCE_CTRL_L2 ? 1.0f : -1.0f;
|
||||
gAxes[GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER] = pad.buttons & SCE_CTRL_R2 ? 1.0f : -1.0f;
|
||||
for (int i = 0; i < touch.reportNum; i++) {
|
||||
if (touch.report[i].y < (panelInfo[port_id].minAaY + panelInfo[port_id].maxAaY) / 2) {
|
||||
if (touch.report[i].x < (panelInfo[port_id].minAaX + panelInfo[port_id].maxAaX) / 2)
|
||||
gAxes[GLFW_GAMEPAD_AXIS_LEFT_TRIGGER] = 1.0f;
|
||||
else
|
||||
gAxes[GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER] = 1.0f;
|
||||
}
|
||||
}
|
||||
if (count)
|
||||
*count = GLFW_GAMEPAD_AXIS_LAST+1;
|
||||
return gAxes;
|
||||
}
|
||||
|
||||
int glfwGetGamepadState(int jid, GLFWgamepadstate* state)
|
||||
{
|
||||
unsigned char *buttons = glfwGetJoystickButtons(jid, NULL);
|
||||
float *axes = glfwGetJoystickAxes(jid, NULL);
|
||||
sceClibMemcpy(state->buttons, buttons, sizeof(state->buttons));
|
||||
sceClibMemcpy(state->axes, axes, sizeof(state->axes));
|
||||
return 1;
|
||||
}
|
||||
|
||||
int glfwJoystickPresent(int jid)
|
||||
{
|
||||
return jid == 0;
|
||||
}
|
||||
|
||||
int glfwJoystickIsGamepad(int jid)
|
||||
{
|
||||
return jid == 0;
|
||||
}
|
||||
|
||||
int glfwGetKey(GLFWwindow* window, int key)
|
||||
{
|
||||
return GLFW_RELEASE;
|
||||
}
|
||||
|
||||
int glfwGetMouseButton(GLFWwindow* window, int button)
|
||||
{
|
||||
return GLFW_RELEASE;
|
||||
}
|
||||
|
||||
void glfwGetCursorPos(GLFWwindow* window, double* xpos, double* ypos)
|
||||
{
|
||||
if (xpos)
|
||||
*xpos = 0.0f;
|
||||
if (ypos)
|
||||
*ypos = 0.0f;
|
||||
return;
|
||||
}
|
||||
|
||||
void glfwSetCursorPos(GLFWwindow* window, double xpos, double ypos)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const char* glfwGetJoystickName(int jid)
|
||||
{
|
||||
return "Vita Pad";
|
||||
}
|
||||
|
||||
int glfwWindowShouldClose(GLFWwindow* window)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
GLFWmonitor* glfwGetPrimaryMonitor(void)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static GLFWvidmode gVideoMode { .width = 960, .height = 544 };
|
||||
const GLFWvidmode* glfwGetVideoMode(GLFWmonitor* monitor)
|
||||
{
|
||||
return &gVideoMode;
|
||||
}
|
||||
|
||||
void glfwSetInputMode(GLFWwindow* handle, int mode, int value)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int clock_gettime(int clk_id, struct timespec *tp)
|
||||
{
|
||||
if (clk_id == CLOCK_MONOTONIC) {
|
||||
SceKernelSysClock ticks;
|
||||
sceKernelGetProcessTime(&ticks);
|
||||
|
||||
tp->tv_sec = ticks / (1000 * 1000);
|
||||
tp->tv_nsec = (ticks * 1000) % (1000 * 1000 * 1000);
|
||||
|
||||
return 0;
|
||||
} else if (clk_id == CLOCK_REALTIME) {
|
||||
time_t seconds;
|
||||
SceDateTime time;
|
||||
sceRtcGetCurrentClockLocalTime(&time);
|
||||
|
||||
sceRtcGetTime_t(&time, &seconds);
|
||||
|
||||
tp->tv_sec = seconds;
|
||||
tp->tv_nsec = time.microsecond * 1000;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
int _lstat(const char *path, struct stat *buf)
|
||||
{
|
||||
return stat(path, buf);
|
||||
}
|
||||
|
||||
char cur_dir[PATH_MAX] = PSP2_DATA_PATH;
|
||||
char *_getcwd(char *buf, size_t size)
|
||||
{
|
||||
if (buf != NULL)
|
||||
strncpy(buf, cur_dir, size);
|
||||
return cur_dir;
|
||||
}
|
||||
|
||||
char *_realpath(const char *path, char *resolved_path)
|
||||
{
|
||||
char data_path[PATH_MAX];
|
||||
_getcwd(data_path, sizeof(data_path));
|
||||
|
||||
if (strncmp(path, "ux0:", 4) == 0)
|
||||
strcpy(resolved_path, path);
|
||||
else
|
||||
sprintf(resolved_path, "%s/%s", data_path, path);
|
||||
|
||||
return resolved_path;
|
||||
}
|
||||
|
||||
ssize_t readlink(const char *path, char *buf, size_t bufsiz)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _chdir(const char *path)
|
||||
{
|
||||
if (strncmp(path, "ux0:", 4) == 0)
|
||||
strcpy(cur_dir, path);
|
||||
else
|
||||
sprintf(cur_dir, "%s/%s", cur_dir, path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _mkdir(const char *pathname, mode_t mode)
|
||||
{
|
||||
char* real = casepath(pathname);
|
||||
int result = sceIoMkdir(real, mode) < 0 ? -1 : 0;
|
||||
free(real);
|
||||
return result;
|
||||
}
|
||||
|
||||
int unlink(const char *pathname)
|
||||
{
|
||||
char* real = casepath(pathname);
|
||||
int result = remove(real);
|
||||
free(real);
|
||||
return result;
|
||||
}
|
||||
|
||||
int _caserename(const char *old_filename, const char *new_filename)
|
||||
{
|
||||
int result;
|
||||
char *real_old = casepath(old_filename);
|
||||
char *real_new = casepath(new_filename);
|
||||
// hack so we don't even try to rename it to new_filename if it already exists
|
||||
if (!real_new) {
|
||||
free(real_old);
|
||||
return -1;
|
||||
}
|
||||
if (!real_old)
|
||||
result = rename(old_filename, real_new);
|
||||
else
|
||||
result = rename(real_old, real_new);
|
||||
free(real_old);
|
||||
free(real_new);
|
||||
return result;
|
||||
}
|
||||
|
||||
HANDLE FindFirstFile(const char* pathname, WIN32_FIND_DATA* firstfile) {
|
||||
char pathCopy[MAX_PATH];
|
||||
snprintf(pathCopy, sizeof(pathCopy), PSP2_DATA_PATH "/%s", pathname);
|
||||
|
||||
char *folder = strtok(pathCopy, "*");
|
||||
char *extension = strtok(NULL, "*");
|
||||
|
||||
// because strtok doesn't return NULL for last delimiter
|
||||
if (extension - folder == strlen(pathname))
|
||||
extension = nil;
|
||||
|
||||
// Case-sensitivity and backslashes...
|
||||
// Will be freed at the bottom
|
||||
char *realFolder = casepath(folder);
|
||||
if (realFolder) {
|
||||
folder = realFolder;
|
||||
}
|
||||
|
||||
strncpy(firstfile->folder, folder, sizeof(firstfile->folder));
|
||||
|
||||
if (extension)
|
||||
strncpy(firstfile->extension, extension, sizeof(firstfile->extension));
|
||||
else
|
||||
firstfile->extension[0] = '\0';
|
||||
|
||||
if (realFolder)
|
||||
free(realFolder);
|
||||
|
||||
HANDLE d;
|
||||
if ((d = (HANDLE)opendir(firstfile->folder)) == NULL || !FindNextFile(d, firstfile))
|
||||
return NULL;
|
||||
|
||||
return d;
|
||||
}
|
||||
|
||||
bool FindNextFile(HANDLE d, WIN32_FIND_DATA* finddata) {
|
||||
dirent *file;
|
||||
static struct stat fileStats;
|
||||
static char path[PATH_MAX], relativepath[NAME_MAX + sizeof(finddata->folder) + 1];
|
||||
int extensionLen = strlen(finddata->extension);
|
||||
while ((file = readdir((DIR*)d)) != NULL) {
|
||||
|
||||
// We only want "DT_REG"ular Files, but reportedly some FS and OSes gives DT_UNKNOWN as type.
|
||||
if (extensionLen == 0 || strncasecmp(&file->d_name[strlen(file->d_name) - extensionLen], finddata->extension, extensionLen) == 0) {
|
||||
|
||||
sprintf(relativepath, "%s/%s", finddata->folder, file->d_name);
|
||||
_realpath(relativepath, path);
|
||||
stat(path, &fileStats);
|
||||
strncpy(finddata->cFileName, file->d_name, sizeof(finddata->cFileName));
|
||||
finddata->ftLastWriteTime = fileStats.st_mtime;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
char* casepath(char const* path, bool checkPathFirst)
|
||||
{
|
||||
char* out = (char*)malloc(PATH_MAX);
|
||||
_realpath(path, out);
|
||||
|
||||
size_t l = strlen(out);
|
||||
for (int i = l-1; i >= 0; i--) {
|
||||
if (out[i] == '\\' || out[i] == '/' || out[i] == ' ')
|
||||
out[i] = '\0';
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
#endif
|
||||
// Codes compatible with Windows and Linux
|
||||
#ifndef _WIN32
|
||||
|
||||
@@ -25,6 +341,9 @@ void GetLocalTime_CP(SYSTEMTIME *out) {
|
||||
|
||||
// Compatible with Linux/POSIX and MinGW on Windows
|
||||
#ifndef _WIN32
|
||||
// The Vita has its own pair above: dirent works there, but paths have to go through
|
||||
// the casepath shim, and there is no cwd to resolve them against.
|
||||
#ifndef PSP2
|
||||
HANDLE FindFirstFile(const char* pathname, WIN32_FIND_DATA* firstfile) {
|
||||
char pathCopy[MAX_PATH];
|
||||
strcpy(pathCopy, pathname);
|
||||
@@ -81,6 +400,7 @@ bool FindNextFile(HANDLE d, WIN32_FIND_DATA* finddata) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
#endif // !PSP2
|
||||
|
||||
void GetDateFormat(int unused1, int unused2, SYSTEMTIME* in, int unused3, char* out, int size) {
|
||||
tm linuxTime;
|
||||
@@ -155,6 +475,9 @@ FILE* _fcaseopen(char const* filename, char const* mode)
|
||||
return result;
|
||||
}
|
||||
|
||||
// _fcaseopen above is shared - it only calls casepath. These two are not: the Vita
|
||||
// supplies its own further up, resolving through sceIo and its faked cwd.
|
||||
#ifndef PSP2
|
||||
int _caserename(const char *old_filename, const char *new_filename)
|
||||
{
|
||||
int result;
|
||||
@@ -292,7 +615,8 @@ char* casepath(char const* path, bool checkPathFirst)
|
||||
}
|
||||
return out;
|
||||
}
|
||||
#endif
|
||||
#endif // !PSP2
|
||||
#endif // !_WIN32
|
||||
|
||||
#if !defined(_MSC_VER) && !defined(__CWCC__)
|
||||
char *strdate(char *buf) {
|
||||
|
||||
@@ -1,6 +1,137 @@
|
||||
#ifndef _CROSSPLATFORM_H_
|
||||
#define _CROSSPLATFORM_H_
|
||||
#include <time.h>
|
||||
#include <limits.h>
|
||||
|
||||
#ifdef PSP2
|
||||
|
||||
#define GLFW_RELEASE 0
|
||||
#define GLFW_PRESS 1
|
||||
|
||||
#define GLFW_KEY_D 68
|
||||
#define GLFW_KEY_R 82
|
||||
|
||||
#define GLFW_MOUSE_BUTTON_1 0
|
||||
#define GLFW_MOUSE_BUTTON_2 1
|
||||
#define GLFW_MOUSE_BUTTON_3 2
|
||||
#define GLFW_MOUSE_BUTTON_4 3
|
||||
#define GLFW_MOUSE_BUTTON_5 4
|
||||
#define GLFW_MOUSE_BUTTON_6 5
|
||||
#define GLFW_MOUSE_BUTTON_7 6
|
||||
#define GLFW_MOUSE_BUTTON_8 7
|
||||
#define GLFW_MOUSE_BUTTON_LAST GLFW_MOUSE_BUTTON_8
|
||||
#define GLFW_MOUSE_BUTTON_LEFT GLFW_MOUSE_BUTTON_1
|
||||
#define GLFW_MOUSE_BUTTON_RIGHT GLFW_MOUSE_BUTTON_2
|
||||
#define GLFW_MOUSE_BUTTON_MIDDLE GLFW_MOUSE_BUTTON_3
|
||||
|
||||
#define GLFW_JOYSTICK_1 0
|
||||
#define GLFW_JOYSTICK_2 1
|
||||
#define GLFW_JOYSTICK_3 2
|
||||
#define GLFW_JOYSTICK_4 3
|
||||
#define GLFW_JOYSTICK_5 4
|
||||
#define GLFW_JOYSTICK_6 5
|
||||
#define GLFW_JOYSTICK_7 6
|
||||
#define GLFW_JOYSTICK_8 7
|
||||
#define GLFW_JOYSTICK_9 8
|
||||
#define GLFW_JOYSTICK_10 9
|
||||
#define GLFW_JOYSTICK_11 10
|
||||
#define GLFW_JOYSTICK_12 11
|
||||
#define GLFW_JOYSTICK_13 12
|
||||
#define GLFW_JOYSTICK_14 13
|
||||
#define GLFW_JOYSTICK_15 14
|
||||
#define GLFW_JOYSTICK_16 15
|
||||
#define GLFW_JOYSTICK_LAST GLFW_JOYSTICK_16
|
||||
|
||||
#define GLFW_GAMEPAD_BUTTON_A 0
|
||||
#define GLFW_GAMEPAD_BUTTON_B 1
|
||||
#define GLFW_GAMEPAD_BUTTON_X 2
|
||||
#define GLFW_GAMEPAD_BUTTON_Y 3
|
||||
#define GLFW_GAMEPAD_BUTTON_LEFT_BUMPER 4
|
||||
#define GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER 5
|
||||
#define GLFW_GAMEPAD_BUTTON_BACK 6
|
||||
#define GLFW_GAMEPAD_BUTTON_START 7
|
||||
#define GLFW_GAMEPAD_BUTTON_GUIDE 8
|
||||
#define GLFW_GAMEPAD_BUTTON_LEFT_THUMB 9
|
||||
#define GLFW_GAMEPAD_BUTTON_RIGHT_THUMB 10
|
||||
#define GLFW_GAMEPAD_BUTTON_DPAD_UP 11
|
||||
#define GLFW_GAMEPAD_BUTTON_DPAD_RIGHT 12
|
||||
#define GLFW_GAMEPAD_BUTTON_DPAD_DOWN 13
|
||||
#define GLFW_GAMEPAD_BUTTON_DPAD_LEFT 14
|
||||
#define GLFW_GAMEPAD_BUTTON_LAST GLFW_GAMEPAD_BUTTON_DPAD_LEFT
|
||||
|
||||
#define GLFW_GAMEPAD_BUTTON_CROSS GLFW_GAMEPAD_BUTTON_A
|
||||
#define GLFW_GAMEPAD_BUTTON_CIRCLE GLFW_GAMEPAD_BUTTON_B
|
||||
#define GLFW_GAMEPAD_BUTTON_SQUARE GLFW_GAMEPAD_BUTTON_X
|
||||
#define GLFW_GAMEPAD_BUTTON_TRIANGLE GLFW_GAMEPAD_BUTTON_Y
|
||||
|
||||
#define GLFW_GAMEPAD_AXIS_LEFT_X 0
|
||||
#define GLFW_GAMEPAD_AXIS_LEFT_Y 1
|
||||
#define GLFW_GAMEPAD_AXIS_RIGHT_X 2
|
||||
#define GLFW_GAMEPAD_AXIS_RIGHT_Y 3
|
||||
#define GLFW_GAMEPAD_AXIS_LEFT_TRIGGER 4
|
||||
#define GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER 5
|
||||
#define GLFW_GAMEPAD_AXIS_LAST GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER
|
||||
|
||||
#define GLFW_CURSOR 0x00033001
|
||||
#define GLFW_CURSOR_HIDDEN 0x00034002
|
||||
#define GLFW_CURSOR_DISABLED 0x00034003
|
||||
|
||||
typedef struct GLFWgamepadstate
|
||||
{
|
||||
unsigned char buttons[15];
|
||||
float axes[6];
|
||||
} GLFWgamepadstate;
|
||||
|
||||
typedef struct GLFWvidmode
|
||||
{
|
||||
int width;
|
||||
int height;
|
||||
} GLFWvidmode;
|
||||
|
||||
typedef void GLFWmonitor;
|
||||
typedef void GLFWwindow;
|
||||
|
||||
GLFWmonitor* glfwGetPrimaryMonitor(void);
|
||||
int glfwWindowShouldClose(GLFWwindow* window);
|
||||
const GLFWvidmode* glfwGetVideoMode(GLFWmonitor* monitor);
|
||||
int glfwGetKey(GLFWwindow* window, int key);
|
||||
int glfwGetMouseButton(GLFWwindow* window, int button);
|
||||
void glfwGetCursorPos(GLFWwindow* window, double* xpos, double* ypos);
|
||||
void glfwSetCursorPos(GLFWwindow* window, double xpos, double ypos);
|
||||
int glfwJoystickPresent(int jid);
|
||||
float* glfwGetJoystickAxes(int jid, int* count);
|
||||
unsigned char* glfwGetJoystickButtons(int jid, int* count);
|
||||
int glfwJoystickIsGamepad(int jid);
|
||||
const char* glfwGetJoystickName(int jid);
|
||||
int glfwGetGamepadState(int jid, GLFWgamepadstate* state);
|
||||
void glfwSetInputMode(GLFWwindow* handle, int mode, int value);
|
||||
|
||||
#define PATH_MAX 1024
|
||||
#define NAME_MAX 255
|
||||
|
||||
// One place for the data directory. There is no working directory on this platform,
|
||||
// so everything relative gets resolved against this by _realpath/casepath.
|
||||
#define PSP2_DATA_PATH "ux0:data/gtavc"
|
||||
|
||||
int _lstat(const char *path, struct stat *buf);
|
||||
char *_realpath(const char *path, char *resolved_path);
|
||||
int _chdir(const char *path);
|
||||
char *_getcwd(char *buf, size_t size);
|
||||
int _mkdir(const char *pathname, mode_t mode);
|
||||
|
||||
#elif !defined(_WIN32)
|
||||
|
||||
// Shared code calls the underscored names so the Vita can resolve paths against
|
||||
// its data directory (it has no working directory of its own). Everywhere else
|
||||
// they are the POSIX originals. Windows is left alone - it has a real _mkdir.
|
||||
#define _lstat lstat
|
||||
#define _realpath realpath
|
||||
#define _mkdir mkdir
|
||||
#define _getcwd getcwd
|
||||
#define _chdir chdir
|
||||
|
||||
#endif
|
||||
|
||||
// This is the common include for platform/renderer specific skeletons(glfw.cpp, win.cpp etc.) and using cross platform things (like Windows directories wrapper, platform specific global arrays etc.)
|
||||
// Functions that's different on glfw and win but have same signature, should be located on platform.h.
|
||||
|
||||
@@ -186,3 +317,5 @@ void GetDateFormat(int, int, SYSTEMTIME*, int, char*, int);
|
||||
#define GLFW_GAMEPAD_BUTTON_Y 2
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -3,11 +3,12 @@
|
||||
// Nintendo Switch / GLFW movie player. Ported from the SDL2 build; only the
|
||||
// windowing-system glue differs (GLFW proc address / buffer swap / timer).
|
||||
//
|
||||
// Switch-only on purpose: Windows D3D9 builds play the intro through the win.cpp
|
||||
// skeleton (DirectShow), and the other GLFW targets never played it at all - the
|
||||
// MPEG states there have always just fallen through. Everyone else gets the stub
|
||||
// at the bottom of this file, which keeps glfw.cpp's intro state machine linkable
|
||||
// without dragging pl_mpeg and OpenAL into those builds.
|
||||
// The PS Vita gets its own backend further down, built on SceAvPlayer, behind the
|
||||
// same interface. Windows D3D9 builds play the intro through the win.cpp skeleton
|
||||
// (DirectShow), and the remaining GLFW targets never played it at all - the MPEG
|
||||
// states there have always just fallen through. Those get the stub at the bottom of
|
||||
// this file, which keeps glfw.cpp's intro state machine linkable without dragging
|
||||
// pl_mpeg and OpenAL into their builds.
|
||||
#if defined __SWITCH__ && defined RW_GL3 && !defined LIBRW_SDL2 && defined AUDIO_OAL
|
||||
|
||||
#include "common.h"
|
||||
@@ -663,6 +664,295 @@ void MoviePlayer::Draw()
|
||||
}
|
||||
}
|
||||
|
||||
#elif defined PSP2
|
||||
|
||||
// PS Vita backend. Same interface, different everything else: decoding is done by
|
||||
// SceAvPlayer rather than pl_mpeg, the frames arrive as GXM textures that are wrapped
|
||||
// into GL ones, and audio is pumped by a dedicated thread instead of OpenAL.
|
||||
// Lifted out of glfw.cpp, where it used to sit inline alongside the intro state machine.
|
||||
|
||||
#include "common.h"
|
||||
#include <malloc.h> // memalign, for the SceAvPlayer allocator callbacks
|
||||
#include <vitasdk.h>
|
||||
#include <vitaGL.h>
|
||||
#include "crossplatform.h"
|
||||
#include "MoviePlayer.h"
|
||||
|
||||
#define FB_ALIGNMENT 0x40000
|
||||
#define ALIGN_MEM(x, align) (((x) + ((align) - 1)) & ~((align) - 1))
|
||||
|
||||
SceAvPlayerHandle movie_player;
|
||||
|
||||
GLuint movie_frame[2];
|
||||
uint8_t movie_frame_idx = 0;
|
||||
SceGxmTexture *movie_tex[2];
|
||||
GLuint movie_fs;
|
||||
GLuint movie_vs;
|
||||
GLuint movie_prog;
|
||||
|
||||
SceUID audio_thid;
|
||||
int audio_new;
|
||||
int audio_port;
|
||||
int audio_len;
|
||||
int audio_freq;
|
||||
int audio_mode;
|
||||
|
||||
enum {
|
||||
PLAYER_INACTIVE,
|
||||
PLAYER_ACTIVE,
|
||||
PLAYER_STOP,
|
||||
};
|
||||
|
||||
int player_state = PLAYER_INACTIVE;
|
||||
|
||||
float movie_pos[8] = {
|
||||
-1.0f, 1.0f,
|
||||
-1.0f, -1.0f,
|
||||
1.0f, 1.0f,
|
||||
1.0f, -1.0f
|
||||
};
|
||||
|
||||
float movie_texcoord[8] = {
|
||||
0.0f, 0.0f,
|
||||
0.0f, 1.0f,
|
||||
1.0f, 0.0f,
|
||||
1.0f, 1.0f
|
||||
};
|
||||
|
||||
void *mem_alloc(void *p, uint32_t align, uint32_t size) {
|
||||
return memalign(align, size);
|
||||
}
|
||||
|
||||
void mem_free(void *p, void *ptr) {
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
void *gpu_alloc(void *p, uint32_t align, uint32_t size) {
|
||||
if (align < FB_ALIGNMENT) {
|
||||
align = FB_ALIGNMENT;
|
||||
}
|
||||
size = ALIGN_MEM(size, align);
|
||||
return vglAlloc(size, VGL_MEM_SLOW);
|
||||
}
|
||||
|
||||
void gpu_free(void *p, void *ptr) {
|
||||
glFinish();
|
||||
vglFree(ptr);
|
||||
}
|
||||
|
||||
void movie_player_audio_init(void) {
|
||||
audio_port = -1;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
if (sceAudioOutGetConfig(i, SCE_AUDIO_OUT_CONFIG_TYPE_LEN) >= 0) {
|
||||
audio_port = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (audio_port == -1) {
|
||||
audio_port = sceAudioOutOpenPort(SCE_AUDIO_OUT_PORT_TYPE_MAIN, 1024, 48000, SCE_AUDIO_OUT_MODE_STEREO);
|
||||
audio_new = 1;
|
||||
} else {
|
||||
audio_len = sceAudioOutGetConfig(audio_port, SCE_AUDIO_OUT_CONFIG_TYPE_LEN);
|
||||
audio_freq = sceAudioOutGetConfig(audio_port, SCE_AUDIO_OUT_CONFIG_TYPE_FREQ);
|
||||
audio_mode = sceAudioOutGetConfig(audio_port, SCE_AUDIO_OUT_CONFIG_TYPE_MODE);
|
||||
audio_new = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void movie_player_audio_shutdown(void) {
|
||||
if (audio_new) {
|
||||
sceAudioOutReleasePort(audio_port);
|
||||
} else {
|
||||
sceAudioOutSetConfig(audio_port, audio_len, audio_freq, (SceAudioOutMode)audio_mode);
|
||||
}
|
||||
}
|
||||
|
||||
int movie_player_audio_thread(SceSize args, void *argp) {
|
||||
SceAvPlayerFrameInfo frame;
|
||||
memset(&frame, 0, sizeof(SceAvPlayerFrameInfo));
|
||||
|
||||
while (player_state == PLAYER_ACTIVE && sceAvPlayerIsActive(movie_player)) {
|
||||
if (sceAvPlayerGetAudioData(movie_player, &frame)) {
|
||||
sceAudioOutSetConfig(audio_port, 1024, frame.details.audio.sampleRate, frame.details.audio.channelCount == 1 ? SCE_AUDIO_OUT_MODE_MONO : SCE_AUDIO_OUT_MODE_STEREO);
|
||||
sceAudioOutOutput(audio_port, frame.pData);
|
||||
} else {
|
||||
sceKernelDelayThread(1000);
|
||||
}
|
||||
}
|
||||
|
||||
return sceKernelExitDeleteThread(0);
|
||||
}
|
||||
|
||||
void movie_player_draw(void) {
|
||||
if (player_state == PLAYER_ACTIVE) {
|
||||
if (sceAvPlayerIsActive(movie_player)) {
|
||||
SceAvPlayerFrameInfo frame;
|
||||
if (sceAvPlayerGetVideoData(movie_player, &frame)) {
|
||||
movie_frame_idx = (movie_frame_idx + 1) % 2;
|
||||
sceGxmTextureInitLinear(
|
||||
movie_tex[movie_frame_idx],
|
||||
frame.pData,
|
||||
SCE_GXM_TEXTURE_FORMAT_YVU420P2_CSC1,
|
||||
frame.details.video.width,
|
||||
frame.details.video.height, 0);
|
||||
sceGxmTextureSetMinFilter(movie_tex[movie_frame_idx], SCE_GXM_TEXTURE_FILTER_LINEAR);
|
||||
sceGxmTextureSetMagFilter(movie_tex[movie_frame_idx], SCE_GXM_TEXTURE_FILTER_LINEAR);
|
||||
glUseProgram(movie_prog);
|
||||
glBindTexture(GL_TEXTURE_2D, movie_frame[movie_frame_idx]);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||
glEnableVertexAttribArray(0);
|
||||
glEnableVertexAttribArray(1);
|
||||
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, &movie_pos[0]);
|
||||
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, &movie_texcoord[0]);
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
vglSwapBuffers(GL_FALSE);
|
||||
}
|
||||
} else {
|
||||
player_state = PLAYER_STOP;
|
||||
}
|
||||
}
|
||||
|
||||
if (player_state == PLAYER_STOP) {
|
||||
sceAvPlayerStop(movie_player);
|
||||
sceKernelWaitThreadEnd(audio_thid, NULL, NULL);
|
||||
sceAvPlayerClose(movie_player);
|
||||
movie_player_audio_shutdown();
|
||||
player_state = PLAYER_INACTIVE;
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
vglSwapBuffers(GL_FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
int movie_player_inited = 0;
|
||||
void movie_player_init() {
|
||||
if (movie_player_inited)
|
||||
return;
|
||||
|
||||
sceSysmoduleLoadModule(SCE_SYSMODULE_AVPLAYER);
|
||||
|
||||
glGenTextures(2, movie_frame);
|
||||
for (int i = 0; i < 2; i++) {
|
||||
glBindTexture(GL_TEXTURE_2D, movie_frame[i]);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 960, 544, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
|
||||
movie_tex[i] = vglGetGxmTexture(GL_TEXTURE_2D);
|
||||
vglFree(vglGetTexDataPointer(GL_TEXTURE_2D));
|
||||
}
|
||||
|
||||
// The precompiled GXP blobs in shaders/movie_[vf].h can no longer be fed to
|
||||
// glShaderBinary: it now expects a vitaGL-serialized blob, so unserialize_shader
|
||||
// reads the "GXP\0" magic as a uniform count and walks off into garbage.
|
||||
// Compile the original Cg source (kept as a comment in those headers) instead.
|
||||
static const char *movie_v_src =
|
||||
"void main(\n"
|
||||
" float2 inPos,\n"
|
||||
" float2 inTex,\n"
|
||||
" float4 out pos : POSITION,\n"
|
||||
" float2 out texcoord : TEXCOORD0\n"
|
||||
") {\n"
|
||||
" texcoord = inTex;\n"
|
||||
" pos = float4(inPos, 1.f, 1.f);\n"
|
||||
"}\n";
|
||||
static const char *movie_f_src =
|
||||
"float4 main(\n"
|
||||
" float2 texcoord : TEXCOORD0,\n"
|
||||
" uniform sampler2D tex\n"
|
||||
") {\n"
|
||||
" return tex2D(tex, texcoord);\n"
|
||||
"}\n";
|
||||
|
||||
movie_vs = glCreateShader(GL_CG_VERTEX_SHADER_EXT);
|
||||
glShaderSource(movie_vs, 1, &movie_v_src, NULL);
|
||||
glCompileShader(movie_vs);
|
||||
|
||||
movie_fs = glCreateShader(GL_CG_FRAGMENT_SHADER_EXT);
|
||||
glShaderSource(movie_fs, 1, &movie_f_src, NULL);
|
||||
glCompileShader(movie_fs);
|
||||
|
||||
movie_prog = glCreateProgram();
|
||||
glAttachShader(movie_prog, movie_vs);
|
||||
glAttachShader(movie_prog, movie_fs);
|
||||
glBindAttribLocation(movie_prog, 0, "inPos");
|
||||
glBindAttribLocation(movie_prog, 1, "inTex");
|
||||
glLinkProgram(movie_prog);
|
||||
|
||||
movie_player_inited = 1;
|
||||
}
|
||||
|
||||
void movie_player_play(const char *file) {
|
||||
SceIoStat st;
|
||||
if (sceIoGetstat(file, &st) < 0)
|
||||
return;
|
||||
|
||||
movie_player_init();
|
||||
movie_player_audio_init();
|
||||
|
||||
SceAvPlayerInitData playerInit;
|
||||
sceClibMemset(&playerInit, 0, sizeof(SceAvPlayerInitData));
|
||||
|
||||
playerInit.memoryReplacement.allocate = mem_alloc;
|
||||
playerInit.memoryReplacement.deallocate = mem_free;
|
||||
playerInit.memoryReplacement.allocateTexture = gpu_alloc;
|
||||
playerInit.memoryReplacement.deallocateTexture = gpu_free;
|
||||
|
||||
playerInit.basePriority = 0xA0;
|
||||
playerInit.numOutputVideoFrameBuffers = 2;
|
||||
playerInit.autoStart = GL_TRUE;
|
||||
|
||||
movie_player = sceAvPlayerInit(&playerInit);
|
||||
|
||||
sceAvPlayerAddSource(movie_player, file);
|
||||
|
||||
audio_thid = sceKernelCreateThread("movie_audio_thread", movie_player_audio_thread, 0x10000100 - 10, 0x4000, 0, 0, NULL);
|
||||
sceKernelStartThread(audio_thid, 0, NULL);
|
||||
|
||||
player_state = PLAYER_ACTIVE;
|
||||
}
|
||||
|
||||
namespace MoviePlayer
|
||||
{
|
||||
void Play(const char *path)
|
||||
{
|
||||
// The shared intro code asks for pl_mpeg's .mpg by a path relative to the
|
||||
// data directory; SceAvPlayer wants .mp4 and an absolute one.
|
||||
char rel[256];
|
||||
strncpy(rel, path, sizeof(rel) - 1);
|
||||
rel[sizeof(rel) - 1] = '\0';
|
||||
char *ext = strrchr(rel, '.');
|
||||
if (ext != nil)
|
||||
strcpy(ext, ".mp4");
|
||||
|
||||
char full[PATH_MAX];
|
||||
_realpath(rel, full);
|
||||
|
||||
// This build has always shipped one set of intro videos, so the localised
|
||||
// title reel the shared code asks for on French and German is not there.
|
||||
// Fall back to the plain one rather than silently dropping the intro.
|
||||
SceIoStat st;
|
||||
if (sceIoGetstat(full, &st) < 0) {
|
||||
char *ger = strstr(rel, "GER.mp4");
|
||||
if (ger != nil) {
|
||||
strcpy(ger, ".mp4");
|
||||
_realpath(rel, full);
|
||||
}
|
||||
}
|
||||
|
||||
movie_player_play(full);
|
||||
}
|
||||
|
||||
void Draw() { movie_player_draw(); }
|
||||
|
||||
bool IsActive() { return player_state != PLAYER_INACTIVE; }
|
||||
|
||||
void Stop()
|
||||
{
|
||||
if (player_state == PLAYER_ACTIVE)
|
||||
player_state = PLAYER_STOP; // movie_player_draw does the teardown
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#else // !(RW_GL3 && !LIBRW_SDL2)
|
||||
|
||||
// Stub for backends that don't build the GLFW/GL movie player (e.g. D3D9, or an
|
||||
|
||||
@@ -14,7 +14,9 @@ DWORD _dwOperatingSystemVersion;
|
||||
long _dwOperatingSystemVersion;
|
||||
#ifndef __SWITCH__
|
||||
#ifndef __APPLE__
|
||||
#if !defined(PSP2)
|
||||
#include <sys/sysinfo.h>
|
||||
#endif
|
||||
#else
|
||||
#include <mach/mach_host.h>
|
||||
#include <sys/sysctl.h>
|
||||
@@ -68,6 +70,18 @@ long _dwOperatingSystemVersion;
|
||||
|
||||
#define MAX_SUBSYSTEMS (16)
|
||||
|
||||
#ifdef PSP2
|
||||
#include <malloc.h>
|
||||
#include <vitasdk.h>
|
||||
#include <vitaGL.h>
|
||||
#include "../message.h"
|
||||
|
||||
int _newlib_heap_size_user = 256 * 1024 * 1024;
|
||||
|
||||
#define DATA_PATH PSP2_DATA_PATH
|
||||
#define RT_INI_PATH DATA_PATH "/" "10thae.ini"
|
||||
#endif
|
||||
|
||||
rw::EngineOpenParams openParams;
|
||||
|
||||
static RwBool ForegroundApp = TRUE;
|
||||
@@ -122,11 +136,13 @@ void _psCreateFolder(const char *path)
|
||||
#else
|
||||
struct stat info;
|
||||
char fullpath[PATH_MAX];
|
||||
realpath(path, fullpath);
|
||||
// Underscored names: the Vita resolves these against its data directory, every
|
||||
// other platform aliases them to the POSIX originals in crossplatform.h.
|
||||
_realpath(path, fullpath);
|
||||
|
||||
if (lstat(fullpath, &info) != 0) {
|
||||
if (_lstat(fullpath, &info) != 0) {
|
||||
if (errno == ENOENT || (errno != EACCES && !S_ISDIR(info.st_mode))) {
|
||||
mkdir(fullpath, 0755);
|
||||
_mkdir(fullpath, 0755);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -556,6 +572,8 @@ psInitialize(void)
|
||||
#elif defined (__SWITCH__)
|
||||
svcGetInfo(&_dwMemAvailPhys, InfoType_UsedMemorySize, CUR_PROCESS_HANDLE, 0);
|
||||
debug("Physical memory size %llu\n", _dwMemAvailPhys);
|
||||
#elif defined(PSP2)
|
||||
_dwMemAvailPhys = 140 * 1024 * 1024;
|
||||
#else
|
||||
#ifndef __APPLE__
|
||||
struct sysinfo systemInfo;
|
||||
@@ -941,6 +959,9 @@ psSelectDevice()
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// None of these exist on the Vita: there is no window and no real GLFW, only the
|
||||
// input stubs in crossplatform.cpp.
|
||||
#if !defined(PSP2)
|
||||
#ifndef GET_KEYBOARD_INPUT_FROM_X11
|
||||
void keypressCB(GLFWwindow* window, int key, int scancode, int action, int mods);
|
||||
#endif
|
||||
@@ -951,6 +972,7 @@ void cursorEnterCB(GLFWwindow* window, int entered);
|
||||
void windowFocusCB(GLFWwindow* window, int focused);
|
||||
void windowIconifyCB(GLFWwindow* window, int iconified);
|
||||
void joysChangeCB(int jid, int event);
|
||||
#endif
|
||||
|
||||
bool IsThisJoystickBlacklisted(int i)
|
||||
{
|
||||
@@ -975,7 +997,7 @@ void _InputInitialiseJoys()
|
||||
PSGLOBAL(joy1id) = -1;
|
||||
PSGLOBAL(joy2id) = -1;
|
||||
|
||||
// Load our gamepad mappings.
|
||||
#if !defined(PSP2)
|
||||
#define SDL_GAMEPAD_DB_PATH "gamecontrollerdb.txt"
|
||||
FILE *f = fopen(SDL_GAMEPAD_DB_PATH, "rb");
|
||||
if (f) {
|
||||
@@ -1004,6 +1026,7 @@ void _InputInitialiseJoys()
|
||||
if (EnvControlConfig != nil) {
|
||||
glfwUpdateGamepadMappings(EnvControlConfig);
|
||||
}
|
||||
#endif // !PSP2
|
||||
|
||||
for (int i = 0; i <= GLFW_JOYSTICK_LAST; i++) {
|
||||
if (glfwJoystickPresent(i) && !IsThisJoystickBlacklisted(i)) {
|
||||
@@ -1016,6 +1039,9 @@ void _InputInitialiseJoys()
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef PSP2
|
||||
ControlsManager.InitDefaultControlConfigJoyPad(16);
|
||||
#else
|
||||
if (PSGLOBAL(joy1id) != -1) {
|
||||
int count;
|
||||
glfwGetJoystickButtons(PSGLOBAL(joy1id), &count);
|
||||
@@ -1024,6 +1050,7 @@ void _InputInitialiseJoys()
|
||||
#endif
|
||||
ControlsManager.InitDefaultControlConfigJoyPad(count);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
int lastCursorMode = GLFW_CURSOR_HIDDEN;
|
||||
@@ -1031,7 +1058,9 @@ long _InputInitialiseMouse(bool exclusive)
|
||||
{
|
||||
// Disabled = keep cursor centered and hide
|
||||
lastCursorMode = exclusive ? GLFW_CURSOR_DISABLED : GLFW_CURSOR_HIDDEN;
|
||||
#if !defined(PSP2)
|
||||
glfwSetInputMode(PSGLOBAL(window), GLFW_CURSOR, lastCursorMode);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1058,6 +1087,8 @@ void psPostRWinit(void)
|
||||
RwVideoMode vm;
|
||||
RwEngineGetVideoModeInfo(&vm, GcurSelVM);
|
||||
|
||||
// There is no window to hang callbacks on under PSP2, and the resolution is fixed.
|
||||
#if !defined(PSP2)
|
||||
glfwSetFramebufferSizeCallback(PSGLOBAL(window), resizeCB);
|
||||
#ifndef IGNORE_MOUSE_KEYBOARD
|
||||
#ifndef GET_KEYBOARD_INPUT_FROM_X11
|
||||
@@ -1070,12 +1101,15 @@ void psPostRWinit(void)
|
||||
glfwSetWindowIconifyCallback(PSGLOBAL(window), windowIconifyCB);
|
||||
glfwSetWindowFocusCallback(PSGLOBAL(window), windowFocusCB);
|
||||
glfwSetJoystickCallback(joysChangeCB);
|
||||
#endif
|
||||
|
||||
_InputInitialiseJoys();
|
||||
_InputInitialiseMouse(false);
|
||||
|
||||
#if !defined(PSP2)
|
||||
if(!(vm.flags & rwVIDEOMODEEXCLUSIVE))
|
||||
glfwSetWindowSize(PSGLOBAL(window), RsGlobal.maximumWidth, RsGlobal.maximumHeight);
|
||||
#endif
|
||||
|
||||
// Make sure all keys are released
|
||||
CPad::GetPad(0)->Clear(true);
|
||||
@@ -1374,7 +1408,7 @@ void HandleExit()
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
#if !defined(_WIN32) && !defined(PSP2)
|
||||
void terminateHandler(int sig, siginfo_t *info, void *ucontext) {
|
||||
RsGlobal.quit = TRUE;
|
||||
}
|
||||
@@ -1386,6 +1420,7 @@ void dummyHandler(int sig){
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if !defined(PSP2)
|
||||
void resizeCB(GLFWwindow* window, int width, int height) {
|
||||
/*
|
||||
* Handle event to ensure window contents are displayed during re-size
|
||||
@@ -1830,14 +1865,18 @@ void checkKeyPresses()
|
||||
|
||||
}
|
||||
#endif
|
||||
#endif // !PSP2
|
||||
|
||||
// R* calls that in ControllerConfig, idk why
|
||||
void
|
||||
_InputTranslateShiftKeyUpDown(RsKeyCodes *rs) {
|
||||
#if !defined(PSP2)
|
||||
RsKeyboardEventHandler(lshiftStatus ? rsKEYDOWN : rsKEYUP, &(*rs = rsLSHIFT));
|
||||
RsKeyboardEventHandler(rshiftStatus ? rsKEYDOWN : rsKEYUP, &(*rs = rsRSHIFT));
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !defined(PSP2)
|
||||
// TODO this only works in frontend(and luckily only frontend use this). Fun fact: if I get pos manually in game, glfw reports that it's > 32000
|
||||
void
|
||||
cursorCB(GLFWwindow* window, double xpos, double ypos) {
|
||||
@@ -1854,7 +1893,9 @@ void
|
||||
cursorEnterCB(GLFWwindow* window, int entered) {
|
||||
PSGLOBAL(cursorIsInWindow) = !!entered;
|
||||
}
|
||||
#endif // !PSP2
|
||||
|
||||
#if !defined(PSP2)
|
||||
void
|
||||
windowFocusCB(GLFWwindow* window, int focused) {
|
||||
WindowFocused = !!focused;
|
||||
@@ -1864,6 +1905,7 @@ void
|
||||
windowIconifyCB(GLFWwindow* window, int iconified) {
|
||||
WindowIconified = !!iconified;
|
||||
}
|
||||
#endif // !PSP2
|
||||
|
||||
/*
|
||||
*****************************************************************************
|
||||
@@ -1902,9 +1944,35 @@ WinMain(HINSTANCE instance,
|
||||
#endif
|
||||
|
||||
#else
|
||||
#ifdef PSP2
|
||||
SceTouchPanelInfo panelInfo[2];
|
||||
#endif
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
#ifdef PSP2
|
||||
sceCtrlSetSamplingModeExt(SCE_CTRL_MODE_ANALOG_WIDE);
|
||||
sceTouchSetSamplingState(SCE_TOUCH_PORT_FRONT, SCE_TOUCH_SAMPLING_STATE_START);
|
||||
sceTouchSetSamplingState(SCE_TOUCH_PORT_BACK, SCE_TOUCH_SAMPLING_STATE_START);
|
||||
// The stock clocks are not enough for this; the port has always overclocked.
|
||||
scePowerSetArmClockFrequency(444);
|
||||
scePowerSetBusClockFrequency(222);
|
||||
scePowerSetGpuClockFrequency(222);
|
||||
scePowerSetGpuXbarClockFrequency(166);
|
||||
sceTouchGetPanelInfo(SCE_TOUCH_PORT_FRONT, &panelInfo[0]);
|
||||
sceTouchGetPanelInfo(SCE_TOUCH_PORT_BACK, &panelInfo[1]);
|
||||
|
||||
// Marker file: bail out with a readable message instead of crashing later if the
|
||||
// game data was never copied over.
|
||||
if (!fileExists(RT_INI_PATH))
|
||||
{
|
||||
showMsgDialog("Liberty's gone quiet.\nNo game files found at " DATA_PATH);
|
||||
sceKernelExitProcess(1);
|
||||
}
|
||||
#ifndef ENABLE_STDOUT
|
||||
fclose(stdout);
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
RwV2d pos;
|
||||
RwInt32 i;
|
||||
@@ -1913,7 +1981,7 @@ main(int argc, char *argv[])
|
||||
InitMemoryMgr();
|
||||
#endif
|
||||
|
||||
#if !defined(_WIN32) && !defined(__SWITCH__)
|
||||
#if !defined(_WIN32) && !defined(__SWITCH__) && !defined(PSP2)
|
||||
struct sigaction act;
|
||||
act.sa_sigaction = terminateHandler;
|
||||
act.sa_flags = SA_SIGINFO;
|
||||
@@ -1966,7 +2034,9 @@ main(int argc, char *argv[])
|
||||
openParams.width = RsGlobal.maximumWidth;
|
||||
openParams.height = RsGlobal.maximumHeight;
|
||||
openParams.windowtitle = RsGlobal.appName;
|
||||
#if !defined(PSP2)
|
||||
openParams.window = &PSGLOBAL(window);
|
||||
#endif
|
||||
|
||||
ControlsManager.MakeControllerActionsBlank();
|
||||
ControlsManager.InitDefaultControlConfiguration();
|
||||
@@ -2086,7 +2156,9 @@ main(int argc, char *argv[])
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined(PSP2)
|
||||
initkeymap();
|
||||
#endif
|
||||
|
||||
while ( TRUE )
|
||||
{
|
||||
@@ -2129,7 +2201,9 @@ main(int argc, char *argv[])
|
||||
while( !RsGlobal.quit && !FrontEndMenuManager.m_bWantToRestart && !glfwWindowShouldClose(PSGLOBAL(window)))
|
||||
#endif
|
||||
{
|
||||
#if !defined(PSP2)
|
||||
glfwPollEvents();
|
||||
#endif
|
||||
#ifdef GET_KEYBOARD_INPUT_FROM_X11
|
||||
checkKeyPresses();
|
||||
#endif
|
||||
@@ -2207,7 +2281,7 @@ main(int argc, char *argv[])
|
||||
case GS_INIT_ONCE:
|
||||
{
|
||||
//CoUninitialize();
|
||||
|
||||
|
||||
#ifdef PS2_MENU
|
||||
extern char version_name[64];
|
||||
if ( CGame::frenchGame || CGame::germanGame )
|
||||
@@ -2222,7 +2296,7 @@ main(int argc, char *argv[])
|
||||
#endif
|
||||
if ( !CGame::InitialiseOnceAfterRW() )
|
||||
RsGlobal.quit = TRUE;
|
||||
|
||||
|
||||
#ifdef PS2_MENU
|
||||
gGameState = GS_INIT_PLAYING_GAME;
|
||||
#else
|
||||
@@ -2567,6 +2641,7 @@ void CapturePad(RwInt32 padID)
|
||||
return;
|
||||
}
|
||||
|
||||
#if !defined(PSP2)
|
||||
void joysChangeCB(int jid, int event)
|
||||
{
|
||||
if (event == GLFW_CONNECTED && !IsThisJoystickBlacklisted(jid)) {
|
||||
@@ -2591,6 +2666,7 @@ void joysChangeCB(int jid, int event)
|
||||
PSGLOBAL(joy2id) = -1;
|
||||
}
|
||||
}
|
||||
#endif // !PSP2
|
||||
|
||||
#if (defined(_MSC_VER))
|
||||
int strcasecmp(const char* str1, const char* str2)
|
||||
|
||||
@@ -0,0 +1,126 @@
|
||||
// Vita-only (SceGxm message dialog). Guarded so the file is an empty translation
|
||||
// unit when the premake/CMake source glob pulls it into non-PSP2 platform builds;
|
||||
// the Vita target itself builds via its own Makefile.
|
||||
#ifdef PSP2
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
#include <psp2/display.h>
|
||||
#include <psp2/message_dialog.h>
|
||||
#include <psp2/io/stat.h>
|
||||
#include <psp2/kernel/clib.h>
|
||||
|
||||
#include "message.h"
|
||||
|
||||
GxmDrawer::GxmDrawer() {
|
||||
constexpr SceGxmInitializeParams params{
|
||||
0, DISPLAY_MAX_PENDING_SWAPS, gxmVsyncCb, sizeof(void *),
|
||||
SCE_GXM_DEFAULT_PARAMETER_BUFFER_SIZE};
|
||||
sceGxmInitialize(¶ms);
|
||||
|
||||
|
||||
for (auto &buf: displayBuf_) {
|
||||
buf.data = dramAlloc(4 * DISPLAY_STRIDE_IN_PIXELS * DISPLAY_HEIGHT,
|
||||
&buf.uid);
|
||||
sceGxmColorSurfaceInit(&buf.surf, SCE_GXM_COLOR_FORMAT_A8B8G8R8,
|
||||
SCE_GXM_COLOR_SURFACE_LINEAR,
|
||||
SCE_GXM_COLOR_SURFACE_SCALE_NONE,
|
||||
SCE_GXM_OUTPUT_REGISTER_SIZE_32BIT,
|
||||
DISPLAY_WIDTH, DISPLAY_HEIGHT,
|
||||
DISPLAY_STRIDE_IN_PIXELS, buf.data);
|
||||
sceGxmSyncObjectCreate(&buf.sync);
|
||||
}
|
||||
}
|
||||
|
||||
GxmDrawer::~GxmDrawer() {
|
||||
sceGxmTerminate();
|
||||
|
||||
for (const auto &buf: displayBuf_) {
|
||||
sceGxmSyncObjectDestroy(buf.sync);
|
||||
sceKernelFreeMemBlock(buf.uid);
|
||||
}
|
||||
}
|
||||
|
||||
void GxmDrawer::gxmSwap() {
|
||||
sceGxmPadHeartbeat(&displayBuf_[backBufferIndex_].surf,
|
||||
displayBuf_[backBufferIndex_].sync);
|
||||
sceGxmDisplayQueueAddEntry(displayBuf_[frontBufferIndex_].sync,
|
||||
displayBuf_[backBufferIndex_].sync,
|
||||
&displayBuf_[backBufferIndex_].data);
|
||||
frontBufferIndex_ = backBufferIndex_;
|
||||
backBufferIndex_ = (backBufferIndex_ + 1) % DISPLAY_BUFFER_COUNT;
|
||||
}
|
||||
|
||||
void GxmDrawer::clearScreenBuffer() const {
|
||||
sceClibMemset(displayBuf_[backBufferIndex_].data,
|
||||
static_cast<int>(0xFF000000),
|
||||
DISPLAY_HEIGHT * DISPLAY_STRIDE_IN_PIXELS * 4);
|
||||
}
|
||||
|
||||
void GxmDrawer::updateSceDialog() const {
|
||||
const SceCommonDialogUpdateParam updateParam{
|
||||
{nullptr, displayBuf_[backBufferIndex_].data,
|
||||
static_cast<SceGxmColorSurfaceType>(0),
|
||||
static_cast<SceGxmColorFormat>(0), DISPLAY_WIDTH,
|
||||
DISPLAY_HEIGHT, DISPLAY_STRIDE_IN_PIXELS},
|
||||
displayBuf_[backBufferIndex_].sync};
|
||||
sceCommonDialogUpdate(&updateParam);
|
||||
}
|
||||
|
||||
void *GxmDrawer::dramAlloc(const std::uint32_t size, SceUID *uid) {
|
||||
void *mem;
|
||||
*uid = sceKernelAllocMemBlock("gpu_mem",
|
||||
SCE_KERNEL_MEMBLOCK_TYPE_USER_CDRAM_RW,
|
||||
ALIGN(size, 256 * 1024), nullptr);
|
||||
sceKernelGetMemBlockBase(*uid, &mem);
|
||||
sceGxmMapMemory(mem, ALIGN(size, 256 * 1024),
|
||||
static_cast<SceGxmMemoryAttribFlags>(
|
||||
SCE_GXM_MEMORY_ATTRIB_READ |
|
||||
SCE_GXM_MEMORY_ATTRIB_WRITE));
|
||||
return mem;
|
||||
}
|
||||
|
||||
void GxmDrawer::gxmVsyncCb(const void *callbackData) {
|
||||
const SceDisplayFrameBuf fb{
|
||||
sizeof(SceDisplayFrameBuf),
|
||||
*static_cast<void **>(const_cast<void *>(callbackData)),
|
||||
DISPLAY_STRIDE_IN_PIXELS,
|
||||
0,
|
||||
DISPLAY_WIDTH,
|
||||
DISPLAY_HEIGHT};
|
||||
sceDisplaySetFrameBuf(&fb, SCE_DISPLAY_SETBUF_NEXTFRAME);
|
||||
}
|
||||
|
||||
void showMsgDialog(const char *message) {
|
||||
GxmDrawer gxmDrawer;
|
||||
|
||||
SceMsgDialogUserMessageParam msgParam;
|
||||
sceClibMemset(&msgParam, 0, sizeof(SceMsgDialogUserMessageParam));
|
||||
msgParam.buttonType = SCE_MSG_DIALOG_BUTTON_TYPE_OK;
|
||||
msgParam.msg = reinterpret_cast<const SceChar8 *>(message);
|
||||
|
||||
SceMsgDialogParam param;
|
||||
sceMsgDialogParamInit(¶m);
|
||||
param.mode = SCE_MSG_DIALOG_MODE_USER_MSG;
|
||||
param.userMsgParam = &msgParam;
|
||||
|
||||
constexpr SceCommonDialogConfigParam confParam{};
|
||||
sceCommonDialogSetConfigParam(&confParam);
|
||||
sceMsgDialogInit(¶m);
|
||||
|
||||
while (sceMsgDialogGetStatus() != SCE_COMMON_DIALOG_STATUS_FINISHED) {
|
||||
gxmDrawer.clearScreenBuffer();
|
||||
gxmDrawer.updateSceDialog();
|
||||
|
||||
gxmDrawer.gxmSwap();
|
||||
sceDisplayWaitVblankStart();
|
||||
}
|
||||
sceMsgDialogTerm();
|
||||
}
|
||||
|
||||
int fileExists(const char *path) {
|
||||
SceIoStat stat;
|
||||
return sceIoGetstat(path, &stat) >= 0;
|
||||
}
|
||||
|
||||
#endif // PSP2
|
||||
@@ -0,0 +1,53 @@
|
||||
#ifndef MESSAGE_H
|
||||
#define MESSAGE_H
|
||||
|
||||
// Vita-only (SceGxm). Everything here pulls psp2/* headers, so keep it out of
|
||||
// non-PSP2 builds that include this header via the source glob. See message.cpp.
|
||||
#ifdef PSP2
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
|
||||
#include <psp2/gxm.h>
|
||||
#include <psp2/kernel/sysmem.h>
|
||||
|
||||
#ifndef ALIGN
|
||||
#define ALIGN(x, a) (((x) + ((a) - 1)) & ~((a) - 1))
|
||||
#endif // ALIGN
|
||||
|
||||
struct DisplayBuffer {
|
||||
void *data;
|
||||
SceGxmSyncObject *sync;
|
||||
SceGxmColorSurface surf;
|
||||
SceUID uid;
|
||||
}; // struct DisplayBuffer
|
||||
|
||||
class GxmDrawer {
|
||||
public:
|
||||
GxmDrawer();
|
||||
~GxmDrawer();
|
||||
|
||||
void gxmSwap();
|
||||
void clearScreenBuffer() const;
|
||||
void updateSceDialog() const;
|
||||
|
||||
static void *dramAlloc(std::uint32_t size, SceUID *uid);
|
||||
static void gxmVsyncCb(const void *callbackData);
|
||||
|
||||
private:
|
||||
static constexpr int DISPLAY_WIDTH{960};
|
||||
static constexpr int DISPLAY_HEIGHT{544};
|
||||
static constexpr int DISPLAY_STRIDE_IN_PIXELS{1024};
|
||||
static constexpr int DISPLAY_BUFFER_COUNT{2};
|
||||
static constexpr int DISPLAY_MAX_PENDING_SWAPS{1};
|
||||
|
||||
std::uint32_t backBufferIndex_{}, frontBufferIndex_{};
|
||||
std::array<DisplayBuffer, DISPLAY_BUFFER_COUNT> displayBuf_{};
|
||||
}; // class GxmDrawer
|
||||
|
||||
void showMsgDialog(const char *message);
|
||||
int fileExists(const char *path);
|
||||
|
||||
#endif // PSP2
|
||||
|
||||
#endif //MESSAGE_H
|
||||