/* $Revision Header * Header built automatically - do not edit! ************* * * (C) Copyright 1990 by MXM * * Name .....: Cycling.c * Created ..: Saturday 23-Sep-90 12:30 * Revision .: 2 * * Date Author Comment * ========= ======== ==================== * 11-May-90 Olsen Rework for Aztec 5.0 release * 23-Sep-89 Olsen Created this file! * * $Revision Header ********************************************************* * * This file contains subroutines handling the colour cycling employed * by LoadImage.c * ***************************************************************************/ /* 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 control the interrupt code. */ #define CY_CYCL (0) /* Keep on cycling. */ #define CY_WAIT (1) /* Don't cycle, wait for startup message. */ /* CycleCode needs this data, InitCycleCode prepares it. */ static struct ViewPort *VPort; /* Where to cycle. */ static struct Interrupt *VBlank; /* The Cycling-interrupt. */ static CRange *Range; /* The cycling-ranges. */ static LONG RangeNum; /* The number of ranges. */ static UWORD ColMap[32]; /* The colourmap. */ static LONG ColNum; /* The number of colours. */ static SHORT TicksPassed[16]; /* Event counter for ranges. */ static UWORD TempCol; /* Temporary colour buffer. */ static UWORD UndoBuffer[32]; /* Original palette buffer. */ static SHORT WeAreWaiting; /* CycleCode is waiting. */ static SHORT Command; /* What is the CycleCode up to do? */ static LONG CodeRun = FALSE; /* Is the CycleCode already running? */ /* CycleCode() : * * CycleCode is the 'C' cycling routine. It runs as an * interrupt server to save task time. */ static LONG CycleCode() { SHORT i,j; /* Loop counter. */ int_start(); /* Are we to wait? */ if(Command == CY_WAIT) { /* Restore the original palette. */ if(!WeAreWaiting) LoadRGB4(VPort,UndoBuffer,ColNum); WeAreWaiting = TRUE; int_end(); /* Don't continue to cycle. */ return(0); } /* We aren't waiting any more. */ if(WeAreWaiting) { /* Re-initialize the palette. */ for(i = 0 ; i < ColNum ; i++) ColMap[i] = UndoBuffer[i]; /* Reset event counters. */ for(i = 0 ; i < RangeNum ; i++) TicksPassed[i] = 0; WeAreWaiting = FALSE; } /* Now handle the cycle ranges. */ for(i = 0 ; i < RangeNum ; i++) { /* Increment event counter. */ TicksPassed[i]++; /* Is this one up to cycle next? */ if(TicksPassed[i] == Range[i] . rate) { /* Reset event counter for this range. */ TicksPassed[i] = 0; /* Is this range active? */ if(!(Range[i] . active & CRNG_ACTIVE)) continue; /* Cycling backwards? */ if(Range[i] . active & CRNG_REVERSE) { /* Move the colours. */ TempCol = ColMap[Range[i] . low]; for(j = Range[i] . low ; j < Range[i] . high ; j++) ColMap[j] = ColMap[j + 1]; ColMap[Range[i] . high] = TempCol; } else { /* This one is cycling forwards. */ TempCol = ColMap[Range[i] . high]; for(j = Range[i] . high ; j > Range[i] . low ; j--) ColMap[j] = ColMap[j - 1]; ColMap[Range[i] . low] = TempCol; } /* Okay, everything has been moved, now * load the new palette. */ LoadRGB4(VPort,ColMap,ColNum); } } int_end(); return(0); } /* InitCycleCode(ViewPort,ColMap,ColNum,Range,RangeNum) : * * Initializes all data and starts up the interrupt * server. */ LONG InitCycleCode(struct ViewPort *Cy_ViewPort,UWORD *Cy_ColMap,LONG Cy_ColNum,CRange *Cy_Range,LONG Cy_RangeNum) { SHORT i; /* Check for valid parameters. */ if(!Cy_ViewPort || !Cy_ColMap || !Cy_ColNum || !Cy_Range || !Cy_RangeNum) return(FALSE); /* See if we can allocate the Interrupt structure. */ if(!(VBlank = (struct Interrupt *)AllocMem(sizeof(struct Interrupt),MEMF_PUBLIC | MEMF_CLEAR))) return(FALSE); /* Copy the data. */ VPort = Cy_ViewPort; ColNum = Cy_ColNum; Range = Cy_Range; RangeNum = Cy_RangeNum; for(i = 0 ; i < ColNum ; i++) ColMap[i] = Cy_ColMap[i]; /* Clear event counters. */ for(i = 0 ; i < Cy_RangeNum ; i++) TicksPassed[i] = 0; /* Copy the original palette to the undo buffer. */ for(i = 0 ; i < Cy_ColNum ; i++) UndoBuffer[i] = Cy_ColMap[i]; /* Let the CycleCode wait. */ Command = CY_WAIT; WeAreWaiting = TRUE; /* Ta Da! The CycleCode enters the stage!. */ VBlank -> is_Code = CycleCode; VBlank -> is_Node . ln_Type = NT_INTERRUPT; VBlank -> is_Node . ln_Name = "Cycling Interrupt"; AddIntServer(INTB_VERTB,VBlank); CodeRun = TRUE; return(TRUE); } /* ClearCycleCode() : * * Forces the CycleCode to hit and quit. */ VOID ClearCycleCode() { SHORT i; /* Is the interrupt already running? */ if(CodeRun && VBlank) { /* Tell it to wait. */ WeAreWaiting = TRUE; Command = CY_WAIT; /* Remove the server code. */ RemIntServer(INTB_VERTB,VBlank); FreeMem(VBlank,sizeof(struct Interrupt)); /* Rebuild palette. */ for(i = 0 ; i < ColNum ; i++) ColMap[i] = UndoBuffer[i]; /* Wait for it to finish. */ WaitTOF(); WaitTOF(); WaitTOF(); /* Close the shop. */ CodeRun = FALSE; } } /* ToggleCycleCode() : * * Toggles the activity of the cycling code. */ VOID ToggleCycleCode() { static BYTE Mode = FALSE; Mode ^= TRUE; if(Mode) Command = CY_CYCL; else Command = CY_WAIT; WaitTOF(); } /* IsCycling() : * * Returns the present status of the cycling code. */ LONG IsCycling() { if(Command == CY_CYCL) return(TRUE); if(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(char *FileName,CRange *Range,LONG MaxRange) { FILE *CycFile; SHORT i; /* GraphiCraft private cycling chunk. */ struct { WORD direction; /* Which direction? */ UBYTE start; /* First colour. */ UBYTE end; /* Last colour. */ LONG seconds; /* Wait time. */ LONG microseconds; /* Wait time. */ WORD pad; /* Expansion/padding byte. */ } 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 if this chunk is * active. */ 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); /* See if it is active. */ if(!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; /* See if there is another chunk. */ if(!FindChunk("CCRT",CycFile)) { i++; break; } } } else { /* Seems that we failed. */ fclose(CycFile); return(FALSE); } } fclose(CycFile); return(i); }