REQUIREMENTS V40.6 of specialfx.library requires graphics.library V39. Future versions may be written for graphics.library V37. Specialfx.library will work on all versions of the Amiga chip sets. SUMMARY OF DIFFERENCES 40.2 -> 40.6 Independant playfield scrolling implemented in LineControl. VTAG_SFX_NORM_SET disables hardware DualPlayfield mode. Added optional copperlist doublebuffering for smoother displays. Added LineControl line repeat rate for mirroring, flows, half heights etc. Replaced ICB_TOGGLE in InterruptControl with INCB_SET and INCB_RESET. PROGRAMMING Each SpecialFX is controlled by the programmer through a structure associated with the effect. Each structure is composed of two parts: a visible part, and an invisible part. The visible part is initialised by the programmer to control the colour, the scroll offset, line repetition or whatever. The invisible part is a cache used by the library for optimising the animation code. As each element is of an unknown size, the memory for each effect has to be allocated by the library with AllocFX(), which returns a handle to this effect for later use, and fills in an array of pointers to the visible part of each effect structure. [The Autodocs that have been written so far are at the end of the document] For example, if we are using a ColorRange effect to modify the colour of one pen over NUMLINES scanlines: APTR ColourHandle; /* just a handle */ ULONG Error; if (ColourHandle = AllocFX(ViewPort, SFX_ColorRange, NUMLINES, &Error)) { struct ColorControl **cc = (struct ColorControl **)ColourHandle; int i; for (i = 0; i < y; i++) { /* Do the sky colours accross the whole screen */ (*cc)->cc_Pen = 0; (*cc)->cc_Line = i; (*cc)->cc_Red = RGBSky[0]; (*cc)->cc_Green = RGBSky[1]; (*cc)->cc_Blue = RGBSky[2]; (*cc)->cc_Flags = 0; cc++; } etc... } Once the memory and handle have been obtained, and the data in the effects structures initialised, we need to install the effect using InstallFX(). This is a tag-based function that builds UserCopperlists to create the changes required. The tags are a list of the pointers to the allocated handles. InstallFX() returns a handle to this Effect which is later used by AnimateFX() to animate the effect. Therefore, with InstallFX(), it is possible to mix together ColorRange effects, ScrollRange effects etc into one SuperEffect. Note that after calling InstallFX(), the programmer needs to remake the display in the usual way to actually show the changes. After this, changes can be made to the data in the visible parts of the Effects structures, and calling AnimateFX() will cause the changes to be made on screen "immediately"; in other words, AnimateFX() does not remake the copperlists, but modifies those already in place. AnimateFX() respects the VideoControl() tag VC_IntermediateCLUpdate for even faster animation time. To clean up, use RemoveFX() to remove the UserCopperlist associated with the effect, and FreeFX() to free the effect's memory. It is possible to combine different SuperEffects in combination. For example, SuperEffect1 is a handle from InstallFX() that consists of a ColorRange and a ScrollLines. SuperEffect2 is another handle that consists of a RepeatLines effect. They are both shown on screen together. Now, I can animate both SuperEffects separately with AnimateFX(), but half way through I want to remove the SuperEffect1, just leaving SuperEffect2 on screen. I can do this with RemoveFX(SuperEffect1), and remake the display, continue animating SuperEffect2, and then later display just the ColorRange again with InstallFX(), just leaving the ColorRange and LineRepeat effects on screen. LIMITATIONS A limitation of the SpecialFX.library is that the SpecialFX and normal UserCopperlists cannot be mixed in the same ViewPort. This is because SpecialFX builds UserCopperlists, and links them together off ViewPort->UCopList. When a programmer's UserCopperlist is freed with FreeUCopList(), the SpecialFX UCopLists would be freed as well. Obviously, there is a limit to the number of effects you can use on a single display line because of the number of copper instructions needed. EFFECTS SFX_ColorControl (horrible spelling) SFX_ColorControl will modify pen(s) on a given scan line to a given 24 bit RGB value. The library will use the most significant bits of the RGB value, so for example, it will set 24 bits of RGB on AA machines, and 12 bits on ECS or A machines. A place holder has been put in the ColorControl structure for horizontal control, although this is ignored under V40. Maybe a future chip set will support accurate horizontal copper control. The colour change for the pen will remain on screen until the same pen is changed with another ColorControl, or until the end of the ViewPort. If you only want the change on one line, and then have the pen restored to its original RGB value, set the CCB_RESTORE bit in the cc_Flags field before calling InstallFX(). struct ColorControl { LONG cc_Pen; /* Pen number to change */ WORD cc_Horizontal; /* X Wait position - ignored for V40 */ WORD cc_Line; /* Y Wait position */ ULONG cc_Red; /* 32 bit red value */ ULONG cc_Green; /* 32 bit green value */ ULONG cc_Blue; /* 32 bit blue value */ UWORD cc_Flags; UWORD cc_Pad; }; #define CCB_MODIFY 0 /* When used with AnimateFXA(), this colour * entry is modified to the RGB value. */ #define CCF_MODIFY (1 << CCB_MODIFY) #define CCB_RESTORE 1 /* if set, then restore the pen number to its * original value. This needs to be set only * once for the pen number, and is used by * InstallFXA() */ #define CCF_RESTORE (1 << CCB_RESTORE) The RGB values of the pen at the various lines can be modified by changing the cc_Red/Green/Blue values in the ColorControl, setting CCF_MODIFY in the cc_Flags field, and calling AnimateFX(). SFX_InterruptControl SFX_InterruptControl will cause a copper interrupt on the specified line. It is up to the application program to install a Copper interrupt server using the standard exec.library AddIntServer() function. If the application is using a custom ViewPort, or it has opened an SA_Exclusive screen, then the application knows that the only copper interrupt was generated by it's SFX_InterruptControl. However, in a multitasking environment this is not desirable, so the Copper interrupt can call specialfx.library's FindVP() function which returns the address of the ViewPort that the interrupt occured in. The interrupt can be set on or off by setting the INCB_SET or INCB_RESET flag inc_Flags field, and calling AnimateFX(). struct InterruptControl { UWORD inc_Line; /* Cause the interrupt at the start of this * line. */ UWORD inc_Flags; /* See below */ }; #define INCB_SET 0 /* When used with AnimateFXA(), the interrupt * at this line is turned on. */ #define INCF_SET (1 << INCB_SET) #define INCB_RESET 1 /* When used with AnimateFXA(), the interrupt * at this line is turned off. */ #define INCF_RESET (1 << INCB_RESET) /* NB - setting both INCF_SET and INCF_RESET is undefined. */ [NB - since V40.2, the InterruptControl prefix has been changed from ic_ to inc_, and the ICB_TOGGLE flag has been replaced with the INCB_SET/RESET flags.] SFX_FineVideoControl SFX_FineVideoControl allows some of the features of graphics.library's VideoControl() function to operate over a range of lines in the ViewPort, rather than over the entire ViewPort that VideoControl() operates over. struct FineVideoControl { struct TagItem *fvc_TagList; /* A pointer to a taglist of VideoControl() * tags. Only a subset of VC() tags will be * supported, listed below. */ UWORD fvc_Line; /* line number the VideoControl() should * start on. */ WORD fvc_Count; /* VideoControl() lasts for this many lines, * and then the previous settings are restored. * If == -1, then maintain this to the end of * the ViewPort. */ UWORD fvc_Flags; /* See below */ UWORD fvc_Pad; }; #define FVCB_MODIFY 0 /* When used with AnimateFXA(), the video * features are replaced for this range of * lines with the new features of the * fvc_TagList. */ #define FVCF_MODIFY (1 << FVCB_MODIFY) After installing the effect, the effects can be modified over the range to a new set of VideoControl effects by modifying the fvc_TagList pointer to point to a new TagList, setting the FVCF_MODIFY flag in fvc_Flags, and calling AnimateFX(). The VideoControl() effects supported are: VTAG_CHROMAKEY_CLR/SET VTAG_BITPLANEKEY_CLR/SET VTAG_BORDERBLANK_CLR/SET VTAG_BORDERNOTRANS_CLR/SET VTAG_CHROMA_PLANE_SET VTAG_PF1_BASE_SET VTAG_PF2_BASE_SET VTAG_SPEVEN_BASE_SET VTAG_SPODD_BASE_SET VTAG_BORDERSPRITE_CLR/SET VTAG_SPRITERESN_SET VTAG_PF1_TO_SPRITEPRI_SET VTAG_PF2_TO_SPRITEPRI_SET Also, some additional effects are available in FineVideoControl which are not available to VideoControl(): VTAG_SFX_DEPTH_SET (changes the display depth) VTAG_SFX_HAM_SET (changes the display mode to HAM) VTAG_SFX_EHB_SET (changes the display mode to ExtraHalfBright) VTAG_SFX_NORM_SET (clears HAM, DualPlayField and ExtraHalfBright) VTAG_SFX_DPF_SET (enable dual playfield - was VTAG_MAKEDPF) VTAG_SFX_PF1PRI (playfield 1 has priority over playfield 2) VTAG_SFX_PF2PRI (playfield 2 has priority over playfield 1) SFX_SpriteControl SFX_SpriteControl allows sprites to be moved within a specified area of the ViewPort, but reused in each area. This is similar to graphics.library's VSprite system, only SFX_SpriteControl can handle AA 32 and 64 bit wide sprites, and does not need the display to be remade each time the sprite is moved. struct SpriteControl { struct ExtSprite *spc_ExtSprite; /* Pointer to an initialised * ExtSprite structure. The * sc_ExtSprite.es_SimpleSprite * structure should be initialised as * normal for the graphics.library * sprite functions. */ struct TagItem *spc_TagList; /* Pointer to a TagList of ChangeExtSpriteA() * tags. As of V40, ChangeExtSpriteA() has no * tags defined, so this should be NULL. There * is no guarantee that SpriteControl will * support all or any of the future * ChangeExtSpriteA() tags. */ UWORD spc_Line; /* First line of the range in which the * sprite is to be used. */ UWORD spc_Flags; /* See below */ }; #define SPCB_MODIFY 0 /* When used with AnimateFX(), replace * the sprite image with that in * sc_ExtSprite. */ #define SPCF_MODIFY (1 << SPCB_MODIFY) [NB - The prefix for the SpriteControl has been changed from sc_ to spc_] The application needs to call graphics.library's AllocSpriteData() for each ExtSprite image that will be used, and GetExtSprite() for each sprite number that will be used in the ViewPort. The sprite can be reused throughout the ViewPort, so long as the range of the sprite (sc_ExtSprite.es_SimpleSprite.y + sc_ExtSprite.es_SimpleSprite.height) < the value of the next lower sc_Line. The sprites can be moved within their limited range after calling InstallFX() by modifying the sc_ExtSprite.es_SimpleSprite.x,y,height and even num values, setting the SCF_MODIFY bit in sc_Flags, and calling AnimateFX(). To change the image of the sprite in the range, replace the sc_ExtSprite pointer to a properly initialised ExtSprite pointer instead. SFX_LineControl SFX_LineControl allows you to scroll different parts of the ViewPort independantly from the rest, much like parallax scrolling seen in many of todays games. Specialfx.library allows you to specify which part of the display is to be scrolled, where the data for that area is to come from (so you can define a larger bitmap than is visible and display the parts outside of the visible range), repeat a line of the bitmap over a number of lines on the screen (for those "flow" fades), and independantly control even and odd playfields. struct LineControl { struct RasInfo *lc_RasInfo; /* Pointer to an initialised RasInfo structure. * Set the RxOffset for the scroll value (+ve * is to the left, -ve to the right) of this area, * and the RyOffset to the line number in the * ViewPort's BitMap to start the effect with. * * If lc_RasInfo->Next is not NULL, then * lc_RasInfo will control the even bitplanes, and * lc_RasInfo->Next the odd bitplanes. * * Note that the RasInfo->BitMap->Planes are ignored. * All operations are on the ViewPort's RasInfo(s) * BitMap(s) Plane(s). * */ UWORD lc_Line; /* Start the effect at this line */ UWORD lc_Count; /* Effect is over this many lines */ UWORD lc_Flags; /* See below */ WORD lc_SkipRateEven; /* Number of lines to skip after displaying */ WORD lc_SkipRateOdd; /* a line. Default = 1.*/ UWORD lc_Pad; }; /* A note about the lc_SkipRate... paramters. * The first line to be displayed at line lc_Line of the display is line * lc_RasInfo->RyOffset of the ViewPort->RasInfo->BitMap. * The next line to be displayed at line (lc_Line + 1) is * (lc_RasInfo->RyOffset + lc_SkipRateEven). * So, if lc_SkipRateEven = * 1, contiguous lines are displayed (this is the default). * 2, every other line is displayed. * 0, the first line is repeated, giving a 'flow' effect. * -1, the image is displayed upside down. */ }; #define LCB_MODIFY 0 /* Set for the changes to be made by * AnimateFX(). */ #define LCF_MODIFY (1 << LCB_MODIFY) [NB - for V40.6, the LCF_REPEATLINE flags have been replaced with more versatile lc_SkipRate... fields.] There are some restrictions with this effect though. 1) The calculted modulo value must be in the range -32768 - +32767. That may mean some lines in interleaved bitmaps may be out of range! 2) In interlaced modes, lc_Line and lc_Count must both be even values, else results are unpredictable. Future releases may try to alleviate these problems as best it can. 3) lc_Line must not = 0. I need to WAIT(-1,0) to set up the first modulo, and there may not be enough coppercycles to do so. KNOWN BUGS As of specialfx.library V40.6: In SFX_LineControl: 1) Lores 4x and Lores 2x do not scroll properly if pushed to the left of the screen. 2) There are some problems with scrolling DualPlayfield screens, notably if there are more than two DPF LineControls. I haven't narrowed down the exact circumstances yet. 3) If the screen was opened with SA_Left of non-zero, scrolling is garbage. 4) If any screen is using specialfx.library with copperlist doublebuffering, the display can become corrupted. General: Handling display coercion has not yet been implemented. ScanDouble modes may have problems.