Comm animations task retired; Talking Pet mind control strobe reworked into an ambient animation; potential buffer overflow and potential wrong summary context fixed (counts towards bug #576)

git-svn-id: svn://svn.code.sf.net/p/sc2/code/trunk@3355 8092fc87-c524-0410-9efc-e669fe64eaf9
This commit is contained in:
avolkov
2009-11-26 17:10:02 +00:00
parent 0489a89e70
commit 98dbf1431b
7 changed files with 228 additions and 289 deletions
+135 -148
View File
@@ -50,6 +50,20 @@
(speechVolumeScale == 0.0f ? NORMAL_VOLUME : (NORMAL_VOLUME >> 1)) (speechVolumeScale == 0.0f ? NORMAL_VOLUME : (NORMAL_VOLUME >> 1))
#define FOREGROUND_VOL NORMAL_VOLUME #define FOREGROUND_VOL NORMAL_VOLUME
// Oscilloscope frame rate
// Should be <= COMM_ANIM_RATE
// XXX: was 32 picked experimentally?
#define OSCILLOSCOPE_RATE (ONE_SECOND / 32)
// Maximum comm animation frame rate (actual execution rate)
// A gfx frame is not always produced during an execution frame,
// and several animations are combined into one gfx frame.
// The rate was originally 120fps which allowed for more animation
// precision which is ultimately wasted on the human eye anyway.
// The highest known stable animation rate is 40fps, so that's what we use.
#define COMM_ANIM_RATE (ONE_SECOND / 40)
static CONTEXT AnimContext;
LOCDATA CommData; LOCDATA CommData;
UNICODE shared_phrase_buf[2048]; UNICODE shared_phrase_buf[2048];
@@ -77,20 +91,14 @@ typedef struct encounter_state
BYTE top_response; BYTE top_response;
RESPONSE_ENTRY response_list[MAX_RESPONSES]; RESPONSE_ENTRY response_list[MAX_RESPONSES];
Task AnimTask; UNICODE phrase_buf[1024];
COUNT phrase_buf_index;
UNICODE phrase_buf[512];
} ENCOUNTER_STATE; } ENCOUNTER_STATE;
static ENCOUNTER_STATE *pCurInputState; static ENCOUNTER_STATE *pCurInputState;
// Mutex guards accesses to SubtitleText, last_subtitle and clear_subtitles. static BOOLEAN clear_subtitles;
static Mutex subtitle_mutex;
// These vars are indirectly accessed by the ambient_anim_task
static volatile BOOLEAN clear_subtitles;
static TEXT SubtitleText; static TEXT SubtitleText;
static const UNICODE * volatile last_subtitle; static const UNICODE *last_subtitle;
static CONTEXT TextCacheContext; static CONTEXT TextCacheContext;
static FRAME TextCacheFrame; static FRAME TextCacheFrame;
@@ -104,6 +112,7 @@ RECT CommWndRect = {
static void ClearSubtitles (void); static void ClearSubtitles (void);
static void CheckSubtitles (void); static void CheckSubtitles (void);
static void RedrawSubtitles (void);
/* _count_lines - sees how many lines a given input string would take to /* _count_lines - sees how many lines a given input string would take to
@@ -392,14 +401,13 @@ DrawSISComWindow (void)
void void
init_communication (void) init_communication (void)
{ {
subtitle_mutex = CreateMutex ("Subtitle Lock", // now a no-op
SYNC_CLASS_TOPLEVEL | SYNC_CLASS_VIDEO);
} }
void void
uninit_communication (void) uninit_communication (void)
{ {
DestroyMutex (subtitle_mutex); // now a no-op
} }
static void static void
@@ -481,18 +489,16 @@ FeedbackPlayerPhrase (UNICODE *pStr)
UnbatchGraphics (); UnbatchGraphics ();
} }
void static void
UpdateSpeechGraphics (BOOLEAN Initialize) InitSpeechGraphics (void)
{ {
CONTEXT OldContext; RECT r;
RECT sr;
if (Initialize)
{
RECT r, sr;
FRAME f; FRAME f;
InitOscilloscope (0, 0, RADAR_WIDTH, RADAR_HEIGHT, InitOscilloscope (0, 0, RADAR_WIDTH, RADAR_HEIGHT,
SetAbsFrameIndex (ActivityFrame, 9)); SetAbsFrameIndex (ActivityFrame, 9));
f = SetAbsFrameIndex (ActivityFrame, 2); f = SetAbsFrameIndex (ActivityFrame, 2);
GetFrameRect (f, &r); GetFrameRect (f, &r);
SetSliderImage (f); SetSliderImage (f);
@@ -500,15 +506,56 @@ UpdateSpeechGraphics (BOOLEAN Initialize)
GetFrameRect (f, &sr); GetFrameRect (f, &sr);
InitSlider (0, SLIDER_Y, SIS_SCREEN_WIDTH, sr.extent.height, InitSlider (0, SLIDER_Y, SIS_SCREEN_WIDTH, sr.extent.height,
r.extent.width, r.extent.height, f); r.extent.width, r.extent.height, f);
} }
static void
UpdateSpeechGraphics (void)
{
static TimeCount NextTime;
CONTEXT OldContext;
if (GetTimeCounter () < NextTime)
return; // too early
NextTime = GetTimeCounter () + OSCILLOSCOPE_RATE;
OldContext = SetContext (RadarContext); OldContext = SetContext (RadarContext);
Oscilloscope (!Initialize); DrawOscilloscope ();
SetContext (SpaceContext); SetContext (SpaceContext);
Slider (); DrawSlider ();
SetContext (OldContext); SetContext (OldContext);
} }
static void
UpdateAnimations (bool paused)
{
static TimeCount NextTime;
CONTEXT OldContext;
BOOLEAN change;
if (GetTimeCounter () < NextTime)
return; // too early
NextTime = GetTimeCounter () + COMM_ANIM_RATE;
OldContext = SetContext (AnimContext);
BatchGraphics ();
// Advance and draw ambient, transit and talk animations
change = ProcessCommAnimations (clear_subtitles, paused);
if (change)
RedrawSubtitles ();
UnbatchGraphics ();
clear_subtitles = FALSE;
SetContext (OldContext);
}
static void
UpdateCommGraphics (void)
{
UpdateAnimations (false);
UpdateSpeechGraphics ();
}
// Derived from INPUT_STATE_DESC // Derived from INPUT_STATE_DESC
typedef struct talking_state typedef struct talking_state
{ {
@@ -560,8 +607,6 @@ DoTalkSegue (TALKING_STATE *pTS)
right = false; right = false;
#endif #endif
LockMutex (GraphicsLock);
if (right) if (right)
{ {
SetSliderImage (SetAbsFrameIndex (ActivityFrame, 3)); SetSliderImage (SetAbsFrameIndex (ActivityFrame, 3));
@@ -570,10 +615,6 @@ DoTalkSegue (TALKING_STATE *pTS)
else if (optSmoothScroll == OPT_3DO) else if (optSmoothScroll == OPT_3DO)
FastForward_Smooth (); FastForward_Smooth ();
pTS->seeking = true; pTS->seeking = true;
// XXX: This causes all animations (talking and ambient)
// in ambient_anim_task to stop progressing. I see no reason why
// the animations cannot continue while seeking.
PauseAnimTask = TRUE;
} }
else if (left || pTS->rewind) else if (left || pTS->rewind)
{ {
@@ -584,8 +625,6 @@ DoTalkSegue (TALKING_STATE *pTS)
else if (optSmoothScroll == OPT_3DO) else if (optSmoothScroll == OPT_3DO)
FastReverse_Smooth (); FastReverse_Smooth ();
pTS->seeking = true; pTS->seeking = true;
// XXX: See pause discussion above
PauseAnimTask = TRUE;
} }
else if (pTS->seeking) else if (pTS->seeking)
{ {
@@ -595,16 +634,21 @@ DoTalkSegue (TALKING_STATE *pTS)
SetSliderImage (SetAbsFrameIndex (ActivityFrame, 2)); SetSliderImage (SetAbsFrameIndex (ActivityFrame, 2));
} }
else else
{ // XXX: See pause discussion above {
// Additionally, this used to have a buggy guard condition, which // This used to have a buggy guard condition, which
// would cause the animations to remain paused in a couple cases // would cause the animations to remain paused in a couple cases
// after seeking back to the beginning. // after seeking back to the beginning.
// Broken cases were: Syreen "several hours later" and Starbase // Broken cases were: Syreen "several hours later" and Starbase
// VUX Beast analysis by the scientist. // VUX Beast analysis by the scientist.
PauseAnimTask = FALSE;
CheckSubtitles (); CheckSubtitles ();
} }
LockMutex (GraphicsLock);
// XXX: When seeking, all animations (talking and ambient) stop
// progressing. This is an original 3DO behavior, and I see no
// reason why the animations cannot continue while seeking.
UpdateAnimations (pTS->seeking);
UpdateSpeechGraphics ();
UnlockMutex (GraphicsLock); UnlockMutex (GraphicsLock);
curTrack = PlayingTrack (); curTrack = PlayingTrack ();
@@ -617,6 +661,15 @@ DoTalkSegue (TALKING_STATE *pTS)
return pTS->seeking || (curTrack && curTrack <= pTS->waitTrack); return pTS->seeking || (curTrack && curTrack <= pTS->waitTrack);
} }
static void
runCommAnimFrame (void)
{
LockMutex (GraphicsLock);
UpdateCommGraphics ();
UnlockMutex (GraphicsLock);
SleepThread (COMM_ANIM_RATE);
}
static BOOLEAN static BOOLEAN
TalkSegue (COUNT wait_track) TalkSegue (COUNT wait_track)
{ {
@@ -630,12 +683,9 @@ TalkSegue (COUNT wait_track)
setRunTalkingAnim (); setRunTalkingAnim ();
// wait until the transition finishes
while (runningIntroAnim ()) while (runningIntroAnim ())
{ // wait until the transition finishes runCommAnimFrame ();
UnlockMutex (GraphicsLock);
SleepThread (ONE_SECOND / 30);
LockMutex (GraphicsLock);
}
} }
memset (&talkingState, 0, sizeof talkingState); memset (&talkingState, 0, sizeof talkingState);
@@ -651,16 +701,12 @@ TalkSegue (COUNT wait_track)
assert (PlayingTrack ()); assert (PlayingTrack ());
} }
UnlockMutex (GraphicsLock);
// Run the talking controls // Run the talking controls
SetMenuSounds (MENU_SOUND_NONE, MENU_SOUND_NONE);
talkingState.InputFunc = DoTalkSegue; talkingState.InputFunc = DoTalkSegue;
talkingState.waitTrack = wait_track; talkingState.waitTrack = wait_track;
DoInput (&talkingState, FALSE); DoInput (&talkingState, FALSE);
LockMutex (GraphicsLock);
PauseAnimTask = FALSE;
ClearSubtitles (); ClearSubtitles ();
if (talkingState.ended) if (talkingState.ended)
@@ -672,20 +718,11 @@ TalkSegue (COUNT wait_track)
if (runningTalkingAnim ()) if (runningTalkingAnim ())
setStopTalkingAnim (); setStopTalkingAnim ();
return talkingState.ended;
}
static void
FlushTalkSegue (void)
{
WaitForNoInput (ONE_SECOND / 2, TRUE);
// Wait until the animation task stops "talking" // Wait until the animation task stops "talking"
do while (runningTalkingAnim ())
SleepThread (ONE_SECOND / 30); runCommAnimFrame ();
while (runningTalkingAnim ());
TalkingFinished = TRUE; return talkingState.ended;
} }
static void static void
@@ -732,53 +769,34 @@ CommIntroTransition (void)
void void
AlienTalkSegue (COUNT wait_track) AlienTalkSegue (COUNT wait_track)
{ {
BOOLEAN done;
// this skips any talk segues that follow an aborted one // this skips any talk segues that follow an aborted one
if ((GLOBAL (CurrentActivity) & CHECK_ABORT) || TalkingFinished) if ((GLOBAL (CurrentActivity) & CHECK_ABORT) || TalkingFinished)
return; return;
LockMutex (GraphicsLock);
if (!pCurInputState->Initialized) if (!pCurInputState->Initialized)
{ {
InitSpeechGraphics ();
LockMutex (GraphicsLock);
SetColorMap (GetColorMapAddress (CommData.AlienColorMap)); SetColorMap (GetColorMapAddress (CommData.AlienColorMap));
SetContext (AnimContext);
DrawAlienFrame (NULL, 0, TRUE); DrawAlienFrame (NULL, 0, TRUE);
UpdateSpeechGraphics (TRUE); UpdateSpeechGraphics ();
CommIntroTransition (); CommIntroTransition ();
UnlockMutex (GraphicsLock);
pCurInputState->Initialized = TRUE; pCurInputState->Initialized = TRUE;
PlayMusic (CommData.AlienSong, TRUE, 1); PlayMusic (CommData.AlienSong, TRUE, 1);
SetMusicVolume (BACKGROUND_VOL); SetMusicVolume (BACKGROUND_VOL);
{ InitCommAnimations ();
DWORD TimeOut;
TimeOut = GetTimeCounter () + (ONE_SECOND >> 1);
// Anim task processes not only ambient animations, but also
// talking animations and subtitles
pCurInputState->AnimTask = StartCommAnimTask ();
UnlockMutex (GraphicsLock);
SleepThreadUntil (TimeOut);
LockMutex (GraphicsLock);
}
LastActivity &= ~CHECK_LOAD; LastActivity &= ~CHECK_LOAD;
} }
done = TalkSegue (wait_track); TalkingFinished = TalkSegue (wait_track);
if (done) if (TalkingFinished)
FadeMusic (FOREGROUND_VOL, ONE_SECOND); FadeMusic (FOREGROUND_VOL, ONE_SECOND);
UnlockMutex (GraphicsLock);
FlushTalkSegue ();
if (!done)
{ // there is more to come
TalkingFinished = FALSE;
}
} }
@@ -835,7 +853,6 @@ DoConvSummary (SUMMARY_STATE *pSS)
RECT r; RECT r;
TEXT t; TEXT t;
int row; int row;
FONT oldFont;
r.corner.x = 0; r.corner.x = 0;
r.corner.y = 0; r.corner.y = 0;
@@ -843,6 +860,7 @@ DoConvSummary (SUMMARY_STATE *pSS)
r.extent.height = SIS_SCREEN_HEIGHT - SLIDER_Y - SLIDER_HEIGHT + 2; r.extent.height = SIS_SCREEN_HEIGHT - SLIDER_Y - SLIDER_HEIGHT + 2;
LockMutex (GraphicsLock); LockMutex (GraphicsLock);
SetContext (AnimContext);
SetContextForeGroundColor (COMM_HISTORY_BACKGROUND_COLOR); SetContextForeGroundColor (COMM_HISTORY_BACKGROUND_COLOR);
DrawFilledRectangle (&r); DrawFilledRectangle (&r);
@@ -852,7 +870,7 @@ DoConvSummary (SUMMARY_STATE *pSS)
t.baseline.x = 2; t.baseline.x = 2;
t.align = ALIGN_LEFT; t.align = ALIGN_LEFT;
t.baseline.y = DELTA_Y_SUMMARY; t.baseline.y = DELTA_Y_SUMMARY;
oldFont = SetContextFont (TinyFont); SetContextFont (TinyFont);
for (row = 0; row < MAX_SUMM_ROWS && pSS->NextSub; for (row = 0; row < MAX_SUMM_ROWS && pSS->NextSub;
++row, pSS->NextSub = GetNextTrackSubtitle (pSS->NextSub)) ++row, pSS->NextSub = GetNextTrackSubtitle (pSS->NextSub))
@@ -910,7 +928,6 @@ DoConvSummary (SUMMARY_STATE *pSS)
font_DrawText (&mt); font_DrawText (&mt);
} }
SetContextFont (oldFont);
UnlockMutex (GraphicsLock); UnlockMutex (GraphicsLock);
pSS->PrintNext = FALSE; pSS->PrintNext = FALSE;
@@ -927,20 +944,16 @@ DoConvSummary (SUMMARY_STATE *pSS)
static void static void
SelectResponse (ENCOUNTER_STATE *pES) SelectResponse (ENCOUNTER_STATE *pES)
{ {
const unsigned char *end;
TEXT *response_text = TEXT *response_text =
&pES->response_list[pES->cur_response].response_text; &pES->response_list[pES->cur_response].response_text;
end = skipUTF8Chars(response_text->pStr, response_text->CharCount); utf8StringCopy (pES->phrase_buf, sizeof pES->phrase_buf,
pES->phrase_buf_index = end - response_text->pStr; response_text->pStr);
memcpy(pES->phrase_buf, response_text->pStr, pES->phrase_buf_index);
pES->phrase_buf[pES->phrase_buf_index++] = '\0';
LockMutex (GraphicsLock); LockMutex (GraphicsLock);
FeedbackPlayerPhrase (pES->phrase_buf); FeedbackPlayerPhrase (pES->phrase_buf);
UnlockMutex (GraphicsLock);
StopTrack (); StopTrack ();
ClearSubtitles (); ClearSubtitles ();
SetSliderImage (SetAbsFrameIndex (ActivityFrame, 2)); SetSliderImage (SetAbsFrameIndex (ActivityFrame, 2));
UnlockMutex (GraphicsLock);
FadeMusic (BACKGROUND_VOL, ONE_SECOND); FadeMusic (BACKGROUND_VOL, ONE_SECOND);
@@ -959,10 +972,7 @@ SelectConversationSummary (ENCOUNTER_STATE *pES)
LockMutex (GraphicsLock); LockMutex (GraphicsLock);
if (pES) if (pES)
FeedbackPlayerPhrase (pES->phrase_buf); FeedbackPlayerPhrase (pES->phrase_buf);
PauseAnimTask = TRUE;
UnlockMutex (GraphicsLock); UnlockMutex (GraphicsLock);
// wait for ambient anim task to pause
SleepThread (ONE_SECOND / 30);
SummaryState.Initialized = FALSE; SummaryState.Initialized = FALSE;
DoConvSummary (&SummaryState); DoConvSummary (&SummaryState);
@@ -971,7 +981,6 @@ SelectConversationSummary (ENCOUNTER_STATE *pES)
if (pES) if (pES)
RefreshResponses (pES); RefreshResponses (pES);
clear_subtitles = TRUE; clear_subtitles = TRUE;
PauseAnimTask = FALSE;
UnlockMutex (GraphicsLock); UnlockMutex (GraphicsLock);
} }
@@ -982,10 +991,9 @@ SelectReplay (ENCOUNTER_STATE *pES)
LockMutex (GraphicsLock); LockMutex (GraphicsLock);
if (pES) if (pES)
FeedbackPlayerPhrase (pES->phrase_buf); FeedbackPlayerPhrase (pES->phrase_buf);
TalkingFinished = FALSE;
TalkSegue (0);
UnlockMutex (GraphicsLock); UnlockMutex (GraphicsLock);
FlushTalkSegue ();
TalkSegue (0);
} }
static void static void
@@ -1058,8 +1066,12 @@ PlayerResponseInput (ENCOUNTER_STATE *pES)
UnlockMutex (GraphicsLock); UnlockMutex (GraphicsLock);
} }
LockMutex (GraphicsLock);
UpdateCommGraphics ();
UnlockMutex (GraphicsLock);
SleepThreadUntil (pES->NextTime); SleepThreadUntil (pES->NextTime);
pES->NextTime = GetTimeCounter () + ONE_SECOND / 20; pES->NextTime = GetTimeCounter () + COMM_ANIM_RATE;
} }
} }
@@ -1097,8 +1109,12 @@ DoLastReplay (LAST_REPLAY_STATE *pLRS)
pLRS->TimeOut = FadeMusic (0, ONE_SECOND * 2) + ONE_SECOND / 60; pLRS->TimeOut = FadeMusic (0, ONE_SECOND * 2) + ONE_SECOND / 60;
} }
LockMutex (GraphicsLock);
UpdateCommGraphics ();
UnlockMutex (GraphicsLock);
SleepThreadUntil (pLRS->NextTime); SleepThreadUntil (pLRS->NextTime);
pLRS->NextTime = GetTimeCounter () + ONE_SECOND / 60; pLRS->NextTime = GetTimeCounter () + COMM_ANIM_RATE;
return TRUE; return TRUE;
} }
@@ -1110,7 +1126,10 @@ DoCommunication (ENCOUNTER_STATE *pES)
// First, finish playing all queued tracks if not done yet // First, finish playing all queued tracks if not done yet
if (!TalkingFinished) if (!TalkingFinished)
{
AlienTalkSegue (WAIT_TRACK_ALL); AlienTalkSegue (WAIT_TRACK_ALL);
return TRUE;
}
if (GLOBAL (CurrentActivity) & CHECK_ABORT) if (GLOBAL (CurrentActivity) & CHECK_ABORT)
; ;
@@ -1128,23 +1147,13 @@ DoCommunication (ENCOUNTER_STATE *pES)
else else
{ {
PlayerResponseInput (pES); PlayerResponseInput (pES);
return (TRUE); return TRUE;
} }
LockMutex (GraphicsLock); LockMutex (GraphicsLock);
if (pES->AnimTask)
{
UnlockMutex (GraphicsLock);
ConcludeTask (pES->AnimTask);
LockMutex (GraphicsLock);
pES->AnimTask = 0;
}
SetContext (SpaceContext); SetContext (SpaceContext);
DestroyContext (TaskContext); DestroyContext (AnimContext);
TaskContext = 0; AnimContext = NULL;
UnlockMutex (GraphicsLock); UnlockMutex (GraphicsLock);
FlushColorXForms (); FlushColorXForms ();
@@ -1155,7 +1164,7 @@ DoCommunication (ENCOUNTER_STATE *pES)
StopTrack (); StopTrack ();
SleepThreadUntil (FadeMusic (NORMAL_VOLUME, 0) + ONE_SECOND / 60); SleepThreadUntil (FadeMusic (NORMAL_VOLUME, 0) + ONE_SECOND / 60);
return (FALSE); return FALSE;
} }
void void
@@ -1234,6 +1243,8 @@ HailAlien (void)
SubtitleText.baseline = CommData.AlienTextBaseline; SubtitleText.baseline = CommData.AlienTextBaseline;
SubtitleText.align = CommData.AlienTextAlign; SubtitleText.align = CommData.AlienTextAlign;
LockMutex (GraphicsLock);
// init subtitle cache context // init subtitle cache context
TextCacheContext = CreateContext ("TextCacheContext"); TextCacheContext = CreateContext ("TextCacheContext");
TextCacheFrame = CaptureDrawable ( TextCacheFrame = CaptureDrawable (
@@ -1247,7 +1258,6 @@ HailAlien (void)
ClearDrawable (); ClearDrawable ();
SetFrameTransparentColor (TextCacheFrame, TextBack); SetFrameTransparentColor (TextCacheFrame, TextBack);
ES.phrase_buf_index = 1;
ES.phrase_buf[0] = '\0'; ES.phrase_buf[0] = '\0';
SetContext (SpaceContext); SetContext (SpaceContext);
@@ -1256,8 +1266,8 @@ HailAlien (void)
{ {
RECT r; RECT r;
TaskContext = CreateContext ("TaskContext"); AnimContext = CreateContext ("AnimContext");
SetContext (TaskContext); SetContext (AnimContext);
SetContextFGFrame (Screen); SetContextFGFrame (Screen);
GetFrameRect (CommData.AlienFrame, &r); GetFrameRect (CommData.AlienFrame, &r);
r.extent.width = SIS_SCREEN_WIDTH; r.extent.width = SIS_SCREEN_WIDTH;
@@ -1308,6 +1318,9 @@ HailAlien (void)
(*CommData.uninit_encounter_func) (); (*CommData.uninit_encounter_func) ();
LockMutex (GraphicsLock); LockMutex (GraphicsLock);
SetContext (SpaceContext);
SetContextFont (OldFont);
UnlockMutex (GraphicsLock);
DestroyStringTable (ReleaseStringTable (CommData.ConversationPhrases)); DestroyStringTable (ReleaseStringTable (CommData.ConversationPhrases));
DestroyMusic (CommData.AlienSong); DestroyMusic (CommData.AlienSong);
@@ -1318,8 +1331,6 @@ HailAlien (void)
DestroyContext (TextCacheContext); DestroyContext (TextCacheContext);
DestroyDrawable (ReleaseDrawable (TextCacheFrame)); DestroyDrawable (ReleaseDrawable (TextCacheFrame));
SetContext (SpaceContext);
SetContextFont (OldFont);
DestroyFont (PlayerFont); DestroyFont (PlayerFont);
// Some support code tests either of these to see if the // Some support code tests either of these to see if the
@@ -1373,6 +1384,8 @@ InitCommunication (CONVERSATION which_comm)
} }
} }
UnlockMutex (GraphicsLock);
if (which_comm == URQUAN_DRONE_CONVERSATION) if (which_comm == URQUAN_DRONE_CONVERSATION)
{ {
status = URQUAN_DRONE_SHIP; status = URQUAN_DRONE_SHIP;
@@ -1416,8 +1429,6 @@ InitCommunication (CONVERSATION which_comm)
CommData = *LocDataPtr; CommData = *LocDataPtr;
} }
UnlockMutex (GraphicsLock);
if (GET_GAME_STATE (BATTLE_SEGUE) == 0) if (GET_GAME_STATE (BATTLE_SEGUE) == 0)
{ {
// Not offered the chance to attack. // Not offered the chance to attack.
@@ -1435,8 +1446,6 @@ InitCommunication (CONVERSATION which_comm)
SET_GAME_STATE (BATTLE_SEGUE, 1); SET_GAME_STATE (BATTLE_SEGUE, 1);
} }
LockMutex (GraphicsLock);
if (status == HAIL) if (status == HAIL)
{ {
HailAlien (); HailAlien ();
@@ -1449,8 +1458,6 @@ InitCommunication (CONVERSATION which_comm)
(*CommData.uninit_encounter_func) (); // cleanup (*CommData.uninit_encounter_func) (); // cleanup
} }
UnlockMutex (GraphicsLock);
status = 0; status = 0;
if (!(GLOBAL (CurrentActivity) & (CHECK_ABORT | CHECK_LOAD))) if (!(GLOBAL (CurrentActivity) & (CHECK_ABORT | CHECK_LOAD)))
{ {
@@ -1625,7 +1632,7 @@ RaceCommunication (void)
} }
} }
void static void
RedrawSubtitles (void) RedrawSubtitles (void)
{ {
TEXT t; TEXT t;
@@ -1633,38 +1640,20 @@ RedrawSubtitles (void)
if (!optSubtitles) if (!optSubtitles)
return; return;
LockMutex (subtitle_mutex);
if (SubtitleText.pStr) if (SubtitleText.pStr)
{ {
t = SubtitleText; t = SubtitleText;
add_text (1, &t); add_text (1, &t);
} }
UnlockMutex (subtitle_mutex);
}
// Returns clear_subtitles and resets it
BOOLEAN
HaveSubtitlesChanged (void)
{
BOOLEAN ret;
LockMutex (subtitle_mutex);
ret = clear_subtitles;
clear_subtitles = FALSE;
UnlockMutex (subtitle_mutex);
return ret;
} }
static void static void
ClearSubtitles (void) ClearSubtitles (void)
{ {
LockMutex (subtitle_mutex);
clear_subtitles = TRUE; clear_subtitles = TRUE;
last_subtitle = NULL; last_subtitle = NULL;
SubtitleText.pStr = NULL; SubtitleText.pStr = NULL;
SubtitleText.CharCount = 0; SubtitleText.CharCount = 0;
UnlockMutex (subtitle_mutex);
} }
static void static void
@@ -1674,7 +1663,6 @@ CheckSubtitles (void)
pStr = GetTrackSubtitle (); pStr = GetTrackSubtitle ();
LockMutex (subtitle_mutex);
if (pStr != SubtitleText.pStr) if (pStr != SubtitleText.pStr)
{ // Subtitles changed { // Subtitles changed
clear_subtitles = TRUE; clear_subtitles = TRUE;
@@ -1688,7 +1676,6 @@ CheckSubtitles (void)
else else
SubtitleText.CharCount = 0; SubtitleText.CharCount = 0;
} }
UnlockMutex (subtitle_mutex);
} }
void void
-2
View File
@@ -115,8 +115,6 @@ extern void RaceCommunication (void);
extern void AlienTalkSegue (COUNT wait_track); extern void AlienTalkSegue (COUNT wait_track);
BOOLEAN getLineWithinWidth(TEXT *pText, const unsigned char **startNext, BOOLEAN getLineWithinWidth(TEXT *pText, const unsigned char **startNext,
SIZE maxWidth, COUNT maxChars); SIZE maxWidth, COUNT maxChars);
extern void RedrawSubtitles (void);
extern BOOLEAN HaveSubtitlesChanged (void);
extern RECT CommWndRect; /* comm window rect */ extern RECT CommWndRect; /* comm window rect */
+16 -18
View File
@@ -22,6 +22,10 @@
#include "uqm/build.h" #include "uqm/build.h"
#define STROBE_RATE 10
#define STROBE_LENGTH (ONE_SECOND * 3 / 2)
#define NUM_STROBES (STROBE_LENGTH * STROBE_RATE / ONE_SECOND)
static LOCDATA talkpet_desc = static LOCDATA talkpet_desc =
{ {
NULL, /* init_encounter_func */ NULL, /* init_encounter_func */
@@ -40,7 +44,7 @@ static LOCDATA talkpet_desc =
NULL_RESOURCE, /* AlienAltSong */ NULL_RESOURCE, /* AlienAltSong */
0, /* AlienSongFlags */ 0, /* AlienSongFlags */
TALKING_PET_CONVERSATION_PHRASES, /* PlayerPhrases */ TALKING_PET_CONVERSATION_PHRASES, /* PlayerPhrases */
16, /* NumAnimations */ 17, /* NumAnimations */
{ /* AlienAmbientArray (ambient animations) */ { /* AlienAmbientArray (ambient animations) */
{ {
7, /* StartIndex */ 7, /* StartIndex */
@@ -173,6 +177,15 @@ static LOCDATA talkpet_desc =
ONE_SECOND, ONE_SECOND * 3, /* RestartRate */ ONE_SECOND, ONE_SECOND * 3, /* RestartRate */
0, /* BlockMask */ 0, /* BlockMask */
}, },
{ /* Mind control strobe (on-demand) */
1, /* StartIndex */
NUM_STROBES * 2, /* NumFrames */
CIRCULAR_ANIM | COLORXFORM_ANIM | ONE_SHOT_ANIM
| ANIM_DISABLED, /* AnimFlags */
ONE_SECOND / (STROBE_RATE * 2), 0, /* FrameRate */
0, 0, /* RestartRate */
0, /* BlockMask */
},
}, },
{ /* AlienTransitionDesc */ { /* AlienTransitionDesc */
0, /* StartIndex */ 0, /* StartIndex */
@@ -197,10 +210,6 @@ static LOCDATA talkpet_desc =
NULL, NULL,
}; };
#define STROBE_RATE 15
#define STROBE_LENGTH (ONE_SECOND * 3 / 2)
#define NUM_STROBES (STROBE_LENGTH * STROBE_RATE / ONE_SECOND)
static void static void
ExitConversation (RESPONSE_REF R) ExitConversation (RESPONSE_REF R)
{ {
@@ -266,19 +275,8 @@ static void PetDevice (RESPONSE_REF R);
static void static void
MindControlStrobe (void) MindControlStrobe (void)
{ {
BYTE i; // Enable the one-shot strobe animation
CommData.AlienAmbientArray[16].AnimFlags &= ~ANIM_DISABLED;
for (i = 0; i < NUM_STROBES; ++i)
{
XFormColorMap (GetColorMapAddress (
SetAbsColorMapIndex (CommData.AlienColorMap, 1)
), 0);
SleepThread (ONE_SECOND / (STROBE_RATE * 2));
XFormColorMap (GetColorMapAddress (
SetAbsColorMapIndex (CommData.AlienColorMap, 0)
), 0);
SleepThread (ONE_SECOND / (STROBE_RATE * 2));
}
} }
static void static void
+56 -97
View File
@@ -27,22 +27,19 @@
#include "libs/mathlib.h" #include "libs/mathlib.h"
// Maximum ambient animation frame rate (actual execution rate) static TimeCount LastTime;
// A gfx frame is not always produced during an execution frame, static SEQUENCE Sequences[MAX_ANIMATIONS + 2];
// and several animations are combined into one gfx frame. // 2 extra for Talk and Transition animations
// The rate was originally 120fps which allowed for more animation static DWORD ActiveMask;
// precision which is ultimately wasted on the human eye anyway. // Bit mask of all animations that are currently active.
// The highest known stable animation rate is 40fps, so that's what we use. // Bit 'i' is set if the animation with index 'i' is active.
#define AMBIENT_ANIM_RATE 40 static ANIMATION_DESC TalkDesc;
static ANIMATION_DESC TransitDesc;
static SEQUENCE* Talk;
static SEQUENCE* Transit;
static COUNT FirstAmbient;
static COUNT TotalSequences;
// Oscilloscope frame rate
// Should be <= AMBIENT_ANIM_RATE
// XXX: was 32 picked experimentally?
#define OSCILLOSCOPE_RATE 32
static int ambient_anim_task (void *data);
volatile BOOLEAN PauseAnimTask = FALSE;
static inline DWORD static inline DWORD
randomFrameRate (SEQUENCE *pSeq) randomFrameRate (SEQUENCE *pSeq)
@@ -354,37 +351,11 @@ AdvanceTransitSequence (SEQUENCE *pSeq, DWORD ElapsedTicks)
return done; return done;
} }
static int void
ambient_anim_task (void *data) InitCommAnimations (void)
{ {
COUNT i;
TimeCount LastTime;
SEQUENCE Sequences[MAX_ANIMATIONS + 2];
// 2 extra for Talk and Transition animations
SEQUENCE *pSeq;
DWORD ActiveMask;
// Bit mask of all animations that are currently active.
// Bit 'i' is set if the animation with index 'i' is active.
DWORD LastOscillTime;
Task task = (Task) data;
BOOLEAN ColorChange = FALSE;
ANIMATION_DESC TalkDesc;
ANIMATION_DESC TransitDesc;
SEQUENCE* Talk;
SEQUENCE* Transit;
COUNT FirstAmbient;
COUNT TotalSequences;
while (!CommData.AlienFrame && !Task_ReadState (task, TASK_EXIT))
TaskSwitch ();
ActiveMask = 0; ActiveMask = 0;
// Certain data must be accessed under GraphicsLock
LockMutex (GraphicsLock);
memset (&DisplayArray[0], 0, sizeof (DisplayArray));
TalkDesc = CommData.AlienTalkDesc; TalkDesc = CommData.AlienTalkDesc;
TransitDesc = CommData.AlienTransitionDesc; TransitDesc = CommData.AlienTransitionDesc;
@@ -403,41 +374,35 @@ ambient_anim_task (void *data)
SetupAmbientSequences (Sequences + FirstAmbient, CommData.NumAnimations); SetupAmbientSequences (Sequences + FirstAmbient, CommData.NumAnimations);
TotalSequences += CommData.NumAnimations; TotalSequences += CommData.NumAnimations;
UnlockMutex (GraphicsLock);
LastTime = GetTimeCounter (); LastTime = GetTimeCounter ();
LastOscillTime = LastTime; }
while (!Task_ReadState (task, TASK_EXIT)) BOOLEAN
ProcessCommAnimations (BOOLEAN FullRedraw, BOOLEAN paused)
{
if (paused)
{ // Drive colormap xforms and nothing else
XFormColorMap_step ();
return FALSE;
}
else
{ {
BOOLEAN CanTalk; COUNT i;
SEQUENCE *pSeq;
BOOLEAN Change;
BOOLEAN CanTalk = TRUE;
TimeCount CurTime; TimeCount CurTime;
DWORD ElapsedTicks; DWORD ElapsedTicks;
DWORD NextActiveMask; DWORD NextActiveMask;
SleepThreadUntil (LastTime + ONE_SECOND / AMBIENT_ANIM_RATE);
LockMutex (GraphicsLock);
BatchGraphics ();
CurTime = GetTimeCounter (); CurTime = GetTimeCounter ();
ElapsedTicks = CurTime - LastTime; ElapsedTicks = CurTime - LastTime;
LastTime = CurTime; LastTime = CurTime;
if (PauseAnimTask)
{ // anims not processed
i = CommData.NumAnimations;
CanTalk = FALSE;
}
else
{
i = 0;
CanTalk = TRUE;
}
// Process ambient animations // Process ambient animations
NextActiveMask = ActiveMask; NextActiveMask = ActiveMask;
pSeq = Sequences + FirstAmbient; pSeq = Sequences + FirstAmbient;
for ( ; i < CommData.NumAnimations; ++i, ++pSeq) for (i = 0; i < CommData.NumAnimations; ++i, ++pSeq)
{ {
ANIMATION_DESC *ADPtr = pSeq->ADPtr; ANIMATION_DESC *ADPtr = pSeq->ADPtr;
DWORD ActiveBit = 1L << i; DWORD ActiveBit = 1L << i;
@@ -542,25 +507,19 @@ ambient_anim_task (void *data)
} }
} }
else else
{ // Not talking (task may be paused) { // Not talking -- disable talking anim if it is done
// Disable talking anim if it is done
if (Talk->Direction == NO_DIR) if (Talk->Direction == NO_DIR)
TalkDesc.AnimFlags |= ANIM_DISABLED; TalkDesc.AnimFlags |= ANIM_DISABLED;
} }
BatchGraphics ();
// Draw all animations // Draw all animations
if (!PauseAnimTask)
{ {
CONTEXT OldContext; BOOLEAN ColorChange = XFormColorMap_step ();
BOOLEAN SubtitleChange;
BOOLEAN FullRedraw;
BOOLEAN Change;
// Clearing any active subtitles counts as 'change' if (ColorChange)
SubtitleChange = HaveSubtitlesChanged (); FullRedraw = TRUE;
FullRedraw = ColorChange || SubtitleChange;
OldContext = SetContext (TaskContext);
// Colormap animations are processed separately // Colormap animations are processed separately
// from picture anims (see XFormColorMap_step) // from picture anims (see XFormColorMap_step)
@@ -568,33 +527,33 @@ ambient_anim_task (void *data)
CommData.NumAnimations); CommData.NumAnimations);
Change = DrawAlienFrame (Sequences, TotalSequences, FullRedraw); Change = DrawAlienFrame (Sequences, TotalSequences, FullRedraw);
if (FullRedraw || Change) if (FullRedraw)
RedrawSubtitles (); Change = TRUE;
SetContext (OldContext);
ColorChange = FALSE;
}
if (LastOscillTime + (ONE_SECOND / OSCILLOSCOPE_RATE) < CurTime)
{
LastOscillTime = CurTime;
UpdateSpeechGraphics (FALSE);
} }
UnbatchGraphics (); UnbatchGraphics ();
UnlockMutex (GraphicsLock);
ColorChange = XFormColorMap_step (); // Post-process ambient animations
pSeq = Sequences + FirstAmbient;
for (i = 0; i < CommData.NumAnimations; ++i, ++pSeq)
{
ANIMATION_DESC *ADPtr = pSeq->ADPtr;
DWORD ActiveBit = 1L << i;
if (ADPtr->AnimFlags & ANIM_DISABLED)
continue;
// We can only disable a one-shot anim here, otherwise the
// last frame will not be drawn
if ((ADPtr->AnimFlags & ONE_SHOT_ANIM)
&& !(NextActiveMask & ActiveBit))
{ // One-shot animation, inactive next frame
ADPtr->AnimFlags |= ANIM_DISABLED;
}
} }
FinishTask (task);
return 0;
}
Task return Change;
StartCommAnimTask (void) }
{
return AssignTask (ambient_anim_task, 3072, "ambient animations");
} }
BOOLEAN BOOLEAN
+6 -6
View File
@@ -19,7 +19,6 @@
#include "libs/compiler.h" #include "libs/compiler.h"
#include "libs/gfxlib.h" #include "libs/gfxlib.h"
#include "libs/tasklib.h"
// Some background: every animation has a neutral frame which returns // Some background: every animation has a neutral frame which returns
// the image to the state it was in before the animation began. Which // the image to the state it was in before the animation began. Which
@@ -57,6 +56,10 @@
#define COLORXFORM_ANIM PAUSE_TALKING #define COLORXFORM_ANIM PAUSE_TALKING
#define ONE_SHOT_ANIM TALK_INTRO
// Set in AlienAmbientArray for animations that should be
// disabled after they run once.
typedef struct typedef struct
{ {
COUNT StartIndex; COUNT StartIndex;
@@ -124,11 +127,8 @@ typedef struct SEQUENCE SEQUENCE;
// Returns TRUE if there was an animation change // Returns TRUE if there was an animation change
extern BOOLEAN DrawAlienFrame (SEQUENCE *pSeq, COUNT Num, BOOLEAN fullRedraw); extern BOOLEAN DrawAlienFrame (SEQUENCE *pSeq, COUNT Num, BOOLEAN fullRedraw);
extern void InitCommAnimations (void);
void UpdateSpeechGraphics (BOOLEAN Initialize); extern BOOLEAN ProcessCommAnimations (BOOLEAN fullRedraw, BOOLEAN paused);
Task StartCommAnimTask(void);
extern volatile BOOLEAN PauseAnimTask;
#endif /* _COMMANIM_H */ #endif /* _COMMANIM_H */
+2 -5
View File
@@ -84,16 +84,13 @@ UninitOscilloscope (void)
// draws the oscilloscope // draws the oscilloscope
void void
Oscilloscope (DWORD grab_data) DrawOscilloscope (void)
{ {
STAMP s; STAMP s;
if (oscillDisabled) if (oscillDisabled)
return; return;
if (!grab_data)
return;
TFB_DrawImage_Image (scope_bg, 0, 0, 0, NULL, scope_surf); TFB_DrawImage_Image (scope_bg, 0, 0, 0, NULL, scope_surf);
if (GraphForegroundStream (scope_data, RADAR_WIDTH - 2, RADAR_HEIGHT - 2)) if (GraphForegroundStream (scope_data, RADAR_WIDTH - 2, RADAR_HEIGHT - 2))
{ {
@@ -150,7 +147,7 @@ SetSliderImage (FRAME f)
} }
void void
Slider (void) DrawSlider (void)
{ {
int offs; int offs;
static int last_offs = -1; static int last_offs = -1;
+2 -2
View File
@@ -25,13 +25,13 @@ extern BOOLEAN oscillDisabled;
extern void InitOscilloscope (DWORD x, DWORD y, DWORD width, DWORD height, extern void InitOscilloscope (DWORD x, DWORD y, DWORD width, DWORD height,
FRAME f); FRAME f);
extern void Oscilloscope (DWORD grab_data); extern void DrawOscilloscope (void);
extern void UninitOscilloscope (void); extern void UninitOscilloscope (void);
extern void InitSlider (int x, int y, int width, int height, extern void InitSlider (int x, int y, int width, int height,
int bwidth, int bheight, FRAME f); int bwidth, int bheight, FRAME f);
extern void SetSliderImage (FRAME f); extern void SetSliderImage (FRAME f);
void Slider (void); void DrawSlider (void);
#endif /* _OSCILL_H */ #endif /* _OSCILL_H */