/* This software is under General Public Licence (GPL) of Free Software
 * Foundation. If you haven't received GPL with this software as COPYING,
 * you should obtain it from URL "ftp://prep.ai.mit.edu/pub/gnu/COPYING".
 * This software may be distributed freely as long as sources remain
 * accessible for at least 2 years and no modifications are made.
 * Copyright (c) in 1997 by Jan Kratochvil <short@k332.feld.cvut.cz>
 */

/* ^^^ Pekna debilita, ale aspon je to po pravni strance v poradku. :-) */

/* Muze mi nekdo vysvetlit, proc mame mysoidni podlozky s napisem
 * "digital: Alpha generation", kdyz to tady piseme na i386-komp.
 * PC-ckach? To nemohl aspon sponzor zapujcit na dobu souteze nejaky
 * Alpha-y? To by bylo hned veseleji.
 */

#include <stdlib.h>
#include <stdio.h>
#include <alloc.h>

/* Here we go...
 * Nevim co s casem, ale algoritmus se mi jiz menit nechce,
 * tak sem naleju aspon neco commentu, at ziskam aspon tech 10 bodu
 * A to to byl tak hezky citelny soft bez jedineho komentare. Bee!
 */

/* Viz nize na patricnem ifdefu */
#define CHANGE_DIR one_completely_unused_string

char buf[200]; /* trashcan */
unsigned char far (*vga)[320]; /* 320x200x256 chunky-pixel pointer */

/* Po pul hodine boje s TurboCckem jsem usoudil, ze se mi asi 64KB velke
 * pole na 16MB masine naalokovat nepodari (farmalloc()==NULL pri jakemkoliv
 * modelu a modleni).
 * Ja uz se GCCcka na soutezich asi nedoziju. Ale budouci generace by
 * mozna jiz mohly...
 * Diky tomu pouzivam pro veskere vypocty pouze visible screen area, ale
 * taky to jde! (Dokonce to ma pak pozitivni vizualni efekty - Yow!)

unsigned char far (*mymap)[320];
 */

/* input file */
FILE *f;
/* GP=general purpose ;-) */
int i,flg;
int idx,x1,y1,x2,y2;
int x,y;
/* strip=posun pri scrolligu, draw=posun pri filleni, curcol=selected barva */
int strip=0,draw,curcol=0;
/* smer obarvovani v pruchodu 2 */
int dir;

/* Barve je stripe! */
#define STRIPE(nn) ((nn)>=240&&(nn)<=254)
/* Barva je nase! (pro druhy pruchod) */
#define OWNCOL(n) (STRIPE((n))||(n)==idx)

/* Barva je taky nase! (pro prvni pruchod) */
#define OWNCOLX(n) ((n)==255||(n)==idx)
/* Barva bodu (mimo screen=0) */
#define GETCOL(xx,yy) ((xx)<0||(xx)>=320||(yy)<0||(yy)>=200?0:vga[(yy)][(xx)])

/* Nakonec unused - melo to vylepsit fillici heuristiku */
#define PASS2(n) (STRIPE((n))||(n)==255)
/*
#define SETCOL(xx,yy) vga[(yy)][(xx)]=((xx)+(yy))%15+240
*/
/* Obarveni pri prvnim pruchodu */
#define SETCOL(xx,yy) vga[(yy)][(xx)]=255

/* Set individual DAC register */
void setdac(int reg,unsigned char r,unsigned char g,unsigned char b)
{
asm {
	mov ax,1010h
	mov bx,reg;
	mov ch,g;
	mov cl,b;
	mov dh,r;
	int 10h;
	}
}

/* Nastaveni obarveni skrollovaciho okraje s posunem strip
 * Pri pouziti blokove verze to zpusobuje strasne cerne pruhy
 * do obrazu - musel bych se patrne syncat na VBLANK, ale nemam
 * tu na to docky.
 * BTW aspon nam to hezky casuje (cca 15/50 sec kazdy krok scrollu)
 */

#if 1

void setstrip(void)
{
int i;
	for (i=0;i<15;i++) {
		setdac((i+strip)%15+240,i*4,i*4,i*4);
		asm {
			mov ax,3;
			int 33h;
			or flg,bx;
			};
		}
}

#else

unsigned char block[15][3];

void setstrip(void)
{
int i,j;
	for (i=0;i<15;i++) {
		j=(i+strip)%15;
		block[j][0]=i*4;
		block[j][1]=i*4;
		block[j][2]=i*4;
		}
	asm {
		mov ax,1012h;
		mov bx,240;
		mov cx,15;
		push es;
		push ds;
		pop es;
		lea dx,&block;
		int 10h;
		pop es;
		};
}

