/****************************************************************************** * * Cycling.c 01/07/89 by: Olaf Barthel * Brabeckstrasse 35 * D-3000 Hannover 71 * * Federal Republic of Germany * * Cycling 1.5 (C) Copyright 1989 by Olaf Barthel & ED Hannover * * Not even a single character of this wonderful piece of code * may be incorporated into any other program without the * author's consent. Yep, still a splendid time is guaranteed * for all! * ******************************************************************************* * * Cycling contains colour cycling support routines for LoadImage.c, * and is based on example source code written by Carolin Scheppner * (Display.c). This version uses interrupt code to handle the * cycling job. * ******************************************************************************/ #include #include #include #include #include /* The typical format of a DPaint colour cycling range. */ typedef struct { WORD pad1; /* Not used. */ WORD rate; /* Cycling speed. */ WORD active; /* Is it active? Which way is it cycling? */ UBYTE low,high; /* Start and stop colour. */ } CRange; /* LoadCycleRange needs these macros. */ #define CRNG_NORATE 36 /* Don't cycle this range. */ #define CRNG_ACTIVE 1 << 0 /* This range is active. */ #define CRNG_REVERSE 1 << 1 /* This range is cycling backwards. */ /* The following values are to controll the interrupt code. */ #define CY_CYCL 0 /* Keep on cycling. */ #define CY_WAIT 1 /* Don't cycle, wait for startup message. */ /* A sole forward declaration. */ extern BOOL FindChunk(); /* CycleCode needs this data, InitCycleCode prepares it. */ struct ViewPort *cy_VPort; /* Where to cycle. */ struct Interrupt cy_VBlank; /* The Cycling-interrupt. */ CRange *cy_Range; /* The cycling-ranges. */ LONG cy_RangeNum; /* The number of ranges. */ UWORD cy_ColMap[32]; /* The colourmap. */ LONG cy_ColNum; /* The number of colours. */ short cy_TicksPassed[16]; /* Event counter for ranges. */ UWORD cy_TempCol; /* Temporary colour buffer. */ UWORD cy_UndoBuffer[32]; short cy_WeAreWaiting; /* CycleCode is waiting. */ short cy_Command; /* What is the CycleCode up to do? */ BOOL cy_CodeRun = FALSE; /* Is the CycleCode already running? */ extern void VBlankHandler(); #asm _VBlankHandler: MOVEM.L A2-A6/D2-D7,-(A7) ; Save some registers JSR _geta4# ; Adjust data register JSR _CycleCode ; Call 'C' routine CLR.L D0 ; D0 must be cleared ; or strange things will ; happen MOVEM.L (A7)+,A2-A6/D2-D7 ; Restore registers RTS ; ...and go on #endasm /* CycleCode() : * * CycleCode is the 'C' cycling routine. It runs as an * interrupt server to save task time. */ void CycleCode() { register short i,j; /* Loop counter. */ /* Are we to wait? */ if(cy_Command == CY_WAIT) { /* Restore the original palette. */ if(!cy_WeAreWaiting) LoadRGB4(cy_VPort,cy_UndoBuffer,cy_ColNum); cy_WeAreWaiting = TRUE; /* Don't continue to cycle. */ return; } /* We aren't waiting any more. */ if(cy_WeAreWaiting) { /* Re-initialize the palette. */ for(i = 0 ; i < cy_ColNum ; i++) cy_ColMap[i] = cy_UndoBuffer[i]; /* Reset event counters. */ for(i = 0 ; i < cy_RangeNum ; i++) cy_TicksPassed[i] = 0; cy_WeAreWaiting = FALSE; } /* Now handle the cycle ranges. */ for(i = 0 ; i < cy_RangeNum ; i++) { /* Increment event counter. */ cy_TicksPassed[i]++; /* Is this one up to cycle next? */ if(cy_TicksPassed[i] == cy_Range[i] . rate) { /* Reset event counter for this range. */ cy_TicksPassed[i] = 0; /* Is this range active? */ if(!(cy_Range[i] . active & CRNG_ACTIVE)) continue; /* Cycling backwards? */ if(cy_Range[i] . active & CRNG_REVERSE) { /* Move the colours. */ cy_TempCol = cy_ColMap[cy_Range[i] . low]; for(j = cy_Range[i] . low ; j < cy_Range[i] . high ; j++) cy_ColMap[j] = cy_ColMap[j + 1]; cy_ColMap[cy_Range[i] . high] = cy_TempCol; } else { /* This one is cycling forwards. */ cy_TempCol = cy_ColMap[cy_Range[i] . high]; for(j = cy_Range[i] . high ; j > cy_Range[i] . low ; j--) cy_ColMap[j] = cy_ColMap[j - 1]; cy_ColMap[cy_Range[i] . low] = cy_TempCol; } /* Okay, everything has been moved, now * load the new palette. */ LoadRGB4(cy_VPort,cy_ColMap,cy_ColNum); } } } /* InitCycleCode(ViewPort,ColMap,ColNum,Range,RangeNum) : * * Initializes all data and starts up the interrupt * server. */ BOOL InitCycleCode(ViewPort,ColMap,ColNum,Range,RangeNum) struct ViewPort *ViewPort; UWORD *ColMap; LONG ColNum; CRange *Range; LONG RangeNum; { register short i; /* Check for valid parameters. */ if(!ViewPort || !ColMap || !ColNum || !Range || !RangeNum) return(FALSE); /* Copy the data. */ cy_VPort = ViewPort; cy_ColNum = ColNum; cy_Range = Range; cy_RangeNum = RangeNum; for(i = 0 ; i < ColNum ; i++) cy_ColMap[i] = ColMap[i]; /* Clear event counters. */ for(i = 0 ; i < cy_RangeNum ; i++) cy_TicksPassed[i] = 0; /* Copy the original palette to the undo buffer. */ for(i = 0 ; i < cy_ColNum ; i++) cy_UndoBuffer[i] = cy_ColMap[i]; /* Let the CycleCode wait. */ cy_Command = CY_WAIT; cy_WeAreWaiting = TRUE; /* Ta Da! The CycleCode enters the stage!. */ cy_VBlank . is_Data = (APTR)NULL; cy_VBlank . is_Code = VBlankHandler; cy_VBlank . is_Node . ln_Succ = NULL; cy_VBlank . is_Node . ln_Pred = NULL; cy_VBlank . is_Node . ln_Type = NT_INTERRUPT; cy_VBlank . is_Node . ln_Pri = 0; cy_VBlank . is_Node . ln_Name = "Cycling Interrupt"; AddIntServer(5,&cy_VBlank); cy_CodeRun = TRUE; return(TRUE); } /* ClearCycleCode() : * * Forces the CycleCode to hit and quit. */ void ClearCycleCode() { register short i; /* Is the interrupt already running? */ if(!cy_CodeRun) return; /* Tell it to wait. */ cy_WeAreWaiting = TRUE; cy_Command = CY_WAIT; /* Remove the server code. */ RemIntServer(5,&cy_VBlank); /* Rebuild palette. */ for(i = 0 ; i < cy_ColNum ; i++) cy_ColMap[i] = cy_UndoBuffer[i]; /* Wait for it to finish. */ WaitTOF(); WaitTOF(); WaitTOF(); /* Close the shop. */ cy_CodeRun = FALSE; } /* ToggleCycleCode() : * * Toggles the activity of the cycling code. */ void ToggleCycleCode() { static short Mode = FALSE; Mode ^= TRUE; if(Mode) cy_Command = CY_CYCL; else cy_Command = CY_WAIT; WaitTOF(); } /* IsCycling() : * * Returns the present status of the cycling code. */ short IsCycling() { if(cy_Command == CY_CYCL) return(TRUE); if(cy_Command == CY_WAIT) return(FALSE); } /* LoadCycleRange(FileName,Range,MaxRange) : * * Searches the IFF-ILBM-file for CRNG or CCRT * chunks und initializes the colour-ranges. */ LONG LoadCycleRange(FileName,Range,MaxRange) char *FileName; CRange *Range; LONG MaxRange; { FILE *CycFile; register short i; /* GraphiCraft private cycling chunk. */ struct { WORD direction; UBYTE start; UBYTE end; LONG seconds; LONG microseconds; WORD pad; } CcrtChunk; /* Clear all ranges. */ for(i = 0 ; i < MaxRange ; i++) Range[i] . active = 0; /* Open the file and try to locate the CRNG chunk. */ if(!(CycFile = fopen(FileName,"r"))) return(FALSE); if(FindChunk("CRNG",CycFile)) { /* Read all ranges. */ for(i = 0 ; i < MaxRange ; i++) { fread(&Range[i],sizeof(CRange),1,CycFile); /* Carefully determine the activity * of the chunk. */ if(Range[i] . active == CRNG_NORATE || !Range[i] . rate || Range[i] . low == Range[i] . high) Range[i] . active = 0; /* Recalculate speed value. */ if(Range[i] . rate > 0) Range[i] . rate = 16384 / Range[i] . rate; else Range[i] . rate = 0; /* Finished reading the chunks? */ if(!FindChunk("CRNG",CycFile)) { i++; break; } } } else { /* Didn't find a CRNG chunk, try to find a * CCRT chunk. */ fseek(CycFile,0,0); if(FindChunk("CCRT",CycFile)) { for(i = 0 ; i < MaxRange ; i++) { fread(&CcrtChunk,sizeof(CcrtChunk),1,CycFile); /* We have located a CCRT chunk, now * make it a CRNG chunk. */ Range[i] . low = CcrtChunk . start; Range[i] . high = CcrtChunk . end; if(CcrtChunk . direction != 0) Range[i] . active = CRNG_ACTIVE; else Range[i] . active = 0; if(CcrtChunk . direction > 0) Range[i] . active |= CRNG_REVERSE; /* Recalculate speed (by * Carolyn Scheppner). */ Range[i] . rate = 16384 / (CcrtChunk . seconds * 60 + (CcrtChunk . microseconds + 8334) / 16667); if(!Range[i] . rate || Range[i] . low == Range[i] . high) Range[i] . active = 0; if(Range[i] . rate > 0) Range[i] . rate = 16384 / Range[i] . rate; else Range[i] . rate = 0; if(!FindChunk("CCRT",CycFile)) { i++; break; } } } else { /* Seems that we failed. */ fclose(CycFile); return(FALSE); } } fclose(CycFile); return(i); }