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
+143 -156
View File
@@ -50,6 +50,20 @@
(speechVolumeScale == 0.0f ? NORMAL_VOLUME : (NORMAL_VOLUME >> 1))
#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;
UNICODE shared_phrase_buf[2048];
@@ -77,20 +91,14 @@ typedef struct encounter_state
BYTE top_response;
RESPONSE_ENTRY response_list[MAX_RESPONSES];
Task AnimTask;
COUNT phrase_buf_index;
UNICODE phrase_buf[512];
UNICODE phrase_buf[1024];
} ENCOUNTER_STATE;
static ENCOUNTER_STATE *pCurInputState;
// Mutex guards accesses to SubtitleText, last_subtitle and clear_subtitles.
static Mutex subtitle_mutex;
// These vars are indirectly accessed by the ambient_anim_task
static volatile BOOLEAN clear_subtitles;
static BOOLEAN clear_subtitles;
static TEXT SubtitleText;
static const UNICODE * volatile last_subtitle;
static const UNICODE *last_subtitle;
static CONTEXT TextCacheContext;
static FRAME TextCacheFrame;
@@ -104,6 +112,7 @@ RECT CommWndRect = {
static void ClearSubtitles (void);
static void CheckSubtitles (void);
static void RedrawSubtitles (void);
/* _count_lines - sees how many lines a given input string would take to
@@ -392,14 +401,13 @@ DrawSISComWindow (void)
void
init_communication (void)
{
subtitle_mutex = CreateMutex ("Subtitle Lock",
SYNC_CLASS_TOPLEVEL | SYNC_CLASS_VIDEO);
// now a no-op
}
void
uninit_communication (void)
{
DestroyMutex (subtitle_mutex);
// now a no-op
}
static void
@@ -481,34 +489,73 @@ FeedbackPlayerPhrase (UNICODE *pStr)
UnbatchGraphics ();
}
void
UpdateSpeechGraphics (BOOLEAN Initialize)
static void
InitSpeechGraphics (void)
{
RECT r;
RECT sr;
FRAME f;
InitOscilloscope (0, 0, RADAR_WIDTH, RADAR_HEIGHT,
SetAbsFrameIndex (ActivityFrame, 9));
f = SetAbsFrameIndex (ActivityFrame, 2);
GetFrameRect (f, &r);
SetSliderImage (f);
f = SetAbsFrameIndex (ActivityFrame, 5);
GetFrameRect (f, &sr);
InitSlider (0, SLIDER_Y, SIS_SCREEN_WIDTH, sr.extent.height,
r.extent.width, r.extent.height, f);
}
static void
UpdateSpeechGraphics (void)
{
static TimeCount NextTime;
CONTEXT OldContext;
if (Initialize)
{
RECT r, sr;
FRAME f;
if (GetTimeCounter () < NextTime)
return; // too early
InitOscilloscope (0, 0, RADAR_WIDTH, RADAR_HEIGHT,
SetAbsFrameIndex (ActivityFrame, 9));
f = SetAbsFrameIndex (ActivityFrame, 2);
GetFrameRect (f, &r);
SetSliderImage (f);
f = SetAbsFrameIndex (ActivityFrame, 5);
GetFrameRect (f, &sr);
InitSlider (0, SLIDER_Y, SIS_SCREEN_WIDTH, sr.extent.height,
r.extent.width, r.extent.height, f);
}
NextTime = GetTimeCounter () + OSCILLOSCOPE_RATE;
OldContext = SetContext (RadarContext);
Oscilloscope (!Initialize);
DrawOscilloscope ();
SetContext (SpaceContext);
Slider ();
DrawSlider ();
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
typedef struct talking_state
{
@@ -560,8 +607,6 @@ DoTalkSegue (TALKING_STATE *pTS)
right = false;
#endif
LockMutex (GraphicsLock);
if (right)
{
SetSliderImage (SetAbsFrameIndex (ActivityFrame, 3));
@@ -570,10 +615,6 @@ DoTalkSegue (TALKING_STATE *pTS)
else if (optSmoothScroll == OPT_3DO)
FastForward_Smooth ();
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)
{
@@ -584,8 +625,6 @@ DoTalkSegue (TALKING_STATE *pTS)
else if (optSmoothScroll == OPT_3DO)
FastReverse_Smooth ();
pTS->seeking = true;
// XXX: See pause discussion above
PauseAnimTask = TRUE;
}
else if (pTS->seeking)
{
@@ -595,16 +634,21 @@ DoTalkSegue (TALKING_STATE *pTS)
SetSliderImage (SetAbsFrameIndex (ActivityFrame, 2));
}
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
// after seeking back to the beginning.
// Broken cases were: Syreen "several hours later" and Starbase
// VUX Beast analysis by the scientist.
PauseAnimTask = FALSE;
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);
curTrack = PlayingTrack ();
@@ -617,6 +661,15 @@ DoTalkSegue (TALKING_STATE *pTS)
return pTS->seeking || (curTrack && curTrack <= pTS->waitTrack);
}
static void
runCommAnimFrame (void)
{
LockMutex (GraphicsLock);
UpdateCommGraphics ();
UnlockMutex (GraphicsLock);
SleepThread (COMM_ANIM_RATE);
}
static BOOLEAN
TalkSegue (COUNT wait_track)
{
@@ -630,12 +683,9 @@ TalkSegue (COUNT wait_track)
setRunTalkingAnim ();
// wait until the transition finishes
while (runningIntroAnim ())
{ // wait until the transition finishes
UnlockMutex (GraphicsLock);
SleepThread (ONE_SECOND / 30);
LockMutex (GraphicsLock);
}
runCommAnimFrame ();
}
memset (&talkingState, 0, sizeof talkingState);
@@ -651,16 +701,12 @@ TalkSegue (COUNT wait_track)
assert (PlayingTrack ());
}
UnlockMutex (GraphicsLock);
// Run the talking controls
SetMenuSounds (MENU_SOUND_NONE, MENU_SOUND_NONE);
talkingState.InputFunc = DoTalkSegue;
talkingState.waitTrack = wait_track;
DoInput (&talkingState, FALSE);
LockMutex (GraphicsLock);
PauseAnimTask = FALSE;
ClearSubtitles ();
if (talkingState.ended)
@@ -672,20 +718,11 @@ TalkSegue (COUNT wait_track)
if (runningTalkingAnim ())
setStopTalkingAnim ();
return talkingState.ended;
}
static void
FlushTalkSegue (void)
{
WaitForNoInput (ONE_SECOND / 2, TRUE);
// Wait until the animation task stops "talking"
do
SleepThread (ONE_SECOND / 30);
while (runningTalkingAnim ());
while (runningTalkingAnim ())
runCommAnimFrame ();
TalkingFinished = TRUE;
return talkingState.ended;
}
static void
@@ -732,53 +769,34 @@ CommIntroTransition (void)
void
AlienTalkSegue (COUNT wait_track)
{
BOOLEAN done;
// this skips any talk segues that follow an aborted one
if ((GLOBAL (CurrentActivity) & CHECK_ABORT) || TalkingFinished)
return;
LockMutex (GraphicsLock);
if (!pCurInputState->Initialized)
{
InitSpeechGraphics ();
LockMutex (GraphicsLock);
SetColorMap (GetColorMapAddress (CommData.AlienColorMap));
SetContext (AnimContext);
DrawAlienFrame (NULL, 0, TRUE);
UpdateSpeechGraphics (TRUE);
UpdateSpeechGraphics ();
CommIntroTransition ();
UnlockMutex (GraphicsLock);
pCurInputState->Initialized = TRUE;
PlayMusic (CommData.AlienSong, TRUE, 1);
SetMusicVolume (BACKGROUND_VOL);
{
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);
}
InitCommAnimations ();
LastActivity &= ~CHECK_LOAD;
}
done = TalkSegue (wait_track);
if (done)
TalkingFinished = TalkSegue (wait_track);
if (TalkingFinished)
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;
TEXT t;
int row;
FONT oldFont;
r.corner.x = 0;
r.corner.y = 0;
@@ -843,6 +860,7 @@ DoConvSummary (SUMMARY_STATE *pSS)
r.extent.height = SIS_SCREEN_HEIGHT - SLIDER_Y - SLIDER_HEIGHT + 2;
LockMutex (GraphicsLock);
SetContext (AnimContext);
SetContextForeGroundColor (COMM_HISTORY_BACKGROUND_COLOR);
DrawFilledRectangle (&r);
@@ -852,7 +870,7 @@ DoConvSummary (SUMMARY_STATE *pSS)
t.baseline.x = 2;
t.align = ALIGN_LEFT;
t.baseline.y = DELTA_Y_SUMMARY;
oldFont = SetContextFont (TinyFont);
SetContextFont (TinyFont);
for (row = 0; row < MAX_SUMM_ROWS && pSS->NextSub;
++row, pSS->NextSub = GetNextTrackSubtitle (pSS->NextSub))
@@ -910,7 +928,6 @@ DoConvSummary (SUMMARY_STATE *pSS)
font_DrawText (&mt);
}
SetContextFont (oldFont);
UnlockMutex (GraphicsLock);
pSS->PrintNext = FALSE;
@@ -927,20 +944,16 @@ DoConvSummary (SUMMARY_STATE *pSS)
static void
SelectResponse (ENCOUNTER_STATE *pES)
{
const unsigned char *end;
TEXT *response_text =
&pES->response_list[pES->cur_response].response_text;
end = skipUTF8Chars(response_text->pStr, response_text->CharCount);
pES->phrase_buf_index = end - response_text->pStr;
memcpy(pES->phrase_buf, response_text->pStr, pES->phrase_buf_index);
pES->phrase_buf[pES->phrase_buf_index++] = '\0';
utf8StringCopy (pES->phrase_buf, sizeof pES->phrase_buf,
response_text->pStr);
LockMutex (GraphicsLock);
FeedbackPlayerPhrase (pES->phrase_buf);
UnlockMutex (GraphicsLock);
StopTrack ();
ClearSubtitles ();
SetSliderImage (SetAbsFrameIndex (ActivityFrame, 2));
UnlockMutex (GraphicsLock);
FadeMusic (BACKGROUND_VOL, ONE_SECOND);
@@ -959,10 +972,7 @@ SelectConversationSummary (ENCOUNTER_STATE *pES)
LockMutex (GraphicsLock);
if (pES)
FeedbackPlayerPhrase (pES->phrase_buf);
PauseAnimTask = TRUE;
UnlockMutex (GraphicsLock);
// wait for ambient anim task to pause
SleepThread (ONE_SECOND / 30);
SummaryState.Initialized = FALSE;
DoConvSummary (&SummaryState);
@@ -971,7 +981,6 @@ SelectConversationSummary (ENCOUNTER_STATE *pES)
if (pES)
RefreshResponses (pES);
clear_subtitles = TRUE;
PauseAnimTask = FALSE;
UnlockMutex (GraphicsLock);
}
@@ -982,10 +991,9 @@ SelectReplay (ENCOUNTER_STATE *pES)
LockMutex (GraphicsLock);
if (pES)
FeedbackPlayerPhrase (pES->phrase_buf);
TalkingFinished = FALSE;
TalkSegue (0);
UnlockMutex (GraphicsLock);
FlushTalkSegue ();
TalkSegue (0);
}
static void
@@ -1058,8 +1066,12 @@ PlayerResponseInput (ENCOUNTER_STATE *pES)
UnlockMutex (GraphicsLock);
}
LockMutex (GraphicsLock);
UpdateCommGraphics ();
UnlockMutex (GraphicsLock);
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;
}
LockMutex (GraphicsLock);
UpdateCommGraphics ();
UnlockMutex (GraphicsLock);
SleepThreadUntil (pLRS->NextTime);
pLRS->NextTime = GetTimeCounter () + ONE_SECOND / 60;
pLRS->NextTime = GetTimeCounter () + COMM_ANIM_RATE;
return TRUE;
}
@@ -1110,7 +1126,10 @@ DoCommunication (ENCOUNTER_STATE *pES)
// First, finish playing all queued tracks if not done yet
if (!TalkingFinished)
{
AlienTalkSegue (WAIT_TRACK_ALL);
return TRUE;
}
if (GLOBAL (CurrentActivity) & CHECK_ABORT)
;
@@ -1128,23 +1147,13 @@ DoCommunication (ENCOUNTER_STATE *pES)
else
{
PlayerResponseInput (pES);
return (TRUE);
return TRUE;
}
LockMutex (GraphicsLock);
if (pES->AnimTask)
{
UnlockMutex (GraphicsLock);
ConcludeTask (pES->AnimTask);
LockMutex (GraphicsLock);
pES->AnimTask = 0;
}
SetContext (SpaceContext);
DestroyContext (TaskContext);
TaskContext = 0;
DestroyContext (AnimContext);
AnimContext = NULL;
UnlockMutex (GraphicsLock);
FlushColorXForms ();
@@ -1155,7 +1164,7 @@ DoCommunication (ENCOUNTER_STATE *pES)
StopTrack ();
SleepThreadUntil (FadeMusic (NORMAL_VOLUME, 0) + ONE_SECOND / 60);
return (FALSE);
return FALSE;
}
void
@@ -1234,6 +1243,8 @@ HailAlien (void)
SubtitleText.baseline = CommData.AlienTextBaseline;
SubtitleText.align = CommData.AlienTextAlign;
LockMutex (GraphicsLock);
// init subtitle cache context
TextCacheContext = CreateContext ("TextCacheContext");
TextCacheFrame = CaptureDrawable (
@@ -1247,7 +1258,6 @@ HailAlien (void)
ClearDrawable ();
SetFrameTransparentColor (TextCacheFrame, TextBack);
ES.phrase_buf_index = 1;
ES.phrase_buf[0] = '\0';
SetContext (SpaceContext);
@@ -1256,8 +1266,8 @@ HailAlien (void)
{
RECT r;
TaskContext = CreateContext ("TaskContext");
SetContext (TaskContext);
AnimContext = CreateContext ("AnimContext");
SetContext (AnimContext);
SetContextFGFrame (Screen);
GetFrameRect (CommData.AlienFrame, &r);
r.extent.width = SIS_SCREEN_WIDTH;
@@ -1308,6 +1318,9 @@ HailAlien (void)
(*CommData.uninit_encounter_func) ();
LockMutex (GraphicsLock);
SetContext (SpaceContext);
SetContextFont (OldFont);
UnlockMutex (GraphicsLock);
DestroyStringTable (ReleaseStringTable (CommData.ConversationPhrases));
DestroyMusic (CommData.AlienSong);
@@ -1318,8 +1331,6 @@ HailAlien (void)
DestroyContext (TextCacheContext);
DestroyDrawable (ReleaseDrawable (TextCacheFrame));
SetContext (SpaceContext);
SetContextFont (OldFont);
DestroyFont (PlayerFont);
// 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)
{
status = URQUAN_DRONE_SHIP;
@@ -1416,8 +1429,6 @@ InitCommunication (CONVERSATION which_comm)
CommData = *LocDataPtr;
}
UnlockMutex (GraphicsLock);
if (GET_GAME_STATE (BATTLE_SEGUE) == 0)
{
// Not offered the chance to attack.
@@ -1435,8 +1446,6 @@ InitCommunication (CONVERSATION which_comm)
SET_GAME_STATE (BATTLE_SEGUE, 1);
}
LockMutex (GraphicsLock);
if (status == HAIL)
{
HailAlien ();
@@ -1449,8 +1458,6 @@ InitCommunication (CONVERSATION which_comm)
(*CommData.uninit_encounter_func) (); // cleanup
}
UnlockMutex (GraphicsLock);
status = 0;
if (!(GLOBAL (CurrentActivity) & (CHECK_ABORT | CHECK_LOAD)))
{
@@ -1625,7 +1632,7 @@ RaceCommunication (void)
}
}
void
static void
RedrawSubtitles (void)
{
TEXT t;
@@ -1633,38 +1640,20 @@ RedrawSubtitles (void)
if (!optSubtitles)
return;
LockMutex (subtitle_mutex);
if (SubtitleText.pStr)
{
t = SubtitleText;
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
ClearSubtitles (void)
{
LockMutex (subtitle_mutex);
clear_subtitles = TRUE;
last_subtitle = NULL;
SubtitleText.pStr = NULL;
SubtitleText.CharCount = 0;
UnlockMutex (subtitle_mutex);
}
static void
@@ -1674,7 +1663,6 @@ CheckSubtitles (void)
pStr = GetTrackSubtitle ();
LockMutex (subtitle_mutex);
if (pStr != SubtitleText.pStr)
{ // Subtitles changed
clear_subtitles = TRUE;
@@ -1688,7 +1676,6 @@ CheckSubtitles (void)
else
SubtitleText.CharCount = 0;
}
UnlockMutex (subtitle_mutex);
}
void
-2
View File
@@ -115,8 +115,6 @@ extern void RaceCommunication (void);
extern void AlienTalkSegue (COUNT wait_track);
BOOLEAN getLineWithinWidth(TEXT *pText, const unsigned char **startNext,
SIZE maxWidth, COUNT maxChars);
extern void RedrawSubtitles (void);
extern BOOLEAN HaveSubtitlesChanged (void);
extern RECT CommWndRect; /* comm window rect */
+16 -18
View File
@@ -22,6 +22,10 @@
#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 =
{
NULL, /* init_encounter_func */
@@ -40,7 +44,7 @@ static LOCDATA talkpet_desc =
NULL_RESOURCE, /* AlienAltSong */
0, /* AlienSongFlags */
TALKING_PET_CONVERSATION_PHRASES, /* PlayerPhrases */
16, /* NumAnimations */
17, /* NumAnimations */
{ /* AlienAmbientArray (ambient animations) */
{
7, /* StartIndex */
@@ -173,6 +177,15 @@ static LOCDATA talkpet_desc =
ONE_SECOND, ONE_SECOND * 3, /* RestartRate */
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 */
0, /* StartIndex */
@@ -197,10 +210,6 @@ static LOCDATA talkpet_desc =
NULL,
};
#define STROBE_RATE 15
#define STROBE_LENGTH (ONE_SECOND * 3 / 2)
#define NUM_STROBES (STROBE_LENGTH * STROBE_RATE / ONE_SECOND)
static void
ExitConversation (RESPONSE_REF R)
{
@@ -266,19 +275,8 @@ static void PetDevice (RESPONSE_REF R);
static void
MindControlStrobe (void)
{
BYTE i;
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));
}
// Enable the one-shot strobe animation
CommData.AlienAmbientArray[16].AnimFlags &= ~ANIM_DISABLED;
}
static void
+57 -98
View File
@@ -27,22 +27,19 @@
#include "libs/mathlib.h"
// Maximum ambient 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 AMBIENT_ANIM_RATE 40
static TimeCount LastTime;
static SEQUENCE Sequences[MAX_ANIMATIONS + 2];
// 2 extra for Talk and Transition animations
static DWORD ActiveMask;
// Bit mask of all animations that are currently active.
// Bit 'i' is set if the animation with index 'i' is active.
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
randomFrameRate (SEQUENCE *pSeq)
@@ -354,37 +351,11 @@ AdvanceTransitSequence (SEQUENCE *pSeq, DWORD ElapsedTicks)
return done;
}
static int
ambient_anim_task (void *data)
void
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;
// Certain data must be accessed under GraphicsLock
LockMutex (GraphicsLock);
memset (&DisplayArray[0], 0, sizeof (DisplayArray));
TalkDesc = CommData.AlienTalkDesc;
TransitDesc = CommData.AlienTransitionDesc;
@@ -403,41 +374,35 @@ ambient_anim_task (void *data)
SetupAmbientSequences (Sequences + FirstAmbient, CommData.NumAnimations);
TotalSequences += CommData.NumAnimations;
UnlockMutex (GraphicsLock);
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;
DWORD ElapsedTicks;
DWORD NextActiveMask;
SleepThreadUntil (LastTime + ONE_SECOND / AMBIENT_ANIM_RATE);
LockMutex (GraphicsLock);
BatchGraphics ();
CurTime = GetTimeCounter ();
ElapsedTicks = CurTime - LastTime;
LastTime = CurTime;
if (PauseAnimTask)
{ // anims not processed
i = CommData.NumAnimations;
CanTalk = FALSE;
}
else
{
i = 0;
CanTalk = TRUE;
}
// Process ambient animations
NextActiveMask = ActiveMask;
pSeq = Sequences + FirstAmbient;
for ( ; i < CommData.NumAnimations; ++i, ++pSeq)
for (i = 0; i < CommData.NumAnimations; ++i, ++pSeq)
{
ANIMATION_DESC *ADPtr = pSeq->ADPtr;
DWORD ActiveBit = 1L << i;
@@ -542,25 +507,19 @@ ambient_anim_task (void *data)
}
}
else
{ // Not talking (task may be paused)
// Disable talking anim if it is done
{ // Not talking -- disable talking anim if it is done
if (Talk->Direction == NO_DIR)
TalkDesc.AnimFlags |= ANIM_DISABLED;
}
BatchGraphics ();
// Draw all animations
if (!PauseAnimTask)
{
CONTEXT OldContext;
BOOLEAN SubtitleChange;
BOOLEAN FullRedraw;
BOOLEAN Change;
BOOLEAN ColorChange = XFormColorMap_step ();
// Clearing any active subtitles counts as 'change'
SubtitleChange = HaveSubtitlesChanged ();
FullRedraw = ColorChange || SubtitleChange;
OldContext = SetContext (TaskContext);
if (ColorChange)
FullRedraw = TRUE;
// Colormap animations are processed separately
// from picture anims (see XFormColorMap_step)
@@ -568,33 +527,33 @@ ambient_anim_task (void *data)
CommData.NumAnimations);
Change = DrawAlienFrame (Sequences, TotalSequences, FullRedraw);
if (FullRedraw || Change)
RedrawSubtitles ();
SetContext (OldContext);
ColorChange = FALSE;
}
if (LastOscillTime + (ONE_SECOND / OSCILLOSCOPE_RATE) < CurTime)
{
LastOscillTime = CurTime;
UpdateSpeechGraphics (FALSE);
if (FullRedraw)
Change = TRUE;
}
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;
}
}
return Change;
}
FinishTask (task);
return 0;
}
Task
StartCommAnimTask (void)
{
return AssignTask (ambient_anim_task, 3072, "ambient animations");
}
BOOLEAN
+6 -6
View File
@@ -19,7 +19,6 @@
#include "libs/compiler.h"
#include "libs/gfxlib.h"
#include "libs/tasklib.h"
// Some background: every animation has a neutral frame which returns
// the image to the state it was in before the animation began. Which
@@ -57,6 +56,10 @@
#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
{
COUNT StartIndex;
@@ -124,11 +127,8 @@ typedef struct SEQUENCE SEQUENCE;
// Returns TRUE if there was an animation change
extern BOOLEAN DrawAlienFrame (SEQUENCE *pSeq, COUNT Num, BOOLEAN fullRedraw);
void UpdateSpeechGraphics (BOOLEAN Initialize);
Task StartCommAnimTask(void);
extern volatile BOOLEAN PauseAnimTask;
extern void InitCommAnimations (void);
extern BOOLEAN ProcessCommAnimations (BOOLEAN fullRedraw, BOOLEAN paused);
#endif /* _COMMANIM_H */
+2 -5
View File
@@ -84,16 +84,13 @@ UninitOscilloscope (void)
// draws the oscilloscope
void
Oscilloscope (DWORD grab_data)
DrawOscilloscope (void)
{
STAMP s;
if (oscillDisabled)
return;
if (!grab_data)
return;
TFB_DrawImage_Image (scope_bg, 0, 0, 0, NULL, scope_surf);
if (GraphForegroundStream (scope_data, RADAR_WIDTH - 2, RADAR_HEIGHT - 2))
{
@@ -150,7 +147,7 @@ SetSliderImage (FRAME f)
}
void
Slider (void)
DrawSlider (void)
{
int offs;
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,
FRAME f);
extern void Oscilloscope (DWORD grab_data);
extern void DrawOscilloscope (void);
extern void UninitOscilloscope (void);
extern void InitSlider (int x, int y, int width, int height,
int bwidth, int bheight, FRAME f);
extern void SetSliderImage (FRAME f);
void Slider (void);
void DrawSlider (void);
#endif /* _OSCILL_H */