#endif

/* Show mouse cursor */
void show(void)
{
asm	{
		mov ax,1;
		int 33h;
		};
}

/* Hide mouse cursor */
void hide(void)
{
asm	{
		mov ax,2;
		int 33h;
		};
}

/* Vykresleni vsech map - pri nastaveni curcol kresli jen tu danou
 * (curcol) mapu - pouze z rychlostnich duvodu.
 */
void redraw(void)
{
int x,y;
	hide();
	fseek(f,0,SEEK_SET);
/* Header file-u nas moc nezajima - mohl by tu byt sanity check */
	fgets(buf,sizeof(buf),f);
	for (;;) {
		if (fscanf(f,"%d%d%d%d%d",&idx,&x1,&y1,&x2,&y2)!=5) break;
		if (curcol&&curcol!=idx||x2<x1||y2<y1||x1<0||x2>319||y1<0||y2>199) continue;

		for (y=y1;y<=y2;y++)
			memset(vga[y]+x1,idx,x2-x1+1);
/* memset-ekvivalentni s:
			for (x=x1;x<=x2;x++)
				vga[y][x]=idx;
 */
		}
	show();
}


/*
 * Bylo jiz prekonano - relikt z predchozich verzi
void checktwo(int x1,int y1,int x2,int y2)
{
	if (vga[y1][x1]==vga[y2][x2]) return;
	mymap[y1][x1]=vga[y1][x1];
	mymap[y2][x2]=vga[y2][x2];
}
*/

