/*************************************************************\
 *                     SCREEN JAEGER                         *
 *                     ~~~~~~ ~~~~~~                         *
 *                                                           *
 *       'Jaeger' - German word meaning HUNTER               *
 *                  I'm not German, but I like the word      *
 *                                                           *
 *               Written by Syd L. Bolton                    *
 *       ©1991 Legendary Design Technologies Inc.            *
 *                                                           *
 *         Compiled using Manx Aztec C (tm) V5.0             *
 *                                                           *
 *      Started:       Date:  May 13, 1991  Time: 18:55:00   *
 *      Version: 1.00  Date: July 12, 1991  Time: 00:17:00   *
 *      Version: 1.01  Date: July 16, 1991  Time: 12:30:00   *
\*************************************************************/

#include <intuition/intuition.h>
#include <intuition/intuitionbase.h>
#include <exec/memory.h>
#include <exec/execbase.h>
#include <graphics/gfx.h>
#include <graphics/gfxbase.h>
#include <math.h>
#include <iff.h>

long *IntuitionBase,*GfxBase,*IFFBase;
extern struct ExecBase *SysBase;
struct MemHeader *mh;
struct BitMap bm;
struct Screen *Screen,*MainScreen;
struct Window *Window,*MessageWindow,*InfoWindow;
struct ViewPort *ViewPort,*vport;
struct RastPort *rport,*mrport,*irport;
UWORD colortable[32];
long upper[2],lower[2],xbody,ybody;
long FOffset[6];
PLANEPTR PlanePtr[6];

#include "screen.h"
#include "main.h"
#include "message.h"
#include "info.h"

#define CHIP 0
#define FAST 1

int num_bitplanes=1,fine=0,direction,plane=0,copy=0,swap=0;
int width,height,NormalRows;
int type=CHIP;
int XOffset=0,YOffset=0;
int overscan=0;

long offset=32768;

main()
{
int i,exit_prog=0;
struct IntuiMessage *message;
ULONG class;

openlibraries();
setup();
show_plane(2,1);

do {
	WaitPort(Window->UserPort);
                  while( (message = (struct IntuiMessage *)
                         GetMsg(Window->UserPort) ) != NULL)
                  {
                      class = message->Class;
                      ReplyMsg(message);
     
		      if ( class == GADGETUP) exit_prog=option(message);
		      if ( class == GADGETDOWN && fine==0) holdit(message);
		      if ( class == VANILLAKEY) key(message);
		}
      } while (exit_prog==0);

closestuff(0);
}

#include "pointer.h"

key(message)
struct IntuiMessage *message;
{
int c;

c=message->Code;

switch (c) {
	case 'b':
	case 'B': ScreenToFront(Screen);
		  break;

	case 'f':
	case 'F': ScreenToFront(MainScreen);
		  break;

	case 'm':
	case 'M': MainScreen->TopEdge=0;
		  MainScreen->ViewPort.DyOffset=0;
		  Screen->TopEdge=57;
		  Screen->ViewPort.DyOffset=57;
		  ScreenToFront(Screen);
		  RemakeDisplay();
		  break;

	case 'n':
	case 'N': MainScreen->TopEdge=NormalRows-56;
		  MainScreen->ViewPort.DyOffset=NormalRows-56;
		  Screen->TopEdge=0;
		  Screen->ViewPort.DyOffset=0;
		  ScreenToFront(MainScreen);
		  RemakeDisplay();
		  break;

	default: break;
	}
}

holdit(message)
struct IntuiMessage *message;
{
struct Gadget *igad;
int gadgid,hiexit=0;
ULONG class;

igad=(struct Gadget *) message->IAddress;
gadgid=igad->GadgetID;

if (copy==1 || swap==1) {
	ClearPointer(Window);
	copy=swap=0;
	}                 /* turn off special modes */

if (overscan) return();

do {
	message=(struct IntuiMessage *) GetMsg(Window->UserPort);
	if (message != NULL) {
		class=message->Class;
		ReplyMsg(message);
		if (class==GADGETUP) hiexit=1;
		}
	switch (gadgid) {	
		case 1: offset-=width;
			if (offset < lower[type]) offset=lower[type];
			redo();
			break;

		case 2: offset++;
			if (offset+(width/8)*height > upper[type]) offset=upper[type]-width/8*height;
			redo();
			break;

		case 3: offset+=width;
			if (offset+(width/8)*height > upper[type]) offset=upper[type]-width/8*height;
			redo();
			break;

		case 4: offset--;
			if (offset < lower[type]) offset=lower[type];
			redo();
			break;

		case 45: redoprop();
			 break;

		default: break;
		}
	} while (hiexit==0);
}

