/*
 * fVDI driver initialization
 * Copyright 1998, Johan Klockars
 * (will be GPL of similar in the future)
 *
 * I don't expect this file to need many changes for different modes
 * and hardware. When necessary, #define should be used as for
 * TRUE_COLOUR etc below.
 *
 * This file will of course be extended when new acceleration options
 * and similar are added to the fVDI kernel.
 */

#define DOALINE	0	/* Do actual drawing w/ linea (clip) */
#if 1
#define FAST	1	/* Write in FastRAM buffer */
#define BOTH	1	/* Write in both FastRAM and on screen */
#else
#undef FAST		0
#undef BOTH		0
#endif
#define LONGS	1
#define GET	1
#define MUL	1	/* Multiply rather than use table */
#define SHIFT	1
#define DEVELOP	1

#undef TRUE_COLOUR
#define TRUE_COLOUR

#undef CHUNKY
#define CHUNKY

#ifdef TRUE_COLOUR
 #define NO_BITPLANES
#else
 #ifdef CHUNKY
  #define NO_BITPLANES
 #endif
#endif

#ifdef TRUE_COLOUR
 int true_colour_mode;
#else
 #ifdef CHUNKY
  int chunky_palette_colour_mode;
 #else
  int bitplane_palette_colour_mode;
 #endif
#endif

#ifdef __PUREC__
   #include <tos.h>
#else
   #include <osbind.h>
#endif

#include "..\vdi.h"
#include "..\relocate.h"

#define MAGIC     "InitMagic"

#define A_TEXT		0x01
#define A_BLIT		(A_TEXT << 1)
#define A_FILL		(A_BLIT << 1)
#define A_EXPAND	(A_FILL << 1)
#define A_LINE		(A_EXPAND << 1)

#define MAX_PALETTE	256
#define Min(x,y)	(((x) <= (y)) ? (x) : (y))


extern void check_linea(Workstation *);
extern void *set_palette;
extern void *get_colour;
extern void *set_pixel;
extern void *c_set_pixel;
extern void *get_pixel;
extern void *c_get_pixel;
extern void *line;
extern void *c_line;
extern void *line_draw;
extern void *c_line_draw;
extern void *expand;
extern void *c_expand;
extern void *expand_area;
extern void *c_expand_area;
extern void *fill;
extern void *c_fill;
extern void *fill_area;
extern void *c_fill_area;
extern void *blit;
extern void *c_blit;
extern void *blit_area;
extern void *c_blit_area;
extern void *text;
extern void *c_text;
extern void *text_area;
extern void *c_text_area;

extern short appl_init(void);
extern short appl_exit(void);
extern void vq_extnd(int handle, int info_flag, short *int_out, short *pts_out);
extern void vq_color(int handle, int colour, int flag, short *int_out);
extern void initialize_palette(Virtual *vwk, int start, int n, short colours[][3], Colour *palette);


void setup_vdi(Virtual *);

/*
 * Global variables
 */

List driver_link = {0, 1, setup_vdi};


/*
 * Local variables
 */
int init(Access *_access, Virtual *wk, char *);

Locator locator = {MAGIC, 0x0010, init};

Access *access;

#ifdef NO_BITPLANES
short colour[1][1];		/* Dummy */
#else
short colour[16][4];
#endif

Virtual *default_vwk = 0;
Workstation *default_wk = 0;
Colour *default_palette = 0;


/*
 * Local functions
 */

void copymem(void *s, void *d, int n)
{
	char *src, *dest;

	src = (char *)s;
	dest = (char *)d;
	for(n = n - 1; n >= 0; n--)
		*dest++ = *src++;
}

