mirror of
https://github.com/TwilitRealm/dusklight
synced 2026-05-27 23:45:55 -04:00
Merge branch 'main' into 26-04-01-quick-transform
This commit is contained in:
@@ -19,6 +19,14 @@ add_subdirectory(extern/aurora EXCLUDE_FROM_ALL)
|
||||
|
||||
option(DUSK_BUILD_WARNINGS "If off, compiler warnings will be suppressed")
|
||||
option(DUSK_SELECTED_OPT "If on, selected parts of the project will be compiled with optimizations on Debug, intending to make the game run at 30 FPS. Note for MSVC: you will need to remove '/RTC1' from your debug flags in CMake.")
|
||||
option(DUSK_MOVIE_SUPPORT "If on, compile against libjpeg-turbo to enable THP file decoding" ON)
|
||||
|
||||
find_package(libjpeg-turbo)
|
||||
set(DUSK_MOVIE_SUPPORT_REAL ${DUSK_MOVIE_SUPPORT})
|
||||
if (DUSK_MOVIE_SUPPORT AND NOT libjpeg-turbo_FOUND)
|
||||
message(WARNING "libjpeg-turbo not found but DUSK_MOVIE_SUPPORT set, movie playback will not be available!")
|
||||
set(DUSK_MOVIE_SUPPORT_REAL OFF)
|
||||
endif ()
|
||||
|
||||
if (CMAKE_SYSTEM_NAME STREQUAL Linux)
|
||||
# -Wno-multichar: Multi-character constants ('ABCD') are implementation-defined but all compilers
|
||||
@@ -108,6 +116,10 @@ add_library(game SHARED ${DOLZEL_FILES} ${Z2AUDIOLIB_FILES} ${SSYSTEM_FILES} ${J
|
||||
src/dusk/imgui/ImGuiAudio.cpp)
|
||||
|
||||
target_link_libraries(game PRIVATE game_debug cxxopts::cxxopts absl::flat_hash_map)
|
||||
if (DUSK_MOVIE_SUPPORT_REAL)
|
||||
target_link_libraries(game PRIVATE libjpeg-turbo::turbojpeg-static)
|
||||
target_compile_definitions(game PRIVATE MOVIE_SUPPORT=1)
|
||||
endif ()
|
||||
target_compile_definitions(game PRIVATE TARGET_PC AVOID_UB=1 VERSION=0 NDEBUG=1 NDEBUG_DEFINED=1 DEBUG_DEFINED=0
|
||||
DUSK_TP_VERSION="${DUSK_TP_VERSION}" DUSK_GAME_NAME="${DUSK_GAME_NAME}" DUSK_GAME_VERSION="${DUSK_GAME_VERSION}")
|
||||
target_precompile_headers(game PRIVATE "$<$<COMPILE_LANGUAGE:CXX>:${CMAKE_SOURCE_DIR}/include/dusk_pch.hpp>")
|
||||
|
||||
Vendored
+1
-1
Submodule extern/aurora updated: 6b9f614d32...4c56dba0a4
@@ -1335,6 +1335,7 @@ set(DUSK_FILES
|
||||
src/d/actor/d_a_alink_quicktransform.cpp
|
||||
src/dusk/asserts.cpp
|
||||
src/dusk/logging.cpp
|
||||
src/dusk/layout.cpp
|
||||
src/dusk/stubs.cpp
|
||||
src/dusk/endian.cpp
|
||||
src/dusk/extras.c
|
||||
@@ -1347,6 +1348,8 @@ set(DUSK_FILES
|
||||
src/dusk/imgui/ImGuiMenuGame.hpp
|
||||
src/dusk/imgui/ImGuiMenuTools.cpp
|
||||
src/dusk/imgui/ImGuiMenuTools.hpp
|
||||
src/dusk/imgui/ImGuiMenuEnhancements.cpp
|
||||
src/dusk/imgui/ImGuiMenuEnhancements.hpp
|
||||
src/dusk/imgui/ImGuiProcessOverlay.cpp
|
||||
src/dusk/imgui/ImGuiCameraOverlay.cpp
|
||||
src/dusk/imgui/ImGuiHeapOverlay.cpp
|
||||
|
||||
@@ -8429,11 +8429,4 @@ inline daAlink_c* daAlink_getAlinkActorClass() {
|
||||
return (daAlink_c*)dComIfGp_getLinkPlayer();
|
||||
}
|
||||
|
||||
#if TARGET_PC
|
||||
namespace dusk::tweaks {
|
||||
extern bool FastIronBoots;
|
||||
extern bool QuickTransform;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* D_A_D_A_ALINK_H */
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
#ifndef D_A_MOVIE_PLAYER_H
|
||||
#define D_A_MOVIE_PLAYER_H
|
||||
|
||||
#if !TARGET_PC
|
||||
#include <thp.h>
|
||||
#else
|
||||
#include <atomic>
|
||||
#endif
|
||||
#include "f_op/f_op_actor.h"
|
||||
#include "d/d_drawlist.h"
|
||||
|
||||
@@ -11,6 +15,85 @@ struct daMP_THPReadBuffer {
|
||||
BOOL isValid;
|
||||
};
|
||||
|
||||
#if TARGET_PC
|
||||
// Copying here because thp.h is probably erroneous in the dolphin lib,
|
||||
// and it's kind of a problem being there (Aurora owns the headers).
|
||||
// TODO: Move this stuff in decomp?
|
||||
typedef struct THPAudioRecordHeader {
|
||||
BE(u32) offsetNextChannel;
|
||||
BE(u32) sampleSize;
|
||||
BE(s16) lCoef[8][2];
|
||||
BE(s16) rCoef[8][2];
|
||||
BE(s16) lYn1;
|
||||
BE(s16) lYn2;
|
||||
BE(s16) rYn1;
|
||||
BE(s16) rYn2;
|
||||
} THPAudioRecordHeader;
|
||||
|
||||
typedef struct THPAudioDecodeInfo {
|
||||
u8* encodeData;
|
||||
u32 offsetNibbles;
|
||||
u8 predictor;
|
||||
u8 scale;
|
||||
s16 yn1;
|
||||
s16 yn2;
|
||||
} THPAudioDecodeInfo;
|
||||
|
||||
typedef struct THPTextureSet {
|
||||
u8* ytexture;
|
||||
u8* utexture;
|
||||
u8* vtexture;
|
||||
s32 frameNumber;
|
||||
} THPTextureSet;
|
||||
|
||||
typedef struct THPAudioBuffer {
|
||||
s16* buffer;
|
||||
s16* curPtr;
|
||||
u32 validSample;
|
||||
} THPAudioBuffer;
|
||||
|
||||
typedef struct THPVideoInfo {
|
||||
BE(u32) xSize;
|
||||
BE(u32) ySize;
|
||||
BE(u32) videoType;
|
||||
} THPVideoInfo;
|
||||
|
||||
typedef struct THPAudioInfo {
|
||||
BE(u32) sndChannels;
|
||||
BE(u32) sndFrequency;
|
||||
BE(u32) sndNumSamples;
|
||||
BE(u32) sndNumTracks;
|
||||
} THPAudioInfo;
|
||||
|
||||
typedef struct THPFrameCompInfo {
|
||||
BE(u32) numComponents;
|
||||
u8 frameComp[16];
|
||||
} THPFrameCompInfo;
|
||||
|
||||
typedef struct THPHeader {
|
||||
/* 0x00 */ char magic[4];
|
||||
/* 0x04 */ BE(u32) version;
|
||||
/* 0x08 */ BE(u32) bufsize;
|
||||
/* 0x0C */ BE(u32) audioMaxSamples;
|
||||
/* 0x10 */ BE(f32) frameRate;
|
||||
/* 0x14 */ BE(u32) numFrames;
|
||||
/* 0x18 */ BE(u32) firstFrameSize;
|
||||
/* 0x1C */ BE(u32) movieDataSize;
|
||||
/* 0x20 */ BE(u32) compInfoDataOffsets;
|
||||
/* 0x24 */ BE(u32) offsetDataOffsets;
|
||||
/* 0x28 */ BE(u32) movieDataOffsets;
|
||||
/* 0x2C */ BE(u32) finalFrameDataOffsets;
|
||||
} THPHeader;
|
||||
|
||||
static u32 THPAudioDecode(s16* audioBuffer, u8* audioFrame, s32 flag);
|
||||
static s32 __THPAudioGetNewSample(THPAudioDecodeInfo* info);
|
||||
static void __THPAudioInitialize(THPAudioDecodeInfo* info, u8* ptr);
|
||||
|
||||
#define THP_AUDIO_BUFFER_COUNT 3
|
||||
#define THP_READ_BUFFER_COUNT 10
|
||||
#define THP_TEXTURE_SET_COUNT 3
|
||||
#endif
|
||||
|
||||
struct daMP_THPPlayer {
|
||||
/* 0x000 */ DVDFileInfo fileInfo;
|
||||
/* 0x03C */ THPHeader header;
|
||||
@@ -34,7 +117,11 @@ struct daMP_THPPlayer {
|
||||
/* 0x0C8 */ s64 retaceCount;
|
||||
/* 0x0D0 */ s32 prevCount;
|
||||
/* 0x0D4 */ s32 curCount;
|
||||
#if TARGET_PC
|
||||
/* 0x0D8 */ std::atomic<s32> videoDecodeCount;
|
||||
#else
|
||||
/* 0x0D8 */ s32 videoDecodeCount;
|
||||
#endif
|
||||
/* 0x0DC */ f32 curVolume;
|
||||
/* 0x0E0 */ f32 targetVolume;
|
||||
/* 0x0E4 */ f32 deltaVolume;
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
#ifndef DUSK_LAYOUT_H
|
||||
#define DUSK_LAYOUT_H
|
||||
|
||||
#include "dolphin/types.h"
|
||||
|
||||
namespace dusk {
|
||||
|
||||
/**
|
||||
* Helper struct for laying things out on the screen. Represents a rectangle via two corner
|
||||
* positions.
|
||||
*/
|
||||
struct LayoutRect {
|
||||
f32 PosX;
|
||||
f32 PosY;
|
||||
f32 PosX2;
|
||||
f32 PosY2;
|
||||
|
||||
[[nodiscard]] constexpr f32 Width() const {
|
||||
return PosX2 - PosX;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr f32 Height() const {
|
||||
return PosY2 - PosY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the position to render one rectangle inside another, centered and maintaining aspect ratio.
|
||||
*/
|
||||
[[nodiscard]] static LayoutRect FitRectInRect(
|
||||
f32 widthOuter,
|
||||
f32 heightOuter,
|
||||
f32 widthInner,
|
||||
f32 heightInner);
|
||||
};
|
||||
}
|
||||
|
||||
#endif // DUSK_LAYOUT_H
|
||||
@@ -617,5 +617,8 @@ static const auto gameRegions = std::to_array({
|
||||
MapEntry("Cutscene: Hyrule Castle Throne Room", "R_SP301", {
|
||||
{0, {0, 20, 100}},
|
||||
}),
|
||||
MapEntry("Title screen movie map", "S_MV000", {
|
||||
{0, {0, 1}},
|
||||
}),
|
||||
})
|
||||
});
|
||||
|
||||
@@ -101,11 +101,22 @@ public:
|
||||
}
|
||||
return message;
|
||||
}
|
||||
#ifdef TARGET_PC
|
||||
OSMessage waitMessageBlock(BOOL* received) {
|
||||
OSMessage message;
|
||||
BOOL rv = OSReceiveMessage(&mMessageQueue, &message, OS_MESSAGE_BLOCK);
|
||||
if (received) {
|
||||
*received = rv;
|
||||
}
|
||||
return message;
|
||||
}
|
||||
#else
|
||||
OSMessage waitMessageBlock() {
|
||||
OSMessage message;
|
||||
OSReceiveMessage(&mMessageQueue, &message, OS_MESSAGE_BLOCK);
|
||||
return message;
|
||||
}
|
||||
#endif
|
||||
void jamMessageBlock(OSMessage message) {
|
||||
OSJamMessage(&mMessageQueue, message, OS_MESSAGE_BLOCK);
|
||||
}
|
||||
|
||||
@@ -260,6 +260,10 @@ void JASDriver::finishDSPFrame() {
|
||||
}
|
||||
|
||||
void JASDriver::registerMixCallback(MixCallback param_0, JASMixMode param_1) {
|
||||
#if TARGET_PC
|
||||
JASCriticalSection section;
|
||||
#endif
|
||||
|
||||
extMixCallback = param_0;
|
||||
sMixMode = param_1;
|
||||
}
|
||||
|
||||
@@ -85,7 +85,15 @@ void* JASTaskThread::run() {
|
||||
JASThreadCallStack* callstack;
|
||||
OSInitFastCast();
|
||||
do {
|
||||
#ifdef TARGET_PC
|
||||
BOOL received = FALSE;
|
||||
callstack = static_cast<JASThreadCallStack*>(waitMessageBlock(&received));
|
||||
if (!received) {
|
||||
break;
|
||||
}
|
||||
#else
|
||||
callstack = static_cast<JASThreadCallStack*>(waitMessageBlock());
|
||||
#endif
|
||||
if (field_0x84) {
|
||||
OSSleepThread(&threadQueue_);
|
||||
}
|
||||
@@ -98,6 +106,9 @@ void* JASTaskThread::run() {
|
||||
|
||||
JASKernel::getCommandHeap()->free(callstack);
|
||||
} while (true);
|
||||
#ifdef TARGET_PC
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
void JASTaskThread::pause(bool param_0) {
|
||||
|
||||
@@ -79,11 +79,15 @@ void JFWSystem::init() {
|
||||
|
||||
JUTGamePad::init();
|
||||
|
||||
#ifndef TARGET_PC
|
||||
JUTDirectPrint* dbPrint = JUTDirectPrint::start();
|
||||
#endif
|
||||
|
||||
JUTAssertion::create();
|
||||
|
||||
#ifndef TARGET_PC
|
||||
JUTException::create(dbPrint);
|
||||
#endif
|
||||
|
||||
systemFont = JKR_NEW JUTResFont(CSetUpParam::systemFontRes, NULL);
|
||||
|
||||
|
||||
@@ -94,7 +94,13 @@ void* JKRAram::run(void) {
|
||||
OSInitMessageQueue(&sMessageQueue, sMessageBuffer, 4);
|
||||
do {
|
||||
OSMessage msg;
|
||||
#ifdef TARGET_PC
|
||||
if (!OSReceiveMessage(&sMessageQueue, &msg, OS_MESSAGE_BLOCK)) {
|
||||
break;
|
||||
}
|
||||
#else
|
||||
OSReceiveMessage(&sMessageQueue, &msg, OS_MESSAGE_BLOCK);
|
||||
#endif
|
||||
JKRAramCommand* message = (JKRAramCommand*)msg;
|
||||
int result = message->field_0x00;
|
||||
JKRAMCommand* command = (JKRAMCommand*)message->command;
|
||||
@@ -106,6 +112,9 @@ void* JKRAram::run(void) {
|
||||
break;
|
||||
}
|
||||
} while (true);
|
||||
#ifdef TARGET_PC
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
void JKRAram::checkOkAddress(u8* addr, u32 size, JKRAramBlock* block, u32 param_4) {
|
||||
|
||||
@@ -43,7 +43,13 @@ void* JKRAramStream::run() {
|
||||
|
||||
for (;;) {
|
||||
OSMessage message;
|
||||
#ifdef TARGET_PC
|
||||
if (!OSReceiveMessage(&sMessageQueue, &message, OS_MESSAGE_BLOCK)) {
|
||||
break;
|
||||
}
|
||||
#else
|
||||
OSReceiveMessage(&sMessageQueue, &message, OS_MESSAGE_BLOCK);
|
||||
#endif
|
||||
JKRAramStreamCommand* command = (JKRAramStreamCommand*)message;
|
||||
|
||||
switch (command->mType) {
|
||||
@@ -55,6 +61,9 @@ void* JKRAramStream::run() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
#ifdef TARGET_PC
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
s32 JKRAramStream::readFromAram() {
|
||||
|
||||
@@ -34,7 +34,13 @@ void* JKRDecomp::run() {
|
||||
OSInitMessageQueue(&sMessageQueue, sMessageBuffer, 8);
|
||||
for (;;) {
|
||||
OSMessage message;
|
||||
#ifdef TARGET_PC
|
||||
if (!OSReceiveMessage(&sMessageQueue, &message, OS_MESSAGE_BLOCK)) {
|
||||
break;
|
||||
}
|
||||
#else
|
||||
OSReceiveMessage(&sMessageQueue, &message, OS_MESSAGE_BLOCK);
|
||||
#endif
|
||||
|
||||
JKRDecompCommand* command = (JKRDecompCommand*)message;
|
||||
decode(command->mSrcBuffer, command->mDstBuffer, command->mSrcLength, command->mDstLength);
|
||||
@@ -57,6 +63,9 @@ void* JKRDecomp::run() {
|
||||
OSSendMessage(&command->mMessageQueue, (OSMessage)1, OS_MESSAGE_NOBLOCK);
|
||||
}
|
||||
}
|
||||
#ifdef TARGET_PC
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
JKRDecompCommand* JKRDecomp::prepareCommand(u8* srcBuffer, u8* dstBuffer, u32 srcLength,
|
||||
|
||||
@@ -309,7 +309,15 @@ void* JKRTask::run() {
|
||||
};
|
||||
OSInitFastCast();
|
||||
while (true) {
|
||||
#ifdef TARGET_PC
|
||||
BOOL received = FALSE;
|
||||
TaskMessage* msg = (TaskMessage*)waitMessageBlock(&received);
|
||||
if (!received) {
|
||||
break;
|
||||
}
|
||||
#else
|
||||
TaskMessage* msg = (TaskMessage*)waitMessageBlock();
|
||||
#endif
|
||||
if (msg->field_0x0) {
|
||||
msg->field_0x0(msg->field_0x4);
|
||||
check();
|
||||
@@ -319,6 +327,9 @@ void* JKRTask::run() {
|
||||
}
|
||||
msg->field_0x0 = NULL;
|
||||
}
|
||||
#ifdef TARGET_PC
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
int JKRTask::check() {
|
||||
|
||||
@@ -81,12 +81,14 @@ void JUTVideo::preRetraceProc(u32 retrace_count) {
|
||||
|
||||
static void* frameBuffer = NULL;
|
||||
|
||||
#ifndef TARGET_PC
|
||||
if (frameBuffer) {
|
||||
const GXRenderModeObj* renderMode = JUTGetVideoManager()->getRenderMode();
|
||||
u16 width = renderMode->fbWidth;
|
||||
u16 height = renderMode->efbHeight;
|
||||
JUTDirectPrint::getManager()->changeFrameBuffer(frameBuffer, width, height);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (getManager()->mSetBlack == 1) {
|
||||
s32 frame_count = getManager()->mSetBlackFrameCount;
|
||||
|
||||
@@ -54,10 +54,6 @@
|
||||
#include "res/Object/Alink.h"
|
||||
#include <cstring>
|
||||
|
||||
#if TARGET_PC
|
||||
bool dusk::tweaks::FastIronBoots = false;
|
||||
#endif
|
||||
|
||||
static int daAlink_Create(fopAc_ac_c* i_this);
|
||||
static int daAlink_Delete(daAlink_c* i_this);
|
||||
static int daAlink_Execute(daAlink_c* i_this);
|
||||
@@ -7514,7 +7510,7 @@ void daAlink_c::setBlendMoveAnime(f32 i_morf) {
|
||||
BOOL sp24 = checkEventRun();
|
||||
BOOL sp20 = checkBootsMoveAnime(1);
|
||||
#if TARGET_PC
|
||||
if (dusk::tweaks::FastIronBoots) {
|
||||
if (dusk::ImGuiMenuEnhancements::m_enhancements.fastIronBoots) {
|
||||
sp20 = FALSE;
|
||||
}
|
||||
#endif
|
||||
@@ -9479,7 +9475,7 @@ void daAlink_c::setStickData() {
|
||||
mHeavySpeedMultiplier = mpHIO->mItem.mIronBoots.m.mInputFactor;
|
||||
}
|
||||
#if TARGET_PC
|
||||
if (dusk::tweaks::FastIronBoots) {
|
||||
if (dusk::ImGuiMenuEnhancements::m_enhancements.fastIronBoots) {
|
||||
mHeavySpeedMultiplier = 1.0f;
|
||||
}
|
||||
#endif
|
||||
@@ -9491,7 +9487,7 @@ void daAlink_c::setStickData() {
|
||||
mHeavySpeedMultiplier = mpHIO->mItem.mIronBoots.m.mWaterInputFactor;
|
||||
}
|
||||
#if TARGET_PC
|
||||
if (dusk::tweaks::FastIronBoots) {
|
||||
if (dusk::ImGuiMenuEnhancements::m_enhancements.fastIronBoots) {
|
||||
mHeavySpeedMultiplier = 1.0f;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -23,6 +23,8 @@
|
||||
#include "d/actor/d_a_npc_tkc.h"
|
||||
#include <cstring>
|
||||
|
||||
#include "dusk/imgui/ImGuiMenuEnhancements.hpp"
|
||||
|
||||
BOOL daAlink_c::checkEventRun() const {
|
||||
return dComIfGp_event_runCheck() || checkPlayerDemoMode();
|
||||
}
|
||||
@@ -4290,7 +4292,7 @@ static fopAc_ac_c* daAlink_searchPortal(fopAc_ac_c* i_actor, void* i_data) {
|
||||
}
|
||||
|
||||
bool daAlink_c::checkAcceptWarp() {
|
||||
#if VERSION != VERSION_WII_USA_R0
|
||||
#if TARGET_PC || VERSION != VERSION_WII_USA_R0
|
||||
cM3dGPla plane;
|
||||
#endif
|
||||
|
||||
@@ -4298,7 +4300,9 @@ bool daAlink_c::checkAcceptWarp() {
|
||||
* Fixed in versions above Wii USA Rev 0 by checking FLG0_WATER_IN_MOVE
|
||||
*/
|
||||
if (mLinkAcch.ChkGroundHit() && !checkModeFlg(MODE_PLAYER_FLY)
|
||||
#if VERSION != VERSION_WII_USA_R0
|
||||
#if TARGET_PC
|
||||
&& (dusk::ImGuiMenuEnhancements::m_enhancements.restoreWiiGlitches || !checkNoResetFlg0(FLG0_WATER_IN_MOVE))
|
||||
#elif VERSION != VERSION_WII_USA_R0
|
||||
&& !checkNoResetFlg0(FLG0_WATER_IN_MOVE)
|
||||
#endif
|
||||
)
|
||||
@@ -4307,7 +4311,9 @@ bool daAlink_c::checkAcceptWarp() {
|
||||
* Fixed in versions above Wii USA Rev 0 by checking getSlidePolygon
|
||||
*/
|
||||
if (
|
||||
#if VERSION != VERSION_WII_USA_R0
|
||||
#if TARGET_PC
|
||||
(dusk::ImGuiMenuEnhancements::m_enhancements.restoreWiiGlitches || !getSlidePolygon(&plane)) &&
|
||||
#elif VERSION != VERSION_WII_USA_R0
|
||||
!getSlidePolygon(&plane) &&
|
||||
#endif
|
||||
!checkForestOldCentury()
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
#include "d/actor/d_a_alink.h"
|
||||
#include "d/actor/d_a_tag_magne.h"
|
||||
|
||||
#include "dusk/imgui/ImGuiMenuEnhancements.hpp"
|
||||
|
||||
void daAlink_c::concatMagneBootMtx() {
|
||||
if (checkMagneBootsOn()) {
|
||||
mDoMtx_stack_c::concat(mMagneBootMtx);
|
||||
@@ -348,7 +350,9 @@ int daAlink_c::procMagneBootsFly() {
|
||||
* Fixed in GCN and Wii KOR versions by adding a checkEquipHeavyBoots check
|
||||
*/
|
||||
if (dComIfG_Bgsp().ChkPolySafe(mPolyInfo2)
|
||||
#if PLATFORM_GCN || VERSION == VERSION_WII_KOR
|
||||
#if TARGET_PC
|
||||
&& (dusk::ImGuiMenuEnhancements::m_enhancements.restoreWiiGlitches || checkEquipHeavyBoots())
|
||||
#elif PLATFORM_GCN || VERSION == VERSION_WII_KOR
|
||||
&& checkEquipHeavyBoots()
|
||||
#endif
|
||||
)
|
||||
|
||||
@@ -3,11 +3,10 @@
|
||||
#include "d/d_meter2.h"
|
||||
#include "d/d_meter2_draw.h"
|
||||
#include "d/d_meter2_info.h"
|
||||
|
||||
bool dusk::tweaks::QuickTransform = false;
|
||||
#include "dusk/imgui/ImGuiMenuEnhancements.hpp"
|
||||
|
||||
void daAlink_c::handleQuickTransform() {
|
||||
if (!dusk::tweaks::QuickTransform) {
|
||||
if (!dusk::ImGuiMenuEnhancements::m_enhancements.quickTransform) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -1096,8 +1096,14 @@ inline int daDemo00_c::execute() {
|
||||
case 2: {
|
||||
u16 sp0A = sp0E & 0x3FFF;
|
||||
if ((sp0E & 0xC000) == 0) {
|
||||
#if !MOVIE_SUPPORT
|
||||
// If movie support isn't available, automatically reset.
|
||||
// TPHD-esque. Maybe not the best solution, but it works.
|
||||
dComIfGp_event_reset();
|
||||
#else
|
||||
fopAcM_create(fpcNm_MOVIE_PLAYER_e, sp0A, NULL, fopAcM_GetRoomNo(this), NULL, NULL, 0xFF);
|
||||
mDoGph_gInf_c::fadeOut(1.0f);
|
||||
#endif
|
||||
} else {
|
||||
switch (sp0A) {
|
||||
case 0:
|
||||
|
||||
@@ -14,21 +14,41 @@
|
||||
#pragma optimization_level 4
|
||||
#pragma optimize_for_size off
|
||||
|
||||
#include "JSystem/JKernel/JKRExpHeap.h"
|
||||
#include <cstring>
|
||||
#include <span>
|
||||
#include "JSystem/JAudio2/JASAiCtrl.h"
|
||||
#include "JSystem/JAudio2/JASDriverIF.h"
|
||||
#include "d/actor/d_a_movie_player.h"
|
||||
#include "JSystem/JKernel/JKRExpHeap.h"
|
||||
#include "Z2AudioLib/Z2Instances.h"
|
||||
#include "d/actor/d_a_movie_player.h"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#include "f_op/f_op_overlap_mng.h"
|
||||
#include <cstring>
|
||||
|
||||
#include "dusk/gx_helper.h"
|
||||
#include "dusk/os.h"
|
||||
#include "dusk/layout.hpp"
|
||||
|
||||
#include "JSystem/JAudio2/JASCriticalSection.h"
|
||||
|
||||
#if MOVIE_SUPPORT
|
||||
#include "turbojpeg.h"
|
||||
#endif
|
||||
|
||||
inline s32 daMP_NEXT_READ_SIZE(daMP_THPReadBuffer* readBuf) {
|
||||
return *(s32*)readBuf->ptr;
|
||||
return *(BE(s32)*)readBuf->ptr;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
#if TARGET_PC
|
||||
// idk what OS_THREAD_ATTR_DETACH does, and it stops OSThreadJoin()
|
||||
// probably the difference doesn't matter since we are using OS threads anyways.
|
||||
#define OS_THREAD_ATTR 0
|
||||
#else
|
||||
#define OS_THREAD_ATTR OS_THREAD_ATTR_DETACH
|
||||
#endif
|
||||
|
||||
#if defined(__cplusplus) && !TARGET_PC
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
@@ -196,6 +216,7 @@ static void __THPAudioInitialize(THPAudioDecodeInfo* info, u8* ptr) {
|
||||
info->encodeData++;
|
||||
}
|
||||
|
||||
#if !TARGET_PC
|
||||
static u8 THPStatistics[1120] ATTRIBUTE_ALIGN(32);
|
||||
|
||||
static THPHuffmanTab* Ydchuff ATTRIBUTE_ALIGN(32);
|
||||
@@ -2562,8 +2583,109 @@ static void __THPHuffDecodeDCTCompV(__REGISTER THPFileInfo* info, THPCoeff* bloc
|
||||
}
|
||||
}
|
||||
}
|
||||
#else // !TARGET_PC
|
||||
|
||||
static daMP_THPPlayer daMP_ActivePlayer;
|
||||
|
||||
#if MOVIE_SUPPORT
|
||||
static std::vector<u8> FixedJpegData;
|
||||
static tjhandle JpegDecompressHandle;
|
||||
|
||||
static const std::vector<u8>& FixJpeg(const std::span<u8> data) {
|
||||
FixedJpegData.resize(0);
|
||||
FixedJpegData.reserve(data.size());
|
||||
|
||||
size_t startOfScanLocation = 0;
|
||||
for (; startOfScanLocation < data.size() - 1; startOfScanLocation++) {
|
||||
if (data[startOfScanLocation] == 0xFF && data[startOfScanLocation + 1] == 0xDA) {
|
||||
goto sosFound;
|
||||
}
|
||||
}
|
||||
|
||||
CRASH("Unable to find SOS marker!");
|
||||
|
||||
sosFound:
|
||||
|
||||
startOfScanLocation += 2; // TODO: Skip entire SOS header?
|
||||
|
||||
size_t endOfImage = data.size() - 1;
|
||||
for (; endOfImage > startOfScanLocation; endOfImage--) {
|
||||
if (data[endOfImage] == 0xFF && data[endOfImage + 1] == 0xD9) {
|
||||
goto eoiFound;
|
||||
}
|
||||
}
|
||||
|
||||
CRASH("Unable to find EOI marker!");
|
||||
eoiFound:
|
||||
|
||||
// Copy data before SOS
|
||||
for (size_t i = 0; i < startOfScanLocation; i++) {
|
||||
FixedJpegData.push_back(data[i]);
|
||||
}
|
||||
|
||||
// Copy data inside SOS, fixing up lacking of "byte shuffling"
|
||||
for (size_t i = startOfScanLocation; i < endOfImage; i++) {
|
||||
u8 value = data[i];
|
||||
FixedJpegData.push_back(value);
|
||||
if (value == 0xFF) {
|
||||
FixedJpegData.push_back(0x00);
|
||||
}
|
||||
}
|
||||
|
||||
// Copy data after SOS.
|
||||
for (size_t i = endOfImage; i < data.size(); i++) {
|
||||
FixedJpegData.push_back(data[i]);
|
||||
}
|
||||
|
||||
return FixedJpegData;
|
||||
}
|
||||
|
||||
static s32 THPVideoDecode(void* file, size_t fileSize, void* tileY, void* tileU, void* tileV, void*) {
|
||||
assert(JpegDecompressHandle);
|
||||
|
||||
const auto handle = JpegDecompressHandle;
|
||||
const auto fixedData = FixJpeg(std::span(static_cast<u8*>(file), fileSize));
|
||||
|
||||
auto ret = tj3DecompressHeader(handle, fixedData.data(), fixedData.size());
|
||||
if (ret == -1) {
|
||||
OSReport_Error("Parsing JPEG header failed: %s", tj3GetErrorStr(handle));
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (tj3Get(handle, TJPARAM_JPEGWIDTH) != daMP_ActivePlayer.videoInfo.xSize) {
|
||||
OSReport_Error("Invalid width in video frame!");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (tj3Get(handle, TJPARAM_JPEGHEIGHT) != daMP_ActivePlayer.videoInfo.ySize) {
|
||||
OSReport_Error("Invalid height in video frame!");
|
||||
return 1;
|
||||
}
|
||||
|
||||
ret = tj3Set(handle, TJPARAM_SUBSAMP, TJSAMP_420);
|
||||
if (ret != 0) {
|
||||
OSReport_Error("Failed to set subsampling mode: %s", tj3GetErrorStr(handle));
|
||||
return 1;
|
||||
}
|
||||
|
||||
u8* planes[3] = {static_cast<u8*>(tileY), static_cast<u8*>(tileU), static_cast<u8*>(tileV)};
|
||||
ret = tj3DecompressToYUVPlanes8(handle, fixedData.data(), fixedData.size(), planes, nullptr);
|
||||
if (ret != 0) {
|
||||
OSReport_Error("Image decompression failed: %s", tj3GetErrorStr(handle));
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else // MOVIE_SUPPORT
|
||||
static s32 THPVideoDecode(void*, size_t, void*, void*, void*, void*) {
|
||||
return 1; // Immediate error.
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
static BOOL THPInit() {
|
||||
#if !TARGET_PC
|
||||
u8* base;
|
||||
base = (u8*)(0xE000 << 16);
|
||||
|
||||
@@ -2585,15 +2707,21 @@ static BOOL THPInit() {
|
||||
OSInitFastCast();
|
||||
|
||||
__THPInitFlag = TRUE;
|
||||
#endif
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
#if defined(__cplusplus) && !TARGET_PC
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !TARGET_PC // Defined earlier in file.
|
||||
static daMP_THPPlayer daMP_ActivePlayer;
|
||||
#endif
|
||||
|
||||
#if TARGET_PC
|
||||
static BOOL ReadThreadCancelled;
|
||||
#endif
|
||||
static BOOL daMP_ReadThreadCreated;
|
||||
|
||||
static OSMessageQueue daMP_FreeReadBufferQueue;
|
||||
@@ -2648,12 +2776,23 @@ void daMP_ReadThreadStart() {
|
||||
|
||||
void daMP_ReadThreadCancel() {
|
||||
if (daMP_ReadThreadCreated) {
|
||||
#if TARGET_PC
|
||||
ReadThreadCancelled = TRUE;
|
||||
OSReceiveMessage(&daMP_ReadedBufferQueue, nullptr, OS_MESSAGE_NOBLOCK);
|
||||
OSSendMessage(&daMP_FreeReadBufferQueue, nullptr, OS_MESSAGE_NOBLOCK);
|
||||
OSJoinThread(&daMP_ReadThread, nullptr);
|
||||
#else
|
||||
OSCancelThread(&daMP_ReadThread);
|
||||
#endif
|
||||
daMP_ReadThreadCreated = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
void* daMP_Reader(void*) {
|
||||
#if TARGET_PC
|
||||
OSSetCurrentThreadName("movie player reader");
|
||||
#endif
|
||||
|
||||
daMP_THPReadBuffer* buf;
|
||||
s32 curFrame;
|
||||
s32 status;
|
||||
@@ -2664,8 +2803,17 @@ void* daMP_Reader(void*) {
|
||||
offset = daMP_ActivePlayer.initOffset;
|
||||
initReadSize = daMP_ActivePlayer.initReadSize;
|
||||
|
||||
#if TARGET_PC
|
||||
while (!ReadThreadCancelled) {
|
||||
#else
|
||||
while (TRUE) {
|
||||
#endif
|
||||
buf = (daMP_THPReadBuffer*)daMP_PopFreeReadBuffer();
|
||||
#if TARGET_PC
|
||||
if (!buf) {
|
||||
return nullptr;
|
||||
}
|
||||
#endif
|
||||
status = DVDReadPrio(&daMP_ActivePlayer.fileInfo, buf->ptr, initReadSize, offset, 2);
|
||||
if (status != initReadSize) {
|
||||
if (status == -1)
|
||||
@@ -2673,7 +2821,11 @@ void* daMP_Reader(void*) {
|
||||
if (frame == 0)
|
||||
daMP_PrepareReady(FALSE);
|
||||
|
||||
#if TARGET_PC
|
||||
return nullptr;
|
||||
#else
|
||||
OSSuspendThread(&daMP_ReadThread);
|
||||
#endif
|
||||
}
|
||||
|
||||
buf->frameNumber = frame;
|
||||
@@ -2686,20 +2838,35 @@ void* daMP_Reader(void*) {
|
||||
if (curFrame == daMP_ActivePlayer.header.numFrames - 1) {
|
||||
if (daMP_ActivePlayer.playFlag & 1)
|
||||
offset = daMP_ActivePlayer.header.movieDataOffsets;
|
||||
else
|
||||
OSSuspendThread(&daMP_ReadThread);
|
||||
else {
|
||||
#if TARGET_PC
|
||||
return nullptr;
|
||||
#else
|
||||
OSSuspendThread(&daMP_ReadThread);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
frame++;
|
||||
}
|
||||
|
||||
#if TARGET_PC
|
||||
return nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
static u8 daMP_ReadThreadStack[0x2000];
|
||||
|
||||
#if TARGET_PC
|
||||
static BOOL VideoThreadCancelled;
|
||||
#endif
|
||||
static BOOL daMP_VideoDecodeThreadCreated;
|
||||
|
||||
static BOOL daMP_CreateReadThread(s32 param_0) {
|
||||
if (!OSCreateThread(&daMP_ReadThread, daMP_Reader, 0, daMP_ReadThreadStack + sizeof(daMP_ReadThreadStack), sizeof(daMP_ReadThreadStack), param_0, 1)) {
|
||||
#if TARGET_PC
|
||||
ReadThreadCancelled = FALSE;
|
||||
#endif
|
||||
if (!OSCreateThread(&daMP_ReadThread, daMP_Reader, 0, daMP_ReadThreadStack + sizeof(daMP_ReadThreadStack), sizeof(daMP_ReadThreadStack), param_0, OS_THREAD_ATTR)) {
|
||||
OSReport("Can't create read thread\n");
|
||||
return FALSE;
|
||||
}
|
||||
@@ -2751,19 +2918,30 @@ static BOOL daMP_First;
|
||||
static void daMP_VideoDecode(daMP_THPReadBuffer* readBuffer) {
|
||||
THPTextureSet* textureSet;
|
||||
s32 i;
|
||||
u32* tileOffsets;
|
||||
BE(u32)* tileOffsets;
|
||||
u8* tile;
|
||||
|
||||
tileOffsets = (u32*)(readBuffer->ptr + 8);
|
||||
tileOffsets = (BE(u32)*)(readBuffer->ptr + 8);
|
||||
tile = &readBuffer->ptr[daMP_ActivePlayer.compInfo.numComponents * 4] + 8;
|
||||
textureSet = (THPTextureSet*)daMP_PopFreeTextureSet();
|
||||
|
||||
#if TARGET_PC
|
||||
if (textureSet == nullptr) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
for (i = 0; i < daMP_ActivePlayer.compInfo.numComponents; i++) {
|
||||
switch (daMP_ActivePlayer.compInfo.frameComp[i]) {
|
||||
case 0: {
|
||||
if ((daMP_ActivePlayer.videoError = THPVideoDecode(
|
||||
tile, textureSet->ytexture, textureSet->utexture,
|
||||
textureSet->vtexture, daMP_ActivePlayer.thpWork))) {
|
||||
tile,
|
||||
#if TARGET_PC
|
||||
*tileOffsets,
|
||||
#endif
|
||||
textureSet->ytexture, textureSet->utexture,
|
||||
textureSet->vtexture,
|
||||
daMP_ActivePlayer.thpWork))) {
|
||||
if (daMP_First) {
|
||||
daMP_PrepareReady(FALSE);
|
||||
daMP_First = FALSE;
|
||||
@@ -2789,12 +2967,24 @@ static void daMP_VideoDecode(daMP_THPReadBuffer* readBuffer) {
|
||||
}
|
||||
|
||||
static void* daMP_VideoDecoder(void* param_0) {
|
||||
daMP_THPReadBuffer* thpBuffer;
|
||||
#if TARGET_PC
|
||||
OSSetCurrentThreadName("movie video decoder");
|
||||
#endif
|
||||
|
||||
daMP_THPReadBuffer* thpBuffer;
|
||||
#if TARGET_PC
|
||||
while (!VideoThreadCancelled) {
|
||||
#else
|
||||
while (TRUE) {
|
||||
#endif
|
||||
if (daMP_ActivePlayer.audioExist) {
|
||||
for (; daMP_ActivePlayer.videoDecodeCount < 0;) {
|
||||
thpBuffer = (daMP_THPReadBuffer*)daMP_PopReadedBuffer2();
|
||||
#if TARGET_PC
|
||||
if (thpBuffer == nullptr) {
|
||||
goto exit;
|
||||
}
|
||||
#endif
|
||||
s32 remaining
|
||||
= ((thpBuffer->frameNumber + daMP_ActivePlayer.initReadFrame)
|
||||
% daMP_ActivePlayer.header.numFrames);
|
||||
@@ -2814,12 +3004,26 @@ static void* daMP_VideoDecoder(void* param_0) {
|
||||
else
|
||||
thpBuffer = (daMP_THPReadBuffer*)daMP_PopReadedBuffer();
|
||||
|
||||
#if TARGET_PC
|
||||
if (thpBuffer == nullptr) {
|
||||
goto exit;
|
||||
}
|
||||
#endif
|
||||
|
||||
daMP_VideoDecode(thpBuffer);
|
||||
daMP_PushFreeReadBuffer(thpBuffer);
|
||||
}
|
||||
#if TARGET_PC
|
||||
exit:;
|
||||
return nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void* daMP_VideoDecoderForOnMemory(void* param_0) {
|
||||
#if TARGET_PC
|
||||
OSSetCurrentThreadName("movie video decoder");
|
||||
#endif
|
||||
|
||||
daMP_THPReadBuffer readBuffer;
|
||||
s32 readSize;
|
||||
s32 frame;
|
||||
@@ -2876,13 +3080,17 @@ static void* daMP_VideoDecoderForOnMemory(void* param_0) {
|
||||
}
|
||||
|
||||
static BOOL daMP_CreateVideoDecodeThread(OSPriority prio, u8* param_1) {
|
||||
#if TARGET_PC
|
||||
VideoThreadCancelled = FALSE;
|
||||
#endif
|
||||
|
||||
if (param_1 != NULL) {
|
||||
if (!OSCreateThread(&daMP_VideoDecodeThread, daMP_VideoDecoderForOnMemory, param_1, daMP_VideoDecodeThreadStack + sizeof(daMP_VideoDecodeThreadStack), sizeof(daMP_VideoDecodeThreadStack), prio, 1)) {
|
||||
if (!OSCreateThread(&daMP_VideoDecodeThread, daMP_VideoDecoderForOnMemory, param_1, daMP_VideoDecodeThreadStack + sizeof(daMP_VideoDecodeThreadStack), sizeof(daMP_VideoDecodeThreadStack), prio, OS_THREAD_ATTR)) {
|
||||
OSReport("Can't create video decode thread\n");
|
||||
return FALSE;
|
||||
}
|
||||
} else {
|
||||
if (!OSCreateThread(&daMP_VideoDecodeThread, daMP_VideoDecoder, NULL, daMP_VideoDecodeThreadStack + sizeof(daMP_VideoDecodeThreadStack), sizeof(daMP_VideoDecodeThreadStack), prio, 1)) {
|
||||
if (!OSCreateThread(&daMP_VideoDecodeThread, daMP_VideoDecoder, NULL, daMP_VideoDecodeThreadStack + sizeof(daMP_VideoDecodeThreadStack), sizeof(daMP_VideoDecodeThreadStack), prio, OS_THREAD_ATTR)) {
|
||||
OSReport("Can't create video decode thread\n");
|
||||
return FALSE;
|
||||
}
|
||||
@@ -2903,12 +3111,24 @@ static void daMP_VideoDecodeThreadStart() {
|
||||
|
||||
void daMP_VideoDecodeThreadCancel() {
|
||||
if (daMP_VideoDecodeThreadCreated) {
|
||||
#if TARGET_PC
|
||||
VideoThreadCancelled = TRUE;
|
||||
// Push junk into the queues so the thread unblocks and can exit cleanly.
|
||||
daMP_PushFreeTextureSet(nullptr);
|
||||
daMP_PushReadedBuffer(nullptr);
|
||||
daMP_PushReadedBuffer2(nullptr);
|
||||
OSJoinThread(&daMP_VideoDecodeThread, nullptr);
|
||||
#else
|
||||
OSCancelThread(&daMP_VideoDecodeThread);
|
||||
#endif
|
||||
daMP_VideoDecodeThreadCreated = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static BOOL daMP_AudioDecodeThreadCreated;
|
||||
#if TARGET_PC
|
||||
static BOOL AudioThreadCancelled;
|
||||
#endif
|
||||
|
||||
static OSThread daMP_AudioDecodeThread;
|
||||
|
||||
@@ -2944,12 +3164,17 @@ static void daMP_PushDecodedAudioBuffer(void* buffer) {
|
||||
static void daMP_AudioDecode(daMP_THPReadBuffer* readBuffer) {
|
||||
THPAudioBuffer* audioBuf;
|
||||
s32 i;
|
||||
u32* offsets;
|
||||
BE(u32)* offsets;
|
||||
u8* audioData;
|
||||
|
||||
offsets = (u32*)(readBuffer->ptr + 8);
|
||||
offsets = (BE(u32)*)(readBuffer->ptr + 8);
|
||||
audioData = &readBuffer->ptr[daMP_ActivePlayer.compInfo.numComponents * 4] + 8;
|
||||
audioBuf = (THPAudioBuffer*)daMP_PopFreeAudioBuffer();
|
||||
#if TARGET_PC
|
||||
if (!audioBuf) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
for (i = 0; i < daMP_ActivePlayer.compInfo.numComponents; i++) {
|
||||
switch (daMP_ActivePlayer.compInfo.frameComp[i]) {
|
||||
@@ -2969,16 +3194,34 @@ static void daMP_AudioDecode(daMP_THPReadBuffer* readBuffer) {
|
||||
}
|
||||
|
||||
static void* daMP_AudioDecoder(void* param_0) {
|
||||
#if TARGET_PC
|
||||
OSSetCurrentThreadName("movie audio decoder");
|
||||
#endif
|
||||
|
||||
daMP_THPReadBuffer* buf;
|
||||
|
||||
#if TARGET_PC
|
||||
while (!AudioThreadCancelled) {
|
||||
#else
|
||||
while (TRUE) {
|
||||
#endif
|
||||
buf = (daMP_THPReadBuffer*)daMP_PopReadedBuffer();
|
||||
#if TARGET_PC
|
||||
if (!buf) {
|
||||
return nullptr;
|
||||
}
|
||||
#endif
|
||||
daMP_AudioDecode(buf);
|
||||
daMP_PushReadedBuffer2(buf);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static void* daMP_AudioDecoderForOnMemory(void* param_0) {
|
||||
#if TARGET_PC
|
||||
OSSetCurrentThreadName("movie audio decoder");
|
||||
#endif
|
||||
|
||||
s32 size;
|
||||
s32 readSize;
|
||||
daMP_THPReadBuffer readBuffer;
|
||||
@@ -2989,7 +3232,11 @@ static void* daMP_AudioDecoderForOnMemory(void* param_0) {
|
||||
readBuffer.ptr = (u8*)param_0;
|
||||
frame = 0;
|
||||
|
||||
#if TARGET_PC
|
||||
while (!AudioThreadCancelled) {
|
||||
#else
|
||||
while (TRUE) {
|
||||
#endif
|
||||
readBuffer.frameNumber = frame;
|
||||
daMP_AudioDecode(&readBuffer);
|
||||
|
||||
@@ -2999,7 +3246,11 @@ static void* daMP_AudioDecoderForOnMemory(void* param_0) {
|
||||
readSize = *(s32*)readBuffer.ptr;
|
||||
readBuffer.ptr = daMP_ActivePlayer.movieData;
|
||||
} else {
|
||||
#if TARGET_PC
|
||||
return nullptr;
|
||||
#else
|
||||
OSSuspendThread(&daMP_AudioDecodeThread);
|
||||
#endif
|
||||
}
|
||||
} else {
|
||||
size = *(s32*)readBuffer.ptr;
|
||||
@@ -3008,6 +3259,7 @@ static void* daMP_AudioDecoderForOnMemory(void* param_0) {
|
||||
}
|
||||
frame++;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static OSMessage daMP_FreeAudioBufferMessage[3];
|
||||
@@ -3015,13 +3267,16 @@ static OSMessage daMP_FreeAudioBufferMessage[3];
|
||||
static OSMessage daMP_DecodedAudioBufferMessage[3];
|
||||
|
||||
static BOOL daMP_CreateAudioDecodeThread(OSPriority prio, u8* param_1) {
|
||||
#if TARGET_PC
|
||||
AudioThreadCancelled = FALSE;
|
||||
#endif
|
||||
if (param_1 != NULL) {
|
||||
if (!OSCreateThread(&daMP_AudioDecodeThread, daMP_AudioDecoderForOnMemory, param_1, daMP_AudioDecodeThreadStack + sizeof(daMP_AudioDecodeThreadStack), sizeof(daMP_AudioDecodeThreadStack), prio, 1)) {
|
||||
if (!OSCreateThread(&daMP_AudioDecodeThread, daMP_AudioDecoderForOnMemory, param_1, daMP_AudioDecodeThreadStack + sizeof(daMP_AudioDecodeThreadStack), sizeof(daMP_AudioDecodeThreadStack), prio, OS_THREAD_ATTR)) {
|
||||
OS_REPORT("Can't create audio decode thread\n");
|
||||
return FALSE;
|
||||
}
|
||||
} else {
|
||||
if (!OSCreateThread(&daMP_AudioDecodeThread, daMP_AudioDecoder, NULL, daMP_AudioDecodeThreadStack + sizeof(daMP_AudioDecodeThreadStack), sizeof(daMP_AudioDecodeThreadStack), prio, 1)) {
|
||||
if (!OSCreateThread(&daMP_AudioDecodeThread, daMP_AudioDecoder, NULL, daMP_AudioDecodeThreadStack + sizeof(daMP_AudioDecodeThreadStack), sizeof(daMP_AudioDecodeThreadStack), prio, OS_THREAD_ATTR)) {
|
||||
OSReport("Can't create audio decode thread\n");
|
||||
return FALSE;
|
||||
}
|
||||
@@ -3042,7 +3297,17 @@ void daMP_AudioDecodeThreadStart() {
|
||||
|
||||
void daMP_AudioDecodeThreadCancel() {
|
||||
if (daMP_AudioDecodeThreadCreated) {
|
||||
#if TARGET_PC
|
||||
AudioThreadCancelled = TRUE;
|
||||
// Push junk into the queues so the thread unblocks and can exit cleanly.
|
||||
OSSendMessage(&daMP_ReadedBufferQueue, nullptr, OS_MESSAGE_NOBLOCK);
|
||||
daMP_PushFreeAudioBuffer(nullptr);
|
||||
OSReceiveMessage(&daMP_ReadedBufferQueue2, nullptr, OS_MESSAGE_NOBLOCK);
|
||||
OSReceiveMessage(&daMP_DecodedAudioBufferQueue, nullptr, OS_MESSAGE_NOBLOCK);
|
||||
OSJoinThread(&daMP_AudioDecodeThread, nullptr);
|
||||
#else
|
||||
OSCancelThread(&daMP_AudioDecodeThread);
|
||||
#endif
|
||||
daMP_AudioDecodeThreadCreated = FALSE;
|
||||
}
|
||||
}
|
||||
@@ -3077,8 +3342,13 @@ static void daMP_THPGXYuv2RgbSetup(const GXRenderModeObj* rmode) {
|
||||
Mtx44 m;
|
||||
Mtx e_m;
|
||||
|
||||
#if TARGET_PC
|
||||
w = JUTVideo::getManager()->getFbWidth();
|
||||
h = JUTVideo::getManager()->getEfbHeight();
|
||||
#else
|
||||
w = rmode->fbWidth;
|
||||
h = rmode->efbHeight;
|
||||
#endif
|
||||
var_f31 = 0.0f;
|
||||
|
||||
#if WIDESCREEN_SUPPORT
|
||||
@@ -3168,19 +3438,26 @@ static void daMP_THPGXYuv2RgbDraw(u8* y_data, u8* u_data, u8* v_data, s16 x,
|
||||
TGXTexObj tobj0;
|
||||
TGXTexObj tobj1;
|
||||
TGXTexObj tobj2;
|
||||
#if TARGET_PC
|
||||
#define FMT (GXTexFmt)GX_TF_R8_PC
|
||||
#else
|
||||
#define FMT GX_TF_I8
|
||||
#endif
|
||||
|
||||
GXInitTexObj(&tobj0, y_data, textureWidth, textureHeight, GX_TF_I8, GX_CLAMP, GX_CLAMP, GX_FALSE);
|
||||
GXInitTexObj(&tobj0, y_data, textureWidth, textureHeight, FMT, GX_CLAMP, GX_CLAMP, GX_FALSE);
|
||||
GXInitTexObjLOD(&tobj0, GX_NEAR, GX_NEAR, 0.0f, 0.0f, 0.0f, 0, 0, GX_ANISO_1);
|
||||
GXLoadTexObj(&tobj0, GX_TEXMAP0);
|
||||
|
||||
GXInitTexObj(&tobj1, u_data, textureWidth >> 1, textureHeight >> 1, GX_TF_I8, GX_CLAMP, GX_CLAMP, GX_FALSE);
|
||||
GXInitTexObj(&tobj1, u_data, textureWidth >> 1, textureHeight >> 1, FMT, GX_CLAMP, GX_CLAMP, GX_FALSE);
|
||||
GXInitTexObjLOD(&tobj1, GX_NEAR, GX_NEAR, 0.0f, 0.0f, 0.0f, 0, 0, GX_ANISO_1);
|
||||
GXLoadTexObj(&tobj1, GX_TEXMAP1);
|
||||
|
||||
GXInitTexObj(&tobj2, v_data, textureWidth >> 1, textureHeight >> 1, GX_TF_I8, GX_CLAMP, GX_CLAMP, GX_FALSE);
|
||||
GXInitTexObj(&tobj2, v_data, textureWidth >> 1, textureHeight >> 1, FMT, GX_CLAMP, GX_CLAMP, GX_FALSE);
|
||||
GXInitTexObjLOD(&tobj2, GX_NEAR, GX_NEAR, 0.0f, 0.0f, 0.0f, 0, 0, GX_ANISO_1);
|
||||
GXLoadTexObj(&tobj2, GX_TEXMAP2);
|
||||
|
||||
#undef FMT
|
||||
|
||||
GXBegin(GX_QUADS, GX_VTXFMT7, 4);
|
||||
GXPosition3s16(x, y, 0);
|
||||
GXTexCoord2u16(0, 0);
|
||||
@@ -3191,6 +3468,12 @@ static void daMP_THPGXYuv2RgbDraw(u8* y_data, u8* u_data, u8* v_data, s16 x,
|
||||
GXPosition3s16(x, y + polygonHeight, 0);
|
||||
GXTexCoord2u16(0, 1);
|
||||
GXEnd();
|
||||
|
||||
#if TARGET_PC
|
||||
GXDestroyTexObj(&tobj0);
|
||||
GXDestroyTexObj(&tobj1);
|
||||
GXDestroyTexObj(&tobj2);
|
||||
#endif
|
||||
}
|
||||
|
||||
static u16 daMP_VolumeTable[] = {
|
||||
@@ -3495,6 +3778,13 @@ static BOOL daMP_THPPlayerOpen(char const* filename, BOOL onMemory) {
|
||||
}
|
||||
|
||||
static BOOL daMP_THPPlayerClose() {
|
||||
#if TARGET_PC && MOVIE_SUPPORT
|
||||
tj3Destroy(JpegDecompressHandle);
|
||||
JpegDecompressHandle = nullptr;
|
||||
|
||||
FixedJpegData.clear();
|
||||
#endif
|
||||
|
||||
if (daMP_ActivePlayer.open && daMP_ActivePlayer.state == 0) {
|
||||
daMP_ActivePlayer.open = 0;
|
||||
DVDClose(&daMP_ActivePlayer.fileInfo);
|
||||
@@ -3546,6 +3836,11 @@ static BOOL daMP_THPPlayerSetBuffer(u8* buffer) {
|
||||
|
||||
ysize = ALIGN_NEXT(daMP_ActivePlayer.videoInfo.xSize * daMP_ActivePlayer.videoInfo.ySize, 32);
|
||||
uvsize = ALIGN_NEXT(daMP_ActivePlayer.videoInfo.xSize * daMP_ActivePlayer.videoInfo.ySize / 4, 32);
|
||||
#if TARGET_PC
|
||||
assert(ysize >= tj3YUVPlaneSize(0, daMP_ActivePlayer.videoInfo.xSize, 0, daMP_ActivePlayer.videoInfo.ySize, TJSAMP_420));
|
||||
assert(uvsize >= tj3YUVPlaneSize(1, daMP_ActivePlayer.videoInfo.xSize, 0, daMP_ActivePlayer.videoInfo.ySize, TJSAMP_420));
|
||||
assert(uvsize >= tj3YUVPlaneSize(2, daMP_ActivePlayer.videoInfo.xSize, 0, daMP_ActivePlayer.videoInfo.ySize, TJSAMP_420));
|
||||
#endif
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(daMP_ActivePlayer.textureSet); i++) {
|
||||
daMP_ActivePlayer.textureSet[i].ytexture = ptr;
|
||||
@@ -3623,6 +3918,12 @@ static BOOL daMP_ProperTimingForGettingNextFrame() {
|
||||
}
|
||||
} else {
|
||||
s32 frameRate = daMP_ActivePlayer.header.frameRate * 100.0f;
|
||||
#if TARGET_PC
|
||||
// DUSK HACK: We only fire retrace callbacks *half* as often as the game expects,
|
||||
// because we only run them once per frame, and normally there should be two scans
|
||||
// per game frame.
|
||||
frameRate *= 2;
|
||||
#endif
|
||||
if (VIGetTvFormat() == VI_PAL) {
|
||||
daMP_ActivePlayer.curCount = daMP_ActivePlayer.retaceCount * frameRate / 5000;
|
||||
} else {
|
||||
@@ -3951,6 +4252,9 @@ static BOOL daMP_THPPlayerSetVolume(s32 vol, s32 duration) {
|
||||
if (duration < 0)
|
||||
duration = 0;
|
||||
|
||||
#if TARGET_PC
|
||||
JASCriticalSection section;
|
||||
#endif
|
||||
interrupt = OSDisableInterrupts();
|
||||
|
||||
daMP_ActivePlayer.targetVolume = vol;
|
||||
@@ -3994,11 +4298,14 @@ static BOOL daMP_ActivePlayer_Init(char const* moviePath) {
|
||||
daMP_THPPlayerGetVideoInfo(&daMP_videoInfo);
|
||||
daMP_THPPlayerGetAudioInfo(&daMP_audioInfo);
|
||||
|
||||
#if !TARGET_PC
|
||||
// Window can be resized during playback, update this during draw.
|
||||
u16 width = JUTVideo::getManager()->getRenderMode()->fbWidth;
|
||||
u16 height = JUTVideo::getManager()->getRenderMode()->efbHeight;
|
||||
|
||||
daMP_DrawPosX = (width - daMP_videoInfo.xSize) >> 1;
|
||||
daMP_DrawPosY = (height - daMP_videoInfo.ySize) >> 1;
|
||||
#endif
|
||||
|
||||
// "The memory needed for this THP movie is %d bytes\n"
|
||||
OS_REPORT("このTHPムービーが必要なメモリは%dバイトです\n", daMP_THPPlayerCalcNeedMemory());
|
||||
@@ -4015,6 +4322,15 @@ static BOOL daMP_ActivePlayer_Init(char const* moviePath) {
|
||||
|
||||
daMP_THPPlayerSetBuffer((u8*)daMP_buffer);
|
||||
|
||||
#if TARGET_PC && MOVIE_SUPPORT
|
||||
assert(JpegDecompressHandle == nullptr);
|
||||
JpegDecompressHandle = tj3Init(TJINIT_DECOMPRESS);
|
||||
if (JpegDecompressHandle == nullptr) {
|
||||
OSReport_Error("Failed to create turbojpeg handle: %s", tj3GetErrorStr(nullptr));
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!daMP_THPPlayerPrepare(0, 0, daMP_audioInfo.sndNumTracks != 1 ? OSGetTick() % daMP_audioInfo.sndNumTracks : 0)) {
|
||||
OSReport("Fail to prepare\n");
|
||||
#if DEBUG
|
||||
@@ -4050,14 +4366,55 @@ static void daMP_ActivePlayer_Main() {
|
||||
}
|
||||
}
|
||||
|
||||
#if TARGET_PC && 0
|
||||
#include "imgui.h"
|
||||
#endif
|
||||
|
||||
static void daMP_ActivePlayer_Draw() {
|
||||
int frame = daMP_THPPlayerDrawCurrentFrame(JUTVideo::getManager()->getRenderMode(), daMP_DrawPosX, daMP_DrawPosY, daMP_videoInfo.xSize, daMP_videoInfo.ySize);
|
||||
#if TARGET_PC
|
||||
u16 width = JUTVideo::getManager()->getFbWidth();
|
||||
u16 height = JUTVideo::getManager()->getEfbHeight();
|
||||
|
||||
const auto rect = dusk::LayoutRect::FitRectInRect(
|
||||
width,
|
||||
height,
|
||||
static_cast<f32>(daMP_videoInfo.xSize),
|
||||
static_cast<f32>(daMP_videoInfo.ySize));
|
||||
|
||||
daMP_DrawPosX = static_cast<u32>(rect.PosX);
|
||||
daMP_DrawPosY = static_cast<u32>(rect.PosY);
|
||||
#endif
|
||||
|
||||
int frame = daMP_THPPlayerDrawCurrentFrame(
|
||||
JUTVideo::getManager()->getRenderMode(),
|
||||
daMP_DrawPosX, daMP_DrawPosY,
|
||||
#if TARGET_PC
|
||||
static_cast<u32>(rect.Width()),
|
||||
static_cast<u32>(rect.Height()));
|
||||
#else
|
||||
daMP_videoInfo.xSize,
|
||||
daMP_videoInfo.ySize);
|
||||
#endif
|
||||
daMP_THPPlayerDrawDone();
|
||||
|
||||
if (!fopOvlpM_IsPeek() && frame > 0 && (cAPICPad_ANY_BUTTON(0) || !daMP_c::daMP_c_Get_MovieRestFrame())) {
|
||||
dComIfGp_event_reset();
|
||||
daMP_c::daMP_c_Set_PercentMovieVolume(0.0f);
|
||||
}
|
||||
|
||||
#if TARGET_PC && 0
|
||||
if (ImGui::Begin("Movie player")) {
|
||||
ImGui::Text("daMP_ReadedBufferQueue: %d", daMP_ReadedBufferQueue.usedCount);
|
||||
ImGui::Text("daMP_ReadedBufferQueue2: %d", daMP_ReadedBufferQueue2.usedCount);
|
||||
ImGui::Text("daMP_FreeReadBufferQueue: %d", daMP_FreeReadBufferQueue.usedCount);
|
||||
ImGui::Text("daMP_DecodedTextureSetQueue: %d", daMP_DecodedTextureSetQueue.usedCount);
|
||||
ImGui::Text("daMP_FreeTextureSetQueue: %d", daMP_FreeTextureSetQueue.usedCount);
|
||||
ImGui::Text("daMP_DecodedAudioBufferQueue: %d", daMP_DecodedAudioBufferQueue.usedCount);
|
||||
ImGui::Text("daMP_FreeAudioBufferQueue: %d", daMP_FreeAudioBufferQueue.usedCount);
|
||||
}
|
||||
|
||||
ImGui::End();
|
||||
#endif
|
||||
}
|
||||
|
||||
static BOOL daMP_Fail_alloc;
|
||||
|
||||
@@ -28,6 +28,8 @@
|
||||
#include "d/d_debug_camera.h"
|
||||
#endif
|
||||
|
||||
#include "dusk/imgui/ImGuiMenuEnhancements.hpp"
|
||||
|
||||
namespace {
|
||||
|
||||
static f32 limitf(f32 value, f32 min, f32 max) {
|
||||
@@ -762,6 +764,13 @@ void dCamera_c::updatePad() {
|
||||
var_f29 = 0.0f;
|
||||
} else {
|
||||
var_f31 = mDoCPd_c::getSubStickX3D(mPadID);
|
||||
|
||||
#if TARGET_PC
|
||||
if (dusk::ImGuiMenuEnhancements::m_enhancements.invertCameraXAxis) {
|
||||
var_f31 *= -1.0f;
|
||||
}
|
||||
#endif
|
||||
|
||||
var_f30 = mDoCPd_c::getSubStickY(mPadID);
|
||||
var_f29 = mDoCPd_c::getSubStickValue(mPadID);
|
||||
}
|
||||
|
||||
+1
-1
@@ -11381,7 +11381,7 @@ void dKy_bg_MAxx_proc(void* bg_model_p) {
|
||||
C_MTXLightPerspective(sp1D8, dComIfGd_getView()->fovy,
|
||||
camera_p->view.aspect, 1.0f, 1.0f,
|
||||
#if TARGET_PC
|
||||
dusk::g_imguiConsole.isWaterProjectionOffsetEnabled() ? -0.01f : 0.0f, 0.0f);
|
||||
dusk::ImGuiMenuEnhancements::m_enhancements.useWaterProjectionOffset ? -0.01f : 0.0f, 0.0f);
|
||||
#else
|
||||
-0.01f, 0.0f);
|
||||
#endif
|
||||
|
||||
+19
-19
@@ -9,31 +9,31 @@
|
||||
|
||||
// temporary until a better solution is found
|
||||
typedef struct dMsgUnit_inf1_entry {
|
||||
u32 dat1EntryOffset;
|
||||
BE(u32) dat1EntryOffset;
|
||||
#if REGION_JPN
|
||||
u16 field_0x04;
|
||||
u16 field_0x06;
|
||||
u16 field_0x08;
|
||||
u16 field_0x0a;
|
||||
u16 field_0x0c;
|
||||
u16 field_0x0e;
|
||||
u16 field_0x10;
|
||||
u16 field_0x12;
|
||||
u16 field_0x14;
|
||||
u16 field_0x16;
|
||||
u16 field_0x18;
|
||||
BE(u16) field_0x04;
|
||||
BE(u16) field_0x06;
|
||||
BE(u16) field_0x08;
|
||||
BE(u16) field_0x0a;
|
||||
BE(u16) field_0x0c;
|
||||
BE(u16) field_0x0e;
|
||||
BE(u16) field_0x10;
|
||||
BE(u16) field_0x12;
|
||||
BE(u16) field_0x14;
|
||||
BE(u16) field_0x16;
|
||||
BE(u16) field_0x18;
|
||||
#else
|
||||
u16 startFrame;
|
||||
u16 endFrame;
|
||||
BE(u16) startFrame;
|
||||
BE(u16) endFrame;
|
||||
#endif
|
||||
} dMsgUnit_inf1_entry;
|
||||
|
||||
typedef struct dMsgUnit_inf1_section_t {
|
||||
/* 0x00 */ u32 msgType; // sectionType
|
||||
/* 0x04 */ u32 size; // total size of the section
|
||||
/* 0x08 */ u16 entryCount;
|
||||
/* 0x0A */ u16 entryLength;
|
||||
/* 0x0C */ u16 msgArchiveId;
|
||||
/* 0x00 */ BE(u32) msgType; // sectionType
|
||||
/* 0x04 */ BE(u32) size; // total size of the section
|
||||
/* 0x08 */ BE(u16) entryCount;
|
||||
/* 0x0A */ BE(u16) entryLength;
|
||||
/* 0x0C */ BE(u16) msgArchiveId;
|
||||
/* 0x10 */ dMsgUnit_inf1_entry entries[0];
|
||||
} dMsgUnit_inf1_section_t;
|
||||
|
||||
|
||||
+5
-4
@@ -20,10 +20,9 @@
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
|
||||
#include "dusk/logging.h"
|
||||
|
||||
#ifndef __MWERKS__
|
||||
#include "dusk/extras.h"
|
||||
#include "dusk/logging.h"
|
||||
#endif
|
||||
|
||||
dRes_info_c::dRes_info_c() {
|
||||
@@ -102,11 +101,13 @@ static void setIndirectTex(J3DModelData* i_modelData) {
|
||||
if (memcmp(textureName, "dummy", 6) == 0) {
|
||||
texture->setResTIMG(i, *mDoGph_gInf_c::getFrameBufferTimg());
|
||||
}
|
||||
#if !TARGET_PC
|
||||
if (memcmp(textureName, "Zbuffer", 8) == 0) {
|
||||
#if !TARGET_PC
|
||||
texture->setResTIMG(i, *mDoGph_gInf_c::getZbufferTimg());
|
||||
}
|
||||
#else
|
||||
DuskLog.warn("Zbuffer texture binding not yet supported");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -72,6 +72,15 @@ static PCCondData& GetCondData(OSCond* cond) {
|
||||
return *it->second;
|
||||
}
|
||||
|
||||
void ClearCondMap() {
|
||||
std::lock_guard<std::mutex> lock(GetCondMapMutex());
|
||||
auto& map = GetCondMap();
|
||||
for (auto& pair : map) {
|
||||
pair.second->cv.notify_all();
|
||||
}
|
||||
map.clear();
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// C API functions
|
||||
// ============================================================================
|
||||
|
||||
+24
-64
@@ -17,6 +17,7 @@
|
||||
#include <memory>
|
||||
|
||||
#include "JSystem/JKernel/JKRHeap.h"
|
||||
#include "dusk/main.h"
|
||||
#include "dusk/os.h"
|
||||
|
||||
#if _WIN32
|
||||
@@ -38,6 +39,13 @@ struct PCThreadData {
|
||||
void* param;
|
||||
bool started = false;
|
||||
bool suspended = false;
|
||||
|
||||
~PCThreadData() {
|
||||
if (dusk::IsShuttingDown) {
|
||||
// Don't care about threads if we're shutting down.
|
||||
nativeThread.detach();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Lazy-initialized to avoid DLL static init crashes (used before DllMain completes)
|
||||
@@ -50,6 +58,16 @@ static std::unordered_map<OSThread*, std::unique_ptr<PCThreadData>>& GetThreadDa
|
||||
return map;
|
||||
}
|
||||
|
||||
static PCThreadData* GetThreadData(OSThread* thread) {
|
||||
std::lock_guard mapLock(GetThreadDataMutex());
|
||||
auto it = GetThreadDataMap().find(thread);
|
||||
if (it != GetThreadDataMap().end()) {
|
||||
return it->second.get();
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Side-table for OSThreadQueue -> condition_variable (for OSSleepThread/OSWakeupThread)
|
||||
static std::mutex& GetQueueCvMutex() {
|
||||
static std::mutex mtx;
|
||||
@@ -85,8 +103,6 @@ static OSThread sDefaultThread;
|
||||
static u8 sDefaultStack[64 * 1024];
|
||||
static u32 sDefaultStackEnd = OS_THREAD_STACK_MAGIC;
|
||||
|
||||
OSThreadQueue __OSActiveThreadQueue;
|
||||
|
||||
// Global interrupt mutex (coarse-grained lock replacing interrupt disable)
|
||||
// Lazy-initialized to avoid DLL static init crashes
|
||||
static std::recursive_mutex& GetInterruptMutex() {
|
||||
@@ -108,36 +124,6 @@ static OSSwitchThreadCallback sSwitchThreadCallback = nullptr;
|
||||
// Internal helpers
|
||||
// ============================================================================
|
||||
|
||||
// Linked list macros for the active thread queue
|
||||
static void EnqueueActive(OSThread* thread) {
|
||||
OSThread* prev = __OSActiveThreadQueue.tail;
|
||||
if (prev == nullptr) {
|
||||
__OSActiveThreadQueue.head = thread;
|
||||
} else {
|
||||
prev->linkActive.next = thread;
|
||||
}
|
||||
thread->linkActive.prev = prev;
|
||||
thread->linkActive.next = nullptr;
|
||||
__OSActiveThreadQueue.tail = thread;
|
||||
}
|
||||
|
||||
static void DequeueActive(OSThread* thread) {
|
||||
OSThread* next = thread->linkActive.next;
|
||||
OSThread* prev = thread->linkActive.prev;
|
||||
if (next == nullptr) {
|
||||
__OSActiveThreadQueue.tail = prev;
|
||||
} else {
|
||||
next->linkActive.prev = prev;
|
||||
}
|
||||
if (prev == nullptr) {
|
||||
__OSActiveThreadQueue.head = next;
|
||||
} else {
|
||||
prev->linkActive.next = next;
|
||||
}
|
||||
thread->linkActive.next = nullptr;
|
||||
thread->linkActive.prev = nullptr;
|
||||
}
|
||||
|
||||
// Thread entry wrapper - runs on the new std::thread
|
||||
static void ThreadEntryWrapper(OSThread* thread, PCThreadData* data) {
|
||||
// Set thread-local pointer
|
||||
@@ -195,8 +181,6 @@ void __OSThreadInit(void) {
|
||||
tls_currentThread = &sDefaultThread;
|
||||
|
||||
// Active queue
|
||||
OSInitThreadQueue(&__OSActiveThreadQueue);
|
||||
EnqueueActive(&sDefaultThread);
|
||||
sActiveThreadCount = 1;
|
||||
|
||||
OSReport("[PC-OSThread] Thread system initialized (multi-threaded mode)\n");
|
||||
@@ -273,7 +257,6 @@ int OSCreateThread(OSThread* thread, void* (*func)(void*), void* param,
|
||||
}
|
||||
|
||||
// Add to active queue
|
||||
EnqueueActive(thread);
|
||||
sActiveThreadCount++;
|
||||
|
||||
OSReport("[PC-OSThread] Created thread %p (priority=%d, stackSize=%u)\n",
|
||||
@@ -353,16 +336,7 @@ s32 OSResumeThread(OSThread* thread) {
|
||||
|
||||
// Only wake up if suspend count drops to 0
|
||||
if (thread->suspend == 0) {
|
||||
PCThreadData* data = nullptr;
|
||||
|
||||
// Lock the global map to safely retrieve our thread data pointer
|
||||
{
|
||||
std::lock_guard<std::mutex> mapLock(GetThreadDataMutex());
|
||||
auto it = GetThreadDataMap().find(thread);
|
||||
if (it != GetThreadDataMap().end()) {
|
||||
data = it->second.get();
|
||||
}
|
||||
}
|
||||
PCThreadData* data = GetThreadData(thread);
|
||||
|
||||
if (data) {
|
||||
// Lock the specific thread mutex to safely modify state and notify
|
||||
@@ -377,7 +351,6 @@ s32 OSResumeThread(OSThread* thread) {
|
||||
threadLock.unlock();
|
||||
|
||||
data->nativeThread = std::thread(ThreadEntryWrapper, thread, data);
|
||||
data->nativeThread.detach();
|
||||
OSReport("[PC-OSThread] Started thread %p\n", thread);
|
||||
} else {
|
||||
// Resume from suspension: signal the condition variable
|
||||
@@ -400,16 +373,7 @@ s32 OSSuspendThread(OSThread* thread) {
|
||||
|
||||
// If transitioning from running (0) to suspended (1)
|
||||
if (prevSuspend == 0) {
|
||||
PCThreadData* data = nullptr;
|
||||
|
||||
// Lock the global map to find our thread data
|
||||
{
|
||||
std::lock_guard<std::mutex> mapLock(GetThreadDataMutex());
|
||||
auto it = GetThreadDataMap().find(thread);
|
||||
if (it != GetThreadDataMap().end()) {
|
||||
data = it->second.get();
|
||||
}
|
||||
}
|
||||
PCThreadData* data = GetThreadData(thread);
|
||||
|
||||
if (data && data->started) {
|
||||
std::unique_lock<std::mutex> threadLock(data->mtx);
|
||||
@@ -497,7 +461,6 @@ void OSExitThread(void* val) {
|
||||
currentThread->val = val;
|
||||
|
||||
if (currentThread->attr & OS_THREAD_ATTR_DETACH) {
|
||||
DequeueActive(currentThread);
|
||||
currentThread->state = 0;
|
||||
} else {
|
||||
currentThread->state = OS_THREAD_STATE_MORIBUND;
|
||||
@@ -509,10 +472,10 @@ void OSExitThread(void* val) {
|
||||
}
|
||||
|
||||
void OSCancelThread(OSThread* thread) {
|
||||
CRASH("OSCancelThread not implemented");
|
||||
if (!thread) return;
|
||||
|
||||
if (thread->attr & OS_THREAD_ATTR_DETACH) {
|
||||
DequeueActive(thread);
|
||||
thread->state = 0;
|
||||
} else {
|
||||
thread->state = OS_THREAD_STATE_MORIBUND;
|
||||
@@ -523,11 +486,11 @@ void OSCancelThread(OSThread* thread) {
|
||||
}
|
||||
|
||||
void OSDetachThread(OSThread* thread) {
|
||||
CRASH("OSDetachThread not implemented");
|
||||
if (!thread) return;
|
||||
thread->attr |= OS_THREAD_ATTR_DETACH;
|
||||
|
||||
if (thread->state == OS_THREAD_STATE_MORIBUND) {
|
||||
DequeueActive(thread);
|
||||
thread->state = 0;
|
||||
}
|
||||
OSWakeupThread(&thread->queueJoin);
|
||||
@@ -536,17 +499,14 @@ void OSDetachThread(OSThread* thread) {
|
||||
int OSJoinThread(OSThread* thread, void* val) {
|
||||
if (!thread) return 0;
|
||||
|
||||
if (!(thread->attr & OS_THREAD_ATTR_DETACH) &&
|
||||
thread->state != OS_THREAD_STATE_MORIBUND &&
|
||||
thread->queueJoin.head == nullptr) {
|
||||
OSSleepThread(&thread->queueJoin);
|
||||
if (!(thread->attr & OS_THREAD_ATTR_DETACH)) {
|
||||
GetThreadData(thread)->nativeThread.join();
|
||||
}
|
||||
|
||||
if (thread->state == OS_THREAD_STATE_MORIBUND) {
|
||||
if (val) {
|
||||
*(s32*)val = (s32)(intptr_t)thread->val;
|
||||
}
|
||||
DequeueActive(thread);
|
||||
thread->state = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -133,6 +133,20 @@ void RenderAudioSubframe() {
|
||||
|
||||
InterleaveOutputData(OutBuffer, OutInterleaveBuffer);
|
||||
|
||||
if (JASDriver::extMixCallback != nullptr && JASDriver::sMixMode == MIX_MODE_INTERLEAVE) {
|
||||
static_assert(OutputSubframe::NUM_CHANNELS == 2); // This code only works with Stereo so far.
|
||||
// NOTE: In the real game, this gets called on the entire audio frame, rather than the subframe.
|
||||
// That's probably more efficient, but I didn't wanna change the code to calculate the
|
||||
// entire audio buffers at once.
|
||||
// This is only used for the movie player, and it seems to work fine with the smaller calls.
|
||||
const auto mixData = JASDriver::extMixCallback(DSP_SUBFRAME_SIZE);
|
||||
if (mixData) {
|
||||
for (int i = 0; i < OutInterleaveBuffer.size(); i++) {
|
||||
OutInterleaveBuffer[i] += static_cast<f32>(mixData[i]) / static_cast<f32>(0x7FFF);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(DUSK_DUMP_AUDIO)
|
||||
outRaw.write((const char*)OutInterleaveBuffer.data(), sizeof(OutInterleaveBuffer));
|
||||
#endif
|
||||
|
||||
@@ -181,6 +181,7 @@ namespace dusk {
|
||||
if (ImGui::BeginMainMenuBar()) {
|
||||
m_menuGame.draw();
|
||||
m_menuTools.draw();
|
||||
m_menuEnhancements.draw();
|
||||
|
||||
ImGui::SetCursorPosX(ImGui::GetWindowWidth() - 80.0f);
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
@@ -223,104 +224,3 @@ namespace dusk {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Limiter
|
||||
{
|
||||
using delta_clock = std::chrono::high_resolution_clock;
|
||||
using duration_t = std::chrono::nanoseconds;
|
||||
|
||||
public:
|
||||
void Reset()
|
||||
{
|
||||
m_oldTime = delta_clock::now();
|
||||
}
|
||||
|
||||
void Sleep(duration_t targetFrameTime)
|
||||
{
|
||||
if (targetFrameTime.count() == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
auto start = delta_clock::now();
|
||||
duration_t adjustedSleepTime = SleepTime(targetFrameTime);
|
||||
if (adjustedSleepTime.count() > 0)
|
||||
{
|
||||
NanoSleep(adjustedSleepTime);
|
||||
duration_t overslept = TimeSince(start) - adjustedSleepTime;
|
||||
if (overslept < duration_t{ targetFrameTime })
|
||||
{
|
||||
m_overheadTimes[m_overheadTimeIdx] = overslept;
|
||||
m_overheadTimeIdx = (m_overheadTimeIdx + 1) % m_overheadTimes.size();
|
||||
}
|
||||
}
|
||||
Reset();
|
||||
}
|
||||
|
||||
duration_t SleepTime(duration_t targetFrameTime)
|
||||
{
|
||||
const auto sleepTime = duration_t{ targetFrameTime } - TimeSince(m_oldTime);
|
||||
m_overhead = std::accumulate(m_overheadTimes.begin(), m_overheadTimes.end(), duration_t{}) /
|
||||
m_overheadTimes.size();
|
||||
if (sleepTime > m_overhead)
|
||||
{
|
||||
return sleepTime - m_overhead;
|
||||
}
|
||||
return duration_t{ 0 };
|
||||
}
|
||||
|
||||
private:
|
||||
delta_clock::time_point m_oldTime;
|
||||
std::array<duration_t, 4> m_overheadTimes{};
|
||||
size_t m_overheadTimeIdx = 0;
|
||||
duration_t m_overhead = duration_t{ 0 };
|
||||
|
||||
duration_t TimeSince(delta_clock::time_point start)
|
||||
{
|
||||
return std::chrono::duration_cast<duration_t>(delta_clock::now() - start);
|
||||
}
|
||||
|
||||
#if _WIN32
|
||||
bool m_initialized;
|
||||
double m_countPerNs;
|
||||
|
||||
void NanoSleep(const duration_t duration)
|
||||
{
|
||||
if (!m_initialized)
|
||||
{
|
||||
LARGE_INTEGER freq;
|
||||
QueryPerformanceFrequency(&freq);
|
||||
m_countPerNs = static_cast<double>(freq.QuadPart) / 1000000000.0;
|
||||
m_initialized = true;
|
||||
}
|
||||
|
||||
DWORD ms = std::chrono::duration_cast<std::chrono::milliseconds>(duration).count();
|
||||
auto tickCount =
|
||||
static_cast<LONGLONG>(static_cast<double>(duration.count()) * m_countPerNs);
|
||||
LARGE_INTEGER count;
|
||||
QueryPerformanceCounter(&count);
|
||||
if (ms > 10)
|
||||
{
|
||||
// Adjust for Sleep overhead
|
||||
::Sleep(ms - 10);
|
||||
}
|
||||
auto end = count.QuadPart + tickCount;
|
||||
do
|
||||
{
|
||||
QueryPerformanceCounter(&count);
|
||||
} while (count.QuadPart < end);
|
||||
}
|
||||
#else
|
||||
void NanoSleep(const duration_t duration)
|
||||
{
|
||||
std::this_thread::sleep_for(duration);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
static Limiter g_frameLimiter;
|
||||
void frame_limiter()
|
||||
{
|
||||
g_frameLimiter.Sleep(
|
||||
std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::seconds{ 1 }) / 60);
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "imgui.h"
|
||||
#include "ImGuiMenuGame.hpp"
|
||||
#include "ImGuiMenuTools.hpp"
|
||||
#include "ImGuiMenuEnhancements.hpp"
|
||||
|
||||
namespace dusk {
|
||||
class ImGuiConsole {
|
||||
@@ -14,8 +15,6 @@ namespace dusk {
|
||||
ImGuiConsole();
|
||||
void draw();
|
||||
|
||||
bool isBloomEnabled() { return m_menuGame.isBloomEnabled(); }
|
||||
bool isWaterProjectionOffsetEnabled() { return m_menuGame.isWaterProjectionOffsetEnabled(); }
|
||||
ImGuiMenuTools::CollisionViewSettings& getCollisionViewSettings() { return m_menuTools.getCollisionViewSettings(); }
|
||||
|
||||
static bool CheckMenuViewToggle(ImGuiKey key, bool& active);
|
||||
@@ -25,6 +24,7 @@ namespace dusk {
|
||||
|
||||
ImGuiMenuGame m_menuGame;
|
||||
ImGuiMenuTools m_menuTools;
|
||||
ImGuiMenuEnhancements m_menuEnhancements;
|
||||
};
|
||||
|
||||
extern ImGuiConsole g_imguiConsole;
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
#include "fmt/format.h"
|
||||
#include "imgui.h"
|
||||
#include "aurora/gfx.h"
|
||||
|
||||
#include "ImGuiConsole.hpp"
|
||||
#include "ImGuiMenuEnhancements.hpp"
|
||||
#include <imgui_internal.h>
|
||||
|
||||
namespace dusk {
|
||||
EnhancementsSettings ImGuiMenuEnhancements::m_enhancements = {
|
||||
.fastIronBoots = false,
|
||||
.invertCameraXAxis = false,
|
||||
.restoreWiiGlitches = false,
|
||||
.enableBloom = true,
|
||||
.useWaterProjectionOffset = false,
|
||||
};
|
||||
|
||||
ImGuiMenuEnhancements::ImGuiMenuEnhancements() {}
|
||||
|
||||
void ImGuiMenuEnhancements::draw() {
|
||||
if (ImGui::BeginMenu("Enhancements")) {
|
||||
if (ImGui::BeginMenu("Quality of Life")) {
|
||||
ImGui::Checkbox("Fast Iron Boots", &m_enhancements.fastIronBoots);
|
||||
ImGui::Checkbox("Invert Camera X Axis", &m_enhancements.invertCameraXAxis);
|
||||
ImGui::Checkbox("Quick Transform (R+Y)", &m_enhancements.quickTransform);
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
|
||||
if (ImGui::BeginMenu("Graphics")) {
|
||||
ImGui::Checkbox("Native Bloom", &m_enhancements.enableBloom);
|
||||
ImGui::Checkbox("Water Projection Offset", &m_enhancements.useWaterProjectionOffset);
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("Adds GC-specific -0.01 transS offset\n"
|
||||
"that causes ~6px ghost artifacts in water reflections");
|
||||
}
|
||||
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
|
||||
if (ImGui::BeginMenu("Restorations")) {
|
||||
ImGui::Checkbox("Restore Wii 1.0 Glitches", &m_enhancements.restoreWiiGlitches);
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("Restores patched glitches from Wii USA 1.0, the first released version");
|
||||
}
|
||||
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
|
||||
if (ImGui::BeginMenu("Cheats")) {
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
#ifndef DUSK_IMGUI_MENUENHANCEMENTS_HPP
|
||||
#define DUSK_IMGUI_MENUENHANCEMENTS_HPP
|
||||
|
||||
#include <aurora/aurora.h>
|
||||
#include <pad.h>
|
||||
#include <string>
|
||||
|
||||
#include "imgui.h"
|
||||
|
||||
namespace dusk {
|
||||
struct EnhancementsSettings {
|
||||
bool fastIronBoots;
|
||||
bool invertCameraXAxis;
|
||||
bool quickTransform;
|
||||
bool restoreWiiGlitches;
|
||||
bool enableBloom;
|
||||
bool useWaterProjectionOffset;
|
||||
};
|
||||
|
||||
class ImGuiMenuEnhancements {
|
||||
public:
|
||||
ImGuiMenuEnhancements();
|
||||
void draw();
|
||||
|
||||
static EnhancementsSettings m_enhancements;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // DUSK_IMGUI_MENUENHANCEMENTS_HPP
|
||||
@@ -25,17 +25,8 @@ namespace dusk {
|
||||
|
||||
if (ImGui::BeginMenu("Graphics")) {
|
||||
if (ImGui::MenuItem("Toggle Fullscreen", "F11")) {
|
||||
m_graphicsSettings.m_fullscreen = !m_graphicsSettings.m_fullscreen;
|
||||
VISetWindowFullscreen(m_graphicsSettings.m_fullscreen);
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
ImGui::Checkbox("Native Bloom", &m_graphicsSettings.m_enableBloom);
|
||||
ImGui::Checkbox("Water Projection Offset", &m_graphicsSettings.m_waterProjectionOffset);
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("Adds GC-specific -0.01 transS offset\n"
|
||||
"that causes ~6px ghost artifacts in water reflections");
|
||||
m_fullscreen = !m_fullscreen;
|
||||
VISetWindowFullscreen(m_fullscreen);
|
||||
}
|
||||
|
||||
ImGui::EndMenu();
|
||||
@@ -76,12 +67,6 @@ namespace dusk {
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
|
||||
if (ImGui::BeginMenu("Tweaks")) {
|
||||
ImGui::MenuItem("Fast iron boots", nullptr, &tweaks::FastIronBoots);
|
||||
ImGui::MenuItem("Quick Transform (R+Y)", nullptr, &tweaks::QuickTransform);
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
|
||||
@@ -93,8 +78,8 @@ namespace dusk {
|
||||
}
|
||||
|
||||
if (ImGui::IsKeyPressed(ImGuiKey_F11)) {
|
||||
m_graphicsSettings.m_fullscreen = !m_graphicsSettings.m_fullscreen;
|
||||
VISetWindowFullscreen(m_graphicsSettings.m_fullscreen);
|
||||
m_fullscreen = !m_fullscreen;
|
||||
VISetWindowFullscreen(m_fullscreen);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,8 +12,6 @@ namespace dusk {
|
||||
public:
|
||||
ImGuiMenuGame();
|
||||
void draw();
|
||||
bool isBloomEnabled() { return m_graphicsSettings.m_enableBloom; }
|
||||
bool isWaterProjectionOffsetEnabled() { return m_graphicsSettings.m_waterProjectionOffset; }
|
||||
|
||||
void windowInputViewer();
|
||||
void windowControllerConfig();
|
||||
@@ -35,11 +33,7 @@ namespace dusk {
|
||||
int m_pendingPort = -1;
|
||||
} m_controllerConfig;
|
||||
|
||||
struct {
|
||||
bool m_enableBloom = 1;
|
||||
bool m_waterProjectionOffset = false;
|
||||
bool m_fullscreen = false;
|
||||
} m_graphicsSettings;
|
||||
bool m_fullscreen = false;
|
||||
|
||||
bool m_showControllerConfig = false;
|
||||
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
#include "dusk/layout.hpp"
|
||||
|
||||
using namespace dusk;
|
||||
|
||||
LayoutRect LayoutRect::FitRectInRect(
|
||||
const f32 widthOuter,
|
||||
const f32 heightOuter,
|
||||
const f32 widthInner,
|
||||
const f32 heightInner) {
|
||||
|
||||
// Try as if constrained vertically first.
|
||||
auto width = widthInner * (heightOuter / heightInner);
|
||||
auto height = heightOuter;
|
||||
if (width > widthOuter) {
|
||||
// Otherwise, constrained horizontally.
|
||||
width = widthOuter;
|
||||
height = heightOuter * (widthOuter / widthInner);
|
||||
}
|
||||
|
||||
// Center it
|
||||
const auto posX = (widthOuter - width) / 2;
|
||||
const auto posY = (heightOuter - height) / 2;
|
||||
|
||||
return {posX, posY, posX + width, posY + height};
|
||||
}
|
||||
+28
-5
@@ -11,7 +11,7 @@
|
||||
#include <unordered_map>
|
||||
#include <memory>
|
||||
#include <dusk/logging.h>
|
||||
|
||||
#include <dusk/main.h>
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <sys/time.h>
|
||||
@@ -84,6 +84,16 @@ static PCMessageQueueData& GetMsgQueueData(OSMessageQueue* mq) {
|
||||
return *it->second;
|
||||
}
|
||||
|
||||
static void ClearMsgQueueMap() {
|
||||
std::lock_guard<std::mutex> lock(GetMsgQueueMapMutex());
|
||||
auto& map = GetMsgQueueMap();
|
||||
for (auto & [_, value] : map) {
|
||||
value->cvReceive.notify_all();
|
||||
value->cvSend.notify_all();
|
||||
}
|
||||
map.clear();
|
||||
}
|
||||
|
||||
void OSInitMessageQueue(OSMessageQueue* mq, void* msgArray, s32 msgCount) {
|
||||
if (!mq) return;
|
||||
mq->queueSend.head = mq->queueSend.tail = nullptr;
|
||||
@@ -104,7 +114,10 @@ int OSSendMessage(OSMessageQueue* mq, void* msg, s32 flags) {
|
||||
if (mq->usedCount >= mq->msgCount) {
|
||||
if (flags == OS_MESSAGE_NOBLOCK) return 0;
|
||||
// BLOCK: wait until space is available
|
||||
data.cvSend.wait(lock, [mq]() { return mq->usedCount < mq->msgCount; });
|
||||
data.cvSend.wait(lock, [mq] { return mq->usedCount < mq->msgCount || dusk::IsShuttingDown; });
|
||||
}
|
||||
if (dusk::IsShuttingDown) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
s32 idx = (mq->firstIndex + mq->usedCount) % mq->msgCount;
|
||||
@@ -124,7 +137,10 @@ int OSReceiveMessage(OSMessageQueue* mq, void* msg, s32 flags) {
|
||||
if (mq->usedCount == 0) {
|
||||
if (flags == OS_MESSAGE_NOBLOCK) return 0;
|
||||
// BLOCK: wait until a message arrives
|
||||
data.cvReceive.wait(lock, [mq]() { return mq->usedCount > 0; });
|
||||
data.cvReceive.wait(lock, [mq] { return mq->usedCount > 0 || dusk::IsShuttingDown; });
|
||||
}
|
||||
if (dusk::IsShuttingDown) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (msg) {
|
||||
@@ -146,7 +162,10 @@ int OSJamMessage(OSMessageQueue* mq, void* msg, s32 flags) {
|
||||
if (mq->usedCount >= mq->msgCount) {
|
||||
if (flags == OS_MESSAGE_NOBLOCK) return 0;
|
||||
// BLOCK: wait until space is available
|
||||
data.cvSend.wait(lock, [mq]() { return mq->usedCount < mq->msgCount; });
|
||||
data.cvSend.wait(lock, [mq] { return mq->usedCount < mq->msgCount || dusk::IsShuttingDown; });
|
||||
}
|
||||
if (dusk::IsShuttingDown) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Jam inserts at the front of the queue
|
||||
@@ -185,8 +204,12 @@ BOOL OSGetResetButtonState() { return FALSE; }
|
||||
BOOL OSInitFont(OSFontHeader* fontData) { return FALSE; }
|
||||
BOOL OSLink(OSModuleInfo* newModule, void* bss) { return TRUE; }
|
||||
|
||||
void ClearCondMap();
|
||||
void OSResetSystem(int reset, u32 resetCode, BOOL forceMenu) {
|
||||
OSReport("[PC] OSResetSystem called (reset=%d, code=%u)\n", reset, resetCode);
|
||||
dusk::IsShuttingDown = true;
|
||||
ClearMsgQueueMap();
|
||||
ClearCondMap();
|
||||
}
|
||||
|
||||
void OSSetStringTable(void* stringTable) {}
|
||||
@@ -998,7 +1021,7 @@ f32 GXGetYScaleFactor(u16 efbHeight, u16 xfbHeight) {
|
||||
void GXInitTexCacheRegion(GXTexRegion* region, GXBool is_32b_mipmap, u32 tmem_even,
|
||||
GXTexCacheSize size_even, u32 tmem_odd, GXTexCacheSize size_odd) {
|
||||
STUB_LOG();
|
||||
}
|
||||
}
|
||||
// XXX, this should be some struct?
|
||||
// GXRenderModeObj GXNtsc480IntDf;
|
||||
//GXRenderModeObj GXNtsc480Int;
|
||||
|
||||
+14
-36
@@ -5,17 +5,11 @@
|
||||
|
||||
#include "m_Do/m_Do_DVDError.h"
|
||||
#include "JSystem/JKernel/JKRAssertHeap.h"
|
||||
#include <os.h>
|
||||
#include <dolphin/os.h>
|
||||
#include "m_Do/m_Do_dvd_thread.h"
|
||||
#include "m_Do/m_Do_ext.h"
|
||||
#include "m_Do/m_Do_Reset.h"
|
||||
|
||||
// Added for the sleep workaround
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
|
||||
#include "dusk/os.h"
|
||||
|
||||
#if PLATFORM_GCN
|
||||
const int stack_size = 3072;
|
||||
#else
|
||||
@@ -31,24 +25,25 @@ static OSThread DvdErr_thread;
|
||||
static u8 DvdErr_stack[stack_size] ATTRIBUTE_ALIGN(16);
|
||||
#pragma pop
|
||||
|
||||
// Alarm is not needed for the PC workaround
|
||||
// static OSAlarm Alarm;
|
||||
static OSAlarm Alarm;
|
||||
|
||||
void mDoDvdErr_ThdInit() {
|
||||
#ifdef TARGET_PC
|
||||
// Thread is not necessary on PC
|
||||
return;
|
||||
#endif
|
||||
|
||||
if (mDoDvdErr_initialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
// OSTime time = OSGetTime(); // Unused in workaround
|
||||
OSTime time = OSGetTime();
|
||||
|
||||
OSCreateThread(&DvdErr_thread, (void* (*)(void*))mDoDvdErr_Watch, NULL,
|
||||
DvdErr_stack + sizeof(DvdErr_stack), sizeof(DvdErr_stack),
|
||||
OSGetThreadPriority(OSGetCurrentThread()) - 3, 1);
|
||||
OSCreateThread(&DvdErr_thread, (void*(*)(void*))mDoDvdErr_Watch, NULL, DvdErr_stack + sizeof(DvdErr_stack),
|
||||
sizeof(DvdErr_stack), OSGetThreadPriority(OSGetCurrentThread()) - 3, 1);
|
||||
OSResumeThread(&DvdErr_thread);
|
||||
|
||||
// PC Workaround: Disable Alarm logic. The thread will sleep itself.
|
||||
// OSCreateAlarm(&Alarm);
|
||||
// OSSetPeriodicAlarm(&Alarm, time, OS_BUS_CLOCK / 4, AlarmHandler);
|
||||
OSCreateAlarm(&Alarm);
|
||||
OSSetPeriodicAlarm(&Alarm, time, OS_BUS_CLOCK / 4, AlarmHandler);
|
||||
|
||||
mDoDvdErr_initialized = true;
|
||||
}
|
||||
@@ -56,22 +51,15 @@ void mDoDvdErr_ThdInit() {
|
||||
void mDoDvdErr_ThdCleanup() {
|
||||
if (mDoDvdErr_initialized) {
|
||||
OSCancelThread(&DvdErr_thread);
|
||||
// OSCancelAlarm(&Alarm); // Disable Alarm cancel
|
||||
OSCancelAlarm(&Alarm);
|
||||
mDoDvdErr_initialized = false;
|
||||
}
|
||||
}
|
||||
|
||||
static void mDoDvdErr_Watch(void*) {
|
||||
#if PLATFORM_GCN
|
||||
#ifndef TARGET_PC
|
||||
OSDisableInterrupts();
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if TARGET_PC
|
||||
OSSetCurrentThreadName("DVD error thread");
|
||||
#endif
|
||||
|
||||
JKRThread(OSGetCurrentThread(), 0);
|
||||
|
||||
JKRSetCurrentHeap(mDoExt_getAssertHeap());
|
||||
@@ -82,20 +70,10 @@ static void mDoDvdErr_Watch(void*) {
|
||||
if (status == DVD_STATE_FATAL_ERROR) {
|
||||
mDoDvdThd::suspend();
|
||||
}
|
||||
|
||||
// PC Workaround:
|
||||
// Instead of suspending and waiting for an Alarm (which might not be implemented),
|
||||
// we simply sleep for a short duration.
|
||||
// OS_BUS_CLOCK / 4 corresponds to roughly 1/4th of a second on GC.
|
||||
// We use 250ms here to simulate the periodic check.
|
||||
|
||||
// OSSuspendThread(&DvdErr_thread); // <-- Original causing deadlock without Alarm
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(250));
|
||||
|
||||
OSSuspendThread(&DvdErr_thread);
|
||||
} while (true);
|
||||
}
|
||||
|
||||
static void AlarmHandler(OSAlarm*, OSContext*) {
|
||||
// This handler is no longer called in the PC workaround
|
||||
OSResumeThread(&DvdErr_thread);
|
||||
}
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "m_Do/m_Do_Reset.h"
|
||||
#include "os_report.h"
|
||||
#include "dusk/os.h"
|
||||
#include "dusk/main.h"
|
||||
|
||||
#if PLATFORM_WII || PLATFORM_SHIELD
|
||||
#include <revolution/nand.h>
|
||||
@@ -103,11 +104,21 @@ void mDoMemCd_Ctrl_c::ThdInit() {
|
||||
void mDoMemCd_Ctrl_c::main() {
|
||||
do {
|
||||
OSLockMutex(&mMutex);
|
||||
while (mCardCommand == COMM_NONE_e) {
|
||||
while (mCardCommand == COMM_NONE_e
|
||||
#ifdef TARGET_PC
|
||||
&& !dusk::IsShuttingDown
|
||||
#endif
|
||||
) {
|
||||
OSWaitCond(&mCond, &mMutex);
|
||||
}
|
||||
OSUnlockMutex(&mMutex);
|
||||
|
||||
#ifdef TARGET_PC
|
||||
if (dusk::IsShuttingDown) {
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
switch (mCardCommand) {
|
||||
#if PLATFORM_GCN || PLATFORM_WII
|
||||
case COMM_RESTORE_e:
|
||||
|
||||
@@ -1166,7 +1166,7 @@ void mDoGph_gInf_c::bloom_c::remove() {
|
||||
|
||||
void mDoGph_gInf_c::bloom_c::draw() {
|
||||
#if TARGET_PC
|
||||
if (!dusk::g_imguiConsole.isBloomEnabled()) {
|
||||
if (!dusk::ImGuiMenuEnhancements::m_enhancements.enableBloom) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
+3
-10
@@ -108,12 +108,8 @@ s32 LOAD_COPYDATE(void*) {
|
||||
AuroraInfo auroraInfo;
|
||||
|
||||
void main01(void) {
|
||||
#if TARGET_PC
|
||||
Limiter frameLimiter{};
|
||||
#endif
|
||||
|
||||
OS_REPORT("\x1b[m");
|
||||
GXSetColorUpdate(GX_ENABLE);
|
||||
|
||||
// 1. Setup
|
||||
mDoMch_Create();
|
||||
mDoGph_Create();
|
||||
@@ -191,10 +187,6 @@ void main01(void) {
|
||||
mDoAud_Execute();
|
||||
|
||||
aurora_end_frame();
|
||||
|
||||
#if TARGET_PC
|
||||
frameLimiter.Sleep(DUSK_FRAME_PERIOD);
|
||||
#endif
|
||||
} while (true);
|
||||
|
||||
exit:;
|
||||
@@ -312,7 +304,8 @@ int game_main(int argc, char* argv[]) {
|
||||
fflush(stdout);
|
||||
fflush(stderr);
|
||||
|
||||
dusk::IsShuttingDown = true;
|
||||
// Notifies all CVs and causes threads to exit
|
||||
OSResetSystem(OS_RESET_SHUTDOWN, 0, 0);
|
||||
|
||||
aurora_shutdown();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user