/* cbzone gemsetup.c
 * Based on various bits of code lifted from books/magazines etc
 * Roland Givan Summer/Autumn 1993; Summer/Autumn 1994
 *
 */

#include "c_includ.h"
#include <stdio.h>
#include <osbind.h>
#include "gem.h"

GEM_SIZE    contrl[12],
	intin[128],
	ptsin[128],
	intout[128],
	ptsout[128];

GEM_SIZE    work_out[57],
	work_in[12];

GEM_SIZE screen_block[8];
GEM_SIZE image_block[8];

typedef struct c_tag {
	GEM_SIZE red;
	GEM_SIZE green;
	GEM_SIZE blue;
} PALETTE_ENTRY;

/* Saved RGB values for all colour modes */
PALETTE_ENTRY saved_colours[16];
/* RGB values for 16 colour mode */
PALETTE_ENTRY new_colours_16[16]={0,0,0,1000,1000,1000,
									1000,0,0,0,1000,0,
									0,0,1000,0,1000,1000,
									1000,1000,0,1000,0,1000,
									800,800,800,577,577,577,
									770,0,0,0,642,0,
									0,0,500,0,500,500,
									500,500,0,500,0,500
									};
/* RGB values for 4 colour mode */
PALETTE_ENTRY new_colours_4[4]={0,0,0,0,1000,1000,
									1000,0,0,0,1000,0};

/* RGB values for 2 colour mode (inverse) */
PALETTE_ENTRY new_colours_2[2]={0,0,0,1000,1000,1000};

MFDB pix_mfdb[NUMPIXMAPS];
MFDB s,d;									/* MFDB for back (source) and front (destination) screens */

extern Bmap bmaps[NUMPIXMAPS];
extern int wid,hei;							/* Internal game co-ords. Max width and height that X-Windows would have worked with */
extern Optionp opt;

short *back_base,*back_ptr,*front_ptr;	/* back and front screen addresses */

GEM_SIZE handle;	/* handle of VDI workstation */
GEM_SIZE gl_hhbox,gl_hwbox,gl_hhchar,gl_hwchar;

int ap_id;	/* Application ID of this process */
OBJECT *dlog;
int width,height;	/* width and height of screen (both values -1) */
int planes;			/* number of 'planes' in screen */
int scalex,scaley,font_size;	/* variables needed for ATARI_VRES variable resolution mode */
int bit_images = FALSE;
int active_colours;	/* no of colour pens we have for drawing */
int colors;			/* no of colors screen mode supports */
int palette_size;	/* size of palatte - 0 for TrueColour */

/* Function prototypes for this file */

void gem_setup(void);
int config_screen_res(int w, int h);
void save_colours(void);
void gem_close_down(void);
void go(void);
void bale_out(void);
void open_work(void);
void create_block(GEM_SIZE *block, int x, int y, int w, int h);
void create_mfdb(short *addr, MFDB *fdb, int width, int height, int planes);
void create_screen_fdb(short *addr, MFDB *fdb, int width, int height, int planes);
void update_front(void);
void set_front(void);
void set_back(void);
void initialise_back_screen(void);
void delete_back_screen(void);
int handle_dialog(OBJECT *dlog,int editnum);
void get_tedinfo(OBJECT *tree, int obj, char *dest);
char *score_dialog(void);
void pause_dialog(void);
void gameover_dialog(void);
void help_dialog(void);
void version_dialog(char *);
#ifdef LATTICE
int warn(char *mess);
#endif
void mouse_on(void);
void mouse_off(void);

void gem_setup(void)
{
	ap_id = appl_init();
	handle = graf_handle(&gl_hwchar,&gl_hhchar,&gl_hwbox,&gl_hhbox);
	open_work();
	if(!config_screen_res(width+1,height+1)){
		form_alert(1,"[3][Unsupported Screen| resolution.][ Quit ]");
		bale_out();
	}

	if(!rsrc_load("CBZONE.RSC")){
		form_alert(1,"[3][Can't load resource file | CBZONE.RSC ][ OK ]");
		bale_out();
	}
}

void go(void)
/* Things we *really don't want to do until we are sure we are going! */
{
	rsrc_gaddr(R_TREE,FORM1,&dlog);
	save_colours();
	initialise_back_screen();
	create_mfdb(front_ptr,&d,width+1,height+1,planes);
	create_mfdb(back_ptr,&s,width+1,height+1,planes);
	wind_update(BEG_UPDATE);

}

