MAG Disk (Jun 1989) : loadpic.c

/*
 * loadpic.c - ILBM loader which runs from the workbench
 *
 * Written by Jonathan Hue - if you decide to steal some of this
 * code (yeah, like anyone would want to), give me credit.
 */
#include <exec/types.h>
#include <workbench/startup.h>
#include <intuition/intuition.h>
#include <graphics/gfxmacros.h>
#include <graphics/view.h>
#include <graphics/gfxbase.h>
#include <graphics/gfx.h>
#include <libraries/dosextens.h>
#include <stdio.h>
#include "types.h"
#include "ilbm.h"

extern struct WBStartup *WBenchMsg;
void LoadPic(), ChkRead(), ErrExit(), cleanup(), ReadPic();
int WaitForMouseClick();
struct IntuitionBase *IntuitionBase;
struct GfxBase *GfxBase;
extern struct ColorMap *GetColorMap();
extern struct FileLock *Lock(), *CurrentDir();
extern struct Window *OpenWindow();

struct View v;
struct ViewPort vp;
struct ColorMap *cm;
struct BitMap b;
BitMapHeader bm;

short WinWidth, WinHeight;	/* Trust me, you don't want to know what */
struct Preferences prefs;	/* I want these for...			 */

main(argc, argv)
int argc;
char **argv;
{
    struct WBArg *arg;
    struct FileLock *lock, *olddir;
    register int i;

    if ((GfxBase = (struct GfxBase *) OpenLibrary("graphics.library", 0)) ==
		   NULL)
	ErrExit("Couldn't open graphics library");
    if ((IntuitionBase = (struct IntuitionBase *)
			 OpenLibrary("intuition.library", 0)) == NULL)
	ErrExit("Couldn't open graphics library");

    WinWidth = GfxBase->NormalDisplayColumns;
    WinHeight = GfxBase->NormalDisplayRows;
    GetPrefs(&prefs, sizeof(prefs));
    puts("Press Left Mouse Button to Exit");
    fflush(stdout);			/* stdout should be line buffered */
    if (argc > 0)
    {
	while (--argc)
	    LoadPic(*++argv);
    }
    else
    {
	for (i = 1, arg = WBenchMsg->sm_ArgList; i < WBenchMsg->sm_NumArgs;
	     i++)
	{
	    ++arg;
	    if (arg->wa_Lock == NULL)
		continue;
	    olddir = CurrentDir(arg->wa_Lock);
	    if ((lock = Lock(arg->wa_Name, SHARED_LOCK)) == NULL)
	    {
		CurrentDir(olddir);
		continue;
	    }
	    LoadPic(arg->wa_Name);
	    UnLock(lock);
	    CurrentDir(olddir);
	}
    }
    cleanup();
}


void
LoadPic(PicName)
char *PicName;
{
    register FILE *fp;
    u_long form, ilbm, id, nbytes, ViewMode = 0;
    register short i;
    register u_short *ColorMapPtr, ColorValue;
    short GotBody = 0, GotHdr = 0, plane;
    struct View *oldview;
    struct RasInfo ri;
	
    if ((fp = fopen(PicName, "r")) == NULL)
    {
	fprintf(stderr, "Couldn't open %s\n", PicName);
	    return;
    }
    ChkRead(fp, &form, sizeof(form));
    fseek(fp, 4L, 1);
    ChkRead(fp, &ilbm, sizeof(ilbm));
    if ((form != ID_FORM) || (ilbm != ID_ILBM))
	ErrExit("Sorry, I can't read this file");
    while (1)
    {
	ChkRead(fp, &id, sizeof(id));
	ChkRead(fp, &nbytes, sizeof(nbytes));
	switch(id)
	{
	    case ID_BMHD:
		GotHdr++;
		if (nbytes != sizeof(bm))
		    ErrExit("Short header length");
		ChkRead(fp, &bm, sizeof(bm));
		break;
	    case ID_CMAP:
		cm = GetColorMap(nbytes / 3);
		ColorMapPtr = (u_short *) cm->ColorTable;
		for (i = 0; i < nbytes / 3; i++)
		{
		    ColorValue = (getc(fp) >> 4) << 8;
		    ColorValue |= (getc(fp) >> 4) << 4;
		    ColorValue |= (getc(fp) >> 4);
		    *ColorMapPtr++ = ColorValue;
		}
		if (nbytes & 1)
		    getc(fp);
		break;
	    case ID_CAMG:
		ChkRead(fp, &ViewMode, sizeof(ViewMode));
		break;
	    case ID_BODY:
		if (!GotHdr)
		    ErrExit("Found BODY before BMHD!!!");
		GotBody = 1;
		break;
	    case ID_GRAB:
	    case ID_DEST:
	    default:
		fseek(fp, nbytes, 1);
		break;
	}
	if (GotBody)
	    break;
    }
    oldview = GfxBase->ActiView;
    InitView(&v);
    InitVPort(&vp);
    v.ViewPort = &vp;
    InitBitMap(&b, bm.bm_numplanes, bm.bm_width, bm.bm_height);
    ri.BitMap = &b;
    ri.RxOffset = 0;
    ri.RyOffset = 0;
    vp.DWidth = bm.bm_width;
    vp.DHeight = bm.bm_height;
    vp.RasInfo = &ri;
    vp.ColorMap = cm;
    for (plane = 0; plane < bm.bm_numplanes; plane++)
	if ((b.Planes[plane] = (PLANEPTR) AllocRaster(bm.bm_width,
	     bm.bm_height)) == NULL)
	    ErrExit("Couldn't allocate enough screen memory");

    if (bm.bm_width > 384)			/* should be set */
	ViewMode |= HIRES;
    if (bm.bm_height > 240)
	ViewMode |= LACE;
    if (ViewMode & LACE)
	v.Modes |= LACE;
    vp.Modes = ViewMode;

    if (ViewMode & HIRES)			/* center */
	vp.DxOffset = (640 - bm.bm_width) / 2;
    else
	vp.DxOffset = (320 - bm.bm_width) / 2;
    if (ViewMode & LACE)
	vp.DyOffset = ((2 * WinHeight) - bm.bm_height) / 2;
    else
	vp.DyOffset = ((2 * WinHeight) - bm.bm_height) / 2;

    MakeVPort(&v, &vp);
    MrgCop(&v);

    ReadPic(fp, &bm, &b);
    LoadView(&v);
    WaitForMouseClick();
    LoadView(oldview);
    for (i = 0; i < bm.bm_numplanes; i++)
    {
	FreeRaster(b.Planes[i], bm.bm_width, bm.bm_height);
	b.Planes[i] = NULL;
    }
    FreeColorMap(cm);
    cm = NULL;
    FreeVPortCopLists(&vp);
    FreeCprList(v.LOFCprList);
    FreeCprList(v.SHFCprList);
}


