diff --git a/assets/materials/static.skm.yaml b/assets/materials/static.skm.yaml index 7dfd264..e0117ff 100644 --- a/assets/materials/static.skm.yaml +++ b/assets/materials/static.skm.yaml @@ -843,7 +843,8 @@ materials: clock_digits: gDPSetTile: filename: ./signage/clock_digits.png - siz: G_IM_SIZ_16b + siz: G_IM_SIZ_4b + twoTone: true gDPSetCombineMode: G_CC_DECALRGBA gDPSetCycleType: G_CYC_1CYCLE \ No newline at end of file diff --git a/assets/models/signage/clock.blend b/assets/models/signage/clock.blend index d5d543c..06742dc 100644 Binary files a/assets/models/signage/clock.blend and b/assets/models/signage/clock.blend differ diff --git a/assets/models/signage/clock_digits.blend b/assets/models/signage/clock_digits.blend index c1aecd9..f300148 100644 Binary files a/assets/models/signage/clock_digits.blend and b/assets/models/signage/clock_digits.blend differ diff --git a/assets/test_chambers/test_chamber_00/test_chamber_00.blend b/assets/test_chambers/test_chamber_00/test_chamber_00.blend index 0846652..bf42779 100644 Binary files a/assets/test_chambers/test_chamber_00/test_chamber_00.blend and b/assets/test_chambers/test_chamber_00/test_chamber_00.blend differ diff --git a/src/audio/soundplayer.c b/src/audio/soundplayer.c index c1035e5..2a29b2b 100644 --- a/src/audio/soundplayer.c +++ b/src/audio/soundplayer.c @@ -195,6 +195,15 @@ ALSndId soundPlayerPlay(int soundClipId, float volume, float pitch, struct Vecto return result; } +float soundClipDuration(int soundClipId, float pitch) { + if (soundClipId < 0 || soundClipId >= gSoundClipArray->soundCount) { + return 0.0f; + } + + ALSound* alSound = gSoundClipArray->sounds[soundClipId]; + return soundPlayerEstimateLength(alSound, pitch); +} + void soundPlayerUpdate() { int index = 0; int writeIndex = 0; @@ -321,6 +330,16 @@ int soundPlayerIsPlaying(ALSndId soundId) { return activeSound->estimatedTimeLeft > 0.0f && alSndpGetState(&gSoundPlayer) != AL_STOPPED; } +float soundPlayerTimeLeft(ALSndId soundId) { + struct ActiveSound* activeSound = soundPlayerFindActiveSound(soundId); + + if (!activeSound) { + return 0.0f; + } + + return activeSound->estimatedTimeLeft; +} + void soundListenerUpdate(struct Vector3* position, struct Quaternion* rotation, struct Vector3* velocity, int listenerIndex) { gSoundListeners[listenerIndex].worldPos = *position; gSoundListeners[listenerIndex].velocity = *velocity; diff --git a/src/audio/soundplayer.h b/src/audio/soundplayer.h index 79ed2be..58429c7 100644 --- a/src/audio/soundplayer.h +++ b/src/audio/soundplayer.h @@ -21,6 +21,7 @@ extern char _soundsTblSegmentRomEnd[]; void soundPlayerInit(); void soundPlayerUpdate(); ALSndId soundPlayerPlay(int soundClipId, float volume, float pitch, struct Vector3* at, struct Vector3* velocity); +float soundClipDuration(int soundClipId, float pitch); void soundPlayerStop(ALSndId soundId); void soundPlayerStopAll(); @@ -31,6 +32,7 @@ void soundPlayerUpdatePosition(ALSndId soundId, struct Vector3* at, struct Vecto void soundPlayerAdjustVolume(ALSndId soundId, float newVolume); int soundPlayerIsPlaying(ALSndId soundId); +float soundPlayerTimeLeft(ALSndId soundId); void soundListenerUpdate(struct Vector3* position, struct Quaternion* rotation, struct Vector3* velocity, int listenerIndex); void soundListenerSetCount(int count); diff --git a/src/levels/cutscene_runner.c b/src/levels/cutscene_runner.c index f161c92..f80e9cc 100644 --- a/src/levels/cutscene_runner.c +++ b/src/levels/cutscene_runner.c @@ -7,6 +7,8 @@ #include "../util/memory.h" #include "../savefile/checkpoint.h" +#include + struct CutsceneRunner* gRunningCutscenes; struct CutsceneRunner* gUnusedRunners; u64 gTriggeredCutscenes; @@ -283,6 +285,32 @@ int cutsceneRunnerUpdateCurrentStep(struct CutsceneRunner* runner) { } } +float cutsceneSoundQueueTime(int channel); + +float cutsceneStepEstimateTime(struct CutsceneStep* step, union CutsceneStepState* state) { + switch (step->type) { + case CutsceneStepTypePlaySound: + return state ? soundPlayerTimeLeft(state->playSound.soundId) : soundClipDuration(step->playSound.soundId, step->playSound.pitch * (1.0f / 64.0f)); + case CutsceneStepTypeQueueSound: + return state ? soundPlayerTimeLeft(state->playSound.soundId) : soundClipDuration(step->queueSound.soundId, gCutsceneChannelPitch[step->queueSound.channel]); + case CutsceneStepTypeWaitForChannel: + { + return state ? cutsceneSoundQueueTime(step->waitForChannel.channel) : 0.0f; + } + case CutsceneStepTypeDelay: + return state ? state->delay : step->delay; + case CutsceneStepTypeWaitForSignal: + return 0.0f; + case CutsceneStepTypeWaitForCutscene: + return cutsceneEstimateTimeLeft(&gCurrentLevel->cutscenes[step->cutscene.cutsceneIndex]); + case CutsceneStepWaitForAnimation: + // Maybe todo + return 0.0f; + default: + return 0.0f; + } +} + void cutsceneRunnerRun(struct CutsceneRunner* runner, struct Cutscene* cutscene) { runner->currentCutscene = cutscene; runner->currentStep = 0; @@ -352,6 +380,23 @@ int cutsceneIsRunning(struct Cutscene* cutscene) { return 0; } +float cutsceneSoundQueueTime(int channel) { + float result = 0.0f; + + if (soundPlayerIsPlaying(gCutsceneCurrentSound[channel])) { + result += soundPlayerTimeLeft(gCutsceneCurrentSound[channel]); + } + + struct QueuedSound* curr = gCutsceneSoundQueues[channel]; + + while (curr) { + result += soundClipDuration(curr->soundId, gCutsceneChannelPitch[channel]); + curr = curr->next; + } + + return result; +} + void cutscenesUpdateSounds() { for (int i = 0; i < CH_COUNT; ++i) { if (!soundPlayerIsPlaying(gCutsceneCurrentSound[i])) { @@ -397,6 +442,30 @@ void cutscenesUpdate() { } } +float cutsceneRunnerEstimateTimeLeft(struct CutsceneRunner* cutsceneRunner) { + float result = 0.0f; + + for (int i = cutsceneRunner->currentStep; i < cutsceneRunner->currentCutscene->stepCount; ++i) { + result += cutsceneStepEstimateTime(&cutsceneRunner->currentCutscene->steps[i], i == cutsceneRunner->currentStep ? &cutsceneRunner->state : NULL); + } + + return result; +} + +float cutsceneEstimateTimeLeft(struct Cutscene* cutscene) { + struct CutsceneRunner* current = gRunningCutscenes; + + while (current) { + if (current->currentCutscene == cutscene) { + return cutsceneRunnerEstimateTimeLeft(current); + } + + current = current->nextRunner; + } + + + return 0.0f; +} void cutsceneCheckTriggers(struct Vector3* playerPos) { for (int i = 0; i < gCurrentLevel->triggerCount; ++i) { diff --git a/src/levels/cutscene_runner.h b/src/levels/cutscene_runner.h index 51d1303..d671139 100644 --- a/src/levels/cutscene_runner.h +++ b/src/levels/cutscene_runner.h @@ -32,6 +32,7 @@ void cutsceneStart(struct Cutscene* cutscene); void cutsceneStop(struct Cutscene* cutscene); int cutsceneIsRunning(struct Cutscene* cutscene); void cutscenesUpdate(); +float cutsceneEstimateTimeLeft(struct Cutscene* cutscene); void cutsceneCheckTriggers(struct Vector3* playerPos); diff --git a/src/scene/clock.c b/src/scene/clock.c index 17bd1b4..ab05ecc 100644 --- a/src/scene/clock.c +++ b/src/scene/clock.c @@ -3,11 +3,68 @@ #include "../scene/dynamic_scene.h" #include "../defs.h" +#include "../levels/levels.h" +#include "../levels/cutscene_runner.h" #include "../build/assets/models/signage/clock.h" #include "../build/assets/models/signage/clock_digits.h" #include "../../build/assets/materials/static.h" +#include + +#define DIGIT_WIDTH 512 + +u8 gCurrentClockDigits[5]; +Vtx* gClockDigits[] = { + signage_clock_digits_clock_digits_minute_01_color, + signage_clock_digits_clock_digits_second_10_color, + signage_clock_digits_clock_digits_second_01_color, + signage_clock_digits_clock_digits_ms_10_color, + signage_clock_digits_clock_digits_ms_01_color, +}; + +void clockSetDigit(int digitIndex, int currDigit) { + int prevDigit = gCurrentClockDigits[digitIndex]; + + if (prevDigit == currDigit) { + return; + } + + for (int i = 0; i < 4; ++i) { + gClockDigits[digitIndex][i].v.tc[0] += (currDigit - prevDigit) * DIGIT_WIDTH; + } + gCurrentClockDigits[digitIndex] = (u8)currDigit; + osWritebackDCache(gClockDigits[digitIndex], sizeof(Vtx) * 4); +} + +void clockSetTime(float timeInSeconds) { + float minutes = floor(timeInSeconds * (1.0f / 60.0f)); + + clockSetDigit(0, (int)minutes); + + timeInSeconds -= minutes *= 60.0f; + + float tenSeconds = floor(timeInSeconds * 0.1f); + + clockSetDigit(1, (int)tenSeconds); + + timeInSeconds -= tenSeconds * 10.0f; + + float seconds = floor(timeInSeconds); + + clockSetDigit(2, (int)seconds); + + timeInSeconds -= seconds; + + float tenthsOfSecond = floor(timeInSeconds * 10.0f); + + clockSetDigit(3, (int)tenthsOfSecond); + + timeInSeconds -= tenthsOfSecond * 0.1f; + + clockSetDigit(4, (int)floor(timeInSeconds * 100.0f)); +} + void clockRenderRender(void* data, struct DynamicRenderDataList* renderList, struct RenderState* renderState) { struct Clock* clock = (struct Clock*)data; @@ -17,6 +74,14 @@ void clockRenderRender(void* data, struct DynamicRenderDataList* renderList, str return; } + float time = 0.0f; + + if (clock->cutsceneIndex != -1) { + time = cutsceneEstimateTimeLeft(&gCurrentLevel->cutscenes[clock->cutsceneIndex]); + } + + clockSetTime(time); + transformToMatrixL(&clock->transform, matrix, SCENE_SCALE); dynamicRenderListAddData( @@ -30,7 +95,7 @@ void clockRenderRender(void* data, struct DynamicRenderDataList* renderList, str dynamicRenderListAddData( renderList, - signage_clock_model_gfx, + signage_clock_digits_model_gfx, matrix, CLOCK_DIGITS_INDEX, &clock->transform.position,