diff --git a/sc2/src/sc2code/comm.c b/sc2/src/sc2code/comm.c index a2ae93386..eea57b44c 100644 --- a/sc2/src/sc2code/comm.c +++ b/sc2/src/sc2code/comm.c @@ -55,11 +55,6 @@ // XXX: was 32 picked experimentally? #define OSCILLOSCOPE_RATE 32 -static void init_xform_control (void); -static void uninit_xform_control (void); -static void xform_complete (void); -static void xform_PLUT_step (SIZE TDelta); -static void FlushPLUTXForms (void); static int ambient_anim_task (void *data); static BOOLEAN getLineWithinWidth(TEXT *pText, @@ -509,177 +504,21 @@ DrawAlienFrame (FRAME aframe, PSEQUENCE pSeq) UnbatchGraphics (); } -typedef struct xform_control -{ - COLORMAPPTR CMapPtr; - SIZE Ticks, TTotal, TOrig; - UBYTE OldCMap[PLUT_BYTE_SIZE]; -} XFORM_CONTROL; - -#define MAX_XFORMS 32 -static struct { - XFORM_CONTROL TaskControl[MAX_XFORMS]; - volatile int XFormCurrent, XFormInsertPoint; - volatile BOOLEAN XFormsPending; - Mutex XFormLock; -} XFormControl; - -static void -init_xform_control (void) -{ - XFormControl.XFormCurrent = XFormControl.XFormInsertPoint = 0; - XFormControl.XFormsPending = FALSE; - XFormControl.XFormLock = CreateMutex ("Transform Lock", SYNC_CLASS_TOPLEVEL | SYNC_CLASS_VIDEO); -} - -static void -uninit_xform_control (void) -{ - DestroyMutex (XFormControl.XFormLock); -} - -static void -xform_complete (void) -{ - LockMutex (XFormControl.XFormLock); - if (XFormControl.XFormsPending) - { - SetColorMap (XFormControl.TaskControl[XFormControl.XFormCurrent].CMapPtr); - if (++XFormControl.XFormCurrent >= MAX_XFORMS) - { - XFormControl.XFormCurrent = 0; - } - if (XFormControl.XFormCurrent == XFormControl.XFormInsertPoint) - { - XFormControl.XFormsPending = FALSE; - } - } - UnlockMutex (XFormControl.XFormLock); -} - void init_communication (void) { subtitle_mutex = CreateMutex ("Subtitle Lock", SYNC_CLASS_TOPLEVEL | SYNC_CLASS_VIDEO); - init_xform_control (); } void uninit_communication (void) { DestroyMutex (subtitle_mutex); - uninit_xform_control (); } -static volatile BOOLEAN ColorChange; static volatile BOOLEAN SummaryChange; static volatile BOOLEAN ClearSubtitle; -/* Only one thread should ever be allowed to be calling this at any time */ -static void -xform_PLUT_step (SIZE TDelta) -{ - XFORM_CONTROL *control; - COLORMAPPTR ColorMapPtr; - int i; - - if (!XFormControl.XFormsPending) - return; - - control = &XFormControl.TaskControl[XFormControl.XFormCurrent]; - - ColorMapPtr = control->CMapPtr; - - if (TDelta > control->TTotal) - TDelta = control->TTotal; - - if (_varPLUTs && control->TOrig != 0) - { -#define XFORM_SCALE 0x10000 - UBYTE *pCurCMap, *pOldCMap, *pNewCMap; - int frac; - - pCurCMap = GET_VAR_PLUT (*ColorMapPtr); - pOldCMap = control->OldCMap; - pNewCMap = (UBYTE*)ColorMapPtr + 2; - - frac = (int)(control->TOrig - control->TTotal) * XFORM_SCALE - / control->TOrig; - - for (i = 0; i < PLUT_BYTE_SIZE; i++) - { - *pCurCMap = (UBYTE)(*pOldCMap + ((int)*pNewCMap - *pOldCMap) - * frac / XFORM_SCALE); - pOldCMap++; - pCurCMap++; - pNewCMap++; - } - ColorChange = TRUE; - } - else if (control->TOrig == 0) - { // asked for immediate xform - ColorChange = TRUE; - } - control->TTotal -= TDelta; - if (!control->TTotal) - { - xform_complete (); - } -} - -/* This should be thread-safe without locking the XFormControl because - * only one thread should be Flushing at any given time, constant - * writes are atomic anyway, and Flush is the only routine that writes - * XFormFlush. */ - -static void -FlushPLUTXForms (void) -{ - while (XFormControl.XFormsPending) - { - xform_complete (); - } -} - -DWORD -XFormPLUT (COLORMAPPTR ColorMapPtr, SIZE TimeInterval) -{ - if (ColorMapPtr) - { - XFORM_CONTROL *control; - - // FlushPLUTXForms (); - - LockMutex (XFormControl.XFormLock); - while (XFormControl.XFormsPending - && (XFormControl.XFormInsertPoint == XFormControl.XFormCurrent)) - { - UnlockMutex (XFormControl.XFormLock); - FlushPLUTXForms (); - LockMutex (XFormControl.XFormLock); - } - - control = &XFormControl.TaskControl[XFormControl.XFormInsertPoint]; - - memcpy (control->OldCMap, GET_VAR_PLUT (*ColorMapPtr), PLUT_BYTE_SIZE); - - control->CMapPtr = ColorMapPtr; - if ((control->Ticks = TimeInterval) <= 0) - control->Ticks = 1; /* prevent divide by zero and negative fade */ - control->TTotal = control->TOrig = TimeInterval; - - if (++XFormControl.XFormInsertPoint >= MAX_XFORMS) - XFormControl.XFormInsertPoint = 0; - - XFormControl.XFormsPending = TRUE; - - UnlockMutex (XFormControl.XFormLock); - - } - - return (0); -} - static void RefreshResponses (PENCOUNTER_STATE pES) { @@ -867,6 +706,7 @@ ambient_anim_task (void *data) BOOLEAN TransitionDone = FALSE; BOOLEAN TalkFrameChanged = FALSE; BOOLEAN FrameChanged[MAX_ANIMATIONS]; + BOOLEAN ColorChange = FALSE; while ((CommFrame = CommData.AlienFrame) == 0 && !Task_ReadState (task, TASK_EXIT)) TaskSwitch (); @@ -963,7 +803,7 @@ ambient_anim_task (void *data) if (pSeq->AnimType == COLOR_ANIM) { - XFormPLUT ( + XFormColorMap ( GetColorMapAddress (pSeq->AnimObj.CurCMap), (COUNT) (pSeq->Alarm - 1) ); @@ -1208,7 +1048,7 @@ ambient_anim_task (void *data) if (!summary) { CONTEXT OldContext; - BOOLEAN CheckSub = 0; + BOOLEAN CheckSub = FALSE; BOOLEAN ClearSub; int sub_state; @@ -1228,8 +1068,8 @@ ambient_anim_task (void *data) CommData.AlienFrame = CommFrame; DrawAlienFrame (TalkFrame, &Sequencer[CommData.NumAnimations - 1]); CommData.AlienFrame = F; - CheckSub = 1; - ClearSub = SummaryChange ? TRUE : FALSE; + CheckSub = TRUE; + ClearSub = SummaryChange; ColorChange = SummaryChange = FALSE; } if (Change || ClearSub) @@ -1270,7 +1110,7 @@ ambient_anim_task (void *data) TalkFrameChanged = FALSE; } Change = FALSE; - CheckSub = 1; + CheckSub = TRUE; } if (optSubtitles && CheckSub && sub_state >= SPACE_SUBTITLE) @@ -1290,7 +1130,7 @@ ambient_anim_task (void *data) } UnbatchGraphics (); UnlockMutex (GraphicsLock); - xform_PLUT_step(ElapsedTicks); + ColorChange = XFormColorMap_step (); } FinishTask (task); return(0); @@ -1914,11 +1754,9 @@ DoCommunication (PENCOUNTER_STATE pES) UnlockMutex (GraphicsLock); - FlushPLUTXForms (); - ColorChange = FALSE; + FlushColorXForms (); ClearSubtitle = FALSE; - FlushColorXForms (); StopMusic (); StopSound (); StopTrack (); diff --git a/sc2/src/sc2code/comm/comandr/comandr.c b/sc2/src/sc2code/comm/comandr/comandr.c index 15a7cb3ee..f57c15436 100644 --- a/sc2/src/sc2code/comm/comandr/comandr.c +++ b/sc2/src/sc2code/comm/comandr/comandr.c @@ -588,7 +588,7 @@ GiveRadios (RESPONSE_REF R) CommData.AlienAmbientArray[2].AnimFlags |= ANIM_DISABLED; UnlockMutex (GraphicsLock); - XFormPLUT (GetColorMapAddress ( + XFormColorMap (GetColorMapAddress ( SetAbsColorMapIndex (CommData.AlienColorMap, 0) ), ONE_SECOND / 2); diff --git a/sc2/src/sc2code/comm/melnorm/melnorm.c b/sc2/src/sc2code/comm/melnorm/melnorm.c index 264d4cee2..2fa762d56 100644 --- a/sc2/src/sc2code/comm/melnorm/melnorm.c +++ b/sc2/src/sc2code/comm/melnorm/melnorm.c @@ -1342,7 +1342,7 @@ NatureOfConversation (RESPONSE_REF R) /* Melnorme reports any news and turns purple */ NPCPhrase (BUY_OR_SELL); AlienTalkSegue(1); - XFormPLUT (GetColorMapAddress ( + XFormColorMap (GetColorMapAddress ( SetAbsColorMapIndex (CommData.AlienColorMap, 1) ), ONE_SECOND / 2); AlienTalkSegue((COUNT)~0); @@ -1432,7 +1432,7 @@ DoBluster (RESPONSE_REF R) if (PLAYER_SAID (R, trade_is_for_the_weak)) { - XFormPLUT (GetColorMapAddress ( + XFormColorMap (GetColorMapAddress ( SetAbsColorMapIndex (CommData.AlienColorMap, 2) ), ONE_SECOND / 2); @@ -1629,7 +1629,7 @@ DoFirstMeeting (RESPONSE_REF R) } else if (PLAYER_SAID (R, yes_really_testing)) { - XFormPLUT (GetColorMapAddress ( + XFormColorMap (GetColorMapAddress ( SetAbsColorMapIndex (CommData.AlienColorMap, 0) ), ONE_SECOND / 2); @@ -1638,7 +1638,7 @@ DoFirstMeeting (RESPONSE_REF R) else if (PLAYER_SAID (R, we_apologize)) { SET_GAME_STATE (MELNORME_ANGER, 0); - XFormPLUT (GetColorMapAddress ( + XFormColorMap (GetColorMapAddress ( SetAbsColorMapIndex (CommData.AlienColorMap, 0) ), ONE_SECOND / 2); @@ -1677,7 +1677,7 @@ DoMelnormeMiffed (RESPONSE_REF R) } SET_GAME_STATE (MELNORME_MIFFED_COUNT, miffed_count); - XFormPLUT (GetColorMapAddress ( + XFormColorMap (GetColorMapAddress ( SetAbsColorMapIndex (CommData.AlienColorMap, 2) ), ONE_SECOND / 2); } @@ -1749,7 +1749,7 @@ DoMelnormePissed (RESPONSE_REF R) } SET_GAME_STATE (MELNORME_PISSED_COUNT, pissed_count); - XFormPLUT (GetColorMapAddress ( + XFormColorMap (GetColorMapAddress ( SetAbsColorMapIndex (CommData.AlienColorMap, 2) ), ONE_SECOND / 2); } @@ -1804,7 +1804,7 @@ DoMelnormeHate (RESPONSE_REF R) } SET_GAME_STATE (MELNORME_HATE_COUNT, hate_count); - XFormPLUT (GetColorMapAddress ( + XFormColorMap (GetColorMapAddress ( SetAbsColorMapIndex (CommData.AlienColorMap, 2) ), ONE_SECOND / 2); diff --git a/sc2/src/sc2code/comm/orz/orzc.c b/sc2/src/sc2code/comm/orz/orzc.c index 65cc77c77..86d094d2d 100644 --- a/sc2/src/sc2code/comm/orz/orzc.c +++ b/sc2/src/sc2code/comm/orz/orzc.c @@ -228,7 +228,7 @@ ExitConversation (RESPONSE_REF R) if (PLAYER_SAID (R, about_andro_3)) ActivateStarShip (ORZ_SHIP, -1); - XFormPLUT (GetColorMapAddress ( + XFormColorMap (GetColorMapAddress ( SetAbsColorMapIndex (CommData.AlienColorMap, 1) ), ONE_SECOND / 2); } diff --git a/sc2/src/sc2code/comm/spahome/spahome.c b/sc2/src/sc2code/comm/spahome/spahome.c index a0d70f794..a1df5370f 100644 --- a/sc2/src/sc2code/comm/spahome/spahome.c +++ b/sc2/src/sc2code/comm/spahome/spahome.c @@ -575,7 +575,7 @@ AllianceOffer (RESPONSE_REF R) if (PLAYER_SAID (R, misunderstanding)) { NPCPhrase (JUST_MISUNDERSTANDING); - XFormPLUT (GetColorMapAddress ( + XFormColorMap (GetColorMapAddress ( SetAbsColorMapIndex (CommData.AlienColorMap, 1) ), ONE_SECOND / 4); @@ -753,7 +753,7 @@ SpathiCouncil (RESPONSE_REF R) else if (PLAYER_SAID (R, good_password)) { NPCPhrase (YES_GOOD_PASSWORD); - XFormPLUT (GetColorMapAddress ( + XFormColorMap (GetColorMapAddress ( SetAbsColorMapIndex (CommData.AlienColorMap, 1) ), ONE_SECOND / 4); diff --git a/sc2/src/sc2code/comm/syreen/syreenc.c b/sc2/src/sc2code/comm/syreen/syreenc.c index 45ce89fd1..708d6aaa0 100644 --- a/sc2/src/sc2code/comm/syreen/syreenc.c +++ b/sc2/src/sc2code/comm/syreen/syreenc.c @@ -214,7 +214,7 @@ FriendlyExit (RESPONSE_REF R) AlienTalkSegue (1); AlienTalkSegue (2); - XFormPLUT (GetColorMapAddress ( + XFormColorMap (GetColorMapAddress ( SetAbsColorMapIndex (CommData.AlienColorMap, 0) ), ONE_SECOND / 2); AlienTalkSegue ((COUNT)~0); @@ -279,7 +279,7 @@ Foreplay (RESPONSE_REF R) NPCPhrase (ABOUT_US); NPCPhrase (MORE_COMFORTABLE); AlienTalkSegue (1); - XFormPLUT (GetColorMapAddress ( + XFormColorMap (GetColorMapAddress ( SetAbsColorMapIndex (CommData.AlienColorMap, 1) ), ONE_SECOND); AlienTalkSegue ((COUNT)~0); diff --git a/sc2/src/sc2code/comm/talkpet/talkpet.c b/sc2/src/sc2code/comm/talkpet/talkpet.c index 94d962b8f..0b8ac324f 100644 --- a/sc2/src/sc2code/comm/talkpet/talkpet.c +++ b/sc2/src/sc2code/comm/talkpet/talkpet.c @@ -264,11 +264,11 @@ MindControlStrobe (void) for (i = 0; i < NUM_STROBES; ++i) { - XFormPLUT (GetColorMapAddress ( + XFormColorMap (GetColorMapAddress ( SetAbsColorMapIndex (CommData.AlienColorMap, 1) ), 0); SleepThread (ONE_SECOND / (STROBE_RATE * 2)); - XFormPLUT (GetColorMapAddress ( + XFormColorMap (GetColorMapAddress ( SetAbsColorMapIndex (CommData.AlienColorMap, 0) ), 0); SleepThread (ONE_SECOND / (STROBE_RATE * 2)); diff --git a/sc2/src/sc2code/comm/vux/vuxc.c b/sc2/src/sc2code/comm/vux/vuxc.c index 849391e34..1bbd0dcaa 100644 --- a/sc2/src/sc2code/comm/vux/vuxc.c +++ b/sc2/src/sc2code/comm/vux/vuxc.c @@ -207,7 +207,7 @@ CombatIsInevitable (RESPONSE_REF R) NPCPhrase (FOOL_AIEE1); AlienTalkSegue (1); - XFormPLUT (GetColorMapAddress ( + XFormColorMap (GetColorMapAddress ( SetAbsColorMapIndex (CommData.AlienColorMap, 1) ), ONE_SECOND / 4); AlienTalkSegue ((COUNT)~0); diff --git a/sc2/src/sc2code/commglue.h b/sc2/src/sc2code/commglue.h index 1f5ff0f01..2440561ab 100644 --- a/sc2/src/sc2code/commglue.h +++ b/sc2/src/sc2code/commglue.h @@ -126,7 +126,5 @@ extern LOCDATAPTR init_zoqfot_comm (void); extern LOCDATAPTR init_umgah_comm (void); -extern DWORD XFormPLUT (COLORMAPPTR ColorMapPtr, SIZE TimeInterval); - #endif /* _COMMGLUE_H */ diff --git a/sc2/src/sc2code/libs/graphics/cmap.c b/sc2/src/sc2code/libs/graphics/cmap.c index 2541abab7..13e509cbc 100644 --- a/sc2/src/sc2code/libs/graphics/cmap.c +++ b/sc2/src/sc2code/libs/graphics/cmap.c @@ -30,37 +30,222 @@ static struct COUNT NumCycles; Task XFormTask; } tc; -} TaskControl; +} FadeControl; + +typedef struct xform_control +{ + int CMapIndex; // -1 means unused + COLORMAPPTR CMapPtr; + SIZE Ticks; + DWORD StartTime; + DWORD EndTime; + TFB_Palette OldCMap[NUMBER_OF_PLUTVALS]; +} XFORM_CONTROL; + +#define MAX_XFORMS 16 +static struct +{ + XFORM_CONTROL TaskControl[MAX_XFORMS]; + volatile int Highest; + // 'pending' is Highest >= 0 + Mutex Lock; +} XFormControl; volatile int FadeAmount = FADE_NORMAL_INTENSITY; -static volatile int end, XForming; +static volatile int FadeEnd, XForming; -UBYTE* _varPLUTs; -static unsigned int varPLUTsize = 0; +#define SPARE_COLORMAPS 20 +#define MAP_POOL_SIZE (MAX_COLORMAPS + SPARE_COLORMAPS) + +static TFB_ColorMap mappool[MAP_POOL_SIZE]; +static TFB_ColorMap *poolhead; + +static TFB_ColorMap * colormaps[MAX_COLORMAPS]; +static int mapcount; +Mutex maplock; -void TFB_ColorMapToRGB (TFB_Palette *pal, int colormap_index) +void +InitColorMaps (void) { int i; - UBYTE *colors; - colors = GET_VAR_PLUT (colormap_index); + // init colormaps + maplock = CreateMutex ("Colormaps Lock", SYNC_CLASS_TOPLEVEL | SYNC_CLASS_VIDEO); + // init static pool + for (i = 0; i < MAP_POOL_SIZE - 1; ++i) + mappool[i].next = mappool + i + 1; + mappool[i].next = NULL; + poolhead = mappool; - for (i = 0; i < NUMBER_OF_PLUTVALS; i++) + // init xform control + XFormControl.Highest = -1; + XFormControl.Lock = CreateMutex ("Transform Lock", SYNC_CLASS_TOPLEVEL | SYNC_CLASS_VIDEO); + for (i = 0; i < MAX_XFORMS; ++i) + XFormControl.TaskControl[i].CMapIndex = -1; +} + +void +UninitColorMaps (void) +{ + // uninit xform control + DestroyMutex (XFormControl.Lock); + + // uninit colormaps + DestroyMutex (maplock); +} + +static inline TFB_ColorMap * +alloc_colormap (void) + // returns an addrefed object +{ + TFB_ColorMap *map; + + if (!poolhead) + return NULL; + + map = poolhead; + poolhead = map->next; + + map->next = NULL; + map->index = -1; + map->refcount = 1; + map->version = 0; + + return map; +} + +static TFB_ColorMap * +clone_colormap (TFB_ColorMap *from, int index) + // returns an addrefed object +{ + TFB_ColorMap *map; + + map = alloc_colormap (); + if (!map) { - pal[i].r = *colors++; - pal[i].g = *colors++; - pal[i].b = *colors++; + static DWORD NextTime = 0; + DWORD Now; + + if (!from) + { + fprintf (stderr, "FATAL: clone_colormap(): no maps available\n"); + abort (); + } + + Now = GetTimeCounter (); + if (Now >= NextTime) + { + fprintf (stderr, "clone_colormap(): static pool exhausted\n"); + NextTime = Now + ONE_SECOND; + } + + // just overwrite the current one -- better than aborting + map = from; + from->refcount++; } + else + { // fresh new map + map->index = index; + if (from) + map->version = from->version; + } + map->version++; + + return map; +} + +static inline void +free_colormap (TFB_ColorMap *map) +{ + if (!map) + { + fprintf (stderr, "free_colormap(): tried to free a NULL map\n"); + return; + } + + map->next = poolhead; + poolhead = map; +} + +static inline TFB_ColorMap * +get_colormap (int index) +{ + TFB_ColorMap *map; + + map = colormaps[index]; + if (!map) + { + fprintf (stderr, "BUG: get_colormap(): map not present\n"); + abort (); + } + + map->refcount++; + return map; +} + +static inline void +release_colormap (TFB_ColorMap *map) +{ + if (!map) + return; + + if (map->refcount <= 0) + { + fprintf (stderr, "BUG: release_colormap(): refcount not >0\n"); + return; + } + + map->refcount--; + if (map->refcount == 0) + free_colormap (map); +} + +void +TFB_ReturnColorMap (TFB_ColorMap *map) +{ + LockMutex (maplock); + release_colormap (map); + UnlockMutex (maplock); +} + +TFB_ColorMap * +TFB_GetColorMap (int index) +{ + TFB_ColorMap *map; + + LockMutex (maplock); + map = get_colormap (index); + UnlockMutex (maplock); + + return map; +} + +void +TFB_ColorMapToRGB (TFB_Palette *pal, int index) +{ + TFB_ColorMap *map = NULL; + + if (index < mapcount) + map = colormaps[index]; + + if (!map) + { + fprintf (stderr, "TFB_ColorMapToRGB(): " + "requested non-present colormap %d\n", index); + return; + } + + memcpy (pal, map->colors, sizeof (map->colors)); } BOOLEAN SetColorMap (COLORMAPPTR map) { int start, end; - DWORD size, total_size; + int total_size; UBYTE *colors = (UBYTE*)map; - UBYTE *vp; + TFB_ColorMap **mpp; if (!map) return TRUE; @@ -68,46 +253,77 @@ SetColorMap (COLORMAPPTR map) start = *colors++; end = *colors++; if (start > end) - return TRUE; - - size = (end - start + 1) * PLUT_BYTE_SIZE; - total_size = (end + 1) * PLUT_BYTE_SIZE; + { + fprintf (stderr, "ERROR: SetColorMap(): " + "starting map (%d) not less or eq ending (%d)\n", + start, end); + return FALSE; + } + if (start >= MAX_COLORMAPS) + { + fprintf (stderr, "ERROR: SetColorMap(): " + "starting map (%d) beyond range (0-%d)\n", + start, (int)MAX_COLORMAPS - 1); + return FALSE; + } + if (end >= MAX_COLORMAPS) + { + fprintf (stderr, "SetColorMap(): " + "ending map (%d) beyond range (0-%d)\n", + end, (int)MAX_COLORMAPS - 1); + end = MAX_COLORMAPS - 1; + } - if (!_varPLUTs) - { - _varPLUTs = (UBYTE *) HMalloc (total_size); - varPLUTsize = total_size; - } - else if (total_size > varPLUTsize) - { - _varPLUTs = (UBYTE *) HRealloc (_varPLUTs, total_size); - varPLUTsize = total_size; - } - if (!_varPLUTs) - { - varPLUTsize = 0; - return TRUE; - } + total_size = end + 1; + + LockMutex (maplock); + + if (total_size > mapcount) + mapcount = total_size; - vp = GET_VAR_PLUT (start); - memcpy (vp, colors, size); + // parse the supplied PLUTs into our colormaps + for (mpp = colormaps + start; start <= end; ++start, ++mpp) + { + int i; + TFB_Palette *pal; + TFB_ColorMap *newmap; + TFB_ColorMap *oldmap; + + oldmap = *mpp; + newmap = clone_colormap (oldmap, start); + + for (i = 0, pal = newmap->colors; i < NUMBER_OF_PLUTVALS; ++i, ++pal) + { + pal->r = *colors++; + pal->g = *colors++; + pal->b = *colors++; + } + + *mpp = newmap; + release_colormap (oldmap); + } + + UnlockMutex (maplock); //fprintf (stderr, "SetColorMap(): vp %x map %x bytes %d, start %d end %d\n", vp, map, bytes, start, end); return TRUE; } +/* Fade Transforms */ + static int -xform_clut_task (void *data) +fade_xform_task (void *data) { SIZE TDelta, TTotal; DWORD CurTime; Task task = (Task)data; XForming = TRUE; - while (TaskControl.tc.XFormTask == 0 && (!Task_ReadState (task, TASK_EXIT))) + while (FadeControl.tc.XFormTask == 0 + && (!Task_ReadState (task, TASK_EXIT))) TaskSwitch (); - TTotal = TaskControl.Ticks; - TaskControl.tc.XFormTask = 0; + TTotal = FadeControl.Ticks; + FadeControl.tc.XFormTask = 0; { CurTime = GetTimeCounter (); @@ -121,8 +337,8 @@ xform_clut_task (void *data) if (!XForming || (TDelta = (SIZE)(CurTime - StartTime)) > TTotal) TDelta = TTotal; - FadeAmount += (end - FadeAmount) * TDelta / TTotal; - //fprintf (stderr, "xform_clut_task FadeAmount %d\n", FadeAmount); + FadeAmount += (FadeEnd - FadeAmount) * TDelta / TTotal; + //fprintf (stderr, "fade_xform_task FadeAmount %d\n", FadeAmount); } while ((TTotal -= TDelta) && (!Task_ReadState (task, TASK_EXIT))); } @@ -132,58 +348,8 @@ xform_clut_task (void *data) return 0; } -DWORD -XFormColorMap (COLORMAPPTR ColorMapPtr, SIZE TimeInterval) -{ - BYTE what; - DWORD TimeOut; - - FlushColorXForms (); - - if (ColorMapPtr == (COLORMAPPTR)0) - return (0); - - what = *ColorMapPtr; - switch (what) - { - case FadeAllToBlack: - case FadeSomeToBlack: - end = FADE_NO_INTENSITY; - break; - case FadeAllToColor: - case FadeSomeToColor: - end = FADE_NORMAL_INTENSITY; - break; - case FadeAllToWhite: - case FadeSomeToWhite: - end = FADE_FULL_INTENSITY; - break; - default: - return (GetTimeCounter ()); - } - - TaskControl.Ticks = TimeInterval; - if (TaskControl.Ticks <= 0 || - (TaskControl.tc.XFormTask = AssignTask (xform_clut_task, - 1024, "transform colormap")) == 0) - { - FadeAmount = end; - TimeOut = GetTimeCounter (); - } - else - { - do - TaskSwitch (); - while (TaskControl.tc.XFormTask); - - TimeOut = GetTimeCounter () + TimeInterval + 1; - } - - return (TimeOut); -} - -void -FlushColorXForms() +static void +FlushFadeXForms (void) { if (XForming) { @@ -191,3 +357,266 @@ FlushColorXForms() TaskSwitch (); } } + +static DWORD +XFormFade (COLORMAPPTR ColorMapPtr, SIZE TimeInterval) +{ + BYTE what; + DWORD TimeOut; + + FlushFadeXForms (); + + what = *ColorMapPtr; + switch (what) + { + case FadeAllToBlack: + case FadeSomeToBlack: + FadeEnd = FADE_NO_INTENSITY; + break; + case FadeAllToColor: + case FadeSomeToColor: + FadeEnd = FADE_NORMAL_INTENSITY; + break; + case FadeAllToWhite: + case FadeSomeToWhite: + FadeEnd = FADE_FULL_INTENSITY; + break; + default: + return (GetTimeCounter ()); + } + + FadeControl.Ticks = TimeInterval; + if (FadeControl.Ticks <= 0 || + (FadeControl.tc.XFormTask = AssignTask (fade_xform_task, + 1024, "fade transform")) == 0) + { + FadeAmount = FadeEnd; + TimeOut = GetTimeCounter (); + } + else + { + do + TaskSwitch (); + while (FadeControl.tc.XFormTask); + + TimeOut = GetTimeCounter () + TimeInterval + 1; + } + + return (TimeOut); +} + +/* Colormap Transforms */ + +static void +finish_colormap_xform (int which) +{ + SetColorMap (XFormControl.TaskControl[which].CMapPtr); + XFormControl.TaskControl[which].CMapIndex = -1; + // check Highest ptr + if (which == XFormControl.Highest) + { + do + --which; + while (which >= 0 && XFormControl.TaskControl[which].CMapIndex == -1); + + XFormControl.Highest = which; + } +} + + +/* This gives the XFormColorMap task a timeslice to do its thing + * Only one thread should ever be allowed to be calling this at any time + */ +BOOLEAN +XFormColorMap_step () +{ + BOOLEAN Changed = FALSE; + int x; + DWORD Now = GetTimeCounter (); + + LockMutex (XFormControl.Lock); + + for (x = 0; x <= XFormControl.Highest; ++x) + { + XFORM_CONTROL *control = &XFormControl.TaskControl[x]; + int index = control->CMapIndex; + int TicksLeft = control->EndTime - Now; + TFB_ColorMap *curmap; + + if (index < 0) + continue; // unused slot + + LockMutex (maplock); + + curmap = colormaps[index]; + if (!curmap) + { + UnlockMutex (maplock); + fprintf (stderr, "BUG: XFormColorMap_step(): no current map\n"); + finish_colormap_xform (x); + continue; + } + + if (TicksLeft > 0) + { +#define XFORM_SCALE 0x10000 + TFB_ColorMap *newmap = NULL; + UBYTE *pNewCMap; + TFB_Palette *pCurCMap, *pOldCMap; + int frac; + int i; + + newmap = clone_colormap (curmap, index); + + pCurCMap = newmap->colors; + pOldCMap = control->OldCMap; + pNewCMap = (UBYTE*)control->CMapPtr + 2; + + frac = (int)(control->Ticks - TicksLeft) * XFORM_SCALE + / control->Ticks; + + for (i = 0; i < NUMBER_OF_PLUTVALS; i++, ++pCurCMap, ++pOldCMap) + { + + pCurCMap->r = (UBYTE)(pOldCMap->r + ((int)*pNewCMap - pOldCMap->r) + * frac / XFORM_SCALE); + pNewCMap++; + + pCurCMap->g = (UBYTE)(pOldCMap->g + ((int)*pNewCMap - pOldCMap->g) + * frac / XFORM_SCALE); + pNewCMap++; + + pCurCMap->b = (UBYTE)(pOldCMap->b + ((int)*pNewCMap - pOldCMap->b) + * frac / XFORM_SCALE); + pNewCMap++; + } + + colormaps[index] = newmap; + release_colormap (curmap); + } + + UnlockMutex (maplock); + + if (TicksLeft <= 0) + { // asked for immediate xform or already done + finish_colormap_xform (x); + } + + Changed = TRUE; + } + + UnlockMutex (XFormControl.Lock); + + return Changed; +} + +static void +FlushPLUTXForms (void) +{ + int i; + + LockMutex (XFormControl.Lock); + + for (i = 0; i <= XFormControl.Highest; ++i) + { + if (XFormControl.TaskControl[i].CMapIndex >= 0) + finish_colormap_xform (i); + } + XFormControl.Highest = -1; // all gone + + UnlockMutex (XFormControl.Lock); +} + +static DWORD +XFormPLUT (COLORMAPPTR ColorMapPtr, SIZE TimeInterval) +{ + TFB_ColorMap *map; + XFORM_CONTROL *control; + int index; + int x; + int first_avail = -1; + DWORD EndTime; + DWORD Now; + + Now = GetTimeCounter (); + index = *ColorMapPtr; + + LockMutex (XFormControl.Lock); + // Find an available slot, or reuse if required + for (x = 0; x <= XFormControl.Highest + && index != XFormControl.TaskControl[x].CMapIndex; + ++x) + { + if (first_avail == -1 && XFormControl.TaskControl[x].CMapIndex == -1) + first_avail = x; + } + + if (index == XFormControl.TaskControl[x].CMapIndex) + { // already xforming this colormap -- cancel and reuse slot + finish_colormap_xform (x); + } + else if (first_avail >= 0) + { // picked up a slot along the way + x = first_avail; + } + else if (x >= MAX_XFORMS) + { // flush some xforms if the queue is full +#ifdef DEBUG + fprintf (stderr, "WARNING: XFormPLUT(): no slots available\n"); +#endif + x = XFormControl.Highest; + finish_colormap_xform (x); + } + // take next unused one + control = &XFormControl.TaskControl[x]; + if (x > XFormControl.Highest) + XFormControl.Highest = x; + + // make a copy of the current map + LockMutex (maplock); + map = colormaps[index]; + if (!map) + { + UnlockMutex (maplock); + UnlockMutex (XFormControl.Lock); + fprintf (stderr, "BUG: XFormPLUT(): no current map\n"); + return (0); + } + memcpy (control->OldCMap, map->colors, sizeof (map->colors)); + UnlockMutex (maplock); + + control->CMapIndex = index; + control->CMapPtr = ColorMapPtr; + control->Ticks = TimeInterval; + if (control->Ticks < 0) + control->Ticks = 0; /* prevent negative fade */ + control->StartTime = Now; + control->EndTime = EndTime = Now + control->Ticks; + + UnlockMutex (XFormControl.Lock); + + return (EndTime); +} + + +DWORD +XFormColorMap (COLORMAPPTR ColorMapPtr, SIZE TimeInterval) +{ + int what; + + if (!ColorMapPtr) + return (0); + + what = *ColorMapPtr; + if (what >= (int)FadeAllToWhite && what <= (int)FadeSomeToColor) + return XFormFade (ColorMapPtr, TimeInterval); + else + return XFormPLUT (ColorMapPtr, TimeInterval); +} + +void +FlushColorXForms (void) +{ + FlushFadeXForms (); + FlushPLUTXForms (); +} diff --git a/sc2/src/sc2code/libs/graphics/cmap.h b/sc2/src/sc2code/libs/graphics/cmap.h index c9efe170d..09dd857f9 100644 --- a/sc2/src/sc2code/libs/graphics/cmap.h +++ b/sc2/src/sc2code/libs/graphics/cmap.h @@ -21,12 +21,10 @@ #ifndef CMAP_H #define CMAP_H -#define NUMBER_OF_VARPLUTS 256 +#define MAX_COLORMAPS 250 #define PLUTVAL_BYTE_SIZE 3 #define NUMBER_OF_PLUTVALS 256 #define PLUT_BYTE_SIZE (PLUTVAL_BYTE_SIZE * NUMBER_OF_PLUTVALS) -#define VARPLUTS_SIZE (NUMBER_OF_VARPLUTS * PLUT_BYTE_SIZE) -#define GET_VAR_PLUT(i) (_varPLUTs + (i) * PLUT_BYTE_SIZE) #define BUILD_FRAME (1 << 0) #define FIND_PAGE (1 << 1) @@ -40,9 +38,25 @@ #define FADE_NORMAL_INTENSITY 255 #define FADE_FULL_INTENSITY 510 -extern UBYTE* _varPLUTs; +typedef struct tfb_colormap +{ + TFB_Palette colors[NUMBER_OF_PLUTVALS]; + int index; + int version; + int refcount; + struct tfb_colormap *next; +} TFB_ColorMap; + extern volatile int FadeAmount; -void TFB_ColorMapToRGB (TFB_Palette *pal, int colormap_index); +extern void InitColorMaps (void); +extern void UninitColorMaps (void); + +extern void TFB_ColorMapToRGB (TFB_Palette *pal, int colormap_index); +extern TFB_ColorMap * TFB_GetColorMap (int index); +extern void TFB_ReturnColorMap (TFB_ColorMap *map); + +extern BOOLEAN XFormColorMap_step (); + #endif diff --git a/sc2/src/sc2code/libs/graphics/drawcmd.h b/sc2/src/sc2code/libs/graphics/drawcmd.h index f61137d47..71fb903aa 100644 --- a/sc2/src/sc2code/libs/graphics/drawcmd.h +++ b/sc2/src/sc2code/libs/graphics/drawcmd.h @@ -62,7 +62,7 @@ typedef struct tfb_dc_img TFB_Image *image; int x, y; SCREEN destBuffer; - BOOLEAN UsePalette; + TFB_ColorMap *colormap; int scale; } TFB_DrawCommand_Image; diff --git a/sc2/src/sc2code/libs/graphics/sdl/canvas.c b/sc2/src/sc2code/libs/graphics/sdl/canvas.c index a608f294e..98ad96595 100644 --- a/sc2/src/sc2code/libs/graphics/sdl/canvas.c +++ b/sc2/src/sc2code/libs/graphics/sdl/canvas.c @@ -61,10 +61,12 @@ TFB_DrawCanvas_Rect (PRECT rect, int r, int g, int b, TFB_Canvas target) } void -TFB_DrawCanvas_Image (TFB_Image *img, int x, int y, int scale, TFB_Palette *palette, TFB_Canvas target) +TFB_DrawCanvas_Image (TFB_Image *img, int x, int y, int scale, + TFB_ColorMap *cmap, TFB_Canvas target) { SDL_Rect srcRect, targetRect, *pSrcRect; SDL_Surface *surf; + TFB_Palette* palette; if (img == 0) { @@ -74,18 +76,25 @@ TFB_DrawCanvas_Image (TFB_Image *img, int x, int y, int scale, TFB_Palette *pale LockMutex (img->mutex); - if (palette == 0) + if (cmap) + palette = cmap->colors; + else palette = img->Palette; + // only set the new palette if it changed + if (((SDL_Surface *)img->NormalImg)->format->palette + && cmap && img->colormap_version != cmap->version) + SDL_SetColors (img->NormalImg, (SDL_Color*)palette, 0, 256); + if (scale != 0 && scale != GSCALE_IDENTITY) { int type; if (optMeleeScale == TFB_SCALE_TRILINEAR && img->MipmapImg) { type = TFB_SCALE_TRILINEAR; - if (((SDL_Surface *)img->NormalImg)->format->palette) - SDL_SetColors (img->NormalImg, (SDL_Color*)palette, 0, 256); - if (((SDL_Surface *)img->MipmapImg)->format->palette) + // only set the new palette if it changed + if (((SDL_Surface *)img->MipmapImg)->format->palette + && cmap && img->colormap_version != cmap->version) SDL_SetColors (img->MipmapImg, (SDL_Color*)palette, 0, 256); } else @@ -95,6 +104,9 @@ TFB_DrawCanvas_Image (TFB_Image *img, int x, int y, int scale, TFB_Palette *pale TFB_DrawImage_FixScaling (img, scale, type); surf = img->ScaledImg; + if (surf->format->palette) + SDL_SetColors (surf, (SDL_Color*)palette, 0, 256); + srcRect.x = 0; srcRect.y = 0; srcRect.w = img->extent.width; @@ -113,8 +125,11 @@ TFB_DrawCanvas_Image (TFB_Image *img, int x, int y, int scale, TFB_Palette *pale targetRect.y = y - img->NormalHs.y; } - if (surf->format->palette) - SDL_SetColors (surf, (SDL_Color*)palette, 0, 256); + if (cmap) + { + img->colormap_version = cmap->version; + TFB_ReturnColorMap (cmap); + } SDL_BlitSurface (surf, pSrcRect, (NativeCanvas) target, &targetRect); UnlockMutex (img->mutex); @@ -254,6 +269,8 @@ TFB_DrawCanvas_FilledImage (TFB_Image *img, int x, int y, int scale, int r, int pal[i].b = b; } SDL_SetColors (surf, pal, 0, 256); + // reflect the change in *actual* image palette + img->colormap_version--; } else { // fill the non-transparent parts of the image with fillcolor diff --git a/sc2/src/sc2code/libs/graphics/sdl/sdl_common.c b/sc2/src/sc2code/libs/graphics/sdl/sdl_common.c index 9a1e2bad8..bc901b2c6 100644 --- a/sc2/src/sc2code/libs/graphics/sdl/sdl_common.c +++ b/sc2/src/sc2code/libs/graphics/sdl/sdl_common.c @@ -152,7 +152,6 @@ TFB_InitGraphics (int driver, int flags, int width, int height, int bpp) Init_DrawCommandQueue (); - TFB_FlushPaletteCache (); TFB_DrawCanvas_Initialize (); RenderingCond = CreateCondVar ("DCQ empty", @@ -614,17 +613,12 @@ TFB_FlushGraphics () // Only call from main thread!! case TFB_DRAWCOMMANDTYPE_IMAGE: { TFB_Image *DC_image = DC.data.image.image; - TFB_Palette *pal; + TFB_ColorMap *cmap = DC.data.image.colormap; int x = DC.data.image.x; int y = DC.data.image.y; - if (DC.data.image.UsePalette) - pal = palette; - else - pal = 0; - TFB_DrawCanvas_Image (DC_image, x, y, - DC.data.image.scale, pal, + DC.data.image.scale, cmap, SDL_Screens[DC.data.image.destBuffer]); if (DC.data.image.destBuffer == 0) diff --git a/sc2/src/sc2code/libs/graphics/tfb_draw.c b/sc2/src/sc2code/libs/graphics/tfb_draw.c index 4e1d19b1f..79205586a 100644 --- a/sc2/src/sc2code/libs/graphics/tfb_draw.c +++ b/sc2/src/sc2code/libs/graphics/tfb_draw.c @@ -78,67 +78,21 @@ TFB_DrawScreen_SetPalette (int paletteIndex, int r, int g, int b) TFB_EnqueueDrawCommand (&DC); } -/* This value is protected by the DCQ's lock. */ -static int _localpal[256][3]; - -void -TFB_FlushPaletteCache () -{ - int i; - Lock_DCQ (-1); - for (i = 0; i < 256; i++) - { - _localpal[i][0] = -1; - _localpal[i][1] = -1; - _localpal[i][2] = -1; - } - Unlock_DCQ (); -} - void TFB_DrawScreen_Image (TFB_Image *img, int x, int y, int scale, - TFB_Palette *palette, SCREEN dest) + TFB_ColorMap *cmap, SCREEN dest) { TFB_DrawCommand DC; DC.Type = TFB_DRAWCOMMANDTYPE_IMAGE; DC.data.image.image = img; + DC.data.image.colormap = cmap; DC.data.image.x = x; DC.data.image.y = y; DC.data.image.scale = (scale == GSCALE_IDENTITY) ? 0 : scale; - - if (palette != NULL) - { - int i, changed; - Lock_DCQ(257); - changed = 0; - for (i = 0; i < 256; i++) - { - if ((_localpal[i][0] != palette[i].r) || - (_localpal[i][1] != palette[i].g) || - (_localpal[i][2] != palette[i].b)) - { - changed++; - _localpal[i][0] = palette[i].r; - _localpal[i][1] = palette[i].g; - _localpal[i][2] = palette[i].b; - TFB_DrawScreen_SetPalette (i, palette[i].r, palette[i].g, - palette[i].b); - } - } - // if (changed) { fprintf (stderr, "Actually changing palette! "); } - DC.data.image.UsePalette = TRUE; - } - else - { - Lock_DCQ (1); - DC.data.image.UsePalette = FALSE; - } - DC.data.image.destBuffer = dest; TFB_EnqueueDrawCommand (&DC); - Unlock_DCQ (); } void @@ -296,10 +250,10 @@ TFB_DrawImage_Rect (PRECT rect, int r, int g, int b, TFB_Image *image) void TFB_DrawImage_Image (TFB_Image *img, int x, int y, int scale, - TFB_Palette *palette, TFB_Image *target) + TFB_ColorMap *cmap, TFB_Image *target) { LockMutex (target->mutex); - TFB_DrawCanvas_Image (img, x, y, scale, palette, target->NormalImg); + TFB_DrawCanvas_Image (img, x, y, scale, cmap, target->NormalImg); target->dirty = TRUE; UnlockMutex (target->mutex); } @@ -334,6 +288,7 @@ TFB_DrawImage_New (TFB_Canvas canvas) img->MipmapImg = NULL; img->FilledImg = NULL; img->colormap_index = -1; + img->colormap_version = 0; img->NormalHs = NullHs; img->MipmapHs = NullHs; img->last_scale_hs = NullHs; @@ -363,6 +318,7 @@ TFB_DrawImage_CreateForScreen (int w, int h, BOOLEAN withalpha) img->MipmapImg = NULL; img->FilledImg = NULL; img->colormap_index = -1; + img->colormap_version = 0; img->NormalHs = NullHs; img->MipmapHs = NullHs; img->last_scale_hs = NullHs; diff --git a/sc2/src/sc2code/libs/graphics/tfb_draw.h b/sc2/src/sc2code/libs/graphics/tfb_draw.h index a40df39f4..f93db9349 100644 --- a/sc2/src/sc2code/libs/graphics/tfb_draw.h +++ b/sc2/src/sc2code/libs/graphics/tfb_draw.h @@ -47,6 +47,7 @@ typedef struct tfb_palette } TFB_Palette; #include "graphics/gfx_common.h" +#include "cmap.h" typedef struct tfb_image { @@ -56,6 +57,7 @@ typedef struct tfb_image TFB_Canvas FilledImg; TFB_Palette *Palette; int colormap_index; + int colormap_version; HOT_SPOT NormalHs; HOT_SPOT MipmapHs; HOT_SPOT last_scale_hs; @@ -92,7 +94,7 @@ typedef struct tfb_pixelformat void TFB_DrawScreen_Line (int x1, int y1, int x2, int y2, int r, int g, int b, SCREEN dest); void TFB_DrawScreen_Rect (PRECT rect, int r, int g, int b, SCREEN dest); -void TFB_DrawScreen_Image (TFB_Image *img, int x, int y, int scale, TFB_Palette *palette, SCREEN dest); +void TFB_DrawScreen_Image (TFB_Image *img, int x, int y, int scale, TFB_ColorMap *cmap, SCREEN dest); void TFB_DrawScreen_Copy (PRECT r, SCREEN src, SCREEN dest); void TFB_DrawScreen_FilledImage (TFB_Image *img, int x, int y, int scale, int r, int g, int b, SCREEN dest); void TFB_DrawScreen_FontChar (TFB_Char *, TFB_Image *backing, int x, int y, SCREEN dest); @@ -103,7 +105,6 @@ void TFB_DrawScreen_DeleteData (void *); void TFB_DrawScreen_WaitForSignal (void); void TFB_DrawScreen_ReinitVideo (int driver, int flags, int width, int height, int bpp); void TFB_DrawScreen_SetPalette (int paletteIndex, int r, int g, int b); -void TFB_FlushPaletteCache (void); TFB_Image *TFB_DrawImage_New (TFB_Canvas canvas); TFB_Image *TFB_DrawImage_CreateForScreen (int w, int h, BOOLEAN withalpha); @@ -113,7 +114,7 @@ void TFB_DrawImage_FixScaling (TFB_Image *image, int target, int type); void TFB_DrawImage_Line (int x1, int y1, int x2, int y2, int r, int g, int b, TFB_Image *dest); void TFB_DrawImage_Rect (PRECT rect, int r, int g, int b, TFB_Image *image); -void TFB_DrawImage_Image (TFB_Image *img, int x, int y, int scale, TFB_Palette *palette, TFB_Image *target); +void TFB_DrawImage_Image (TFB_Image *img, int x, int y, int scale, TFB_ColorMap *cmap, TFB_Image *target); void TFB_DrawImage_FilledImage (TFB_Image *img, int x, int y, int scale, int r, int g, int b, TFB_Image *target); void TFB_DrawImage_FontChar (TFB_Char *, TFB_Image *backing, int x, int y, TFB_Image *target); @@ -137,7 +138,7 @@ void TFB_DrawCanvas_Delete (TFB_Canvas canvas); void TFB_DrawCanvas_Line (int x1, int y1, int x2, int y2, int r, int g, int b, TFB_Canvas dest); void TFB_DrawCanvas_Rect (PRECT rect, int r, int g, int b, TFB_Canvas image); -void TFB_DrawCanvas_Image (TFB_Image *img, int x, int y, int scale, TFB_Palette *palette, TFB_Canvas target); +void TFB_DrawCanvas_Image (TFB_Image *img, int x, int y, int scale, TFB_ColorMap *cmap, TFB_Canvas target); void TFB_DrawCanvas_FilledImage (TFB_Image *img, int x, int y, int scale, int r, int g, int b, TFB_Canvas target); void TFB_DrawCanvas_FontChar (TFB_Char *, TFB_Image *backing, int x, int y, TFB_Canvas target); diff --git a/sc2/src/sc2code/libs/graphics/tfb_prim.c b/sc2/src/sc2code/libs/graphics/tfb_prim.c index ae2126ab8..f1a0d33e5 100644 --- a/sc2/src/sc2code/libs/graphics/tfb_prim.c +++ b/sc2/src/sc2code/libs/graphics/tfb_prim.c @@ -119,8 +119,7 @@ TFB_Prim_Stamp (PSTAMP stmp) int x, y; PFRAME_DESC SrcFramePtr; TFB_Image *img; - BOOLEAN paletted; - TFB_Palette palette[256]; + TFB_ColorMap *cmap = NULL; int gscale; SrcFramePtr = (PFRAME_DESC)stmp->frame; @@ -143,25 +142,22 @@ TFB_Prim_Stamp (PSTAMP stmp) img->NormalHs = SrcFramePtr->HotSpot; x = stmp->origin.x - _CurFramePtr->HotSpot.x; y = stmp->origin.y - _CurFramePtr->HotSpot.y; - paletted = FALSE; if (TFB_DrawCanvas_IsPaletted(img->NormalImg) && img->colormap_index != -1) { - TFB_ColorMapToRGB (palette, img->colormap_index); - paletted = TRUE; + // returned cmap is addrefed, must release later + cmap = TFB_GetColorMap (img->colormap_index); } UnlockMutex (img->mutex); if (TYPE_GET (_CurFramePtr->TypeIndexAndFlags) == SCREEN_DRAWABLE) { - TFB_DrawScreen_Image (img, x, y, gscale, (paletted ? palette : NULL), - TFB_SCREEN_MAIN); + TFB_DrawScreen_Image (img, x, y, gscale, cmap, TFB_SCREEN_MAIN); } else { - TFB_DrawImage_Image (img, x, y, gscale, (paletted ? palette : NULL), - _CurFramePtr->image); + TFB_DrawImage_Image (img, x, y, gscale, cmap, _CurFramePtr->image); } }