@@ -10,6 +10,16 @@ namespace Impacto {
1010using namespace Profile ::ConfigSystem;
1111using 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+
1323void 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
117155float 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
154184float 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
0 commit comments