int init(Access *_access, Virtual *vwk, char *opts)
{
	int fast_w_bytes;
	char *buf;
#ifndef NO_BITPLANES
	int i, j, v;
#endif
	Workstation *wk;
	const char *ptr;
	char token[80], *tmp, ch;
	int shadow, accelerate;
	
	access = _access;

	shadow = 0;
	accelerate = 0xffff;             /* Default to everything on */
	ptr = opts;
	ptr = access->funcs.skip_space(ptr);
	while (ptr) {
		ptr = access->funcs.get_token(ptr, token, 80);
		if (access->funcs.equal(token, "shadow"))
			shadow = 1;
		if (access->funcs.equal(token, "accelerate")) {
			if (!(ptr = access->funcs.skip_space(ptr)))
				;		/* *********** Error, somehow */
	       		ptr = access->funcs.get_token(ptr, token, 80);
			accelerate = 0;
			tmp = token;
			while (ch = *tmp++) {
				accelerate <<= 1;
				if ((ch != '0') && (ch != '-'))
					accelerate++;
			}
		}
		ptr = access->funcs.skip_space(ptr);
	}

	if (!(default_wk = (Workstation *)Malloc(sizeof(Workstation))))
		return 0;

	if (!(default_vwk = (Virtual *)Malloc(sizeof(Virtual)))) {
		Mfree(default_wk);
		return 0;
	}

	copymem(vwk->real_address, default_wk, sizeof(Workstation));
	copymem(vwk, default_vwk, sizeof(Virtual));

	wk = default_wk;
	default_vwk->real_address = wk;
#if 1					/* Only temporary */
	wk = vwk->real_address;
#endif
	
	check_linea(wk);

	wk->screen.palette.size = Min(1L << wk->screen.mfdb.bitplanes, MAX_PALETTE);
	wk->screen.mfdb.address = (void *)Physbase();
	wk->screen.mfdb.wdwidth = wk->screen.mfdb.width / 16;
#if 0
	wk->screen.logical = Logical();
#endif

	if (!(default_palette = (Colour *)Malloc(wk->screen.palette.size * sizeof(Colour)))) {
		Mfree(default_vwk);
		Mfree(default_wk);
		return 0;
	}
	wk->screen.palette.colours = default_palette;

	if (shadow && FAST) {
 #if 0			/* It's not clear that this is a good idea */
		fast_w_bytes = (wk->screen.wrap + 15) & 0xfffffff0;
 #else
		fast_w_bytes = wk->screen.wrap;
 #endif
		buf = Mxalloc(fast_w_bytes * wk->screen.mfdb.height + 255, 1);
		if (buf) {
			wk->screen.shadow.buffer = buf;
			wk->screen.shadow.address = (void *)(((long)buf + 255) & 0xffffff00);
			wk->screen.shadow.wrap = fast_w_bytes;
		} else {
			access->funcs.error("Can't allocate FastRAM!", 0);
			wk->screen.shadow.buffer = 0;
			wk->screen.shadow.address = 0;
		}
		if (!BOTH)
			wk->screen.mfdb.address = wk->screen.shadow.address;
	}

#ifndef NO_BITPLANES
	for(i = 0; i < 16; i++) {
		switch (wk->screen.mfdb.bitplanes) {
		case 1:
			v = (i & 0x01) ? 0x000f : 0;
			break;
		case 2:
			v = i & 0x03;
			v |= v << 2;
			break;
		default:
			v = i;
			break;
		}
		for(j = 0; j < 4; j++) {
			if (v & 0x01)
				colour[i][j] = 0xffff;
			else
				colour[i][j] = 0;
			v >>= 1;
		}
	}
#endif

	wk->screen.mfdb.standard = 0;
	wk->screen.type = 4;
	wk->screen.colour = 1;
	wk->screen.bkg_colours = 0;			/* ? */
#ifdef TRUE_COLOUR
	wk->screen.look_up_table = 0;			/* True colour */
#else
	wk->screen.look_up_table = 1;			/* Not true colour */
#endif
#ifdef CHUNKY
	wk->screen.palette.possibilities = 1 << 24;	/* Graphics card */
#else
	wk->screen.palette.possibilities = 1 << 18;	/* On a Falcon */
#endif
/* Values and transformation table */
/* Pixel width/height */
/* Coordinates (what's 'course?  max/min should be more sophisticated */
	wk->screen.coordinates.max_x = wk->screen.mfdb.width - 1;
	wk->screen.coordinates.max_y = wk->screen.mfdb.height - 1;
/* 16x16 op/s */
	wk->various.buttons = 2;
	wk->various.cursor_movement = 2;
	wk->various.number_entry = 1;
	wk->various.selection = 1;
	wk->various.typing = 1;
	wk->various.workstation_type = 2;
		
	wk->r.set_palette = &set_palette;
	wk->r.get_colour = &get_colour;
	wk->r.set_pixel = &set_pixel;
	wk->r.get_pixel = &get_pixel;
	if (accelerate & A_LINE) {
		if(*(short *)&line_draw != 0x4e75)
			wk->r.line = &line;
		else if(*(short *)&c_line_draw != 0x4e75)
			wk->r.line = &c_line;
	}
	if (accelerate & A_EXPAND) {
		if (*(short *)&expand_area != 0x4e75)
			wk->r.expand = &expand;
		else if (*(short *)&c_expand_area != 0x4e75)
			wk->r.expand = &c_expand;
	}
	if (accelerate & A_FILL) {
		if (*(short *)&fill_area != 0x4e75)
			wk->r.fill = &fill;
		else if (*(short *)&c_fill_area != 0x4e75)
			wk->r.fill = &c_fill;
	}
	if (accelerate & A_BLIT) {
		if (*(short *)&blit_area != 0x4e75)
			wk->r.blit = &blit;
		else if (*(short *)&c_blit_area != 0x4e75)
			wk->r.blit = &c_blit;
	}
	if (accelerate & A_TEXT) {
		if (*(short *)&text_area != 0x4e75)
			wk->r.text = &text;
		else if (*(short *)&c_text_area != 0x4e75)
			wk->r.text = &c_text;
	}

/* Perhaps set up default clipping? */

	return (int)&driver_link;
}

#if 0
void setup_vdi(void)
#else
void setup_vdi(Virtual *vwk)
#endif
{
	Workstation *wk;
#if 0
	Virtual *vwk;
#endif
	short colours[256][3];
	short intout[45];
#if 0
	short ptsout[12];
#endif
	int i, size;
	
#if 0
	wk = default_wk;
	vwk = default_vwk;
#else
	wk = vwk->real_address;
#endif
	size = wk->screen.palette.size;
	for(i = 0; i < size; i++) {
		vq_color(1, i, 0, intout);
		if (intout[0] == -1) {
			size = i;			/* Should not really happen */
			break;
		}
		colours[i][0] = intout[1];
		colours[i][1] = intout[2];
		colours[i][2] = intout[3];
	}
	initialize_palette(vwk, 0, size, colours, wk->screen.palette.colours);
#if 0
	vq_extnd(1, 0, intout, ptsout);
	vq_extnd(1, 1, intout, ptsout);
#endif
}