int config_screen_res(int w, int h)
{
	int scale_factor[4]={0,1,2,2};
	int font_factor[4]={8,4,4,4};
	int xratio,yratio,lut;

	vq_extnd(handle,1,work_out);
	planes=work_out[4];
	lut = work_out[5];
	if ((lut==0) && (active_colours > 2)){
		return(FALSE);		/* Probably a TrueColour mode */
	}
	/* Above check for TC fails under current versions of NVDI (lut is returned incorrectly*/
	/* So we do this one as well ... RMG */
	if ((int)(pow((double)(2),(double)(planes)))!=colors){		/* 2^planes != colors */
		return(FALSE);		/* Probably a TrueColour mode */
	}
	if (active_colours==2){
		opt->mono = TRUE;
	}else{
		opt->mono = FALSE;
	}

	xratio = wid/w;
	yratio = hei/h;
	if ((xratio < 3) && (yratio < 4)){
		scalex=scale_factor[xratio];
		scaley=scale_factor[yratio];
		font_size=font_factor[xratio];
		create_block(&screen_block[0],SCLX(70),SCLY(74),SCLX(860),SCLY(340));
		if ((xratio == 0) && (yratio == 0)){
			bit_images=TRUE;
		} 
		return(TRUE);
	}else{
		return(FALSE);
	}
}

void save_colours(void)
{
	int x;

	for (x=0; x<active_colours; x++){
		vq_color(handle,x,1,(GEM_SIZE *)(&saved_colours[x]));
	}
}

void set_colours(void)
{
	int x;

	for (x=0; x<active_colours; x++){
		switch(active_colours){
		case 2:
			vs_color(handle,x,(GEM_SIZE *)(&new_colours_2[x]));
			break;
		case 4:
			vs_color(handle,x,(GEM_SIZE *)(&new_colours_4[x]));
			break;
		case 16:
			vs_color(handle,x,(GEM_SIZE *)(&new_colours_16[x]));
			break;
		}
	}
}

void restore_colours(void)
{
	int x;

	for (x=0; x<active_colours; x++){
		vs_color(handle,x,(GEM_SIZE *)(&saved_colours[x]));
	}
}

void gem_close_down(void)
{
	set_front();
	mouse_on();
	wind_update(END_UPDATE);
	delete_back_screen();
	rsrc_free();
	restore_colours();
	bale_out();
}

void bale_out(void)
{
	v_clsvwk(handle);
	form_dial(FMD_START,0,0,0,0,0,0,width,height);
	form_dial(FMD_FINISH,0,0,0,0,0,0,width,height);
	appl_exit();
	exit(0);
}

void open_work(void)
{
	int i;

	for (i=0; i<10; work_in[i++]=1);
	work_in[10] = 2;
	v_opnvwk(work_in, &handle, work_out);
	v_clrwk(handle);
#ifdef DEBUG
delete_log();	/* delete old log if any */
#endif
	width = work_out[0];
	height = work_out[1];
	active_colours = colors = work_out[13];
	if (active_colours>16){
		active_colours = 16;	/* Only deal with 16 colours max */
	}
	palette_size = work_out[39];

}

void create_block(GEM_SIZE *block, int x, int y, int w, int h)
{

        /* Coverts height and width coords to absolute x,y coords */
        *(block)=x;
        *(block+1)=y;
        *(block+2)=x+w-1;
        *(block+3)=y+h-1;
        *(block+4)=x;
        *(block+5)=y;
        *(block+6)=x+w-1;
        *(block+7)=y+h-1;
}

void create_mfdb(short *addr, MFDB *fdb, int width, int height, int planes)
/* Fills in a blank MFDB with standard information and the supplied
   data address */
{
		int word_width,no_of_words;

		if (((width/16)*16)!=width){
			word_width = ((width/16)+1)*16;
		}else{
			word_width = width;
		}
		no_of_words = word_width/16;

#ifdef LATTICE
        fdb->fd_addr = (void *)(addr); /* changed from (long) to (void *) */
#else
        fdb->fd_addr = (long)(addr);
#endif
        fdb->fd_w = (short)(word_width);
        fdb->fd_h = (short)(height);
        fdb->fd_wdwidth = (short)(no_of_words);
        fdb->fd_stand = (short)(0);
        fdb->fd_nplanes = (short)(planes);
        fdb->fd_r1 = (short)(0);
        fdb->fd_r2 = (short)(0);
        fdb->fd_r3 = (short)(0);
}

#if 0 /* doesn't work yet so don't bother ATM. RMG */
void draw_image(int icon, int dx, int dy)
{
	if (bit_images){
		create_block(&image_block[0],0,0,bmaps[icon].width,bmaps[icon].height);
		image_block[4]=dx;
		image_block[5]=dy;
		image_block[6]=dx+bmaps[icon].width;
		image_block[7]=dy+bmaps[icon].height;
       	vro_cpyfm(handle,S_ONLY,image_block,&pix_mfdb[icon],&d);
	}
}

