From 01ea7801fdd51852a4312350cd6c8bf91efe8666 Mon Sep 17 00:00:00 2001 From: Andrew Udvare Date: Tue, 29 Sep 2020 20:39:18 -0400 Subject: [PATCH 1/4] macOS support; thanks to @MrYadro This should support ARM64 and x86-64. -target flag based on information from https://developer.apple.com/documentation/xcode/building_a_universal_macos_binary#3618377. --- .travis.yml | 43 ++++++++++++++++++---- premake5.lua | 35 ++++++++++++++++++ src/core/CdStreamPosix.cpp | 73 +++++++++++++++++++++++++------------- src/skel/glfw/glfw.cpp | 25 ++++++++++--- 4 files changed, 141 insertions(+), 35 deletions(-) diff --git a/.travis.yml b/.travis.yml index 51ef58eb..c124a9f0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,15 +1,44 @@ language: cpp -os: linux dist: focal -matrix: +os: linux +jobs: include: - env: TARGET=release_linux-amd64-librw_gl3_glfw-oal + os: linux - env: TARGET=debug_linux-amd64-librw_gl3_glfw-oal + os: linux + - env: TARGET=release_macosx-amd64-librw_gl3_glfw-oal PREMAKE5=premake-5.0.0-alpha15 + compiler: clang + os: osx + osx_image: xcode12u + - env: TARGET=debug_macosx-amd64-librw_gl3_glfw-oal PREMAKE5=premake-5.0.0-alpha15 + compiler: clang + os: osx + osx_image: xcode12u +addons: + apt: + update: true + packages: + - linux-libc-dev + - libopenal-dev + - libglew-dev + - libglfw3-dev + - libsndfile1-dev + - libmpg123-dev + - gcc-8-multilib + - g++-8-multilib + homebrew: + packages: + - libsndfile + - mpg123 + - glew + - glfw + - openal-soft script: - - sudo apt-get update - - sudo apt-get -y install linux-libc-dev libopenal-dev libglew-dev libglfw3-dev libsndfile1-dev libmpg123-dev gcc-8-multilib g++-8-multilib - mkdir -p "$TRAVIS_BUILD_DIR/build" - cd "$TRAVIS_BUILD_DIR" - - ./premake5Linux --with-librw gmake2 - - cd build - - CC=gcc-8 CXX=g++-8 make config=$TARGET -j4 verbose=1 + - if [ "$TRAVIS_OS_NAME" = linux ]; then ./premake5Linux --with-librw gmake2; fi + - if [ "$TRAVIS_OS_NAME" = osx ]; then curl -L -o "${PREMAKE5}.zip" "https://github.com/premake/premake-core/releases/download/v5.0.0-alpha15/${PREMAKE5}-src.zip" && unzip -q "${PREMAKE5}.zip" && cd "$PREMAKE5" && make -f Bootstrap.mak osx && cd .. && "./${PREMAKE5}/bin/release/premake5" --with-librw gmake2; fi + - cd build + - if [ "$TRAVIS_OS_NAME" = linux ]; then env CC=gcc-8 CXX=g++-8 make config=$TARGET -j4 verbose=1; fi + - if [ "$TRAVIS_OS_NAME" = osx ]; then make config=$TARGET -j4 verbose=1; fi diff --git a/premake5.lua b/premake5.lua index 881035ef..36388a1e 100644 --- a/premake5.lua +++ b/premake5.lua @@ -85,6 +85,12 @@ workspace "re3" "bsd-amd64-librw_gl3_glfw-oal" } + filter { "system:macosx" } + platforms { + "macosx-amd64-librw_gl3_glfw-oal", + "macosx-arm64-librw_gl3_glfw-oal", + } + filter "configurations:Debug" defines { "DEBUG" } @@ -100,6 +106,9 @@ workspace "re3" filter { "platforms:bsd*" } system "bsd" + + filter { "platforms:macosx*" } + system "macosx" filter { "platforms:*x86*" } architecture "x86" @@ -110,6 +119,12 @@ workspace "re3" filter { "platforms:*arm*" } architecture "ARM" + filter { "platforms:macosx-arm64-*" } + buildoptions { "-target", "arm64-apple-macos11", "-std=gnu++14" } + + filter { "platforms:macosx-amd64-*" } + buildoptions { "-target", "x86_64-apple-macos10.12", "-std=gnu++14" } + filter { "platforms:*librw_d3d9*" } defines { "RW_D3D9" } if(not _OPTIONS["with-librw"]) then @@ -162,6 +177,13 @@ project "librw" filter "platforms:bsd*" includedirs { "/usr/local/include" } libdirs { "/usr/local/lib" } + + filter "platforms:macosx*" + -- Support MacPorts and Homebrew + includedirs { "/opt/local/include" } + includedirs {"/usr/local/include" } + libdirs { "/opt/local/lib" } + libdirs { "/usr/local/lib" } filter "platforms:*RW33*" flags { "ExcludeFromBuild" } @@ -276,6 +298,11 @@ project "re3" filter "platforms:bsd*oal" links { "openal", "mpg123", "sndfile", "pthread" } + + filter "platforms:macosx*oal" + links { "openal", "mpg123", "sndfile", "pthread" } + includedirs { "/usr/local/opt/openal-soft/include" } + libdirs { "/usr/local/opt/openal-soft/lib" } if _OPTIONS["with-opus"] then filter {} @@ -329,3 +356,11 @@ project "re3" links { "GL", "GLEW", "glfw", "sysinfo" } includedirs { "/usr/local/include" } libdirs { "/usr/local/lib" } + + filter "platforms:macosx*gl3_glfw*" + links { "GLEW", "glfw" } + linkoptions { "-framework OpenGL" } + includedirs { "/opt/local/include" } + includedirs { "/usr/local/include" } + libdirs { "/opt/local/lib" } + libdirs { "/usr/local/lib" } diff --git a/src/core/CdStreamPosix.cpp b/src/core/CdStreamPosix.cpp index e114a29a..895143a4 100644 --- a/src/core/CdStreamPosix.cpp +++ b/src/core/CdStreamPosix.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -21,6 +22,30 @@ #define CDDEBUG(f, ...) debug ("%s: " f "\n", "cdvd_stream", ## __VA_ARGS__) #define CDTRACE(f, ...) printf("%s: " f "\n", "cdvd_stream", ## __VA_ARGS__) +#ifdef __APPLE__ +#define COMPAT_SEM_T sem_t * +int compat_sem_init(sem_t **ptr, __attribute__((unused)) int x, __attribute__((unused)) int y) { + *ptr = sem_open("/semaphore", O_CREAT, 0644, 1); + return *ptr == SEM_FAILED ? -1 : 0; +} +int compat_sem_post(sem_t **sem) { + return sem_post(*sem); +} +int compat_sem_wait(sem_t **sem) { + return sem_wait(*sem); +} +int compat_sem_destroy(sem_t **sem, const char * name) { + sem_close(*sem); + sem_unlink(name); +} +#else +#define COMPAT_SEM_T sem_t +#define compat_sem_post sem_post +#define compat_sem_destroy(x, y) sem_destroy(x) +#define compat_sem_init sem_init +#define compat_sem_wait sem_wait +#endif + // #define ONE_THREAD_PER_CHANNEL // Don't use if you're not on SSD/Flash. (Also you may want to benefit from this via using all channels in Streaming.cpp) bool flushStream[MAX_CDCHANNELS]; @@ -35,11 +60,11 @@ struct CdReadInfo int32 nStatus; #ifdef ONE_THREAD_PER_CHANNEL int8 nThreadStatus; // 0: created 1:initalized 2:abort now - pthread_t pChannelThread; - sem_t pStartSemaphore; + pthread_t pChannelThread; + COMPAT_SEM_T pStartSemaphore; #endif - sem_t pDoneSemaphore; // used for CdStreamSync - int32 hFile; + COMPAT_SEM_T pDoneSemaphore; // used for CdStreamSync + int32 hFile; }; char gCdImageNames[MAX_CDIMAGES+1][64]; @@ -51,7 +76,7 @@ char *gImgNames[MAX_CDIMAGES]; #ifndef ONE_THREAD_PER_CHANNEL pthread_t _gCdStreamThread; -sem_t gCdStreamSema; // released when we have new thing to read(so channel is set) +COMPAT_SEM_T gCdStreamSema; // released when we have new thing to read(so channel is set) int8 gCdStreamThreadStatus; // 0: created 1:initalized 2:abort now Queue gChannelRequestQ; bool _gbCdStreamOverlapped; @@ -76,7 +101,7 @@ CdStreamInitThread(void) gChannelRequestQ.tail = 0; gChannelRequestQ.size = gNumChannels + 1; ASSERT(gChannelRequestQ.items != nil ); - status = sem_init(&gCdStreamSema, 0, 0); + status = compat_sem_init(&gCdStreamSema, 0, 0); #endif @@ -91,7 +116,7 @@ CdStreamInitThread(void) { for ( int32 i = 0; i < gNumChannels; i++ ) { - status = sem_init(&gpReadInfo[i].pDoneSemaphore, 0, 0); + status = compat_sem_init(&gpReadInfo[i].pDoneSemaphore, 0, 0); if (status == -1) { @@ -100,7 +125,7 @@ CdStreamInitThread(void) return; } #ifdef ONE_THREAD_PER_CHANNEL - status = sem_init(&gpReadInfo[i].pStartSemaphore, 0, 0); + status = compat_sem_init(&gpReadInfo[i].pStartSemaphore, 0, 0); if (status == -1) { @@ -214,13 +239,13 @@ CdStreamShutdown(void) // Destroying semaphores and free(gpReadInfo) will be done at threads #ifndef ONE_THREAD_PER_CHANNEL gCdStreamThreadStatus = 2; - sem_post(&gCdStreamSema); + compat_sem_post(&gCdStreamSema); #endif #ifdef ONE_THREAD_PER_CHANNEL for ( int32 i = 0; i < gNumChannels; i++ ) { gpReadInfo[i].nThreadStatus = 2; - sem_post(&gpReadInfo[i].pStartSemaphore); + compat_sem_post(&gpReadInfo[i].pStartSemaphore); } #endif } @@ -254,10 +279,10 @@ CdStreamRead(int32 channel, void *buffer, uint32 offset, uint32 size) #ifndef ONE_THREAD_PER_CHANNEL AddToQueue(&gChannelRequestQ, channel); - if ( sem_post(&gCdStreamSema) != 0 ) + if ( compat_sem_post(&gCdStreamSema) != 0 ) printf("Signal Sema Error\n"); #else - if ( sem_post(&gpReadInfo[channel].pStartSemaphore) != 0 ) + if ( compat_sem_post(&gpReadInfo[channel].pStartSemaphore) != 0 ) printf("Signal Sema Error\n"); #endif @@ -332,7 +357,7 @@ CdStreamSync(int32 channel) { pChannel->bLocked = true; - sem_wait(&pChannel->pDoneSemaphore); + compat_sem_wait(&pChannel->pDoneSemaphore); } pChannel->bReading = false; @@ -383,12 +408,12 @@ void *CdStreamThread(void *param) #ifndef ONE_THREAD_PER_CHANNEL while (gCdStreamThreadStatus != 2) { - sem_wait(&gCdStreamSema); + compat_sem_wait(&gCdStreamSema); int32 channel = GetFirstInQueue(&gChannelRequestQ); #else int channel = *((int*)param); while (gpReadInfo[channel].nThreadStatus != 2){ - sem_wait(&gpReadInfo[channel].pStartSemaphore); + compat_sem_wait(&gpReadInfo[channel].pStartSemaphore); #endif ASSERT( channel < gNumChannels ); @@ -437,22 +462,22 @@ void *CdStreamThread(void *param) if ( pChannel->bLocked ) { - sem_post(&pChannel->pDoneSemaphore); + compat_sem_post(&pChannel->pDoneSemaphore); } pChannel->bReading = false; } #ifndef ONE_THREAD_PER_CHANNEL - for ( int32 i = 0; i < gNumChannels; i++ ) - { - sem_destroy(&gpReadInfo[i].pDoneSemaphore); - } - sem_destroy(&gCdStreamSema); + for ( int32 i = 0; i < gNumChannels; i++ ) + { + compat_sem_destroy(&gpReadInfo[i].pDoneSemaphore, "/semaphoredone"); + } + compat_sem_destroy(&gCdStreamSema, "/semaphore"); free(gChannelRequestQ.items); #else - sem_destroy(&gpReadInfo[channel].pStartSemaphore); - sem_destroy(&gpReadInfo[channel].pDoneSemaphore); + compat_sem_destroy(&gpReadInfo[channel].pStartSemaphore, "/semaphorestart"); + compat_sem_destroy(&gpReadInfo[channel].pDoneSemaphore, "/semaphoredone"); #endif - free(gpReadInfo); + free(gpReadInfo); pthread_exit(nil); } diff --git a/src/skel/glfw/glfw.cpp b/src/skel/glfw/glfw.cpp index b9dbf5ac..48701921 100644 --- a/src/skel/glfw/glfw.cpp +++ b/src/skel/glfw/glfw.cpp @@ -81,7 +81,12 @@ DWORD _dwOperatingSystemVersion; #include "resource.h" #else long _dwOperatingSystemVersion; +#ifndef __APPLE__ #include +#else +#include +#include +#endif #include #include #include @@ -445,15 +450,27 @@ psInitialize(void) #endif #endif +#ifndef __APPLE__ struct sysinfo systemInfo; sysinfo(&systemInfo); - _dwMemAvailPhys = systemInfo.freeram; - _dwOperatingSystemVersion = OS_WINXP; // To fool other classes - debug("Physical memory size %u\n", systemInfo.totalram); debug("Available physical memory %u\n", systemInfo.freeram); - +#else + uint64_t size = 0; + uint64_t page_size = 0; + size_t uint64_len = sizeof(uint64_t); + size_t ull_len = sizeof(unsigned long long); + sysctl((int[]){CTL_HW, HW_PAGESIZE}, 2, &page_size, &ull_len, NULL, 0); + sysctl((int[]){CTL_HW, HW_MEMSIZE}, 2, &size, &uint64_len, NULL, 0); + vm_statistics_data_t vm_stat; + mach_msg_type_number_t count = HOST_VM_INFO_COUNT; + host_statistics(mach_host_self(), HOST_VM_INFO, (host_info_t)&vm_stat, &count); + _dwMemAvailPhys = (uint64_t)(vm_stat.free_count * page_size); + debug("Physical memory size %llu\n", _dwMemAvailPhys); + debug("Available physical memory %llu\n", size); +#endif + _dwOperatingSystemVersion = OS_WINXP; // To fool other classes #endif TheText.Unload(); From bbb578c5b1cd603b61ebd5f6fec184477f1c5dd4 Mon Sep 17 00:00:00 2001 From: Andrew Udvare Date: Thu, 1 Oct 2020 03:21:06 -0400 Subject: [PATCH 2/4] core/CdStreamPosix: switch to named semaphores to support macOS macOS does not support unnamed semaphores. The functions return ENOSYS. --- src/core/CdStreamPosix.cpp | 87 +++++++++++++++----------------------- 1 file changed, 33 insertions(+), 54 deletions(-) diff --git a/src/core/CdStreamPosix.cpp b/src/core/CdStreamPosix.cpp index 895143a4..3d9316c9 100644 --- a/src/core/CdStreamPosix.cpp +++ b/src/core/CdStreamPosix.cpp @@ -4,7 +4,6 @@ #include #include #include -#include #include #include #include @@ -22,30 +21,6 @@ #define CDDEBUG(f, ...) debug ("%s: " f "\n", "cdvd_stream", ## __VA_ARGS__) #define CDTRACE(f, ...) printf("%s: " f "\n", "cdvd_stream", ## __VA_ARGS__) -#ifdef __APPLE__ -#define COMPAT_SEM_T sem_t * -int compat_sem_init(sem_t **ptr, __attribute__((unused)) int x, __attribute__((unused)) int y) { - *ptr = sem_open("/semaphore", O_CREAT, 0644, 1); - return *ptr == SEM_FAILED ? -1 : 0; -} -int compat_sem_post(sem_t **sem) { - return sem_post(*sem); -} -int compat_sem_wait(sem_t **sem) { - return sem_wait(*sem); -} -int compat_sem_destroy(sem_t **sem, const char * name) { - sem_close(*sem); - sem_unlink(name); -} -#else -#define COMPAT_SEM_T sem_t -#define compat_sem_post sem_post -#define compat_sem_destroy(x, y) sem_destroy(x) -#define compat_sem_init sem_init -#define compat_sem_wait sem_wait -#endif - // #define ONE_THREAD_PER_CHANNEL // Don't use if you're not on SSD/Flash. (Also you may want to benefit from this via using all channels in Streaming.cpp) bool flushStream[MAX_CDCHANNELS]; @@ -60,11 +35,11 @@ struct CdReadInfo int32 nStatus; #ifdef ONE_THREAD_PER_CHANNEL int8 nThreadStatus; // 0: created 1:initalized 2:abort now - pthread_t pChannelThread; - COMPAT_SEM_T pStartSemaphore; + pthread_t pChannelThread; + sem_t *pStartSemaphore; #endif - COMPAT_SEM_T pDoneSemaphore; // used for CdStreamSync - int32 hFile; + sem_t *pDoneSemaphore; // used for CdStreamSync + int32 hFile; }; char gCdImageNames[MAX_CDIMAGES+1][64]; @@ -76,7 +51,7 @@ char *gImgNames[MAX_CDIMAGES]; #ifndef ONE_THREAD_PER_CHANNEL pthread_t _gCdStreamThread; -COMPAT_SEM_T gCdStreamSema; // released when we have new thing to read(so channel is set) +sem_t *gCdStreamSema; // released when we have new thing to read(so channel is set) int8 gCdStreamThreadStatus; // 0: created 1:initalized 2:abort now Queue gChannelRequestQ; bool _gbCdStreamOverlapped; @@ -101,11 +76,11 @@ CdStreamInitThread(void) gChannelRequestQ.tail = 0; gChannelRequestQ.size = gNumChannels + 1; ASSERT(gChannelRequestQ.items != nil ); - status = compat_sem_init(&gCdStreamSema, 0, 0); + gCdStreamSema = sem_open("/semaphore_cd_stream", O_CREAT, 0644, 1); #endif - if (status == -1) { + if (gCdStreamSema == SEM_FAILED) { CDTRACE("failed to create stream semaphore"); ASSERT(0); return; @@ -116,18 +91,18 @@ CdStreamInitThread(void) { for ( int32 i = 0; i < gNumChannels; i++ ) { - status = compat_sem_init(&gpReadInfo[i].pDoneSemaphore, 0, 0); + gpReadInfo[i].pDoneSemaphore = sem_open("/semaphore_done", O_CREAT, 0644, 1); - if (status == -1) + if (gpReadInfo[i].pDoneSemaphore == SEM_FAILED) { CDTRACE("failed to create sync semaphore"); ASSERT(0); return; } #ifdef ONE_THREAD_PER_CHANNEL - status = compat_sem_init(&gpReadInfo[i].pStartSemaphore, 0, 0); + gpReadInfo[i].pStartSemaphore = sem_open("/semaphore_start", O_CREAT, 0644, 1); - if (status == -1) + if (gpReadInfo[i].pStartSemaphore == SEM_FAILED) { CDTRACE("failed to create start semaphore"); ASSERT(0); @@ -160,7 +135,7 @@ CdStreamInitThread(void) return; } #else - debug("Using seperate streaming threads for each channel\n"); + debug("Using separate streaming threads for each channel\n"); #endif } @@ -239,13 +214,13 @@ CdStreamShutdown(void) // Destroying semaphores and free(gpReadInfo) will be done at threads #ifndef ONE_THREAD_PER_CHANNEL gCdStreamThreadStatus = 2; - compat_sem_post(&gCdStreamSema); + sem_post(gCdStreamSema); #endif #ifdef ONE_THREAD_PER_CHANNEL for ( int32 i = 0; i < gNumChannels; i++ ) { gpReadInfo[i].nThreadStatus = 2; - compat_sem_post(&gpReadInfo[i].pStartSemaphore); + sem_post(&gpReadInfo[i].pStartSemaphore); } #endif } @@ -279,10 +254,10 @@ CdStreamRead(int32 channel, void *buffer, uint32 offset, uint32 size) #ifndef ONE_THREAD_PER_CHANNEL AddToQueue(&gChannelRequestQ, channel); - if ( compat_sem_post(&gCdStreamSema) != 0 ) + if ( sem_post(gCdStreamSema) != 0 ) printf("Signal Sema Error\n"); #else - if ( compat_sem_post(&gpReadInfo[channel].pStartSemaphore) != 0 ) + if ( sem_post(&gpReadInfo[channel].pStartSemaphore) != 0 ) printf("Signal Sema Error\n"); #endif @@ -357,7 +332,7 @@ CdStreamSync(int32 channel) { pChannel->bLocked = true; - compat_sem_wait(&pChannel->pDoneSemaphore); + sem_wait(pChannel->pDoneSemaphore); } pChannel->bReading = false; @@ -408,12 +383,12 @@ void *CdStreamThread(void *param) #ifndef ONE_THREAD_PER_CHANNEL while (gCdStreamThreadStatus != 2) { - compat_sem_wait(&gCdStreamSema); + sem_wait(gCdStreamSema); int32 channel = GetFirstInQueue(&gChannelRequestQ); #else int channel = *((int*)param); while (gpReadInfo[channel].nThreadStatus != 2){ - compat_sem_wait(&gpReadInfo[channel].pStartSemaphore); + sem_wait(&gpReadInfo[channel].pStartSemaphore); #endif ASSERT( channel < gNumChannels ); @@ -462,22 +437,26 @@ void *CdStreamThread(void *param) if ( pChannel->bLocked ) { - compat_sem_post(&pChannel->pDoneSemaphore); + sem_post(pChannel->pDoneSemaphore); } pChannel->bReading = false; } #ifndef ONE_THREAD_PER_CHANNEL - for ( int32 i = 0; i < gNumChannels; i++ ) - { - compat_sem_destroy(&gpReadInfo[i].pDoneSemaphore, "/semaphoredone"); - } - compat_sem_destroy(&gCdStreamSema, "/semaphore"); - free(gChannelRequestQ.items); + for ( int32 i = 0; i < gNumChannels; i++ ) + { + sem_close(gpReadInfo[i].pDoneSemaphore); + sem_unlink("/semaphore_done"); + } + sem_close(gCdStreamSema); + sem_unlink("/semaphore_cd_stream"); + free(gChannelRequestQ.items); #else - compat_sem_destroy(&gpReadInfo[channel].pStartSemaphore, "/semaphorestart"); - compat_sem_destroy(&gpReadInfo[channel].pDoneSemaphore, "/semaphoredone"); + sem_close(gpReadInfo[channel].pStartSemaphore); + sem_unlink("/semaphore_start"); + sem_close(gpReadInfo[channel].pDoneSemaphore); + sem_unlink("/semaphore_done"); #endif - free(gpReadInfo); + free(gpReadInfo); pthread_exit(nil); } From 34579ae9c39e2c0a8c4d136cf0d0dd4c7dac1ade Mon Sep 17 00:00:00 2001 From: Andrew Udvare Date: Thu, 1 Oct 2020 20:44:33 -0400 Subject: [PATCH 3/4] premake5: Place macosx-amd64 after arm64 Fixes xcode4 project from Premake getting the wrong target (for now). --- premake5.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/premake5.lua b/premake5.lua index 36388a1e..49be07c3 100644 --- a/premake5.lua +++ b/premake5.lua @@ -87,8 +87,8 @@ workspace "re3" filter { "system:macosx" } platforms { - "macosx-amd64-librw_gl3_glfw-oal", "macosx-arm64-librw_gl3_glfw-oal", + "macosx-amd64-librw_gl3_glfw-oal", } filter "configurations:Debug" From f6bc2b654c4b6f8ae27646f1a166d3214f6f56aa Mon Sep 17 00:00:00 2001 From: Andrew Udvare Date: Thu, 1 Oct 2020 20:45:38 -0400 Subject: [PATCH 4/4] CdStreamPosix: fix type issues --- src/core/CdStreamPosix.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/CdStreamPosix.cpp b/src/core/CdStreamPosix.cpp index 3d9316c9..40000f03 100644 --- a/src/core/CdStreamPosix.cpp +++ b/src/core/CdStreamPosix.cpp @@ -163,7 +163,7 @@ CdStreamInit(int32 numChannels) debug("Using no buffered loading for streaming\n"); } */ - void *pBuffer = (void *)RwMallocAlign(CDSTREAM_SECTOR_SIZE, fsInfo.f_bsize); + void *pBuffer = (void *)RwMallocAlign(CDSTREAM_SECTOR_SIZE, (RwUInt32)fsInfo.f_bsize); ASSERT( pBuffer != nil ); gNumImages = 0; @@ -205,7 +205,7 @@ GetGTA3ImgSize(void) return 0; } ok: - return statbuf.st_size; + return (uint32)statbuf.st_size; } void