option(message)
struct IntuiMessage *message;
{
struct Gadget *igad;
int gadgid;
long temp;
ULONG size,max;

igad=(struct Gadet *) message->IAddress;
gadgid=igad->GadgetID;

switch(gadgid) {
	case 1: if (overscan) doscan(1);
		else {
		offset-=width/(7*fine+1);
		if (offset < lower[type]) offset=lower[type];
		redo();
		}
		break;

	case 2: if (overscan) doscan(2);
		else {
		offset++;
		if (offset+(width/8)*height > upper[type]) offset=upper[type]-width/8*height;
		redo();
		}
		break;

	case 3: if (overscan) doscan(3);
		else {
		offset+=width/(7*fine+1);
		if (offset+(width/8)*height > upper[type]) offset=upper[type]-width/8*height;
		redo();
		}
		break;

	case 4: if (overscan) doscan(4);
		else {
		offset--;
		if (offset < lower[type]) offset=lower[type];
		redo();
		}
		break;

	case 5: num_bitplanes++;
		if (num_bitplanes > 6) num_bitplanes=6;
		if (type==FAST) {
			PlanePtr[num_bitplanes-1]=AllocRaster(width,height);
			if (PlanePtr[num_bitplanes-1]) {
				CopyMem(lower[FAST],PlanePtr[num_bitplanes-1],(width/8)*height);
				bm.Planes[num_bitplanes-1]=PlanePtr[num_bitplanes-1];
				Screen->RastPort.BitMap->Planes[num_bitplanes-1]=PlanePtr[num_bitplanes-1];			/* if not, couldn't allocate the chip memory */
				}
			else num_bitplanes--;
			}
		set_depth();
		break;

	case 6: num_bitplanes--;
		if (num_bitplanes < 1) num_bitplanes=1;
		if (type==FAST) {
			if (PlanePtr[num_bitplanes]) FreeRaster(PlanePtr[num_bitplanes],width,height);
			PlanePtr[num_bitplanes]=0;
			}
		set_depth();
		if (plane >= num_bitplanes) {
			show_plane(1,2);
			plane=num_bitplanes-1;
			show_plane(2,1);
			}
		break;

	case 7: offset=atoi(Gadget32SIBuff);
		if (offset < lower[type]) offset=lower[type];
		if (offset+width/8*height > upper[type]) offset=upper[type]-width/8*height;
		redo();
		calcpropgad();
		break;

	case 9: if (Gadget6.Flags & SELECTED)
			fine=1;
		else fine=0;
		break;   

	case 10: if (Gadget13.Flags & SELECTED) {
			if (type==FAST) freefastmem();
			Screen->ViewPort.Modes |= LACE;
			Screen->RastPort.BitMap->Rows=NormalRows*2;
			bm.Rows=NormalRows*2;		
			Screen->Height=NormalRows*2;
			Screen->ViewPort.DHeight=NormalRows*2;
			height=NormalRows*2;
			if (type==FAST) allocfastmem();
			}
		 else {
			if (type==FAST) freefastmem();
			Screen->ViewPort.Modes &= ~LACE;
			Screen->RastPort.BitMap->Rows=NormalRows;
			bm.Rows=NormalRows;
			Screen->Height=NormalRows;
			Screen->ViewPort.DHeight=NormalRows;
			height=NormalRows;
			if (type==FAST) allocfastmem();
			}
		 calcpropgad();
		 fixhwgads();
		 RemakeDisplay();
		 break;

	case 11: if (Gadget14.Flags & SELECTED) {
			if (type==FAST) freefastmem();
			Screen->ViewPort.Modes |= HIRES;
			Screen->Width=640;
			Screen->RastPort.BitMap->BytesPerRow=80;
			bm.BytesPerRow=80;    /* 640 div 8 */
			Screen->ViewPort.DWidth=640;
			width=640;
			if (type==FAST) allocfastmem();
			}
		 else {
			if (type==FAST) freefastmem();
			Screen->ViewPort.Modes &= ~HIRES;
			Screen->Width=320;
			bm.BytesPerRow=40;   /* 320 div 8 */
			Screen->RastPort.BitMap->BytesPerRow=40;
			Screen->ViewPort.DWidth=320;
			width=320;
			if (type==FAST) allocfastmem();
			}
		 calcpropgad();
		 fixhwgads();
		 RemakeDisplay();
		 break;

	case 12: if (Gadget15.Flags & SELECTED) {
			Screen->ViewPort.Modes |= EXTRA_HALFBRITE;
			if (num_bitplanes < 6) Message("WARNING: Should have 6 bitplanes.");
			}
		 else
			Screen->ViewPort.Modes &= ~EXTRA_HALFBRITE;
		 RemakeDisplay();
		 break;

	case 13: if (Gadget16.Flags & SELECTED) {
			Screen->ViewPort.Modes |= HAM;
			if (num_bitplanes < 6) Message("WARNING: Should have 6 bitplanes.");
			}
		 else
			Screen->ViewPort.Modes &= ~HAM;
		 RemakeDisplay();
		 break;

	case 20:
	case 21:
	case 22:
	case 23:
	case 24:
	case 25: if (gadgid-19 > num_bitplanes) break;
		 if (type==FAST) FOffset[plane]=offset;
		 if (copy==1) {
			bm.Planes[gadgid-20]=Screen->RastPort.BitMap->Planes[gadgid-20]=bm.Planes[plane];
			copy=0;
			ClearPointer(Window);
			RemakeDisplay();
			}
		 if (swap==1) {
			temp=bm.Planes[plane];
			bm.Planes[plane]=Screen->RastPort.BitMap->Planes[plane]=bm.Planes[gadgid-20];
			bm.Planes[gadgid-20]=Screen->RastPort.BitMap->Planes[gadgid-20]=temp;
			swap=0;
			ClearPointer(Window);
			RemakeDisplay();
			}
		 show_plane(1,2);
		 plane=gadgid-20;	
		 if (type==CHIP) offset=bm.Planes[plane];
		 if (type==FAST) {
			offset=FOffset[plane];
			if (offset < lower[FAST]) offset=lower[FAST];
			}
		 show_plane(2,1);		  
		 display_offset();   /* update gadget */
		 break;

	case 30: autooffset();
		 break;
		 
	case 31: copy=1-copy;
		 if (copy) do_ToSprite(Window);
		 	else ClearPointer(Window);
		 break;

	case 32: swap=1-swap;
		 if (swap) do_ExSprite(Window);
		 	else ClearPointer(Window);
		 break;

	case 40: save_iff();
		 break;             /* save file */

	case 41: if (type==CHIP) {
			 max=AvailMem(MEMF_CHIP|MEMF_LARGEST);
			 if (max) size=AllocMem(max,MEMF_CHIP|MEMF_CLEAR);
			 if (size) FreeMem(size,max);
			 }
		 if (type==FAST) {
			max=AvailMem(MEMF_FAST|MEMF_LARGEST);
			if (max) size=AllocMem(max,MEMF_FAST|MEMF_CLEAR);
			if (size) FreeMem(size,max);
			}
		 break;

	case 42:
	case 43: redo_dimensions();
		 break;

	case 45: redoprop();
		 break;

	case 46: if (type==CHIP) break;
		 type=CHIP;
		 show_mem_type();
		 offset=lower[CHIP];
		 freefastmem();
		 redo();		 
		 break;

	case 47: if (type==FAST) break;
		 if (lower[FAST]==0) {
			type=CHIP;
			show_mem_type();
			break;
			}
		 type=FAST;
		 show_mem_type();
		 offset=lower[FAST];
		 allocfastmem();
		 redo();
		 break;

	case 50: return(1);
	
	case 75: if (Gadget30.Flags & SELECTED)
			overscan=1;
		 else overscan=0;
		 break;

	case 80: ScreenInfo();
		 break;

	default: break;
	}
if ((swap==1 || copy==1) && (gadgid!=31 && gadgid!=32)) {
	ClearPointer(Window);
	swap=copy=0;
	}
return(0);
}