int get_pix_size(int w,int h)
{
	int pix_size;
	if (((w/8)*8)!=w){				/* Calculate bytes in pixmap from width and height values */
		pix_size = ((w/8)+1)*h;
	}else{
		pix_size = (w/8)*h;
	}
/*
printf("pix_size = %d\n",pix_size);
*/
	return(pix_size);
}

char reverse(char s)
{
	int x;
	int a1=1;
	int a2=128;
	char d=0;

	for (x=0; x<8; x++){
		if (s&a1){
				d=d|a2;
		}
		a1=a1*2;
		a2=a2/2;
	}
	return(d);
}

#endif

void update_front(void)
/* update_front becomes a nice 'front end' for vro_cpyfm so we don't have Atari specific calls in the main code */
{
        vro_cpyfm(handle,S_ONLY,screen_block,&s,&d);
}

void set_front(void)
/* Sets writing screen to front */
{
        Setscreen(front_ptr,(void *)(-1),-1);
}

void set_back(void)
/* Sets writing screen to back */
{
        Setscreen(back_ptr,(void *)(-1),-1);
}

void initialise_back_screen(void){
		size_t mem_req;
        front_ptr = (short *)(Physbase()); /* This line isn't strictly ANSI as
                                                Physbase expands to a {}
                                                which isn't allowed in an
                                                expression */

			/* calculate memory requirments of screen in *words* (Not a safe calculation for all Falcon modes :-( */
		mem_req=((width+1)*(height+1)*planes)/16;
        back_base = (short *)(calloc((mem_req+0x80),2));
			/* allign on 256 byte boundry, for those machines that care */
        back_ptr = (short *)((long)(((char *)(back_base) + 0xFF)) & (long)(0xFFFFFF00));
}

void delete_back_screen(void){
        free(back_base);
}

int handle_dialog(OBJECT *dlog,int editnum)
{
	GEM_SIZE x,y,w,h;
	int but;

	form_center(dlog,&x,&y,&w,&h);
	form_dial(FMD_START,0,0,0,0,x,y,w,h);
	objc_draw(dlog,0,10,x,y,w,h);
	but=form_do(dlog,editnum);
	form_dial(FMD_FINISH,0,0,0,0,x,y,w,h);
	dlog[but].ob_state&=~SELECTED;	/* de-select exit button */
	return(but);
}


/*
 * copy the string from a TEDINFO into another string
 */
void get_tedinfo(OBJECT *tree, int obj, char *dest)
{
	char *source;

	source=((TEDINFO *)tree[obj].ob_spec)->te_ptext;	/* extract address */
	strcpy(dest,source);
}

char *score_dialog(void)
{
	char name[20];
	int but;
	
	mouse_on();
	but=handle_dialog(dlog,name_field);
	if (but==ok_field){
		get_tedinfo(dlog,name_field,name);
	}else{
		strcpy(name,"Mr X");
	}
	mouse_off();
	return(name);
}

void pause_dialog(void)
{
	set_front();
	mouse_on();
	form_alert(1,"[3][ Game Paused ][ CONTINUE ]");
	mouse_off();
	set_back();
}

void gameover_dialog(void)
{
	mouse_on();
	form_alert(1,"[3][ GAME OVER | 1986 JSR ][ OK ]");
	mouse_off();
}

void help_dialog(void)
{
	form_alert(1,"[3][ Sorry help information | not available ][ Cancel ]");
}

void version_dialog(char *ver)
{
	char buf[100];

	sprintf(buf,"[0][ CBZONE Version: | %s | Atari Version 1.0 3/11/94 ][ OK ]",ver);
	form_alert(1,buf);
}

void debug_dialog(char *mess)
{
	char buff[100];
	sprintf(buff,"[3][ %s ][ CONTINUE ]",mess);
	form_alert(1,buff);
}

#ifdef LATTICE
int warn(char *mess)
{
	char buf[100];

	if (opt->nowarn){
		return(TRUE);		/* warnings have been turned off. RMG */
	}
	sprintf(buf,"[3][ %s ][ Continue | Quit ]",mess);
	switch(form_alert(2,buf)){
	case 1:
		return(TRUE);
		break;
	case 2:
	default:
		return(FALSE);
		break;
	}
}
#endif

void mouse_on(void)
{
	graf_mouse(ARROW,(void *)(0));		/* force an arrow pointer */
	v_show_c(handle,1);		/* show mouse pointer */
}

void mouse_off(void)
{
	v_hide_c(handle);		/* hide mouse pointer */
}
