home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
AmigActive 3
/
AACD03.BIN
/
AACD
/
Graphics
/
ViewILBM
/
Source
/
view.c
< prev
next >
Wrap
C/C++ Source or Header
|
1999-10-08
|
53KB
|
2,605 lines
/*
* $Id: view.c 1.10 1999/10/08 10:55:20 olsen Exp olsen $
*
* :ts=4
*
* ViewILBM, by Olaf `Olsen' Barthel, public domain
*
* Postal address: Olaf Barthel
* Brabeckstr. 35
* 30559 Hannover
*
* Federal Republic of Germany
*
* e-mail address: olsen@sourcery.han.de
*/
#include "global.h"
#include "ViewILBM_rev.h"
/******************************************************************************/
enum
{
ERR_BASE = 30000,
ERR_NO_INTUITION,
ERR_NO_GRAPHICS,
ERR_NO_ICON,
ERR_NO_UTILITY,
ERR_NO_ASL,
ERR_NO_IFFPARSE,
ERR_NO_CYBERGFX,
ERR_NO_PORT,
ERR_NO_REQUEST,
ERR_NO_TIMER,
ERR_NO_MEMORY,
ERR_NO_WINDOW,
ERR_NO_SCREEN,
ERR_NO_ASL_REQUEST,
ERR_IFF_BASE,
ERR_IFF_EOF,
ERR_IFF_EOC,
ERR_IFF_NOSCOPE,
ERR_IFF_NOMEM,
ERR_IFF_READ,
ERR_IFF_WRITE,
ERR_IFF_SEEK,
ERR_IFF_MANGLED,
ERR_IFF_SYNTAX,
ERR_IFF_NOTIFF,
ERR_IFF_NOHOOK,
ERR_UNKNOWN_COMPRESSION,
ERR_NOT_IFF_ILBM,
ERR_MODE_NOT_AVAILABLE,
ERR_DIM_TOO_BIG,
ERR_DIM_TOO_DEPTH,
ERR_DOUBLE_BUF_TOO_BIG,
ERR_CANT_OPEN_SCREEN,
ERR_ABORTED,
};
/******************************************************************************/
#define MILLION 1000000
/******************************************************************************/
#define MAX_FILENAME_LEN 256
#define MAX_PATHNAME_LEN 512
/******************************************************************************/
typedef long SWITCH;
typedef unsigned char * KEYWORD;
typedef long * NUMBER;
/******************************************************************************/
#define SAME (0)
#define OK (0)
#define DONT !
#define NO !
#define BUSY ((struct IORequest *)NULL)
/******************************************************************************/
#define NUM_ENTRIES(t) (sizeof(t) / sizeof(t[0]))
/******************************************************************************/
#define BRIGHTNESS(r,g,b) (((WORD)r) * 30 + ((WORD)g) * 59 + ((WORD)b) * 11) / 100
/******************************************************************************/
#define FLAG_IS_SET(x,f) ((x & f) == f)
#define FLAG_IS_CLEAR(x,f) ((x & f) == 0)
#define CLEAR_FLAG(x,f) (x &= ~(f))
#define SET_FLAG(x,f) (x |= f)
/******************************************************************************/
/* Masking techniques */
#define mskNone 0
#define mskHasMask 1
/* Compression techniques */
#define cmpNone 0
#define cmpByteRun1 1
/* Bitmap header (BMHD) structure */
struct BitMapHeader
{
UWORD bmh_Width;
UWORD bmh_Height;
WORD bmh_Left;
WORD bmh_Top;
UBYTE bmh_Depth;
UBYTE bmh_Masking;
UBYTE bmh_Compression;
UBYTE bmh_Pad;
UWORD bmh_Transparent;
UBYTE bmh_XAspect;
UBYTE bmh_YAspect;
WORD bmh_PageWidth;
WORD bmh_PageHeight;
};
/******************************************************************************/
/* A "CRNG" chunk contains "color register range" information. It's used
* by Electronic Arts' Deluxe Paint program to identify a contiguous
* range of color registers for a "shade range" and color cycling. There
* can be zero or more CRNG chunks in an ILBM, but all should appear
* before the BODY chunk. Deluxe Paint normally writes 4 CRNG chunks
* in an ILBM when the user asks it to "Save Picture".
*/
struct CRange
{
WORD counter; /* Reserved for future use; store 0 here */
WORD rate; /* The field "rate" determines the speed at which the colors will step
* when color cycling is on. The units are such that a rate of 60 steps
* per second is represented as 214 = 16384. Slower rates can be obtained
* by linear scaling: for 30 steps/second, rate = 8192; for 1 step/second,
* rate = 16384/60, i.e. 273.
*/
WORD active; /* Nonzero means cycle the colors */
UBYTE low,high; /* The fields "low" and "high" indicate the range of color registers (color
* numbers) selected by this CRange.
*/
};
/* Commodore's Graphicraft program uses a similar chunk "CCRT" (for Color
* Cyling Range and Timing). This chunk contains a CycleInfo structure.
* This is pretty similar to a CRNG chunk. A program would probably only
* use one of these two methods of expressing color cycle data. You could
* write out both if you want to communicate this information to both
* Deluxe Paint and Graphicraft.
*
* A CCRT chunk expresses the color cycling rate as a number of seconds
* plus a number of microseconds.
*/
struct CycleInfo
{
WORD direction; /* 0 = don't cycle. -1 = cycle forwards (1, 2, 3).
* 1 = cycle backwards (3, 2, 1)
*/
UBYTE start,end; /* Lower and upper color registers selected */
LONG seconds; /* # seconds between changing colors */
LONG microseconds; /* # microseconds between changing colors */
WORD pad; /* Reserved for future use; store 0 here */
};
/******************************************************************************/
/* IFF types that may be in pictures */
#define ID_ILBM MAKE_ID('I','L','B','M')
#define ID_BMHD MAKE_ID('B','M','H','D')
#define ID_CMAP MAKE_ID('C','M','A','P')
#define ID_CAMG MAKE_ID('C','A','M','G')
#define ID_BODY MAKE_ID('B','O','D','Y')
#define ID_CCRT MAKE_ID('C','C','R','T')
#define ID_CRNG MAKE_ID('C','R','N','G')
/******************************************************************************/
#define MODIFY_RED6 0x20
#define MODIFY_GREEN6 0x30
#define MODIFY_BLUE6 0x10
#define MODIFY_MASK6 0x30
#define MODIFY_LUT6 0x00
#define MODIFY_RED8 0x80
#define MODIFY_GREEN8 0xC0
#define MODIFY_BLUE8 0x40
#define MODIFY_MASK8 0xC0
#define MODIFY_LUT8 0x00
/******************************************************************************/
#define PORTMASK(p) (1L << ((struct MsgPort *)(p))->mp_SigBit)
#define SPREAD(a) (0x01010101 * (a))
/******************************************************************************/
struct ColorRegister
{
UBYTE red, green, blue;
};
/******************************************************************************/
struct CycleData
{
struct Task * cd_Task;
LONG cd_A4;
struct Task * cd_Parent;
struct Screen * cd_Screen;
struct CRange cd_Ranges[8];
LONG cd_PaletteSize;
struct ColorRegister * cd_OriginalPalette;
struct ColorRegister * cd_CurrentPalette;
BOOL cd_Cycling;
BOOL cd_IsEHB;
};
/******************************************************************************/
STRPTR VersTag = VERSTAG;
/******************************************************************************/
struct Library * IntuitionBase;
struct Library * GfxBase;
struct Library * AslBase;
struct Library * UtilityBase;
struct Library * CyberGfxBase;
struct Library * IFFParseBase;
struct Library * IconBase;
/******************************************************************************/
struct MsgPort * TimePort;
struct timerequest * TimeRequest;
BOOL TimeTicking;
/******************************************************************************/
struct Screen * Screen;
struct Window * Window;
LONG DisplayDepth;
Object * TransparentPointer;
/******************************************************************************/
BOOL PrefCenter,
PrefQuiet,
PrefCycle,
PrefHAM,
PrefEHB;
LONG PrefWait,
PrefWaitAfterOpen;
/******************************************************************************/
VOID __asm ReadPlanarLine8(register __a0 struct BitMap * source,
register __a1 UBYTE * line,
register __d0 LONG interleave);
/******************************************************************************/
VOID
CloseDisplay(VOID)
{
if(Window != NULL)
{
CloseWindow(Window);
Window = NULL;
}
if(Screen != NULL)
{
CloseScreen(Screen);
Screen = NULL;
}
if(TransparentPointer != NULL)
{
DisposeObject(TransparentPointer);
TransparentPointer = NULL;
}
}
ULONG *
SetupPalette(UBYTE * palette,LONG numColours)
{
STATIC ULONG LoadTable[1 + 256*3 + 1];
ULONG * t = LoadTable;
LONG i,j;
(*t++) = numColours << 16;
for(i = 0 ; i < numColours ; i++)
{
for(j = 0 ; j < 3 ; j++)
(*t++) = SPREAD(*palette++);
}
(*t) = 0;
return(LoadTable);
}
ERRORCODE
OpenDisplay(
UWORD width,
UWORD height,
UWORD depth,
UBYTE backgroundColour,
UBYTE * palette,
LONG numColours)
{
ERRORCODE error = OK;
ULONG displayID;
displayID = BestCModeIDTags(
CYBRBIDTG_NominalWidth, width,
CYBRBIDTG_NominalHeight, height,
CYBRBIDTG_Depth, depth,
TAG_DONE);
if(displayID != INVALID_ID)
{
STATIC struct BitMap pointerBitMap;
STATIC UWORD blank[2];
memset(blank,0,sizeof(blank));
memset(&pointerBitMap,0,sizeof(pointerBitMap));
InitBitMap(&pointerBitMap,2,16,1);
pointerBitMap.Planes[0] = (PLANEPTR)&blank[0];
pointerBitMap.Planes[1] = (PLANEPTR)&blank[1];
TransparentPointer = NewObject(NULL,POINTERCLASS,
POINTERA_BitMap, &pointerBitMap,
POINTERA_WordWidth, 1,
TAG_DONE);
if(TransparentPointer != NULL)
{
ULONG colors32tag = TAG_IGNORE;
ULONG * colors32 = NULL;
if(palette != NULL && numColours > 0 && depth <= 8)
{
colors32tag = SA_Colors32;
colors32 = SetupPalette(palette,numColours);
}
Screen = OpenScreenTags(NULL,
SA_DisplayID, displayID,
SA_Depth, depth,
SA_Quiet, TRUE,
SA_ShowTitle, FALSE,
SA_BackFill, LAYERS_NOBACKFILL,
SA_Interleaved, TRUE,
colors32tag, colors32,
TAG_DONE);
if(Screen != NULL)
{
DisplayDepth = depth;
Window = OpenWindowTags(NULL,
WA_Width, Screen->Width,
WA_Height, Screen->Height,
WA_Left, 0,
WA_Height, 0,
WA_Backdrop, TRUE,
WA_Borderless, TRUE,
WA_RMBTrap, TRUE,
WA_SimpleRefresh, TRUE,
WA_NoCareRefresh, TRUE,
WA_IDCMP, IDCMP_VANILLAKEY | IDCMP_MOUSEBUTTONS,
WA_Activate, TRUE,
WA_CustomScreen, Screen,
WA_BackFill, LAYERS_NOBACKFILL,
WA_BusyPointer, TRUE,
TAG_DONE);
if(Window != NULL)
{
if(depth == 24)
SetRGB4(&Screen->ViewPort,0,0,0,0);
SetRast(Window->RPort,backgroundColour);
if(PrefWaitAfterOpen > 0)
Delay(TICKS_PER_SECOND * PrefWaitAfterOpen);
}
else
{
error = ERR_NO_WINDOW;
}
}
else
{
error = ERR_NO_SCREEN;
}
}
else
{
error = ERROR_NO_FREE_STORE;
}
}
else
{
error = ERR_NO_SCREEN;
}
if(error != OK)
{
CloseDisplay();
}
return(error);
}
/******************************************************************************/
VOID
DivideRange(UBYTE * range,LONG rangesize,LONG numvalues,LONG maxvalue)
{
LONG i,j,from,to,value;
for(i = 0; i < numvalues; i++)
{
from = (i * rangesize) / numvalues;
to = ((i + 1) * rangesize) / numvalues;
value = (i * maxvalue) / (numvalues - 1);
for(j = from ; j < to ; j++)
range[j] = value;
}
}
/******************************************************************************/
enum
{
PICTURETYPE_Planar,
PICTURETYPE_HAM6,
PICTURETYPE_HAM8,
PICTURETYPE_TrueColour
};
struct BitPlaneData
{
struct BitMap bpd_Planes;
PLANEPTR bpd_MorePlanes[16];
struct BitMap bpd_PlanesWithoutMask;
struct BitMap bpd_Red;
struct BitMap bpd_Green;
struct BitMap bpd_Blue;
UBYTE * bpd_PlaneZero;
UBYTE * bpd_PlaneData[24];
UBYTE * bpd_Pixels;
UBYTE bpd_Translation[256];
LONG bpd_Width;
LONG bpd_PictureType;
};
VOID
DeleteBitPlaneData(struct BitPlaneData * bpd)
{
if(bpd != NULL)
{
LONG i;
FreeVec(bpd->bpd_PlaneZero);
for(i = 0 ; i < 24 ; i++)
FreeVec(bpd->bpd_PlaneData[i]);
FreeVec(bpd->bpd_Pixels);
FreeVec(bpd);
}
}
struct BitPlaneData *
CreateBitPlaneData(struct BitMapHeader * bmh,ULONG viewModes)
{
struct BitPlaneData * bpd;
LONG depth = bmh->bmh_Depth;
LONG bytesPerPixel;
LONG bytesPerRow;
LONG i;
bpd = AllocVec(sizeof(*bpd),MEMF_ANY|MEMF_CLEAR);
if(bpd == NULL)
{
goto cleanup;
}
if((depth > 8) && ((depth < 12) || (depth > 24) || (depth % 3) != 0))
{
goto cleanup;
}
if((depth > 8) && (bmh->bmh_Masking != mskNone))
{
goto cleanup;
}
if(depth > 8)
{
bpd->bpd_PictureType = PICTURETYPE_TrueColour;
}
else
{
if(FLAG_IS_SET(viewModes,HAM))
{
if(bmh->bmh_Depth == 6)
bpd->bpd_PictureType = PICTURETYPE_HAM6;
else
bpd->bpd_PictureType = PICTURETYPE_HAM8;
}
else
{
bpd->bpd_PictureType = PICTURETYPE_Planar;
}
}
if(depth <= 8 && FLAG_IS_CLEAR(viewModes,HAM))
bytesPerPixel = 1;
else
bytesPerPixel = 3;
bpd->bpd_Width = bmh->bmh_Width;
InitBitMap(&bpd->bpd_PlanesWithoutMask,max(24,depth),bmh->bmh_Width,bmh->bmh_Height);
InitBitMap(&bpd->bpd_Planes,8,bmh->bmh_Width,bmh->bmh_Height);
InitBitMap(&bpd->bpd_Red,8,bmh->bmh_Width,bmh->bmh_Height);
InitBitMap(&bpd->bpd_Green,8,bmh->bmh_Width,bmh->bmh_Height);
InitBitMap(&bpd->bpd_Blue,8,bmh->bmh_Width,bmh->bmh_Height);
bytesPerRow = bpd->bpd_Planes.BytesPerRow;
bpd->bpd_PlaneZero = AllocVec(bytesPerRow,MEMF_ANY|MEMF_CLEAR);
if(bpd->bpd_PlaneZero == NULL)
{
goto cleanup;
}
bpd->bpd_Pixels = AllocVec(((bmh->bmh_Width + 15) & ~15) * bytesPerPixel * 2,MEMF_ANY);
if(bpd->bpd_Pixels == NULL)
{
goto cleanup;
}
for(i = 0 ; i < 24 ; i++)
{
bpd->bpd_Planes.Planes[i] = bpd->bpd_PlaneZero;
}
for(i = 0 ; i < 8 ; i++)
{
bpd->bpd_PlanesWithoutMask.Planes[i] = bpd->bpd_PlaneZero;
bpd->bpd_Red.Planes[i] = bpd->bpd_PlaneZero;
bpd->bpd_Green.Planes[i] = bpd->bpd_PlaneZero;
bpd->bpd_Blue.Planes[i] = bpd->bpd_PlaneZero;
}
if(depth <= 8)
{
for(i = 0 ; i < 9 ; i++)
{
bpd->bpd_PlaneData[i] = AllocVec(bytesPerRow,MEMF_ANY);
if(bpd->bpd_PlaneData[i] == NULL)
{
goto cleanup;
}
}
for(i = 0 ; i < depth ; i++)
{
bpd->bpd_Planes.Planes[i] = bpd->bpd_PlaneData[i];
bpd->bpd_PlanesWithoutMask.Planes[i] = bpd->bpd_PlaneData[i];
}
if(bmh->bmh_Masking == mskHasMask)
{
bpd->bpd_Planes.Planes[depth] = bpd->bpd_PlaneData[depth];
}
}
else
{
LONG oneThird = depth / 3;
for(i = 0 ; i < 24 ; i++)
{
bpd->bpd_PlaneData[i] = AllocVec(bytesPerRow,MEMF_ANY);
if(bpd->bpd_PlaneData[i] == NULL)
{
goto cleanup;
}
}
for(i = 0 ; i < depth ; i++)
{
bpd->bpd_Planes.Planes[i] = bpd->bpd_PlaneData[i];
}
for(i = 0 ; i < oneThird ; i++)
{
bpd->bpd_Red.Planes[i] = bpd->bpd_PlaneData[i];
bpd->bpd_Green.Planes[i] = bpd->bpd_PlaneData[i + oneThird];
bpd->bpd_Blue.Planes[i] = bpd->bpd_PlaneData[i + oneThird + oneThird];
}
if(oneThird == 8)
{
for(i = 0 ; i < 256 ; i++)
bpd->bpd_Translation[i] = i;
}
else
{
DivideRange(bpd->bpd_Translation,256,(1L << oneThird),255);
}
}
return(bpd);
cleanup:
DeleteBitPlaneData(bpd);
return(NULL);
}
/******************************************************************************/
VOID
StopTimer(VOID)
{
if(TimeTicking)
{
if(CheckIO((struct IORequest *)TimeRequest) == BUSY)
AbortIO((struct IORequest *)TimeRequest);
WaitIO((struct IORequest *)TimeRequest);
TimeTicking = FALSE;
SetSignal(0,PORTMASK(TimePort));
}
}
VOID
StartTimer(ULONG seconds,ULONG micros)
{
StopTimer();
TimeRequest->tr_node.io_Command = TR_ADDREQUEST;
TimeRequest->tr_time.tv_secs = seconds;
TimeRequest->tr_time.tv_micro = micros;
SetSignal(0,PORTMASK(TimePort));
SendIO((struct IORequest *)TimeRequest);
TimeTicking = TRUE;
}
/******************************************************************************/
VOID
PutLine(LONG left,LONG top,BOOL doubleHorizontal,struct BitPlaneData * bpd,UBYTE * palette,ULONG viewModes)
{
if(top < Screen->Height)
{
LONG lineLength;
if(doubleHorizontal)
lineLength = 2 * bpd->bpd_Width;
else
lineLength = bpd->bpd_Width;
if(lineLength > Screen->Width - left)
lineLength = Screen->Width - left;
if(lineLength > 0)
{
LONG bytesPerPixel;
LONG format;
if(bpd->bpd_PictureType == PICTURETYPE_Planar)
{
format = RECTFMT_LUT8;
bytesPerPixel = 1;
}
else
{
format = RECTFMT_RGB;
bytesPerPixel = 3;
}
if(bpd->bpd_PictureType == PICTURETYPE_HAM6)
{
UBYTE * t;
UBYTE r,g,b;
LONG colour,i;
ReadPlanarLine8(&bpd->bpd_Planes,bpd->bpd_Pixels,3);
r = g = b = 0;
t = bpd->bpd_Pixels;
for(i = 0 ; i < bpd->bpd_Width ; i++)
{
switch((*t) & MODIFY_MASK6)
{
case MODIFY_LUT6:
colour = (*t) & 15;
r = palette[colour * 3];
g = palette[colour * 3 + 1];
b = palette[colour * 3 + 2];
break;
case MODIFY_BLUE6:
colour = (*t) & 15;
b = 0x11 * colour;
break;
case MODIFY_RED6:
colour = (*t) & 15;
r = 0x11 * colour;
break;
case MODIFY_GREEN6:
colour = (*t) & 15;
g = 0x11 * colour;
break;
}
(*t++) = r;
(*t++) = g;
(*t++) = b;
}
}
if(bpd->bpd_PictureType == PICTURETYPE_HAM8)
{
UBYTE * t;
UBYTE r,g,b;
LONG colour,i;
ReadPlanarLine8(&bpd->bpd_Planes,bpd->bpd_Pixels,3);
r = g = b = 0;
t = bpd->bpd_Pixels;
for(i = 0 ; i < bpd->bpd_Width ; i++)
{
switch((*t) & MODIFY_MASK8)
{
case MODIFY_LUT8:
colour = (*t) & 63;
r = palette[colour * 3];
g = palette[colour * 3 + 1];
b = palette[colour * 3 + 2];
break;
case MODIFY_BLUE8:
colour = (*t) & 63;
b = (colour << 2) | (colour >> 4);
break;
case MODIFY_RED8:
colour = (*t) & 63;
r = (colour << 2) | (colour >> 4);
break;
case MODIFY_GREEN8:
colour = (*t) & 63;
g = (colour << 2) | (colour >> 4);
break;
}
(*t++) = r;
(*t++) = g;
(*t++) = b;
}
}
if(bpd->bpd_PictureType == PICTURETYPE_Planar)
{
ReadPlanarLine8(&bpd->bpd_Planes,bpd->bpd_Pixels,1);
}
if(bpd->bpd_PictureType == PICTURETYPE_TrueColour)
{
UBYTE * t;
LONG i;
ReadPlanarLine8(&bpd->bpd_Red,bpd->bpd_Pixels,3);
ReadPlanarLine8(&bpd->bpd_Green,bpd->bpd_Pixels+1,3);
ReadPlanarLine8(&bpd->bpd_Blue,bpd->bpd_Pixels+2,3);
for(t = bpd->bpd_Pixels, i = 0 ; i < 3*lineLength ; i++, t++)
{
(*t) = bpd->bpd_Translation[(*t)];
}
}
if(doubleHorizontal)
{
LONG total = 2 * bpd->bpd_Width;
if(bytesPerPixel == 1)
{
UBYTE * src;
UBYTE * dst;
LONG i;
src = bpd->bpd_Pixels + bpd->bpd_Width - 1;
dst = bpd->bpd_Pixels + total - 1;
for(i = 0 ; i < bpd->bpd_Width ; i++)
(*dst--) = (*dst--) = (*src--);
}
else
{
UBYTE * src;
UBYTE * dst;
LONG i;
src = bpd->bpd_Pixels + 3 * bpd->bpd_Width - 1;
dst = bpd->bpd_Pixels + 3 * total - 1;
for(i = 0 ; i < bpd->bpd_Width ; i++)
{
(*dst--) = src[ 0];
(*dst--) = src[-1];
(*dst--) = src[-2];
(*dst--) = (*src--);
(*dst--) = (*src--);
(*dst--) = (*src--);
}
}
}
WritePixelArray(bpd->bpd_Pixels,0,0,lineLength * bytesPerPixel,Window->RPort,left,top,lineLength,1,format);
}
}
}
/******************************************************************************/
STRPTR
GetErrorString(ERRORCODE error)
{
STATIC struct { LONG Code; STRPTR Name; } LocalErrors[] =
{
ERR_NO_INTUITION, "Error opening intuition.library v39",
ERR_NO_GRAPHICS, "Error opening graphics.library v39",
ERR_NO_UTILITY, "Error opening utility.library v37",
ERR_NO_ICON, "Error opening icon.library v37",
ERR_NO_ASL, "Error opening asl.library v37",
ERR_NO_IFFPARSE, "Error opening iffparse.library v40",
ERR_NO_CYBERGFX, "Error opening cybergraphics.library v40",
ERR_NO_WINDOW, "Error opening window",
ERR_NO_SCREEN, "Error opening screen",
ERR_NO_MEMORY, "Out of memory",
ERR_NO_PORT, "Error opening message port",
ERR_NO_REQUEST, "Error allocating timer request",
ERR_NO_TIMER, "Error opening timer.device",
ERR_NO_ASL_REQUEST, "Error allocating file requester",
ERR_MODE_NOT_AVAILABLE, "Requested screen mode is not available",
ERR_DIM_TOO_BIG, "Requested screen size is too large",
ERR_DIM_TOO_DEPTH, "Requested number of colours not available",
ERR_DOUBLE_BUF_TOO_BIG, "Not enough memory for double-buffering",
ERR_CANT_OPEN_SCREEN, "Background screen did not open",
ERR_UNKNOWN_COMPRESSION,"Unknown compression format",
ERR_NOT_IFF_ILBM, "Not an IFF-ILBM file",
ERR_IFF_EOF, "Reached logical end of file",
ERR_IFF_EOC, "About to leave context",
ERR_IFF_NOSCOPE, "No valid scope for property",
ERR_IFF_NOMEM, "Internal memory allocation failed",
ERR_IFF_READ, "Stream read error",
ERR_IFF_WRITE, "Stream write error",
ERR_IFF_SEEK, "Stream seek error",
ERR_IFF_MANGLED, "Data in file is corrupt",
ERR_IFF_SYNTAX, "IFF syntax error",
ERR_IFF_NOTIFF, "Not an IFF file",
ERR_IFF_NOHOOK, "No call-back hook provided",
0, NULL
};
STRPTR result = NULL;
LONG i;
for(i = 0 ; LocalErrors[i].Name != NULL ; i++)
{
if(LocalErrors[i].Code == error)
{
result = LocalErrors[i].Name;
break;
}
}
if(result == NULL)
{
STATIC UBYTE buffer[256];
Fault(error,NULL,buffer,sizeof(buffer));
result = buffer;
}
return(result);
}
VOID
PrintErrorString(ERRORCODE error,STRPTR header)
{
if(header != NULL)
Printf("%s: %s\n",header,GetErrorString(error));
else
Printf("%s\n",GetErrorString(error));
}
/******************************************************************************/
ERRORCODE
ProcessWindowInput(struct Window * window,struct CycleData * cd)
{
struct IntuiMessage * message;
ERRORCODE error = OK;
while((message = (struct IntuiMessage *)GetMsg(window->UserPort)) != NULL)
{
switch(message->Class)
{
case IDCMP_VANILLAKEY:
if(message->Code == '\33' || message->Code == '\3')
{
error = ERR_ABORTED;
}
else
{
if(message->Code == '\t')
{
if(cd != NULL)
{
if(cd->cd_Cycling)
{
DisableCycling(cd);
ResetCycling(cd);
}
else
{
EnableCycling(cd);
}
}
}
else
{
error = ERROR_BREAK;
}
}
break;
case IDCMP_MOUSEBUTTONS:
if(message->Code == MENUDOWN)
{
error = ERR_ABORTED;
}
else
{
if(FLAG_IS_CLEAR(message->Code,IECODE_UP_PREFIX))
error = ERROR_BREAK;
}
break;
}
ReplyMsg((struct Message *)message);
}
return(error);
}
ERRORCODE
WaitForEvent(struct CycleData * cd)
{
ERRORCODE error;
ULONG signals;
do
{
error = OK;
signals = Wait(PORTMASK(Window->UserPort) | PORTMASK(TimePort) | SIGBREAKF_CTRL_C | SIGBREAKF_CTRL_F);
if(FLAG_IS_SET(signals,PORTMASK(Window->UserPort)))
{
error = ProcessWindowInput(Window,cd);
}
if(FLAG_IS_SET(signals,PORTMASK(TimePort)))
{
break;
}
if(FLAG_IS_SET(signals,SIGBREAKF_CTRL_C))
{
error = ERR_ABORTED;
}
if(FLAG_IS_SET(signals,SIGBREAKF_CTRL_F))
{
ScreenToFront(Screen);
}
}
while(error == OK);
return(error);
}
/******************************************************************************/
STATIC LONG __asm
AsyncStreamHandler(
register __a0 struct Hook * hook,
register __a2 struct IFFHandle * iff,
register __a1 struct IFFStreamCmd * actionpkt)
{
AsyncFile * stream;
LONG nbytes,error;
UBYTE * buf;
LONG a4 = getreg(REG_A4);
putreg(REG_A4,(LONG)hook->h_Data);
stream = (AsyncFile *)iff->iff_Stream;
nbytes = actionpkt->sc_NBytes;
buf = (UBYTE *)actionpkt->sc_Buf;
switch(actionpkt->sc_Command)
{
case IFFCMD_READ:
error = (ReadAsync(stream,buf,nbytes) != nbytes);
break;
case IFFCMD_SEEK:
error = (SeekAsync(stream,nbytes,MODE_CURRENT) == -1);
break;
default:
error = OK;
break;
}
putreg(REG_A4,a4);
return(error);
}
STATIC struct Hook AsyncStreamHook =
{
{NULL},
(HOOKFUNC)AsyncStreamHandler
};
/****************************************************************************/
VOID
CloseIFFFile(struct IFFHandle * iff)
{
if(iff != NULL)
{
CloseIFF(iff);
CloseAsync((AsyncFile *)iff->iff_Stream);
FreeIFF(iff);
}
}
struct IFFHandle *
OpenIFFFile(const STRPTR fileName)
{
struct IFFHandle * iff;
iff = AllocIFF();
if(iff != NULL)
{
iff->iff_Stream = (ULONG)OpenAsync((STRPTR)fileName,MODE_READ,8192);
if(iff->iff_Stream != NULL)
{
AsyncStreamHook.h_Data = (APTR)getreg(REG_A4);
InitIFF(iff,IFFF_FSEEK | IFFF_RSEEK,&AsyncStreamHook);
if(OpenIFF(iff,IFFF_READ) == OK)
return(iff);
CloseAsync((AsyncFile *)iff->iff_Stream);
}
FreeIFF(iff);
}
return(NULL);
}
/******************************************************************************/
LONG
ReadPlanes(struct IFFHandle * iff,struct BitMap * bitmap,LONG numPlanes)
{
LONG bytesPerRow = bitmap->BytesPerRow;
LONG status;
LONG i;
for(i = 0 ; i < numPlanes ; i++)
{
status = ReadChunkBytes(iff,bitmap->Planes[i],bytesPerRow);
if(status != bytesPerRow)
{
return(status);
}
}
return(OK);
}
/******************************************************************************/
struct IFFCache
{
struct IFFHandle * ic_Handle;
UBYTE ic_Data[4096];
UBYTE * ic_Index;
LONG ic_BytesLeft;
LONG ic_BytesInCache;
};
VOID
DeleteIFFCache(struct IFFCache * ic)
{
FreeVec(ic);
}
struct IFFCache *
CreateIFFCache(struct IFFHandle * iff,LONG bytesLeft)
{
struct IFFCache * ic;
ic = AllocVec(sizeof(*ic),MEMF_ANY);
if(ic != NULL)
{
ic->ic_Handle = iff;
ic->ic_Index = ic->ic_Data;
ic->ic_BytesLeft = bytesLeft;
ic->ic_BytesInCache = 0;
}
return(ic);
}
LONG
FillIFFCache(struct IFFCache * ic)
{
LONG bytesToRead;
LONG status = IFFERR_EOF;
bytesToRead = min(ic->ic_BytesLeft,sizeof(ic->ic_Data));
if(bytesToRead > 0)
{
status = ReadChunkBytes(ic->ic_Handle,ic->ic_Data,bytesToRead);
if(status == bytesToRead)
{
status = OK;
ic->ic_Index = ic->ic_Data;
ic->ic_BytesInCache = bytesToRead;
ic->ic_BytesLeft -= bytesToRead;
}
}
return(status);
}
LONG
GetIFFCache(struct IFFCache * ic,UBYTE * c)
{
if(ic->ic_BytesInCache == 0)
{
LONG result;
result = FillIFFCache(ic);
if(result != OK)
{
return(result);
}
}
(*c) = (*ic->ic_Index++);
ic->ic_BytesInCache--;
return(OK);
}
LONG
ReadIFFCache(struct IFFCache * ic,APTR mem,LONG bytesToRead)
{
UBYTE * data = mem;
LONG bytesRead = 0;
LONG numBytes;
while(bytesToRead > 0)
{
if(ic->ic_BytesInCache == 0)
{
LONG result;
result = FillIFFCache(ic);
if(result != OK)
{
return(result);
}
}
numBytes = min(bytesToRead,ic->ic_BytesInCache);
memcpy(data,ic->ic_Index,numBytes);
ic->ic_Index += numBytes;
ic->ic_BytesInCache -= numBytes;
bytesToRead -= numBytes;
bytesRead += numBytes;
data += numBytes;
}
return(bytesRead);
}
/******************************************************************************/
LONG
ReadByteRun1Planes(struct IFFCache * ic,struct BitMap * bitmap,LONG numPlanes)
{
LONG status;
PLANEPTR plane;
LONG count,bytesNeeded,i;
BYTE value;
for(i = 0 ; i < numPlanes ; i++)
{
bytesNeeded = bitmap->BytesPerRow;
plane = bitmap->Planes[i];
while(bytesNeeded > 0)
{
status = GetIFFCache(ic,(UBYTE *)&value);
if(status != OK)
{
return(status);
}
if(value == -128)
{
}
else if (value >= 0)
{
count = ((LONG)value) + 1;
bytesNeeded -= count;
if(bytesNeeded < 0)
{
return(IFFERR_EOF);
}
status = ReadIFFCache(ic,plane,count);
if(status != count)
{
return(status);
}
plane += count;
}
else
{
UBYTE c;
count = ((LONG)-value) + 1;
bytesNeeded -= count;
if(bytesNeeded < 0)
{
return(IFFERR_EOF);
}
status = GetIFFCache(ic,(UBYTE *)&c);
if(status != OK)
{
return(status);
}
while(--count >= 0)
(*plane++) = c;
}
}
}
return(OK);
}
/******************************************************************************/
ERRORCODE
ShowILBM(STRPTR fileName)
{
STATIC LONG Stops[] =
{
ID_ILBM,ID_BMHD,
ID_ILBM,ID_CMAP,
ID_ILBM,ID_CAMG,
ID_ILBM,ID_BODY,
ID_ILBM,ID_CCRT,
ID_ILBM,ID_CRNG
};
enum
{
HAVE_Nothing = 0,
HAVE_BitMapHeader = 1,
HAVE_ColorMap = 2,
HAVE_CAMG = 4,
HAVE_Body = 8
};
struct ContextNode * cn;
ERRORCODE error = OK;
struct IFFHandle * iff;
LONG status;
LONG have;
struct BitMapHeader bmh;
ULONG viewModes;
UBYTE * palette;
LONG paletteSize;
struct BitPlaneData * bpd;
struct IFFCache * ic;
BOOL doubleVertical;
BOOL doubleHorizontal;
LONG verticalScale;
LONG horizontalScale;
LONG numCycleRanges;
struct CRange cycleRanges[8];
struct CycleInfo cycleInfo;
struct CycleData * cd;
LONG depth;
BOOL done;
LONG darkest;
memset(&bmh,0,sizeof(bmh));
viewModes = 0;
palette = NULL;
paletteSize = 0;
have = HAVE_Nothing;
bpd = NULL;
ic = NULL;
numCycleRanges = 0;
cd = NULL;
depth = 0;
memset(cycleRanges,0,sizeof(cycleRanges));
iff = OpenIFFFile(fileName);
if(iff == NULL)
{
error = IoErr();
goto cleanup;
}
status = StopChunks(iff,Stops,NUM_ENTRIES(Stops)/2);
if(status != OK)
{
error = ERR_IFF_BASE - status;
goto cleanup;
}
done = FALSE;
while(NOT done && (status = ParseIFF(iff,IFFPARSE_SCAN)) == OK)
{
cn = CurrentChunk(iff);
switch(cn->cn_ID)
{
case ID_BMHD:
status = ReadChunkBytes(iff,&bmh,sizeof(bmh));
if(status != sizeof(bmh))
{
error = ERR_IFF_BASE - status;
goto cleanup;
}
SET_FLAG(have,HAVE_BitMapHeader);
break;
case ID_CMAP:
paletteSize = cn->cn_Size / 3;
FreeVec(palette);
palette = AllocVec(256 * 3,MEMF_ANY|MEMF_CLEAR|MEMF_PUBLIC);
if(palette == NULL)
{
error = ERROR_NO_FREE_STORE;
goto cleanup;
}
status = ReadChunkBytes(iff,palette,paletteSize * 3);
if(status != paletteSize * 3)
{
error = ERR_IFF_BASE - status;
goto cleanup;
}
SET_FLAG(have,HAVE_ColorMap);
break;
case ID_CAMG:
status = ReadChunkBytes(iff,&viewModes,sizeof(viewModes));
if(status != sizeof(viewModes))
{
error = ERR_IFF_BASE - status;
goto cleanup;
}
SET_FLAG(have,HAVE_CAMG);
if(FLAG_IS_CLEAR(viewModes,MONITOR_ID_MASK) || (FLAG_IS_SET(viewModes,EXTENDED_MODE) && FLAG_IS_CLEAR(viewModes,0xFFFF0000)))
{
CLEAR_FLAG(viewModes,EXTENDED_MODE|SPRITES|GENLOCK_AUDIO|GENLOCK_VIDEO|VP_HIDE);
}
if(FLAG_IS_SET(viewModes,0xFFFF0000) && FLAG_IS_CLEAR(viewModes,0x00001000))
{
CLEAR_FLAG(have,HAVE_CAMG);
}
break;
case ID_CRNG:
if(numCycleRanges < NUM_ENTRIES(cycleRanges))
{
status = ReadChunkBytes(iff,&cycleRanges[numCycleRanges],sizeof(struct CRange));
if(status != sizeof(struct CRange))
{
error = ERR_IFF_BASE - status;
goto cleanup;
}
numCycleRanges++;
}
break;
case ID_CCRT:
if(numCycleRanges < NUM_ENTRIES(cycleRanges))
{
status = ReadChunkBytes(iff,&cycleInfo,sizeof(cycleInfo));
if(status != sizeof(cycleInfo))
{
error = ERR_IFF_BASE - status;
goto cleanup;
}
cycleRanges[numCycleRanges].rate = 16384 / (cycleInfo.seconds * 60 + (cycleInfo.microseconds + 8334) / 16667);
cycleRanges[numCycleRanges].active = -cycleInfo.direction;
cycleRanges[numCycleRanges].low = cycleInfo.start;
cycleRanges[numCycleRanges].high = cycleInfo.end;
numCycleRanges++;
}
break;
case ID_BODY:
if(FLAG_IS_SET(have,HAVE_BitMapHeader))
{
SET_FLAG(have,HAVE_Body);
if(FLAG_IS_CLEAR(have,HAVE_CAMG))
{
if(bmh.bmh_Width >= 640)
SET_FLAG(viewModes,HIRES);
if(bmh.bmh_Height >= 400)
SET_FLAG(viewModes,LACE);
if(bmh.bmh_Depth == 6)
{
if(PrefEHB && NOT PrefHAM)
SET_FLAG(viewModes,EXTRA_HALFBRITE);
else
SET_FLAG(viewModes,HAM);
}
}
if(FLAG_IS_SET(viewModes,HIRES) && FLAG_IS_CLEAR(viewModes,LACE))
{
doubleVertical = TRUE;
verticalScale = 2;
}
else
{
doubleVertical = FALSE;
verticalScale = 1;
}
if(FLAG_IS_CLEAR(viewModes,HIRES) && FLAG_IS_SET(viewModes,LACE))
{
doubleHorizontal = TRUE;
horizontalScale = 2;
}
else
{
doubleHorizontal = FALSE;
horizontalScale = 1;
}
darkest = 0;
if(bmh.bmh_Depth <= 8 && FLAG_IS_CLEAR(viewModes,HAM))
{
LONG darkestValue;
LONG value;
LONG i;
darkestValue = BRIGHTNESS(palette[0],palette[1],palette[2]);
for(i = 1 ; i < paletteSize ; i++)
{
value = BRIGHTNESS(palette[3 * i + 0],palette[3 * i + 1],palette[3 * i + 2]);
if(value < darkestValue)
{
darkest = i;
darkestValue = value;
}
}
}
if(FLAG_IS_SET(viewModes,EXTRA_HALFBRITE) && bmh.bmh_Depth == 6)
{
UBYTE * from;
UBYTE * to;
LONG i;
from = &palette[ 0 * 3];
to = &palette[32 * 3];
for(i = 0 ; i < 32 ; i++)
{
(*to++) = (*from++) / 2;
(*to++) = (*from++) / 2;
(*to++) = (*from++) / 2;
}
paletteSize *= 2;
}
if(bmh.bmh_Depth <= 8)
{
depth = 8;
if(FLAG_IS_SET(viewModes,HAM))
depth = 24;
}
else
{
depth = 24;
}
bpd = CreateBitPlaneData(&bmh,viewModes);
if(bpd == NULL)
{
error = ERROR_NO_FREE_STORE;
goto cleanup;
}
if(PrefCenter && Screen != NULL)
{
if((bmh.bmh_PageWidth * horizontalScale) > Screen->Width || (bmh.bmh_PageHeight * verticalScale) > Screen->Height || depth != DisplayDepth)
CloseDisplay();
}
if(Screen != NULL)
{
SetRast(Window->RPort,darkest);
SetWindowPointer(Window,
WA_BusyPointer,TRUE,
TAG_DONE);
if(depth <= 8)
LoadRGB32(&Screen->ViewPort,SetupPalette(palette,paletteSize));
}
else
{
error = OpenDisplay(bmh.bmh_PageWidth * horizontalScale,bmh.bmh_PageHeight * verticalScale,depth,darkest,palette,paletteSize);
}
if(error == OK)
{
LONG LeftEdge,TopEdge,i;
LONG numPlanes;
if(bmh.bmh_Masking == mskHasMask)
{
numPlanes = bmh.bmh_Depth + 1;
}
else
{
numPlanes = bmh.bmh_Depth;
}
if(PrefCenter)
{
LeftEdge = (Screen->Width - (bmh.bmh_Width * horizontalScale)) / 2;
if(LeftEdge < 0)
LeftEdge = 0;
TopEdge = (Screen->Height - (bmh.bmh_Height * verticalScale)) / 2;
if(TopEdge < 0)
TopEdge = 0;
}
else
{
LeftEdge = bmh.bmh_Left;
TopEdge = bmh.bmh_Top;
}
if(bmh.bmh_Compression == cmpByteRun1)
{
ic = CreateIFFCache(iff,cn->cn_Size);
if(ic == NULL)
{
error = ERROR_NO_FREE_STORE;
goto cleanup;
}
for(i = 0 ; i < bmh.bmh_Height ; i++)
{
if(CheckSignal(SIGBREAKF_CTRL_C))
{
error = ERR_ABORTED;
break;
}
if(Window != NULL)
{
error = ProcessWindowInput(Window,NULL);
if(error != OK)
{
break;
}
}
status = ReadByteRun1Planes(ic,&bpd->bpd_Planes,numPlanes);
if(status != OK)
{
break;
}
if(doubleVertical)
{
PutLine(LeftEdge,TopEdge+2*i,doubleHorizontal,bpd,palette,viewModes);
PutLine(LeftEdge,TopEdge+2*i+1,doubleHorizontal,bpd,palette,viewModes);
}
else
{
PutLine(LeftEdge,TopEdge+i,doubleHorizontal,bpd,palette,viewModes);
}
}
}
else if (bmh.bmh_Compression == cmpNone)
{
for(i = 0 ; i < bmh.bmh_Height ; i++)
{
if(CheckSignal(SIGBREAKF_CTRL_C))
{
error = ERR_ABORTED;
break;
}
if(Window != NULL)
{
error = ProcessWindowInput(Window,NULL);
if(error != OK)
{
break;
}
}
status = ReadPlanes(iff,&bpd->bpd_Planes,numPlanes);
if(status != OK)
{
break;
}
if(doubleVertical)
{
PutLine(LeftEdge,TopEdge+2*i,doubleHorizontal,bpd,palette,viewModes);
PutLine(LeftEdge,TopEdge+2*i+1,doubleHorizontal,bpd,palette,viewModes);
}
else
{
PutLine(LeftEdge,TopEdge+i,doubleHorizontal,bpd,palette,viewModes);
}
}
}
else
{
error = ERR_UNKNOWN_COMPRESSION;
goto cleanup;
}
done = TRUE;
}
}
break;
}
if(cn->cn_Type != ID_ILBM)
{
error = ERR_NOT_IFF_ILBM;
break;
}
}
if(error == OK && status != OK)
{
if(status == IFFERR_EOF)
error = OK;
else
error = ERR_IFF_BASE - status;
}
if(error == OK && FLAG_IS_CLEAR(have,HAVE_Body))
{
error = ERR_NOT_IFF_ILBM;
}
if(error == OK && Window != NULL)
{
SetWindowPointer(Window,
WA_Pointer,TransparentPointer,
TAG_DONE);
if(PrefWait > 0)
StartTimer(PrefWait,0);
if(depth <= 8 && numCycleRanges > 0)
{
cd = CreateCycleData(Screen,(BOOL)(FLAG_IS_SET(viewModes,EXTRA_HALFBRITE) && bmh.bmh_Depth == 6),cycleRanges,palette,paletteSize);
if(PrefCycle)
EnableCycling(cd);
}
error = WaitForEvent(cd);
if(error == ERROR_BREAK)
error = OK;
StopTimer();
if(NOT PrefCenter)
{
DeleteCycleData(cd);
cd = NULL;
CloseDisplay();
}
}
cleanup:
DeleteCycleData(cd);
DeleteIFFCache(ic);
CloseIFFFile(iff);
DeleteBitPlaneData(bpd);
FreeVec(palette);
return(error);
}
/******************************************************************************/
STATIC VOID
CycleTask(VOID)
{
struct Library * SysBase = *(struct Library **)4;
struct Task * task = FindTask(NULL);
struct CycleData * cd = task->tc_UserData;
struct MsgPort * port;
struct timerequest * tr;
putreg(REG_A4,cd->cd_A4);
port = CreateMsgPort();
if(port != NULL)
{
tr = (struct timerequest *)CreateIORequest(port,sizeof(*tr));
if(tr != NULL)
{
if(OpenDevice(TIMERNAME,UNIT_VBLANK,(struct IORequest *)tr,0) == OK)
{
ULONG timerMask = (1UL << port->mp_SigBit);
BOOL ticking = FALSE;
BOOL start = FALSE;
ULONG signals;
BOOL reload;
LONG i;
cd->cd_Task = task;
Signal(cd->cd_Parent,SIGF_SINGLE);
FOREVER
{
signals = Wait(timerMask | SIGBREAKF_CTRL_C | SIGBREAKF_CTRL_D | SIGBREAKF_CTRL_E | SIGBREAKF_CTRL_F);
if(FLAG_IS_SET(signals,SIGBREAKF_CTRL_C))
break;
if(FLAG_IS_SET(signals,SIGBREAKF_CTRL_D))
{
cd->cd_Cycling = FALSE;
Signal(cd->cd_Parent,SIGF_SINGLE);
}
if(FLAG_IS_SET(signals,SIGBREAKF_CTRL_E))
{
cd->cd_Cycling = start = TRUE;
Signal(cd->cd_Parent,SIGF_SINGLE);
}
reload = FALSE;
if(FLAG_IS_SET(signals,timerMask) || start)
{
start = FALSE;
if(ticking)
{
WaitIO((struct IORequest *)tr);
ticking = FALSE;
}
if(cd->cd_Cycling)
{
for(i = 0 ; i < NUM_ENTRIES(cd->cd_Ranges) ; i++)
{
if(cd->cd_Ranges[i].active != 0)
{
cd->cd_Ranges[i].counter += cd->cd_Ranges[i].rate;
if(cd->cd_Ranges[i].counter >= 16384)
{
struct ColorRegister t;
LONG j;
cd->cd_Ranges[i].counter = 0;
if(cd->cd_Ranges[i].active > 0)
{
t = cd->cd_CurrentPalette[cd->cd_Ranges[i].high];
for(j = cd->cd_Ranges[i].high ; j > cd->cd_Ranges[i].low ; j--)
cd->cd_CurrentPalette[j] = cd->cd_CurrentPalette[j-1];
cd->cd_CurrentPalette[cd->cd_Ranges[i].low] = t;
if(cd->cd_IsEHB)
{
t = cd->cd_CurrentPalette[cd->cd_Ranges[i].high + 31];
for(j = cd->cd_Ranges[i].high + 31 ; j > cd->cd_Ranges[i].low + 31 ; j--)
cd->cd_CurrentPalette[j] = cd->cd_CurrentPalette[j-1];
cd->cd_CurrentPalette[cd->cd_Ranges[i].low + 31] = t;
}
}
else
{
t = cd->cd_CurrentPalette[cd->cd_Ranges[i].low];
for(j = cd->cd_Ranges[i].low ; j < cd->cd_Ranges[i].high ; j++)
cd->cd_CurrentPalette[j] = cd->cd_CurrentPalette[j+1];
cd->cd_CurrentPalette[cd->cd_Ranges[i].high] = t;
if(cd->cd_IsEHB)
{
t = cd->cd_CurrentPalette[cd->cd_Ranges[i].low + 31];
for(j = cd->cd_Ranges[i].low + 31 ; j < cd->cd_Ranges[i].high + 31 ; j++)
cd->cd_CurrentPalette[j] = cd->cd_CurrentPalette[j+1];
cd->cd_CurrentPalette[cd->cd_Ranges[i].high + 31] = t;
}
}
reload = TRUE;
}
}
}
tr->tr_node.io_Command = TR_ADDREQUEST;
tr->tr_time.tv_secs = 0;
tr->tr_time.tv_micro = MILLION / 60;
SetSignal(0,timerMask);
SendIO((struct IORequest *)tr);
ticking = TRUE;
}
}
if(signals & SIGBREAKF_CTRL_F)
{
LONG i;
memcpy(cd->cd_CurrentPalette,cd->cd_OriginalPalette,sizeof(struct ColorRegister) * cd->cd_PaletteSize);
for(i = 0 ; i < NUM_ENTRIES(cd->cd_Ranges) ; i++)
cd->cd_Ranges[i].counter = 0;
reload = TRUE;
Signal(cd->cd_Parent,SIGF_SINGLE);
}
if(reload)
LoadRGB32(&cd->cd_Screen->ViewPort,SetupPalette((UBYTE *)cd->cd_CurrentPalette,cd->cd_PaletteSize));
}
if(ticking)
{
if(CheckIO((struct IORequest *)tr) == BUSY)
AbortIO((struct IORequest *)tr);
WaitIO((struct IORequest *)tr);
}
CloseDevice((struct IORequest *)tr);
}
DeleteIORequest((struct IORequest *)tr);
}
DeleteMsgPort(port);
}
Forbid();
cd->cd_Task = NULL;
if(cd->cd_Parent != NULL)
Signal(cd->cd_Parent,SIGF_SINGLE);
}
/******************************************************************************/
VOID
DisableCycling(struct CycleData * cd)
{
if(cd != NULL)
{
SetSignal(0,SIGF_SINGLE);
Signal(cd->cd_Task,SIGBREAKF_CTRL_D);
Wait(SIGF_SINGLE);
}
}
VOID
EnableCycling(struct CycleData * cd)
{
if(cd != NULL)
{
SetSignal(0,SIGF_SINGLE);
Signal(cd->cd_Task,SIGBREAKF_CTRL_E);
Wait(SIGF_SINGLE);
}
}
VOID
ResetCycling(struct CycleData * cd)
{
if(cd != NULL)
{
SetSignal(0,SIGF_SINGLE);
Signal(cd->cd_Task,SIGBREAKF_CTRL_F);
Wait(SIGF_SINGLE);
}
}
VOID
DeleteCycleData(struct CycleData * cd)
{
if(cd != NULL)
{
if(cd->cd_Task != NULL)
{
Forbid();
Signal(cd->cd_Task,SIGBREAKF_CTRL_C);
SetSignal(0,SIGF_SINGLE);
Wait(SIGF_SINGLE);
Permit();
}
FreeVec(cd);
}
}
struct CycleData *
CreateCycleData(struct Screen * screen,BOOL isEHB,struct CRange * ranges,UBYTE * palette,LONG paletteSize)
{
struct CycleData * result = NULL;
struct CycleData * cd;
cd = AllocVec(sizeof(*cd) + 2 * paletteSize * sizeof(struct ColorRegister),MEMF_ANY|MEMF_PUBLIC|MEMF_CLEAR);
if(cd != NULL)
{
struct Task * task;
LONG numActive;
LONG i;
cd->cd_A4 = getreg(REG_A4);
cd->cd_Parent = (struct Task *)FindTask(NULL);
cd->cd_Screen = screen;
cd->cd_PaletteSize = paletteSize;
cd->cd_IsEHB = isEHB;
memcpy(cd->cd_Ranges,ranges,sizeof(cd->cd_Ranges));
numActive = 0;
for(i = 0 ; i < NUM_ENTRIES(cd->cd_Ranges) ; i++)
{
cd->cd_Ranges[i].counter = 0;
if(cd->cd_Ranges[i].rate <= 36 || cd->cd_Ranges[i].low >= cd->cd_Ranges[i].high)
cd->cd_Ranges[i].active = 0;
if(cd->cd_Ranges[i].active != 0)
numActive++;
}
if(numActive > 0)
{
cd->cd_OriginalPalette = (struct ColorRegister *)(cd + 1);
cd->cd_CurrentPalette = cd->cd_OriginalPalette + paletteSize;
memcpy(cd->cd_OriginalPalette,palette,sizeof(struct ColorRegister) * paletteSize);
memcpy(cd->cd_CurrentPalette,palette,sizeof(struct ColorRegister) * paletteSize);
Forbid();
task = CreateTask("Cycle Task",0,(APTR)CycleTask,8192);
task->tc_UserData = cd;
SetSignal(0,SIGF_SINGLE);
Wait(SIGF_SINGLE);
Permit();
if(cd->cd_Task != NULL)
result = cd;
}
}
if(result == NULL)
DeleteCycleData(cd);
return(result);
}
/******************************************************************************/
VOID
IconCheck(struct DiskObject *Icon)
{
STRPTR String;
if(String = FindToolType(Icon->do_ToolTypes,"CENTER"))
{
if(MatchToolValue(String,"ON") || MatchToolValue(String,"YES"))
PrefCenter = TRUE;
if(MatchToolValue(String,"OFF") || MatchToolValue(String,"NO"))
PrefCenter = FALSE;
}
if(String = FindToolType(Icon->do_ToolTypes,"CYCLE"))
{
if(MatchToolValue(String,"ON") || MatchToolValue(String,"YES"))
PrefCycle = TRUE;
if(MatchToolValue(String,"OFF") || MatchToolValue(String,"NO"))
PrefCycle = FALSE;
}
if(String = FindToolType(Icon->do_ToolTypes,"HAM"))
{
if(MatchToolValue(String,"ON") || MatchToolValue(String,"YES"))
PrefHAM = TRUE;
if(MatchToolValue(String,"OFF") || MatchToolValue(String,"NO"))
PrefHAM = FALSE;
}
if(String = FindToolType(Icon->do_ToolTypes,"EHB"))
{
if(MatchToolValue(String,"ON") || MatchToolValue(String,"YES"))
PrefEHB = TRUE;
if(MatchToolValue(String,"OFF") || MatchToolValue(String,"NO"))
PrefEHB = FALSE;
}
if(String = FindToolType(Icon->do_ToolTypes,"WAIT"))
{
LONG Value;
if(StrToLong(String,&Value) > 0)
{
if(Value > 0)
PrefWait = Value;
else
PrefWait = 0;
}
else
{
PrefWait = 0;
}
}
if(String = FindToolType(Icon->do_ToolTypes,"WAITAFTEROPEN"))
{
LONG Value;
if(StrToLong(String,&Value) > 0)
{
if(Value > 0)
PrefWaitAfterOpen = Value;
else
PrefWaitAfterOpen = 0;
}
else
{
PrefWaitAfterOpen = 0;
}
}
}
/******************************************************************************/
VOID
CloseAll(VOID)
{
CloseDisplay();
StopTimer();
if(TimeRequest != NULL)
{
if(TimeRequest->tr_node.io_Device != NULL)
CloseDevice(TimeRequest);
DeleteIORequest(TimeRequest);
TimeRequest = NULL;
}
if(TimePort != NULL)
{
DeleteMsgPort(TimePort);
TimePort = NULL;
}
if(CyberGfxBase != NULL)
{
CloseLibrary(CyberGfxBase);
CyberGfxBase = NULL;
}
if(IFFParseBase != NULL)
{
CloseLibrary(IFFParseBase);
IFFParseBase = NULL;
}
if(AslBase != NULL)
{
CloseLibrary(AslBase);
AslBase = NULL;
}
if(IconBase != NULL)
{
CloseLibrary(IconBase);
IconBase = NULL;
}
if(UtilityBase != NULL)
{
CloseLibrary(UtilityBase);
UtilityBase = NULL;
}
if(GfxBase != NULL)
{
CloseLibrary(GfxBase);
GfxBase = NULL;
}
if(IntuitionBase != NULL)
{
CloseLibrary(IntuitionBase);
IntuitionBase = NULL;
}
}
ERRORCODE
OpenAll(VOID)
{
IntuitionBase = OpenLibrary("intuition.library",39);
if(IntuitionBase == NULL)
return(ERR_NO_INTUITION);
GfxBase = OpenLibrary("graphics.library",39);
if(GfxBase == NULL)
return(ERR_NO_GRAPHICS);
UtilityBase = OpenLibrary("utility.library",37);
if(UtilityBase == NULL)
return(ERR_NO_UTILITY);
IFFParseBase = OpenLibrary("iffparse.library",40);
if(IFFParseBase == NULL)
return(ERR_NO_IFFPARSE);
CyberGfxBase = OpenLibrary("cybergraphics.library",40);
if(CyberGfxBase == NULL)
return(ERR_NO_CYBERGFX);
IconBase = OpenLibrary("icon.library",37);
if(IconBase == NULL)
return(ERR_NO_ICON);
AslBase = OpenLibrary("asl.library",37);
if(AslBase == NULL)
return(ERR_NO_ASL);
TimePort = CreateMsgPort();
if(TimePort == NULL)
return(ERR_NO_PORT);
TimeRequest = (struct timerequest *)CreateIORequest(TimePort,sizeof(struct timerequest));
if(TimeRequest == NULL)
return(ERR_NO_REQUEST);
if(OpenDevice(TIMERNAME,UNIT_VBLANK,TimeRequest,NULL) != OK)
return(ERR_NO_TIMER);
return(OK);
}
/******************************************************************************/
int
main(int argc,char **argv)
{
int result = RETURN_FAIL;
if(DOSBase->lib_Version >= 37)
{
ERRORCODE error;
error = OpenAll();
if(error == OK)
{
if(argc > 0)
{
struct
{
KEYWORD * Files;
SWITCH Center;
NUMBER Wait;
SWITCH Quiet;
SWITCH All;
NUMBER WaitAfterOpen;
SWITCH Cycle;
SWITCH UseHAM;
SWITCH UseEHB;
} args;
struct RDArgs * rda;
memset(&args,0,sizeof(args));
rda = ReadArgs("FILES/M/A,"
"C=CENTER/S,"
"W=WAIT/K/N,"
"Q=QUIET/S,"
"A=ALL/S,"
"WAO=WAITAFTEROPEN/K/N,"
"CYCLE/S,"
"HAM/S,"
"EHB/S",
(LONG *)&args,NULL);
if(rda)
{
STRPTR * files = (STRPTR *)args.Files;
struct AnchorPath * ap;
if(args.Wait != NULL)
{
if((*args.Wait) > 0)
PrefWait = (*args.Wait);
}
if(args.WaitAfterOpen != NULL)
{
if((*args.WaitAfterOpen) > 0)
PrefWaitAfterOpen = (*args.WaitAfterOpen);
}
if(args.Center)
PrefCenter = TRUE;
if(args.Quiet)
PrefQuiet = TRUE;
if(args.Cycle)
PrefCycle = TRUE;
if(args.UseHAM)
PrefHAM = TRUE;
if(args.UseEHB)
PrefEHB = TRUE;
result = RETURN_OK;
ap = (struct AnchorPath *)AllocVec(sizeof(*ap) + MAX_PATHNAME_LEN,MEMF_ANY);
if(ap != NULL)
{
BOOL errorPrinted = FALSE;
while((*files) != NULL && error == OK)
{
memset(ap,0,sizeof(*ap) + MAX_PATHNAME_LEN);
ap->ap_Strlen = MAX_PATHNAME_LEN;
ap->ap_BreakBits = SIGBREAKF_CTRL_C;
error = MatchFirst((*files++),ap);
if(error == OK && ap->ap_Info.fib_DirEntryType > 0)
{
SET_FLAG(ap->ap_Flags,APF_DODIR);
}
while(error == OK)
{
if(ap->ap_Info.fib_DirEntryType < 0 && ap->ap_Info.fib_Size > 0)
{
if(NOT PrefQuiet)
{
Printf("Showing \"%s\"... ",ap->ap_Buf);
Flush(Output());
}
error = ShowILBM(ap->ap_Buf);
if(NOT PrefQuiet)
{
switch(error)
{
case OK:
Printf("Done.\n");
break;
case ERROR_BREAK:
PrintErrorString(ERROR_BREAK,NULL);
error = OK;
break;
case ERR_ABORTED:
PrintErrorString(ERROR_BREAK,NULL);
error = ERROR_BREAK;
break;
default:
PrintErrorString(error,NULL);
error = OK;
break;
}
if(error != OK)
errorPrinted = TRUE;
}
}
if(args.All && ap->ap_Info.fib_DirEntryType > 0)
{
if(FLAG_IS_SET(ap->ap_Flags,APF_DIDDIR))
CLEAR_FLAG(ap->ap_Flags,APF_DIDDIR);
else
SET_FLAG(ap->ap_Flags,APF_DODIR);
}
if(error == OK)
error = MatchNext(ap);
}
MatchEnd(ap);
}
if((error == ERROR_NO_MORE_ENTRIES) || (error != OK && errorPrinted))
error = OK;
FreeVec(ap);
}
else
{
error = ERROR_NO_FREE_STORE;
}
if(error != OK)
PrintErrorString(error,"ViewILBM");
FreeArgs(rda);
}
else
{
PrintErrorString(IoErr(),"ViewILBM");
result = RETURN_ERROR;
}
}
else
{
struct WBStartup * WBenchMsg = (struct WBStartup *)argv;
if(WBenchMsg->sm_NumArgs > 0)
{
struct DiskObject * Icon;
BPTR OldDir;
LONG i;
result = RETURN_OK;
Icon = GetDiskObject(WBenchMsg->sm_ArgList[0].wa_Name);
if(Icon != NULL)
{
IconCheck(Icon);
FreeDiskObject(Icon);
}
if(WBenchMsg->sm_NumArgs > 1)
{
for(i = 1 ; error == OK && i < WBenchMsg->sm_NumArgs ; i++)
{
OldDir = CurrentDir(WBenchMsg->sm_ArgList[i].wa_Lock);
Icon = GetDiskObject(WBenchMsg->sm_ArgList[i].wa_Name);
if(Icon != NULL)
{
IconCheck(Icon);
FreeDiskObject(Icon);
}
error = ShowILBM(WBenchMsg->sm_ArgList[i].wa_Name);
if(error != ERR_ABORTED)
error = OK;
CurrentDir(OldDir);
}
}
else
{
struct FileRequester *FileRequest;
FileRequest = (struct FileRequester *)AllocAslRequestTags(ASL_FileRequest,
ASL_Hail, "Load which file?",
ASL_OKText, "Load",
ASL_FuncFlags, FILF_PATGAD | FILF_MULTISELECT,
TAG_DONE);
if(FileRequest != NULL)
{
while(AslRequestTags(FileRequest, ASLFR_RejectIcons,TRUE, TAG_DONE) && FileRequest->fr_NumArgs > 0)
{
for(i = 0 ; error == OK && i < FileRequest->fr_NumArgs ; i++)
{
OldDir = CurrentDir(FileRequest->fr_ArgList[i].wa_Lock);
Icon = GetDiskObject(FileRequest->fr_ArgList[i].wa_Name);
if(Icon != NULL)
{
IconCheck(Icon);
FreeDiskObject(Icon);
}
error = ShowILBM(FileRequest->fr_ArgList[i].wa_Name);
if(error != ERR_ABORTED)
error = OK;
CurrentDir(OldDir);
}
}
FreeAslRequest(FileRequest);
}
}
}
}
}
else
{
PrintErrorString(error,"ViewILBM");
}
CloseAll();
}
return(result);
}