doscan(dir)
int dir;
{
switch (dir) {
	case 1: YOffset--;
		break;

	case 2: XOffset++;
		break;

	case 3: YOffset++;
		break;

	case 4: XOffset--;
		break;

	default: break;
	}
if (YOffset < -46) YOffset=-46;
if (YOffset > 534) YOffset=534;
if (XOffset < -36) XOffset=-36;
if (YOffset > 724) XOffset=724;

Screen->ViewPort.DyOffset=YOffset;
Screen->ViewPort.DxOffset=XOffset;

RemakeDisplay();
}

allocfastmem()
{
int i,rv=0;

for (i=0; i<num_bitplanes; i++) {
	PlanePtr[i]=AllocRaster(width,height);
	if (PlanePtr[i]) {
		bm.Planes[i]=PlanePtr[i];
		Screen->RastPort.BitMap->Planes[i]=PlanePtr[i];
		}
	else rv=-1;
	}
return(rv);
}

freefastmem()
{
int i;

for (i=0; i<num_bitplanes; i++) {
	if (PlanePtr[i]) FreeRaster(PlanePtr[i],width,height);
	PlanePtr[i]=0;   /* just clear it out to be safe later */
	bm.Planes[i]=lower[CHIP];
	Screen->RastPort.BitMap->Planes[i]=lower[CHIP];
	}
}

