Skip to content

Commit 4e4c6e4

Browse files
committed
constant-text-fade-duration: refactor glyph progress calculation and add duration helper methods
1 parent 58e4717 commit 4e4c6e4

2 files changed

Lines changed: 72 additions & 49 deletions

File tree

src/text/typewritereffect.cpp

Lines changed: 66 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,16 @@ namespace Impacto {
1010
using namespace Profile::ConfigSystem;
1111
using namespace Profile::Dialogue;
1212

13+
namespace {
14+
float CalcLinearProgress(float progress, float startProgress,
15+
float endProgress) {
16+
if (endProgress <= startProgress)
17+
return progress >= endProgress ? 1.0f : 0.0f;
18+
return std::clamp((progress - startProgress) / (endProgress - startProgress),
19+
0.0f, 1.0f);
20+
}
21+
} // namespace
22+
1323
void TypewriterEffect::Start(const bool voiced) {
1424
DurationIn = 1.0f;
1525
Voiced = voiced;
@@ -90,41 +100,62 @@ TypewriterEffect::ParallelBlock TypewriterEffect::GetParallelBlock(
90100
}
91101
}
92102

93-
std::pair<float, float> TypewriterEffect::GetGlyphWritingProgresses(
94-
const size_t glyph) {
95-
const ParallelBlock block = GetParallelBlock(glyph);
103+
float TypewriterEffect::GetTypewriterDurationSeconds() const {
104+
if (Voiced && Profile::ConfigSystem::SyncVoice) {
105+
return std::max(Audio::Channels[Audio::AC_VOICE0]->DurationInSeconds(),
106+
0.0f);
107+
}
96108

97-
const size_t parallelBlockGlyphNo = glyph - block.Start;
109+
if (Profile::ConfigSystem::TextSpeed >=
110+
Profile::ConfigSystem::TextSpeedBounds.y) {
111+
return std::max(TextFadeInDuration, 0.0f);
112+
}
98113

99-
// We start displaying a glyph after the previous one is 25% opaque, hence
100-
// totalDisplayTime = glyphCount * (0.25 * glyphDisplayTime) +
101-
// glyphDisplayTime * 0.75
114+
if (Profile::ConfigSystem::TextSpeed <= 0.0f) return 0.0f;
102115

103-
constexpr float singleGlyphDuration = 1.0f;
104-
constexpr float glyphPropagateProgress = 0.25f;
105-
constexpr float glyphPropagateDuration =
106-
singleGlyphDuration * glyphPropagateProgress;
107-
const float totalDuration =
108-
block.Size * glyphPropagateDuration +
109-
(1.0f - glyphPropagateProgress) * singleGlyphDuration;
116+
return static_cast<float>(GlyphCount) / Profile::ConfigSystem::TextSpeed;
117+
}
110118

111-
const float startTime = glyphPropagateDuration * parallelBlockGlyphNo;
112-
const float endTime = startTime + singleGlyphDuration;
119+
float TypewriterEffect::GetSingleGlyphFadeDurationSeconds(
120+
float totalDurationSeconds) const {
121+
if (totalDurationSeconds <= 0.0f || TextFadeInDuration <= 0.0f) return 0.0f;
113122

114-
return {startTime / totalDuration, endTime / totalDuration};
123+
return std::min(TextFadeInDuration, totalDurationSeconds);
124+
}
125+
126+
std::pair<float, float> TypewriterEffect::GetWritingProgresses(
127+
const size_t glyphNo, const size_t glyphCount,
128+
const float totalDurationSeconds) const {
129+
if (glyphCount == 0 || totalDurationSeconds <= 0.0f) return {0.0f, 1.0f};
130+
131+
const float glyphFadeDuration =
132+
GetSingleGlyphFadeDurationSeconds(totalDurationSeconds);
133+
134+
float startTime = 0.0f;
135+
if (glyphCount > 1 && totalDurationSeconds > glyphFadeDuration) {
136+
const float glyphStartInterval =
137+
(totalDurationSeconds - glyphFadeDuration) / (glyphCount - 1);
138+
startTime = glyphStartInterval * glyphNo;
139+
}
140+
141+
const float endTime =
142+
std::min(startTime + glyphFadeDuration, totalDurationSeconds);
143+
144+
return {startTime / totalDurationSeconds, endTime / totalDurationSeconds};
145+
}
146+
147+
std::pair<float, float> TypewriterEffect::GetGlyphWritingProgresses(
148+
const size_t glyph) {
149+
const ParallelBlock block = GetParallelBlock(glyph);
150+
151+
return GetWritingProgresses(glyph - block.Start, block.Size,
152+
GetTypewriterDurationSeconds());
115153
}
116154

117155
float TypewriterEffect::CalcOpacity(size_t glyph) {
118156
if (glyph < FirstGlyph) return 1.0f;
119157
if (glyph >= FirstGlyph + GlyphCount) return 0.0f;
120158

121-
if (!IsCancelled &&
122-
Profile::ConfigSystem::TextSpeed >=
123-
Profile::ConfigSystem::TextSpeedBounds.y &&
124-
!(Voiced && Profile::ConfigSystem::SyncVoice)) {
125-
return Progress;
126-
}
127-
128159
const auto [startProgress, endProgress] = GetGlyphWritingProgresses(glyph);
129160

130161
if (IsCancelled) {
@@ -142,13 +173,12 @@ float TypewriterEffect::CalcOpacity(size_t glyph) {
142173
// Translucent glyphs fade in further, in addition to the opacity they
143174
// already had
144175
const float glyphProgressBeforeCancellation =
145-
(ProgressOnCancel - startProgress) / (endProgress - startProgress);
176+
CalcLinearProgress(ProgressOnCancel, startProgress, endProgress);
146177
return glyphProgressBeforeCancellation +
147178
cancelProgress * (1.0f - glyphProgressBeforeCancellation);
148179
}
149180

150-
return std::clamp((Progress - startProgress) / (endProgress - startProgress),
151-
0.0f, 1.0f);
181+
return CalcLinearProgress(Progress, startProgress, endProgress);
152182
}
153183

154184
float TypewriterEffect::CalcRubyOpacity(const size_t rubyGlyphId,
@@ -180,27 +210,16 @@ float TypewriterEffect::CalcRubyOpacity(const size_t rubyGlyphId,
180210
}
181211

182212
const float baseProgressLength = baseEndProgress - baseStartProgress;
183-
184-
// We start displaying a glyph after the previous one is 25% opaque, hence
185-
// totalDisplayTime = glyphCount * (0.25 * glyphDisplayTime) +
186-
// glyphDisplayTime * 0.75
187-
188-
constexpr float singleGlyphDuration = 1.0f;
189-
constexpr float glyphPropagateProgress = 0.25f;
190-
constexpr float glyphPropagateDuration =
191-
singleGlyphDuration * glyphPropagateProgress;
192-
const float totalDuration =
193-
chunk.Length * glyphPropagateDuration +
194-
(1.0f - glyphPropagateProgress) * singleGlyphDuration;
195-
196-
const float glyphStartTime = glyphPropagateDuration * rubyGlyphId;
197-
const float glyphEndTime = glyphStartTime + singleGlyphDuration;
213+
const float baseDurationSeconds =
214+
GetTypewriterDurationSeconds() * baseProgressLength;
215+
const auto [glyphStartProgressInBase, glyphEndProgressInBase] =
216+
GetWritingProgresses(rubyGlyphId, chunk.Length, baseDurationSeconds);
198217

199218
// Convert back to progress-space
200219
const float startProgress =
201-
baseStartProgress + (glyphStartTime / totalDuration) * baseProgressLength;
220+
baseStartProgress + glyphStartProgressInBase * baseProgressLength;
202221
const float endProgress =
203-
baseStartProgress + (glyphEndTime / totalDuration) * baseProgressLength;
222+
baseStartProgress + glyphEndProgressInBase * baseProgressLength;
204223

205224
if (IsCancelled) {
206225
if (ProgressOnCancel >= endProgress) return 1.0f;
@@ -210,12 +229,11 @@ float TypewriterEffect::CalcRubyOpacity(const size_t rubyGlyphId,
210229
if (ProgressOnCancel <= startProgress) return cancelProgress;
211230

212231
const float glyphProgressBeforeCancellation =
213-
(ProgressOnCancel - startProgress) / (endProgress - startProgress);
232+
CalcLinearProgress(ProgressOnCancel, startProgress, endProgress);
214233
return glyphProgressBeforeCancellation +
215234
cancelProgress * (1.0f - glyphProgressBeforeCancellation);
216235
}
217236

218-
return std::clamp((Progress - startProgress) / (endProgress - startProgress),
219-
0.0f, 1.0f);
237+
return CalcLinearProgress(Progress, startProgress, endProgress);
220238
}
221-
} // namespace Impacto
239+
} // namespace Impacto

src/text/typewritereffect.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,12 @@ struct TypewriterEffect : public Animation {
4141
};
4242
ParallelBlock GetParallelBlock(size_t glyph);
4343

44+
float GetTypewriterDurationSeconds() const;
45+
float GetSingleGlyphFadeDurationSeconds(float totalDurationSeconds) const;
46+
// {startProgress, endProgress} in [0, 1]
47+
std::pair<float, float> GetWritingProgresses(
48+
size_t glyphNo, size_t glyphCount, float totalDurationSeconds) const;
4449
// {startProgress, endProgress}
4550
std::pair<float, float> GetGlyphWritingProgresses(size_t glyph);
4651
};
47-
} // namespace Impacto
52+
} // namespace Impacto

0 commit comments

Comments
 (0)