Unit AwesomeFade; { Awesome Fade by Scott Cogan Pascal version of Clut Fade by Ingemar R 1994. It turned out to be pretty tricky, since Pascal doesn't have "unsigned" integers, and rgb values are most "unsigned" to their nature, using the full range 0..65535 in 16 bits. The solution was to convert them to longints using BitAnd. Updated by Bill Catambay 1999. Uses UNSIGNED (now available in CW Pascal) and made to be PPC native (CW Pro 4). } Interface Uses Toolbox; Const kMaxByte = 256; Type long = 0..65535; FadeValues = Record reds, greens, blues: Array[0..kMaxByte] Of integer; End; Var gFade, { 'clut' to alter with fading functions} gOrig: CTabHandle; { 'clut' to hold a copy of original} gTempH: Handle; { temporary handle to copy 'clut'} gRealColors: CTabHandle;{ Holds real current color values when you want to draw. When you want to draw to a } { window, all drawing functions have to draw the picture in the current clut, stored } { in gFade. If you draw while the screen is blacked out, then everything you draw will } { be in black when you fade back. So, you need to trick the drawing. gOrig holds the } { clut you want to draw in, so when you pass true for the drawing parameter, it puts } { gFade into gRealColors to save the clut currently on the screen and then puts gOrig } { into gFade at the end of the fade, so everything will be drawn correctly. The next } { time you try to fade, it puts gRealColors back into gFade so it can fade according } { to what's on the screen. This is confusing, I know, so basically all you have to do } { is pass true when you want to draw after a fade, and pass false if your going to fade } { again before drawing. } gCtSize: Integer; gMainGD: GDHandle; gFadingInited, gGetClutNextTime: boolean; { If gGetClutNextTime is true, that means that the colors on the screen } { have been saved in gRealColors so the next time a fade is done, } { gRealColors is put into gFade. } Procedure InitFades; Procedure GetClut; Procedure SetClut (aCT: CTabHandle); Procedure CLUTFadeToBlack (speed: Integer; drawing: boolean); Procedure CLUTFadeToWhite (speed: Integer; drawing: boolean); Procedure FadeToCT (speed: Integer; destCT: CTabHandle; drawing: boolean); Procedure FadeToRGB (speed: Integer; theRGB: RGBColor; drawing: boolean); Procedure RGBTakeoverCT (foreFade: integer; theRGB: RGBColor; aCT: CTabHandle; drawing: boolean); Procedure RotateCT (start, endd, howMany: integer; aCT: CTabHandle; Forward: boolean; drawing: boolean); Procedure BlackOut; Procedure WhiteOut; Procedure RestoreClut; Function MakeRGB (R, G, B: integer): RGBColor; Implementation (********************************** GetClut *********************************) Procedure GetClut; Var i: integer; Begin If gFadingInited And gGetClutNextTime Then For i := 0 To gCtSize Do gFade^^.ctTable[i].rgb := gRealColors^^.ctTable[i].rgb; gGetClutNextTime := false; End; {GetClut} (********************************** InitFades *********************************) Procedure InitFades; Begin gFadingInited := true; gMainGD := GetMainDevice; SetGDevice(gMainGD); gCtSize := gMainGD^^.gdPMap^^.pmTable^^.ctSize; {Yet another case where Pascal is a lot easier.} If gCtSize < 1 Then gFadingInited := false; { Can't run if no CLUT!} If gCtSize > kMaxByte Then gFadingInited := false; { We don't expect that big CLUTs!} { Copy Cluts } gFade := gMainGD^^.gdPMap^^.pmTable; gTempH := Handle(gMainGD^^.gdPMap^^.pmTable); If noErr <> HandToHand(gTempH) Then gFadingInited := false; gOrig := CTabHandle(gTempH); HLock(Handle(gFade)); HLock(Handle(gOrig)); gRealColors := gMainGD^^.gdPMap^^.pmTable; If noErr <> HandToHand(Handle(gRealColors)) Then gFadingInited := false; gGetClutNextTime := false; End; {InitFades} (********************************** SetClut **********************************) Procedure SetClut (aCT: CTabHandle); Var i: integer; Begin gCtSize := gMainGD^^.gdPMap^^.pmTable^^.ctSize; SetEntries(0, gCtSize, aCT^^.ctTable); For i := 0 To gCtSize Do Begin gFade^^.ctTable[i] := aCT^^.ctTable[i]; gRealColors^^.ctTable[i] := aCT^^.ctTable[i]; End; End; {SetClut} (*********************************** FadeToBlack ***********************************) Procedure CLUTFadeToBlack (speed: Integer; drawing: boolean); Var i, j: Integer; rgbs: FadeValues; Begin GetClut; If Not gFadingInited Then exit(CLUTFadeToBlack); For i := 0 To gCtSize Do Begin rgbs.reds[i] := BitAnd(gFade^^.ctTable[i].rgb.red, $0ffff) Div speed; rgbs.greens[i] := BitAnd(gFade^^.ctTable[i].rgb.green, $0ffff) Div speed; rgbs.blues[i] := BitAnd(gFade^^.ctTable[i].rgb.blue, $0ffff) Div speed; End; For j := speed Downto 0 Do Begin For i := 0 To gCtSize Do Begin If BitAnd(gFade^^.ctTable[i].rgb.red, $0ffff) > rgbs.reds[i] Then gFade^^.ctTable[i].rgb.red := gFade^^.ctTable[i].rgb.red - rgbs.reds[i]; If BitAnd(gFade^^.ctTable[i].rgb.green, $0ffff) > rgbs.greens[i] Then gFade^^.ctTable[i].rgb.green := gFade^^.ctTable[i].rgb.green - rgbs.greens[i]; If BitAnd(gFade^^.ctTable[i].rgb.blue, $0ffff) > rgbs.blues[i] Then gFade^^.ctTable[i].rgb.blue := gFade^^.ctTable[i].rgb.blue - rgbs.blues[i]; End; SetEntries(0, gCtSize, gFade^^.ctTable); End; BlackOut; If drawing Then RestoreClut; End; {CLUTFadeToBlack} (*********************************** FadeToWhite ***********************************) Procedure CLUTFadeToWhite (speed: Integer; drawing: boolean); Var i, j: Integer; rgbs: FadeValues; Begin GetClut; If Not gFadingInited Then exit(CLUTFadeToWhite); For i := 0 To gCtSize Do Begin rgbs.reds[i] := (65535 - BitAnd(gFade^^.ctTable[i].rgb.red, $0ffff)) Div speed; rgbs.greens[i] := (65535 - BitAnd(gFade^^.ctTable[i].rgb.green, $0ffff)) Div speed; rgbs.blues[i] := (65535 - BitAnd(gFade^^.ctTable[i].rgb.blue, $0ffff)) Div speed; End; For j := speed Downto 0 Do Begin For i := 0 To gCtSize Do Begin If (65535 - BitAnd(gFade^^.ctTable[i].rgb.red, $0ffff)) > rgbs.reds[i] Then gFade^^.ctTable[i].rgb.red := gFade^^.ctTable[i].rgb.red + rgbs.reds[i]; If (65535 - BitAnd(gFade^^.ctTable[i].rgb.green, $0ffff)) > rgbs.greens[i] Then gFade^^.ctTable[i].rgb.green := gFade^^.ctTable[i].rgb.green + rgbs.greens[i]; If (65535 - BitAnd(gFade^^.ctTable[i].rgb.blue, $0ffff)) > rgbs.blues[i] Then gFade^^.ctTable[i].rgb.blue := gFade^^.ctTable[i].rgb.blue + rgbs.blues[i]; End; SetEntries(0, gCtSize, gFade^^.ctTable); End; WhiteOut; If drawing Then RestoreClut; End; {CLUTFadeToWhite} (************************************ FadeToCT ***********************************) Procedure FadeToCT (speed: Integer; destCT: CTabHandle; drawing: boolean); Var i, j: Integer; rgbs: FadeValues; Begin GetClut; If Not gFadingInited Then exit(FadeToCT); For i := 0 To gCtSize Do Begin rgbs.reds[i] := (BitAnd(destCT^^.ctTable[i].rgb.red, $0ffff) - BitAnd(gFade^^.ctTable[i].rgb.red, $0ffff)) Div speed; rgbs.greens[i] := (BitAnd(destCT^^.ctTable[i].rgb.green, $0ffff) - BitAnd(gFade^^.ctTable[i].rgb.green, $0ffff)) Div speed; rgbs.blues[i] := (BitAnd(destCT^^.ctTable[i].rgb.blue, $0ffff) - BitAnd(gFade^^.ctTable[i].rgb.blue, $0ffff)) Div speed; End; For j := speed Downto 0 Do Begin For i := 0 To gCtSize Do Begin If abs(BitAnd(destCT^^.ctTable[i].rgb.red, $0ffff) - BitAnd(gFade^^.ctTable[i].rgb.red, $0ffff)) > abs(rgbs.reds[i]) Then gFade^^.ctTable[i].rgb.red := gFade^^.ctTable[i].rgb.red + rgbs.reds[i]; If abs(BitAnd(destCT^^.ctTable[i].rgb.green, $0ffff) - BitAnd(gFade^^.ctTable[i].rgb.green, $0ffff)) > abs(rgbs.greens[i]) Then gFade^^.ctTable[i].rgb.green := gFade^^.ctTable[i].rgb.green + rgbs.greens[i]; If abs(BitAnd(destCT^^.ctTable[i].rgb.blue, $0ffff) - BitAnd(gFade^^.ctTable[i].rgb.blue, $0ffff)) > abs(rgbs.blues[i]) Then gFade^^.ctTable[i].rgb.blue := gFade^^.ctTable[i].rgb.blue + rgbs.blues[i]; End; SetEntries(0, gCtSize, gFade^^.ctTable); End; For i := 0 To gCtSize Do Begin gFade^^.ctTable[i].rgb := destCT^^.ctTable[i].rgb; End; SetEntries(0, gCtSize, gFade^^.ctTable); If drawing Then RestoreClut; End; {FadeToCT} (************************************ RotateCT ***********************************) Procedure RotateCT (start, endd, howMany: integer; aCT: CTabHandle; Forward: boolean; drawing: boolean); Var i, j: Integer; Begin GetClut; If Not gFadingInited Then exit(RotateCT); For i := start To endd Do Begin gFade^^.ctTable[i].rgb := aCT^^.ctTable[i].rgb; End; If Forward Then Begin For j := 1 To howMany Do Begin gFade^^.ctTable[start].rgb := gFade^^.ctTable[endd].rgb; For i := endd - 1 Downto start Do Begin gFade^^.ctTable[i + 1].rgb := gFade^^.ctTable[i].rgb; End; SetEntries(0, gCtSize, gFade^^.ctTable); End; End Else Begin For j := 1 To howMany Do Begin For i := start + 1 To endd Do Begin gFade^^.ctTable[i - 1].rgb := gFade^^.ctTable[i].rgb; End; gFade^^.ctTable[endd].rgb := gFade^^.ctTable[start].rgb; SetEntries(0, gCtSize, gFade^^.ctTable); End; End; If drawing Then RestoreClut; End; {RotateCT} (************************************ RGBTakeoverCT ***********************************) Procedure RGBTakeoverCT (foreFade: integer; theRGB: RGBColor; aCT: CTabHandle; drawing: boolean); Var i, j: Integer; rgbs: FadeValues; Begin GetClut; If Not gFadingInited Then exit(RGBTakeoverCT); For i := 0 To gCtSize Do Begin gFade^^.ctTable[i].rgb := aCT^^.ctTable[i].rgb; End; For i := 0 To gCtSize Do Begin rgbs.reds[i] := (BitAnd(theRGB.red, $0ffff) - BitAnd(gFade^^.ctTable[i].rgb.red, $0ffff)) Div foreFade; rgbs.greens[i] := (BitAnd(theRGB.green, $0ffff) - BitAnd(gFade^^.ctTable[i].rgb.green, $0ffff)) Div foreFade; rgbs.blues[i] := (BitAnd(theRGB.blue, $0ffff) - BitAnd(gFade^^.ctTable[i].rgb.blue, $0ffff)) Div foreFade; End; For i := 1 To (gCtSize + foreFade) Do Begin For j := 1 To (foreFade - 1) Do Begin If ((i - j) >= 0) And ((i - j) < 256) Then Begin gFade^^.ctTable[i - j].rgb.red := gFade^^.ctTable[i - j].rgb.red + rgbs.reds[i - j]; gFade^^.ctTable[i - j].rgb.green := gFade^^.ctTable[i - j].rgb.green + rgbs.greens[i - j]; gFade^^.ctTable[i - j].rgb.blue := gFade^^.ctTable[i - j].rgb.blue + rgbs.blues[i - j]; End; If (i - foreFade) >= 0 Then gFade^^.ctTable[i - foreFade].rgb := theRGB; End; SetEntries(0, gCtSize, gFade^^.ctTable); End; If drawing Then RestoreClut; End; {RGBTakeoverCT} (************************************ FadeToRGB ***********************************) Procedure FadeToRGB (speed: Integer; theRGB: RGBColor; drawing: boolean); Var i, j: Integer; rgbs: FadeValues; Begin GetClut; If Not gFadingInited Then exit(FadeToRGB); For i := 0 To gCtSize Do Begin rgbs.reds[i] := (BitAnd(theRGB.red, $0ffff) - BitAnd(gFade^^.ctTable[i].rgb.red, $0ffff)) Div speed; rgbs.greens[i] := (BitAnd(theRGB.green, $0ffff) - BitAnd(gFade^^.ctTable[i].rgb.green, $0ffff)) Div speed; rgbs.blues[i] := (BitAnd(theRGB.blue, $0ffff) - BitAnd(gFade^^.ctTable[i].rgb.blue, $0ffff)) Div speed; End; For j := speed Downto 0 Do Begin For i := 0 To gCtSize Do Begin If abs(BitAnd(theRGB.red, $0ffff) - BitAnd(gFade^^.ctTable[i].rgb.red, $0ffff)) > abs(rgbs.reds[i]) Then gFade^^.ctTable[i].rgb.red := gFade^^.ctTable[i].rgb.red + rgbs.reds[i]; If abs(BitAnd(theRGB.green, $0ffff) - BitAnd(gFade^^.ctTable[i].rgb.green, $0ffff)) > abs(rgbs.greens[i]) Then gFade^^.ctTable[i].rgb.green := gFade^^.ctTable[i].rgb.green + rgbs.greens[i]; If abs(BitAnd(theRGB.blue, $0ffff) - BitAnd(gFade^^.ctTable[i].rgb.blue, $0ffff)) > abs(rgbs.blues[i]) Then gFade^^.ctTable[i].rgb.blue := gFade^^.ctTable[i].rgb.blue + rgbs.blues[i]; End; SetEntries(0, gCtSize, gFade^^.ctTable); End; For i := 0 To gCtSize Do Begin gFade^^.ctTable[i].rgb.red := BitAnd(theRGB.red, $0ffff); gFade^^.ctTable[i].rgb.green := BitAnd(theRGB.green, $0ffff); gFade^^.ctTable[i].rgb.blue := BitAnd(theRGB.blue, $0ffff); End; SetEntries(0, gCtSize, gFade^^.ctTable); If drawing Then RestoreClut; End; {FadeToRGB} (*********************************** BlackOut **********************************) Procedure BlackOut; Var i: Integer; Begin If Not gFadingInited Then exit(BlackOut); For i := 0 To gCtSize Do Begin gFade^^.ctTable[i].rgb.red := 0; gFade^^.ctTable[i].rgb.green := 0; gFade^^.ctTable[i].rgb.blue := 0; End; SetEntries(0, gCtSize, gFade^^.ctTable); End; {BlackOut} (*********************************** WhiteOut **********************************) Procedure WhiteOut; Var i: Integer; Begin If Not gFadingInited Then exit(WhiteOut); For i := 0 To gCtSize Do Begin gFade^^.ctTable[i].rgb.red := 65535; gFade^^.ctTable[i].rgb.green := 65535; gFade^^.ctTable[i].rgb.blue := 65535; End; SetEntries(0, gCtSize, gFade^^.ctTable); End; {WhiteOut} (********************************** RestoreClut ********************************) Procedure RestoreClut; Var i: Integer; Begin gCtSize := gMainGD^^.gdPMap^^.pmTable^^.ctSize; { ADDED } SetEntries(0, gCtSize, gOrig^^.ctTable); { ADDED } For i := 0 To gCtSize Do Begin // gRealColors^^.ctTable[i].rgb := gFade^^.ctTable[i].rgb; // gFade^^.ctTable[i].rgb := gOrig^^.ctTable[i].rgb; gRealColors^^.ctTable[i] := gOrig^^.ctTable[i]; { ADDED } gFade^^.ctTable[i] := gOrig^^.ctTable[i]; { ADDED } End; gFade^^.ctSeed := GetCTSeed; MakeITable(Nil, Nil, 0); HUnlock(Handle(gFade)); HUnlock(Handle(gOrig)); gGetClutNextTime := true; End; {RestoreClut} (********************************** MakeRGB ********************************) Function MakeRGB (R, G, B: integer): RGBColor; Begin MakeRGB.red := R; MakeRGB.green := G; MakeRGB.blue := B; End; {MakeRGB} End.