fixhwgads()
{
sprintf(Gadget25SIBuff,"%-d",width);
sprintf(Gadget26SIBuff,"%-d",height);
RefreshGadgets(&Gadget25,Window,NULL);
show_mem_type();  /* just so it doesn't get lost */
}

redo_dimensions()
{
int swidth,sheight;

swidth=atoi(Gadget25SIBuff);
sheight=atoi(Gadget26SIBuff);

if (swidth > 1024) swidth=1024;
if (sheight > 1024) sheight=1024;
if (swidth < 1) swidth=1;
if (sheight < 1) swidth=1;
sprintf(Gadget25SIBuff,"%-d",swidth);
sprintf(Gadget26SIBuff,"%-d",sheight);

if (type==FAST) freefastmem();
Screen->Width=swidth;
bm.BytesPerRow=swidth/8;
bm.Rows=sheight;
Screen->RastPort.BitMap->Rows=sheight;
Screen->RastPort.BitMap->BytesPerRow=swidth/8;
Screen->ViewPort.DWidth=swidth;
Screen->Height=sheight;
Screen->ViewPort.DHeight=sheight;

width=swidth; height=sheight;
if (height > 399) {
	Screen->ViewPort.Modes |= LACE;
	Gadget13.Flags |= SELECTED;
	}
	else {
	Screen->ViewPort.Modes &= ~LACE;
	Gadget13.Flags &= ~SELECTED;
	}
if (width > 639) {
	Screen->ViewPort.Modes |= HIRES;
	Gadget14.Flags |= SELECTED;
	}
	else {
	Screen->ViewPort.Modes &= HIRES;
	Gadget14.Flags &= ~SELECTED;
	}
if (type==FAST) allocfastmem();
RefreshGadgets(&Gadget13,Window,NULL);
show_mem_type();
RemakeDisplay();
}

show_plane(a,b)
int a,b;
{
char p[4];

SetAPen(rport,a);
SetBPen(rport,b);
Move(rport,301+33*plane,9);
sprintf(p," %1d ",plane+1);
Text(rport,p,3);
}

show_mem_type()
{
SetAPen(rport,1-type+1);
SetBPen(rport,type+1);
Move(rport,102,30);
Text(rport," CHIP ",6);
SetAPen(rport,type+1);
SetBPen(rport,1-type+1);
Move(rport,160,30);
Text(rport," FAST ",6);
}

autooffset()
{
int i;

if (num_bitplanes < 2) return();

for (i=1; i<num_bitplanes; i++) {
	bm.Planes[i]=bm.Planes[0]+i*(width*height/8);
	Screen->RastPort.BitMap->Planes[i]=bm.Planes[0]+i*(width*height/8);
	}
RemakeDisplay();
}

set_depth()
{
char msg[2];

sprintf(msg,"%-1d",num_bitplanes);
Move(rport,242,10);
SetAPen(rport,1); SetBPen(rport,0);
Text(rport,msg,1);
bm.Depth=num_bitplanes;
Screen->Depth=num_bitplanes;
Screen->RastPort.BitMap->Depth=num_bitplanes;
RemakeDisplay();
}