void
ReadPic(fp, bmhdr, bm)
register FILE *fp;
register BitMapHeader *bmhdr;
register struct BitMap *bm;
{
    register u_char Pixel, *PixelPtr;
    register short plane, row, nbytes, count;

    if (bmhdr->bm_compression == 1)
    {
	for (row = 0; row < bmhdr->bm_height; row++)
	{
	    for (plane = 0; plane < bmhdr->bm_numplanes; plane++)
	    {
		PixelPtr = bm->Planes[plane] + (row * bm->BytesPerRow);
		nbytes = bm->BytesPerRow;
		while (nbytes > 0)
		{
		    count = (char) getc(fp);	/* might be negative */
		    if (count >= 0)		/* copy n+1 literal */
		    {
			count++;
			nbytes -= count;
			while (count--)
			    *PixelPtr++ = getc(fp);
		    }
		    else if (count >= -127)	/* repeat next -n+1 times */
		    {
			count = 1 - count;
			nbytes -= count;
			Pixel = getc(fp);
			while (count--)
			    *PixelPtr++ = Pixel;
		    }
		}
	    }
	}
    }
    else
    {
	for (row = 0; row < bmhdr->bm_height; row++)
	    for (plane = 0; plane < bmhdr->bm_numplanes; plane++)
		ChkRead(fp, bm->Planes[plane] + (row * bm->BytesPerRow),
		        bm->BytesPerRow);
    }
}


void
ChkRead(fp, buf, nbytes)
FILE *fp;
char *buf;
int nbytes;
{
    if (fread(buf, nbytes, 1, fp) != 1)
	ErrExit("Short read");
}


void
ErrExit(s)
char *s;
{
    char b[10];

    fprintf(stderr, "%s\nPress RETURN", s);
    gets(b);
    cleanup();
    exit(10);
}


int
WaitForMouseClick()
{
    static struct NewWindow CheeseWhiz = {
	0, 0,			/* position in upper left */
	0, 0,			/* don't init yet */
	-1, -1,			/* default pens */
	MOUSEBUTTONS,
	BORDERLESS | ACTIVATE,
	NULL, NULL, NULL,
	NULL, NULL,
	0, 0, 0, 0,
	WBENCHSCREEN    
    };
    struct IntuiMessage *message;
    struct Window *win;

    CheeseWhiz.Width = WinWidth;
    CheeseWhiz.Height = WinHeight;
    if (prefs.LaceWB)
	CheeseWhiz.Height += WinHeight;
    if ((win = OpenWindow(&CheeseWhiz)) == NULL)
	return(-1);
    Wait(1 << win->UserPort->mp_SigBit);
    message = (struct IntuiMessage *) GetMsg(win->UserPort);
    ReplyMsg(message);
    CloseWindow(win);
    return(0);
}


void
cleanup()
{
    register short i;

    if (cm)			/* forget about the other bits */
	FreeColorMap(cm);
    for (i = 0; i < bm.bm_numplanes; i++)
    {
	if (b.Planes[i])
	    FreeRaster(b.Planes[i], bm.bm_width, bm.bm_height);
    }
    CloseLibrary(GfxBase);
    CloseLibrary(IntuitionBase);
    fclose(stdin);
    fclose(stdout);
    fclose(stderr);
    rbrk();
}