/*
	mask.c：マスク管理

	mask_init			領域指定処理の初期化
	mask_chkxy			ある座標が、指定領域内かどうかを調べる
	mask_chkxylen		ある座標から右に何ドット同じフラグが連続しているか
	mask_clear
	mask_hline			set, clear, exchange の３方式でのマスクの描画
	mask_setswitch		マスクの有効／無効化スイッチ
	mask_tempoff_begin
	mask_tempoff_end
*/

#include <stdio.h>
#include <stdefs.h>
#include <egb.h>
#include <malloc.h>
#include <stdlib.h>
#include <msdos.cf>
#include <memory.h>
#include <interrup.cf>

#include "ge.h"
#include "plt16.h"
#include "math2.h"
#include "decimal.h"
#include "dispman.h"
#include "imageman.h"


static char		*mask_buf = NULL, *mask_buf2 = NULL;
static bool		masksizevar = NO;	// マスクバッファの縦横サイズが可変か
static int		maskxlen, maskylen;	// masksizevar=YES 時の縦横サイズ
static	bool	mask_sw;			// マスクが有効かどうか


#define	MASKXLEN	512

int mask_init(void)
// 返値: 0=成功  0以外=メモリ不足
{
	int size;
	if (EIMgetxsize() <= MASKXLEN)
		masksizevar = NO, maskxlen = MASKXLEN;
	else
		masksizevar = YES, maskxlen=(EIMgetxsize()+7)&0xffff8;
	maskylen = EIMgetysize();
	size = (maskxlen / 8) * maskylen;
	if (mask_buf == NULL)
	{
		if ((mask_buf = calloc(1,size*2)) == NULL)
		{
			DEBUG_MSG("マスクバッファ用メモリ領域　確保失敗");
			return -1;
		}
		else
			DEBUG_MSG("マスクバッファ用メモリ領域　確保成功");
		mask_buf2 = mask_buf + size;
	}
	mask_sw = YES;
	return 0;
}


void mask_clear(void)
{
	memset(mask_buf, 0, (maskxlen >> 3)*maskylen);
}


void mask_hline(int x1,int x2,int y, int method)
{
	#define SETMASK(p, bitpat, method) \
		( (method)==2 ? *(p) ^= (bitpat)  : \
		  (method)==1 ? *(p) &= ~(bitpat) : \
		                *(p) |= (bitpat) )
	char *p;  int x,leftx,rightx,xr1,xr2;
	if (x1 > x2)
		swap(x1,x2);
	p = mask_buf + (maskxlen >> 3) * y + (x1 >> 3);
	leftx = x1 & 0xfff8;
	xr1 = x1 & 7;
	rightx = x2 & 0xfff8;
	xr2 = x2 & 7;
	if (leftx == rightx)
	{
		SETMASK(p, (0xff << xr1) & (0xff >> (7-xr2)), method);
	}
	else
	{
		x = leftx;
		SETMASK(p,(0xff<<xr1)&0xff,method), p++, x += 8;	// 左端
		while (x < rightx)									// 真ん中
			SETMASK(p,0xff,method), p++, x += 8;
		SETMASK(p, (0xff >> (7-xr2)), method);				// 右端
	}
}



static char bit8[] = {1,2,4,8,16,32,64,128};


static bool _mask_chkxy(char *maskbuf, int x, int y)
// (x,y) が領域指定されているかを調べる
{
	if (!mask_sw || x < 0 || y < 0 || maskxlen <= x || maskylen <= y)
		return NO;
	if (!masksizevar)
	{
		char r = (x & 7);
		return (*(maskbuf+y*(MASKXLEN/8)+(x>>3)) & bit8[r]) == 0 ? NO : YES;
	}
	else
	{
		char r = (x & 7);
		return (*(maskbuf+y*(maskxlen>>3)+(x>>3)) & bit8[r]) == 0 ? NO : YES;
	}
}

bool mask_chkxy(int x, int y)
{
	return _mask_chkxy(mask_buf, x, y);
}

bool mask_chkxy_back(int x, int y)
{
	return _mask_chkxy(mask_buf2, x, y);
}


static int _mask_chkxylen(int x,int xmax,int y,bool nega, char *maskbuf)
// (x,y) から右に何ドット連続して指定されているかを調べる(or 0)
// nega: 働きを逆にする(領域指定されていない点の連続数を求める)
{
	int _maxx = _min(xmax,maskxlen-1);
	int xbytes = maskxlen >> 3;
	char *p = maskbuf + y*xbytes + (x>>3);
	int i,r;
	if (!nega)
	{
		if (!mask_sw || x < 0 || _maxx < x || y < 0 || maskylen <= y)
			return 0;
		for (i=x,r=x&7; i<=_maxx; )
		{
			if (r==0 && *p == 255)
			{
				i+=8, p++;
				continue;
			}
			else if ((*p & bit8[r]) == 0)
				break;
			i++;
			if (++r == 8)
				r=0, p++;
		}
	}
	else
	{
		int dr = _max(0, xmax - x + 1);
		if (!mask_sw || x < 0 || _maxx < x || y < 0 || maskylen <= y)
			return dr;
		for (i=x,r=x&7; i<=_maxx; )
		{
			if (r==0 && *p == 0)
			{
				i+=8, p++;
				continue;
			}
			else if ((*p & bit8[r]) != 0)
				break;
			i++;
			if (++r == 8)
				r=0, p++;
		}
	}
	i = _min(_maxx+1,i);
	return i-x;
}

int mask_chkxylen(int x,int xmax,int y,bool nega)
{
	return _mask_chkxylen(x,xmax,y,nega, mask_buf);
}

int mask_chkxylen_back(int x,int xmax,int y,bool nega)
{
	return _mask_chkxylen(x,xmax,y,nega, mask_buf2);
}

bool mask_getswitch(void)
{
	return mask_sw;
}

void mask_setswitch(bool sw)
{
	mask_sw = sw;
}

void	mask_backup(void)
{
	memcpy(mask_buf2, mask_buf, (maskxlen >> 3)*maskylen);
}

static bool tempmasksw;

void	mask_tempoff_begin(void)
{
	tempmasksw = mask_sw;
	mask_sw = NO;
}

void	mask_tempoff_end(void)
{
	mask_sw = tempmasksw;
}