redo()
{
display_offset();
if (type==CHIP) {
	bm.Planes[plane]=offset;
	Screen->RastPort.BitMap->Planes[plane]=offset;
	RemakeDisplay();
	}
if (type==FAST) {
	CopyMem(offset,PlanePtr[plane],(width/8)*height);
	RemakeDisplay();
	}
}

display_offset()
{
sprintf(Gadget32SIBuff,"%-d",offset);
RefreshGadgets(&Gadget32,Window,NULL);
}

calcpropgad()
{
USHORT VertPot,HorizPot;
long value,xpos,ypos;

value=(upper[type]-lower[type])/(width/8*height);
xbody=sqrt(value*3)+0.5;   /* for rounding of course */
ybody=sqrt(value/3)+0.5;
value=offset/(width/8*height);
xpos=sqrt(value*3)+0.5; xpos++;
ypos=sqrt(value/3)+0.5; ypos++;
HorizPot=(UWORD) (((ULONG) xpos * MAXPOT) / (xbody-1));
 VertPot=(UWORD) (((ULONG) ypos * MAXPOT) / (ybody-1));
NewModifyProp(&Gadget27,Window,NULL,AUTOKNOB+FREEHORIZ+FREEVERT,HorizPot,VertPot,0xffff/xbody,0xffff/ybody,1);
}

redoprop()
{
USHORT VertPot,HorizPot;
USHORT mx,my;
int dmem;

dmem=width/8*height;

VertPot=Gadget27SInfo.VertPot; HorizPot=Gadget27SInfo.HorizPot;
mx=((HorizPot+1)*(xbody-1))>>16; mx++;
my=((VertPot+1)*(ybody-1))>>16; my++;
offset=lower[type]+mx*my*dmem;
if (offset < lower[type]) offset=lower[type];
if (offset > upper[type]-dmem) offset=upper[type]-dmem;
redo();
}

Message(text)
char *text;
{
struct IntuiMessage *message;

MesWin.Screen=MainScreen;
MessageWindow=OpenWindow(&MesWin);
if (MessageWindow==NULL) return();

mrport=MessageWindow->RPort;
Move(mrport,10,20);
Text(mrport,text,strlen(text));

WaitPort(MessageWindow->UserPort);
                  while( (message = (struct IntuiMessage *)
                         GetMsg(MessageWindow->UserPort) ) != NULL)
                  	ReplyMsg(message);
CloseWindow(MessageWindow);
}

ScreenInfo()
{
struct IntuiMessage *message;
char string[10];
long available,tmem;

InfoWin.Screen=MainScreen;
InfoWindow=OpenWindow(&InfoWin);
if (InfoWindow==NULL) return();

irport=InfoWindow->RPort;
PrintIText(irport,&ITextList,0,0);

SetAPen(irport,3); SetBPen(irport,0);  /* set lighter color */

sprintf(string,"%-8d",lower[CHIP]); Move(irport,59,20); Text(irport,string,8);
sprintf(string,"%-8d",upper[CHIP]); Move(irport,176,20); Text(irport,string,8);
sprintf(string,"%-8d",lower[FAST]); Move(irport,59,41); Text(irport,string,8);
sprintf(string,"%-8d",upper[FAST]); Move(irport,176,41); Text(irport,string,8);
available=(upper[CHIP]-lower[CHIP])+(upper[FAST]-lower[FAST]);
sprintf(string,"%-8d",available); Move(irport,149,51); Text(irport,string,8);
sprintf(string,"%-3d",XOffset); Move(irport,494,20); Text(irport,string,3);
sprintf(string,"%-3d",YOffset); Move(irport,551,20); Text(irport,string,3);
tmem=(width/8)*height*num_bitplanes;
sprintf(string,"%8d",tmem); Move(irport,471,41); Text(irport,string,8);

WaitPort(InfoWindow->UserPort);
                  while( (message = (struct IntuiMessage *)
                         GetMsg(InfoWindow->UserPort) ) != NULL)
                  	ReplyMsg(message);
CloseWindow(InfoWindow);
}