int main(int argc,char **argv)
{
	if (argc!=2) {
		puts("Syntax: 11mview <data.mdf>");
		exit(0);
		}
/*	printf("%lu",farcoreleft());
	gets(buf);*/
	f=fopen(argv[1],"rt");
	if (!f) {
		printf("Cannot open \"%s\" - %s!\n",argv[1],strerror(errno));
		exit(EXIT_FAILURE);
		}

/* Video mode... */
	asm {
	mov	ax,13h
	int 10h;
	}
/* Mouse reset... */
	asm {
		xor ax,ax;
		int 33h;
		mov flg,ax
		};
	if ((unsigned)flg!=0xFFFF) {
		asm {
			mov ax,3;
			int 10h;
			};
		puts("No mouse driver installed - cannot run!");
/* Amiga debugger: "CPU 68000 not fitted - cannot debug!"
 * Na prvni pohled zcestna hlaska, na druhy docela pochopitelna.
 * Od 68010 vyse se zmenit layout stack framu pri exceptionu.
 * :-)
 */
		exit(EXIT_FAILURE);
		}
/* Pallette... */
	for(i=0;i<256;i++) {
		if (i==0||i==255) setdac(i,i,i,i);
		else setdac(i,((i>>5)*255)/7,(((i>>2)&7)*255)/7,((i&3)*255)/3);
		}
/* Tohle zatuhne (i Gdyz to neni potreba) - hide(); */
/* VGA base: */
	vga=(void far *)0xA0000000;
/*
	Onen problematicky kod, ktery byl vyhozen:
	mymap=(void far *)farmalloc(64000UL);
	if (!mymap) {
		puts("Alloc failure!");
		exit(10);
		}*/
/*	memset(mymap,0,320*200);*/
	setstrip();

/* Full-blown redraw! Bourning again... */
	show();
	redraw();

	show();
	flg=0;
	for (;;) {

/* Any key */
	if (bioskey(1)) goto key;

/* Posun stripe-u */
	setstrip();
	strip=(strip+1)%15;

/* Mouse get */
	asm {
		mov ax,3;
		int 33h;
		or flg,bx;
		mov x,cx;
		mov y,dx;
		};
	x/=2; /* Proc proboha tohle? */

	idx=curcol;

/* Nic se nestalo...*/
	if (!(flg&1)||((flg&1)&&OWNCOL(vga[y][x]))) {flg=0; continue; }
	flg=0;
/* Zrus predchozi oblast */
	if (curcol) { redraw(); curcol=0; }

	hide();

	idx=vga[y][x];
/* Klick mimo mapu? */
	if (!(idx&&idx<240)) { show(); continue; }

/* Pruchod 1 - vsechny hranice s NASI barvu prebarvime na 255
 * (pouze smerem dovnitr).
 */
	curcol=idx;
	for (y=-1;y<200;y++)
	for (x=-1;x<320;x++) {
unsigned char a=GETCOL(x,y),b,a1;
/* Horizontalni diference */
		b=GETCOL(x+1,y);
		if ((a1=OWNCOLX(a))^OWNCOLX(b)) {
			if (a1) SETCOL(x,y);
			else SETCOL(x+1,y);
			}
/* Vertikalni diference */
		b=GETCOL(x,y+1);
		if ((a1=OWNCOLX(a))^OWNCOLX(b)) {
			if (a1) SETCOL(x,y);
			else SETCOL(x,y+1);
			}
		}
/* Pruchod 2 - "Vyzereme" vsechny cesticky 255-ek a budeme to cestou
 * cyklicky barvit */

	draw=0; dir=0;
	for (y1=0;y1<200;y1++)
	for (x1=0;x1<320;x1++)
	if (vga[y1][x1]==255) {
		x=x1; y=y1;
		for (;;) {
			vga[y][x]=240+draw;
			if (dir) {
				if (draw) draw--;
				else draw=14;
				}
			else draw=(draw+1)%15;
/* Zkousi to nejdriv horizontalni/vertikalni smer - kdyz to selze,
 * zkusi to jeste diagonaly. - Uz to neni pravda. Jedine zlepseni
 * bylo v PENTA.MDF, a to stejne silne diskutabilni. A zavadelo to chaos.
 * Melo by to davat o trochu lepsi vysledky, ale stejne je to heuristika. :-)
 */
			if (x<319       &&vga[y  ][x+1]==255) { x++;      continue; }
			if (x<319&&y<199&&vga[y+1][x+1]==255) { x++; y++; continue; }
			if (       y<199&&vga[y+1][x  ]==255) {      y++; continue; }
			if (x>0  &&y<199&&vga[y+1][x-1]==255) { x--; y++; continue; }
			if (x>0         &&vga[y  ][x-1]==255) { x--;      continue; }
			if (x>0  &&y>0  &&vga[y-1][x-1]==255) { x--; y--; continue; }
			if (       y>0  &&vga[y-1][x  ]==255) {      y--; continue; }
			if (x<319&&y>0  &&vga[y-1][x+1]==255) { x++; y--; continue; }
			break;
			}
/* Kazdy segment cyklu zkusime jinym smerem - na slozitych obrazich
 * to vypada lip. - na PENTA.MDF to udela pekny bordel. */

#ifdef CHANGE_DIR
		dir=!dir;
#endif

/* Jak jste si dozajiste vsimli, v nekterych pripadech to muze "nacyklovat"
 * malinko blbe - prvni pruchod je spravny VZDY, ale u ruznych uzkych
 * ci jinak divnych oblasti to muze spadnout do slepe ulicky - zrestartuje
 * se to pak pres vnejsi dvojity cyklus, ale neni to stejne uplne idealni.
 * Ex.: Argentina v Jizni Americe (huh - 3 roky nemam zemepis - je to vubec
 *      Argentina? - myslim, ze jo). - uz to nedela (po sesystematicteni
 *      prohledavani).
 * Na druhou stranu:
 *  1. Na "normalnejsich" oblastech to nenastava.
 *  2. I kdyz to nastane, tak to vetsinou neni ani videt
 *  3. Algoritmus je takhle velmi primitivni - nemely by v nem byt tedy
 *     chyby a je vcelku elegantni
 *  4. Pokryva to vsechny LEVELy, aniz by to vubec o necem takovem vedelo.
 *     To neni zas tak spatne.
 *
 * Takova skodoliba poznamka pro "jkj": Procpak ten vzorovy program
 *   podporuje pouze level 1?!? :-))))) Ze by neco podobneho?
 */

		}
/* We're ready for Freddie! Go'n'get it. */
	show();

	}

/* Dalsi relikt:
	for (y=0;y<200-1;y++)
	for (x=0;x<320-1;x++) {
		checktwo(x,y,x+1,y);
		checktwo(x,y,x,y+1);
		}

	show();

	while (!bioskey(1)) {
		}
*/

/* Debugging-relikt:
	gets(buf);*/

key:
	bioskey(0); /* Sezrat to */
	hide(); /* Schovat se */
	fclose(f); /* Zavrit se */
	asm { /* Zcernat */
		mov ax,3;
/* Mame obnovit predchozi mod nebo forcenout 3-ku?
 * Na VGA nadela asi mene zla ta 3-ka. (Ale co na MDAcku?)
 */
		int 10h;
		};
	puts("Segmentation fault. (core dumped)"); /* Zfaultat :-) */
/* (Z)vratit se */
	return 0;
}
/* Proboha, ja uz tu snad zacnu psat vtipy... Kdybych si tak moh'
 * aspon rozumne cist postu - ty SMSka jsou strasne orezany.
 */
