//////////////////////////////////////////////////////////////////////////////
//
//  This file is part of the Atari Machine Specific Library,
//  and is Copyright 1992 by Warwick W. Allison.
//
//  You are free to copy and modify these sources, provided you acknoledge
//  the origin by retaining this notice, and adhere to the conditions
//  described in the file COPYING.
//
//////////////////////////////////////////////////////////////////////////////

#include "screen.h"
#include "resolution.h"
#include "ca_pack.h"
#include "ca_unpac.h"
#include <stdio.h>
#include <osbind.h>
#include <alloc.h>
#include <builtin.h>


static void *Page(void *adr)
{
	unsigned long a=(unsigned long)adr;
	return (void *)((a & 0xffffff00)+0x100);
}

Screen::Screen(const Screen& Same) :
	Res(Same.Res),
	AllocSize(BytesPerLine[Res]*ScreenHeight[Res]+254),
	AllocArea(new char[AllocSize]),
	location(Page(AllocArea)),
	Palette(new short[NumberOfColours[Res]])
{
	memcpy(location,Same.location,BytesPerLine[Res]*ScreenHeight[Res]);
	memcpy(Palette,Same.Palette,sizeof(Palette[0])*NumberOfColours[Res]);
}

Screen::Screen(Resolution res) :
	Res(res),
	AllocSize(BytesPerLine[Res]*ScreenHeight[Res]+254),
	AllocArea(new char[AllocSize]),
	location(Page(AllocArea)),
	Palette(new short[NumberOfColours[Res]])
{ }

Screen::Screen(short LinesAbove, short LinesBelow) :
	Res(Getrez()),
	AllocSize(BytesPerLine[Res]*(ScreenHeight[Res]+LinesAbove+LinesBelow)+254),
	AllocArea(new char[AllocSize]),
	location(Page(AllocArea)),
	Palette(new short[NumberOfColours[Res]])
{ }

Screen::Screen() :
	Res(Getrez()),
	AllocSize(BytesPerLine[Res]*ScreenHeight[Res]+254),
	AllocArea(new char[AllocSize]),
	location(Page(AllocArea)),
	Palette(new short[NumberOfColours[Res]])
{ }

Screen::Screen(char *At)
{
	Res=Getrez();

	AllocSize=0;
	AllocArea=0;
	if (At) {
		location=At;
	}
	else {
		location=Physbase();
	}
	Palette=malloc(sizeof(Palette[0])*NumberOfColours[Res]);
	for (int i=0; i<NumberOfColours[Res]; i++) {
		Palette[i]=Setcolor(i,-1);
	}
}

Screen::Screen(Resolution res, short LinesAbove, short LinesBelow)
{
	short BPL=BytesPerLine[res];
	int BaseSize=BPL*ScreenHeight[res]+254;

	AllocSize=BaseSize+(LinesAbove+LinesBelow)*BPL;
	AllocArea=malloc(AllocSize);
	location=Page(AllocArea+BPL*LinesAbove);
	Palette=malloc(sizeof(Palette[0])*NumberOfColours[res]);
	Res=res;
}

Screen::~Screen()
{
	if (AllocArea) delete AllocArea;
	delete Palette;
}


void Screen::Clear()
{
/* Clear visible region? */
	int i=BytesPerLine[Res]*ScreenHeight[Res]/sizeof(long);
	long * data=(long*) location;

/* ...or clear whole area?
	int i=AllocSize/sizeof(long);
	long *data=(long *)AllocArea;
*/

	while (i--) data[i]=0;
}

#define CHECK(x) {if ((x)<=0) {fclose(file); return 0;}}

int Screen::LoadDegasPalette(const char *filename)
{
	FILE *file;
	short res;

	file=fopen(filename,"rb");
	if (!file) return 0;

	CHECK(fread(&res,sizeof(res),1,file));
	CHECK(fread(Palette,sizeof(short),NumberOfColours[Res],file));

	fclose(file);

	return 1;
}

int Screen::LoadDegas(const char *filename)
{
	FILE *file;
	short res;
	short junk;

	file=fopen(filename,"rb");
	if (!file) return 0;

	CHECK(fread(&res,sizeof(res),1,file));
	if (NumberOfColours[res]!=NumberOfColours[Res]) {
		delete Palette;
		Palette=new short[NumberOfColours[Res]];
	}
	Res=res;
	CHECK(fread(Palette,sizeof(short),NumberOfColours[Res],file));
	for (int ignore=16-NumberOfColours[Res]; ignore>0; ignore--)
		CHECK(fread(&junk,sizeof(short),1,file));
	CHECK(fread(location,1,BytesPerLine[Res]*ScreenHeight[Res],file));

	fclose(file);

	return 1;
}