save_iff()
{
int k,max_colors;
long val1,val2;

max_colors=1 << num_bitplanes;
if (max_colors > 32) max_colors=32;

for (k=0; k < max_colors; k++)
	colortable[k]=GetRGB4(ViewPort->ColorMap,k);

for (k=0; k<num_bitplanes; k++) {               /* we must do this       */
	val1=val2=bm.Planes[k];			/* to insure that the    */
	val1=val1/2;				/* BITMAP is alinged     */
	val1=val1*2;				/* to a word. Otherwise  */
	if (val1 != val2) {			/* the resultant picture */
		bm.Planes[k]--;			/* will be screwed!      */
		Screen->BitMap.Planes[k]--;
		}
	}

SaveBitMap(Gadget19SIBuff,&Screen->BitMap,&colortable[0],1);
}

setup()
{
int i;

InitBitMap(&bm,1,320,NormalRows);
for (i=0; i<6; i++)
	bm.Planes[i]=offset;
NewScreenStructure.Depth=1;

width=320; height=NormalRows;

if(!(Screen=OpenScreen(&NewScreenStructure))) {
	problem("   Screen Jaeger: Couldn't open Screen.  ");
	closestuff(1);
	}

Screen2.TopEdge=NormalRows-56;
Screen2.Height=55;

if(!(MainScreen=OpenScreen(&Screen2))) {
	problem("   Screen Jaeger: Couldn't open S.Screen!  ");
	closestuff(1);
	}

sprintf(Gadget26SIBuff,"%-d",NormalRows);
strcpy(Gadget25SIBuff,"320");
vport=&MainScreen->ViewPort;
ViewPort=&Screen->ViewPort;
LoadRGB4(vport,&Palette[0],PaletteColorCount);
NewWindowStructure1.Screen=MainScreen;
if(!(Window=OpenWindow(&NewWindowStructure1))) {
	problem("   Screen Jaeger: Couldn't open Window!.  ");
	closestuff(1);
	}
rport=Window->RPort;
Move(rport,178,10);
SetAPen(rport,1); SetBPen(rport,0);
Text(rport,"Planes: 1",9);
display_offset();
show_mem_type();
lower[0]=0; lower[1]=0; upper[0]=0; upper[1]=0;  /* clear mem values */
Forbid();
for (mh=(struct MemHeader *) SysBase->MemList.lh_Head; mh->mh_Node.ln_Succ;
	mh=(struct MemHeader *)mh->mh_Node.ln_Succ) {
	if (mh->mh_Attributes & MEMF_CHIP) {
		lower[CHIP]=mh->mh_Lower; upper[CHIP]=mh->mh_Upper; }
	if (mh->mh_Attributes & MEMF_FAST) {
		lower[FAST]=mh->mh_Lower; upper[FAST]=mh->mh_Upper; }
	}
Permit();
calcpropgad();
}

problem(message)
char *message;
{
int l;

message[0]=0; message[1]=8; message[2]=14;
l=strlen(message);
message[l-2]=0; message[l-1]=0;
DisplayAlert(RECOVERY_ALERT,message,30);
}

openlibraries()
{
if(!(IntuitionBase=OpenLibrary("intuition.library",0L))) {
	problem("   Screen Jaeger: Couldn't open Intuition.  ");
	exit(1);
	}

if(!(GfxBase=OpenLibrary("graphics.library",0L))) {
	problem("   Screen Jaeger: Couldn't open Graphics!!  ");
	exit(1);
	}
NormalRows=GfxBase->NormalDisplayRows;  /* see if we're PAL or not! */
if(!(IFFBase=OpenLibrary("iff.library",15))) {
	problem("   Screen Jaeger: Please copy iff.library V15 or higher to SYS:LIBS directory!  ");
	exit(1);
	}
}

closestuff(value)
int value;
{
if (type==FAST) freefastmem();
if (Screen) {
	type=CHIP;
	num_bitplanes=1;
	set_depth();
	bm.Planes[0]=MainScreen->RastPort.BitMap->Planes[0];
	Screen->RastPort.BitMap->Planes[0]=MainScreen->RastPort.BitMap->Planes[0];
	CloseScreen(Screen);
	}
if (Window) CloseWindow(Window);
if (MainScreen) CloseScreen(MainScreen);
if (IFFBase) CloseLibrary(IFFBase);
if (GfxBase) CloseLibrary(GfxBase);
if (IntuitionBase) CloseLibrary(IntuitionBase);
if (value > 0) exit(-1);
}