int Screen::SaveDegas(const char *filename)
{
	FILE *file;
	short res;

	file=fopen(filename,"wb");
	if (!file) return 0;

	res=Res;
	CHECK(fwrite(&res,sizeof(short),1,file));
	CHECK(fwrite(Palette,sizeof(short),NumberOfColours[Res],file));
	if (NumberOfColours[Res] < 16) {
		short junk=0;
		for (int ignore=16-NumberOfColours[Res]; ignore; ignore--)
			CHECK(fwrite(&junk,sizeof(short),1,file));
	}
	CHECK(fwrite(location,1,BytesPerLine[Res]*ScreenHeight[Res],file));
	fclose(file);

	return 1;
}


PaletteChange::PaletteChange() :
	ncols(16),
	col(new short[ncols])
{
	for (int i=0; i<ncols; i++) {
		col[i]=Setcolor(i,-1);
	}
}

PaletteChange::~PaletteChange()
{
	Setpalette(col);

	delete col;
}

/////////////////////////////////////////////////
//                                             //
//  CrackArt I/O as per GFA basic code:        //
//                                             //
//    CRACK ART 'CA_PACK'                      //
//                                             //
//    Kompressionsroutine fr CA?-Bilder       //
//                                             //
//    ½ Detlef R”ttger & Jan Borchers 1989-91  //
//                                             //
/////////////////////////////////////////////////

int Screen::LoadCrackArtPalette(const char *Filename)
{
	FILE* fp=fopen(Filename,"rb");

	if (!fp) return 0;

	char Magic[2];
	fread(Magic,sizeof(char),2,fp);
	if (Magic[0]!='C' || Magic[1]!='A') {
		fclose(fp);
		return 0;
	}

	short Rez;
	fread(&Rez,sizeof(short),1,fp);
	Rez&=255;

	if (Rez!=Res) {
		return 0;
	}

	// NB. CrackArt file format is WRONG for CA3 - it doesn't save a palette
	//     this is very wrong - especially on the TT.  So we can't load one.
	if (Rez==STHigh) {
		Palette[0]=0x777;
		Palette[1]=0x000;
	} else {
		fread(Palette,sizeof(short),NumberOfColours[Rez],fp);
	}

	fclose(fp);

	return 1;
}

int Screen::LoadCrackArt(const char *Filename)
{
	FILE* fp=fopen(Filename,"rb");

	if (!fp) return 0;

	char Magic[2];
	fread(Magic,sizeof(char),2,fp);
	if (Magic[0]!='C' || Magic[1]!='A') {
		fclose(fp);
		return 0;
	}

	short Rez;
	fread(&Rez,sizeof(short),1,fp);
	Rez&=255;

	if (Rez!=Res) {
		Res=Rez;
		// Reallocate? Fail? *******************
	}

	// NB. CrackArt file format is WRONG for CA3 - it doesn't save a palette
	//     this is very wrong - especially on the TT.  We could load one,
	//     expecting CrackArt to correct the problem, if they ever support
	//     mono rez, but then we couldn't load them!  Perhaps we could add a
	//     hack to set a bit in the reserved byte after Rez, but it's not
	//     our format!  Now the question is, do we make CrackArt's mistake
	//     again and not support a palette in TTHigh?  No.
	if (Rez==STHigh) {
		Palette[0]=0x777;
		Palette[1]=0x000;
	} else {
		fread(Palette,sizeof(short),NumberOfColours[Rez],fp);
	}

	LoadCrackArtData((unsigned char*)location,BytesPerLine[Rez]*ScreenHeight[Rez],fp);

	fclose(fp);

	return 1;
}


int Screen::SaveCrackArt(const char *Filename, int Compression=3)
{
	FILE* fp=fopen(Filename,"wb");

	if (!fp) return 0;

	fwrite("CA",sizeof(char),2,fp);

	short Rez=256+Res;
	fwrite(&Rez,sizeof(short),1,fp);

	// NB. CrackArt file format is WRONG for CA3 - it doesn't save a palette
	//     this is very wrong - especially on the TT.  So we don't save one.
	if (Res!=STHigh) fwrite(Palette,sizeof(short),NumberOfColours[Res],fp);

	SaveCrackArtData((unsigned char*)location,BytesPerLine[Res]*ScreenHeight[Res],fp,Compression);

	fclose(fp);

	return 1;
}
